diff --git a/sys/net/tap/if_tap.c b/sys/net/tap/if_tap.c index f4bd6ca..e50ae4b 100644 --- a/sys/net/tap/if_tap.c +++ b/sys/net/tap/if_tap.c @@ -65,6 +65,7 @@ #include #include #include +#include #include #include @@ -87,6 +88,11 @@ static int tapmodevent (module_t, int, void *); /* device */ static void tapcreate (cdev_t); +/* clone */ +static int tap_clone_create(struct if_clone *, int); +static void tap_clone_destroy(struct ifnet *); + + /* network interface */ static void tapifstart (struct ifnet *); static int tapifioctl (struct ifnet *, u_long, caddr_t, @@ -117,10 +123,24 @@ static struct dev_ops tap_ops = { static int taprefcnt = 0; /* module ref. counter */ static int taplastunit = -1; /* max. open unit number */ static int tapdebug = 0; /* debug flag */ +static int tapuopen = 0; /* all user open() */ +static int tapuponopen = 0; /* IFF_UP */ MALLOC_DECLARE(M_TAP); MALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface"); +struct if_clone tap_cloner = IF_CLONE_INITIALIZER("tap", + tap_clone_create, + tap_clone_destroy, 0, IF_MAXUNIT); SYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, ""); +SYSCTL_DECL(_net_link); +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, up_on_open, CTLFLAG_RW, &tapuponopen, 0, + "Bring interface up when /dev/tap is opened"); +SYSCTL_INT(_net_link_tap, OID_AUTO, debug, CTLFLAG_RW, &tapdebug, 0, ""); + DEV_MODULE(if_tap, tapmodevent, NULL); /* @@ -131,55 +151,28 @@ DEV_MODULE(if_tap, tapmodevent, NULL); static int tapmodevent(module_t mod, int type, void *data) { - static int attached = 0; - struct ifnet *ifp = NULL; - int unit; - + struct tap_softc* tp; switch (type) { case MOD_LOAD: - if (attached) + if (!SLIST_EMPTY(&tap_listhead)) return (EEXIST); dev_ops_add(&tap_ops, 0, 0); - attached = 1; + SLIST_INIT(&tap_listhead); + if_clone_attach(&tap_cloner); + break; case MOD_UNLOAD: if (taprefcnt > 0) return (EBUSY); + if_clone_detach(&tap_cloner); dev_ops_remove(&tap_ops, 0, 0); - /* XXX: maintain tap ifs in a local list */ - unit = 0; - while (unit <= taplastunit) { - TAILQ_FOREACH(ifp, &ifnet, if_link) { - if ((strcmp(ifp->if_dname, TAP) == 0) || - (strcmp(ifp->if_dname, VMNET) == 0)) { - if (ifp->if_dunit == unit) - break; - } - } - - if (ifp != NULL) { - struct tap_softc *tp = ifp->if_softc; - - TAPDEBUG(ifp, "detached. minor = %#x, " \ - "taplastunit = %d\n", - minor(tp->tap_dev), taplastunit); - - ifnet_serialize_all(ifp); - tapifstop(tp, 1); - ifnet_deserialize_all(ifp); - - ether_ifdetach(ifp); - destroy_dev(tp->tap_dev); - kfree(tp, M_TAP); - } else { - unit++; - } - } - attached = 0; + /* maintain tap ifs in a local list */ + SLIST_FOREACH(tp, &tap_listhead, tap_entries) + tap_clone_destroy(&tp->tap_if); break; default: @@ -250,9 +243,64 @@ tapcreate(cdev_t dev) tp->tap_flags |= TAP_INITED; tp->tap_devq.ifq_maxlen = ifqmaxlen; + SLIST_INSERT_HEAD(&tap_listhead, tp, tap_entries); + TAPDEBUG(ifp, "created. minor = %#x\n", minor(tp->tap_dev)); } /* tapcreate */ +/* + * tap_clone_create: + * + * Create a new tap instance. + */ +static int +tap_clone_create(struct if_clone *ifc, int unit) +{ + struct ifnet *ifp = NULL; + struct tap_softc *tp = NULL; + uint8_t ether_addr[ETHER_ADDR_LEN]; + + MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO); + + tp->tap_dev = make_dev(&tap_ops, unit, UID_ROOT, GID_WHEEL, + 0600, "%s%d", ifc->ifc_name, unit); + tp->tap_dev->si_drv1 = tp; + reference_dev(tp->tap_dev); /* so we can destroy it later */ + + /* generate fake MAC address: 00 bd xx xx xx unit_no */ + ether_addr[0] = 0x00; + ether_addr[1] = 0xbd; + bcopy(&ticks, ðer_addr[2], 3); + ether_addr[5] = (u_char)unit; + + ifp = &tp->tap_if; + ifp->if_softc = tp; + + if_initname(ifp, ifc->ifc_name, unit); + if (unit > taplastunit) + taplastunit = unit; + + ifp->if_init = tapifinit; + ifp->if_start = tapifstart; + ifp->if_ioctl = tapifioctl; + ifp->if_mtu = ETHERMTU; + ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); + ifq_set_maxlen(&ifp->if_snd, ifqmaxlen); + ifq_set_ready(&ifp->if_snd); + + ether_ifattach(ifp, ether_addr, NULL); + + tp->tap_flags |= TAP_INITED; + tp->tap_devq.ifq_maxlen = ifqmaxlen; + + SLIST_INSERT_HEAD(&tap_listhead, tp, tap_entries); + + TAPDEBUG(ifp, "clone created. minor = %#x tap_flags = 0x%x\n", + minor(tp->tap_dev), tp->tap_flags); + + return (0); +} + /* * tapopen @@ -262,15 +310,17 @@ tapcreate(cdev_t dev) static int tapopen(struct dev_open_args *ap) { - cdev_t dev = ap->a_head.a_dev; + cdev_t dev = NULL; struct tap_softc *tp = NULL; struct ifnet *ifp = NULL; int error; - if ((error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0)) != 0) + if (tapuopen == 0 && + (error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0)) != 0) return (error); get_mplock(); + dev = ap->a_head.a_dev; tp = dev->si_drv1; if (tp == NULL) { tapcreate(dev); @@ -296,6 +346,10 @@ tapopen(struct dev_open_args *ap) fsetown(curthread->td_proc->p_pid, &tp->tap_sigtd); tp->tap_flags |= TAP_OPEN; taprefcnt ++; + ifp = &tp->tap_if; + + if (tapuponopen) + ifp->if_flags |= IFF_UP; TAPDEBUG(ifp, "opened. minor = %#x, refcnt = %d, taplastunit = %d\n", minor(tp->tap_dev), taprefcnt, taplastunit); @@ -366,6 +420,35 @@ tapclose(struct dev_close_args *ap) return (0); } +/* + * tap_clone_destroy: + * + * Destroy a tap instance. + */ +static void +tap_clone_destroy(struct ifnet *ifp) +{ + struct tap_softc *tp = ifp->if_softc; + + TAPDEBUG(ifp, "clone destroyed. minor = %#x, refcnt = %d, taplastunit = %d\n", + minor(tp->tap_dev), taprefcnt, taplastunit); + /* + * Do we really need this? + */ + IF_DRAIN(&ifp->if_snd); + + ifnet_serialize_all(ifp); + tapifstop(tp, 1); + ifnet_deserialize_all(ifp); + + ether_ifdetach(ifp); + SLIST_REMOVE(&tap_listhead, tp, tap_softc, tap_entries); + + destroy_dev(tp->tap_dev); + kfree(tp, M_TAP); + + taplastunit--; +} /* * tapifinit @@ -380,7 +463,8 @@ tapifinit(void *xtp) struct tap_softc *tp = xtp; struct ifnet *ifp = &tp->tap_if; - TAPDEBUG(ifp, "initializing, minor = %#x\n", minor(tp->tap_dev)); + TAPDEBUG(ifp, "initializing, minor = %#x tap_flags = 0x%x\n", + minor(tp->tap_dev), tp->tap_flags); ASSERT_IFNET_SERIALIZED_ALL(ifp); @@ -745,7 +829,7 @@ tapwrite(struct dev_write_args *ap) struct mbuf *top = NULL, **mp = NULL, *m = NULL; int error = 0, tlen, mlen; - TAPDEBUG(ifp, "writing, minor = %#x\n", minor(tp->tap_dev)); +// TAPDEBUG(ifp, "writing, minor = %#x\n", minor(tp->tap_dev)); if (uio->uio_resid == 0) return (0); @@ -844,7 +928,8 @@ tappoll(struct dev_poll_args *ap) if (ap->a_events & (POLLOUT | POLLWRNORM)) revents |= (ap->a_events & (POLLOUT | POLLWRNORM)); ap->a_events = revents; - return(0); + + return revents; } /* diff --git a/sys/net/tap/if_tapvar.h b/sys/net/tap/if_tapvar.h index 2cd173e..cc712d5 100644 --- a/sys/net/tap/if_tapvar.h +++ b/sys/net/tap/if_tapvar.h @@ -61,6 +61,10 @@ struct tap_softc { struct sigio *tap_sigio; /* information for async I/O */ struct selinfo tap_rsel; /* read select */ struct ifqueue tap_devq; + + SLIST_ENTRY(tap_softc) tap_entries; }; +SLIST_HEAD(,tap_softc) tap_listhead; + #endif /* !_NET_IF_TAPVAR_H_ */