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:
parent
ec109627bd
commit
136600fe59
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=181690
@ -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 */
|
||||
|
142
sys/net/bpf.c
142
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,
|
||||
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user