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--