if_tap.c revision 126080
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 126080 2004-02-21 21:10:55Z phk $
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 <sys/queue.h>
5863670Snsayer
5963670Snsayer#include <net/bpf.h>
6063670Snsayer#include <net/ethernet.h>
6163670Snsayer#include <net/if.h>
6263670Snsayer#include <net/if_arp.h>
6363670Snsayer#include <net/route.h>
6463670Snsayer
6563670Snsayer#include <netinet/in.h>
6663670Snsayer
6763670Snsayer#include <net/if_tapvar.h>
6863670Snsayer#include <net/if_tap.h>
6963670Snsayer
7063670Snsayer
7163670Snsayer#define CDEV_NAME	"tap"
7263670Snsayer#define TAPDEBUG	if (tapdebug) printf
7363670Snsayer
7463670Snsayer#define TAP		"tap"
7563670Snsayer#define VMNET		"vmnet"
7683043Sbrooks#define TAPMAXUNIT	0x7fff
77126077Sphk#define VMNET_DEV_MASK	CLONE_FLAG0
7863670Snsayer
7963670Snsayer/* module */
80111742Sdesstatic int		tapmodevent(module_t, int, void *);
8163670Snsayer
8263670Snsayer/* device */
8393084Sbdestatic void		tapclone(void *, char *, int, dev_t *);
8493084Sbdestatic void		tapcreate(dev_t);
8563670Snsayer
8663670Snsayer/* network interface */
8793084Sbdestatic void		tapifstart(struct ifnet *);
8893084Sbdestatic int		tapifioctl(struct ifnet *, u_long, caddr_t);
8993084Sbdestatic void		tapifinit(void *);
9063670Snsayer
9163670Snsayer/* character device */
9263670Snsayerstatic d_open_t		tapopen;
9363670Snsayerstatic d_close_t	tapclose;
9463670Snsayerstatic d_read_t		tapread;
9563670Snsayerstatic d_write_t	tapwrite;
9663670Snsayerstatic d_ioctl_t	tapioctl;
9763670Snsayerstatic d_poll_t		tappoll;
9863670Snsayer
9963670Snsayerstatic struct cdevsw	tap_cdevsw = {
100126080Sphk	.d_version =	D_VERSION,
101126080Sphk	.d_flags =	D_NEEDGIANT,
102111815Sphk	.d_open =	tapopen,
103111815Sphk	.d_close =	tapclose,
104111815Sphk	.d_read =	tapread,
105111815Sphk	.d_write =	tapwrite,
106111815Sphk	.d_ioctl =	tapioctl,
107111815Sphk	.d_poll =	tappoll,
108111815Sphk	.d_name =	CDEV_NAME,
109126077Sphk	.d_flags =	D_PSEUDO,
11063670Snsayer};
11163670Snsayer
11283043Sbrooksstatic int			tapdebug = 0;        /* debug flag   */
11383043Sbrooksstatic SLIST_HEAD(, tap_softc)	taphead;             /* first device */
114126077Sphkstatic struct clonedevs 	*tapclones;
11563670Snsayer
11663670SnsayerMALLOC_DECLARE(M_TAP);
11763670SnsayerMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface");
11863670SnsayerSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, "");
11963670SnsayerDEV_MODULE(if_tap, tapmodevent, NULL);
12063670Snsayer
12163670Snsayer/*
12263670Snsayer * tapmodevent
12363670Snsayer *
12463670Snsayer * module event handler
12563670Snsayer */
12663670Snsayerstatic int
12763670Snsayertapmodevent(mod, type, data)
12863670Snsayer	module_t	 mod;
12963670Snsayer	int		 type;
13063670Snsayer	void		*data;
13163670Snsayer{
13283043Sbrooks	static eventhandler_tag	 eh_tag = NULL;
13383043Sbrooks	struct tap_softc	*tp = NULL;
13483043Sbrooks	struct ifnet		*ifp = NULL;
135126077Sphk	int			 s;
13663670Snsayer
13763670Snsayer	switch (type) {
13863670Snsayer	case MOD_LOAD:
13963670Snsayer
14083043Sbrooks		/* intitialize device */
14183043Sbrooks
14283043Sbrooks		SLIST_INIT(&taphead);
14383043Sbrooks
14471602Sphk		eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000);
145126077Sphk		if (eh_tag == NULL)
146126077Sphk			return (ENOMEM);
14783043Sbrooks		return (0);
14863670Snsayer
14983043Sbrooks	case MOD_UNLOAD:
15083043Sbrooks		SLIST_FOREACH(tp, &taphead, tap_next)
151126077Sphk			if (tp->tap_flags & TAP_OPEN)
15283043Sbrooks				return (EBUSY);
15383043Sbrooks
15471602Sphk		EVENTHANDLER_DEREGISTER(dev_clone, eh_tag);
15563670Snsayer
15683043Sbrooks		while ((tp = SLIST_FIRST(&taphead)) != NULL) {
15783043Sbrooks			SLIST_REMOVE_HEAD(&taphead, tap_next);
15883043Sbrooks
15983043Sbrooks			ifp = &tp->tap_if;
16083043Sbrooks
161121816Sbrooks			TAPDEBUG("detaching %s\n", ifp->if_xname);
16283043Sbrooks
163121816Sbrooks			KASSERT(!(tp->tap_flags & TAP_OPEN),
164121816Sbrooks				("%s flags is out of sync", ifp->if_xname));
16583043Sbrooks
166126077Sphk			destroy_dev(tp->tap_dev);
16763670Snsayer			s = splimp();
168106939Ssam			ether_ifdetach(ifp);
16963670Snsayer			splx(s);
17063670Snsayer
17193752Sluigi			free(tp, M_TAP);
17283043Sbrooks		}
173126077Sphk		clone_cleanup(&tapclones);
17463670Snsayer
17583043Sbrooks		break;
17663670Snsayer
17763670Snsayer	default:
17863670Snsayer		return (EOPNOTSUPP);
17963670Snsayer	}
18063670Snsayer
18163670Snsayer	return (0);
18263670Snsayer} /* tapmodevent */
18363670Snsayer
18463670Snsayer
18563670Snsayer/*
18671602Sphk * DEVFS handler
18771602Sphk *
18871602Sphk * We need to support two kind of devices - tap and vmnet
18971602Sphk */
19071602Sphkstatic void
19171602Sphktapclone(arg, name, namelen, dev)
19271602Sphk	void	*arg;
19371602Sphk	char	*name;
19471602Sphk	int	 namelen;
19571602Sphk	dev_t	*dev;
19671602Sphk{
197126077Sphk	u_int		extra;
198126077Sphk	int		i, unit;
19983043Sbrooks	char		*device_name = name;
20071602Sphk
20171602Sphk	if (*dev != NODEV)
20271602Sphk		return;
20371602Sphk
204126077Sphk	device_name = TAP;
205126077Sphk	extra = 0;
206126077Sphk	if (strcmp(name, TAP) == 0) {
207126077Sphk		unit = -1;
208126077Sphk	} else if (strcmp(name, VMNET) == 0) {
209126077Sphk		device_name = VMNET;
210126077Sphk		extra = VMNET_DEV_MASK;
211126077Sphk		unit = -1;
212126077Sphk	} else if (dev_stdclone(name, NULL, device_name, &unit) != 1) {
213126077Sphk		device_name = VMNET;
214126077Sphk		extra = VMNET_DEV_MASK;
215126077Sphk		if (dev_stdclone(name, NULL, device_name, &unit) != 1)
216126077Sphk			return;
21783043Sbrooks	}
21871602Sphk
219126077Sphk	/* find any existing device, or allocate new unit number */
220126077Sphk	i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra);
221126077Sphk	if (i) {
222126077Sphk		*dev = make_dev(&tap_cdevsw, unit2minor(unit) | extra,
223126077Sphk		     UID_ROOT, GID_WHEEL, 0600, "%s%d", device_name, unit);
224126077Sphk		if (*dev != NULL)
225126077Sphk			(*dev)->si_flags |= SI_CHEAPCLONE;
22671602Sphk	}
22771602Sphk} /* tapclone */
22871602Sphk
22971602Sphk
23071602Sphk/*
23163670Snsayer * tapcreate
23263670Snsayer *
23363670Snsayer * to create interface
23463670Snsayer */
23563670Snsayerstatic void
23663670Snsayertapcreate(dev)
23763670Snsayer	dev_t	dev;
23863670Snsayer{
23963670Snsayer	struct ifnet		*ifp = NULL;
24063670Snsayer	struct tap_softc	*tp = NULL;
24163670Snsayer	unsigned short		 macaddr_hi;
24263803Snsayer	int			 unit, s;
24363670Snsayer	char			*name = NULL;
24463670Snsayer
245126077Sphk	dev->si_flags &= ~SI_CHEAPCLONE;
246126077Sphk
24763670Snsayer	/* allocate driver storage and create device */
248111119Simp	MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO);
24983043Sbrooks	SLIST_INSERT_HEAD(&taphead, tp, tap_next);
25063670Snsayer
25183043Sbrooks	unit = dev2unit(dev) & TAPMAXUNIT;
25283043Sbrooks
25363670Snsayer	/* select device: tap or vmnet */
25463670Snsayer	if (minor(dev) & VMNET_DEV_MASK) {
25563670Snsayer		name = VMNET;
25663803Snsayer		tp->tap_flags |= TAP_VMNET;
25783043Sbrooks	} else
25863670Snsayer		name = TAP;
25963670Snsayer
26083043Sbrooks	TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev));
26183043Sbrooks
26283043Sbrooks	if (!(dev->si_flags & SI_NAMED))
263111742Sdes		dev = make_dev(&tap_cdevsw, minor(dev), UID_ROOT, GID_WHEEL,
26463670Snsayer						0600, "%s%d", name, unit);
26563670Snsayer
26663670Snsayer	/* generate fake MAC address: 00 bd xx xx xx unit_no */
26763670Snsayer	macaddr_hi = htons(0x00bd);
26863670Snsayer	bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short));
26963670Snsayer	bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long));
27063670Snsayer	tp->arpcom.ac_enaddr[5] = (u_char)unit;
27163670Snsayer
272111742Sdes	/* fill the rest and attach interface */
27363670Snsayer	ifp = &tp->tap_if;
27463670Snsayer	ifp->if_softc = tp;
275121816Sbrooks	if_initname(ifp, name, unit);
27663670Snsayer	ifp->if_init = tapifinit;
27763670Snsayer	ifp->if_start = tapifstart;
27863670Snsayer	ifp->if_ioctl = tapifioctl;
27963670Snsayer	ifp->if_mtu = ETHERMTU;
28063670Snsayer	ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
28163670Snsayer	ifp->if_snd.ifq_maxlen = ifqmaxlen;
28263670Snsayer
28383043Sbrooks	dev->si_drv1 = tp;
284126077Sphk	tp->tap_dev = dev;
28583043Sbrooks
28663803Snsayer	s = splimp();
287106939Ssam	ether_ifattach(ifp, tp->arpcom.ac_enaddr);
28863803Snsayer	splx(s);
28963670Snsayer
29063803Snsayer	tp->tap_flags |= TAP_INITED;
29163803Snsayer
292121816Sbrooks	TAPDEBUG("interface %s is created. minor = %#x\n",
293121816Sbrooks		ifp->if_xname, minor(dev));
29463670Snsayer} /* tapcreate */
29563670Snsayer
29663670Snsayer
29763670Snsayer/*
298111742Sdes * tapopen
29963670Snsayer *
30063670Snsayer * to open tunnel. must be superuser
30163670Snsayer */
30263670Snsayerstatic int
30383366Sjuliantapopen(dev, flag, mode, td)
30463670Snsayer	dev_t		 dev;
30563670Snsayer	int		 flag;
30663670Snsayer	int		 mode;
30783366Sjulian	struct thread	*td;
30863670Snsayer{
30963670Snsayer	struct tap_softc	*tp = NULL;
31083043Sbrooks	int			 unit, error;
31163670Snsayer
31293593Sjhb	if ((error = suser(td)) != 0)
31363670Snsayer		return (error);
31463670Snsayer
31583043Sbrooks	unit = dev2unit(dev) & TAPMAXUNIT;
31683043Sbrooks
31783043Sbrooks
31863670Snsayer	tp = dev->si_drv1;
31963670Snsayer	if (tp == NULL) {
32063670Snsayer		tapcreate(dev);
32163670Snsayer		tp = dev->si_drv1;
32263670Snsayer	}
32363670Snsayer
324121816Sbrooks	KASSERT(!(tp->tap_flags & TAP_OPEN),
325121816Sbrooks		("%s flags is out of sync", tp->tap_if.if_xname));
32663670Snsayer
32763861Snsayer	bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr));
32863861Snsayer
32983366Sjulian	tp->tap_pid = td->td_proc->p_pid;
33063670Snsayer	tp->tap_flags |= TAP_OPEN;
33163670Snsayer
332121816Sbrooks	TAPDEBUG("%s is open. minor = %#x\n",
333121816Sbrooks		tp->tap_if.if_xname, minor(dev));
33463670Snsayer
33563670Snsayer	return (0);
33663670Snsayer} /* tapopen */
33763670Snsayer
33863670Snsayer
33963670Snsayer/*
34063670Snsayer * tapclose
34163670Snsayer *
34263670Snsayer * close the device - mark i/f down & delete routing info
34363670Snsayer */
34463670Snsayerstatic int
34583366Sjuliantapclose(dev, foo, bar, td)
34663670Snsayer	dev_t		 dev;
34763670Snsayer	int		 foo;
34863670Snsayer	int		 bar;
34983366Sjulian	struct thread	*td;
35063670Snsayer{
35163670Snsayer	struct tap_softc	*tp = dev->si_drv1;
35263670Snsayer	struct ifnet		*ifp = &tp->tap_if;
353126077Sphk	int			s;
35463670Snsayer
35563670Snsayer	/* junk all pending output */
35683043Sbrooks	IF_DRAIN(&ifp->if_snd);
35763670Snsayer
35863803Snsayer	/*
35963803Snsayer	 * do not bring the interface down, and do not anything with
36063803Snsayer	 * interface, if we are in VMnet mode. just close the device.
36163803Snsayer	 */
36263803Snsayer
36363803Snsayer	if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) {
36463670Snsayer		s = splimp();
36563670Snsayer		if_down(ifp);
36663670Snsayer		if (ifp->if_flags & IFF_RUNNING) {
36763670Snsayer			/* find internet addresses and delete routes */
36863670Snsayer			struct ifaddr	*ifa = NULL;
36963670Snsayer
37063803Snsayer			TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
37163670Snsayer				if (ifa->ifa_addr->sa_family == AF_INET) {
37263670Snsayer					rtinit(ifa, (int)RTM_DELETE, 0);
37363670Snsayer
37463670Snsayer					/* remove address from interface */
375111742Sdes					bzero(ifa->ifa_addr,
37663670Snsayer						   sizeof(*(ifa->ifa_addr)));
377111742Sdes					bzero(ifa->ifa_dstaddr,
37863670Snsayer						   sizeof(*(ifa->ifa_dstaddr)));
379111742Sdes					bzero(ifa->ifa_netmask,
38063670Snsayer						   sizeof(*(ifa->ifa_netmask)));
38163670Snsayer				}
38263670Snsayer			}
38363670Snsayer
38463670Snsayer			ifp->if_flags &= ~IFF_RUNNING;
38563670Snsayer		}
38663670Snsayer		splx(s);
38763670Snsayer	}
38863670Snsayer
38996122Salfred	funsetown(&tp->tap_sigio);
390122352Stanimura	selwakeuppri(&tp->tap_rsel, PZERO+1);
39163670Snsayer
39263670Snsayer	tp->tap_flags &= ~TAP_OPEN;
39363670Snsayer	tp->tap_pid = 0;
39463670Snsayer
395121816Sbrooks	TAPDEBUG("%s is closed. minor = %#x\n",
396121816Sbrooks		ifp->if_xname, minor(dev));
39763670Snsayer
39863670Snsayer	return (0);
39963670Snsayer} /* tapclose */
40063670Snsayer
40163670Snsayer
40263670Snsayer/*
40363670Snsayer * tapifinit
40463670Snsayer *
40563670Snsayer * network interface initialization function
40663670Snsayer */
40763670Snsayerstatic void
40863670Snsayertapifinit(xtp)
40963670Snsayer	void	*xtp;
41063670Snsayer{
41163670Snsayer	struct tap_softc	*tp = (struct tap_softc *)xtp;
41263670Snsayer	struct ifnet		*ifp = &tp->tap_if;
41363670Snsayer
414121816Sbrooks	TAPDEBUG("initializing %s\n", ifp->if_xname);
41563670Snsayer
41663670Snsayer	ifp->if_flags |= IFF_RUNNING;
41763670Snsayer	ifp->if_flags &= ~IFF_OACTIVE;
41863670Snsayer
41963670Snsayer	/* attempt to start output */
42063670Snsayer	tapifstart(ifp);
42163670Snsayer} /* tapifinit */
42263670Snsayer
42363670Snsayer
42463670Snsayer/*
42563670Snsayer * tapifioctl
42663670Snsayer *
42763670Snsayer * Process an ioctl request on network interface
42863670Snsayer */
429105228Sphkstatic int
43063670Snsayertapifioctl(ifp, cmd, data)
43163670Snsayer	struct ifnet	*ifp;
43263670Snsayer	u_long		 cmd;
43363670Snsayer	caddr_t		 data;
43463670Snsayer{
435111742Sdes	struct tap_softc	*tp = (struct tap_softc *)(ifp->if_softc);
43663670Snsayer	struct ifstat		*ifs = NULL;
43763670Snsayer	int			 s, dummy;
43863670Snsayer
43963670Snsayer	switch (cmd) {
44063670Snsayer		case SIOCSIFFLAGS: /* XXX -- just like vmnet does */
44163670Snsayer		case SIOCADDMULTI:
44263670Snsayer		case SIOCDELMULTI:
44383043Sbrooks			break;
44463670Snsayer
44563670Snsayer		case SIOCGIFSTATUS:
44663670Snsayer			s = splimp();
44763670Snsayer			ifs = (struct ifstat *)data;
44863670Snsayer			dummy = strlen(ifs->ascii);
44963670Snsayer			if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii))
45063670Snsayer				snprintf(ifs->ascii + dummy,
45163670Snsayer					sizeof(ifs->ascii) - dummy,
45263670Snsayer					"\tOpened by PID %d\n", tp->tap_pid);
45363670Snsayer			splx(s);
45483043Sbrooks			break;
45563670Snsayer
45663670Snsayer		default:
457106939Ssam			s = splimp();
458106939Ssam			dummy = ether_ioctl(ifp, cmd, data);
459106939Ssam			splx(s);
460106939Ssam			return (dummy);
46163670Snsayer	}
46263670Snsayer
46363670Snsayer	return (0);
46463670Snsayer} /* tapifioctl */
46563670Snsayer
46663670Snsayer
46763670Snsayer/*
468111742Sdes * tapifstart
469111742Sdes *
47063670Snsayer * queue packets from higher level ready to put out
47163670Snsayer */
47263670Snsayerstatic void
47363670Snsayertapifstart(ifp)
47463670Snsayer	struct ifnet	*ifp;
47563670Snsayer{
47663670Snsayer	struct tap_softc	*tp = ifp->if_softc;
47763670Snsayer	int			 s;
47863670Snsayer
479121816Sbrooks	TAPDEBUG("%s starting\n", ifp->if_xname);
48063670Snsayer
48163803Snsayer	/*
48263803Snsayer	 * do not junk pending output if we are in VMnet mode.
48363803Snsayer	 * XXX: can this do any harm because of queue overflow?
48463803Snsayer	 */
48563803Snsayer
486111742Sdes	if (((tp->tap_flags & TAP_VMNET) == 0) &&
48763803Snsayer	    ((tp->tap_flags & TAP_READY) != TAP_READY)) {
48863670Snsayer		struct mbuf	*m = NULL;
48963670Snsayer
490121816Sbrooks		TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname,
491121816Sbrooks		    tp->tap_flags);
49263670Snsayer
49363670Snsayer		s = splimp();
49463670Snsayer		do {
49563670Snsayer			IF_DEQUEUE(&ifp->if_snd, m);
49663670Snsayer			if (m != NULL)
49763670Snsayer				m_freem(m);
49863670Snsayer			ifp->if_oerrors ++;
49963670Snsayer		} while (m != NULL);
50063670Snsayer		splx(s);
50163670Snsayer
50263670Snsayer		return;
50363670Snsayer	}
50463670Snsayer
50563670Snsayer	s = splimp();
50663670Snsayer	ifp->if_flags |= IFF_OACTIVE;
50763670Snsayer
50863670Snsayer	if (ifp->if_snd.ifq_len != 0) {
50963670Snsayer		if (tp->tap_flags & TAP_RWAIT) {
51063670Snsayer			tp->tap_flags &= ~TAP_RWAIT;
511111748Sdes			wakeup(tp);
51263670Snsayer		}
51363670Snsayer
51463670Snsayer		if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL))
51595883Salfred			pgsigio(&tp->tap_sigio, SIGIO, 0);
51663670Snsayer
517122352Stanimura		selwakeuppri(&tp->tap_rsel, PZERO+1);
51863670Snsayer		ifp->if_opackets ++; /* obytes are counted in ether_output */
51963670Snsayer	}
52063670Snsayer
52163670Snsayer	ifp->if_flags &= ~IFF_OACTIVE;
52263670Snsayer	splx(s);
52363670Snsayer} /* tapifstart */
52463670Snsayer
52563670Snsayer
52663670Snsayer/*
52763670Snsayer * tapioctl
52863670Snsayer *
52963670Snsayer * the cdevsw interface is now pretty minimal
53063670Snsayer */
53163670Snsayerstatic int
53283366Sjuliantapioctl(dev, cmd, data, flag, td)
53363670Snsayer	dev_t		 dev;
53463670Snsayer	u_long		 cmd;
53563670Snsayer	caddr_t		 data;
53663670Snsayer	int		 flag;
53783366Sjulian	struct thread	*td;
53863670Snsayer{
53963670Snsayer	struct tap_softc	*tp = dev->si_drv1;
54063670Snsayer	struct ifnet		*ifp = &tp->tap_if;
541111742Sdes	struct tapinfo		*tapp = NULL;
54263670Snsayer	int			 s;
543102052Ssobomax	int			 f;
54463670Snsayer
54563670Snsayer	switch (cmd) {
546111742Sdes		case TAPSIFINFO:
54763670Snsayer			s = splimp();
548111742Sdes			tapp = (struct tapinfo *)data;
549111742Sdes			ifp->if_mtu = tapp->mtu;
550111742Sdes			ifp->if_type = tapp->type;
551111742Sdes			ifp->if_baudrate = tapp->baudrate;
55263670Snsayer			splx(s);
553111742Sdes			break;
55463670Snsayer
555111742Sdes		case TAPGIFINFO:
556111742Sdes			tapp = (struct tapinfo *)data;
557111742Sdes			tapp->mtu = ifp->if_mtu;
558111742Sdes			tapp->type = ifp->if_type;
559111742Sdes			tapp->baudrate = ifp->if_baudrate;
560111742Sdes			break;
56163670Snsayer
56263670Snsayer		case TAPSDEBUG:
56363670Snsayer			tapdebug = *(int *)data;
56483043Sbrooks			break;
56563670Snsayer
56663670Snsayer		case TAPGDEBUG:
56763670Snsayer			*(int *)data = tapdebug;
56883043Sbrooks			break;
56963670Snsayer
57063670Snsayer		case FIONBIO:
57183043Sbrooks			break;
57263670Snsayer
57363670Snsayer		case FIOASYNC:
57463803Snsayer			s = splimp();
57563670Snsayer			if (*(int *)data)
57663670Snsayer				tp->tap_flags |= TAP_ASYNC;
57763670Snsayer			else
57863670Snsayer				tp->tap_flags &= ~TAP_ASYNC;
57963803Snsayer			splx(s);
58083043Sbrooks			break;
58163670Snsayer
58263670Snsayer		case FIONREAD:
58363670Snsayer			s = splimp();
58463670Snsayer			if (ifp->if_snd.ifq_head) {
58563670Snsayer				struct mbuf	*mb = ifp->if_snd.ifq_head;
58663670Snsayer
58763803Snsayer				for(*(int *)data = 0;mb != NULL;mb = mb->m_next)
58863670Snsayer					*(int *)data += mb->m_len;
58983043Sbrooks			} else
59063670Snsayer				*(int *)data = 0;
59163670Snsayer			splx(s);
59283043Sbrooks			break;
59363670Snsayer
59463670Snsayer		case FIOSETOWN:
59563670Snsayer			return (fsetown(*(int *)data, &tp->tap_sigio));
59663670Snsayer
59763670Snsayer		case FIOGETOWN:
598104393Struckman			*(int *)data = fgetown(&tp->tap_sigio);
59963670Snsayer			return (0);
60063670Snsayer
60163670Snsayer		/* this is deprecated, FIOSETOWN should be used instead */
60263670Snsayer		case TIOCSPGRP:
60363670Snsayer			return (fsetown(-(*(int *)data), &tp->tap_sigio));
60463670Snsayer
60563670Snsayer		/* this is deprecated, FIOGETOWN should be used instead */
60663670Snsayer		case TIOCGPGRP:
607104393Struckman			*(int *)data = -fgetown(&tp->tap_sigio);
60863670Snsayer			return (0);
60963670Snsayer
61063670Snsayer		/* VMware/VMnet port ioctl's */
61163670Snsayer
61263670Snsayer		case SIOCGIFFLAGS:	/* get ifnet flags */
61363670Snsayer			bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags));
61483043Sbrooks			break;
61563670Snsayer
61683043Sbrooks		case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */
617102052Ssobomax			f = *(int *)data;
61863670Snsayer			f &= 0x0fff;
61963670Snsayer			f &= ~IFF_CANTCHANGE;
62063670Snsayer			f |= IFF_UP;
62163670Snsayer
62263670Snsayer			s = splimp();
62363670Snsayer			ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE);
62463670Snsayer			splx(s);
62583043Sbrooks			break;
62663670Snsayer
62763861Snsayer		case OSIOCGIFADDR:	/* get MAC address of the remote side */
62863670Snsayer		case SIOCGIFADDR:
62963861Snsayer			bcopy(tp->ether_addr, data, sizeof(tp->ether_addr));
63083043Sbrooks			break;
63163670Snsayer
63263861Snsayer		case SIOCSIFADDR:	/* set MAC address of the remote side */
63363861Snsayer			bcopy(data, tp->ether_addr, sizeof(tp->ether_addr));
63483043Sbrooks			break;
63563670Snsayer
63663670Snsayer		default:
63763670Snsayer			return (ENOTTY);
63863670Snsayer	}
63963670Snsayer	return (0);
64063670Snsayer} /* tapioctl */
64163670Snsayer
64263670Snsayer
64363670Snsayer/*
64463670Snsayer * tapread
64563670Snsayer *
64663670Snsayer * the cdevsw read interface - reads a packet at a time, or at
64763670Snsayer * least as much of a packet as can be read
64863670Snsayer */
64963670Snsayerstatic int
65063670Snsayertapread(dev, uio, flag)
65163670Snsayer	dev_t		 dev;
65263670Snsayer	struct uio	*uio;
65363670Snsayer	int		 flag;
65463670Snsayer{
65563670Snsayer	struct tap_softc	*tp = dev->si_drv1;
65663670Snsayer	struct ifnet		*ifp = &tp->tap_if;
65790227Sdillon	struct mbuf		*m = NULL;
65863670Snsayer	int			 error = 0, len, s;
65963670Snsayer
660121816Sbrooks	TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, minor(dev));
66163670Snsayer
66263670Snsayer	if ((tp->tap_flags & TAP_READY) != TAP_READY) {
663121816Sbrooks		TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n",
664121816Sbrooks			ifp->if_xname, minor(dev), tp->tap_flags);
66563803Snsayer
66663670Snsayer		return (EHOSTDOWN);
66763670Snsayer	}
66863670Snsayer
66963670Snsayer	tp->tap_flags &= ~TAP_RWAIT;
67063670Snsayer
67163670Snsayer	/* sleep until we get a packet */
67263670Snsayer	do {
67363670Snsayer		s = splimp();
67490227Sdillon		IF_DEQUEUE(&ifp->if_snd, m);
67563670Snsayer		splx(s);
67663670Snsayer
67790227Sdillon		if (m == NULL) {
67863670Snsayer			if (flag & IO_NDELAY)
67963670Snsayer				return (EWOULDBLOCK);
680111742Sdes
68163670Snsayer			tp->tap_flags |= TAP_RWAIT;
682111748Sdes			error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0);
68363670Snsayer			if (error)
68463670Snsayer				return (error);
68563670Snsayer		}
68690227Sdillon	} while (m == NULL);
68763670Snsayer
68863670Snsayer	/* feed packet to bpf */
689106939Ssam	BPF_MTAP(ifp, m);
69063670Snsayer
69163670Snsayer	/* xfer packet to user space */
69290227Sdillon	while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) {
69390227Sdillon		len = min(uio->uio_resid, m->m_len);
69463670Snsayer		if (len == 0)
69563670Snsayer			break;
69663670Snsayer
697111741Sdes		error = uiomove(mtod(m, void *), len, uio);
69890227Sdillon		m = m_free(m);
69963670Snsayer	}
70063670Snsayer
70190227Sdillon	if (m != NULL) {
702121816Sbrooks		TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname,
703121816Sbrooks			minor(dev));
70490227Sdillon		m_freem(m);
70563670Snsayer	}
70663670Snsayer
70763670Snsayer	return (error);
70863670Snsayer} /* tapread */
70963670Snsayer
71063670Snsayer
71163670Snsayer/*
71263670Snsayer * tapwrite
71363670Snsayer *
71463670Snsayer * the cdevsw write interface - an atomic write is a packet - or else!
71563670Snsayer */
71663670Snsayerstatic int
71763670Snsayertapwrite(dev, uio, flag)
71863670Snsayer	dev_t		 dev;
71963670Snsayer	struct uio	*uio;
72063670Snsayer	int		 flag;
72163670Snsayer{
72263670Snsayer	struct tap_softc	*tp = dev->si_drv1;
72363670Snsayer	struct ifnet		*ifp = &tp->tap_if;
72463670Snsayer	struct mbuf		*top = NULL, **mp = NULL, *m = NULL;
725111742Sdes	int			 error = 0, tlen, mlen;
72663670Snsayer
727121816Sbrooks	TAPDEBUG("%s writting, minor = %#x\n",
728121816Sbrooks		ifp->if_xname, minor(dev));
72963670Snsayer
73063670Snsayer	if (uio->uio_resid == 0)
73163670Snsayer		return (0);
73263670Snsayer
73363670Snsayer	if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) {
734121816Sbrooks		TAPDEBUG("%s invalid packet len = %d, minor = %#x\n",
735121816Sbrooks			ifp->if_xname, uio->uio_resid, minor(dev));
73663803Snsayer
73763670Snsayer		return (EIO);
73863670Snsayer	}
73963670Snsayer	tlen = uio->uio_resid;
74063670Snsayer
74163670Snsayer	/* get a header mbuf */
742111119Simp	MGETHDR(m, M_DONTWAIT, MT_DATA);
74363670Snsayer	if (m == NULL)
74463670Snsayer		return (ENOBUFS);
74563670Snsayer	mlen = MHLEN;
74663670Snsayer
74763670Snsayer	top = 0;
74863670Snsayer	mp = &top;
74963670Snsayer	while ((error == 0) && (uio->uio_resid > 0)) {
75063670Snsayer		m->m_len = min(mlen, uio->uio_resid);
751111741Sdes		error = uiomove(mtod(m, void *), m->m_len, uio);
75263670Snsayer		*mp = m;
75363670Snsayer		mp = &m->m_next;
75463670Snsayer		if (uio->uio_resid > 0) {
755111119Simp			MGET(m, M_DONTWAIT, MT_DATA);
75663803Snsayer			if (m == NULL) {
75763670Snsayer				error = ENOBUFS;
75863670Snsayer				break;
75963670Snsayer			}
76063670Snsayer			mlen = MLEN;
76163670Snsayer		}
76263670Snsayer	}
76363670Snsayer	if (error) {
76463670Snsayer		ifp->if_ierrors ++;
76563670Snsayer		if (top)
76663670Snsayer			m_freem(top);
76763670Snsayer		return (error);
76863670Snsayer	}
76963670Snsayer
77063670Snsayer	top->m_pkthdr.len = tlen;
77163670Snsayer	top->m_pkthdr.rcvif = ifp;
772111742Sdes
773106939Ssam	/* Pass packet up to parent. */
774106939Ssam	(*ifp->if_input)(ifp, top);
775106939Ssam	ifp->if_ipackets ++; /* ibytes are counted in parent */
77663670Snsayer
77763670Snsayer	return (0);
77863670Snsayer} /* tapwrite */
77963670Snsayer
78063670Snsayer
78163670Snsayer/*
78263670Snsayer * tappoll
78363670Snsayer *
78463670Snsayer * the poll interface, this is only useful on reads
78563670Snsayer * really. the write detect always returns true, write never blocks
78663670Snsayer * anyway, it either accepts the packet or drops it
78763670Snsayer */
78863670Snsayerstatic int
78983366Sjuliantappoll(dev, events, td)
79063670Snsayer	dev_t		 dev;
79163670Snsayer	int		 events;
79283366Sjulian	struct thread	*td;
79363670Snsayer{
79463670Snsayer	struct tap_softc	*tp = dev->si_drv1;
79563670Snsayer	struct ifnet		*ifp = &tp->tap_if;
796111742Sdes	int			 s, revents = 0;
79763670Snsayer
798121816Sbrooks	TAPDEBUG("%s polling, minor = %#x\n",
799121816Sbrooks		ifp->if_xname, minor(dev));
80063670Snsayer
80163670Snsayer	s = splimp();
80263670Snsayer	if (events & (POLLIN | POLLRDNORM)) {
80363670Snsayer		if (ifp->if_snd.ifq_len > 0) {
804121816Sbrooks			TAPDEBUG("%s have data in queue. len = %d, " \
805121816Sbrooks				"minor = %#x\n", ifp->if_xname,
80683043Sbrooks				ifp->if_snd.ifq_len, minor(dev));
80763803Snsayer
80863670Snsayer			revents |= (events & (POLLIN | POLLRDNORM));
80983043Sbrooks		} else {
810121816Sbrooks			TAPDEBUG("%s waiting for data, minor = %#x\n",
811121816Sbrooks				ifp->if_xname, minor(dev));
81263803Snsayer
81383805Sjhb			selrecord(td, &tp->tap_rsel);
81463670Snsayer		}
81563670Snsayer	}
81663670Snsayer
81763670Snsayer	if (events & (POLLOUT | POLLWRNORM))
81863670Snsayer		revents |= (events & (POLLOUT | POLLWRNORM));
81963670Snsayer
82063670Snsayer	splx(s);
82163670Snsayer	return (revents);
82263670Snsayer} /* tappoll */
823