Device megapatch 2/6:

This commit adds a couple of functions for pseudodrivers to use for
implementing cloning in a manner we will be able to lock down (shortly).

Basically what happens is that pseudo drivers get a way to ask for
"give me the dev_t with this unit number" or alternatively "give
me a dev_t with the lowest guaranteed free unit number" (there is
unfortunately a lot of non-POLA in the exact numeric value of this
number, just live with it for now)

Managing the unit number space this way removes the need to use
rman(9) to do so in the drivers this greatly simplifies the code in
the drivers because even using rman(9) they still needed to manage
their dev_t's anyway.

I have taken the if_tun, if_tap, snp and nmdm drivers through the
mill, partly because they (ab)used makedev(), but mostly because
together they represent three different problems for device-cloning:

if_tun and snp is the plain case: just give me a device.

if_tap has two kinds of devices, with a flag for device type.

nmdm has paired devices (ala pty) can you can clone either of them.
This commit is contained in:
phk 2004-02-21 20:29:52 +00:00
parent df397dedea
commit 32b7c9a433
10 changed files with 341 additions and 397 deletions

View File

@ -23,7 +23,6 @@
5 *pts pseudo tty "tty" half
6 *ptc pseudo tty "master" half
7 *log system log
18 *nmdm nullmodem back-to-back tty ports
19 *tw X-10 power interface
22 *fd (/dev/stdin etc)
30 *snd sound driver system
@ -37,7 +36,6 @@
42 *cx Cronyx/Sigma serial adapter
43 vn vnode "disk" device (retired)
46 - -
52 *tun IP tunnel device
54 OLDnic ISDN system
58 - Was dgb: Digiboard PC/Xe
62 worm SCSI "worm type"
@ -77,7 +75,6 @@
139 wanrouter Sangoma Technologies Inc. (al.feldman@sangoma.com)
141 pcdmx PCDMX theatre lighting controller
142 skip SKIP port (security/skip) control device
149 *tap Ethernet tunneling device <myevmenkin@att.com>
154 *asr Adaptec SCSI RAID <msmith@freebsd.org>
155 phone Quicknet PhoneJACK and LineJACK cards for VoIP <roger>
159 *ata ATA control device

View File

