if_tap.c revision 122352
163670Snsayer/*
263670Snsayer * Copyright (C) 1999-2000 by Maksim Yevmenkin <m_evmenkin@yahoo.com>
363670Snsayer * All rights reserved.
463670Snsayer *
563670Snsayer * Redistribution and use in source and binary forms, with or without
663670Snsayer * modification, are permitted provided that the following conditions
763670Snsayer * are met:
863670Snsayer * 1. Redistributions of source code must retain the above copyright
963670Snsayer *    notice, this list of conditions and the following disclaimer.
1063670Snsayer * 2. Redistributions in binary form must reproduce the above copyright
1163670Snsayer *    notice, this list of conditions and the following disclaimer in the
1263670Snsayer *    documentation and/or other materials provided with the distribution.
1363670Snsayer *
1463670Snsayer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1563670Snsayer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1663670Snsayer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1763670Snsayer * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1863670Snsayer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1963670Snsayer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2063670Snsayer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2163670Snsayer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2263670Snsayer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2363670Snsayer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2463670Snsayer * SUCH DAMAGE.
2563670Snsayer *
2663670Snsayer * BASED ON:
2763670Snsayer * -------------------------------------------------------------------------
2863670Snsayer *
2963670Snsayer * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk>
3063670Snsayer * Nottingham University 1987.
3163670Snsayer */
3263670Snsayer
3363670Snsayer/*
3463670Snsayer * $FreeBSD: head/sys/net/if_tap.c 122352 2003-11-09 09:17:26Z tanimura $
3563803Snsayer * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $
3663670Snsayer */
3763670Snsayer
3863670Snsayer#include "opt_inet.h"
3963670Snsayer
4063670Snsayer#include <sys/param.h>
4163670Snsayer#include <sys/conf.h>
4263670Snsayer#include <sys/filedesc.h>
4363670Snsayer#include <sys/filio.h>
4463670Snsayer#include <sys/kernel.h>
4563670Snsayer#include <sys/malloc.h>
4663670Snsayer#include <sys/mbuf.h>
4763670Snsayer#include <sys/poll.h>
4863670Snsayer#include <sys/proc.h>
4963670Snsayer#include <sys/signalvar.h>
5063670Snsayer#include <sys/socket.h>
5163670Snsayer#include <sys/sockio.h>
5263670Snsayer#include <sys/sysctl.h>
5363670Snsayer#include <sys/systm.h>
5463670Snsayer#include <sys/ttycom.h>
5563670Snsayer#include <sys/uio.h>
5663670Snsayer#include <sys/vnode.h>
5783043Sbrooks#include <machine/bus.h>	/* XXX: Shouldn't really be required! */
5883043Sbrooks#include <sys/rman.h>
5983043Sbrooks#include <sys/queue.h>
6063670Snsayer
6163670Snsayer#include <net/bpf.h>
6263670Snsayer#include <net/ethernet.h>
6363670Snsayer#include <net/if.h>
6463670Snsayer#include <net/if_arp.h>
6563670Snsayer#include <net/route.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 CDEV_MAJOR	149
7563670Snsayer#define TAPDEBUG	if (tapdebug) printf
7663670Snsayer
7763670Snsayer#define TAP		"tap"
7863670Snsayer#define VMNET		"vmnet"
7983043Sbrooks#define TAPMAXUNIT	0x7fff
8083043Sbrooks#define VMNET_DEV_MASK	0x00800000
8183043Sbrooks		/*	0x007f00ff	*/
8263670Snsayer
8363670Snsayer/* module */
84111742Sdesstatic int		tapmodevent(module_t, int, void *);
8563670Snsayer
8663670Snsayer/* device */
8793084Sbdestatic void		tapclone(void *, char *, int, dev_t *);
8893084Sbdestatic void		tapcreate(dev_t);
8963670Snsayer
9063670Snsayer/* network interface */
9193084Sbdestatic void		tapifstart(struct ifnet *);
9293084Sbdestatic int		tapifioctl(struct ifnet *, u_long, caddr_t);
9393084Sbdestatic void		tapifinit(void *);
9463670Snsayer
9563670Snsayer/* character device */
9663670Snsayerstatic d_open_t		tapopen;
9763670Snsayerstatic d_close_t	tapclose;
9863670Snsayerstatic d_read_t		tapread;
9963670Snsayerstatic d_write_t	tapwrite;
10063670Snsayerstatic d_ioctl_t	tapioctl;
10163670Snsayerstatic d_poll_t		tappoll;
10263670Snsayer
10363670Snsayerstatic struct cdevsw	tap_cdevsw = {
104111815Sphk	.d_open =	tapopen,
105111815Sphk	.d_close =	tapclose,
106111815Sphk	.d_read =	tapread,
107111815Sphk	.d_write =	tapwrite,
108111815Sphk	.d_ioctl =	tapioctl,
109111815Sphk	.d_poll =	tappoll,
110111815Sphk	.d_name =	CDEV_NAME,
111111815Sphk	.d_maj =	CDEV_MAJOR,
11263670Snsayer};
11363670Snsayer
11483043Sbrooksstatic int			tapdebug = 0;        /* debug flag   */
11583043Sbrooksstatic SLIST_HEAD(, tap_softc)	taphead;             /* first device */
11683043Sbrooksstatic udev_t			tapbasedev = NOUDEV; /* base device  */
11783043Sbrooksstatic struct rman		tapdevunits[2];      /* device units */
11883043Sbrooks#define		tapunits	tapdevunits
11983043Sbrooks#define		vmnetunits	(tapdevunits + 1)
12063670Snsayer
12163670SnsayerMALLOC_DECLARE(M_TAP);
12263670SnsayerMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface");
12363670SnsayerSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, "");
12463670SnsayerDEV_MODULE(if_tap, tapmodevent, NULL);
12563670Snsayer
12663670Snsayer/*
12763670Snsayer * tapmodevent
12863670Snsayer *
12963670Snsayer * module event handler
13063670Snsayer */
13163670Snsayerstatic int
13263670Snsayertapmodevent(mod, type, data)
13363670Snsayer	module_t	 mod;
13463670Snsayer	int		 type;
13563670Snsayer	void		*data;
13663670Snsayer{
13783043Sbrooks	static eventhandler_tag	 eh_tag = NULL;
13883043Sbrooks	struct tap_softc	*tp = NULL;
13983043Sbrooks	struct ifnet		*ifp = NULL;
14083043Sbrooks	int			 error, s;
14163670Snsayer
14263670Snsayer	switch (type) {
14363670Snsayer	case MOD_LOAD:
14483043Sbrooks		/* initialize resources */
14583043Sbrooks		tapunits->rm_type = RMAN_ARRAY;
14683043Sbrooks		tapunits->rm_descr = "open tap units";
14783043Sbrooks		vmnetunits->rm_type = RMAN_ARRAY;
14883043Sbrooks		vmnetunits->rm_descr = "open vmnet units";
14963670Snsayer
15083043Sbrooks		error = rman_init(tapunits);
15183043Sbrooks		if (error != 0)
15283043Sbrooks			goto bail;
15383043Sbrooks
15483043Sbrooks		error = rman_init(vmnetunits);
15583043Sbrooks		if (error != 0)
15683043Sbrooks			goto bail1;
15783043Sbrooks
15883043Sbrooks		error = rman_manage_region(tapunits, 0, TAPMAXUNIT);
15983043Sbrooks		if (error != 0)
16083043Sbrooks			goto bail2;
16183043Sbrooks
16283043Sbrooks		error = rman_manage_region(vmnetunits, 0, TAPMAXUNIT);
16383043Sbrooks		if (error != 0)
16483043Sbrooks			goto bail2;
16583043Sbrooks
16683043Sbrooks		/* intitialize device */
16783043Sbrooks
16883043Sbrooks		SLIST_INIT(&taphead);
16983043Sbrooks
17071602Sphk		eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000);
17183043Sbrooks		if (eh_tag == NULL) {
17283043Sbrooks			error = ENOMEM;
17383043Sbrooks			goto bail2;
17483043Sbrooks		}
17563670Snsayer
17671602Sphk
17783043Sbrooks		return (0);
17883043Sbrooksbail2:
17983043Sbrooks		rman_fini(vmnetunits);
18083043Sbrooksbail1:
18183043Sbrooks		rman_fini(tapunits);
18283043Sbrooksbail:
18383043Sbrooks		return (error);
18463670Snsayer
18583043Sbrooks	case MOD_UNLOAD:
18683043Sbrooks		SLIST_FOREACH(tp, &taphead, tap_next)
18783043Sbrooks			if (tp->tap_unit != NULL)
18883043Sbrooks				return (EBUSY);
18983043Sbrooks
19071602Sphk		EVENTHANDLER_DEREGISTER(dev_clone, eh_tag);
19163670Snsayer
19283043Sbrooks		error = rman_fini(tapunits);
19383043Sbrooks		KASSERT((error == 0), ("Could not fini tap units"));
19483043Sbrooks		error = rman_fini(vmnetunits);
19583043Sbrooks		KASSERT((error == 0), ("Could not fini vmnet units"));
19671602Sphk
19783043Sbrooks		while ((tp = SLIST_FIRST(&taphead)) != NULL) {
19883043Sbrooks			SLIST_REMOVE_HEAD(&taphead, tap_next);
19983043Sbrooks
20083043Sbrooks			ifp = &tp->tap_if;
20183043Sbrooks
202121816Sbrooks			TAPDEBUG("detaching %s\n", ifp->if_xname);
20383043Sbrooks
204121816Sbrooks			KASSERT(!(tp->tap_flags & TAP_OPEN),
205121816Sbrooks				("%s flags is out of sync", ifp->if_xname));
20683043Sbrooks
20783043Sbrooks			/* XXX makedev check? nah.. not right now :) */
20883043Sbrooks
20963670Snsayer			s = splimp();
210106939Ssam			ether_ifdetach(ifp);
21163670Snsayer			splx(s);
21263670Snsayer
21393752Sluigi			free(tp, M_TAP);
21483043Sbrooks		}
21563670Snsayer
216111742Sdes		if (tapbasedev != NOUDEV)
21783043Sbrooks			destroy_dev(udev2dev(tapbasedev, 0));
21863670Snsayer
21963670Snsayer
22083043Sbrooks		break;
22163670Snsayer
22263670Snsayer	default:
22363670Snsayer		return (EOPNOTSUPP);
22463670Snsayer	}
22563670Snsayer
22663670Snsayer	return (0);
22763670Snsayer} /* tapmodevent */
22863670Snsayer
22963670Snsayer
23063670Snsayer/*
23171602Sphk * DEVFS handler
23271602Sphk *
23371602Sphk * We need to support two kind of devices - tap and vmnet
23471602Sphk */
23571602Sphkstatic void
23671602Sphktapclone(arg, name, namelen, dev)
23771602Sphk	void	*arg;
23871602Sphk	char	*name;
23971602Sphk	int	 namelen;
24071602Sphk	dev_t	*dev;
24171602Sphk{
24283043Sbrooks	int		 unit, minor = 0 /* XXX avoid warning */ , error;
24383043Sbrooks	char		*device_name = name;
24483043Sbrooks	struct resource	*r = NULL;
24571602Sphk
24671602Sphk	if (*dev != NODEV)
24771602Sphk		return;
24871602Sphk
24983043Sbrooks	if (strcmp(device_name, TAP) == 0) {
25083043Sbrooks		/* get first free tap unit */
251111742Sdes		r = rman_reserve_resource(tapunits, 0, TAPMAXUNIT, 1,
25283043Sbrooks			RF_ALLOCATED | RF_ACTIVE, NULL);
25383043Sbrooks		unit = rman_get_start(r);
25483043Sbrooks		minor = unit2minor(unit);
25583043Sbrooks	}
25683043Sbrooks	else if (strcmp(device_name, VMNET) == 0) {
25783043Sbrooks		/* get first free vmnet unit */
258111742Sdes		r = rman_reserve_resource(vmnetunits, 0, TAPMAXUNIT, 1,
25983043Sbrooks			RF_ALLOCATED | RF_ACTIVE, NULL);
26083043Sbrooks		unit = rman_get_start(r);
26183043Sbrooks		minor = unit2minor(unit) | VMNET_DEV_MASK;
26283043Sbrooks	}
26371602Sphk
26483043Sbrooks	if (r != NULL) { /* need cloning */
26583043Sbrooks		TAPDEBUG("%s%d is available. minor = %#x\n",
26683043Sbrooks			device_name, unit, minor);
26771602Sphk
26883043Sbrooks		error = rman_release_resource(r);
26983043Sbrooks		KASSERT((error == 0), ("Could not release tap/vmnet unit"));
27083043Sbrooks
27183043Sbrooks		/* check if device for the unit has been created */
27283043Sbrooks		*dev = makedev(CDEV_MAJOR, minor);
27383043Sbrooks		if ((*dev)->si_flags & SI_NAMED) {
274111742Sdes			TAPDEBUG("%s%d device exists. minor = %#x\n",
27583043Sbrooks				device_name, unit, minor);
27683043Sbrooks			return; /* device has been created */
27783043Sbrooks		}
27883043Sbrooks	} else { /* try to match name/unit, first try tap then vmnet */
27983043Sbrooks		device_name = TAP;
28083043Sbrooks		if (dev_stdclone(name, NULL, device_name, &unit) != 1) {
28183043Sbrooks			device_name = VMNET;
28283043Sbrooks
28383043Sbrooks			if (dev_stdclone(name, NULL, device_name, &unit) != 1)
28483043Sbrooks				return;
28583043Sbrooks
28683043Sbrooks			minor = unit2minor(unit) | VMNET_DEV_MASK;
28783043Sbrooks		} else
28883043Sbrooks			minor = unit2minor(unit);
28971602Sphk	}
29071602Sphk
29183043Sbrooks	TAPDEBUG("make_dev(%s%d). minor = %#x\n", device_name, unit, minor);
29283043Sbrooks
29371602Sphk	*dev = make_dev(&tap_cdevsw, minor, UID_ROOT, GID_WHEEL, 0600, "%s%d",
29471602Sphk			device_name, unit);
29583043Sbrooks
29683043Sbrooks	if (tapbasedev == NOUDEV)
29783043Sbrooks		tapbasedev = (*dev)->si_udev;
29883043Sbrooks	else {
29983043Sbrooks		(*dev)->si_flags |= SI_CHEAPCLONE;
30083043Sbrooks		dev_depends(udev2dev(tapbasedev, 0), *dev);
30183043Sbrooks	}
30271602Sphk} /* tapclone */
30371602Sphk
30471602Sphk
30571602Sphk/*
30663670Snsayer * tapcreate
30763670Snsayer *
30863670Snsayer * to create interface
30963670Snsayer */
31063670Snsayerstatic void
31163670Snsayertapcreate(dev)
31263670Snsayer	dev_t	dev;
31363670Snsayer{
31463670Snsayer	struct ifnet		*ifp = NULL;
31563670Snsayer	struct tap_softc	*tp = NULL;
31663670Snsayer	unsigned short		 macaddr_hi;
31763803Snsayer	int			 unit, s;
31863670Snsayer	char			*name = NULL;
31963670Snsayer
32063670Snsayer	/* allocate driver storage and create device */
321111119Simp	MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO);
32283043Sbrooks	SLIST_INSERT_HEAD(&taphead, tp, tap_next);
32363670Snsayer
32483043Sbrooks	unit = dev2unit(dev) & TAPMAXUNIT;
32583043Sbrooks
32663670Snsayer	/* select device: tap or vmnet */
32763670Snsayer	if (minor(dev) & VMNET_DEV_MASK) {
32863670Snsayer		name = VMNET;
32963803Snsayer		tp->tap_flags |= TAP_VMNET;
33083043Sbrooks	} else
33163670Snsayer		name = TAP;
33263670Snsayer
33383043Sbrooks	TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev));
33483043Sbrooks
33583043Sbrooks	if (!(dev->si_flags & SI_NAMED))
336111742Sdes		dev = make_dev(&tap_cdevsw, minor(dev), UID_ROOT, GID_WHEEL,
33763670Snsayer						0600, "%s%d", name, unit);
33863670Snsayer
33963670Snsayer	/* generate fake MAC address: 00 bd xx xx xx unit_no */
34063670Snsayer	macaddr_hi = htons(0x00bd);
34163670Snsayer	bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short));
34263670Snsayer	bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long));
34363670Snsayer	tp->arpcom.ac_enaddr[5] = (u_char)unit;
34463670Snsayer
345111742Sdes	/* fill the rest and attach interface */
34663670Snsayer	ifp = &tp->tap_if;
34763670Snsayer	ifp->if_softc = tp;
348121816Sbrooks	if_initname(ifp, name, unit);
34963670Snsayer	ifp->if_init = tapifinit;
35063670Snsayer	ifp->if_start = tapifstart;
35163670Snsayer	ifp->if_ioctl = tapifioctl;
35263670Snsayer	ifp->if_mtu = ETHERMTU;
35363670Snsayer	ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
35463670Snsayer	ifp->if_snd.ifq_maxlen = ifqmaxlen;
35563670Snsayer
35683043Sbrooks	dev->si_drv1 = tp;
35783043Sbrooks
35863803Snsayer	s = splimp();
359106939Ssam	ether_ifattach(ifp, tp->arpcom.ac_enaddr);
36063803Snsayer	splx(s);
36163670Snsayer
36263803Snsayer	tp->tap_flags |= TAP_INITED;
36363803Snsayer
364121816Sbrooks	TAPDEBUG("interface %s is created. minor = %#x\n",
365121816Sbrooks		ifp->if_xname, minor(dev));
36663670Snsayer} /* tapcreate */
36763670Snsayer
36863670Snsayer
36963670Snsayer/*
370111742Sdes * tapopen
37163670Snsayer *
37263670Snsayer * to open tunnel. must be superuser
37363670Snsayer */
37463670Snsayerstatic int
37583366Sjuliantapopen(dev, flag, mode, td)
37663670Snsayer	dev_t		 dev;
37763670Snsayer	int		 flag;
37863670Snsayer	int		 mode;
37983366Sjulian	struct thread	*td;
38063670Snsayer{
38163670Snsayer	struct tap_softc	*tp = NULL;
38283043Sbrooks	int			 unit, error;
38383043Sbrooks	struct resource		*r = NULL;
38463670Snsayer
38593593Sjhb	if ((error = suser(td)) != 0)
38663670Snsayer		return (error);
38763670Snsayer
38883043Sbrooks	unit = dev2unit(dev) & TAPMAXUNIT;
38983043Sbrooks
39083043Sbrooks	if (minor(dev) & VMNET_DEV_MASK)
391111742Sdes		r = rman_reserve_resource(vmnetunits, unit, unit, 1,
39283043Sbrooks			RF_ALLOCATED | RF_ACTIVE, NULL);
39383043Sbrooks	else
394111742Sdes		r = rman_reserve_resource(tapunits, unit, unit, 1,
39583043Sbrooks			RF_ALLOCATED | RF_ACTIVE, NULL);
39683043Sbrooks
39783043Sbrooks	if (r == NULL)
39883043Sbrooks		return (EBUSY);
39983043Sbrooks
40083043Sbrooks	dev->si_flags &= ~SI_CHEAPCLONE;
40183043Sbrooks
40263670Snsayer	tp = dev->si_drv1;
40363670Snsayer	if (tp == NULL) {
40463670Snsayer		tapcreate(dev);
40563670Snsayer		tp = dev->si_drv1;
40663670Snsayer	}
40763670Snsayer
408121816Sbrooks	KASSERT(!(tp->tap_flags & TAP_OPEN),
409121816Sbrooks		("%s flags is out of sync", tp->tap_if.if_xname));
41063670Snsayer
41163861Snsayer	bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr));
41263861Snsayer
41383043Sbrooks	tp->tap_unit = r;
41483366Sjulian	tp->tap_pid = td->td_proc->p_pid;
41563670Snsayer	tp->tap_flags |= TAP_OPEN;
41663670Snsayer
417121816Sbrooks	TAPDEBUG("%s is open. minor = %#x\n",
418121816Sbrooks		tp->tap_if.if_xname, minor(dev));
41963670Snsayer
42063670Snsayer	return (0);
42163670Snsayer} /* tapopen */
42263670Snsayer
42363670Snsayer
42463670Snsayer/*
42563670Snsayer * tapclose
42663670Snsayer *
42763670Snsayer * close the device - mark i/f down & delete routing info
42863670Snsayer */
42963670Snsayerstatic int
43083366Sjuliantapclose(dev, foo, bar, td)
43163670Snsayer	dev_t		 dev;
43263670Snsayer	int		 foo;
43363670Snsayer	int		 bar;
43483366Sjulian	struct thread	*td;
43563670Snsayer{
43683043Sbrooks	int			 s, error;
43763670Snsayer	struct tap_softc	*tp = dev->si_drv1;
43863670Snsayer	struct ifnet		*ifp = &tp->tap_if;
43963670Snsayer
44087914Sjlemon	KASSERT((tp->tap_unit != NULL),
441121816Sbrooks		("%s is not open", ifp->if_xname));
44283043Sbrooks
44363670Snsayer	/* junk all pending output */
44483043Sbrooks	IF_DRAIN(&ifp->if_snd);
44563670Snsayer
44663803Snsayer	/*
44763803Snsayer	 * do not bring the interface down, and do not anything with
44863803Snsayer	 * interface, if we are in VMnet mode. just close the device.
44963803Snsayer	 */
45063803Snsayer
45163803Snsayer	if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) {
45263670Snsayer		s = splimp();
45363670Snsayer		if_down(ifp);
45463670Snsayer		if (ifp->if_flags & IFF_RUNNING) {
45563670Snsayer			/* find internet addresses and delete routes */
45663670Snsayer			struct ifaddr	*ifa = NULL;
45763670Snsayer
45863803Snsayer			TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
45963670Snsayer				if (ifa->ifa_addr->sa_family == AF_INET) {
46063670Snsayer					rtinit(ifa, (int)RTM_DELETE, 0);
46163670Snsayer
46263670Snsayer					/* remove address from interface */
463111742Sdes					bzero(ifa->ifa_addr,
46463670Snsayer						   sizeof(*(ifa->ifa_addr)));
465111742Sdes					bzero(ifa->ifa_dstaddr,
46663670Snsayer						   sizeof(*(ifa->ifa_dstaddr)));
467111742Sdes					bzero(ifa->ifa_netmask,
46863670Snsayer						   sizeof(*(ifa->ifa_netmask)));
46963670Snsayer				}
47063670Snsayer			}
47163670Snsayer
47263670Snsayer			ifp->if_flags &= ~IFF_RUNNING;
47363670Snsayer		}
47463670Snsayer		splx(s);
47563670Snsayer	}
47663670Snsayer
47796122Salfred	funsetown(&tp->tap_sigio);
478122352Stanimura	selwakeuppri(&tp->tap_rsel, PZERO+1);
47963670Snsayer
48063670Snsayer	tp->tap_flags &= ~TAP_OPEN;
48163670Snsayer	tp->tap_pid = 0;
48283043Sbrooks	error = rman_release_resource(tp->tap_unit);
483121816Sbrooks	KASSERT((error == 0),
484121816Sbrooks		("%s could not release unit", ifp->if_xname));
48583043Sbrooks	tp->tap_unit = NULL;
48663670Snsayer
487121816Sbrooks	TAPDEBUG("%s is closed. minor = %#x\n",
488121816Sbrooks		ifp->if_xname, minor(dev));
48963670Snsayer
49063670Snsayer	return (0);
49163670Snsayer} /* tapclose */
49263670Snsayer
49363670Snsayer
49463670Snsayer/*
49563670Snsayer * tapifinit
49663670Snsayer *
49763670Snsayer * network interface initialization function
49863670Snsayer */
49963670Snsayerstatic void
50063670Snsayertapifinit(xtp)
50163670Snsayer	void	*xtp;
50263670Snsayer{
50363670Snsayer	struct tap_softc	*tp = (struct tap_softc *)xtp;
50463670Snsayer	struct ifnet		*ifp = &tp->tap_if;
50563670Snsayer
506121816Sbrooks	TAPDEBUG("initializing %s\n", ifp->if_xname);
50763670Snsayer
50863670Snsayer	ifp->if_flags |= IFF_RUNNING;
50963670Snsayer	ifp->if_flags &= ~IFF_OACTIVE;
51063670Snsayer
51163670Snsayer	/* attempt to start output */
51263670Snsayer	tapifstart(ifp);
51363670Snsayer} /* tapifinit */
51463670Snsayer
51563670Snsayer
51663670Snsayer/*
51763670Snsayer * tapifioctl
51863670Snsayer *
51963670Snsayer * Process an ioctl request on network interface
52063670Snsayer */
521105228Sphkstatic int
52263670Snsayertapifioctl(ifp, cmd, data)
52363670Snsayer	struct ifnet	*ifp;
52463670Snsayer	u_long		 cmd;
52563670Snsayer	caddr_t		 data;
52663670Snsayer{
527111742Sdes	struct tap_softc	*tp = (struct tap_softc *)(ifp->if_softc);
52863670Snsayer	struct ifstat		*ifs = NULL;
52963670Snsayer	int			 s, dummy;
53063670Snsayer
53163670Snsayer	switch (cmd) {
53263670Snsayer		case SIOCSIFFLAGS: /* XXX -- just like vmnet does */
53363670Snsayer		case SIOCADDMULTI:
53463670Snsayer		case SIOCDELMULTI:
53583043Sbrooks			break;
53663670Snsayer
53763670Snsayer		case SIOCGIFSTATUS:
53863670Snsayer			s = splimp();
53963670Snsayer			ifs = (struct ifstat *)data;
54063670Snsayer			dummy = strlen(ifs->ascii);
54163670Snsayer			if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii))
54263670Snsayer				snprintf(ifs->ascii + dummy,
54363670Snsayer					sizeof(ifs->ascii) - dummy,
54463670Snsayer					"\tOpened by PID %d\n", tp->tap_pid);
54563670Snsayer			splx(s);
54683043Sbrooks			break;
54763670Snsayer
54863670Snsayer		default:
549106939Ssam			s = splimp();
550106939Ssam			dummy = ether_ioctl(ifp, cmd, data);
551106939Ssam			splx(s);
552106939Ssam			return (dummy);
55363670Snsayer	}
55463670Snsayer
55563670Snsayer	return (0);
55663670Snsayer} /* tapifioctl */
55763670Snsayer
55863670Snsayer
55963670Snsayer/*
560111742Sdes * tapifstart
561111742Sdes *
56263670Snsayer * queue packets from higher level ready to put out
56363670Snsayer */
56463670Snsayerstatic void
56563670Snsayertapifstart(ifp)
56663670Snsayer	struct ifnet	*ifp;
56763670Snsayer{
56863670Snsayer	struct tap_softc	*tp = ifp->if_softc;
56963670Snsayer	int			 s;
57063670Snsayer
571121816Sbrooks	TAPDEBUG("%s starting\n", ifp->if_xname);
57263670Snsayer
57363803Snsayer	/*
57463803Snsayer	 * do not junk pending output if we are in VMnet mode.
57563803Snsayer	 * XXX: can this do any harm because of queue overflow?
57663803Snsayer	 */
57763803Snsayer
578111742Sdes	if (((tp->tap_flags & TAP_VMNET) == 0) &&
57963803Snsayer	    ((tp->tap_flags & TAP_READY) != TAP_READY)) {
58063670Snsayer		struct mbuf	*m = NULL;
58163670Snsayer
582121816Sbrooks		TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname,
583121816Sbrooks		    tp->tap_flags);
58463670Snsayer
58563670Snsayer		s = splimp();
58663670Snsayer		do {
58763670Snsayer			IF_DEQUEUE(&ifp->if_snd, m);
58863670Snsayer			if (m != NULL)
58963670Snsayer				m_freem(m);
59063670Snsayer			ifp->if_oerrors ++;
59163670Snsayer		} while (m != NULL);
59263670Snsayer		splx(s);
59363670Snsayer
59463670Snsayer		return;
59563670Snsayer	}
59663670Snsayer
59763670Snsayer	s = splimp();
59863670Snsayer	ifp->if_flags |= IFF_OACTIVE;
59963670Snsayer
60063670Snsayer	if (ifp->if_snd.ifq_len != 0) {
60163670Snsayer		if (tp->tap_flags & TAP_RWAIT) {
60263670Snsayer			tp->tap_flags &= ~TAP_RWAIT;
603111748Sdes			wakeup(tp);
60463670Snsayer		}
60563670Snsayer
60663670Snsayer		if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL))
60795883Salfred			pgsigio(&tp->tap_sigio, SIGIO, 0);
60863670Snsayer
609122352Stanimura		selwakeuppri(&tp->tap_rsel, PZERO+1);
61063670Snsayer		ifp->if_opackets ++; /* obytes are counted in ether_output */
61163670Snsayer	}
61263670Snsayer
61363670Snsayer	ifp->if_flags &= ~IFF_OACTIVE;
61463670Snsayer	splx(s);
61563670Snsayer} /* tapifstart */
61663670Snsayer
61763670Snsayer
61863670Snsayer/*
61963670Snsayer * tapioctl
62063670Snsayer *
62163670Snsayer * the cdevsw interface is now pretty minimal
62263670Snsayer */
62363670Snsayerstatic int
62483366Sjuliantapioctl(dev, cmd, data, flag, td)
62563670Snsayer	dev_t		 dev;
62663670Snsayer	u_long		 cmd;
62763670Snsayer	caddr_t		 data;
62863670Snsayer	int		 flag;
62983366Sjulian	struct thread	*td;
63063670Snsayer{
63163670Snsayer	struct tap_softc	*tp = dev->si_drv1;
63263670Snsayer	struct ifnet		*ifp = &tp->tap_if;
633111742Sdes	struct tapinfo		*tapp = NULL;
63463670Snsayer	int			 s;
635102052Ssobomax	int			 f;
63663670Snsayer
63763670Snsayer	switch (cmd) {
638111742Sdes		case TAPSIFINFO:
63963670Snsayer			s = splimp();
640111742Sdes			tapp = (struct tapinfo *)data;
641111742Sdes			ifp->if_mtu = tapp->mtu;
642111742Sdes			ifp->if_type = tapp->type;
643111742Sdes			ifp->if_baudrate = tapp->baudrate;
64463670Snsayer			splx(s);
645111742Sdes			break;
64663670Snsayer
647111742Sdes		case TAPGIFINFO:
648111742Sdes			tapp = (struct tapinfo *)data;
649111742Sdes			tapp->mtu = ifp->if_mtu;
650111742Sdes			tapp->type = ifp->if_type;
651111742Sdes			tapp->baudrate = ifp->if_baudrate;
652111742Sdes			break;
65363670Snsayer
65463670Snsayer		case TAPSDEBUG:
65563670Snsayer			tapdebug = *(int *)data;
65683043Sbrooks			break;
65763670Snsayer
65863670Snsayer		case TAPGDEBUG:
65963670Snsayer			*(int *)data = tapdebug;
66083043Sbrooks			break;
66163670Snsayer
66263670Snsayer		case FIONBIO:
66383043Sbrooks			break;
66463670Snsayer
66563670Snsayer		case FIOASYNC:
66663803Snsayer			s = splimp();
66763670Snsayer			if (*(int *)data)
66863670Snsayer				tp->tap_flags |= TAP_ASYNC;
66963670Snsayer			else
67063670Snsayer				tp->tap_flags &= ~TAP_ASYNC;
67163803Snsayer			splx(s);
67283043Sbrooks			break;
67363670Snsayer
67463670Snsayer		case FIONREAD:
67563670Snsayer			s = splimp();
67663670Snsayer			if (ifp->if_snd.ifq_head) {
67763670Snsayer				struct mbuf	*mb = ifp->if_snd.ifq_head;
67863670Snsayer
67963803Snsayer				for(*(int *)data = 0;mb != NULL;mb = mb->m_next)
68063670Snsayer					*(int *)data += mb->m_len;
68183043Sbrooks			} else
68263670Snsayer				*(int *)data = 0;
68363670Snsayer			splx(s);
68483043Sbrooks			break;
68563670Snsayer
68663670Snsayer		case FIOSETOWN:
68763670Snsayer			return (fsetown(*(int *)data, &tp->tap_sigio));
68863670Snsayer
68963670Snsayer		case FIOGETOWN:
690104393Struckman			*(int *)data = fgetown(&tp->tap_sigio);
69163670Snsayer			return (0);
69263670Snsayer
69363670Snsayer		/* this is deprecated, FIOSETOWN should be used instead */
69463670Snsayer		case TIOCSPGRP:
69563670Snsayer			return (fsetown(-(*(int *)data), &tp->tap_sigio));
69663670Snsayer
69763670Snsayer		/* this is deprecated, FIOGETOWN should be used instead */
69863670Snsayer		case TIOCGPGRP:
699104393Struckman			*(int *)data = -fgetown(&tp->tap_sigio);
70063670Snsayer			return (0);
70163670Snsayer
70263670Snsayer		/* VMware/VMnet port ioctl's */
70363670Snsayer
70463670Snsayer		case SIOCGIFFLAGS:	/* get ifnet flags */
70563670Snsayer			bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags));
70683043Sbrooks			break;
70763670Snsayer
70883043Sbrooks		case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */
709102052Ssobomax			f = *(int *)data;
71063670Snsayer			f &= 0x0fff;
71163670Snsayer			f &= ~IFF_CANTCHANGE;
71263670Snsayer			f |= IFF_UP;
71363670Snsayer
71463670Snsayer			s = splimp();
71563670Snsayer			ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE);
71663670Snsayer			splx(s);
71783043Sbrooks			break;
71863670Snsayer
71963861Snsayer		case OSIOCGIFADDR:	/* get MAC address of the remote side */
72063670Snsayer		case SIOCGIFADDR:
72163861Snsayer			bcopy(tp->ether_addr, data, sizeof(tp->ether_addr));
72283043Sbrooks			break;
72363670Snsayer
72463861Snsayer		case SIOCSIFADDR:	/* set MAC address of the remote side */
72563861Snsayer			bcopy(data, tp->ether_addr, sizeof(tp->ether_addr));
72683043Sbrooks			break;
72763670Snsayer
72863670Snsayer		default:
72963670Snsayer			return (ENOTTY);
73063670Snsayer	}
73163670Snsayer	return (0);
73263670Snsayer} /* tapioctl */
73363670Snsayer
73463670Snsayer
73563670Snsayer/*
73663670Snsayer * tapread
73763670Snsayer *
73863670Snsayer * the cdevsw read interface - reads a packet at a time, or at
73963670Snsayer * least as much of a packet as can be read
74063670Snsayer */
74163670Snsayerstatic int
74263670Snsayertapread(dev, uio, flag)
74363670Snsayer	dev_t		 dev;
74463670Snsayer	struct uio	*uio;
74563670Snsayer	int		 flag;
74663670Snsayer{
74763670Snsayer	struct tap_softc	*tp = dev->si_drv1;
74863670Snsayer	struct ifnet		*ifp = &tp->tap_if;
74990227Sdillon	struct mbuf		*m = NULL;
75063670Snsayer	int			 error = 0, len, s;
75163670Snsayer
752121816Sbrooks	TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, minor(dev));
75363670Snsayer
75463670Snsayer	if ((tp->tap_flags & TAP_READY) != TAP_READY) {
755121816Sbrooks		TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n",
756121816Sbrooks			ifp->if_xname, minor(dev), tp->tap_flags);
75763803Snsayer
75863670Snsayer		return (EHOSTDOWN);
75963670Snsayer	}
76063670Snsayer
76163670Snsayer	tp->tap_flags &= ~TAP_RWAIT;
76263670Snsayer
76363670Snsayer	/* sleep until we get a packet */
76463670Snsayer	do {
76563670Snsayer		s = splimp();
76690227Sdillon		IF_DEQUEUE(&ifp->if_snd, m);
76763670Snsayer		splx(s);
76863670Snsayer
76990227Sdillon		if (m == NULL) {
77063670Snsayer			if (flag & IO_NDELAY)
77163670Snsayer				return (EWOULDBLOCK);
772111742Sdes
77363670Snsayer			tp->tap_flags |= TAP_RWAIT;
774111748Sdes			error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0);
77563670Snsayer			if (error)
77663670Snsayer				return (error);
77763670Snsayer		}
77890227Sdillon	} while (m == NULL);
77963670Snsayer
78063670Snsayer	/* feed packet to bpf */
781106939Ssam	BPF_MTAP(ifp, m);
78263670Snsayer
78363670Snsayer	/* xfer packet to user space */
78490227Sdillon	while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) {
78590227Sdillon		len = min(uio->uio_resid, m->m_len);
78663670Snsayer		if (len == 0)
78763670Snsayer			break;
78863670Snsayer
789111741Sdes		error = uiomove(mtod(m, void *), len, uio);
79090227Sdillon		m = m_free(m);
79163670Snsayer	}
79263670Snsayer
79390227Sdillon	if (m != NULL) {
794121816Sbrooks		TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname,
795121816Sbrooks			minor(dev));
79690227Sdillon		m_freem(m);
79763670Snsayer	}
79863670Snsayer
79963670Snsayer	return (error);
80063670Snsayer} /* tapread */
80163670Snsayer
80263670Snsayer
80363670Snsayer/*
80463670Snsayer * tapwrite
80563670Snsayer *
80663670Snsayer * the cdevsw write interface - an atomic write is a packet - or else!
80763670Snsayer */
80863670Snsayerstatic int
80963670Snsayertapwrite(dev, uio, flag)
81063670Snsayer	dev_t		 dev;
81163670Snsayer	struct uio	*uio;
81263670Snsayer	int		 flag;
81363670Snsayer{
81463670Snsayer	struct tap_softc	*tp = dev->si_drv1;
81563670Snsayer	struct ifnet		*ifp = &tp->tap_if;
81663670Snsayer	struct mbuf		*top = NULL, **mp = NULL, *m = NULL;
817111742Sdes	int			 error = 0, tlen, mlen;
81863670Snsayer
819121816Sbrooks	TAPDEBUG("%s writting, minor = %#x\n",
820121816Sbrooks		ifp->if_xname, minor(dev));
82163670Snsayer
82263670Snsayer	if (uio->uio_resid == 0)
82363670Snsayer		return (0);
82463670Snsayer
82563670Snsayer	if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) {
826121816Sbrooks		TAPDEBUG("%s invalid packet len = %d, minor = %#x\n",
827121816Sbrooks			ifp->if_xname, uio->uio_resid, minor(dev));
82863803Snsayer
82963670Snsayer		return (EIO);
83063670Snsayer	}
83163670Snsayer	tlen = uio->uio_resid;
83263670Snsayer
83363670Snsayer	/* get a header mbuf */
834111119Simp	MGETHDR(m, M_DONTWAIT, MT_DATA);
83563670Snsayer	if (m == NULL)
83663670Snsayer		return (ENOBUFS);
83763670Snsayer	mlen = MHLEN;
83863670Snsayer
83963670Snsayer	top = 0;
84063670Snsayer	mp = &top;
84163670Snsayer	while ((error == 0) && (uio->uio_resid > 0)) {
84263670Snsayer		m->m_len = min(mlen, uio->uio_resid);
843111741Sdes		error = uiomove(mtod(m, void *), m->m_len, uio);
84463670Snsayer		*mp = m;
84563670Snsayer		mp = &m->m_next;
84663670Snsayer		if (uio->uio_resid > 0) {
847111119Simp			MGET(m, M_DONTWAIT, MT_DATA);
84863803Snsayer			if (m == NULL) {
84963670Snsayer				error = ENOBUFS;
85063670Snsayer				break;
85163670Snsayer			}
85263670Snsayer			mlen = MLEN;
85363670Snsayer		}
85463670Snsayer	}
85563670Snsayer	if (error) {
85663670Snsayer		ifp->if_ierrors ++;
85763670Snsayer		if (top)
85863670Snsayer			m_freem(top);
85963670Snsayer		return (error);
86063670Snsayer	}
86163670Snsayer
86263670Snsayer	top->m_pkthdr.len = tlen;
86363670Snsayer	top->m_pkthdr.rcvif = ifp;
864111742Sdes
865106939Ssam	/* Pass packet up to parent. */
866106939Ssam	(*ifp->if_input)(ifp, top);
867106939Ssam	ifp->if_ipackets ++; /* ibytes are counted in parent */
86863670Snsayer
86963670Snsayer	return (0);
87063670Snsayer} /* tapwrite */
87163670Snsayer
87263670Snsayer
87363670Snsayer/*
87463670Snsayer * tappoll
87563670Snsayer *
87663670Snsayer * the poll interface, this is only useful on reads
87763670Snsayer * really. the write detect always returns true, write never blocks
87863670Snsayer * anyway, it either accepts the packet or drops it
87963670Snsayer */
88063670Snsayerstatic int
88183366Sjuliantappoll(dev, events, td)
88263670Snsayer	dev_t		 dev;
88363670Snsayer	int		 events;
88483366Sjulian	struct thread	*td;
88563670Snsayer{
88663670Snsayer	struct tap_softc	*tp = dev->si_drv1;
88763670Snsayer	struct ifnet		*ifp = &tp->tap_if;
888111742Sdes	int			 s, revents = 0;
88963670Snsayer
890121816Sbrooks	TAPDEBUG("%s polling, minor = %#x\n",
891121816Sbrooks		ifp->if_xname, minor(dev));
89263670Snsayer
89363670Snsayer	s = splimp();
89463670Snsayer	if (events & (POLLIN | POLLRDNORM)) {
89563670Snsayer		if (ifp->if_snd.ifq_len > 0) {
896121816Sbrooks			TAPDEBUG("%s have data in queue. len = %d, " \
897121816Sbrooks				"minor = %#x\n", ifp->if_xname,
89883043Sbrooks				ifp->if_snd.ifq_len, minor(dev));
89963803Snsayer
90063670Snsayer			revents |= (events & (POLLIN | POLLRDNORM));
90183043Sbrooks		} else {
902121816Sbrooks			TAPDEBUG("%s waiting for data, minor = %#x\n",
903121816Sbrooks				ifp->if_xname, minor(dev));
90463803Snsayer
90583805Sjhb			selrecord(td, &tp->tap_rsel);
90663670Snsayer		}
90763670Snsayer	}
90863670Snsayer
90963670Snsayer	if (events & (POLLOUT | POLLWRNORM))
91063670Snsayer		revents |= (events & (POLLOUT | POLLWRNORM));
91163670Snsayer
91263670Snsayer	splx(s);
91363670Snsayer	return (revents);
91463670Snsayer} /* tappoll */
915