Subject: bpf patch: bpf_mtap2
To: None <tech-net@netbsd.org>
From: David Young <dyoung@pobox.com>
List: tech-net
Date: 04/29/2004 19:34:54
--DIOMP1UsTsWJauNi
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

FreeBSD has added bpf_mtap2, which taps a packet whose head is in a data
buffer and whose tail is in an mbuf chain.  It's now used in ath(4).
I foresee using it in several drivers.

I have added bpf_mtap2 to NetBSD and refactored.  How does the attached
code look?  Barring objections, I will commit it very soon.

There are at least four uses for bpf_mtap2 in our WiFi drivers.  For
radiotap(9) purposes, we presently fake-up an mbuf on the stack, prepend
it to an mbuf chain, and then call bpf_mtap.  bpf_mtap2 consolidates
this function in one place.  See ath, atw, wi, maybe an.

Dave

-- 
David Young             OJC Technologies
dyoung@ojctech.com      Urbana, IL * (217) 278-3933

--DIOMP1UsTsWJauNi
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=bpf-diffs

Index: bpf.c
===================================================================
RCS file: /cvsroot/src/sys/net/bpf.c,v
retrieving revision 1.95
diff -u -r1.95 bpf.c
--- bpf.c	20 Apr 2004 10:51:09 -0000	1.95
+++ bpf.c	30 Apr 2004 00:24:22 -0000
@@ -1232,6 +1232,77 @@
 }
 
 /*
+ * Dispatch a packet to all the listeners on interface bp.
+ *
+ * marg    pointer to the packet, either a data buffer or an mbuf chain
+ * buflen  buffer length, if marg is a data buffer
+ * cpfn    a function that can copy marg into the listener's buffer
+ * pktlen  length of the packet
+ * rcvif   either NULL or the interface the packet came in on.
+ */
+static __inline void
+bpf_deliver(bp, cpfn, marg, pktlen, buflen, rcvif)
+	struct bpf_if *bp;
+	void *(*cpfn)(void *, const void *, size_t);
+	void *marg;
+	u_int pktlen, buflen;
+	struct ifnet *rcvif;
+{
+	u_int slen;
+	struct bpf_d *d;
+
+	for (d = bp->bif_dlist; d != 0; d = d->bd_next) {
+		if (!d->bd_seesent && (rcvif == NULL))
+			continue;
+		++d->bd_rcount;
+		slen = bpf_filter(d->bd_filter, marg, pktlen, buflen);
+		if (slen != 0)
+			catchpacket(d, marg, pktlen, slen, cpfn);
+	}
+}
+
+static __inline u_int
+bpf_measure(struct mbuf *m)
+{
+	struct mbuf *m0;
+	u_int pktlen;
+
+	pktlen = 0;
+	for (m0 = m; m0 != 0; m0 = m0->m_next)
+		pktlen += m0->m_len;
+	return pktlen;
+}
+
+/*
+ * Incoming linkage from device drivers, when the head of the packet is in
+ * a buffer, and the tail is in an mbuf chain.
+ */
+void
+bpf_mtap2(arg, data, dlen, m)
+	caddr_t arg;
+	void *data;
+	u_int dlen;
+	struct mbuf *m;
+{
+	struct bpf_if *bp = (struct bpf_if *)arg;
+	u_int pktlen;
+	struct mbuf mb;
+
+	pktlen = bpf_measure(m) + dlen;
+
+	/*
+	 * Craft on-stack mbuf suitable for passing to bpf_filter.
+	 * Note that we cut corners here; we only setup what's
+	 * absolutely needed--this mbuf should never go anywhere else.
+	 */
+	mb.m_next = m;
+	mb.m_data = data;
+	mb.m_len = dlen;
+
+	bpf_deliver(bp, bpf_mcpy, &mb, pktlen, 0, m->m_pkthdr.rcvif);
+}
+
+/*
  * Incoming linkage from device drivers, when packet is in an mbuf chain.
  */
 void
@@ -1241,14 +1312,10 @@
 {
 	void *(*cpfn) __P((void *, const void *, size_t));
 	struct bpf_if *bp = (struct bpf_if *)arg;
-	struct bpf_d *d;
-	u_int pktlen, slen, buflen;
-	struct mbuf *m0;
+	u_int pktlen, buflen;
 	void *marg;
 
-	pktlen = 0;
-	for (m0 = m; m0 != 0; m0 = m0->m_next)
-		pktlen += m0->m_len;
+	pktlen = bpf_measure(m);
 
 	if (pktlen == m->m_len) {
 		cpfn = memcpy;
@@ -1260,14 +1327,7 @@
 		buflen = 0;
 	}
 
-	for (d = bp->bif_dlist; d != 0; d = d->bd_next) {
-		if (!d->bd_seesent && (m->m_pkthdr.rcvif == NULL))
-			continue;
-		++d->bd_rcount;
-		slen = bpf_filter(d->bd_filter, marg, pktlen, buflen);
-		if (slen != 0)
-			catchpacket(d, marg, pktlen, slen, cpfn);
-	}
+	bpf_deliver(bp, cpfn, marg, pktlen, buflen, m->m_pkthdr.rcvif);
 }
 
 /*
Index: bpf.h
===================================================================
RCS file: /cvsroot/src/sys/net/bpf.h,v
retrieving revision 1.36
diff -u -r1.36 bpf.h
--- bpf.h	15 Apr 2004 15:17:11 -0000	1.36
+++ bpf.h	30 Apr 2004 00:24:22 -0000
@@ -250,6 +250,7 @@
 int	 bpf_validate __P((struct bpf_insn *, int));
 void	 bpf_tap __P((caddr_t, u_char *, u_int));
 void	 bpf_mtap __P((caddr_t, struct mbuf *));
+void	 bpf_mtap2 __P((caddr_t, void *, u_int, struct mbuf *));
 void	 bpfattach __P((struct ifnet *, u_int, u_int));
 void	 bpfattach2 __P((struct ifnet *, u_int, u_int, caddr_t *));
 void	 bpfdetach __P((struct ifnet *));

--DIOMP1UsTsWJauNi--