diff options
author | Martin Pieuchot <mpi@cvs.openbsd.org> | 2017-01-03 19:28:51 +0000 |
---|---|---|
committer | Martin Pieuchot <mpi@cvs.openbsd.org> | 2017-01-03 19:28:51 +0000 |
commit | 136eecd279033aea7eb63fffd75ac88e96bb9723 (patch) | |
tree | 11a04ca9efba766191717d5f379bb98c4fa716d4 /sys/net/bpf.c | |
parent | 14578659e0f61803f28069c77d0c616ea4ed6d88 (diff) |
Revert previous, there's still a problem with recursive entries in
bpf_mpath_ether().
Problem reported by Hrvoje Popovski.
Diffstat (limited to 'sys/net/bpf.c')
-rw-r--r-- | sys/net/bpf.c | 195 |
1 files changed, 74 insertions, 121 deletions
diff --git a/sys/net/bpf.c b/sys/net/bpf.c index 16345bf1366..e55e4a9ad3c 100644 --- a/sys/net/bpf.c +++ b/sys/net/bpf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bpf.c,v 1.156 2017/01/02 11:07:31 mpi Exp $ */ +/* $OpenBSD: bpf.c,v 1.157 2017/01/03 19:28:50 mpi Exp $ */ /* $NetBSD: bpf.c,v 1.33 1997/02/21 23:59:35 thorpej Exp $ */ /* @@ -116,9 +116,6 @@ int bpf_sysctl_locked(int *, u_int, void *, size_t *, void *, size_t); 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 *); @@ -263,12 +260,11 @@ bpf_movein(struct uio *uio, u_int linktype, struct mbuf **mp, /* * 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 @@ -291,8 +287,6 @@ bpf_detachd(struct bpf_d *d) { struct bpf_if *bp; - MUTEX_ASSERT_LOCKED(&d->bd_mtx); - bp = d->bd_bif; /* Not attached. */ if (bp == NULL) @@ -319,13 +313,7 @@ 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 @@ -365,7 +353,6 @@ bpfopen(dev_t dev, int flag, int mode, struct proc *p) 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) @@ -385,14 +372,15 @@ int bpfclose(dev_t dev, int flag, int mode, struct proc *p) { struct bpf_d *d; + int s; d = bpfilter_lookup(minor(dev)); - mtx_enter(&d->bd_mtx); + s = splnet(); bpf_detachd(d); bpf_wakeup(d); LIST_REMOVE(d, bd_list); - mtx_leave(&d->bd_mtx); bpf_put(d); + splx(s); return (0); } @@ -403,13 +391,11 @@ bpfclose(dev_t dev, int flag, int mode, struct proc *p) * Zero the length of the new store buffer. */ #define ROTATE_BUFFERS(d) \ - KASSERT(d->bd_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 = NULL; + (d)->bd_fbuf = 0; /* * bpfread - read next chunk of packets from buffers */ @@ -417,17 +403,15 @@ int bpfread(dev_t dev, struct uio *uio, int ioflag) { struct bpf_d *d; - caddr_t hbuf; - int hlen, error; - - KERNEL_ASSERT_LOCKED(); + int error; + int s; d = bpfilter_lookup(minor(dev)); if (d->bd_bif == NULL) return (ENXIO); + s = splnet(); bpf_get(d); - mtx_enter(&d->bd_mtx); /* * Restrict application to use a buffer the same size as @@ -476,8 +460,8 @@ bpfread(dev_t dev, struct uio *uio, int ioflag) error = EWOULDBLOCK; } else { if ((d->bd_rdStart + d->bd_rtout) < ticks) { - error = msleep(d, &d->bd_mtx, PRINET|PCATCH, - "bpf", d->bd_rtout); + error = tsleep((caddr_t)d, PRINET|PCATCH, "bpf", + d->bd_rtout); } else error = EWOULDBLOCK; } @@ -508,30 +492,22 @@ bpfread(dev_t dev, struct uio *uio, int ioflag) /* * At this point, we know we have something in the hold slot. */ - hbuf = d->bd_hbuf; - hlen = d->bd_hlen; - d->bd_hbuf = NULL; - d->bd_hlen = 0; - d->bd_fbuf = NULL; - d->bd_in_uiomove = 1; + splx(s); /* * 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. */ - 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->bd_in_uiomove = 0; + 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; out: - mtx_leave(&d->bd_mtx); bpf_put(d); + splx(s); return (error); } @@ -543,8 +519,6 @@ out: 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 @@ -578,21 +552,17 @@ bpfwrite(dev_t dev, struct uio *uio, int ioflag) 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)); - bpf_get(d); - mtx_enter(&d->bd_mtx); - if (d->bd_bif == NULL) { - error = ENXIO; - goto out; - } + if (d->bd_bif == NULL) + return (ENXIO); + bpf_get(d); ifp = d->bd_bif->bif_ifp; + if ((ifp->if_flags & IFF_UP) == 0) { error = ENETDOWN; goto out; @@ -610,9 +580,7 @@ bpfwrite(dev_t dev, struct uio *uio, int ioflag) dlt = d->bd_bif->bif_dlt; - mtx_leave(&d->bd_mtx); error = bpf_movein(uio, dlt, &m, (struct sockaddr *)&dst, fcode); - mtx_enter(&d->bd_mtx); if (error) goto out; @@ -628,25 +596,23 @@ bpfwrite(dev_t dev, struct uio *uio, int ioflag) 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); + 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. + * receive and drop counts. Should be called at splnet. */ void bpf_resetd(struct bpf_d *d) { - MUTEX_ASSERT_LOCKED(&d->bd_mtx); - KASSERT(d->bd_in_uiomove == 0); - - if (d->bd_hbuf != NULL) { + if (d->bd_hbuf) { /* Free the hold buffer. */ d->bd_fbuf = d->bd_hbuf; d->bd_hbuf = NULL; @@ -680,7 +646,7 @@ int bpfioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) { struct bpf_d *d; - int error = 0; + int s, error = 0; d = bpfilter_lookup(minor(dev)); if (d->bd_locked && suser(p, 0) != 0) { @@ -708,9 +674,8 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) } } - bpf_get(d); - switch (cmd) { + default: error = EINVAL; break; @@ -722,11 +687,11 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) { int n; - mtx_enter(&d->bd_mtx); + s = splnet(); n = d->bd_slen; - if (d->bd_hbuf != NULL) + if (d->bd_hbuf) n += d->bd_hlen; - mtx_leave(&d->bd_mtx); + splx(s); *(int *)addr = n; break; @@ -752,9 +717,7 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) *(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; @@ -776,9 +739,9 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) * Flush read packet buffer. */ case BIOCFLUSH: - mtx_enter(&d->bd_mtx); + s = splnet(); bpf_resetd(d); - mtx_leave(&d->bd_mtx); + splx(s); break; /* @@ -790,14 +753,15 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) * No interface attached yet. */ error = EINVAL; - } 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; - } + break; + } + s = splnet(); + if (d->bd_promisc == 0) { + error = ifpromisc(d->bd_bif->bif_ifp, 1); + if (error == 0) + d->bd_promisc = 1; } + splx(s); break; /* @@ -826,11 +790,8 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) case BIOCSDLT: if (d->bd_bif == NULL) error = EINVAL; - else { - mtx_enter(&d->bd_mtx); + else error = bpf_setdlt(d, *(u_int *)addr); - mtx_leave(&d->bd_mtx); - } break; /* @@ -978,8 +939,6 @@ bpfioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) *(u_int *)addr = d->bd_sig; break; } - - bpf_put(d); return (error); } @@ -994,6 +953,7 @@ bpf_setf(struct bpf_d *d, struct bpf_program *fp, int wf) struct srp *filter; struct bpf_insn *fcode; u_int flen, size; + int s; KERNEL_ASSERT_LOCKED(); filter = wf ? &d->bd_wfilter : &d->bd_rfilter; @@ -1002,9 +962,9 @@ bpf_setf(struct bpf_d *d, struct bpf_program *fp, int wf) if (fp->bf_len != 0) return (EINVAL); srp_update_locked(&bpf_insn_gc, filter, NULL); - mtx_enter(&d->bd_mtx); + s = splnet(); bpf_resetd(d); - mtx_leave(&d->bd_mtx); + splx(s); return (0); } flen = fp->bf_len; @@ -1029,9 +989,9 @@ bpf_setf(struct bpf_d *d, struct bpf_program *fp, int wf) srp_update_locked(&bpf_insn_gc, filter, bf); - mtx_enter(&d->bd_mtx); + s = splnet(); bpf_resetd(d); - mtx_leave(&d->bd_mtx); + splx(s); return (0); } @@ -1045,6 +1005,7 @@ bpf_setif(struct bpf_d *d, struct ifreq *ifr) { struct bpf_if *bp, *candidate = NULL; int error = 0; + int s; /* * Look through attached interfaces for the named one. @@ -1069,7 +1030,7 @@ bpf_setif(struct bpf_d *d, struct ifreq *ifr) * If we're already attached to requested interface, * just flush the buffer. */ - mtx_enter(&d->bd_mtx); + s = splnet(); if (d->bd_sbuf == NULL) { if ((error = bpf_allocbufs(d))) goto out; @@ -1083,7 +1044,7 @@ bpf_setif(struct bpf_d *d, struct ifreq *ifr) } bpf_resetd(d); out: - mtx_leave(&d->bd_mtx); + splx(s); return (error); } @@ -1103,9 +1064,7 @@ int bpfpoll(dev_t dev, int events, struct proc *p) { struct bpf_d *d; - int revents; - - KERNEL_ASSERT_LOCKED(); + int s, revents; /* * An imitation of the FIONREAD ioctl code. @@ -1126,7 +1085,7 @@ bpfpoll(dev_t dev, int events, struct proc *p) revents = events & (POLLOUT | POLLWRNORM); if (events & (POLLIN | POLLRDNORM)) { - mtx_enter(&d->bd_mtx); + s = splnet(); if (d->bd_hlen != 0 || (d->bd_immediate && d->bd_slen != 0)) revents |= events & (POLLIN | POLLRDNORM); else { @@ -1138,7 +1097,7 @@ bpfpoll(dev_t dev, int events, struct proc *p) d->bd_rdStart = ticks; selrecord(p, &d->bd_sel); } - mtx_leave(&d->bd_mtx); + splx(s); } return (revents); } @@ -1151,11 +1110,9 @@ bpfkqfilter(dev_t dev, struct knote *kn) { struct bpf_d *d; struct klist *klist; - - KERNEL_ASSERT_LOCKED(); + int s; d = bpfilter_lookup(minor(dev)); - switch (kn->kn_filter) { case EVFILT_READ: klist = &d->bd_sel.si_note; @@ -1165,14 +1122,14 @@ bpfkqfilter(dev_t dev, struct knote *kn) return (EINVAL); } - bpf_get(d); kn->kn_hook = d; - SLIST_INSERT_HEAD(klist, kn, kn_selnext); - mtx_enter(&d->bd_mtx); + s = splnet(); + bpf_get(d); + SLIST_INSERT_HEAD(klist, kn, kn_selnext); if (d->bd_rtout != -1 && d->bd_rdStart == 0) d->bd_rdStart = ticks; - mtx_leave(&d->bd_mtx); + splx(s); return (0); } @@ -1181,11 +1138,12 @@ void filt_bpfrdetach(struct knote *kn) { struct bpf_d *d = kn->kn_hook; + int s; - KERNEL_ASSERT_LOCKED(); - + s = splnet(); SLIST_REMOVE(&d->bd_sel.si_note, kn, knote, kn_selnext); bpf_put(d); + splx(s); } int @@ -1193,14 +1151,9 @@ filt_bpfread(struct knote *kn, long hint) { struct bpf_d *d = kn->kn_hook; - KERNEL_ASSERT_LOCKED(); - - mtx_enter(&d->bd_mtx); kn->kn_data = d->bd_hlen; if (d->bd_immediate) kn->kn_data += d->bd_slen; - mtx_leave(&d->bd_mtx); - return (kn->kn_data > 0); } @@ -1243,6 +1196,7 @@ _bpf_mtap(caddr_t arg, const struct mbuf *m, u_int direction, struct timeval tv; int gottime = 0; int drop = 0; + int s; if (m == NULL) return (0); @@ -1278,10 +1232,12 @@ _bpf_mtap(caddr_t arg, const struct mbuf *m, u_int direction, if (!gottime++) microtime(&tv); - mtx_enter(&d->bd_mtx); + KERNEL_LOCK(); + s = splnet(); bpf_catchpacket(d, (u_char *)m, pktlen, slen, cpfn, &tv); - mtx_leave(&d->bd_mtx); + splx(s); + KERNEL_UNLOCK(); if (d->bd_fildrop) drop = 1; @@ -1411,7 +1367,6 @@ bpf_catchpacket(struct bpf_d *d, u_char *pkt, size_t pktlen, size_t snaplen, int totlen, curlen; int hdrlen, do_wakeup = 0; - MUTEX_ASSERT_LOCKED(&d->bd_mtx); if (d->bd_bif == NULL) return; @@ -1495,8 +1450,6 @@ bpf_catchpacket(struct bpf_d *d, u_char *pkt, size_t pktlen, size_t snaplen, int bpf_allocbufs(struct bpf_d *d) { - MUTEX_ASSERT_LOCKED(&d->bd_mtx); - d->bd_fbuf = malloc(d->bd_bufsize, M_DEVBUF, M_NOWAIT); if (d->bd_fbuf == NULL) return (ENOMEM); @@ -1516,7 +1469,7 @@ bpf_allocbufs(struct bpf_d *d) void bpf_get(struct bpf_d *bd) { - atomic_inc_int(&bd->bd_ref); + bd->bd_ref++; } /* @@ -1526,7 +1479,7 @@ bpf_get(struct bpf_d *bd) void bpf_put(struct bpf_d *bd) { - if (atomic_dec_int_nv(&bd->bd_ref) > 0) + if (--bd->bd_ref > 0) return; free(bd->bd_sbuf, M_DEVBUF, 0); @@ -1661,8 +1614,6 @@ 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); @@ -1706,10 +1657,10 @@ bpf_getdltlist(struct bpf_d *d, struct bpf_dltlist *bfl) 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; @@ -1719,9 +1670,11 @@ bpf_setdlt(struct bpf_d *d, u_int dlt) } if (bp == NULL) return (EINVAL); + s = splnet(); bpf_detachd(d); bpf_attachd(d, bp); bpf_resetd(d); + splx(s); return (0); } |