if_tap.c revision 63861
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 63861 2000-07-25 23:50:30Z nsayer $
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>
5763670Snsayer
5863670Snsayer#include <net/bpf.h>
5963670Snsayer#include <net/ethernet.h>
6063670Snsayer#include <net/if.h>
6163670Snsayer#include <net/if_arp.h>
6263670Snsayer#include <net/route.h>
6363670Snsayer
6463670Snsayer#include <netinet/in.h>
6563670Snsayer
6663670Snsayer#include <net/if_tapvar.h>
6763670Snsayer#include <net/if_tap.h>
6863670Snsayer
6963670Snsayer
7063670Snsayer#define CDEV_NAME	"tap"
7163670Snsayer#define CDEV_MAJOR	149
7263670Snsayer#define TAPDEBUG	if (tapdebug) printf
7363670Snsayer
7463670Snsayer#define TAP		"tap"
7563670Snsayer#define VMNET		"vmnet"
7663670Snsayer#define VMNET_DEV_MASK	0x00010000
7763670Snsayer
7863670Snsayer/* module */
7963670Snsayerstatic int 		tapmodevent	__P((module_t, int, void *));
8063670Snsayer
8163670Snsayer/* device */
8263670Snsayerstatic void		tapcreate	__P((dev_t));
8363670Snsayer
8463670Snsayer/* network interface */
8563670Snsayerstatic void		tapifstart	__P((struct ifnet *));
8663670Snsayerstatic int		tapifioctl	__P((struct ifnet *, u_long, caddr_t));
8763670Snsayerstatic void		tapifinit	__P((void *));
8863670Snsayer
8963670Snsayer/* character device */
9063670Snsayerstatic d_open_t		tapopen;
9163670Snsayerstatic d_close_t	tapclose;
9263670Snsayerstatic d_read_t		tapread;
9363670Snsayerstatic d_write_t	tapwrite;
9463670Snsayerstatic d_ioctl_t	tapioctl;
9563670Snsayerstatic d_poll_t		tappoll;
9663670Snsayer
9763670Snsayerstatic struct cdevsw	tap_cdevsw = {
9863670Snsayer	/* open */	tapopen,
9963670Snsayer	/* close */	tapclose,
10063670Snsayer	/* read */	tapread,
10163670Snsayer	/* write */	tapwrite,
10263670Snsayer	/* ioctl */	tapioctl,
10363670Snsayer	/* poll */	tappoll,
10463670Snsayer	/* mmap */	nommap,
10563670Snsayer	/* startegy */	nostrategy,
10663670Snsayer	/* dev name */	CDEV_NAME,
10763670Snsayer	/* dev major */	CDEV_MAJOR,
10863670Snsayer	/* dump */	nodump,
10963670Snsayer	/* psize */	nopsize,
11063670Snsayer	/* flags */	0,
11163670Snsayer	/* bmaj */	-1
11263670Snsayer};
11363670Snsayer
11463670Snsayerstatic int		taprefcnt = 0;		/* module ref. counter   */
11563670Snsayerstatic int		taplastunit = -1;	/* max. open unit number */
11663670Snsayerstatic int		tapdebug = 0;		/* debug flag            */
11763670Snsayer
11863670SnsayerMALLOC_DECLARE(M_TAP);
11963670SnsayerMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface");
12063670SnsayerSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, "");
12163670SnsayerDEV_MODULE(if_tap, tapmodevent, NULL);
12263670Snsayer
12363670Snsayer/*
12463670Snsayer * tapmodevent
12563670Snsayer *
12663670Snsayer * module event handler
12763670Snsayer */
12863670Snsayerstatic int
12963670Snsayertapmodevent(mod, type, data)
13063670Snsayer	module_t	 mod;
13163670Snsayer	int		 type;
13263670Snsayer	void		*data;
13363670Snsayer{
13463670Snsayer	static int		 attached = 0;
13563670Snsayer	struct ifnet		*ifp = NULL;
13663670Snsayer	int			 unit, s;
13763670Snsayer
13863670Snsayer	switch (type) {
13963670Snsayer	case MOD_LOAD:
14063670Snsayer		if (attached)
14163670Snsayer			return (EEXIST);
14263670Snsayer
14363670Snsayer		cdevsw_add(&tap_cdevsw);
14463670Snsayer		attached = 1;
14563670Snsayer	break;
14663670Snsayer
14763670Snsayer	case MOD_UNLOAD:
14863670Snsayer		if (taprefcnt > 0)
14963670Snsayer			return (EBUSY);
15063670Snsayer
15163670Snsayer		cdevsw_remove(&tap_cdevsw);
15263670Snsayer
15363670Snsayer		unit = 0;
15463670Snsayer		while (unit <= taplastunit) {
15563670Snsayer			s = splimp();
15663670Snsayer			TAILQ_FOREACH(ifp, &ifnet, if_link)
15763670Snsayer				if ((strcmp(ifp->if_name, TAP) == 0) ||
15863670Snsayer				    (strcmp(ifp->if_name, VMNET) == 0))
15963670Snsayer					if (ifp->if_unit == unit)
16063670Snsayer						break;
16163670Snsayer			splx(s);
16263670Snsayer
16363670Snsayer			if (ifp != NULL) {
16463670Snsayer				struct tap_softc	*tp = ifp->if_softc;
16563670Snsayer
16663803Snsayer				TAPDEBUG("detaching %s%d. minor = %#x, " \
16763803Snsayer					"taplastunit = %d\n",
16863803Snsayer					ifp->if_name, unit, minor(tp->tap_dev),
16963803Snsayer					taplastunit);
17063670Snsayer
17163803Snsayer				s = splimp();
17263670Snsayer				ether_ifdetach(ifp, 1);
17363803Snsayer				splx(s);
17463670Snsayer				destroy_dev(tp->tap_dev);
17563670Snsayer				FREE(tp, M_TAP);
17663670Snsayer			}
17763670Snsayer			else
17863670Snsayer				unit ++;
17963670Snsayer		}
18063670Snsayer
18163670Snsayer		attached = 0;
18263670Snsayer	break;
18363670Snsayer
18463670Snsayer	default:
18563670Snsayer		return (EOPNOTSUPP);
18663670Snsayer	}
18763670Snsayer
18863670Snsayer	return (0);
18963670Snsayer} /* tapmodevent */
19063670Snsayer
19163670Snsayer
19263670Snsayer/*
19363670Snsayer * tapcreate
19463670Snsayer *
19563670Snsayer * to create interface
19663670Snsayer */
19763670Snsayerstatic void
19863670Snsayertapcreate(dev)
19963670Snsayer	dev_t	dev;
20063670Snsayer{
20163670Snsayer	struct ifnet		*ifp = NULL;
20263670Snsayer	struct tap_softc	*tp = NULL;
20363670Snsayer	unsigned short		 macaddr_hi;
20463803Snsayer	int			 unit, s;
20563670Snsayer	char			*name = NULL;
20663670Snsayer
20763670Snsayer	/* allocate driver storage and create device */
20863670Snsayer	MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK);
20963670Snsayer	bzero(tp, sizeof(*tp));
21063670Snsayer
21163670Snsayer	/* select device: tap or vmnet */
21263670Snsayer	if (minor(dev) & VMNET_DEV_MASK) {
21363670Snsayer		name = VMNET;
21463670Snsayer		unit = lminor(dev) & 0xff;
21563803Snsayer		tp->tap_flags |= TAP_VMNET;
21663670Snsayer	}
21763670Snsayer	else {
21863670Snsayer		name = TAP;
21963670Snsayer		unit = lminor(dev);
22063670Snsayer	}
22163670Snsayer
22263803Snsayer	tp->tap_dev = make_dev(&tap_cdevsw, minor(dev), UID_ROOT, GID_WHEEL,
22363670Snsayer						0600, "%s%d", name, unit);
22463670Snsayer	tp->tap_dev->si_drv1 = dev->si_drv1 = tp;
22563670Snsayer
22663670Snsayer	/* generate fake MAC address: 00 bd xx xx xx unit_no */
22763670Snsayer	macaddr_hi = htons(0x00bd);
22863670Snsayer	bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short));
22963670Snsayer	bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long));
23063670Snsayer	tp->arpcom.ac_enaddr[5] = (u_char)unit;
23163670Snsayer
23263670Snsayer	/* fill the rest and attach interface */
23363670Snsayer	ifp = &tp->tap_if;
23463670Snsayer	ifp->if_softc = tp;
23563670Snsayer
23663670Snsayer	ifp->if_unit = unit;
23763670Snsayer	if (unit > taplastunit)
23863670Snsayer		taplastunit = unit;
23963670Snsayer
24063670Snsayer	ifp->if_name = name;
24163670Snsayer	ifp->if_init = tapifinit;
24263670Snsayer	ifp->if_output = ether_output;
24363670Snsayer	ifp->if_start = tapifstart;
24463670Snsayer	ifp->if_ioctl = tapifioctl;
24563670Snsayer	ifp->if_mtu = ETHERMTU;
24663670Snsayer	ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
24763670Snsayer	ifp->if_snd.ifq_maxlen = ifqmaxlen;
24863670Snsayer
24963803Snsayer	s = splimp();
25063670Snsayer	ether_ifattach(ifp, 1);
25163803Snsayer	splx(s);
25263670Snsayer
25363803Snsayer	tp->tap_flags |= TAP_INITED;
25463803Snsayer
25563803Snsayer	TAPDEBUG("interface %s%d created. minor = %#x\n",
25663803Snsayer			ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
25763670Snsayer} /* tapcreate */
25863670Snsayer
25963670Snsayer
26063670Snsayer/*
26163670Snsayer * tapopen
26263670Snsayer *
26363670Snsayer * to open tunnel. must be superuser
26463670Snsayer */
26563670Snsayerstatic int
26663670Snsayertapopen(dev, flag, mode, p)
26763670Snsayer	dev_t		 dev;
26863670Snsayer	int		 flag;
26963670Snsayer	int		 mode;
27063670Snsayer	struct proc	*p;
27163670Snsayer{
27263670Snsayer	struct tap_softc	*tp = NULL;
27363670Snsayer	int			 error;
27463670Snsayer
27563670Snsayer	if ((error = suser(p)) != 0)
27663670Snsayer		return (error);
27763670Snsayer
27863670Snsayer	tp = dev->si_drv1;
27963670Snsayer	if (tp == NULL) {
28063670Snsayer		tapcreate(dev);
28163670Snsayer		tp = dev->si_drv1;
28263670Snsayer	}
28363670Snsayer
28463670Snsayer	if (tp->tap_flags & TAP_OPEN)
28563670Snsayer		return (EBUSY);
28663670Snsayer
28763861Snsayer	bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr));
28863861Snsayer
28963670Snsayer	tp->tap_pid = p->p_pid;
29063670Snsayer	tp->tap_flags |= TAP_OPEN;
29163670Snsayer	taprefcnt ++;
29263670Snsayer
29363803Snsayer	TAPDEBUG("%s%d is open. minor = %#x, refcnt = %d, taplastunit = %d\n",
29463803Snsayer		tp->tap_if.if_name, tp->tap_if.if_unit,
29563803Snsayer		minor(tp->tap_dev), taprefcnt, taplastunit);
29663670Snsayer
29763670Snsayer	return (0);
29863670Snsayer} /* tapopen */
29963670Snsayer
30063670Snsayer
30163670Snsayer/*
30263670Snsayer * tapclose
30363670Snsayer *
30463670Snsayer * close the device - mark i/f down & delete routing info
30563670Snsayer */
30663670Snsayerstatic int
30763670Snsayertapclose(dev, foo, bar, p)
30863670Snsayer	dev_t		 dev;
30963670Snsayer	int		 foo;
31063670Snsayer	int		 bar;
31163670Snsayer	struct proc	*p;
31263670Snsayer{
31363670Snsayer	int			 s;
31463670Snsayer	struct tap_softc	*tp = dev->si_drv1;
31563670Snsayer	struct ifnet		*ifp = &tp->tap_if;
31663670Snsayer	struct mbuf		*m = NULL;
31763670Snsayer
31863670Snsayer	/* junk all pending output */
31963670Snsayer
32063670Snsayer	s = splimp();
32163670Snsayer	do {
32263670Snsayer		IF_DEQUEUE(&ifp->if_snd, m);
32363670Snsayer		if (m != NULL)
32463670Snsayer			m_freem(m);
32563670Snsayer	} while (m != NULL);
32663670Snsayer	splx(s);
32763670Snsayer
32863803Snsayer	/*
32963803Snsayer	 * do not bring the interface down, and do not anything with
33063803Snsayer	 * interface, if we are in VMnet mode. just close the device.
33163803Snsayer	 */
33263803Snsayer
33363803Snsayer	if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) {
33463670Snsayer		s = splimp();
33563670Snsayer		if_down(ifp);
33663670Snsayer		if (ifp->if_flags & IFF_RUNNING) {
33763670Snsayer			/* find internet addresses and delete routes */
33863670Snsayer			struct ifaddr	*ifa = NULL;
33963670Snsayer
34063803Snsayer			TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
34163670Snsayer				if (ifa->ifa_addr->sa_family == AF_INET) {
34263670Snsayer					rtinit(ifa, (int)RTM_DELETE, 0);
34363670Snsayer
34463670Snsayer					/* remove address from interface */
34563670Snsayer					bzero(ifa->ifa_addr,
34663670Snsayer						   sizeof(*(ifa->ifa_addr)));
34763670Snsayer					bzero(ifa->ifa_dstaddr,
34863670Snsayer						   sizeof(*(ifa->ifa_dstaddr)));
34963670Snsayer					bzero(ifa->ifa_netmask,
35063670Snsayer						   sizeof(*(ifa->ifa_netmask)));
35163670Snsayer				}
35263670Snsayer			}
35363670Snsayer
35463670Snsayer			ifp->if_flags &= ~IFF_RUNNING;
35563670Snsayer		}
35663670Snsayer		splx(s);
35763670Snsayer	}
35863670Snsayer
35963670Snsayer	funsetown(tp->tap_sigio);
36063670Snsayer	selwakeup(&tp->tap_rsel);
36163670Snsayer
36263670Snsayer	tp->tap_flags &= ~TAP_OPEN;
36363670Snsayer	tp->tap_pid = 0;
36463670Snsayer
36563670Snsayer	taprefcnt --;
36663670Snsayer	if (taprefcnt < 0) {
36763670Snsayer		taprefcnt = 0;
36863803Snsayer		printf("%s%d minor = %#x, refcnt = %d is out of sync. " \
36963803Snsayer			"set refcnt to 0\n", ifp->if_name, ifp->if_unit,
37063803Snsayer			minor(tp->tap_dev), taprefcnt);
37163670Snsayer	}
37263670Snsayer
37363803Snsayer	TAPDEBUG("%s%d is closed. minor = %#x, refcnt = %d, taplastunit = %d\n",
37463803Snsayer			ifp->if_name, ifp->if_unit, minor(tp->tap_dev),
37563803Snsayer			taprefcnt, taplastunit);
37663670Snsayer
37763670Snsayer	return (0);
37863670Snsayer} /* tapclose */
37963670Snsayer
38063670Snsayer
38163670Snsayer/*
38263670Snsayer * tapifinit
38363670Snsayer *
38463670Snsayer * network interface initialization function
38563670Snsayer */
38663670Snsayerstatic void
38763670Snsayertapifinit(xtp)
38863670Snsayer	void	*xtp;
38963670Snsayer{
39063670Snsayer	struct tap_softc	*tp = (struct tap_softc *)xtp;
39163670Snsayer	struct ifnet		*ifp = &tp->tap_if;
39263670Snsayer
39363803Snsayer	TAPDEBUG("initializing %s%d, minor = %#x\n",
39463803Snsayer			ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
39563670Snsayer
39663670Snsayer	ifp->if_flags |= IFF_RUNNING;
39763670Snsayer	ifp->if_flags &= ~IFF_OACTIVE;
39863670Snsayer
39963670Snsayer	/* attempt to start output */
40063670Snsayer	tapifstart(ifp);
40163670Snsayer} /* tapifinit */
40263670Snsayer
40363670Snsayer
40463670Snsayer/*
40563670Snsayer * tapifioctl
40663670Snsayer *
40763670Snsayer * Process an ioctl request on network interface
40863670Snsayer */
40963670Snsayerint
41063670Snsayertapifioctl(ifp, cmd, data)
41163670Snsayer	struct ifnet	*ifp;
41263670Snsayer	u_long		 cmd;
41363670Snsayer	caddr_t		 data;
41463670Snsayer{
41563670Snsayer	struct tap_softc 	*tp = (struct tap_softc *)(ifp->if_softc);
41663670Snsayer	struct ifstat		*ifs = NULL;
41763670Snsayer	int			 s, dummy;
41863670Snsayer
41963670Snsayer	switch (cmd) {
42063670Snsayer		case SIOCSIFADDR:
42163670Snsayer		case SIOCGIFADDR:
42263670Snsayer		case SIOCSIFMTU:
42363670Snsayer			s = splimp();
42463670Snsayer			dummy = ether_ioctl(ifp, cmd, data);
42563670Snsayer			splx(s);
42663670Snsayer			return (dummy);
42763670Snsayer
42863670Snsayer		case SIOCSIFFLAGS: /* XXX -- just like vmnet does */
42963670Snsayer		case SIOCADDMULTI:
43063670Snsayer		case SIOCDELMULTI:
43163670Snsayer		break;
43263670Snsayer
43363670Snsayer		case SIOCGIFSTATUS:
43463670Snsayer			s = splimp();
43563670Snsayer			ifs = (struct ifstat *)data;
43663670Snsayer			dummy = strlen(ifs->ascii);
43763670Snsayer			if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii))
43863670Snsayer				snprintf(ifs->ascii + dummy,
43963670Snsayer					sizeof(ifs->ascii) - dummy,
44063670Snsayer					"\tOpened by PID %d\n", tp->tap_pid);
44163670Snsayer			splx(s);
44263670Snsayer		break;
44363670Snsayer
44463670Snsayer		default:
44563670Snsayer			return (EINVAL);
44663670Snsayer	}
44763670Snsayer
44863670Snsayer	return (0);
44963670Snsayer} /* tapifioctl */
45063670Snsayer
45163670Snsayer
45263670Snsayer/*
45363670Snsayer * tapifstart
45463670Snsayer *
45563670Snsayer * queue packets from higher level ready to put out
45663670Snsayer */
45763670Snsayerstatic void
45863670Snsayertapifstart(ifp)
45963670Snsayer	struct ifnet	*ifp;
46063670Snsayer{
46163670Snsayer	struct tap_softc	*tp = ifp->if_softc;
46263670Snsayer	int			 s;
46363670Snsayer
46463803Snsayer	TAPDEBUG("%s%d starting, minor = %#x\n",
46563803Snsayer			ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
46663670Snsayer
46763803Snsayer	/*
46863803Snsayer	 * do not junk pending output if we are in VMnet mode.
46963803Snsayer	 * XXX: can this do any harm because of queue overflow?
47063803Snsayer	 */
47163803Snsayer
47263803Snsayer	if (((tp->tap_flags & TAP_VMNET) == 0) &&
47363803Snsayer	    ((tp->tap_flags & TAP_READY) != TAP_READY)) {
47463670Snsayer		struct mbuf	*m = NULL;
47563670Snsayer
47663803Snsayer		TAPDEBUG("%s%d not ready. minor = %#x, tap_flags = 0x%x\n",
47763803Snsayer			ifp->if_name, ifp->if_unit,
47863803Snsayer			minor(tp->tap_dev), tp->tap_flags);
47963670Snsayer
48063670Snsayer		s = splimp();
48163670Snsayer		do {
48263670Snsayer			IF_DEQUEUE(&ifp->if_snd, m);
48363670Snsayer			if (m != NULL)
48463670Snsayer				m_freem(m);
48563670Snsayer			ifp->if_oerrors ++;
48663670Snsayer		} while (m != NULL);
48763670Snsayer		splx(s);
48863670Snsayer
48963670Snsayer		return;
49063670Snsayer	}
49163670Snsayer
49263670Snsayer	s = splimp();
49363670Snsayer	ifp->if_flags |= IFF_OACTIVE;
49463670Snsayer
49563670Snsayer	if (ifp->if_snd.ifq_len != 0) {
49663670Snsayer		if (tp->tap_flags & TAP_RWAIT) {
49763670Snsayer			tp->tap_flags &= ~TAP_RWAIT;
49863670Snsayer			wakeup((caddr_t)tp);
49963670Snsayer		}
50063670Snsayer
50163670Snsayer		if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL))
50263670Snsayer			pgsigio(tp->tap_sigio, SIGIO, 0);
50363670Snsayer
50463670Snsayer		selwakeup(&tp->tap_rsel);
50563670Snsayer		ifp->if_opackets ++; /* obytes are counted in ether_output */
50663670Snsayer	}
50763670Snsayer
50863670Snsayer	ifp->if_flags &= ~IFF_OACTIVE;
50963670Snsayer	splx(s);
51063670Snsayer} /* tapifstart */
51163670Snsayer
51263670Snsayer
51363670Snsayer/*
51463670Snsayer * tapioctl
51563670Snsayer *
51663670Snsayer * the cdevsw interface is now pretty minimal
51763670Snsayer */
51863670Snsayerstatic int
51963670Snsayertapioctl(dev, cmd, data, flag, p)
52063670Snsayer	dev_t		 dev;
52163670Snsayer	u_long		 cmd;
52263670Snsayer	caddr_t		 data;
52363670Snsayer	int		 flag;
52463670Snsayer	struct proc	*p;
52563670Snsayer{
52663670Snsayer	struct tap_softc	*tp = dev->si_drv1;
52763670Snsayer	struct ifnet		*ifp = &tp->tap_if;
52863670Snsayer 	struct tapinfo		*tapp = NULL;
52963670Snsayer	int			 s;
53063670Snsayer
53163670Snsayer	switch (cmd) {
53263670Snsayer 		case TAPSIFINFO:
53363670Snsayer			s = splimp();
53463670Snsayer 		        tapp = (struct tapinfo *)data;
53563670Snsayer 			ifp->if_mtu = tapp->mtu;
53663670Snsayer 			ifp->if_type = tapp->type;
53763670Snsayer 			ifp->if_baudrate = tapp->baudrate;
53863670Snsayer			splx(s);
53963670Snsayer 		break;
54063670Snsayer
54163670Snsayer	 	case TAPGIFINFO:
54263670Snsayer 			tapp = (struct tapinfo *)data;
54363670Snsayer 			tapp->mtu = ifp->if_mtu;
54463670Snsayer 			tapp->type = ifp->if_type;
54563670Snsayer 			tapp->baudrate = ifp->if_baudrate;
54663670Snsayer 		break;
54763670Snsayer
54863670Snsayer		case TAPSDEBUG:
54963670Snsayer			tapdebug = *(int *)data;
55063670Snsayer		break;
55163670Snsayer
55263670Snsayer		case TAPGDEBUG:
55363670Snsayer			*(int *)data = tapdebug;
55463670Snsayer		break;
55563670Snsayer
55663670Snsayer		case FIONBIO:
55763670Snsayer		break;
55863670Snsayer
55963670Snsayer		case FIOASYNC:
56063803Snsayer			s = splimp();
56163670Snsayer			if (*(int *)data)
56263670Snsayer				tp->tap_flags |= TAP_ASYNC;
56363670Snsayer			else
56463670Snsayer				tp->tap_flags &= ~TAP_ASYNC;
56563803Snsayer			splx(s);
56663670Snsayer		break;
56763670Snsayer
56863670Snsayer		case FIONREAD:
56963670Snsayer			s = splimp();
57063670Snsayer			if (ifp->if_snd.ifq_head) {
57163670Snsayer				struct mbuf	*mb = ifp->if_snd.ifq_head;
57263670Snsayer
57363803Snsayer				for(*(int *)data = 0;mb != NULL;mb = mb->m_next)
57463670Snsayer					*(int *)data += mb->m_len;
57563670Snsayer			}
57663670Snsayer			else
57763670Snsayer				*(int *)data = 0;
57863670Snsayer			splx(s);
57963670Snsayer		break;
58063670Snsayer
58163670Snsayer		case FIOSETOWN:
58263670Snsayer			return (fsetown(*(int *)data, &tp->tap_sigio));
58363670Snsayer
58463670Snsayer		case FIOGETOWN:
58563670Snsayer			*(int *)data = fgetown(tp->tap_sigio);
58663670Snsayer			return (0);
58763670Snsayer
58863670Snsayer		/* this is deprecated, FIOSETOWN should be used instead */
58963670Snsayer		case TIOCSPGRP:
59063670Snsayer			return (fsetown(-(*(int *)data), &tp->tap_sigio));
59163670Snsayer
59263670Snsayer		/* this is deprecated, FIOGETOWN should be used instead */
59363670Snsayer		case TIOCGPGRP:
59463670Snsayer			*(int *)data = -fgetown(tp->tap_sigio);
59563670Snsayer			return (0);
59663670Snsayer
59763670Snsayer		/* VMware/VMnet port ioctl's */
59863670Snsayer
59963670Snsayer		case SIOCGIFFLAGS:	/* get ifnet flags */
60063670Snsayer			bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags));
60163670Snsayer		break;
60263670Snsayer
60363670Snsayer		case VMIO_SIOCSIFFLAGS: { /* VMware/VMnet SIOCSIFFLAGS */
60463670Snsayer			short	f = *(short *)data;
60563670Snsayer
60663670Snsayer			f &= 0x0fff;
60763670Snsayer			f &= ~IFF_CANTCHANGE;
60863670Snsayer			f |= IFF_UP;
60963670Snsayer
61063670Snsayer			s = splimp();
61163670Snsayer			ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE);
61263670Snsayer			splx(s);
61363670Snsayer		} break;
61463670Snsayer
61563861Snsayer		case OSIOCGIFADDR:	/* get MAC address of the remote side */
61663670Snsayer		case SIOCGIFADDR:
61763861Snsayer			bcopy(tp->ether_addr, data, sizeof(tp->ether_addr));
61863670Snsayer		break;
61963670Snsayer
62063861Snsayer		case SIOCSIFADDR:	/* set MAC address of the remote side */
62163861Snsayer			bcopy(data, tp->ether_addr, sizeof(tp->ether_addr));
62263670Snsayer		break;
62363670Snsayer
62463670Snsayer		default:
62563670Snsayer			return (ENOTTY);
62663670Snsayer	}
62763670Snsayer	return (0);
62863670Snsayer} /* tapioctl */
62963670Snsayer
63063670Snsayer
63163670Snsayer/*
63263670Snsayer * tapread
63363670Snsayer *
63463670Snsayer * the cdevsw read interface - reads a packet at a time, or at
63563670Snsayer * least as much of a packet as can be read
63663670Snsayer */
63763670Snsayerstatic int
63863670Snsayertapread(dev, uio, flag)
63963670Snsayer	dev_t		 dev;
64063670Snsayer	struct uio	*uio;
64163670Snsayer	int		 flag;
64263670Snsayer{
64363670Snsayer	struct tap_softc	*tp = dev->si_drv1;
64463670Snsayer	struct ifnet		*ifp = &tp->tap_if;
64563670Snsayer	struct mbuf		*m = NULL, *m0 = NULL;
64663670Snsayer	int			 error = 0, len, s;
64763670Snsayer
64863803Snsayer	TAPDEBUG("%s%d reading, minor = %#x\n",
64963803Snsayer			ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
65063670Snsayer
65163670Snsayer	if ((tp->tap_flags & TAP_READY) != TAP_READY) {
65263803Snsayer		TAPDEBUG("%s%d not ready. minor = %#x, tap_flags = 0x%x\n",
65363803Snsayer				ifp->if_name, ifp->if_unit,
65463803Snsayer				minor(tp->tap_dev), tp->tap_flags);
65563803Snsayer
65663670Snsayer		return (EHOSTDOWN);
65763670Snsayer	}
65863670Snsayer
65963670Snsayer	tp->tap_flags &= ~TAP_RWAIT;
66063670Snsayer
66163670Snsayer	/* sleep until we get a packet */
66263670Snsayer	do {
66363670Snsayer		s = splimp();
66463670Snsayer		IF_DEQUEUE(&ifp->if_snd, m0);
66563670Snsayer		splx(s);
66663670Snsayer
66763670Snsayer		if (m0 == NULL) {
66863670Snsayer			if (flag & IO_NDELAY)
66963670Snsayer				return (EWOULDBLOCK);
67063670Snsayer
67163670Snsayer			tp->tap_flags |= TAP_RWAIT;
67263670Snsayer			error = tsleep((caddr_t)tp,PCATCH|(PZERO+1),"taprd",0);
67363670Snsayer			if (error)
67463670Snsayer				return (error);
67563670Snsayer		}
67663803Snsayer	} while (m0 == NULL);
67763670Snsayer
67863670Snsayer	/* feed packet to bpf */
67963670Snsayer	if (ifp->if_bpf != NULL)
68063670Snsayer		bpf_mtap(ifp, m0);
68163670Snsayer
68263670Snsayer	/* xfer packet to user space */
68363670Snsayer	while ((m0 != NULL) && (uio->uio_resid > 0) && (error == 0)) {
68463670Snsayer		len = min(uio->uio_resid, m0->m_len);
68563670Snsayer		if (len == 0)
68663670Snsayer			break;
68763670Snsayer
68863670Snsayer		error = uiomove(mtod(m0, caddr_t), len, uio);
68963670Snsayer		MFREE(m0, m);
69063670Snsayer		m0 = m;
69163670Snsayer	}
69263670Snsayer
69363670Snsayer	if (m0 != NULL) {
69463803Snsayer		TAPDEBUG("%s%d dropping mbuf, minor = %#x\n",
69563803Snsayer				ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
69663670Snsayer		m_freem(m0);
69763670Snsayer	}
69863670Snsayer
69963670Snsayer	return (error);
70063670Snsayer} /* tapread */
70163670Snsayer
70263670Snsayer
70363670Snsayer/*
70463670Snsayer * tapwrite
70563670Snsayer *
70663670Snsayer * the cdevsw write interface - an atomic write is a packet - or else!
70763670Snsayer */
70863670Snsayerstatic int
70963670Snsayertapwrite(dev, uio, flag)
71063670Snsayer	dev_t		 dev;
71163670Snsayer	struct uio	*uio;
71263670Snsayer	int		 flag;
71363670Snsayer{
71463670Snsayer	struct tap_softc	*tp = dev->si_drv1;
71563670Snsayer	struct ifnet		*ifp = &tp->tap_if;
71663670Snsayer	struct mbuf		*top = NULL, **mp = NULL, *m = NULL;
71763670Snsayer	struct ether_header	*eh = NULL;
71863670Snsayer	int		 	 error = 0, tlen, mlen;
71963670Snsayer
72063803Snsayer	TAPDEBUG("%s%d writting, minor = %#x\n",
72163803Snsayer				ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
72263670Snsayer
72363670Snsayer	if (uio->uio_resid == 0)
72463670Snsayer		return (0);
72563670Snsayer
72663670Snsayer	if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) {
72763803Snsayer		TAPDEBUG("%s%d invalid packet len = %d, minor = %#x\n",
72863803Snsayer				ifp->if_name, ifp->if_unit,
72963803Snsayer				uio->uio_resid, minor(tp->tap_dev));
73063803Snsayer
73163670Snsayer		return (EIO);
73263670Snsayer	}
73363670Snsayer	tlen = uio->uio_resid;
73463670Snsayer
73563670Snsayer	/* get a header mbuf */
73663670Snsayer	MGETHDR(m, M_DONTWAIT, MT_DATA);
73763670Snsayer	if (m == NULL)
73863670Snsayer		return (ENOBUFS);
73963670Snsayer	mlen = MHLEN;
74063670Snsayer
74163670Snsayer	top = 0;
74263670Snsayer	mp = &top;
74363670Snsayer	while ((error == 0) && (uio->uio_resid > 0)) {
74463670Snsayer		m->m_len = min(mlen, uio->uio_resid);
74563670Snsayer		error = uiomove(mtod(m, caddr_t), m->m_len, uio);
74663670Snsayer		*mp = m;
74763670Snsayer		mp = &m->m_next;
74863670Snsayer		if (uio->uio_resid > 0) {
74963670Snsayer			MGET(m, M_DONTWAIT, MT_DATA);
75063803Snsayer			if (m == NULL) {
75163670Snsayer				error = ENOBUFS;
75263670Snsayer				break;
75363670Snsayer			}
75463670Snsayer			mlen = MLEN;
75563670Snsayer		}
75663670Snsayer	}
75763670Snsayer	if (error) {
75863670Snsayer		ifp->if_ierrors ++;
75963670Snsayer		if (top)
76063670Snsayer			m_freem(top);
76163670Snsayer		return (error);
76263670Snsayer	}
76363670Snsayer
76463670Snsayer	top->m_pkthdr.len = tlen;
76563670Snsayer	top->m_pkthdr.rcvif = ifp;
76663670Snsayer
76763670Snsayer	/*
76863670Snsayer	 * Ethernet bridge and bpf are handled in ether_input
76963670Snsayer	 *
77063670Snsayer	 * adjust mbuf and give packet to the ether_input
77163670Snsayer	 */
77263670Snsayer
77363670Snsayer	eh = mtod(top, struct ether_header *);
77463670Snsayer	m_adj(top, sizeof(struct ether_header));
77563670Snsayer	ether_input(ifp, eh, top);
77663670Snsayer	ifp->if_ipackets ++; /* ibytes are counted in ether_input */
77763670Snsayer
77863670Snsayer	return (0);
77963670Snsayer} /* tapwrite */
78063670Snsayer
78163670Snsayer
78263670Snsayer/*
78363670Snsayer * tappoll
78463670Snsayer *
78563670Snsayer * the poll interface, this is only useful on reads
78663670Snsayer * really. the write detect always returns true, write never blocks
78763670Snsayer * anyway, it either accepts the packet or drops it
78863670Snsayer */
78963670Snsayerstatic int
79063670Snsayertappoll(dev, events, p)
79163670Snsayer	dev_t		 dev;
79263670Snsayer	int		 events;
79363670Snsayer	struct proc	*p;
79463670Snsayer{
79563670Snsayer	struct tap_softc	*tp = dev->si_drv1;
79663670Snsayer	struct ifnet		*ifp = &tp->tap_if;
79763670Snsayer	int		 	 s, revents = 0;
79863670Snsayer
79963803Snsayer	TAPDEBUG("%s%d polling, minor = %#x\n",
80063803Snsayer				ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
80163670Snsayer
80263670Snsayer	s = splimp();
80363670Snsayer	if (events & (POLLIN | POLLRDNORM)) {
80463670Snsayer		if (ifp->if_snd.ifq_len > 0) {
80563803Snsayer			TAPDEBUG("%s%d have data in queue. len = %d, " \
80663803Snsayer				"minor = %#x\n", ifp->if_name, ifp->if_unit,
80763803Snsayer				ifp->if_snd.ifq_len, minor(tp->tap_dev));
80863803Snsayer
80963670Snsayer			revents |= (events & (POLLIN | POLLRDNORM));
81063670Snsayer		}
81163670Snsayer		else {
81263803Snsayer			TAPDEBUG("%s%d waiting for data, minor = %#x\n",
81363803Snsayer				ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
81463803Snsayer
81563670Snsayer			selrecord(p, &tp->tap_rsel);
81663670Snsayer		}
81763670Snsayer	}
81863670Snsayer
81963670Snsayer	if (events & (POLLOUT | POLLWRNORM))
82063670Snsayer		revents |= (events & (POLLOUT | POLLWRNORM));
82163670Snsayer
82263670Snsayer	splx(s);
82363670Snsayer	return (revents);
82463670Snsayer} /* tappoll */
825