if_tun.c revision 137101
112115Sdyson/*	$NetBSD: if_tun.c,v 1.14 1994/06/29 06:36:25 cgd Exp $	*/
212115Sdyson
312115Sdyson/*
412115Sdyson * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk>
512115Sdyson * Nottingham University 1987.
612115Sdyson *
712115Sdyson * This source may be freely distributed, however I would be interested
812115Sdyson * in any changes that are made.
912115Sdyson *
1012115Sdyson * This driver takes packets off the IP i/f and hands them up to a
1112115Sdyson * user process to have its wicked way with. This driver has it's
1212115Sdyson * roots in a similar driver written by Phil Cockcroft (formerly) at
1312115Sdyson * UCL. This driver is based much more on read/write/poll mode of
1412115Sdyson * operation though.
1512115Sdyson *
1612115Sdyson * $FreeBSD: head/sys/net/if_tun.c 137101 2004-10-31 17:39:46Z glebius $
1712115Sdyson */
1812115Sdyson
1912115Sdyson#include "opt_atalk.h"
2012115Sdyson#include "opt_inet.h"
2112115Sdyson#include "opt_inet6.h"
2212115Sdyson#include "opt_ipx.h"
2312115Sdyson#include "opt_mac.h"
2412115Sdyson
2512115Sdyson#include <sys/param.h>
2612115Sdyson#include <sys/proc.h>
2712115Sdyson#include <sys/systm.h>
2812115Sdyson#include <sys/mac.h>
2912115Sdyson#include <sys/mbuf.h>
3012115Sdyson#include <sys/module.h>
3112115Sdyson#include <sys/socket.h>
3212115Sdyson#include <sys/filio.h>
3312115Sdyson#include <sys/sockio.h>
3412115Sdyson#include <sys/ttycom.h>
3512115Sdyson#include <sys/poll.h>
3612115Sdyson#include <sys/signalvar.h>
3712115Sdyson#include <sys/filedesc.h>
3812115Sdyson#include <sys/kernel.h>
3912115Sdyson#include <sys/sysctl.h>
4012115Sdyson#include <sys/conf.h>
4112115Sdyson#include <sys/uio.h>
4213260Swollman#include <sys/vnode.h>
4312115Sdyson#include <sys/malloc.h>
4412115Sdyson#include <sys/random.h>
4512115Sdyson
4612115Sdyson#include <net/if.h>
4712115Sdyson#include <net/if_types.h>
4812115Sdyson#include <net/netisr.h>
4912115Sdyson#include <net/route.h>
5012115Sdyson#ifdef INET
5112115Sdyson#include <netinet/in.h>
5229906Skato#endif
5324131Sbde#include <net/bpf.h>
5412115Sdyson#include <net/if_tun.h>
5512115Sdyson
5612115Sdyson#include <sys/queue.h>
5712115Sdyson
5812115Sdyson/*
5912115Sdyson * tun_list is protected by global tunmtx.  Other mutable fields are
6012115Sdyson * protected by tun->tun_mtx, or by their owning subsystem.  tun_dev is
6112115Sdyson * static for the duration of a tunnel interface.
6212115Sdyson */
6312115Sdysonstruct tun_softc {
6412115Sdyson	TAILQ_ENTRY(tun_softc)	tun_list;
6512115Sdyson	struct cdev *tun_dev;
6612115Sdyson	u_short	tun_flags;		/* misc flags */
6712115Sdyson#define	TUN_OPEN	0x0001
6812115Sdyson#define	TUN_INITED	0x0002
6912115Sdyson#define	TUN_RCOLL	0x0004
7028270Swollman#define	TUN_IASET	0x0008
7112911Sphk#define	TUN_DSTADDR	0x0010
7212911Sphk#define	TUN_LMODE	0x0020
7312911Sphk#define	TUN_RWAIT	0x0040
7412911Sphk#define	TUN_ASYNC	0x0080
7512911Sphk#define	TUN_IFHEAD	0x0100
7612911Sphk
7712911Sphk#define TUN_READY       (TUN_OPEN | TUN_INITED)
7812911Sphk
7912911Sphk	/*
8012911Sphk	 * XXXRW: tun_pid is used to exclusively lock /dev/tun.  Is this
8112911Sphk	 * actually needed?  Can we just return EBUSY if already open?
8212911Sphk	 * Problem is that this involved inherent races when a tun device
8312911Sphk	 * is handed off from one process to another, as opposed to just
8412115Sdyson	 * being slightly stale informationally.
8531315Sbde	 */
8630280Sphk	pid_t	tun_pid;		/* owning pid */
8712911Sphk	struct	ifnet tun_if;		/* the interface */
8812115Sdyson	struct  sigio *tun_sigio;	/* information for async I/O */
8912115Sdyson	struct	selinfo	tun_rsel;	/* read select */
9012115Sdyson	struct mtx	tun_mtx;	/* protect mutable softc fields */
9112115Sdyson};
9212115Sdyson
9312115Sdyson#define TUNDEBUG	if (tundebug) if_printf
9412115Sdyson#define	TUNNAME		"tun"
9512115Sdyson
9612115Sdyson/*
9712115Sdyson * All mutable global variables in if_tun are locked using tunmtx, with
9812115Sdyson * the exception of tundebug, which is used unlocked, and tunclones,
9912115Sdyson * which is static after setup.
10012115Sdyson */
10112115Sdysonstatic struct mtx tunmtx;
10212115Sdysonstatic MALLOC_DEFINE(M_TUN, TUNNAME, "Tunnel Interface");
10312115Sdysonstatic int tundebug = 0;
10412115Sdysonstatic struct clonedevs *tunclones;
10512911Sphkstatic TAILQ_HEAD(,tun_softc)	tunhead = TAILQ_HEAD_INITIALIZER(tunhead);
10612115SdysonSYSCTL_INT(_debug, OID_AUTO, if_tun_debug, CTLFLAG_RW, &tundebug, 0, "");
10716322Sgpalmer
10816322Sgpalmerstatic void	tunclone(void *arg, char *name, int namelen, struct cdev **dev);
10916322Sgpalmerstatic void	tuncreate(struct cdev *dev);
11016322Sgpalmerstatic int	tunifioctl(struct ifnet *, u_long, caddr_t);
11116322Sgpalmerstatic int	tuninit(struct ifnet *);
11216322Sgpalmerstatic int	tunmodevent(module_t, int, void *);
11316322Sgpalmerstatic int	tunoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
11412115Sdyson		    struct rtentry *rt);
11516322Sgpalmerstatic void	tunstart(struct ifnet *);
11612115Sdyson
11712115Sdysonstatic d_open_t		tunopen;
11812115Sdysonstatic d_close_t	tunclose;
11912115Sdysonstatic d_read_t		tunread;
12012115Sdysonstatic d_write_t	tunwrite;
12112911Sphkstatic d_ioctl_t	tunioctl;
12212115Sdysonstatic d_poll_t		tunpoll;
12312115Sdyson
12412115Sdysonstatic struct cdevsw tun_cdevsw = {
12512115Sdyson	.d_version =	D_VERSION,
12612115Sdyson	.d_flags =	D_PSEUDO | D_NEEDGIANT,
12712115Sdyson	.d_open =	tunopen,
12812115Sdyson	.d_close =	tunclose,
12912115Sdyson	.d_read =	tunread,
13012115Sdyson	.d_write =	tunwrite,
13129208Sbde	.d_ioctl =	tunioctl,
13229208Sbde	.d_poll =	tunpoll,
13329208Sbde	.d_name =	TUNNAME,
13429208Sbde};
13512115Sdyson
13612115Sdysonstatic void
13712115Sdysontunclone(void *arg, char *name, int namelen, struct cdev **dev)
13812115Sdyson{
13929888Skato	int u, i;
14029888Skato
14129888Skato	if (*dev != NULL)
14229888Skato		return;
14312115Sdyson
14412115Sdyson	if (strcmp(name, TUNNAME) == 0) {
14512115Sdyson		u = -1;
14612115Sdyson	} else if (dev_stdclone(name, NULL, TUNNAME, &u) != 1)
14712115Sdyson		return;	/* Don't recognise the name */
14812115Sdyson	if (u != -1 && u > IF_MAXUNIT)
14912115Sdyson		return;	/* Unit number too high */
15012115Sdyson
15112115Sdyson	/* find any existing device, or allocate new unit number */
15230469Sjulian	i = clone_create(&tunclones, &tun_cdevsw, &u, dev, 0);
15312115Sdyson	if (i) {
15412115Sdyson		/* No preexisting struct cdev *, create one */
15512115Sdyson		*dev = make_dev(&tun_cdevsw, unit2minor(u),
15612115Sdyson		    UID_UUCP, GID_DIALER, 0600, "tun%d", u);
15712115Sdyson		if (*dev != NULL)
15812115Sdyson			(*dev)->si_flags |= SI_CHEAPCLONE;
15912115Sdyson	}
16012115Sdyson}
16112115Sdyson
16212115Sdysonstatic void
16312115Sdysontun_destroy(struct tun_softc *tp)
16412115Sdyson{
16512115Sdyson	struct cdev *dev;
16612115Sdyson
16712115Sdyson	/* Unlocked read. */
16812115Sdyson	KASSERT((tp->tun_flags & TUN_OPEN) == 0,
16916322Sgpalmer	    ("tununits is out of sync - unit %d", tp->tun_if.if_dunit));
17012115Sdyson
17112115Sdyson	dev = tp->tun_dev;
17212115Sdyson	bpfdetach(&tp->tun_if);
17312115Sdyson	if_detach(&tp->tun_if);
17412115Sdyson	destroy_dev(dev);
17512115Sdyson	mtx_destroy(&tp->tun_mtx);
17612911Sphk	free(tp, M_TUN);
17712115Sdyson}
17812115Sdyson
17912115Sdysonstatic int
18012115Sdysontunmodevent(module_t mod, int type, void *data)
18112115Sdyson{
18212115Sdyson	static eventhandler_tag tag;
18312115Sdyson	struct tun_softc *tp;
18412115Sdyson
18512115Sdyson	switch (type) {
18612115Sdyson	case MOD_LOAD:
18712115Sdyson		mtx_init(&tunmtx, "tunmtx", NULL, MTX_DEF);
18812115Sdyson		clone_setup(&tunclones);
18912115Sdyson		tag = EVENTHANDLER_REGISTER(dev_clone, tunclone, 0, 1000);
19012115Sdyson		if (tag == NULL)
19112115Sdyson			return (ENOMEM);
19212115Sdyson		break;
19312115Sdyson	case MOD_UNLOAD:
19412115Sdyson		EVENTHANDLER_DEREGISTER(dev_clone, tag);
19512115Sdyson
19629888Skato		mtx_lock(&tunmtx);
19729888Skato		while ((tp = TAILQ_FIRST(&tunhead)) != NULL) {
19812115Sdyson			TAILQ_REMOVE(&tunhead, tp, tun_list);
19912115Sdyson			mtx_unlock(&tunmtx);
20012115Sdyson			tun_destroy(tp);
20112115Sdyson			mtx_lock(&tunmtx);
20212115Sdyson		}
20329888Skato		mtx_unlock(&tunmtx);
20429888Skato		clone_cleanup(&tunclones);
20529888Skato		mtx_destroy(&tunmtx);
20629888Skato		break;
20712115Sdyson	default:
20812115Sdyson		return EOPNOTSUPP;
20912115Sdyson	}
21012115Sdyson	return 0;
21122521Sdyson}
21212115Sdyson
21312115Sdysonstatic moduledata_t tun_mod = {
21422521Sdyson	"if_tun",
21512115Sdyson	tunmodevent,
21612115Sdyson	0
21712115Sdyson};
21812115Sdyson
21912115SdysonDECLARE_MODULE(if_tun, tun_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
22031132Sjulian
22112115Sdysonstatic void
22212115Sdysontunstart(struct ifnet *ifp)
22312115Sdyson{
22412115Sdyson	struct tun_softc *tp = ifp->if_softc;
22512115Sdyson	struct mbuf *m;
22612115Sdyson
22712115Sdyson	if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
22812115Sdyson		IFQ_LOCK(&ifp->if_snd);
22912115Sdyson		IFQ_POLL_NOLOCK(&ifp->if_snd, m);
23012115Sdyson		if (m == NULL) {
23112115Sdyson			IFQ_UNLOCK(&ifp->if_snd);
23212115Sdyson			return;
23312115Sdyson		}
23412115Sdyson		IFQ_UNLOCK(&ifp->if_snd);
23512115Sdyson	}
23612115Sdyson
23712115Sdyson	mtx_lock(&tp->tun_mtx);
23812115Sdyson	if (tp->tun_flags & TUN_RWAIT) {
23912115Sdyson		tp->tun_flags &= ~TUN_RWAIT;
24012115Sdyson		wakeup(tp);
24112115Sdyson	}
24212115Sdyson	if (tp->tun_flags & TUN_ASYNC && tp->tun_sigio) {
24312115Sdyson		mtx_unlock(&tp->tun_mtx);
24412115Sdyson		pgsigio(&tp->tun_sigio, SIGIO, 0);
24512115Sdyson	} else
24612115Sdyson		mtx_unlock(&tp->tun_mtx);
24712115Sdyson	selwakeuppri(&tp->tun_rsel, PZERO + 1);
24812115Sdyson}
24912115Sdyson
25012115Sdysonstatic void
25129888Skatotuncreate(struct cdev *dev)
25229888Skato{
25329888Skato	struct tun_softc *sc;
25429888Skato	struct ifnet *ifp;
25529888Skato
25612115Sdyson	dev->si_flags &= ~SI_CHEAPCLONE;
25729888Skato
25812115Sdyson	MALLOC(sc, struct tun_softc *, sizeof(*sc), M_TUN, M_WAITOK | M_ZERO);
25912115Sdyson	mtx_init(&sc->tun_mtx, "tun_mtx", NULL, MTX_DEF);
26012115Sdyson	sc->tun_flags = TUN_INITED;
26112115Sdyson	sc->tun_dev = dev;
26212115Sdyson	mtx_lock(&tunmtx);
26312115Sdyson	TAILQ_INSERT_TAIL(&tunhead, sc, tun_list);
26412115Sdyson	mtx_unlock(&tunmtx);
26512115Sdyson
26612115Sdyson	ifp = &sc->tun_if;
26712115Sdyson	if_initname(ifp, TUNNAME, dev2unit(dev));
26812115Sdyson	ifp->if_mtu = TUNMTU;
26912115Sdyson	ifp->if_ioctl = tunifioctl;
27012115Sdyson	ifp->if_output = tunoutput;
27112115Sdyson	ifp->if_start = tunstart;
27212115Sdyson	ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
27312115Sdyson	ifp->if_type = IFT_PPP;
27412115Sdyson	ifp->if_softc = sc;
27512115Sdyson	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
27612115Sdyson	ifp->if_snd.ifq_drv_maxlen = 0;
27712115Sdyson	IFQ_SET_READY(&ifp->if_snd);
27812115Sdyson
27912115Sdyson	if_attach(ifp);
28012115Sdyson	bpfattach(ifp, DLT_NULL, sizeof(u_int));
28112115Sdyson	dev->si_drv1 = sc;
28212115Sdyson}
28312115Sdyson
28412115Sdysonstatic int
28512115Sdysontunopen(struct cdev *dev, int flag, int mode, struct thread *td)
28612115Sdyson{
28712115Sdyson	struct ifnet	*ifp;
28812115Sdyson	struct tun_softc *tp;
28912115Sdyson
29012115Sdyson	/*
29112115Sdyson	 * XXXRW: Non-atomic test and set of dev->si_drv1 requires
29212115Sdyson	 * synchronization.
29312115Sdyson	 */
29412115Sdyson	tp = dev->si_drv1;
29512115Sdyson	if (!tp) {
29612115Sdyson		tuncreate(dev);
29712115Sdyson		tp = dev->si_drv1;
29812115Sdyson	}
29912115Sdyson
30012115Sdyson	/*
30112115Sdyson	 * XXXRW: This use of tun_pid is subject to error due to the
30212115Sdyson	 * fact that a reference to the tunnel can live beyond the
30312115Sdyson	 * death of the process that created it.  Can we replace this
30412115Sdyson	 * with a simple busy flag?
30512115Sdyson	 */
30612115Sdyson	mtx_lock(&tp->tun_mtx);
30712115Sdyson	if (tp->tun_pid != 0 && tp->tun_pid != td->td_proc->p_pid) {
30812115Sdyson		mtx_unlock(&tp->tun_mtx);
30912115Sdyson		return (EBUSY);
31012115Sdyson	}
31112115Sdyson	tp->tun_pid = td->td_proc->p_pid;
31212115Sdyson
31312115Sdyson	tp->tun_flags |= TUN_OPEN;
31412115Sdyson	mtx_unlock(&tp->tun_mtx);
31512115Sdyson	ifp = &tp->tun_if;
31612115Sdyson	TUNDEBUG(ifp, "open\n");
31712115Sdyson
31812115Sdyson	return (0);
31912115Sdyson}
32012115Sdyson
32112115Sdyson/*
32212115Sdyson * tunclose - close the device - mark i/f down & delete
32312115Sdyson * routing info
32412115Sdyson */
32512115Sdysonstatic	int
32612115Sdysontunclose(struct cdev *dev, int foo, int bar, struct thread *td)
32712115Sdyson{
32812115Sdyson	struct tun_softc *tp;
32912115Sdyson	struct ifnet *ifp;
33012115Sdyson	int s;
33112115Sdyson
33212115Sdyson	tp = dev->si_drv1;
33312115Sdyson	ifp = &tp->tun_if;
33412115Sdyson
33512115Sdyson	mtx_lock(&tp->tun_mtx);
33612115Sdyson	tp->tun_flags &= ~TUN_OPEN;
33712115Sdyson	tp->tun_pid = 0;
33812115Sdyson
33912115Sdyson	/*
34012115Sdyson	 * junk all pending output
34112115Sdyson	 */
34212115Sdyson	s = splimp();
34312115Sdyson	IFQ_PURGE(&ifp->if_snd);
34412115Sdyson	splx(s);
34512115Sdyson	mtx_unlock(&tp->tun_mtx);
34612115Sdyson
34712115Sdyson	if (ifp->if_flags & IFF_UP) {
34812115Sdyson		s = splimp();
34912115Sdyson		if_down(ifp);
35012115Sdyson		splx(s);
35112115Sdyson	}
35212115Sdyson
35312115Sdyson	if (ifp->if_flags & IFF_RUNNING) {
35412115Sdyson		struct ifaddr *ifa;
35512115Sdyson
35612115Sdyson		s = splimp();
35712115Sdyson		/* find internet addresses and delete routes */
35812115Sdyson		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
35912115Sdyson			if (ifa->ifa_addr->sa_family == AF_INET)
36012115Sdyson				/* Unlocked read. */
36112115Sdyson				rtinit(ifa, (int)RTM_DELETE,
36212115Sdyson				    tp->tun_flags & TUN_DSTADDR ? RTF_HOST : 0);
36312115Sdyson		ifp->if_flags &= ~IFF_RUNNING;
36412115Sdyson		splx(s);
36512115Sdyson	}
36612115Sdyson
36712115Sdyson	funsetown(&tp->tun_sigio);
36812115Sdyson	selwakeuppri(&tp->tun_rsel, PZERO + 1);
36912115Sdyson	TUNDEBUG (ifp, "closed\n");
37012115Sdyson	return (0);
37112115Sdyson}
37212115Sdyson
37312115Sdysonstatic int
37412115Sdysontuninit(struct ifnet *ifp)
37512115Sdyson{
37612115Sdyson	struct tun_softc *tp = ifp->if_softc;
37712115Sdyson	struct ifaddr *ifa;
37812115Sdyson	int error = 0;
37912115Sdyson
38012115Sdyson	TUNDEBUG(ifp, "tuninit\n");
38112115Sdyson
38212115Sdyson	ifp->if_flags |= IFF_UP | IFF_RUNNING;
38312115Sdyson	getmicrotime(&ifp->if_lastchange);
38412115Sdyson
38512115Sdyson	for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa;
38612115Sdyson	     ifa = TAILQ_NEXT(ifa, ifa_link)) {
38712115Sdyson		if (ifa->ifa_addr == NULL)
38812115Sdyson			error = EFAULT;
38912115Sdyson			/* XXX: Should maybe return straight off? */
39012115Sdyson		else {
39112115Sdyson#ifdef INET
39212115Sdyson			if (ifa->ifa_addr->sa_family == AF_INET) {
39312115Sdyson			    struct sockaddr_in *si;
39412115Sdyson
39512115Sdyson			    si = (struct sockaddr_in *)ifa->ifa_addr;
39612115Sdyson			    mtx_lock(&tp->tun_mtx);
39712115Sdyson			    if (si->sin_addr.s_addr)
39812115Sdyson				    tp->tun_flags |= TUN_IASET;
39912115Sdyson
40012115Sdyson			    si = (struct sockaddr_in *)ifa->ifa_dstaddr;
40112115Sdyson			    if (si && si->sin_addr.s_addr)
40212115Sdyson				    tp->tun_flags |= TUN_DSTADDR;
40312115Sdyson			    mtx_unlock(&tp->tun_mtx);
40412115Sdyson			}
40512115Sdyson#endif
40612115Sdyson		}
40712115Sdyson	}
40812115Sdyson	return (error);
40912115Sdyson}
41027881Sdyson
41127881Sdyson/*
41212115Sdyson * Process an ioctl request.
41312115Sdyson */
41412115Sdysonstatic int
41527881Sdysontunifioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
41612115Sdyson{
41712115Sdyson	struct ifreq *ifr = (struct ifreq *)data;
41812115Sdyson	struct tun_softc *tp = ifp->if_softc;
41912115Sdyson	struct ifstat *ifs;
42012115Sdyson	int		error = 0, s;
42112115Sdyson
42212115Sdyson	s = splimp();
42312115Sdyson	switch(cmd) {
42412115Sdyson	case SIOCGIFSTATUS:
42512115Sdyson		ifs = (struct ifstat *)data;
42612115Sdyson		mtx_lock(&tp->tun_mtx);
42712115Sdyson		if (tp->tun_pid)
42812115Sdyson			sprintf(ifs->ascii + strlen(ifs->ascii),
42912115Sdyson			    "\tOpened by PID %d\n", tp->tun_pid);
43012115Sdyson		mtx_unlock(&tp->tun_mtx);
43112115Sdyson		break;
43212115Sdyson	case SIOCSIFADDR:
43312115Sdyson		error = tuninit(ifp);
43412115Sdyson		TUNDEBUG(ifp, "address set, error=%d\n", error);
43512115Sdyson		break;
43612115Sdyson	case SIOCSIFDSTADDR:
43712115Sdyson		error = tuninit(ifp);
43812115Sdyson		TUNDEBUG(ifp, "destination address set, error=%d\n", error);
43912115Sdyson		break;
44012115Sdyson	case SIOCSIFMTU:
44112115Sdyson		ifp->if_mtu = ifr->ifr_mtu;
44212115Sdyson		TUNDEBUG(ifp, "mtu set\n");
44312115Sdyson		break;
44412115Sdyson	case SIOCSIFFLAGS:
44512115Sdyson	case SIOCADDMULTI:
44612911Sphk	case SIOCDELMULTI:
44712115Sdyson		break;
44812115Sdyson	default:
44912115Sdyson		error = EINVAL;
45012115Sdyson	}
45112115Sdyson	splx(s);
45212115Sdyson	return (error);
45312115Sdyson}
45412115Sdyson
45512115Sdyson/*
45612115Sdyson * tunoutput - queue packets from higher level ready to put out.
45712147Sdyson */
45812115Sdysonstatic int
45912115Sdysontunoutput(
46012115Sdyson	struct ifnet *ifp,
46112115Sdyson	struct mbuf *m0,
46212115Sdyson	struct sockaddr *dst,
46312115Sdyson	struct rtentry *rt)
46412115Sdyson{
46512115Sdyson	struct tun_softc *tp = ifp->if_softc;
46612115Sdyson	u_short cached_tun_flags;
46712115Sdyson	int error;
46812115Sdyson
46912115Sdyson	TUNDEBUG (ifp, "tunoutput\n");
47012115Sdyson
47112115Sdyson#ifdef MAC
47212115Sdyson	error = mac_check_ifnet_transmit(ifp, m0);
47312115Sdyson	if (error) {
47412115Sdyson		m_freem(m0);
47512115Sdyson		return (error);
47612115Sdyson	}
47712115Sdyson#endif
47812115Sdyson
47912115Sdyson	/* Could be unlocked read? */
48012115Sdyson	mtx_lock(&tp->tun_mtx);
48112115Sdyson	cached_tun_flags = tp->tun_flags;
48212115Sdyson	mtx_unlock(&tp->tun_mtx);
48312115Sdyson	if ((cached_tun_flags & TUN_READY) != TUN_READY) {
48412115Sdyson		TUNDEBUG (ifp, "not ready 0%o\n", tp->tun_flags);
48512115Sdyson		m_freem (m0);
48612115Sdyson		return (EHOSTDOWN);
48712115Sdyson	}
48812115Sdyson
48912115Sdyson	if ((ifp->if_flags & IFF_UP) != IFF_UP) {
49012115Sdyson		m_freem (m0);
49112115Sdyson		return (EHOSTDOWN);
49212115Sdyson	}
49312115Sdyson
49412115Sdyson	/* BPF write needs to be handled specially */
49512115Sdyson	if (dst->sa_family == AF_UNSPEC) {
49612115Sdyson		dst->sa_family = *(mtod(m0, int *));
49712115Sdyson		m0->m_len -= sizeof(int);
49812115Sdyson		m0->m_pkthdr.len -= sizeof(int);
49912115Sdyson		m0->m_data += sizeof(int);
50012115Sdyson	}
50112115Sdyson
50212115Sdyson	if (ifp->if_bpf) {
50312115Sdyson		uint32_t af = dst->sa_family;
50412115Sdyson		bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m0);
50512115Sdyson	}
50612115Sdyson
50712115Sdyson	/* prepend sockaddr? this may abort if the mbuf allocation fails */
50812115Sdyson	if (cached_tun_flags & TUN_LMODE) {
50912115Sdyson		/* allocate space for sockaddr */
51012115Sdyson		M_PREPEND(m0, dst->sa_len, M_DONTWAIT);
51122521Sdyson
51212115Sdyson		/* if allocation failed drop packet */
51312115Sdyson		if (m0 == NULL) {
51412115Sdyson			ifp->if_iqdrops++;
51512115Sdyson			ifp->if_oerrors++;
51612115Sdyson			return (ENOBUFS);
51712115Sdyson		} else {
51812115Sdyson			bcopy(dst, m0->m_data, dst->sa_len);
51912115Sdyson		}
52012115Sdyson	}
52112115Sdyson
52212115Sdyson	if (cached_tun_flags & TUN_IFHEAD) {
52312115Sdyson		/* Prepend the address family */
52412115Sdyson		M_PREPEND(m0, 4, M_DONTWAIT);
52512115Sdyson
52612115Sdyson		/* if allocation failed drop packet */
52712115Sdyson		if (m0 == NULL) {
52812115Sdyson			ifp->if_iqdrops++;
52912115Sdyson			ifp->if_oerrors++;
53012115Sdyson			return (ENOBUFS);
53112115Sdyson		} else
53212115Sdyson			*(u_int32_t *)m0->m_data = htonl(dst->sa_family);
53312115Sdyson	} else {
53412115Sdyson#ifdef INET
53512115Sdyson		if (dst->sa_family != AF_INET)
53612115Sdyson#endif
53712115Sdyson		{
53812115Sdyson			m_freem(m0);
53912911Sphk			return (EAFNOSUPPORT);
54012115Sdyson		}
54112115Sdyson	}
54212115Sdyson
54312115Sdyson	IFQ_HANDOFF(ifp, m0, error);
54412115Sdyson	if (error) {
54512115Sdyson		ifp->if_collisions++;
54612115Sdyson		return (ENOBUFS);
54712115Sdyson	}
54812115Sdyson	ifp->if_opackets++;
54912115Sdyson	return (0);
55012115Sdyson}
55112115Sdyson
55212115Sdyson/*
55312115Sdyson * the cdevsw interface is now pretty minimal.
55412115Sdyson */
55512115Sdysonstatic	int
55612115Sdysontunioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
55712115Sdyson{
55812115Sdyson	int		s;
55912115Sdyson	int		error;
56012115Sdyson	struct tun_softc *tp = dev->si_drv1;
56112115Sdyson	struct tuninfo *tunp;
56212115Sdyson
56312115Sdyson	switch (cmd) {
56412115Sdyson	case TUNSIFINFO:
56512115Sdyson		tunp = (struct tuninfo *)data;
56612115Sdyson		if (tunp->mtu < IF_MINMTU)
56712115Sdyson			return (EINVAL);
56812115Sdyson		if (tp->tun_if.if_mtu != tunp->mtu
56912115Sdyson		&& (error = suser(td)) != 0)
57012115Sdyson			return (error);
57112115Sdyson		tp->tun_if.if_mtu = tunp->mtu;
57212115Sdyson		tp->tun_if.if_type = tunp->type;
57312115Sdyson		tp->tun_if.if_baudrate = tunp->baudrate;
57412115Sdyson		break;
57512115Sdyson	case TUNGIFINFO:
57612115Sdyson		tunp = (struct tuninfo *)data;
57712115Sdyson		tunp->mtu = tp->tun_if.if_mtu;
57812115Sdyson		tunp->type = tp->tun_if.if_type;
57912115Sdyson		tunp->baudrate = tp->tun_if.if_baudrate;
58012115Sdyson		break;
58112115Sdyson	case TUNSDEBUG:
58212115Sdyson		tundebug = *(int *)data;
58312115Sdyson		break;
58412115Sdyson	case TUNGDEBUG:
58512115Sdyson		*(int *)data = tundebug;
58612115Sdyson		break;
58712115Sdyson	case TUNSLMODE:
58812115Sdyson		mtx_lock(&tp->tun_mtx);
58912115Sdyson		if (*(int *)data) {
59012115Sdyson			tp->tun_flags |= TUN_LMODE;
59112115Sdyson			tp->tun_flags &= ~TUN_IFHEAD;
59212115Sdyson		} else
59312115Sdyson			tp->tun_flags &= ~TUN_LMODE;
59412115Sdyson		mtx_unlock(&tp->tun_mtx);
59512115Sdyson		break;
59612115Sdyson	case TUNSIFHEAD:
59712115Sdyson		mtx_lock(&tp->tun_mtx);
59812115Sdyson		if (*(int *)data) {
59912115Sdyson			tp->tun_flags |= TUN_IFHEAD;
60030280Sphk			tp->tun_flags &= ~TUN_LMODE;
60130474Sphk		} else
60230474Sphk			tp->tun_flags &= ~TUN_IFHEAD;
60330492Sphk		mtx_unlock(&tp->tun_mtx);
60430474Sphk		break;
60530474Sphk	case TUNGIFHEAD:
60612115Sdyson		/* Could be unlocked read? */
60712115Sdyson		mtx_lock(&tp->tun_mtx);
60812115Sdyson		*(int *)data = (tp->tun_flags & TUN_IFHEAD) ? 1 : 0;
60912115Sdyson		mtx_unlock(&tp->tun_mtx);
61012115Sdyson		break;
61112115Sdyson	case TUNSIFMODE:
61212115Sdyson		/* deny this if UP */
61312115Sdyson		if (tp->tun_if.if_flags & IFF_UP)
61412115Sdyson			return(EBUSY);
61512115Sdyson
61612115Sdyson		switch (*(int *)data & ~IFF_MULTICAST) {
61712115Sdyson		case IFF_POINTOPOINT:
61812115Sdyson		case IFF_BROADCAST:
61912115Sdyson			tp->tun_if.if_flags &=
62012115Sdyson			    ~(IFF_BROADCAST|IFF_POINTOPOINT|IFF_MULTICAST);
62112115Sdyson			tp->tun_if.if_flags |= *(int *)data;
62212115Sdyson			break;
62312115Sdyson		default:
62412115Sdyson			return(EINVAL);
62512115Sdyson		}
62612115Sdyson		break;
62712115Sdyson	case TUNSIFPID:
62812115Sdyson		mtx_lock(&tp->tun_mtx);
62912115Sdyson		tp->tun_pid = curthread->td_proc->p_pid;
63012115Sdyson		mtx_unlock(&tp->tun_mtx);
63112115Sdyson		break;
63212115Sdyson	case FIONBIO:
63312115Sdyson		break;
63412115Sdyson	case FIOASYNC:
63512115Sdyson		mtx_lock(&tp->tun_mtx);
63612115Sdyson		if (*(int *)data)
63712115Sdyson			tp->tun_flags |= TUN_ASYNC;
63812115Sdyson		else
63912115Sdyson			tp->tun_flags &= ~TUN_ASYNC;
64012115Sdyson		mtx_unlock(&tp->tun_mtx);
64112115Sdyson		break;
64212115Sdyson	case FIONREAD:
64312115Sdyson		s = splimp();
64412115Sdyson		if (!IFQ_IS_EMPTY(&tp->tun_if.if_snd)) {
64512115Sdyson			struct mbuf *mb;
64612115Sdyson			IFQ_LOCK(&tp->tun_if.if_snd);
64712115Sdyson			IFQ_POLL_NOLOCK(&tp->tun_if.if_snd, mb);
64812115Sdyson			for( *(int *)data = 0; mb != 0; mb = mb->m_next)
64912115Sdyson				*(int *)data += mb->m_len;
65012115Sdyson			IFQ_UNLOCK(&tp->tun_if.if_snd);
65112115Sdyson		} else
65212115Sdyson			*(int *)data = 0;
65312115Sdyson		splx(s);
65412115Sdyson		break;
65512115Sdyson	case FIOSETOWN:
65612115Sdyson		return (fsetown(*(int *)data, &tp->tun_sigio));
65712115Sdyson
65812115Sdyson	case FIOGETOWN:
65912115Sdyson		*(int *)data = fgetown(&tp->tun_sigio);
66012115Sdyson		return (0);
66112115Sdyson
66212115Sdyson	/* This is deprecated, FIOSETOWN should be used instead. */
66312115Sdyson	case TIOCSPGRP:
66412115Sdyson		return (fsetown(-(*(int *)data), &tp->tun_sigio));
66512115Sdyson
66612115Sdyson	/* This is deprecated, FIOGETOWN should be used instead. */
66712115Sdyson	case TIOCGPGRP:
66812115Sdyson		*(int *)data = -fgetown(&tp->tun_sigio);
66912911Sphk		return (0);
67012115Sdyson
67112115Sdyson	default:
67212115Sdyson		return (ENOTTY);
67312115Sdyson	}
67412115Sdyson	return (0);
67512115Sdyson}
67612115Sdyson
67712115Sdyson/*
67812115Sdyson * The cdevsw read interface - reads a packet at a time, or at
67912115Sdyson * least as much of a packet as can be read.
68012115Sdyson */
68112115Sdysonstatic	int
68212115Sdysontunread(struct cdev *dev, struct uio *uio, int flag)
68312115Sdyson{
68412115Sdyson	struct tun_softc *tp = dev->si_drv1;
68512115Sdyson	struct ifnet	*ifp = &tp->tun_if;
68612115Sdyson	struct mbuf	*m;
68712115Sdyson	int		error=0, len, s;
68812115Sdyson
68912115Sdyson	TUNDEBUG (ifp, "read\n");
69012115Sdyson	mtx_lock(&tp->tun_mtx);
69112115Sdyson	if ((tp->tun_flags & TUN_READY) != TUN_READY) {
69212115Sdyson		mtx_unlock(&tp->tun_mtx);
69312115Sdyson		TUNDEBUG (ifp, "not ready 0%o\n", tp->tun_flags);
69427881Sdyson		return (EHOSTDOWN);
69512115Sdyson	}
69612115Sdyson
69727881Sdyson	tp->tun_flags &= ~TUN_RWAIT;
69827881Sdyson	mtx_unlock(&tp->tun_mtx);
69912115Sdyson
70012115Sdyson	s = splimp();
70112115Sdyson	do {
70227881Sdyson		IFQ_DEQUEUE(&ifp->if_snd, m);
70327881Sdyson		if (m == NULL) {
70412115Sdyson			if (flag & IO_NDELAY) {
70512115Sdyson				splx(s);
70627881Sdyson				return (EWOULDBLOCK);
70712115Sdyson			}
70812115Sdyson			mtx_lock(&tp->tun_mtx);
70912115Sdyson			tp->tun_flags |= TUN_RWAIT;
71012115Sdyson			mtx_unlock(&tp->tun_mtx);
71112115Sdyson			if((error = tsleep(tp, PCATCH | (PZERO + 1),
71212115Sdyson					"tunread", 0)) != 0) {
71312115Sdyson				splx(s);
71412115Sdyson				return (error);
71512115Sdyson			}
71612115Sdyson		}
71712115Sdyson	} while (m == NULL);
71812115Sdyson	splx(s);
71912115Sdyson
72012115Sdyson	while (m && uio->uio_resid > 0 && error == 0) {
72112115Sdyson		len = min(uio->uio_resid, m->m_len);
72212115Sdyson		if (len != 0)
72312911Sphk			error = uiomove(mtod(m, void *), len, uio);
72412115Sdyson		m = m_free(m);
72512115Sdyson	}
72612115Sdyson
72712115Sdyson	if (m) {
72812115Sdyson		TUNDEBUG(ifp, "Dropping mbuf\n");
72912115Sdyson		m_freem(m);
73012147Sdyson	}
73112746Sbde	return (error);
73212746Sbde}
73312746Sbde
73412115Sdyson/*
73512115Sdyson * the cdevsw write interface - an atomic write is a packet - or else!
73612115Sdyson */
73712115Sdysonstatic	int
73812115Sdysontunwrite(struct cdev *dev, struct uio *uio, int flag)
73912115Sdyson{
74012115Sdyson	struct tun_softc *tp = dev->si_drv1;
74112115Sdyson	struct ifnet	*ifp = &tp->tun_if;
74212115Sdyson	struct mbuf	*m;
74312115Sdyson	int		error = 0;
74412115Sdyson	uint32_t	family;
74512115Sdyson	int 		isr;
74612115Sdyson
74712115Sdyson	TUNDEBUG(ifp, "tunwrite\n");
74812115Sdyson
74912115Sdyson	if ((ifp->if_flags & IFF_UP) != IFF_UP)
75012115Sdyson		/* ignore silently */
75112115Sdyson		return (0);
75212115Sdyson
75312115Sdyson	if (uio->uio_resid == 0)
75412115Sdyson		return (0);
75512115Sdyson
75612115Sdyson	if (uio->uio_resid < 0 || uio->uio_resid > TUNMRU) {
75712115Sdyson		TUNDEBUG(ifp, "len=%d!\n", uio->uio_resid);
75812115Sdyson		return (EIO);
75912911Sphk	}
76012115Sdyson
76112115Sdyson	if ((m = m_uiotombuf(uio, M_DONTWAIT, 0)) == NULL) {
76212115Sdyson		ifp->if_ierrors++;
76312115Sdyson		return (error);
76412115Sdyson	}
76512115Sdyson
76612115Sdyson	m->m_pkthdr.rcvif = ifp;
76712115Sdyson#ifdef MAC
76812115Sdyson	mac_create_mbuf_from_ifnet(ifp, m);
76912115Sdyson#endif
77012115Sdyson
77112115Sdyson	/* Could be unlocked read? */
77212115Sdyson	mtx_lock(&tp->tun_mtx);
77312115Sdyson	if (tp->tun_flags & TUN_IFHEAD) {
77412115Sdyson		mtx_unlock(&tp->tun_mtx);
77512115Sdyson		if (m->m_len < sizeof(family) &&
77612115Sdyson		    (m = m_pullup(m, sizeof(family))) == NULL)
77712115Sdyson			return (ENOBUFS);
77812115Sdyson		family = ntohl(*mtod(m, u_int32_t *));
77912115Sdyson		m_adj(m, sizeof(family));
78012115Sdyson	} else {
78112115Sdyson		mtx_unlock(&tp->tun_mtx);
78212115Sdyson		family = AF_INET;
78312115Sdyson	}
78412115Sdyson
78512115Sdyson	BPF_MTAP2(ifp, &family, sizeof(family), m);
78612115Sdyson
78712115Sdyson	switch (family) {
78812115Sdyson#ifdef INET
78912115Sdyson	case AF_INET:
79012115Sdyson		isr = NETISR_IP;
79112115Sdyson		break;
79212115Sdyson#endif
79312115Sdyson#ifdef INET6
79412115Sdyson	case AF_INET6:
79512115Sdyson		isr = NETISR_IPV6;
79612115Sdyson		break;
79712115Sdyson#endif
79812115Sdyson#ifdef IPX
79912115Sdyson	case AF_IPX:
80012115Sdyson		isr = NETISR_IPX;
80112115Sdyson		break;
80212115Sdyson#endif
80312115Sdyson#ifdef NETATALK
80412115Sdyson	case AF_APPLETALK:
80512115Sdyson		isr = NETISR_ATALK2;
80612115Sdyson		break;
80712115Sdyson#endif
80812115Sdyson	default:
80912115Sdyson		m_freem(m);
81012115Sdyson		return (EAFNOSUPPORT);
81112115Sdyson	}
81212115Sdyson	/* First chunk of an mbuf contains good junk */
81312115Sdyson	if (harvest.point_to_point)
81412911Sphk		random_harvest(m, 16, 3, 0, RANDOM_NET);
81512115Sdyson	ifp->if_ibytes += m->m_pkthdr.len;
81612115Sdyson	ifp->if_ipackets++;
81712115Sdyson	netisr_dispatch(isr, m);
81812115Sdyson	return (0);
81912115Sdyson}
82012115Sdyson
82112115Sdyson/*
82212115Sdyson * tunpoll - the poll interface, this is only useful on reads
82312115Sdyson * really. The write detect always returns true, write never blocks
82412115Sdyson * anyway, it either accepts the packet or drops it.
82512115Sdyson */
82612115Sdysonstatic	int
82712115Sdysontunpoll(struct cdev *dev, int events, struct thread *td)
82812115Sdyson{
82912115Sdyson	int		s;
83012115Sdyson	struct tun_softc *tp = dev->si_drv1;
83112115Sdyson	struct ifnet	*ifp = &tp->tun_if;
83212115Sdyson	int		revents = 0;
83312115Sdyson	struct mbuf	*m;
83412115Sdyson
83512115Sdyson	s = splimp();
83612115Sdyson	TUNDEBUG(ifp, "tunpoll\n");
83712115Sdyson
83812115Sdyson	if (events & (POLLIN | POLLRDNORM)) {
83912115Sdyson		IFQ_LOCK(&ifp->if_snd);
84012115Sdyson		IFQ_POLL_NOLOCK(&ifp->if_snd, m);
84112115Sdyson		if (m != NULL) {
84212115Sdyson			TUNDEBUG(ifp, "tunpoll q=%d\n", ifp->if_snd.ifq_len);
84312115Sdyson			revents |= events & (POLLIN | POLLRDNORM);
84412115Sdyson		} else {
84512115Sdyson			TUNDEBUG(ifp, "tunpoll waiting\n");
84612115Sdyson			selrecord(td, &tp->tun_rsel);
84712115Sdyson		}
84812115Sdyson		IFQ_UNLOCK(&ifp->if_snd);
84912115Sdyson	}
85012115Sdyson	if (events & (POLLOUT | POLLWRNORM))
85112115Sdyson		revents |= events & (POLLOUT | POLLWRNORM);
85212115Sdyson
85312115Sdyson	splx(s);
85412115Sdyson	return (revents);
85512115Sdyson}
85612115Sdyson