if_tap.c revision 148887
1139823Simp/*-
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 148887 2005-08-09 10:20:02Z 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>
42139207Sphk#include <sys/fcntl.h>
4363670Snsayer#include <sys/filio.h>
4463670Snsayer#include <sys/kernel.h>
4563670Snsayer#include <sys/malloc.h>
4663670Snsayer#include <sys/mbuf.h>
47129880Sphk#include <sys/module.h>
4863670Snsayer#include <sys/poll.h>
4963670Snsayer#include <sys/proc.h>
50139207Sphk#include <sys/selinfo.h>
5163670Snsayer#include <sys/signalvar.h>
5263670Snsayer#include <sys/socket.h>
5363670Snsayer#include <sys/sockio.h>
5463670Snsayer#include <sys/sysctl.h>
5563670Snsayer#include <sys/systm.h>
5663670Snsayer#include <sys/ttycom.h>
5763670Snsayer#include <sys/uio.h>
5883043Sbrooks#include <sys/queue.h>
5963670Snsayer
6063670Snsayer#include <net/bpf.h>
6163670Snsayer#include <net/ethernet.h>
6263670Snsayer#include <net/if.h>
6363670Snsayer#include <net/if_arp.h>
6463670Snsayer#include <net/route.h>
65147256Sbrooks#include <net/if_types.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 TAPDEBUG	if (tapdebug) printf
7563670Snsayer
7663670Snsayer#define TAP		"tap"
7763670Snsayer#define VMNET		"vmnet"
7883043Sbrooks#define TAPMAXUNIT	0x7fff
79126077Sphk#define VMNET_DEV_MASK	CLONE_FLAG0
8063670Snsayer
8163670Snsayer/* module */
82111742Sdesstatic int		tapmodevent(module_t, int, void *);
8363670Snsayer
8463670Snsayer/* device */
85148868Srwatsonstatic void		tapclone(void *, struct ucred *, char *, int,
86148868Srwatson			    struct cdev **);
87130585Sphkstatic void		tapcreate(struct cdev *);
8863670Snsayer
8963670Snsayer/* network interface */
9093084Sbdestatic void		tapifstart(struct ifnet *);
9193084Sbdestatic int		tapifioctl(struct ifnet *, u_long, caddr_t);
9293084Sbdestatic void		tapifinit(void *);
9363670Snsayer
9463670Snsayer/* character device */
9563670Snsayerstatic d_open_t		tapopen;
9663670Snsayerstatic d_close_t	tapclose;
9763670Snsayerstatic d_read_t		tapread;
9863670Snsayerstatic d_write_t	tapwrite;
9963670Snsayerstatic d_ioctl_t	tapioctl;
10063670Snsayerstatic d_poll_t		tappoll;
10163670Snsayer
10263670Snsayerstatic struct cdevsw	tap_cdevsw = {
103126080Sphk	.d_version =	D_VERSION,
104126188Sbde	.d_flags =	D_PSEUDO | D_NEEDGIANT,
105111815Sphk	.d_open =	tapopen,
106111815Sphk	.d_close =	tapclose,
107111815Sphk	.d_read =	tapread,
108111815Sphk	.d_write =	tapwrite,
109111815Sphk	.d_ioctl =	tapioctl,
110111815Sphk	.d_poll =	tappoll,
111111815Sphk	.d_name =	CDEV_NAME,
11263670Snsayer};
11363670Snsayer
114127003Srwatson/*
115127003Srwatson * All global variables in if_tap.c are locked with tapmtx, with the
116127003Srwatson * exception of tapdebug, which is accessed unlocked; tapclones is
117127003Srwatson * static at runtime.
118127003Srwatson */
119127003Srwatsonstatic struct mtx		tapmtx;
12083043Sbrooksstatic int			tapdebug = 0;        /* debug flag   */
121144979Smdoddstatic int			tapuopen = 0;        /* allow user open() */
12283043Sbrooksstatic SLIST_HEAD(, tap_softc)	taphead;             /* first device */
123126077Sphkstatic struct clonedevs 	*tapclones;
12463670Snsayer
12563670SnsayerMALLOC_DECLARE(M_TAP);
12663670SnsayerMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface");
12763670SnsayerSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, "");
128144979Smdodd
129144979SmdoddSYSCTL_DECL(_net_link);
130144979SmdoddSYSCTL_NODE(_net_link, OID_AUTO, tap, CTLFLAG_RW, 0,
131144979Smdodd    "Ethernet tunnel software network interface");
132144979SmdoddSYSCTL_INT(_net_link_tap, OID_AUTO, user_open, CTLFLAG_RW, &tapuopen, 0,
133144979Smdodd	"Allow user to open /dev/tap (based on node permissions)");
134144979SmdoddSYSCTL_INT(_net_link_tap, OID_AUTO, debug, CTLFLAG_RW, &tapdebug, 0, "");
135144979Smdodd
13663670SnsayerDEV_MODULE(if_tap, tapmodevent, NULL);
13763670Snsayer
13863670Snsayer/*
13963670Snsayer * tapmodevent
14063670Snsayer *
14163670Snsayer * module event handler
14263670Snsayer */
14363670Snsayerstatic int
14463670Snsayertapmodevent(mod, type, data)
14563670Snsayer	module_t	 mod;
14663670Snsayer	int		 type;
14763670Snsayer	void		*data;
14863670Snsayer{
14983043Sbrooks	static eventhandler_tag	 eh_tag = NULL;
15083043Sbrooks	struct tap_softc	*tp = NULL;
15183043Sbrooks	struct ifnet		*ifp = NULL;
152126077Sphk	int			 s;
15363670Snsayer
15463670Snsayer	switch (type) {
15563670Snsayer	case MOD_LOAD:
15663670Snsayer
15783043Sbrooks		/* intitialize device */
15883043Sbrooks
159127003Srwatson		mtx_init(&tapmtx, "tapmtx", NULL, MTX_DEF);
16083043Sbrooks		SLIST_INIT(&taphead);
16183043Sbrooks
162126845Sphk		clone_setup(&tapclones);
16371602Sphk		eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000);
164127003Srwatson		if (eh_tag == NULL) {
165127170Srwatson			clone_cleanup(&tapclones);
166127003Srwatson			mtx_destroy(&tapmtx);
167126077Sphk			return (ENOMEM);
168127003Srwatson		}
16983043Sbrooks		return (0);
17063670Snsayer
17183043Sbrooks	case MOD_UNLOAD:
172127003Srwatson		/*
173127003Srwatson		 * The EBUSY algorithm here can't quite atomically
174127003Srwatson		 * guarantee that this is race-free since we have to
175127003Srwatson		 * release the tap mtx to deregister the clone handler.
176127003Srwatson		 */
177127003Srwatson		mtx_lock(&tapmtx);
178127003Srwatson		SLIST_FOREACH(tp, &taphead, tap_next) {
179127098Srwatson			mtx_lock(&tp->tap_mtx);
180127003Srwatson			if (tp->tap_flags & TAP_OPEN) {
181127098Srwatson				mtx_unlock(&tp->tap_mtx);
182127003Srwatson				mtx_unlock(&tapmtx);
18383043Sbrooks				return (EBUSY);
184127003Srwatson			}
185127098Srwatson			mtx_unlock(&tp->tap_mtx);
186127003Srwatson		}
187127003Srwatson		mtx_unlock(&tapmtx);
18883043Sbrooks
18971602Sphk		EVENTHANDLER_DEREGISTER(dev_clone, eh_tag);
19063670Snsayer
191127003Srwatson		mtx_lock(&tapmtx);
19283043Sbrooks		while ((tp = SLIST_FIRST(&taphead)) != NULL) {
19383043Sbrooks			SLIST_REMOVE_HEAD(&taphead, tap_next);
194127003Srwatson			mtx_unlock(&tapmtx);
19583043Sbrooks
196147256Sbrooks			ifp = tp->tap_ifp;
19783043Sbrooks
198121816Sbrooks			TAPDEBUG("detaching %s\n", ifp->if_xname);
19983043Sbrooks
200127098Srwatson			/* Unlocked read. */
201121816Sbrooks			KASSERT(!(tp->tap_flags & TAP_OPEN),
202121816Sbrooks				("%s flags is out of sync", ifp->if_xname));
20383043Sbrooks
204126077Sphk			destroy_dev(tp->tap_dev);
20563670Snsayer			s = splimp();
206106939Ssam			ether_ifdetach(ifp);
207147256Sbrooks			if_free_type(ifp, IFT_ETHER);
20863670Snsayer			splx(s);
20963670Snsayer
210127098Srwatson			mtx_destroy(&tp->tap_mtx);
21193752Sluigi			free(tp, M_TAP);
212127003Srwatson			mtx_lock(&tapmtx);
21383043Sbrooks		}
214127003Srwatson		mtx_unlock(&tapmtx);
215126077Sphk		clone_cleanup(&tapclones);
21663670Snsayer
217135354Srwatson		mtx_destroy(&tapmtx);
218135354Srwatson
21983043Sbrooks		break;
22063670Snsayer
22163670Snsayer	default:
22263670Snsayer		return (EOPNOTSUPP);
22363670Snsayer	}
22463670Snsayer
22563670Snsayer	return (0);
22663670Snsayer} /* tapmodevent */
22763670Snsayer
22863670Snsayer
22963670Snsayer/*
23071602Sphk * DEVFS handler
23171602Sphk *
23271602Sphk * We need to support two kind of devices - tap and vmnet
23371602Sphk */
23471602Sphkstatic void
235148868Srwatsontapclone(arg, cred, name, namelen, dev)
23671602Sphk	void	*arg;
237148868Srwatson	struct ucred *cred;
23871602Sphk	char	*name;
23971602Sphk	int	 namelen;
240130585Sphk	struct cdev **dev;
24171602Sphk{
242126077Sphk	u_int		extra;
243126077Sphk	int		i, unit;
24483043Sbrooks	char		*device_name = name;
24571602Sphk
246130640Sphk	if (*dev != NULL)
24771602Sphk		return;
24871602Sphk
249126077Sphk	device_name = TAP;
250126077Sphk	extra = 0;
251126077Sphk	if (strcmp(name, TAP) == 0) {
252126077Sphk		unit = -1;
253126077Sphk	} else if (strcmp(name, VMNET) == 0) {
254126077Sphk		device_name = VMNET;
255126077Sphk		extra = VMNET_DEV_MASK;
256126077Sphk		unit = -1;
257126077Sphk	} else if (dev_stdclone(name, NULL, device_name, &unit) != 1) {
258126077Sphk		device_name = VMNET;
259126077Sphk		extra = VMNET_DEV_MASK;
260126077Sphk		if (dev_stdclone(name, NULL, device_name, &unit) != 1)
261126077Sphk			return;
26283043Sbrooks	}
26371602Sphk
264126077Sphk	/* find any existing device, or allocate new unit number */
265126077Sphk	i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra);
266126077Sphk	if (i) {
267126796Sphk		*dev = make_dev(&tap_cdevsw, unit2minor(unit | extra),
268126077Sphk		     UID_ROOT, GID_WHEEL, 0600, "%s%d", device_name, unit);
269144389Sphk		if (*dev != NULL) {
270144389Sphk			dev_ref(*dev);
271126077Sphk			(*dev)->si_flags |= SI_CHEAPCLONE;
272144389Sphk		}
27371602Sphk	}
27471602Sphk} /* tapclone */
27571602Sphk
27671602Sphk
27771602Sphk/*
27863670Snsayer * tapcreate
27963670Snsayer *
28063670Snsayer * to create interface
28163670Snsayer */
28263670Snsayerstatic void
28363670Snsayertapcreate(dev)
284130585Sphk	struct cdev *dev;
28563670Snsayer{
28663670Snsayer	struct ifnet		*ifp = NULL;
28763670Snsayer	struct tap_softc	*tp = NULL;
28863670Snsayer	unsigned short		 macaddr_hi;
28963803Snsayer	int			 unit, s;
29063670Snsayer	char			*name = NULL;
291147256Sbrooks	u_char			eaddr[6];
29263670Snsayer
293126077Sphk	dev->si_flags &= ~SI_CHEAPCLONE;
294126077Sphk
29563670Snsayer	/* allocate driver storage and create device */
296111119Simp	MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO);
297127098Srwatson	mtx_init(&tp->tap_mtx, "tap_mtx", NULL, MTX_DEF);
298127003Srwatson	mtx_lock(&tapmtx);
29983043Sbrooks	SLIST_INSERT_HEAD(&taphead, tp, tap_next);
300127003Srwatson	mtx_unlock(&tapmtx);
30163670Snsayer
302126796Sphk	unit = dev2unit(dev);
30383043Sbrooks
30463670Snsayer	/* select device: tap or vmnet */
305126796Sphk	if (unit & VMNET_DEV_MASK) {
30663670Snsayer		name = VMNET;
30763803Snsayer		tp->tap_flags |= TAP_VMNET;
30883043Sbrooks	} else
30963670Snsayer		name = TAP;
31063670Snsayer
311126796Sphk	unit &= TAPMAXUNIT;
312126796Sphk
31383043Sbrooks	TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev));
31483043Sbrooks
31563670Snsayer	/* generate fake MAC address: 00 bd xx xx xx unit_no */
31663670Snsayer	macaddr_hi = htons(0x00bd);
317147256Sbrooks	bcopy(&macaddr_hi, eaddr, sizeof(short));
318147256Sbrooks	bcopy(&ticks, &eaddr[2], sizeof(long));
319147256Sbrooks	eaddr[5] = (u_char)unit;
32063670Snsayer
321111742Sdes	/* fill the rest and attach interface */
322147256Sbrooks	ifp = tp->tap_ifp = if_alloc(IFT_ETHER);
323147256Sbrooks	if (ifp == NULL)
324147256Sbrooks		panic("%s%d: can not if_alloc()", name, unit);
32563670Snsayer	ifp->if_softc = tp;
326121816Sbrooks	if_initname(ifp, name, unit);
32763670Snsayer	ifp->if_init = tapifinit;
32863670Snsayer	ifp->if_start = tapifstart;
32963670Snsayer	ifp->if_ioctl = tapifioctl;
33063670Snsayer	ifp->if_mtu = ETHERMTU;
33163670Snsayer	ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
33263670Snsayer	ifp->if_snd.ifq_maxlen = ifqmaxlen;
33363670Snsayer
33483043Sbrooks	dev->si_drv1 = tp;
335126077Sphk	tp->tap_dev = dev;
33683043Sbrooks
33763803Snsayer	s = splimp();
338147256Sbrooks	ether_ifattach(ifp, eaddr);
33963803Snsayer	splx(s);
34063670Snsayer
341127098Srwatson	mtx_lock(&tp->tap_mtx);
34263803Snsayer	tp->tap_flags |= TAP_INITED;
343127098Srwatson	mtx_unlock(&tp->tap_mtx);
34463803Snsayer
345121816Sbrooks	TAPDEBUG("interface %s is created. minor = %#x\n",
346121816Sbrooks		ifp->if_xname, minor(dev));
34763670Snsayer} /* tapcreate */
34863670Snsayer
34963670Snsayer
35063670Snsayer/*
351111742Sdes * tapopen
35263670Snsayer *
35363670Snsayer * to open tunnel. must be superuser
35463670Snsayer */
35563670Snsayerstatic int
35683366Sjuliantapopen(dev, flag, mode, td)
357130585Sphk	struct cdev *dev;
35863670Snsayer	int		 flag;
35963670Snsayer	int		 mode;
36083366Sjulian	struct thread	*td;
36163670Snsayer{
36263670Snsayer	struct tap_softc	*tp = NULL;
363133460Semax	struct ifnet		*ifp = NULL;
364144979Smdodd	int			 s;
36563670Snsayer
366144979Smdodd	if (tapuopen == 0 && suser(td) != 0)
367144979Smdodd		return (EPERM);
36863670Snsayer
369126796Sphk	if ((dev2unit(dev) & CLONE_UNITMASK) > TAPMAXUNIT)
370126796Sphk		return (ENXIO);
37183043Sbrooks
372127165Srwatson	/*
373127165Srwatson	 * XXXRW: Non-atomic test-and-set of si_drv1.  Currently protected
374127165Srwatson	 * by Giant, but the race actually exists under memory pressure as
375127165Srwatson	 * well even when running with Giant, as malloc() may sleep.
376127165Srwatson	 */
37763670Snsayer	tp = dev->si_drv1;
37863670Snsayer	if (tp == NULL) {
37963670Snsayer		tapcreate(dev);
38063670Snsayer		tp = dev->si_drv1;
38163670Snsayer	}
38263670Snsayer
383127165Srwatson	mtx_lock(&tp->tap_mtx);
384127165Srwatson	if (tp->tap_flags & TAP_OPEN) {
385127165Srwatson		mtx_unlock(&tp->tap_mtx);
386127165Srwatson		return (EBUSY);
387127165Srwatson	}
38863670Snsayer
389147256Sbrooks	bcopy(IFP2ENADDR(tp->tap_ifp), tp->ether_addr, sizeof(tp->ether_addr));
39083366Sjulian	tp->tap_pid = td->td_proc->p_pid;
39163670Snsayer	tp->tap_flags |= TAP_OPEN;
392147256Sbrooks	ifp = tp->tap_ifp;
393127098Srwatson	mtx_unlock(&tp->tap_mtx);
39463670Snsayer
395133460Semax	s = splimp();
396148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
397148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
398133460Semax	splx(s);
39963670Snsayer
400133460Semax	TAPDEBUG("%s is open. minor = %#x\n", ifp->if_xname, minor(dev));
401133460Semax
40263670Snsayer	return (0);
40363670Snsayer} /* tapopen */
40463670Snsayer
40563670Snsayer
40663670Snsayer/*
40763670Snsayer * tapclose
40863670Snsayer *
40963670Snsayer * close the device - mark i/f down & delete routing info
41063670Snsayer */
41163670Snsayerstatic int
41283366Sjuliantapclose(dev, foo, bar, td)
413130585Sphk	struct cdev *dev;
41463670Snsayer	int		 foo;
41563670Snsayer	int		 bar;
41683366Sjulian	struct thread	*td;
41763670Snsayer{
418146620Speadar	struct ifaddr *ifa;
41963670Snsayer	struct tap_softc	*tp = dev->si_drv1;
420147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
421126077Sphk	int			s;
42263670Snsayer
42363670Snsayer	/* junk all pending output */
42483043Sbrooks	IF_DRAIN(&ifp->if_snd);
42563670Snsayer
42663803Snsayer	/*
42763803Snsayer	 * do not bring the interface down, and do not anything with
42863803Snsayer	 * interface, if we are in VMnet mode. just close the device.
42963803Snsayer	 */
43063803Snsayer
431127098Srwatson	mtx_lock(&tp->tap_mtx);
43263803Snsayer	if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) {
433127098Srwatson		mtx_unlock(&tp->tap_mtx);
43463670Snsayer		s = splimp();
43563670Snsayer		if_down(ifp);
436148887Srwatson		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
43763803Snsayer			TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
438146620Speadar				rtinit(ifa, (int)RTM_DELETE, 0);
43963670Snsayer			}
440146620Speadar			if_purgeaddrs(ifp);
441148887Srwatson			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
44263670Snsayer		}
44363670Snsayer		splx(s);
444127098Srwatson	} else
445127098Srwatson		mtx_unlock(&tp->tap_mtx);
44663670Snsayer
44796122Salfred	funsetown(&tp->tap_sigio);
448122352Stanimura	selwakeuppri(&tp->tap_rsel, PZERO+1);
44963670Snsayer
450127098Srwatson	mtx_lock(&tp->tap_mtx);
45163670Snsayer	tp->tap_flags &= ~TAP_OPEN;
45263670Snsayer	tp->tap_pid = 0;
453127098Srwatson	mtx_unlock(&tp->tap_mtx);
45463670Snsayer
455121816Sbrooks	TAPDEBUG("%s is closed. minor = %#x\n",
456121816Sbrooks		ifp->if_xname, minor(dev));
45763670Snsayer
45863670Snsayer	return (0);
45963670Snsayer} /* tapclose */
46063670Snsayer
46163670Snsayer
46263670Snsayer/*
46363670Snsayer * tapifinit
46463670Snsayer *
46563670Snsayer * network interface initialization function
46663670Snsayer */
46763670Snsayerstatic void
46863670Snsayertapifinit(xtp)
46963670Snsayer	void	*xtp;
47063670Snsayer{
47163670Snsayer	struct tap_softc	*tp = (struct tap_softc *)xtp;
472147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
47363670Snsayer
474121816Sbrooks	TAPDEBUG("initializing %s\n", ifp->if_xname);
47563670Snsayer
476148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
477148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
47863670Snsayer
47963670Snsayer	/* attempt to start output */
48063670Snsayer	tapifstart(ifp);
48163670Snsayer} /* tapifinit */
48263670Snsayer
48363670Snsayer
48463670Snsayer/*
48563670Snsayer * tapifioctl
48663670Snsayer *
48763670Snsayer * Process an ioctl request on network interface
48863670Snsayer */
489105228Sphkstatic int
49063670Snsayertapifioctl(ifp, cmd, data)
49163670Snsayer	struct ifnet	*ifp;
49263670Snsayer	u_long		 cmd;
49363670Snsayer	caddr_t		 data;
49463670Snsayer{
495111742Sdes	struct tap_softc	*tp = (struct tap_softc *)(ifp->if_softc);
49663670Snsayer	struct ifstat		*ifs = NULL;
49763670Snsayer	int			 s, dummy;
49863670Snsayer
49963670Snsayer	switch (cmd) {
50063670Snsayer		case SIOCSIFFLAGS: /* XXX -- just like vmnet does */
50163670Snsayer		case SIOCADDMULTI:
50263670Snsayer		case SIOCDELMULTI:
50383043Sbrooks			break;
50463670Snsayer
50563670Snsayer		case SIOCGIFSTATUS:
50663670Snsayer			s = splimp();
50763670Snsayer			ifs = (struct ifstat *)data;
50863670Snsayer			dummy = strlen(ifs->ascii);
509127098Srwatson			mtx_lock(&tp->tap_mtx);
51063670Snsayer			if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii))
51163670Snsayer				snprintf(ifs->ascii + dummy,
51263670Snsayer					sizeof(ifs->ascii) - dummy,
51363670Snsayer					"\tOpened by PID %d\n", tp->tap_pid);
514127098Srwatson			mtx_unlock(&tp->tap_mtx);
51563670Snsayer			splx(s);
51683043Sbrooks			break;
51763670Snsayer
51863670Snsayer		default:
519106939Ssam			s = splimp();
520106939Ssam			dummy = ether_ioctl(ifp, cmd, data);
521106939Ssam			splx(s);
522106939Ssam			return (dummy);
52363670Snsayer	}
52463670Snsayer
52563670Snsayer	return (0);
52663670Snsayer} /* tapifioctl */
52763670Snsayer
52863670Snsayer
52963670Snsayer/*
530111742Sdes * tapifstart
531111742Sdes *
53263670Snsayer * queue packets from higher level ready to put out
53363670Snsayer */
53463670Snsayerstatic void
53563670Snsayertapifstart(ifp)
53663670Snsayer	struct ifnet	*ifp;
53763670Snsayer{
53863670Snsayer	struct tap_softc	*tp = ifp->if_softc;
53963670Snsayer	int			 s;
54063670Snsayer
541121816Sbrooks	TAPDEBUG("%s starting\n", ifp->if_xname);
54263670Snsayer
54363803Snsayer	/*
54463803Snsayer	 * do not junk pending output if we are in VMnet mode.
54563803Snsayer	 * XXX: can this do any harm because of queue overflow?
54663803Snsayer	 */
54763803Snsayer
548127098Srwatson	mtx_lock(&tp->tap_mtx);
549111742Sdes	if (((tp->tap_flags & TAP_VMNET) == 0) &&
55063803Snsayer	    ((tp->tap_flags & TAP_READY) != TAP_READY)) {
55163670Snsayer		struct mbuf	*m = NULL;
55263670Snsayer
553127098Srwatson		mtx_unlock(&tp->tap_mtx);
554127098Srwatson
555127098Srwatson		/* Unlocked read. */
556121816Sbrooks		TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname,
557121816Sbrooks		    tp->tap_flags);
55863670Snsayer
55963670Snsayer		s = splimp();
56063670Snsayer		do {
56163670Snsayer			IF_DEQUEUE(&ifp->if_snd, m);
56263670Snsayer			if (m != NULL)
56363670Snsayer				m_freem(m);
56463670Snsayer			ifp->if_oerrors ++;
56563670Snsayer		} while (m != NULL);
56663670Snsayer		splx(s);
56763670Snsayer
56863670Snsayer		return;
56963670Snsayer	}
570127098Srwatson	mtx_unlock(&tp->tap_mtx);
57163670Snsayer
57263670Snsayer	s = splimp();
573148887Srwatson	ifp->if_drv_flags |= IFF_DRV_OACTIVE;
57463670Snsayer
57563670Snsayer	if (ifp->if_snd.ifq_len != 0) {
576127098Srwatson		mtx_lock(&tp->tap_mtx);
57763670Snsayer		if (tp->tap_flags & TAP_RWAIT) {
57863670Snsayer			tp->tap_flags &= ~TAP_RWAIT;
579111748Sdes			wakeup(tp);
58063670Snsayer		}
58163670Snsayer
582127098Srwatson		if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) {
583127098Srwatson			mtx_unlock(&tp->tap_mtx);
58495883Salfred			pgsigio(&tp->tap_sigio, SIGIO, 0);
585127098Srwatson		} else
586127098Srwatson			mtx_unlock(&tp->tap_mtx);
58763670Snsayer
588122352Stanimura		selwakeuppri(&tp->tap_rsel, PZERO+1);
58963670Snsayer		ifp->if_opackets ++; /* obytes are counted in ether_output */
59063670Snsayer	}
59163670Snsayer
592148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
59363670Snsayer	splx(s);
59463670Snsayer} /* tapifstart */
59563670Snsayer
59663670Snsayer
59763670Snsayer/*
59863670Snsayer * tapioctl
59963670Snsayer *
60063670Snsayer * the cdevsw interface is now pretty minimal
60163670Snsayer */
60263670Snsayerstatic int
60383366Sjuliantapioctl(dev, cmd, data, flag, td)
604130585Sphk	struct cdev *dev;
60563670Snsayer	u_long		 cmd;
60663670Snsayer	caddr_t		 data;
60763670Snsayer	int		 flag;
60883366Sjulian	struct thread	*td;
60963670Snsayer{
61063670Snsayer	struct tap_softc	*tp = dev->si_drv1;
611147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
612111742Sdes	struct tapinfo		*tapp = NULL;
61363670Snsayer	int			 s;
614102052Ssobomax	int			 f;
61563670Snsayer
61663670Snsayer	switch (cmd) {
617111742Sdes		case TAPSIFINFO:
61863670Snsayer			s = splimp();
619111742Sdes			tapp = (struct tapinfo *)data;
620111742Sdes			ifp->if_mtu = tapp->mtu;
621111742Sdes			ifp->if_type = tapp->type;
622111742Sdes			ifp->if_baudrate = tapp->baudrate;
62363670Snsayer			splx(s);
624111742Sdes			break;
62563670Snsayer
626111742Sdes		case TAPGIFINFO:
627111742Sdes			tapp = (struct tapinfo *)data;
628111742Sdes			tapp->mtu = ifp->if_mtu;
629111742Sdes			tapp->type = ifp->if_type;
630111742Sdes			tapp->baudrate = ifp->if_baudrate;
631111742Sdes			break;
63263670Snsayer
63363670Snsayer		case TAPSDEBUG:
63463670Snsayer			tapdebug = *(int *)data;
63583043Sbrooks			break;
63663670Snsayer
63763670Snsayer		case TAPGDEBUG:
63863670Snsayer			*(int *)data = tapdebug;
63983043Sbrooks			break;
64063670Snsayer
64163670Snsayer		case FIONBIO:
64283043Sbrooks			break;
64363670Snsayer
64463670Snsayer		case FIOASYNC:
64563803Snsayer			s = splimp();
646127098Srwatson			mtx_lock(&tp->tap_mtx);
64763670Snsayer			if (*(int *)data)
64863670Snsayer				tp->tap_flags |= TAP_ASYNC;
64963670Snsayer			else
65063670Snsayer				tp->tap_flags &= ~TAP_ASYNC;
651127098Srwatson			mtx_unlock(&tp->tap_mtx);
65263803Snsayer			splx(s);
65383043Sbrooks			break;
65463670Snsayer
65563670Snsayer		case FIONREAD:
65663670Snsayer			s = splimp();
65763670Snsayer			if (ifp->if_snd.ifq_head) {
65863670Snsayer				struct mbuf	*mb = ifp->if_snd.ifq_head;
65963670Snsayer
66063803Snsayer				for(*(int *)data = 0;mb != NULL;mb = mb->m_next)
66163670Snsayer					*(int *)data += mb->m_len;
66283043Sbrooks			} else
66363670Snsayer				*(int *)data = 0;
66463670Snsayer			splx(s);
66583043Sbrooks			break;
66663670Snsayer
66763670Snsayer		case FIOSETOWN:
66863670Snsayer			return (fsetown(*(int *)data, &tp->tap_sigio));
66963670Snsayer
67063670Snsayer		case FIOGETOWN:
671104393Struckman			*(int *)data = fgetown(&tp->tap_sigio);
67263670Snsayer			return (0);
67363670Snsayer
67463670Snsayer		/* this is deprecated, FIOSETOWN should be used instead */
67563670Snsayer		case TIOCSPGRP:
67663670Snsayer			return (fsetown(-(*(int *)data), &tp->tap_sigio));
67763670Snsayer
67863670Snsayer		/* this is deprecated, FIOGETOWN should be used instead */
67963670Snsayer		case TIOCGPGRP:
680104393Struckman			*(int *)data = -fgetown(&tp->tap_sigio);
68163670Snsayer			return (0);
68263670Snsayer
68363670Snsayer		/* VMware/VMnet port ioctl's */
68463670Snsayer
68563670Snsayer		case SIOCGIFFLAGS:	/* get ifnet flags */
68663670Snsayer			bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags));
68783043Sbrooks			break;
68863670Snsayer
68983043Sbrooks		case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */
690102052Ssobomax			f = *(int *)data;
69163670Snsayer			f &= 0x0fff;
69263670Snsayer			f &= ~IFF_CANTCHANGE;
69363670Snsayer			f |= IFF_UP;
69463670Snsayer
69563670Snsayer			s = splimp();
69663670Snsayer			ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE);
69763670Snsayer			splx(s);
69883043Sbrooks			break;
69963670Snsayer
70063861Snsayer		case OSIOCGIFADDR:	/* get MAC address of the remote side */
70163670Snsayer		case SIOCGIFADDR:
702127165Srwatson			mtx_lock(&tp->tap_mtx);
70363861Snsayer			bcopy(tp->ether_addr, data, sizeof(tp->ether_addr));
704127165Srwatson			mtx_unlock(&tp->tap_mtx);
70583043Sbrooks			break;
70663670Snsayer
70763861Snsayer		case SIOCSIFADDR:	/* set MAC address of the remote side */
708127165Srwatson			mtx_lock(&tp->tap_mtx);
70963861Snsayer			bcopy(data, tp->ether_addr, sizeof(tp->ether_addr));
710127165Srwatson			mtx_unlock(&tp->tap_mtx);
71183043Sbrooks			break;
71263670Snsayer
71363670Snsayer		default:
71463670Snsayer			return (ENOTTY);
71563670Snsayer	}
71663670Snsayer	return (0);
71763670Snsayer} /* tapioctl */
71863670Snsayer
71963670Snsayer
72063670Snsayer/*
72163670Snsayer * tapread
72263670Snsayer *
72363670Snsayer * the cdevsw read interface - reads a packet at a time, or at
72463670Snsayer * least as much of a packet as can be read
72563670Snsayer */
72663670Snsayerstatic int
72763670Snsayertapread(dev, uio, flag)
728130585Sphk	struct cdev *dev;
72963670Snsayer	struct uio	*uio;
73063670Snsayer	int		 flag;
73163670Snsayer{
73263670Snsayer	struct tap_softc	*tp = dev->si_drv1;
733147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
73490227Sdillon	struct mbuf		*m = NULL;
73563670Snsayer	int			 error = 0, len, s;
73663670Snsayer
737121816Sbrooks	TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, minor(dev));
73863670Snsayer
739127098Srwatson	mtx_lock(&tp->tap_mtx);
74063670Snsayer	if ((tp->tap_flags & TAP_READY) != TAP_READY) {
741127098Srwatson		mtx_unlock(&tp->tap_mtx);
742127098Srwatson
743127098Srwatson		/* Unlocked read. */
744121816Sbrooks		TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n",
745121816Sbrooks			ifp->if_xname, minor(dev), tp->tap_flags);
74663803Snsayer
74763670Snsayer		return (EHOSTDOWN);
74863670Snsayer	}
74963670Snsayer
75063670Snsayer	tp->tap_flags &= ~TAP_RWAIT;
751127098Srwatson	mtx_unlock(&tp->tap_mtx);
75263670Snsayer
75363670Snsayer	/* sleep until we get a packet */
75463670Snsayer	do {
75563670Snsayer		s = splimp();
75690227Sdillon		IF_DEQUEUE(&ifp->if_snd, m);
75763670Snsayer		splx(s);
75863670Snsayer
75990227Sdillon		if (m == NULL) {
760139207Sphk			if (flag & O_NONBLOCK)
76163670Snsayer				return (EWOULDBLOCK);
762111742Sdes
763127098Srwatson			mtx_lock(&tp->tap_mtx);
76463670Snsayer			tp->tap_flags |= TAP_RWAIT;
765127098Srwatson			mtx_unlock(&tp->tap_mtx);
766111748Sdes			error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0);
76763670Snsayer			if (error)
76863670Snsayer				return (error);
76963670Snsayer		}
77090227Sdillon	} while (m == NULL);
77163670Snsayer
77263670Snsayer	/* feed packet to bpf */
773106939Ssam	BPF_MTAP(ifp, m);
77463670Snsayer
77563670Snsayer	/* xfer packet to user space */
77690227Sdillon	while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) {
77790227Sdillon		len = min(uio->uio_resid, m->m_len);
77863670Snsayer		if (len == 0)
77963670Snsayer			break;
78063670Snsayer
781111741Sdes		error = uiomove(mtod(m, void *), len, uio);
78290227Sdillon		m = m_free(m);
78363670Snsayer	}
78463670Snsayer
78590227Sdillon	if (m != NULL) {
786121816Sbrooks		TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname,
787121816Sbrooks			minor(dev));
78890227Sdillon		m_freem(m);
78963670Snsayer	}
79063670Snsayer
79163670Snsayer	return (error);
79263670Snsayer} /* tapread */
79363670Snsayer
79463670Snsayer
79563670Snsayer/*
79663670Snsayer * tapwrite
79763670Snsayer *
79863670Snsayer * the cdevsw write interface - an atomic write is a packet - or else!
79963670Snsayer */
80063670Snsayerstatic int
80163670Snsayertapwrite(dev, uio, flag)
802130585Sphk	struct cdev *dev;
80363670Snsayer	struct uio	*uio;
80463670Snsayer	int		 flag;
80563670Snsayer{
80663670Snsayer	struct tap_softc	*tp = dev->si_drv1;
807147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
808137101Sglebius	struct mbuf		*m;
809137101Sglebius	int			 error = 0;
81063670Snsayer
811121816Sbrooks	TAPDEBUG("%s writting, minor = %#x\n",
812121816Sbrooks		ifp->if_xname, minor(dev));
81363670Snsayer
81463670Snsayer	if (uio->uio_resid == 0)
81563670Snsayer		return (0);
81663670Snsayer
81763670Snsayer	if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) {
818121816Sbrooks		TAPDEBUG("%s invalid packet len = %d, minor = %#x\n",
819121816Sbrooks			ifp->if_xname, uio->uio_resid, minor(dev));
82063803Snsayer
82163670Snsayer		return (EIO);
82263670Snsayer	}
82363670Snsayer
824145883Semax	if ((m = m_uiotombuf(uio, M_DONTWAIT, 0, ETHER_ALIGN)) == NULL) {
82563670Snsayer		ifp->if_ierrors ++;
82663670Snsayer		return (error);
82763670Snsayer	}
82863670Snsayer
829137101Sglebius	m->m_pkthdr.rcvif = ifp;
830111742Sdes
831106939Ssam	/* Pass packet up to parent. */
832137101Sglebius	(*ifp->if_input)(ifp, m);
833106939Ssam	ifp->if_ipackets ++; /* ibytes are counted in parent */
83463670Snsayer
83563670Snsayer	return (0);
83663670Snsayer} /* tapwrite */
83763670Snsayer
83863670Snsayer
83963670Snsayer/*
84063670Snsayer * tappoll
84163670Snsayer *
84263670Snsayer * the poll interface, this is only useful on reads
84363670Snsayer * really. the write detect always returns true, write never blocks
84463670Snsayer * anyway, it either accepts the packet or drops it
84563670Snsayer */
84663670Snsayerstatic int
84783366Sjuliantappoll(dev, events, td)
848130585Sphk	struct cdev *dev;
84963670Snsayer	int		 events;
85083366Sjulian	struct thread	*td;
85163670Snsayer{
85263670Snsayer	struct tap_softc	*tp = dev->si_drv1;
853147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
854111742Sdes	int			 s, revents = 0;
85563670Snsayer
856121816Sbrooks	TAPDEBUG("%s polling, minor = %#x\n",
857121816Sbrooks		ifp->if_xname, minor(dev));
85863670Snsayer
85963670Snsayer	s = splimp();
86063670Snsayer	if (events & (POLLIN | POLLRDNORM)) {
86163670Snsayer		if (ifp->if_snd.ifq_len > 0) {
862121816Sbrooks			TAPDEBUG("%s have data in queue. len = %d, " \
863121816Sbrooks				"minor = %#x\n", ifp->if_xname,
86483043Sbrooks				ifp->if_snd.ifq_len, minor(dev));
86563803Snsayer
86663670Snsayer			revents |= (events & (POLLIN | POLLRDNORM));
86783043Sbrooks		} else {
868121816Sbrooks			TAPDEBUG("%s waiting for data, minor = %#x\n",
869121816Sbrooks				ifp->if_xname, minor(dev));
87063803Snsayer
87183805Sjhb			selrecord(td, &tp->tap_rsel);
87263670Snsayer		}
87363670Snsayer	}
87463670Snsayer
87563670Snsayer	if (events & (POLLOUT | POLLWRNORM))
87663670Snsayer		revents |= (events & (POLLOUT | POLLWRNORM));
87763670Snsayer
87863670Snsayer	splx(s);
87963670Snsayer	return (revents);
88063670Snsayer} /* tappoll */
881