Skip site navigation (1)Skip section navigation (2)
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>