if_tun.c revision 205222
161560Sn_hibma/*	$NetBSD: if_tun.c,v 1.14 1994/06/29 06:36:25 cgd Exp $	*/
261560Sn_hibma
361560Sn_hibma/*-
461560Sn_hibma * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk>
561560Sn_hibma * Nottingham University 1987.
661560Sn_hibma *
761560Sn_hibma * This source may be freely distributed, however I would be interested
861560Sn_hibma * in any changes that are made.
961560Sn_hibma *
1061560Sn_hibma * This driver takes packets off the IP i/f and hands them up to a
1161560Sn_hibma * user process to have its wicked way with. This driver has it's
1261560Sn_hibma * roots in a similar driver written by Phil Cockcroft (formerly) at
1361560Sn_hibma * UCL. This driver is based much more on read/write/poll mode of
1461560Sn_hibma * operation though.
1561560Sn_hibma *
1661560Sn_hibma * $FreeBSD: head/sys/net/if_tun.c 205222 2010-03-16 17:59:12Z qingli $
1761560Sn_hibma */
1861560Sn_hibma
1961560Sn_hibma#include "opt_atalk.h"
2061560Sn_hibma#include "opt_inet.h"
2161560Sn_hibma#include "opt_inet6.h"
22163675Smarkus#include "opt_ipx.h"
2361560Sn_hibma
2461560Sn_hibma#include <sys/param.h>
2561560Sn_hibma#include <sys/priv.h>
2661560Sn_hibma#include <sys/proc.h>
2761560Sn_hibma#include <sys/systm.h>
2861560Sn_hibma#include <sys/jail.h>
2961560Sn_hibma#include <sys/mbuf.h>
3061560Sn_hibma#include <sys/module.h>
3161560Sn_hibma#include <sys/socket.h>
3261560Sn_hibma#include <sys/fcntl.h>
3361560Sn_hibma#include <sys/filio.h>
3461560Sn_hibma#include <sys/sockio.h>
3561560Sn_hibma#include <sys/ttycom.h>
36163675Smarkus#include <sys/poll.h>
37163675Smarkus#include <sys/selinfo.h>
3861560Sn_hibma#include <sys/signalvar.h>
3961560Sn_hibma#include <sys/filedesc.h>
4061560Sn_hibma#include <sys/kernel.h>
4161560Sn_hibma#include <sys/sysctl.h>
4261560Sn_hibma#include <sys/conf.h>
4361560Sn_hibma#include <sys/uio.h>
4461560Sn_hibma#include <sys/malloc.h>
45163675Smarkus#include <sys/random.h>
46163675Smarkus
4761560Sn_hibma#include <net/if.h>
4861560Sn_hibma#include <net/if_clone.h>
4961560Sn_hibma#include <net/if_types.h>
5061560Sn_hibma#include <net/netisr.h>
5161560Sn_hibma#include <net/route.h>
5261560Sn_hibma#include <net/vnet.h>
5361560Sn_hibma#ifdef INET
5461560Sn_hibma#include <netinet/in.h>
5561560Sn_hibma#endif
5661560Sn_hibma#include <net/bpf.h>
5761560Sn_hibma#include <net/if_tun.h>
5861560Sn_hibma
5961560Sn_hibma#include <sys/queue.h>
6061560Sn_hibma#include <sys/condvar.h>
61163675Smarkus
62163675Smarkus#include <security/mac/mac_framework.h>
6361560Sn_hibma
6461560Sn_hibma/*
6561560Sn_hibma * tun_list is protected by global tunmtx.  Other mutable fields are
6661560Sn_hibma * protected by tun->tun_mtx, or by their owning subsystem.  tun_dev is
67163675Smarkus * static for the duration of a tunnel interface.
68163675Smarkus */
69163675Smarkusstruct tun_softc {
70163675Smarkus	TAILQ_ENTRY(tun_softc)	tun_list;
71163675Smarkus	struct cdev *tun_dev;
72163675Smarkus	u_short	tun_flags;		/* misc flags */
73163675Smarkus#define	TUN_OPEN	0x0001
74163675Smarkus#define	TUN_INITED	0x0002
75163675Smarkus#define	TUN_RCOLL	0x0004
76163675Smarkus#define	TUN_IASET	0x0008
77163675Smarkus#define	TUN_DSTADDR	0x0010
78163675Smarkus#define	TUN_LMODE	0x0020
79163675Smarkus#define	TUN_RWAIT	0x0040
80163675Smarkus#define	TUN_ASYNC	0x0080
81163675Smarkus#define	TUN_IFHEAD	0x0100
82163675Smarkus
83163675Smarkus#define TUN_READY       (TUN_OPEN | TUN_INITED)
8461560Sn_hibma
8561560Sn_hibma	/*
8661560Sn_hibma	 * XXXRW: tun_pid is used to exclusively lock /dev/tun.  Is this
8761560Sn_hibma	 * actually needed?  Can we just return EBUSY if already open?
8861560Sn_hibma	 * Problem is that this involved inherent races when a tun device
8961560Sn_hibma	 * is handed off from one process to another, as opposed to just
9061560Sn_hibma	 * being slightly stale informationally.
9161560Sn_hibma	 */
9261560Sn_hibma	pid_t	tun_pid;		/* owning pid */
9361560Sn_hibma	struct	ifnet *tun_ifp;		/* the interface */
9461560Sn_hibma	struct  sigio *tun_sigio;	/* information for async I/O */
9561560Sn_hibma	struct	selinfo	tun_rsel;	/* read select */
9661560Sn_hibma	struct mtx	tun_mtx;	/* protect mutable softc fields */
9761560Sn_hibma	struct cv	tun_cv;		/* protect against ref'd dev destroy */
98163675Smarkus};
9961560Sn_hibma#define TUN2IFP(sc)	((sc)->tun_ifp)
10061560Sn_hibma
10161560Sn_hibma#define TUNDEBUG	if (tundebug) if_printf
10261560Sn_hibma#define	TUNNAME		"tun"
10361560Sn_hibma
10461560Sn_hibma/*
105163675Smarkus * All mutable global variables in if_tun are locked using tunmtx, with
10661560Sn_hibma * the exception of tundebug, which is used unlocked, and tunclones,
10761560Sn_hibma * which is static after setup.
10861560Sn_hibma */
109163675Smarkusstatic struct mtx tunmtx;
11061560Sn_hibmastatic MALLOC_DEFINE(M_TUN, TUNNAME, "Tunnel Interface");
11161560Sn_hibmastatic int tundebug = 0;
11261560Sn_hibmastatic int tundclone = 1;
113163675Smarkusstatic struct clonedevs *tunclones;
11461560Sn_hibmastatic TAILQ_HEAD(,tun_softc)	tunhead = TAILQ_HEAD_INITIALIZER(tunhead);
11561560Sn_hibmaSYSCTL_INT(_debug, OID_AUTO, if_tun_debug, CTLFLAG_RW, &tundebug, 0, "");
11661560Sn_hibma
11761560Sn_hibmaSYSCTL_DECL(_net_link);
11861560Sn_hibmaSYSCTL_NODE(_net_link, OID_AUTO, tun, CTLFLAG_RW, 0,
11961560Sn_hibma    "IP tunnel software network interface.");
12061560Sn_hibmaSYSCTL_INT(_net_link_tun, OID_AUTO, devfs_cloning, CTLFLAG_RW, &tundclone, 0,
12161560Sn_hibma    "Enable legacy devfs interface creation.");
12261560Sn_hibma
12361560Sn_hibmaTUNABLE_INT("net.link.tun.devfs_cloning", &tundclone);
12461560Sn_hibma
12561560Sn_hibmastatic void	tunclone(void *arg, struct ucred *cred, char *name,
12661560Sn_hibma		    int namelen, struct cdev **dev);
12761560Sn_hibmastatic void	tuncreate(const char *name, struct cdev *dev);
12861560Sn_hibmastatic int	tunifioctl(struct ifnet *, u_long, caddr_t);
12961560Sn_hibmastatic int	tuninit(struct ifnet *);
13061560Sn_hibmastatic int	tunmodevent(module_t, int, void *);
13161560Sn_hibmastatic int	tunoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
13261560Sn_hibma		    struct route *ro);
13361560Sn_hibmastatic void	tunstart(struct ifnet *);
13461560Sn_hibma
13561560Sn_hibmastatic int	tun_clone_create(struct if_clone *, int, caddr_t);
13661560Sn_hibmastatic void	tun_clone_destroy(struct ifnet *);
13761560Sn_hibma
13861560Sn_hibmaIFC_SIMPLE_DECLARE(tun, 0);
13961560Sn_hibma
14061560Sn_hibmastatic d_open_t		tunopen;
14161560Sn_hibmastatic d_close_t	tunclose;
14261560Sn_hibmastatic d_read_t		tunread;
14361560Sn_hibmastatic d_write_t	tunwrite;
14461560Sn_hibmastatic d_ioctl_t	tunioctl;
14561560Sn_hibmastatic d_poll_t		tunpoll;
14661560Sn_hibmastatic d_kqfilter_t	tunkqfilter;
14761560Sn_hibma
14861560Sn_hibmastatic int		tunkqread(struct knote *, long);
14961560Sn_hibmastatic int		tunkqwrite(struct knote *, long);
15061560Sn_hibmastatic void		tunkqdetach(struct knote *);
15161560Sn_hibma
15261560Sn_hibmastatic struct filterops tun_read_filterops = {
15361560Sn_hibma	.f_isfd =	1,
15461560Sn_hibma	.f_attach =	NULL,
15561560Sn_hibma	.f_detach =	tunkqdetach,
15661560Sn_hibma	.f_event =	tunkqread,
15761560Sn_hibma};
15861560Sn_hibma
15961560Sn_hibmastatic struct filterops tun_write_filterops = {
16061560Sn_hibma	.f_isfd =	1,
16161560Sn_hibma	.f_attach =	NULL,
16261560Sn_hibma	.f_detach =	tunkqdetach,
16361560Sn_hibma	.f_event =	tunkqwrite,
16461560Sn_hibma};
16561560Sn_hibma
16661560Sn_hibmastatic struct cdevsw tun_cdevsw = {
16761560Sn_hibma	.d_version =	D_VERSION,
16861560Sn_hibma	.d_flags =	D_PSEUDO | D_NEEDGIANT | D_NEEDMINOR,
16961560Sn_hibma	.d_open =	tunopen,
17061560Sn_hibma	.d_close =	tunclose,
17161560Sn_hibma	.d_read =	tunread,
17261560Sn_hibma	.d_write =	tunwrite,
17361560Sn_hibma	.d_ioctl =	tunioctl,
17461560Sn_hibma	.d_poll =	tunpoll,
17561560Sn_hibma	.d_kqfilter =	tunkqfilter,
17661560Sn_hibma	.d_name =	TUNNAME,
17761560Sn_hibma};
17861560Sn_hibma
17961560Sn_hibmastatic int
18061560Sn_hibmatun_clone_create(struct if_clone *ifc, int unit, caddr_t params)
18161560Sn_hibma{
18261560Sn_hibma	struct cdev *dev;
18361560Sn_hibma	int i;
18461560Sn_hibma
18561560Sn_hibma	/* find any existing device, or allocate new unit number */
18661560Sn_hibma	i = clone_create(&tunclones, &tun_cdevsw, &unit, &dev, 0);
18761560Sn_hibma	if (i) {
18861560Sn_hibma		/* No preexisting struct cdev *, create one */
18961560Sn_hibma		dev = make_dev(&tun_cdevsw, unit,
19061560Sn_hibma		    UID_UUCP, GID_DIALER, 0600, "%s%d", ifc->ifc_name, unit);
19161560Sn_hibma	}
19261560Sn_hibma	tuncreate(ifc->ifc_name, dev);
19361560Sn_hibma
19461560Sn_hibma	return (0);
19561560Sn_hibma}
19661560Sn_hibma
19761560Sn_hibmastatic void
19861560Sn_hibmatunclone(void *arg, struct ucred *cred, char *name, int namelen,
199163675Smarkus    struct cdev **dev)
200163675Smarkus{
20161560Sn_hibma	char devname[SPECNAMELEN + 1];
20261560Sn_hibma	int u, i, append_unit;
20361560Sn_hibma
20461560Sn_hibma	if (*dev != NULL)
20561560Sn_hibma		return;
20661560Sn_hibma
20761560Sn_hibma	/*
20861560Sn_hibma	 * If tun cloning is enabled, only the superuser can create an
20961560Sn_hibma	 * interface.
21061560Sn_hibma	 */
21161560Sn_hibma	if (!tundclone || priv_check_cred(cred, PRIV_NET_IFCREATE, 0) != 0)
21261560Sn_hibma		return;
21361560Sn_hibma
21461560Sn_hibma	if (strcmp(name, TUNNAME) == 0) {
21561560Sn_hibma		u = -1;
21661560Sn_hibma	} else if (dev_stdclone(name, NULL, TUNNAME, &u) != 1)
21761560Sn_hibma		return;	/* Don't recognise the name */
21861560Sn_hibma	if (u != -1 && u > IF_MAXUNIT)
21961560Sn_hibma		return;	/* Unit number too high */
22061560Sn_hibma
22161560Sn_hibma	if (u == -1)
22261560Sn_hibma		append_unit = 1;
223163675Smarkus	else
224163675Smarkus		append_unit = 0;
225163675Smarkus
226163675Smarkus	CURVNET_SET(CRED_TO_VNET(cred));
227163675Smarkus	/* find any existing device, or allocate new unit number */
228163675Smarkus	i = clone_create(&tunclones, &tun_cdevsw, &u, dev, 0);
229163675Smarkus	if (i) {
230163675Smarkus		if (append_unit) {
231163675Smarkus			namelen = snprintf(devname, sizeof(devname), "%s%d", name,
232163675Smarkus			    u);
23361560Sn_hibma			name = devname;
23461560Sn_hibma		}
23561560Sn_hibma		/* No preexisting struct cdev *, create one */
23661560Sn_hibma		*dev = make_dev_credf(MAKEDEV_REF, &tun_cdevsw, u, cred,
23761560Sn_hibma		    UID_UUCP, GID_DIALER, 0600, "%s", name);
23861560Sn_hibma	}
23961560Sn_hibma
24061560Sn_hibma	if_clone_create(name, namelen, NULL);
24161560Sn_hibma	CURVNET_RESTORE();
24261560Sn_hibma}
24361560Sn_hibma
24461560Sn_hibmastatic void
24561560Sn_hibmatun_destroy(struct tun_softc *tp)
24661560Sn_hibma{
24761560Sn_hibma	struct cdev *dev;
24861560Sn_hibma
24961560Sn_hibma	/* Unlocked read. */
25061560Sn_hibma	mtx_lock(&tp->tun_mtx);
25161560Sn_hibma	if ((tp->tun_flags & TUN_OPEN) != 0)
25261560Sn_hibma		cv_wait_unlock(&tp->tun_cv, &tp->tun_mtx);
25361560Sn_hibma	else
25461560Sn_hibma		mtx_unlock(&tp->tun_mtx);
25561560Sn_hibma
25661560Sn_hibma	CURVNET_SET(TUN2IFP(tp)->if_vnet);
25761560Sn_hibma	dev = tp->tun_dev;
25861560Sn_hibma	bpfdetach(TUN2IFP(tp));
25961560Sn_hibma	if_detach(TUN2IFP(tp));
26061560Sn_hibma	if_free(TUN2IFP(tp));
26161560Sn_hibma	destroy_dev(dev);
26261560Sn_hibma	knlist_destroy(&tp->tun_rsel.si_note);
26361560Sn_hibma	mtx_destroy(&tp->tun_mtx);
26461560Sn_hibma	cv_destroy(&tp->tun_cv);
26561560Sn_hibma	free(tp, M_TUN);
26661560Sn_hibma	CURVNET_RESTORE();
26761560Sn_hibma}
26861560Sn_hibma
26961560Sn_hibmastatic void
27061560Sn_hibmatun_clone_destroy(struct ifnet *ifp)
27161560Sn_hibma{
27261560Sn_hibma	struct tun_softc *tp = ifp->if_softc;
27361560Sn_hibma
27461560Sn_hibma	mtx_lock(&tunmtx);
27561560Sn_hibma	TAILQ_REMOVE(&tunhead, tp, tun_list);
27661560Sn_hibma	mtx_unlock(&tunmtx);
27761560Sn_hibma	tun_destroy(tp);
27861560Sn_hibma}
27961560Sn_hibma
28061560Sn_hibmastatic int
28161560Sn_hibmatunmodevent(module_t mod, int type, void *data)
28261560Sn_hibma{
28361560Sn_hibma	static eventhandler_tag tag;
28461560Sn_hibma	struct tun_softc *tp;
28561560Sn_hibma
28661560Sn_hibma	switch (type) {
28761560Sn_hibma	case MOD_LOAD:
288163675Smarkus		mtx_init(&tunmtx, "tunmtx", NULL, MTX_DEF);
28961560Sn_hibma		clone_setup(&tunclones);
29061560Sn_hibma		tag = EVENTHANDLER_REGISTER(dev_clone, tunclone, 0, 1000);
29161560Sn_hibma		if (tag == NULL)
29261560Sn_hibma			return (ENOMEM);
29361560Sn_hibma		if_clone_attach(&tun_cloner);
29461560Sn_hibma		break;
29561560Sn_hibma	case MOD_UNLOAD:
29661560Sn_hibma		if_clone_detach(&tun_cloner);
29761560Sn_hibma		EVENTHANDLER_DEREGISTER(dev_clone, tag);
29861560Sn_hibma		drain_dev_clone_events();
29961560Sn_hibma
30061560Sn_hibma		mtx_lock(&tunmtx);
30161560Sn_hibma		while ((tp = TAILQ_FIRST(&tunhead)) != NULL) {
30261560Sn_hibma			TAILQ_REMOVE(&tunhead, tp, tun_list);
30361560Sn_hibma			mtx_unlock(&tunmtx);
30461560Sn_hibma			tun_destroy(tp);
30561560Sn_hibma			mtx_lock(&tunmtx);
30661560Sn_hibma		}
30761560Sn_hibma		mtx_unlock(&tunmtx);
30861560Sn_hibma		clone_cleanup(&tunclones);
30961560Sn_hibma		mtx_destroy(&tunmtx);
31061560Sn_hibma		break;
31161560Sn_hibma	default:
31261560Sn_hibma		return EOPNOTSUPP;
31361560Sn_hibma	}
31461560Sn_hibma	return 0;
31561560Sn_hibma}
31661560Sn_hibma
31761560Sn_hibmastatic moduledata_t tun_mod = {
31861560Sn_hibma	"if_tun",
31961560Sn_hibma	tunmodevent,
32061560Sn_hibma	0
32161560Sn_hibma};
32261560Sn_hibma
32361560Sn_hibmaDECLARE_MODULE(if_tun, tun_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
32461560Sn_hibma
32561560Sn_hibmastatic void
32661560Sn_hibmatunstart(struct ifnet *ifp)
32761560Sn_hibma{
32861560Sn_hibma	struct tun_softc *tp = ifp->if_softc;
32961560Sn_hibma	struct mbuf *m;
33061560Sn_hibma
33161560Sn_hibma	TUNDEBUG(ifp,"%s starting\n", ifp->if_xname);
33261560Sn_hibma	if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
33361560Sn_hibma		IFQ_LOCK(&ifp->if_snd);
33461560Sn_hibma		IFQ_POLL_NOLOCK(&ifp->if_snd, m);
33561560Sn_hibma		if (m == NULL) {
33661560Sn_hibma			IFQ_UNLOCK(&ifp->if_snd);
33761560Sn_hibma			return;
33861560Sn_hibma		}
33961560Sn_hibma		IFQ_UNLOCK(&ifp->if_snd);
34061560Sn_hibma	}
34161560Sn_hibma
34261560Sn_hibma	mtx_lock(&tp->tun_mtx);
34361560Sn_hibma	if (tp->tun_flags & TUN_RWAIT) {
34461560Sn_hibma		tp->tun_flags &= ~TUN_RWAIT;
34561560Sn_hibma		wakeup(tp);
34661560Sn_hibma	}
34761560Sn_hibma	if (tp->tun_flags & TUN_ASYNC && tp->tun_sigio) {
34861560Sn_hibma		mtx_unlock(&tp->tun_mtx);
34961560Sn_hibma		pgsigio(&tp->tun_sigio, SIGIO, 0);
35061560Sn_hibma	} else
35161560Sn_hibma		mtx_unlock(&tp->tun_mtx);
35261560Sn_hibma	selwakeuppri(&tp->tun_rsel, PZERO + 1);
35361560Sn_hibma	KNOTE_UNLOCKED(&tp->tun_rsel.si_note, 0);
35461560Sn_hibma}
35561560Sn_hibma
35661560Sn_hibma/* XXX: should return an error code so it can fail. */
35761560Sn_hibmastatic void
35861560Sn_hibmatuncreate(const char *name, struct cdev *dev)
35961560Sn_hibma{
36061560Sn_hibma	struct tun_softc *sc;
36161560Sn_hibma	struct ifnet *ifp;
36261560Sn_hibma
36361560Sn_hibma	dev->si_flags &= ~SI_CHEAPCLONE;
36461560Sn_hibma
36561560Sn_hibma	sc = malloc(sizeof(*sc), M_TUN, M_WAITOK | M_ZERO);
36661560Sn_hibma	mtx_init(&sc->tun_mtx, "tun_mtx", NULL, MTX_DEF);
36761560Sn_hibma	cv_init(&sc->tun_cv, "tun_condvar");
36861560Sn_hibma	sc->tun_flags = TUN_INITED;
36961560Sn_hibma	sc->tun_dev = dev;
37061560Sn_hibma	mtx_lock(&tunmtx);
37161560Sn_hibma	TAILQ_INSERT_TAIL(&tunhead, sc, tun_list);
37261560Sn_hibma	mtx_unlock(&tunmtx);
37361560Sn_hibma
37461560Sn_hibma	ifp = sc->tun_ifp = if_alloc(IFT_PPP);
37561560Sn_hibma	if (ifp == NULL)
37661560Sn_hibma		panic("%s%d: failed to if_alloc() interface.\n",
37761560Sn_hibma		    name, dev2unit(dev));
37861560Sn_hibma	if_initname(ifp, name, dev2unit(dev));
37961560Sn_hibma	ifp->if_mtu = TUNMTU;
38061560Sn_hibma	ifp->if_ioctl = tunifioctl;
38161560Sn_hibma	ifp->if_output = tunoutput;
38261560Sn_hibma	ifp->if_start = tunstart;
38361560Sn_hibma	ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
38461560Sn_hibma	ifp->if_softc = sc;
38561560Sn_hibma	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
38661560Sn_hibma	ifp->if_snd.ifq_drv_maxlen = 0;
38761560Sn_hibma	IFQ_SET_READY(&ifp->if_snd);
38861560Sn_hibma	knlist_init_mtx(&sc->tun_rsel.si_note, NULL);
38961560Sn_hibma	ifp->if_capabilities |= IFCAP_LINKSTATE;
39061560Sn_hibma	ifp->if_capenable |= IFCAP_LINKSTATE;
39161560Sn_hibma
39261560Sn_hibma	if_attach(ifp);
39361560Sn_hibma	bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
39461560Sn_hibma	dev->si_drv1 = sc;
39561560Sn_hibma	TUNDEBUG(ifp, "interface %s is created, minor = %#x\n",
39661560Sn_hibma	    ifp->if_xname, dev2unit(dev));
39761560Sn_hibma}
39861560Sn_hibma
399163675Smarkusstatic int
400163675Smarkustunopen(struct cdev *dev, int flag, int mode, struct thread *td)
401163675Smarkus{
402163675Smarkus	struct ifnet	*ifp;
403163675Smarkus	struct tun_softc *tp;
404163675Smarkus
405163675Smarkus	/*
406163675Smarkus	 * XXXRW: Non-atomic test and set of dev->si_drv1 requires
407163675Smarkus	 * synchronization.
408163675Smarkus	 */
409163675Smarkus	tp = dev->si_drv1;
410163675Smarkus	if (!tp) {
411163675Smarkus		tuncreate(TUNNAME, dev);
412163675Smarkus		tp = dev->si_drv1;
413163675Smarkus	}
414163675Smarkus
415163675Smarkus	/*
416163675Smarkus	 * XXXRW: This use of tun_pid is subject to error due to the
417163675Smarkus	 * fact that a reference to the tunnel can live beyond the
418163675Smarkus	 * death of the process that created it.  Can we replace this
419163675Smarkus	 * with a simple busy flag?
420163675Smarkus	 */
421163675Smarkus	mtx_lock(&tp->tun_mtx);
422163675Smarkus	if (tp->tun_pid != 0 && tp->tun_pid != td->td_proc->p_pid) {
423163675Smarkus		mtx_unlock(&tp->tun_mtx);
424163675Smarkus		return (EBUSY);
425163675Smarkus	}
426163675Smarkus	tp->tun_pid = td->td_proc->p_pid;
427163675Smarkus
428163675Smarkus	tp->tun_flags |= TUN_OPEN;
429163675Smarkus	mtx_unlock(&tp->tun_mtx);
430163675Smarkus	ifp = TUN2IFP(tp);
431163675Smarkus	if_link_state_change(ifp, LINK_STATE_UP);
432163675Smarkus	TUNDEBUG(ifp, "open\n");
433163675Smarkus
434163675Smarkus	return (0);
435163675Smarkus}
436163675Smarkus
437163675Smarkus/*
438163675Smarkus * tunclose - close the device - mark i/f down & delete
439163675Smarkus * routing info
440163675Smarkus */
441163675Smarkusstatic	int
442163675Smarkustunclose(struct cdev *dev, int foo, int bar, struct thread *td)
443163675Smarkus{
444163675Smarkus	struct tun_softc *tp;
44561560Sn_hibma	struct ifnet *ifp;
44661560Sn_hibma	int s;
44761560Sn_hibma
44861560Sn_hibma	tp = dev->si_drv1;
44961560Sn_hibma	ifp = TUN2IFP(tp);
45061560Sn_hibma
45161560Sn_hibma	mtx_lock(&tp->tun_mtx);
45261560Sn_hibma	tp->tun_flags &= ~TUN_OPEN;
45361560Sn_hibma	tp->tun_pid = 0;
45461560Sn_hibma	mtx_unlock(&tp->tun_mtx);
45561560Sn_hibma
45661560Sn_hibma	/*
45761560Sn_hibma	 * junk all pending output
45861560Sn_hibma	 */
45961560Sn_hibma	CURVNET_SET(ifp->if_vnet);
46061560Sn_hibma	s = splimp();
46161560Sn_hibma	IFQ_PURGE(&ifp->if_snd);
46261560Sn_hibma	splx(s);
46361560Sn_hibma
46461560Sn_hibma	if (ifp->if_flags & IFF_UP) {
46561560Sn_hibma		s = splimp();
46661560Sn_hibma		if_down(ifp);
46761560Sn_hibma		splx(s);
46861560Sn_hibma	}
46961560Sn_hibma
470163675Smarkus	/* Delete all addresses and routes which reference this interface. */
47161560Sn_hibma	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
47261560Sn_hibma		struct ifaddr *ifa;
47361560Sn_hibma
47461560Sn_hibma		s = splimp();
47561560Sn_hibma		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
47661560Sn_hibma			/* deal w/IPv4 PtP destination; unlocked read */
47761560Sn_hibma			if (ifa->ifa_addr->sa_family == AF_INET) {
47861560Sn_hibma				rtinit(ifa, (int)RTM_DELETE,
47961560Sn_hibma				    tp->tun_flags & TUN_DSTADDR ? RTF_HOST : 0);
48061560Sn_hibma			} else {
48161560Sn_hibma				rtinit(ifa, (int)RTM_DELETE, 0);
48261560Sn_hibma			}
48361560Sn_hibma		}
48461560Sn_hibma		if_purgeaddrs(ifp);
48561560Sn_hibma		ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
48661560Sn_hibma		splx(s);
48761560Sn_hibma	}
48861560Sn_hibma	if_link_state_change(ifp, LINK_STATE_DOWN);
48961560Sn_hibma	CURVNET_RESTORE();
49061560Sn_hibma
49161560Sn_hibma	mtx_lock(&tp->tun_mtx);
49261560Sn_hibma	funsetown(&tp->tun_sigio);
49361560Sn_hibma	selwakeuppri(&tp->tun_rsel, PZERO + 1);
49461560Sn_hibma	KNOTE_UNLOCKED(&tp->tun_rsel.si_note, 0);
49561560Sn_hibma	TUNDEBUG (ifp, "closed\n");
49661560Sn_hibma
49761560Sn_hibma	cv_broadcast(&tp->tun_cv);
49861560Sn_hibma	mtx_unlock(&tp->tun_mtx);
49961560Sn_hibma	return (0);
50061560Sn_hibma}
50161560Sn_hibma
50261560Sn_hibmastatic int
50361560Sn_hibmatuninit(struct ifnet *ifp)
50461560Sn_hibma{
50561560Sn_hibma#ifdef INET
50661560Sn_hibma	struct tun_softc *tp = ifp->if_softc;
50761560Sn_hibma	struct ifaddr *ifa;
50861560Sn_hibma#endif
50961560Sn_hibma	int error = 0;
51061560Sn_hibma
51161560Sn_hibma	TUNDEBUG(ifp, "tuninit\n");
51261560Sn_hibma
51361560Sn_hibma	ifp->if_flags |= IFF_UP;
51461560Sn_hibma	ifp->if_drv_flags |= IFF_DRV_RUNNING;
51561560Sn_hibma	getmicrotime(&ifp->if_lastchange);
51661560Sn_hibma
51761560Sn_hibma#ifdef INET
51861560Sn_hibma	if_addr_rlock(ifp);
51961560Sn_hibma	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
52061560Sn_hibma		if (ifa->ifa_addr->sa_family == AF_INET) {
52161560Sn_hibma			struct sockaddr_in *si;
52261560Sn_hibma
52361560Sn_hibma			si = (struct sockaddr_in *)ifa->ifa_addr;
52461560Sn_hibma			mtx_lock(&tp->tun_mtx);
52561560Sn_hibma			if (si->sin_addr.s_addr)
52661560Sn_hibma				tp->tun_flags |= TUN_IASET;
527163675Smarkus
528163675Smarkus			si = (struct sockaddr_in *)ifa->ifa_dstaddr;
529163675Smarkus			if (si && si->sin_addr.s_addr)
53061560Sn_hibma				tp->tun_flags |= TUN_DSTADDR;
53161560Sn_hibma			mtx_unlock(&tp->tun_mtx);
53261560Sn_hibma		}
53361560Sn_hibma	}
53461560Sn_hibma	if_addr_runlock(ifp);
53561560Sn_hibma#endif
53661560Sn_hibma	return (error);
53761560Sn_hibma}
53861560Sn_hibma
539163675Smarkus/*
54061560Sn_hibma * Process an ioctl request.
54161560Sn_hibma */
54261560Sn_hibmastatic int
54361560Sn_hibmatunifioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
54461560Sn_hibma{
54561560Sn_hibma	struct ifreq *ifr = (struct ifreq *)data;
54661560Sn_hibma	struct tun_softc *tp = ifp->if_softc;
54761560Sn_hibma	struct ifstat *ifs;
54861560Sn_hibma	int		error = 0, s;
54961560Sn_hibma
55061560Sn_hibma	s = splimp();
55161560Sn_hibma	switch(cmd) {
55261560Sn_hibma	case SIOCGIFSTATUS:
55361560Sn_hibma		ifs = (struct ifstat *)data;
55461560Sn_hibma		mtx_lock(&tp->tun_mtx);
55561560Sn_hibma		if (tp->tun_pid)
55661560Sn_hibma			sprintf(ifs->ascii + strlen(ifs->ascii),
55761560Sn_hibma			    "\tOpened by PID %d\n", tp->tun_pid);
55861560Sn_hibma		mtx_unlock(&tp->tun_mtx);
55961560Sn_hibma		break;
56061560Sn_hibma	case SIOCSIFADDR:
56161560Sn_hibma		error = tuninit(ifp);
56261560Sn_hibma		TUNDEBUG(ifp, "address set, error=%d\n", error);
56361560Sn_hibma		break;
56461560Sn_hibma	case SIOCSIFDSTADDR:
56561560Sn_hibma		error = tuninit(ifp);
56661560Sn_hibma		TUNDEBUG(ifp, "destination address set, error=%d\n", error);
56761560Sn_hibma		break;
568163675Smarkus	case SIOCSIFMTU:
56961560Sn_hibma		ifp->if_mtu = ifr->ifr_mtu;
57061560Sn_hibma		TUNDEBUG(ifp, "mtu set\n");
57161560Sn_hibma		break;
57261560Sn_hibma	case SIOCSIFFLAGS:
57361560Sn_hibma	case SIOCADDMULTI:
57461560Sn_hibma	case SIOCDELMULTI:
57561560Sn_hibma		break;
57661560Sn_hibma	default:
57761560Sn_hibma		error = EINVAL;
57861560Sn_hibma	}
57961560Sn_hibma	splx(s);
58061560Sn_hibma	return (error);
58161560Sn_hibma}
58261560Sn_hibma
58361560Sn_hibma/*
58461560Sn_hibma * tunoutput - queue packets from higher level ready to put out.
58561560Sn_hibma */
58661560Sn_hibmastatic int
58761560Sn_hibmatunoutput(
58861560Sn_hibma	struct ifnet *ifp,
58961560Sn_hibma	struct mbuf *m0,
59061560Sn_hibma	struct sockaddr *dst,
591163675Smarkus	struct route *ro)
592163675Smarkus{
59361560Sn_hibma	struct tun_softc *tp = ifp->if_softc;
59461560Sn_hibma	u_short cached_tun_flags;
59561560Sn_hibma	int error;
59661560Sn_hibma	u_int32_t af;
59761560Sn_hibma
59861560Sn_hibma	TUNDEBUG (ifp, "tunoutput\n");
59961560Sn_hibma
60061560Sn_hibma#ifdef MAC
60161560Sn_hibma	error = mac_ifnet_check_transmit(ifp, m0);
60261560Sn_hibma	if (error) {
60361560Sn_hibma		m_freem(m0);
60461560Sn_hibma		return (error);
60561560Sn_hibma	}
60661560Sn_hibma#endif
60761560Sn_hibma
60861560Sn_hibma	/* Could be unlocked read? */
60961560Sn_hibma	mtx_lock(&tp->tun_mtx);
61061560Sn_hibma	cached_tun_flags = tp->tun_flags;
61161560Sn_hibma	mtx_unlock(&tp->tun_mtx);
61261560Sn_hibma	if ((cached_tun_flags & TUN_READY) != TUN_READY) {
61361560Sn_hibma		TUNDEBUG (ifp, "not ready 0%o\n", tp->tun_flags);
61461560Sn_hibma		m_freem (m0);
615163675Smarkus		return (EHOSTDOWN);
616163675Smarkus	}
617163675Smarkus
61861560Sn_hibma	if ((ifp->if_flags & IFF_UP) != IFF_UP) {
61961560Sn_hibma		m_freem (m0);
62061560Sn_hibma		return (EHOSTDOWN);
62161560Sn_hibma	}
62261560Sn_hibma
62361560Sn_hibma	/* BPF writes need to be handled specially. */
62461560Sn_hibma	if (dst->sa_family == AF_UNSPEC) {
62561560Sn_hibma		bcopy(dst->sa_data, &af, sizeof(af));
62661560Sn_hibma		dst->sa_family = af;
62761560Sn_hibma	}
62861560Sn_hibma
629163675Smarkus	if (bpf_peers_present(ifp->if_bpf)) {
63061560Sn_hibma		af = dst->sa_family;
63161560Sn_hibma		bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m0);
63261560Sn_hibma	}
63361560Sn_hibma
63461560Sn_hibma	/* prepend sockaddr? this may abort if the mbuf allocation fails */
63561560Sn_hibma	if (cached_tun_flags & TUN_LMODE) {
63661560Sn_hibma		/* allocate space for sockaddr */
63761560Sn_hibma		M_PREPEND(m0, dst->sa_len, M_DONTWAIT);
63861560Sn_hibma
63961560Sn_hibma		/* if allocation failed drop packet */
64061560Sn_hibma		if (m0 == NULL) {
64161560Sn_hibma			ifp->if_iqdrops++;
64261560Sn_hibma			ifp->if_oerrors++;
64361560Sn_hibma			return (ENOBUFS);
64461560Sn_hibma		} else {
64561560Sn_hibma			bcopy(dst, m0->m_data, dst->sa_len);
64661560Sn_hibma		}
64761560Sn_hibma	}
64861560Sn_hibma
64961560Sn_hibma	if (cached_tun_flags & TUN_IFHEAD) {
65061560Sn_hibma		/* Prepend the address family */
65161560Sn_hibma		M_PREPEND(m0, 4, M_DONTWAIT);
65261560Sn_hibma
65361560Sn_hibma		/* if allocation failed drop packet */
65461560Sn_hibma		if (m0 == NULL) {
65561560Sn_hibma			ifp->if_iqdrops++;
65661560Sn_hibma			ifp->if_oerrors++;
65761560Sn_hibma			return (ENOBUFS);
65861560Sn_hibma		} else
65961560Sn_hibma			*(u_int32_t *)m0->m_data = htonl(dst->sa_family);
66061560Sn_hibma	} else {
66161560Sn_hibma#ifdef INET
66261560Sn_hibma		if (dst->sa_family != AF_INET)
66361560Sn_hibma#endif
66461560Sn_hibma		{
66561560Sn_hibma			m_freem(m0);
66661560Sn_hibma			return (EAFNOSUPPORT);
66761560Sn_hibma		}
66861560Sn_hibma	}
66961560Sn_hibma
67061560Sn_hibma	error = (ifp->if_transmit)(ifp, m0);
67161560Sn_hibma	if (error) {
67261560Sn_hibma		ifp->if_collisions++;
67361560Sn_hibma		return (ENOBUFS);
67461560Sn_hibma	}
67561560Sn_hibma	ifp->if_opackets++;
67661560Sn_hibma	return (0);
67761560Sn_hibma}
67861560Sn_hibma
67961560Sn_hibma/*
68061560Sn_hibma * the cdevsw interface is now pretty minimal.
68161560Sn_hibma */
68261560Sn_hibmastatic	int
68361560Sn_hibmatunioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
68461560Sn_hibma{
68561560Sn_hibma	int		s;
68661560Sn_hibma	int		error;
68761560Sn_hibma	struct tun_softc *tp = dev->si_drv1;
68861560Sn_hibma	struct tuninfo *tunp;
68961560Sn_hibma
69061560Sn_hibma	switch (cmd) {
69161560Sn_hibma	case TUNSIFINFO:
69261560Sn_hibma		tunp = (struct tuninfo *)data;
69361560Sn_hibma		if (tunp->mtu < IF_MINMTU)
69461560Sn_hibma			return (EINVAL);
69561560Sn_hibma		if (TUN2IFP(tp)->if_mtu != tunp->mtu) {
69661560Sn_hibma			error = priv_check(td, PRIV_NET_SETIFMTU);
69761560Sn_hibma			if (error)
69861560Sn_hibma				return (error);
69961560Sn_hibma		}
70061560Sn_hibma		TUN2IFP(tp)->if_mtu = tunp->mtu;
70161560Sn_hibma		TUN2IFP(tp)->if_type = tunp->type;
70261560Sn_hibma		TUN2IFP(tp)->if_baudrate = tunp->baudrate;
70361560Sn_hibma		break;
70461560Sn_hibma	case TUNGIFINFO:
70561560Sn_hibma		tunp = (struct tuninfo *)data;
70661560Sn_hibma		tunp->mtu = TUN2IFP(tp)->if_mtu;
70761560Sn_hibma		tunp->type = TUN2IFP(tp)->if_type;
708163675Smarkus		tunp->baudrate = TUN2IFP(tp)->if_baudrate;
709163675Smarkus		break;
710163675Smarkus	case TUNSDEBUG:
71161560Sn_hibma		tundebug = *(int *)data;
71261560Sn_hibma		break;
71361560Sn_hibma	case TUNGDEBUG:
71461560Sn_hibma		*(int *)data = tundebug;
71561560Sn_hibma		break;
71661560Sn_hibma	case TUNSLMODE:
71761560Sn_hibma		mtx_lock(&tp->tun_mtx);
71861560Sn_hibma		if (*(int *)data) {
71961560Sn_hibma			tp->tun_flags |= TUN_LMODE;
720163675Smarkus			tp->tun_flags &= ~TUN_IFHEAD;
721163675Smarkus		} else
72261560Sn_hibma			tp->tun_flags &= ~TUN_LMODE;
72361560Sn_hibma		mtx_unlock(&tp->tun_mtx);
72461560Sn_hibma		break;
72561560Sn_hibma	case TUNSIFHEAD:
72661560Sn_hibma		mtx_lock(&tp->tun_mtx);
72761560Sn_hibma		if (*(int *)data) {
72861560Sn_hibma			tp->tun_flags |= TUN_IFHEAD;
72961560Sn_hibma			tp->tun_flags &= ~TUN_LMODE;
730163675Smarkus		} else
73161560Sn_hibma			tp->tun_flags &= ~TUN_IFHEAD;
73261560Sn_hibma		mtx_unlock(&tp->tun_mtx);
73361560Sn_hibma		break;
73461560Sn_hibma	case TUNGIFHEAD:
73561560Sn_hibma		/* Could be unlocked read? */
73661560Sn_hibma		mtx_lock(&tp->tun_mtx);
737163675Smarkus		*(int *)data = (tp->tun_flags & TUN_IFHEAD) ? 1 : 0;
738163675Smarkus		mtx_unlock(&tp->tun_mtx);
739163675Smarkus		break;
740163675Smarkus	case TUNSIFMODE:
741163675Smarkus		/* deny this if UP */
74261560Sn_hibma		if (TUN2IFP(tp)->if_flags & IFF_UP)
74361560Sn_hibma			return(EBUSY);
74461560Sn_hibma
74561560Sn_hibma		switch (*(int *)data & ~IFF_MULTICAST) {
74661560Sn_hibma		case IFF_POINTOPOINT:
74761560Sn_hibma		case IFF_BROADCAST:
74861560Sn_hibma			TUN2IFP(tp)->if_flags &=
74961560Sn_hibma			    ~(IFF_BROADCAST|IFF_POINTOPOINT|IFF_MULTICAST);
75061560Sn_hibma			TUN2IFP(tp)->if_flags |= *(int *)data;
75161560Sn_hibma			break;
75261560Sn_hibma		default:
75361560Sn_hibma			return(EINVAL);
75461560Sn_hibma		}
75561560Sn_hibma		break;
75661560Sn_hibma	case TUNSIFPID:
75761560Sn_hibma		mtx_lock(&tp->tun_mtx);
75861560Sn_hibma		tp->tun_pid = curthread->td_proc->p_pid;
75961560Sn_hibma		mtx_unlock(&tp->tun_mtx);
76061560Sn_hibma		break;
76161560Sn_hibma	case FIONBIO:
76261560Sn_hibma		break;
76361560Sn_hibma	case FIOASYNC:
76461560Sn_hibma		mtx_lock(&tp->tun_mtx);
76561560Sn_hibma		if (*(int *)data)
76661560Sn_hibma			tp->tun_flags |= TUN_ASYNC;
76761560Sn_hibma		else
76861560Sn_hibma			tp->tun_flags &= ~TUN_ASYNC;
76961560Sn_hibma		mtx_unlock(&tp->tun_mtx);
77061560Sn_hibma		break;
77161560Sn_hibma	case FIONREAD:
77261560Sn_hibma		s = splimp();
77361560Sn_hibma		if (!IFQ_IS_EMPTY(&TUN2IFP(tp)->if_snd)) {
77461560Sn_hibma			struct mbuf *mb;
77561560Sn_hibma			IFQ_LOCK(&TUN2IFP(tp)->if_snd);
77661560Sn_hibma			IFQ_POLL_NOLOCK(&TUN2IFP(tp)->if_snd, mb);
77761560Sn_hibma			for( *(int *)data = 0; mb != 0; mb = mb->m_next)
77861560Sn_hibma				*(int *)data += mb->m_len;
77961560Sn_hibma			IFQ_UNLOCK(&TUN2IFP(tp)->if_snd);
78061560Sn_hibma		} else
78161560Sn_hibma			*(int *)data = 0;
78261560Sn_hibma		splx(s);
78361560Sn_hibma		break;
78461560Sn_hibma	case FIOSETOWN:
78561560Sn_hibma		return (fsetown(*(int *)data, &tp->tun_sigio));
78661560Sn_hibma
78761560Sn_hibma	case FIOGETOWN:
78861560Sn_hibma		*(int *)data = fgetown(&tp->tun_sigio);
78961560Sn_hibma		return (0);
79061560Sn_hibma
79161560Sn_hibma	/* This is deprecated, FIOSETOWN should be used instead. */
79261560Sn_hibma	case TIOCSPGRP:
79361560Sn_hibma		return (fsetown(-(*(int *)data), &tp->tun_sigio));
79461560Sn_hibma
79561560Sn_hibma	/* This is deprecated, FIOGETOWN should be used instead. */
79661560Sn_hibma	case TIOCGPGRP:
79761560Sn_hibma		*(int *)data = -fgetown(&tp->tun_sigio);
79861560Sn_hibma		return (0);
79961560Sn_hibma
80061560Sn_hibma	default:
80161560Sn_hibma		return (ENOTTY);
802163675Smarkus	}
803163675Smarkus	return (0);
804163675Smarkus}
805163675Smarkus
806163675Smarkus/*
807163675Smarkus * The cdevsw read interface - reads a packet at a time, or at
808163675Smarkus * least as much of a packet as can be read.
809163675Smarkus */
810163675Smarkusstatic	int
811163675Smarkustunread(struct cdev *dev, struct uio *uio, int flag)
812163675Smarkus{
813163675Smarkus	struct tun_softc *tp = dev->si_drv1;
814163675Smarkus	struct ifnet	*ifp = TUN2IFP(tp);
815163675Smarkus	struct mbuf	*m;
816163675Smarkus	int		error=0, len, s;
817163675Smarkus
818163675Smarkus	TUNDEBUG (ifp, "read\n");
819163675Smarkus	mtx_lock(&tp->tun_mtx);
820163675Smarkus	if ((tp->tun_flags & TUN_READY) != TUN_READY) {
821163675Smarkus		mtx_unlock(&tp->tun_mtx);
822163675Smarkus		TUNDEBUG (ifp, "not ready 0%o\n", tp->tun_flags);
823163675Smarkus		return (EHOSTDOWN);
824163675Smarkus	}
825163675Smarkus
826163675Smarkus	tp->tun_flags &= ~TUN_RWAIT;
827163675Smarkus	mtx_unlock(&tp->tun_mtx);
828163675Smarkus
829163675Smarkus	s = splimp();
830163675Smarkus	do {
831163675Smarkus		IFQ_DEQUEUE(&ifp->if_snd, m);
832163675Smarkus		if (m == NULL) {
833163675Smarkus			if (flag & O_NONBLOCK) {
834163675Smarkus				splx(s);
83561560Sn_hibma				return (EWOULDBLOCK);
83661560Sn_hibma			}
83761560Sn_hibma			mtx_lock(&tp->tun_mtx);
83861560Sn_hibma			tp->tun_flags |= TUN_RWAIT;
83961560Sn_hibma			mtx_unlock(&tp->tun_mtx);
84061560Sn_hibma			if ((error = tsleep(tp, PCATCH | (PZERO + 1),
84161560Sn_hibma					"tunread", 0)) != 0) {
84261560Sn_hibma				splx(s);
84361560Sn_hibma				return (error);
84461560Sn_hibma			}
84561560Sn_hibma		}
84661560Sn_hibma	} while (m == NULL);
84761560Sn_hibma	splx(s);
84861560Sn_hibma
84961560Sn_hibma	while (m && uio->uio_resid > 0 && error == 0) {
85061560Sn_hibma		len = min(uio->uio_resid, m->m_len);
85161560Sn_hibma		if (len != 0)
85261560Sn_hibma			error = uiomove(mtod(m, void *), len, uio);
85361560Sn_hibma		m = m_free(m);
85461560Sn_hibma	}
85561560Sn_hibma
85661560Sn_hibma	if (m) {
85761560Sn_hibma		TUNDEBUG(ifp, "Dropping mbuf\n");
85861560Sn_hibma		m_freem(m);
85961560Sn_hibma	}
86061560Sn_hibma	return (error);
86161560Sn_hibma}
86261560Sn_hibma
86361560Sn_hibma/*
86461560Sn_hibma * the cdevsw write interface - an atomic write is a packet - or else!
86561560Sn_hibma */
86661560Sn_hibmastatic	int
86761560Sn_hibmatunwrite(struct cdev *dev, struct uio *uio, int flag)
86861560Sn_hibma{
86961560Sn_hibma	struct tun_softc *tp = dev->si_drv1;
87061560Sn_hibma	struct ifnet	*ifp = TUN2IFP(tp);
87161560Sn_hibma	struct mbuf	*m;
87261560Sn_hibma	int		error = 0;
87361560Sn_hibma	uint32_t	family;
87461560Sn_hibma	int 		isr;
87561560Sn_hibma
87661560Sn_hibma	TUNDEBUG(ifp, "tunwrite\n");
87761560Sn_hibma
87861560Sn_hibma	if ((ifp->if_flags & IFF_UP) != IFF_UP)
87961560Sn_hibma		/* ignore silently */
880163675Smarkus		return (0);
881163675Smarkus
882163675Smarkus	if (uio->uio_resid == 0)
883163675Smarkus		return (0);
884163675Smarkus
885163675Smarkus	if (uio->uio_resid < 0 || uio->uio_resid > TUNMRU) {
886163675Smarkus		TUNDEBUG(ifp, "len=%zd!\n", uio->uio_resid);
887163675Smarkus		return (EIO);
888163675Smarkus	}
889163675Smarkus
890163675Smarkus	if ((m = m_uiotombuf(uio, M_DONTWAIT, 0, 0, M_PKTHDR)) == NULL) {
891163675Smarkus		ifp->if_ierrors++;
892163675Smarkus		return (error);
893163675Smarkus	}
894163675Smarkus
895163675Smarkus	m->m_pkthdr.rcvif = ifp;
896163675Smarkus#ifdef MAC
897163675Smarkus	mac_ifnet_create_mbuf(ifp, m);
898163675Smarkus#endif
899163675Smarkus
900163675Smarkus	/* Could be unlocked read? */
901163675Smarkus	mtx_lock(&tp->tun_mtx);
902163675Smarkus	if (tp->tun_flags & TUN_IFHEAD) {
903163675Smarkus		mtx_unlock(&tp->tun_mtx);
904163675Smarkus		if (m->m_len < sizeof(family) &&
905163675Smarkus		    (m = m_pullup(m, sizeof(family))) == NULL)
906163675Smarkus			return (ENOBUFS);
907163675Smarkus		family = ntohl(*mtod(m, u_int32_t *));
908163675Smarkus		m_adj(m, sizeof(family));
909163675Smarkus	} else {
910163675Smarkus		mtx_unlock(&tp->tun_mtx);
911163675Smarkus		family = AF_INET;
912163675Smarkus	}
913163675Smarkus
914163675Smarkus	BPF_MTAP2(ifp, &family, sizeof(family), m);
915163675Smarkus
916163675Smarkus	switch (family) {
917163675Smarkus#ifdef INET
918163675Smarkus	case AF_INET:
919163675Smarkus		isr = NETISR_IP;
920163675Smarkus		break;
921163675Smarkus#endif
922163675Smarkus#ifdef INET6
923163675Smarkus	case AF_INET6:
924163675Smarkus		isr = NETISR_IPV6;
925163675Smarkus		break;
926163675Smarkus#endif
927163675Smarkus#ifdef IPX
928163675Smarkus	case AF_IPX:
929163675Smarkus		isr = NETISR_IPX;
930163675Smarkus		break;
931163675Smarkus#endif
932163675Smarkus#ifdef NETATALK
933163675Smarkus	case AF_APPLETALK:
934163675Smarkus		isr = NETISR_ATALK2;
935163675Smarkus		break;
936163675Smarkus#endif
937163675Smarkus	default:
938163675Smarkus		m_freem(m);
939163675Smarkus		return (EAFNOSUPPORT);
940163675Smarkus	}
941163675Smarkus	/* First chunk of an mbuf contains good junk */
942163675Smarkus	if (harvest.point_to_point)
943163675Smarkus		random_harvest(m, 16, 3, 0, RANDOM_NET);
944163675Smarkus	ifp->if_ibytes += m->m_pkthdr.len;
945163675Smarkus	ifp->if_ipackets++;
946163675Smarkus	CURVNET_SET(ifp->if_vnet);
947163675Smarkus	netisr_dispatch(isr, m);
948163675Smarkus	CURVNET_RESTORE();
949163675Smarkus	return (0);
950163675Smarkus}
951163675Smarkus
952163675Smarkus/*
953163675Smarkus * tunpoll - the poll interface, this is only useful on reads
954163675Smarkus * really. The write detect always returns true, write never blocks
955163675Smarkus * anyway, it either accepts the packet or drops it.
956163675Smarkus */
957163675Smarkusstatic	int
958163675Smarkustunpoll(struct cdev *dev, int events, struct thread *td)
959163675Smarkus{
960163675Smarkus	int		s;
961163675Smarkus	struct tun_softc *tp = dev->si_drv1;
962163675Smarkus	struct ifnet	*ifp = TUN2IFP(tp);
963163675Smarkus	int		revents = 0;
964163675Smarkus	struct mbuf	*m;
965163675Smarkus
966163675Smarkus	s = splimp();
967163675Smarkus	TUNDEBUG(ifp, "tunpoll\n");
968163675Smarkus
969163675Smarkus	if (events & (POLLIN | POLLRDNORM)) {
970163675Smarkus		IFQ_LOCK(&ifp->if_snd);
971163675Smarkus		IFQ_POLL_NOLOCK(&ifp->if_snd, m);
972163675Smarkus		if (m != NULL) {
973163675Smarkus			TUNDEBUG(ifp, "tunpoll q=%d\n", ifp->if_snd.ifq_len);
974163675Smarkus			revents |= events & (POLLIN | POLLRDNORM);
975163675Smarkus		} else {
97661560Sn_hibma			TUNDEBUG(ifp, "tunpoll waiting\n");
97761560Sn_hibma			selrecord(td, &tp->tun_rsel);
97861560Sn_hibma		}
97961560Sn_hibma		IFQ_UNLOCK(&ifp->if_snd);
98061560Sn_hibma	}
98161560Sn_hibma	if (events & (POLLOUT | POLLWRNORM))
98261560Sn_hibma		revents |= events & (POLLOUT | POLLWRNORM);
98361560Sn_hibma
98461560Sn_hibma	splx(s);
98561560Sn_hibma	return (revents);
986163675Smarkus}
98761560Sn_hibma
98861560Sn_hibma/*
98961560Sn_hibma * tunkqfilter - support for the kevent() system call.
99061560Sn_hibma */
99161560Sn_hibmastatic int
992223153Smavtunkqfilter(struct cdev *dev, struct knote *kn)
99361560Sn_hibma{
99461560Sn_hibma	int			s;
99561560Sn_hibma	struct tun_softc	*tp = dev->si_drv1;
996223153Smav	struct ifnet	*ifp = TUN2IFP(tp);
99761560Sn_hibma
99861560Sn_hibma	s = splimp();
99961560Sn_hibma	switch(kn->kn_filter) {
100061560Sn_hibma	case EVFILT_READ:
100161560Sn_hibma		TUNDEBUG(ifp, "%s kqfilter: EVFILT_READ, minor = %#x\n",
100261560Sn_hibma		    ifp->if_xname, dev2unit(dev));
100361560Sn_hibma		kn->kn_fop = &tun_read_filterops;
100461560Sn_hibma		break;
100561560Sn_hibma
100661560Sn_hibma	case EVFILT_WRITE:
100761560Sn_hibma		TUNDEBUG(ifp, "%s kqfilter: EVFILT_WRITE, minor = %#x\n",
100861560Sn_hibma		    ifp->if_xname, dev2unit(dev));
100961560Sn_hibma		kn->kn_fop = &tun_write_filterops;
101061560Sn_hibma		break;
101161560Sn_hibma
101261560Sn_hibma	default:
101361560Sn_hibma		TUNDEBUG(ifp, "%s kqfilter: invalid filter, minor = %#x\n",
101461560Sn_hibma		    ifp->if_xname, dev2unit(dev));
101561560Sn_hibma		splx(s);
101661560Sn_hibma		return(EINVAL);
101761560Sn_hibma	}
101861560Sn_hibma	splx(s);
101961560Sn_hibma
1020223153Smav	kn->kn_hook = (caddr_t) dev;
1021223153Smav	knlist_add(&tp->tun_rsel.si_note, kn, 0);
1022223153Smav
1023223153Smav	return (0);
1024223153Smav}
1025223153Smav
1026223153Smav/*
1027223153Smav * Return true of there is data in the interface queue.
102861560Sn_hibma */
102961560Sn_hibmastatic int
1030163675Smarkustunkqread(struct knote *kn, long hint)
1031163675Smarkus{
1032163675Smarkus	int			ret, s;
1033163675Smarkus	struct cdev		*dev = (struct cdev *)(kn->kn_hook);
1034163675Smarkus	struct tun_softc	*tp = dev->si_drv1;
1035163675Smarkus	struct ifnet	*ifp = TUN2IFP(tp);
1036163675Smarkus
1037163675Smarkus	s = splimp();
1038163675Smarkus	if ((kn->kn_data = ifp->if_snd.ifq_len) > 0) {
1039163675Smarkus		TUNDEBUG(ifp,
1040163675Smarkus		    "%s have data in the queue.  Len = %d, minor = %#x\n",
1041163675Smarkus		    ifp->if_xname, ifp->if_snd.ifq_len, dev2unit(dev));
1042163675Smarkus		ret = 1;
1043163675Smarkus	} else {
1044163675Smarkus		TUNDEBUG(ifp,
1045163675Smarkus		    "%s waiting for data, minor = %#x\n", ifp->if_xname,
1046163675Smarkus		    dev2unit(dev));
1047163675Smarkus		ret = 0;
1048163675Smarkus	}
1049163675Smarkus	splx(s);
1050163675Smarkus
1051163675Smarkus	return (ret);
1052163675Smarkus}
1053163675Smarkus
1054163675Smarkus/*
1055163675Smarkus * Always can write, always return MTU in kn->data.
1056163675Smarkus */
1057163675Smarkusstatic int
1058163675Smarkustunkqwrite(struct knote *kn, long hint)
1059163675Smarkus{
1060163675Smarkus	int			s;
1061163675Smarkus	struct tun_softc	*tp = ((struct cdev *)kn->kn_hook)->si_drv1;
1062163675Smarkus	struct ifnet	*ifp = TUN2IFP(tp);
1063163675Smarkus
1064163675Smarkus	s = splimp();
1065163675Smarkus	kn->kn_data = ifp->if_mtu;
1066163675Smarkus	splx(s);
1067163675Smarkus
1068163675Smarkus	return (1);
1069163675Smarkus}
1070163675Smarkus
1071163675Smarkusstatic void
1072163675Smarkustunkqdetach(struct knote *kn)
1073163675Smarkus{
1074163675Smarkus	struct tun_softc	*tp = ((struct cdev *)kn->kn_hook)->si_drv1;
1075163675Smarkus
1076163675Smarkus	knlist_remove(&tp->tun_rsel.si_note, kn, 0);
1077163675Smarkus}
1078163675Smarkus