Here's the big scary diff I've been using for some months now to stop grabbing the KERNEL_LOCK() in bpf_mtap(9). This has been originally written to prevent lock ordering inside pf_test(). Now that we're heading toward using a rwlock, we won't have this problem, but fewer usages of KERNEL_LOCK() is still interesting.
I'm going to split this diff in small chunks to ease the review. But I'd appreciate if people could try to break it, test & report back. Some notes: - Now that selwakeup() is called in a thread context (task) we only rely on the KERNEL_LOCK() to serialize access to kqueue(9) data. - The reference counting is here to make sure a descriptor is not freed during a sleep. That's why the KERNEL_LOCK() is still necessary in the slow path. On the other hand bpf_catchpacket() relies on the reference guaranteed by the SRP list. - A mutex now protects the rotating buffers and their associated fields. It is dropped before calling ifpromisc() because USB devices sleep. - The dance around uiomove(9) is here to check that buffers aren't rotated while data is copied to userland. Setting ``b->bd_fbuf'' to NULL should be enough to let bpf_catchpacket() to drop the patcket. But I added ``__in_uiomove'' to be able to have usable panic if something weird happen. Comments? Index: net/bpf.c =================================================================== RCS file: /cvs/src/sys/net/bpf.c,v retrieving revision 1.149 diff -u -p -r1.149 bpf.c --- net/bpf.c 12 Sep 2016 16:24:37 -0000 1.149 +++ net/bpf.c 13 Sep 2016 09:56:18 -0000 @@ -92,15 +92,13 @@ int bpf_maxbufsize = BPF_MAXBUFSIZE; struct bpf_if *bpf_iflist; LIST_HEAD(, bpf_d) bpf_d_list; -void bpf_allocbufs(struct bpf_d *); +int bpf_allocbufs(struct bpf_d *); void bpf_ifname(struct ifnet *, 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); int bpf_movein(struct uio *, u_int, struct mbuf **, struct sockaddr *, struct bpf_insn *); -void bpf_attachd(struct bpf_d *, struct bpf_if *); -void bpf_detachd(struct bpf_d *); int bpf_setif(struct bpf_d *, struct ifreq *); int bpfpoll(dev_t, int, struct proc *); int bpfkqfilter(dev_t, struct knote *); @@ -108,7 +106,6 @@ void bpf_wakeup(struct bpf_d *); void bpf_wakeup_cb(void *); void bpf_catchpacket(struct bpf_d *, u_char *, size_t, size_t, void (*)(const void *, void *, size_t), struct timeval *); -void bpf_reset_d(struct bpf_d *); int bpf_getdltlist(struct bpf_d *, struct bpf_dltlist *); int bpf_setdlt(struct bpf_d *, u_int); @@ -120,6 +117,13 @@ int bpf_sysctl_locked(int *, u_int, void struct bpf_d *bpfilter_lookup(int); /* + * Called holding ``bd_mtx''. + */ +void bpf_attachd(struct bpf_d *, struct bpf_if *); +void bpf_detachd(struct bpf_d *); +void bpf_resetd(struct bpf_d *); + +/* * Reference count access to descriptor buffers */ void bpf_get(struct bpf_d *); @@ -259,11 +263,12 @@ bpf_movein(struct uio *uio, u_int linkty /* * Attach file to the bpf interface, i.e. make d listen on bp. - * Must be called at splnet. */ void bpf_attachd(struct bpf_d *d, struct bpf_if *bp) { + MUTEX_ASSERT_LOCKED(&d->bd_mtx); + /* * Point d at bp, and add d to the interface's list of listeners. * Finally, point the driver's bpf cookie at the interface so @@ -286,7 +291,23 @@ bpf_detachd(struct bpf_d *d) { struct bpf_if *bp; + MUTEX_ASSERT_LOCKED(&d->bd_mtx); + bp = d->bd_bif; + + /* Remove d from the interface's descriptor list. */ + KERNEL_ASSERT_LOCKED(); + SRPL_REMOVE_LOCKED(&bpf_d_rc, &bp->bif_dlist, d, bpf_d, bd_next); + + if (SRPL_EMPTY_LOCKED(&bp->bif_dlist)) { + /* + * Let the driver know that there are no more listeners. + */ + *bp->bif_driverp = NULL; + } + + d->bd_bif = NULL; + /* * Check if this descriptor had requested promiscuous mode. * If so, turn it off. @@ -295,7 +316,13 @@ bpf_detachd(struct bpf_d *d) int error; d->bd_promisc = 0; + + bpf_get(d); + mtx_leave(&d->bd_mtx); error = ifpromisc(bp->bif_ifp, 0); + mtx_enter(&d->bd_mtx); + bpf_put(d); + if (error && !(error == EINVAL || error == ENODEV)) /* * Something is really wrong if we were able to put @@ -304,19 +331,6 @@ bpf_detachd(struct bpf_d *d) */ panic("bpf: ifpromisc failed"); } - - /* Remove d from the interface's descriptor list. */ - KERNEL_ASSERT_LOCKED(); - SRPL_REMOVE_LOCKED(&bpf_d_rc, &bp->bif_dlist, d, bpf_d, bd_next); - - if (SRPL_EMPTY_LOCKED(&bp->bif_dlist)) { - /* - * Let the driver know that there are no more listeners. - */ - *d->bd_bif->bif_driverp = 0; - } - - d->bd_bif = NULL; } void @@ -348,6 +362,7 @@ bpfopen(dev_t dev, int flag, int mode, s bd->bd_unit = unit; bd->bd_bufsize = bpf_bufsize; bd->bd_sig = SIGIO; + mtx_init(&bd->bd_mtx, IPL_NET); task_set(&bd->bd_wake_task, bpf_wakeup_cb, bd); if (flag & FNONBLOCK) @@ -367,16 +382,15 @@ 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) + mtx_enter(&d->bd_mtx); + if (d->bd_bif != NULL) bpf_detachd(d); bpf_wakeup(d); LIST_REMOVE(d, bd_list); + mtx_leave(&d->bd_mtx); bpf_put(d); - splx(s); return (0); } @@ -387,11 +401,13 @@ bpfclose(dev_t dev, int flag, int mode, * Zero the length of the new store buffer. */ #define ROTATE_BUFFERS(d) \ + KASSERT(d->__in_uiomove == 0); \ + MUTEX_ASSERT_LOCKED(&d->bd_mtx); \ (d)->bd_hbuf = (d)->bd_sbuf; \ (d)->bd_hlen = (d)->bd_slen; \ (d)->bd_sbuf = (d)->bd_fbuf; \ (d)->bd_slen = 0; \ - (d)->bd_fbuf = 0; + (d)->bd_fbuf = NULL; /* * bpfread - read next chunk of packets from buffers */ @@ -399,23 +415,26 @@ int bpfread(dev_t dev, struct uio *uio, int ioflag) { struct bpf_d *d; - int error; - int s; + caddr_t hbuf; + int hlen, error; + + KERNEL_ASSERT_LOCKED(); d = bpfilter_lookup(minor(dev)); if (d->bd_bif == NULL) return (ENXIO); + bpf_get(d); + mtx_enter(&d->bd_mtx); + /* * Restrict application to use a buffer the same size as * as kernel buffers. */ - if (uio->uio_resid != d->bd_bufsize) - return (EINVAL); - - s = splnet(); - - bpf_get(d); + if (uio->uio_resid != d->bd_bufsize) { + error = EINVAL; + goto out; + } /* * If there's a timeout, bd_rdStart is tagged when we start the read. @@ -431,13 +450,12 @@ bpfread(dev_t dev, struct uio *uio, int * ends when the timeout expires or when enough packets * have arrived to fill the store buffer. */ - while (d->bd_hbuf == 0) { + while (d->bd_hbuf == NULL) { if (d->bd_bif == NULL) { /* interface is gone */ if (d->bd_slen == 0) { - bpf_put(d); - splx(s); - return (EIO); + error = EIO; + goto out; } ROTATE_BUFFERS(d); break; @@ -456,23 +474,20 @@ bpfread(dev_t dev, struct uio *uio, int error = EWOULDBLOCK; } else { if ((d->bd_rdStart + d->bd_rtout) < ticks) { - error = tsleep((caddr_t)d, PRINET|PCATCH, "bpf", - d->bd_rtout); + error = msleep(d, &d->bd_mtx, PRINET|PCATCH, + "bpf", d->bd_rtout); } else error = EWOULDBLOCK; } - if (error == EINTR || error == ERESTART) { - bpf_put(d); - splx(s); - return (error); - } + if (error == EINTR || error == ERESTART) + goto out; if (error == EWOULDBLOCK) { /* * On a timeout, return what's in the buffer, * which may be nothing. If there is something * in the store buffer, we can rotate the buffers. */ - if (d->bd_hbuf) + if (d->bd_hbuf != NULL) /* * We filled up the buffer in between * getting the timeout and arriving @@ -481,9 +496,8 @@ bpfread(dev_t dev, struct uio *uio, int break; if (d->bd_slen == 0) { - bpf_put(d); - splx(s); - return (0); + error = 0; + goto out; } ROTATE_BUFFERS(d); break; @@ -492,22 +506,30 @@ bpfread(dev_t dev, struct uio *uio, int /* * At this point, we know we have something in the hold slot. */ - splx(s); + hbuf = d->bd_hbuf; + hlen = d->bd_hlen; + d->bd_hbuf = NULL; + d->bd_hlen = 0; + d->bd_fbuf = NULL; + d->__in_uiomove = 1; /* * Move data from hold buffer into user space. * We know the entire buffer is transferred since * we checked above that the read buffer is bpf_bufsize bytes. */ - error = uiomove(d->bd_hbuf, d->bd_hlen, uio); - - s = splnet(); - d->bd_fbuf = d->bd_hbuf; - d->bd_hbuf = NULL; - d->bd_hlen = 0; - + mtx_leave(&d->bd_mtx); + error = uiomove(hbuf, hlen, uio); + mtx_enter(&d->bd_mtx); + + /* Ensure that bpf_resetd() or ROTATE_BUFFERS() haven't been called. */ + KASSERT(d->bd_fbuf == NULL); + KASSERT(d->bd_hbuf == NULL); + d->bd_fbuf = hbuf; + d->__in_uiomove = 0; +out: + mtx_leave(&d->bd_mtx); bpf_put(d); - splx(s); return (error); } @@ -519,6 +541,8 @@ bpfread(dev_t dev, struct uio *uio, int void bpf_wakeup(struct bpf_d *d) { + MUTEX_ASSERT_LOCKED(&d->bd_mtx); + /* * As long as csignal() and selwakeup() need to be protected * by the KERNEL_LOCK() we have to delay the wakeup to @@ -542,6 +566,7 @@ bpf_wakeup_cb(void *xd) selwakeup(&d->bd_sel); bpf_put(d); + } int @@ -552,34 +577,49 @@ bpfwrite(dev_t dev, struct uio *uio, int struct mbuf *m; struct bpf_program *bf; struct bpf_insn *fcode = NULL; - int error, s; struct sockaddr_storage dst; + u_int dlt; + int error; + + KERNEL_ASSERT_LOCKED(); d = bpfilter_lookup(minor(dev)); - if (d->bd_bif == NULL) - return (ENXIO); + bpf_get(d); + mtx_enter(&d->bd_mtx); + if (d->bd_bif == NULL) { + error = ENXIO; + goto out; + } ifp = d->bd_bif->bif_ifp; - if ((ifp->if_flags & IFF_UP) == 0) - return (ENETDOWN); + if ((ifp->if_flags & IFF_UP) == 0) { + error = ENETDOWN; + goto out; + } - if (uio->uio_resid == 0) - return (0); + if (uio->uio_resid == 0) { + error = 0; + goto out; + } KERNEL_ASSERT_LOCKED(); /* for accessing bd_wfilter */ bf = srp_get_locked(&d->bd_wfilter); if (bf != NULL) fcode = bf->bf_insns; - error = bpf_movein(uio, d->bd_bif->bif_dlt, &m, - (struct sockaddr *)&dst, fcode); + dlt = d->bd_bif->bif_dlt; + + mtx_leave(&d->bd_mtx); + error = bpf_movein(uio, dlt, &m,(struct sockaddr *)&dst, fcode); if (error) return (error); + mtx_enter(&d->bd_mtx); if (m->m_pkthdr.len > ifp->if_mtu) { m_freem(m); - return (EMSGSIZE); + error = EMSGSIZE; + goto out; } m->m_pkthdr.ph_rtableid = ifp->if_rdomain; @@ -588,23 +628,25 @@ bpfwrite(dev_t dev, struct uio *uio, int if (d->bd_hdrcmplt && dst.ss_family == AF_UNSPEC) dst.ss_family = pseudo_AF_HDRCMPLT; - s = splsoftnet(); error = ifp->if_output(ifp, m, (struct sockaddr *)&dst, NULL); - splx(s); - /* - * The driver frees the mbuf. - */ +out: + mtx_leave(&d->bd_mtx); + bpf_put(d); + return (error); } /* * Reset a descriptor by flushing its packet buffer and clearing the - * receive and drop counts. Should be called at splnet. + * receive and drop counts. */ void -bpf_reset_d(struct bpf_d *d) +bpf_resetd(struct bpf_d *d) { - if (d->bd_hbuf) { + MUTEX_ASSERT_LOCKED(&d->bd_mtx); + KASSERT(d->__in_uiomove == 0); + + if (d->bd_hbuf != NULL) { /* Free the hold buffer. */ d->bd_fbuf = d->bd_hbuf; d->bd_hbuf = NULL; @@ -638,7 +680,7 @@ int bpfioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) { struct bpf_d *d; - int s, error = 0; + int error = 0; d = bpfilter_lookup(minor(dev)); if (d->bd_locked && suser(p, 0) != 0) { @@ -666,8 +708,9 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t } } - switch (cmd) { + bpf_get(d); + switch (cmd) { default: error = EINVAL; break; @@ -679,11 +722,11 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t { int n; - s = splnet(); + mtx_enter(&d->bd_mtx); n = d->bd_slen; - if (d->bd_hbuf) + if (d->bd_hbuf != NULL) n += d->bd_hlen; - splx(s); + mtx_leave(&d->bd_mtx); *(int *)addr = n; break; @@ -709,7 +752,9 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t *(u_int *)addr = size = bpf_maxbufsize; else if (size < BPF_MINBUFSIZE) *(u_int *)addr = size = BPF_MINBUFSIZE; + mtx_enter(&d->bd_mtx); d->bd_bufsize = size; + mtx_leave(&d->bd_mtx); } break; @@ -731,9 +776,9 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t * Flush read packet buffer. */ case BIOCFLUSH: - s = splnet(); - bpf_reset_d(d); - splx(s); + mtx_enter(&d->bd_mtx); + bpf_resetd(d); + mtx_leave(&d->bd_mtx); break; /* @@ -745,15 +790,14 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t * No interface attached yet. */ error = EINVAL; - break; - } - s = splnet(); - if (d->bd_promisc == 0) { - error = ifpromisc(d->bd_bif->bif_ifp, 1); - if (error == 0) - d->bd_promisc = 1; + } else { + if (d->bd_promisc == 0) { + MUTEX_ASSERT_UNLOCKED(&d->bd_mtx); + error = ifpromisc(d->bd_bif->bif_ifp, 1); + if (error == 0) + d->bd_promisc = 1; + } } - splx(s); break; /* @@ -770,30 +814,36 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t * Get device parameters. */ case BIOCGDLT: + mtx_enter(&d->bd_mtx); if (d->bd_bif == NULL) error = EINVAL; else *(u_int *)addr = d->bd_bif->bif_dlt; + mtx_leave(&d->bd_mtx); break; /* * Set device parameters. */ case BIOCSDLT: + mtx_enter(&d->bd_mtx); if (d->bd_bif == NULL) error = EINVAL; else error = bpf_setdlt(d, *(u_int *)addr); + mtx_leave(&d->bd_mtx); break; /* * Set interface name. */ case BIOCGETIF: + mtx_enter(&d->bd_mtx); if (d->bd_bif == NULL) error = EINVAL; else bpf_ifname(d->bd_bif->bif_ifp, (struct ifreq *)addr); + mtx_leave(&d->bd_mtx); break; /* @@ -931,6 +981,8 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t *(u_int *)addr = d->bd_sig; break; } + + bpf_put(d); return (error); } @@ -945,7 +997,6 @@ bpf_setf(struct bpf_d *d, struct bpf_pro struct srp *filter; struct bpf_insn *fcode; u_int flen, size; - int s; KERNEL_ASSERT_LOCKED(); filter = wf ? &d->bd_wfilter : &d->bd_rfilter; @@ -954,9 +1005,9 @@ bpf_setf(struct bpf_d *d, struct bpf_pro if (fp->bf_len != 0) return (EINVAL); srp_update_locked(&bpf_insn_gc, filter, NULL); - s = splnet(); - bpf_reset_d(d); - splx(s); + mtx_enter(&d->bd_mtx); + bpf_resetd(d); + mtx_leave(&d->bd_mtx); return (0); } flen = fp->bf_len; @@ -981,9 +1032,9 @@ bpf_setf(struct bpf_d *d, struct bpf_pro srp_update_locked(&bpf_insn_gc, filter, bf); - s = splnet(); - bpf_reset_d(d); - splx(s); + mtx_enter(&d->bd_mtx); + bpf_resetd(d); + mtx_leave(&d->bd_mtx); return (0); } @@ -996,7 +1047,7 @@ int bpf_setif(struct bpf_d *d, struct ifreq *ifr) { struct bpf_if *bp, *candidate = NULL; - int s; + int error = 0; /* * Look through attached interfaces for the named one. @@ -1012,30 +1063,33 @@ bpf_setif(struct bpf_d *d, struct ifreq 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 == NULL) - bpf_allocbufs(d); - s = splnet(); - if (candidate != d->bd_bif) { - if (d->bd_bif) - /* - * Detach if attached to something else. - */ - bpf_detachd(d); + /* Not found. */ + if (candidate == NULL) + return (ENXIO); - bpf_attachd(d, candidate); - } - bpf_reset_d(d); - splx(s); - return (0); + /* + * Allocate the packet buffers if we need to. + * If we're already attached to requested interface, + * just flush the buffer. + */ + mtx_enter(&d->bd_mtx); + if (d->bd_sbuf == NULL) { + if ((error = bpf_allocbufs(d))) + goto out; } - /* Not found. */ - return (ENXIO); + if (candidate != d->bd_bif) { + if (d->bd_bif) + /* + * Detach if attached to something else. + */ + bpf_detachd(d); + + bpf_attachd(d, candidate); + } + bpf_resetd(d); +out: + mtx_leave(&d->bd_mtx); + return (error); } /* @@ -1054,7 +1108,9 @@ int bpfpoll(dev_t dev, int events, struct proc *p) { struct bpf_d *d; - int s, revents; + int revents; + + KERNEL_ASSERT_LOCKED(); /* * An imitation of the FIONREAD ioctl code. @@ -1075,7 +1131,7 @@ bpfpoll(dev_t dev, int events, struct pr revents = events & (POLLOUT | POLLWRNORM); if (events & (POLLIN | POLLRDNORM)) { - s = splnet(); + mtx_enter(&d->bd_mtx); if (d->bd_hlen != 0 || (d->bd_immediate && d->bd_slen != 0)) revents |= events & (POLLIN | POLLRDNORM); else { @@ -1087,7 +1143,7 @@ bpfpoll(dev_t dev, int events, struct pr d->bd_rdStart = ticks; selrecord(p, &d->bd_sel); } - splx(s); + mtx_leave(&d->bd_mtx); } return (revents); } @@ -1100,9 +1156,11 @@ bpfkqfilter(dev_t dev, struct knote *kn) { struct bpf_d *d; struct klist *klist; - int s; + + KERNEL_ASSERT_LOCKED(); d = bpfilter_lookup(minor(dev)); + switch (kn->kn_filter) { case EVFILT_READ: klist = &d->bd_sel.si_note; @@ -1112,14 +1170,14 @@ bpfkqfilter(dev_t dev, struct knote *kn) return (EINVAL); } - kn->kn_hook = d; - - s = splnet(); bpf_get(d); + kn->kn_hook = d; SLIST_INSERT_HEAD(klist, kn, kn_selnext); + + mtx_enter(&d->bd_mtx); if (d->bd_rtout != -1 && d->bd_rdStart == 0) d->bd_rdStart = ticks; - splx(s); + mtx_leave(&d->bd_mtx); return (0); } @@ -1128,12 +1186,11 @@ void filt_bpfrdetach(struct knote *kn) { struct bpf_d *d = kn->kn_hook; - int s; - s = splnet(); + KERNEL_ASSERT_LOCKED(); + SLIST_REMOVE(&d->bd_sel.si_note, kn, knote, kn_selnext); bpf_put(d); - splx(s); } int @@ -1141,6 +1198,8 @@ filt_bpfread(struct knote *kn, long hint { struct bpf_d *d = kn->kn_hook; + KERNEL_ASSERT_LOCKED(); + kn->kn_data = d->bd_hlen; if (d->bd_immediate) kn->kn_data += d->bd_slen; @@ -1186,7 +1245,6 @@ _bpf_mtap(caddr_t arg, const struct mbuf struct timeval tv; int gottime = 0; int drop = 0; - int s; if (m == NULL) return (0); @@ -1222,12 +1280,10 @@ _bpf_mtap(caddr_t arg, const struct mbuf if (!gottime++) microtime(&tv); - KERNEL_LOCK(); - s = splnet(); + mtx_enter(&d->bd_mtx); bpf_catchpacket(d, (u_char *)m, pktlen, slen, cpfn, &tv); - splx(s); - KERNEL_UNLOCK(); + mtx_leave(&d->bd_mtx); if (d->bd_fildrop) drop = 1; @@ -1355,8 +1411,9 @@ bpf_catchpacket(struct bpf_d *d, u_char { struct bpf_hdr *hp; int totlen, curlen; - int hdrlen; + int hdrlen, do_wakeup = 0; + MUTEX_ASSERT_LOCKED(&d->bd_mtx); if (d->bd_bif == NULL) return; @@ -1391,7 +1448,7 @@ bpf_catchpacket(struct bpf_d *d, u_char return; } ROTATE_BUFFERS(d); - bpf_wakeup(d); + do_wakeup = 1; curlen = 0; } @@ -1414,7 +1471,7 @@ bpf_catchpacket(struct bpf_d *d, u_char * Immediate mode is set. A packet arrived so any * reads should be woken up. */ - bpf_wakeup(d); + do_wakeup = 1; } if (d->bd_rdStart && (d->bd_rtout + d->bd_rdStart < ticks)) { @@ -1423,24 +1480,39 @@ bpf_catchpacket(struct bpf_d *d, u_char * may have timeouts set. We got here by getting * a packet, so wake up the reader. */ - if (d->bd_fbuf) { + if (d->bd_fbuf != NULL) { d->bd_rdStart = 0; ROTATE_BUFFERS(d); - bpf_wakeup(d); + do_wakeup = 1; } } + + if (do_wakeup) + bpf_wakeup(d); } /* * Initialize all nonzero fields of a descriptor. */ -void +int bpf_allocbufs(struct bpf_d *d) { - d->bd_fbuf = malloc(d->bd_bufsize, M_DEVBUF, M_WAITOK); - d->bd_sbuf = malloc(d->bd_bufsize, M_DEVBUF, M_WAITOK); + MUTEX_ASSERT_LOCKED(&d->bd_mtx); + + d->bd_fbuf = malloc(d->bd_bufsize, M_DEVBUF, M_NOWAIT); + if (d->bd_fbuf == NULL) + return (ENOMEM); + + d->bd_sbuf = malloc(d->bd_bufsize, M_DEVBUF, M_NOWAIT); + if (d->bd_sbuf == NULL) { + free(d->bd_fbuf, M_DEVBUF, d->bd_bufsize); + return (ENOMEM); + } + d->bd_slen = 0; d->bd_hlen = 0; + + return (0); } void @@ -1591,6 +1663,8 @@ bpfilter_lookup(int unit) { struct bpf_d *bd; + KERNEL_ASSERT_LOCKED(); + LIST_FOREACH(bd, &bpf_d_list, bd_list) if (bd->bd_unit == unit) return (bd); @@ -1634,10 +1708,10 @@ bpf_getdltlist(struct bpf_d *d, struct b int bpf_setdlt(struct bpf_d *d, u_int dlt) { - int s; struct ifnet *ifp; 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; @@ -1647,11 +1721,10 @@ bpf_setdlt(struct bpf_d *d, u_int dlt) } if (bp == NULL) return (EINVAL); - s = splnet(); bpf_detachd(d); bpf_attachd(d, bp); - bpf_reset_d(d); - splx(s); + bpf_resetd(d); + return (0); } Index: net/bpfdesc.h =================================================================== RCS file: /cvs/src/sys/net/bpfdesc.h,v retrieving revision 1.31 diff -u -p -r1.31 bpfdesc.h --- net/bpfdesc.h 22 Aug 2016 10:40:36 -0000 1.31 +++ net/bpfdesc.h 12 Sep 2016 11:59:49 -0000 @@ -56,15 +56,17 @@ struct bpf_d { * fbuf (free) - When read is done, put cluster here. * On receiving, if sbuf is full and fbuf is 0, packet is dropped. */ + struct mutex bd_mtx; /* protect buffer slots below */ caddr_t bd_sbuf; /* store slot */ caddr_t bd_hbuf; /* hold slot */ caddr_t bd_fbuf; /* free slot */ int bd_slen; /* current length of store buffer */ int bd_hlen; /* current length of hold buffer */ - int bd_bufsize; /* absolute length of buffers */ - struct bpf_if * bd_bif; /* interface descriptor */ + int __in_uiomove; + + struct bpf_if *bd_bif; /* interface descriptor */ u_long bd_rtout; /* Read timeout in 'ticks' */ u_long bd_rdStart; /* when the read started */ struct srp bd_rfilter; /* read filter code */