Bug #1357 ยป tap7.diff
sys/net/tap/if_tap.c | ||
---|---|---|
#include <net/if.h>
|
||
#include <net/ifq_var.h>
|
||
#include <net/if_arp.h>
|
||
#include <net/if_clone.h>
|
||
#include <net/route.h>
|
||
#include <netinet/in.h>
|
||
... | ... | |
/* 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,
|
||
... | ... | |
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);
|
||
/*
|
||
... | ... | |
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:
|
||
... | ... | |
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
|
||
... | ... | |
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);
|
||
... | ... | |
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);
|
||
... | ... | |
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
|
||
... | ... | |
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);
|
||
... | ... | |
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);
|
||
... | ... | |
if (ap->a_events & (POLLOUT | POLLWRNORM))
|
||
revents |= (ap->a_events & (POLLOUT | POLLWRNORM));
|
||
ap->a_events = revents;
|
||
return(0);
|
||
return revents;
|
||
}
|
||
/*
|
sys/net/tap/if_tapvar.h | ||
---|---|---|
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_ */
|