if_tun.c revision 121778
1133251Simp/*	$NetBSD: if_tun.c,v 1.14 1994/06/29 06:36:25 cgd Exp $	*/
241967Sdillon
3133251Simp/*
4133251Simp * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk>
5133251Simp * Nottingham University 1987.
6133251Simp *
7133251Simp * This source may be freely distributed, however I would be interested
8133251Simp * in any changes that are made.
9133251Simp *
10133251Simp * This driver takes packets off the IP i/f and hands them up to a
11133251Simp * user process to have its wicked way with. This driver has it's
12133251Simp * roots in a similar driver written by Phil Cockcroft (formerly) at
13133251Simp * UCL. This driver is based much more on read/write/poll mode of
14133251Simp * operation though.
15133251Simp *
16133251Simp * $FreeBSD: head/sys/net/if_tun.c 121778 2003-10-31 02:48:12Z brooks $
17133251Simp */
18133251Simp
19133251Simp#include "opt_atalk.h"
20133251Simp#include "opt_inet.h"
21133251Simp#include "opt_inet6.h"
22133251Simp#include "opt_ipx.h"
23133251Simp#include "opt_mac.h"
2450476Speter
2541967Sdillon#include <sys/param.h>
26260084Spluknet#include <sys/proc.h>
2741967Sdillon#include <sys/systm.h>
2879538Sru#include <sys/mac.h>
2941967Sdillon#include <sys/mbuf.h>
3041967Sdillon#include <sys/module.h>
31158489Skeramida#include <sys/socket.h>
3241967Sdillon#include <sys/filio.h>
3341967Sdillon#include <sys/sockio.h>
3441967Sdillon#include <sys/ttycom.h>
3541967Sdillon#include <sys/poll.h>
3651372Sdillon#include <sys/signalvar.h>
3790814Srwatson#include <sys/filedesc.h>
38130524Sru#include <sys/kernel.h>
3944389Sghelmer#include <sys/sysctl.h>
40130524Sru#include <sys/conf.h>
41130524Sru#include <sys/uio.h>
4241967Sdillon#include <sys/vnode.h>
4379727Sschweikh#include <sys/malloc.h>
4444389Sghelmer#include <machine/bus.h>	/* XXX Shouldn't really be required ! */
4544389Sghelmer#include <sys/random.h>
4642062Sobrien#include <sys/rman.h>
47130524Sru
48130524Sru#include <net/if.h>
49130524Sru#include <net/if_types.h>
5041967Sdillon#include <net/netisr.h>
5141967Sdillon#include <net/route.h>
5241967Sdillon#ifdef INET
53130524Sru#include <netinet/in.h>
54130524Sru#endif
5551372Sdillon#include <net/bpf.h>
56130524Sru#include <net/if_tunvar.h>
5751372Sdillon#include <net/if_tun.h>
58130524Sru
5951372Sdillon#define TUNDEBUG	if (tundebug) if_printf
60130524Sru#define	TUNNAME		"tun"
61130524Sru
6251372Sdillonstatic MALLOC_DEFINE(M_TUN, TUNNAME, "Tunnel Interface");
6341967Sdillonstatic int tundebug = 0;
6441967Sdillonstatic struct tun_softc *tunhead = NULL;
65130524Srustatic struct rman tununits;
6641967Sdillonstatic udev_t tunbasedev = NOUDEV;
6741967SdillonSYSCTL_INT(_debug, OID_AUTO, if_tun_debug, CTLFLAG_RW, &tundebug, 0, "");
6841967Sdillon
6942062Sobrienstatic void	tunclone(void *arg, char *name, int namelen, dev_t *dev);
7041967Sdillonstatic void	tuncreate(dev_t dev);
7142062Sobrienstatic int	tunifioctl(struct ifnet *, u_long, caddr_t);
7251372Sdillonstatic int	tuninit(struct ifnet *);
7351372Sdillonstatic int	tunmodevent(module_t, int, void *);
7441967Sdillonstatic int	tunoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
7541967Sdillon		    struct rtentry *rt);
7641967Sdillonstatic void	tunstart(struct ifnet *);
77130524Sru
78130524Srustatic d_open_t		tunopen;
7941967Sdillonstatic d_close_t	tunclose;
80130524Srustatic d_read_t		tunread;
81130524Srustatic d_write_t	tunwrite;
82130524Srustatic d_ioctl_t	tunioctl;
83130524Srustatic d_poll_t		tunpoll;
84130524Sru
85130524Sru#define CDEV_MAJOR 52
8651372Sdillonstatic struct cdevsw tun_cdevsw = {
87130524Sru	.d_open =	tunopen,
88130524Sru	.d_close =	tunclose,
89130524Sru	.d_read =	tunread,
9089127Smpp	.d_write =	tunwrite,
91201539Sbrueffer	.d_ioctl =	tunioctl,
9251372Sdillon	.d_poll =	tunpoll,
9341967Sdillon	.d_name =	TUNNAME,
94130524Sru	.d_maj =	CDEV_MAJOR,
95130524Sru};
96130524Sru
97130524Srustatic void
98130524Srutunclone(void *arg, char *name, int namelen, dev_t *dev)
99130524Sru{
100130524Sru	struct resource *r;
101130524Sru	int err;
102130524Sru	int u;
103130524Sru
104130524Sru	if (*dev != NODEV)
105130524Sru		return;
10641967Sdillon
107130524Sru	if (strcmp(name, TUNNAME) == 0) {
108130524Sru		r = rman_reserve_resource(&tununits, 0, IF_MAXUNIT, 1,
109130524Sru		    RF_ALLOCATED | RF_ACTIVE, NULL);
11051372Sdillon		u = rman_get_start(r);
11141967Sdillon		err = rman_release_resource(r);
11241967Sdillon		KASSERT(err == 0, ("Unexpected failure releasing resource"));
11341967Sdillon		*dev = makedev(CDEV_MAJOR, unit2minor(u));
114130524Sru		if ((*dev)->si_flags & SI_NAMED)
115130524Sru			return;	/* Already make_dev()d */
11641967Sdillon	} else if (dev_stdclone(name, NULL, TUNNAME, &u) != 1)
117130524Sru		return;	/* Don't recognise the name */
118130524Sru
11941967Sdillon	*dev = make_dev(&tun_cdevsw, unit2minor(u),
12086875Sdd	    UID_ROOT, GID_WHEEL, 0600, "tun%d", u);
12151372Sdillon
12289127Smpp	/*
12341967Sdillon	 * All devices depend on tunbasedev so that we can simply
12479727Sschweikh	 * destroy_dev() this device at module unload time to get
125130524Sru	 * rid of all our make_dev()d resources.
126130524Sru	 */
12751372Sdillon	if (tunbasedev == NOUDEV)
12841967Sdillon		tunbasedev = (*dev)->si_udev;
129130524Sru	else {
13079727Sschweikh		(*dev)->si_flags |= SI_CHEAPCLONE;
131130524Sru		dev_depends(udev2dev(tunbasedev, 0), *dev);
132130524Sru	}
13360258Ssheldonh}
13451372Sdillon
135130524Srustatic int
136130524Srutunmodevent(module_t mod, int type, void *data)
137130524Sru{
138130524Sru	static eventhandler_tag tag;
139129397Sdannyboy	struct tun_softc *tp;
140129400Sdannyboy	dev_t dev;
141219126Sbrucec	int err;
14241967Sdillon
14351372Sdillon	switch (type) {
144130524Sru	case MOD_LOAD:
14541967Sdillon		tag = EVENTHANDLER_REGISTER(dev_clone, tunclone, 0, 1000);
14641967Sdillon		if (tag == NULL)
14741967Sdillon			return (ENOMEM);
14841967Sdillon		tununits.rm_type = RMAN_ARRAY;
14941967Sdillon		tununits.rm_descr = "open if_tun units";
150130524Sru		err = rman_init(&tununits);
15141967Sdillon		if (err != 0) {
15241967Sdillon			EVENTHANDLER_DEREGISTER(dev_clone, tag);
15341967Sdillon			return (err);
15479727Sschweikh		}
15541967Sdillon		err = rman_manage_region(&tununits, 0, IF_MAXUNIT);
156107788Sru		if (err != 0) {
15741967Sdillon			printf("%s: tununits: rman_manage_region: Failed %d\n",
15851372Sdillon			    TUNNAME, err);
15941967Sdillon			rman_fini(&tununits);
16041967Sdillon			EVENTHANDLER_DEREGISTER(dev_clone, tag);
16141967Sdillon			return (err);
16241967Sdillon		}
163130524Sru		break;
164130524Sru	case MOD_UNLOAD:
165130524Sru		err = rman_fini(&tununits);
166130524Sru		if (err != 0)
16744389Sghelmer			return (err);
168130524Sru		EVENTHANDLER_DEREGISTER(dev_clone, tag);
169130524Sru
170130524Sru		while (tunhead != NULL) {
171130524Sru			KASSERT((tunhead->tun_flags & TUN_OPEN) == 0,
17251372Sdillon			    ("tununits is out of sync - unit %d",
17351372Sdillon			    tunhead->tun_if.if_unit));
17451372Sdillon			tp = tunhead;
17551372Sdillon			dev = makedev(tun_cdevsw.d_maj,
176130524Sru			    unit2minor(tp->tun_if.if_unit));
177130524Sru			KASSERT(dev->si_drv1 == tp, ("Bad makedev result"));
178201736Sdanger			tunhead = tp->next;
17979727Sschweikh			bpfdetach(&tp->tun_if);
180130524Sru			if_detach(&tp->tun_if);
18151372Sdillon			KASSERT(dev->si_flags & SI_NAMED, ("Missing make_dev"));
182130524Sru			free(tp, M_TUN);
183130524Sru		}
184130524Sru
185130524Sru		/*
186130524Sru		 * Destroying tunbasedev results in all of our make_dev()s
187130524Sru		 * conveniently going away.
188130524Sru		 */
189130524Sru		if (tunbasedev != NOUDEV)
190130524Sru			destroy_dev(udev2dev(tunbasedev, 0));
191130524Sru
192130524Sru		break;
193130524Sru	}
194130524Sru	return 0;
195130524Sru}
19651372Sdillon
19741967Sdillonstatic moduledata_t tun_mod = {
19842015Sdillon	"if_tun",
199130524Sru	tunmodevent,
200130524Sru	0
201130524Sru};
202130524Sru
203130524SruDECLARE_MODULE(if_tun, tun_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
204130524Sru
205130524Srustatic void
20681251Srutunstart(struct ifnet *ifp)
207130524Sru{
208130524Sru	struct tun_softc *tp = ifp->if_softc;
209130524Sru
210130524Sru	if (tp->tun_flags & TUN_RWAIT) {
211130524Sru		tp->tun_flags &= ~TUN_RWAIT;
212130524Sru		wakeup(tp);
213130524Sru	}
214130524Sru	if (tp->tun_flags & TUN_ASYNC && tp->tun_sigio)
215130524Sru		pgsigio(&tp->tun_sigio, SIGIO, 0);
216130524Sru	selwakeup(&tp->tun_rsel);
217130524Sru}
218130524Sru
219130524Srustatic void
220130524Srutuncreate(dev_t dev)
221130524Sru{
222130524Sru	struct tun_softc *sc;
223130524Sru	struct ifnet *ifp;
224130524Sru
225130524Sru	if (!(dev->si_flags & SI_NAMED))
226130524Sru		dev = make_dev(&tun_cdevsw, minor(dev),
227130524Sru		    UID_UUCP, GID_DIALER, 0600, "tun%d", dev2unit(dev));
228130524Sru
229130524Sru	MALLOC(sc, struct tun_softc *, sizeof(*sc), M_TUN, M_WAITOK | M_ZERO);
230130524Sru	sc->tun_flags = TUN_INITED;
231130524Sru	sc->next = tunhead;
23251372Sdillon	tunhead = sc;
23351372Sdillon
234130524Sru	ifp = &sc->tun_if;
235130524Sru	ifp->if_unit = dev2unit(dev);
236130524Sru	ifp->if_name = TUNNAME;
237130524Sru	ifp->if_mtu = TUNMTU;
238130524Sru	ifp->if_ioctl = tunifioctl;
239130524Sru	ifp->if_output = tunoutput;
240130524Sru	ifp->if_start = tunstart;
24151372Sdillon	ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
242130524Sru	ifp->if_type = IFT_PPP;
243130524Sru	ifp->if_snd.ifq_maxlen = ifqmaxlen;
244130524Sru	ifp->if_softc = sc;
245130524Sru	if_attach(ifp);
246130524Sru	bpfattach(ifp, DLT_NULL, sizeof(u_int));
24751372Sdillon	dev->si_drv1 = sc;
24841967Sdillon}
24941967Sdillon
25041967Sdillonstatic int
251130524Srutunopen(dev_t dev, int flag, int mode, struct thread *td)
252130524Sru{
253129397Sdannyboy	struct resource *r;
254129397Sdannyboy	struct ifnet	*ifp;
255130524Sru	struct tun_softc *tp;
256130524Sru	int unit;
25779727Sschweikh
258140573Sru	unit = dev2unit(dev);
25944389Sghelmer	if (unit > IF_MAXUNIT)
26044389Sghelmer		return (ENXIO);
26144389Sghelmer
262130524Sru	r = rman_reserve_resource(&tununits, unit, unit, 1,
263130524Sru	    RF_ALLOCATED | RF_ACTIVE, NULL);
264130524Sru	if (r == NULL)
265130524Sru		return (EBUSY);
266130524Sru
267130524Sru	dev->si_flags &= ~SI_CHEAPCLONE;
26881251Sru
26944389Sghelmer	tp = dev->si_drv1;
27079727Sschweikh	if (!tp) {
27144389Sghelmer		tuncreate(dev);
27244389Sghelmer		tp = dev->si_drv1;
27344389Sghelmer	}
27442062Sobrien	KASSERT(!(tp->tun_flags & TUN_OPEN), ("Resource & flags out-of-sync"));
275130524Sru	tp->tun_unit = r;
276130524Sru	tp->tun_pid = td->td_proc->p_pid;
27741967Sdillon	ifp = &tp->tun_if;
278130524Sru	tp->tun_flags |= TUN_OPEN;
27941967Sdillon	TUNDEBUG(ifp, "open\n");
28041967Sdillon
28141967Sdillon	return (0);
282130524Sru}
283130524Sru
284130524Sru/*
285130524Sru * tunclose - close the device - mark i/f down & delete
286130524Sru * routing info
28779727Sschweikh */
28844389Sghelmerstatic	int
28944389Sghelmertunclose(dev_t dev, int foo, int bar, struct thread *td)
290130524Sru{
29141967Sdillon	struct tun_softc *tp;
29242062Sobrien	struct ifnet *ifp;
29342015Sdillon	int s;
29441967Sdillon	int err;
29541967Sdillon
296130524Sru	tp = dev->si_drv1;
29741967Sdillon	ifp = &tp->tun_if;
298130524Sru
299130524Sru	KASSERT(tp->tun_unit, ("Unit %d not marked open", ifp->if_unit));
30079727Sschweikh	tp->tun_flags &= ~TUN_OPEN;
301130524Sru	tp->tun_pid = 0;
302130524Sru
303130524Sru	/*
304130524Sru	 * junk all pending output
305130524Sru	 */
30644389Sghelmer	IF_DRAIN(&ifp->if_snd);
30781251Sru
308130524Sru	if (ifp->if_flags & IFF_UP) {
309130524Sru		s = splimp();
310130524Sru		if_down(ifp);
311130524Sru		splx(s);
312130524Sru	}
313130524Sru
314130524Sru	if (ifp->if_flags & IFF_RUNNING) {
315148011Sbrueffer		struct ifaddr *ifa;
316130524Sru
317130524Sru		s = splimp();
318130524Sru		/* find internet addresses and delete routes */
319130524Sru		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
320130524Sru			if (ifa->ifa_addr->sa_family == AF_INET)
321130524Sru				rtinit(ifa, (int)RTM_DELETE,
322130524Sru				    tp->tun_flags & TUN_DSTADDR ? RTF_HOST : 0);
323130524Sru		ifp->if_flags &= ~IFF_RUNNING;
324130524Sru		splx(s);
325130524Sru	}
326130524Sru
327130524Sru	funsetown(&tp->tun_sigio);
328130524Sru	selwakeup(&tp->tun_rsel);
329130524Sru
330130524Sru	TUNDEBUG (ifp, "closed\n");
33141967Sdillon	err = rman_release_resource(tp->tun_unit);
332130524Sru	KASSERT(err == 0, ("Unit %d failed to release", ifp->if_unit));
333130524Sru
334130524Sru	return (0);
335130524Sru}
33641967Sdillon
337130524Srustatic int
338130524Srutuninit(struct ifnet *ifp)
339130524Sru{
340130524Sru	struct tun_softc *tp = ifp->if_softc;
341130524Sru	struct ifaddr *ifa;
342130524Sru	int error = 0;
343130524Sru
344130524Sru	TUNDEBUG(ifp, "tuninit\n");
34541967Sdillon
34650911Sphantom	ifp->if_flags |= IFF_UP | IFF_RUNNING;
347130524Sru	getmicrotime(&ifp->if_lastchange);
348130524Sru
349130524Sru	for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa;
350130524Sru	     ifa = TAILQ_NEXT(ifa, ifa_link)) {
351130524Sru		if (ifa->ifa_addr == NULL)
352130524Sru			error = EFAULT;
353130524Sru			/* XXX: Should maybe return straight off? */
35441967Sdillon		else {
355130524Sru#ifdef INET
356130524Sru			if (ifa->ifa_addr->sa_family == AF_INET) {
35742015Sdillon			    struct sockaddr_in *si;
35841967Sdillon
35941967Sdillon			    si = (struct sockaddr_in *)ifa->ifa_addr;
360130524Sru			    if (si->sin_addr.s_addr)
361130524Sru				    tp->tun_flags |= TUN_IASET;
362130524Sru
363130524Sru			    si = (struct sockaddr_in *)ifa->ifa_dstaddr;
364130524Sru			    if (si && si->sin_addr.s_addr)
365130524Sru				    tp->tun_flags |= TUN_DSTADDR;
366148140Sschweikh			}
36744389Sghelmer#endif
36881251Sru		}
36944389Sghelmer	}
37042062Sobrien	return (error);
37141967Sdillon}
37241967Sdillon
373130524Sru/*
374130524Sru * Process an ioctl request.
375130524Sru */
376130524Srustatic int
37744389Sghelmertunifioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
378130524Sru{
37944389Sghelmer	struct ifreq *ifr = (struct ifreq *)data;
38044389Sghelmer	struct tun_softc *tp = ifp->if_softc;
38144389Sghelmer	struct ifstat *ifs;
382130524Sru	int		error = 0, s;
383130524Sru
384130524Sru	s = splimp();
385130524Sru	switch(cmd) {
386148011Sbrueffer	case SIOCGIFSTATUS:
387130524Sru		ifs = (struct ifstat *)data;
38844389Sghelmer		if (tp->tun_pid)
389130524Sru			sprintf(ifs->ascii + strlen(ifs->ascii),
39041967Sdillon			    "\tOpened by PID %d\n", tp->tun_pid);
39144389Sghelmer		break;
392130524Sru	case SIOCSIFADDR:
393130524Sru		error = tuninit(ifp);
394130524Sru		TUNDEBUG(ifp, "address set, error=%d\n", error);
395130524Sru		break;
396130524Sru	case SIOCSIFDSTADDR:
397130524Sru		error = tuninit(ifp);
398130524Sru		TUNDEBUG(ifp, "destination address set, error=%d\n", error);
39944389Sghelmer		break;
40044389Sghelmer	case SIOCSIFMTU:
40144389Sghelmer		ifp->if_mtu = ifr->ifr_mtu;
402130524Sru		TUNDEBUG(ifp, "mtu set\n");
403130524Sru		break;
404130524Sru	case SIOCSIFFLAGS:
405130524Sru	case SIOCADDMULTI:
406130524Sru	case SIOCDELMULTI:
407130524Sru		break;
408130524Sru	default:
409130524Sru		error = EINVAL;
410130524Sru	}
411130524Sru	splx(s);
412130524Sru	return (error);
41351372Sdillon}
41479727Sschweikh
41579727Sschweikh/*
41641967Sdillon * tunoutput - queue packets from higher level ready to put out.
41741967Sdillon */
41841967Sdillonstatic int
419130524Srutunoutput(
420130524Sru	struct ifnet *ifp,
421130524Sru	struct mbuf *m0,
422130524Sru	struct sockaddr *dst,
423130524Sru	struct rtentry *rt)
42441967Sdillon{
425130524Sru	struct tun_softc *tp = ifp->if_softc;
426130524Sru#ifdef MAC
427130524Sru	int error;
428130524Sru#endif
42979727Sschweikh
43051372Sdillon	TUNDEBUG (ifp, "tunoutput\n");
43151372Sdillon
43241967Sdillon#ifdef MAC
43379727Sschweikh	error = mac_check_ifnet_transmit(ifp, m0);
434130524Sru	if (error) {
435130524Sru		m_freem(m0);
43644389Sghelmer		return (error);
43744389Sghelmer	}
43844389Sghelmer#endif
43979727Sschweikh
44041967Sdillon	if ((tp->tun_flags & TUN_READY) != TUN_READY) {
44141967Sdillon		TUNDEBUG (ifp, "not ready 0%o\n", tp->tun_flags);
44279727Sschweikh		m_freem (m0);
44344389Sghelmer		return (EHOSTDOWN);
44481251Sru	}
445130524Sru
44681251Sru	if ((ifp->if_flags & IFF_UP) != IFF_UP) {
447107788Sru		m_freem (m0);
44841967Sdillon		return (EHOSTDOWN);
449130524Sru	}
450130524Sru
451130524Sru	/* BPF write needs to be handled specially */
45250911Sphantom	if (dst->sa_family == AF_UNSPEC) {
45344389Sghelmer		dst->sa_family = *(mtod(m0, int *));
45444389Sghelmer		m0->m_len -= sizeof(int);
455130524Sru		m0->m_pkthdr.len -= sizeof(int);
456130524Sru		m0->m_data += sizeof(int);
457130524Sru	}
458130524Sru
459130524Sru	if (ifp->if_bpf) {
460130524Sru		/*
461130524Sru		 * We need to prepend the address family as
462130524Sru		 * a four byte field.  Cons up a dummy header
46341967Sdillon		 * to pacify bpf.  This is safe because bpf
464130524Sru		 * will only read from the mbuf (i.e., it won't
465130524Sru		 * try to free it or keep a pointer to it).
466130524Sru		 */
46744389Sghelmer		struct mbuf m;
46844389Sghelmer		uint32_t af = dst->sa_family;
46944389Sghelmer
470130524Sru		m.m_next = m0;
471130524Sru		m.m_len = 4;
47251372Sdillon		m.m_data = (char *)&af;
47351372Sdillon
47444389Sghelmer		BPF_MTAP(ifp, &m);
47579727Sschweikh	}
476130524Sru
477130524Sru	/* prepend sockaddr? this may abort if the mbuf allocation fails */
478130524Sru	if (tp->tun_flags & TUN_LMODE) {
47944389Sghelmer		/* allocate space for sockaddr */
480149766Sgarys		M_PREPEND(m0, dst->sa_len, M_DONTWAIT);
481149766Sgarys
482130524Sru		/* if allocation failed drop packet */
483130524Sru		if (m0 == NULL) {
484130524Sru			ifp->if_iqdrops++;
485130524Sru			ifp->if_oerrors++;
486130524Sru			return (ENOBUFS);
487149766Sgarys		} else {
488130524Sru			bcopy(dst, m0->m_data, dst->sa_len);
489130524Sru		}
490130524Sru	}
491130524Sru
492130524Sru	if (tp->tun_flags & TUN_IFHEAD) {
493130524Sru		/* Prepend the address family */
49444389Sghelmer		M_PREPEND(m0, 4, M_DONTWAIT);
495130524Sru
49644389Sghelmer		/* if allocation failed drop packet */
497149766Sgarys		if (m0 == NULL) {
498149766Sgarys			ifp->if_iqdrops++;
499130524Sru			ifp->if_oerrors++;
500149766Sgarys			return (ENOBUFS);
501130524Sru		} else
502149766Sgarys			*(u_int32_t *)m0->m_data = htonl(dst->sa_family);
503130524Sru	} else {
504130524Sru#ifdef INET
505130524Sru		if (dst->sa_family != AF_INET)
506130524Sru#endif
507130524Sru		{
508130524Sru			m_freem(m0);
509130524Sru			return (EAFNOSUPPORT);
510130524Sru		}
511130524Sru	}
512130524Sru
51351372Sdillon	if (! IF_HANDOFF(&ifp->if_snd, m0, ifp)) {
51451372Sdillon		ifp->if_collisions++;
515149766Sgarys		return (ENOBUFS);
516149766Sgarys	}
517149766Sgarys	ifp->if_opackets++;
518149766Sgarys	return (0);
519149766Sgarys}
520149766Sgarys
521149766Sgarys/*
522149766Sgarys * the cdevsw interface is now pretty minimal.
523149766Sgarys */
524149766Sgarysstatic	int
525149766Sgarystunioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
526149766Sgarys{
527149766Sgarys	int		s;
528149766Sgarys	int		error;
529149766Sgarys	struct tun_softc *tp = dev->si_drv1;
530149766Sgarys	struct tuninfo *tunp;
531160306Skeramida
532160306Skeramida	switch (cmd) {
533149766Sgarys	case TUNSIFINFO:
534160306Skeramida		tunp = (struct tuninfo *)data;
535149766Sgarys		if (tunp->mtu < IF_MINMTU)
536160306Skeramida			return (EINVAL);
537149766Sgarys		if (tp->tun_if.if_mtu != tunp->mtu
538149766Sgarys		&& (error = suser(td)) != 0)
539149766Sgarys			return (error);
540226089Sobrien		tp->tun_if.if_mtu = tunp->mtu;
541226089Sobrien		tp->tun_if.if_type = tunp->type;
542226089Sobrien		tp->tun_if.if_baudrate = tunp->baudrate;
543226089Sobrien		break;
544226089Sobrien	case TUNGIFINFO:
545226089Sobrien		tunp = (struct tuninfo *)data;
546149766Sgarys		tunp->mtu = tp->tun_if.if_mtu;
547149766Sgarys		tunp->type = tp->tun_if.if_type;
548149766Sgarys		tunp->baudrate = tp->tun_if.if_baudrate;
549149766Sgarys		break;
550149766Sgarys	case TUNSDEBUG:
551149766Sgarys		tundebug = *(int *)data;
552149766Sgarys		break;
553149766Sgarys	case TUNGDEBUG:
554149766Sgarys		*(int *)data = tundebug;
555149766Sgarys		break;
556149766Sgarys	case TUNSLMODE:
557149766Sgarys		if (*(int *)data) {
558149766Sgarys			tp->tun_flags |= TUN_LMODE;
559149766Sgarys			tp->tun_flags &= ~TUN_IFHEAD;
560149766Sgarys		} else
561149766Sgarys			tp->tun_flags &= ~TUN_LMODE;
562149766Sgarys		break;
563149766Sgarys	case TUNSIFHEAD:
564149766Sgarys		if (*(int *)data) {
565149766Sgarys			tp->tun_flags |= TUN_IFHEAD;
566149766Sgarys			tp->tun_flags &= ~TUN_LMODE;
567149766Sgarys		} else
568149766Sgarys			tp->tun_flags &= ~TUN_IFHEAD;
569149766Sgarys		break;
570149766Sgarys	case TUNGIFHEAD:
571149766Sgarys		*(int *)data = (tp->tun_flags & TUN_IFHEAD) ? 1 : 0;
572149766Sgarys		break;
573149766Sgarys	case TUNSIFMODE:
574154558Sceri		/* deny this if UP */
575231244Sgjb		if (tp->tun_if.if_flags & IFF_UP)
57641967Sdillon			return(EBUSY);
57741967Sdillon
57841967Sdillon		switch (*(int *)data & ~IFF_MULTICAST) {
579130524Sru		case IFF_POINTOPOINT:
580130524Sru		case IFF_BROADCAST:
581130524Sru			tp->tun_if.if_flags &=
582130524Sru			    ~(IFF_BROADCAST|IFF_POINTOPOINT|IFF_MULTICAST);
583130524Sru			tp->tun_if.if_flags |= *(int *)data;
584130524Sru			break;
585130524Sru		default:
586130524Sru			return(EINVAL);
587130524Sru		}
588130524Sru		break;
589130524Sru	case TUNSIFPID:
590130524Sru		tp->tun_pid = curthread->td_proc->p_pid;
591129397Sdannyboy		break;
59251372Sdillon	case FIONBIO:
593130524Sru		break;
594130524Sru	case FIOASYNC:
595108260Sru		if (*(int *)data)
596129400Sdannyboy			tp->tun_flags |= TUN_ASYNC;
59751372Sdillon		else
59841967Sdillon			tp->tun_flags &= ~TUN_ASYNC;
59951372Sdillon		break;
600130524Sru	case FIONREAD:
601130524Sru		s = splimp();
60251372Sdillon		if (tp->tun_if.if_snd.ifq_head) {
60351372Sdillon			struct mbuf *mb = tp->tun_if.if_snd.ifq_head;
60479727Sschweikh			for( *(int *)data = 0; mb != 0; mb = mb->m_next)
605129397Sdannyboy				*(int *)data += mb->m_len;
60651372Sdillon		} else
60751372Sdillon			*(int *)data = 0;
60851372Sdillon		splx(s);
609130524Sru		break;
610130524Sru	case FIOSETOWN:
611130524Sru		return (fsetown(*(int *)data, &tp->tun_sigio));
612129397Sdannyboy
613130524Sru	case FIOGETOWN:
614130524Sru		*(int *)data = fgetown(&tp->tun_sigio);
61551372Sdillon		return (0);
616130524Sru
617130524Sru	/* This is deprecated, FIOSETOWN should be used instead. */
61851372Sdillon	case TIOCSPGRP:
619130524Sru		return (fsetown(-(*(int *)data), &tp->tun_sigio));
620130524Sru
62151372Sdillon	/* This is deprecated, FIOGETOWN should be used instead. */
62251372Sdillon	case TIOCGPGRP:
62379727Sschweikh		*(int *)data = -fgetown(&tp->tun_sigio);
624130524Sru		return (0);
625130524Sru
62651372Sdillon	default:
62751372Sdillon		return (ENOTTY);
62844389Sghelmer	}
629130524Sru	return (0);
630130524Sru}
63151372Sdillon
632130524Sru/*
63351382Sdillon * The cdevsw read interface - reads a packet at a time, or at
63451382Sdillon * least as much of a packet as can be read.
63551382Sdillon */
63651382Sdillonstatic	int
637130524Srutunread(dev_t dev, struct uio *uio, int flag)
638130524Sru{
63951372Sdillon	struct tun_softc *tp = dev->si_drv1;
640130524Sru	struct ifnet	*ifp = &tp->tun_if;
641130524Sru	struct mbuf	*m;
642130524Sru	int		error=0, len, s;
64351372Sdillon
64451372Sdillon	TUNDEBUG (ifp, "read\n");
64551372Sdillon	if ((tp->tun_flags & TUN_READY) != TUN_READY) {
646130524Sru		TUNDEBUG (ifp, "not ready 0%o\n", tp->tun_flags);
64741967Sdillon		return (EHOSTDOWN);
648130524Sru	}
649130524Sru
650130524Sru	tp->tun_flags &= ~TUN_RWAIT;
651130524Sru
65251372Sdillon	s = splimp();
653130524Sru	do {
654130524Sru		IF_DEQUEUE(&ifp->if_snd, m);
655130524Sru		if (m == NULL) {
656130524Sru			if (flag & IO_NDELAY) {
657130524Sru				splx(s);
658130524Sru				return (EWOULDBLOCK);
659130524Sru			}
660130524Sru			tp->tun_flags |= TUN_RWAIT;
661130524Sru			if((error = tsleep(tp, PCATCH | (PZERO + 1),
662130524Sru					"tunread", 0)) != 0) {
66351372Sdillon				splx(s);
66441967Sdillon				return (error);
66541967Sdillon			}
66651382Sdillon		}
667130524Sru	} while (m == NULL);
668131530Sru	splx(s);
66941967Sdillon
67051372Sdillon	while (m && uio->uio_resid > 0 && error == 0) {
671130524Sru		len = min(uio->uio_resid, m->m_len);
672130524Sru		if (len != 0)
673138188Sru			error = uiomove(mtod(m, void *), len, uio);
674130524Sru		m = m_free(m);
675130524Sru	}
676130524Sru
677138188Sru	if (m) {
67881251Sru		TUNDEBUG(ifp, "Dropping mbuf\n");
67981251Sru		m_freem(m);
680138188Sru	}
681130524Sru	return (error);
68251372Sdillon}
683125973Sceri
68441967Sdillon/*
68544389Sghelmer * the cdevsw write interface - an atomic write is a packet - or else!
68681251Sru */
68781251Srustatic	int
68844389Sghelmertunwrite(dev_t dev, struct uio *uio, int flag)
68942062Sobrien{
690130524Sru	struct tun_softc *tp = dev->si_drv1;
691130524Sru	struct ifnet	*ifp = &tp->tun_if;
69251372Sdillon	struct mbuf	*top, **mp, *m;
69342062Sobrien	int		error=0, tlen, mlen;
69441967Sdillon	uint32_t	family;
69541967Sdillon	int 		isr;
696129397Sdannyboy
697130524Sru	TUNDEBUG(ifp, "tunwrite\n");
698130524Sru
69979727Sschweikh	if ((ifp->if_flags & IFF_UP) != IFF_UP)
700130524Sru		/* ignore silently */
701130524Sru		return (0);
70251372Sdillon
70351372Sdillon	if (uio->uio_resid == 0)
70441967Sdillon		return (0);
705130524Sru
706130524Sru	if (uio->uio_resid < 0 || uio->uio_resid > TUNMRU) {
707129397Sdannyboy		TUNDEBUG(ifp, "len=%d!\n", uio->uio_resid);
708129397Sdannyboy		return (EIO);
709130524Sru	}
710130524Sru	tlen = uio->uio_resid;
711129397Sdannyboy
71251372Sdillon	/* get a header mbuf */
713129397Sdannyboy	MGETHDR(m, M_DONTWAIT, MT_DATA);
714130524Sru	if (m == NULL)
715130524Sru		return (ENOBUFS);
716130524Sru	mlen = MHLEN;
717130524Sru
71841967Sdillon	top = 0;
71979727Sschweikh	mp = &top;
72041967Sdillon	while (error == 0 && uio->uio_resid > 0) {
72141967Sdillon		m->m_len = min(mlen, uio->uio_resid);
72241967Sdillon		error = uiomove(mtod(m, void *), m->m_len, uio);
72341967Sdillon		*mp = m;
724130524Sru		mp = &m->m_next;
72541967Sdillon		if (uio->uio_resid > 0) {
72641967Sdillon			MGET (m, M_DONTWAIT, MT_DATA);
72741967Sdillon			if (m == 0) {
72841967Sdillon				error = ENOBUFS;
729130524Sru				break;
73042062Sobrien			}
731130524Sru			mlen = MLEN;
732130524Sru		}
733130524Sru	}
734130524Sru	if (error) {
73544389Sghelmer		if (top)
73641967Sdillon			m_freem (top);
73779727Sschweikh		ifp->if_ierrors++;
738130524Sru		return (error);
739130524Sru	}
740130524Sru
741130524Sru	top->m_pkthdr.len = tlen;
74244389Sghelmer	top->m_pkthdr.rcvif = ifp;
743130524Sru#ifdef MAC
74444389Sghelmer	mac_create_mbuf_from_ifnet(ifp, top);
74544389Sghelmer#endif
746130524Sru
747130524Sru	if (ifp->if_bpf) {
74844389Sghelmer		if (tp->tun_flags & TUN_IFHEAD) {
74944389Sghelmer			/*
750130524Sru			 * Conveniently, we already have a 4-byte address
751130524Sru			 * family prepended to our packet !
752130524Sru			 * Inconveniently, it's in the wrong byte order !
75379727Sschweikh			 */
75441967Sdillon			if ((top = m_pullup(top, sizeof(family))) == NULL)
755130524Sru				return (ENOBUFS);
756130524Sru			*mtod(top, u_int32_t *) =
757130524Sru			    ntohl(*mtod(top, u_int32_t *));
75844389Sghelmer			BPF_MTAP(ifp, top);
75944389Sghelmer			*mtod(top, u_int32_t *) =
760130524Sru			    htonl(*mtod(top, u_int32_t *));
761130524Sru		} else {
762130524Sru			/*
763130524Sru			 * We need to prepend the address family as
764130524Sru			 * a four byte field.  Cons up a dummy header
765130524Sru			 * to pacify bpf.  This is safe because bpf
76644389Sghelmer			 * will only read from the mbuf (i.e., it won't
767130524Sru			 * try to free it or keep a pointer to it).
768130524Sru			 */
769130524Sru			struct mbuf m;
770130524Sru			uint32_t af = AF_INET;
771130524Sru
772130524Sru			m.m_next = top;
773130524Sru			m.m_len = 4;
774130524Sru			m.m_data = (char *)&af;
775130524Sru
776130524Sru			BPF_MTAP(ifp, &m);
77744389Sghelmer		}
77879727Sschweikh	}
779130524Sru
78044389Sghelmer	if (tp->tun_flags & TUN_IFHEAD) {
781130524Sru		if (top->m_len < sizeof(family) &&
782130524Sru		    (top = m_pullup(top, sizeof(family))) == NULL)
78344389Sghelmer			return (ENOBUFS);
78444389Sghelmer		family = ntohl(*mtod(top, u_int32_t *));
78544389Sghelmer		m_adj(top, sizeof(family));
786130524Sru	} else
787130524Sru		family = AF_INET;
788130524Sru
789130524Sru	switch (family) {
79041967Sdillon#ifdef INET
791130524Sru	case AF_INET:
792130524Sru		isr = NETISR_IP;
793130524Sru		break;
79479727Sschweikh#endif
79544389Sghelmer#ifdef INET6
79644389Sghelmer	case AF_INET6:
79744389Sghelmer		isr = NETISR_IPV6;
79844389Sghelmer		break;
79941967Sdillon#endif
80041967Sdillon#ifdef IPX
80179727Sschweikh	case AF_IPX:
802130524Sru		isr = NETISR_IPX;
803130524Sru		break;
80441967Sdillon#endif
80541967Sdillon#ifdef NETATALK
80641967Sdillon	case AF_APPLETALK:
807130524Sru		isr = NETISR_ATALK2;
808130524Sru		break;
80979727Sschweikh#endif
810130524Sru	default:
811130524Sru		m_freem(m);
812130524Sru		return (EAFNOSUPPORT);
81344389Sghelmer	}
814129397Sdannyboy	/* First chunk of an mbuf contains good junk */
815129397Sdannyboy	if (harvest.point_to_point)
816129397Sdannyboy		random_harvest(m, 16, 3, 0, RANDOM_NET);
81744389Sghelmer	ifp->if_ibytes += top->m_pkthdr.len;
81844389Sghelmer	ifp->if_ipackets++;
81941967Sdillon	netisr_dispatch(isr, top);
820130524Sru	return (0);
821130524Sru}
822130524Sru
82341967Sdillon/*
82441967Sdillon * tunpoll - the poll interface, this is only useful on reads
825129397Sdannyboy * really. The write detect always returns true, write never blocks
82679727Sschweikh * anyway, it either accepts the packet or drops it.
827130524Sru */
82844389Sghelmerstatic	int
829130524Srutunpoll(dev_t dev, int events, struct thread *td)
830130524Sru{
83141967Sdillon	int		s;
832130524Sru	struct tun_softc *tp = dev->si_drv1;
833130524Sru	struct ifnet	*ifp = &tp->tun_if;
83450911Sphantom	int		revents = 0;
83544389Sghelmer
83641967Sdillon	s = splimp();
837130524Sru	TUNDEBUG(ifp, "tunpoll\n");
838130524Sru
839130524Sru	if (events & (POLLIN | POLLRDNORM)) {
84044389Sghelmer		if (ifp->if_snd.ifq_len > 0) {
841130524Sru			TUNDEBUG(ifp, "tunpoll q=%d\n", ifp->if_snd.ifq_len);
842130524Sru			revents |= events & (POLLIN | POLLRDNORM);
84341967Sdillon		} else {
84444389Sghelmer			TUNDEBUG(ifp, "tunpoll waiting\n");
84581251Sru			selrecord(td, &tp->tun_rsel);
84681251Sru		}
84741967Sdillon	}
848130524Sru	if (events & (POLLOUT | POLLWRNORM))
84941967Sdillon		revents |= events & (POLLOUT | POLLWRNORM);
850130524Sru
851130524Sru	splx(s);
852130524Sru	return (revents);
853130524Sru}
85441967Sdillon