On 10.06.2012 18:20, Alexander V. Chernikov wrote:
On 27.04.2012 03:44, Hiroki Sato wrote:
"Alexander V. Chernikov"<melif...@freebsd.org> wrote
in<4f96e71b.9020...@freebsd.org>:

me> On 24.04.2012 21:05, Hiroki Sato wrote:

Proof-of-concept patch attached.

Hopefully, libcap code is easily extendable.
New version attached:
* BPF code is now able to use 'virtual' interfaces without real ifnet
* New bpfattach3() / bpfdetach3() routines were added to attach virtual ifaces * New BIOCGIFLIST ioctl is added to permit userland to retrieve available virtual interfaces * freebsd-specific 'platform_finddevs' version is added to libpcap code (new file)

There are some rough edges (conditional code in pcap-bpf.c, lack of documentation, maybe some style issues), but generally it seems to work and does not interfere with contrib/ code much (from my point of view).

ipfw log device was converted to use new bpf(4) api, see attached patch.


Small example:

4:17 [0] zfscurr0# tcpdump -D
1.em0
2.em1
3.lo0
4:17 [0] zfscurr0# kldload ipfw
4:17 [0] zfscurr0# ifconfig -l
em0 em1 lo0
4:17 [0] zfscurr0# tcpdump -D
1.em0
2.ipfw0 (ipfw log interface)
3.em1
4.lo0

4:40 [1] zfscurr0# ipfw add 100 count log logamount 0 ip from any to any
00100 count log ip from any to any

4:40 [0] zfscurr0# tcpdump -i ipfw0 -lns0
tcpdump: WARNING: SIOCGIFADDR: ipfw0: Device not configured
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ipfw0, link-type EN10MB (Ethernet), capture size 65535 bytes
04:41:27.233653 IP 10.0.0.92.22 > 10.0.0.5.59076: Flags [P.], seq 2783103749:2783103941, ack 3836123088, win 1040, options [nop,nop,TS val 1668094903 ecr 564715671], length 192 04:41:27.233678 IP 10.0.0.5.59076 > 10.0.0.92.22: Flags [.], ack 0, win 1039, options [nop,nop,TS val 564715680 ecr 1668094903], length 0


Btw, do we still need warning about lack of IPv4 address?


Unfortunately, there are problems with this approach, too.

pcap_findalldevs() uses external to BPF method (possibly NET_RT_IFLIST),
so programs relying on that function for showing some kind of combo-box
(like wireshark) with all possible variant won't allow user to specify
such interface.

Additionally, tcpdump assumes that passed interface name is real and
warns us that SIOCGIFADDR returns error.



-- Hiroki


Index: lib/libpcap/Makefile
===================================================================
--- lib/libpcap/Makefile        (revision 243778)
+++ lib/libpcap/Makefile        (working copy)
@@ -6,7 +6,7 @@ SHLIBDIR?= /lib
 .include <bsd.own.mk>
 
 LIB=   pcap
-SRCS=  grammar.y tokdefs.h version.h pcap-bpf.c \
+SRCS=  grammar.y tokdefs.h version.h pcap-bpf.c pcap-freebsd.c \
        pcap.c pcap-common.c inet.c fad-getad.c gencode.c optimize.c 
nametoaddr.c \
        etherent.c savefile.c bpf_filter.c bpf_image.c bpf_dump.c \
        scanner.l sf-pcap.c sf-pcap-ng.c version.c
Index: sys/net/bpf.c
===================================================================
--- sys/net/bpf.c       (revision 243778)
+++ sys/net/bpf.c       (working copy)
@@ -151,6 +151,7 @@ static void bpf_detachd_locked(struct bpf_d *);
 static void    bpf_freed(struct bpf_d *);
 static int     bpf_movein(struct uio *, int, struct ifnet *, struct mbuf **,
                    struct sockaddr *, int *, struct bpf_insn *);
+static int     bpf_getiflist(struct bpf_d *, struct bpf_iflist *);
 static int     bpf_setif(struct bpf_d *, struct ifreq *);
 static void    bpf_timed_out(void *);
 static __inline void
