if_tap.c revision 166497
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 166497 2007-02-04 16:32:46Z bms $
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,
135126188Sbde	.d_flags =	D_PSEUDO | D_NEEDGIANT,
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   */
153144979Smdoddstatic int			tapuopen = 0;        /* allow user open() */
154166497Sbmsstatic int			tapdclone = 1;	/* enable devfs cloning */
15583043Sbrooksstatic SLIST_HEAD(, tap_softc)	taphead;             /* first device */
156126077Sphkstatic struct clonedevs 	*tapclones;
15763670Snsayer
15863670SnsayerMALLOC_DECLARE(M_TAP);
15963670SnsayerMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface");
16063670SnsayerSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, "");
161144979Smdodd
162144979SmdoddSYSCTL_DECL(_net_link);
163144979SmdoddSYSCTL_NODE(_net_link, OID_AUTO, tap, CTLFLAG_RW, 0,
164144979Smdodd    "Ethernet tunnel software network interface");
165144979SmdoddSYSCTL_INT(_net_link_tap, OID_AUTO, user_open, CTLFLAG_RW, &tapuopen, 0,
166144979Smdodd	"Allow user to open /dev/tap (based on node permissions)");
167166497SbmsSYSCTL_INT(_net_link_tap, OID_AUTO, devfs_cloning, CTLFLAG_RW, &tapdclone, 0,
168166497Sbms	"Enably legacy devfs interface creation");
169144979SmdoddSYSCTL_INT(_net_link_tap, OID_AUTO, debug, CTLFLAG_RW, &tapdebug, 0, "");
170144979Smdodd
171166497SbmsTUNABLE_INT("net.link.tap.devfs_cloning", &tapdclone);
172166497Sbms
17363670SnsayerDEV_MODULE(if_tap, tapmodevent, NULL);
17463670Snsayer
175166497Sbmsstatic int
176166497Sbmstap_clone_create(struct if_clone *ifc, int unit, caddr_t params)
177166497Sbms{
178166497Sbms	struct cdev *dev;
179166497Sbms	int i;
180166497Sbms	int extra;
181166497Sbms
182166497Sbms	if (strcmp(ifc->ifc_name, VMNET) == 0)
183166497Sbms		extra = VMNET_DEV_MASK;
184166497Sbms	else
185166497Sbms		extra = 0;
186166497Sbms
187166497Sbms	/* find any existing device, or allocate new unit number */
188166497Sbms	i = clone_create(&tapclones, &tap_cdevsw, &unit, &dev, extra);
189166497Sbms	if (i) {
190166497Sbms		dev = make_dev(&tap_cdevsw, unit2minor(unit | extra),
191166497Sbms		     UID_ROOT, GID_WHEEL, 0600, "%s%d", ifc->ifc_name, unit);
192166497Sbms		if (dev != NULL) {
193166497Sbms			dev_ref(dev);
194166497Sbms			dev->si_flags |= SI_CHEAPCLONE;
195166497Sbms		}
196166497Sbms	}
197166497Sbms
198166497Sbms	tapcreate(dev);
199166497Sbms	return (0);
200166497Sbms}
201166497Sbms
202166497Sbms/* vmnet devices are tap devices in disguise */
203166497Sbmsstatic int
204166497Sbmsvmnet_clone_create(struct if_clone *ifc, int unit, caddr_t params)
205166497Sbms{
206166497Sbms	return tap_clone_create(ifc, unit, params);
207166497Sbms}
208166497Sbms
209166497Sbmsstatic void
210166497Sbmstap_destroy(struct tap_softc *tp)
211166497Sbms{
212166497Sbms	struct ifnet *ifp = tp->tap_ifp;
213166497Sbms	int s;
214166497Sbms
215166497Sbms	/* Unlocked read. */
216166497Sbms	KASSERT(!(tp->tap_flags & TAP_OPEN),
217166497Sbms		("%s flags is out of sync", ifp->if_xname));
218166497Sbms
219166497Sbms	knlist_destroy(&tp->tap_rsel.si_note);
220166497Sbms	destroy_dev(tp->tap_dev);
221166497Sbms	s = splimp();
222166497Sbms	ether_ifdetach(ifp);
223166497Sbms	if_free_type(ifp, IFT_ETHER);
224166497Sbms	splx(s);
225166497Sbms
226166497Sbms	mtx_destroy(&tp->tap_mtx);
227166497Sbms	free(tp, M_TAP);
228166497Sbms}
229166497Sbms
230166497Sbmsstatic void
231166497Sbmstap_clone_destroy(struct ifnet *ifp)
232166497Sbms{
233166497Sbms	struct tap_softc *tp = ifp->if_softc;
234166497Sbms
235166497Sbms	mtx_lock(&tapmtx);
236166497Sbms	SLIST_REMOVE(&taphead, tp, tap_softc, tap_next);
237166497Sbms	mtx_unlock(&tapmtx);
238166497Sbms	tap_destroy(tp);
239166497Sbms}
240166497Sbms
241166497Sbms/* vmnet devices are tap devices in disguise */
242166497Sbmsstatic void
243166497Sbmsvmnet_clone_destroy(struct ifnet *ifp)
244166497Sbms{
245166497Sbms	tap_clone_destroy(ifp);
246166497Sbms}
247166497Sbms
24863670Snsayer/*
24963670Snsayer * tapmodevent
25063670Snsayer *
25163670Snsayer * module event handler
25263670Snsayer */
25363670Snsayerstatic int
254156783Semaxtapmodevent(module_t mod, int type, void *data)
25563670Snsayer{
25683043Sbrooks	static eventhandler_tag	 eh_tag = NULL;
25783043Sbrooks	struct tap_softc	*tp = NULL;
25883043Sbrooks	struct ifnet		*ifp = NULL;
25963670Snsayer
26063670Snsayer	switch (type) {
26163670Snsayer	case MOD_LOAD:
26263670Snsayer
26383043Sbrooks		/* intitialize device */
26483043Sbrooks
265127003Srwatson		mtx_init(&tapmtx, "tapmtx", NULL, MTX_DEF);
26683043Sbrooks		SLIST_INIT(&taphead);
26783043Sbrooks
268126845Sphk		clone_setup(&tapclones);
26971602Sphk		eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000);
270127003Srwatson		if (eh_tag == NULL) {
271127170Srwatson			clone_cleanup(&tapclones);
272127003Srwatson			mtx_destroy(&tapmtx);
273126077Sphk			return (ENOMEM);
274127003Srwatson		}
275166497Sbms		if_clone_attach(&tap_cloner);
276166497Sbms		if_clone_attach(&vmnet_cloner);
27783043Sbrooks		return (0);
27863670Snsayer
27983043Sbrooks	case MOD_UNLOAD:
280127003Srwatson		/*
281127003Srwatson		 * The EBUSY algorithm here can't quite atomically
282127003Srwatson		 * guarantee that this is race-free since we have to
283127003Srwatson		 * release the tap mtx to deregister the clone handler.
284127003Srwatson		 */
285127003Srwatson		mtx_lock(&tapmtx);
286127003Srwatson		SLIST_FOREACH(tp, &taphead, tap_next) {
287127098Srwatson			mtx_lock(&tp->tap_mtx);
288127003Srwatson			if (tp->tap_flags & TAP_OPEN) {
289127098Srwatson				mtx_unlock(&tp->tap_mtx);
290127003Srwatson				mtx_unlock(&tapmtx);
29183043Sbrooks				return (EBUSY);
292127003Srwatson			}
293127098Srwatson			mtx_unlock(&tp->tap_mtx);
294127003Srwatson		}
295127003Srwatson		mtx_unlock(&tapmtx);
29683043Sbrooks
29771602Sphk		EVENTHANDLER_DEREGISTER(dev_clone, eh_tag);
298166497Sbms		if_clone_detach(&tap_cloner);
299166497Sbms		if_clone_detach(&vmnet_cloner);
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
343166497Sbms	/*
344166497Sbms	 * If tap cloning is enabled, only the superuser can create
345166497Sbms	 * an interface.
346166497Sbms	 */
347166497Sbms	if (!tapdclone || priv_check_cred(cred, PRIV_NET_IFCREATE, 0) != 0)
348166497Sbms		return;
349166497Sbms
350166497Sbms	unit = 0;
351166497Sbms	append_unit = 0;
352126077Sphk	extra = 0;
353166497Sbms
354166497Sbms	/* We're interested in only tap/vmnet devices. */
355126077Sphk	if (strcmp(name, TAP) == 0) {
356126077Sphk		unit = -1;
357126077Sphk	} else if (strcmp(name, VMNET) == 0) {
358126077Sphk		unit = -1;
359126077Sphk		extra = VMNET_DEV_MASK;
360166497Sbms	} else if (dev_stdclone(name, NULL, TAP, &unit) != 1) {
361166497Sbms		if (dev_stdclone(name, NULL, VMNET, &unit) != 1) {
362126077Sphk			return;
363166497Sbms		} else {
364166497Sbms			extra = VMNET_DEV_MASK;
365166497Sbms		}
36683043Sbrooks	}
36771602Sphk
368166497Sbms	if (unit == -1)
369166497Sbms		append_unit = 1;
370166497Sbms
371126077Sphk	/* find any existing device, or allocate new unit number */
372126077Sphk	i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra);
373126077Sphk	if (i) {
374166497Sbms		if (append_unit) {
375166497Sbms			/*
376166497Sbms			 * We were passed 'tun' or 'tap', with no unit specified
377166497Sbms			 * so we'll need to append it now.
378166497Sbms			 */
379166497Sbms			namelen = snprintf(devname, sizeof(devname), "%s%d", name,
380166497Sbms			    unit);
381166497Sbms			name = devname;
382166497Sbms		}
383166497Sbms
384126796Sphk		*dev = make_dev(&tap_cdevsw, unit2minor(unit | extra),
385166497Sbms		     UID_ROOT, GID_WHEEL, 0600, "%s", name);
386144389Sphk		if (*dev != NULL) {
387144389Sphk			dev_ref(*dev);
388126077Sphk			(*dev)->si_flags |= SI_CHEAPCLONE;
389144389Sphk		}
39071602Sphk	}
391166497Sbms
392166497Sbms	if_clone_create(name, namelen, NULL);
39371602Sphk} /* tapclone */
39471602Sphk
39571602Sphk
39671602Sphk/*
39763670Snsayer * tapcreate
39863670Snsayer *
39963670Snsayer * to create interface
40063670Snsayer */
40163670Snsayerstatic void
402156783Semaxtapcreate(struct cdev *dev)
40363670Snsayer{
40463670Snsayer	struct ifnet		*ifp = NULL;
40563670Snsayer	struct tap_softc	*tp = NULL;
40663670Snsayer	unsigned short		 macaddr_hi;
40763803Snsayer	int			 unit, s;
40863670Snsayer	char			*name = NULL;
409147256Sbrooks	u_char			eaddr[6];
41063670Snsayer
411126077Sphk	dev->si_flags &= ~SI_CHEAPCLONE;
412126077Sphk
41363670Snsayer	/* allocate driver storage and create device */
414111119Simp	MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO);
415127098Srwatson	mtx_init(&tp->tap_mtx, "tap_mtx", NULL, MTX_DEF);
416127003Srwatson	mtx_lock(&tapmtx);
41783043Sbrooks	SLIST_INSERT_HEAD(&taphead, tp, tap_next);
418127003Srwatson	mtx_unlock(&tapmtx);
41963670Snsayer
420126796Sphk	unit = dev2unit(dev);
42183043Sbrooks
42263670Snsayer	/* select device: tap or vmnet */
423126796Sphk	if (unit & VMNET_DEV_MASK) {
42463670Snsayer		name = VMNET;
42563803Snsayer		tp->tap_flags |= TAP_VMNET;
42683043Sbrooks	} else
42763670Snsayer		name = TAP;
42863670Snsayer
429126796Sphk	unit &= TAPMAXUNIT;
430126796Sphk
43183043Sbrooks	TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev));
43283043Sbrooks
43363670Snsayer	/* generate fake MAC address: 00 bd xx xx xx unit_no */
43463670Snsayer	macaddr_hi = htons(0x00bd);
435147256Sbrooks	bcopy(&macaddr_hi, eaddr, sizeof(short));
436147256Sbrooks	bcopy(&ticks, &eaddr[2], sizeof(long));
437147256Sbrooks	eaddr[5] = (u_char)unit;
43863670Snsayer
439111742Sdes	/* fill the rest and attach interface */
440147256Sbrooks	ifp = tp->tap_ifp = if_alloc(IFT_ETHER);
441147256Sbrooks	if (ifp == NULL)
442147256Sbrooks		panic("%s%d: can not if_alloc()", name, unit);
44363670Snsayer	ifp->if_softc = tp;
444121816Sbrooks	if_initname(ifp, name, unit);
44563670Snsayer	ifp->if_init = tapifinit;
44663670Snsayer	ifp->if_start = tapifstart;
44763670Snsayer	ifp->if_ioctl = tapifioctl;
44863670Snsayer	ifp->if_mtu = ETHERMTU;
44963670Snsayer	ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
45063670Snsayer	ifp->if_snd.ifq_maxlen = ifqmaxlen;
45163670Snsayer
45283043Sbrooks	dev->si_drv1 = tp;
453126077Sphk	tp->tap_dev = dev;
45483043Sbrooks
45563803Snsayer	s = splimp();
456147256Sbrooks	ether_ifattach(ifp, eaddr);
45763803Snsayer	splx(s);
45863670Snsayer
459127098Srwatson	mtx_lock(&tp->tap_mtx);
46063803Snsayer	tp->tap_flags |= TAP_INITED;
461127098Srwatson	mtx_unlock(&tp->tap_mtx);
46263803Snsayer
463158697Semax	knlist_init(&tp->tap_rsel.si_note, NULL, NULL, NULL, NULL);
464158697Semax
465121816Sbrooks	TAPDEBUG("interface %s is created. minor = %#x\n",
466121816Sbrooks		ifp->if_xname, minor(dev));
46763670Snsayer} /* tapcreate */
46863670Snsayer
46963670Snsayer
47063670Snsayer/*
471111742Sdes * tapopen
47263670Snsayer *
47363670Snsayer * to open tunnel. must be superuser
47463670Snsayer */
47563670Snsayerstatic int
476156783Semaxtapopen(struct cdev *dev, int flag, int mode, struct thread *td)
47763670Snsayer{
47863670Snsayer	struct tap_softc	*tp = NULL;
479133460Semax	struct ifnet		*ifp = NULL;
480164033Srwatson	int			 error, s;
48163670Snsayer
482164033Srwatson	if (tapuopen == 0) {
483164033Srwatson		error = priv_check(td, PRIV_NET_TAP);
484164033Srwatson		if (error)
485164033Srwatson			return (error);
486164033Srwatson	}
48763670Snsayer
488126796Sphk	if ((dev2unit(dev) & CLONE_UNITMASK) > TAPMAXUNIT)
489126796Sphk		return (ENXIO);
49083043Sbrooks
49163670Snsayer	tp = dev->si_drv1;
49263670Snsayer
493127165Srwatson	mtx_lock(&tp->tap_mtx);
494127165Srwatson	if (tp->tap_flags & TAP_OPEN) {
495127165Srwatson		mtx_unlock(&tp->tap_mtx);
496127165Srwatson		return (EBUSY);
497127165Srwatson	}
49863670Snsayer
499152315Sru	bcopy(IF_LLADDR(tp->tap_ifp), tp->ether_addr, sizeof(tp->ether_addr));
50083366Sjulian	tp->tap_pid = td->td_proc->p_pid;
50163670Snsayer	tp->tap_flags |= TAP_OPEN;
502147256Sbrooks	ifp = tp->tap_ifp;
503127098Srwatson	mtx_unlock(&tp->tap_mtx);
50463670Snsayer
505133460Semax	s = splimp();
506148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
507148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
508133460Semax	splx(s);
50963670Snsayer
510133460Semax	TAPDEBUG("%s is open. minor = %#x\n", ifp->if_xname, minor(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
55396122Salfred	funsetown(&tp->tap_sigio);
554122352Stanimura	selwakeuppri(&tp->tap_rsel, PZERO+1);
555156783Semax	KNOTE_UNLOCKED(&tp->tap_rsel.si_note, 0);
55663670Snsayer
557127098Srwatson	mtx_lock(&tp->tap_mtx);
55863670Snsayer	tp->tap_flags &= ~TAP_OPEN;
55963670Snsayer	tp->tap_pid = 0;
560127098Srwatson	mtx_unlock(&tp->tap_mtx);
56163670Snsayer
562121816Sbrooks	TAPDEBUG("%s is closed. minor = %#x\n",
563121816Sbrooks		ifp->if_xname, minor(dev));
56463670Snsayer
56563670Snsayer	return (0);
56663670Snsayer} /* tapclose */
56763670Snsayer
56863670Snsayer
56963670Snsayer/*
57063670Snsayer * tapifinit
57163670Snsayer *
57263670Snsayer * network interface initialization function
57363670Snsayer */
57463670Snsayerstatic void
575156783Semaxtapifinit(void *xtp)
57663670Snsayer{
57763670Snsayer	struct tap_softc	*tp = (struct tap_softc *)xtp;
578147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
57963670Snsayer
580121816Sbrooks	TAPDEBUG("initializing %s\n", ifp->if_xname);
58163670Snsayer
582148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
583148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
58463670Snsayer
58563670Snsayer	/* attempt to start output */
58663670Snsayer	tapifstart(ifp);
58763670Snsayer} /* tapifinit */
58863670Snsayer
58963670Snsayer
59063670Snsayer/*
59163670Snsayer * tapifioctl
59263670Snsayer *
59363670Snsayer * Process an ioctl request on network interface
59463670Snsayer */
595105228Sphkstatic int
596156783Semaxtapifioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
59763670Snsayer{
598160376Sbrooks	struct tap_softc	*tp = ifp->if_softc;
59963670Snsayer	struct ifstat		*ifs = NULL;
60063670Snsayer	int			 s, dummy;
60163670Snsayer
60263670Snsayer	switch (cmd) {
60363670Snsayer		case SIOCSIFFLAGS: /* XXX -- just like vmnet does */
60463670Snsayer		case SIOCADDMULTI:
60563670Snsayer		case SIOCDELMULTI:
60683043Sbrooks			break;
60763670Snsayer
60863670Snsayer		case SIOCGIFSTATUS:
60963670Snsayer			s = splimp();
61063670Snsayer			ifs = (struct ifstat *)data;
61163670Snsayer			dummy = strlen(ifs->ascii);
612127098Srwatson			mtx_lock(&tp->tap_mtx);
61363670Snsayer			if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii))
61463670Snsayer				snprintf(ifs->ascii + dummy,
61563670Snsayer					sizeof(ifs->ascii) - dummy,
61663670Snsayer					"\tOpened by PID %d\n", tp->tap_pid);
617127098Srwatson			mtx_unlock(&tp->tap_mtx);
61863670Snsayer			splx(s);
61983043Sbrooks			break;
62063670Snsayer
62163670Snsayer		default:
622106939Ssam			s = splimp();
623106939Ssam			dummy = ether_ioctl(ifp, cmd, data);
624106939Ssam			splx(s);
625106939Ssam			return (dummy);
626156783Semax			/* NOT REACHED */
62763670Snsayer	}
62863670Snsayer
62963670Snsayer	return (0);
63063670Snsayer} /* tapifioctl */
63163670Snsayer
63263670Snsayer
63363670Snsayer/*
634111742Sdes * tapifstart
635111742Sdes *
63663670Snsayer * queue packets from higher level ready to put out
63763670Snsayer */
63863670Snsayerstatic void
639156783Semaxtapifstart(struct ifnet *ifp)
64063670Snsayer{
64163670Snsayer	struct tap_softc	*tp = ifp->if_softc;
64263670Snsayer	int			 s;
64363670Snsayer
644121816Sbrooks	TAPDEBUG("%s starting\n", ifp->if_xname);
64563670Snsayer
64663803Snsayer	/*
64763803Snsayer	 * do not junk pending output if we are in VMnet mode.
64863803Snsayer	 * XXX: can this do any harm because of queue overflow?
64963803Snsayer	 */
65063803Snsayer
651127098Srwatson	mtx_lock(&tp->tap_mtx);
652111742Sdes	if (((tp->tap_flags & TAP_VMNET) == 0) &&
65363803Snsayer	    ((tp->tap_flags & TAP_READY) != TAP_READY)) {
65463670Snsayer		struct mbuf	*m = NULL;
65563670Snsayer
656127098Srwatson		mtx_unlock(&tp->tap_mtx);
657127098Srwatson
658127098Srwatson		/* Unlocked read. */
659121816Sbrooks		TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname,
660121816Sbrooks		    tp->tap_flags);
66163670Snsayer
66263670Snsayer		s = splimp();
66363670Snsayer		do {
66463670Snsayer			IF_DEQUEUE(&ifp->if_snd, m);
66563670Snsayer			if (m != NULL)
66663670Snsayer				m_freem(m);
66763670Snsayer			ifp->if_oerrors ++;
66863670Snsayer		} while (m != NULL);
66963670Snsayer		splx(s);
67063670Snsayer
67163670Snsayer		return;
67263670Snsayer	}
673127098Srwatson	mtx_unlock(&tp->tap_mtx);
67463670Snsayer
67563670Snsayer	s = splimp();
676148887Srwatson	ifp->if_drv_flags |= IFF_DRV_OACTIVE;
67763670Snsayer
67863670Snsayer	if (ifp->if_snd.ifq_len != 0) {
679127098Srwatson		mtx_lock(&tp->tap_mtx);
68063670Snsayer		if (tp->tap_flags & TAP_RWAIT) {
68163670Snsayer			tp->tap_flags &= ~TAP_RWAIT;
682111748Sdes			wakeup(tp);
68363670Snsayer		}
68463670Snsayer
685127098Srwatson		if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) {
686127098Srwatson			mtx_unlock(&tp->tap_mtx);
68795883Salfred			pgsigio(&tp->tap_sigio, SIGIO, 0);
688127098Srwatson		} else
689127098Srwatson			mtx_unlock(&tp->tap_mtx);
69063670Snsayer
691122352Stanimura		selwakeuppri(&tp->tap_rsel, PZERO+1);
692156783Semax		KNOTE_UNLOCKED(&tp->tap_rsel.si_note, 0);
69363670Snsayer		ifp->if_opackets ++; /* obytes are counted in ether_output */
69463670Snsayer	}
69563670Snsayer
696148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
69763670Snsayer	splx(s);
69863670Snsayer} /* tapifstart */
69963670Snsayer
70063670Snsayer
70163670Snsayer/*
70263670Snsayer * tapioctl
70363670Snsayer *
70463670Snsayer * the cdevsw interface is now pretty minimal
70563670Snsayer */
70663670Snsayerstatic int
707156783Semaxtapioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
70863670Snsayer{
70963670Snsayer	struct tap_softc	*tp = dev->si_drv1;
710147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
711111742Sdes	struct tapinfo		*tapp = NULL;
71263670Snsayer	int			 s;
713102052Ssobomax	int			 f;
714162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
715162711Sru    defined(COMPAT_FREEBSD4)
716162711Sru	int			 ival;
717162711Sru#endif
71863670Snsayer
71963670Snsayer	switch (cmd) {
720111742Sdes		case TAPSIFINFO:
72163670Snsayer			s = splimp();
722111742Sdes			tapp = (struct tapinfo *)data;
723111742Sdes			ifp->if_mtu = tapp->mtu;
724111742Sdes			ifp->if_type = tapp->type;
725111742Sdes			ifp->if_baudrate = tapp->baudrate;
72663670Snsayer			splx(s);
727111742Sdes			break;
72863670Snsayer
729111742Sdes		case TAPGIFINFO:
730111742Sdes			tapp = (struct tapinfo *)data;
731111742Sdes			tapp->mtu = ifp->if_mtu;
732111742Sdes			tapp->type = ifp->if_type;
733111742Sdes			tapp->baudrate = ifp->if_baudrate;
734111742Sdes			break;
73563670Snsayer
73663670Snsayer		case TAPSDEBUG:
737159079Smarius			tapdebug = *(int *)data;
73883043Sbrooks			break;
73963670Snsayer
74063670Snsayer		case TAPGDEBUG:
741159079Smarius			*(int *)data = tapdebug;
74283043Sbrooks			break;
74363670Snsayer
74463670Snsayer		case FIONBIO:
74583043Sbrooks			break;
74663670Snsayer
74763670Snsayer		case FIOASYNC:
74863803Snsayer			s = splimp();
749127098Srwatson			mtx_lock(&tp->tap_mtx);
750159079Smarius			if (*(int *)data)
75163670Snsayer				tp->tap_flags |= TAP_ASYNC;
75263670Snsayer			else
75363670Snsayer				tp->tap_flags &= ~TAP_ASYNC;
754127098Srwatson			mtx_unlock(&tp->tap_mtx);
75563803Snsayer			splx(s);
75683043Sbrooks			break;
75763670Snsayer
75863670Snsayer		case FIONREAD:
75963670Snsayer			s = splimp();
76063670Snsayer			if (ifp->if_snd.ifq_head) {
76163670Snsayer				struct mbuf	*mb = ifp->if_snd.ifq_head;
76263670Snsayer
763159079Smarius				for(*(int *)data = 0;mb != NULL;mb = mb->m_next)
764159079Smarius					*(int *)data += mb->m_len;
76583043Sbrooks			} else
766159079Smarius				*(int *)data = 0;
76763670Snsayer			splx(s);
76883043Sbrooks			break;
76963670Snsayer
77063670Snsayer		case FIOSETOWN:
771159079Smarius			return (fsetown(*(int *)data, &tp->tap_sigio));
77263670Snsayer
77363670Snsayer		case FIOGETOWN:
774159079Smarius			*(int *)data = fgetown(&tp->tap_sigio);
77563670Snsayer			return (0);
77663670Snsayer
77763670Snsayer		/* this is deprecated, FIOSETOWN should be used instead */
77863670Snsayer		case TIOCSPGRP:
779159079Smarius			return (fsetown(-(*(int *)data), &tp->tap_sigio));
78063670Snsayer
78163670Snsayer		/* this is deprecated, FIOGETOWN should be used instead */
78263670Snsayer		case TIOCGPGRP:
783159079Smarius			*(int *)data = -fgetown(&tp->tap_sigio);
78463670Snsayer			return (0);
78563670Snsayer
78663670Snsayer		/* VMware/VMnet port ioctl's */
78763670Snsayer
78863670Snsayer		case SIOCGIFFLAGS:	/* get ifnet flags */
78963670Snsayer			bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags));
79083043Sbrooks			break;
79163670Snsayer
792162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
793162711Sru    defined(COMPAT_FREEBSD4)
794162711Sru		case _IO('V', 0):
795162711Sru			ival = IOCPARM_IVAL(data);
796162711Sru			data = (caddr_t)&ival;
797162711Sru			/* FALLTHROUGH */
798162711Sru#endif
79983043Sbrooks		case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */
800162711Sru			f = *(int *)data;
80163670Snsayer			f &= 0x0fff;
80263670Snsayer			f &= ~IFF_CANTCHANGE;
80363670Snsayer			f |= IFF_UP;
80463670Snsayer
80563670Snsayer			s = splimp();
80663670Snsayer			ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE);
80763670Snsayer			splx(s);
80883043Sbrooks			break;
80963670Snsayer
81063861Snsayer		case OSIOCGIFADDR:	/* get MAC address of the remote side */
81163670Snsayer		case SIOCGIFADDR:
812127165Srwatson			mtx_lock(&tp->tap_mtx);
81363861Snsayer			bcopy(tp->ether_addr, data, sizeof(tp->ether_addr));
814127165Srwatson			mtx_unlock(&tp->tap_mtx);
81583043Sbrooks			break;
81663670Snsayer
81763861Snsayer		case SIOCSIFADDR:	/* set MAC address of the remote side */
818127165Srwatson			mtx_lock(&tp->tap_mtx);
81963861Snsayer			bcopy(data, tp->ether_addr, sizeof(tp->ether_addr));
820127165Srwatson			mtx_unlock(&tp->tap_mtx);
82183043Sbrooks			break;
82263670Snsayer
82363670Snsayer		default:
82463670Snsayer			return (ENOTTY);
82563670Snsayer	}
82663670Snsayer	return (0);
82763670Snsayer} /* tapioctl */
82863670Snsayer
82963670Snsayer
83063670Snsayer/*
83163670Snsayer * tapread
83263670Snsayer *
83363670Snsayer * the cdevsw read interface - reads a packet at a time, or at
83463670Snsayer * least as much of a packet as can be read
83563670Snsayer */
83663670Snsayerstatic int
837156783Semaxtapread(struct cdev *dev, struct uio *uio, int flag)
83863670Snsayer{
83963670Snsayer	struct tap_softc	*tp = dev->si_drv1;
840147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
84190227Sdillon	struct mbuf		*m = NULL;
84263670Snsayer	int			 error = 0, len, s;
84363670Snsayer
844121816Sbrooks	TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, minor(dev));
84563670Snsayer
846127098Srwatson	mtx_lock(&tp->tap_mtx);
84763670Snsayer	if ((tp->tap_flags & TAP_READY) != TAP_READY) {
848127098Srwatson		mtx_unlock(&tp->tap_mtx);
849127098Srwatson
850127098Srwatson		/* Unlocked read. */
851121816Sbrooks		TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n",
852121816Sbrooks			ifp->if_xname, minor(dev), tp->tap_flags);
85363803Snsayer
85463670Snsayer		return (EHOSTDOWN);
85563670Snsayer	}
85663670Snsayer
85763670Snsayer	tp->tap_flags &= ~TAP_RWAIT;
858127098Srwatson	mtx_unlock(&tp->tap_mtx);
85963670Snsayer
86063670Snsayer	/* sleep until we get a packet */
86163670Snsayer	do {
86263670Snsayer		s = splimp();
86390227Sdillon		IF_DEQUEUE(&ifp->if_snd, m);
86463670Snsayer		splx(s);
86563670Snsayer
86690227Sdillon		if (m == NULL) {
867139207Sphk			if (flag & O_NONBLOCK)
86863670Snsayer				return (EWOULDBLOCK);
869111742Sdes
870127098Srwatson			mtx_lock(&tp->tap_mtx);
87163670Snsayer			tp->tap_flags |= TAP_RWAIT;
872127098Srwatson			mtx_unlock(&tp->tap_mtx);
873111748Sdes			error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0);
87463670Snsayer			if (error)
87563670Snsayer				return (error);
87663670Snsayer		}
87790227Sdillon	} while (m == NULL);
87863670Snsayer
87963670Snsayer	/* feed packet to bpf */
880106939Ssam	BPF_MTAP(ifp, m);
88163670Snsayer
88263670Snsayer	/* xfer packet to user space */
88390227Sdillon	while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) {
88490227Sdillon		len = min(uio->uio_resid, m->m_len);
88563670Snsayer		if (len == 0)
88663670Snsayer			break;
88763670Snsayer
888111741Sdes		error = uiomove(mtod(m, void *), len, uio);
88990227Sdillon		m = m_free(m);
89063670Snsayer	}
89163670Snsayer
89290227Sdillon	if (m != NULL) {
893121816Sbrooks		TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname,
894121816Sbrooks			minor(dev));
89590227Sdillon		m_freem(m);
89663670Snsayer	}
89763670Snsayer
89863670Snsayer	return (error);
89963670Snsayer} /* tapread */
90063670Snsayer
90163670Snsayer
90263670Snsayer/*
90363670Snsayer * tapwrite
90463670Snsayer *
90563670Snsayer * the cdevsw write interface - an atomic write is a packet - or else!
90663670Snsayer */
90763670Snsayerstatic int
908156783Semaxtapwrite(struct cdev *dev, struct uio *uio, int flag)
90963670Snsayer{
910166443Sbms	struct ether_header	*eh;
91163670Snsayer	struct tap_softc	*tp = dev->si_drv1;
912147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
913137101Sglebius	struct mbuf		*m;
91463670Snsayer
915121816Sbrooks	TAPDEBUG("%s writting, minor = %#x\n",
916121816Sbrooks		ifp->if_xname, minor(dev));
91763670Snsayer
91863670Snsayer	if (uio->uio_resid == 0)
91963670Snsayer		return (0);
92063670Snsayer
92163670Snsayer	if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) {
922121816Sbrooks		TAPDEBUG("%s invalid packet len = %d, minor = %#x\n",
923121816Sbrooks			ifp->if_xname, uio->uio_resid, minor(dev));
92463803Snsayer
92563670Snsayer		return (EIO);
92663670Snsayer	}
92763670Snsayer
928163915Sandre	if ((m = m_uiotombuf(uio, M_DONTWAIT, 0, ETHER_ALIGN,
929163915Sandre	    M_PKTHDR)) == NULL) {
93063670Snsayer		ifp->if_ierrors ++;
931163986Scsjp		return (ENOBUFS);
93263670Snsayer	}
93363670Snsayer
934137101Sglebius	m->m_pkthdr.rcvif = ifp;
935111742Sdes
936166443Sbms	/*
937166443Sbms	 * Only pass a unicast frame to ether_input(), if it would actually
938166443Sbms	 * have been received by non-virtual hardware.
939166443Sbms	 */
940166443Sbms	if (m->m_len < sizeof(struct ether_header)) {
941166443Sbms		m_freem(m);
942166443Sbms		return (0);
943166443Sbms	}
944166443Sbms	eh = mtod(m, struct ether_header *);
945166443Sbms
946166443Sbms	if (eh && (ifp->if_flags & IFF_PROMISC) == 0 &&
947166443Sbms	    !ETHER_IS_MULTICAST(eh->ether_dhost) &&
948166443Sbms	    bcmp(eh->ether_dhost, IF_LLADDR(ifp), ETHER_ADDR_LEN) != 0) {
949166443Sbms		m_freem(m);
950166443Sbms		return (0);
951166443Sbms	}
952166443Sbms
953106939Ssam	/* Pass packet up to parent. */
954137101Sglebius	(*ifp->if_input)(ifp, m);
955106939Ssam	ifp->if_ipackets ++; /* ibytes are counted in parent */
95663670Snsayer
95763670Snsayer	return (0);
95863670Snsayer} /* tapwrite */
95963670Snsayer
96063670Snsayer
96163670Snsayer/*
96263670Snsayer * tappoll
96363670Snsayer *
96463670Snsayer * the poll interface, this is only useful on reads
96563670Snsayer * really. the write detect always returns true, write never blocks
96663670Snsayer * anyway, it either accepts the packet or drops it
96763670Snsayer */
96863670Snsayerstatic int
969156783Semaxtappoll(struct cdev *dev, int events, struct thread *td)
97063670Snsayer{
97163670Snsayer	struct tap_softc	*tp = dev->si_drv1;
972147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
973111742Sdes	int			 s, revents = 0;
97463670Snsayer
975121816Sbrooks	TAPDEBUG("%s polling, minor = %#x\n",
976121816Sbrooks		ifp->if_xname, minor(dev));
97763670Snsayer
97863670Snsayer	s = splimp();
97963670Snsayer	if (events & (POLLIN | POLLRDNORM)) {
98063670Snsayer		if (ifp->if_snd.ifq_len > 0) {
981121816Sbrooks			TAPDEBUG("%s have data in queue. len = %d, " \
982121816Sbrooks				"minor = %#x\n", ifp->if_xname,
98383043Sbrooks				ifp->if_snd.ifq_len, minor(dev));
98463803Snsayer
98563670Snsayer			revents |= (events & (POLLIN | POLLRDNORM));
98683043Sbrooks		} else {
987121816Sbrooks			TAPDEBUG("%s waiting for data, minor = %#x\n",
988121816Sbrooks				ifp->if_xname, minor(dev));
98963803Snsayer
99083805Sjhb			selrecord(td, &tp->tap_rsel);
99163670Snsayer		}
99263670Snsayer	}
99363670Snsayer
99463670Snsayer	if (events & (POLLOUT | POLLWRNORM))
99563670Snsayer		revents |= (events & (POLLOUT | POLLWRNORM));
99663670Snsayer
99763670Snsayer	splx(s);
99863670Snsayer	return (revents);
99963670Snsayer} /* tappoll */
1000156783Semax
1001156783Semax
1002156783Semax/*
1003156783Semax * tap_kqfilter
1004156783Semax *
1005156783Semax * support for kevent() system call
1006156783Semax */
1007156783Semaxstatic int
1008156783Semaxtapkqfilter(struct cdev *dev, struct knote *kn)
1009156783Semax{
1010156783Semax    	int			 s;
1011156783Semax	struct tap_softc	*tp = dev->si_drv1;
1012156783Semax	struct ifnet		*ifp = tp->tap_ifp;
1013156783Semax
1014156783Semax	s = splimp();
1015156783Semax	switch (kn->kn_filter) {
1016156783Semax	case EVFILT_READ:
1017156783Semax		TAPDEBUG("%s kqfilter: EVFILT_READ, minor = %#x\n",
1018156783Semax			ifp->if_xname, minor(dev));
1019156783Semax		kn->kn_fop = &tap_read_filterops;
1020156783Semax		break;
1021156783Semax
1022156783Semax	case EVFILT_WRITE:
1023156783Semax		TAPDEBUG("%s kqfilter: EVFILT_WRITE, minor = %#x\n",
1024156783Semax			ifp->if_xname, minor(dev));
1025156783Semax		kn->kn_fop = &tap_write_filterops;
1026156783Semax		break;
1027156783Semax
1028156783Semax	default:
1029156783Semax		TAPDEBUG("%s kqfilter: invalid filter, minor = %#x\n",
1030156783Semax			ifp->if_xname, minor(dev));
1031156783Semax		splx(s);
1032156783Semax		return (EINVAL);
1033156783Semax		/* NOT REACHED */
1034156783Semax	}
1035156783Semax	splx(s);
1036156783Semax
1037156783Semax	kn->kn_hook = (caddr_t) dev;
1038156783Semax	knlist_add(&tp->tap_rsel.si_note, kn, 0);
1039156783Semax
1040156783Semax	return (0);
1041156783Semax} /* tapkqfilter */
1042156783Semax
1043156783Semax
1044156783Semax/*
1045156783Semax * tap_kqread
1046156783Semax *
1047156783Semax * Return true if there is data in the interface queue
1048156783Semax */
1049156783Semaxstatic int
1050156783Semaxtapkqread(struct knote *kn, long hint)
1051156783Semax{
1052156783Semax	int			 ret, s;
1053156783Semax	struct cdev		*dev = (struct cdev *)(kn->kn_hook);
1054156783Semax	struct tap_softc	*tp = dev->si_drv1;
1055156783Semax	struct ifnet		*ifp = tp->tap_ifp;
1056156783Semax
1057156783Semax	s = splimp();
1058156783Semax	if ((kn->kn_data = ifp->if_snd.ifq_len) > 0) {
1059156783Semax		TAPDEBUG("%s have data in queue. len = %d, minor = %#x\n",
1060156783Semax			ifp->if_xname, ifp->if_snd.ifq_len, minor(dev));
1061156783Semax		ret = 1;
1062156783Semax	} else {
1063156783Semax		TAPDEBUG("%s waiting for data, minor = %#x\n",
1064156783Semax			ifp->if_xname, minor(dev));
1065156783Semax		ret = 0;
1066156783Semax	}
1067156783Semax	splx(s);
1068156783Semax
1069156783Semax	return (ret);
1070156783Semax} /* tapkqread */
1071156783Semax
1072156783Semax
1073156783Semax/*
1074156783Semax * tap_kqwrite
1075156783Semax *
1076156783Semax * Always can write. Return the MTU in kn->data
1077156783Semax */
1078156783Semaxstatic int
1079156783Semaxtapkqwrite(struct knote *kn, long hint)
1080156783Semax{
1081156783Semax	int			 s;
1082156783Semax	struct tap_softc	*tp = ((struct cdev *) kn->kn_hook)->si_drv1;
1083156783Semax	struct ifnet		*ifp = tp->tap_ifp;
1084156783Semax
1085156783Semax	s = splimp();
1086156783Semax	kn->kn_data = ifp->if_mtu;
1087156783Semax	splx(s);
1088156783Semax
1089156783Semax	return (1);
1090156783Semax} /* tapkqwrite */
1091156783Semax
1092156783Semax
1093156783Semaxstatic void
1094156783Semaxtapkqdetach(struct knote *kn)
1095156783Semax{
1096156783Semax	struct tap_softc	*tp = ((struct cdev *) kn->kn_hook)->si_drv1;
1097156783Semax
1098156783Semax	knlist_remove(&tp->tap_rsel.si_note, kn, 0);
1099156783Semax} /* tapkqdetach */
1100156783Semax
1101