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
This commit is contained in:
Ed Schouten 2008-08-13 15:41:21 +00:00
parent ec109627bd
commit 136600fe59
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=181690
2 changed files with 63 additions and 81 deletions

View File

@ -15,7 +15,7 @@
/* #undef BDEBUG */
/* define if you have a cloning BPF device */
/* #undef HAVE_CLONING_BPF */
#define HAVE_CLONING_BPF 1
/* define if you have the DAG API */
/* #undef HAVE_DAG_API */

View File

@ -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,
@ -584,6 +580,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
@ -634,48 +647,20 @@ bpfopen(struct cdev *dev, int flags, int fmt, struct thread *td)
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_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);
/*
@ -2007,30 +2001,18 @@ bpf_setdlt(struct bpf_d *d, u_int dlt)
return (bp == NULL ? EINVAL : 0);
}
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