if_tap.c revision 145883
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 145883 2005-05-04 18:55:03Z emax $
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>
6563670Snsayer
6663670Snsayer#include <netinet/in.h>
6763670Snsayer
6863670Snsayer#include <net/if_tapvar.h>
6963670Snsayer#include <net/if_tap.h>
7063670Snsayer
7163670Snsayer
7263670Snsayer#define CDEV_NAME	"tap"
7363670Snsayer#define TAPDEBUG	if (tapdebug) printf
7463670Snsayer
7563670Snsayer#define TAP		"tap"
7663670Snsayer#define VMNET		"vmnet"
7783043Sbrooks#define TAPMAXUNIT	0x7fff
78126077Sphk#define VMNET_DEV_MASK	CLONE_FLAG0
7963670Snsayer
8063670Snsayer/* module */
81111742Sdesstatic int		tapmodevent(module_t, int, void *);
8263670Snsayer
8363670Snsayer/* device */
84130585Sphkstatic void		tapclone(void *, char *, int, struct cdev **);
85130585Sphkstatic void		tapcreate(struct cdev *);
8663670Snsayer
8763670Snsayer/* network interface */
8893084Sbdestatic void		tapifstart(struct ifnet *);
8993084Sbdestatic int		tapifioctl(struct ifnet *, u_long, caddr_t);
9093084Sbdestatic void		tapifinit(void *);
9163670Snsayer
9263670Snsayer/* character device */
9363670Snsayerstatic d_open_t		tapopen;
9463670Snsayerstatic d_close_t	tapclose;
9563670Snsayerstatic d_read_t		tapread;
9663670Snsayerstatic d_write_t	tapwrite;
9763670Snsayerstatic d_ioctl_t	tapioctl;
9863670Snsayerstatic d_poll_t		tappoll;
9963670Snsayer
10063670Snsayerstatic struct cdevsw	tap_cdevsw = {
101126080Sphk	.d_version =	D_VERSION,
102126188Sbde	.d_flags =	D_PSEUDO | D_NEEDGIANT,
103111815Sphk	.d_open =	tapopen,
104111815Sphk	.d_close =	tapclose,
105111815Sphk	.d_read =	tapread,
106111815Sphk	.d_write =	tapwrite,
107111815Sphk	.d_ioctl =	tapioctl,
108111815Sphk	.d_poll =	tappoll,
109111815Sphk	.d_name =	CDEV_NAME,
11063670Snsayer};
11163670Snsayer
112127003Srwatson/*
113127003Srwatson * All global variables in if_tap.c are locked with tapmtx, with the
114127003Srwatson * exception of tapdebug, which is accessed unlocked; tapclones is
115127003Srwatson * static at runtime.
116127003Srwatson */
117127003Srwatsonstatic struct mtx		tapmtx;
11883043Sbrooksstatic int			tapdebug = 0;        /* debug flag   */
119144979Smdoddstatic int			tapuopen = 0;        /* allow user open() */
12083043Sbrooksstatic SLIST_HEAD(, tap_softc)	taphead;             /* first device */
121126077Sphkstatic struct clonedevs 	*tapclones;
12263670Snsayer
12363670SnsayerMALLOC_DECLARE(M_TAP);
12463670SnsayerMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface");
12563670SnsayerSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, "");
126144979Smdodd
127144979SmdoddSYSCTL_DECL(_net_link);
128144979SmdoddSYSCTL_NODE(_net_link, OID_AUTO, tap, CTLFLAG_RW, 0,
129144979Smdodd    "Ethernet tunnel software network interface");
130144979SmdoddSYSCTL_INT(_net_link_tap, OID_AUTO, user_open, CTLFLAG_RW, &tapuopen, 0,
131144979Smdodd	"Allow user to open /dev/tap (based on node permissions)");
132144979SmdoddSYSCTL_INT(_net_link_tap, OID_AUTO, debug, CTLFLAG_RW, &tapdebug, 0, "");
133144979Smdodd
13463670SnsayerDEV_MODULE(if_tap, tapmodevent, NULL);
13563670Snsayer
13663670Snsayer/*
13763670Snsayer * tapmodevent
13863670Snsayer *
13963670Snsayer * module event handler
14063670Snsayer */
14163670Snsayerstatic int
14263670Snsayertapmodevent(mod, type, data)
14363670Snsayer	module_t	 mod;
14463670Snsayer	int		 type;
14563670Snsayer	void		*data;
14663670Snsayer{
14783043Sbrooks	static eventhandler_tag	 eh_tag = NULL;
14883043Sbrooks	struct tap_softc	*tp = NULL;
14983043Sbrooks	struct ifnet		*ifp = NULL;
150126077Sphk	int			 s;
15163670Snsayer
15263670Snsayer	switch (type) {
15363670Snsayer	case MOD_LOAD:
15463670Snsayer
15583043Sbrooks		/* intitialize device */
15683043Sbrooks
157127003Srwatson		mtx_init(&tapmtx, "tapmtx", NULL, MTX_DEF);
15883043Sbrooks		SLIST_INIT(&taphead);
15983043Sbrooks
160126845Sphk		clone_setup(&tapclones);
16171602Sphk		eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000);
162127003Srwatson		if (eh_tag == NULL) {
163127170Srwatson			clone_cleanup(&tapclones);
164127003Srwatson			mtx_destroy(&tapmtx);
165126077Sphk			return (ENOMEM);
166127003Srwatson		}
16783043Sbrooks		return (0);
16863670Snsayer
16983043Sbrooks	case MOD_UNLOAD:
170127003Srwatson		/*
171127003Srwatson		 * The EBUSY algorithm here can't quite atomically
172127003Srwatson		 * guarantee that this is race-free since we have to
173127003Srwatson		 * release the tap mtx to deregister the clone handler.
174127003Srwatson		 */
175127003Srwatson		mtx_lock(&tapmtx);
176127003Srwatson		SLIST_FOREACH(tp, &taphead, tap_next) {
177127098Srwatson			mtx_lock(&tp->tap_mtx);
178127003Srwatson			if (tp->tap_flags & TAP_OPEN) {
179127098Srwatson				mtx_unlock(&tp->tap_mtx);
180127003Srwatson				mtx_unlock(&tapmtx);
18183043Sbrooks				return (EBUSY);
182127003Srwatson			}
183127098Srwatson			mtx_unlock(&tp->tap_mtx);
184127003Srwatson		}
185127003Srwatson		mtx_unlock(&tapmtx);
18683043Sbrooks
18771602Sphk		EVENTHANDLER_DEREGISTER(dev_clone, eh_tag);
18863670Snsayer
189127003Srwatson		mtx_lock(&tapmtx);
19083043Sbrooks		while ((tp = SLIST_FIRST(&taphead)) != NULL) {
19183043Sbrooks			SLIST_REMOVE_HEAD(&taphead, tap_next);
192127003Srwatson			mtx_unlock(&tapmtx);
19383043Sbrooks
19483043Sbrooks			ifp = &tp->tap_if;
19583043Sbrooks
196121816Sbrooks			TAPDEBUG("detaching %s\n", ifp->if_xname);
19783043Sbrooks
198127098Srwatson			/* Unlocked read. */
199121816Sbrooks			KASSERT(!(tp->tap_flags & TAP_OPEN),
200121816Sbrooks				("%s flags is out of sync", ifp->if_xname));
20183043Sbrooks
202126077Sphk			destroy_dev(tp->tap_dev);
20363670Snsayer			s = splimp();
204106939Ssam			ether_ifdetach(ifp);
20563670Snsayer			splx(s);
20663670Snsayer
207127098Srwatson			mtx_destroy(&tp->tap_mtx);
20893752Sluigi			free(tp, M_TAP);
209127003Srwatson			mtx_lock(&tapmtx);
21083043Sbrooks		}
211127003Srwatson		mtx_unlock(&tapmtx);
212126077Sphk		clone_cleanup(&tapclones);
21363670Snsayer
214135354Srwatson		mtx_destroy(&tapmtx);
215135354Srwatson
21683043Sbrooks		break;
21763670Snsayer
21863670Snsayer	default:
21963670Snsayer		return (EOPNOTSUPP);
22063670Snsayer	}
22163670Snsayer
22263670Snsayer	return (0);
22363670Snsayer} /* tapmodevent */
22463670Snsayer
22563670Snsayer
22663670Snsayer/*
22771602Sphk * DEVFS handler
22871602Sphk *
22971602Sphk * We need to support two kind of devices - tap and vmnet
23071602Sphk */
23171602Sphkstatic void
23271602Sphktapclone(arg, name, namelen, dev)
23371602Sphk	void	*arg;
23471602Sphk	char	*name;
23571602Sphk	int	 namelen;
236130585Sphk	struct cdev **dev;
23771602Sphk{
238126077Sphk	u_int		extra;
239126077Sphk	int		i, unit;
24083043Sbrooks	char		*device_name = name;
24171602Sphk
242130640Sphk	if (*dev != NULL)
24371602Sphk		return;
24471602Sphk
245126077Sphk	device_name = TAP;
246126077Sphk	extra = 0;
247126077Sphk	if (strcmp(name, TAP) == 0) {
248126077Sphk		unit = -1;
249126077Sphk	} else if (strcmp(name, VMNET) == 0) {
250126077Sphk		device_name = VMNET;
251126077Sphk		extra = VMNET_DEV_MASK;
252126077Sphk		unit = -1;
253126077Sphk	} else if (dev_stdclone(name, NULL, device_name, &unit) != 1) {
254126077Sphk		device_name = VMNET;
255126077Sphk		extra = VMNET_DEV_MASK;
256126077Sphk		if (dev_stdclone(name, NULL, device_name, &unit) != 1)
257126077Sphk			return;
25883043Sbrooks	}
25971602Sphk
260126077Sphk	/* find any existing device, or allocate new unit number */
261126077Sphk	i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra);
262126077Sphk	if (i) {
263126796Sphk		*dev = make_dev(&tap_cdevsw, unit2minor(unit | extra),
264126077Sphk		     UID_ROOT, GID_WHEEL, 0600, "%s%d", device_name, unit);
265144389Sphk		if (*dev != NULL) {
266144389Sphk			dev_ref(*dev);
267126077Sphk			(*dev)->si_flags |= SI_CHEAPCLONE;
268144389Sphk		}
26971602Sphk	}
27071602Sphk} /* tapclone */
27171602Sphk
27271602Sphk
27371602Sphk/*
27463670Snsayer * tapcreate
27563670Snsayer *
27663670Snsayer * to create interface
27763670Snsayer */
27863670Snsayerstatic void
27963670Snsayertapcreate(dev)
280130585Sphk	struct cdev *dev;
28163670Snsayer{
28263670Snsayer	struct ifnet		*ifp = NULL;
28363670Snsayer	struct tap_softc	*tp = NULL;
28463670Snsayer	unsigned short		 macaddr_hi;
28563803Snsayer	int			 unit, s;
28663670Snsayer	char			*name = NULL;
28763670Snsayer
288126077Sphk	dev->si_flags &= ~SI_CHEAPCLONE;
289126077Sphk
29063670Snsayer	/* allocate driver storage and create device */
291111119Simp	MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO);
292127098Srwatson	mtx_init(&tp->tap_mtx, "tap_mtx", NULL, MTX_DEF);
293127003Srwatson	mtx_lock(&tapmtx);
29483043Sbrooks	SLIST_INSERT_HEAD(&taphead, tp, tap_next);
295127003Srwatson	mtx_unlock(&tapmtx);
29663670Snsayer
297126796Sphk	unit = dev2unit(dev);
29883043Sbrooks
29963670Snsayer	/* select device: tap or vmnet */
300126796Sphk	if (unit & VMNET_DEV_MASK) {
30163670Snsayer		name = VMNET;
30263803Snsayer		tp->tap_flags |= TAP_VMNET;
30383043Sbrooks	} else
30463670Snsayer		name = TAP;
30563670Snsayer
306126796Sphk	unit &= TAPMAXUNIT;
307126796Sphk
30883043Sbrooks	TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev));
30983043Sbrooks
31063670Snsayer	/* generate fake MAC address: 00 bd xx xx xx unit_no */
31163670Snsayer	macaddr_hi = htons(0x00bd);
31263670Snsayer	bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short));
31363670Snsayer	bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long));
31463670Snsayer	tp->arpcom.ac_enaddr[5] = (u_char)unit;
31563670Snsayer
316111742Sdes	/* fill the rest and attach interface */
31763670Snsayer	ifp = &tp->tap_if;
31863670Snsayer	ifp->if_softc = tp;
319121816Sbrooks	if_initname(ifp, name, unit);
32063670Snsayer	ifp->if_init = tapifinit;
32163670Snsayer	ifp->if_start = tapifstart;
32263670Snsayer	ifp->if_ioctl = tapifioctl;
32363670Snsayer	ifp->if_mtu = ETHERMTU;
32463670Snsayer	ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
32563670Snsayer	ifp->if_snd.ifq_maxlen = ifqmaxlen;
32663670Snsayer
32783043Sbrooks	dev->si_drv1 = tp;
328126077Sphk	tp->tap_dev = dev;
32983043Sbrooks
33063803Snsayer	s = splimp();
331106939Ssam	ether_ifattach(ifp, tp->arpcom.ac_enaddr);
33263803Snsayer	splx(s);
33363670Snsayer
334127098Srwatson	mtx_lock(&tp->tap_mtx);
33563803Snsayer	tp->tap_flags |= TAP_INITED;
336127098Srwatson	mtx_unlock(&tp->tap_mtx);
33763803Snsayer
338121816Sbrooks	TAPDEBUG("interface %s is created. minor = %#x\n",
339121816Sbrooks		ifp->if_xname, minor(dev));
34063670Snsayer} /* tapcreate */
34163670Snsayer
34263670Snsayer
34363670Snsayer/*
344111742Sdes * tapopen
34563670Snsayer *
34663670Snsayer * to open tunnel. must be superuser
34763670Snsayer */
34863670Snsayerstatic int
34983366Sjuliantapopen(dev, flag, mode, td)
350130585Sphk	struct cdev *dev;
35163670Snsayer	int		 flag;
35263670Snsayer	int		 mode;
35383366Sjulian	struct thread	*td;
35463670Snsayer{
35563670Snsayer	struct tap_softc	*tp = NULL;
356133460Semax	struct ifnet		*ifp = NULL;
357144979Smdodd	int			 s;
35863670Snsayer
359144979Smdodd	if (tapuopen == 0 && suser(td) != 0)
360144979Smdodd		return (EPERM);
36163670Snsayer
362126796Sphk	if ((dev2unit(dev) & CLONE_UNITMASK) > TAPMAXUNIT)
363126796Sphk		return (ENXIO);
36483043Sbrooks
365127165Srwatson	/*
366127165Srwatson	 * XXXRW: Non-atomic test-and-set of si_drv1.  Currently protected
367127165Srwatson	 * by Giant, but the race actually exists under memory pressure as
368127165Srwatson	 * well even when running with Giant, as malloc() may sleep.
369127165Srwatson	 */
37063670Snsayer	tp = dev->si_drv1;
37163670Snsayer	if (tp == NULL) {
37263670Snsayer		tapcreate(dev);
37363670Snsayer		tp = dev->si_drv1;
37463670Snsayer	}
37563670Snsayer
376127165Srwatson	mtx_lock(&tp->tap_mtx);
377127165Srwatson	if (tp->tap_flags & TAP_OPEN) {
378127165Srwatson		mtx_unlock(&tp->tap_mtx);
379127165Srwatson		return (EBUSY);
380127165Srwatson	}
38163670Snsayer
38263861Snsayer	bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr));
38383366Sjulian	tp->tap_pid = td->td_proc->p_pid;
38463670Snsayer	tp->tap_flags |= TAP_OPEN;
385133460Semax	ifp = &tp->tap_if;
386127098Srwatson	mtx_unlock(&tp->tap_mtx);
38763670Snsayer
388133460Semax	s = splimp();
389133460Semax	ifp->if_flags |= IFF_RUNNING;
390133460Semax	ifp->if_flags &= ~IFF_OACTIVE;
391133460Semax	splx(s);
39263670Snsayer
393133460Semax	TAPDEBUG("%s is open. minor = %#x\n", ifp->if_xname, minor(dev));
394133460Semax
39563670Snsayer	return (0);
39663670Snsayer} /* tapopen */
39763670Snsayer
39863670Snsayer
39963670Snsayer/*
40063670Snsayer * tapclose
40163670Snsayer *
40263670Snsayer * close the device - mark i/f down & delete routing info
40363670Snsayer */
40463670Snsayerstatic int
40583366Sjuliantapclose(dev, foo, bar, td)
406130585Sphk	struct cdev *dev;
40763670Snsayer	int		 foo;
40863670Snsayer	int		 bar;
40983366Sjulian	struct thread	*td;
41063670Snsayer{
41163670Snsayer	struct tap_softc	*tp = dev->si_drv1;
41263670Snsayer	struct ifnet		*ifp = &tp->tap_if;
413126077Sphk	int			s;
41463670Snsayer
41563670Snsayer	/* junk all pending output */
41683043Sbrooks	IF_DRAIN(&ifp->if_snd);
41763670Snsayer
41863803Snsayer	/*
41963803Snsayer	 * do not bring the interface down, and do not anything with
42063803Snsayer	 * interface, if we are in VMnet mode. just close the device.
42163803Snsayer	 */
42263803Snsayer
423127098Srwatson	mtx_lock(&tp->tap_mtx);
42463803Snsayer	if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) {
425127098Srwatson		mtx_unlock(&tp->tap_mtx);
42663670Snsayer		s = splimp();
42763670Snsayer		if_down(ifp);
42863670Snsayer		if (ifp->if_flags & IFF_RUNNING) {
42963670Snsayer			/* find internet addresses and delete routes */
43063670Snsayer			struct ifaddr	*ifa = NULL;
43163670Snsayer
432127098Srwatson			/* In desparate need of ifaddr locking. */
43363803Snsayer			TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
43463670Snsayer				if (ifa->ifa_addr->sa_family == AF_INET) {
43563670Snsayer					rtinit(ifa, (int)RTM_DELETE, 0);
43663670Snsayer
43763670Snsayer					/* remove address from interface */
438111742Sdes					bzero(ifa->ifa_addr,
43963670Snsayer						   sizeof(*(ifa->ifa_addr)));
440111742Sdes					bzero(ifa->ifa_dstaddr,
44163670Snsayer						   sizeof(*(ifa->ifa_dstaddr)));
442111742Sdes					bzero(ifa->ifa_netmask,
44363670Snsayer						   sizeof(*(ifa->ifa_netmask)));
44463670Snsayer				}
44563670Snsayer			}
44663670Snsayer
44763670Snsayer			ifp->if_flags &= ~IFF_RUNNING;
44863670Snsayer		}
44963670Snsayer		splx(s);
450127098Srwatson	} else
451127098Srwatson		mtx_unlock(&tp->tap_mtx);
45263670Snsayer
45396122Salfred	funsetown(&tp->tap_sigio);
454122352Stanimura	selwakeuppri(&tp->tap_rsel, PZERO+1);
45563670Snsayer
456127098Srwatson	mtx_lock(&tp->tap_mtx);
45763670Snsayer	tp->tap_flags &= ~TAP_OPEN;
45863670Snsayer	tp->tap_pid = 0;
459127098Srwatson	mtx_unlock(&tp->tap_mtx);
46063670Snsayer
461121816Sbrooks	TAPDEBUG("%s is closed. minor = %#x\n",
462121816Sbrooks		ifp->if_xname, minor(dev));
46363670Snsayer
46463670Snsayer	return (0);
46563670Snsayer} /* tapclose */
46663670Snsayer
46763670Snsayer
46863670Snsayer/*
46963670Snsayer * tapifinit
47063670Snsayer *
47163670Snsayer * network interface initialization function
47263670Snsayer */
47363670Snsayerstatic void
47463670Snsayertapifinit(xtp)
47563670Snsayer	void	*xtp;
47663670Snsayer{
47763670Snsayer	struct tap_softc	*tp = (struct tap_softc *)xtp;
47863670Snsayer	struct ifnet		*ifp = &tp->tap_if;
47963670Snsayer
480121816Sbrooks	TAPDEBUG("initializing %s\n", ifp->if_xname);
48163670Snsayer
48263670Snsayer	ifp->if_flags |= IFF_RUNNING;
48363670Snsayer	ifp->if_flags &= ~IFF_OACTIVE;
48463670Snsayer
48563670Snsayer	/* attempt to start output */
48663670Snsayer	tapifstart(ifp);
48763670Snsayer} /* tapifinit */
48863670Snsayer
48963670Snsayer
49063670Snsayer/*
49163670Snsayer * tapifioctl
49263670Snsayer *
49363670Snsayer * Process an ioctl request on network interface
49463670Snsayer */
495105228Sphkstatic int
49663670Snsayertapifioctl(ifp, cmd, data)
49763670Snsayer	struct ifnet	*ifp;
49863670Snsayer	u_long		 cmd;
49963670Snsayer	caddr_t		 data;
50063670Snsayer{
501111742Sdes	struct tap_softc	*tp = (struct tap_softc *)(ifp->if_softc);
50263670Snsayer	struct ifstat		*ifs = NULL;
50363670Snsayer	int			 s, dummy;
50463670Snsayer
50563670Snsayer	switch (cmd) {
50663670Snsayer		case SIOCSIFFLAGS: /* XXX -- just like vmnet does */
50763670Snsayer		case SIOCADDMULTI:
50863670Snsayer		case SIOCDELMULTI:
50983043Sbrooks			break;
51063670Snsayer
51163670Snsayer		case SIOCGIFSTATUS:
51263670Snsayer			s = splimp();
51363670Snsayer			ifs = (struct ifstat *)data;
51463670Snsayer			dummy = strlen(ifs->ascii);
515127098Srwatson			mtx_lock(&tp->tap_mtx);
51663670Snsayer			if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii))
51763670Snsayer				snprintf(ifs->ascii + dummy,
51863670Snsayer					sizeof(ifs->ascii) - dummy,
51963670Snsayer					"\tOpened by PID %d\n", tp->tap_pid);
520127098Srwatson			mtx_unlock(&tp->tap_mtx);
52163670Snsayer			splx(s);
52283043Sbrooks			break;
52363670Snsayer
52463670Snsayer		default:
525106939Ssam			s = splimp();
526106939Ssam			dummy = ether_ioctl(ifp, cmd, data);
527106939Ssam			splx(s);
528106939Ssam			return (dummy);
52963670Snsayer	}
53063670Snsayer
53163670Snsayer	return (0);
53263670Snsayer} /* tapifioctl */
53363670Snsayer
53463670Snsayer
53563670Snsayer/*
536111742Sdes * tapifstart
537111742Sdes *
53863670Snsayer * queue packets from higher level ready to put out
53963670Snsayer */
54063670Snsayerstatic void
54163670Snsayertapifstart(ifp)
54263670Snsayer	struct ifnet	*ifp;
54363670Snsayer{
54463670Snsayer	struct tap_softc	*tp = ifp->if_softc;
54563670Snsayer	int			 s;
54663670Snsayer
547121816Sbrooks	TAPDEBUG("%s starting\n", ifp->if_xname);
54863670Snsayer
54963803Snsayer	/*
55063803Snsayer	 * do not junk pending output if we are in VMnet mode.
55163803Snsayer	 * XXX: can this do any harm because of queue overflow?
55263803Snsayer	 */
55363803Snsayer
554127098Srwatson	mtx_lock(&tp->tap_mtx);
555111742Sdes	if (((tp->tap_flags & TAP_VMNET) == 0) &&
55663803Snsayer	    ((tp->tap_flags & TAP_READY) != TAP_READY)) {
55763670Snsayer		struct mbuf	*m = NULL;
55863670Snsayer
559127098Srwatson		mtx_unlock(&tp->tap_mtx);
560127098Srwatson
561127098Srwatson		/* Unlocked read. */
562121816Sbrooks		TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname,
563121816Sbrooks		    tp->tap_flags);
56463670Snsayer
56563670Snsayer		s = splimp();
56663670Snsayer		do {
56763670Snsayer			IF_DEQUEUE(&ifp->if_snd, m);
56863670Snsayer			if (m != NULL)
56963670Snsayer				m_freem(m);
57063670Snsayer			ifp->if_oerrors ++;
57163670Snsayer		} while (m != NULL);
57263670Snsayer		splx(s);
57363670Snsayer
57463670Snsayer		return;
57563670Snsayer	}
576127098Srwatson	mtx_unlock(&tp->tap_mtx);
57763670Snsayer
57863670Snsayer	s = splimp();
57963670Snsayer	ifp->if_flags |= IFF_OACTIVE;
58063670Snsayer
58163670Snsayer	if (ifp->if_snd.ifq_len != 0) {
582127098Srwatson		mtx_lock(&tp->tap_mtx);
58363670Snsayer		if (tp->tap_flags & TAP_RWAIT) {
58463670Snsayer			tp->tap_flags &= ~TAP_RWAIT;
585111748Sdes			wakeup(tp);
58663670Snsayer		}
58763670Snsayer
588127098Srwatson		if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) {
589127098Srwatson			mtx_unlock(&tp->tap_mtx);
59095883Salfred			pgsigio(&tp->tap_sigio, SIGIO, 0);
591127098Srwatson		} else
592127098Srwatson			mtx_unlock(&tp->tap_mtx);
59363670Snsayer
594122352Stanimura		selwakeuppri(&tp->tap_rsel, PZERO+1);
59563670Snsayer		ifp->if_opackets ++; /* obytes are counted in ether_output */
59663670Snsayer	}
59763670Snsayer
59863670Snsayer	ifp->if_flags &= ~IFF_OACTIVE;
59963670Snsayer	splx(s);
60063670Snsayer} /* tapifstart */
60163670Snsayer
60263670Snsayer
60363670Snsayer/*
60463670Snsayer * tapioctl
60563670Snsayer *
60663670Snsayer * the cdevsw interface is now pretty minimal
60763670Snsayer */
60863670Snsayerstatic int
60983366Sjuliantapioctl(dev, cmd, data, flag, td)
610130585Sphk	struct cdev *dev;
61163670Snsayer	u_long		 cmd;
61263670Snsayer	caddr_t		 data;
61363670Snsayer	int		 flag;
61483366Sjulian	struct thread	*td;
61563670Snsayer{
61663670Snsayer	struct tap_softc	*tp = dev->si_drv1;
61763670Snsayer	struct ifnet		*ifp = &tp->tap_if;
618111742Sdes	struct tapinfo		*tapp = NULL;
61963670Snsayer	int			 s;
620102052Ssobomax	int			 f;
62163670Snsayer
62263670Snsayer	switch (cmd) {
623111742Sdes		case TAPSIFINFO:
62463670Snsayer			s = splimp();
625111742Sdes			tapp = (struct tapinfo *)data;
626111742Sdes			ifp->if_mtu = tapp->mtu;
627111742Sdes			ifp->if_type = tapp->type;
628111742Sdes			ifp->if_baudrate = tapp->baudrate;
62963670Snsayer			splx(s);
630111742Sdes			break;
63163670Snsayer
632111742Sdes		case TAPGIFINFO:
633111742Sdes			tapp = (struct tapinfo *)data;
634111742Sdes			tapp->mtu = ifp->if_mtu;
635111742Sdes			tapp->type = ifp->if_type;
636111742Sdes			tapp->baudrate = ifp->if_baudrate;
637111742Sdes			break;
63863670Snsayer
63963670Snsayer		case TAPSDEBUG:
64063670Snsayer			tapdebug = *(int *)data;
64183043Sbrooks			break;
64263670Snsayer
64363670Snsayer		case TAPGDEBUG:
64463670Snsayer			*(int *)data = tapdebug;
64583043Sbrooks			break;
64663670Snsayer
64763670Snsayer		case FIONBIO:
64883043Sbrooks			break;
64963670Snsayer
65063670Snsayer		case FIOASYNC:
65163803Snsayer			s = splimp();
652127098Srwatson			mtx_lock(&tp->tap_mtx);
65363670Snsayer			if (*(int *)data)
65463670Snsayer				tp->tap_flags |= TAP_ASYNC;
65563670Snsayer			else
65663670Snsayer				tp->tap_flags &= ~TAP_ASYNC;
657127098Srwatson			mtx_unlock(&tp->tap_mtx);
65863803Snsayer			splx(s);
65983043Sbrooks			break;
66063670Snsayer
66163670Snsayer		case FIONREAD:
66263670Snsayer			s = splimp();
66363670Snsayer			if (ifp->if_snd.ifq_head) {
66463670Snsayer				struct mbuf	*mb = ifp->if_snd.ifq_head;
66563670Snsayer
66663803Snsayer				for(*(int *)data = 0;mb != NULL;mb = mb->m_next)
66763670Snsayer					*(int *)data += mb->m_len;
66883043Sbrooks			} else
66963670Snsayer				*(int *)data = 0;
67063670Snsayer			splx(s);
67183043Sbrooks			break;
67263670Snsayer
67363670Snsayer		case FIOSETOWN:
67463670Snsayer			return (fsetown(*(int *)data, &tp->tap_sigio));
67563670Snsayer
67663670Snsayer		case FIOGETOWN:
677104393Struckman			*(int *)data = fgetown(&tp->tap_sigio);
67863670Snsayer			return (0);
67963670Snsayer
68063670Snsayer		/* this is deprecated, FIOSETOWN should be used instead */
68163670Snsayer		case TIOCSPGRP:
68263670Snsayer			return (fsetown(-(*(int *)data), &tp->tap_sigio));
68363670Snsayer
68463670Snsayer		/* this is deprecated, FIOGETOWN should be used instead */
68563670Snsayer		case TIOCGPGRP:
686104393Struckman			*(int *)data = -fgetown(&tp->tap_sigio);
68763670Snsayer			return (0);
68863670Snsayer
68963670Snsayer		/* VMware/VMnet port ioctl's */
69063670Snsayer
69163670Snsayer		case SIOCGIFFLAGS:	/* get ifnet flags */
69263670Snsayer			bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags));
69383043Sbrooks			break;
69463670Snsayer
69583043Sbrooks		case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */
696102052Ssobomax			f = *(int *)data;
69763670Snsayer			f &= 0x0fff;
69863670Snsayer			f &= ~IFF_CANTCHANGE;
69963670Snsayer			f |= IFF_UP;
70063670Snsayer
70163670Snsayer			s = splimp();
70263670Snsayer			ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE);
70363670Snsayer			splx(s);
70483043Sbrooks			break;
70563670Snsayer
70663861Snsayer		case OSIOCGIFADDR:	/* get MAC address of the remote side */
70763670Snsayer		case SIOCGIFADDR:
708127165Srwatson			mtx_lock(&tp->tap_mtx);
70963861Snsayer			bcopy(tp->ether_addr, data, sizeof(tp->ether_addr));
710127165Srwatson			mtx_unlock(&tp->tap_mtx);
71183043Sbrooks			break;
71263670Snsayer
71363861Snsayer		case SIOCSIFADDR:	/* set MAC address of the remote side */
714127165Srwatson			mtx_lock(&tp->tap_mtx);
71563861Snsayer			bcopy(data, tp->ether_addr, sizeof(tp->ether_addr));
716127165Srwatson			mtx_unlock(&tp->tap_mtx);
71783043Sbrooks			break;
71863670Snsayer
71963670Snsayer		default:
72063670Snsayer			return (ENOTTY);
72163670Snsayer	}
72263670Snsayer	return (0);
72363670Snsayer} /* tapioctl */
72463670Snsayer
72563670Snsayer
72663670Snsayer/*
72763670Snsayer * tapread
72863670Snsayer *
72963670Snsayer * the cdevsw read interface - reads a packet at a time, or at
73063670Snsayer * least as much of a packet as can be read
73163670Snsayer */
73263670Snsayerstatic int
73363670Snsayertapread(dev, uio, flag)
734130585Sphk	struct cdev *dev;
73563670Snsayer	struct uio	*uio;
73663670Snsayer	int		 flag;
73763670Snsayer{
73863670Snsayer	struct tap_softc	*tp = dev->si_drv1;
73963670Snsayer	struct ifnet		*ifp = &tp->tap_if;
74090227Sdillon	struct mbuf		*m = NULL;
74163670Snsayer	int			 error = 0, len, s;
74263670Snsayer
743121816Sbrooks	TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, minor(dev));
74463670Snsayer
745127098Srwatson	mtx_lock(&tp->tap_mtx);
74663670Snsayer	if ((tp->tap_flags & TAP_READY) != TAP_READY) {
747127098Srwatson		mtx_unlock(&tp->tap_mtx);
748127098Srwatson
749127098Srwatson		/* Unlocked read. */
750121816Sbrooks		TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n",
751121816Sbrooks			ifp->if_xname, minor(dev), tp->tap_flags);
75263803Snsayer
75363670Snsayer		return (EHOSTDOWN);
75463670Snsayer	}
75563670Snsayer
75663670Snsayer	tp->tap_flags &= ~TAP_RWAIT;
757127098Srwatson	mtx_unlock(&tp->tap_mtx);
75863670Snsayer
75963670Snsayer	/* sleep until we get a packet */
76063670Snsayer	do {
76163670Snsayer		s = splimp();
76290227Sdillon		IF_DEQUEUE(&ifp->if_snd, m);
76363670Snsayer		splx(s);
76463670Snsayer
76590227Sdillon		if (m == NULL) {
766139207Sphk			if (flag & O_NONBLOCK)
76763670Snsayer				return (EWOULDBLOCK);
768111742Sdes
769127098Srwatson			mtx_lock(&tp->tap_mtx);
77063670Snsayer			tp->tap_flags |= TAP_RWAIT;
771127098Srwatson			mtx_unlock(&tp->tap_mtx);
772111748Sdes			error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0);
77363670Snsayer			if (error)
77463670Snsayer				return (error);
77563670Snsayer		}
77690227Sdillon	} while (m == NULL);
77763670Snsayer
77863670Snsayer	/* feed packet to bpf */
779106939Ssam	BPF_MTAP(ifp, m);
78063670Snsayer
78163670Snsayer	/* xfer packet to user space */
78290227Sdillon	while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) {
78390227Sdillon		len = min(uio->uio_resid, m->m_len);
78463670Snsayer		if (len == 0)
78563670Snsayer			break;
78663670Snsayer
787111741Sdes		error = uiomove(mtod(m, void *), len, uio);
78890227Sdillon		m = m_free(m);
78963670Snsayer	}
79063670Snsayer
79190227Sdillon	if (m != NULL) {
792121816Sbrooks		TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname,
793121816Sbrooks			minor(dev));
79490227Sdillon		m_freem(m);
79563670Snsayer	}
79663670Snsayer
79763670Snsayer	return (error);
79863670Snsayer} /* tapread */
79963670Snsayer
80063670Snsayer
80163670Snsayer/*
80263670Snsayer * tapwrite
80363670Snsayer *
80463670Snsayer * the cdevsw write interface - an atomic write is a packet - or else!
80563670Snsayer */
80663670Snsayerstatic int
80763670Snsayertapwrite(dev, uio, flag)
808130585Sphk	struct cdev *dev;
80963670Snsayer	struct uio	*uio;
81063670Snsayer	int		 flag;
81163670Snsayer{
81263670Snsayer	struct tap_softc	*tp = dev->si_drv1;
81363670Snsayer	struct ifnet		*ifp = &tp->tap_if;
814137101Sglebius	struct mbuf		*m;
815137101Sglebius	int			 error = 0;
81663670Snsayer
817121816Sbrooks	TAPDEBUG("%s writting, minor = %#x\n",
818121816Sbrooks		ifp->if_xname, minor(dev));
81963670Snsayer
82063670Snsayer	if (uio->uio_resid == 0)
82163670Snsayer		return (0);
82263670Snsayer
82363670Snsayer	if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) {
824121816Sbrooks		TAPDEBUG("%s invalid packet len = %d, minor = %#x\n",
825121816Sbrooks			ifp->if_xname, uio->uio_resid, minor(dev));
82663803Snsayer
82763670Snsayer		return (EIO);
82863670Snsayer	}
82963670Snsayer
830145883Semax	if ((m = m_uiotombuf(uio, M_DONTWAIT, 0, ETHER_ALIGN)) == NULL) {
83163670Snsayer		ifp->if_ierrors ++;
83263670Snsayer		return (error);
83363670Snsayer	}
83463670Snsayer
835137101Sglebius	m->m_pkthdr.rcvif = ifp;
836111742Sdes
837106939Ssam	/* Pass packet up to parent. */
838137101Sglebius	(*ifp->if_input)(ifp, m);
839106939Ssam	ifp->if_ipackets ++; /* ibytes are counted in parent */
84063670Snsayer
84163670Snsayer	return (0);
84263670Snsayer} /* tapwrite */
84363670Snsayer
84463670Snsayer
84563670Snsayer/*
84663670Snsayer * tappoll
84763670Snsayer *
84863670Snsayer * the poll interface, this is only useful on reads
84963670Snsayer * really. the write detect always returns true, write never blocks
85063670Snsayer * anyway, it either accepts the packet or drops it
85163670Snsayer */
85263670Snsayerstatic int
85383366Sjuliantappoll(dev, events, td)
854130585Sphk	struct cdev *dev;
85563670Snsayer	int		 events;
85683366Sjulian	struct thread	*td;
85763670Snsayer{
85863670Snsayer	struct tap_softc	*tp = dev->si_drv1;
85963670Snsayer	struct ifnet		*ifp = &tp->tap_if;
860111742Sdes	int			 s, revents = 0;
86163670Snsayer
862121816Sbrooks	TAPDEBUG("%s polling, minor = %#x\n",
863121816Sbrooks		ifp->if_xname, minor(dev));
86463670Snsayer
86563670Snsayer	s = splimp();
86663670Snsayer	if (events & (POLLIN | POLLRDNORM)) {
86763670Snsayer		if (ifp->if_snd.ifq_len > 0) {
868121816Sbrooks			TAPDEBUG("%s have data in queue. len = %d, " \
869121816Sbrooks				"minor = %#x\n", ifp->if_xname,
87083043Sbrooks				ifp->if_snd.ifq_len, minor(dev));
87163803Snsayer
87263670Snsayer			revents |= (events & (POLLIN | POLLRDNORM));
87383043Sbrooks		} else {
874121816Sbrooks			TAPDEBUG("%s waiting for data, minor = %#x\n",
875121816Sbrooks				ifp->if_xname, minor(dev));
87663803Snsayer
87783805Sjhb			selrecord(td, &tp->tap_rsel);
87863670Snsayer		}
87963670Snsayer	}
88063670Snsayer
88163670Snsayer	if (events & (POLLOUT | POLLWRNORM))
88263670Snsayer		revents |= (events & (POLLOUT | POLLWRNORM));
88363670Snsayer
88463670Snsayer	splx(s);
88563670Snsayer	return (revents);
88663670Snsayer} /* tappoll */
887