Author: kib
Date: Sun Apr 25 16:43:41 2010
New Revision: 207195
URL: http://svn.freebsd.org/changeset/base/207195

Log:
  Provide compat32 shims for bpf(4), except zero-copy facilities.
  
  bd_compat32 field of struct bpf_d is kept unconditionally to not
  impose the requirement of including "opt_compat.h" on all numerous
  users of bpfdesc.h.
  
  Submitted by: jhb (version for 6.x)
  Reviewed and tested by:       emaste
  MFC after:    2 weeks

Modified:
  head/sys/net/bpf.c
  head/sys/net/bpfdesc.h

Modified: head/sys/net/bpf.c
==============================================================================
--- head/sys/net/bpf.c  Sun Apr 25 16:42:47 2010        (r207194)
+++ head/sys/net/bpf.c  Sun Apr 25 16:43:41 2010        (r207195)
@@ -38,6 +38,7 @@
 __FBSDID("$FreeBSD$");
 
 #include "opt_bpf.h"
+#include "opt_compat.h"
 #include "opt_netgraph.h"
 
 #include <sys/types.h>
@@ -89,6 +90,43 @@ MALLOC_DEFINE(M_BPF, "BPF", "BPF data");
 
 #define PRINET  26                     /* interruptible */
 
+#ifdef COMPAT_FREEBSD32
+#include <sys/mount.h>
+#include <compat/freebsd32/freebsd32.h>
+#define BPF_ALIGNMENT32 sizeof(int32_t)
+#define BPF_WORDALIGN32(x) (((x)+(BPF_ALIGNMENT32-1))&~(BPF_ALIGNMENT32-1))
+
+/*
+ * 32-bit version of structure prepended to each packet.  We use this header
+ * instead of the standard one for 32-bit streams.  We mark the a stream as
+ * 32-bit the first time we see a 32-bit compat ioctl request.
+ */
+struct bpf_hdr32 {
+       struct timeval32 bh_tstamp;     /* time stamp */
+       uint32_t        bh_caplen;      /* length of captured portion */
+       uint32_t        bh_datalen;     /* original length of packet */
+       uint16_t        bh_hdrlen;      /* length of bpf header (this struct
+                                          plus alignment padding) */
+};
+
+struct bpf_program32 {
+       u_int bf_len;
+       uint32_t bf_insns;
+};
+
+struct bpf_dltlist32 {
+       u_int   bfl_len;
+       u_int   bfl_list;
+};
+
+#define        BIOCSETF32      _IOW('B', 103, struct bpf_program32)
+#define        BIOCSRTIMEOUT32 _IOW('B',109, struct timeval32)
+#define        BIOCGRTIMEOUT32 _IOR('B',110, struct timeval32)
+#define        BIOCGDLTLIST32  _IOWR('B',121, struct bpf_dltlist32)
+#define        BIOCSETWF32     _IOW('B',123, struct bpf_program32)
+#define        BIOCSETFNR32    _IOW('B',130, struct bpf_program32)
+#endif
+
 /*
  * bpf_iflist is a list of BPF interface structures, each corresponding to a
  * specific DLT.  The same network interface might have several BPF interface
@@ -1005,8 +1043,14 @@ bpfioctl(struct cdev *dev, u_long cmd, c
                case BIOCFLUSH:
                case BIOCGDLT:
                case BIOCGDLTLIST:
+#ifdef COMPAT_FREEBSD32
+               case BIOCGDLTLIST32:
+#endif
                case BIOCGETIF:
                case BIOCGRTIMEOUT:
+#ifdef COMPAT_FREEBSD32
+               case BIOCGRTIMEOUT32:
+#endif
                case BIOCGSTATS:
                case BIOCVERSION:
                case BIOCGRSIG:
@@ -1015,6 +1059,9 @@ bpfioctl(struct cdev *dev, u_long cmd, c
                case FIONREAD:
                case BIOCLOCK:
                case BIOCSRTIMEOUT:
+#ifdef COMPAT_FREEBSD32
+               case BIOCSRTIMEOUT32:
+#endif
                case BIOCIMMEDIATE:
                case TIOCGPGRP:
                case BIOCROTZBUF:
@@ -1023,6 +1070,22 @@ bpfioctl(struct cdev *dev, u_long cmd, c
                        return (EPERM);
                }
        }
+#ifdef COMPAT_FREEBSD32
+       /*
+        * If we see a 32-bit compat ioctl, mark the stream as 32-bit so
+        * that it will get 32-bit packet headers.
+        */
+       switch (cmd) {
+       case BIOCSETF32:
+       case BIOCSETFNR32:
+       case BIOCSETWF32:
+       case BIOCGDLTLIST32:
+       case BIOCGRTIMEOUT32:
+       case BIOCSRTIMEOUT32:
+               d->bd_compat32 = 1;
+       }
+#endif
+
        CURVNET_SET(TD_TO_VNET(td));
        switch (cmd) {
 
@@ -1080,6 +1143,11 @@ bpfioctl(struct cdev *dev, u_long cmd, c
        case BIOCSETF:
        case BIOCSETFNR:
        case BIOCSETWF:
+#ifdef COMPAT_FREEBSD32
+       case BIOCSETF32:
+       case BIOCSETFNR32:
+       case BIOCSETWF32:
+#endif
                error = bpf_setf(d, (struct bpf_program *)addr, cmd);
                break;
 
@@ -1123,6 +1191,26 @@ bpfioctl(struct cdev *dev, u_long cmd, c
        /*
         * Get a list of supported data link types.
         */
+#ifdef COMPAT_FREEBSD32
+       case BIOCGDLTLIST32:
+               {
+                       struct bpf_dltlist32 *list32;
+                       struct bpf_dltlist dltlist;
+
+                       list32 = (struct bpf_dltlist32 *)addr;
+                       dltlist.bfl_len = list32->bfl_len;
+                       dltlist.bfl_list = PTRIN(list32->bfl_list);
+                       if (d->bd_bif == NULL)
+                               error = EINVAL;
+                       else {
+                               error = bpf_getdltlist(d, &dltlist);
+                               if (error == 0)
+                                       list32->bfl_len = dltlist.bfl_len;
+                       }
+                       break;
+               }
+#endif
+
        case BIOCGDLTLIST:
                if (d->bd_bif == NULL)
                        error = EINVAL;
@@ -1166,8 +1254,23 @@ bpfioctl(struct cdev *dev, u_long cmd, c
         * Set read timeout.
         */
        case BIOCSRTIMEOUT:
+#ifdef COMPAT_FREEBSD32
+       case BIOCSRTIMEOUT32:
+#endif
                {
                        struct timeval *tv = (struct timeval *)addr;
+#ifdef COMPAT_FREEBSD32
+                       struct timeval32 *tv32;
+                       struct timeval tv64;
+
+                       if (cmd == BIOCSRTIMEOUT32) {
+                               tv32 = (struct timeval32 *)addr;
+                               tv = &tv64;
+                               tv->tv_sec = tv32->tv_sec;
+                               tv->tv_usec = tv32->tv_usec;
+                       } else
+#endif
+                               tv = (struct timeval *)addr;
 
                        /*
                         * Subtract 1 tick from tvtohz() since this isn't
@@ -1182,11 +1285,31 @@ bpfioctl(struct cdev *dev, u_long cmd, c
         * Get read timeout.
         */
        case BIOCGRTIMEOUT:
+#ifdef COMPAT_FREEBSD32
+       case BIOCGRTIMEOUT32:
+#endif
                {
-                       struct timeval *tv = (struct timeval *)addr;
+                       struct timeval *tv;
+#ifdef COMPAT_FREEBSD32
+                       struct timeval32 *tv32;
+                       struct timeval tv64;
+
+                       if (cmd == BIOCGRTIMEOUT32)
+                               tv = &tv64;
+                       else
+#endif
+                               tv = (struct timeval *)addr;
 
                        tv->tv_sec = d->bd_rtout / hz;
                        tv->tv_usec = (d->bd_rtout % hz) * tick;
+#ifdef COMPAT_FREEBSD32
+                       if (cmd == BIOCGRTIMEOUT32) {
+                               tv32 = (struct timeval32 *)addr;
+                               tv32->tv_sec = tv->tv_sec;
+                               tv32->tv_usec = tv->tv_usec;
+                       }
+#endif
+
                        break;
                }
 
@@ -1369,7 +1492,19 @@ bpf_setf(struct bpf_d *d, struct bpf_pro
 #ifdef BPF_JITTER
        bpf_jit_filter *ofunc;
 #endif
-
+#ifdef COMPAT_FREEBSD32
+       struct bpf_program32 *fp32;
+       struct bpf_program fp_swab;
+
+       if (cmd == BIOCSETWF32 || cmd == BIOCSETF32 || cmd == BIOCSETFNR32) {
+               fp32 = (struct bpf_program32 *)fp;
+               fp_swab.bf_len = fp32->bf_len;
+               fp_swab.bf_insns = (struct bpf_insn *)(uintptr_t)fp32->bf_insns;
+               fp = &fp_swab;
+               if (cmd == BIOCSETWF32)
+                       cmd = BIOCSETWF;
+       }
+#endif
        if (cmd == BIOCSETWF) {
                old = d->bd_wfilter;
                wfilter = 1;
@@ -1771,6 +1906,9 @@ catchpacket(struct bpf_d *d, u_char *pkt
     struct timeval *tv)
 {
        struct bpf_hdr hdr;
+#ifdef COMPAT_FREEBSD32
+       struct bpf_hdr32 hdr32;
+#endif
        int totlen, curlen;
        int hdrlen = d->bd_bif->bif_hdrlen;
        int do_wakeup = 0;
@@ -1809,7 +1947,12 @@ catchpacket(struct bpf_d *d, u_char *pkt
         * buffer is considered immutable by the buffer model, try to rotate
         * the buffer and wakeup pending processes.
         */
-       curlen = BPF_WORDALIGN(d->bd_slen);
+#ifdef COMPAT_FREEBSD32
+       if (d->bd_compat32)
+               curlen = BPF_WORDALIGN32(d->bd_slen);
+       else
+#endif
+               curlen = BPF_WORDALIGN(d->bd_slen);
        if (curlen + totlen > d->bd_bufsize || !bpf_canwritebuf(d)) {
                if (d->bd_fbuf == NULL) {
                        /*
@@ -1831,6 +1974,22 @@ catchpacket(struct bpf_d *d, u_char *pkt
                 * reader should be woken up.
                 */
                do_wakeup = 1;
+#ifdef COMPAT_FREEBSD32
+       /*
+        * If this is a 32-bit stream, then stick a 32-bit header at the
+        * front and copy the data into the buffer.
+        */
+       if (d->bd_compat32) {
+               bzero(&hdr32, sizeof(hdr32));
+               hdr32.bh_tstamp.tv_sec = tv->tv_sec;
+               hdr32.bh_tstamp.tv_usec = tv->tv_usec;
+               hdr32.bh_datalen = pktlen;
+               hdr32.bh_hdrlen = hdrlen;
+               hdr.bh_caplen = hdr32.bh_caplen = totlen - hdrlen;
+               bpf_append_bytes(d, d->bd_sbuf, curlen, &hdr32, sizeof(hdr32));
+               goto copy;
+       }
+#endif
 
        /*
         * Append the bpf header.  Note we append the actual header size, but
@@ -1846,6 +2005,9 @@ catchpacket(struct bpf_d *d, u_char *pkt
        /*
         * Copy the packet data into the store buffer and update its length.
         */
+#ifdef COMPAT_FREEBSD32
+ copy:
+#endif
        (*cpfn)(d, d->bd_sbuf, curlen + hdrlen, pkt, hdr.bh_caplen);
        d->bd_slen = curlen + totlen;
 

Modified: head/sys/net/bpfdesc.h
==============================================================================
--- head/sys/net/bpfdesc.h      Sun Apr 25 16:42:47 2010        (r207194)
+++ head/sys/net/bpfdesc.h      Sun Apr 25 16:43:41 2010        (r207195)
@@ -97,6 +97,7 @@ struct bpf_d {
        u_int64_t       bd_wfcount;     /* number of packets that matched write 
filter */
        u_int64_t       bd_wdcount;     /* number of packets dropped during a 
write */
        u_int64_t       bd_zcopy;       /* number of zero copy operations */
+       u_char          bd_compat32;    /* 32-bit stream on LP64 system */
 };
 
 /* Values for bd_state */
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to