if_tap.c revision 144389
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 144389 2005-03-31 12:19:44Z phk $
3563803Snsayer * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $
3663670Snsayer */
3763670Snsayer
3863670Snsayer#include "opt_inet.h"
3963670Snsayer
4063670Snsayer#include <sys/param.h>
4163670Snsayer#include <sys/conf.h>
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   */
11983043Sbrooksstatic SLIST_HEAD(, tap_softc)	taphead;             /* first device */
120126077Sphkstatic struct clonedevs 	*tapclones;
12163670Snsayer
12263670SnsayerMALLOC_DECLARE(M_TAP);
12363670SnsayerMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface");
12463670SnsayerSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, "");
12563670SnsayerDEV_MODULE(if_tap, tapmodevent, NULL);
12663670Snsayer
12763670Snsayer/*
12863670Snsayer * tapmodevent
12963670Snsayer *
13063670Snsayer * module event handler
13163670Snsayer */
13263670Snsayerstatic int
13363670Snsayertapmodevent(mod, type, data)
13463670Snsayer	module_t	 mod;
13563670Snsayer	int		 type;
13663670Snsayer	void		*data;
13763670Snsayer{
13883043Sbrooks	static eventhandler_tag	 eh_tag = NULL;
13983043Sbrooks	struct tap_softc	*tp = NULL;
14083043Sbrooks	struct ifnet		*ifp = NULL;
141126077Sphk	int			 s;
14263670Snsayer
14363670Snsayer	switch (type) {
14463670Snsayer	case MOD_LOAD:
14563670Snsayer
14683043Sbrooks		/* intitialize device */
14783043Sbrooks
148127003Srwatson		mtx_init(&tapmtx, "tapmtx", NULL, MTX_DEF);
14983043Sbrooks		SLIST_INIT(&taphead);
15083043Sbrooks
151126845Sphk		clone_setup(&tapclones);
15271602Sphk		eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000);
153127003Srwatson		if (eh_tag == NULL) {
154127170Srwatson			clone_cleanup(&tapclones);
155127003Srwatson			mtx_destroy(&tapmtx);
156126077Sphk			return (ENOMEM);
157127003Srwatson		}
15883043Sbrooks		return (0);
15963670Snsayer
16083043Sbrooks	case MOD_UNLOAD:
161127003Srwatson		/*
162127003Srwatson		 * The EBUSY algorithm here can't quite atomically
163127003Srwatson		 * guarantee that this is race-free since we have to
164127003Srwatson		 * release the tap mtx to deregister the clone handler.
165127003Srwatson		 */
166127003Srwatson		mtx_lock(&tapmtx);
167127003Srwatson		SLIST_FOREACH(tp, &taphead, tap_next) {
168127098Srwatson			mtx_lock(&tp->tap_mtx);
169127003Srwatson			if (tp->tap_flags & TAP_OPEN) {
170127098Srwatson				mtx_unlock(&tp->tap_mtx);
171127003Srwatson				mtx_unlock(&tapmtx);
17283043Sbrooks				return (EBUSY);
173127003Srwatson			}
174127098Srwatson			mtx_unlock(&tp->tap_mtx);
175127003Srwatson		}
176127003Srwatson		mtx_unlock(&tapmtx);
17783043Sbrooks
17871602Sphk		EVENTHANDLER_DEREGISTER(dev_clone, eh_tag);
17963670Snsayer
180127003Srwatson		mtx_lock(&tapmtx);
18183043Sbrooks		while ((tp = SLIST_FIRST(&taphead)) != NULL) {
18283043Sbrooks			SLIST_REMOVE_HEAD(&taphead, tap_next);
183127003Srwatson			mtx_unlock(&tapmtx);
18483043Sbrooks
18583043Sbrooks			ifp = &tp->tap_if;
18683043Sbrooks
187121816Sbrooks			TAPDEBUG("detaching %s\n", ifp->if_xname);
18883043Sbrooks
189127098Srwatson			/* Unlocked read. */
190121816Sbrooks			KASSERT(!(tp->tap_flags & TAP_OPEN),
191121816Sbrooks				("%s flags is out of sync", ifp->if_xname));
19283043Sbrooks
193126077Sphk			destroy_dev(tp->tap_dev);
19463670Snsayer			s = splimp();
195106939Ssam			ether_ifdetach(ifp);
19663670Snsayer			splx(s);
19763670Snsayer
198127098Srwatson			mtx_destroy(&tp->tap_mtx);
19993752Sluigi			free(tp, M_TAP);
200127003Srwatson			mtx_lock(&tapmtx);
20183043Sbrooks		}
202127003Srwatson		mtx_unlock(&tapmtx);
203126077Sphk		clone_cleanup(&tapclones);
20463670Snsayer
205135354Srwatson		mtx_destroy(&tapmtx);
206135354Srwatson
20783043Sbrooks		break;
20863670Snsayer
20963670Snsayer	default:
21063670Snsayer		return (EOPNOTSUPP);
21163670Snsayer	}
21263670Snsayer
21363670Snsayer	return (0);
21463670Snsayer} /* tapmodevent */
21563670Snsayer
21663670Snsayer
21763670Snsayer/*
21871602Sphk * DEVFS handler
21971602Sphk *
22071602Sphk * We need to support two kind of devices - tap and vmnet
22171602Sphk */
22271602Sphkstatic void
22371602Sphktapclone(arg, name, namelen, dev)
22471602Sphk	void	*arg;
22571602Sphk	char	*name;
22671602Sphk	int	 namelen;
227130585Sphk	struct cdev **dev;
22871602Sphk{
229126077Sphk	u_int		extra;
230126077Sphk	int		i, unit;
23183043Sbrooks	char		*device_name = name;
23271602Sphk
233130640Sphk	if (*dev != NULL)
23471602Sphk		return;
23571602Sphk
236126077Sphk	device_name = TAP;
237126077Sphk	extra = 0;
238126077Sphk	if (strcmp(name, TAP) == 0) {
239126077Sphk		unit = -1;
240126077Sphk	} else if (strcmp(name, VMNET) == 0) {
241126077Sphk		device_name = VMNET;
242126077Sphk		extra = VMNET_DEV_MASK;
243126077Sphk		unit = -1;
244126077Sphk	} else if (dev_stdclone(name, NULL, device_name, &unit) != 1) {
245126077Sphk		device_name = VMNET;
246126077Sphk		extra = VMNET_DEV_MASK;
247126077Sphk		if (dev_stdclone(name, NULL, device_name, &unit) != 1)
248126077Sphk			return;
24983043Sbrooks	}
25071602Sphk
251126077Sphk	/* find any existing device, or allocate new unit number */
252126077Sphk	i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra);
253126077Sphk	if (i) {
254126796Sphk		*dev = make_dev(&tap_cdevsw, unit2minor(unit | extra),
255126077Sphk		     UID_ROOT, GID_WHEEL, 0600, "%s%d", device_name, unit);
256144389Sphk		if (*dev != NULL) {
257144389Sphk			dev_ref(*dev);
258126077Sphk			(*dev)->si_flags |= SI_CHEAPCLONE;
259144389Sphk		}
26071602Sphk	}
26171602Sphk} /* tapclone */
26271602Sphk
26371602Sphk
26471602Sphk/*
26563670Snsayer * tapcreate
26663670Snsayer *
26763670Snsayer * to create interface
26863670Snsayer */
26963670Snsayerstatic void
27063670Snsayertapcreate(dev)
271130585Sphk	struct cdev *dev;
27263670Snsayer{
27363670Snsayer	struct ifnet		*ifp = NULL;
27463670Snsayer	struct tap_softc	*tp = NULL;
27563670Snsayer	unsigned short		 macaddr_hi;
27663803Snsayer	int			 unit, s;
27763670Snsayer	char			*name = NULL;
27863670Snsayer
279126077Sphk	dev->si_flags &= ~SI_CHEAPCLONE;
280126077Sphk
28163670Snsayer	/* allocate driver storage and create device */
282111119Simp	MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO);
283127098Srwatson	mtx_init(&tp->tap_mtx, "tap_mtx", NULL, MTX_DEF);
284127003Srwatson	mtx_lock(&tapmtx);
28583043Sbrooks	SLIST_INSERT_HEAD(&taphead, tp, tap_next);
286127003Srwatson	mtx_unlock(&tapmtx);
28763670Snsayer
288126796Sphk	unit = dev2unit(dev);
28983043Sbrooks
29063670Snsayer	/* select device: tap or vmnet */
291126796Sphk	if (unit & VMNET_DEV_MASK) {
29263670Snsayer		name = VMNET;
29363803Snsayer		tp->tap_flags |= TAP_VMNET;
29483043Sbrooks	} else
29563670Snsayer		name = TAP;
29663670Snsayer
297126796Sphk	unit &= TAPMAXUNIT;
298126796Sphk
29983043Sbrooks	TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev));
30083043Sbrooks
30163670Snsayer	/* generate fake MAC address: 00 bd xx xx xx unit_no */
30263670Snsayer	macaddr_hi = htons(0x00bd);
30363670Snsayer	bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short));
30463670Snsayer	bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long));
30563670Snsayer	tp->arpcom.ac_enaddr[5] = (u_char)unit;
30663670Snsayer
307111742Sdes	/* fill the rest and attach interface */
30863670Snsayer	ifp = &tp->tap_if;
30963670Snsayer	ifp->if_softc = tp;
310121816Sbrooks	if_initname(ifp, name, unit);
31163670Snsayer	ifp->if_init = tapifinit;
31263670Snsayer	ifp->if_start = tapifstart;
31363670Snsayer	ifp->if_ioctl = tapifioctl;
31463670Snsayer	ifp->if_mtu = ETHERMTU;
31563670Snsayer	ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
31663670Snsayer	ifp->if_snd.ifq_maxlen = ifqmaxlen;
31763670Snsayer
31883043Sbrooks	dev->si_drv1 = tp;
319126077Sphk	tp->tap_dev = dev;
32083043Sbrooks
32163803Snsayer	s = splimp();
322106939Ssam	ether_ifattach(ifp, tp->arpcom.ac_enaddr);
32363803Snsayer	splx(s);
32463670Snsayer
325127098Srwatson	mtx_lock(&tp->tap_mtx);
32663803Snsayer	tp->tap_flags |= TAP_INITED;
327127098Srwatson	mtx_unlock(&tp->tap_mtx);
32863803Snsayer
329121816Sbrooks	TAPDEBUG("interface %s is created. minor = %#x\n",
330121816Sbrooks		ifp->if_xname, minor(dev));
33163670Snsayer} /* tapcreate */
33263670Snsayer
33363670Snsayer
33463670Snsayer/*
335111742Sdes * tapopen
33663670Snsayer *
33763670Snsayer * to open tunnel. must be superuser
33863670Snsayer */
33963670Snsayerstatic int
34083366Sjuliantapopen(dev, flag, mode, td)
341130585Sphk	struct cdev *dev;
34263670Snsayer	int		 flag;
34363670Snsayer	int		 mode;
34483366Sjulian	struct thread	*td;
34563670Snsayer{
34663670Snsayer	struct tap_softc	*tp = NULL;
347133460Semax	struct ifnet		*ifp = NULL;
348133460Semax	int			 error, s;
34963670Snsayer
35093593Sjhb	if ((error = suser(td)) != 0)
35163670Snsayer		return (error);
35263670Snsayer
353126796Sphk	if ((dev2unit(dev) & CLONE_UNITMASK) > TAPMAXUNIT)
354126796Sphk		return (ENXIO);
35583043Sbrooks
356127165Srwatson	/*
357127165Srwatson	 * XXXRW: Non-atomic test-and-set of si_drv1.  Currently protected
358127165Srwatson	 * by Giant, but the race actually exists under memory pressure as
359127165Srwatson	 * well even when running with Giant, as malloc() may sleep.
360127165Srwatson	 */
36163670Snsayer	tp = dev->si_drv1;
36263670Snsayer	if (tp == NULL) {
36363670Snsayer		tapcreate(dev);
36463670Snsayer		tp = dev->si_drv1;
36563670Snsayer	}
36663670Snsayer
367127165Srwatson	mtx_lock(&tp->tap_mtx);
368127165Srwatson	if (tp->tap_flags & TAP_OPEN) {
369127165Srwatson		mtx_unlock(&tp->tap_mtx);
370127165Srwatson		return (EBUSY);
371127165Srwatson	}
37263670Snsayer
37363861Snsayer	bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr));
37483366Sjulian	tp->tap_pid = td->td_proc->p_pid;
37563670Snsayer	tp->tap_flags |= TAP_OPEN;
376133460Semax	ifp = &tp->tap_if;
377127098Srwatson	mtx_unlock(&tp->tap_mtx);
37863670Snsayer
379133460Semax	s = splimp();
380133460Semax	ifp->if_flags |= IFF_RUNNING;
381133460Semax	ifp->if_flags &= ~IFF_OACTIVE;
382133460Semax	splx(s);
38363670Snsayer
384133460Semax	TAPDEBUG("%s is open. minor = %#x\n", ifp->if_xname, minor(dev));
385133460Semax
38663670Snsayer	return (0);
38763670Snsayer} /* tapopen */
38863670Snsayer
38963670Snsayer
39063670Snsayer/*
39163670Snsayer * tapclose
39263670Snsayer *
39363670Snsayer * close the device - mark i/f down & delete routing info
39463670Snsayer */
39563670Snsayerstatic int
39683366Sjuliantapclose(dev, foo, bar, td)
397130585Sphk	struct cdev *dev;
39863670Snsayer	int		 foo;
39963670Snsayer	int		 bar;
40083366Sjulian	struct thread	*td;
40163670Snsayer{
40263670Snsayer	struct tap_softc	*tp = dev->si_drv1;
40363670Snsayer	struct ifnet		*ifp = &tp->tap_if;
404126077Sphk	int			s;
40563670Snsayer
40663670Snsayer	/* junk all pending output */
40783043Sbrooks	IF_DRAIN(&ifp->if_snd);
40863670Snsayer
40963803Snsayer	/*
41063803Snsayer	 * do not bring the interface down, and do not anything with
41163803Snsayer	 * interface, if we are in VMnet mode. just close the device.
41263803Snsayer	 */
41363803Snsayer
414127098Srwatson	mtx_lock(&tp->tap_mtx);
41563803Snsayer	if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) {
416127098Srwatson		mtx_unlock(&tp->tap_mtx);
41763670Snsayer		s = splimp();
41863670Snsayer		if_down(ifp);
41963670Snsayer		if (ifp->if_flags & IFF_RUNNING) {
42063670Snsayer			/* find internet addresses and delete routes */
42163670Snsayer			struct ifaddr	*ifa = NULL;
42263670Snsayer
423127098Srwatson			/* In desparate need of ifaddr locking. */
42463803Snsayer			TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
42563670Snsayer				if (ifa->ifa_addr->sa_family == AF_INET) {
42663670Snsayer					rtinit(ifa, (int)RTM_DELETE, 0);
42763670Snsayer
42863670Snsayer					/* remove address from interface */
429111742Sdes					bzero(ifa->ifa_addr,
43063670Snsayer						   sizeof(*(ifa->ifa_addr)));
431111742Sdes					bzero(ifa->ifa_dstaddr,
43263670Snsayer						   sizeof(*(ifa->ifa_dstaddr)));
433111742Sdes					bzero(ifa->ifa_netmask,
43463670Snsayer						   sizeof(*(ifa->ifa_netmask)));
43563670Snsayer				}
43663670Snsayer			}
43763670Snsayer
43863670Snsayer			ifp->if_flags &= ~IFF_RUNNING;
43963670Snsayer		}
44063670Snsayer		splx(s);
441127098Srwatson	} else
442127098Srwatson		mtx_unlock(&tp->tap_mtx);
44363670Snsayer
44496122Salfred	funsetown(&tp->tap_sigio);
445122352Stanimura	selwakeuppri(&tp->tap_rsel, PZERO+1);
44663670Snsayer
447127098Srwatson	mtx_lock(&tp->tap_mtx);
44863670Snsayer	tp->tap_flags &= ~TAP_OPEN;
44963670Snsayer	tp->tap_pid = 0;
450127098Srwatson	mtx_unlock(&tp->tap_mtx);
45163670Snsayer
452121816Sbrooks	TAPDEBUG("%s is closed. minor = %#x\n",
453121816Sbrooks		ifp->if_xname, minor(dev));
45463670Snsayer
45563670Snsayer	return (0);
45663670Snsayer} /* tapclose */
45763670Snsayer
45863670Snsayer
45963670Snsayer/*
46063670Snsayer * tapifinit
46163670Snsayer *
46263670Snsayer * network interface initialization function
46363670Snsayer */
46463670Snsayerstatic void
46563670Snsayertapifinit(xtp)
46663670Snsayer	void	*xtp;
46763670Snsayer{
46863670Snsayer	struct tap_softc	*tp = (struct tap_softc *)xtp;
46963670Snsayer	struct ifnet		*ifp = &tp->tap_if;
47063670Snsayer
471121816Sbrooks	TAPDEBUG("initializing %s\n", ifp->if_xname);
47263670Snsayer
47363670Snsayer	ifp->if_flags |= IFF_RUNNING;
47463670Snsayer	ifp->if_flags &= ~IFF_OACTIVE;
47563670Snsayer
47663670Snsayer	/* attempt to start output */
47763670Snsayer	tapifstart(ifp);
47863670Snsayer} /* tapifinit */
47963670Snsayer
48063670Snsayer
48163670Snsayer/*
48263670Snsayer * tapifioctl
48363670Snsayer *
48463670Snsayer * Process an ioctl request on network interface
48563670Snsayer */
486105228Sphkstatic int
48763670Snsayertapifioctl(ifp, cmd, data)
48863670Snsayer	struct ifnet	*ifp;
48963670Snsayer	u_long		 cmd;
49063670Snsayer	caddr_t		 data;
49163670Snsayer{
492111742Sdes	struct tap_softc	*tp = (struct tap_softc *)(ifp->if_softc);
49363670Snsayer	struct ifstat		*ifs = NULL;
49463670Snsayer	int			 s, dummy;
49563670Snsayer
49663670Snsayer	switch (cmd) {
49763670Snsayer		case SIOCSIFFLAGS: /* XXX -- just like vmnet does */
49863670Snsayer		case SIOCADDMULTI:
49963670Snsayer		case SIOCDELMULTI:
50083043Sbrooks			break;
50163670Snsayer
50263670Snsayer		case SIOCGIFSTATUS:
50363670Snsayer			s = splimp();
50463670Snsayer			ifs = (struct ifstat *)data;
50563670Snsayer			dummy = strlen(ifs->ascii);
506127098Srwatson			mtx_lock(&tp->tap_mtx);
50763670Snsayer			if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii))
50863670Snsayer				snprintf(ifs->ascii + dummy,
50963670Snsayer					sizeof(ifs->ascii) - dummy,
51063670Snsayer					"\tOpened by PID %d\n", tp->tap_pid);
511127098Srwatson			mtx_unlock(&tp->tap_mtx);
51263670Snsayer			splx(s);
51383043Sbrooks			break;
51463670Snsayer
51563670Snsayer		default:
516106939Ssam			s = splimp();
517106939Ssam			dummy = ether_ioctl(ifp, cmd, data);
518106939Ssam			splx(s);
519106939Ssam			return (dummy);
52063670Snsayer	}
52163670Snsayer
52263670Snsayer	return (0);
52363670Snsayer} /* tapifioctl */
52463670Snsayer
52563670Snsayer
52663670Snsayer/*
527111742Sdes * tapifstart
528111742Sdes *
52963670Snsayer * queue packets from higher level ready to put out
53063670Snsayer */
53163670Snsayerstatic void
53263670Snsayertapifstart(ifp)
53363670Snsayer	struct ifnet	*ifp;
53463670Snsayer{
53563670Snsayer	struct tap_softc	*tp = ifp->if_softc;
53663670Snsayer	int			 s;
53763670Snsayer
538121816Sbrooks	TAPDEBUG("%s starting\n", ifp->if_xname);
53963670Snsayer
54063803Snsayer	/*
54163803Snsayer	 * do not junk pending output if we are in VMnet mode.
54263803Snsayer	 * XXX: can this do any harm because of queue overflow?
54363803Snsayer	 */
54463803Snsayer
545127098Srwatson	mtx_lock(&tp->tap_mtx);
546111742Sdes	if (((tp->tap_flags & TAP_VMNET) == 0) &&
54763803Snsayer	    ((tp->tap_flags & TAP_READY) != TAP_READY)) {
54863670Snsayer		struct mbuf	*m = NULL;
54963670Snsayer
550127098Srwatson		mtx_unlock(&tp->tap_mtx);
551127098Srwatson
552127098Srwatson		/* Unlocked read. */
553121816Sbrooks		TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname,
554121816Sbrooks		    tp->tap_flags);
55563670Snsayer
55663670Snsayer		s = splimp();
55763670Snsayer		do {
55863670Snsayer			IF_DEQUEUE(&ifp->if_snd, m);
55963670Snsayer			if (m != NULL)
56063670Snsayer				m_freem(m);
56163670Snsayer			ifp->if_oerrors ++;
56263670Snsayer		} while (m != NULL);
56363670Snsayer		splx(s);
56463670Snsayer
56563670Snsayer		return;
56663670Snsayer	}
567127098Srwatson	mtx_unlock(&tp->tap_mtx);
56863670Snsayer
56963670Snsayer	s = splimp();
57063670Snsayer	ifp->if_flags |= IFF_OACTIVE;
57163670Snsayer
57263670Snsayer	if (ifp->if_snd.ifq_len != 0) {
573127098Srwatson		mtx_lock(&tp->tap_mtx);
57463670Snsayer		if (tp->tap_flags & TAP_RWAIT) {
57563670Snsayer			tp->tap_flags &= ~TAP_RWAIT;
576111748Sdes			wakeup(tp);
57763670Snsayer		}
57863670Snsayer
579127098Srwatson		if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) {
580127098Srwatson			mtx_unlock(&tp->tap_mtx);
58195883Salfred			pgsigio(&tp->tap_sigio, SIGIO, 0);
582127098Srwatson		} else
583127098Srwatson			mtx_unlock(&tp->tap_mtx);
58463670Snsayer
585122352Stanimura		selwakeuppri(&tp->tap_rsel, PZERO+1);
58663670Snsayer		ifp->if_opackets ++; /* obytes are counted in ether_output */
58763670Snsayer	}
58863670Snsayer
58963670Snsayer	ifp->if_flags &= ~IFF_OACTIVE;
59063670Snsayer	splx(s);
59163670Snsayer} /* tapifstart */
59263670Snsayer
59363670Snsayer
59463670Snsayer/*
59563670Snsayer * tapioctl
59663670Snsayer *
59763670Snsayer * the cdevsw interface is now pretty minimal
59863670Snsayer */
59963670Snsayerstatic int
60083366Sjuliantapioctl(dev, cmd, data, flag, td)
601130585Sphk	struct cdev *dev;
60263670Snsayer	u_long		 cmd;
60363670Snsayer	caddr_t		 data;
60463670Snsayer	int		 flag;
60583366Sjulian	struct thread	*td;
60663670Snsayer{
60763670Snsayer	struct tap_softc	*tp = dev->si_drv1;
60863670Snsayer	struct ifnet		*ifp = &tp->tap_if;
609111742Sdes	struct tapinfo		*tapp = NULL;
61063670Snsayer	int			 s;
611102052Ssobomax	int			 f;
61263670Snsayer
61363670Snsayer	switch (cmd) {
614111742Sdes		case TAPSIFINFO:
61563670Snsayer			s = splimp();
616111742Sdes			tapp = (struct tapinfo *)data;
617111742Sdes			ifp->if_mtu = tapp->mtu;
618111742Sdes			ifp->if_type = tapp->type;
619111742Sdes			ifp->if_baudrate = tapp->baudrate;
62063670Snsayer			splx(s);
621111742Sdes			break;
62263670Snsayer
623111742Sdes		case TAPGIFINFO:
624111742Sdes			tapp = (struct tapinfo *)data;
625111742Sdes			tapp->mtu = ifp->if_mtu;
626111742Sdes			tapp->type = ifp->if_type;
627111742Sdes			tapp->baudrate = ifp->if_baudrate;
628111742Sdes			break;
62963670Snsayer
63063670Snsayer		case TAPSDEBUG:
63163670Snsayer			tapdebug = *(int *)data;
63283043Sbrooks			break;
63363670Snsayer
63463670Snsayer		case TAPGDEBUG:
63563670Snsayer			*(int *)data = tapdebug;
63683043Sbrooks			break;
63763670Snsayer
63863670Snsayer		case FIONBIO:
63983043Sbrooks			break;
64063670Snsayer
64163670Snsayer		case FIOASYNC:
64263803Snsayer			s = splimp();
643127098Srwatson			mtx_lock(&tp->tap_mtx);
64463670Snsayer			if (*(int *)data)
64563670Snsayer				tp->tap_flags |= TAP_ASYNC;
64663670Snsayer			else
64763670Snsayer				tp->tap_flags &= ~TAP_ASYNC;
648127098Srwatson			mtx_unlock(&tp->tap_mtx);
64963803Snsayer			splx(s);
65083043Sbrooks			break;
65163670Snsayer
65263670Snsayer		case FIONREAD:
65363670Snsayer			s = splimp();
65463670Snsayer			if (ifp->if_snd.ifq_head) {
65563670Snsayer				struct mbuf	*mb = ifp->if_snd.ifq_head;
65663670Snsayer
65763803Snsayer				for(*(int *)data = 0;mb != NULL;mb = mb->m_next)
65863670Snsayer					*(int *)data += mb->m_len;
65983043Sbrooks			} else
66063670Snsayer				*(int *)data = 0;
66163670Snsayer			splx(s);
66283043Sbrooks			break;
66363670Snsayer
66463670Snsayer		case FIOSETOWN:
66563670Snsayer			return (fsetown(*(int *)data, &tp->tap_sigio));
66663670Snsayer
66763670Snsayer		case FIOGETOWN:
668104393Struckman			*(int *)data = fgetown(&tp->tap_sigio);
66963670Snsayer			return (0);
67063670Snsayer
67163670Snsayer		/* this is deprecated, FIOSETOWN should be used instead */
67263670Snsayer		case TIOCSPGRP:
67363670Snsayer			return (fsetown(-(*(int *)data), &tp->tap_sigio));
67463670Snsayer
67563670Snsayer		/* this is deprecated, FIOGETOWN should be used instead */
67663670Snsayer		case TIOCGPGRP:
677104393Struckman			*(int *)data = -fgetown(&tp->tap_sigio);
67863670Snsayer			return (0);
67963670Snsayer
68063670Snsayer		/* VMware/VMnet port ioctl's */
68163670Snsayer
68263670Snsayer		case SIOCGIFFLAGS:	/* get ifnet flags */
68363670Snsayer			bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags));
68483043Sbrooks			break;
68563670Snsayer
68683043Sbrooks		case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */
687102052Ssobomax			f = *(int *)data;
68863670Snsayer			f &= 0x0fff;
68963670Snsayer			f &= ~IFF_CANTCHANGE;
69063670Snsayer			f |= IFF_UP;
69163670Snsayer
69263670Snsayer			s = splimp();
69363670Snsayer			ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE);
69463670Snsayer			splx(s);
69583043Sbrooks			break;
69663670Snsayer
69763861Snsayer		case OSIOCGIFADDR:	/* get MAC address of the remote side */
69863670Snsayer		case SIOCGIFADDR:
699127165Srwatson			mtx_lock(&tp->tap_mtx);
70063861Snsayer			bcopy(tp->ether_addr, data, sizeof(tp->ether_addr));
701127165Srwatson			mtx_unlock(&tp->tap_mtx);
70283043Sbrooks			break;
70363670Snsayer
70463861Snsayer		case SIOCSIFADDR:	/* set MAC address of the remote side */
705127165Srwatson			mtx_lock(&tp->tap_mtx);
70663861Snsayer			bcopy(data, tp->ether_addr, sizeof(tp->ether_addr));
707127165Srwatson			mtx_unlock(&tp->tap_mtx);
70883043Sbrooks			break;
70963670Snsayer
71063670Snsayer		default:
71163670Snsayer			return (ENOTTY);
71263670Snsayer	}
71363670Snsayer	return (0);
71463670Snsayer} /* tapioctl */
71563670Snsayer
71663670Snsayer
71763670Snsayer/*
71863670Snsayer * tapread
71963670Snsayer *
72063670Snsayer * the cdevsw read interface - reads a packet at a time, or at
72163670Snsayer * least as much of a packet as can be read
72263670Snsayer */
72363670Snsayerstatic int
72463670Snsayertapread(dev, uio, flag)
725130585Sphk	struct cdev *dev;
72663670Snsayer	struct uio	*uio;
72763670Snsayer	int		 flag;
72863670Snsayer{
72963670Snsayer	struct tap_softc	*tp = dev->si_drv1;
73063670Snsayer	struct ifnet		*ifp = &tp->tap_if;
73190227Sdillon	struct mbuf		*m = NULL;
73263670Snsayer	int			 error = 0, len, s;
73363670Snsayer
734121816Sbrooks	TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, minor(dev));
73563670Snsayer
736127098Srwatson	mtx_lock(&tp->tap_mtx);
73763670Snsayer	if ((tp->tap_flags & TAP_READY) != TAP_READY) {
738127098Srwatson		mtx_unlock(&tp->tap_mtx);
739127098Srwatson
740127098Srwatson		/* Unlocked read. */
741121816Sbrooks		TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n",
742121816Sbrooks			ifp->if_xname, minor(dev), tp->tap_flags);
74363803Snsayer
74463670Snsayer		return (EHOSTDOWN);
74563670Snsayer	}
74663670Snsayer
74763670Snsayer	tp->tap_flags &= ~TAP_RWAIT;
748127098Srwatson	mtx_unlock(&tp->tap_mtx);
74963670Snsayer
75063670Snsayer	/* sleep until we get a packet */
75163670Snsayer	do {
75263670Snsayer		s = splimp();
75390227Sdillon		IF_DEQUEUE(&ifp->if_snd, m);
75463670Snsayer		splx(s);
75563670Snsayer
75690227Sdillon		if (m == NULL) {
757139207Sphk			if (flag & O_NONBLOCK)
75863670Snsayer				return (EWOULDBLOCK);
759111742Sdes
760127098Srwatson			mtx_lock(&tp->tap_mtx);
76163670Snsayer			tp->tap_flags |= TAP_RWAIT;
762127098Srwatson			mtx_unlock(&tp->tap_mtx);
763111748Sdes			error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0);
76463670Snsayer			if (error)
76563670Snsayer				return (error);
76663670Snsayer		}
76790227Sdillon	} while (m == NULL);
76863670Snsayer
76963670Snsayer	/* feed packet to bpf */
770106939Ssam	BPF_MTAP(ifp, m);
77163670Snsayer
77263670Snsayer	/* xfer packet to user space */
77390227Sdillon	while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) {
77490227Sdillon		len = min(uio->uio_resid, m->m_len);
77563670Snsayer		if (len == 0)
77663670Snsayer			break;
77763670Snsayer
778111741Sdes		error = uiomove(mtod(m, void *), len, uio);
77990227Sdillon		m = m_free(m);
78063670Snsayer	}
78163670Snsayer
78290227Sdillon	if (m != NULL) {
783121816Sbrooks		TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname,
784121816Sbrooks			minor(dev));
78590227Sdillon		m_freem(m);
78663670Snsayer	}
78763670Snsayer
78863670Snsayer	return (error);
78963670Snsayer} /* tapread */
79063670Snsayer
79163670Snsayer
79263670Snsayer/*
79363670Snsayer * tapwrite
79463670Snsayer *
79563670Snsayer * the cdevsw write interface - an atomic write is a packet - or else!
79663670Snsayer */
79763670Snsayerstatic int
79863670Snsayertapwrite(dev, uio, flag)
799130585Sphk	struct cdev *dev;
80063670Snsayer	struct uio	*uio;
80163670Snsayer	int		 flag;
80263670Snsayer{
80363670Snsayer	struct tap_softc	*tp = dev->si_drv1;
80463670Snsayer	struct ifnet		*ifp = &tp->tap_if;
805137101Sglebius	struct mbuf		*m;
806137101Sglebius	int			 error = 0;
80763670Snsayer
808121816Sbrooks	TAPDEBUG("%s writting, minor = %#x\n",
809121816Sbrooks		ifp->if_xname, minor(dev));
81063670Snsayer
81163670Snsayer	if (uio->uio_resid == 0)
81263670Snsayer		return (0);
81363670Snsayer
81463670Snsayer	if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) {
815121816Sbrooks		TAPDEBUG("%s invalid packet len = %d, minor = %#x\n",
816121816Sbrooks			ifp->if_xname, uio->uio_resid, minor(dev));
81763803Snsayer
81863670Snsayer		return (EIO);
81963670Snsayer	}
82063670Snsayer
821137101Sglebius	if ((m = m_uiotombuf(uio, M_DONTWAIT, 0)) == NULL) {
82263670Snsayer		ifp->if_ierrors ++;
82363670Snsayer		return (error);
82463670Snsayer	}
82563670Snsayer
826137101Sglebius	m->m_pkthdr.rcvif = ifp;
827111742Sdes
828106939Ssam	/* Pass packet up to parent. */
829137101Sglebius	(*ifp->if_input)(ifp, m);
830106939Ssam	ifp->if_ipackets ++; /* ibytes are counted in parent */
83163670Snsayer
83263670Snsayer	return (0);
83363670Snsayer} /* tapwrite */
83463670Snsayer
83563670Snsayer
83663670Snsayer/*
83763670Snsayer * tappoll
83863670Snsayer *
83963670Snsayer * the poll interface, this is only useful on reads
84063670Snsayer * really. the write detect always returns true, write never blocks
84163670Snsayer * anyway, it either accepts the packet or drops it
84263670Snsayer */
84363670Snsayerstatic int
84483366Sjuliantappoll(dev, events, td)
845130585Sphk	struct cdev *dev;
84663670Snsayer	int		 events;
84783366Sjulian	struct thread	*td;
84863670Snsayer{
84963670Snsayer	struct tap_softc	*tp = dev->si_drv1;
85063670Snsayer	struct ifnet		*ifp = &tp->tap_if;
851111742Sdes	int			 s, revents = 0;
85263670Snsayer
853121816Sbrooks	TAPDEBUG("%s polling, minor = %#x\n",
854121816Sbrooks		ifp->if_xname, minor(dev));
85563670Snsayer
85663670Snsayer	s = splimp();
85763670Snsayer	if (events & (POLLIN | POLLRDNORM)) {
85863670Snsayer		if (ifp->if_snd.ifq_len > 0) {
859121816Sbrooks			TAPDEBUG("%s have data in queue. len = %d, " \
860121816Sbrooks				"minor = %#x\n", ifp->if_xname,
86183043Sbrooks				ifp->if_snd.ifq_len, minor(dev));
86263803Snsayer
86363670Snsayer			revents |= (events & (POLLIN | POLLRDNORM));
86483043Sbrooks		} else {
865121816Sbrooks			TAPDEBUG("%s waiting for data, minor = %#x\n",
866121816Sbrooks				ifp->if_xname, minor(dev));
86763803Snsayer
86883805Sjhb			selrecord(td, &tp->tap_rsel);
86963670Snsayer		}
87063670Snsayer	}
87163670Snsayer
87263670Snsayer	if (events & (POLLOUT | POLLWRNORM))
87363670Snsayer		revents |= (events & (POLLOUT | POLLWRNORM));
87463670Snsayer
87563670Snsayer	splx(s);
87663670Snsayer	return (revents);
87763670Snsayer} /* tappoll */
878