From ed1d8121c2d1b33f2c886c475109ef3f556b90c6 Mon Sep 17 00:00:00 2001 From: jmg Date: Tue, 5 Aug 2003 07:12:49 +0000 Subject: add support for using kqueue to watch bpf sockets. Submitted by: Brian Buchanan of nCircle, Inc. Tested on: i386 and sparc64 --- sys/net/bpf.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++------- sys/net/bpfdesc.h | 6 +++++ 2 files changed, 77 insertions(+), 9 deletions(-) (limited to 'sys/net') diff --git a/sys/net/bpf.c b/sys/net/bpf.c index 0b6f5e8..ff8112c 100644 --- a/sys/net/bpf.c +++ b/sys/net/bpf.c @@ -44,6 +44,7 @@ #include "opt_mac.h" #include "opt_netgraph.h" +#include #include #include #include @@ -58,7 +59,10 @@ #include #include +#include +#include #include +#include #include #include @@ -111,6 +115,8 @@ static void reset_d(struct bpf_d *); static int bpf_setf(struct bpf_d *, struct bpf_program *); 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 d_open_t bpfopen; static d_close_t bpfclose; @@ -118,6 +124,7 @@ 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; #define CDEV_MAJOR 23 static struct cdevsw bpf_cdevsw = { @@ -129,8 +136,11 @@ static struct cdevsw bpf_cdevsw = { .d_poll = bpfpoll, .d_name = "bpf", .d_maj = CDEV_MAJOR, + .d_kqfilter = bpfkqfilter, }; +static struct filterops bpfread_filtops = + { 1, NULL, filt_bpfdetach, filt_bpfread }; static int bpf_movein(uio, linktype, mp, sockp, datlen) @@ -518,6 +528,7 @@ bpf_wakeup(d) pgsigio(&d->bd_sigio, d->bd_sig, 0); selwakeup(&d->bd_sel); + KNOTE(&d->bd_sel.si_note, 0); } static void @@ -1046,15 +1057,7 @@ bpfpoll(dev, events, td) revents = events & (POLLOUT | POLLWRNORM); BPFD_LOCK(d); if (events & (POLLIN | POLLRDNORM)) { - /* - * An imitation of the FIONREAD ioctl code. - * XXX not quite. An exact imitation: - * if (d->b_slen != 0 || - * (d->bd_hbuf != NULL && d->bd_hlen != 0) - */ - if (d->bd_hlen != 0 || - ((d->bd_immediate || d->bd_state == BPF_TIMED_OUT) && - d->bd_slen != 0)) + if (bpf_ready(d)) revents |= events & (POLLIN | POLLRDNORM); else { selrecord(td, &d->bd_sel); @@ -1071,6 +1074,65 @@ bpfpoll(dev, events, td) } /* + * Support for kevent() system call. Register EVFILT_READ filters and + * reject all others. + */ +int +bpfkqfilter(dev, kn) + dev_t dev; + struct knote *kn; +{ + struct bpf_d *d = (struct bpf_d *)dev->si_drv1; + + if (kn->kn_filter != EVFILT_READ) + return (1); + + kn->kn_fop = &bpfread_filtops; + kn->kn_hook = d; + BPFD_LOCK(d); + SLIST_INSERT_HEAD(&d->bd_sel.si_note, kn, kn_selnext); + BPFD_UNLOCK(d); + + return (0); +} + +static void +filt_bpfdetach(kn) + struct knote *kn; +{ + struct bpf_d *d = (struct bpf_d *)kn->kn_hook; + + BPFD_LOCK(d); + SLIST_REMOVE(&d->bd_sel.si_note, kn, knote, kn_selnext); + BPFD_UNLOCK(d); +} + +static int +filt_bpfread(kn, hint) + struct knote *kn; + long hint; +{ + struct bpf_d *d = (struct bpf_d *)kn->kn_hook; + int ready; + + BPFD_LOCK(d); + ready = bpf_ready(d); + if (ready) { + kn->kn_data = d->bd_slen; + if (d->bd_hbuf) + kn->kn_data += d->bd_hlen; + } + else 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 (ready); +} + +/* * Incoming linkage from device drivers. Process the packet pkt, of length * pktlen, which is stored in a contiguous buffer. The packet is parsed * by each process' filter, and if accepted, stashed into the corresponding diff --git a/sys/net/bpfdesc.h b/sys/net/bpfdesc.h index fe059cd..73dcc90 100644 --- a/sys/net/bpfdesc.h +++ b/sys/net/bpfdesc.h @@ -104,6 +104,12 @@ struct bpf_d { #define BPFD_LOCK(bd) mtx_lock(&(bd)->bd_mtx) #define BPFD_UNLOCK(bd) mtx_unlock(&(bd)->bd_mtx) +/* Test whether a BPF is ready for read(). */ +#define bpf_ready(bd) \ + ((bd)->bd_hlen != 0 || \ + (((bd)->bd_immediate || (bd)->bd_state == BPF_TIMED_OUT) && \ + (bd)->bd_slen != 0)) + /* * Descriptor associated with each attached hardware interface. */ -- cgit v1.1