if_tap.c revision 127170
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 127170 2004-03-18 14:18:51Z rwatson $
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,
101126188Sbde	.d_flags =	D_PSEUDO | 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,
10963670Snsayer};
11063670Snsayer
111127003Srwatson/*
112127003Srwatson * All global variables in if_tap.c are locked with tapmtx, with the
113127003Srwatson * exception of tapdebug, which is accessed unlocked; tapclones is
114127003Srwatson * static at runtime.
115127003Srwatson */
116127003Srwatsonstatic struct mtx		tapmtx;
11783043Sbrooksstatic int			tapdebug = 0;        /* debug flag   */
11883043Sbrooksstatic SLIST_HEAD(, tap_softc)	taphead;             /* first device */
119126077Sphkstatic struct clonedevs 	*tapclones;
12063670Snsayer
12163670SnsayerMALLOC_DECLARE(M_TAP);
12263670SnsayerMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface");
12363670SnsayerSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, "");
12463670SnsayerDEV_MODULE(if_tap, tapmodevent, NULL);
12563670Snsayer
12663670Snsayer/*
12763670Snsayer * tapmodevent
12863670Snsayer *
12963670Snsayer * module event handler
13063670Snsayer */
13163670Snsayerstatic int
13263670Snsayertapmodevent(mod, type, data)
13363670Snsayer	module_t	 mod;
13463670Snsayer	int		 type;
13563670Snsayer	void		*data;
13663670Snsayer{
13783043Sbrooks	static eventhandler_tag	 eh_tag = NULL;
13883043Sbrooks	struct tap_softc	*tp = NULL;
13983043Sbrooks	struct ifnet		*ifp = NULL;
140126077Sphk	int			 s;
14163670Snsayer
14263670Snsayer	switch (type) {
14363670Snsayer	case MOD_LOAD:
14463670Snsayer
14583043Sbrooks		/* intitialize device */
14683043Sbrooks
147127003Srwatson		mtx_init(&tapmtx, "tapmtx", NULL, MTX_DEF);
14883043Sbrooks		SLIST_INIT(&taphead);
14983043Sbrooks
150126845Sphk		clone_setup(&tapclones);
15171602Sphk		eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000);
152127003Srwatson		if (eh_tag == NULL) {
153127170Srwatson			clone_cleanup(&tapclones);
154127003Srwatson			mtx_destroy(&tapmtx);
155126077Sphk			return (ENOMEM);
156127003Srwatson		}
15783043Sbrooks		return (0);
15863670Snsayer
15983043Sbrooks	case MOD_UNLOAD:
160127003Srwatson		/*
161127003Srwatson		 * The EBUSY algorithm here can't quite atomically
162127003Srwatson		 * guarantee that this is race-free since we have to
163127003Srwatson		 * release the tap mtx to deregister the clone handler.
164127003Srwatson		 */
165127003Srwatson		mtx_lock(&tapmtx);
166127003Srwatson		SLIST_FOREACH(tp, &taphead, tap_next) {
167127098Srwatson			mtx_lock(&tp->tap_mtx);
168127003Srwatson			if (tp->tap_flags & TAP_OPEN) {
169127098Srwatson				mtx_unlock(&tp->tap_mtx);
170127003Srwatson				mtx_unlock(&tapmtx);
17183043Sbrooks				return (EBUSY);
172127003Srwatson			}
173127098Srwatson			mtx_unlock(&tp->tap_mtx);
174127003Srwatson		}
175127003Srwatson		mtx_unlock(&tapmtx);
17683043Sbrooks
17771602Sphk		EVENTHANDLER_DEREGISTER(dev_clone, eh_tag);
17863670Snsayer
179127003Srwatson		mtx_lock(&tapmtx);
18083043Sbrooks		while ((tp = SLIST_FIRST(&taphead)) != NULL) {
18183043Sbrooks			SLIST_REMOVE_HEAD(&taphead, tap_next);
182127003Srwatson			mtx_unlock(&tapmtx);
18383043Sbrooks
18483043Sbrooks			ifp = &tp->tap_if;
18583043Sbrooks
186121816Sbrooks			TAPDEBUG("detaching %s\n", ifp->if_xname);
18783043Sbrooks
188127098Srwatson			/* Unlocked read. */
189121816Sbrooks			KASSERT(!(tp->tap_flags & TAP_OPEN),
190121816Sbrooks				("%s flags is out of sync", ifp->if_xname));
19183043Sbrooks
192126077Sphk			destroy_dev(tp->tap_dev);
19363670Snsayer			s = splimp();
194106939Ssam			ether_ifdetach(ifp);
19563670Snsayer			splx(s);
19663670Snsayer
197127098Srwatson			mtx_destroy(&tp->tap_mtx);
19893752Sluigi			free(tp, M_TAP);
199127003Srwatson			mtx_lock(&tapmtx);
20083043Sbrooks		}
201127003Srwatson		mtx_unlock(&tapmtx);
202126077Sphk		clone_cleanup(&tapclones);
20363670Snsayer
20483043Sbrooks		break;
20563670Snsayer
20663670Snsayer	default:
20763670Snsayer		return (EOPNOTSUPP);
20863670Snsayer	}
20963670Snsayer
21063670Snsayer	return (0);
21163670Snsayer} /* tapmodevent */
21263670Snsayer
21363670Snsayer
21463670Snsayer/*
21571602Sphk * DEVFS handler
21671602Sphk *
21771602Sphk * We need to support two kind of devices - tap and vmnet
21871602Sphk */
21971602Sphkstatic void
22071602Sphktapclone(arg, name, namelen, dev)
22171602Sphk	void	*arg;
22271602Sphk	char	*name;
22371602Sphk	int	 namelen;
22471602Sphk	dev_t	*dev;
22571602Sphk{
226126077Sphk	u_int		extra;
227126077Sphk	int		i, unit;
22883043Sbrooks	char		*device_name = name;
22971602Sphk
23071602Sphk	if (*dev != NODEV)
23171602Sphk		return;
23271602Sphk
233126077Sphk	device_name = TAP;
234126077Sphk	extra = 0;
235126077Sphk	if (strcmp(name, TAP) == 0) {
236126077Sphk		unit = -1;
237126077Sphk	} else if (strcmp(name, VMNET) == 0) {
238126077Sphk		device_name = VMNET;
239126077Sphk		extra = VMNET_DEV_MASK;
240126077Sphk		unit = -1;
241126077Sphk	} else if (dev_stdclone(name, NULL, device_name, &unit) != 1) {
242126077Sphk		device_name = VMNET;
243126077Sphk		extra = VMNET_DEV_MASK;
244126077Sphk		if (dev_stdclone(name, NULL, device_name, &unit) != 1)
245126077Sphk			return;
24683043Sbrooks	}
24771602Sphk
248126077Sphk	/* find any existing device, or allocate new unit number */
249126077Sphk	i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra);
250126077Sphk	if (i) {
251126796Sphk		*dev = make_dev(&tap_cdevsw, unit2minor(unit | extra),
252126077Sphk		     UID_ROOT, GID_WHEEL, 0600, "%s%d", device_name, unit);
253126077Sphk		if (*dev != NULL)
254126077Sphk			(*dev)->si_flags |= SI_CHEAPCLONE;
25571602Sphk	}
25671602Sphk} /* tapclone */
25771602Sphk
25871602Sphk
25971602Sphk/*
26063670Snsayer * tapcreate
26163670Snsayer *
26263670Snsayer * to create interface
26363670Snsayer */
26463670Snsayerstatic void
26563670Snsayertapcreate(dev)
26663670Snsayer	dev_t	dev;
26763670Snsayer{
26863670Snsayer	struct ifnet		*ifp = NULL;
26963670Snsayer	struct tap_softc	*tp = NULL;
27063670Snsayer	unsigned short		 macaddr_hi;
27163803Snsayer	int			 unit, s;
27263670Snsayer	char			*name = NULL;
27363670Snsayer
274126077Sphk	dev->si_flags &= ~SI_CHEAPCLONE;
275126077Sphk
27663670Snsayer	/* allocate driver storage and create device */
277111119Simp	MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO);
278127098Srwatson	mtx_init(&tp->tap_mtx, "tap_mtx", NULL, MTX_DEF);
279127003Srwatson	mtx_lock(&tapmtx);
28083043Sbrooks	SLIST_INSERT_HEAD(&taphead, tp, tap_next);
281127003Srwatson	mtx_unlock(&tapmtx);
28263670Snsayer
283126796Sphk	unit = dev2unit(dev);
28483043Sbrooks
28563670Snsayer	/* select device: tap or vmnet */
286126796Sphk	if (unit & VMNET_DEV_MASK) {
28763670Snsayer		name = VMNET;
28863803Snsayer		tp->tap_flags |= TAP_VMNET;
28983043Sbrooks	} else
29063670Snsayer		name = TAP;
29163670Snsayer
292126796Sphk	unit &= TAPMAXUNIT;
293126796Sphk
29483043Sbrooks	TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev));
29583043Sbrooks
29663670Snsayer	/* generate fake MAC address: 00 bd xx xx xx unit_no */
29763670Snsayer	macaddr_hi = htons(0x00bd);
29863670Snsayer	bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short));
29963670Snsayer	bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long));
30063670Snsayer	tp->arpcom.ac_enaddr[5] = (u_char)unit;
30163670Snsayer
302111742Sdes	/* fill the rest and attach interface */
30363670Snsayer	ifp = &tp->tap_if;
30463670Snsayer	ifp->if_softc = tp;
305121816Sbrooks	if_initname(ifp, name, unit);
30663670Snsayer	ifp->if_init = tapifinit;
30763670Snsayer	ifp->if_start = tapifstart;
30863670Snsayer	ifp->if_ioctl = tapifioctl;
30963670Snsayer	ifp->if_mtu = ETHERMTU;
31063670Snsayer	ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
31163670Snsayer	ifp->if_snd.ifq_maxlen = ifqmaxlen;
31263670Snsayer
31383043Sbrooks	dev->si_drv1 = tp;
314126077Sphk	tp->tap_dev = dev;
31583043Sbrooks
31663803Snsayer	s = splimp();
317106939Ssam	ether_ifattach(ifp, tp->arpcom.ac_enaddr);
31863803Snsayer	splx(s);
31963670Snsayer
320127098Srwatson	mtx_lock(&tp->tap_mtx);
32163803Snsayer	tp->tap_flags |= TAP_INITED;
322127098Srwatson	mtx_unlock(&tp->tap_mtx);
32363803Snsayer
324121816Sbrooks	TAPDEBUG("interface %s is created. minor = %#x\n",
325121816Sbrooks		ifp->if_xname, minor(dev));
32663670Snsayer} /* tapcreate */
32763670Snsayer
32863670Snsayer
32963670Snsayer/*
330111742Sdes * tapopen
33163670Snsayer *
33263670Snsayer * to open tunnel. must be superuser
33363670Snsayer */
33463670Snsayerstatic int
33583366Sjuliantapopen(dev, flag, mode, td)
33663670Snsayer	dev_t		 dev;
33763670Snsayer	int		 flag;
33863670Snsayer	int		 mode;
33983366Sjulian	struct thread	*td;
34063670Snsayer{
34163670Snsayer	struct tap_softc	*tp = NULL;
342126796Sphk	int			 error;
34363670Snsayer
34493593Sjhb	if ((error = suser(td)) != 0)
34563670Snsayer		return (error);
34663670Snsayer
347126796Sphk	if ((dev2unit(dev) & CLONE_UNITMASK) > TAPMAXUNIT)
348126796Sphk		return (ENXIO);
34983043Sbrooks
350127165Srwatson	/*
351127165Srwatson	 * XXXRW: Non-atomic test-and-set of si_drv1.  Currently protected
352127165Srwatson	 * by Giant, but the race actually exists under memory pressure as
353127165Srwatson	 * well even when running with Giant, as malloc() may sleep.
354127165Srwatson	 */
35563670Snsayer	tp = dev->si_drv1;
35663670Snsayer	if (tp == NULL) {
35763670Snsayer		tapcreate(dev);
35863670Snsayer		tp = dev->si_drv1;
35963670Snsayer	}
36063670Snsayer
361127165Srwatson	mtx_lock(&tp->tap_mtx);
362127165Srwatson	if (tp->tap_flags & TAP_OPEN) {
363127165Srwatson		mtx_unlock(&tp->tap_mtx);
364127165Srwatson		return (EBUSY);
365127165Srwatson	}
36663670Snsayer
36763861Snsayer	bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr));
36883366Sjulian	tp->tap_pid = td->td_proc->p_pid;
36963670Snsayer	tp->tap_flags |= TAP_OPEN;
370127098Srwatson	mtx_unlock(&tp->tap_mtx);
37163670Snsayer
372121816Sbrooks	TAPDEBUG("%s is open. minor = %#x\n",
373121816Sbrooks		tp->tap_if.if_xname, minor(dev));
37463670Snsayer
37563670Snsayer	return (0);
37663670Snsayer} /* tapopen */
37763670Snsayer
37863670Snsayer
37963670Snsayer/*
38063670Snsayer * tapclose
38163670Snsayer *
38263670Snsayer * close the device - mark i/f down & delete routing info
38363670Snsayer */
38463670Snsayerstatic int
38583366Sjuliantapclose(dev, foo, bar, td)
38663670Snsayer	dev_t		 dev;
38763670Snsayer	int		 foo;
38863670Snsayer	int		 bar;
38983366Sjulian	struct thread	*td;
39063670Snsayer{
39163670Snsayer	struct tap_softc	*tp = dev->si_drv1;
39263670Snsayer	struct ifnet		*ifp = &tp->tap_if;
393126077Sphk	int			s;
39463670Snsayer
39563670Snsayer	/* junk all pending output */
39683043Sbrooks	IF_DRAIN(&ifp->if_snd);
39763670Snsayer
39863803Snsayer	/*
39963803Snsayer	 * do not bring the interface down, and do not anything with
40063803Snsayer	 * interface, if we are in VMnet mode. just close the device.
40163803Snsayer	 */
40263803Snsayer
403127098Srwatson	mtx_lock(&tp->tap_mtx);
40463803Snsayer	if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) {
405127098Srwatson		mtx_unlock(&tp->tap_mtx);
40663670Snsayer		s = splimp();
40763670Snsayer		if_down(ifp);
40863670Snsayer		if (ifp->if_flags & IFF_RUNNING) {
40963670Snsayer			/* find internet addresses and delete routes */
41063670Snsayer			struct ifaddr	*ifa = NULL;
41163670Snsayer
412127098Srwatson			/* In desparate need of ifaddr locking. */
41363803Snsayer			TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
41463670Snsayer				if (ifa->ifa_addr->sa_family == AF_INET) {
41563670Snsayer					rtinit(ifa, (int)RTM_DELETE, 0);
41663670Snsayer
41763670Snsayer					/* remove address from interface */
418111742Sdes					bzero(ifa->ifa_addr,
41963670Snsayer						   sizeof(*(ifa->ifa_addr)));
420111742Sdes					bzero(ifa->ifa_dstaddr,
42163670Snsayer						   sizeof(*(ifa->ifa_dstaddr)));
422111742Sdes					bzero(ifa->ifa_netmask,
42363670Snsayer						   sizeof(*(ifa->ifa_netmask)));
42463670Snsayer				}
42563670Snsayer			}
42663670Snsayer
42763670Snsayer			ifp->if_flags &= ~IFF_RUNNING;
42863670Snsayer		}
42963670Snsayer		splx(s);
430127098Srwatson	} else
431127098Srwatson		mtx_unlock(&tp->tap_mtx);
43263670Snsayer
43396122Salfred	funsetown(&tp->tap_sigio);
434122352Stanimura	selwakeuppri(&tp->tap_rsel, PZERO+1);
43563670Snsayer
436127098Srwatson	mtx_lock(&tp->tap_mtx);
43763670Snsayer	tp->tap_flags &= ~TAP_OPEN;
43863670Snsayer	tp->tap_pid = 0;
439127098Srwatson	mtx_unlock(&tp->tap_mtx);
44063670Snsayer
441121816Sbrooks	TAPDEBUG("%s is closed. minor = %#x\n",
442121816Sbrooks		ifp->if_xname, minor(dev));
44363670Snsayer
44463670Snsayer	return (0);
44563670Snsayer} /* tapclose */
44663670Snsayer
44763670Snsayer
44863670Snsayer/*
44963670Snsayer * tapifinit
45063670Snsayer *
45163670Snsayer * network interface initialization function
45263670Snsayer */
45363670Snsayerstatic void
45463670Snsayertapifinit(xtp)
45563670Snsayer	void	*xtp;
45663670Snsayer{
45763670Snsayer	struct tap_softc	*tp = (struct tap_softc *)xtp;
45863670Snsayer	struct ifnet		*ifp = &tp->tap_if;
45963670Snsayer
460121816Sbrooks	TAPDEBUG("initializing %s\n", ifp->if_xname);
46163670Snsayer
46263670Snsayer	ifp->if_flags |= IFF_RUNNING;
46363670Snsayer	ifp->if_flags &= ~IFF_OACTIVE;
46463670Snsayer
46563670Snsayer	/* attempt to start output */
46663670Snsayer	tapifstart(ifp);
46763670Snsayer} /* tapifinit */
46863670Snsayer
46963670Snsayer
47063670Snsayer/*
47163670Snsayer * tapifioctl
47263670Snsayer *
47363670Snsayer * Process an ioctl request on network interface
47463670Snsayer */
475105228Sphkstatic int
47663670Snsayertapifioctl(ifp, cmd, data)
47763670Snsayer	struct ifnet	*ifp;
47863670Snsayer	u_long		 cmd;
47963670Snsayer	caddr_t		 data;
48063670Snsayer{
481111742Sdes	struct tap_softc	*tp = (struct tap_softc *)(ifp->if_softc);
48263670Snsayer	struct ifstat		*ifs = NULL;
48363670Snsayer	int			 s, dummy;
48463670Snsayer
48563670Snsayer	switch (cmd) {
48663670Snsayer		case SIOCSIFFLAGS: /* XXX -- just like vmnet does */
48763670Snsayer		case SIOCADDMULTI:
48863670Snsayer		case SIOCDELMULTI:
48983043Sbrooks			break;
49063670Snsayer
49163670Snsayer		case SIOCGIFSTATUS:
49263670Snsayer			s = splimp();
49363670Snsayer			ifs = (struct ifstat *)data;
49463670Snsayer			dummy = strlen(ifs->ascii);
495127098Srwatson			mtx_lock(&tp->tap_mtx);
49663670Snsayer			if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii))
49763670Snsayer				snprintf(ifs->ascii + dummy,
49863670Snsayer					sizeof(ifs->ascii) - dummy,
49963670Snsayer					"\tOpened by PID %d\n", tp->tap_pid);
500127098Srwatson			mtx_unlock(&tp->tap_mtx);
50163670Snsayer			splx(s);
50283043Sbrooks			break;
50363670Snsayer
50463670Snsayer		default:
505106939Ssam			s = splimp();
506106939Ssam			dummy = ether_ioctl(ifp, cmd, data);
507106939Ssam			splx(s);
508106939Ssam			return (dummy);
50963670Snsayer	}
51063670Snsayer
51163670Snsayer	return (0);
51263670Snsayer} /* tapifioctl */
51363670Snsayer
51463670Snsayer
51563670Snsayer/*
516111742Sdes * tapifstart
517111742Sdes *
51863670Snsayer * queue packets from higher level ready to put out
51963670Snsayer */
52063670Snsayerstatic void
52163670Snsayertapifstart(ifp)
52263670Snsayer	struct ifnet	*ifp;
52363670Snsayer{
52463670Snsayer	struct tap_softc	*tp = ifp->if_softc;
52563670Snsayer	int			 s;
52663670Snsayer
527121816Sbrooks	TAPDEBUG("%s starting\n", ifp->if_xname);
52863670Snsayer
52963803Snsayer	/*
53063803Snsayer	 * do not junk pending output if we are in VMnet mode.
53163803Snsayer	 * XXX: can this do any harm because of queue overflow?
53263803Snsayer	 */
53363803Snsayer
534127098Srwatson	mtx_lock(&tp->tap_mtx);
535111742Sdes	if (((tp->tap_flags & TAP_VMNET) == 0) &&
53663803Snsayer	    ((tp->tap_flags & TAP_READY) != TAP_READY)) {
53763670Snsayer		struct mbuf	*m = NULL;
53863670Snsayer
539127098Srwatson		mtx_unlock(&tp->tap_mtx);
540127098Srwatson
541127098Srwatson		/* Unlocked read. */
542121816Sbrooks		TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname,
543121816Sbrooks		    tp->tap_flags);
54463670Snsayer
54563670Snsayer		s = splimp();
54663670Snsayer		do {
54763670Snsayer			IF_DEQUEUE(&ifp->if_snd, m);
54863670Snsayer			if (m != NULL)
54963670Snsayer				m_freem(m);
55063670Snsayer			ifp->if_oerrors ++;
55163670Snsayer		} while (m != NULL);
55263670Snsayer		splx(s);
55363670Snsayer
55463670Snsayer		return;
55563670Snsayer	}
556127098Srwatson	mtx_unlock(&tp->tap_mtx);
55763670Snsayer
55863670Snsayer	s = splimp();
55963670Snsayer	ifp->if_flags |= IFF_OACTIVE;
56063670Snsayer
56163670Snsayer	if (ifp->if_snd.ifq_len != 0) {
562127098Srwatson		mtx_lock(&tp->tap_mtx);
56363670Snsayer		if (tp->tap_flags & TAP_RWAIT) {
56463670Snsayer			tp->tap_flags &= ~TAP_RWAIT;
565111748Sdes			wakeup(tp);
56663670Snsayer		}
56763670Snsayer
568127098Srwatson		if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) {
569127098Srwatson			mtx_unlock(&tp->tap_mtx);
57095883Salfred			pgsigio(&tp->tap_sigio, SIGIO, 0);
571127098Srwatson		} else
572127098Srwatson			mtx_unlock(&tp->tap_mtx);
57363670Snsayer
574122352Stanimura		selwakeuppri(&tp->tap_rsel, PZERO+1);
57563670Snsayer		ifp->if_opackets ++; /* obytes are counted in ether_output */
57663670Snsayer	}
57763670Snsayer
57863670Snsayer	ifp->if_flags &= ~IFF_OACTIVE;
57963670Snsayer	splx(s);
58063670Snsayer} /* tapifstart */
58163670Snsayer
58263670Snsayer
58363670Snsayer/*
58463670Snsayer * tapioctl
58563670Snsayer *
58663670Snsayer * the cdevsw interface is now pretty minimal
58763670Snsayer */
58863670Snsayerstatic int
58983366Sjuliantapioctl(dev, cmd, data, flag, td)
59063670Snsayer	dev_t		 dev;
59163670Snsayer	u_long		 cmd;
59263670Snsayer	caddr_t		 data;
59363670Snsayer	int		 flag;
59483366Sjulian	struct thread	*td;
59563670Snsayer{
59663670Snsayer	struct tap_softc	*tp = dev->si_drv1;
59763670Snsayer	struct ifnet		*ifp = &tp->tap_if;
598111742Sdes	struct tapinfo		*tapp = NULL;
59963670Snsayer	int			 s;
600102052Ssobomax	int			 f;
60163670Snsayer
60263670Snsayer	switch (cmd) {
603111742Sdes		case TAPSIFINFO:
60463670Snsayer			s = splimp();
605111742Sdes			tapp = (struct tapinfo *)data;
606111742Sdes			ifp->if_mtu = tapp->mtu;
607111742Sdes			ifp->if_type = tapp->type;
608111742Sdes			ifp->if_baudrate = tapp->baudrate;
60963670Snsayer			splx(s);
610111742Sdes			break;
61163670Snsayer
612111742Sdes		case TAPGIFINFO:
613111742Sdes			tapp = (struct tapinfo *)data;
614111742Sdes			tapp->mtu = ifp->if_mtu;
615111742Sdes			tapp->type = ifp->if_type;
616111742Sdes			tapp->baudrate = ifp->if_baudrate;
617111742Sdes			break;
61863670Snsayer
61963670Snsayer		case TAPSDEBUG:
62063670Snsayer			tapdebug = *(int *)data;
62183043Sbrooks			break;
62263670Snsayer
62363670Snsayer		case TAPGDEBUG:
62463670Snsayer			*(int *)data = tapdebug;
62583043Sbrooks			break;
62663670Snsayer
62763670Snsayer		case FIONBIO:
62883043Sbrooks			break;
62963670Snsayer
63063670Snsayer		case FIOASYNC:
63163803Snsayer			s = splimp();
632127098Srwatson			mtx_lock(&tp->tap_mtx);
63363670Snsayer			if (*(int *)data)
63463670Snsayer				tp->tap_flags |= TAP_ASYNC;
63563670Snsayer			else
63663670Snsayer				tp->tap_flags &= ~TAP_ASYNC;
637127098Srwatson			mtx_unlock(&tp->tap_mtx);
63863803Snsayer			splx(s);
63983043Sbrooks			break;
64063670Snsayer
64163670Snsayer		case FIONREAD:
64263670Snsayer			s = splimp();
64363670Snsayer			if (ifp->if_snd.ifq_head) {
64463670Snsayer				struct mbuf	*mb = ifp->if_snd.ifq_head;
64563670Snsayer
64663803Snsayer				for(*(int *)data = 0;mb != NULL;mb = mb->m_next)
64763670Snsayer					*(int *)data += mb->m_len;
64883043Sbrooks			} else
64963670Snsayer				*(int *)data = 0;
65063670Snsayer			splx(s);
65183043Sbrooks			break;
65263670Snsayer
65363670Snsayer		case FIOSETOWN:
65463670Snsayer			return (fsetown(*(int *)data, &tp->tap_sigio));
65563670Snsayer
65663670Snsayer		case FIOGETOWN:
657104393Struckman			*(int *)data = fgetown(&tp->tap_sigio);
65863670Snsayer			return (0);
65963670Snsayer
66063670Snsayer		/* this is deprecated, FIOSETOWN should be used instead */
66163670Snsayer		case TIOCSPGRP:
66263670Snsayer			return (fsetown(-(*(int *)data), &tp->tap_sigio));
66363670Snsayer
66463670Snsayer		/* this is deprecated, FIOGETOWN should be used instead */
66563670Snsayer		case TIOCGPGRP:
666104393Struckman			*(int *)data = -fgetown(&tp->tap_sigio);
66763670Snsayer			return (0);
66863670Snsayer
66963670Snsayer		/* VMware/VMnet port ioctl's */
67063670Snsayer
67163670Snsayer		case SIOCGIFFLAGS:	/* get ifnet flags */
67263670Snsayer			bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags));
67383043Sbrooks			break;
67463670Snsayer
67583043Sbrooks		case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */
676102052Ssobomax			f = *(int *)data;
67763670Snsayer			f &= 0x0fff;
67863670Snsayer			f &= ~IFF_CANTCHANGE;
67963670Snsayer			f |= IFF_UP;
68063670Snsayer
68163670Snsayer			s = splimp();
68263670Snsayer			ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE);
68363670Snsayer			splx(s);
68483043Sbrooks			break;
68563670Snsayer
68663861Snsayer		case OSIOCGIFADDR:	/* get MAC address of the remote side */
68763670Snsayer		case SIOCGIFADDR:
688127165Srwatson			mtx_lock(&tp->tap_mtx);
68963861Snsayer			bcopy(tp->ether_addr, data, sizeof(tp->ether_addr));
690127165Srwatson			mtx_unlock(&tp->tap_mtx);
69183043Sbrooks			break;
69263670Snsayer
69363861Snsayer		case SIOCSIFADDR:	/* set MAC address of the remote side */
694127165Srwatson			mtx_lock(&tp->tap_mtx);
69563861Snsayer			bcopy(data, tp->ether_addr, sizeof(tp->ether_addr));
696127165Srwatson			mtx_unlock(&tp->tap_mtx);
69783043Sbrooks			break;
69863670Snsayer
69963670Snsayer		default:
70063670Snsayer			return (ENOTTY);
70163670Snsayer	}
70263670Snsayer	return (0);
70363670Snsayer} /* tapioctl */
70463670Snsayer
70563670Snsayer
70663670Snsayer/*
70763670Snsayer * tapread
70863670Snsayer *
70963670Snsayer * the cdevsw read interface - reads a packet at a time, or at
71063670Snsayer * least as much of a packet as can be read
71163670Snsayer */
71263670Snsayerstatic int
71363670Snsayertapread(dev, uio, flag)
71463670Snsayer	dev_t		 dev;
71563670Snsayer	struct uio	*uio;
71663670Snsayer	int		 flag;
71763670Snsayer{
71863670Snsayer	struct tap_softc	*tp = dev->si_drv1;
71963670Snsayer	struct ifnet		*ifp = &tp->tap_if;
72090227Sdillon	struct mbuf		*m = NULL;
72163670Snsayer	int			 error = 0, len, s;
72263670Snsayer
723121816Sbrooks	TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, minor(dev));
72463670Snsayer
725127098Srwatson	mtx_lock(&tp->tap_mtx);
72663670Snsayer	if ((tp->tap_flags & TAP_READY) != TAP_READY) {
727127098Srwatson		mtx_unlock(&tp->tap_mtx);
728127098Srwatson
729127098Srwatson		/* Unlocked read. */
730121816Sbrooks		TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n",
731121816Sbrooks			ifp->if_xname, minor(dev), tp->tap_flags);
73263803Snsayer
73363670Snsayer		return (EHOSTDOWN);
73463670Snsayer	}
73563670Snsayer
73663670Snsayer	tp->tap_flags &= ~TAP_RWAIT;
737127098Srwatson	mtx_unlock(&tp->tap_mtx);
73863670Snsayer
73963670Snsayer	/* sleep until we get a packet */
74063670Snsayer	do {
74163670Snsayer		s = splimp();
74290227Sdillon		IF_DEQUEUE(&ifp->if_snd, m);
74363670Snsayer		splx(s);
74463670Snsayer
74590227Sdillon		if (m == NULL) {
74663670Snsayer			if (flag & IO_NDELAY)
74763670Snsayer				return (EWOULDBLOCK);
748111742Sdes
749127098Srwatson			mtx_lock(&tp->tap_mtx);
75063670Snsayer			tp->tap_flags |= TAP_RWAIT;
751127098Srwatson			mtx_unlock(&tp->tap_mtx);
752111748Sdes			error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0);
75363670Snsayer			if (error)
75463670Snsayer				return (error);
75563670Snsayer		}
75690227Sdillon	} while (m == NULL);
75763670Snsayer
75863670Snsayer	/* feed packet to bpf */
759106939Ssam	BPF_MTAP(ifp, m);
76063670Snsayer
76163670Snsayer	/* xfer packet to user space */
76290227Sdillon	while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) {
76390227Sdillon		len = min(uio->uio_resid, m->m_len);
76463670Snsayer		if (len == 0)
76563670Snsayer			break;
76663670Snsayer
767111741Sdes		error = uiomove(mtod(m, void *), len, uio);
76890227Sdillon		m = m_free(m);
76963670Snsayer	}
77063670Snsayer
77190227Sdillon	if (m != NULL) {
772121816Sbrooks		TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname,
773121816Sbrooks			minor(dev));
77490227Sdillon		m_freem(m);
77563670Snsayer	}
77663670Snsayer
77763670Snsayer	return (error);
77863670Snsayer} /* tapread */
77963670Snsayer
78063670Snsayer
78163670Snsayer/*
78263670Snsayer * tapwrite
78363670Snsayer *
78463670Snsayer * the cdevsw write interface - an atomic write is a packet - or else!
78563670Snsayer */
78663670Snsayerstatic int
78763670Snsayertapwrite(dev, uio, flag)
78863670Snsayer	dev_t		 dev;
78963670Snsayer	struct uio	*uio;
79063670Snsayer	int		 flag;
79163670Snsayer{
79263670Snsayer	struct tap_softc	*tp = dev->si_drv1;
79363670Snsayer	struct ifnet		*ifp = &tp->tap_if;
79463670Snsayer	struct mbuf		*top = NULL, **mp = NULL, *m = NULL;
795111742Sdes	int			 error = 0, tlen, mlen;
79663670Snsayer
797121816Sbrooks	TAPDEBUG("%s writting, minor = %#x\n",
798121816Sbrooks		ifp->if_xname, minor(dev));
79963670Snsayer
80063670Snsayer	if (uio->uio_resid == 0)
80163670Snsayer		return (0);
80263670Snsayer
80363670Snsayer	if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) {
804121816Sbrooks		TAPDEBUG("%s invalid packet len = %d, minor = %#x\n",
805121816Sbrooks			ifp->if_xname, uio->uio_resid, minor(dev));
80663803Snsayer
80763670Snsayer		return (EIO);
80863670Snsayer	}
80963670Snsayer	tlen = uio->uio_resid;
81063670Snsayer
81163670Snsayer	/* get a header mbuf */
812111119Simp	MGETHDR(m, M_DONTWAIT, MT_DATA);
81363670Snsayer	if (m == NULL)
81463670Snsayer		return (ENOBUFS);
81563670Snsayer	mlen = MHLEN;
81663670Snsayer
81763670Snsayer	top = 0;
81863670Snsayer	mp = &top;
81963670Snsayer	while ((error == 0) && (uio->uio_resid > 0)) {
82063670Snsayer		m->m_len = min(mlen, uio->uio_resid);
821111741Sdes		error = uiomove(mtod(m, void *), m->m_len, uio);
82263670Snsayer		*mp = m;
82363670Snsayer		mp = &m->m_next;
82463670Snsayer		if (uio->uio_resid > 0) {
825111119Simp			MGET(m, M_DONTWAIT, MT_DATA);
82663803Snsayer			if (m == NULL) {
82763670Snsayer				error = ENOBUFS;
82863670Snsayer				break;
82963670Snsayer			}
83063670Snsayer			mlen = MLEN;
83163670Snsayer		}
83263670Snsayer	}
83363670Snsayer	if (error) {
83463670Snsayer		ifp->if_ierrors ++;
83563670Snsayer		if (top)
83663670Snsayer			m_freem(top);
83763670Snsayer		return (error);
83863670Snsayer	}
83963670Snsayer
84063670Snsayer	top->m_pkthdr.len = tlen;
84163670Snsayer	top->m_pkthdr.rcvif = ifp;
842111742Sdes
843106939Ssam	/* Pass packet up to parent. */
844106939Ssam	(*ifp->if_input)(ifp, top);
845106939Ssam	ifp->if_ipackets ++; /* ibytes are counted in parent */
84663670Snsayer
84763670Snsayer	return (0);
84863670Snsayer} /* tapwrite */
84963670Snsayer
85063670Snsayer
85163670Snsayer/*
85263670Snsayer * tappoll
85363670Snsayer *
85463670Snsayer * the poll interface, this is only useful on reads
85563670Snsayer * really. the write detect always returns true, write never blocks
85663670Snsayer * anyway, it either accepts the packet or drops it
85763670Snsayer */
85863670Snsayerstatic int
85983366Sjuliantappoll(dev, events, td)
86063670Snsayer	dev_t		 dev;
86163670Snsayer	int		 events;
86283366Sjulian	struct thread	*td;
86363670Snsayer{
86463670Snsayer	struct tap_softc	*tp = dev->si_drv1;
86563670Snsayer	struct ifnet		*ifp = &tp->tap_if;
866111742Sdes	int			 s, revents = 0;
86763670Snsayer
868121816Sbrooks	TAPDEBUG("%s polling, minor = %#x\n",
869121816Sbrooks		ifp->if_xname, minor(dev));
87063670Snsayer
87163670Snsayer	s = splimp();
87263670Snsayer	if (events & (POLLIN | POLLRDNORM)) {
87363670Snsayer		if (ifp->if_snd.ifq_len > 0) {
874121816Sbrooks			TAPDEBUG("%s have data in queue. len = %d, " \
875121816Sbrooks				"minor = %#x\n", ifp->if_xname,
87683043Sbrooks				ifp->if_snd.ifq_len, minor(dev));
87763803Snsayer
87863670Snsayer			revents |= (events & (POLLIN | POLLRDNORM));
87983043Sbrooks		} else {
880121816Sbrooks			TAPDEBUG("%s waiting for data, minor = %#x\n",
881121816Sbrooks				ifp->if_xname, minor(dev));
88263803Snsayer
88383805Sjhb			selrecord(td, &tp->tap_rsel);
88463670Snsayer		}
88563670Snsayer	}
88663670Snsayer
88763670Snsayer	if (events & (POLLOUT | POLLWRNORM))
88863670Snsayer		revents |= (events & (POLLOUT | POLLWRNORM));
88963670Snsayer
89063670Snsayer	splx(s);
89163670Snsayer	return (revents);
89263670Snsayer} /* tappoll */
893