add support for bpf on "subsystems", not just network interfaces
authordlg <dlg@openbsd.org>
Wed, 24 Jan 2018 00:25:17 +0000 (00:25 +0000)
committerdlg <dlg@openbsd.org>
Wed, 24 Jan 2018 00:25:17 +0000 (00:25 +0000)
bpf assumed that it was being unconditionally attached to network
interfaces, and maintained a pointer to a struct ifnet *. this was
mostly used to get at the name of the interface, which is how
userland asks to be attached to a particular interface. this diff
adds a pointer to the name and uses it instead of the interface
pointer for these lookups. this in turn allows bpf to be attached
to arbitrary subsystems in the kernel which just have to supply a
name rather than an interface pointer. for example, bpf could be
attached to pf_test so you can see what packets are about to be
filtered. mpi@ is using this to look at usb transfers.

bpf still uses the interface pointer for bpfwrite, and for enabling
and disabling promisc. however, these are nopped out for subsystems.

ok mpi@

sys/net/bpf.c
sys/net/bpf.h
sys/net/bpfdesc.h

index 55bc2ba..2d37951 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: bpf.c,v 1.165 2017/12/30 23:08:29 guenther Exp $      */
+/*     $OpenBSD: bpf.c,v 1.166 2018/01/24 00:25:17 dlg Exp $   */
 /*     $NetBSD: bpf.c,v 1.33 1997/02/21 23:59:35 thorpej Exp $ */
 
 /*
@@ -93,7 +93,7 @@ struct bpf_if *bpf_iflist;
 LIST_HEAD(, bpf_d) bpf_d_list;
 
 int    bpf_allocbufs(struct bpf_d *);
-void   bpf_ifname(struct ifnet *, struct ifreq *);
+void   bpf_ifname(struct bpf_if*, struct ifreq *);
 int    _bpf_mtap(caddr_t, const struct mbuf *, u_int,
            void (*)(const void *, void *, size_t));
 void   bpf_mcopy(const void *, void *, size_t);
@@ -320,6 +320,8 @@ bpf_detachd(struct bpf_d *d)
        if (d->bd_promisc) {
                int error;
 
+               KASSERT(bp->bif_ifp != NULL);
+
                d->bd_promisc = 0;
 
                bpf_get(d);
@@ -593,7 +595,7 @@ bpfwrite(dev_t dev, struct uio *uio, int ioflag)
        bpf_get(d);
        ifp = d->bd_bif->bif_ifp;
 
-       if ((ifp->if_flags & IFF_UP) == 0) {
+       if (ifp == NULL || (ifp->if_flags & IFF_UP) == 0) {
                error = ENETDOWN;
                goto out;
        }
@@ -789,7 +791,7 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
                         * No interface attached yet.
                         */
                        error = EINVAL;
