Date: Mon, 29 Jan 2007 13:08:45 GMT From: Robert Watson <rwatson@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 113664 for review Message-ID: <200701291308.l0TD8jDQ016841@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=113664 Change 113664 by rwatson@rwatson_cinnamon on 2007/01/29 13:08:15 Trim a lot of stuff from bpf_buffer.c, mostly the right stuff sort of. Affected files ... .. //depot/projects/zcopybpf/src/sys/net/bpf_buffer.c#2 edit Differences ... ==== //depot/projects/zcopybpf/src/sys/net/bpf_buffer.c#2 (text+ko) ==== @@ -86,373 +86,6 @@ #define PRINET 26 /* interruptible */ /* - * bpf_iflist is a list of BPF interface structures, each corresponding to a - * specific DLT. The same network interface might have several BPF interface - * structures registered by different layers in the stack (i.e., 802.11 - * frames, ethernet frames, etc). - */ -static LIST_HEAD(, bpf_if) bpf_iflist; -static struct mtx bpf_mtx; /* bpf global lock */ -static int bpf_bpfd_cnt; - -static void bpf_allocbufs(struct bpf_d *); -static void bpf_attachd(struct bpf_d *, struct bpf_if *); -static void bpf_detachd(struct bpf_d *); -static void bpf_freed(struct bpf_d *); -static void bpf_mcopy(const void *, void *, size_t); -static int bpf_movein(struct uio *, int, int, - struct mbuf **, struct sockaddr *, struct bpf_insn *); -static int bpf_setif(struct bpf_d *, struct ifreq *); -static void bpf_timed_out(void *); -static __inline void - bpf_wakeup(struct bpf_d *); -static void catchpacket(struct bpf_d *, u_char *, u_int, - u_int, void (*)(const void *, void *, size_t), - struct timeval *); -static void reset_d(struct bpf_d *); -static int bpf_setf(struct bpf_d *, struct bpf_program *, u_long cmd); -static int bpf_getdltlist(struct bpf_d *, struct bpf_dltlist *); -static int bpf_setdlt(struct bpf_d *, u_int); -static void filt_bpfdetach(struct knote *); -static int filt_bpfread(struct knote *, long); -static void bpf_drvinit(void *); -static void bpf_clone(void *, struct ucred *, char *, int, struct cdev **); -static int bpf_stats_sysctl(SYSCTL_HANDLER_ARGS); - -/* - * The default read buffer size is patchable. - */ -SYSCTL_NODE(_net, OID_AUTO, bpf, CTLFLAG_RW, 0, "bpf sysctl"); -static int bpf_bufsize = 4096; -SYSCTL_INT(_net_bpf, OID_AUTO, bufsize, CTLFLAG_RW, - &bpf_bufsize, 0, ""); -static int bpf_maxbufsize = BPF_MAXBUFSIZE; -SYSCTL_INT(_net_bpf, OID_AUTO, maxbufsize, CTLFLAG_RW, - &bpf_maxbufsize, 0, ""); -static int bpf_maxinsns = BPF_MAXINSNS; -SYSCTL_INT(_net_bpf, OID_AUTO, maxinsns, CTLFLAG_RW, - &bpf_maxinsns, 0, "Maximum bpf program instructions"); -SYSCTL_NODE(_net_bpf, OID_AUTO, stats, CTLFLAG_RW, - bpf_stats_sysctl, "bpf statistics portal"); - -static d_open_t bpfopen; -static d_close_t bpfclose; -static d_read_t bpfread; -static d_write_t bpfwrite; -static d_ioctl_t bpfioctl; -static d_poll_t bpfpoll; -static d_kqfilter_t bpfkqfilter; - -static struct cdevsw bpf_cdevsw = { - .d_version = D_VERSION, - .d_flags = D_NEEDGIANT, - .d_open = bpfopen, - .d_close = bpfclose, - .d_read = bpfread, - .d_write = bpfwrite, - .d_ioctl = bpfioctl, - .d_poll = bpfpoll, - .d_name = "bpf", - .d_kqfilter = bpfkqfilter, -}; - -static struct filterops bpfread_filtops = - { 1, NULL, filt_bpfdetach, filt_bpfread }; - -static int -bpf_movein(struct uio *uio, int linktype, int mtu, struct mbuf **mp, - struct sockaddr *sockp, struct bpf_insn *wfilter) -{ - const struct ieee80211_bpf_params *p; - struct mbuf *m; - int error; - int len; - int hlen; - int slen; - - /* - * Build a sockaddr based on the data link layer type. - * We do this at this level because the ethernet header - * is copied directly into the data field of the sockaddr. - * In the case of SLIP, there is no header and the packet - * is forwarded as is. - * Also, we are careful to leave room at the front of the mbuf - * for the link level header. - */ - switch (linktype) { - - case DLT_SLIP: - sockp->sa_family = AF_INET; - hlen = 0; - break; - - case DLT_EN10MB: - sockp->sa_family = AF_UNSPEC; - /* XXX Would MAXLINKHDR be better? */ - hlen = ETHER_HDR_LEN; - break; - - case DLT_FDDI: - sockp->sa_family = AF_IMPLINK; - hlen = 0; - break; - - case DLT_RAW: - sockp->sa_family = AF_UNSPEC; - hlen = 0; - break; - - case DLT_NULL: - /* - * null interface types require a 4 byte pseudo header which - * corresponds to the address family of the packet. - */ - sockp->sa_family = AF_UNSPEC; - hlen = 4; - break; - - case DLT_ATM_RFC1483: - /* - * en atm driver requires 4-byte atm pseudo header. - * though it isn't standard, vpi:vci needs to be - * specified anyway. - */ - sockp->sa_family = AF_UNSPEC; - hlen = 12; /* XXX 4(ATM_PH) + 3(LLC) + 5(SNAP) */ - break; - - case DLT_PPP: - sockp->sa_family = AF_UNSPEC; - hlen = 4; /* This should match PPP_HDRLEN */ - break; - - case DLT_IEEE802_11: /* IEEE 802.11 wireless */ - sockp->sa_family = AF_IEEE80211; - hlen = 0; - break; - - case DLT_IEEE802_11_RADIO: /* IEEE 802.11 wireless w/ phy params */ - sockp->sa_family = AF_IEEE80211; - sockp->sa_len = 12; /* XXX != 0 */ - hlen = sizeof(struct ieee80211_bpf_params); - break; - - default: - return (EIO); - } - - len = uio->uio_resid; - - if (len - hlen > mtu) - return (EMSGSIZE); - - if ((unsigned)len > MCLBYTES) - return (EIO); - - if (len > MHLEN) { - m = m_getcl(M_TRYWAIT, MT_DATA, M_PKTHDR); - } else { - MGETHDR(m, M_TRYWAIT, MT_DATA); - } - if (m == NULL) - return (ENOBUFS); - m->m_pkthdr.len = m->m_len = len; - m->m_pkthdr.rcvif = NULL; - *mp = m; - - if (m->m_len < hlen) { - error = EPERM; - goto bad; - } - - error = uiomove(mtod(m, u_char *), len, uio); - if (error) - goto bad; - - slen = bpf_filter(wfilter, mtod(m, u_char *), len, len); - if (slen == 0) { - error = EPERM; - goto bad; - } - - /* - * Make room for link header, and copy it to sockaddr - */ - if (hlen != 0) { - if (sockp->sa_family == AF_IEEE80211) { - /* - * Collect true length from the parameter header - * NB: sockp is known to be zero'd so if we do a - * short copy unspecified parameters will be - * zero. - * NB: packet may not be aligned after stripping - * bpf params - * XXX check ibp_vers - */ - p = mtod(m, const struct ieee80211_bpf_params *); - hlen = p->ibp_len; - if (hlen > sizeof(sockp->sa_data)) { - error = EINVAL; - goto bad; - } - } - bcopy(m->m_data, sockp->sa_data, hlen); - m->m_pkthdr.len -= hlen; - m->m_len -= hlen; -#if BSD >= 199103 - m->m_data += hlen; /* XXX */ -#else - m->m_off += hlen; -#endif - } - - return (0); -bad: - m_freem(m); - return (error); -} - -/* - * Attach file to the bpf interface, i.e. make d listen on bp. - */ -static void -bpf_attachd(struct bpf_d *d, struct bpf_if *bp) -{ - /* - * 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 - * it will divert packets to bpf. - */ - BPFIF_LOCK(bp); - d->bd_bif = bp; - LIST_INSERT_HEAD(&bp->bif_dlist, d, bd_next); - - bpf_bpfd_cnt++; - BPFIF_UNLOCK(bp); -} - -/* - * Detach a file from its interface. - */ -static void -bpf_detachd(struct bpf_d *d) -{ - int error; - struct bpf_if *bp; - struct ifnet *ifp; - - bp = d->bd_bif; - BPFIF_LOCK(bp); - BPFD_LOCK(d); - ifp = d->bd_bif->bif_ifp; - - /* - * Remove d from the interface's descriptor list. - */ - LIST_REMOVE(d, bd_next); - - bpf_bpfd_cnt--; - d->bd_bif = NULL; - BPFD_UNLOCK(d); - BPFIF_UNLOCK(bp); - - /* - * Check if this descriptor had requested promiscuous mode. - * If so, turn it off. - */ - if (d->bd_promisc) { - d->bd_promisc = 0; - error = ifpromisc(ifp, 0); - if (error != 0 && error != ENXIO) { - /* - * ENXIO can happen if a pccard is unplugged - * Something is really wrong if we were able to put - * the driver into promiscuous mode, but can't - * take it out. - */ - if_printf(bp->bif_ifp, - "bpf_detach: ifpromisc failed (%d)\n", error); - } - } -} - -/* - * Open ethernet device. Returns ENXIO for illegal minor device number, - * EBUSY if file is open by another process. - */ -/* ARGSUSED */ -static int -bpfopen(struct cdev *dev, int flags, int fmt, struct thread *td) -{ - struct bpf_d *d; - - mtx_lock(&bpf_mtx); - d = dev->si_drv1; - /* - * Each minor can be opened by only one process. If the requested - * minor is in use, return EBUSY. - */ - if (d != NULL) { - mtx_unlock(&bpf_mtx); - return (EBUSY); - } - dev->si_drv1 = (struct bpf_d *)~0; /* mark device in use */ - mtx_unlock(&bpf_mtx); - - if ((dev->si_flags & SI_NAMED) == 0) - make_dev(&bpf_cdevsw, minor(dev), UID_ROOT, GID_WHEEL, 0600, - "bpf%d", dev2unit(dev)); - MALLOC(d, struct bpf_d *, sizeof(*d), M_BPF, M_WAITOK | M_ZERO); - dev->si_drv1 = d; - d->bd_bufsize = bpf_bufsize; - d->bd_sig = SIGIO; - d->bd_seesent = 1; - d->bd_pid = td->td_proc->p_pid; -#ifdef MAC - mac_init_bpfdesc(d); - mac_create_bpfdesc(td->td_ucred, d); -#endif - mtx_init(&d->bd_mtx, devtoname(dev), "bpf cdev lock", MTX_DEF); - callout_init(&d->bd_callout, NET_CALLOUT_MPSAFE); - knlist_init(&d->bd_sel.si_note, &d->bd_mtx, NULL, NULL, NULL); - - return (0); -} - -/* - * Close the descriptor by detaching it from its interface, - * deallocating its buffers, and marking it free. - */ -/* ARGSUSED */ -static int -bpfclose(struct cdev *dev, int flags, int fmt, struct thread *td) -{ - struct bpf_d *d = dev->si_drv1; - - BPFD_LOCK(d); - if (d->bd_state == BPF_WAITING) - callout_stop(&d->bd_callout); - d->bd_state = BPF_IDLE; - BPFD_UNLOCK(d); - funsetown(&d->bd_sigio); - mtx_lock(&bpf_mtx); - if (d->bd_bif) - bpf_detachd(d); - mtx_unlock(&bpf_mtx); - selwakeuppri(&d->bd_sel, PRINET); -#ifdef MAC - mac_destroy_bpfdesc(d); -#endif /* MAC */ - knlist_destroy(&d->bd_sel.si_note); - bpf_freed(d); - dev->si_drv1 = NULL; - free(d, M_BPF); - - return (0); -} - - -/* * Rotate the packet buffers in descriptor d. Move the store buffer * into the hold slot, and the free buffer into the store slot. * Zero the length of the new store buffer. @@ -565,701 +198,7 @@ return (error); } - -/* - * If there are processes sleeping on this descriptor, wake them up. - */ -static __inline void -bpf_wakeup(struct bpf_d *d) -{ - - BPFD_LOCK_ASSERT(d); - if (d->bd_state == BPF_WAITING) { - callout_stop(&d->bd_callout); - d->bd_state = BPF_IDLE; - } - wakeup(d); - if (d->bd_async && d->bd_sig && d->bd_sigio) - pgsigio(&d->bd_sigio, d->bd_sig, 0); - - selwakeuppri(&d->bd_sel, PRINET); - KNOTE_LOCKED(&d->bd_sel.si_note, 0); -} - -static void -bpf_timed_out(void *arg) -{ - struct bpf_d *d = (struct bpf_d *)arg; - - BPFD_LOCK(d); - if (d->bd_state == BPF_WAITING) { - d->bd_state = BPF_TIMED_OUT; - if (d->bd_slen != 0) - bpf_wakeup(d); - } - BPFD_UNLOCK(d); -} - -static int -bpfwrite(struct cdev *dev, struct uio *uio, int ioflag) -{ - struct bpf_d *d = dev->si_drv1; - struct ifnet *ifp; - struct mbuf *m; - int error; - struct sockaddr dst; - - if (d->bd_bif == NULL) - return (ENXIO); - - ifp = d->bd_bif->bif_ifp; - - if ((ifp->if_flags & IFF_UP) == 0) - return (ENETDOWN); - - if (uio->uio_resid == 0) - return (0); - - bzero(&dst, sizeof(dst)); - error = bpf_movein(uio, (int)d->bd_bif->bif_dlt, ifp->if_mtu, - &m, &dst, d->bd_wfilter); - if (error) - return (error); - - if (d->bd_hdrcmplt) - dst.sa_family = pseudo_AF_HDRCMPLT; - -#ifdef MAC - BPFD_LOCK(d); - mac_create_mbuf_from_bpfdesc(d, m); - BPFD_UNLOCK(d); -#endif - NET_LOCK_GIANT(); - error = (*ifp->if_output)(ifp, m, &dst, NULL); - NET_UNLOCK_GIANT(); - /* - * The driver frees the mbuf. - */ - return (error); -} - -/* - * Reset a descriptor by flushing its packet buffer and clearing the - * receive and drop counts. - */ -static void -reset_d(struct bpf_d *d) -{ - - mtx_assert(&d->bd_mtx, MA_OWNED); - if (d->bd_hbuf) { - /* Free the hold buffer. */ - d->bd_fbuf = d->bd_hbuf; - d->bd_hbuf = NULL; - } - d->bd_slen = 0; - d->bd_hlen = 0; - d->bd_rcount = 0; - d->bd_dcount = 0; - d->bd_fcount = 0; -} - -/* - * FIONREAD Check for read packet available. - * SIOCGIFADDR Get interface address - convenient hook to driver. - * BIOCGBLEN Get buffer len [for read()]. - * BIOCSETF Set ethernet read filter. - * BIOCSETWF Set ethernet write filter. - * BIOCFLUSH Flush read packet buffer. - * BIOCPROMISC Put interface into promiscuous mode. - * BIOCGDLT Get link layer type. - * BIOCGETIF Get interface name. - * BIOCSETIF Set interface. - * BIOCSRTIMEOUT Set read timeout. - * BIOCGRTIMEOUT Get read timeout. - * BIOCGSTATS Get packet stats. - * BIOCIMMEDIATE Set immediate mode. - * BIOCVERSION Get filter language version. - * BIOCGHDRCMPLT Get "header already complete" flag - * BIOCSHDRCMPLT Set "header already complete" flag - * BIOCGSEESENT Get "see packets sent" flag - * BIOCSSEESENT Set "see packets sent" flag - * BIOCLOCK Set "locked" flag - */ -/* ARGSUSED */ -static int -bpfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, - struct thread *td) -{ - struct bpf_d *d = dev->si_drv1; - int error = 0; - - /* - * Refresh PID associated with this descriptor. - */ - BPFD_LOCK(d); - d->bd_pid = td->td_proc->p_pid; - if (d->bd_state == BPF_WAITING) - callout_stop(&d->bd_callout); - d->bd_state = BPF_IDLE; - BPFD_UNLOCK(d); - - if (d->bd_locked == 1) { - 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: - break; - default: - return (EPERM); - } - } - switch (cmd) { - - default: - error = EINVAL; - break; - - /* - * Check for read packet available. - */ - case FIONREAD: - { - int n; - - BPFD_LOCK(d); - n = d->bd_slen; - if (d->bd_hbuf) - n += d->bd_hlen; - BPFD_UNLOCK(d); - - *(int *)addr = n; - break; - } - - case SIOCGIFADDR: - { - struct ifnet *ifp; - - if (d->bd_bif == NULL) - error = EINVAL; - else { - ifp = d->bd_bif->bif_ifp; - error = (*ifp->if_ioctl)(ifp, cmd, addr); - } - break; - } - - /* - * Get buffer len [for read()]. - */ - case BIOCGBLEN: - *(u_int *)addr = d->bd_bufsize; - break; - - /* - * Set buffer length. - */ - case BIOCSBLEN: - if (d->bd_bif != NULL) - 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: - case BIOCSETWF: - error = bpf_setf(d, (struct bpf_program *)addr, cmd); - break; - - /* - * Flush read packet buffer. - */ - case BIOCFLUSH: - BPFD_LOCK(d); - reset_d(d); - BPFD_UNLOCK(d); - break; - - /* - * Put interface into promiscuous mode. - */ - case BIOCPROMISC: - if (d->bd_bif == NULL) { - /* - * No interface attached yet. - */ - error = EINVAL; - break; - } - if (d->bd_promisc == 0) { - mtx_lock(&Giant); - error = ifpromisc(d->bd_bif->bif_ifp, 1); - mtx_unlock(&Giant); - if (error == 0) - d->bd_promisc = 1; - } - break; - - /* - * Get current data link type. - */ - case BIOCGDLT: - if (d->bd_bif == NULL) - error = EINVAL; - else - *(u_int *)addr = d->bd_bif->bif_dlt; - break; - - /* - * Get a list of supported data link types. - */ - case BIOCGDLTLIST: - if (d->bd_bif == NULL) - error = EINVAL; - else - error = bpf_getdltlist(d, (struct bpf_dltlist *)addr); - break; - - /* - * Set data link type. - */ - case BIOCSDLT: - if (d->bd_bif == NULL) - error = EINVAL; - else - error = bpf_setdlt(d, *(u_int *)addr); - break; - - /* - * Get interface name. - */ - case BIOCGETIF: - if (d->bd_bif == NULL) - error = EINVAL; - else { - struct ifnet *const ifp = d->bd_bif->bif_ifp; - struct ifreq *const ifr = (struct ifreq *)addr; - - strlcpy(ifr->ifr_name, ifp->if_xname, - sizeof(ifr->ifr_name)); - } - break; - - /* - * Set interface. - */ - case BIOCSETIF: - error = bpf_setif(d, (struct ifreq *)addr); - break; - - /* - * Set read timeout. - */ - case BIOCSRTIMEOUT: - { - struct timeval *tv = (struct timeval *)addr; - - /* - * Subtract 1 tick from tvtohz() since this isn't - * a one-shot timer. - */ - if ((error = itimerfix(tv)) == 0) - d->bd_rtout = tvtohz(tv) - 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; - } - - /* - * Get "header already complete" flag - */ - case BIOCGHDRCMPLT: - *(u_int *)addr = d->bd_hdrcmplt; - break; - - case BIOCLOCK: - d->bd_locked = 1; - break; - /* - * Set "header already complete" flag - */ - case BIOCSHDRCMPLT: - d->bd_hdrcmplt = *(u_int *)addr ? 1 : 0; - break; - - /* - * Get "see sent packets" flag - */ - case BIOCGSEESENT: - *(u_int *)addr = d->bd_seesent; - break; - - /* - * Set "see sent packets" flag - */ - case BIOCSSEESENT: - d->bd_seesent = *(u_int *)addr; - break; - - case FIONBIO: /* Non-blocking I/O */ - break; - - case FIOASYNC: /* Send signal on receive packets */ - d->bd_async = *(int *)addr; - break; - - case FIOSETOWN: - error = fsetown(*(int *)addr, &d->bd_sigio); - break; - - case FIOGETOWN: - *(int *)addr = fgetown(&d->bd_sigio); - break; - - /* This is deprecated, FIOSETOWN should be used instead. */ - case TIOCSPGRP: - error = fsetown(-(*(int *)addr), &d->bd_sigio); - break; - - /* This is deprecated, FIOGETOWN should be used instead. */ - case TIOCGPGRP: - *(int *)addr = -fgetown(&d->bd_sigio); - 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); -} - -/* - * Set d's packet filter program to fp. If this file already has a filter, - * free it and replace it. Returns EINVAL for bogus requests. - */ -static int -bpf_setf(struct bpf_d *d, struct bpf_program *fp, u_long cmd) -{ - struct bpf_insn *fcode, *old; - u_int wfilter, flen, size; -#ifdef BPF_JITTER - bpf_jit_filter *ofunc; -#endif - - if (cmd == BIOCSETWF) { - old = d->bd_wfilter; - wfilter = 1; -#ifdef BPF_JITTER - ofunc = NULL; -#endif - } else { - wfilter = 0; - old = d->bd_rfilter; -#ifdef BPF_JITTER - ofunc = d->bd_bfilter; -#endif - } - if (fp->bf_insns == NULL) { - if (fp->bf_len != 0) - return (EINVAL); - BPFD_LOCK(d); - if (wfilter) - d->bd_wfilter = NULL; - else { - d->bd_rfilter = NULL; -#ifdef BPF_JITTER - d->bd_bfilter = NULL; -#endif - } - reset_d(d); - BPFD_UNLOCK(d); - if (old != NULL) - free((caddr_t)old, M_BPF); -#ifdef BPF_JITTER - if (ofunc != NULL) - bpf_destroy_jit_filter(ofunc); -#endif - return (0); - } - flen = fp->bf_len; - if (flen > bpf_maxinsns) - return (EINVAL); - - size = flen * sizeof(*fp->bf_insns); - fcode = (struct bpf_insn *)malloc(size, M_BPF, M_WAITOK); - if (copyin((caddr_t)fp->bf_insns, (caddr_t)fcode, size) == 0 && - bpf_validate(fcode, (int)flen)) { - BPFD_LOCK(d); - if (wfilter) - d->bd_wfilter = fcode; - else { - d->bd_rfilter = fcode; -#ifdef BPF_JITTER - d->bd_bfilter = bpf_jitter(fcode, flen); -#endif - } - reset_d(d); - BPFD_UNLOCK(d); - if (old != NULL) - free((caddr_t)old, M_BPF); -#ifdef BPF_JITTER - if (ofunc != NULL) - bpf_destroy_jit_filter(ofunc); -#endif - - return (0); - } - free((caddr_t)fcode, M_BPF); - return (EINVAL); -} - -/* - * 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, struct ifreq *ifr) -{ - struct bpf_if *bp; - struct ifnet *theywant; - - theywant = ifunit(ifr->ifr_name); - if (theywant == NULL || theywant->if_bpf == NULL) - return (ENXIO); - - bp = theywant->if_bpf; - /* - * 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); - if (bp != d->bd_bif) { - if (d->bd_bif) - /* - * Detach if attached to something else. - */ - bpf_detachd(d); - - bpf_attachd(d, bp); - } - BPFD_LOCK(d); - reset_d(d); - BPFD_UNLOCK(d); - return (0); -} - -/* - * Support for select() and poll() system calls - * - * Return true iff the specific operation will not block indefinitely. - * Otherwise, return false but make a note that a selwakeup() must be done. - */ -static int -bpfpoll(struct cdev *dev, int events, struct thread *td) -{ - struct bpf_d *d; - int revents; - - d = dev->si_drv1; - if (d->bd_bif == NULL) - return (ENXIO); - - /* - * Refresh PID associated with this descriptor. - */ - revents = events & (POLLOUT | POLLWRNORM); - BPFD_LOCK(d); - d->bd_pid = td->td_proc->p_pid; - if (events & (POLLIN | POLLRDNORM)) { - if (bpf_ready(d)) - revents |= events & (POLLIN | POLLRDNORM); - else { - selrecord(td, &d->bd_sel); - /* Start the read timeout if necessary. */ - if (d->bd_rtout > 0 && d->bd_state == BPF_IDLE) { - callout_reset(&d->bd_callout, d->bd_rtout, - bpf_timed_out, d); - d->bd_state = BPF_WAITING; - } - } - } - BPFD_UNLOCK(d); - return (revents); -} - -/* - * Support for kevent() system call. Register EVFILT_READ filters and - * reject all others. - */ -int -bpfkqfilter(struct cdev *dev, struct knote *kn) -{ - struct bpf_d *d = (struct bpf_d *)dev->si_drv1; - - if (kn->kn_filter != EVFILT_READ) - return (1); - >>> TRUNCATED FOR MAIL (1000 lines) <<<
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200701291308.l0TD8jDQ016841>