if_tap.c revision 166443
190792Sgshapiro/*-
294334Sgshapiro * Copyright (C) 1999-2000 by Maksim Yevmenkin <m_evmenkin@yahoo.com>
390792Sgshapiro * All rights reserved.
490792Sgshapiro *
590792Sgshapiro * Redistribution and use in source and binary forms, with or without
690792Sgshapiro * modification, are permitted provided that the following conditions
790792Sgshapiro * are met:
890792Sgshapiro * 1. Redistributions of source code must retain the above copyright
990792Sgshapiro *    notice, this list of conditions and the following disclaimer.
1090792Sgshapiro * 2. Redistributions in binary form must reproduce the above copyright
1190792Sgshapiro *    notice, this list of conditions and the following disclaimer in the
1290792Sgshapiro *    documentation and/or other materials provided with the distribution.
13102528Sgshapiro *
1490792Sgshapiro * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1590792Sgshapiro * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1690792Sgshapiro * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1790792Sgshapiro * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1890792Sgshapiro * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1990792Sgshapiro * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2090792Sgshapiro * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2190792Sgshapiro * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2290792Sgshapiro * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2390792Sgshapiro * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2490792Sgshapiro * SUCH DAMAGE.
2590792Sgshapiro *
2690792Sgshapiro * BASED ON:
2790792Sgshapiro * -------------------------------------------------------------------------
2890792Sgshapiro *
2990792Sgshapiro * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk>
3090792Sgshapiro * Nottingham University 1987.
3190792Sgshapiro */
3290792Sgshapiro
3390792Sgshapiro/*
3490792Sgshapiro * $FreeBSD: head/sys/net/if_tap.c 166443 2007-02-03 02:57:45Z bms $
3590792Sgshapiro * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $
3690792Sgshapiro */
3790792Sgshapiro
3890792Sgshapiro#include "opt_compat.h"
3990792Sgshapiro#include "opt_inet.h"
4090792Sgshapiro
4190792Sgshapiro#include <sys/param.h>
4290792Sgshapiro#include <sys/conf.h>
4390792Sgshapiro#include <sys/fcntl.h>
4490792Sgshapiro#include <sys/filio.h>
4590792Sgshapiro#include <sys/kernel.h>
4690792Sgshapiro#include <sys/malloc.h>
4790792Sgshapiro#include <sys/mbuf.h>
4890792Sgshapiro#include <sys/module.h>
4990792Sgshapiro#include <sys/poll.h>
5090792Sgshapiro#include <sys/priv.h>
5190792Sgshapiro#include <sys/proc.h>
5290792Sgshapiro#include <sys/selinfo.h>
5390792Sgshapiro#include <sys/signalvar.h>
5490792Sgshapiro#include <sys/socket.h>
5590792Sgshapiro#include <sys/sockio.h>
5690792Sgshapiro#include <sys/sysctl.h>
5790792Sgshapiro#include <sys/systm.h>
5890792Sgshapiro#include <sys/ttycom.h>
5990792Sgshapiro#include <sys/uio.h>
6090792Sgshapiro#include <sys/queue.h>
6190792Sgshapiro
6290792Sgshapiro#include <net/bpf.h>
6390792Sgshapiro#include <net/ethernet.h>
6490792Sgshapiro#include <net/if.h>
6590792Sgshapiro#include <net/if_dl.h>
6690792Sgshapiro#include <net/route.h>
6790792Sgshapiro#include <net/if_types.h>
6890792Sgshapiro
6990792Sgshapiro#include <netinet/in.h>
7090792Sgshapiro
7190792Sgshapiro#include <net/if_tapvar.h>
7290792Sgshapiro#include <net/if_tap.h>
7390792Sgshapiro
7490792Sgshapiro
7590792Sgshapiro#define CDEV_NAME	"tap"
7690792Sgshapiro#define TAPDEBUG	if (tapdebug) printf
7790792Sgshapiro
7890792Sgshapiro#define TAP		"tap"
7990792Sgshapiro#define VMNET		"vmnet"
8090792Sgshapiro#define TAPMAXUNIT	0x7fff
8190792Sgshapiro#define VMNET_DEV_MASK	CLONE_FLAG0
8290792Sgshapiro
8390792Sgshapiro/* module */
8490792Sgshapirostatic int		tapmodevent(module_t, int, void *);
8590792Sgshapiro
8690792Sgshapiro/* device */
8790792Sgshapirostatic void		tapclone(void *, struct ucred *, char *, int,
8890792Sgshapiro			    struct cdev **);
8990792Sgshapirostatic void		tapcreate(struct cdev *);
9090792Sgshapiro
9190792Sgshapiro/* network interface */
9290792Sgshapirostatic void		tapifstart(struct ifnet *);
9390792Sgshapirostatic int		tapifioctl(struct ifnet *, u_long, caddr_t);
9490792Sgshapirostatic void		tapifinit(void *);
9590792Sgshapiro
9690792Sgshapiro/* character device */
9790792Sgshapirostatic d_open_t		tapopen;
9890792Sgshapirostatic d_close_t	tapclose;
9990792Sgshapirostatic d_read_t		tapread;
10090792Sgshapirostatic d_write_t	tapwrite;
10190792Sgshapirostatic d_ioctl_t	tapioctl;
10290792Sgshapirostatic d_poll_t		tappoll;
10390792Sgshapirostatic d_kqfilter_t	tapkqfilter;
10490792Sgshapiro
10590792Sgshapiro/* kqueue(2) */
10690792Sgshapirostatic int		tapkqread(struct knote *, long);
10790792Sgshapirostatic int		tapkqwrite(struct knote *, long);
10894334Sgshapirostatic void		tapkqdetach(struct knote *);
10990792Sgshapiro
11090792Sgshapirostatic struct filterops	tap_read_filterops = {
11190792Sgshapiro	.f_isfd =	1,
11290792Sgshapiro	.f_attach =	NULL,
11390792Sgshapiro	.f_detach =	tapkqdetach,
11490792Sgshapiro	.f_event =	tapkqread,
11590792Sgshapiro};
11690792Sgshapiro
11790792Sgshapirostatic struct filterops	tap_write_filterops = {
11890792Sgshapiro	.f_isfd =	1,
11990792Sgshapiro	.f_attach =	NULL,
12090792Sgshapiro	.f_detach =	tapkqdetach,
12190792Sgshapiro	.f_event =	tapkqwrite,
12290792Sgshapiro};
12390792Sgshapiro
12490792Sgshapirostatic struct cdevsw	tap_cdevsw = {
12590792Sgshapiro	.d_version =	D_VERSION,
12690792Sgshapiro	.d_flags =	D_PSEUDO | D_NEEDGIANT,
12790792Sgshapiro	.d_open =	tapopen,
12890792Sgshapiro	.d_close =	tapclose,
12990792Sgshapiro	.d_read =	tapread,
13090792Sgshapiro	.d_write =	tapwrite,
13190792Sgshapiro	.d_ioctl =	tapioctl,
13290792Sgshapiro	.d_poll =	tappoll,
13390792Sgshapiro	.d_name =	CDEV_NAME,
13490792Sgshapiro	.d_kqfilter =	tapkqfilter,
13590792Sgshapiro};
13690792Sgshapiro
13790792Sgshapiro/*
13890792Sgshapiro * All global variables in if_tap.c are locked with tapmtx, with the
13990792Sgshapiro * exception of tapdebug, which is accessed unlocked; tapclones is
14090792Sgshapiro * static at runtime.
14190792Sgshapiro */
14290792Sgshapirostatic struct mtx		tapmtx;
14390792Sgshapirostatic int			tapdebug = 0;        /* debug flag   */
14490792Sgshapirostatic int			tapuopen = 0;        /* allow user open() */
14590792Sgshapirostatic SLIST_HEAD(, tap_softc)	taphead;             /* first device */
14690792Sgshapirostatic struct clonedevs 	*tapclones;
14790792Sgshapiro
14890792SgshapiroMALLOC_DECLARE(M_TAP);
14990792SgshapiroMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface");
15090792SgshapiroSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, "");
15190792Sgshapiro
15290792SgshapiroSYSCTL_DECL(_net_link);
15390792SgshapiroSYSCTL_NODE(_net_link, OID_AUTO, tap, CTLFLAG_RW, 0,
15490792Sgshapiro    "Ethernet tunnel software network interface");
15590792SgshapiroSYSCTL_INT(_net_link_tap, OID_AUTO, user_open, CTLFLAG_RW, &tapuopen, 0,
15690792Sgshapiro	"Allow user to open /dev/tap (based on node permissions)");
15790792SgshapiroSYSCTL_INT(_net_link_tap, OID_AUTO, debug, CTLFLAG_RW, &tapdebug, 0, "");
15890792Sgshapiro
15990792SgshapiroDEV_MODULE(if_tap, tapmodevent, NULL);
16090792Sgshapiro
16190792Sgshapiro/*
16290792Sgshapiro * tapmodevent
16390792Sgshapiro *
16490792Sgshapiro * module event handler
16590792Sgshapiro */
16690792Sgshapirostatic int
16790792Sgshapirotapmodevent(module_t mod, int type, void *data)
16890792Sgshapiro{
16990792Sgshapiro	static eventhandler_tag	 eh_tag = NULL;
17090792Sgshapiro	struct tap_softc	*tp = NULL;
17190792Sgshapiro	struct ifnet		*ifp = NULL;
17290792Sgshapiro	int			 s;
17390792Sgshapiro
17490792Sgshapiro	switch (type) {
17590792Sgshapiro	case MOD_LOAD:
17690792Sgshapiro
17790792Sgshapiro		/* intitialize device */
17890792Sgshapiro
17990792Sgshapiro		mtx_init(&tapmtx, "tapmtx", NULL, MTX_DEF);
18090792Sgshapiro		SLIST_INIT(&taphead);
18190792Sgshapiro
18290792Sgshapiro		clone_setup(&tapclones);
18390792Sgshapiro		eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000);
18490792Sgshapiro		if (eh_tag == NULL) {
18590792Sgshapiro			clone_cleanup(&tapclones);
18690792Sgshapiro			mtx_destroy(&tapmtx);
18790792Sgshapiro			return (ENOMEM);
18890792Sgshapiro		}
18990792Sgshapiro		return (0);
19090792Sgshapiro
19190792Sgshapiro	case MOD_UNLOAD:
19290792Sgshapiro		/*
19390792Sgshapiro		 * The EBUSY algorithm here can't quite atomically
19490792Sgshapiro		 * guarantee that this is race-free since we have to
19590792Sgshapiro		 * release the tap mtx to deregister the clone handler.
19690792Sgshapiro		 */
19790792Sgshapiro		mtx_lock(&tapmtx);
19890792Sgshapiro		SLIST_FOREACH(tp, &taphead, tap_next) {
19990792Sgshapiro			mtx_lock(&tp->tap_mtx);
20090792Sgshapiro			if (tp->tap_flags & TAP_OPEN) {
20190792Sgshapiro				mtx_unlock(&tp->tap_mtx);
20290792Sgshapiro				mtx_unlock(&tapmtx);
20390792Sgshapiro				return (EBUSY);
20490792Sgshapiro			}
20590792Sgshapiro			mtx_unlock(&tp->tap_mtx);
20690792Sgshapiro		}
20790792Sgshapiro		mtx_unlock(&tapmtx);
20890792Sgshapiro
20990792Sgshapiro		EVENTHANDLER_DEREGISTER(dev_clone, eh_tag);
21090792Sgshapiro
21190792Sgshapiro		mtx_lock(&tapmtx);
21290792Sgshapiro		while ((tp = SLIST_FIRST(&taphead)) != NULL) {
21390792Sgshapiro			SLIST_REMOVE_HEAD(&taphead, tap_next);
21490792Sgshapiro			mtx_unlock(&tapmtx);
21590792Sgshapiro
21690792Sgshapiro			ifp = tp->tap_ifp;
21790792Sgshapiro
21890792Sgshapiro			TAPDEBUG("detaching %s\n", ifp->if_xname);
21990792Sgshapiro
22090792Sgshapiro			/* Unlocked read. */
22190792Sgshapiro			KASSERT(!(tp->tap_flags & TAP_OPEN),
22290792Sgshapiro				("%s flags is out of sync", ifp->if_xname));
22390792Sgshapiro
22490792Sgshapiro			knlist_destroy(&tp->tap_rsel.si_note);
22590792Sgshapiro			destroy_dev(tp->tap_dev);
22690792Sgshapiro			s = splimp();
22790792Sgshapiro			ether_ifdetach(ifp);
22890792Sgshapiro			if_free_type(ifp, IFT_ETHER);
22990792Sgshapiro			splx(s);
23090792Sgshapiro
23190792Sgshapiro			mtx_destroy(&tp->tap_mtx);
23290792Sgshapiro			free(tp, M_TAP);
23390792Sgshapiro			mtx_lock(&tapmtx);
23490792Sgshapiro		}
23590792Sgshapiro		mtx_unlock(&tapmtx);
23690792Sgshapiro		clone_cleanup(&tapclones);
23790792Sgshapiro
23890792Sgshapiro		mtx_destroy(&tapmtx);
23990792Sgshapiro
24090792Sgshapiro		break;
24190792Sgshapiro
24290792Sgshapiro	default:
24390792Sgshapiro		return (EOPNOTSUPP);
24490792Sgshapiro	}
24590792Sgshapiro
24690792Sgshapiro	return (0);
24790792Sgshapiro} /* tapmodevent */
24890792Sgshapiro
24990792Sgshapiro
25090792Sgshapiro/*
25190792Sgshapiro * DEVFS handler
25290792Sgshapiro *
25390792Sgshapiro * We need to support two kind of devices - tap and vmnet
25490792Sgshapiro */
25590792Sgshapirostatic void
25690792Sgshapirotapclone(void *arg, struct ucred *cred, char *name, int namelen, struct cdev **dev)
25790792Sgshapiro{
25890792Sgshapiro	int		extra;
25990792Sgshapiro	int		i, unit;
26090792Sgshapiro	char		*device_name = name;
26190792Sgshapiro
26290792Sgshapiro	if (*dev != NULL)
26390792Sgshapiro		return;
26490792Sgshapiro
26590792Sgshapiro	device_name = TAP;
26690792Sgshapiro	extra = 0;
26790792Sgshapiro	if (strcmp(name, TAP) == 0) {
26890792Sgshapiro		unit = -1;
26990792Sgshapiro	} else if (strcmp(name, VMNET) == 0) {
27090792Sgshapiro		device_name = VMNET;
27190792Sgshapiro		extra = VMNET_DEV_MASK;
27290792Sgshapiro		unit = -1;
27390792Sgshapiro	} else if (dev_stdclone(name, NULL, device_name, &unit) != 1) {
27490792Sgshapiro		device_name = VMNET;
27590792Sgshapiro		extra = VMNET_DEV_MASK;
27690792Sgshapiro		if (dev_stdclone(name, NULL, device_name, &unit) != 1)
27790792Sgshapiro			return;
27890792Sgshapiro	}
27990792Sgshapiro
28090792Sgshapiro	/* find any existing device, or allocate new unit number */
28190792Sgshapiro	i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra);
28290792Sgshapiro	if (i) {
28390792Sgshapiro		*dev = make_dev(&tap_cdevsw, unit2minor(unit | extra),
28490792Sgshapiro		     UID_ROOT, GID_WHEEL, 0600, "%s%d", device_name, unit);
28590792Sgshapiro		if (*dev != NULL) {
28690792Sgshapiro			dev_ref(*dev);
28790792Sgshapiro			(*dev)->si_flags |= SI_CHEAPCLONE;
28890792Sgshapiro		}
28990792Sgshapiro	}
29090792Sgshapiro} /* tapclone */
29190792Sgshapiro
29290792Sgshapiro
29390792Sgshapiro/*
29490792Sgshapiro * tapcreate
29590792Sgshapiro *
29690792Sgshapiro * to create interface
29790792Sgshapiro */
29890792Sgshapirostatic void
29990792Sgshapirotapcreate(struct cdev *dev)
30090792Sgshapiro{
30190792Sgshapiro	struct ifnet		*ifp = NULL;
30290792Sgshapiro	struct tap_softc	*tp = NULL;
30390792Sgshapiro	unsigned short		 macaddr_hi;
30490792Sgshapiro	int			 unit, s;
30590792Sgshapiro	char			*name = NULL;
30690792Sgshapiro	u_char			eaddr[6];
30790792Sgshapiro
30890792Sgshapiro	dev->si_flags &= ~SI_CHEAPCLONE;
30990792Sgshapiro
31090792Sgshapiro	/* allocate driver storage and create device */
31190792Sgshapiro	MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO);
31290792Sgshapiro	mtx_init(&tp->tap_mtx, "tap_mtx", NULL, MTX_DEF);
31390792Sgshapiro	mtx_lock(&tapmtx);
31490792Sgshapiro	SLIST_INSERT_HEAD(&taphead, tp, tap_next);
31590792Sgshapiro	mtx_unlock(&tapmtx);
31690792Sgshapiro
31790792Sgshapiro	unit = dev2unit(dev);
31890792Sgshapiro
31990792Sgshapiro	/* select device: tap or vmnet */
32090792Sgshapiro	if (unit & VMNET_DEV_MASK) {
32190792Sgshapiro		name = VMNET;
32290792Sgshapiro		tp->tap_flags |= TAP_VMNET;
32390792Sgshapiro	} else
32490792Sgshapiro		name = TAP;
32590792Sgshapiro
32690792Sgshapiro	unit &= TAPMAXUNIT;
32790792Sgshapiro
32890792Sgshapiro	TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev));
32990792Sgshapiro
33090792Sgshapiro	/* generate fake MAC address: 00 bd xx xx xx unit_no */
33190792Sgshapiro	macaddr_hi = htons(0x00bd);
33290792Sgshapiro	bcopy(&macaddr_hi, eaddr, sizeof(short));
33390792Sgshapiro	bcopy(&ticks, &eaddr[2], sizeof(long));
33490792Sgshapiro	eaddr[5] = (u_char)unit;
33590792Sgshapiro
33690792Sgshapiro	/* fill the rest and attach interface */
33790792Sgshapiro	ifp = tp->tap_ifp = if_alloc(IFT_ETHER);
33890792Sgshapiro	if (ifp == NULL)
33990792Sgshapiro		panic("%s%d: can not if_alloc()", name, unit);
34090792Sgshapiro	ifp->if_softc = tp;
34190792Sgshapiro	if_initname(ifp, name, unit);
34290792Sgshapiro	ifp->if_init = tapifinit;
34390792Sgshapiro	ifp->if_start = tapifstart;
34490792Sgshapiro	ifp->if_ioctl = tapifioctl;
34590792Sgshapiro	ifp->if_mtu = ETHERMTU;
34690792Sgshapiro	ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
34790792Sgshapiro	ifp->if_snd.ifq_maxlen = ifqmaxlen;
34890792Sgshapiro
34990792Sgshapiro	dev->si_drv1 = tp;
35090792Sgshapiro	tp->tap_dev = dev;
35190792Sgshapiro
35290792Sgshapiro	s = splimp();
35390792Sgshapiro	ether_ifattach(ifp, eaddr);
35490792Sgshapiro	splx(s);
35590792Sgshapiro
35690792Sgshapiro	mtx_lock(&tp->tap_mtx);
35790792Sgshapiro	tp->tap_flags |= TAP_INITED;
35890792Sgshapiro	mtx_unlock(&tp->tap_mtx);
35990792Sgshapiro
36090792Sgshapiro	knlist_init(&tp->tap_rsel.si_note, NULL, NULL, NULL, NULL);
36190792Sgshapiro
36290792Sgshapiro	TAPDEBUG("interface %s is created. minor = %#x\n",
36390792Sgshapiro		ifp->if_xname, minor(dev));
36490792Sgshapiro} /* tapcreate */
36590792Sgshapiro
36690792Sgshapiro
36790792Sgshapiro/*
36890792Sgshapiro * tapopen
36990792Sgshapiro *
37090792Sgshapiro * to open tunnel. must be superuser
37190792Sgshapiro */
37290792Sgshapirostatic int
37390792Sgshapirotapopen(struct cdev *dev, int flag, int mode, struct thread *td)
37490792Sgshapiro{
37590792Sgshapiro	struct tap_softc	*tp = NULL;
37690792Sgshapiro	struct ifnet		*ifp = NULL;
37790792Sgshapiro	int			 error, s;
37890792Sgshapiro
37990792Sgshapiro	if (tapuopen == 0) {
38090792Sgshapiro		error = priv_check(td, PRIV_NET_TAP);
38190792Sgshapiro		if (error)
38290792Sgshapiro			return (error);
38390792Sgshapiro	}
38490792Sgshapiro
38590792Sgshapiro	if ((dev2unit(dev) & CLONE_UNITMASK) > TAPMAXUNIT)
38690792Sgshapiro		return (ENXIO);
38790792Sgshapiro
38890792Sgshapiro	/*
38990792Sgshapiro	 * XXXRW: Non-atomic test-and-set of si_drv1.  Currently protected
39090792Sgshapiro	 * by Giant, but the race actually exists under memory pressure as
39190792Sgshapiro	 * well even when running with Giant, as malloc() may sleep.
39290792Sgshapiro	 */
39390792Sgshapiro	tp = dev->si_drv1;
39490792Sgshapiro	if (tp == NULL) {
39590792Sgshapiro		tapcreate(dev);
39690792Sgshapiro		tp = dev->si_drv1;
39790792Sgshapiro	}
39890792Sgshapiro
39990792Sgshapiro	mtx_lock(&tp->tap_mtx);
40090792Sgshapiro	if (tp->tap_flags & TAP_OPEN) {
40190792Sgshapiro		mtx_unlock(&tp->tap_mtx);
40290792Sgshapiro		return (EBUSY);
40390792Sgshapiro	}
40490792Sgshapiro
40590792Sgshapiro	bcopy(IF_LLADDR(tp->tap_ifp), tp->ether_addr, sizeof(tp->ether_addr));
40690792Sgshapiro	tp->tap_pid = td->td_proc->p_pid;
40790792Sgshapiro	tp->tap_flags |= TAP_OPEN;
40890792Sgshapiro	ifp = tp->tap_ifp;
40990792Sgshapiro	mtx_unlock(&tp->tap_mtx);
41090792Sgshapiro
41190792Sgshapiro	s = splimp();
41290792Sgshapiro	ifp->if_drv_flags |= IFF_DRV_RUNNING;
41390792Sgshapiro	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
41490792Sgshapiro	splx(s);
41590792Sgshapiro
41690792Sgshapiro	TAPDEBUG("%s is open. minor = %#x\n", ifp->if_xname, minor(dev));
41790792Sgshapiro
41890792Sgshapiro	return (0);
41990792Sgshapiro} /* tapopen */
42090792Sgshapiro
42190792Sgshapiro
42290792Sgshapiro/*
42390792Sgshapiro * tapclose
42490792Sgshapiro *
42590792Sgshapiro * close the device - mark i/f down & delete routing info
42690792Sgshapiro */
42790792Sgshapirostatic int
42890792Sgshapirotapclose(struct cdev *dev, int foo, int bar, struct thread *td)
42990792Sgshapiro{
43090792Sgshapiro	struct ifaddr		*ifa;
43190792Sgshapiro	struct tap_softc	*tp = dev->si_drv1;
43290792Sgshapiro	struct ifnet		*ifp = tp->tap_ifp;
43390792Sgshapiro	int			s;
43490792Sgshapiro
43590792Sgshapiro	/* junk all pending output */
43690792Sgshapiro	IF_DRAIN(&ifp->if_snd);
43790792Sgshapiro
43890792Sgshapiro	/*
43990792Sgshapiro	 * do not bring the interface down, and do not anything with
44090792Sgshapiro	 * interface, if we are in VMnet mode. just close the device.
44190792Sgshapiro	 */
44290792Sgshapiro
44390792Sgshapiro	mtx_lock(&tp->tap_mtx);
44490792Sgshapiro	if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) {
44590792Sgshapiro		mtx_unlock(&tp->tap_mtx);
44690792Sgshapiro		s = splimp();
44790792Sgshapiro		if_down(ifp);
44890792Sgshapiro		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
44990792Sgshapiro			TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
45090792Sgshapiro				rtinit(ifa, (int)RTM_DELETE, 0);
45190792Sgshapiro			}
45290792Sgshapiro			if_purgeaddrs(ifp);
45390792Sgshapiro			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
45490792Sgshapiro		}
45590792Sgshapiro		splx(s);
45690792Sgshapiro	} else
45790792Sgshapiro		mtx_unlock(&tp->tap_mtx);
45890792Sgshapiro
45990792Sgshapiro	funsetown(&tp->tap_sigio);
46090792Sgshapiro	selwakeuppri(&tp->tap_rsel, PZERO+1);
46190792Sgshapiro	KNOTE_UNLOCKED(&tp->tap_rsel.si_note, 0);
46290792Sgshapiro
46390792Sgshapiro	mtx_lock(&tp->tap_mtx);
46490792Sgshapiro	tp->tap_flags &= ~TAP_OPEN;
46590792Sgshapiro	tp->tap_pid = 0;
46690792Sgshapiro	mtx_unlock(&tp->tap_mtx);
46790792Sgshapiro
46890792Sgshapiro	TAPDEBUG("%s is closed. minor = %#x\n",
46990792Sgshapiro		ifp->if_xname, minor(dev));
47090792Sgshapiro
47190792Sgshapiro	return (0);
47290792Sgshapiro} /* tapclose */
47390792Sgshapiro
47490792Sgshapiro
47590792Sgshapiro/*
47690792Sgshapiro * tapifinit
47790792Sgshapiro *
47890792Sgshapiro * network interface initialization function
47990792Sgshapiro */
48090792Sgshapirostatic void
48190792Sgshapirotapifinit(void *xtp)
48290792Sgshapiro{
48390792Sgshapiro	struct tap_softc	*tp = (struct tap_softc *)xtp;
48490792Sgshapiro	struct ifnet		*ifp = tp->tap_ifp;
48590792Sgshapiro
48690792Sgshapiro	TAPDEBUG("initializing %s\n", ifp->if_xname);
48790792Sgshapiro
48890792Sgshapiro	ifp->if_drv_flags |= IFF_DRV_RUNNING;
48990792Sgshapiro	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
49090792Sgshapiro
49190792Sgshapiro	/* attempt to start output */
49290792Sgshapiro	tapifstart(ifp);
49390792Sgshapiro} /* tapifinit */
49490792Sgshapiro
49590792Sgshapiro
49690792Sgshapiro/*
49790792Sgshapiro * tapifioctl
49890792Sgshapiro *
49990792Sgshapiro * Process an ioctl request on network interface
50090792Sgshapiro */
50190792Sgshapirostatic int
50290792Sgshapirotapifioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
50390792Sgshapiro{
50490792Sgshapiro	struct tap_softc	*tp = ifp->if_softc;
50590792Sgshapiro	struct ifstat		*ifs = NULL;
50690792Sgshapiro	int			 s, dummy;
50790792Sgshapiro
50890792Sgshapiro	switch (cmd) {
50990792Sgshapiro		case SIOCSIFFLAGS: /* XXX -- just like vmnet does */
51090792Sgshapiro		case SIOCADDMULTI:
51190792Sgshapiro		case SIOCDELMULTI:
51290792Sgshapiro			break;
51390792Sgshapiro
51490792Sgshapiro		case SIOCGIFSTATUS:
51590792Sgshapiro			s = splimp();
51690792Sgshapiro			ifs = (struct ifstat *)data;
51790792Sgshapiro			dummy = strlen(ifs->ascii);
51890792Sgshapiro			mtx_lock(&tp->tap_mtx);
51990792Sgshapiro			if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii))
52090792Sgshapiro				snprintf(ifs->ascii + dummy,
52190792Sgshapiro					sizeof(ifs->ascii) - dummy,
52290792Sgshapiro					"\tOpened by PID %d\n", tp->tap_pid);
52390792Sgshapiro			mtx_unlock(&tp->tap_mtx);
52490792Sgshapiro			splx(s);
52590792Sgshapiro			break;
52690792Sgshapiro
52790792Sgshapiro		default:
52890792Sgshapiro			s = splimp();
52990792Sgshapiro			dummy = ether_ioctl(ifp, cmd, data);
53090792Sgshapiro			splx(s);
53190792Sgshapiro			return (dummy);
53290792Sgshapiro			/* NOT REACHED */
53390792Sgshapiro	}
53490792Sgshapiro
53590792Sgshapiro	return (0);
53690792Sgshapiro} /* tapifioctl */
53790792Sgshapiro
53890792Sgshapiro
53990792Sgshapiro/*
54090792Sgshapiro * tapifstart
54190792Sgshapiro *
54290792Sgshapiro * queue packets from higher level ready to put out
54390792Sgshapiro */
54490792Sgshapirostatic void
54590792Sgshapirotapifstart(struct ifnet *ifp)
54690792Sgshapiro{
54790792Sgshapiro	struct tap_softc	*tp = ifp->if_softc;
54890792Sgshapiro	int			 s;
54990792Sgshapiro
55090792Sgshapiro	TAPDEBUG("%s starting\n", ifp->if_xname);
55190792Sgshapiro
55290792Sgshapiro	/*
55390792Sgshapiro	 * do not junk pending output if we are in VMnet mode.
55490792Sgshapiro	 * XXX: can this do any harm because of queue overflow?
55590792Sgshapiro	 */
55690792Sgshapiro
55790792Sgshapiro	mtx_lock(&tp->tap_mtx);
55890792Sgshapiro	if (((tp->tap_flags & TAP_VMNET) == 0) &&
55990792Sgshapiro	    ((tp->tap_flags & TAP_READY) != TAP_READY)) {
56090792Sgshapiro		struct mbuf	*m = NULL;
56190792Sgshapiro
56290792Sgshapiro		mtx_unlock(&tp->tap_mtx);
56390792Sgshapiro
56490792Sgshapiro		/* Unlocked read. */
56590792Sgshapiro		TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname,
56690792Sgshapiro		    tp->tap_flags);
56790792Sgshapiro
56890792Sgshapiro		s = splimp();
56990792Sgshapiro		do {
57090792Sgshapiro			IF_DEQUEUE(&ifp->if_snd, m);
57190792Sgshapiro			if (m != NULL)
57290792Sgshapiro				m_freem(m);
57390792Sgshapiro			ifp->if_oerrors ++;
57490792Sgshapiro		} while (m != NULL);
57590792Sgshapiro		splx(s);
57690792Sgshapiro
57790792Sgshapiro		return;
57890792Sgshapiro	}
57990792Sgshapiro	mtx_unlock(&tp->tap_mtx);
58090792Sgshapiro
58190792Sgshapiro	s = splimp();
58290792Sgshapiro	ifp->if_drv_flags |= IFF_DRV_OACTIVE;
58390792Sgshapiro
58490792Sgshapiro	if (ifp->if_snd.ifq_len != 0) {
58590792Sgshapiro		mtx_lock(&tp->tap_mtx);
58690792Sgshapiro		if (tp->tap_flags & TAP_RWAIT) {
58790792Sgshapiro			tp->tap_flags &= ~TAP_RWAIT;
58890792Sgshapiro			wakeup(tp);
58990792Sgshapiro		}
59090792Sgshapiro
59190792Sgshapiro		if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) {
59290792Sgshapiro			mtx_unlock(&tp->tap_mtx);
59390792Sgshapiro			pgsigio(&tp->tap_sigio, SIGIO, 0);
59490792Sgshapiro		} else
59590792Sgshapiro			mtx_unlock(&tp->tap_mtx);
59690792Sgshapiro
59790792Sgshapiro		selwakeuppri(&tp->tap_rsel, PZERO+1);
59890792Sgshapiro		KNOTE_UNLOCKED(&tp->tap_rsel.si_note, 0);
59990792Sgshapiro		ifp->if_opackets ++; /* obytes are counted in ether_output */
60090792Sgshapiro	}
60190792Sgshapiro
60290792Sgshapiro	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
60390792Sgshapiro	splx(s);
60490792Sgshapiro} /* tapifstart */
60590792Sgshapiro
60690792Sgshapiro
60790792Sgshapiro/*
60890792Sgshapiro * tapioctl
60990792Sgshapiro *
61090792Sgshapiro * the cdevsw interface is now pretty minimal
61190792Sgshapiro */
61298121Sgshapirostatic int
61398121Sgshapirotapioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
61498121Sgshapiro{
61598121Sgshapiro	struct tap_softc	*tp = dev->si_drv1;
61698121Sgshapiro	struct ifnet		*ifp = tp->tap_ifp;
61798121Sgshapiro	struct tapinfo		*tapp = NULL;
61890792Sgshapiro	int			 s;
61990792Sgshapiro	int			 f;
62090792Sgshapiro#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
62190792Sgshapiro    defined(COMPAT_FREEBSD4)
62290792Sgshapiro	int			 ival;
62390792Sgshapiro#endif
62490792Sgshapiro
62590792Sgshapiro	switch (cmd) {
62690792Sgshapiro		case TAPSIFINFO:
62794334Sgshapiro			s = splimp();
62894334Sgshapiro			tapp = (struct tapinfo *)data;
62994334Sgshapiro			ifp->if_mtu = tapp->mtu;
63094334Sgshapiro			ifp->if_type = tapp->type;
63194334Sgshapiro			ifp->if_baudrate = tapp->baudrate;
63294334Sgshapiro			splx(s);
63394334Sgshapiro			break;
63494334Sgshapiro
63594334Sgshapiro		case TAPGIFINFO:
63690792Sgshapiro			tapp = (struct tapinfo *)data;
63790792Sgshapiro			tapp->mtu = ifp->if_mtu;
63890792Sgshapiro			tapp->type = ifp->if_type;
63990792Sgshapiro			tapp->baudrate = ifp->if_baudrate;
64090792Sgshapiro			break;
64190792Sgshapiro
64290792Sgshapiro		case TAPSDEBUG:
64390792Sgshapiro			tapdebug = *(int *)data;
64490792Sgshapiro			break;
64590792Sgshapiro
64690792Sgshapiro		case TAPGDEBUG:
64790792Sgshapiro			*(int *)data = tapdebug;
64890792Sgshapiro			break;
64990792Sgshapiro
65090792Sgshapiro		case FIONBIO:
65190792Sgshapiro			break;
65290792Sgshapiro
65390792Sgshapiro		case FIOASYNC:
65490792Sgshapiro			s = splimp();
65590792Sgshapiro			mtx_lock(&tp->tap_mtx);
65690792Sgshapiro			if (*(int *)data)
65790792Sgshapiro				tp->tap_flags |= TAP_ASYNC;
65890792Sgshapiro			else
65990792Sgshapiro				tp->tap_flags &= ~TAP_ASYNC;
66090792Sgshapiro			mtx_unlock(&tp->tap_mtx);
66190792Sgshapiro			splx(s);
66290792Sgshapiro			break;
66390792Sgshapiro
66490792Sgshapiro		case FIONREAD:
66590792Sgshapiro			s = splimp();
66690792Sgshapiro			if (ifp->if_snd.ifq_head) {
66790792Sgshapiro				struct mbuf	*mb = ifp->if_snd.ifq_head;
66890792Sgshapiro
66990792Sgshapiro				for(*(int *)data = 0;mb != NULL;mb = mb->m_next)
67090792Sgshapiro					*(int *)data += mb->m_len;
67190792Sgshapiro			} else
67290792Sgshapiro				*(int *)data = 0;
67390792Sgshapiro			splx(s);
67490792Sgshapiro			break;
67590792Sgshapiro
67690792Sgshapiro		case FIOSETOWN:
67790792Sgshapiro			return (fsetown(*(int *)data, &tp->tap_sigio));
67890792Sgshapiro
67990792Sgshapiro		case FIOGETOWN:
68090792Sgshapiro			*(int *)data = fgetown(&tp->tap_sigio);
68190792Sgshapiro			return (0);
68290792Sgshapiro
68390792Sgshapiro		/* this is deprecated, FIOSETOWN should be used instead */
68490792Sgshapiro		case TIOCSPGRP:
68590792Sgshapiro			return (fsetown(-(*(int *)data), &tp->tap_sigio));
68690792Sgshapiro
68790792Sgshapiro		/* this is deprecated, FIOGETOWN should be used instead */
68890792Sgshapiro		case TIOCGPGRP:
68990792Sgshapiro			*(int *)data = -fgetown(&tp->tap_sigio);
69090792Sgshapiro			return (0);
69190792Sgshapiro
69290792Sgshapiro		/* VMware/VMnet port ioctl's */
69390792Sgshapiro
69490792Sgshapiro		case SIOCGIFFLAGS:	/* get ifnet flags */
69590792Sgshapiro			bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags));
69690792Sgshapiro			break;
69790792Sgshapiro
69890792Sgshapiro#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
69990792Sgshapiro    defined(COMPAT_FREEBSD4)
70090792Sgshapiro		case _IO('V', 0):
70190792Sgshapiro			ival = IOCPARM_IVAL(data);
70290792Sgshapiro			data = (caddr_t)&ival;
70390792Sgshapiro			/* FALLTHROUGH */
70490792Sgshapiro#endif
70590792Sgshapiro		case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */
70690792Sgshapiro			f = *(int *)data;
70790792Sgshapiro			f &= 0x0fff;
70890792Sgshapiro			f &= ~IFF_CANTCHANGE;
70990792Sgshapiro			f |= IFF_UP;
71090792Sgshapiro
71190792Sgshapiro			s = splimp();
71290792Sgshapiro			ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE);
71390792Sgshapiro			splx(s);
71490792Sgshapiro			break;
71590792Sgshapiro
71690792Sgshapiro		case OSIOCGIFADDR:	/* get MAC address of the remote side */
71790792Sgshapiro		case SIOCGIFADDR:
71890792Sgshapiro			mtx_lock(&tp->tap_mtx);
71990792Sgshapiro			bcopy(tp->ether_addr, data, sizeof(tp->ether_addr));
72090792Sgshapiro			mtx_unlock(&tp->tap_mtx);
72190792Sgshapiro			break;
72290792Sgshapiro
72390792Sgshapiro		case SIOCSIFADDR:	/* set MAC address of the remote side */
724102528Sgshapiro			mtx_lock(&tp->tap_mtx);
72590792Sgshapiro			bcopy(data, tp->ether_addr, sizeof(tp->ether_addr));
72690792Sgshapiro			mtx_unlock(&tp->tap_mtx);
72790792Sgshapiro			break;
72890792Sgshapiro
72990792Sgshapiro		default:
73090792Sgshapiro			return (ENOTTY);
73190792Sgshapiro	}
73290792Sgshapiro	return (0);
73390792Sgshapiro} /* tapioctl */
73490792Sgshapiro
73594334Sgshapiro
73694334Sgshapiro/*
737102528Sgshapiro * tapread
73894334Sgshapiro *
73990792Sgshapiro * the cdevsw read interface - reads a packet at a time, or at
74090792Sgshapiro * least as much of a packet as can be read
74190792Sgshapiro */
74290792Sgshapirostatic int
74390792Sgshapirotapread(struct cdev *dev, struct uio *uio, int flag)
74490792Sgshapiro{
74590792Sgshapiro	struct tap_softc	*tp = dev->si_drv1;
74690792Sgshapiro	struct ifnet		*ifp = tp->tap_ifp;
74790792Sgshapiro	struct mbuf		*m = NULL;
74890792Sgshapiro	int			 error = 0, len, s;
74990792Sgshapiro
75090792Sgshapiro	TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, minor(dev));
75190792Sgshapiro
75290792Sgshapiro	mtx_lock(&tp->tap_mtx);
75390792Sgshapiro	if ((tp->tap_flags & TAP_READY) != TAP_READY) {
75490792Sgshapiro		mtx_unlock(&tp->tap_mtx);
75590792Sgshapiro
75690792Sgshapiro		/* Unlocked read. */
75790792Sgshapiro		TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n",
75890792Sgshapiro			ifp->if_xname, minor(dev), tp->tap_flags);
75990792Sgshapiro
76090792Sgshapiro		return (EHOSTDOWN);
76190792Sgshapiro	}
76290792Sgshapiro
76390792Sgshapiro	tp->tap_flags &= ~TAP_RWAIT;
76490792Sgshapiro	mtx_unlock(&tp->tap_mtx);
76590792Sgshapiro
76690792Sgshapiro	/* sleep until we get a packet */
76790792Sgshapiro	do {
76890792Sgshapiro		s = splimp();
76990792Sgshapiro		IF_DEQUEUE(&ifp->if_snd, m);
77090792Sgshapiro		splx(s);
77190792Sgshapiro
77290792Sgshapiro		if (m == NULL) {
77390792Sgshapiro			if (flag & O_NONBLOCK)
77490792Sgshapiro				return (EWOULDBLOCK);
77590792Sgshapiro
77690792Sgshapiro			mtx_lock(&tp->tap_mtx);
77790792Sgshapiro			tp->tap_flags |= TAP_RWAIT;
77890792Sgshapiro			mtx_unlock(&tp->tap_mtx);
77990792Sgshapiro			error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0);
78090792Sgshapiro			if (error)
78190792Sgshapiro				return (error);
78290792Sgshapiro		}
78390792Sgshapiro	} while (m == NULL);
78490792Sgshapiro
78590792Sgshapiro	/* feed packet to bpf */
78690792Sgshapiro	BPF_MTAP(ifp, m);
78790792Sgshapiro
78890792Sgshapiro	/* xfer packet to user space */
78990792Sgshapiro	while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) {
79090792Sgshapiro		len = min(uio->uio_resid, m->m_len);
79190792Sgshapiro		if (len == 0)
79290792Sgshapiro			break;
79390792Sgshapiro
79490792Sgshapiro		error = uiomove(mtod(m, void *), len, uio);
79590792Sgshapiro		m = m_free(m);
79690792Sgshapiro	}
79790792Sgshapiro
79890792Sgshapiro	if (m != NULL) {
79990792Sgshapiro		TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname,
80090792Sgshapiro			minor(dev));
80190792Sgshapiro		m_freem(m);
80290792Sgshapiro	}
80390792Sgshapiro
80490792Sgshapiro	return (error);
80590792Sgshapiro} /* tapread */
80690792Sgshapiro
80790792Sgshapiro
80890792Sgshapiro/*
80990792Sgshapiro * tapwrite
81090792Sgshapiro *
81190792Sgshapiro * the cdevsw write interface - an atomic write is a packet - or else!
81290792Sgshapiro */
81390792Sgshapirostatic int
81490792Sgshapirotapwrite(struct cdev *dev, struct uio *uio, int flag)
81590792Sgshapiro{
81690792Sgshapiro	struct ether_header	*eh;
81790792Sgshapiro	struct tap_softc	*tp = dev->si_drv1;
81890792Sgshapiro	struct ifnet		*ifp = tp->tap_ifp;
81990792Sgshapiro	struct mbuf		*m;
82090792Sgshapiro
82190792Sgshapiro	TAPDEBUG("%s writting, minor = %#x\n",
82290792Sgshapiro		ifp->if_xname, minor(dev));
82390792Sgshapiro
82490792Sgshapiro	if (uio->uio_resid == 0)
82590792Sgshapiro		return (0);
82690792Sgshapiro
82790792Sgshapiro	if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) {
82890792Sgshapiro		TAPDEBUG("%s invalid packet len = %d, minor = %#x\n",
82990792Sgshapiro			ifp->if_xname, uio->uio_resid, minor(dev));
83090792Sgshapiro
83190792Sgshapiro		return (EIO);
83290792Sgshapiro	}
83390792Sgshapiro
83490792Sgshapiro	if ((m = m_uiotombuf(uio, M_DONTWAIT, 0, ETHER_ALIGN,
83590792Sgshapiro	    M_PKTHDR)) == NULL) {
83690792Sgshapiro		ifp->if_ierrors ++;
83790792Sgshapiro		return (ENOBUFS);
83890792Sgshapiro	}
83990792Sgshapiro
84090792Sgshapiro	m->m_pkthdr.rcvif = ifp;
84190792Sgshapiro
84290792Sgshapiro	/*
84390792Sgshapiro	 * Only pass a unicast frame to ether_input(), if it would actually
84490792Sgshapiro	 * have been received by non-virtual hardware.
84590792Sgshapiro	 */
84690792Sgshapiro	if (m->m_len < sizeof(struct ether_header)) {
84790792Sgshapiro		m_freem(m);
84890792Sgshapiro		return (0);
84990792Sgshapiro	}
85090792Sgshapiro	eh = mtod(m, struct ether_header *);
85190792Sgshapiro
85290792Sgshapiro	if (eh && (ifp->if_flags & IFF_PROMISC) == 0 &&
85390792Sgshapiro	    !ETHER_IS_MULTICAST(eh->ether_dhost) &&
85490792Sgshapiro	    bcmp(eh->ether_dhost, IF_LLADDR(ifp), ETHER_ADDR_LEN) != 0) {
85590792Sgshapiro		m_freem(m);
85690792Sgshapiro		return (0);
85790792Sgshapiro	}
85890792Sgshapiro
85990792Sgshapiro	/* Pass packet up to parent. */
86090792Sgshapiro	(*ifp->if_input)(ifp, m);
86190792Sgshapiro	ifp->if_ipackets ++; /* ibytes are counted in parent */
86290792Sgshapiro
86390792Sgshapiro	return (0);
86490792Sgshapiro} /* tapwrite */
86590792Sgshapiro
86690792Sgshapiro
86790792Sgshapiro/*
86890792Sgshapiro * tappoll
86990792Sgshapiro *
87090792Sgshapiro * the poll interface, this is only useful on reads
87190792Sgshapiro * really. the write detect always returns true, write never blocks
87290792Sgshapiro * anyway, it either accepts the packet or drops it
87390792Sgshapiro */
87490792Sgshapirostatic int
87590792Sgshapirotappoll(struct cdev *dev, int events, struct thread *td)
87690792Sgshapiro{
87790792Sgshapiro	struct tap_softc	*tp = dev->si_drv1;
87890792Sgshapiro	struct ifnet		*ifp = tp->tap_ifp;
87990792Sgshapiro	int			 s, revents = 0;
88090792Sgshapiro
88190792Sgshapiro	TAPDEBUG("%s polling, minor = %#x\n",
88290792Sgshapiro		ifp->if_xname, minor(dev));
88390792Sgshapiro
88490792Sgshapiro	s = splimp();
88590792Sgshapiro	if (events & (POLLIN | POLLRDNORM)) {
88690792Sgshapiro		if (ifp->if_snd.ifq_len > 0) {
88790792Sgshapiro			TAPDEBUG("%s have data in queue. len = %d, " \
88890792Sgshapiro				"minor = %#x\n", ifp->if_xname,
88990792Sgshapiro				ifp->if_snd.ifq_len, minor(dev));
89090792Sgshapiro
89190792Sgshapiro			revents |= (events & (POLLIN | POLLRDNORM));
89290792Sgshapiro		} else {
89390792Sgshapiro			TAPDEBUG("%s waiting for data, minor = %#x\n",
89490792Sgshapiro				ifp->if_xname, minor(dev));
89590792Sgshapiro
89690792Sgshapiro			selrecord(td, &tp->tap_rsel);
89790792Sgshapiro		}
89890792Sgshapiro	}
89990792Sgshapiro
90090792Sgshapiro	if (events & (POLLOUT | POLLWRNORM))
90190792Sgshapiro		revents |= (events & (POLLOUT | POLLWRNORM));
90290792Sgshapiro
90390792Sgshapiro	splx(s);
90490792Sgshapiro	return (revents);
90590792Sgshapiro} /* tappoll */
90690792Sgshapiro
90790792Sgshapiro
90890792Sgshapiro/*
90990792Sgshapiro * tap_kqfilter
91090792Sgshapiro *
91190792Sgshapiro * support for kevent() system call
91290792Sgshapiro */
91390792Sgshapirostatic int
91490792Sgshapirotapkqfilter(struct cdev *dev, struct knote *kn)
91590792Sgshapiro{
91690792Sgshapiro    	int			 s;
91790792Sgshapiro	struct tap_softc	*tp = dev->si_drv1;
91890792Sgshapiro	struct ifnet		*ifp = tp->tap_ifp;
91990792Sgshapiro
92090792Sgshapiro	s = splimp();
92190792Sgshapiro	switch (kn->kn_filter) {
92290792Sgshapiro	case EVFILT_READ:
92390792Sgshapiro		TAPDEBUG("%s kqfilter: EVFILT_READ, minor = %#x\n",
92490792Sgshapiro			ifp->if_xname, minor(dev));
92590792Sgshapiro		kn->kn_fop = &tap_read_filterops;
92690792Sgshapiro		break;
92790792Sgshapiro
92890792Sgshapiro	case EVFILT_WRITE:
92990792Sgshapiro		TAPDEBUG("%s kqfilter: EVFILT_WRITE, minor = %#x\n",
93090792Sgshapiro			ifp->if_xname, minor(dev));
93190792Sgshapiro		kn->kn_fop = &tap_write_filterops;
93290792Sgshapiro		break;
93390792Sgshapiro
93490792Sgshapiro	default:
93590792Sgshapiro		TAPDEBUG("%s kqfilter: invalid filter, minor = %#x\n",
93690792Sgshapiro			ifp->if_xname, minor(dev));
93790792Sgshapiro		splx(s);
93890792Sgshapiro		return (EINVAL);
93990792Sgshapiro		/* NOT REACHED */
94090792Sgshapiro	}
94190792Sgshapiro	splx(s);
94290792Sgshapiro
94390792Sgshapiro	kn->kn_hook = (caddr_t) dev;
94490792Sgshapiro	knlist_add(&tp->tap_rsel.si_note, kn, 0);
94590792Sgshapiro
94690792Sgshapiro	return (0);
94790792Sgshapiro} /* tapkqfilter */
94890792Sgshapiro
94990792Sgshapiro
95090792Sgshapiro/*
95190792Sgshapiro * tap_kqread
95290792Sgshapiro *
95390792Sgshapiro * Return true if there is data in the interface queue
95490792Sgshapiro */
95590792Sgshapirostatic int
95690792Sgshapirotapkqread(struct knote *kn, long hint)
95790792Sgshapiro{
95890792Sgshapiro	int			 ret, s;
95990792Sgshapiro	struct cdev		*dev = (struct cdev *)(kn->kn_hook);
96090792Sgshapiro	struct tap_softc	*tp = dev->si_drv1;
96190792Sgshapiro	struct ifnet		*ifp = tp->tap_ifp;
96290792Sgshapiro
96390792Sgshapiro	s = splimp();
96490792Sgshapiro	if ((kn->kn_data = ifp->if_snd.ifq_len) > 0) {
96590792Sgshapiro		TAPDEBUG("%s have data in queue. len = %d, minor = %#x\n",
96690792Sgshapiro			ifp->if_xname, ifp->if_snd.ifq_len, minor(dev));
96790792Sgshapiro		ret = 1;
96890792Sgshapiro	} else {
96990792Sgshapiro		TAPDEBUG("%s waiting for data, minor = %#x\n",
97090792Sgshapiro			ifp->if_xname, minor(dev));
97190792Sgshapiro		ret = 0;
97290792Sgshapiro	}
97390792Sgshapiro	splx(s);
97490792Sgshapiro
97590792Sgshapiro	return (ret);
97690792Sgshapiro} /* tapkqread */
97790792Sgshapiro
97890792Sgshapiro
97990792Sgshapiro/*
98090792Sgshapiro * tap_kqwrite
98190792Sgshapiro *
98290792Sgshapiro * Always can write. Return the MTU in kn->data
98390792Sgshapiro */
98490792Sgshapirostatic int
98590792Sgshapirotapkqwrite(struct knote *kn, long hint)
98690792Sgshapiro{
98790792Sgshapiro	int			 s;
98890792Sgshapiro	struct tap_softc	*tp = ((struct cdev *) kn->kn_hook)->si_drv1;
98990792Sgshapiro	struct ifnet		*ifp = tp->tap_ifp;
99090792Sgshapiro
99190792Sgshapiro	s = splimp();
99290792Sgshapiro	kn->kn_data = ifp->if_mtu;
99390792Sgshapiro	splx(s);
99490792Sgshapiro
99590792Sgshapiro	return (1);
99690792Sgshapiro} /* tapkqwrite */
99790792Sgshapiro
99890792Sgshapiro
99990792Sgshapirostatic void
100090792Sgshapirotapkqdetach(struct knote *kn)
100190792Sgshapiro{
100290792Sgshapiro	struct tap_softc	*tp = ((struct cdev *) kn->kn_hook)->si_drv1;
100390792Sgshapiro
100490792Sgshapiro	knlist_remove(&tp->tap_rsel.si_note, kn, 0);
100590792Sgshapiro} /* tapkqdetach */
100690792Sgshapiro
100790792Sgshapiro