-               } else {
+               } else if (d->bd_bif->bif_ifp != NULL) { 
                        if (d->bd_promisc == 0) {
                                MUTEX_ASSERT_UNLOCKED(&d->bd_mtx);
                                error = ifpromisc(d->bd_bif->bif_ifp, 1);
@@ -839,7 +841,7 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
                if (d->bd_bif == NULL)
                        error = EINVAL;
                else
-                       bpf_ifname(d->bd_bif->bif_ifp, (struct ifreq *)addr);
+                       bpf_ifname(d->bd_bif, (struct ifreq *)addr);
                break;
 
        /*
@@ -1049,10 +1051,7 @@ bpf_setif(struct bpf_d *d, struct ifreq *ifr)
         * Look through attached interfaces for the named one.
         */
        for (bp = bpf_iflist; bp != NULL; bp = bp->bif_next) {
-               struct ifnet *ifp = bp->bif_ifp;
-
-               if (ifp == NULL ||
-                   strcmp(ifp->if_xname, ifr->ifr_name) != 0)
+               if (strcmp(bp->bif_name, ifr->ifr_name) != 0)
                        continue;
 
                if (candidate == NULL || candidate->bif_dlt > bp->bif_dlt)
@@ -1090,9 +1089,9 @@ out:
  * Copy the interface name to the ifreq.
  */
 void
-bpf_ifname(struct ifnet *ifp, struct ifreq *ifr)
+bpf_ifname(struct bpf_if *bif, struct ifreq *ifr)
 {
-       bcopy(ifp->if_xname, ifr->ifr_name, IFNAMSIZ);
+       bcopy(bif->bif_name, ifr->ifr_name, sizeof(ifr->ifr_name));
 }
 
 /*
@@ -1538,21 +1537,17 @@ bpf_put(struct bpf_d *bd)
        free(bd, M_DEVBUF, sizeof(*bd));
 }
 
-/*
- * Attach an interface to bpf.  driverp is a pointer to a (struct bpf_if *)
- * in the driver's softc; dlt is the link layer type; hdrlen is the fixed
- * size of the link header (variable length headers not yet supported).
- */
-void
-bpfattach(caddr_t *driverp, struct ifnet *ifp, u_int dlt, u_int hdrlen)
+void *
+bpfsattach(caddr_t *bpfp, const char *name, u_int dlt, u_int hdrlen)
 {
        struct bpf_if *bp;
 
        if ((bp = malloc(sizeof(*bp), M_DEVBUF, M_NOWAIT)) == NULL)
                panic("bpfattach");
        SRPL_INIT(&bp->bif_dlist);
-       bp->bif_driverp = (struct bpf_if **)driverp;
-       bp->bif_ifp = ifp;
+       bp->bif_driverp = (struct bpf_if **)bpfp;
+       bp->bif_name = name;
+       bp->bif_ifp = NULL;
        bp->bif_dlt = dlt;
 
        bp->bif_next = bpf_iflist;
@@ -1567,6 +1562,17 @@ bpfattach(caddr_t *driverp, struct ifnet *ifp, u_int dlt, u_int hdrlen)
         * performance reasons and to alleviate alignment restrictions).
         */
        bp->bif_hdrlen = BPF_WORDALIGN(hdrlen + SIZEOF_BPF_HDR) - hdrlen;
+
+       return (bp);
+}
+
+void
+bpfattach(caddr_t *driverp, struct ifnet *ifp, u_int dlt, u_int hdrlen)
+{
+       struct bpf_if *bp;
+
+       bp = bpfsattach(driverp, ifp->if_xname, dlt, hdrlen);
+       bp->bif_ifp = ifp;
 }
 
 /* Detach an interface from its attached bpf device.  */
@@ -1574,31 +1580,39 @@ void
 bpfdetach(struct ifnet *ifp)
 {
        struct bpf_if *bp, *nbp, **pbp = &bpf_iflist;
-       struct bpf_d *bd;
-       int maj;
 
        KERNEL_ASSERT_LOCKED();
 
        for (bp = bpf_iflist; bp; bp = nbp) {
-               nbp= bp->bif_next;
+               nbp = bp->bif_next;
                if (bp->bif_ifp == ifp) {
                        *pbp = nbp;
 
-                       /* Locate the major number. */
-                       for (maj = 0; maj < nchrdev; maj++)
-                               if (cdevsw[maj].d_open == bpfopen)
-                                       break;
-
-                       while ((bd = SRPL_FIRST_LOCKED(&bp->bif_dlist)))
-                               vdevgone(maj, bd->bd_unit, bd->bd_unit, VCHR);
-
-                       free(bp, M_DEVBUF, sizeof *bp);
+                       bpfsdetach(bp);
                } else
                        pbp = &bp->bif_next;
        }
        ifp->if_bpf = NULL;
 }
 
+void
+bpfsdetach(void *p)
+{
+       struct bpf_if *bp = p;
+       struct bpf_d *bd;
+       int maj;
+
+       /* Locate the major number. */
+       for (maj = 0; maj < nchrdev; maj++)
+               if (cdevsw[maj].d_open == bpfopen)
+                       break;
+
+       while ((bd = SRPL_FIRST_LOCKED(&bp->bif_dlist)))
+               vdevgone(maj, bd->bd_unit, bd->bd_unit, VCHR);
+
+       free(bp, M_DEVBUF, sizeof *bp);
+}
+
 int
 bpf_sysctl_locked(int *name, u_int namelen, void *oldp, size_t *oldlenp,
     void *newp, size_t newlen)
@@ -1674,14 +1688,14 @@ int
 bpf_getdltlist(struct bpf_d *d, struct bpf_dltlist *bfl)
 {
        int n, error;
-       struct ifnet *ifp;
        struct bpf_if *bp;
+       const char *name;
 
-       ifp = d->bd_bif->bif_ifp;
+       name = d->bd_bif->bif_name;
        n = 0;
        error = 0;
        for (bp = bpf_iflist; bp != NULL; bp = bp->bif_next) {
-               if (bp->bif_ifp != ifp)
+               if (strcmp(name, bp->bif_name) != 0)
                        continue;
                if (bfl->bfl_list != NULL) {
                        if (n >= bfl->bfl_len)
@@ -1704,15 +1718,17 @@ bpf_getdltlist(struct bpf_d *d, struct bpf_dltlist *bfl)
 int
 bpf_setdlt(struct bpf_d *d, u_int dlt)
 {
-       struct ifnet *ifp;
+       const char *name;
        struct bpf_if *bp;
 
        MUTEX_ASSERT_LOCKED(&d->bd_mtx);
        if (d->bd_bif->bif_dlt == dlt)
                return (0);
-       ifp = d->bd_bif->bif_ifp;
+       name = d->bd_bif->bif_name;
        for (bp = bpf_iflist; bp != NULL; bp = bp->bif_next) {
-               if (bp->bif_ifp == ifp && bp->bif_dlt == dlt)
+               if (strcmp(name, bp->bif_name) != 0)
+                       continue;
+               if (bp->bif_dlt == dlt)
                        break;
        }
        if (bp == NULL)
index 1583d44..98afe4f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: bpf.h,v 1.62 2017/02/22 09:56:03 reyk Exp $   */
+/*     $OpenBSD: bpf.h,v 1.63 2018/01/24 00:25:17 dlg Exp $    */
 /*     $NetBSD: bpf.h,v 1.15 1996/12/13 07:57:33 mikel Exp $   */
 
 /*
@@ -313,6 +313,8 @@ int  bpf_mtap_af(caddr_t, u_int32_t, const struct mbuf *, u_int);
 int     bpf_mtap_ether(caddr_t, const struct mbuf *, u_int);
 void    bpfattach(caddr_t *, struct ifnet *, u_int, u_int);
 void    bpfdetach(struct ifnet *);
+void   *bpfsattach(caddr_t *, const char *, u_int, u_int);
+void    bpfsdetach(void *);
 void    bpfilterattach(int);
 
 u_int   bpf_mfilter(const struct bpf_insn *, const struct mbuf *, u_int);
index 4d32c4f..85a1171 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: bpfdesc.h,v 1.35 2017/01/24 10:08:30 krw Exp $        */
+/*     $OpenBSD: bpfdesc.h,v 1.36 2018/01/24 00:25:17 dlg Exp $        */
 /*     $NetBSD: bpfdesc.h,v 1.11 1995/09/27 18:30:42 thorpej Exp $     */
 
 /*
@@ -103,6 +103,7 @@ struct bpf_if {
        struct bpf_if **bif_driverp;    /* pointer into softc */
        u_int bif_dlt;                  /* link layer type */
        u_int bif_hdrlen;               /* length of header (with padding) */
+       const char *bif_name;           /* name of "subsystem" */
        struct ifnet *bif_ifp;          /* corresponding interface */
 };