if_tap.c revision 347376
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: stable/11/sys/net/if_tap.c 347376 2019-05-09 01:16:03Z kevans $
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>
45236724Strociny#include <sys/jail.h>
4663670Snsayer#include <sys/kernel.h>
4763670Snsayer#include <sys/malloc.h>
4863670Snsayer#include <sys/mbuf.h>
49129880Sphk#include <sys/module.h>
5063670Snsayer#include <sys/poll.h>
51164033Srwatson#include <sys/priv.h>
5263670Snsayer#include <sys/proc.h>
53139207Sphk#include <sys/selinfo.h>
5463670Snsayer#include <sys/signalvar.h>
5563670Snsayer#include <sys/socket.h>
5663670Snsayer#include <sys/sockio.h>
5763670Snsayer#include <sys/sysctl.h>
5863670Snsayer#include <sys/systm.h>
5963670Snsayer#include <sys/ttycom.h>
6063670Snsayer#include <sys/uio.h>
6183043Sbrooks#include <sys/queue.h>
6263670Snsayer
6363670Snsayer#include <net/bpf.h>
6463670Snsayer#include <net/ethernet.h>
6563670Snsayer#include <net/if.h>
66257176Sglebius#include <net/if_var.h>
67166497Sbms#include <net/if_clone.h>
68152315Sru#include <net/if_dl.h>
69238183Semaste#include <net/if_media.h>
70236725Strociny#include <net/if_types.h>
7163670Snsayer#include <net/route.h>
72236724Strociny#include <net/vnet.h>
7363670Snsayer
7463670Snsayer#include <netinet/in.h>
7563670Snsayer
7663670Snsayer#include <net/if_tapvar.h>
7763670Snsayer#include <net/if_tap.h>
7863670Snsayer
7963670Snsayer
8063670Snsayer#define CDEV_NAME	"tap"
8163670Snsayer#define TAPDEBUG	if (tapdebug) printf
8263670Snsayer
83241610Sglebiusstatic const char tapname[] = "tap";
84241610Sglebiusstatic const char vmnetname[] = "vmnet";
8583043Sbrooks#define TAPMAXUNIT	0x7fff
86126077Sphk#define VMNET_DEV_MASK	CLONE_FLAG0
8763670Snsayer
8863670Snsayer/* module */
89111742Sdesstatic int		tapmodevent(module_t, int, void *);
9063670Snsayer
9163670Snsayer/* device */
92148868Srwatsonstatic void		tapclone(void *, struct ucred *, char *, int,
93148868Srwatson			    struct cdev **);
94130585Sphkstatic void		tapcreate(struct cdev *);
9563670Snsayer
9663670Snsayer/* network interface */
9793084Sbdestatic void		tapifstart(struct ifnet *);
9893084Sbdestatic int		tapifioctl(struct ifnet *, u_long, caddr_t);
9993084Sbdestatic void		tapifinit(void *);
10063670Snsayer
101166497Sbmsstatic int		tap_clone_create(struct if_clone *, int, caddr_t);
102166497Sbmsstatic void		tap_clone_destroy(struct ifnet *);
103241610Sglebiusstatic struct if_clone *tap_cloner;
104166497Sbmsstatic int		vmnet_clone_create(struct if_clone *, int, caddr_t);
105166497Sbmsstatic void		vmnet_clone_destroy(struct ifnet *);
106241610Sglebiusstatic struct if_clone *vmnet_cloner;
107166497Sbms
10863670Snsayer/* character device */
10963670Snsayerstatic d_open_t		tapopen;
11063670Snsayerstatic d_close_t	tapclose;
11163670Snsayerstatic d_read_t		tapread;
11263670Snsayerstatic d_write_t	tapwrite;
11363670Snsayerstatic d_ioctl_t	tapioctl;
11463670Snsayerstatic d_poll_t		tappoll;
115156783Semaxstatic d_kqfilter_t	tapkqfilter;
11663670Snsayer
117156783Semax/* kqueue(2) */
118156783Semaxstatic int		tapkqread(struct knote *, long);
119156783Semaxstatic int		tapkqwrite(struct knote *, long);
120156783Semaxstatic void		tapkqdetach(struct knote *);
121156783Semax
122156783Semaxstatic struct filterops	tap_read_filterops = {
123156783Semax	.f_isfd =	1,
124156783Semax	.f_attach =	NULL,
125156783Semax	.f_detach =	tapkqdetach,
126156783Semax	.f_event =	tapkqread,
127156783Semax};
128156783Semax
129156783Semaxstatic struct filterops	tap_write_filterops = {
130156783Semax	.f_isfd =	1,
131156783Semax	.f_attach =	NULL,
132156783Semax	.f_detach =	tapkqdetach,
133156783Semax	.f_event =	tapkqwrite,
134156783Semax};
135156783Semax
13663670Snsayerstatic struct cdevsw	tap_cdevsw = {
137126080Sphk	.d_version =	D_VERSION,
138226500Sed	.d_flags =	D_NEEDMINOR,
139111815Sphk	.d_open =	tapopen,
140111815Sphk	.d_close =	tapclose,
141111815Sphk	.d_read =	tapread,
142111815Sphk	.d_write =	tapwrite,
143111815Sphk	.d_ioctl =	tapioctl,
144111815Sphk	.d_poll =	tappoll,
145111815Sphk	.d_name =	CDEV_NAME,
146156783Semax	.d_kqfilter =	tapkqfilter,
14763670Snsayer};
14863670Snsayer
149127003Srwatson/*
150127003Srwatson * All global variables in if_tap.c are locked with tapmtx, with the
151127003Srwatson * exception of tapdebug, which is accessed unlocked; tapclones is
152127003Srwatson * static at runtime.
153127003Srwatson */
154127003Srwatsonstatic struct mtx		tapmtx;
15583043Sbrooksstatic int			tapdebug = 0;        /* debug flag   */
156167713Sbmsstatic int			tapuopen = 0;        /* allow user open() */
157167713Sbmsstatic int			tapuponopen = 0;    /* IFF_UP on open() */
158166497Sbmsstatic int			tapdclone = 1;	/* enable devfs cloning */
15983043Sbrooksstatic SLIST_HEAD(, tap_softc)	taphead;             /* first device */
160126077Sphkstatic struct clonedevs 	*tapclones;
16163670Snsayer
16263670SnsayerMALLOC_DECLARE(M_TAP);
16363670SnsayerMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface");
16463670SnsayerSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, "");
165144979Smdodd
166144979SmdoddSYSCTL_DECL(_net_link);
167227309Sedstatic SYSCTL_NODE(_net_link, OID_AUTO, tap, CTLFLAG_RW, 0,
168144979Smdodd    "Ethernet tunnel software network interface");
169144979SmdoddSYSCTL_INT(_net_link_tap, OID_AUTO, user_open, CTLFLAG_RW, &tapuopen, 0,
170144979Smdodd	"Allow user to open /dev/tap (based on node permissions)");
171167713SbmsSYSCTL_INT(_net_link_tap, OID_AUTO, up_on_open, CTLFLAG_RW, &tapuponopen, 0,
172167713Sbms	"Bring interface up when /dev/tap is opened");
173267992ShselaskySYSCTL_INT(_net_link_tap, OID_AUTO, devfs_cloning, CTLFLAG_RWTUN, &tapdclone, 0,
174289718Semaste	"Enable legacy devfs interface creation");
175144979SmdoddSYSCTL_INT(_net_link_tap, OID_AUTO, debug, CTLFLAG_RW, &tapdebug, 0, "");
176144979Smdodd
17763670SnsayerDEV_MODULE(if_tap, tapmodevent, NULL);
178346803SkevansMODULE_VERSION(if_tap, 1);
17963670Snsayer
180166497Sbmsstatic int
181166497Sbmstap_clone_create(struct if_clone *ifc, int unit, caddr_t params)
182166497Sbms{
183166497Sbms	struct cdev *dev;
184166497Sbms	int i;
185166497Sbms
186241610Sglebius	/* Find any existing device, or allocate new unit number. */
187241610Sglebius	i = clone_create(&tapclones, &tap_cdevsw, &unit, &dev, 0);
188166497Sbms	if (i) {
189243615Sdavidxu		dev = make_dev(&tap_cdevsw, unit, UID_ROOT, GID_WHEEL, 0600,
190241610Sglebius		    "%s%d", tapname, unit);
191166497Sbms	}
192166497Sbms
193166497Sbms	tapcreate(dev);
194166497Sbms	return (0);
195166497Sbms}
196166497Sbms
197166497Sbms/* vmnet devices are tap devices in disguise */
198166497Sbmsstatic int
199166497Sbmsvmnet_clone_create(struct if_clone *ifc, int unit, caddr_t params)
200166497Sbms{
201241610Sglebius	struct cdev *dev;
202241610Sglebius	int i;
203241610Sglebius
204241610Sglebius	/* Find any existing device, or allocate new unit number. */
205241610Sglebius	i = clone_create(&tapclones, &tap_cdevsw, &unit, &dev, VMNET_DEV_MASK);
206241610Sglebius	if (i) {
207241610Sglebius		dev = make_dev(&tap_cdevsw, unit | VMNET_DEV_MASK, UID_ROOT,
208257078Sgrehan		    GID_WHEEL, 0600, "%s%d", vmnetname, unit);
209241610Sglebius	}
210241610Sglebius
211241610Sglebius	tapcreate(dev);
212241610Sglebius	return (0);
213166497Sbms}
214166497Sbms
215166497Sbmsstatic void
216166497Sbmstap_destroy(struct tap_softc *tp)
217166497Sbms{
218166497Sbms	struct ifnet *ifp = tp->tap_ifp;
219166497Sbms
220236724Strociny	CURVNET_SET(ifp->if_vnet);
221240938Semaste	destroy_dev(tp->tap_dev);
222225177Sattilio	seldrain(&tp->tap_rsel);
223256008Sglebius	knlist_clear(&tp->tap_rsel.si_note, 0);
224166497Sbms	knlist_destroy(&tp->tap_rsel.si_note);
225166497Sbms	ether_ifdetach(ifp);
226227459Sbrooks	if_free(ifp);
227166497Sbms
228166497Sbms	mtx_destroy(&tp->tap_mtx);
229166497Sbms	free(tp, M_TAP);
230236724Strociny	CURVNET_RESTORE();
231166497Sbms}
232166497Sbms
233166497Sbmsstatic void
234166497Sbmstap_clone_destroy(struct ifnet *ifp)
235166497Sbms{
236166497Sbms	struct tap_softc *tp = ifp->if_softc;
237166497Sbms
238166497Sbms	mtx_lock(&tapmtx);
239166497Sbms	SLIST_REMOVE(&taphead, tp, tap_softc, tap_next);
240166497Sbms	mtx_unlock(&tapmtx);
241166497Sbms	tap_destroy(tp);
242166497Sbms}
243166497Sbms
244166497Sbms/* vmnet devices are tap devices in disguise */
245166497Sbmsstatic void
246166497Sbmsvmnet_clone_destroy(struct ifnet *ifp)
247166497Sbms{
248166497Sbms	tap_clone_destroy(ifp);
249166497Sbms}
250166497Sbms
25163670Snsayer/*
25263670Snsayer * tapmodevent
25363670Snsayer *
25463670Snsayer * module event handler
25563670Snsayer */
25663670Snsayerstatic int
257156783Semaxtapmodevent(module_t mod, int type, void *data)
25863670Snsayer{
25983043Sbrooks	static eventhandler_tag	 eh_tag = NULL;
26083043Sbrooks	struct tap_softc	*tp = NULL;
26183043Sbrooks	struct ifnet		*ifp = NULL;
26263670Snsayer
26363670Snsayer	switch (type) {
26463670Snsayer	case MOD_LOAD:
26563670Snsayer
26683043Sbrooks		/* intitialize device */
26783043Sbrooks
268127003Srwatson		mtx_init(&tapmtx, "tapmtx", NULL, MTX_DEF);
26983043Sbrooks		SLIST_INIT(&taphead);
27083043Sbrooks
271126845Sphk		clone_setup(&tapclones);
27271602Sphk		eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000);
273127003Srwatson		if (eh_tag == NULL) {
274127170Srwatson			clone_cleanup(&tapclones);
275127003Srwatson			mtx_destroy(&tapmtx);
276126077Sphk			return (ENOMEM);
277127003Srwatson		}
278241610Sglebius		tap_cloner = if_clone_simple(tapname, tap_clone_create,
279241610Sglebius		    tap_clone_destroy, 0);
280241610Sglebius		vmnet_cloner = if_clone_simple(vmnetname, vmnet_clone_create,
281241610Sglebius		    vmnet_clone_destroy, 0);
28283043Sbrooks		return (0);
28363670Snsayer
28483043Sbrooks	case MOD_UNLOAD:
285127003Srwatson		/*
286127003Srwatson		 * The EBUSY algorithm here can't quite atomically
287127003Srwatson		 * guarantee that this is race-free since we have to
288127003Srwatson		 * release the tap mtx to deregister the clone handler.
289127003Srwatson		 */
290127003Srwatson		mtx_lock(&tapmtx);
291127003Srwatson		SLIST_FOREACH(tp, &taphead, tap_next) {
292127098Srwatson			mtx_lock(&tp->tap_mtx);
293127003Srwatson			if (tp->tap_flags & TAP_OPEN) {
294127098Srwatson				mtx_unlock(&tp->tap_mtx);
295127003Srwatson				mtx_unlock(&tapmtx);
29683043Sbrooks				return (EBUSY);
297127003Srwatson			}
298127098Srwatson			mtx_unlock(&tp->tap_mtx);
299127003Srwatson		}
300127003Srwatson		mtx_unlock(&tapmtx);
30183043Sbrooks
30271602Sphk		EVENTHANDLER_DEREGISTER(dev_clone, eh_tag);
303241610Sglebius		if_clone_detach(tap_cloner);
304241610Sglebius		if_clone_detach(vmnet_cloner);
305204464Skib		drain_dev_clone_events();
30663670Snsayer
307127003Srwatson		mtx_lock(&tapmtx);
30883043Sbrooks		while ((tp = SLIST_FIRST(&taphead)) != NULL) {
30983043Sbrooks			SLIST_REMOVE_HEAD(&taphead, tap_next);
310127003Srwatson			mtx_unlock(&tapmtx);
31183043Sbrooks
312147256Sbrooks			ifp = tp->tap_ifp;
31383043Sbrooks
314121816Sbrooks			TAPDEBUG("detaching %s\n", ifp->if_xname);
31583043Sbrooks
316166497Sbms			tap_destroy(tp);
317127003Srwatson			mtx_lock(&tapmtx);
31883043Sbrooks		}
319127003Srwatson		mtx_unlock(&tapmtx);
320126077Sphk		clone_cleanup(&tapclones);
32163670Snsayer
322135354Srwatson		mtx_destroy(&tapmtx);
323135354Srwatson
32483043Sbrooks		break;
32563670Snsayer
32663670Snsayer	default:
32763670Snsayer		return (EOPNOTSUPP);
32863670Snsayer	}
32963670Snsayer
33063670Snsayer	return (0);
33163670Snsayer} /* tapmodevent */
33263670Snsayer
33363670Snsayer
33463670Snsayer/*
33571602Sphk * DEVFS handler
33671602Sphk *
33771602Sphk * We need to support two kind of devices - tap and vmnet
33871602Sphk */
33971602Sphkstatic void
340156783Semaxtapclone(void *arg, struct ucred *cred, char *name, int namelen, struct cdev **dev)
34171602Sphk{
342166497Sbms	char		devname[SPECNAMELEN + 1];
343166497Sbms	int		i, unit, append_unit;
344166438Sbms	int		extra;
34571602Sphk
346130640Sphk	if (*dev != NULL)
34771602Sphk		return;
34871602Sphk
349166514Sbms	if (!tapdclone ||
350166514Sbms	    (!tapuopen && priv_check_cred(cred, PRIV_NET_IFCREATE, 0) != 0))
351166497Sbms		return;
352166497Sbms
353166497Sbms	unit = 0;
354166497Sbms	append_unit = 0;
355126077Sphk	extra = 0;
356166497Sbms
357166497Sbms	/* We're interested in only tap/vmnet devices. */
358241610Sglebius	if (strcmp(name, tapname) == 0) {
359126077Sphk		unit = -1;
360241610Sglebius	} else if (strcmp(name, vmnetname) == 0) {
361126077Sphk		unit = -1;
362126077Sphk		extra = VMNET_DEV_MASK;
363241610Sglebius	} else if (dev_stdclone(name, NULL, tapname, &unit) != 1) {
364241610Sglebius		if (dev_stdclone(name, NULL, vmnetname, &unit) != 1) {
365126077Sphk			return;
366166497Sbms		} else {
367166497Sbms			extra = VMNET_DEV_MASK;
368166497Sbms		}
36983043Sbrooks	}
37071602Sphk
371166497Sbms	if (unit == -1)
372166497Sbms		append_unit = 1;
373166497Sbms
374236724Strociny	CURVNET_SET(CRED_TO_VNET(cred));
375126077Sphk	/* find any existing device, or allocate new unit number */
376126077Sphk	i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra);
377126077Sphk	if (i) {
378166497Sbms		if (append_unit) {
379166497Sbms			/*
380166497Sbms			 * We were passed 'tun' or 'tap', with no unit specified
381166497Sbms			 * so we'll need to append it now.
382166497Sbms			 */
383166497Sbms			namelen = snprintf(devname, sizeof(devname), "%s%d", name,
384166497Sbms			    unit);
385166497Sbms			name = devname;
386166497Sbms		}
387166497Sbms
388204464Skib		*dev = make_dev_credf(MAKEDEV_REF, &tap_cdevsw, unit | extra,
389204464Skib		     cred, UID_ROOT, GID_WHEEL, 0600, "%s", name);
39071602Sphk	}
391166497Sbms
392166497Sbms	if_clone_create(name, namelen, NULL);
393236724Strociny	CURVNET_RESTORE();
39471602Sphk} /* tapclone */
39571602Sphk
39671602Sphk
39771602Sphk/*
39863670Snsayer * tapcreate
39963670Snsayer *
40063670Snsayer * to create interface
40163670Snsayer */
40263670Snsayerstatic void
403156783Semaxtapcreate(struct cdev *dev)
40463670Snsayer{
40563670Snsayer	struct ifnet		*ifp = NULL;
40663670Snsayer	struct tap_softc	*tp = NULL;
40763670Snsayer	unsigned short		 macaddr_hi;
408178221Semax	uint32_t		 macaddr_mid;
409213028Sjhb	int			 unit;
410241610Sglebius	const char		*name = NULL;
411147256Sbrooks	u_char			eaddr[6];
41263670Snsayer
41363670Snsayer	/* allocate driver storage and create device */
414184205Sdes	tp = malloc(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) {
424241610Sglebius		name = vmnetname;
42563803Snsayer		tp->tap_flags |= TAP_VMNET;
42683043Sbrooks	} else
427241610Sglebius		name = tapname;
42863670Snsayer
429126796Sphk	unit &= TAPMAXUNIT;
430126796Sphk
431183397Sed	TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, dev2unit(dev));
43283043Sbrooks
43363670Snsayer	/* generate fake MAC address: 00 bd xx xx xx unit_no */
43463670Snsayer	macaddr_hi = htons(0x00bd);
435178221Semax	macaddr_mid = (uint32_t) ticks;
436147256Sbrooks	bcopy(&macaddr_hi, eaddr, sizeof(short));
437178221Semax	bcopy(&macaddr_mid, &eaddr[2], sizeof(uint32_t));
438147256Sbrooks	eaddr[5] = (u_char)unit;
43963670Snsayer
440111742Sdes	/* fill the rest and attach interface */
441147256Sbrooks	ifp = tp->tap_ifp = if_alloc(IFT_ETHER);
442147256Sbrooks	if (ifp == NULL)
443147256Sbrooks		panic("%s%d: can not if_alloc()", name, unit);
44463670Snsayer	ifp->if_softc = tp;
445121816Sbrooks	if_initname(ifp, name, unit);
44663670Snsayer	ifp->if_init = tapifinit;
44763670Snsayer	ifp->if_start = tapifstart;
44863670Snsayer	ifp->if_ioctl = tapifioctl;
44963670Snsayer	ifp->if_mtu = ETHERMTU;
45063670Snsayer	ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
451213028Sjhb	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
452205222Sqingli	ifp->if_capabilities |= IFCAP_LINKSTATE;
453205222Sqingli	ifp->if_capenable |= IFCAP_LINKSTATE;
45463670Snsayer
45583043Sbrooks	dev->si_drv1 = tp;
456126077Sphk	tp->tap_dev = dev;
45783043Sbrooks
458147256Sbrooks	ether_ifattach(ifp, eaddr);
45963670Snsayer
460127098Srwatson	mtx_lock(&tp->tap_mtx);
46163803Snsayer	tp->tap_flags |= TAP_INITED;
462127098Srwatson	mtx_unlock(&tp->tap_mtx);
46363803Snsayer
464213028Sjhb	knlist_init_mtx(&tp->tap_rsel.si_note, &tp->tap_mtx);
465158697Semax
466121816Sbrooks	TAPDEBUG("interface %s is created. minor = %#x\n",
467183397Sed		ifp->if_xname, dev2unit(dev));
46863670Snsayer} /* tapcreate */
46963670Snsayer
47063670Snsayer
47163670Snsayer/*
472111742Sdes * tapopen
47363670Snsayer *
47463670Snsayer * to open tunnel. must be superuser
47563670Snsayer */
47663670Snsayerstatic int
477156783Semaxtapopen(struct cdev *dev, int flag, int mode, struct thread *td)
47863670Snsayer{
47963670Snsayer	struct tap_softc	*tp = NULL;
480133460Semax	struct ifnet		*ifp = NULL;
481213028Sjhb	int			 error;
48263670Snsayer
483164033Srwatson	if (tapuopen == 0) {
484164033Srwatson		error = priv_check(td, PRIV_NET_TAP);
485164033Srwatson		if (error)
486164033Srwatson			return (error);
487164033Srwatson	}
48863670Snsayer
489126796Sphk	if ((dev2unit(dev) & CLONE_UNITMASK) > TAPMAXUNIT)
490126796Sphk		return (ENXIO);
49183043Sbrooks
49263670Snsayer	tp = dev->si_drv1;
49363670Snsayer
494127165Srwatson	mtx_lock(&tp->tap_mtx);
495127165Srwatson	if (tp->tap_flags & TAP_OPEN) {
496127165Srwatson		mtx_unlock(&tp->tap_mtx);
497127165Srwatson		return (EBUSY);
498127165Srwatson	}
49963670Snsayer
500152315Sru	bcopy(IF_LLADDR(tp->tap_ifp), tp->ether_addr, sizeof(tp->ether_addr));
50183366Sjulian	tp->tap_pid = td->td_proc->p_pid;
50263670Snsayer	tp->tap_flags |= TAP_OPEN;
503147256Sbrooks	ifp = tp->tap_ifp;
50463670Snsayer
505148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
506148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
507167713Sbms	if (tapuponopen)
508167713Sbms		ifp->if_flags |= IFF_UP;
509205024Sqingli	if_link_state_change(ifp, LINK_STATE_UP);
510213028Sjhb	mtx_unlock(&tp->tap_mtx);
51163670Snsayer
512183397Sed	TAPDEBUG("%s is open. minor = %#x\n", ifp->if_xname, dev2unit(dev));
513133460Semax
51463670Snsayer	return (0);
51563670Snsayer} /* tapopen */
51663670Snsayer
51763670Snsayer
51863670Snsayer/*
51963670Snsayer * tapclose
52063670Snsayer *
52163670Snsayer * close the device - mark i/f down & delete routing info
52263670Snsayer */
52363670Snsayerstatic int
524156783Semaxtapclose(struct cdev *dev, int foo, int bar, struct thread *td)
52563670Snsayer{
526156783Semax	struct ifaddr		*ifa;
52763670Snsayer	struct tap_softc	*tp = dev->si_drv1;
528147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
52963670Snsayer
53063670Snsayer	/* junk all pending output */
531213028Sjhb	mtx_lock(&tp->tap_mtx);
532236724Strociny	CURVNET_SET(ifp->if_vnet);
53383043Sbrooks	IF_DRAIN(&ifp->if_snd);
53463670Snsayer
53563803Snsayer	/*
536281363Sglebius	 * Do not bring the interface down, and do not anything with
537281363Sglebius	 * interface, if we are in VMnet mode. Just close the device.
53863803Snsayer	 */
539281363Sglebius	if (((tp->tap_flags & TAP_VMNET) == 0) &&
540281363Sglebius	    (ifp->if_flags & (IFF_UP | IFF_LINK0)) == IFF_UP) {
541127098Srwatson		mtx_unlock(&tp->tap_mtx);
54263670Snsayer		if_down(ifp);
543213028Sjhb		mtx_lock(&tp->tap_mtx);
544148887Srwatson		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
545213028Sjhb			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
546213028Sjhb			mtx_unlock(&tp->tap_mtx);
54763803Snsayer			TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
548146620Speadar				rtinit(ifa, (int)RTM_DELETE, 0);
54963670Snsayer			}
550146620Speadar			if_purgeaddrs(ifp);
551213028Sjhb			mtx_lock(&tp->tap_mtx);
55263670Snsayer		}
553213028Sjhb	}
55463670Snsayer
555205024Sqingli	if_link_state_change(ifp, LINK_STATE_DOWN);
556236724Strociny	CURVNET_RESTORE();
557236724Strociny
55896122Salfred	funsetown(&tp->tap_sigio);
559122352Stanimura	selwakeuppri(&tp->tap_rsel, PZERO+1);
560213028Sjhb	KNOTE_LOCKED(&tp->tap_rsel.si_note, 0);
56163670Snsayer
56263670Snsayer	tp->tap_flags &= ~TAP_OPEN;
56363670Snsayer	tp->tap_pid = 0;
564127098Srwatson	mtx_unlock(&tp->tap_mtx);
56563670Snsayer
566121816Sbrooks	TAPDEBUG("%s is closed. minor = %#x\n",
567183397Sed		ifp->if_xname, dev2unit(dev));
56863670Snsayer
56963670Snsayer	return (0);
57063670Snsayer} /* tapclose */
57163670Snsayer
57263670Snsayer
57363670Snsayer/*
57463670Snsayer * tapifinit
57563670Snsayer *
57663670Snsayer * network interface initialization function
57763670Snsayer */
57863670Snsayerstatic void
579156783Semaxtapifinit(void *xtp)
58063670Snsayer{
58163670Snsayer	struct tap_softc	*tp = (struct tap_softc *)xtp;
582147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
58363670Snsayer
584121816Sbrooks	TAPDEBUG("initializing %s\n", ifp->if_xname);
58563670Snsayer
586213028Sjhb	mtx_lock(&tp->tap_mtx);
587148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
588148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
589213028Sjhb	mtx_unlock(&tp->tap_mtx);
59063670Snsayer
59163670Snsayer	/* attempt to start output */
59263670Snsayer	tapifstart(ifp);
59363670Snsayer} /* tapifinit */
59463670Snsayer
59563670Snsayer
59663670Snsayer/*
59763670Snsayer * tapifioctl
59863670Snsayer *
59963670Snsayer * Process an ioctl request on network interface
60063670Snsayer */
601105228Sphkstatic int
602156783Semaxtapifioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
60363670Snsayer{
604160376Sbrooks	struct tap_softc	*tp = ifp->if_softc;
605189866Sscf	struct ifreq		*ifr = (struct ifreq *)data;
60663670Snsayer	struct ifstat		*ifs = NULL;
607238183Semaste	struct ifmediareq	*ifmr = NULL;
608238183Semaste	int			 dummy, error = 0;
60963670Snsayer
61063670Snsayer	switch (cmd) {
61163670Snsayer		case SIOCSIFFLAGS: /* XXX -- just like vmnet does */
61263670Snsayer		case SIOCADDMULTI:
61363670Snsayer		case SIOCDELMULTI:
61483043Sbrooks			break;
61563670Snsayer
616238183Semaste		case SIOCGIFMEDIA:
617238183Semaste			ifmr = (struct ifmediareq *)data;
618238183Semaste			dummy = ifmr->ifm_count;
619238183Semaste			ifmr->ifm_count = 1;
620238183Semaste			ifmr->ifm_status = IFM_AVALID;
621238183Semaste			ifmr->ifm_active = IFM_ETHER;
622238183Semaste			if (tp->tap_flags & TAP_OPEN)
623238183Semaste				ifmr->ifm_status |= IFM_ACTIVE;
624238183Semaste			ifmr->ifm_current = ifmr->ifm_active;
625238183Semaste			if (dummy >= 1) {
626238183Semaste				int media = IFM_ETHER;
627238183Semaste				error = copyout(&media, ifmr->ifm_ulist,
628238183Semaste				    sizeof(int));
629238183Semaste			}
630238183Semaste			break;
631238183Semaste
632189866Sscf		case SIOCSIFMTU:
633189866Sscf			ifp->if_mtu = ifr->ifr_mtu;
634189866Sscf			break;
635189866Sscf
63663670Snsayer		case SIOCGIFSTATUS:
63763670Snsayer			ifs = (struct ifstat *)data;
638127098Srwatson			mtx_lock(&tp->tap_mtx);
639260394Smelifaro			if (tp->tap_pid != 0)
640260394Smelifaro				snprintf(ifs->ascii, sizeof(ifs->ascii),
64163670Snsayer					"\tOpened by PID %d\n", tp->tap_pid);
642260394Smelifaro			else
643260394Smelifaro				ifs->ascii[0] = '\0';
644127098Srwatson			mtx_unlock(&tp->tap_mtx);
64583043Sbrooks			break;
64663670Snsayer
64763670Snsayer		default:
648238183Semaste			error = ether_ioctl(ifp, cmd, data);
649238183Semaste			break;
65063670Snsayer	}
65163670Snsayer
652238183Semaste	return (error);
65363670Snsayer} /* tapifioctl */
65463670Snsayer
65563670Snsayer
65663670Snsayer/*
657111742Sdes * tapifstart
658111742Sdes *
65963670Snsayer * queue packets from higher level ready to put out
66063670Snsayer */
66163670Snsayerstatic void
662156783Semaxtapifstart(struct ifnet *ifp)
66363670Snsayer{
66463670Snsayer	struct tap_softc	*tp = ifp->if_softc;
66563670Snsayer
666121816Sbrooks	TAPDEBUG("%s starting\n", ifp->if_xname);
66763670Snsayer
66863803Snsayer	/*
66963803Snsayer	 * do not junk pending output if we are in VMnet mode.
67063803Snsayer	 * XXX: can this do any harm because of queue overflow?
67163803Snsayer	 */
67263803Snsayer
673127098Srwatson	mtx_lock(&tp->tap_mtx);
674111742Sdes	if (((tp->tap_flags & TAP_VMNET) == 0) &&
67563803Snsayer	    ((tp->tap_flags & TAP_READY) != TAP_READY)) {
676213028Sjhb		struct mbuf *m;
67763670Snsayer
678127098Srwatson		/* Unlocked read. */
679121816Sbrooks		TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname,
680121816Sbrooks		    tp->tap_flags);
68163670Snsayer
682213028Sjhb		for (;;) {
68363670Snsayer			IF_DEQUEUE(&ifp->if_snd, m);
684213028Sjhb			if (m != NULL) {
68563670Snsayer				m_freem(m);
686271867Sglebius				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
687213028Sjhb			} else
688213028Sjhb				break;
689213028Sjhb		}
690213028Sjhb		mtx_unlock(&tp->tap_mtx);
69163670Snsayer
69263670Snsayer		return;
69363670Snsayer	}
69463670Snsayer
695148887Srwatson	ifp->if_drv_flags |= IFF_DRV_OACTIVE;
69663670Snsayer
697213028Sjhb	if (!IFQ_IS_EMPTY(&ifp->if_snd)) {
69863670Snsayer		if (tp->tap_flags & TAP_RWAIT) {
69963670Snsayer			tp->tap_flags &= ~TAP_RWAIT;
700111748Sdes			wakeup(tp);
70163670Snsayer		}
70263670Snsayer
703127098Srwatson		if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) {
704127098Srwatson			mtx_unlock(&tp->tap_mtx);
70595883Salfred			pgsigio(&tp->tap_sigio, SIGIO, 0);
706213028Sjhb			mtx_lock(&tp->tap_mtx);
707213028Sjhb		}
70863670Snsayer
709122352Stanimura		selwakeuppri(&tp->tap_rsel, PZERO+1);
710213028Sjhb		KNOTE_LOCKED(&tp->tap_rsel.si_note, 0);
711271867Sglebius		if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); /* obytes are counted in ether_output */
71263670Snsayer	}
71363670Snsayer
714148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
715213028Sjhb	mtx_unlock(&tp->tap_mtx);
71663670Snsayer} /* tapifstart */
71763670Snsayer
71863670Snsayer
71963670Snsayer/*
72063670Snsayer * tapioctl
72163670Snsayer *
72263670Snsayer * the cdevsw interface is now pretty minimal
72363670Snsayer */
72463670Snsayerstatic int
725156783Semaxtapioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
72663670Snsayer{
727341884Shselasky	struct ifreq		 ifr;
72863670Snsayer	struct tap_softc	*tp = dev->si_drv1;
729147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
730111742Sdes	struct tapinfo		*tapp = NULL;
731102052Ssobomax	int			 f;
732341884Shselasky	int			 error;
733162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
734162711Sru    defined(COMPAT_FREEBSD4)
735162711Sru	int			 ival;
736162711Sru#endif
73763670Snsayer
73863670Snsayer	switch (cmd) {
739111742Sdes		case TAPSIFINFO:
740111742Sdes			tapp = (struct tapinfo *)data;
741326691Shselasky			if (ifp->if_type != tapp->type)
742326691Shselasky				return (EPROTOTYPE);
743213028Sjhb			mtx_lock(&tp->tap_mtx);
744341884Shselasky			if (ifp->if_mtu != tapp->mtu) {
745347376Skevans				strlcpy(ifr.ifr_name, if_name(ifp), IFNAMSIZ);
746341884Shselasky				ifr.ifr_mtu = tapp->mtu;
747341884Shselasky				CURVNET_SET(ifp->if_vnet);
748341884Shselasky				error = ifhwioctl(SIOCSIFMTU, ifp,
749341884Shselasky				    (caddr_t)&ifr, td);
750341884Shselasky				CURVNET_RESTORE();
751341884Shselasky				if (error) {
752341884Shselasky					mtx_unlock(&tp->tap_mtx);
753341884Shselasky					return (error);
754341884Shselasky				}
755341884Shselasky			}
756111742Sdes			ifp->if_baudrate = tapp->baudrate;
757213028Sjhb			mtx_unlock(&tp->tap_mtx);
758111742Sdes			break;
75963670Snsayer
760111742Sdes		case TAPGIFINFO:
761111742Sdes			tapp = (struct tapinfo *)data;
762213028Sjhb			mtx_lock(&tp->tap_mtx);
763111742Sdes			tapp->mtu = ifp->if_mtu;
764111742Sdes			tapp->type = ifp->if_type;
765111742Sdes			tapp->baudrate = ifp->if_baudrate;
766213028Sjhb			mtx_unlock(&tp->tap_mtx);
767111742Sdes			break;
76863670Snsayer
76963670Snsayer		case TAPSDEBUG:
770159079Smarius			tapdebug = *(int *)data;
77183043Sbrooks			break;
77263670Snsayer
77363670Snsayer		case TAPGDEBUG:
774159079Smarius			*(int *)data = tapdebug;
77583043Sbrooks			break;
77663670Snsayer
777182880Semax		case TAPGIFNAME: {
778182880Semax			struct ifreq	*ifr = (struct ifreq *) data;
779182880Semax
780182880Semax			strlcpy(ifr->ifr_name, ifp->if_xname, IFNAMSIZ);
781182880Semax			} break;
782182880Semax
78363670Snsayer		case FIONBIO:
78483043Sbrooks			break;
78563670Snsayer
78663670Snsayer		case FIOASYNC:
787127098Srwatson			mtx_lock(&tp->tap_mtx);
788159079Smarius			if (*(int *)data)
78963670Snsayer				tp->tap_flags |= TAP_ASYNC;
79063670Snsayer			else
79163670Snsayer				tp->tap_flags &= ~TAP_ASYNC;
792127098Srwatson			mtx_unlock(&tp->tap_mtx);
79383043Sbrooks			break;
79463670Snsayer
79563670Snsayer		case FIONREAD:
796213028Sjhb			if (!IFQ_IS_EMPTY(&ifp->if_snd)) {
797213028Sjhb				struct mbuf *mb;
79863670Snsayer
799213028Sjhb				IFQ_LOCK(&ifp->if_snd);
800213028Sjhb				IFQ_POLL_NOLOCK(&ifp->if_snd, mb);
801213028Sjhb				for (*(int *)data = 0; mb != NULL;
802213028Sjhb				     mb = mb->m_next)
803159079Smarius					*(int *)data += mb->m_len;
804213028Sjhb				IFQ_UNLOCK(&ifp->if_snd);
80583043Sbrooks			} else
806159079Smarius				*(int *)data = 0;
80783043Sbrooks			break;
80863670Snsayer
80963670Snsayer		case FIOSETOWN:
810159079Smarius			return (fsetown(*(int *)data, &tp->tap_sigio));
81163670Snsayer
81263670Snsayer		case FIOGETOWN:
813159079Smarius			*(int *)data = fgetown(&tp->tap_sigio);
81463670Snsayer			return (0);
81563670Snsayer
81663670Snsayer		/* this is deprecated, FIOSETOWN should be used instead */
81763670Snsayer		case TIOCSPGRP:
818159079Smarius			return (fsetown(-(*(int *)data), &tp->tap_sigio));
81963670Snsayer
82063670Snsayer		/* this is deprecated, FIOGETOWN should be used instead */
82163670Snsayer		case TIOCGPGRP:
822159079Smarius			*(int *)data = -fgetown(&tp->tap_sigio);
82363670Snsayer			return (0);
82463670Snsayer
82563670Snsayer		/* VMware/VMnet port ioctl's */
82663670Snsayer
827162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
828162711Sru    defined(COMPAT_FREEBSD4)
829162711Sru		case _IO('V', 0):
830162711Sru			ival = IOCPARM_IVAL(data);
831162711Sru			data = (caddr_t)&ival;
832162711Sru			/* FALLTHROUGH */
833162711Sru#endif
83483043Sbrooks		case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */
835162711Sru			f = *(int *)data;
83663670Snsayer			f &= 0x0fff;
83763670Snsayer			f &= ~IFF_CANTCHANGE;
83863670Snsayer			f |= IFF_UP;
83963670Snsayer
840213028Sjhb			mtx_lock(&tp->tap_mtx);
84163670Snsayer			ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE);
842213028Sjhb			mtx_unlock(&tp->tap_mtx);
84383043Sbrooks			break;
84463670Snsayer
845257696Sglebius		case SIOCGIFADDR:	/* get MAC address of the remote side */
846127165Srwatson			mtx_lock(&tp->tap_mtx);
84763861Snsayer			bcopy(tp->ether_addr, data, sizeof(tp->ether_addr));
848127165Srwatson			mtx_unlock(&tp->tap_mtx);
84983043Sbrooks			break;
85063670Snsayer
85163861Snsayer		case SIOCSIFADDR:	/* set MAC address of the remote side */
852127165Srwatson			mtx_lock(&tp->tap_mtx);
85363861Snsayer			bcopy(data, tp->ether_addr, sizeof(tp->ether_addr));
854127165Srwatson			mtx_unlock(&tp->tap_mtx);
85583043Sbrooks			break;
85663670Snsayer
85763670Snsayer		default:
85863670Snsayer			return (ENOTTY);
85963670Snsayer	}
86063670Snsayer	return (0);
86163670Snsayer} /* tapioctl */
86263670Snsayer
86363670Snsayer
86463670Snsayer/*
86563670Snsayer * tapread
86663670Snsayer *
86763670Snsayer * the cdevsw read interface - reads a packet at a time, or at
86863670Snsayer * least as much of a packet as can be read
86963670Snsayer */
87063670Snsayerstatic int
871156783Semaxtapread(struct cdev *dev, struct uio *uio, int flag)
87263670Snsayer{
87363670Snsayer	struct tap_softc	*tp = dev->si_drv1;
874147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
87590227Sdillon	struct mbuf		*m = NULL;
876213028Sjhb	int			 error = 0, len;
87763670Snsayer
878183397Sed	TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, dev2unit(dev));
87963670Snsayer
880127098Srwatson	mtx_lock(&tp->tap_mtx);
88163670Snsayer	if ((tp->tap_flags & TAP_READY) != TAP_READY) {
882127098Srwatson		mtx_unlock(&tp->tap_mtx);
883127098Srwatson
884127098Srwatson		/* Unlocked read. */
885121816Sbrooks		TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n",
886183397Sed			ifp->if_xname, dev2unit(dev), tp->tap_flags);
88763803Snsayer
88863670Snsayer		return (EHOSTDOWN);
88963670Snsayer	}
89063670Snsayer
89163670Snsayer	tp->tap_flags &= ~TAP_RWAIT;
89263670Snsayer
89363670Snsayer	/* sleep until we get a packet */
89463670Snsayer	do {
89590227Sdillon		IF_DEQUEUE(&ifp->if_snd, m);
89663670Snsayer
89790227Sdillon		if (m == NULL) {
898213028Sjhb			if (flag & O_NONBLOCK) {
899213028Sjhb				mtx_unlock(&tp->tap_mtx);
90063670Snsayer				return (EWOULDBLOCK);
901213028Sjhb			}
902111742Sdes
90363670Snsayer			tp->tap_flags |= TAP_RWAIT;
904213028Sjhb			error = mtx_sleep(tp, &tp->tap_mtx, PCATCH | (PZERO + 1),
905213028Sjhb			    "taprd", 0);
906213028Sjhb			if (error) {
907213028Sjhb				mtx_unlock(&tp->tap_mtx);
90863670Snsayer				return (error);
909213028Sjhb			}
91063670Snsayer		}
91190227Sdillon	} while (m == NULL);
912213028Sjhb	mtx_unlock(&tp->tap_mtx);
91363670Snsayer
91463670Snsayer	/* feed packet to bpf */
915106939Ssam	BPF_MTAP(ifp, m);
91663670Snsayer
91763670Snsayer	/* xfer packet to user space */
91890227Sdillon	while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) {
91990227Sdillon		len = min(uio->uio_resid, m->m_len);
92063670Snsayer		if (len == 0)
92163670Snsayer			break;
92263670Snsayer
923111741Sdes		error = uiomove(mtod(m, void *), len, uio);
92490227Sdillon		m = m_free(m);
92563670Snsayer	}
92663670Snsayer
92790227Sdillon	if (m != NULL) {
928121816Sbrooks		TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname,
929183397Sed			dev2unit(dev));
93090227Sdillon		m_freem(m);
93163670Snsayer	}
93263670Snsayer
93363670Snsayer	return (error);
93463670Snsayer} /* tapread */
93563670Snsayer
93663670Snsayer
93763670Snsayer/*
93863670Snsayer * tapwrite
93963670Snsayer *
94063670Snsayer * the cdevsw write interface - an atomic write is a packet - or else!
94163670Snsayer */
94263670Snsayerstatic int
943156783Semaxtapwrite(struct cdev *dev, struct uio *uio, int flag)
94463670Snsayer{
945166443Sbms	struct ether_header	*eh;
94663670Snsayer	struct tap_softc	*tp = dev->si_drv1;
947147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
948137101Sglebius	struct mbuf		*m;
94963670Snsayer
950240945Semaste	TAPDEBUG("%s writing, minor = %#x\n",
951183397Sed		ifp->if_xname, dev2unit(dev));
95263670Snsayer
95363670Snsayer	if (uio->uio_resid == 0)
95463670Snsayer		return (0);
95563670Snsayer
95663670Snsayer	if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) {
957194990Skib		TAPDEBUG("%s invalid packet len = %zd, minor = %#x\n",
958183397Sed			ifp->if_xname, uio->uio_resid, dev2unit(dev));
95963803Snsayer
96063670Snsayer		return (EIO);
96163670Snsayer	}
96263670Snsayer
963243882Sglebius	if ((m = m_uiotombuf(uio, M_NOWAIT, 0, ETHER_ALIGN,
964163915Sandre	    M_PKTHDR)) == NULL) {
965271867Sglebius		if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
966163986Scsjp		return (ENOBUFS);
96763670Snsayer	}
96863670Snsayer
969137101Sglebius	m->m_pkthdr.rcvif = ifp;
970111742Sdes
971166443Sbms	/*
972166443Sbms	 * Only pass a unicast frame to ether_input(), if it would actually
973166443Sbms	 * have been received by non-virtual hardware.
974166443Sbms	 */
975166443Sbms	if (m->m_len < sizeof(struct ether_header)) {
976166443Sbms		m_freem(m);
977166443Sbms		return (0);
978166443Sbms	}
979166443Sbms	eh = mtod(m, struct ether_header *);
980166443Sbms
981166443Sbms	if (eh && (ifp->if_flags & IFF_PROMISC) == 0 &&
982166443Sbms	    !ETHER_IS_MULTICAST(eh->ether_dhost) &&
983166443Sbms	    bcmp(eh->ether_dhost, IF_LLADDR(ifp), ETHER_ADDR_LEN) != 0) {
984166443Sbms		m_freem(m);
985166443Sbms		return (0);
986166443Sbms	}
987166443Sbms
988106939Ssam	/* Pass packet up to parent. */
989236724Strociny	CURVNET_SET(ifp->if_vnet);
990137101Sglebius	(*ifp->if_input)(ifp, m);
991236724Strociny	CURVNET_RESTORE();
992271867Sglebius	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); /* ibytes are counted in parent */
99363670Snsayer
99463670Snsayer	return (0);
99563670Snsayer} /* tapwrite */
99663670Snsayer
99763670Snsayer
99863670Snsayer/*
99963670Snsayer * tappoll
100063670Snsayer *
100163670Snsayer * the poll interface, this is only useful on reads
100263670Snsayer * really. the write detect always returns true, write never blocks
100363670Snsayer * anyway, it either accepts the packet or drops it
100463670Snsayer */
100563670Snsayerstatic int
1006156783Semaxtappoll(struct cdev *dev, int events, struct thread *td)
100763670Snsayer{
100863670Snsayer	struct tap_softc	*tp = dev->si_drv1;
1009147256Sbrooks	struct ifnet		*ifp = tp->tap_ifp;
1010213028Sjhb	int			 revents = 0;
101163670Snsayer
1012121816Sbrooks	TAPDEBUG("%s polling, minor = %#x\n",
1013183397Sed		ifp->if_xname, dev2unit(dev));
101463670Snsayer
101563670Snsayer	if (events & (POLLIN | POLLRDNORM)) {
1016213028Sjhb		IFQ_LOCK(&ifp->if_snd);
1017213028Sjhb		if (!IFQ_IS_EMPTY(&ifp->if_snd)) {
1018121816Sbrooks			TAPDEBUG("%s have data in queue. len = %d, " \
1019121816Sbrooks				"minor = %#x\n", ifp->if_xname,
1020183397Sed				ifp->if_snd.ifq_len, dev2unit(dev));
102163803Snsayer
102263670Snsayer			revents |= (events & (POLLIN | POLLRDNORM));
102383043Sbrooks		} else {
1024121816Sbrooks			TAPDEBUG("%s waiting for data, minor = %#x\n",
1025183397Sed				ifp->if_xname, dev2unit(dev));
102663803Snsayer
102783805Sjhb			selrecord(td, &tp->tap_rsel);
102863670Snsayer		}
1029213028Sjhb		IFQ_UNLOCK(&ifp->if_snd);
103063670Snsayer	}
103163670Snsayer
103263670Snsayer	if (events & (POLLOUT | POLLWRNORM))
103363670Snsayer		revents |= (events & (POLLOUT | POLLWRNORM));
103463670Snsayer
103563670Snsayer	return (revents);
103663670Snsayer} /* tappoll */
1037156783Semax
1038156783Semax
1039156783Semax/*
1040156783Semax * tap_kqfilter
1041156783Semax *
1042156783Semax * support for kevent() system call
1043156783Semax */
1044156783Semaxstatic int
1045156783Semaxtapkqfilter(struct cdev *dev, struct knote *kn)
1046156783Semax{
1047156783Semax	struct tap_softc	*tp = dev->si_drv1;
1048156783Semax	struct ifnet		*ifp = tp->tap_ifp;
1049156783Semax
1050156783Semax	switch (kn->kn_filter) {
1051156783Semax	case EVFILT_READ:
1052156783Semax		TAPDEBUG("%s kqfilter: EVFILT_READ, minor = %#x\n",
1053183397Sed			ifp->if_xname, dev2unit(dev));
1054156783Semax		kn->kn_fop = &tap_read_filterops;
1055156783Semax		break;
1056156783Semax
1057156783Semax	case EVFILT_WRITE:
1058156783Semax		TAPDEBUG("%s kqfilter: EVFILT_WRITE, minor = %#x\n",
1059183397Sed			ifp->if_xname, dev2unit(dev));
1060156783Semax		kn->kn_fop = &tap_write_filterops;
1061156783Semax		break;
1062156783Semax
1063156783Semax	default:
1064156783Semax		TAPDEBUG("%s kqfilter: invalid filter, minor = %#x\n",
1065183397Sed			ifp->if_xname, dev2unit(dev));
1066156783Semax		return (EINVAL);
1067156783Semax		/* NOT REACHED */
1068156783Semax	}
1069156783Semax
1070213028Sjhb	kn->kn_hook = tp;
1071156783Semax	knlist_add(&tp->tap_rsel.si_note, kn, 0);
1072156783Semax
1073156783Semax	return (0);
1074156783Semax} /* tapkqfilter */
1075156783Semax
1076156783Semax
1077156783Semax/*
1078156783Semax * tap_kqread
1079156783Semax *
1080156783Semax * Return true if there is data in the interface queue
1081156783Semax */
1082156783Semaxstatic int
1083156783Semaxtapkqread(struct knote *kn, long hint)
1084156783Semax{
1085213028Sjhb	int			 ret;
1086213028Sjhb	struct tap_softc	*tp = kn->kn_hook;
1087213028Sjhb	struct cdev		*dev = tp->tap_dev;
1088156783Semax	struct ifnet		*ifp = tp->tap_ifp;
1089156783Semax
1090156783Semax	if ((kn->kn_data = ifp->if_snd.ifq_len) > 0) {
1091156783Semax		TAPDEBUG("%s have data in queue. len = %d, minor = %#x\n",
1092183397Sed			ifp->if_xname, ifp->if_snd.ifq_len, dev2unit(dev));
1093156783Semax		ret = 1;
1094156783Semax	} else {
1095156783Semax		TAPDEBUG("%s waiting for data, minor = %#x\n",
1096183397Sed			ifp->if_xname, dev2unit(dev));
1097156783Semax		ret = 0;
1098156783Semax	}
1099156783Semax
1100156783Semax	return (ret);
1101156783Semax} /* tapkqread */
1102156783Semax
1103156783Semax
1104156783Semax/*
1105156783Semax * tap_kqwrite
1106156783Semax *
1107156783Semax * Always can write. Return the MTU in kn->data
1108156783Semax */
1109156783Semaxstatic int
1110156783Semaxtapkqwrite(struct knote *kn, long hint)
1111156783Semax{
1112213028Sjhb	struct tap_softc	*tp = kn->kn_hook;
1113156783Semax	struct ifnet		*ifp = tp->tap_ifp;
1114156783Semax
1115156783Semax	kn->kn_data = ifp->if_mtu;
1116156783Semax
1117156783Semax	return (1);
1118156783Semax} /* tapkqwrite */
1119156783Semax
1120156783Semax
1121156783Semaxstatic void
1122156783Semaxtapkqdetach(struct knote *kn)
1123156783Semax{
1124213028Sjhb	struct tap_softc	*tp = kn->kn_hook;
1125156783Semax
1126156783Semax	knlist_remove(&tp->tap_rsel.si_note, kn, 0);
1127156783Semax} /* tapkqdetach */
1128156783Semax
1129