summaryrefslogtreecommitdiffstats
path: root/sys/net/if_tun.c
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2004-02-21 20:29:52 +0000
committerphk <phk@FreeBSD.org>2004-02-21 20:29:52 +0000
commit32b7c9a433930842533064d829ba214aadf6a67d (patch)
treec97716bebd5c7c784bf841850192a5addeaf0347 /sys/net/if_tun.c
parentdf397dedeab80f98300da9e5999d17a57c01b19f (diff)
downloadFreeBSD-src-32b7c9a433930842533064d829ba214aadf6a67d.zip
FreeBSD-src-32b7c9a433930842533064d829ba214aadf6a67d.tar.gz
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.
Diffstat (limited to 'sys/net/if_tun.c')
-rw-r--r--sys/net/if_tun.c163
1 files changed, 62 insertions, 101 deletions
diff --git a/sys/net/if_tun.c b/sys/net/if_tun.c
index 516d299..4a64da4 100644
--- a/sys/net/if_tun.c
+++ b/sys/net/if_tun.c
@@ -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 */
-
- *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);
+ if (u != -1 && u > IF_MAXUNIT)
+ return; /* Unit number too high */
+
+ /* 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;
OpenPOWER on IntegriCloud