@ -63,8 +63,7 @@ MALLOC_DEFINE(M_NLMDM, "nullmodem", "nullmodem data structures");
static void nmdmstart(struct tty *tp);
static void nmdmstop(struct tty *tp, int rw);
static void wakeup_other(struct tty *tp, int flag);
static void nmdminit(int);
static int nmdmshutdown(void);
static void nmdminit(dev_t dev);
static d_open_t nmdmopen;
static d_close_t nmdmclose;
@ -72,7 +71,6 @@ static d_read_t nmdmread;
static d_write_t nmdmwrite;
static d_ioctl_t nmdmioctl;
#define CDEV_MAJOR 18
static struct cdevsw nmdm_cdevsw = {
.d_open = nmdmopen,
.d_close = nmdmclose,
@ -80,14 +78,14 @@ static struct cdevsw nmdm_cdevsw = {
.d_write = nmdmwrite,
.d_ioctl = nmdmioctl,
.d_poll = ttypoll,
.d_name = "pts",
.d_maj = CDEV_MAJOR,
.d_flags = D_TTY,
.d_name = "nmdm",
.d_flags = D_TTY | D_PSEUDO,
};
#define BUFSIZ 100 /* Chunk size iomoved to/from user */
#define NMDM_MAX_NUM 128 /* Artificially limit # devices. */
#define PF_STOPPED 0x10 /* user told stopped */
#define BFLAG CLONE_FLAG0
struct softpart {
struct tty nm_tty;
@ -97,11 +95,61 @@ struct softpart {
};
struct nm_softc {
int pt_flags;
struct softpart part1, part2;
struct prison *pt_prison;
TAILQ_ENTRY(nm_softc) pt_list;
int pt_flags;
struct softpart part1, part2;
struct prison *pt_prison;
};
static struct clonedevs *nmdmclones;
static TAILQ_HEAD(,nm_softc) nmdmhead = TAILQ_HEAD_INITIALIZER(nmdmhead);
static void
nmdm_clone(void *arg, char *name, int nameen, dev_t *dev)
{
int i, unit;
char *p;
dev_t d1, d2;
if (*dev != NODEV)
return;
if (strcmp(name, "nmdm") == 0) {
p = NULL;
unit = -1;
} else {
i = dev_stdclone(name, &p, "nmdm", &unit);
if (i == 0)
return;
if (p[0] != '\0' && p[0] != 'A' && p[0] != 'B')
return;
else if (p[0] != '\0' && p[1] != '\0')
return;
}
i = clone_create(&nmdmclones, &nmdm_cdevsw, &unit, &d1, 0);
if (i) {
d1 = make_dev(&nmdm_cdevsw, unit2minor(unit),
0, 0, 0666, "nmdm%dA", unit);
if (d1 == NULL)
return;
d2 = make_dev(&nmdm_cdevsw, unit2minor(unit) | BFLAG,
0, 0, 0666, "nmdm%dB", unit);
if (d2 == NULL) {
destroy_dev(d1);
return;
}
d2->si_drv2 = d1;
d1->si_drv2 = d2;
dev_depends(d1, d2);
dev_depends(d2, d1);
d1->si_flags |= SI_CHEAPCLONE;
d2->si_flags |= SI_CHEAPCLONE;
}
if (p != NULL && p[0] == 'B')
*dev = d1->si_drv2;
else
*dev = d1;
}
static void
nmdm_crossover(struct nm_softc *pti,
struct softpart *ourpart,
@ -123,24 +171,22 @@ do { \
* This function creates and initializes a pair of ttys.
*/
static void
nmdminit(n)
int n;
nmdminit(dev_t dev1)
{
dev_t dev1, dev2;
dev_t dev2;
struct nm_softc *pt;
/* For now we only map the lower 8 bits of the minor */
if (n & ~0xff)
return;
dev2 = dev1->si_drv2;
pt = malloc(sizeof(*pt), M_NLMDM, M_WAITOK);
bzero(pt, sizeof(*pt));
pt->part1.dev = dev1 = make_dev(&nmdm_cdevsw, n+n,
0, 0, 0666, "nmdm%dA", n);
pt->part2.dev = dev2 = make_dev(&nmdm_cdevsw, n+n+1,
0, 0, 0666, "nmdm%dB", n);
dev1->si_flags &= ~SI_CHEAPCLONE;
dev2->si_flags &= ~SI_CHEAPCLONE;
pt = malloc(sizeof(*pt), M_NLMDM, M_WAITOK | M_ZERO);
TAILQ_INSERT_TAIL(&nmdmhead, pt, pt_list);
dev1->si_drv1 = dev2->si_drv1 = pt;
pt->part1.dev = dev1;
pt->part2.dev = dev2;
dev1->si_tty = &pt->part1.nm_tty;
dev2->si_tty = &pt->part2.nm_tty;
ttyregister(&pt->part1.nm_tty);
@ -148,9 +194,9 @@ nmdminit(n)
pt->part1.nm_tty.t_oproc = nmdmstart;
pt->part2.nm_tty.t_oproc = nmdmstart;
pt->part1.nm_tty.t_stop = nmdmstop;
pt->part2.nm_tty.t_stop = nmdmstop;
pt->part2.nm_tty.t_dev = dev1;
pt->part1.nm_tty.t_dev = dev2;
pt->part2.nm_tty.t_stop = nmdmstop;
}
/*
@ -161,39 +207,14 @@ nmdmopen(dev_t dev, int flag, int devtype, struct thread *td)
{
register struct tty *tp, *tp2;
int error;
int minr;
dev_t nextdev;
struct nm_softc *pti;
int is_b;
int pair;
struct softpart *ourpart, *otherpart;
/*
* XXX: Gross hack for DEVFS:
* If we openned this device, ensure we have the
* next one too, so people can open it.
*/
minr = dev2unit(dev);
pair = minr >> 1;
is_b = minr & 1;
if (pair < (NMDM_MAX_NUM - 1)) {
nextdev = makedev(major(dev), minr + 2);
if (!nextdev->si_drv1) {
nmdminit(pair + 1);
}
} else { /* Limit ourselves to 128 of them for now */
if (pair > (NMDM_MAX_NUM - 1))
return (ENXIO);
}
if (!dev->si_drv1)
nmdminit(pair);
if (!dev->si_drv1)
return(ENXIO);
if (dev->si_drv1 == NULL)
nmdminit(dev);
pti = dev->si_drv1;
if (is_b)
if (minor(dev) & BFLAG)
tp = &pti->part2.nm_tty;
else
tp = &pti->part1.nm_tty;
@ -567,20 +588,27 @@ nmdm_crossover(struct nm_softc *pti, struct softpart *ourpart,
static int
nmdm_modevent(module_t mod, int type, void *data)
{
static eventhandler_tag tag;
struct nm_softc *pt, *tpt;
int error = 0;
switch(type) {
case MOD_LOAD: /* start with 4 of them */
nmdminit(0);
nmdminit(1);
nmdminit(2);
nmdminit(3);
case MOD_LOAD:
tag = EVENTHANDLER_REGISTER(dev_clone, nmdm_clone, 0, 1000);
if (tag == NULL)
return (ENOMEM);
break;
case MOD_SHUTDOWN:
/* FALLTHROUGH */
case MOD_UNLOAD:
nmdmshutdown();
EVENTHANDLER_DEREGISTER(dev_clone, tag);
TAILQ_FOREACH_SAFE(pt, &nmdmhead, pt_list, tpt) {
destroy_dev(pt->part1.dev);
TAILQ_REMOVE(&nmdmhead, pt, pt_list);
free(pt, M_NLMDM);
}
clone_cleanup(&nmdmclones);
break;
default:
error = EOPNOTSUPP;
@ -588,31 +616,4 @@ nmdm_modevent(module_t mod, int type, void *data)
return (error);
}
/*
* Handle teardown of device
*/
static int
nmdmshutdown(void)
{
int i;
dev_t nextdev1;
dev_t nextdev2;
void * ptr1;
for(i = 0;( i < NMDM_MAX_NUM) ;i++) {
nextdev1 = makedev(CDEV_MAJOR, (i+i) );
nextdev2 = makedev(CDEV_MAJOR, (i+i) + 1);
ptr1 = nextdev1->si_drv1;
if (ptr1) {
destroy_dev(nextdev1);
destroy_dev(nextdev2);
free(ptr1, M_NLMDM);
} else {
freedev(nextdev1);
freedev(nextdev2);
}
}
return(0);
}
DEV_MODULE(nmdm, nmdm_modevent, NULL);

View File

@ -38,7 +38,6 @@ static d_write_t snpwrite;
static d_ioctl_t snpioctl;
static d_poll_t snppoll;
#define CDEV_MAJOR 53
static struct cdevsw snp_cdevsw = {
.d_open = snpopen,
.d_close = snpclose,
@ -47,7 +46,7 @@ static struct cdevsw snp_cdevsw = {
.d_ioctl = snpioctl,
.d_poll = snppoll,
.d_name = "snp",
.d_maj = CDEV_MAJOR,
.d_flags = D_PSEUDO,
};
static struct linesw snpdisc = {
@ -101,10 +100,9 @@ static MALLOC_DEFINE(M_SNP, "snp", "Snoop device data");
* module load time.
*/
static int snooplinedisc;
static udev_t snpbasedev = NOUDEV;
static LIST_HEAD(, snoop) snp_sclist = LIST_HEAD_INITIALIZER(&snp_sclist);
static struct clonedevs *snpclones;
static struct tty *snpdevtotty(dev_t dev);
static void snp_clone(void *arg, char *name,
@ -384,9 +382,7 @@ snpopen(dev, flag, mode, td)
struct snoop *snp;
if (dev->si_drv1 == NULL) {
if (!(dev->si_flags & SI_NAMED))
make_dev(&snp_cdevsw, minor(dev), UID_ROOT, GID_WHEEL,
0600, "snp%d", dev2unit(dev));
dev->si_flags &= ~SI_CHEAPCLONE;
dev->si_drv1 = snp = malloc(sizeof(*snp), M_SNP,
M_WAITOK | M_ZERO);
snp->snp_unit = dev2unit(dev);
@ -466,6 +462,7 @@ snpclose(dev, flags, fmt, td)
free(snp->snp_buf, M_SNP);
snp->snp_flags &= ~SNOOP_OPEN;
dev->si_drv1 = NULL;
destroy_dev(dev);
return (snp_detach(snp));
}
@ -608,20 +605,18 @@ snp_clone(arg, name, namelen, dev)
int namelen;
dev_t *dev;
{
int u;
int u, i;
if (*dev != NODEV)
return;
if (dev_stdclone(name, NULL, "snp", &u) != 1)
return;
*dev = make_dev(&snp_cdevsw, unit2minor(u), UID_ROOT, GID_WHEEL, 0600,
"snp%d", u);
if (snpbasedev == NOUDEV)
snpbasedev = (*dev)->si_udev;
else {
i = clone_create(&snpclones, &snp_cdevsw, &u, dev, 0);
if (i)
*dev = make_dev(&snp_cdevsw, unit2minor(u),
UID_ROOT, GID_WHEEL, 0600, "snp%d", u);
if (*dev != NULL)
(*dev)->si_flags |= SI_CHEAPCLONE;
dev_depends(udev2dev(snpbasedev, 0), *dev);
}
}
static int
@ -642,8 +637,7 @@ snp_modevent(mod, type, data)
if (!LIST_EMPTY(&snp_sclist))
return (EBUSY);
EVENTHANDLER_DEREGISTER(dev_clone, eh_tag);
if (snpbasedev != NOUDEV)
destroy_dev(udev2dev(snpbasedev, 0));
clone_cleanup(&snpclones);
ldisc_deregister(snooplinedisc);
break;
default:
@ -657,4 +651,4 @@ static moduledata_t snp_mod = {
snp_modevent,
NULL
};
DECLARE_MODULE(snp, snp_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE + CDEV_MAJOR);
DECLARE_MODULE(snp, snp_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);

View File

@ -324,10 +324,22 @@ makeudev(int x, int y)
}
static void
prep_cdevsw(struct cdevsw *devsw)
find_major(struct cdevsw *devsw)
{
int i;
for (i = NUMCDEVSW - 1; i > 0; i--)
if (reserved_majors[i] != i)
break;
KASSERT(i > 0, ("Out of major numbers (%s)", devsw->d_name));
devsw->d_maj = i;
reserved_majors[i] = i;
}
static void
prep_cdevsw(struct cdevsw *devsw)
{
if (devsw->d_open == NULL) devsw->d_open = null_open;
if (devsw->d_close == NULL) devsw->d_close = null_close;
if (devsw->d_read == NULL) devsw->d_read = no_read;
@ -339,12 +351,7 @@ prep_cdevsw(struct cdevsw *devsw)
if (devsw->d_dump == NULL) devsw->d_dump = no_dump;
if (devsw->d_kqfilter == NULL) devsw->d_kqfilter = no_kqfilter;
if (devsw->d_maj == MAJOR_AUTO) {
for (i = NUMCDEVSW - 1; i > 0; i--)
if (reserved_majors[i] != i)
break;
KASSERT(i > 0, ("Out of major numbers (%s)", devsw->d_name));
devsw->d_maj = i;
reserved_majors[i] = i;
find_major(devsw);
} else {
if (devsw->d_maj == 256) /* XXX: tty_cons.c is magic */
devsw->d_maj = 0;
@ -458,17 +465,22 @@ destroy_dev(dev_t dev)
}
devfs_destroy(dev);
dev->si_flags &= ~SI_NAMED;
if (dev->si_flags & SI_CHILD) {
LIST_REMOVE(dev, si_siblings);
dev->si_flags &= ~SI_CHILD;
}
while (!LIST_EMPTY(&dev->si_children))
destroy_dev(LIST_FIRST(&dev->si_children));
if (dev->si_flags & SI_CLONELIST) {
LIST_REMOVE(dev, si_clone);
dev->si_flags &= ~SI_CLONELIST;
}
dev->si_drv1 = 0;
dev->si_drv2 = 0;
dev->si_devsw = 0;
bzero(&dev->__si_u, sizeof(dev->__si_u));
dev->si_flags &= ~SI_NAMED;
dev->si_flags &= ~SI_ALIAS;
freedev(dev);
}
@ -522,6 +534,115 @@ dev_stdclone(char *name, char **namep, const char *stem, int *unit)
return (1);
}
/*
* Helper functions for cloning device drivers.
*
* The objective here is to make it unnecessary for the device drivers to
* use rman or similar to manage their unit number space. Due to the way
* we do "on-demand" devices, using rman or other "private" methods
* will be very tricky to lock down properly once we lock down this file.
*
* Instead we give the drivers these routines which puts the dev_t's that
* are to be managed on their own list, and gives the driver the ability
* to ask for the first free unit number or a given specified unit number.
*
* In addition these routines support paired devices (pty, nmdm and similar)
* by respecting a number of "flag" bits in the minor number.
*
*/
struct clonedevs {
LIST_HEAD(,cdev) head;
};
int
clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, dev_t *dp, u_int extra)
{
struct clonedevs *cd;
dev_t dev, dl, de;
int unit, low, u;
KASSERT(!(extra & CLONE_UNITMASK),
("Illegal extra bits (0x%x) in clone_create", extra));
KASSERT(*up <= CLONE_UNITMASK,
("Too high unit (0x%x) in clone_create", *up));
if (csw->d_maj == MAJOR_AUTO)
find_major(csw);
/* if clonedevs have not been initialized, we do it here */
cd = *cdp;
if (cd == NULL) {
cd = malloc(sizeof *cd, M_DEVBUF, M_WAITOK | M_ZERO);
LIST_INIT(&cd->head);
*cdp = cd;
}
/*
* Search the list for a lot of things in one go:
* A preexisting match is returned immediately.
* The lowest free unit number if we are passed -1, and the place
* in the list where we should insert that new element.
* The place to insert a specified unit number, if applicable
* the end of the list.
*/
unit = *up;
low = 0;
de = dl = NULL;
LIST_FOREACH(dev, &cd->head, si_clone) {
u = dev2unit(dev);
if (u == (unit | extra)) {
*dp = dev;
return (0);
}
if (unit == -1 && u == low) {
low++;
de = dev;
continue;
}
if (u > unit) {
dl = dev;
break;
}
de = dev;
}
if (unit == -1)
unit = low;
dev = makedev(csw->d_maj, unit2minor(unit | extra));
KASSERT(!(dev->si_flags & SI_CLONELIST),
("Dev %p should not be on clonelist", dev));
if (dl != NULL)
LIST_INSERT_BEFORE(dl, dev, si_clone);
else if (de != NULL)
LIST_INSERT_AFTER(de, dev, si_clone);
else
LIST_INSERT_HEAD(&cd->head, dev, si_clone);
dev->si_flags |= SI_CLONELIST;
*up = unit;
return (1);
}
/*
* Kill everything still on the list. The driver should already have
* disposed of any softc hung of the dev_t's at this time.
*/
void
clone_cleanup(struct clonedevs **cdp)
{
dev_t dev, tdev;
struct clonedevs *cd;
cd = *cdp;
if (cd == NULL)
return;
LIST_FOREACH_SAFE(dev, &cd->head, si_clone, tdev) {
KASSERT(dev->si_flags & SI_NAMED,
("Driver has goofed in cloning underways udev %x", dev->si_udev));
destroy_dev(dev);
}
free(cd, M_DEVBUF);
*cdp = NULL;
}
/*
* Helper sysctl for devname(3). We're given a {u}dev_t and return
* the name, if any, registered by the device driver.

View File

@ -54,8 +54,6 @@
#include <sys/ttycom.h>
#include <sys/uio.h>
#include <sys/vnode.h>
#include <machine/bus.h> /* XXX: Shouldn't really be required! */
#include <sys/rman.h>
#include <sys/queue.h>
#include <net/bpf.h>
@ -71,14 +69,12 @@
#define CDEV_NAME "tap"
#define CDEV_MAJOR 149
#define TAPDEBUG if (tapdebug) printf
#define TAP "tap"
#define VMNET "vmnet"
#define TAPMAXUNIT 0x7fff
#define VMNET_DEV_MASK 0x00800000
/* 0x007f00ff */
#define VMNET_DEV_MASK CLONE_FLAG0
/* module */
static int tapmodevent(module_t, int, void *);
@ -108,15 +104,12 @@ static struct cdevsw tap_cdevsw = {
.d_ioctl = tapioctl,
.d_poll = tappoll,
.d_name = CDEV_NAME,
.d_maj = CDEV_MAJOR,
.d_flags = D_PSEUDO,
};
static int tapdebug = 0; /* debug flag */
static SLIST_HEAD(, tap_softc) taphead; /* first device */
static udev_t tapbasedev = NOUDEV; /* base device */
static struct rman tapdevunits[2]; /* device units */
#define tapunits tapdevunits
#define vmnetunits (tapdevunits + 1)
static struct clonedevs *tapclones;
MALLOC_DECLARE(M_TAP);
MALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface");
@ -137,63 +130,27 @@ tapmodevent(mod, type, data)
static eventhandler_tag eh_tag = NULL;
struct tap_softc *tp = NULL;
struct ifnet *ifp = NULL;
int error, s;
int s;
switch (type) {
case MOD_LOAD:
/* initialize resources */
tapunits->rm_type = RMAN_ARRAY;
tapunits->rm_descr = "open tap units";
vmnetunits->rm_type = RMAN_ARRAY;
vmnetunits->rm_descr = "open vmnet units";
error = rman_init(tapunits);
if (error != 0)
goto bail;
error = rman_init(vmnetunits);
if (error != 0)
goto bail1;
error = rman_manage_region(tapunits, 0, TAPMAXUNIT);
if (error != 0)
goto bail2;
error = rman_manage_region(vmnetunits, 0, TAPMAXUNIT);
if (error != 0)
goto bail2;
/* intitialize device */
SLIST_INIT(&taphead);
eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000);
if (eh_tag == NULL) {
error = ENOMEM;
goto bail2;
}
if (eh_tag == NULL)
return (ENOMEM);
return (0);
bail2:
rman_fini(vmnetunits);
bail1:
rman_fini(tapunits);
bail:
return (error);
case MOD_UNLOAD:
SLIST_FOREACH(tp, &taphead, tap_next)
if (tp->tap_unit != NULL)
if (tp->tap_flags & TAP_OPEN)
return (EBUSY);
EVENTHANDLER_DEREGISTER(dev_clone, eh_tag);
error = rman_fini(tapunits);
KASSERT((error == 0), ("Could not fini tap units"));
error = rman_fini(vmnetunits);
KASSERT((error == 0), ("Could not fini vmnet units"));
while ((tp = SLIST_FIRST(&taphead)) != NULL) {
SLIST_REMOVE_HEAD(&taphead, tap_next);
@ -204,18 +161,14 @@ tapmodevent(mod, type, data)
KASSERT(!(tp->tap_flags & TAP_OPEN),
("%s flags is out of sync", ifp->if_xname));
/* XXX makedev check? nah.. not right now :) */
destroy_dev(tp->tap_dev);
s = splimp();
ether_ifdetach(ifp);
splx(s);
free(tp, M_TAP);
}
if (tapbasedev != NOUDEV)
destroy_dev(udev2dev(tapbasedev, 0));
clone_cleanup(&tapclones);
break;
@ -239,65 +192,35 @@ tapclone(arg, name, namelen, dev)
int namelen;
dev_t *dev;
{
int unit, minor = 0 /* XXX avoid warning */ , error;
u_int extra;
int i, unit;
char *device_name = name;
struct resource *r = NULL;
if (*dev != NODEV)
return;
if (strcmp(device_name, TAP) == 0) {
/* get first free tap unit */
r = rman_reserve_resource(tapunits, 0, TAPMAXUNIT, 1,
RF_ALLOCATED | RF_ACTIVE, NULL);
unit = rman_get_start(r);
minor = unit2minor(unit);
}
else if (strcmp(device_name, VMNET) == 0) {
/* get first free vmnet unit */
r = rman_reserve_resource(vmnetunits, 0, TAPMAXUNIT, 1,
RF_ALLOCATED | RF_ACTIVE, NULL);
unit = rman_get_start(r);
minor = unit2minor(unit) | VMNET_DEV_MASK;
device_name = TAP;
extra = 0;
if (strcmp(name, TAP) == 0) {
unit = -1;
} else if (strcmp(name, VMNET) == 0) {
device_name = VMNET;
extra = VMNET_DEV_MASK;
unit = -1;
} else if (dev_stdclone(name, NULL, device_name, &unit) != 1) {
device_name = VMNET;
extra = VMNET_DEV_MASK;
if (dev_stdclone(name, NULL, device_name, &unit) != 1)
return;
}
if (r != NULL) { /* need cloning */
TAPDEBUG("%s%d is available. minor = %#x\n",
device_name, unit, minor);
error = rman_release_resource(r);
KASSERT((error == 0), ("Could not release tap/vmnet unit"));
/* check if device for the unit has been created */
*dev = makedev(CDEV_MAJOR, minor);
if ((*dev)->si_flags & SI_NAMED) {
TAPDEBUG("%s%d device exists. minor = %#x\n",
device_name, unit, minor);
return; /* device has been created */
}
} else { /* try to match name/unit, first try tap then vmnet */
device_name = TAP;
if (dev_stdclone(name, NULL, device_name, &unit) != 1) {
device_name = VMNET;
if (dev_stdclone(name, NULL, device_name, &unit) != 1)
return;
minor = unit2minor(unit) | VMNET_DEV_MASK;
} else
minor = unit2minor(unit);
}
TAPDEBUG("make_dev(%s%d). minor = %#x\n", device_name, unit, minor);
*dev = make_dev(&tap_cdevsw, minor, UID_ROOT, GID_WHEEL, 0600, "%s%d",
device_name, unit);
if (tapbasedev == NOUDEV)
tapbasedev = (*dev)->si_udev;
else {
(*dev)->si_flags |= SI_CHEAPCLONE;
dev_depends(udev2dev(tapbasedev, 0), *dev);
/* find any existing device, or allocate new unit number */
i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra);
if (i) {
*dev = make_dev(&tap_cdevsw, unit2minor(unit) | extra,
UID_ROOT, GID_WHEEL, 0600, "%s%d", device_name, unit);
if (*dev != NULL)
(*dev)->si_flags |= SI_CHEAPCLONE;
}
} /* tapclone */
@ -317,6 +240,8 @@ tapcreate(dev)
int unit, s;
char *name = NULL;
dev->si_flags &= ~SI_CHEAPCLONE;
/* allocate driver storage and create device */
MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO);
SLIST_INSERT_HEAD(&taphead, tp, tap_next);
@ -354,6 +279,7 @@ tapcreate(dev)
ifp->if_snd.ifq_maxlen = ifqmaxlen;
dev->si_drv1 = tp;
tp->tap_dev = dev;
s = splimp();
ether_ifattach(ifp, tp->arpcom.ac_enaddr);
@ -380,24 +306,12 @@ tapopen(dev, flag, mode, td)
{
struct tap_softc *tp = NULL;
int unit, error;
struct resource *r = NULL;
if ((error = suser(td)) != 0)
return (error);
unit = dev2unit(dev) & TAPMAXUNIT;
if (minor(dev) & VMNET_DEV_MASK)
r = rman_reserve_resource(vmnetunits, unit, unit, 1,
RF_ALLOCATED | RF_ACTIVE, NULL);
else
r = rman_reserve_resource(tapunits, unit, unit, 1,
RF_ALLOCATED | RF_ACTIVE, NULL);
if (r == NULL)
return (EBUSY);
dev->si_flags &= ~SI_CHEAPCLONE;
tp = dev->si_drv1;
if (tp == NULL) {
@ -410,7 +324,6 @@ tapopen(dev, flag, mode, td)
bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr));
tp->tap_unit = r;
tp->tap_pid = td->td_proc->p_pid;
tp->tap_flags |= TAP_OPEN;
@ -433,12 +346,9 @@ tapclose(dev, foo, bar, td)
int bar;
struct thread *td;
{
int s, error;
struct tap_softc *tp = dev->si_drv1;
struct ifnet *ifp = &tp->tap_if;
KASSERT((tp->tap_unit != NULL),
("%s is not open", ifp->if_xname));
int s;
/* junk all pending output */
IF_DRAIN(&ifp->if_snd);
@ -479,10 +389,6 @@ tapclose(dev, foo, bar, td)
tp->tap_flags &= ~TAP_OPEN;
tp->tap_pid = 0;
error = rman_release_resource(tp->tap_unit);
KASSERT((error == 0),
("%s could not release unit", ifp->if_xname));
tp->tap_unit = NULL;
TAPDEBUG("%s is closed. minor = %#x\n",
ifp->if_xname, minor(dev));

View File

@ -61,6 +61,7 @@ struct tap_softc {
struct selinfo tap_rsel; /* read select */
SLIST_ENTRY(tap_softc) tap_next; /* next device in chain */
dev_t tap_dev;
};
#endif /* !_NET_IF_TAPVAR_H_ */

View File

@ -41,9 +41,7 @@
#include <sys/uio.h>
#include <sys/vnode.h>
#include <sys/malloc.h>
#include <machine/bus.h> /* XXX Shouldn't really be required ! */
#include <sys/random.h>
#include <sys/rman.h>
#include <net/if.h>
#include <net/if_types.h>
@ -53,17 +51,40 @@
#include <netinet/in.h>
#endif
#include <net/bpf.h>
#include <net/if_tunvar.h>
#include <net/if_tun.h>
#include <sys/queue.h>
struct tun_softc {
TAILQ_ENTRY(tun_softc) tun_list;
int tun_unit;
dev_t tun_dev;
u_short tun_flags; /* misc flags */
#define TUN_OPEN 0x0001
#define TUN_INITED 0x0002
#define TUN_RCOLL 0x0004
#define TUN_IASET 0x0008
#define TUN_DSTADDR 0x0010
#define TUN_LMODE 0x0020
#define TUN_RWAIT 0x0040
#define TUN_ASYNC 0x0080
#define TUN_IFHEAD 0x0100
#define TUN_READY (TUN_OPEN | TUN_INITED)
struct proc *tun_proc; /* Owning process */
struct ifnet tun_if; /* the interface */
struct sigio *tun_sigio; /* information for async I/O */
struct selinfo tun_rsel; /* read select */
};
#define TUNDEBUG if (tundebug) if_printf
#define TUNNAME "tun"
static MALLOC_DEFINE(M_TUN, TUNNAME, "Tunnel Interface");
static int tundebug = 0;
static struct tun_softc *tunhead = NULL;
static struct rman tununits;
static udev_t tunbasedev = NOUDEV;
static struct clonedevs *tunclones;
static TAILQ_HEAD(,tun_softc) tunhead = TAILQ_HEAD_INITIALIZER(tunhead);
SYSCTL_INT(_debug, OID_AUTO, if_tun_debug, CTLFLAG_RW, &tundebug, 0, "");
static void tunclone(void *arg, char *name, int namelen, dev_t *dev);
@ -82,7 +103,6 @@ static d_write_t tunwrite;
static d_ioctl_t tunioctl;
static d_poll_t tunpoll;
#define CDEV_MAJOR 52
static struct cdevsw tun_cdevsw = {
.d_open = tunopen,
.d_close = tunclose,
@ -91,44 +111,32 @@ static struct cdevsw tun_cdevsw = {
.d_ioctl = tunioctl,
.d_poll = tunpoll,
.d_name = TUNNAME,
.d_maj = CDEV_MAJOR,
.d_flags = D_PSEUDO,
};
static void
tunclone(void *arg, char *name, int namelen, dev_t *dev)
{
struct resource *r;
int err;
int u;
int u, i;
if (*dev != NODEV)
return;
if (strcmp(name, TUNNAME) == 0) {
r = rman_reserve_resource(&tununits, 0, IF_MAXUNIT, 1,
RF_ALLOCATED | RF_ACTIVE, NULL);
u = rman_get_start(r);
err = rman_release_resource(r);
KASSERT(err == 0, ("Unexpected failure releasing resource"));
*dev = makedev(CDEV_MAJOR, unit2minor(u));
if ((*dev)->si_flags & SI_NAMED)
return; /* Already make_dev()d */
u = -1;
} else if (dev_stdclone(name, NULL, TUNNAME, &u) != 1)
return; /* Don't recognise the name */
if (u != -1 && u > IF_MAXUNIT)
return; /* Unit number too high */
*dev = make_dev(&tun_cdevsw, unit2minor(u),
UID_ROOT, GID_WHEEL, 0600, "tun%d", u);
/*
* All devices depend on tunbasedev so that we can simply
* destroy_dev() this device at module unload time to get
* rid of all our make_dev()d resources.
*/
if (tunbasedev == NOUDEV)
tunbasedev = (*dev)->si_udev;
else {
(*dev)->si_flags |= SI_CHEAPCLONE;
dev_depends(udev2dev(tunbasedev, 0), *dev);
/* find any existing device, or allocate new unit number */
i = clone_create(&tunclones, &tun_cdevsw, &u, dev, 0);
if (i) {
/* No preexisting dev_t, create one */
*dev = make_dev(&tun_cdevsw, unit2minor(u),
UID_UUCP, GID_DIALER, 0600, "tun%d", u);
if (*dev != NULL)
(*dev)->si_flags |= SI_CHEAPCLONE;
}
}
@ -138,57 +146,29 @@ tunmodevent(module_t mod, int type, void *data)
static eventhandler_tag tag;
struct tun_softc *tp;
dev_t dev;
int err;
switch (type) {
case MOD_LOAD:
tag = EVENTHANDLER_REGISTER(dev_clone, tunclone, 0, 1000);
if (tag == NULL)
return (ENOMEM);
tununits.rm_type = RMAN_ARRAY;
tununits.rm_descr = "open if_tun units";
err = rman_init(&tununits);
if (err != 0) {
EVENTHANDLER_DEREGISTER(dev_clone, tag);
return (err);
}
err = rman_manage_region(&tununits, 0, IF_MAXUNIT);
if (err != 0) {
printf("%s: tununits: rman_manage_region: Failed %d\n",
TUNNAME, err);
rman_fini(&tununits);
EVENTHANDLER_DEREGISTER(dev_clone, tag);
return (err);
}
break;
case MOD_UNLOAD:
err = rman_fini(&tununits);
if (err != 0)
return (err);
EVENTHANDLER_DEREGISTER(dev_clone, tag);
while (tunhead != NULL) {
KASSERT((tunhead->tun_flags & TUN_OPEN) == 0,
while (!TAILQ_EMPTY(&tunhead)) {
tp = TAILQ_FIRST(&tunhead);
KASSERT((tp->tun_flags & TUN_OPEN) == 0,
("tununits is out of sync - unit %d",
tunhead->tun_if.if_dunit));
tp = tunhead;
dev = makedev(tun_cdevsw.d_maj,
unit2minor(tp->tun_if.if_dunit));
KASSERT(dev->si_drv1 == tp, ("Bad makedev result"));
tunhead = tp->next;
tp->tun_if.if_dunit));
TAILQ_REMOVE(&tunhead, tp, tun_list);
dev = tp->tun_dev;
bpfdetach(&tp->tun_if);
if_detach(&tp->tun_if);
KASSERT(dev->si_flags & SI_NAMED, ("Missing make_dev"));
destroy_dev(dev);
free(tp, M_TUN);
}
/*
* Destroying tunbasedev results in all of our make_dev()s
* conveniently going away.
*/
if (tunbasedev != NOUDEV)
destroy_dev(udev2dev(tunbasedev, 0));
clone_cleanup(&tunclones);
break;
}
return 0;
@ -222,14 +202,12 @@ tuncreate(dev_t dev)
struct tun_softc *sc;
struct ifnet *ifp;
if (!(dev->si_flags & SI_NAMED))
dev = make_dev(&tun_cdevsw, minor(dev),
UID_UUCP, GID_DIALER, 0600, "tun%d", dev2unit(dev));
dev->si_flags &= ~SI_CHEAPCLONE;
MALLOC(sc, struct tun_softc *, sizeof(*sc), M_TUN, M_WAITOK | M_ZERO);
sc->tun_flags = TUN_INITED;
sc->next = tunhead;
tunhead = sc;
sc->tun_dev = dev;
TAILQ_INSERT_TAIL(&tunhead, sc, tun_list);
ifp = &sc->tun_if;
if_initname(ifp, TUNNAME, dev2unit(dev));
@ -249,32 +227,21 @@ tuncreate(dev_t dev)
static int
tunopen(dev_t dev, int flag, int mode, struct thread *td)
{
struct resource *r;
struct ifnet *ifp;
struct tun_softc *tp;
int unit;
unit = dev2unit(dev);
if (unit > IF_MAXUNIT)
return (ENXIO);
r = rman_reserve_resource(&tununits, unit, unit, 1,
RF_ALLOCATED | RF_ACTIVE, NULL);
if (r == NULL)
return (EBUSY);
dev->si_flags &= ~SI_CHEAPCLONE;
tp = dev->si_drv1;
if (!tp) {
tuncreate(dev);
tp = dev->si_drv1;
}
KASSERT(!(tp->tun_flags & TUN_OPEN), ("Resource & flags out-of-sync"));
tp->tun_unit = r;
tp->tun_pid = td->td_proc->p_pid;
ifp = &tp->tun_if;
if (tp->tun_proc != NULL && tp->tun_proc != td->td_proc)
return (EBUSY);
tp->tun_proc = td->td_proc;
tp->tun_flags |= TUN_OPEN;
ifp = &tp->tun_if;
TUNDEBUG(ifp, "open\n");
return (0);
@ -290,14 +257,12 @@ tunclose(dev_t dev, int foo, int bar, struct thread *td)
struct tun_softc *tp;
struct ifnet *ifp;
int s;
int err;
tp = dev->si_drv1;
ifp = &tp->tun_if;
KASSERT(tp->tun_unit, ("Unit %d not marked open", tp->tun_if.if_dunit));
tp->tun_flags &= ~TUN_OPEN;
tp->tun_pid = 0;
tp->tun_proc = NULL;
/*
* junk all pending output
@ -325,11 +290,7 @@ tunclose(dev_t dev, int foo, int bar, struct thread *td)
funsetown(&tp->tun_sigio);
selwakeuppri(&tp->tun_rsel, PZERO + 1);
TUNDEBUG (ifp, "closed\n");
err = rman_release_resource(tp->tun_unit);
KASSERT(err == 0, ("Unit %d failed to release", tp->tun_if.if_dunit));
return (0);
}
@ -384,9 +345,9 @@ tunifioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
switch(cmd) {
case SIOCGIFSTATUS:
ifs = (struct ifstat *)data;
if (tp->tun_pid)
if (tp->tun_proc)
sprintf(ifs->ascii + strlen(ifs->ascii),
"\tOpened by PID %d\n", tp->tun_pid);
"\tOpened by PID %d\n", tp->tun_proc->p_pid);
break;
case SIOCSIFADDR:
error = tuninit(ifp);
@ -573,7 +534,7 @@ tunioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
}
break;
case TUNSIFPID:
tp->tun_pid = curthread->td_proc->p_pid;
tp->tun_proc = curthread->td_proc;
break;
case FIONBIO:
break;

View File

@ -1,55 +0,0 @@
/*-
* Copyright (c) 1998 Brian Somers <brian@Awfulhak.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _NET_IF_TUNVAR_H_
#define _NET_IF_TUNVAR_H_
struct tun_softc {
u_short tun_flags; /* misc flags */
#define TUN_OPEN 0x0001
#define TUN_INITED 0x0002
#define TUN_RCOLL 0x0004
#define TUN_IASET 0x0008
#define TUN_DSTADDR 0x0010
#define TUN_LMODE 0x0020
#define TUN_RWAIT 0x0040
#define TUN_ASYNC 0x0080
#define TUN_IFHEAD 0x0100
#define TUN_READY (TUN_OPEN | TUN_INITED)
pid_t tun_pid; /* PID of process to open */
struct ifnet tun_if; /* the interface */
struct sigio *tun_sigio; /* information for async I/O */
struct selinfo tun_rsel; /* read select */
struct tun_softc *next; /* Next softc in list */
struct resource *tun_unit; /* resource allocated for this unit */
};
#endif /* !_NET_IF_TUNVAR_H_ */

View File

@ -64,10 +64,12 @@ struct cdev {
#define SI_CONSOPEN 0x0040 /* opened by console */
#define SI_DUMPDEV 0x0080 /* is kernel dumpdev */
#define SI_CANDELETE 0x0100 /* can do BIO_DELETE */
#define SI_CLONELIST 0x0200 /* on a clone list */
struct timespec si_atime;
struct timespec si_ctime;
struct timespec si_mtime;
udev_t si_udev;
LIST_ENTRY(cdev) si_clone;
LIST_ENTRY(cdev) si_hash;
SLIST_HEAD(, vnode) si_hlist;
LIST_HEAD(, cdev) si_children;
@ -125,6 +127,7 @@ struct buf;
struct thread;
struct uio;
struct knote;
struct clonedevs;
/*
* Note: d_thread_t is provided as a transition aid for those drivers
@ -198,6 +201,7 @@ typedef int dumper_t(
#define D_NAGGED 0x00020000 /* nagged about missing make_dev() */
#define D_TRACKCLOSE 0x00080000 /* track all closes */
#define D_MMAP_ANON 0x00100000 /* special treatment in vm_mmap.c */
#define D_PSEUDO 0x00200000 /* make_dev() can return NULL */
#define D_NOGIANT 0x00400000 /* Doesn't want Giant */
/*
@ -274,6 +278,11 @@ static moduledata_t name##_mod = { \
DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE)
void clone_cleanup(struct clonedevs **);
#define CLONE_UNITMASK 0xfffff
#define CLONE_FLAG0 (CLONE_UNITMASK + 1)
int clone_create(struct clonedevs **, struct cdevsw *, int *unit, dev_t *dev, u_int extra);
int count_dev(dev_t _dev);
void destroy_dev(dev_t _dev);
struct cdevsw *devsw(dev_t _dev);

View File

@ -64,10 +64,12 @@ struct cdev {
#define SI_CONSOPEN 0x0040 /* opened by console */
#define SI_DUMPDEV 0x0080 /* is kernel dumpdev */
#define SI_CANDELETE 0x0100 /* can do BIO_DELETE */
#define SI_CLONELIST 0x0200 /* on a clone list */
struct timespec si_atime;
struct timespec si_ctime;
struct timespec si_mtime;
udev_t si_udev;
LIST_ENTRY(cdev) si_clone;
LIST_ENTRY(cdev) si_hash;
SLIST_HEAD(, vnode) si_hlist;
LIST_HEAD(, cdev) si_children;
@ -125,6 +127,7 @@ struct buf;
struct thread;
struct uio;
struct knote;
struct clonedevs;
/*
* Note: d_thread_t is provided as a transition aid for those drivers
@ -198,6 +201,7 @@ typedef int dumper_t(
#define D_NAGGED 0x00020000 /* nagged about missing make_dev() */
#define D_TRACKCLOSE 0x00080000 /* track all closes */
#define D_MMAP_ANON 0x00100000 /* special treatment in vm_mmap.c */
#define D_PSEUDO 0x00200000 /* make_dev() can return NULL */
#define D_NOGIANT 0x00400000 /* Doesn't want Giant */
/*
@ -274,6 +278,11 @@ static moduledata_t name##_mod = { \
DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE)
void clone_cleanup(struct clonedevs **);
#define CLONE_UNITMASK 0xfffff
#define CLONE_FLAG0 (CLONE_UNITMASK + 1)
int clone_create(struct clonedevs **, struct cdevsw *, int *unit, dev_t *dev, u_int extra);
int count_dev(dev_t _dev);
void destroy_dev(dev_t _dev);
struct cdevsw *devsw(dev_t _dev);