aboutsummaryrefslogtreecommitdiff
path: root/sys/net
diff options
context:
space:
mode:
authorBruce M Simpson <bms@FreeBSD.org>2007-03-04 14:34:42 +0000
committerBruce M Simpson <bms@FreeBSD.org>2007-03-04 14:34:42 +0000
commit7c12c9ef5febb17d939e9c15f7695cc434ca6040 (patch)
treec7ef8f5c53b22a1ff6c064025bf3ee5fbaa676e4 /sys/net
parent5a71d8bbbcb16282d85bfbb90557d19dff3e6c57 (diff)
Notes
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/if_tap.c173
-rw-r--r--sys/net/if_tun.c122
2 files changed, 231 insertions, 64 deletions
diff --git a/sys/net/if_tap.c b/sys/net/if_tap.c
index 20b37e553c99..5b8390553664 100644
--- a/sys/net/if_tap.c
+++ b/sys/net/if_tap.c
@@ -61,6 +61,8 @@
#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_arp.h>
+#include <net/if_clone.h>
+#include <net/if_dl.h>
#include <net/route.h>
#include <net/if_types.h>
@@ -91,6 +93,14 @@ static void tapifstart(struct ifnet *);
static int tapifioctl(struct ifnet *, u_long, caddr_t);
static void tapifinit(void *);
+static int tap_clone_create(struct if_clone *, int);
+static void tap_clone_destroy(struct ifnet *);
+static int vmnet_clone_create(struct if_clone *, int);
+static void vmnet_clone_destroy(struct ifnet *);
+
+IFC_SIMPLE_DECLARE(tap, 0);
+IFC_SIMPLE_DECLARE(vmnet, 0);
+
/* character device */
static d_open_t tapopen;
static d_close_t tapclose;
@@ -140,6 +150,7 @@ static struct cdevsw tap_cdevsw = {
static struct mtx tapmtx;
static int tapdebug = 0; /* debug flag */
static int tapuopen = 0; /* allow user open() */
+static int tapdclone = 1; /* enable devfs cloning */
static SLIST_HEAD(, tap_softc) taphead; /* first device */
static struct clonedevs *tapclones;
@@ -152,10 +163,87 @@ SYSCTL_NODE(_net_link, OID_AUTO, tap, CTLFLAG_RW, 0,
"Ethernet tunnel software network interface");
SYSCTL_INT(_net_link_tap, OID_AUTO, user_open, CTLFLAG_RW, &tapuopen, 0,
"Allow user to open /dev/tap (based on node permissions)");
+SYSCTL_INT(_net_link_tap, OID_AUTO, devfs_cloning, CTLFLAG_RW, &tapdclone, 0,
+ "Enably legacy devfs interface creation");
SYSCTL_INT(_net_link_tap, OID_AUTO, debug, CTLFLAG_RW, &tapdebug, 0, "");
+TUNABLE_INT("net.link.tap.devfs_cloning", &tapdclone);
+
DEV_MODULE(if_tap, tapmodevent, NULL);
+static int
+tap_clone_create(struct if_clone *ifc, int unit)
+{
+ struct cdev *dev;
+ int i;
+ int extra;
+
+ if (strcmp(ifc->ifc_name, VMNET) == 0)
+ extra = VMNET_DEV_MASK;
+ else
+ extra = 0;
+
+ /* 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", ifc->ifc_name, unit);
+ if (dev != NULL) {
+ dev_ref(dev);
+ dev->si_flags |= SI_CHEAPCLONE;
+ }
+ }
+
+ tapcreate(dev);
+ return (0);
+}
+
+/* vmnet devices are tap devices in disguise */
+static int
+vmnet_clone_create(struct if_clone *ifc, int unit)
+{
+ return tap_clone_create(ifc, unit);
+}
+
+static void
+tap_destroy(struct tap_softc *tp)
+{
+ struct ifnet *ifp = tp->tap_ifp;
+ int s;
+
+ /* Unlocked read. */
+ KASSERT(!(tp->tap_flags & TAP_OPEN),
+ ("%s flags is out of sync", ifp->if_xname));
+
+ knlist_destroy(&tp->tap_rsel.si_note);
+ destroy_dev(tp->tap_dev);
+ s = splimp();
+ ether_ifdetach(ifp);
+ if_free_type(ifp, IFT_ETHER);
+ splx(s);
+
+ mtx_destroy(&tp->tap_mtx);
+ free(tp, M_TAP);
+}
+
+static void
+tap_clone_destroy(struct ifnet *ifp)
+{
+ struct tap_softc *tp = ifp->if_softc;
+
+ mtx_lock(&tapmtx);
+ SLIST_REMOVE(&taphead, tp, tap_softc, tap_next);
+ mtx_unlock(&tapmtx);
+ tap_destroy(tp);
+}
+
+/* vmnet devices are tap devices in disguise */
+static void
+vmnet_clone_destroy(struct ifnet *ifp)
+{
+ tap_clone_destroy(ifp);
+}
+
/*
* tapmodevent
*
@@ -167,7 +255,6 @@ tapmodevent(module_t mod, int type, void *data)
static eventhandler_tag eh_tag = NULL;
struct tap_softc *tp = NULL;
struct ifnet *ifp = NULL;
- int s;
switch (type) {
case MOD_LOAD:
@@ -184,6 +271,8 @@ tapmodevent(module_t mod, int type, void *data)
mtx_destroy(&tapmtx);
return (ENOMEM);
}
+ if_clone_attach(&tap_cloner);
+ if_clone_attach(&vmnet_cloner);
return (0);
case MOD_UNLOAD:
@@ -205,6 +294,8 @@ tapmodevent(module_t mod, int type, void *data)
mtx_unlock(&tapmtx);
EVENTHANDLER_DEREGISTER(dev_clone, eh_tag);
+ if_clone_detach(&tap_cloner);
+ if_clone_detach(&vmnet_cloner);
mtx_lock(&tapmtx);
while ((tp = SLIST_FIRST(&taphead)) != NULL) {
@@ -215,19 +306,7 @@ tapmodevent(module_t mod, int type, void *data)
TAPDEBUG("detaching %s\n", ifp->if_xname);
- /* Unlocked read. */
- KASSERT(!(tp->tap_flags & TAP_OPEN),
- ("%s flags is out of sync", ifp->if_xname));
-
- knlist_destroy(&tp->tap_rsel.si_note);
- destroy_dev(tp->tap_dev);
- s = splimp();
- ether_ifdetach(ifp);
- if_free_type(ifp, IFT_ETHER);
- splx(s);
-
- mtx_destroy(&tp->tap_mtx);
- free(tp, M_TAP);
+ tap_destroy(tp);
mtx_lock(&tapmtx);
}
mtx_unlock(&tapmtx);
@@ -253,38 +332,60 @@ tapmodevent(module_t mod, int type, void *data)
static void
tapclone(void *arg, struct ucred *cred, char *name, int namelen, struct cdev **dev)
{
+ char devname[SPECNAMELEN + 1];
+ int i, unit, append_unit;
int extra;
- int i, unit;
- char *device_name = name;
if (*dev != NULL)
return;
- device_name = TAP;
+ if (!tapdclone ||
+ (!tapuopen && suser_cred(cred, SUSER_ALLOWJAIL) != 0))
+ return;
+
+ unit = 0;
+ append_unit = 0;
extra = 0;
+
+ /* We're interested in only tap/vmnet devices. */
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)
+ } else if (dev_stdclone(name, NULL, TAP, &unit) != 1) {
+ if (dev_stdclone(name, NULL, VMNET, &unit) != 1) {
return;
+ } else {
+ extra = VMNET_DEV_MASK;
+ }
}
+ if (unit == -1)
+ append_unit = 1;
+
/* find any existing device, or allocate new unit number */
i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra);
if (i) {
+ if (append_unit) {
+ /*
+ * We were passed 'tun' or 'tap', with no unit specified
+ * so we'll need to append it now.
+ */
+ namelen = snprintf(devname, sizeof(devname), "%s%d", name,
+ unit);
+ name = devname;
+ }
+
*dev = make_dev(&tap_cdevsw, unit2minor(unit | extra),
- UID_ROOT, GID_WHEEL, 0600, "%s%d", device_name, unit);
+ UID_ROOT, GID_WHEEL, 0600, "%s", name);
if (*dev != NULL) {
dev_ref(*dev);
(*dev)->si_flags |= SI_CHEAPCLONE;
}
}
+
+ if_clone_create(name, namelen);
} /* tapclone */
@@ -372,24 +473,18 @@ tapopen(struct cdev *dev, int flag, int mode, struct thread *td)
{
struct tap_softc *tp = NULL;
struct ifnet *ifp = NULL;
- int s;
+ int error, s;
- if (tapuopen == 0 && suser(td) != 0)
- return (EPERM);
+ if (tapuopen == 0) {
+ error = suser(td);
+ if (error != 0)
+ return (error);
+ }
if ((dev2unit(dev) & CLONE_UNITMASK) > TAPMAXUNIT)
return (ENXIO);
- /*
- * XXXRW: Non-atomic test-and-set of si_drv1. Currently protected
- * by Giant, but the race actually exists under memory pressure as
- * well even when running with Giant, as malloc() may sleep.
- */
tp = dev->si_drv1;
- if (tp == NULL) {
- tapcreate(dev);
- tp = dev->si_drv1;
- }
mtx_lock(&tp->tap_mtx);
if (tp->tap_flags & TAP_OPEN) {
@@ -496,7 +591,7 @@ tapifinit(void *xtp)
static int
tapifioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
- struct tap_softc *tp = (struct tap_softc *)(ifp->if_softc);
+ struct tap_softc *tp = ifp->if_softc;
struct ifstat *ifs = NULL;
int s, dummy;
@@ -612,7 +707,10 @@ tapioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td
struct tapinfo *tapp = NULL;
int s;
int f;
+#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
+ defined(COMPAT_FREEBSD4)
int ival;
+#endif
switch (cmd) {
case TAPSIFINFO:
@@ -687,10 +785,13 @@ tapioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td
bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags));
break;
+#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
+ defined(COMPAT_FREEBSD4)
case _IO('V', 0):
ival = IOCPARM_IVAL(data);
data = (caddr_t)&ival;
/* FALLTHROUGH */
+#endif
case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */
f = *(int *)data;
f &= 0x0fff;
diff --git a/sys/net/if_tun.c b/sys/net/if_tun.c
index f3eab702bb23..075ffedfc358 100644
--- a/sys/net/if_tun.c
+++ b/sys/net/if_tun.c
@@ -45,6 +45,7 @@
#include <sys/random.h>
#include <net/if.h>
+#include <net/if_clone.h>
#include <net/if_types.h>
#include <net/netisr.h>
#include <net/route.h>
@@ -103,13 +104,22 @@ struct tun_softc {
static struct mtx tunmtx;
static MALLOC_DEFINE(M_TUN, TUNNAME, "Tunnel Interface");
static int tundebug = 0;
+static int tundclone = 1;
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, "");
+SYSCTL_DECL(_net_link);
+SYSCTL_NODE(_net_link, OID_AUTO, tun, CTLFLAG_RW, 0,
+ "IP tunnel software network interface.");
+SYSCTL_INT(_net_link_tun, OID_AUTO, devfs_cloning, CTLFLAG_RW, &tundclone, 0,
+ "Enable legacy devfs interface creation.");
+
+TUNABLE_INT("net.link.tun.devfs_cloning", &tundclone);
+
static void tunclone(void *arg, struct ucred *cred, char *name,
int namelen, struct cdev **dev);
-static void tuncreate(struct cdev *dev);
+static void tuncreate(const char *name, struct cdev *dev);
static int tunifioctl(struct ifnet *, u_long, caddr_t);
static int tuninit(struct ifnet *);
static int tunmodevent(module_t, int, void *);
@@ -117,6 +127,11 @@ static int tunoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *rt);
static void tunstart(struct ifnet *);
+static int tun_clone_create(struct if_clone *, int);
+static void tun_clone_destroy(struct ifnet *);
+
+IFC_SIMPLE_DECLARE(tun, 0);
+
static d_open_t tunopen;
static d_close_t tunclose;
static d_read_t tunread;
@@ -156,15 +171,45 @@ static struct cdevsw tun_cdevsw = {
.d_name = TUNNAME,
};
+static int
+tun_clone_create(struct if_clone *ifc, int unit)
+{
+ struct cdev *dev;
+ int i;
+
+ /* find any existing device, or allocate new unit number */
+ i = clone_create(&tunclones, &tun_cdevsw, &unit, &dev, 0);
+ if (i) {
+ /* No preexisting struct cdev *, create one */
+ dev = make_dev(&tun_cdevsw, unit2minor(unit),
+ UID_UUCP, GID_DIALER, 0600, "%s%d", ifc->ifc_name, unit);
+ if (dev != NULL) {
+ dev_ref(dev);
+ dev->si_flags |= SI_CHEAPCLONE;
+ }
+ }
+ tuncreate(ifc->ifc_name, dev);
+
+ return (0);
+}
+
static void
tunclone(void *arg, struct ucred *cred, char *name, int namelen,
struct cdev **dev)
{
- int u, i;
+ char devname[SPECNAMELEN + 1];
+ int u, i, append_unit;
if (*dev != NULL)
return;
+ /*
+ * If tun cloning is enabled, only the superuser can create an
+ * interface.
+ */
+ if (!tundclone || suser_cred(cred, SUSER_ALLOWJAIL) != 0)
+ return;
+
if (strcmp(name, TUNNAME) == 0) {
u = -1;
} else if (dev_stdclone(name, NULL, TUNNAME, &u) != 1)
@@ -172,17 +217,29 @@ tunclone(void *arg, struct ucred *cred, char *name, int namelen,
if (u != -1 && u > IF_MAXUNIT)
return; /* Unit number too high */
+ if (u == -1)
+ append_unit = 1;
+ else
+ append_unit = 0;
+
/* find any existing device, or allocate new unit number */
i = clone_create(&tunclones, &tun_cdevsw, &u, dev, 0);
if (i) {
+ if (append_unit) {
+ namelen = snprintf(devname, sizeof(devname), "%s%d", name,
+ u);
+ name = devname;
+ }
/* No preexisting struct cdev *, create one */
*dev = make_dev(&tun_cdevsw, unit2minor(u),
- UID_UUCP, GID_DIALER, 0600, "tun%d", u);
+ UID_UUCP, GID_DIALER, 0600, "%s", name);
if (*dev != NULL) {
dev_ref(*dev);
(*dev)->si_flags |= SI_CHEAPCLONE;
}
}
+
+ if_clone_create(name, namelen);
}
static void
@@ -204,6 +261,17 @@ tun_destroy(struct tun_softc *tp)
free(tp, M_TUN);
}
+static void
+tun_clone_destroy(struct ifnet *ifp)
+{
+ struct tun_softc *tp = ifp->if_softc;
+
+ mtx_lock(&tunmtx);
+ TAILQ_REMOVE(&tunhead, tp, tun_list);
+ mtx_unlock(&tunmtx);
+ tun_destroy(tp);
+}
+
static int
tunmodevent(module_t mod, int type, void *data)
{
@@ -217,8 +285,10 @@ tunmodevent(module_t mod, int type, void *data)
tag = EVENTHANDLER_REGISTER(dev_clone, tunclone, 0, 1000);
if (tag == NULL)
return (ENOMEM);
+ if_clone_attach(&tun_cloner);
break;
case MOD_UNLOAD:
+ if_clone_detach(&tun_cloner);
EVENTHANDLER_DEREGISTER(dev_clone, tag);
mtx_lock(&tunmtx);
@@ -279,7 +349,7 @@ tunstart(struct ifnet *ifp)
/* XXX: should return an error code so it can fail. */
static void
-tuncreate(struct cdev *dev)
+tuncreate(const char *name, struct cdev *dev)
{
struct tun_softc *sc;
struct ifnet *ifp;
@@ -297,8 +367,8 @@ tuncreate(struct cdev *dev)
ifp = sc->tun_ifp = if_alloc(IFT_PPP);
if (ifp == NULL)
panic("%s%d: failed to if_alloc() interface.\n",
- TUNNAME, dev2unit(dev));
- if_initname(ifp, TUNNAME, dev2unit(dev));
+ name, dev2unit(dev));
+ if_initname(ifp, name, dev2unit(dev));
ifp->if_mtu = TUNMTU;
ifp->if_ioctl = tunifioctl;
ifp->if_output = tunoutput;
@@ -329,7 +399,7 @@ tunopen(struct cdev *dev, int flag, int mode, struct thread *td)
*/
tp = dev->si_drv1;
if (!tp) {
- tuncreate(dev);
+ tuncreate(TUNNAME, dev);
tp = dev->si_drv1;
}
@@ -425,29 +495,23 @@ tuninit(struct ifnet *ifp)
ifp->if_drv_flags |= IFF_DRV_RUNNING;
getmicrotime(&ifp->if_lastchange);
- for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa;
- ifa = TAILQ_NEXT(ifa, ifa_link)) {
- if (ifa->ifa_addr == NULL)
- error = EFAULT;
- /* XXX: Should maybe return straight off? */
- else {
#ifdef INET
- if (ifa->ifa_addr->sa_family == AF_INET) {
- struct sockaddr_in *si;
+ TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ if (ifa->ifa_addr->sa_family == AF_INET) {
+ struct sockaddr_in *si;
- si = (struct sockaddr_in *)ifa->ifa_addr;
- mtx_lock(&tp->tun_mtx);
- if (si->sin_addr.s_addr)
- tp->tun_flags |= TUN_IASET;
+ si = (struct sockaddr_in *)ifa->ifa_addr;
+ mtx_lock(&tp->tun_mtx);
+ if (si->sin_addr.s_addr)
+ tp->tun_flags |= TUN_IASET;
- si = (struct sockaddr_in *)ifa->ifa_dstaddr;
- if (si && si->sin_addr.s_addr)
- tp->tun_flags |= TUN_DSTADDR;
- mtx_unlock(&tp->tun_mtx);
- }
-#endif
+ si = (struct sockaddr_in *)ifa->ifa_dstaddr;
+ if (si && si->sin_addr.s_addr)
+ tp->tun_flags |= TUN_DSTADDR;
+ mtx_unlock(&tp->tun_mtx);
}
}
+#endif
return (error);
}
@@ -607,9 +671,11 @@ tunioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td
tunp = (struct tuninfo *)data;
if (tunp->mtu < IF_MINMTU)
return (EINVAL);
- if (TUN2IFP(tp)->if_mtu != tunp->mtu
- && (error = suser(td)) != 0)
- return (error);
+ if (TUN2IFP(tp)->if_mtu != tunp->mtu) {
+ error = suser(td);
+ if (error != 0)
+ return (error);
+ }
TUN2IFP(tp)->if_mtu = tunp->mtu;
TUN2IFP(tp)->if_type = tunp->type;
TUN2IFP(tp)->if_baudrate = tunp->baudrate;