if_tap.c revision 213028
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 213028 2010-09-22 21:02:43Z jhb $
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,
135213028Sjhb	.d_flags =	D_PSEUDO | 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
213166497Sbms	/* Unlocked read. */
214166497Sbms	KASSERT(!(tp->tap_flags & TAP_OPEN),
215166497Sbms		("%s flags is out of sync", ifp->if_xname));
216166497Sbms
217166497Sbms	knlist_destroy(&tp->tap_rsel.si_note);
218166497Sbms	destroy_dev(tp->tap_dev);
219166497Sbms	ether_ifdetach(ifp);
220166497Sbms	if_free_type(ifp, IFT_ETHER);
221166497Sbms
222166497Sbms	mtx_destroy(&tp->tap_mtx);
223166497Sbms	free(tp, M_TAP);
224166497Sbms}
225166497Sbms
226166497Sbmsstatic void
227166497Sbmstap_clone_destroy(struct ifnet *ifp)
228166497Sbms{
229166497Sbms	struct tap_softc *tp = ifp->if_softc;
230166497Sbms
231166497Sbms	mtx_lock(&tapmtx);
232166497Sbms	SLIST_REMOVE(&taphead, tp, tap_softc, tap_next);
233166497Sbms	mtx_unlock(&tapmtx);
234166497Sbms	tap_destroy(tp);
235166497Sbms}
236166497Sbms
237166497Sbms/* vmnet devices are tap devices in disguise */
238166497Sbmsstatic void
239166497Sbmsvmnet_clone_destroy(struct ifnet *ifp)
240166497Sbms{
241166497Sbms	tap_clone_destroy(ifp);
242166497Sbms}
243166497Sbms
24463670Snsayer/*
24563670Snsayer * tapmodevent
24663670Snsayer *
24763670Snsayer * module event handler
24863670Snsayer */
24963670Snsayerstatic int
250156783Semaxtapmodevent(module_t mod, int type, void *data)
25163670Snsayer{
25283043Sbrooks	static eventhandler_tag	 eh_tag = NULL;
25383043Sbrooks	struct tap_softc	*tp = NULL;
25483043Sbrooks	struct ifnet		*ifp = NULL;
25563670Snsayer
25663670Snsayer	switch (type) {
25763670Snsayer	case MOD_LOAD:
25863670Snsayer
25983043Sbrooks		/* intitialize device */
26083043Sbrooks
261127003Srwatson		mtx_init(&tapmtx, "tapmtx", NULL, MTX_DEF);
26283043Sbrooks		SLIST_INIT(&taphead);
26383043Sbrooks
264126845Sphk		clone_setup(&tapclones);
26571602Sphk		eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000);
266127003Srwatson		if (eh_tag == NULL) {
267127170Srwatson			clone_cleanup(&tapclones);
268127003Srwatson			mtx_destroy(&tapmtx);
269126077Sphk			return (ENOMEM);
270127003Srwatson		}
271166497Sbms		if_clone_attach(&tap_cloner);
272166497Sbms		if_clone_attach(&vmnet_cloner);
27383043Sbrooks		return (0);
27463670Snsayer
27583043Sbrooks	case MOD_UNLOAD:
276127003Srwatson		/*
277127003Srwatson		 * The EBUSY algorithm here can't quite atomically
278127003Srwatson		 * guarantee that this is race-free since we have to
279127003Srwatson		 * release the tap mtx to deregister the clone handler.
280127003Srwatson		 */
281127003Srwatson		mtx_lock(&tapmtx);
282127003Srwatson		SLIST_FOREACH(tp, &taphead, tap_next) {
283127098Srwatson			mtx_lock(&tp->tap_mtx);
284127003Srwatson			if (tp->tap_flags & TAP_OPEN) {
285127098Srwatson				mtx_unlock(&tp->tap_mtx);
286127003Srwatson				mtx_unlock(&tapmtx);
28783043Sbrooks				return (EBUSY);
288127003Srwatson			}
289127098Srwatson			mtx_unlock(&tp->tap_mtx);
290127003Srwatson		}
291127003Srwatson		mtx_unlock(&tapmtx);
29283043Sbrooks
29371602Sphk		EVENTHANDLER_DEREGISTER(dev_clone, eh_tag);
294166497Sbms		if_clone_detach(&tap_cloner);
295166497Sbms		if_clone_detach(&vmnet_cloner);
296204464Skib		drain_dev_clone_events();
29763670Snsayer
298127003Srwatson		mtx_lock(&tapmtx);
29983043Sbrooks		while ((tp = SLIST_FIRST(&taphead)) != NULL) {
30083043Sbrooks			SLIST_REMOVE_HEAD(&taphead, tap_next);
301127003Srwatson			mtx_unlock(&tapmtx);
30283043Sbrooks
303147256Sbrooks			ifp = tp->tap_ifp;
30483043Sbrooks
305121816Sbrooks			TAPDEBUG("detaching %s\n", ifp->if_xname);
30683043Sbrooks
307166497Sbms			tap_destroy(tp);
308127003Srwatson			mtx_lock(&tapmtx);
30983043Sbrooks		}
310127003Srwatson		mtx_unlock(&tapmtx);
311126077Sphk		clone_cleanup(&tapclones);
31263670Snsayer
313135354Srwatson		mtx_destroy(&tapmtx);
314135354Srwatson
31583043Sbrooks		break;
31663670Snsayer
31763670Snsayer	default:
31863670Snsayer		return (EOPNOTSUPP);
31963670Snsayer	}
32063670Snsayer
32163670Snsayer	return (0);
32263670Snsayer} /* tapmodevent */
32363670Snsayer
32463670Snsayer
32563670Snsayer/*
32671602Sphk * DEVFS handler
32771602Sphk *
32871602Sphk * We need to support two kind of devices - tap and vmnet
32971602Sphk */
33071602Sphkstatic void
331156783Semaxtapclone(void *arg, struct ucred *cred, char *name, int namelen, struct cdev **dev)
33271602Sphk{
333166497Sbms	char		devname[SPECNAMELEN + 1];
334166497Sbms	int		i, unit, append_unit;
335166438Sbms	int		extra;
33671602Sphk
337130640Sphk	if (*dev != NULL)
33871602Sphk		return;
33971602Sphk
340166514Sbms	if (!tapdclone ||
341166514Sbms	    (!tapuopen && priv_check_cred(cred, PRIV_NET_IFCREATE, 0) != 0))
342166497Sbms		return;
343166497Sbms
344166497Sbms	unit = 0;
345166497Sbms	append_unit = 0;
346126077Sphk	extra = 0;
347166497Sbms
348166497Sbms	/* We're interested in only tap/vmnet devices. */
349126077Sphk	if (strcmp(name, TAP) == 0) {
350126077Sphk		unit = -1;
351126077Sphk	} else if (strcmp(name, VMNET) == 0) {
352126077Sphk		unit = -1;
353126077Sphk		extra = VMNET_DEV_MASK;
354166497Sbms	} else if (dev_stdclone(name, NULL, TAP, &unit) != 1) {
355166497Sbms		if (dev_stdclone(name, NULL, VMNET, &unit) != 1) {
356126077Sphk			return;
357166497Sbms		} else {
358166497Sbms			extra = VMNET_DEV_MASK;
359166497Sbms		}
36083043Sbrooks	}
36171602Sphk
362166497Sbms	if (unit == -1)
363166497Sbms		append_unit = 1;
364166497Sbms
365126077Sphk	/* find any existing device, or allocate new unit number */
366126077Sphk	i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra);
367126077Sphk	if (i) {
368166497Sbms		if (append_unit) {
369166497Sbms			/*
370166497Sbms			 * We were passed 'tun' or 'tap', with no unit specified
371166497Sbms			 * so we'll need to append it now.
372166497Sbms			 */
373166497Sbms			namelen = snprintf(devname, sizeof(devname), "%s%d", name,
374166497Sbms			    unit);
375166497Sbms			name = devname;
376166497Sbms		}
377166497Sbms
378204464Skib		*dev = make_dev_credf(MAKEDEV_REF, &tap_cdevsw, unit | extra,
379204464Skib		     cred, UID_ROOT, GID_WHEEL, 0600, "%s", name);
38071602Sphk	}
381166497Sbms
382166497Sbms	if_clone_create(name, namelen, NULL);
38371602Sphk} /* tapclone */
38471602Sphk
38571602Sphk
38671602Sphk/*
38763670Snsayer * tapcreate
38863670Snsayer *
38963670Snsayer * to create interface
39063670Snsayer */
39163670Snsayerstatic void
392156783Semaxtapcreate(struct cdev *dev)
39363670Snsayer{
39463670Snsayer	struct ifnet		*ifp = NULL;
39563670Snsayer	struct tap_softc	*tp = NULL;
39663670Snsayer	unsigned short		 macaddr_hi;
397178221Semax	uint32_t		 macaddr_mid;
398213028Sjhb	int			 unit;
39963670Snsayer	char			*name = NULL;
400147256Sbrooks	u_char			eaddr[6];
40163670Snsayer
402126077Sphk	dev->si_flags &= ~SI_CHEAPCLONE;
403126077Sphk
40463670Snsayer	/* allocate driver storage and create device */
405184205Sdes	tp = malloc(sizeof(*tp), M_TAP, M_WAITOK | M_ZERO);
406127098Srwatson	mtx_init(&tp->tap_mtx, "tap_mtx", NULL, MTX_DEF);
407127003Srwatson	mtx_lock(&tapmtx);
40883043Sbrooks	SLIST_INSERT_HEAD(&taphead, tp, tap_next);
409127003Srwatson	mtx_unlock(&tapmtx);
41063670Snsayer
411126796Sphk	unit = dev2unit(dev);
41283043Sbrooks
41363670Snsayer	/* select device: tap or vmnet */
414126796Sphk	if (unit & VMNET_DEV_MASK) {
41563670Snsayer		name = VMNET;
41663803Snsayer		tp->tap_flags |= TAP_VMNET;
41783043Sbrooks	} else
41863670Snsayer		name = TAP;
41963670Snsayer
420126796Sphk	unit &= TAPMAXUNIT;
421126796Sphk
422183397Sed	TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, dev2unit(dev));
42383043Sbrooks
42463670Snsayer	/* generate fake MAC address: 00 bd xx xx xx unit_no */
42563670Snsayer	macaddr_hi = htons(0x00bd);
426178221Semax	macaddr_mid = (uint32_t) ticks;
427147256Sbrooks	bcopy(&macaddr_hi, eaddr, sizeof(short));
428178221Semax	bcopy(&macaddr_mid, &eaddr[2], sizeof(uint32_t));
429147256Sbrooks	eaddr[5] = (u_char)unit;
43063670Snsayer
431111742Sdes	/* fill the rest and attach interface */
432147256Sbrooks	ifp = tp->tap_ifp = if_alloc(IFT_ETHER);
433147256Sbrooks	if (ifp == NULL)
434147256Sbrooks		panic("%s%d: can not if_alloc()", name, unit);
43563670Snsayer	ifp->if_softc = tp;
436121816Sbrooks	if_initname(ifp, name, unit);
43763670Snsayer	ifp->if_init = tapifinit;
43863670Snsayer	ifp->if_start = tapifstart;
43963670Snsayer	ifp->if_ioctl = tapifioctl;
44063670Snsayer	ifp->if_mtu = ETHERMTU;
44163670Snsayer	ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
442213028Sjhb	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
443205222Sqingli	ifp->if_capabilities |= IFCAP_LINKSTATE;
444205222Sqingli	ifp->if_capenable |= IFCAP_LINKSTATE;
44563670Snsayer
44683043Sbrooks	dev->si_drv1 = tp;
447126077Sphk	tp->tap_dev = dev;
44883043Sbrooks
449147256Sbrooks	ether_ifattach(ifp, eaddr);
45063670Snsayer
451127098Srwatson	mtx_lock(&tp->tap_mtx);
45263803Snsayer	tp->tap_flags |= TAP_INITED;
453127098Srwatson	mtx_unlock(&tp->tap_mtx);
45463803Snsayer
455213028Sjhb	knlist_init_mtx(&tp->tap_rsel.si_note, &tp->tap_mtx);
456158697Semax
457121816Sbrooks	TAPDEBUG("interface %s is created. minor = %#x\n",
458183397Sed		ifp->if_xname, dev2unit(dev));
45963670Snsayer} /* tapcreate */
46063670Snsayer
46163670Snsayer
46263670Snsayer/*
463111742Sdes * tapopen
46463670Snsayer *
46563670Snsayer * to open tunnel. must be superuser
46663670Snsayer */
46763670Snsayerstatic int
468156783Semaxtapopen(struct cdev *dev, int flag, int mode, struct thread *td)
46963670Snsayer{
47063670Snsayer	struct tap_softc	*tp = NULL;
471133460Semax	struct ifnet		*ifp = NULL;
472213028Sjhb	int			 error;
47363670Snsayer
474164033Srwatson	if (tapuopen == 0) {
475164033Srwatson		error = priv_check(td, PRIV_NET_TAP);
476164033Srwatson		if (error)
477164033Srwatson			return (error);
478164033Srwatson	}
47963670Snsayer
480126796Sphk	if ((dev2unit(dev) & CLONE_UNITMASK) > TAPMAXUNIT)
481126796Sphk		return (ENXIO);
48283043Sbrooks
48363670Snsayer	tp = dev->si_drv1;
48463670Snsayer
485127165Srwatson	mtx_lock(&tp->tap_mtx);
486127165Srwatson	if (tp->tap_flags & TAP_OPEN) {
487127165Srwatson		mtx_unlock(&tp->tap_mtx);
488127165Srwatson		return (EBUSY);
489127165Srwatson	}
49063670Snsayer
491152315Sru	bcopy(IF_LLADDR(tp->tap_ifp), tp->ether_addr, sizeof(tp->ether_addr));
49283366Sjulian	tp->tap_pid = td->td_proc->p_pid;
49363670Snsayer	tp->tap_flags |= TAP_OPEN;
494147256Sbrooks	ifp = tp->tap_ifp;
49563670Snsayer
496148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
497148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
498167713Sbms	if (tapuponopen)
499167713Sbms		ifp->if_flags |= IFF_UP;
500205024Sqingli	if_link_state_change(ifp, LINK_STATE_UP);
501213028Sjhb	mtx_unlock(&tp->tap_mtx);
50263670Snsayer
503183397Sed	TAPDEBUG("%s is open. minor = %#x\n", ifp->if_xname, dev2unit(dev));
504133460Semax
50563670Snsayer	return (0);
50663670Snsayer} /* tapopen */
50763670Snsayer
50863670Snsayer
50963670Snsayer/*
51063670Snsayer * tapclose
51163670Snsayer *
51263670Snsayer * close the device - mark i/f down & delete routing info
51363670Snsayer */
51463670Snsayerstatic int
515156783Semaxtapclose(struct cdev *dev, int foo, int bar, struct thread *td)
51663670Snsayer{
517156783Semax	struct ifaddr		*ifa;
51863670Snsayer	struct tap_softc	*tp = dev->si_drv1;
519147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
52063670Snsayer
52163670Snsayer	/* junk all pending output */
522213028Sjhb	mtx_lock(&tp->tap_mtx);
52383043Sbrooks	IF_DRAIN(&ifp->if_snd);
52463670Snsayer
52563803Snsayer	/*
52663803Snsayer	 * do not bring the interface down, and do not anything with
52763803Snsayer	 * interface, if we are in VMnet mode. just close the device.
52863803Snsayer	 */
52963803Snsayer
53063803Snsayer	if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) {
531127098Srwatson		mtx_unlock(&tp->tap_mtx);
53263670Snsayer		if_down(ifp);
533213028Sjhb		mtx_lock(&tp->tap_mtx);
534148887Srwatson		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
535213028Sjhb			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
536213028Sjhb			mtx_unlock(&tp->tap_mtx);
53763803Snsayer			TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
538146620Speadar				rtinit(ifa, (int)RTM_DELETE, 0);
53963670Snsayer			}
540146620Speadar			if_purgeaddrs(ifp);
541213028Sjhb			mtx_lock(&tp->tap_mtx);
54263670Snsayer		}
543213028Sjhb	}
54463670Snsayer
545205024Sqingli	if_link_state_change(ifp, LINK_STATE_DOWN);
54696122Salfred	funsetown(&tp->tap_sigio);
547122352Stanimura	selwakeuppri(&tp->tap_rsel, PZERO+1);
548213028Sjhb	KNOTE_LOCKED(&tp->tap_rsel.si_note, 0);
54963670Snsayer
55063670Snsayer	tp->tap_flags &= ~TAP_OPEN;
55163670Snsayer	tp->tap_pid = 0;
552127098Srwatson	mtx_unlock(&tp->tap_mtx);
55363670Snsayer
554121816Sbrooks	TAPDEBUG("%s is closed. minor = %#x\n",
555183397Sed		ifp->if_xname, dev2unit(dev));
55663670Snsayer
55763670Snsayer	return (0);
55863670Snsayer} /* tapclose */
55963670Snsayer
56063670Snsayer
56163670Snsayer/*
56263670Snsayer * tapifinit
56363670Snsayer *
56463670Snsayer * network interface initialization function
56563670Snsayer */
56663670Snsayerstatic void
567156783Semaxtapifinit(void *xtp)
56863670Snsayer{
56963670Snsayer	struct tap_softc	*tp = (struct tap_softc *)xtp;
570147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
57163670Snsayer
572121816Sbrooks	TAPDEBUG("initializing %s\n", ifp->if_xname);
57363670Snsayer
574213028Sjhb	mtx_lock(&tp->tap_mtx);
575148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
576148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
577213028Sjhb	mtx_unlock(&tp->tap_mtx);
57863670Snsayer
57963670Snsayer	/* attempt to start output */
58063670Snsayer	tapifstart(ifp);
58163670Snsayer} /* tapifinit */
58263670Snsayer
58363670Snsayer
58463670Snsayer/*
58563670Snsayer * tapifioctl
58663670Snsayer *
58763670Snsayer * Process an ioctl request on network interface
58863670Snsayer */
589105228Sphkstatic int
590156783Semaxtapifioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
59163670Snsayer{
592160376Sbrooks	struct tap_softc	*tp = ifp->if_softc;
593189866Sscf	struct ifreq		*ifr = (struct ifreq *)data;
59463670Snsayer	struct ifstat		*ifs = NULL;
595213028Sjhb	int			 dummy;
59663670Snsayer
59763670Snsayer	switch (cmd) {
59863670Snsayer		case SIOCSIFFLAGS: /* XXX -- just like vmnet does */
59963670Snsayer		case SIOCADDMULTI:
60063670Snsayer		case SIOCDELMULTI:
60183043Sbrooks			break;
60263670Snsayer
603189866Sscf		case SIOCSIFMTU:
604189866Sscf			ifp->if_mtu = ifr->ifr_mtu;
605189866Sscf			break;
606189866Sscf
60763670Snsayer		case SIOCGIFSTATUS:
60863670Snsayer			ifs = (struct ifstat *)data;
60963670Snsayer			dummy = strlen(ifs->ascii);
610127098Srwatson			mtx_lock(&tp->tap_mtx);
61163670Snsayer			if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii))
61263670Snsayer				snprintf(ifs->ascii + dummy,
61363670Snsayer					sizeof(ifs->ascii) - dummy,
61463670Snsayer					"\tOpened by PID %d\n", tp->tap_pid);
615127098Srwatson			mtx_unlock(&tp->tap_mtx);
61683043Sbrooks			break;
61763670Snsayer
61863670Snsayer		default:
619213028Sjhb			return (ether_ioctl(ifp, cmd, data));
620156783Semax			/* NOT REACHED */
62163670Snsayer	}
62263670Snsayer
62363670Snsayer	return (0);
62463670Snsayer} /* tapifioctl */
62563670Snsayer
62663670Snsayer
62763670Snsayer/*
628111742Sdes * tapifstart
629111742Sdes *
63063670Snsayer * queue packets from higher level ready to put out
63163670Snsayer */
63263670Snsayerstatic void
633156783Semaxtapifstart(struct ifnet *ifp)
63463670Snsayer{
63563670Snsayer	struct tap_softc	*tp = ifp->if_softc;
63663670Snsayer
637121816Sbrooks	TAPDEBUG("%s starting\n", ifp->if_xname);
63863670Snsayer
63963803Snsayer	/*
64063803Snsayer	 * do not junk pending output if we are in VMnet mode.
64163803Snsayer	 * XXX: can this do any harm because of queue overflow?
64263803Snsayer	 */
64363803Snsayer
644127098Srwatson	mtx_lock(&tp->tap_mtx);
645111742Sdes	if (((tp->tap_flags & TAP_VMNET) == 0) &&
64663803Snsayer	    ((tp->tap_flags & TAP_READY) != TAP_READY)) {
647213028Sjhb		struct mbuf *m;
64863670Snsayer
649127098Srwatson		/* Unlocked read. */
650121816Sbrooks		TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname,
651121816Sbrooks		    tp->tap_flags);
65263670Snsayer
653213028Sjhb		for (;;) {
65463670Snsayer			IF_DEQUEUE(&ifp->if_snd, m);
655213028Sjhb			if (m != NULL) {
65663670Snsayer				m_freem(m);
657213028Sjhb				ifp->if_oerrors++;
658213028Sjhb			} else
659213028Sjhb				break;
660213028Sjhb		}
661213028Sjhb		mtx_unlock(&tp->tap_mtx);
66263670Snsayer
66363670Snsayer		return;
66463670Snsayer	}
66563670Snsayer
666148887Srwatson	ifp->if_drv_flags |= IFF_DRV_OACTIVE;
66763670Snsayer
668213028Sjhb	if (!IFQ_IS_EMPTY(&ifp->if_snd)) {
66963670Snsayer		if (tp->tap_flags & TAP_RWAIT) {
67063670Snsayer			tp->tap_flags &= ~TAP_RWAIT;
671111748Sdes			wakeup(tp);
67263670Snsayer		}
67363670Snsayer
674127098Srwatson		if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) {
675127098Srwatson			mtx_unlock(&tp->tap_mtx);
67695883Salfred			pgsigio(&tp->tap_sigio, SIGIO, 0);
677213028Sjhb			mtx_lock(&tp->tap_mtx);
678213028Sjhb		}
67963670Snsayer
680122352Stanimura		selwakeuppri(&tp->tap_rsel, PZERO+1);
681213028Sjhb		KNOTE_LOCKED(&tp->tap_rsel.si_note, 0);
68263670Snsayer		ifp->if_opackets ++; /* obytes are counted in ether_output */
68363670Snsayer	}
68463670Snsayer
685148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
686213028Sjhb	mtx_unlock(&tp->tap_mtx);
68763670Snsayer} /* tapifstart */
68863670Snsayer
68963670Snsayer
69063670Snsayer/*
69163670Snsayer * tapioctl
69263670Snsayer *
69363670Snsayer * the cdevsw interface is now pretty minimal
69463670Snsayer */
69563670Snsayerstatic int
696156783Semaxtapioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
69763670Snsayer{
69863670Snsayer	struct tap_softc	*tp = dev->si_drv1;
699147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
700111742Sdes	struct tapinfo		*tapp = NULL;
701102052Ssobomax	int			 f;
702162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
703162711Sru    defined(COMPAT_FREEBSD4)
704162711Sru	int			 ival;
705162711Sru#endif
70663670Snsayer
70763670Snsayer	switch (cmd) {
708111742Sdes		case TAPSIFINFO:
709111742Sdes			tapp = (struct tapinfo *)data;
710213028Sjhb			mtx_lock(&tp->tap_mtx);
711111742Sdes			ifp->if_mtu = tapp->mtu;
712111742Sdes			ifp->if_type = tapp->type;
713111742Sdes			ifp->if_baudrate = tapp->baudrate;
714213028Sjhb			mtx_unlock(&tp->tap_mtx);
715111742Sdes			break;
71663670Snsayer
717111742Sdes		case TAPGIFINFO:
718111742Sdes			tapp = (struct tapinfo *)data;
719213028Sjhb			mtx_lock(&tp->tap_mtx);
720111742Sdes			tapp->mtu = ifp->if_mtu;
721111742Sdes			tapp->type = ifp->if_type;
722111742Sdes			tapp->baudrate = ifp->if_baudrate;
723213028Sjhb			mtx_unlock(&tp->tap_mtx);
724111742Sdes			break;
72563670Snsayer
72663670Snsayer		case TAPSDEBUG:
727159079Smarius			tapdebug = *(int *)data;
72883043Sbrooks			break;
72963670Snsayer
73063670Snsayer		case TAPGDEBUG:
731159079Smarius			*(int *)data = tapdebug;
73283043Sbrooks			break;
73363670Snsayer
734182880Semax		case TAPGIFNAME: {
735182880Semax			struct ifreq	*ifr = (struct ifreq *) data;
736182880Semax
737182880Semax			strlcpy(ifr->ifr_name, ifp->if_xname, IFNAMSIZ);
738182880Semax			} break;
739182880Semax
74063670Snsayer		case FIONBIO:
74183043Sbrooks			break;
74263670Snsayer
74363670Snsayer		case FIOASYNC:
744127098Srwatson			mtx_lock(&tp->tap_mtx);
745159079Smarius			if (*(int *)data)
74663670Snsayer				tp->tap_flags |= TAP_ASYNC;
74763670Snsayer			else
74863670Snsayer				tp->tap_flags &= ~TAP_ASYNC;
749127098Srwatson			mtx_unlock(&tp->tap_mtx);
75083043Sbrooks			break;
75163670Snsayer
75263670Snsayer		case FIONREAD:
753213028Sjhb			if (!IFQ_IS_EMPTY(&ifp->if_snd)) {
754213028Sjhb				struct mbuf *mb;
75563670Snsayer
756213028Sjhb				IFQ_LOCK(&ifp->if_snd);
757213028Sjhb				IFQ_POLL_NOLOCK(&ifp->if_snd, mb);
758213028Sjhb				for (*(int *)data = 0; mb != NULL;
759213028Sjhb				     mb = mb->m_next)
760159079Smarius					*(int *)data += mb->m_len;
761213028Sjhb				IFQ_UNLOCK(&ifp->if_snd);
76283043Sbrooks			} else
763159079Smarius				*(int *)data = 0;
76483043Sbrooks			break;
76563670Snsayer
76663670Snsayer		case FIOSETOWN:
767159079Smarius			return (fsetown(*(int *)data, &tp->tap_sigio));
76863670Snsayer
76963670Snsayer		case FIOGETOWN:
770159079Smarius			*(int *)data = fgetown(&tp->tap_sigio);
77163670Snsayer			return (0);
77263670Snsayer
77363670Snsayer		/* this is deprecated, FIOSETOWN should be used instead */
77463670Snsayer		case TIOCSPGRP:
775159079Smarius			return (fsetown(-(*(int *)data), &tp->tap_sigio));
77663670Snsayer
77763670Snsayer		/* this is deprecated, FIOGETOWN should be used instead */
77863670Snsayer		case TIOCGPGRP:
779159079Smarius			*(int *)data = -fgetown(&tp->tap_sigio);
78063670Snsayer			return (0);
78163670Snsayer
78263670Snsayer		/* VMware/VMnet port ioctl's */
78363670Snsayer
784162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
785162711Sru    defined(COMPAT_FREEBSD4)
786162711Sru		case _IO('V', 0):
787162711Sru			ival = IOCPARM_IVAL(data);
788162711Sru			data = (caddr_t)&ival;
789162711Sru			/* FALLTHROUGH */
790162711Sru#endif
79183043Sbrooks		case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */
792162711Sru			f = *(int *)data;
79363670Snsayer			f &= 0x0fff;
79463670Snsayer			f &= ~IFF_CANTCHANGE;
79563670Snsayer			f |= IFF_UP;
79663670Snsayer
797213028Sjhb			mtx_lock(&tp->tap_mtx);
79863670Snsayer			ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE);
799213028Sjhb			mtx_unlock(&tp->tap_mtx);
80083043Sbrooks			break;
80163670Snsayer
80263861Snsayer		case OSIOCGIFADDR:	/* get MAC address of the remote side */
80363670Snsayer		case SIOCGIFADDR:
804127165Srwatson			mtx_lock(&tp->tap_mtx);
80563861Snsayer			bcopy(tp->ether_addr, data, sizeof(tp->ether_addr));
806127165Srwatson			mtx_unlock(&tp->tap_mtx);
80783043Sbrooks			break;
80863670Snsayer
80963861Snsayer		case SIOCSIFADDR:	/* set MAC address of the remote side */
810127165Srwatson			mtx_lock(&tp->tap_mtx);
81163861Snsayer			bcopy(data, tp->ether_addr, sizeof(tp->ether_addr));
812127165Srwatson			mtx_unlock(&tp->tap_mtx);
81383043Sbrooks			break;
81463670Snsayer
81563670Snsayer		default:
81663670Snsayer			return (ENOTTY);
81763670Snsayer	}
81863670Snsayer	return (0);
81963670Snsayer} /* tapioctl */
82063670Snsayer
82163670Snsayer
82263670Snsayer/*
82363670Snsayer * tapread
82463670Snsayer *
82563670Snsayer * the cdevsw read interface - reads a packet at a time, or at
82663670Snsayer * least as much of a packet as can be read
82763670Snsayer */
82863670Snsayerstatic int
829156783Semaxtapread(struct cdev *dev, struct uio *uio, int flag)
83063670Snsayer{
83163670Snsayer	struct tap_softc	*tp = dev->si_drv1;
832147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
83390227Sdillon	struct mbuf		*m = NULL;
834213028Sjhb	int			 error = 0, len;
83563670Snsayer
836183397Sed	TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, dev2unit(dev));
83763670Snsayer
838127098Srwatson	mtx_lock(&tp->tap_mtx);
83963670Snsayer	if ((tp->tap_flags & TAP_READY) != TAP_READY) {
840127098Srwatson		mtx_unlock(&tp->tap_mtx);
841127098Srwatson
842127098Srwatson		/* Unlocked read. */
843121816Sbrooks		TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n",
844183397Sed			ifp->if_xname, dev2unit(dev), tp->tap_flags);
84563803Snsayer
84663670Snsayer		return (EHOSTDOWN);
84763670Snsayer	}
84863670Snsayer
84963670Snsayer	tp->tap_flags &= ~TAP_RWAIT;
85063670Snsayer
85163670Snsayer	/* sleep until we get a packet */
85263670Snsayer	do {
85390227Sdillon		IF_DEQUEUE(&ifp->if_snd, m);
85463670Snsayer
85590227Sdillon		if (m == NULL) {
856213028Sjhb			if (flag & O_NONBLOCK) {
857213028Sjhb				mtx_unlock(&tp->tap_mtx);
85863670Snsayer				return (EWOULDBLOCK);
859213028Sjhb			}
860111742Sdes
86163670Snsayer			tp->tap_flags |= TAP_RWAIT;
862213028Sjhb			error = mtx_sleep(tp, &tp->tap_mtx, PCATCH | (PZERO + 1),
863213028Sjhb			    "taprd", 0);
864213028Sjhb			if (error) {
865213028Sjhb				mtx_unlock(&tp->tap_mtx);
86663670Snsayer				return (error);
867213028Sjhb			}
86863670Snsayer		}
86990227Sdillon	} while (m == NULL);
870213028Sjhb	mtx_unlock(&tp->tap_mtx);
87163670Snsayer
87263670Snsayer	/* feed packet to bpf */
873106939Ssam	BPF_MTAP(ifp, m);
87463670Snsayer
87563670Snsayer	/* xfer packet to user space */
87690227Sdillon	while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) {
87790227Sdillon		len = min(uio->uio_resid, m->m_len);
87863670Snsayer		if (len == 0)
87963670Snsayer			break;
88063670Snsayer
881111741Sdes		error = uiomove(mtod(m, void *), len, uio);
88290227Sdillon		m = m_free(m);
88363670Snsayer	}
88463670Snsayer
88590227Sdillon	if (m != NULL) {
886121816Sbrooks		TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname,
887183397Sed			dev2unit(dev));
88890227Sdillon		m_freem(m);
88963670Snsayer	}
89063670Snsayer
89163670Snsayer	return (error);
89263670Snsayer} /* tapread */
89363670Snsayer
89463670Snsayer
89563670Snsayer/*
89663670Snsayer * tapwrite
89763670Snsayer *
89863670Snsayer * the cdevsw write interface - an atomic write is a packet - or else!
89963670Snsayer */
90063670Snsayerstatic int
901156783Semaxtapwrite(struct cdev *dev, struct uio *uio, int flag)
90263670Snsayer{
903166443Sbms	struct ether_header	*eh;
90463670Snsayer	struct tap_softc	*tp = dev->si_drv1;
905147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
906137101Sglebius	struct mbuf		*m;
90763670Snsayer
908121816Sbrooks	TAPDEBUG("%s writting, minor = %#x\n",
909183397Sed		ifp->if_xname, dev2unit(dev));
91063670Snsayer
91163670Snsayer	if (uio->uio_resid == 0)
91263670Snsayer		return (0);
91363670Snsayer
91463670Snsayer	if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) {
915194990Skib		TAPDEBUG("%s invalid packet len = %zd, minor = %#x\n",
916183397Sed			ifp->if_xname, uio->uio_resid, dev2unit(dev));
91763803Snsayer
91863670Snsayer		return (EIO);
91963670Snsayer	}
92063670Snsayer
921163915Sandre	if ((m = m_uiotombuf(uio, M_DONTWAIT, 0, ETHER_ALIGN,
922163915Sandre	    M_PKTHDR)) == NULL) {
92363670Snsayer		ifp->if_ierrors ++;
924163986Scsjp		return (ENOBUFS);
92563670Snsayer	}
92663670Snsayer
927137101Sglebius	m->m_pkthdr.rcvif = ifp;
928111742Sdes
929166443Sbms	/*
930166443Sbms	 * Only pass a unicast frame to ether_input(), if it would actually
931166443Sbms	 * have been received by non-virtual hardware.
932166443Sbms	 */
933166443Sbms	if (m->m_len < sizeof(struct ether_header)) {
934166443Sbms		m_freem(m);
935166443Sbms		return (0);
936166443Sbms	}
937166443Sbms	eh = mtod(m, struct ether_header *);
938166443Sbms
939166443Sbms	if (eh && (ifp->if_flags & IFF_PROMISC) == 0 &&
940166443Sbms	    !ETHER_IS_MULTICAST(eh->ether_dhost) &&
941166443Sbms	    bcmp(eh->ether_dhost, IF_LLADDR(ifp), ETHER_ADDR_LEN) != 0) {
942166443Sbms		m_freem(m);
943166443Sbms		return (0);
944166443Sbms	}
945166443Sbms
946106939Ssam	/* Pass packet up to parent. */
947137101Sglebius	(*ifp->if_input)(ifp, m);
948106939Ssam	ifp->if_ipackets ++; /* ibytes are counted in parent */
94963670Snsayer
95063670Snsayer	return (0);
95163670Snsayer} /* tapwrite */
95263670Snsayer
95363670Snsayer
95463670Snsayer/*
95563670Snsayer * tappoll
95663670Snsayer *
95763670Snsayer * the poll interface, this is only useful on reads
95863670Snsayer * really. the write detect always returns true, write never blocks
95963670Snsayer * anyway, it either accepts the packet or drops it
96063670Snsayer */
96163670Snsayerstatic int
962156783Semaxtappoll(struct cdev *dev, int events, struct thread *td)
96363670Snsayer{
96463670Snsayer	struct tap_softc	*tp = dev->si_drv1;
965147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
966213028Sjhb	int			 revents = 0;
96763670Snsayer
968121816Sbrooks	TAPDEBUG("%s polling, minor = %#x\n",
969183397Sed		ifp->if_xname, dev2unit(dev));
97063670Snsayer
97163670Snsayer	if (events & (POLLIN | POLLRDNORM)) {
972213028Sjhb		IFQ_LOCK(&ifp->if_snd);
973213028Sjhb		if (!IFQ_IS_EMPTY(&ifp->if_snd)) {
974121816Sbrooks			TAPDEBUG("%s have data in queue. len = %d, " \
975121816Sbrooks				"minor = %#x\n", ifp->if_xname,
976183397Sed				ifp->if_snd.ifq_len, dev2unit(dev));
97763803Snsayer
97863670Snsayer			revents |= (events & (POLLIN | POLLRDNORM));
97983043Sbrooks		} else {
980121816Sbrooks			TAPDEBUG("%s waiting for data, minor = %#x\n",
981183397Sed				ifp->if_xname, dev2unit(dev));
98263803Snsayer
98383805Sjhb			selrecord(td, &tp->tap_rsel);
98463670Snsayer		}
985213028Sjhb		IFQ_UNLOCK(&ifp->if_snd);
98663670Snsayer	}
98763670Snsayer
98863670Snsayer	if (events & (POLLOUT | POLLWRNORM))
98963670Snsayer		revents |= (events & (POLLOUT | POLLWRNORM));
99063670Snsayer
99163670Snsayer	return (revents);
99263670Snsayer} /* tappoll */
993156783Semax
994156783Semax
995156783Semax/*
996156783Semax * tap_kqfilter
997156783Semax *
998156783Semax * support for kevent() system call
999156783Semax */
1000156783Semaxstatic int
1001156783Semaxtapkqfilter(struct cdev *dev, struct knote *kn)
1002156783Semax{
1003156783Semax	struct tap_softc	*tp = dev->si_drv1;
1004156783Semax	struct ifnet		*ifp = tp->tap_ifp;
1005156783Semax
1006156783Semax	switch (kn->kn_filter) {
1007156783Semax	case EVFILT_READ:
1008156783Semax		TAPDEBUG("%s kqfilter: EVFILT_READ, minor = %#x\n",
1009183397Sed			ifp->if_xname, dev2unit(dev));
1010156783Semax		kn->kn_fop = &tap_read_filterops;
1011156783Semax		break;
1012156783Semax
1013156783Semax	case EVFILT_WRITE:
1014156783Semax		TAPDEBUG("%s kqfilter: EVFILT_WRITE, minor = %#x\n",
1015183397Sed			ifp->if_xname, dev2unit(dev));
1016156783Semax		kn->kn_fop = &tap_write_filterops;
1017156783Semax		break;
1018156783Semax
1019156783Semax	default:
1020156783Semax		TAPDEBUG("%s kqfilter: invalid filter, minor = %#x\n",
1021183397Sed			ifp->if_xname, dev2unit(dev));
1022156783Semax		return (EINVAL);
1023156783Semax		/* NOT REACHED */
1024156783Semax	}
1025156783Semax
1026213028Sjhb	kn->kn_hook = tp;
1027156783Semax	knlist_add(&tp->tap_rsel.si_note, kn, 0);
1028156783Semax
1029156783Semax	return (0);
1030156783Semax} /* tapkqfilter */
1031156783Semax
1032156783Semax
1033156783Semax/*
1034156783Semax * tap_kqread
1035156783Semax *
1036156783Semax * Return true if there is data in the interface queue
1037156783Semax */
1038156783Semaxstatic int
1039156783Semaxtapkqread(struct knote *kn, long hint)
1040156783Semax{
1041213028Sjhb	int			 ret;
1042213028Sjhb	struct tap_softc	*tp = kn->kn_hook;
1043213028Sjhb	struct cdev		*dev = tp->tap_dev;
1044156783Semax	struct ifnet		*ifp = tp->tap_ifp;
1045156783Semax
1046156783Semax	if ((kn->kn_data = ifp->if_snd.ifq_len) > 0) {
1047156783Semax		TAPDEBUG("%s have data in queue. len = %d, minor = %#x\n",
1048183397Sed			ifp->if_xname, ifp->if_snd.ifq_len, dev2unit(dev));
1049156783Semax		ret = 1;
1050156783Semax	} else {
1051156783Semax		TAPDEBUG("%s waiting for data, minor = %#x\n",
1052183397Sed			ifp->if_xname, dev2unit(dev));
1053156783Semax		ret = 0;
1054156783Semax	}
1055156783Semax
1056156783Semax	return (ret);
1057156783Semax} /* tapkqread */
1058156783Semax
1059156783Semax
1060156783Semax/*
1061156783Semax * tap_kqwrite
1062156783Semax *
1063156783Semax * Always can write. Return the MTU in kn->data
1064156783Semax */
1065156783Semaxstatic int
1066156783Semaxtapkqwrite(struct knote *kn, long hint)
1067156783Semax{
1068213028Sjhb	struct tap_softc	*tp = kn->kn_hook;
1069156783Semax	struct ifnet		*ifp = tp->tap_ifp;
1070156783Semax
1071156783Semax	kn->kn_data = ifp->if_mtu;
1072156783Semax
1073156783Semax	return (1);
1074156783Semax} /* tapkqwrite */
1075156783Semax
1076156783Semax
1077156783Semaxstatic void
1078156783Semaxtapkqdetach(struct knote *kn)
1079156783Semax{
1080213028Sjhb	struct tap_softc	*tp = kn->kn_hook;
1081156783Semax
1082156783Semax	knlist_remove(&tp->tap_rsel.si_note, kn, 0);
1083156783Semax} /* tapkqdetach */
1084156783Semax
1085