@@ -654,7 +655,7 @@ bpf_attachd(struct bpf_d *d, struct bpf_if *bp)
        CTR3(KTR_NET, "%s: bpf_attach called by pid %d, adding to %s list",
            __func__, d->bd_pid, d->bd_writer ? "writer" : "active");
 
-       if (op_w == 0)
+       if ((op_w == 0) && (!BPF_IS_VIRTUAL(bp)))
                EVENTHANDLER_INVOKE(bpf_track, bp->bif_ifp, bp->bif_dlt, 1);
 }
 
@@ -696,7 +697,8 @@ bpf_upgraded(struct bpf_d *d)
 
        CTR2(KTR_NET, "%s: upgrade required by pid %d", __func__, d->bd_pid);
 
-       EVENTHANDLER_INVOKE(bpf_track, bp->bif_ifp, bp->bif_dlt, 1);
+       if (!BPF_IS_VIRTUAL(bp))
+               EVENTHANDLER_INVOKE(bpf_track, bp->bif_ifp, bp->bif_dlt, 1);
 }
 
 /*
@@ -743,6 +745,10 @@ bpf_detachd_locked(struct bpf_d *d)
 
        bpf_bpfd_cnt--;
 
+       /* Nothing to do for fake interfaces */
+       if (BPF_IS_VIRTUAL(bp))
+               return;
+
        /* Call event handler iff d is attached */
        if (error == 0)
                EVENTHANDLER_INVOKE(bpf_track, ifp, bp->bif_dlt, 0);
@@ -1037,7 +1043,11 @@ bpfwrite(struct cdev *dev, struct uio *uio, int io
                return (ENXIO);
        }
 
