if_tap.c revision 166443
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 166443 2007-02-03 02:57:45Z 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>
65152315Sru#include <net/if_dl.h>
6663670Snsayer#include <net/route.h>
67147256Sbrooks#include <net/if_types.h>
6863670Snsayer
6963670Snsayer#include <netinet/in.h>
7063670Snsayer
7163670Snsayer#include <net/if_tapvar.h>
7263670Snsayer#include <net/if_tap.h>
7363670Snsayer
7463670Snsayer
7563670Snsayer#define CDEV_NAME	"tap"
7663670Snsayer#define TAPDEBUG	if (tapdebug) printf
7763670Snsayer
7863670Snsayer#define TAP		"tap"
7963670Snsayer#define VMNET		"vmnet"
8083043Sbrooks#define TAPMAXUNIT	0x7fff
81126077Sphk#define VMNET_DEV_MASK	CLONE_FLAG0
8263670Snsayer
8363670Snsayer/* module */
84111742Sdesstatic int		tapmodevent(module_t, int, void *);
8563670Snsayer
8663670Snsayer/* device */
87148868Srwatsonstatic void		tapclone(void *, struct ucred *, char *, int,
88148868Srwatson			    struct cdev **);
89130585Sphkstatic void		tapcreate(struct cdev *);
9063670Snsayer
9163670Snsayer/* network interface */
9293084Sbdestatic void		tapifstart(struct ifnet *);
9393084Sbdestatic int		tapifioctl(struct ifnet *, u_long, caddr_t);
9493084Sbdestatic void		tapifinit(void *);
9563670Snsayer
9663670Snsayer/* character device */
9763670Snsayerstatic d_open_t		tapopen;
9863670Snsayerstatic d_close_t	tapclose;
9963670Snsayerstatic d_read_t		tapread;
10063670Snsayerstatic d_write_t	tapwrite;
10163670Snsayerstatic d_ioctl_t	tapioctl;
10263670Snsayerstatic d_poll_t		tappoll;
103156783Semaxstatic d_kqfilter_t	tapkqfilter;
10463670Snsayer
105156783Semax/* kqueue(2) */
106156783Semaxstatic int		tapkqread(struct knote *, long);
107156783Semaxstatic int		tapkqwrite(struct knote *, long);
108156783Semaxstatic void		tapkqdetach(struct knote *);
109156783Semax
110156783Semaxstatic struct filterops	tap_read_filterops = {
111156783Semax	.f_isfd =	1,
112156783Semax	.f_attach =	NULL,
113156783Semax	.f_detach =	tapkqdetach,
114156783Semax	.f_event =	tapkqread,
115156783Semax};
116156783Semax
117156783Semaxstatic struct filterops	tap_write_filterops = {
118156783Semax	.f_isfd =	1,
119156783Semax	.f_attach =	NULL,
120156783Semax	.f_detach =	tapkqdetach,
121156783Semax	.f_event =	tapkqwrite,
122156783Semax};
123156783Semax
12463670Snsayerstatic struct cdevsw	tap_cdevsw = {
125126080Sphk	.d_version =	D_VERSION,
126126188Sbde	.d_flags =	D_PSEUDO | D_NEEDGIANT,
127111815Sphk	.d_open =	tapopen,
128111815Sphk	.d_close =	tapclose,
129111815Sphk	.d_read =	tapread,
130111815Sphk	.d_write =	tapwrite,
131111815Sphk	.d_ioctl =	tapioctl,
132111815Sphk	.d_poll =	tappoll,
133111815Sphk	.d_name =	CDEV_NAME,
134156783Semax	.d_kqfilter =	tapkqfilter,
13563670Snsayer};
13663670Snsayer
137127003Srwatson/*
138127003Srwatson * All global variables in if_tap.c are locked with tapmtx, with the
139127003Srwatson * exception of tapdebug, which is accessed unlocked; tapclones is
140127003Srwatson * static at runtime.
141127003Srwatson */
142127003Srwatsonstatic struct mtx		tapmtx;
14383043Sbrooksstatic int			tapdebug = 0;        /* debug flag   */
144144979Smdoddstatic int			tapuopen = 0;        /* allow user open() */
14583043Sbrooksstatic SLIST_HEAD(, tap_softc)	taphead;             /* first device */
146126077Sphkstatic struct clonedevs 	*tapclones;
14763670Snsayer
14863670SnsayerMALLOC_DECLARE(M_TAP);
14963670SnsayerMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface");
15063670SnsayerSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, "");
151144979Smdodd
152144979SmdoddSYSCTL_DECL(_net_link);
153144979SmdoddSYSCTL_NODE(_net_link, OID_AUTO, tap, CTLFLAG_RW, 0,
154144979Smdodd    "Ethernet tunnel software network interface");
155144979SmdoddSYSCTL_INT(_net_link_tap, OID_AUTO, user_open, CTLFLAG_RW, &tapuopen, 0,
156144979Smdodd	"Allow user to open /dev/tap (based on node permissions)");
157144979SmdoddSYSCTL_INT(_net_link_tap, OID_AUTO, debug, CTLFLAG_RW, &tapdebug, 0, "");
158144979Smdodd
15963670SnsayerDEV_MODULE(if_tap, tapmodevent, NULL);
16063670Snsayer
16163670Snsayer/*
16263670Snsayer * tapmodevent
16363670Snsayer *
16463670Snsayer * module event handler
16563670Snsayer */
16663670Snsayerstatic int
167156783Semaxtapmodevent(module_t mod, int type, void *data)
16863670Snsayer{
16983043Sbrooks	static eventhandler_tag	 eh_tag = NULL;
17083043Sbrooks	struct tap_softc	*tp = NULL;
17183043Sbrooks	struct ifnet		*ifp = NULL;
172126077Sphk	int			 s;
17363670Snsayer
17463670Snsayer	switch (type) {
17563670Snsayer	case MOD_LOAD:
17663670Snsayer
17783043Sbrooks		/* intitialize device */
17883043Sbrooks
179127003Srwatson		mtx_init(&tapmtx, "tapmtx", NULL, MTX_DEF);
18083043Sbrooks		SLIST_INIT(&taphead);
18183043Sbrooks
182126845Sphk		clone_setup(&tapclones);
18371602Sphk		eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000);
184127003Srwatson		if (eh_tag == NULL) {
185127170Srwatson			clone_cleanup(&tapclones);
186127003Srwatson			mtx_destroy(&tapmtx);
187126077Sphk			return (ENOMEM);
188127003Srwatson		}
18983043Sbrooks		return (0);
19063670Snsayer
19183043Sbrooks	case MOD_UNLOAD:
192127003Srwatson		/*
193127003Srwatson		 * The EBUSY algorithm here can't quite atomically
194127003Srwatson		 * guarantee that this is race-free since we have to
195127003Srwatson		 * release the tap mtx to deregister the clone handler.
196127003Srwatson		 */
197127003Srwatson		mtx_lock(&tapmtx);
198127003Srwatson		SLIST_FOREACH(tp, &taphead, tap_next) {
199127098Srwatson			mtx_lock(&tp->tap_mtx);
200127003Srwatson			if (tp->tap_flags & TAP_OPEN) {
201127098Srwatson				mtx_unlock(&tp->tap_mtx);
202127003Srwatson				mtx_unlock(&tapmtx);
20383043Sbrooks				return (EBUSY);
204127003Srwatson			}
205127098Srwatson			mtx_unlock(&tp->tap_mtx);
206127003Srwatson		}
207127003Srwatson		mtx_unlock(&tapmtx);
20883043Sbrooks
20971602Sphk		EVENTHANDLER_DEREGISTER(dev_clone, eh_tag);
21063670Snsayer
211127003Srwatson		mtx_lock(&tapmtx);
21283043Sbrooks		while ((tp = SLIST_FIRST(&taphead)) != NULL) {
21383043Sbrooks			SLIST_REMOVE_HEAD(&taphead, tap_next);
214127003Srwatson			mtx_unlock(&tapmtx);
21583043Sbrooks
216147256Sbrooks			ifp = tp->tap_ifp;
21783043Sbrooks
218121816Sbrooks			TAPDEBUG("detaching %s\n", ifp->if_xname);
21983043Sbrooks
220127098Srwatson			/* Unlocked read. */
221121816Sbrooks			KASSERT(!(tp->tap_flags & TAP_OPEN),
222121816Sbrooks				("%s flags is out of sync", ifp->if_xname));
22383043Sbrooks
224158697Semax			knlist_destroy(&tp->tap_rsel.si_note);
225126077Sphk			destroy_dev(tp->tap_dev);
22663670Snsayer			s = splimp();
227106939Ssam			ether_ifdetach(ifp);
228147256Sbrooks			if_free_type(ifp, IFT_ETHER);
22963670Snsayer			splx(s);
23063670Snsayer
231127098Srwatson			mtx_destroy(&tp->tap_mtx);
23293752Sluigi			free(tp, M_TAP);
233127003Srwatson			mtx_lock(&tapmtx);
23483043Sbrooks		}
235127003Srwatson		mtx_unlock(&tapmtx);
236126077Sphk		clone_cleanup(&tapclones);
23763670Snsayer
238135354Srwatson		mtx_destroy(&tapmtx);
239135354Srwatson
24083043Sbrooks		break;
24163670Snsayer
24263670Snsayer	default:
24363670Snsayer		return (EOPNOTSUPP);
24463670Snsayer	}
24563670Snsayer
24663670Snsayer	return (0);
24763670Snsayer} /* tapmodevent */
24863670Snsayer
24963670Snsayer
25063670Snsayer/*
25171602Sphk * DEVFS handler
25271602Sphk *
25371602Sphk * We need to support two kind of devices - tap and vmnet
25471602Sphk */
25571602Sphkstatic void
256156783Semaxtapclone(void *arg, struct ucred *cred, char *name, int namelen, struct cdev **dev)
25771602Sphk{
258166438Sbms	int		extra;
259126077Sphk	int		i, unit;
26083043Sbrooks	char		*device_name = name;
26171602Sphk
262130640Sphk	if (*dev != NULL)
26371602Sphk		return;
26471602Sphk
265126077Sphk	device_name = TAP;
266126077Sphk	extra = 0;
267126077Sphk	if (strcmp(name, TAP) == 0) {
268126077Sphk		unit = -1;
269126077Sphk	} else if (strcmp(name, VMNET) == 0) {
270126077Sphk		device_name = VMNET;
271126077Sphk		extra = VMNET_DEV_MASK;
272126077Sphk		unit = -1;
273126077Sphk	} else if (dev_stdclone(name, NULL, device_name, &unit) != 1) {
274126077Sphk		device_name = VMNET;
275126077Sphk		extra = VMNET_DEV_MASK;
276126077Sphk		if (dev_stdclone(name, NULL, device_name, &unit) != 1)
277126077Sphk			return;
27883043Sbrooks	}
27971602Sphk
280126077Sphk	/* find any existing device, or allocate new unit number */
281126077Sphk	i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra);
282126077Sphk	if (i) {
283126796Sphk		*dev = make_dev(&tap_cdevsw, unit2minor(unit | extra),
284126077Sphk		     UID_ROOT, GID_WHEEL, 0600, "%s%d", device_name, unit);
285144389Sphk		if (*dev != NULL) {
286144389Sphk			dev_ref(*dev);
287126077Sphk			(*dev)->si_flags |= SI_CHEAPCLONE;
288144389Sphk		}
28971602Sphk	}
29071602Sphk} /* tapclone */
29171602Sphk
29271602Sphk
29371602Sphk/*
29463670Snsayer * tapcreate
29563670Snsayer *
29663670Snsayer * to create interface
29763670Snsayer */
29863670Snsayerstatic void
299156783Semaxtapcreate(struct cdev *dev)
30063670Snsayer{
30163670Snsayer	struct ifnet		*ifp = NULL;
30263670Snsayer	struct tap_softc	*tp = NULL;
30363670Snsayer	unsigned short		 macaddr_hi;
30463803Snsayer	int			 unit, s;
30563670Snsayer	char			*name = NULL;
306147256Sbrooks	u_char			eaddr[6];
30763670Snsayer
308126077Sphk	dev->si_flags &= ~SI_CHEAPCLONE;
309126077Sphk
31063670Snsayer	/* allocate driver storage and create device */
311111119Simp	MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO);
312127098Srwatson	mtx_init(&tp->tap_mtx, "tap_mtx", NULL, MTX_DEF);
313127003Srwatson	mtx_lock(&tapmtx);
31483043Sbrooks	SLIST_INSERT_HEAD(&taphead, tp, tap_next);
315127003Srwatson	mtx_unlock(&tapmtx);
31663670Snsayer
317126796Sphk	unit = dev2unit(dev);
31883043Sbrooks
31963670Snsayer	/* select device: tap or vmnet */
320126796Sphk	if (unit & VMNET_DEV_MASK) {
32163670Snsayer		name = VMNET;
32263803Snsayer		tp->tap_flags |= TAP_VMNET;
32383043Sbrooks	} else
32463670Snsayer		name = TAP;
32563670Snsayer
326126796Sphk	unit &= TAPMAXUNIT;
327126796Sphk
32883043Sbrooks	TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev));
32983043Sbrooks
33063670Snsayer	/* generate fake MAC address: 00 bd xx xx xx unit_no */
33163670Snsayer	macaddr_hi = htons(0x00bd);
332147256Sbrooks	bcopy(&macaddr_hi, eaddr, sizeof(short));
333147256Sbrooks	bcopy(&ticks, &eaddr[2], sizeof(long));
334147256Sbrooks	eaddr[5] = (u_char)unit;
33563670Snsayer
336111742Sdes	/* fill the rest and attach interface */
337147256Sbrooks	ifp = tp->tap_ifp = if_alloc(IFT_ETHER);
338147256Sbrooks	if (ifp == NULL)
339147256Sbrooks		panic("%s%d: can not if_alloc()", name, unit);
34063670Snsayer	ifp->if_softc = tp;
341121816Sbrooks	if_initname(ifp, name, unit);
34263670Snsayer	ifp->if_init = tapifinit;
34363670Snsayer	ifp->if_start = tapifstart;
34463670Snsayer	ifp->if_ioctl = tapifioctl;
34563670Snsayer	ifp->if_mtu = ETHERMTU;
34663670Snsayer	ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
34763670Snsayer	ifp->if_snd.ifq_maxlen = ifqmaxlen;
34863670Snsayer
34983043Sbrooks	dev->si_drv1 = tp;
350126077Sphk	tp->tap_dev = dev;
35183043Sbrooks
35263803Snsayer	s = splimp();
353147256Sbrooks	ether_ifattach(ifp, eaddr);
35463803Snsayer	splx(s);
35563670Snsayer
356127098Srwatson	mtx_lock(&tp->tap_mtx);
35763803Snsayer	tp->tap_flags |= TAP_INITED;
358127098Srwatson	mtx_unlock(&tp->tap_mtx);
35963803Snsayer
360158697Semax	knlist_init(&tp->tap_rsel.si_note, NULL, NULL, NULL, NULL);
361158697Semax
362121816Sbrooks	TAPDEBUG("interface %s is created. minor = %#x\n",
363121816Sbrooks		ifp->if_xname, minor(dev));
36463670Snsayer} /* tapcreate */
36563670Snsayer
36663670Snsayer
36763670Snsayer/*
368111742Sdes * tapopen
36963670Snsayer *
37063670Snsayer * to open tunnel. must be superuser
37163670Snsayer */
37263670Snsayerstatic int
373156783Semaxtapopen(struct cdev *dev, int flag, int mode, struct thread *td)
37463670Snsayer{
37563670Snsayer	struct tap_softc	*tp = NULL;
376133460Semax	struct ifnet		*ifp = NULL;
377164033Srwatson	int			 error, s;
37863670Snsayer
379164033Srwatson	if (tapuopen == 0) {
380164033Srwatson		error = priv_check(td, PRIV_NET_TAP);
381164033Srwatson		if (error)
382164033Srwatson			return (error);
383164033Srwatson	}
38463670Snsayer
385126796Sphk	if ((dev2unit(dev) & CLONE_UNITMASK) > TAPMAXUNIT)
386126796Sphk		return (ENXIO);
38783043Sbrooks
388127165Srwatson	/*
389127165Srwatson	 * XXXRW: Non-atomic test-and-set of si_drv1.  Currently protected
390127165Srwatson	 * by Giant, but the race actually exists under memory pressure as
391127165Srwatson	 * well even when running with Giant, as malloc() may sleep.
392127165Srwatson	 */
39363670Snsayer	tp = dev->si_drv1;
39463670Snsayer	if (tp == NULL) {
39563670Snsayer		tapcreate(dev);
39663670Snsayer		tp = dev->si_drv1;
39763670Snsayer	}
39863670Snsayer
399127165Srwatson	mtx_lock(&tp->tap_mtx);
400127165Srwatson	if (tp->tap_flags & TAP_OPEN) {
401127165Srwatson		mtx_unlock(&tp->tap_mtx);
402127165Srwatson		return (EBUSY);
403127165Srwatson	}
40463670Snsayer
405152315Sru	bcopy(IF_LLADDR(tp->tap_ifp), tp->ether_addr, sizeof(tp->ether_addr));
40683366Sjulian	tp->tap_pid = td->td_proc->p_pid;
40763670Snsayer	tp->tap_flags |= TAP_OPEN;
408147256Sbrooks	ifp = tp->tap_ifp;
409127098Srwatson	mtx_unlock(&tp->tap_mtx);
41063670Snsayer
411133460Semax	s = splimp();
412148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
413148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
414133460Semax	splx(s);
41563670Snsayer
416133460Semax	TAPDEBUG("%s is open. minor = %#x\n", ifp->if_xname, minor(dev));
417133460Semax
41863670Snsayer	return (0);
41963670Snsayer} /* tapopen */
42063670Snsayer
42163670Snsayer
42263670Snsayer/*
42363670Snsayer * tapclose
42463670Snsayer *
42563670Snsayer * close the device - mark i/f down & delete routing info
42663670Snsayer */
42763670Snsayerstatic int
428156783Semaxtapclose(struct cdev *dev, int foo, int bar, struct thread *td)
42963670Snsayer{
430156783Semax	struct ifaddr		*ifa;
43163670Snsayer	struct tap_softc	*tp = dev->si_drv1;
432147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
433126077Sphk	int			s;
43463670Snsayer
43563670Snsayer	/* junk all pending output */
43683043Sbrooks	IF_DRAIN(&ifp->if_snd);
43763670Snsayer
43863803Snsayer	/*
43963803Snsayer	 * do not bring the interface down, and do not anything with
44063803Snsayer	 * interface, if we are in VMnet mode. just close the device.
44163803Snsayer	 */
44263803Snsayer
443127098Srwatson	mtx_lock(&tp->tap_mtx);
44463803Snsayer	if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) {
445127098Srwatson		mtx_unlock(&tp->tap_mtx);
44663670Snsayer		s = splimp();
44763670Snsayer		if_down(ifp);
448148887Srwatson		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
44963803Snsayer			TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
450146620Speadar				rtinit(ifa, (int)RTM_DELETE, 0);
45163670Snsayer			}
452146620Speadar			if_purgeaddrs(ifp);
453148887Srwatson			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
45463670Snsayer		}
45563670Snsayer		splx(s);
456127098Srwatson	} else
457127098Srwatson		mtx_unlock(&tp->tap_mtx);
45863670Snsayer
45996122Salfred	funsetown(&tp->tap_sigio);
460122352Stanimura	selwakeuppri(&tp->tap_rsel, PZERO+1);
461156783Semax	KNOTE_UNLOCKED(&tp->tap_rsel.si_note, 0);
46263670Snsayer
463127098Srwatson	mtx_lock(&tp->tap_mtx);
46463670Snsayer	tp->tap_flags &= ~TAP_OPEN;
46563670Snsayer	tp->tap_pid = 0;
466127098Srwatson	mtx_unlock(&tp->tap_mtx);
46763670Snsayer
468121816Sbrooks	TAPDEBUG("%s is closed. minor = %#x\n",
469121816Sbrooks		ifp->if_xname, minor(dev));
47063670Snsayer
47163670Snsayer	return (0);
47263670Snsayer} /* tapclose */
47363670Snsayer
47463670Snsayer
47563670Snsayer/*
47663670Snsayer * tapifinit
47763670Snsayer *
47863670Snsayer * network interface initialization function
47963670Snsayer */
48063670Snsayerstatic void
481156783Semaxtapifinit(void *xtp)
48263670Snsayer{
48363670Snsayer	struct tap_softc	*tp = (struct tap_softc *)xtp;
484147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
48563670Snsayer
486121816Sbrooks	TAPDEBUG("initializing %s\n", ifp->if_xname);
48763670Snsayer
488148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
489148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
49063670Snsayer
49163670Snsayer	/* attempt to start output */
49263670Snsayer	tapifstart(ifp);
49363670Snsayer} /* tapifinit */
49463670Snsayer
49563670Snsayer
49663670Snsayer/*
49763670Snsayer * tapifioctl
49863670Snsayer *
49963670Snsayer * Process an ioctl request on network interface
50063670Snsayer */
501105228Sphkstatic int
502156783Semaxtapifioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
50363670Snsayer{
504160376Sbrooks	struct tap_softc	*tp = ifp->if_softc;
50563670Snsayer	struct ifstat		*ifs = NULL;
50663670Snsayer	int			 s, dummy;
50763670Snsayer
50863670Snsayer	switch (cmd) {
50963670Snsayer		case SIOCSIFFLAGS: /* XXX -- just like vmnet does */
51063670Snsayer		case SIOCADDMULTI:
51163670Snsayer		case SIOCDELMULTI:
51283043Sbrooks			break;
51363670Snsayer
51463670Snsayer		case SIOCGIFSTATUS:
51563670Snsayer			s = splimp();
51663670Snsayer			ifs = (struct ifstat *)data;
51763670Snsayer			dummy = strlen(ifs->ascii);
518127098Srwatson			mtx_lock(&tp->tap_mtx);
51963670Snsayer			if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii))
52063670Snsayer				snprintf(ifs->ascii + dummy,
52163670Snsayer					sizeof(ifs->ascii) - dummy,
52263670Snsayer					"\tOpened by PID %d\n", tp->tap_pid);
523127098Srwatson			mtx_unlock(&tp->tap_mtx);
52463670Snsayer			splx(s);
52583043Sbrooks			break;
52663670Snsayer
52763670Snsayer		default:
528106939Ssam			s = splimp();
529106939Ssam			dummy = ether_ioctl(ifp, cmd, data);
530106939Ssam			splx(s);
531106939Ssam			return (dummy);
532156783Semax			/* NOT REACHED */
53363670Snsayer	}
53463670Snsayer
53563670Snsayer	return (0);
53663670Snsayer} /* tapifioctl */
53763670Snsayer
53863670Snsayer
53963670Snsayer/*
540111742Sdes * tapifstart
541111742Sdes *
54263670Snsayer * queue packets from higher level ready to put out
54363670Snsayer */
54463670Snsayerstatic void
545156783Semaxtapifstart(struct ifnet *ifp)
54663670Snsayer{
54763670Snsayer	struct tap_softc	*tp = ifp->if_softc;
54863670Snsayer	int			 s;
54963670Snsayer
550121816Sbrooks	TAPDEBUG("%s starting\n", ifp->if_xname);
55163670Snsayer
55263803Snsayer	/*
55363803Snsayer	 * do not junk pending output if we are in VMnet mode.
55463803Snsayer	 * XXX: can this do any harm because of queue overflow?
55563803Snsayer	 */
55663803Snsayer
557127098Srwatson	mtx_lock(&tp->tap_mtx);
558111742Sdes	if (((tp->tap_flags & TAP_VMNET) == 0) &&
55963803Snsayer	    ((tp->tap_flags & TAP_READY) != TAP_READY)) {
56063670Snsayer		struct mbuf	*m = NULL;
56163670Snsayer
562127098Srwatson		mtx_unlock(&tp->tap_mtx);
563127098Srwatson
564127098Srwatson		/* Unlocked read. */
565121816Sbrooks		TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname,
566121816Sbrooks		    tp->tap_flags);
56763670Snsayer
56863670Snsayer		s = splimp();
56963670Snsayer		do {
57063670Snsayer			IF_DEQUEUE(&ifp->if_snd, m);
57163670Snsayer			if (m != NULL)
57263670Snsayer				m_freem(m);
57363670Snsayer			ifp->if_oerrors ++;
57463670Snsayer		} while (m != NULL);
57563670Snsayer		splx(s);
57663670Snsayer
57763670Snsayer		return;
57863670Snsayer	}
579127098Srwatson	mtx_unlock(&tp->tap_mtx);
58063670Snsayer
58163670Snsayer	s = splimp();
582148887Srwatson	ifp->if_drv_flags |= IFF_DRV_OACTIVE;
58363670Snsayer
58463670Snsayer	if (ifp->if_snd.ifq_len != 0) {
585127098Srwatson		mtx_lock(&tp->tap_mtx);
58663670Snsayer		if (tp->tap_flags & TAP_RWAIT) {
58763670Snsayer			tp->tap_flags &= ~TAP_RWAIT;
588111748Sdes			wakeup(tp);
58963670Snsayer		}
59063670Snsayer
591127098Srwatson		if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) {
592127098Srwatson			mtx_unlock(&tp->tap_mtx);
59395883Salfred			pgsigio(&tp->tap_sigio, SIGIO, 0);
594127098Srwatson		} else
595127098Srwatson			mtx_unlock(&tp->tap_mtx);
59663670Snsayer
597122352Stanimura		selwakeuppri(&tp->tap_rsel, PZERO+1);
598156783Semax		KNOTE_UNLOCKED(&tp->tap_rsel.si_note, 0);
59963670Snsayer		ifp->if_opackets ++; /* obytes are counted in ether_output */
60063670Snsayer	}
60163670Snsayer
602148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
60363670Snsayer	splx(s);
60463670Snsayer} /* tapifstart */
60563670Snsayer
60663670Snsayer
60763670Snsayer/*
60863670Snsayer * tapioctl
60963670Snsayer *
61063670Snsayer * the cdevsw interface is now pretty minimal
61163670Snsayer */
61263670Snsayerstatic int
613156783Semaxtapioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
61463670Snsayer{
61563670Snsayer	struct tap_softc	*tp = dev->si_drv1;
616147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
617111742Sdes	struct tapinfo		*tapp = NULL;
61863670Snsayer	int			 s;
619102052Ssobomax	int			 f;
620162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
621162711Sru    defined(COMPAT_FREEBSD4)
622162711Sru	int			 ival;
623162711Sru#endif
62463670Snsayer
62563670Snsayer	switch (cmd) {
626111742Sdes		case TAPSIFINFO:
62763670Snsayer			s = splimp();
628111742Sdes			tapp = (struct tapinfo *)data;
629111742Sdes			ifp->if_mtu = tapp->mtu;
630111742Sdes			ifp->if_type = tapp->type;
631111742Sdes			ifp->if_baudrate = tapp->baudrate;
63263670Snsayer			splx(s);
633111742Sdes			break;
63463670Snsayer
635111742Sdes		case TAPGIFINFO:
636111742Sdes			tapp = (struct tapinfo *)data;
637111742Sdes			tapp->mtu = ifp->if_mtu;
638111742Sdes			tapp->type = ifp->if_type;
639111742Sdes			tapp->baudrate = ifp->if_baudrate;
640111742Sdes			break;
64163670Snsayer
64263670Snsayer		case TAPSDEBUG:
643159079Smarius			tapdebug = *(int *)data;
64483043Sbrooks			break;
64563670Snsayer
64663670Snsayer		case TAPGDEBUG:
647159079Smarius			*(int *)data = tapdebug;
64883043Sbrooks			break;
64963670Snsayer
65063670Snsayer		case FIONBIO:
65183043Sbrooks			break;
65263670Snsayer
65363670Snsayer		case FIOASYNC:
65463803Snsayer			s = splimp();
655127098Srwatson			mtx_lock(&tp->tap_mtx);
656159079Smarius			if (*(int *)data)
65763670Snsayer				tp->tap_flags |= TAP_ASYNC;
65863670Snsayer			else
65963670Snsayer				tp->tap_flags &= ~TAP_ASYNC;
660127098Srwatson			mtx_unlock(&tp->tap_mtx);
66163803Snsayer			splx(s);
66283043Sbrooks			break;
66363670Snsayer
66463670Snsayer		case FIONREAD:
66563670Snsayer			s = splimp();
66663670Snsayer			if (ifp->if_snd.ifq_head) {
66763670Snsayer				struct mbuf	*mb = ifp->if_snd.ifq_head;
66863670Snsayer
669159079Smarius				for(*(int *)data = 0;mb != NULL;mb = mb->m_next)
670159079Smarius					*(int *)data += mb->m_len;
67183043Sbrooks			} else
672159079Smarius				*(int *)data = 0;
67363670Snsayer			splx(s);
67483043Sbrooks			break;
67563670Snsayer
67663670Snsayer		case FIOSETOWN:
677159079Smarius			return (fsetown(*(int *)data, &tp->tap_sigio));
67863670Snsayer
67963670Snsayer		case FIOGETOWN:
680159079Smarius			*(int *)data = fgetown(&tp->tap_sigio);
68163670Snsayer			return (0);
68263670Snsayer
68363670Snsayer		/* this is deprecated, FIOSETOWN should be used instead */
68463670Snsayer		case TIOCSPGRP:
685159079Smarius			return (fsetown(-(*(int *)data), &tp->tap_sigio));
68663670Snsayer
68763670Snsayer		/* this is deprecated, FIOGETOWN should be used instead */
68863670Snsayer		case TIOCGPGRP:
689159079Smarius			*(int *)data = -fgetown(&tp->tap_sigio);
69063670Snsayer			return (0);
69163670Snsayer
69263670Snsayer		/* VMware/VMnet port ioctl's */
69363670Snsayer
69463670Snsayer		case SIOCGIFFLAGS:	/* get ifnet flags */
69563670Snsayer			bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags));
69683043Sbrooks			break;
69763670Snsayer
698162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
699162711Sru    defined(COMPAT_FREEBSD4)
700162711Sru		case _IO('V', 0):
701162711Sru			ival = IOCPARM_IVAL(data);
702162711Sru			data = (caddr_t)&ival;
703162711Sru			/* FALLTHROUGH */
704162711Sru#endif
70583043Sbrooks		case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */
706162711Sru			f = *(int *)data;
70763670Snsayer			f &= 0x0fff;
70863670Snsayer			f &= ~IFF_CANTCHANGE;
70963670Snsayer			f |= IFF_UP;
71063670Snsayer
71163670Snsayer			s = splimp();
71263670Snsayer			ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE);
71363670Snsayer			splx(s);
71483043Sbrooks			break;
71563670Snsayer
71663861Snsayer		case OSIOCGIFADDR:	/* get MAC address of the remote side */
71763670Snsayer		case SIOCGIFADDR:
718127165Srwatson			mtx_lock(&tp->tap_mtx);
71963861Snsayer			bcopy(tp->ether_addr, data, sizeof(tp->ether_addr));
720127165Srwatson			mtx_unlock(&tp->tap_mtx);
72183043Sbrooks			break;
72263670Snsayer
72363861Snsayer		case SIOCSIFADDR:	/* set MAC address of the remote side */
724127165Srwatson			mtx_lock(&tp->tap_mtx);
72563861Snsayer			bcopy(data, tp->ether_addr, sizeof(tp->ether_addr));
726127165Srwatson			mtx_unlock(&tp->tap_mtx);
72783043Sbrooks			break;
72863670Snsayer
72963670Snsayer		default:
73063670Snsayer			return (ENOTTY);
73163670Snsayer	}
73263670Snsayer	return (0);
73363670Snsayer} /* tapioctl */
73463670Snsayer
73563670Snsayer
73663670Snsayer/*
73763670Snsayer * tapread
73863670Snsayer *
73963670Snsayer * the cdevsw read interface - reads a packet at a time, or at
74063670Snsayer * least as much of a packet as can be read
74163670Snsayer */
74263670Snsayerstatic int
743156783Semaxtapread(struct cdev *dev, struct uio *uio, int flag)
74463670Snsayer{
74563670Snsayer	struct tap_softc	*tp = dev->si_drv1;
746147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
74790227Sdillon	struct mbuf		*m = NULL;
74863670Snsayer	int			 error = 0, len, s;
74963670Snsayer
750121816Sbrooks	TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, minor(dev));
75163670Snsayer
752127098Srwatson	mtx_lock(&tp->tap_mtx);
75363670Snsayer	if ((tp->tap_flags & TAP_READY) != TAP_READY) {
754127098Srwatson		mtx_unlock(&tp->tap_mtx);
755127098Srwatson
756127098Srwatson		/* Unlocked read. */
757121816Sbrooks		TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n",
758121816Sbrooks			ifp->if_xname, minor(dev), tp->tap_flags);
75963803Snsayer
76063670Snsayer		return (EHOSTDOWN);
76163670Snsayer	}
76263670Snsayer
76363670Snsayer	tp->tap_flags &= ~TAP_RWAIT;
764127098Srwatson	mtx_unlock(&tp->tap_mtx);
76563670Snsayer
76663670Snsayer	/* sleep until we get a packet */
76763670Snsayer	do {
76863670Snsayer		s = splimp();
76990227Sdillon		IF_DEQUEUE(&ifp->if_snd, m);
77063670Snsayer		splx(s);
77163670Snsayer
77290227Sdillon		if (m == NULL) {
773139207Sphk			if (flag & O_NONBLOCK)
77463670Snsayer				return (EWOULDBLOCK);
775111742Sdes
776127098Srwatson			mtx_lock(&tp->tap_mtx);
77763670Snsayer			tp->tap_flags |= TAP_RWAIT;
778127098Srwatson			mtx_unlock(&tp->tap_mtx);
779111748Sdes			error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0);
78063670Snsayer			if (error)
78163670Snsayer				return (error);
78263670Snsayer		}
78390227Sdillon	} while (m == NULL);
78463670Snsayer
78563670Snsayer	/* feed packet to bpf */
786106939Ssam	BPF_MTAP(ifp, m);
78763670Snsayer
78863670Snsayer	/* xfer packet to user space */
78990227Sdillon	while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) {
79090227Sdillon		len = min(uio->uio_resid, m->m_len);
79163670Snsayer		if (len == 0)
79263670Snsayer			break;
79363670Snsayer
794111741Sdes		error = uiomove(mtod(m, void *), len, uio);
79590227Sdillon		m = m_free(m);
79663670Snsayer	}
79763670Snsayer
79890227Sdillon	if (m != NULL) {
799121816Sbrooks		TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname,
800121816Sbrooks			minor(dev));
80190227Sdillon		m_freem(m);
80263670Snsayer	}
80363670Snsayer
80463670Snsayer	return (error);
80563670Snsayer} /* tapread */
80663670Snsayer
80763670Snsayer
80863670Snsayer/*
80963670Snsayer * tapwrite
81063670Snsayer *
81163670Snsayer * the cdevsw write interface - an atomic write is a packet - or else!
81263670Snsayer */
81363670Snsayerstatic int
814156783Semaxtapwrite(struct cdev *dev, struct uio *uio, int flag)
81563670Snsayer{
816166443Sbms	struct ether_header	*eh;
81763670Snsayer	struct tap_softc	*tp = dev->si_drv1;
818147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
819137101Sglebius	struct mbuf		*m;
82063670Snsayer
821121816Sbrooks	TAPDEBUG("%s writting, minor = %#x\n",
822121816Sbrooks		ifp->if_xname, minor(dev));
82363670Snsayer
82463670Snsayer	if (uio->uio_resid == 0)
82563670Snsayer		return (0);
82663670Snsayer
82763670Snsayer	if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) {
828121816Sbrooks		TAPDEBUG("%s invalid packet len = %d, minor = %#x\n",
829121816Sbrooks			ifp->if_xname, uio->uio_resid, minor(dev));
83063803Snsayer
83163670Snsayer		return (EIO);
83263670Snsayer	}
83363670Snsayer
834163915Sandre	if ((m = m_uiotombuf(uio, M_DONTWAIT, 0, ETHER_ALIGN,
835163915Sandre	    M_PKTHDR)) == NULL) {
83663670Snsayer		ifp->if_ierrors ++;
837163986Scsjp		return (ENOBUFS);
83863670Snsayer	}
83963670Snsayer
840137101Sglebius	m->m_pkthdr.rcvif = ifp;
841111742Sdes
842166443Sbms	/*
843166443Sbms	 * Only pass a unicast frame to ether_input(), if it would actually
844166443Sbms	 * have been received by non-virtual hardware.
845166443Sbms	 */
846166443Sbms	if (m->m_len < sizeof(struct ether_header)) {
847166443Sbms		m_freem(m);
848166443Sbms		return (0);
849166443Sbms	}
850166443Sbms	eh = mtod(m, struct ether_header *);
851166443Sbms
852166443Sbms	if (eh && (ifp->if_flags & IFF_PROMISC) == 0 &&
853166443Sbms	    !ETHER_IS_MULTICAST(eh->ether_dhost) &&
854166443Sbms	    bcmp(eh->ether_dhost, IF_LLADDR(ifp), ETHER_ADDR_LEN) != 0) {
855166443Sbms		m_freem(m);
856166443Sbms		return (0);
857166443Sbms	}
858166443Sbms
859106939Ssam	/* Pass packet up to parent. */
860137101Sglebius	(*ifp->if_input)(ifp, m);
861106939Ssam	ifp->if_ipackets ++; /* ibytes are counted in parent */
86263670Snsayer
86363670Snsayer	return (0);
86463670Snsayer} /* tapwrite */
86563670Snsayer
86663670Snsayer
86763670Snsayer/*
86863670Snsayer * tappoll
86963670Snsayer *
87063670Snsayer * the poll interface, this is only useful on reads
87163670Snsayer * really. the write detect always returns true, write never blocks
87263670Snsayer * anyway, it either accepts the packet or drops it
87363670Snsayer */
87463670Snsayerstatic int
875156783Semaxtappoll(struct cdev *dev, int events, struct thread *td)
87663670Snsayer{
87763670Snsayer	struct tap_softc	*tp = dev->si_drv1;
878147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
879111742Sdes	int			 s, revents = 0;
88063670Snsayer
881121816Sbrooks	TAPDEBUG("%s polling, minor = %#x\n",
882121816Sbrooks		ifp->if_xname, minor(dev));
88363670Snsayer
88463670Snsayer	s = splimp();
88563670Snsayer	if (events & (POLLIN | POLLRDNORM)) {
88663670Snsayer		if (ifp->if_snd.ifq_len > 0) {
887121816Sbrooks			TAPDEBUG("%s have data in queue. len = %d, " \
888121816Sbrooks				"minor = %#x\n", ifp->if_xname,
88983043Sbrooks				ifp->if_snd.ifq_len, minor(dev));
89063803Snsayer
89163670Snsayer			revents |= (events & (POLLIN | POLLRDNORM));
89283043Sbrooks		} else {
893121816Sbrooks			TAPDEBUG("%s waiting for data, minor = %#x\n",
894121816Sbrooks				ifp->if_xname, minor(dev));
89563803Snsayer
89683805Sjhb			selrecord(td, &tp->tap_rsel);
89763670Snsayer		}
89863670Snsayer	}
89963670Snsayer
90063670Snsayer	if (events & (POLLOUT | POLLWRNORM))
90163670Snsayer		revents |= (events & (POLLOUT | POLLWRNORM));
90263670Snsayer
90363670Snsayer	splx(s);
90463670Snsayer	return (revents);
90563670Snsayer} /* tappoll */
906156783Semax
907156783Semax
908156783Semax/*
909156783Semax * tap_kqfilter
910156783Semax *
911156783Semax * support for kevent() system call
912156783Semax */
913156783Semaxstatic int
914156783Semaxtapkqfilter(struct cdev *dev, struct knote *kn)
915156783Semax{
916156783Semax    	int			 s;
917156783Semax	struct tap_softc	*tp = dev->si_drv1;
918156783Semax	struct ifnet		*ifp = tp->tap_ifp;
919156783Semax
920156783Semax	s = splimp();
921156783Semax	switch (kn->kn_filter) {
922156783Semax	case EVFILT_READ:
923156783Semax		TAPDEBUG("%s kqfilter: EVFILT_READ, minor = %#x\n",
924156783Semax			ifp->if_xname, minor(dev));
925156783Semax		kn->kn_fop = &tap_read_filterops;
926156783Semax		break;
927156783Semax
928156783Semax	case EVFILT_WRITE:
929156783Semax		TAPDEBUG("%s kqfilter: EVFILT_WRITE, minor = %#x\n",
930156783Semax			ifp->if_xname, minor(dev));
931156783Semax		kn->kn_fop = &tap_write_filterops;
932156783Semax		break;
933156783Semax
934156783Semax	default:
935156783Semax		TAPDEBUG("%s kqfilter: invalid filter, minor = %#x\n",
936156783Semax			ifp->if_xname, minor(dev));
937156783Semax		splx(s);
938156783Semax		return (EINVAL);
939156783Semax		/* NOT REACHED */
940156783Semax	}
941156783Semax	splx(s);
942156783Semax
943156783Semax	kn->kn_hook = (caddr_t) dev;
944156783Semax	knlist_add(&tp->tap_rsel.si_note, kn, 0);
945156783Semax
946156783Semax	return (0);
947156783Semax} /* tapkqfilter */
948156783Semax
949156783Semax
950156783Semax/*
951156783Semax * tap_kqread
952156783Semax *
953156783Semax * Return true if there is data in the interface queue
954156783Semax */
955156783Semaxstatic int
956156783Semaxtapkqread(struct knote *kn, long hint)
957156783Semax{
958156783Semax	int			 ret, s;
959156783Semax	struct cdev		*dev = (struct cdev *)(kn->kn_hook);
960156783Semax	struct tap_softc	*tp = dev->si_drv1;
961156783Semax	struct ifnet		*ifp = tp->tap_ifp;
962156783Semax
963156783Semax	s = splimp();
964156783Semax	if ((kn->kn_data = ifp->if_snd.ifq_len) > 0) {
965156783Semax		TAPDEBUG("%s have data in queue. len = %d, minor = %#x\n",
966156783Semax			ifp->if_xname, ifp->if_snd.ifq_len, minor(dev));
967156783Semax		ret = 1;
968156783Semax	} else {
969156783Semax		TAPDEBUG("%s waiting for data, minor = %#x\n",
970156783Semax			ifp->if_xname, minor(dev));
971156783Semax		ret = 0;
972156783Semax	}
973156783Semax	splx(s);
974156783Semax
975156783Semax	return (ret);
976156783Semax} /* tapkqread */
977156783Semax
978156783Semax
979156783Semax/*
980156783Semax * tap_kqwrite
981156783Semax *
982156783Semax * Always can write. Return the MTU in kn->data
983156783Semax */
984156783Semaxstatic int
985156783Semaxtapkqwrite(struct knote *kn, long hint)
986156783Semax{
987156783Semax	int			 s;
988156783Semax	struct tap_softc	*tp = ((struct cdev *) kn->kn_hook)->si_drv1;
989156783Semax	struct ifnet		*ifp = tp->tap_ifp;
990156783Semax
991156783Semax	s = splimp();
992156783Semax	kn->kn_data = ifp->if_mtu;
993156783Semax	splx(s);
994156783Semax
995156783Semax	return (1);
996156783Semax} /* tapkqwrite */
997156783Semax
998156783Semax
999156783Semaxstatic void
1000156783Semaxtapkqdetach(struct knote *kn)
1001156783Semax{
1002156783Semax	struct tap_softc	*tp = ((struct cdev *) kn->kn_hook)->si_drv1;
1003156783Semax
1004156783Semax	knlist_remove(&tp->tap_rsel.si_note, kn, 0);
1005156783Semax} /* tapkqdetach */
1006156783Semax
1007