Date: Sat, 18 Mar 2000 21:21:36 -0500 (EST) From: Robert Watson <robert@cyrus.watson.org> To: Kurakin Roman <rik@cronyx.ru> Cc: freebsd-net@FreeBSD.ORG Subject: Patch to introduce bpfdetach(), Re: BPF question (FreeBSD 40) Message-ID: <Pine.NEB.3.96L.1000318204927.3649A-300000@fledge.watson.org> In-Reply-To: <38D39537.867C357C@cronyx.ru>
next in thread | previous in thread | raw e-mail | index | archive | help
[-- Attachment #1 --] On Sat, 18 Mar 2000, Kurakin Roman wrote: > I have question about using bpf in my KLD module driver. At attach I > call > bpfattach function. What should I call at detach? > Could some one describe to me how bpf is work (function calls, not bpf > as pf :)). I noticed the same behavior a few weeks ago when using tcpdump in wi0 and ejecting the card. This occurs if there are open bpf descriptors for the device, and ifdetach is called (freeing the ifnet structure), at the bp_bif pointer is not set to NULL. I've been running a bpf patch for the last few hours that attempts to clean this behavior up. It introduces a bpfdetach(ifp), which should be called just prior to ifdetach(ifp). If there are any open descriptors on the interface, it sets the bif pointer to NULL, and wakes up listeners. In the bpfread loop, if there are no remaining buffers on the bpf descriptor, and it sees a bp_bif of NULL, it now returns ENXIO to the caller. The remaining fd calls already appeared to have NULL checks for bp_bif, just not bpfread in its wait loop. After this, it frees the bpf_desc structure. It appears to clean up the wi0 tcpdump crash, but I haven't tested it much more than that. Needless to say, any location where ifdetach() is called (that had a matching bpfattach) should now also call bpfdetach(). I have only updated if_wi.c in my patch, as that's all I have on hand right now. Pccard drivers such as ep0 don't require the patch, as they never ifdetach(), leaving the ifnet epX around but unbound. One file attached patches src/sys/net to add the bpfdetach code (bpfdetach.diff). The other patch patches if_wi.c to call bpfdetach (if_wi.diff) Once it's adequately tested (volunteers welcome), I'll commit it to 5.0-CURRENT. > Hi, > > Kurakin Roman > > > > > To Unsubscribe: send mail to majordomo@FreeBSD.org > with "unsubscribe freebsd-net" in the body of the message > Robert N M Watson robert@fledge.watson.org http://www.watson.org/~robert/ PGP key fingerprint: AF B5 5F FF A6 4A 79 37 ED 5F 55 E9 58 04 6A B1 TIS Labs at Network Associates, Safeport Network Services [-- Attachment #2 --] Only in /data/fbsd-commit/src/sys/net: CVS diff -u /data/fbsd-commit/src/sys/net/bpf.c ./bpf.c --- /data/fbsd-commit/src/sys/net/bpf.c Sat Mar 18 01:30:41 2000 +++ ./bpf.c Sat Mar 18 21:17:20 2000 @@ -477,6 +477,18 @@ ROTATE_BUFFERS(d); break; } + + /* + * No data is available, check to see if the bpf device + * is still pointed at a real interface. If not, return + * ENXIO so that the userland process knows to rebind + * it before using it again. + */ + if (d->bd_bif == NULL) { + splx(s); + return (ENXIO); + } + if (ioflag & IO_NDELAY) error = EWOULDBLOCK; else @@ -1285,6 +1297,60 @@ if (bootverbose) printf("bpf: %s%d attached\n", ifp->if_name, ifp->if_unit); +} + +/* + * Detach bpf from an interface. This involves detaching each descriptor + * associated with the interface, and leaving bd_bif NULL. Notify each + * descriptor as it's detached so that any sleepers wake up and get + * ENXIO. + */ +void +bpfdetach(ifp) + struct ifnet *ifp; +{ + struct bpf_if *bp, *bp_prev; + struct bpf_d *d; + int s; + + printf("bpfdetach: %s%d is being detached\n", ifp->if_name, + ifp->if_unit); + + /* XXX is this needed? Is it right? */ + s = splimp(); + + /* Locate BPF interface information */ + bp_prev = NULL; + for (bp = bpf_iflist; bp != NULL; bp = bp->bif_next) { + if (ifp == bp->bif_ifp) + break; + bp_prev = bp; + } + + /* Interface wasn't attached */ + if (bp->bif_ifp == NULL) { + splx(s); + printf("bpfdetach: %s%d was not attached\n", ifp->if_name, + ifp->if_unit); + return; + } + + while ((d = bp->bif_dlist) != NULL) { + bpf_detachd(d); + bpf_wakeup(d); + } + + if (bp_prev) { + bp_prev->bif_next = bp->bif_next; + } else { + bpf_iflist = bp->bif_next; + } + + free(bp, M_BPF); + + splx(s); + + printf("bpfdetach: %s%d is detached\n", ifp->if_name, ifp->if_unit); } static void bpf_drvinit __P((void *unused)); diff -u /data/fbsd-commit/src/sys/net/bpf.h ./bpf.h --- /data/fbsd-commit/src/sys/net/bpf.h Sat Mar 18 01:30:42 2000 +++ ./bpf.h Sat Mar 18 21:16:33 2000 @@ -232,6 +232,8 @@ void bpf_tap __P((struct ifnet *, u_char *, u_int)); void bpf_mtap __P((struct ifnet *, struct mbuf *)); void bpfattach __P((struct ifnet *, u_int, u_int)); +void bpfdetach __P((struct ifnet *)); + void bpfilterattach __P((int)); u_int bpf_filter __P((const struct bpf_insn *, u_char *, u_int, u_int)); #endif [-- Attachment #3 --] --- if_wi.c Wed Feb 2 12:59:12 2000 +++ /tmp/if_wi.c Sat Mar 18 21:19:39 2000 @@ -214,6 +214,8 @@ } wi_stop(sc); + + bpfdetach(ifp); if_detach(ifp); bus_teardown_intr(dev, sc->irq, sc->wi_intrhand); wi_free(dev);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.NEB.3.96L.1000318204927.3649A-300000>