-       ifp = d->bd_bif->bif_ifp;
+       /* XXX: Writing to fake interfaces is not supported */
+       if ((ifp = d->bd_bif->bif_ifp) == NULL) {
+               d->bd_wdcount++;
+               return (ENXIO);
+       }
 
        if ((ifp->if_flags & IFF_UP) == 0) {
                d->bd_wdcount++;
@@ -1266,10 +1276,17 @@ bpfioctl(struct cdev *dev, u_long cmd, caddr_t add
                {
                        struct ifnet *ifp;
 
-                       if (d->bd_bif == NULL)
+                       /*
+                        * Lock d since other thread can do reatach in
+                        * other thread causing d->bd_bif to be set to NULL
+                        */
+                       BPFD_LOCK(d);
+                       if ((d->bd_bif == NULL) || (BPF_IS_VIRTUAL(d->bd_bif))) 
{
                                error = EINVAL;
-                       else {
+                               BPFD_UNLOCK(d);
+                       } else {
                                ifp = d->bd_bif->bif_ifp;
+                               BPFD_UNLOCK(d);
                                error = (*ifp->if_ioctl)(ifp, cmd, addr);
                        }
                        break;
@@ -1325,6 +1342,13 @@ bpfioctl(struct cdev *dev, u_long cmd, caddr_t add
                        error = EINVAL;
                        break;
                }
+
+               if (BPF_IS_VIRTUAL(d->bd_bif)) {
+                       /* Silently ignore fake interfaces */
+                       error = 0;
+                       break;
+               }
+
                if (d->bd_promisc == 0) {
                        error = ifpromisc(d->bd_bif->bif_ifp, 1);
                        if (error == 0)
@@ -1390,6 +1414,12 @@ bpfioctl(struct cdev *dev, u_long cmd, caddr_t add
                BPF_UNLOCK();
                break;
 
+       case BIOCGIFLIST:
+               BPF_LOCK();
+               error = bpf_getiflist(d, (struct bpf_iflist *)addr);
+               BPF_UNLOCK();
+               break;
+
        /*
         * Get interface name.
         */
@@ -1401,7 +1431,8 @@ bpfioctl(struct cdev *dev, u_long cmd, caddr_t add
                        struct ifnet *const ifp = d->bd_bif->bif_ifp;
                        struct ifreq *const ifr = (struct ifreq *)addr;
 
-                       strlcpy(ifr->ifr_name, ifp->if_xname,
+                       strlcpy(ifr->ifr_name, BPF_IS_VIRTUAL(d->bd_bif) ?
+                           d->bd_bif->ifname : ifp->if_xname,
                            sizeof(ifr->ifr_name));
                }
                BPF_UNLOCK();
@@ -1701,6 +1732,7 @@ bpfioctl(struct cdev *dev, u_long cmd, caddr_t add
                break;
        }
        CURVNET_RESTORE();
+
        return (error);
 }
 
@@ -1834,6 +1866,55 @@ bpf_setf(struct bpf_d *d, struct bpf_program *fp,
 }
 
 /*
+ * Get a list of available virtual interfaces
+ */
+static int
+bpf_getiflist(struct bpf_d *d, struct bpf_iflist *ifl)
+{
+       int len, tot_len, error;
+       struct bpf_if *bp;
+       struct bpf_ifreply ifr;
+       char *buffer;
+
+       BPF_LOCK_ASSERT();
+
+       tot_len = 0;
+       error = 0;
+       buffer = ifl->ifl_list;
+       LIST_FOREACH(bp, &bpf_iflist, bif_next) {
+               if (!BPF_IS_VIRTUAL(bp))
+                       continue;
+
+               /* Count total length */
+               len = offsetof(struct bpf_ifreply, ifr_descr) +
+                   strlen(bp->ifdescr) + 1;
+               /* Align on 4-byte boundary */
+               len = roundup2(len, 4);
+
+               if (buffer != NULL) {
+                       if (tot_len + len >= ifl->ifl_len)
+                               return (ENOMEM);
+
+                       /* Fill in interface record */
+                       memset(&ifr, 0, sizeof(ifr));
+                       ifr.ifr_len = len;
+                       strlcpy(ifr.ifr_name, bp->ifname, IFNAMSIZ + 1);
+
+                       copyout(&ifr, buffer, sizeof(ifr));
+                       /* Write interface description */
+                       error = copyout(bp->ifdescr,
+                           buffer + offsetof(struct bpf_ifreply, ifr_descr),
+                           strlen(bp->ifdescr) + 1);
+
+                       buffer += len;
+               }
+               tot_len += len;
+       }
+       ifl->ifl_len = tot_len;
+       return (error);
+}
+
+/*
  * Detach a file from its current interface (if attached at all) and attach
  * to the interface indicated by the name stored in ifr.
  * Return an errno or 0.
@@ -1847,10 +1928,19 @@ bpf_setif(struct bpf_d *d, struct ifreq *ifr)
        BPF_LOCK_ASSERT();
 
        theywant = ifunit(ifr->ifr_name);
-       if (theywant == NULL || theywant->if_bpf == NULL)
-               return (ENXIO);
+       if (theywant == NULL || theywant->if_bpf == NULL) {
+               /* Check for fake interface existance */
+               LIST_FOREACH(bp, &bpf_iflist, bif_next) {
+                       if (!BPF_IS_VIRTUAL(bp))
+                               continue;
+                       if (!strcmp(bp->ifname, ifr->ifr_name))
+                               break;
+               }
 
-       bp = theywant->if_bpf;
+               if (bp == NULL)
+                       return (ENXIO);
+       } else
+               bp = theywant->if_bpf;
 
        /* Check if interface is not being detached from BPF */
        BPFIF_RLOCK(bp);
@@ -2075,7 +2165,8 @@ bpf_tap(struct bpf_if *bp, u_char *pkt, u_int pktl
                        if (gottime < bpf_ts_quality(d->bd_tstamp))
                                gottime = bpf_gettime(&bt, d->bd_tstamp, NULL);
 #ifdef MAC
-                       if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0)
+                       if (BPF_IS_VIRTUAL(bp) ||
+                               (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 
0))
 #endif
                                catchpacket(d, pkt, pktlen, slen,
                                    bpf_append_bytes, &bt);
@@ -2085,6 +2176,7 @@ bpf_tap(struct bpf_if *bp, u_char *pkt, u_int pktl
        BPFIF_RUNLOCK(bp);
 }
 
+/* Note i CAN be NULL */
 #define        BPF_CHECK_DIRECTION(d, r, i)                            \
            (((d)->bd_direction == BPF_D_IN && (r) != (i)) ||   \
            ((d)->bd_direction == BPF_D_OUT && (r) == (i)))
@@ -2134,7 +2226,8 @@ bpf_mtap(struct bpf_if *bp, struct mbuf *m)
                        if (gottime < bpf_ts_quality(d->bd_tstamp))
                                gottime = bpf_gettime(&bt, d->bd_tstamp, m);
 #ifdef MAC
-                       if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0)
+                       if ((BPF_IS_VIRTUAL(bp)) ||
+                               (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 
0))
 #endif
                                catchpacket(d, (u_char *)m, pktlen, slen,
                                    bpf_append_mbuf, &bt);
@@ -2190,7 +2283,8 @@ bpf_mtap2(struct bpf_if *bp, void *data, u_int dle
                        if (gottime < bpf_ts_quality(d->bd_tstamp))
                                gottime = bpf_gettime(&bt, d->bd_tstamp, m);
 #ifdef MAC
-                       if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0)
+                       if ((BPF_IS_VIRTUAL(bp)) ||
+                               (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 
0))
 #endif
                                catchpacket(d, (u_char *)&mb, pktlen, slen,
                                    bpf_append_mbuf, &bt);
@@ -2484,6 +2578,45 @@ bpfattach2(struct ifnet *ifp, u_int dlt, u_int hdr
 }
 
 /*
+ * Attach fake interface to bpf. ifname is interface name to be attached,
+ * dlt is the link layer type, and hdrlen is the fixed size of the link header
+ * (variable length headers are not yet supporrted).
+ */
+void
+bpfattach3(char *ifname, char *ifdescr, u_int dlt, u_int hdrlen, struct bpf_if 
**driverp)
+{
+       struct bpf_if *bp;
+       int len;
+
+       len = strlen(ifdescr) + 1;
+
+       /* Assume bpf_if to be properly aligned */
+       bp = malloc(sizeof(*bp) + len, M_BPF, M_NOWAIT | M_ZERO);
+       if (bp == NULL)
+               panic("bpfattach");
+
+       LIST_INIT(&bp->bif_dlist);
+       LIST_INIT(&bp->bif_wlist);
+       strlcpy(bp->ifname, ifname, IFNAMSIZ + 1);
+       bp->ifdescr = (char *)(bp + 1);
+       strlcpy(bp->ifdescr, ifdescr, len);
+       bp->bif_dlt = dlt;
+       rw_init(&bp->bif_lock, "bpf interface lock");
+       KASSERT(*driverp == NULL, ("bpfattach3: driverp already initialized"));
+       *driverp = bp;
+
+       BPF_LOCK();
+       LIST_INSERT_HEAD(&bpf_iflist, bp, bif_next);
+       BPF_UNLOCK();
+
+       bp->bif_hdrlen = hdrlen;
+
+       if (bootverbose)
+               printf("%s: bpf attached\n", bp->ifname);
+}
+
+
+/*
  * Detach bpf from an interface. This involves detaching each descriptor
  * associated with the interface. Notify each descriptor as it's detached
  * so that any sleepers wake up and get ENXIO.
@@ -2546,6 +2679,54 @@ bpfdetach(struct ifnet *ifp)
 }
 
 /*
+ * Detach bpf from the fake interface. This involves detaching each descriptor
+ * associated with the interface. Notify each descriptor as it's detached
+ * so that any sleepers wake up and get ENXIO.
+ */
+void
+bpfdetach3(char *ifname)
+{
+       struct bpf_if   *bp;
+       struct bpf_d    *d;
+
+       BPF_LOCK();
+       /* Find all bpf_if struct's which reference ifp and detach them. */
+       LIST_FOREACH(bp, &bpf_iflist, bif_next) {
+               if (!BPF_IS_VIRTUAL(bp))
+                       continue;
+               if (!strcmp(bp->ifname, ifname))
+                       break;
+       }
+
+       if (bp != NULL)
+               LIST_REMOVE(bp, bif_next);
+       
+       BPF_UNLOCK();
+
+       if (bp != NULL) {
+               while ((d = LIST_FIRST(&bp->bif_dlist)) != NULL) {
+                       bpf_detachd_locked(d);
+                       BPFD_LOCK(d);
+                       bpf_wakeup(d);
+                       BPFD_UNLOCK(d);
+               }
+               /* Free writer-only descriptors */
+               while ((d = LIST_FIRST(&bp->bif_wlist)) != NULL) {
+                       bpf_detachd_locked(d);
+                       BPFD_LOCK(d);
+                       bpf_wakeup(d);
+                       BPFD_UNLOCK(d);
+               }
+
+               /*
+                * Since this interface is fake we can free our
+                * structure immediately.
+                */
+               rw_destroy(&bp->bif_lock);
+               free(bp, M_BPF);
+       }
+}
+/*
  * Interface departure handler.
  * Note departure event does not guarantee interface is going down.
  */
@@ -2594,6 +2775,9 @@ bpf_getdltlist(struct bpf_d *d, struct bpf_dltlist
        LIST_FOREACH(bp, &bpf_iflist, bif_next) {
                if (bp->bif_ifp != ifp)
                        continue;
+               /* Compare fake interfaces by name */
+               if ((ifp == NULL) && (strcmp(d->bd_bif->ifname, bp->ifname)))
+                       continue;
                if (bfl->bfl_list != NULL) {
                        if (n >= bfl->bfl_len)
                                return (ENOMEM);
@@ -2623,7 +2807,13 @@ bpf_setdlt(struct bpf_d *d, u_int dlt)
        ifp = d->bd_bif->bif_ifp;
 
        LIST_FOREACH(bp, &bpf_iflist, bif_next) {
-               if (bp->bif_ifp == ifp && bp->bif_dlt == dlt)
+               if (bp->bif_ifp != ifp)
+                       continue;
+
+               if ((ifp == NULL) && strcmp(d->bd_bif->ifname, bp->ifname))
+                       continue;
+
+               if (bp->bif_dlt == dlt)
                        break;
        }
 
@@ -2718,8 +2908,10 @@ bpfstats_fill_xbpf(struct xbpf_d *d, struct bpf_d
        d->bd_hlen = bd->bd_hlen;
        d->bd_bufsize = bd->bd_bufsize;
        d->bd_pid = bd->bd_pid;
-       strlcpy(d->bd_ifname,
-           bd->bd_bif->bif_ifp->if_xname, IFNAMSIZ);
+       if (!BPF_IS_VIRTUAL(bd->bd_bif))
+               strlcpy(d->bd_ifname, bd->bd_bif->bif_ifp->if_xname, IFNAMSIZ);
+       else
+               strlcpy(d->bd_ifname, bd->bd_bif->ifname, IFNAMSIZ);
        d->bd_locked = bd->bd_locked;
        d->bd_wcount = bd->bd_wcount;
        d->bd_wdcount = bd->bd_wdcount;
Index: sys/net/bpf.h
===================================================================
--- sys/net/bpf.h       (revision 243778)
+++ sys/net/bpf.h       (working copy)
@@ -147,6 +147,7 @@ struct bpf_zbuf {
 #define        BIOCSETFNR      _IOW('B', 130, struct bpf_program)
 #define        BIOCGTSTAMP     _IOR('B', 131, u_int)
 #define        BIOCSTSTAMP     _IOW('B', 132, u_int)
+#define        BIOCGIFLIST     _IOWR('B', 133, struct bpf_iflist)
 
 /* Obsolete */
 #define        BIOCGSEESENT    BIOCGDIRECTION
@@ -1224,6 +1225,25 @@ struct bpf_dltlist {
        u_int   *bfl_list;      /* array of DLTs */
 };
 
+#define        BIFNAMSIZ       16
+#if !defined(_KERNEL) || defined(BPF_INTERNAL)
+/*
+ * Structure to retrieve virtual BPF intefaces.
+ */
+struct bpf_iflist {
+       u_int   ifl_len;        /* total memory size */
+       u_int   ifl_ver;        /* version (set to 0) */
+       char    *ifl_list;      /* array of interfaces */
+};
+
+struct bpf_ifreply {
+       u_int   ifr_len;        /* Total record length */
+       u_int   ifr_spare[3];   /* Spare data */
+       char    ifr_name[BIFNAMSIZ + 1];        /* Interface name */
+       char    ifr_descr[0];   /* Interface description (variable) */
+};
+#endif
+
 #ifdef _KERNEL
 #ifdef MALLOC_DECLARE
 MALLOC_DECLARE(M_BPF);
@@ -1262,6 +1282,8 @@ struct bpf_if {
        struct rwlock bif_lock;         /* interface lock */
        LIST_HEAD(, bpf_d)      bif_wlist;      /* writer-only list */
        int flags;                      /* Interface flags */
+       char ifname[IFNAMSIZ + 1];      /* Virtual interface name */
+       char *ifdescr;                  /* Virtual interface description */
 #endif
 };
 
@@ -1272,7 +1294,9 @@ void       bpf_mtap(struct bpf_if *, struct mbuf *);
 void    bpf_mtap2(struct bpf_if *, void *, u_int, struct mbuf *);
 void    bpfattach(struct ifnet *, u_int, u_int);
 void    bpfattach2(struct ifnet *, u_int, u_int, struct bpf_if **);
+void    bpfattach3(char *, char *, u_int, u_int, struct bpf_if **);
 void    bpfdetach(struct ifnet *);
+void    bpfdetach3(char *);
 
 void    bpfilterattach(int);
 u_int   bpf_filter(const struct bpf_insn *, u_char *, u_int, u_int);
Index: sys/net/bpfdesc.h
===================================================================
--- sys/net/bpfdesc.h   (revision 243778)
+++ sys/net/bpfdesc.h   (working copy)
@@ -102,6 +102,8 @@ struct bpf_d {
        u_char          bd_compat32;    /* 32-bit stream on LP64 system */
 };
 
+#define        BPF_IS_VIRTUAL(x)       ((x)->bif_ifp == NULL)
+
 /* Values for bd_state */
 #define BPF_IDLE       0               /* no select in progress */
 #define BPF_WAITING    1               /* waiting for read timeout in select */
Index: sys/netpfil/ipfw/ip_fw_log.c
===================================================================
--- sys/netpfil/ipfw/ip_fw_log.c        (revision 243778)
+++ sys/netpfil/ipfw/ip_fw_log.c        (working copy)
@@ -93,142 +93,31 @@ ipfw_log_bpf(int onoff)
 {
 }
 #else /* !WITHOUT_BPF */
-static struct ifnet *log_if;   /* hook to attach to bpf */
-static struct rwlock log_if_lock;
-#define        LOGIF_LOCK_INIT(x)      rw_init(&log_if_lock, "ipfw log_if 
lock")
-#define        LOGIF_LOCK_DESTROY(x)   rw_destroy(&log_if_lock)
-#define        LOGIF_RLOCK(x)          rw_rlock(&log_if_lock)
-#define        LOGIF_RUNLOCK(x)        rw_runlock(&log_if_lock)
-#define        LOGIF_WLOCK(x)          rw_wlock(&log_if_lock)
-#define        LOGIF_WUNLOCK(x)        rw_wunlock(&log_if_lock)
+static struct bpf_if *log_bpfif = NULL;        /* hook to attach to bpf */
+#define BPF_IFNAME     "ipfw0"
+#define        IPFW_MTAP(_if_bpf,_data,_dlen,_m) do {                  \
+       if (bpf_peers_present(_if_bpf)) {               \
+               M_ASSERTVALID(_m);                              \
+               bpf_mtap2((_if_bpf),(_data),(_dlen),(_m));      \
+       }                                                       \
+} while (0)
 
-static const char ipfwname[] = "ipfw";
-
-/* we use this dummy function for all ifnet callbacks */
-static int
-log_dummy(struct ifnet *ifp, u_long cmd, caddr_t addr)
-{
-       return EINVAL;
-}
-
-static int
-ipfw_log_output(struct ifnet *ifp, struct mbuf *m,
-       struct sockaddr *dst, struct route *ro)
-{
-       if (m != NULL)
-               FREE_PKT(m);
-       return EINVAL;
-}
-
-static void
-ipfw_log_start(struct ifnet* ifp)
-{
-       panic("ipfw_log_start() must not be called");
-}
-
 static const u_char ipfwbroadcastaddr[6] =
        { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
-static int
-ipfw_log_clone_match(struct if_clone *ifc, const char *name)
-{
-
-       return (strncmp(name, ipfwname, sizeof(ipfwname) - 1) == 0);
-}
-
-static int
-ipfw_log_clone_create(struct if_clone *ifc, char *name, size_t len,
-    caddr_t params)
-{
-       int error;
-       int unit;
-       struct ifnet *ifp;
-
-       error = ifc_name2unit(name, &unit);
-       if (error)
-               return (error);
-
-       error = ifc_alloc_unit(ifc, &unit);
-       if (error)
-               return (error);
-
-       ifp = if_alloc(IFT_PFLOG);
-       if (ifp == NULL) {
-               ifc_free_unit(ifc, unit);
-               return (ENOSPC);
-       }
-       ifp->if_dname = ipfwname;
-       ifp->if_dunit = unit;
-       snprintf(ifp->if_xname, IFNAMSIZ, "%s%d", ipfwname, unit);
-       strlcpy(name, ifp->if_xname, len);
-       ifp->if_mtu = 65536;
-       ifp->if_flags = IFF_UP | IFF_SIMPLEX | IFF_MULTICAST;
-       ifp->if_init = (void *)log_dummy;
-       ifp->if_ioctl = log_dummy;
-       ifp->if_start = ipfw_log_start;
-       ifp->if_output = ipfw_log_output;
-       ifp->if_addrlen = 6;
-       ifp->if_hdrlen = 14;
-       ifp->if_broadcastaddr = ipfwbroadcastaddr;
-       ifp->if_baudrate = IF_Mbps(10);
-
-       LOGIF_WLOCK();
-       if (log_if == NULL)
-               log_if = ifp;
-       else {
-               LOGIF_WUNLOCK();
-               if_free(ifp);
-               ifc_free_unit(ifc, unit);
-               return (EEXIST);
-       }
-       LOGIF_WUNLOCK();
-       if_attach(ifp);
-       bpfattach(ifp, DLT_EN10MB, 14);
-
-       return (0);
-}
-
-static int
-ipfw_log_clone_destroy(struct if_clone *ifc, struct ifnet *ifp)
-{
-       int unit;
-
-       if (ifp == NULL)
-               return (0);
-
-       LOGIF_WLOCK();
-       if (log_if != NULL && ifp == log_if)
-               log_if = NULL;
-       else {
-               LOGIF_WUNLOCK();
-               return (EINVAL);
-       }
-       LOGIF_WUNLOCK();
-
-       unit = ifp->if_dunit;
-       bpfdetach(ifp);
-       if_detach(ifp);
-       if_free(ifp);
-       ifc_free_unit(ifc, unit);
-
-       return (0);
-}
-
-static struct if_clone *ipfw_log_cloner;
-
 void
 ipfw_log_bpf(int onoff)
 {
 
-       if (onoff) {
-               LOGIF_LOCK_INIT();
-               ipfw_log_cloner = if_clone_advanced(ipfwname, 0,
-                   ipfw_log_clone_match, ipfw_log_clone_create,
-                   ipfw_log_clone_destroy);
-       } else {
-               if_clone_detach(ipfw_log_cloner);
-               LOGIF_LOCK_DESTROY();
-       }
+       if (onoff) {
+               if (log_bpfif)
+                       return;
+               bpfattach3(BPF_IFNAME, "ipfw log interface", DLT_EN10MB, 14, 
&log_bpfif);
+       } else {
+               if (log_bpfif != NULL)
+                       bpfdetach3(BPF_IFNAME);
+               log_bpfif = NULL;
+       }
 }
 #endif /* !WITHOUT_BPF */
 
@@ -247,20 +136,18 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw
 
        if (V_fw_verbose == 0) {
 #ifndef WITHOUT_BPF
-               LOGIF_RLOCK();
-               if (log_if == NULL || log_if->if_bpf == NULL) {
-                       LOGIF_RUNLOCK();
+               if (log_bpfif == NULL)
                        return;
-               }
 
                if (args->eh) /* layer2, use orig hdr */
-                       BPF_MTAP2(log_if, args->eh, ETHER_HDR_LEN, m);
+                       IPFW_MTAP(log_bpfif, args->eh, ETHER_HDR_LEN, m);
                else
-                       /* Add fake header. Later we will store
+                       /*
+                        * Add fake header. Later we will store
                         * more info in the header.
                         */
-                       BPF_MTAP2(log_if, "DDDDDDSSSSSS\x08\x00", 
ETHER_HDR_LEN, m);
-               LOGIF_RUNLOCK();
+                       IPFW_MTAP(log_bpfif, "DDDDDDSSSSSS\x08\x00",
+                           ETHER_HDR_LEN, m);
 #endif /* !WITHOUT_BPF */
                return;
        }
Index: contrib/libpcap/pcap-bpf.c
===================================================================
--- contrib/libpcap/pcap-bpf.c  (revision 243778)
+++ contrib/libpcap/pcap-bpf.c  (working copy)
@@ -132,6 +132,8 @@ static int bpf_load(char *errbuf);
 #include "pcap-snf.h"
 #endif /* HAVE_SNF_API */
 
+#include "pcap-freebsd.h"
+
 #ifdef HAVE_OS_PROTO_H
 #include "os-proto.h"
 #endif
@@ -2311,6 +2313,8 @@ pcap_platform_finddevs(pcap_if_t **alldevsp, char
        if (snf_platform_finddevs(alldevsp, errbuf) < 0)
                return (-1);
 #endif /* HAVE_SNF_API */
+       if (freebsd_platform_finddevs(alldevsp, errbuf) < 0)
+               return (-1);
 
        return (0);
 }
--- /dev/null   2012-12-02 04:22:01.000000000 +0400
+++ contrib/libpcap/pcap-freebsd.h      2012-12-02 02:50:44.251624161 +0400
@@ -0,0 +1 @@
+int freebsd_platform_finddevs(pcap_if_t **devlistp, char *errbuf);
--- /dev/null   2012-12-02 04:22:01.000000000 +0400
+++ contrib/libpcap/pcap-freebsd.c      2012-12-02 04:22:11.404710869 +0400
@@ -0,0 +1,138 @@
+/*
+ *  pcap-freebsd.c: Packet capture advanced interface to the FreeBSD kernel
+ *
+ *  License: BSD
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <net/bpf.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "pcap-int.h"
+
+int
+freebsd_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
+{
+       int ret;
+
+       struct bpf_iflist ifl;
+       struct bpf_ifreply *ifr;
+       char *device = "/dev/bpf";
+       int fd, i, len, res;
+       caddr_t databuf;
+
+       if ((fd = open(device, O_RDWR)) == -1) {
+               snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                   "(cannot open device) %s: %s",
+                   device, pcap_strerror(errno));
+
+               return (-1);
+       }
+
+       res = 0;
+
+       for (i = 0; i < 10; i++) {
+               /* Get size */
+               memset(&ifl, 0, sizeof(ifl));
+
+               if (ioctl(fd, BIOCGIFLIST, (caddr_t)&ifl) != 0) {
+                       snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                           "(cannot get interface list length): %s",
+                           pcap_strerror(errno));
+
+                       close(fd);
+                       return (-1);
+               }
+
+               /* Allocate requested length */
+               len = ifl.ifl_len + 1024;
+               databuf = calloc(1, len);
+
+               /* Try to read data */
+               ifl.ifl_list = databuf;
+               ifl.ifl_len = len;
+               
+               if (ioctl(fd, BIOCGIFLIST, (caddr_t)&ifl) != 0) {
+                       if (errno == ENOMEM) {
+                               /*
+                                * Probably new interface added.
+                                * Let's try another time.
+                                */
+                               free(databuf);
+                               databuf = NULL;
+                               ifl.ifl_len = 0;
+                               continue;
+                       }
+
+                       snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                           "(cannot read interface list): %s",
+                           pcap_strerror(errno));
+
+                       close(fd);
+                       return (-1);
+               }
+
+               res = 1;
+               break;
+       }
+
+       close(fd);
+
+       if (res == 0) {
+               snprintf(errbuf, PCAP_ERRBUF_SIZE,
+                   "(error reading interface list): retries exceeded");
+               return (-1);
+       }
+
+       /* Okay, let's parse */
+       for (len = 0; len < ifl.ifl_len; ) {
+               ifr = (struct bpf_ifreply *)&databuf[len];
+
+               if (pcap_add_if(alldevsp, ifr->ifr_name, 0,
+                   ifr->ifr_descr, errbuf) < 0)
+                       return (-1);
+
+               len += ifr->ifr_len;
+       }
+
+       return (0);
+}
+
_______________________________________________
freebsd-ipfw@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-ipfw
To unsubscribe, send any mail to "freebsd-ipfw-unsubscr...@freebsd.org"

Reply via email to