if_tap.c revision 111119
163670Snsayer/*
263670Snsayer * Copyright (C) 1999-2000 by Maksim Yevmenkin <m_evmenkin@yahoo.com>
363670Snsayer * All rights reserved.
463670Snsayer *
563670Snsayer * Redistribution and use in source and binary forms, with or without
663670Snsayer * modification, are permitted provided that the following conditions
763670Snsayer * are met:
863670Snsayer * 1. Redistributions of source code must retain the above copyright
963670Snsayer *    notice, this list of conditions and the following disclaimer.
1063670Snsayer * 2. Redistributions in binary form must reproduce the above copyright
1163670Snsayer *    notice, this list of conditions and the following disclaimer in the
1263670Snsayer *    documentation and/or other materials provided with the distribution.
1363670Snsayer *
1463670Snsayer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1563670Snsayer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1663670Snsayer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1763670Snsayer * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1863670Snsayer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1963670Snsayer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2063670Snsayer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2163670Snsayer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2263670Snsayer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2363670Snsayer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2463670Snsayer * SUCH DAMAGE.
2563670Snsayer *
2663670Snsayer * BASED ON:
2763670Snsayer * -------------------------------------------------------------------------
2863670Snsayer *
2963670Snsayer * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk>
3063670Snsayer * Nottingham University 1987.
3163670Snsayer */
3263670Snsayer
3363670Snsayer/*
3463670Snsayer * $FreeBSD: head/sys/net/if_tap.c 111119 2003-02-19 05:47:46Z imp $
3563803Snsayer * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $
3663670Snsayer */
3763670Snsayer
3863670Snsayer#include "opt_inet.h"
3963670Snsayer
4063670Snsayer#include <sys/param.h>
4163670Snsayer#include <sys/conf.h>
4263670Snsayer#include <sys/filedesc.h>
4363670Snsayer#include <sys/filio.h>
4463670Snsayer#include <sys/kernel.h>
4563670Snsayer#include <sys/malloc.h>
4663670Snsayer#include <sys/mbuf.h>
4763670Snsayer#include <sys/poll.h>
4863670Snsayer#include <sys/proc.h>
4963670Snsayer#include <sys/signalvar.h>
5063670Snsayer#include <sys/socket.h>
5163670Snsayer#include <sys/sockio.h>
5263670Snsayer#include <sys/sysctl.h>
5363670Snsayer#include <sys/systm.h>
5463670Snsayer#include <sys/ttycom.h>
5563670Snsayer#include <sys/uio.h>
5663670Snsayer#include <sys/vnode.h>
5783043Sbrooks#include <machine/bus.h>	/* XXX: Shouldn't really be required! */
5883043Sbrooks#include <sys/rman.h>
5983043Sbrooks#include <sys/queue.h>
6063670Snsayer
6163670Snsayer#include <net/bpf.h>
6263670Snsayer#include <net/ethernet.h>
6363670Snsayer#include <net/if.h>
6463670Snsayer#include <net/if_arp.h>
6563670Snsayer#include <net/route.h>
6663670Snsayer
6763670Snsayer#include <netinet/in.h>
6863670Snsayer
6963670Snsayer#include <net/if_tapvar.h>
7063670Snsayer#include <net/if_tap.h>
7163670Snsayer
7263670Snsayer
7363670Snsayer#define CDEV_NAME	"tap"
7463670Snsayer#define CDEV_MAJOR	149
7563670Snsayer#define TAPDEBUG	if (tapdebug) printf
7663670Snsayer
7763670Snsayer#define TAP		"tap"
7863670Snsayer#define VMNET		"vmnet"
7983043Sbrooks#define TAPMAXUNIT	0x7fff
8083043Sbrooks#define VMNET_DEV_MASK	0x00800000
8183043Sbrooks		/*	0x007f00ff	*/
8263670Snsayer
8363670Snsayer/* module */
8493084Sbdestatic int 		tapmodevent(module_t, int, void *);
8563670Snsayer
8663670Snsayer/* device */
8793084Sbdestatic void		tapclone(void *, char *, int, dev_t *);
8893084Sbdestatic void		tapcreate(dev_t);
8963670Snsayer
9063670Snsayer/* network interface */
9193084Sbdestatic void		tapifstart(struct ifnet *);
9293084Sbdestatic int		tapifioctl(struct ifnet *, u_long, caddr_t);
9393084Sbdestatic void		tapifinit(void *);
9463670Snsayer
9563670Snsayer/* character device */
9663670Snsayerstatic d_open_t		tapopen;
9763670Snsayerstatic d_close_t	tapclose;
9863670Snsayerstatic d_read_t		tapread;
9963670Snsayerstatic d_write_t	tapwrite;
10063670Snsayerstatic d_ioctl_t	tapioctl;
10163670Snsayerstatic d_poll_t		tappoll;
10263670Snsayer
10363670Snsayerstatic struct cdevsw	tap_cdevsw = {
10463670Snsayer	/* open */	tapopen,
10563670Snsayer	/* close */	tapclose,
10663670Snsayer	/* read */	tapread,
10763670Snsayer	/* write */	tapwrite,
10863670Snsayer	/* ioctl */	tapioctl,
10963670Snsayer	/* poll */	tappoll,
11063670Snsayer	/* mmap */	nommap,
11163670Snsayer	/* startegy */	nostrategy,
11263670Snsayer	/* dev name */	CDEV_NAME,
11363670Snsayer	/* dev major */	CDEV_MAJOR,
11463670Snsayer	/* dump */	nodump,
11563670Snsayer	/* psize */	nopsize,
11663670Snsayer	/* flags */	0,
11763670Snsayer};
11863670Snsayer
11983043Sbrooksstatic int			tapdebug = 0;        /* debug flag   */
12083043Sbrooksstatic SLIST_HEAD(, tap_softc)	taphead;             /* first device */
12183043Sbrooksstatic udev_t			tapbasedev = NOUDEV; /* base device  */
12283043Sbrooksstatic struct rman		tapdevunits[2];      /* device units */
12383043Sbrooks#define		tapunits	tapdevunits
12483043Sbrooks#define		vmnetunits	(tapdevunits + 1)
12563670Snsayer
12663670SnsayerMALLOC_DECLARE(M_TAP);
12763670SnsayerMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface");
12863670SnsayerSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, "");
12963670SnsayerDEV_MODULE(if_tap, tapmodevent, NULL);
13063670Snsayer
13163670Snsayer/*
13263670Snsayer * tapmodevent
13363670Snsayer *
13463670Snsayer * module event handler
13563670Snsayer */
13663670Snsayerstatic int
13763670Snsayertapmodevent(mod, type, data)
13863670Snsayer	module_t	 mod;
13963670Snsayer	int		 type;
14063670Snsayer	void		*data;
14163670Snsayer{
14283043Sbrooks	static eventhandler_tag	 eh_tag = NULL;
14383043Sbrooks	struct tap_softc	*tp = NULL;
14483043Sbrooks	struct ifnet		*ifp = NULL;
14583043Sbrooks	int			 error, s;
14663670Snsayer
14763670Snsayer	switch (type) {
14863670Snsayer	case MOD_LOAD:
14983043Sbrooks		/* initialize resources */
15083043Sbrooks		tapunits->rm_type = RMAN_ARRAY;
15183043Sbrooks		tapunits->rm_descr = "open tap units";
15283043Sbrooks		vmnetunits->rm_type = RMAN_ARRAY;
15383043Sbrooks		vmnetunits->rm_descr = "open vmnet units";
15463670Snsayer
15583043Sbrooks		error = rman_init(tapunits);
15683043Sbrooks		if (error != 0)
15783043Sbrooks			goto bail;
15883043Sbrooks
15983043Sbrooks		error = rman_init(vmnetunits);
16083043Sbrooks		if (error != 0)
16183043Sbrooks			goto bail1;
16283043Sbrooks
16383043Sbrooks		error = rman_manage_region(tapunits, 0, TAPMAXUNIT);
16483043Sbrooks		if (error != 0)
16583043Sbrooks			goto bail2;
16683043Sbrooks
16783043Sbrooks		error = rman_manage_region(vmnetunits, 0, TAPMAXUNIT);
16883043Sbrooks		if (error != 0)
16983043Sbrooks			goto bail2;
17083043Sbrooks
17183043Sbrooks		/* intitialize device */
17283043Sbrooks
17383043Sbrooks		SLIST_INIT(&taphead);
17483043Sbrooks
17571602Sphk		eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000);
17683043Sbrooks		if (eh_tag == NULL) {
17783043Sbrooks			error = ENOMEM;
17883043Sbrooks			goto bail2;
17983043Sbrooks		}
18063670Snsayer
18171602Sphk
18283043Sbrooks		return (0);
18383043Sbrooksbail2:
18483043Sbrooks		rman_fini(vmnetunits);
18583043Sbrooksbail1:
18683043Sbrooks		rman_fini(tapunits);
18783043Sbrooksbail:
18883043Sbrooks		return (error);
18963670Snsayer
19083043Sbrooks	case MOD_UNLOAD:
19183043Sbrooks		SLIST_FOREACH(tp, &taphead, tap_next)
19283043Sbrooks			if (tp->tap_unit != NULL)
19383043Sbrooks				return (EBUSY);
19483043Sbrooks
19571602Sphk		EVENTHANDLER_DEREGISTER(dev_clone, eh_tag);
19663670Snsayer
19783043Sbrooks		error = rman_fini(tapunits);
19883043Sbrooks		KASSERT((error == 0), ("Could not fini tap units"));
19983043Sbrooks		error = rman_fini(vmnetunits);
20083043Sbrooks		KASSERT((error == 0), ("Could not fini vmnet units"));
20171602Sphk
20283043Sbrooks		while ((tp = SLIST_FIRST(&taphead)) != NULL) {
20383043Sbrooks			SLIST_REMOVE_HEAD(&taphead, tap_next);
20483043Sbrooks
20583043Sbrooks			ifp = &tp->tap_if;
20683043Sbrooks
20783043Sbrooks			TAPDEBUG("detaching %s%d\n", ifp->if_name,ifp->if_unit);
20883043Sbrooks
20983043Sbrooks			KASSERT(!(tp->tap_flags & TAP_OPEN),
21083043Sbrooks				("%s%d flags is out of sync", ifp->if_name,
21183043Sbrooks				ifp->if_unit));
21283043Sbrooks
21383043Sbrooks			/* XXX makedev check? nah.. not right now :) */
21483043Sbrooks
21563670Snsayer			s = splimp();
216106939Ssam			ether_ifdetach(ifp);
21763670Snsayer			splx(s);
21863670Snsayer
21993752Sluigi			free(tp, M_TAP);
22083043Sbrooks		}
22163670Snsayer
22283043Sbrooks 		if (tapbasedev != NOUDEV)
22383043Sbrooks			destroy_dev(udev2dev(tapbasedev, 0));
22463670Snsayer
22563670Snsayer
22683043Sbrooks		break;
22763670Snsayer
22863670Snsayer	default:
22963670Snsayer		return (EOPNOTSUPP);
23063670Snsayer	}
23163670Snsayer
23263670Snsayer	return (0);
23363670Snsayer} /* tapmodevent */
23463670Snsayer
23563670Snsayer
23663670Snsayer/*
23771602Sphk * DEVFS handler
23871602Sphk *
23971602Sphk * We need to support two kind of devices - tap and vmnet
24071602Sphk */
24171602Sphkstatic void
24271602Sphktapclone(arg, name, namelen, dev)
24371602Sphk	void	*arg;
24471602Sphk	char	*name;
24571602Sphk	int	 namelen;
24671602Sphk	dev_t	*dev;
24771602Sphk{
24883043Sbrooks	int		 unit, minor = 0 /* XXX avoid warning */ , error;
24983043Sbrooks	char		*device_name = name;
25083043Sbrooks	struct resource	*r = NULL;
25171602Sphk
25271602Sphk	if (*dev != NODEV)
25371602Sphk		return;
25471602Sphk
25583043Sbrooks	if (strcmp(device_name, TAP) == 0) {
25683043Sbrooks		/* get first free tap unit */
25783043Sbrooks		r = rman_reserve_resource(tapunits, 0, TAPMAXUNIT, 1,
25883043Sbrooks			RF_ALLOCATED | RF_ACTIVE, NULL);
25983043Sbrooks		unit = rman_get_start(r);
26083043Sbrooks		minor = unit2minor(unit);
26183043Sbrooks	}
26283043Sbrooks	else if (strcmp(device_name, VMNET) == 0) {
26383043Sbrooks		/* get first free vmnet unit */
26483043Sbrooks		r = rman_reserve_resource(vmnetunits, 0, TAPMAXUNIT, 1,
26583043Sbrooks			RF_ALLOCATED | RF_ACTIVE, NULL);
26683043Sbrooks		unit = rman_get_start(r);
26783043Sbrooks		minor = unit2minor(unit) | VMNET_DEV_MASK;
26883043Sbrooks	}
26971602Sphk
27083043Sbrooks	if (r != NULL) { /* need cloning */
27183043Sbrooks		TAPDEBUG("%s%d is available. minor = %#x\n",
27283043Sbrooks			device_name, unit, minor);
27371602Sphk
27483043Sbrooks		error = rman_release_resource(r);
27583043Sbrooks		KASSERT((error == 0), ("Could not release tap/vmnet unit"));
27683043Sbrooks
27783043Sbrooks		/* check if device for the unit has been created */
27883043Sbrooks		*dev = makedev(CDEV_MAJOR, minor);
27983043Sbrooks		if ((*dev)->si_flags & SI_NAMED) {
28083043Sbrooks			TAPDEBUG("%s%d device exists. minor = %#x\n",
28183043Sbrooks				device_name, unit, minor);
28283043Sbrooks			return; /* device has been created */
28383043Sbrooks		}
28483043Sbrooks	} else { /* try to match name/unit, first try tap then vmnet */
28583043Sbrooks		device_name = TAP;
28683043Sbrooks		if (dev_stdclone(name, NULL, device_name, &unit) != 1) {
28783043Sbrooks			device_name = VMNET;
28883043Sbrooks
28983043Sbrooks			if (dev_stdclone(name, NULL, device_name, &unit) != 1)
29083043Sbrooks				return;
29183043Sbrooks
29283043Sbrooks			minor = unit2minor(unit) | VMNET_DEV_MASK;
29383043Sbrooks		} else
29483043Sbrooks			minor = unit2minor(unit);
29571602Sphk	}
29671602Sphk
29783043Sbrooks	TAPDEBUG("make_dev(%s%d). minor = %#x\n", device_name, unit, minor);
29883043Sbrooks
29971602Sphk	*dev = make_dev(&tap_cdevsw, minor, UID_ROOT, GID_WHEEL, 0600, "%s%d",
30071602Sphk			device_name, unit);
30183043Sbrooks
30283043Sbrooks	if (tapbasedev == NOUDEV)
30383043Sbrooks		tapbasedev = (*dev)->si_udev;
30483043Sbrooks	else {
30583043Sbrooks		(*dev)->si_flags |= SI_CHEAPCLONE;
30683043Sbrooks		dev_depends(udev2dev(tapbasedev, 0), *dev);
30783043Sbrooks	}
30871602Sphk} /* tapclone */
30971602Sphk
31071602Sphk
31171602Sphk/*
31263670Snsayer * tapcreate
31363670Snsayer *
31463670Snsayer * to create interface
31563670Snsayer */
31663670Snsayerstatic void
31763670Snsayertapcreate(dev)
31863670Snsayer	dev_t	dev;
31963670Snsayer{
32063670Snsayer	struct ifnet		*ifp = NULL;
32163670Snsayer	struct tap_softc	*tp = NULL;
32263670Snsayer	unsigned short		 macaddr_hi;
32363803Snsayer	int			 unit, s;
32463670Snsayer	char			*name = NULL;
32563670Snsayer
32663670Snsayer	/* allocate driver storage and create device */
327111119Simp	MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO);
32883043Sbrooks	SLIST_INSERT_HEAD(&taphead, tp, tap_next);
32963670Snsayer
33083043Sbrooks	unit = dev2unit(dev) & TAPMAXUNIT;
33183043Sbrooks
33263670Snsayer	/* select device: tap or vmnet */
33363670Snsayer	if (minor(dev) & VMNET_DEV_MASK) {
33463670Snsayer		name = VMNET;
33563803Snsayer		tp->tap_flags |= TAP_VMNET;
33683043Sbrooks	} else
33763670Snsayer		name = TAP;
33863670Snsayer
33983043Sbrooks	TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev));
34083043Sbrooks
34183043Sbrooks	if (!(dev->si_flags & SI_NAMED))
34283043Sbrooks		dev = make_dev(&tap_cdevsw, minor(dev), UID_ROOT, GID_WHEEL,
34363670Snsayer						0600, "%s%d", name, unit);
34463670Snsayer
34563670Snsayer	/* generate fake MAC address: 00 bd xx xx xx unit_no */
34663670Snsayer	macaddr_hi = htons(0x00bd);
34763670Snsayer	bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short));
34863670Snsayer	bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long));
34963670Snsayer	tp->arpcom.ac_enaddr[5] = (u_char)unit;
35063670Snsayer
35163670Snsayer	/* fill the rest and attach interface */
35263670Snsayer	ifp = &tp->tap_if;
35363670Snsayer	ifp->if_softc = tp;
35463670Snsayer	ifp->if_unit = unit;
35563670Snsayer	ifp->if_name = name;
35663670Snsayer	ifp->if_init = tapifinit;
35763670Snsayer	ifp->if_start = tapifstart;
35863670Snsayer	ifp->if_ioctl = tapifioctl;
35963670Snsayer	ifp->if_mtu = ETHERMTU;
36063670Snsayer	ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
36163670Snsayer	ifp->if_snd.ifq_maxlen = ifqmaxlen;
36263670Snsayer
36383043Sbrooks	dev->si_drv1 = tp;
36483043Sbrooks
36563803Snsayer	s = splimp();
366106939Ssam	ether_ifattach(ifp, tp->arpcom.ac_enaddr);
36763803Snsayer	splx(s);
36863670Snsayer
36963803Snsayer	tp->tap_flags |= TAP_INITED;
37063803Snsayer
37183043Sbrooks	TAPDEBUG("interface %s%d is created. minor = %#x\n",
37283043Sbrooks		ifp->if_name, ifp->if_unit, minor(dev));
37363670Snsayer} /* tapcreate */
37463670Snsayer
37563670Snsayer
37663670Snsayer/*
37763670Snsayer * tapopen
37863670Snsayer *
37963670Snsayer * to open tunnel. must be superuser
38063670Snsayer */
38163670Snsayerstatic int
38283366Sjuliantapopen(dev, flag, mode, td)
38363670Snsayer	dev_t		 dev;
38463670Snsayer	int		 flag;
38563670Snsayer	int		 mode;
38683366Sjulian	struct thread	*td;
38763670Snsayer{
38863670Snsayer	struct tap_softc	*tp = NULL;
38983043Sbrooks	int			 unit, error;
39083043Sbrooks	struct resource		*r = NULL;
39163670Snsayer
39293593Sjhb	if ((error = suser(td)) != 0)
39363670Snsayer		return (error);
39463670Snsayer
39583043Sbrooks	unit = dev2unit(dev) & TAPMAXUNIT;
39683043Sbrooks
39783043Sbrooks	if (minor(dev) & VMNET_DEV_MASK)
39883043Sbrooks		r = rman_reserve_resource(vmnetunits, unit, unit, 1,
39983043Sbrooks			RF_ALLOCATED | RF_ACTIVE, NULL);
40083043Sbrooks	else
40183043Sbrooks		r = rman_reserve_resource(tapunits, unit, unit, 1,
40283043Sbrooks			RF_ALLOCATED | RF_ACTIVE, NULL);
40383043Sbrooks
40483043Sbrooks	if (r == NULL)
40583043Sbrooks		return (EBUSY);
40683043Sbrooks
40783043Sbrooks	dev->si_flags &= ~SI_CHEAPCLONE;
40883043Sbrooks
40963670Snsayer	tp = dev->si_drv1;
41063670Snsayer	if (tp == NULL) {
41163670Snsayer		tapcreate(dev);
41263670Snsayer		tp = dev->si_drv1;
41363670Snsayer	}
41463670Snsayer
41583043Sbrooks	KASSERT(!(tp->tap_flags & TAP_OPEN),
41683043Sbrooks		("%s%d flags is out of sync", tp->tap_if.if_name, unit));
41763670Snsayer
41863861Snsayer	bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr));
41963861Snsayer
42083043Sbrooks	tp->tap_unit = r;
42183366Sjulian	tp->tap_pid = td->td_proc->p_pid;
42263670Snsayer	tp->tap_flags |= TAP_OPEN;
42363670Snsayer
42483043Sbrooks	TAPDEBUG("%s%d is open. minor = %#x\n",
42583043Sbrooks		tp->tap_if.if_name, unit, minor(dev));
42663670Snsayer
42763670Snsayer	return (0);
42863670Snsayer} /* tapopen */
42963670Snsayer
43063670Snsayer
43163670Snsayer/*
43263670Snsayer * tapclose
43363670Snsayer *
43463670Snsayer * close the device - mark i/f down & delete routing info
43563670Snsayer */
43663670Snsayerstatic int
43783366Sjuliantapclose(dev, foo, bar, td)
43863670Snsayer	dev_t		 dev;
43963670Snsayer	int		 foo;
44063670Snsayer	int		 bar;
44183366Sjulian	struct thread	*td;
44263670Snsayer{
44383043Sbrooks	int			 s, error;
44463670Snsayer	struct tap_softc	*tp = dev->si_drv1;
44563670Snsayer	struct ifnet		*ifp = &tp->tap_if;
44663670Snsayer
44787914Sjlemon	KASSERT((tp->tap_unit != NULL),
44883043Sbrooks		("%s%d is not open", ifp->if_name, ifp->if_unit));
44983043Sbrooks
45063670Snsayer	/* junk all pending output */
45183043Sbrooks	IF_DRAIN(&ifp->if_snd);
45263670Snsayer
45363803Snsayer	/*
45463803Snsayer	 * do not bring the interface down, and do not anything with
45563803Snsayer	 * interface, if we are in VMnet mode. just close the device.
45663803Snsayer	 */
45763803Snsayer
45863803Snsayer	if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) {
45963670Snsayer		s = splimp();
46063670Snsayer		if_down(ifp);
46163670Snsayer		if (ifp->if_flags & IFF_RUNNING) {
46263670Snsayer			/* find internet addresses and delete routes */
46363670Snsayer			struct ifaddr	*ifa = NULL;
46463670Snsayer
46563803Snsayer			TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
46663670Snsayer				if (ifa->ifa_addr->sa_family == AF_INET) {
46763670Snsayer					rtinit(ifa, (int)RTM_DELETE, 0);
46863670Snsayer
46963670Snsayer					/* remove address from interface */
47063670Snsayer					bzero(ifa->ifa_addr,
47163670Snsayer						   sizeof(*(ifa->ifa_addr)));
47263670Snsayer					bzero(ifa->ifa_dstaddr,
47363670Snsayer						   sizeof(*(ifa->ifa_dstaddr)));
47463670Snsayer					bzero(ifa->ifa_netmask,
47563670Snsayer						   sizeof(*(ifa->ifa_netmask)));
47663670Snsayer				}
47763670Snsayer			}
47863670Snsayer
47963670Snsayer			ifp->if_flags &= ~IFF_RUNNING;
48063670Snsayer		}
48163670Snsayer		splx(s);
48263670Snsayer	}
48363670Snsayer
48496122Salfred	funsetown(&tp->tap_sigio);
48563670Snsayer	selwakeup(&tp->tap_rsel);
48663670Snsayer
48763670Snsayer	tp->tap_flags &= ~TAP_OPEN;
48863670Snsayer	tp->tap_pid = 0;
48983043Sbrooks	error = rman_release_resource(tp->tap_unit);
49083043Sbrooks	KASSERT((error == 0),
49183043Sbrooks		("%s%d could not release unit", ifp->if_name, ifp->if_unit));
49283043Sbrooks	tp->tap_unit = NULL;
49363670Snsayer
49483043Sbrooks	TAPDEBUG("%s%d is closed. minor = %#x\n",
49583043Sbrooks		ifp->if_name, ifp->if_unit, minor(dev));
49663670Snsayer
49763670Snsayer	return (0);
49863670Snsayer} /* tapclose */
49963670Snsayer
50063670Snsayer
50163670Snsayer/*
50263670Snsayer * tapifinit
50363670Snsayer *
50463670Snsayer * network interface initialization function
50563670Snsayer */
50663670Snsayerstatic void
50763670Snsayertapifinit(xtp)
50863670Snsayer	void	*xtp;
50963670Snsayer{
51063670Snsayer	struct tap_softc	*tp = (struct tap_softc *)xtp;
51163670Snsayer	struct ifnet		*ifp = &tp->tap_if;
51263670Snsayer
51383043Sbrooks	TAPDEBUG("initializing %s%d\n", ifp->if_name, ifp->if_unit);
51463670Snsayer
51563670Snsayer	ifp->if_flags |= IFF_RUNNING;
51663670Snsayer	ifp->if_flags &= ~IFF_OACTIVE;
51763670Snsayer
51863670Snsayer	/* attempt to start output */
51963670Snsayer	tapifstart(ifp);
52063670Snsayer} /* tapifinit */
52163670Snsayer
52263670Snsayer
52363670Snsayer/*
52463670Snsayer * tapifioctl
52563670Snsayer *
52663670Snsayer * Process an ioctl request on network interface
52763670Snsayer */
528105228Sphkstatic int
52963670Snsayertapifioctl(ifp, cmd, data)
53063670Snsayer	struct ifnet	*ifp;
53163670Snsayer	u_long		 cmd;
53263670Snsayer	caddr_t		 data;
53363670Snsayer{
53463670Snsayer	struct tap_softc 	*tp = (struct tap_softc *)(ifp->if_softc);
53563670Snsayer	struct ifstat		*ifs = NULL;
53663670Snsayer	int			 s, dummy;
53763670Snsayer
53863670Snsayer	switch (cmd) {
53963670Snsayer		case SIOCSIFFLAGS: /* XXX -- just like vmnet does */
54063670Snsayer		case SIOCADDMULTI:
54163670Snsayer		case SIOCDELMULTI:
54283043Sbrooks			break;
54363670Snsayer
54463670Snsayer		case SIOCGIFSTATUS:
54563670Snsayer			s = splimp();
54663670Snsayer			ifs = (struct ifstat *)data;
54763670Snsayer			dummy = strlen(ifs->ascii);
54863670Snsayer			if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii))
54963670Snsayer				snprintf(ifs->ascii + dummy,
55063670Snsayer					sizeof(ifs->ascii) - dummy,
55163670Snsayer					"\tOpened by PID %d\n", tp->tap_pid);
55263670Snsayer			splx(s);
55383043Sbrooks			break;
55463670Snsayer
55563670Snsayer		default:
556106939Ssam			s = splimp();
557106939Ssam			dummy = ether_ioctl(ifp, cmd, data);
558106939Ssam			splx(s);
559106939Ssam			return (dummy);
56063670Snsayer	}
56163670Snsayer
56263670Snsayer	return (0);
56363670Snsayer} /* tapifioctl */
56463670Snsayer
56563670Snsayer
56663670Snsayer/*
56763670Snsayer * tapifstart
56863670Snsayer *
56963670Snsayer * queue packets from higher level ready to put out
57063670Snsayer */
57163670Snsayerstatic void
57263670Snsayertapifstart(ifp)
57363670Snsayer	struct ifnet	*ifp;
57463670Snsayer{
57563670Snsayer	struct tap_softc	*tp = ifp->if_softc;
57663670Snsayer	int			 s;
57763670Snsayer
57883043Sbrooks	TAPDEBUG("%s%d starting\n", ifp->if_name, ifp->if_unit);
57963670Snsayer
58063803Snsayer	/*
58163803Snsayer	 * do not junk pending output if we are in VMnet mode.
58263803Snsayer	 * XXX: can this do any harm because of queue overflow?
58363803Snsayer	 */
58463803Snsayer
58563803Snsayer	if (((tp->tap_flags & TAP_VMNET) == 0) &&
58663803Snsayer	    ((tp->tap_flags & TAP_READY) != TAP_READY)) {
58763670Snsayer		struct mbuf	*m = NULL;
58863670Snsayer
58983043Sbrooks		TAPDEBUG("%s%d not ready, tap_flags = 0x%x\n", ifp->if_name,
59083043Sbrooks			ifp->if_unit, tp->tap_flags);
59163670Snsayer
59263670Snsayer		s = splimp();
59363670Snsayer		do {
59463670Snsayer			IF_DEQUEUE(&ifp->if_snd, m);
59563670Snsayer			if (m != NULL)
59663670Snsayer				m_freem(m);
59763670Snsayer			ifp->if_oerrors ++;
59863670Snsayer		} while (m != NULL);
59963670Snsayer		splx(s);
60063670Snsayer
60163670Snsayer		return;
60263670Snsayer	}
60363670Snsayer
60463670Snsayer	s = splimp();
60563670Snsayer	ifp->if_flags |= IFF_OACTIVE;
60663670Snsayer
60763670Snsayer	if (ifp->if_snd.ifq_len != 0) {
60863670Snsayer		if (tp->tap_flags & TAP_RWAIT) {
60963670Snsayer			tp->tap_flags &= ~TAP_RWAIT;
61063670Snsayer			wakeup((caddr_t)tp);
61163670Snsayer		}
61263670Snsayer
61363670Snsayer		if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL))
61495883Salfred			pgsigio(&tp->tap_sigio, SIGIO, 0);
61563670Snsayer
61663670Snsayer		selwakeup(&tp->tap_rsel);
61763670Snsayer		ifp->if_opackets ++; /* obytes are counted in ether_output */
61863670Snsayer	}
61963670Snsayer
62063670Snsayer	ifp->if_flags &= ~IFF_OACTIVE;
62163670Snsayer	splx(s);
62263670Snsayer} /* tapifstart */
62363670Snsayer
62463670Snsayer
62563670Snsayer/*
62663670Snsayer * tapioctl
62763670Snsayer *
62863670Snsayer * the cdevsw interface is now pretty minimal
62963670Snsayer */
63063670Snsayerstatic int
63183366Sjuliantapioctl(dev, cmd, data, flag, td)
63263670Snsayer	dev_t		 dev;
63363670Snsayer	u_long		 cmd;
63463670Snsayer	caddr_t		 data;
63563670Snsayer	int		 flag;
63683366Sjulian	struct thread	*td;
63763670Snsayer{
63863670Snsayer	struct tap_softc	*tp = dev->si_drv1;
63963670Snsayer	struct ifnet		*ifp = &tp->tap_if;
64063670Snsayer 	struct tapinfo		*tapp = NULL;
64163670Snsayer	int			 s;
642102052Ssobomax	int			 f;
64363670Snsayer
64463670Snsayer	switch (cmd) {
64563670Snsayer 		case TAPSIFINFO:
64663670Snsayer			s = splimp();
64763670Snsayer 		        tapp = (struct tapinfo *)data;
64863670Snsayer 			ifp->if_mtu = tapp->mtu;
64963670Snsayer 			ifp->if_type = tapp->type;
65063670Snsayer 			ifp->if_baudrate = tapp->baudrate;
65163670Snsayer			splx(s);
65283043Sbrooks 			break;
65363670Snsayer
65463670Snsayer	 	case TAPGIFINFO:
65563670Snsayer 			tapp = (struct tapinfo *)data;
65663670Snsayer 			tapp->mtu = ifp->if_mtu;
65763670Snsayer 			tapp->type = ifp->if_type;
65863670Snsayer 			tapp->baudrate = ifp->if_baudrate;
65983043Sbrooks 			break;
66063670Snsayer
66163670Snsayer		case TAPSDEBUG:
66263670Snsayer			tapdebug = *(int *)data;
66383043Sbrooks			break;
66463670Snsayer
66563670Snsayer		case TAPGDEBUG:
66663670Snsayer			*(int *)data = tapdebug;
66783043Sbrooks			break;
66863670Snsayer
66963670Snsayer		case FIONBIO:
67083043Sbrooks			break;
67163670Snsayer
67263670Snsayer		case FIOASYNC:
67363803Snsayer			s = splimp();
67463670Snsayer			if (*(int *)data)
67563670Snsayer				tp->tap_flags |= TAP_ASYNC;
67663670Snsayer			else
67763670Snsayer				tp->tap_flags &= ~TAP_ASYNC;
67863803Snsayer			splx(s);
67983043Sbrooks			break;
68063670Snsayer
68163670Snsayer		case FIONREAD:
68263670Snsayer			s = splimp();
68363670Snsayer			if (ifp->if_snd.ifq_head) {
68463670Snsayer				struct mbuf	*mb = ifp->if_snd.ifq_head;
68563670Snsayer
68663803Snsayer				for(*(int *)data = 0;mb != NULL;mb = mb->m_next)
68763670Snsayer					*(int *)data += mb->m_len;
68883043Sbrooks			} else
68963670Snsayer				*(int *)data = 0;
69063670Snsayer			splx(s);
69183043Sbrooks			break;
69263670Snsayer
69363670Snsayer		case FIOSETOWN:
69463670Snsayer			return (fsetown(*(int *)data, &tp->tap_sigio));
69563670Snsayer
69663670Snsayer		case FIOGETOWN:
697104393Struckman			*(int *)data = fgetown(&tp->tap_sigio);
69863670Snsayer			return (0);
69963670Snsayer
70063670Snsayer		/* this is deprecated, FIOSETOWN should be used instead */
70163670Snsayer		case TIOCSPGRP:
70263670Snsayer			return (fsetown(-(*(int *)data), &tp->tap_sigio));
70363670Snsayer
70463670Snsayer		/* this is deprecated, FIOGETOWN should be used instead */
70563670Snsayer		case TIOCGPGRP:
706104393Struckman			*(int *)data = -fgetown(&tp->tap_sigio);
70763670Snsayer			return (0);
70863670Snsayer
70963670Snsayer		/* VMware/VMnet port ioctl's */
71063670Snsayer
71163670Snsayer		case SIOCGIFFLAGS:	/* get ifnet flags */
71263670Snsayer			bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags));
71383043Sbrooks			break;
71463670Snsayer
71583043Sbrooks		case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */
716102052Ssobomax			f = *(int *)data;
71763670Snsayer			f &= 0x0fff;
71863670Snsayer			f &= ~IFF_CANTCHANGE;
71963670Snsayer			f |= IFF_UP;
72063670Snsayer
72163670Snsayer			s = splimp();
72263670Snsayer			ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE);
72363670Snsayer			splx(s);
72483043Sbrooks			break;
72563670Snsayer
72663861Snsayer		case OSIOCGIFADDR:	/* get MAC address of the remote side */
72763670Snsayer		case SIOCGIFADDR:
72863861Snsayer			bcopy(tp->ether_addr, data, sizeof(tp->ether_addr));
72983043Sbrooks			break;
73063670Snsayer
73163861Snsayer		case SIOCSIFADDR:	/* set MAC address of the remote side */
73263861Snsayer			bcopy(data, tp->ether_addr, sizeof(tp->ether_addr));
73383043Sbrooks			break;
73463670Snsayer
73563670Snsayer		default:
73663670Snsayer			return (ENOTTY);
73763670Snsayer	}
73863670Snsayer	return (0);
73963670Snsayer} /* tapioctl */
74063670Snsayer
74163670Snsayer
74263670Snsayer/*
74363670Snsayer * tapread
74463670Snsayer *
74563670Snsayer * the cdevsw read interface - reads a packet at a time, or at
74663670Snsayer * least as much of a packet as can be read
74763670Snsayer */
74863670Snsayerstatic int
74963670Snsayertapread(dev, uio, flag)
75063670Snsayer	dev_t		 dev;
75163670Snsayer	struct uio	*uio;
75263670Snsayer	int		 flag;
75363670Snsayer{
75463670Snsayer	struct tap_softc	*tp = dev->si_drv1;
75563670Snsayer	struct ifnet		*ifp = &tp->tap_if;
75690227Sdillon	struct mbuf		*m = NULL;
75763670Snsayer	int			 error = 0, len, s;
75863670Snsayer
75983043Sbrooks	TAPDEBUG("%s%d reading, minor = %#x\n",
76083043Sbrooks		ifp->if_name, ifp->if_unit, minor(dev));
76163670Snsayer
76263670Snsayer	if ((tp->tap_flags & TAP_READY) != TAP_READY) {
76363803Snsayer		TAPDEBUG("%s%d not ready. minor = %#x, tap_flags = 0x%x\n",
76483043Sbrooks			ifp->if_name, ifp->if_unit, minor(dev), tp->tap_flags);
76563803Snsayer
76663670Snsayer		return (EHOSTDOWN);
76763670Snsayer	}
76863670Snsayer
76963670Snsayer	tp->tap_flags &= ~TAP_RWAIT;
77063670Snsayer
77163670Snsayer	/* sleep until we get a packet */
77263670Snsayer	do {
77363670Snsayer		s = splimp();
77490227Sdillon		IF_DEQUEUE(&ifp->if_snd, m);
77563670Snsayer		splx(s);
77663670Snsayer
77790227Sdillon		if (m == NULL) {
77863670Snsayer			if (flag & IO_NDELAY)
77963670Snsayer				return (EWOULDBLOCK);
78063670Snsayer
78163670Snsayer			tp->tap_flags |= TAP_RWAIT;
78263670Snsayer			error = tsleep((caddr_t)tp,PCATCH|(PZERO+1),"taprd",0);
78363670Snsayer			if (error)
78463670Snsayer				return (error);
78563670Snsayer		}
78690227Sdillon	} while (m == NULL);
78763670Snsayer
78863670Snsayer	/* feed packet to bpf */
789106939Ssam	BPF_MTAP(ifp, m);
79063670Snsayer
79163670Snsayer	/* xfer packet to user space */
79290227Sdillon	while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) {
79390227Sdillon		len = min(uio->uio_resid, m->m_len);
79463670Snsayer		if (len == 0)
79563670Snsayer			break;
79663670Snsayer
79790227Sdillon		error = uiomove(mtod(m, caddr_t), len, uio);
79890227Sdillon		m = m_free(m);
79963670Snsayer	}
80063670Snsayer
80190227Sdillon	if (m != NULL) {
80283043Sbrooks		TAPDEBUG("%s%d dropping mbuf, minor = %#x\n", ifp->if_name,
80383043Sbrooks			ifp->if_unit, minor(dev));
80490227Sdillon		m_freem(m);
80563670Snsayer	}
80663670Snsayer
80763670Snsayer	return (error);
80863670Snsayer} /* tapread */
80963670Snsayer
81063670Snsayer
81163670Snsayer/*
81263670Snsayer * tapwrite
81363670Snsayer *
81463670Snsayer * the cdevsw write interface - an atomic write is a packet - or else!
81563670Snsayer */
81663670Snsayerstatic int
81763670Snsayertapwrite(dev, uio, flag)
81863670Snsayer	dev_t		 dev;
81963670Snsayer	struct uio	*uio;
82063670Snsayer	int		 flag;
82163670Snsayer{
82263670Snsayer	struct tap_softc	*tp = dev->si_drv1;
82363670Snsayer	struct ifnet		*ifp = &tp->tap_if;
82463670Snsayer	struct mbuf		*top = NULL, **mp = NULL, *m = NULL;
82563670Snsayer	int		 	 error = 0, tlen, mlen;
82663670Snsayer
82783043Sbrooks	TAPDEBUG("%s%d writting, minor = %#x\n",
82883043Sbrooks		ifp->if_name, ifp->if_unit, minor(dev));
82963670Snsayer
83063670Snsayer	if (uio->uio_resid == 0)
83163670Snsayer		return (0);
83263670Snsayer
83363670Snsayer	if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) {
83463803Snsayer		TAPDEBUG("%s%d invalid packet len = %d, minor = %#x\n",
83583043Sbrooks			ifp->if_name, ifp->if_unit, uio->uio_resid, minor(dev));
83663803Snsayer
83763670Snsayer		return (EIO);
83863670Snsayer	}
83963670Snsayer	tlen = uio->uio_resid;
84063670Snsayer
84163670Snsayer	/* get a header mbuf */
842111119Simp	MGETHDR(m, M_DONTWAIT, MT_DATA);
84363670Snsayer	if (m == NULL)
84463670Snsayer		return (ENOBUFS);
84563670Snsayer	mlen = MHLEN;
84663670Snsayer
84763670Snsayer	top = 0;
84863670Snsayer	mp = &top;
84963670Snsayer	while ((error == 0) && (uio->uio_resid > 0)) {
85063670Snsayer		m->m_len = min(mlen, uio->uio_resid);
85163670Snsayer		error = uiomove(mtod(m, caddr_t), m->m_len, uio);
85263670Snsayer		*mp = m;
85363670Snsayer		mp = &m->m_next;
85463670Snsayer		if (uio->uio_resid > 0) {
855111119Simp			MGET(m, M_DONTWAIT, MT_DATA);
85663803Snsayer			if (m == NULL) {
85763670Snsayer				error = ENOBUFS;
85863670Snsayer				break;
85963670Snsayer			}
86063670Snsayer			mlen = MLEN;
86163670Snsayer		}
86263670Snsayer	}
86363670Snsayer	if (error) {
86463670Snsayer		ifp->if_ierrors ++;
86563670Snsayer		if (top)
86663670Snsayer			m_freem(top);
86763670Snsayer		return (error);
86863670Snsayer	}
86963670Snsayer
87063670Snsayer	top->m_pkthdr.len = tlen;
87163670Snsayer	top->m_pkthdr.rcvif = ifp;
87263670Snsayer
873106939Ssam	/* Pass packet up to parent. */
874106939Ssam	(*ifp->if_input)(ifp, top);
875106939Ssam	ifp->if_ipackets ++; /* ibytes are counted in parent */
87663670Snsayer
87763670Snsayer	return (0);
87863670Snsayer} /* tapwrite */
87963670Snsayer
88063670Snsayer
88163670Snsayer/*
88263670Snsayer * tappoll
88363670Snsayer *
88463670Snsayer * the poll interface, this is only useful on reads
88563670Snsayer * really. the write detect always returns true, write never blocks
88663670Snsayer * anyway, it either accepts the packet or drops it
88763670Snsayer */
88863670Snsayerstatic int
88983366Sjuliantappoll(dev, events, td)
89063670Snsayer	dev_t		 dev;
89163670Snsayer	int		 events;
89283366Sjulian	struct thread	*td;
89363670Snsayer{
89463670Snsayer	struct tap_softc	*tp = dev->si_drv1;
89563670Snsayer	struct ifnet		*ifp = &tp->tap_if;
89663670Snsayer	int		 	 s, revents = 0;
89763670Snsayer
89883043Sbrooks	TAPDEBUG("%s%d polling, minor = %#x\n",
89983043Sbrooks		ifp->if_name, ifp->if_unit, minor(dev));
90063670Snsayer
90163670Snsayer	s = splimp();
90263670Snsayer	if (events & (POLLIN | POLLRDNORM)) {
90363670Snsayer		if (ifp->if_snd.ifq_len > 0) {
90463803Snsayer			TAPDEBUG("%s%d have data in queue. len = %d, " \
90563803Snsayer				"minor = %#x\n", ifp->if_name, ifp->if_unit,
90683043Sbrooks				ifp->if_snd.ifq_len, minor(dev));
90763803Snsayer
90863670Snsayer			revents |= (events & (POLLIN | POLLRDNORM));
90983043Sbrooks		} else {
91063803Snsayer			TAPDEBUG("%s%d waiting for data, minor = %#x\n",
91183043Sbrooks				ifp->if_name, ifp->if_unit, minor(dev));
91263803Snsayer
91383805Sjhb			selrecord(td, &tp->tap_rsel);
91463670Snsayer		}
91563670Snsayer	}
91663670Snsayer
91763670Snsayer	if (events & (POLLOUT | POLLWRNORM))
91863670Snsayer		revents |= (events & (POLLOUT | POLLWRNORM));
91963670Snsayer
92063670Snsayer	splx(s);
92163670Snsayer	return (revents);
92263670Snsayer} /* tappoll */
923