if_tap.c revision 205222
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 205222 2010-03-16 17:59:12Z qingli $
3563803Snsayer * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $
3663670Snsayer */
3763670Snsayer
38162711Sru#include "opt_compat.h"
3963670Snsayer#include "opt_inet.h"
4063670Snsayer
4163670Snsayer#include <sys/param.h>
4263670Snsayer#include <sys/conf.h>
43139207Sphk#include <sys/fcntl.h>
4463670Snsayer#include <sys/filio.h>
4563670Snsayer#include <sys/kernel.h>
4663670Snsayer#include <sys/malloc.h>
4763670Snsayer#include <sys/mbuf.h>
48129880Sphk#include <sys/module.h>
4963670Snsayer#include <sys/poll.h>
50164033Srwatson#include <sys/priv.h>
5163670Snsayer#include <sys/proc.h>
52139207Sphk#include <sys/selinfo.h>
5363670Snsayer#include <sys/signalvar.h>
5463670Snsayer#include <sys/socket.h>
5563670Snsayer#include <sys/sockio.h>
5663670Snsayer#include <sys/sysctl.h>
5763670Snsayer#include <sys/systm.h>
5863670Snsayer#include <sys/ttycom.h>
5963670Snsayer#include <sys/uio.h>
6083043Sbrooks#include <sys/queue.h>
6163670Snsayer
6263670Snsayer#include <net/bpf.h>
6363670Snsayer#include <net/ethernet.h>
6463670Snsayer#include <net/if.h>
65166497Sbms#include <net/if_clone.h>
66152315Sru#include <net/if_dl.h>
6763670Snsayer#include <net/route.h>
68147256Sbrooks#include <net/if_types.h>
6963670Snsayer
7063670Snsayer#include <netinet/in.h>
7163670Snsayer
7263670Snsayer#include <net/if_tapvar.h>
7363670Snsayer#include <net/if_tap.h>
7463670Snsayer
7563670Snsayer
7663670Snsayer#define CDEV_NAME	"tap"
7763670Snsayer#define TAPDEBUG	if (tapdebug) printf
7863670Snsayer
7963670Snsayer#define TAP		"tap"
8063670Snsayer#define VMNET		"vmnet"
8183043Sbrooks#define TAPMAXUNIT	0x7fff
82126077Sphk#define VMNET_DEV_MASK	CLONE_FLAG0
8363670Snsayer
8463670Snsayer/* module */
85111742Sdesstatic int		tapmodevent(module_t, int, void *);
8663670Snsayer
8763670Snsayer/* device */
88148868Srwatsonstatic void		tapclone(void *, struct ucred *, char *, int,
89148868Srwatson			    struct cdev **);
90130585Sphkstatic void		tapcreate(struct cdev *);
9163670Snsayer
9263670Snsayer/* network interface */
9393084Sbdestatic void		tapifstart(struct ifnet *);
9493084Sbdestatic int		tapifioctl(struct ifnet *, u_long, caddr_t);
9593084Sbdestatic void		tapifinit(void *);
9663670Snsayer
97166497Sbmsstatic int		tap_clone_create(struct if_clone *, int, caddr_t);
98166497Sbmsstatic void		tap_clone_destroy(struct ifnet *);
99166497Sbmsstatic int		vmnet_clone_create(struct if_clone *, int, caddr_t);
100166497Sbmsstatic void		vmnet_clone_destroy(struct ifnet *);
101166497Sbms
102166497SbmsIFC_SIMPLE_DECLARE(tap, 0);
103166497SbmsIFC_SIMPLE_DECLARE(vmnet, 0);
104166497Sbms
10563670Snsayer/* character device */
10663670Snsayerstatic d_open_t		tapopen;
10763670Snsayerstatic d_close_t	tapclose;
10863670Snsayerstatic d_read_t		tapread;
10963670Snsayerstatic d_write_t	tapwrite;
11063670Snsayerstatic d_ioctl_t	tapioctl;
11163670Snsayerstatic d_poll_t		tappoll;
112156783Semaxstatic d_kqfilter_t	tapkqfilter;
11363670Snsayer
114156783Semax/* kqueue(2) */
115156783Semaxstatic int		tapkqread(struct knote *, long);
116156783Semaxstatic int		tapkqwrite(struct knote *, long);
117156783Semaxstatic void		tapkqdetach(struct knote *);
118156783Semax
119156783Semaxstatic struct filterops	tap_read_filterops = {
120156783Semax	.f_isfd =	1,
121156783Semax	.f_attach =	NULL,
122156783Semax	.f_detach =	tapkqdetach,
123156783Semax	.f_event =	tapkqread,
124156783Semax};
125156783Semax
126156783Semaxstatic struct filterops	tap_write_filterops = {
127156783Semax	.f_isfd =	1,
128156783Semax	.f_attach =	NULL,
129156783Semax	.f_detach =	tapkqdetach,
130156783Semax	.f_event =	tapkqwrite,
131156783Semax};
132156783Semax
13363670Snsayerstatic struct cdevsw	tap_cdevsw = {
134126080Sphk	.d_version =	D_VERSION,
135179726Sed	.d_flags =	D_PSEUDO | D_NEEDGIANT | D_NEEDMINOR,
136111815Sphk	.d_open =	tapopen,
137111815Sphk	.d_close =	tapclose,
138111815Sphk	.d_read =	tapread,
139111815Sphk	.d_write =	tapwrite,
140111815Sphk	.d_ioctl =	tapioctl,
141111815Sphk	.d_poll =	tappoll,
142111815Sphk	.d_name =	CDEV_NAME,
143156783Semax	.d_kqfilter =	tapkqfilter,
14463670Snsayer};
14563670Snsayer
146127003Srwatson/*
147127003Srwatson * All global variables in if_tap.c are locked with tapmtx, with the
148127003Srwatson * exception of tapdebug, which is accessed unlocked; tapclones is
149127003Srwatson * static at runtime.
150127003Srwatson */
151127003Srwatsonstatic struct mtx		tapmtx;
15283043Sbrooksstatic int			tapdebug = 0;        /* debug flag   */
153167713Sbmsstatic int			tapuopen = 0;        /* allow user open() */
154167713Sbmsstatic int			tapuponopen = 0;    /* IFF_UP on open() */
155166497Sbmsstatic int			tapdclone = 1;	/* enable devfs cloning */
15683043Sbrooksstatic SLIST_HEAD(, tap_softc)	taphead;             /* first device */
157126077Sphkstatic struct clonedevs 	*tapclones;
15863670Snsayer
15963670SnsayerMALLOC_DECLARE(M_TAP);
16063670SnsayerMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface");
16163670SnsayerSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, "");
162144979Smdodd
163144979SmdoddSYSCTL_DECL(_net_link);
164144979SmdoddSYSCTL_NODE(_net_link, OID_AUTO, tap, CTLFLAG_RW, 0,
165144979Smdodd    "Ethernet tunnel software network interface");
166144979SmdoddSYSCTL_INT(_net_link_tap, OID_AUTO, user_open, CTLFLAG_RW, &tapuopen, 0,
167144979Smdodd	"Allow user to open /dev/tap (based on node permissions)");
168167713SbmsSYSCTL_INT(_net_link_tap, OID_AUTO, up_on_open, CTLFLAG_RW, &tapuponopen, 0,
169167713Sbms	"Bring interface up when /dev/tap is opened");
170166497SbmsSYSCTL_INT(_net_link_tap, OID_AUTO, devfs_cloning, CTLFLAG_RW, &tapdclone, 0,
171166497Sbms	"Enably legacy devfs interface creation");
172144979SmdoddSYSCTL_INT(_net_link_tap, OID_AUTO, debug, CTLFLAG_RW, &tapdebug, 0, "");
173144979Smdodd
174166497SbmsTUNABLE_INT("net.link.tap.devfs_cloning", &tapdclone);
175166497Sbms
17663670SnsayerDEV_MODULE(if_tap, tapmodevent, NULL);
17763670Snsayer
178166497Sbmsstatic int
179166497Sbmstap_clone_create(struct if_clone *ifc, int unit, caddr_t params)
180166497Sbms{
181166497Sbms	struct cdev *dev;
182166497Sbms	int i;
183166497Sbms	int extra;
184166497Sbms
185166497Sbms	if (strcmp(ifc->ifc_name, VMNET) == 0)
186166497Sbms		extra = VMNET_DEV_MASK;
187166497Sbms	else
188166497Sbms		extra = 0;
189166497Sbms
190166497Sbms	/* find any existing device, or allocate new unit number */
191166497Sbms	i = clone_create(&tapclones, &tap_cdevsw, &unit, &dev, extra);
192166497Sbms	if (i) {
193183381Sed		dev = make_dev(&tap_cdevsw, unit | extra,
194166497Sbms		     UID_ROOT, GID_WHEEL, 0600, "%s%d", ifc->ifc_name, unit);
195166497Sbms	}
196166497Sbms
197166497Sbms	tapcreate(dev);
198166497Sbms	return (0);
199166497Sbms}
200166497Sbms
201166497Sbms/* vmnet devices are tap devices in disguise */
202166497Sbmsstatic int
203166497Sbmsvmnet_clone_create(struct if_clone *ifc, int unit, caddr_t params)
204166497Sbms{
205166497Sbms	return tap_clone_create(ifc, unit, params);
206166497Sbms}
207166497Sbms
208166497Sbmsstatic void
209166497Sbmstap_destroy(struct tap_softc *tp)
210166497Sbms{
211166497Sbms	struct ifnet *ifp = tp->tap_ifp;
212166497Sbms	int s;
213166497Sbms
214166497Sbms	/* Unlocked read. */
215166497Sbms	KASSERT(!(tp->tap_flags & TAP_OPEN),
216166497Sbms		("%s flags is out of sync", ifp->if_xname));
217166497Sbms
218166497Sbms	knlist_destroy(&tp->tap_rsel.si_note);
219166497Sbms	destroy_dev(tp->tap_dev);
220166497Sbms	s = splimp();
221166497Sbms	ether_ifdetach(ifp);
222166497Sbms	if_free_type(ifp, IFT_ETHER);
223166497Sbms	splx(s);
224166497Sbms
225166497Sbms	mtx_destroy(&tp->tap_mtx);
226166497Sbms	free(tp, M_TAP);
227166497Sbms}
228166497Sbms
229166497Sbmsstatic void
230166497Sbmstap_clone_destroy(struct ifnet *ifp)
231166497Sbms{
232166497Sbms	struct tap_softc *tp = ifp->if_softc;
233166497Sbms
234166497Sbms	mtx_lock(&tapmtx);
235166497Sbms	SLIST_REMOVE(&taphead, tp, tap_softc, tap_next);
236166497Sbms	mtx_unlock(&tapmtx);
237166497Sbms	tap_destroy(tp);
238166497Sbms}
239166497Sbms
240166497Sbms/* vmnet devices are tap devices in disguise */
241166497Sbmsstatic void
242166497Sbmsvmnet_clone_destroy(struct ifnet *ifp)
243166497Sbms{
244166497Sbms	tap_clone_destroy(ifp);
245166497Sbms}
246166497Sbms
24763670Snsayer/*
24863670Snsayer * tapmodevent
24963670Snsayer *
25063670Snsayer * module event handler
25163670Snsayer */
25263670Snsayerstatic int
253156783Semaxtapmodevent(module_t mod, int type, void *data)
25463670Snsayer{
25583043Sbrooks	static eventhandler_tag	 eh_tag = NULL;
25683043Sbrooks	struct tap_softc	*tp = NULL;
25783043Sbrooks	struct ifnet		*ifp = NULL;
25863670Snsayer
25963670Snsayer	switch (type) {
26063670Snsayer	case MOD_LOAD:
26163670Snsayer
26283043Sbrooks		/* intitialize device */
26383043Sbrooks
264127003Srwatson		mtx_init(&tapmtx, "tapmtx", NULL, MTX_DEF);
26583043Sbrooks		SLIST_INIT(&taphead);
26683043Sbrooks
267126845Sphk		clone_setup(&tapclones);
26871602Sphk		eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000);
269127003Srwatson		if (eh_tag == NULL) {
270127170Srwatson			clone_cleanup(&tapclones);
271127003Srwatson			mtx_destroy(&tapmtx);
272126077Sphk			return (ENOMEM);
273127003Srwatson		}
274166497Sbms		if_clone_attach(&tap_cloner);
275166497Sbms		if_clone_attach(&vmnet_cloner);
27683043Sbrooks		return (0);
27763670Snsayer
27883043Sbrooks	case MOD_UNLOAD:
279127003Srwatson		/*
280127003Srwatson		 * The EBUSY algorithm here can't quite atomically
281127003Srwatson		 * guarantee that this is race-free since we have to
282127003Srwatson		 * release the tap mtx to deregister the clone handler.
283127003Srwatson		 */
284127003Srwatson		mtx_lock(&tapmtx);
285127003Srwatson		SLIST_FOREACH(tp, &taphead, tap_next) {
286127098Srwatson			mtx_lock(&tp->tap_mtx);
287127003Srwatson			if (tp->tap_flags & TAP_OPEN) {
288127098Srwatson				mtx_unlock(&tp->tap_mtx);
289127003Srwatson				mtx_unlock(&tapmtx);
29083043Sbrooks				return (EBUSY);
291127003Srwatson			}
292127098Srwatson			mtx_unlock(&tp->tap_mtx);
293127003Srwatson		}
294127003Srwatson		mtx_unlock(&tapmtx);
29583043Sbrooks
29671602Sphk		EVENTHANDLER_DEREGISTER(dev_clone, eh_tag);
297166497Sbms		if_clone_detach(&tap_cloner);
298166497Sbms		if_clone_detach(&vmnet_cloner);
299204464Skib		drain_dev_clone_events();
30063670Snsayer
301127003Srwatson		mtx_lock(&tapmtx);
30283043Sbrooks		while ((tp = SLIST_FIRST(&taphead)) != NULL) {
30383043Sbrooks			SLIST_REMOVE_HEAD(&taphead, tap_next);
304127003Srwatson			mtx_unlock(&tapmtx);
30583043Sbrooks
306147256Sbrooks			ifp = tp->tap_ifp;
30783043Sbrooks
308121816Sbrooks			TAPDEBUG("detaching %s\n", ifp->if_xname);
30983043Sbrooks
310166497Sbms			tap_destroy(tp);
311127003Srwatson			mtx_lock(&tapmtx);
31283043Sbrooks		}
313127003Srwatson		mtx_unlock(&tapmtx);
314126077Sphk		clone_cleanup(&tapclones);
31563670Snsayer
316135354Srwatson		mtx_destroy(&tapmtx);
317135354Srwatson
31883043Sbrooks		break;
31963670Snsayer
32063670Snsayer	default:
32163670Snsayer		return (EOPNOTSUPP);
32263670Snsayer	}
32363670Snsayer
32463670Snsayer	return (0);
32563670Snsayer} /* tapmodevent */
32663670Snsayer
32763670Snsayer
32863670Snsayer/*
32971602Sphk * DEVFS handler
33071602Sphk *
33171602Sphk * We need to support two kind of devices - tap and vmnet
33271602Sphk */
33371602Sphkstatic void
334156783Semaxtapclone(void *arg, struct ucred *cred, char *name, int namelen, struct cdev **dev)
33571602Sphk{
336166497Sbms	char		devname[SPECNAMELEN + 1];
337166497Sbms	int		i, unit, append_unit;
338166438Sbms	int		extra;
33971602Sphk
340130640Sphk	if (*dev != NULL)
34171602Sphk		return;
34271602Sphk
343166514Sbms	if (!tapdclone ||
344166514Sbms	    (!tapuopen && priv_check_cred(cred, PRIV_NET_IFCREATE, 0) != 0))
345166497Sbms		return;
346166497Sbms
347166497Sbms	unit = 0;
348166497Sbms	append_unit = 0;
349126077Sphk	extra = 0;
350166497Sbms
351166497Sbms	/* We're interested in only tap/vmnet devices. */
352126077Sphk	if (strcmp(name, TAP) == 0) {
353126077Sphk		unit = -1;
354126077Sphk	} else if (strcmp(name, VMNET) == 0) {
355126077Sphk		unit = -1;
356126077Sphk		extra = VMNET_DEV_MASK;
357166497Sbms	} else if (dev_stdclone(name, NULL, TAP, &unit) != 1) {
358166497Sbms		if (dev_stdclone(name, NULL, VMNET, &unit) != 1) {
359126077Sphk			return;
360166497Sbms		} else {
361166497Sbms			extra = VMNET_DEV_MASK;
362166497Sbms		}
36383043Sbrooks	}
36471602Sphk
365166497Sbms	if (unit == -1)
366166497Sbms		append_unit = 1;
367166497Sbms
368126077Sphk	/* find any existing device, or allocate new unit number */
369126077Sphk	i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra);
370126077Sphk	if (i) {
371166497Sbms		if (append_unit) {
372166497Sbms			/*
373166497Sbms			 * We were passed 'tun' or 'tap', with no unit specified
374166497Sbms			 * so we'll need to append it now.
375166497Sbms			 */
376166497Sbms			namelen = snprintf(devname, sizeof(devname), "%s%d", name,
377166497Sbms			    unit);
378166497Sbms			name = devname;
379166497Sbms		}
380166497Sbms
381204464Skib		*dev = make_dev_credf(MAKEDEV_REF, &tap_cdevsw, unit | extra,
382204464Skib		     cred, UID_ROOT, GID_WHEEL, 0600, "%s", name);
38371602Sphk	}
384166497Sbms
385166497Sbms	if_clone_create(name, namelen, NULL);
38671602Sphk} /* tapclone */
38771602Sphk
38871602Sphk
38971602Sphk/*
39063670Snsayer * tapcreate
39163670Snsayer *
39263670Snsayer * to create interface
39363670Snsayer */
39463670Snsayerstatic void
395156783Semaxtapcreate(struct cdev *dev)
39663670Snsayer{
39763670Snsayer	struct ifnet		*ifp = NULL;
39863670Snsayer	struct tap_softc	*tp = NULL;
39963670Snsayer	unsigned short		 macaddr_hi;
400178221Semax	uint32_t		 macaddr_mid;
40163803Snsayer	int			 unit, s;
40263670Snsayer	char			*name = NULL;
403147256Sbrooks	u_char			eaddr[6];
40463670Snsayer
405126077Sphk	dev->si_flags &= ~SI_CHEAPCLONE;
406126077Sphk
40763670Snsayer	/* allocate driver storage and create device */
408184205Sdes	tp = malloc(sizeof(*tp), M_TAP, M_WAITOK | M_ZERO);
409127098Srwatson	mtx_init(&tp->tap_mtx, "tap_mtx", NULL, MTX_DEF);
410127003Srwatson	mtx_lock(&tapmtx);
41183043Sbrooks	SLIST_INSERT_HEAD(&taphead, tp, tap_next);
412127003Srwatson	mtx_unlock(&tapmtx);
41363670Snsayer
414126796Sphk	unit = dev2unit(dev);
41583043Sbrooks
41663670Snsayer	/* select device: tap or vmnet */
417126796Sphk	if (unit & VMNET_DEV_MASK) {
41863670Snsayer		name = VMNET;
41963803Snsayer		tp->tap_flags |= TAP_VMNET;
42083043Sbrooks	} else
42163670Snsayer		name = TAP;
42263670Snsayer
423126796Sphk	unit &= TAPMAXUNIT;
424126796Sphk
425183397Sed	TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, dev2unit(dev));
42683043Sbrooks
42763670Snsayer	/* generate fake MAC address: 00 bd xx xx xx unit_no */
42863670Snsayer	macaddr_hi = htons(0x00bd);
429178221Semax	macaddr_mid = (uint32_t) ticks;
430147256Sbrooks	bcopy(&macaddr_hi, eaddr, sizeof(short));
431178221Semax	bcopy(&macaddr_mid, &eaddr[2], sizeof(uint32_t));
432147256Sbrooks	eaddr[5] = (u_char)unit;
43363670Snsayer
434111742Sdes	/* fill the rest and attach interface */
435147256Sbrooks	ifp = tp->tap_ifp = if_alloc(IFT_ETHER);
436147256Sbrooks	if (ifp == NULL)
437147256Sbrooks		panic("%s%d: can not if_alloc()", name, unit);
43863670Snsayer	ifp->if_softc = tp;
439121816Sbrooks	if_initname(ifp, name, unit);
44063670Snsayer	ifp->if_init = tapifinit;
44163670Snsayer	ifp->if_start = tapifstart;
44263670Snsayer	ifp->if_ioctl = tapifioctl;
44363670Snsayer	ifp->if_mtu = ETHERMTU;
44463670Snsayer	ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
44563670Snsayer	ifp->if_snd.ifq_maxlen = ifqmaxlen;
446205222Sqingli	ifp->if_capabilities |= IFCAP_LINKSTATE;
447205222Sqingli	ifp->if_capenable |= IFCAP_LINKSTATE;
44863670Snsayer
44983043Sbrooks	dev->si_drv1 = tp;
450126077Sphk	tp->tap_dev = dev;
45183043Sbrooks
45263803Snsayer	s = splimp();
453147256Sbrooks	ether_ifattach(ifp, eaddr);
45463803Snsayer	splx(s);
45563670Snsayer
456127098Srwatson	mtx_lock(&tp->tap_mtx);
45763803Snsayer	tp->tap_flags |= TAP_INITED;
458127098Srwatson	mtx_unlock(&tp->tap_mtx);
45963803Snsayer
460193951Skib	knlist_init_mtx(&tp->tap_rsel.si_note, NULL);
461158697Semax
462121816Sbrooks	TAPDEBUG("interface %s is created. minor = %#x\n",
463183397Sed		ifp->if_xname, dev2unit(dev));
46463670Snsayer} /* tapcreate */
46563670Snsayer
46663670Snsayer
46763670Snsayer/*
468111742Sdes * tapopen
46963670Snsayer *
47063670Snsayer * to open tunnel. must be superuser
47163670Snsayer */
47263670Snsayerstatic int
473156783Semaxtapopen(struct cdev *dev, int flag, int mode, struct thread *td)
47463670Snsayer{
47563670Snsayer	struct tap_softc	*tp = NULL;
476133460Semax	struct ifnet		*ifp = NULL;
477164033Srwatson	int			 error, s;
47863670Snsayer
479164033Srwatson	if (tapuopen == 0) {
480164033Srwatson		error = priv_check(td, PRIV_NET_TAP);
481164033Srwatson		if (error)
482164033Srwatson			return (error);
483164033Srwatson	}
48463670Snsayer
485126796Sphk	if ((dev2unit(dev) & CLONE_UNITMASK) > TAPMAXUNIT)
486126796Sphk		return (ENXIO);
48783043Sbrooks
48863670Snsayer	tp = dev->si_drv1;
48963670Snsayer
490127165Srwatson	mtx_lock(&tp->tap_mtx);
491127165Srwatson	if (tp->tap_flags & TAP_OPEN) {
492127165Srwatson		mtx_unlock(&tp->tap_mtx);
493127165Srwatson		return (EBUSY);
494127165Srwatson	}
49563670Snsayer
496152315Sru	bcopy(IF_LLADDR(tp->tap_ifp), tp->ether_addr, sizeof(tp->ether_addr));
49783366Sjulian	tp->tap_pid = td->td_proc->p_pid;
49863670Snsayer	tp->tap_flags |= TAP_OPEN;
499147256Sbrooks	ifp = tp->tap_ifp;
500127098Srwatson	mtx_unlock(&tp->tap_mtx);
50163670Snsayer
502133460Semax	s = splimp();
503148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
504148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
505167713Sbms	if (tapuponopen)
506167713Sbms		ifp->if_flags |= IFF_UP;
507205024Sqingli	if_link_state_change(ifp, LINK_STATE_UP);
508133460Semax	splx(s);
50963670Snsayer
510183397Sed	TAPDEBUG("%s is open. minor = %#x\n", ifp->if_xname, dev2unit(dev));
511133460Semax
51263670Snsayer	return (0);
51363670Snsayer} /* tapopen */
51463670Snsayer
51563670Snsayer
51663670Snsayer/*
51763670Snsayer * tapclose
51863670Snsayer *
51963670Snsayer * close the device - mark i/f down & delete routing info
52063670Snsayer */
52163670Snsayerstatic int
522156783Semaxtapclose(struct cdev *dev, int foo, int bar, struct thread *td)
52363670Snsayer{
524156783Semax	struct ifaddr		*ifa;
52563670Snsayer	struct tap_softc	*tp = dev->si_drv1;
526147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
527126077Sphk	int			s;
52863670Snsayer
52963670Snsayer	/* junk all pending output */
53083043Sbrooks	IF_DRAIN(&ifp->if_snd);
53163670Snsayer
53263803Snsayer	/*
53363803Snsayer	 * do not bring the interface down, and do not anything with
53463803Snsayer	 * interface, if we are in VMnet mode. just close the device.
53563803Snsayer	 */
53663803Snsayer
537127098Srwatson	mtx_lock(&tp->tap_mtx);
53863803Snsayer	if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) {
539127098Srwatson		mtx_unlock(&tp->tap_mtx);
54063670Snsayer		s = splimp();
54163670Snsayer		if_down(ifp);
542148887Srwatson		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
54363803Snsayer			TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
544146620Speadar				rtinit(ifa, (int)RTM_DELETE, 0);
54563670Snsayer			}
546146620Speadar			if_purgeaddrs(ifp);
547148887Srwatson			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
54863670Snsayer		}
54963670Snsayer		splx(s);
550127098Srwatson	} else
551127098Srwatson		mtx_unlock(&tp->tap_mtx);
55263670Snsayer
553205024Sqingli	if_link_state_change(ifp, LINK_STATE_DOWN);
55496122Salfred	funsetown(&tp->tap_sigio);
555122352Stanimura	selwakeuppri(&tp->tap_rsel, PZERO+1);
556156783Semax	KNOTE_UNLOCKED(&tp->tap_rsel.si_note, 0);
55763670Snsayer
558127098Srwatson	mtx_lock(&tp->tap_mtx);
55963670Snsayer	tp->tap_flags &= ~TAP_OPEN;
56063670Snsayer	tp->tap_pid = 0;
561127098Srwatson	mtx_unlock(&tp->tap_mtx);
56263670Snsayer
563121816Sbrooks	TAPDEBUG("%s is closed. minor = %#x\n",
564183397Sed		ifp->if_xname, dev2unit(dev));
56563670Snsayer
56663670Snsayer	return (0);
56763670Snsayer} /* tapclose */
56863670Snsayer
56963670Snsayer
57063670Snsayer/*
57163670Snsayer * tapifinit
57263670Snsayer *
57363670Snsayer * network interface initialization function
57463670Snsayer */
57563670Snsayerstatic void
576156783Semaxtapifinit(void *xtp)
57763670Snsayer{
57863670Snsayer	struct tap_softc	*tp = (struct tap_softc *)xtp;
579147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
58063670Snsayer
581121816Sbrooks	TAPDEBUG("initializing %s\n", ifp->if_xname);
58263670Snsayer
583148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
584148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
58563670Snsayer
58663670Snsayer	/* attempt to start output */
58763670Snsayer	tapifstart(ifp);
58863670Snsayer} /* tapifinit */
58963670Snsayer
59063670Snsayer
59163670Snsayer/*
59263670Snsayer * tapifioctl
59363670Snsayer *
59463670Snsayer * Process an ioctl request on network interface
59563670Snsayer */
596105228Sphkstatic int
597156783Semaxtapifioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
59863670Snsayer{
599160376Sbrooks	struct tap_softc	*tp = ifp->if_softc;
600189866Sscf	struct ifreq		*ifr = (struct ifreq *)data;
60163670Snsayer	struct ifstat		*ifs = NULL;
60263670Snsayer	int			 s, dummy;
60363670Snsayer
60463670Snsayer	switch (cmd) {
60563670Snsayer		case SIOCSIFFLAGS: /* XXX -- just like vmnet does */
60663670Snsayer		case SIOCADDMULTI:
60763670Snsayer		case SIOCDELMULTI:
60883043Sbrooks			break;
60963670Snsayer
610189866Sscf		case SIOCSIFMTU:
611189866Sscf			ifp->if_mtu = ifr->ifr_mtu;
612189866Sscf			break;
613189866Sscf
61463670Snsayer		case SIOCGIFSTATUS:
61563670Snsayer			s = splimp();
61663670Snsayer			ifs = (struct ifstat *)data;
61763670Snsayer			dummy = strlen(ifs->ascii);
618127098Srwatson			mtx_lock(&tp->tap_mtx);
61963670Snsayer			if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii))
62063670Snsayer				snprintf(ifs->ascii + dummy,
62163670Snsayer					sizeof(ifs->ascii) - dummy,
62263670Snsayer					"\tOpened by PID %d\n", tp->tap_pid);
623127098Srwatson			mtx_unlock(&tp->tap_mtx);
62463670Snsayer			splx(s);
62583043Sbrooks			break;
62663670Snsayer
62763670Snsayer		default:
628106939Ssam			s = splimp();
629106939Ssam			dummy = ether_ioctl(ifp, cmd, data);
630106939Ssam			splx(s);
631106939Ssam			return (dummy);
632156783Semax			/* NOT REACHED */
63363670Snsayer	}
63463670Snsayer
63563670Snsayer	return (0);
63663670Snsayer} /* tapifioctl */
63763670Snsayer
63863670Snsayer
63963670Snsayer/*
640111742Sdes * tapifstart
641111742Sdes *
64263670Snsayer * queue packets from higher level ready to put out
64363670Snsayer */
64463670Snsayerstatic void
645156783Semaxtapifstart(struct ifnet *ifp)
64663670Snsayer{
64763670Snsayer	struct tap_softc	*tp = ifp->if_softc;
64863670Snsayer	int			 s;
64963670Snsayer
650121816Sbrooks	TAPDEBUG("%s starting\n", ifp->if_xname);
65163670Snsayer
65263803Snsayer	/*
65363803Snsayer	 * do not junk pending output if we are in VMnet mode.
65463803Snsayer	 * XXX: can this do any harm because of queue overflow?
65563803Snsayer	 */
65663803Snsayer
657127098Srwatson	mtx_lock(&tp->tap_mtx);
658111742Sdes	if (((tp->tap_flags & TAP_VMNET) == 0) &&
65963803Snsayer	    ((tp->tap_flags & TAP_READY) != TAP_READY)) {
66063670Snsayer		struct mbuf	*m = NULL;
66163670Snsayer
662127098Srwatson		mtx_unlock(&tp->tap_mtx);
663127098Srwatson
664127098Srwatson		/* Unlocked read. */
665121816Sbrooks		TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname,
666121816Sbrooks		    tp->tap_flags);
66763670Snsayer
66863670Snsayer		s = splimp();
66963670Snsayer		do {
67063670Snsayer			IF_DEQUEUE(&ifp->if_snd, m);
67163670Snsayer			if (m != NULL)
67263670Snsayer				m_freem(m);
67363670Snsayer			ifp->if_oerrors ++;
67463670Snsayer		} while (m != NULL);
67563670Snsayer		splx(s);
67663670Snsayer
67763670Snsayer		return;
67863670Snsayer	}
679127098Srwatson	mtx_unlock(&tp->tap_mtx);
68063670Snsayer
68163670Snsayer	s = splimp();
682148887Srwatson	ifp->if_drv_flags |= IFF_DRV_OACTIVE;
68363670Snsayer
68463670Snsayer	if (ifp->if_snd.ifq_len != 0) {
685127098Srwatson		mtx_lock(&tp->tap_mtx);
68663670Snsayer		if (tp->tap_flags & TAP_RWAIT) {
68763670Snsayer			tp->tap_flags &= ~TAP_RWAIT;
688111748Sdes			wakeup(tp);
68963670Snsayer		}
69063670Snsayer
691127098Srwatson		if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) {
692127098Srwatson			mtx_unlock(&tp->tap_mtx);
69395883Salfred			pgsigio(&tp->tap_sigio, SIGIO, 0);
694127098Srwatson		} else
695127098Srwatson			mtx_unlock(&tp->tap_mtx);
69663670Snsayer
697122352Stanimura		selwakeuppri(&tp->tap_rsel, PZERO+1);
698156783Semax		KNOTE_UNLOCKED(&tp->tap_rsel.si_note, 0);
69963670Snsayer		ifp->if_opackets ++; /* obytes are counted in ether_output */
70063670Snsayer	}
70163670Snsayer
702148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
70363670Snsayer	splx(s);
70463670Snsayer} /* tapifstart */
70563670Snsayer
70663670Snsayer
70763670Snsayer/*
70863670Snsayer * tapioctl
70963670Snsayer *
71063670Snsayer * the cdevsw interface is now pretty minimal
71163670Snsayer */
71263670Snsayerstatic int
713156783Semaxtapioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
71463670Snsayer{
71563670Snsayer	struct tap_softc	*tp = dev->si_drv1;
716147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
717111742Sdes	struct tapinfo		*tapp = NULL;
71863670Snsayer	int			 s;
719102052Ssobomax	int			 f;
720162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
721162711Sru    defined(COMPAT_FREEBSD4)
722162711Sru	int			 ival;
723162711Sru#endif
72463670Snsayer
72563670Snsayer	switch (cmd) {
726111742Sdes		case TAPSIFINFO:
72763670Snsayer			s = splimp();
728111742Sdes			tapp = (struct tapinfo *)data;
729111742Sdes			ifp->if_mtu = tapp->mtu;
730111742Sdes			ifp->if_type = tapp->type;
731111742Sdes			ifp->if_baudrate = tapp->baudrate;
73263670Snsayer			splx(s);
733111742Sdes			break;
73463670Snsayer
735111742Sdes		case TAPGIFINFO:
736111742Sdes			tapp = (struct tapinfo *)data;
737111742Sdes			tapp->mtu = ifp->if_mtu;
738111742Sdes			tapp->type = ifp->if_type;
739111742Sdes			tapp->baudrate = ifp->if_baudrate;
740111742Sdes			break;
74163670Snsayer
74263670Snsayer		case TAPSDEBUG:
743159079Smarius			tapdebug = *(int *)data;
74483043Sbrooks			break;
74563670Snsayer
74663670Snsayer		case TAPGDEBUG:
747159079Smarius			*(int *)data = tapdebug;
74883043Sbrooks			break;
74963670Snsayer
750182880Semax		case TAPGIFNAME: {
751182880Semax			struct ifreq	*ifr = (struct ifreq *) data;
752182880Semax
753182880Semax			strlcpy(ifr->ifr_name, ifp->if_xname, IFNAMSIZ);
754182880Semax			} break;
755182880Semax
75663670Snsayer		case FIONBIO:
75783043Sbrooks			break;
75863670Snsayer
75963670Snsayer		case FIOASYNC:
76063803Snsayer			s = splimp();
761127098Srwatson			mtx_lock(&tp->tap_mtx);
762159079Smarius			if (*(int *)data)
76363670Snsayer				tp->tap_flags |= TAP_ASYNC;
76463670Snsayer			else
76563670Snsayer				tp->tap_flags &= ~TAP_ASYNC;
766127098Srwatson			mtx_unlock(&tp->tap_mtx);
76763803Snsayer			splx(s);
76883043Sbrooks			break;
76963670Snsayer
77063670Snsayer		case FIONREAD:
77163670Snsayer			s = splimp();
77263670Snsayer			if (ifp->if_snd.ifq_head) {
77363670Snsayer				struct mbuf	*mb = ifp->if_snd.ifq_head;
77463670Snsayer
775159079Smarius				for(*(int *)data = 0;mb != NULL;mb = mb->m_next)
776159079Smarius					*(int *)data += mb->m_len;
77783043Sbrooks			} else
778159079Smarius				*(int *)data = 0;
77963670Snsayer			splx(s);
78083043Sbrooks			break;
78163670Snsayer
78263670Snsayer		case FIOSETOWN:
783159079Smarius			return (fsetown(*(int *)data, &tp->tap_sigio));
78463670Snsayer
78563670Snsayer		case FIOGETOWN:
786159079Smarius			*(int *)data = fgetown(&tp->tap_sigio);
78763670Snsayer			return (0);
78863670Snsayer
78963670Snsayer		/* this is deprecated, FIOSETOWN should be used instead */
79063670Snsayer		case TIOCSPGRP:
791159079Smarius			return (fsetown(-(*(int *)data), &tp->tap_sigio));
79263670Snsayer
79363670Snsayer		/* this is deprecated, FIOGETOWN should be used instead */
79463670Snsayer		case TIOCGPGRP:
795159079Smarius			*(int *)data = -fgetown(&tp->tap_sigio);
79663670Snsayer			return (0);
79763670Snsayer
79863670Snsayer		/* VMware/VMnet port ioctl's */
79963670Snsayer
80063670Snsayer		case SIOCGIFFLAGS:	/* get ifnet flags */
80163670Snsayer			bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags));
80283043Sbrooks			break;
80363670Snsayer
804162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
805162711Sru    defined(COMPAT_FREEBSD4)
806162711Sru		case _IO('V', 0):
807162711Sru			ival = IOCPARM_IVAL(data);
808162711Sru			data = (caddr_t)&ival;
809162711Sru			/* FALLTHROUGH */
810162711Sru#endif
81183043Sbrooks		case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */
812162711Sru			f = *(int *)data;
81363670Snsayer			f &= 0x0fff;
81463670Snsayer			f &= ~IFF_CANTCHANGE;
81563670Snsayer			f |= IFF_UP;
81663670Snsayer
81763670Snsayer			s = splimp();
81863670Snsayer			ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE);
81963670Snsayer			splx(s);
82083043Sbrooks			break;
82163670Snsayer
82263861Snsayer		case OSIOCGIFADDR:	/* get MAC address of the remote side */
82363670Snsayer		case SIOCGIFADDR:
824127165Srwatson			mtx_lock(&tp->tap_mtx);
82563861Snsayer			bcopy(tp->ether_addr, data, sizeof(tp->ether_addr));
826127165Srwatson			mtx_unlock(&tp->tap_mtx);
82783043Sbrooks			break;
82863670Snsayer
82963861Snsayer		case SIOCSIFADDR:	/* set MAC address of the remote side */
830127165Srwatson			mtx_lock(&tp->tap_mtx);
83163861Snsayer			bcopy(data, tp->ether_addr, sizeof(tp->ether_addr));
832127165Srwatson			mtx_unlock(&tp->tap_mtx);
83383043Sbrooks			break;
83463670Snsayer
83563670Snsayer		default:
83663670Snsayer			return (ENOTTY);
83763670Snsayer	}
83863670Snsayer	return (0);
83963670Snsayer} /* tapioctl */
84063670Snsayer
84163670Snsayer
84263670Snsayer/*
84363670Snsayer * tapread
84463670Snsayer *
84563670Snsayer * the cdevsw read interface - reads a packet at a time, or at
84663670Snsayer * least as much of a packet as can be read
84763670Snsayer */
84863670Snsayerstatic int
849156783Semaxtapread(struct cdev *dev, struct uio *uio, int flag)
85063670Snsayer{
85163670Snsayer	struct tap_softc	*tp = dev->si_drv1;
852147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
85390227Sdillon	struct mbuf		*m = NULL;
85463670Snsayer	int			 error = 0, len, s;
85563670Snsayer
856183397Sed	TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, dev2unit(dev));
85763670Snsayer
858127098Srwatson	mtx_lock(&tp->tap_mtx);
85963670Snsayer	if ((tp->tap_flags & TAP_READY) != TAP_READY) {
860127098Srwatson		mtx_unlock(&tp->tap_mtx);
861127098Srwatson
862127098Srwatson		/* Unlocked read. */
863121816Sbrooks		TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n",
864183397Sed			ifp->if_xname, dev2unit(dev), tp->tap_flags);
86563803Snsayer
86663670Snsayer		return (EHOSTDOWN);
86763670Snsayer	}
86863670Snsayer
86963670Snsayer	tp->tap_flags &= ~TAP_RWAIT;
870127098Srwatson	mtx_unlock(&tp->tap_mtx);
87163670Snsayer
87263670Snsayer	/* sleep until we get a packet */
87363670Snsayer	do {
87463670Snsayer		s = splimp();
87590227Sdillon		IF_DEQUEUE(&ifp->if_snd, m);
87663670Snsayer		splx(s);
87763670Snsayer
87890227Sdillon		if (m == NULL) {
879139207Sphk			if (flag & O_NONBLOCK)
88063670Snsayer				return (EWOULDBLOCK);
881111742Sdes
882127098Srwatson			mtx_lock(&tp->tap_mtx);
88363670Snsayer			tp->tap_flags |= TAP_RWAIT;
884127098Srwatson			mtx_unlock(&tp->tap_mtx);
885111748Sdes			error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0);
88663670Snsayer			if (error)
88763670Snsayer				return (error);
88863670Snsayer		}
88990227Sdillon	} while (m == NULL);
89063670Snsayer
89163670Snsayer	/* feed packet to bpf */
892106939Ssam	BPF_MTAP(ifp, m);
89363670Snsayer
89463670Snsayer	/* xfer packet to user space */
89590227Sdillon	while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) {
89690227Sdillon		len = min(uio->uio_resid, m->m_len);
89763670Snsayer		if (len == 0)
89863670Snsayer			break;
89963670Snsayer
900111741Sdes		error = uiomove(mtod(m, void *), len, uio);
90190227Sdillon		m = m_free(m);
90263670Snsayer	}
90363670Snsayer
90490227Sdillon	if (m != NULL) {
905121816Sbrooks		TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname,
906183397Sed			dev2unit(dev));
90790227Sdillon		m_freem(m);
90863670Snsayer	}
90963670Snsayer
91063670Snsayer	return (error);
91163670Snsayer} /* tapread */
91263670Snsayer
91363670Snsayer
91463670Snsayer/*
91563670Snsayer * tapwrite
91663670Snsayer *
91763670Snsayer * the cdevsw write interface - an atomic write is a packet - or else!
91863670Snsayer */
91963670Snsayerstatic int
920156783Semaxtapwrite(struct cdev *dev, struct uio *uio, int flag)
92163670Snsayer{
922166443Sbms	struct ether_header	*eh;
92363670Snsayer	struct tap_softc	*tp = dev->si_drv1;
924147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
925137101Sglebius	struct mbuf		*m;
92663670Snsayer
927121816Sbrooks	TAPDEBUG("%s writting, minor = %#x\n",
928183397Sed		ifp->if_xname, dev2unit(dev));
92963670Snsayer
93063670Snsayer	if (uio->uio_resid == 0)
93163670Snsayer		return (0);
93263670Snsayer
93363670Snsayer	if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) {
934194990Skib		TAPDEBUG("%s invalid packet len = %zd, minor = %#x\n",
935183397Sed			ifp->if_xname, uio->uio_resid, dev2unit(dev));
93663803Snsayer
93763670Snsayer		return (EIO);
93863670Snsayer	}
93963670Snsayer
940163915Sandre	if ((m = m_uiotombuf(uio, M_DONTWAIT, 0, ETHER_ALIGN,
941163915Sandre	    M_PKTHDR)) == NULL) {
94263670Snsayer		ifp->if_ierrors ++;
943163986Scsjp		return (ENOBUFS);
94463670Snsayer	}
94563670Snsayer
946137101Sglebius	m->m_pkthdr.rcvif = ifp;
947111742Sdes
948166443Sbms	/*
949166443Sbms	 * Only pass a unicast frame to ether_input(), if it would actually
950166443Sbms	 * have been received by non-virtual hardware.
951166443Sbms	 */
952166443Sbms	if (m->m_len < sizeof(struct ether_header)) {
953166443Sbms		m_freem(m);
954166443Sbms		return (0);
955166443Sbms	}
956166443Sbms	eh = mtod(m, struct ether_header *);
957166443Sbms
958166443Sbms	if (eh && (ifp->if_flags & IFF_PROMISC) == 0 &&
959166443Sbms	    !ETHER_IS_MULTICAST(eh->ether_dhost) &&
960166443Sbms	    bcmp(eh->ether_dhost, IF_LLADDR(ifp), ETHER_ADDR_LEN) != 0) {
961166443Sbms		m_freem(m);
962166443Sbms		return (0);
963166443Sbms	}
964166443Sbms
965106939Ssam	/* Pass packet up to parent. */
966137101Sglebius	(*ifp->if_input)(ifp, m);
967106939Ssam	ifp->if_ipackets ++; /* ibytes are counted in parent */
96863670Snsayer
96963670Snsayer	return (0);
97063670Snsayer} /* tapwrite */
97163670Snsayer
97263670Snsayer
97363670Snsayer/*
97463670Snsayer * tappoll
97563670Snsayer *
97663670Snsayer * the poll interface, this is only useful on reads
97763670Snsayer * really. the write detect always returns true, write never blocks
97863670Snsayer * anyway, it either accepts the packet or drops it
97963670Snsayer */
98063670Snsayerstatic int
981156783Semaxtappoll(struct cdev *dev, int events, struct thread *td)
98263670Snsayer{
98363670Snsayer	struct tap_softc	*tp = dev->si_drv1;
984147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
985111742Sdes	int			 s, revents = 0;
98663670Snsayer
987121816Sbrooks	TAPDEBUG("%s polling, minor = %#x\n",
988183397Sed		ifp->if_xname, dev2unit(dev));
98963670Snsayer
99063670Snsayer	s = splimp();
99163670Snsayer	if (events & (POLLIN | POLLRDNORM)) {
99263670Snsayer		if (ifp->if_snd.ifq_len > 0) {
993121816Sbrooks			TAPDEBUG("%s have data in queue. len = %d, " \
994121816Sbrooks				"minor = %#x\n", ifp->if_xname,
995183397Sed				ifp->if_snd.ifq_len, dev2unit(dev));
99663803Snsayer
99763670Snsayer			revents |= (events & (POLLIN | POLLRDNORM));
99883043Sbrooks		} else {
999121816Sbrooks			TAPDEBUG("%s waiting for data, minor = %#x\n",
1000183397Sed				ifp->if_xname, dev2unit(dev));
100163803Snsayer
100283805Sjhb			selrecord(td, &tp->tap_rsel);
100363670Snsayer		}
100463670Snsayer	}
100563670Snsayer
100663670Snsayer	if (events & (POLLOUT | POLLWRNORM))
100763670Snsayer		revents |= (events & (POLLOUT | POLLWRNORM));
100863670Snsayer
100963670Snsayer	splx(s);
101063670Snsayer	return (revents);
101163670Snsayer} /* tappoll */
1012156783Semax
1013156783Semax
1014156783Semax/*
1015156783Semax * tap_kqfilter
1016156783Semax *
1017156783Semax * support for kevent() system call
1018156783Semax */
1019156783Semaxstatic int
1020156783Semaxtapkqfilter(struct cdev *dev, struct knote *kn)
1021156783Semax{
1022156783Semax    	int			 s;
1023156783Semax	struct tap_softc	*tp = dev->si_drv1;
1024156783Semax	struct ifnet		*ifp = tp->tap_ifp;
1025156783Semax
1026156783Semax	s = splimp();
1027156783Semax	switch (kn->kn_filter) {
1028156783Semax	case EVFILT_READ:
1029156783Semax		TAPDEBUG("%s kqfilter: EVFILT_READ, minor = %#x\n",
1030183397Sed			ifp->if_xname, dev2unit(dev));
1031156783Semax		kn->kn_fop = &tap_read_filterops;
1032156783Semax		break;
1033156783Semax
1034156783Semax	case EVFILT_WRITE:
1035156783Semax		TAPDEBUG("%s kqfilter: EVFILT_WRITE, minor = %#x\n",
1036183397Sed			ifp->if_xname, dev2unit(dev));
1037156783Semax		kn->kn_fop = &tap_write_filterops;
1038156783Semax		break;
1039156783Semax
1040156783Semax	default:
1041156783Semax		TAPDEBUG("%s kqfilter: invalid filter, minor = %#x\n",
1042183397Sed			ifp->if_xname, dev2unit(dev));
1043156783Semax		splx(s);
1044156783Semax		return (EINVAL);
1045156783Semax		/* NOT REACHED */
1046156783Semax	}
1047156783Semax	splx(s);
1048156783Semax
1049156783Semax	kn->kn_hook = (caddr_t) dev;
1050156783Semax	knlist_add(&tp->tap_rsel.si_note, kn, 0);
1051156783Semax
1052156783Semax	return (0);
1053156783Semax} /* tapkqfilter */
1054156783Semax
1055156783Semax
1056156783Semax/*
1057156783Semax * tap_kqread
1058156783Semax *
1059156783Semax * Return true if there is data in the interface queue
1060156783Semax */
1061156783Semaxstatic int
1062156783Semaxtapkqread(struct knote *kn, long hint)
1063156783Semax{
1064156783Semax	int			 ret, s;
1065156783Semax	struct cdev		*dev = (struct cdev *)(kn->kn_hook);
1066156783Semax	struct tap_softc	*tp = dev->si_drv1;
1067156783Semax	struct ifnet		*ifp = tp->tap_ifp;
1068156783Semax
1069156783Semax	s = splimp();
1070156783Semax	if ((kn->kn_data = ifp->if_snd.ifq_len) > 0) {
1071156783Semax		TAPDEBUG("%s have data in queue. len = %d, minor = %#x\n",
1072183397Sed			ifp->if_xname, ifp->if_snd.ifq_len, dev2unit(dev));
1073156783Semax		ret = 1;
1074156783Semax	} else {
1075156783Semax		TAPDEBUG("%s waiting for data, minor = %#x\n",
1076183397Sed			ifp->if_xname, dev2unit(dev));
1077156783Semax		ret = 0;
1078156783Semax	}
1079156783Semax	splx(s);
1080156783Semax
1081156783Semax	return (ret);
1082156783Semax} /* tapkqread */
1083156783Semax
1084156783Semax
1085156783Semax/*
1086156783Semax * tap_kqwrite
1087156783Semax *
1088156783Semax * Always can write. Return the MTU in kn->data
1089156783Semax */
1090156783Semaxstatic int
1091156783Semaxtapkqwrite(struct knote *kn, long hint)
1092156783Semax{
1093156783Semax	int			 s;
1094156783Semax	struct tap_softc	*tp = ((struct cdev *) kn->kn_hook)->si_drv1;
1095156783Semax	struct ifnet		*ifp = tp->tap_ifp;
1096156783Semax
1097156783Semax	s = splimp();
1098156783Semax	kn->kn_data = ifp->if_mtu;
1099156783Semax	splx(s);
1100156783Semax
1101156783Semax	return (1);
1102156783Semax} /* tapkqwrite */
1103156783Semax
1104156783Semax
1105156783Semaxstatic void
1106156783Semaxtapkqdetach(struct knote *kn)
1107156783Semax{
1108156783Semax	struct tap_softc	*tp = ((struct cdev *) kn->kn_hook)->si_drv1;
1109156783Semax
1110156783Semax	knlist_remove(&tp->tap_rsel.si_note, kn, 0);
1111156783Semax} /* tapkqdetach */
1112156783Semax
1113