Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 02 Dec 2012 04:48:18 +0400
From:      "Alexander V. Chernikov" <melifaro@FreeBSD.org>
To:        Hiroki Sato <hrs@FreeBSD.org>
Cc:        freebsd-ipfw@FreeBSD.org, Gleb Smirnoff <glebius@FreeBSD.org>, delphij@freebsd.org, "freebsd-net@freebsd.org" <freebsd-net@FreeBSD.org>
Subject:   [CFT] Virtual BPF interfaces (was: CFR: ipfw0 pseudo-interface clonable)
Message-ID:  <50BAA552.1010707@FreeBSD.org>
In-Reply-To: <4FD4AD29.3040204@FreeBSD.org>
References:  <4F96D11B.2060007@FreeBSD.org> <20120425.020518.406495893112283552.hrs@allbsd.org> <4F96E71B.9020405@FreeBSD.org> <20120427.084414.1142593201575277510.hrs@allbsd.org> <4FD4AD29.3040204@FreeBSD.org>

next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.
--------------080701070400070005040601
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

On 10.06.2012 18:20, Alexander V. Chernikov wrote:
> On 27.04.2012 03:44, Hiroki Sato wrote:
>> "Alexander V. Chernikov"<melifaro@FreeBSD.org> wrote
>> in<4F96E71B.9020405@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
>


--------------080701070400070005040601
Content-Type: text/plain;
 name="bpf_virtual.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename="bpf_virtual.diff"

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);
+}
+

--------------080701070400070005040601--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?50BAA552.1010707>