summaryrefslogtreecommitdiffstats
path: root/sys/net/if_tun.c
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2004-03-29 18:42:51 +0000
committerrwatson <rwatson@FreeBSD.org>2004-03-29 18:42:51 +0000
commit1d1b2c7f35d1158639ebc40e2a97c5fdb1888f4c (patch)
tree453bb875a2c70c8c786e9408f7fb28d341c2ab69 /sys/net/if_tun.c
parentf758b08c5a4eaeddcb7827e76fe9c0a8903c0cca (diff)
downloadFreeBSD-src-1d1b2c7f35d1158639ebc40e2a97c5fdb1888f4c.zip
FreeBSD-src-1d1b2c7f35d1158639ebc40e2a97c5fdb1888f4c.tar.gz
Lock down if_tun global variables using a new mutex, tunmtx. As with
other pseudo-interfaces, break out tear-down of a softc into a separate tun_destroy() function, and invoke that from the module unloader. Hold tunmtx across manipulations of the global softc list.
Diffstat (limited to 'sys/net/if_tun.c')
-rw-r--r--sys/net/if_tun.c42
1 files changed, 31 insertions, 11 deletions
diff --git a/sys/net/if_tun.c b/sys/net/if_tun.c
index 2579b93..bda7bb1 100644
--- a/sys/net/if_tun.c
+++ b/sys/net/if_tun.c
@@ -87,6 +87,12 @@ struct tun_softc {
#define TUNDEBUG if (tundebug) if_printf
#define TUNNAME "tun"
+/*
+ * All mutable global variables in if_tun are locked using tunmtx, with
+ * the exception of tundebug, which is used unlocked, and tunclones,
+ * which is static after setup.
+ */
+static struct mtx tunmtx;
static MALLOC_DEFINE(M_TUN, TUNNAME, "Tunnel Interface");
static int tundebug = 0;
static struct clonedevs *tunclones;
@@ -147,15 +153,30 @@ tunclone(void *arg, char *name, int namelen, dev_t *dev)
}
}
+static void
+tun_destroy(struct tun_softc *tp)
+{
+ dev_t dev;
+
+ KASSERT((tp->tun_flags & TUN_OPEN) == 0,
+ ("tununits is out of sync - unit %d", tp->tun_if.if_dunit));
+
+ dev = tp->tun_dev;
+ bpfdetach(&tp->tun_if);
+ if_detach(&tp->tun_if);
+ destroy_dev(dev);
+ free(tp, M_TUN);
+}
+
static int
tunmodevent(module_t mod, int type, void *data)
{
static eventhandler_tag tag;
struct tun_softc *tp;
- dev_t dev;
switch (type) {
case MOD_LOAD:
+ mtx_init(&tunmtx, "tunmtx", NULL, MTX_DEF);
clone_setup(&tunclones);
tag = EVENTHANDLER_REGISTER(dev_clone, tunclone, 0, 1000);
if (tag == NULL)
@@ -164,19 +185,16 @@ tunmodevent(module_t mod, int type, void *data)
case MOD_UNLOAD:
EVENTHANDLER_DEREGISTER(dev_clone, tag);
- while (!TAILQ_EMPTY(&tunhead)) {
- tp = TAILQ_FIRST(&tunhead);
- KASSERT((tp->tun_flags & TUN_OPEN) == 0,
- ("tununits is out of sync - unit %d",
- tp->tun_if.if_dunit));
+ mtx_lock(&tunmtx);
+ while ((tp = TAILQ_FIRST(&tunhead)) != NULL) {
TAILQ_REMOVE(&tunhead, tp, tun_list);
- dev = tp->tun_dev;
- bpfdetach(&tp->tun_if);
- if_detach(&tp->tun_if);
- destroy_dev(dev);
- free(tp, M_TUN);
+ mtx_unlock(&tunmtx);
+ tun_destroy(tp);
+ mtx_lock(&tunmtx);
}
+ mtx_unlock(&tunmtx);
clone_cleanup(&tunclones);
+ mtx_destroy(&tunmtx);
break;
}
return 0;
@@ -215,7 +233,9 @@ tuncreate(dev_t dev)
MALLOC(sc, struct tun_softc *, sizeof(*sc), M_TUN, M_WAITOK | M_ZERO);
sc->tun_flags = TUN_INITED;
sc->tun_dev = dev;
+ mtx_lock(&tunmtx);
TAILQ_INSERT_TAIL(&tunhead, sc, tun_list);
+ mtx_unlock(&tunmtx);
ifp = &sc->tun_if;
if_initname(ifp, TUNNAME, dev2unit(dev));
OpenPOWER on IntegriCloud