int bpfkqfilter(dev_t dev, struct knote *kn) { struct bpf_d *d; struct klist *klist; int s; d = bpfilter_lookup(minor(dev)); switch (kn->kn_filter) { case EVFILT_READ: klist = &d->bd_sel.si_note; kn->kn_fop = &bpfread_filtops; break; default: return (1); } kn->kn_hook = (caddr_t)((u_long)dev); s = splnet(); SLIST_INSERT_HEAD(klist, kn, kn_selnext); splx(s); return (0); }
/* * Support for poll() system call */ int bpfpoll(dev_t dev, int events, struct proc *p) { struct bpf_d *d; int s, revents; revents = events & (POLLIN | POLLRDNORM); if (revents == 0) return (0); /* only support reading */ /* * An imitation of the FIONREAD ioctl code. */ d = bpfilter_lookup(minor(dev)); s = splnet(); if (d->bd_hlen == 0 && (!d->bd_immediate || d->bd_slen == 0)) { revents = 0; /* no data waiting */ /* * if there's a timeout, mark the time we started waiting. */ if (d->bd_rtout != -1 && d->bd_rdStart == 0) d->bd_rdStart = ticks; selrecord(p, &d->bd_sel); } splx(s); return (revents); }
int filt_bpfread(struct knote *kn, long hint) { dev_t dev = (dev_t)((u_long)kn->kn_hook); struct bpf_d *d; d = bpfilter_lookup(minor(dev)); kn->kn_data = d->bd_hlen; if (d->bd_immediate) kn->kn_data += d->bd_slen; return (kn->kn_data > 0); }
void filt_bpfrdetach(struct knote *kn) { dev_t dev = (dev_t)((u_long)kn->kn_hook); struct bpf_d *d; int s; d = bpfilter_lookup(minor(dev)); s = splnet(); SLIST_REMOVE(&d->bd_sel.si_note, kn, knote, kn_selnext); splx(s); }
/* 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); }
int bpfwrite(dev_t dev, struct uio *uio, int ioflag) { struct bpf_d *d; struct ifnet *ifp; struct mbuf *m; int error, s; struct sockaddr_storage dst; d = bpfilter_lookup(minor(dev)); if (d->bd_bif == 0) return (ENXIO); ifp = d->bd_bif->bif_ifp; if ((ifp->if_flags & IFF_UP) == 0) return (ENETDOWN); if (uio->uio_resid == 0) return (0); error = bpf_movein(uio, d->bd_bif->bif_dlt, &m, (struct sockaddr *)&dst, d->bd_wfilter); if (error) return (error); if (m->m_pkthdr.len > ifp->if_mtu) { m_freem(m); return (EMSGSIZE); } m->m_pkthdr.rdomain = ifp->if_rdomain; if (d->bd_hdrcmplt) dst.ss_family = pseudo_AF_HDRCMPLT; s = splsoftnet(); error = (*ifp->if_output)(ifp, m, (struct sockaddr *)&dst, (struct rtentry *)0); splx(s); /* * The driver frees the mbuf. */ return (error); }
/* * Support for poll() system call */ int bpfpoll(dev_t dev, int events, struct proc *p) { struct bpf_d *d; int s, revents; /* * An imitation of the FIONREAD ioctl code. */ d = bpfilter_lookup(minor(dev)); /* * XXX The USB stack manages it to trigger some race condition * which causes bpfilter_lookup to return NULL when a USB device * gets detached while it is up and has an open bpf handler (e.g. * dhclient). We still should recheck if we can fix the root * cause of this issue. */ if (d == NULL) return (POLLERR); /* Always ready to write data */ revents = events & (POLLOUT | POLLWRNORM); if (events & (POLLIN | POLLRDNORM)) { s = splnet(); if (d->bd_hlen != 0 || (d->bd_immediate && d->bd_slen != 0)) revents |= events & (POLLIN | POLLRDNORM); else { /* * if there's a timeout, mark the time we * started waiting. */ if (d->bd_rtout != -1 && d->bd_rdStart == 0) d->bd_rdStart = ticks; selrecord(p, &d->bd_sel); } splx(s); } return (revents); }
/* ARGSUSED */ int bpfioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) { struct bpf_d *d; int s, error = 0; d = bpfilter_lookup(minor(dev)); if (d->bd_locked && suser(p, 0) != 0) { /* list of allowed ioctls when locked and not root */ switch (cmd) { case BIOCGBLEN: case BIOCFLUSH: case BIOCGDLT: case BIOCGDLTLIST: case BIOCGETIF: case BIOCGRTIMEOUT: case BIOCGSTATS: case BIOCVERSION: case BIOCGRSIG: case BIOCGHDRCMPLT: case FIONREAD: case BIOCLOCK: case BIOCSRTIMEOUT: case BIOCIMMEDIATE: case TIOCGPGRP: case BIOCGDIRFILT: break; default: return (EPERM); } } switch (cmd) { default: error = EINVAL; break; /* * Check for read packet available. */ case FIONREAD: { int n; s = splnet(); n = d->bd_slen; if (d->bd_hbuf) n += d->bd_hlen; splx(s); *(int *)addr = n; break; } /* * Get buffer len [for read()]. */ case BIOCGBLEN: *(u_int *)addr = d->bd_bufsize; break; /* * Set buffer length. */ case BIOCSBLEN: if (d->bd_bif != 0) error = EINVAL; else { u_int size = *(u_int *)addr; if (size > bpf_maxbufsize) *(u_int *)addr = size = bpf_maxbufsize; else if (size < BPF_MINBUFSIZE) *(u_int *)addr = size = BPF_MINBUFSIZE; d->bd_bufsize = size; } break; /* * Set link layer read filter. */ case BIOCSETF: error = bpf_setf(d, (struct bpf_program *)addr, 0); break; /* * Set link layer write filter. */ case BIOCSETWF: error = bpf_setf(d, (struct bpf_program *)addr, 1); break; /* * Flush read packet buffer. */ case BIOCFLUSH: s = splnet(); bpf_reset_d(d); splx(s); break; /* * Put interface into promiscuous mode. */ case BIOCPROMISC: if (d->bd_bif == 0) { /* * 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; } splx(s); break; /* * Get a list of supported device parameters. */ case BIOCGDLTLIST: if (d->bd_bif == NULL) error = EINVAL; else error = bpf_getdltlist(d, (struct bpf_dltlist *)addr); break; /* * Get device parameters. */ case BIOCGDLT: if (d->bd_bif == 0) error = EINVAL; else *(u_int *)addr = d->bd_bif->bif_dlt; break; /* * Set device parameters. */ case BIOCSDLT: if (d->bd_bif == NULL) error = EINVAL; else error = bpf_setdlt(d, *(u_int *)addr); break; /* * Set interface name. */ case BIOCGETIF: if (d->bd_bif == 0) error = EINVAL; else bpf_ifname(d->bd_bif->bif_ifp, (struct ifreq *)addr); break; /* * Set interface. */ case BIOCSETIF: error = bpf_setif(d, (struct ifreq *)addr); break; /* * Set read timeout. */ case BIOCSRTIMEOUT: { struct timeval *tv = (struct timeval *)addr; /* Compute number of ticks. */ d->bd_rtout = tv->tv_sec * hz + tv->tv_usec / tick; if (d->bd_rtout == 0 && tv->tv_usec != 0) d->bd_rtout = 1; break; } /* * Get read timeout. */ case BIOCGRTIMEOUT: { struct timeval *tv = (struct timeval *)addr; tv->tv_sec = d->bd_rtout / hz; tv->tv_usec = (d->bd_rtout % hz) * tick; break; } /* * Get packet stats. */ case BIOCGSTATS: { struct bpf_stat *bs = (struct bpf_stat *)addr; bs->bs_recv = d->bd_rcount; bs->bs_drop = d->bd_dcount; break; } /* * Set immediate mode. */ case BIOCIMMEDIATE: d->bd_immediate = *(u_int *)addr; break; case BIOCVERSION: { struct bpf_version *bv = (struct bpf_version *)addr; bv->bv_major = BPF_MAJOR_VERSION; bv->bv_minor = BPF_MINOR_VERSION; break; } case BIOCGHDRCMPLT: /* get "header already complete" flag */ *(u_int *)addr = d->bd_hdrcmplt; break; case BIOCSHDRCMPLT: /* set "header already complete" flag */ d->bd_hdrcmplt = *(u_int *)addr ? 1 : 0; break; case BIOCLOCK: /* set "locked" flag (no reset) */ d->bd_locked = 1; break; case BIOCGFILDROP: /* get "filter-drop" flag */ *(u_int *)addr = d->bd_fildrop; break; case BIOCSFILDROP: /* set "filter-drop" flag */ d->bd_fildrop = *(u_int *)addr ? 1 : 0; break; case BIOCGDIRFILT: /* get direction filter */ *(u_int *)addr = d->bd_dirfilt; break; case BIOCSDIRFILT: /* set direction filter */ d->bd_dirfilt = (*(u_int *)addr) & (BPF_DIRECTION_IN|BPF_DIRECTION_OUT); break; case FIONBIO: /* Non-blocking I/O */ if (*(int *)addr) d->bd_rtout = -1; else d->bd_rtout = 0; break; case FIOASYNC: /* Send signal on receive packets */ d->bd_async = *(int *)addr; break; /* * N.B. ioctl (FIOSETOWN) and fcntl (F_SETOWN) both end up doing * the equivalent of a TIOCSPGRP and hence end up here. *However* * TIOCSPGRP's arg is a process group if it's positive and a process * id if it's negative. This is exactly the opposite of what the * other two functions want! Therefore there is code in ioctl and * fcntl to negate the arg before calling here. */ case TIOCSPGRP: /* Process or group to send signals to */ d->bd_pgid = *(int *)addr; d->bd_siguid = p->p_cred->p_ruid; d->bd_sigeuid = p->p_ucred->cr_uid; break; case TIOCGPGRP: *(int *)addr = d->bd_pgid; break; case BIOCSRSIG: /* Set receive signal */ { u_int sig; sig = *(u_int *)addr; if (sig >= NSIG) error = EINVAL; else d->bd_sig = sig; break; } case BIOCGRSIG: *(u_int *)addr = d->bd_sig; break; } return (error); }
/* * bpfread - read next chunk of packets from buffers */ int bpfread(dev_t dev, struct uio *uio, int ioflag) { struct bpf_d *d; int error; int s; d = bpfilter_lookup(minor(dev)); if (d->bd_bif == 0) return (ENXIO); /* * Restrict application to use a buffer the same size as * as kernel buffers. */ if (uio->uio_resid != d->bd_bufsize) return (EINVAL); s = splnet(); D_GET(d); /* * bd_rdStart is tagged when we start the read, iff there's a timeout. * we can then figure out when we're done reading. */ if (d->bd_rtout != -1 && d->bd_rdStart == 0) d->bd_rdStart = ticks; else d->bd_rdStart = 0; /* * If the hold buffer is empty, then do a timed sleep, which * ends when the timeout expires or when enough packets * have arrived to fill the store buffer. */ while (d->bd_hbuf == 0) { if (d->bd_bif == NULL) { /* interface is gone */ if (d->bd_slen == 0) { D_PUT(d); splx(s); return (EIO); } ROTATE_BUFFERS(d); break; } if (d->bd_immediate && d->bd_slen != 0) { /* * A packet(s) either arrived since the previous * read or arrived while we were asleep. * Rotate the buffers and return what's here. */ ROTATE_BUFFERS(d); break; } if ((d->bd_rtout != -1) || (d->bd_rdStart + d->bd_rtout) < ticks) { error = tsleep((caddr_t)d, PRINET|PCATCH, "bpf", d->bd_rtout); } else { if (d->bd_rtout == -1) { /* User requested non-blocking I/O */ error = EWOULDBLOCK; } else error = 0; } if (error == EINTR || error == ERESTART) { D_PUT(d); splx(s); return (error); } 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) /* * We filled up the buffer in between * getting the timeout and arriving * here, so we don't need to rotate. */ break; if (d->bd_slen == 0) { D_PUT(d); splx(s); return (0); } ROTATE_BUFFERS(d); break; } } /* * At this point, we know we have something in the hold slot. */ 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. */ error = uiomove(d->bd_hbuf, d->bd_hlen, uio); s = splnet(); d->bd_fbuf = d->bd_hbuf; d->bd_hbuf = 0; d->bd_hlen = 0; D_PUT(d); splx(s); return (error); }