summaryrefslogtreecommitdiffstats
path: root/sys/net
diff options
context:
space:
mode:
authored <ed@FreeBSD.org>2008-08-13 15:41:21 +0000
committered <ed@FreeBSD.org>2008-08-13 15:41:21 +0000
commitc392c350356d4e10651d40ed2906f1c9f50d789e (patch)
tree1e922da37e301531803c58fc0415966f29b6a5bd /sys/net
parent1a091133592a52542225ae632b0ecdfa2b068da7 (diff)
downloadFreeBSD-src-c392c350356d4e10651d40ed2906f1c9f50d789e.zip
FreeBSD-src-c392c350356d4e10651d40ed2906f1c9f50d789e.tar.gz
Change bpf(4) to use the cdevpriv API.
Right now the bpf(4) driver uses the cloning API to generate /dev/bpf%u. When an application such as tcpdump needs a BPF, it opens /dev/bpf0, /dev/bpf1, etc. until it opens the first available device node. We used this approach, because our devfs implementation didn't allow per-descriptor data. Now that we can, make it use devfs_get_cdevpriv() to obtain the private data. To remain compatible with the existing implementation, add a symlink from /dev/bpf0 to /dev/bpf. I've already changed libpcap to compile with HAVE_CLONING_BPF, which makes it use /dev/bpf. There may be other applications in the base system (dhclient) that use the loop to obtain a valid bpf. Discussed on: src-committers Approved by: csjp
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/bpf.c142
1 files changed, 62 insertions, 80 deletions
diff --git a/sys/net/bpf.c b/sys/net/bpf.c
index f9f3b7d..946e23b 100644
--- a/sys/net/bpf.c
+++ b/sys/net/bpf.c
@@ -117,7 +117,6 @@ 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);
SYSCTL_NODE(_net, OID_AUTO, bpf, CTLFLAG_RW, 0, "bpf sysctl");
@@ -131,7 +130,6 @@ 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;
@@ -140,9 +138,7 @@ static d_kqfilter_t bpfkqfilter;
static struct cdevsw bpf_cdevsw = {
.d_version = D_VERSION,
- .d_flags = D_TRACKCLOSE,
.d_open = bpfopen,
- .d_close = bpfclose,
.d_read = bpfread,
.d_write = bpfwrite,
.d_ioctl = bpfioctl,
@@ -585,6 +581,34 @@ bpf_detachd(struct bpf_d *d)
}
/*
+ * Close the descriptor by detaching it from its interface,
+ * deallocating its buffers, and marking it free.
+ */
+static void
+bpf_dtor(void *data)
+{
+ struct bpf_d *d = data;
+
+ 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_bpfdesc_destroy(d);
+#endif /* MAC */
+ knlist_destroy(&d->bd_sel.si_note);
+ bpf_freed(d);
+ free(d, M_BPF);
+}
+
+/*
* Open ethernet device. Returns ENXIO for illegal minor device number,
* EBUSY if file is open by another process.
*/
@@ -593,25 +617,14 @@ static int
bpfopen(struct cdev *dev, int flags, int fmt, struct thread *td)
{
struct bpf_d *d;
+ int error;
- 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;
+ error = devfs_set_cdevpriv(d, bpf_dtor);
+ if (error != 0) {
+ free(d, M_BPF);
+ return (error);
+ }
/*
* For historical reasons, perform a one-time initialization call to
@@ -635,47 +648,19 @@ bpfopen(struct cdev *dev, int flags, int fmt, struct thread *td)
}
/*
- * 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_bpfdesc_destroy(d);
-#endif /* MAC */
- knlist_destroy(&d->bd_sel.si_note);
- bpf_freed(d);
- dev->si_drv1 = NULL;
- free(d, M_BPF);
-
- return (0);
-}
-
-/*
* bpfread - read next chunk of packets from buffers
*/
static int
bpfread(struct cdev *dev, struct uio *uio, int ioflag)
{
- struct bpf_d *d = dev->si_drv1;
+ struct bpf_d *d;
int timed_out;
int error;
+ error = devfs_get_cdevpriv((void **)&d);
+ if (error != 0)
+ return (error);
+
/*
* Restrict application to use a buffer the same size as
* as kernel buffers.
@@ -829,12 +814,16 @@ bpf_ready(struct bpf_d *d)
static int
bpfwrite(struct cdev *dev, struct uio *uio, int ioflag)
{
- struct bpf_d *d = dev->si_drv1;
+ struct bpf_d *d;
struct ifnet *ifp;
struct mbuf *m, *mc;
struct sockaddr dst;
int error, hlen;
+ error = devfs_get_cdevpriv((void **)&d);
+ if (error != 0)
+ return (error);
+
d->bd_pid = curthread->td_proc->p_pid;
d->bd_wcount++;
if (d->bd_bif == NULL) {
@@ -963,8 +952,12 @@ 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;
+ struct bpf_d *d;
+ int error;
+
+ error = devfs_get_cdevpriv((void **)&d);
+ if (error != 0)
+ return (error);
/*
* Refresh PID associated with this descriptor.
@@ -1482,9 +1475,9 @@ 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);
+ if (devfs_get_cdevpriv((void **)&d) != 0 || d->bd_bif == NULL)
+ return (events &
+ (POLLHUP|POLLIN|POLLRDNORM|POLLOUT|POLLWRNORM));
/*
* Refresh PID associated with this descriptor.
@@ -1516,9 +1509,10 @@ bpfpoll(struct cdev *dev, int events, struct thread *td)
int
bpfkqfilter(struct cdev *dev, struct knote *kn)
{
- struct bpf_d *d = (struct bpf_d *)dev->si_drv1;
+ struct bpf_d *d;
- if (kn->kn_filter != EVFILT_READ)
+ if (devfs_get_cdevpriv((void **)&d) != 0 ||
+ kn->kn_filter != EVFILT_READ)
return (1);
/*
@@ -2008,29 +2002,17 @@ bpf_setdlt(struct bpf_d *d, u_int dlt)
}
static void
-bpf_clone(void *arg, struct ucred *cred, char *name, int namelen,
- struct cdev **dev)
-{
- int u;
-
- if (*dev != NULL)
- return;
- if (dev_stdclone(name, NULL, "bpf", &u) != 1)
- return;
- *dev = make_dev(&bpf_cdevsw, unit2minor(u), UID_ROOT, GID_WHEEL, 0600,
- "bpf%d", u);
- dev_ref(*dev);
- (*dev)->si_flags |= SI_CHEAPCLONE;
- return;
-}
-
-static void
bpf_drvinit(void *unused)
{
+ struct cdev *dev;
mtx_init(&bpf_mtx, "bpf global lock", NULL, MTX_DEF);
LIST_INIT(&bpf_iflist);
- EVENTHANDLER_REGISTER(dev_clone, bpf_clone, 0, 1000);
+
+ dev = make_dev(&bpf_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "bpf");
+ /* For compatibility */
+ make_dev_alias(dev, "bpf0");
+
}
static void
OpenPOWER on IntegriCloud