Project

General

Profile

Bug #1357 ยป tap7.diff

naoya.sugioka, 05/06/2009 12:38 AM

View differences:

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, &ether_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_ */
    (1-1/1)