/* ARGSUSED */ int bpfclose(dev_t dev, __unused int flags, __unused int fmt, __unused struct proc *p) { struct bpf_d *d; /* Take BPF lock to ensure no other thread is using the device */ lck_mtx_lock(bpf_mlock); d = bpf_dtab[minor(dev)]; if (d == 0 || d == (void *)1) { lck_mtx_unlock(bpf_mlock); return (ENXIO); } bpf_dtab[minor(dev)] = (void *)1; /* Mark closing */ if (d->bd_bif) bpf_detachd(d); selthreadclear(&d->bd_sel); #if CONFIG_MACF_NET mac_bpfdesc_label_destroy(d); #endif bpf_freed(d); /* Mark free in same context as bpfopen comes to check */ bpf_dtab[minor(dev)] = NULL; /* Mark closed */ lck_mtx_unlock(bpf_mlock); _FREE(d, M_DEVBUF); return (0); }
/* * Detach a file from its current interface (if attached at all) and attach * to the interface indicated by the name stored in ifr. * Return an errno or 0. */ int bpf_setif(struct bpf_d *d, struct ifreq *ifr) { struct bpf_if *bp, *candidate = NULL; int s, error; /* * Look through attached interfaces for the named one. */ for (bp = bpf_iflist; bp != 0; bp = bp->bif_next) { struct ifnet *ifp = bp->bif_ifp; if (ifp == 0 || strcmp(ifp->if_xname, ifr->ifr_name) != 0) continue; /* * We found the requested interface. */ if (candidate == NULL || candidate->bif_dlt > bp->bif_dlt) candidate = bp; } if (candidate != NULL) { /* * Allocate the packet buffers if we need to. * If we're already attached to requested interface, * just flush the buffer. */ if (d->bd_sbuf == 0) { error = bpf_allocbufs(d); if (error != 0) return (error); } s = splnet(); if (candidate != d->bd_bif) { if (d->bd_bif) /* * Detach if attached to something else. */ bpf_detachd(d); bpf_attachd(d, candidate); } bpf_reset_d(d); splx(s); return (0); } /* Not found. */ return (ENXIO); }
/* ARGSUSED */ int bpfclose(dev_t dev, int flag, int mode, struct proc *p) { struct bpf_d *d; int s; d = bpfilter_lookup(minor(dev)); s = splnet(); if (d->bd_bif) bpf_detachd(d); bpf_wakeup(d); D_PUT(d); splx(s); return (0); }
/* * Detach a file from its current interface (if attached at all) and attach * to the interface indicated by the name stored in ifr. * Return an errno or 0. */ static int bpf_setif(struct bpf_d *d, ifnet_t theywant, u_int32_t dlt) { struct bpf_if *bp; int error; /* * Look through attached interfaces for the named one. */ for (bp = bpf_iflist; bp != 0; bp = bp->bif_next) { struct ifnet *ifp = bp->bif_ifp; if (ifp == 0 || ifp != theywant || (dlt != 0 && dlt != bp->bif_dlt)) continue; /* * We found the requested interface. * If it's not up, return an error. * Allocate the packet buffers if we need to. * If we're already attached to requested interface, * just flush the buffer. */ if ((ifp->if_flags & IFF_UP) == 0) return (ENETDOWN); if (d->bd_sbuf == 0) { error = bpf_allocbufs(d); if (error != 0) return (error); } if (bp != d->bd_bif) { if (d->bd_bif) /* * Detach if attached to something else. */ bpf_detachd(d); if (bpf_attachd(d, bp) != 0) { return ENXIO; } } reset_d(d); return (0); } /* Not found. */ return (ENXIO); }
/* * 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(struct ifnet *ifp) { struct bpf_if *bp, *bp_prev, *bp_next; struct bpf_if *bp_free = NULL; struct bpf_d *d; lck_mtx_lock(bpf_mlock); /* Locate BPF interface information */ bp_prev = NULL; for (bp = bpf_iflist; bp != NULL; bp = bp_next) { bp_next = bp->bif_next; if (ifp != bp->bif_ifp) { bp_prev = bp; continue; } 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; } bp->bif_next = bp_free; bp_free = bp; ifnet_release(ifp); } lck_mtx_unlock(bpf_mlock); FREE(bp, M_DEVBUF); }
/* * Set the data link type of a BPF instance. */ static int bpf_setdlt(struct bpf_d *d, uint32_t dlt) { int error, opromisc; struct ifnet *ifp; struct bpf_if *bp; if (d->bd_bif->bif_dlt == dlt) return (0); ifp = d->bd_bif->bif_ifp; for (bp = bpf_iflist; bp; bp = bp->bif_next) { if (bp->bif_ifp == ifp && bp->bif_dlt == dlt) break; } if (bp != NULL) { opromisc = d->bd_promisc; bpf_detachd(d); error = bpf_attachd(d, bp); if (error) { printf("bpf_setdlt: bpf_attachd %s%d failed (%d)\n", ifnet_name(bp->bif_ifp), ifnet_unit(bp->bif_ifp), error); return error; } reset_d(d); if (opromisc) { lck_mtx_unlock(bpf_mlock); error = ifnet_set_promiscuous(bp->bif_ifp, 1); lck_mtx_lock(bpf_mlock); if (error) printf("bpf_setdlt: ifpromisc %s%d failed (%d)\n", ifnet_name(bp->bif_ifp), ifnet_unit(bp->bif_ifp), error); else d->bd_promisc = 1; } } return (bp == NULL ? EINVAL : 0); }