if_tun.c revision 71959
1199989Srdivacky/*	$NetBSD: if_tun.c,v 1.14 1994/06/29 06:36:25 cgd Exp $	*/
2199989Srdivacky
3199989Srdivacky/*
4199989Srdivacky * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk>
5199989Srdivacky * Nottingham University 1987.
6199989Srdivacky *
7199989Srdivacky * This source may be freely distributed, however I would be interested
8199989Srdivacky * in any changes that are made.
9199989Srdivacky *
10199989Srdivacky * This driver takes packets off the IP i/f and hands them up to a
11199989Srdivacky * user process to have its wicked way with. This driver has it's
12199989Srdivacky * roots in a similar driver written by Phil Cockcroft (formerly) at
13199989Srdivacky * UCL. This driver is based much more on read/write/poll mode of
14199989Srdivacky * operation though.
15199989Srdivacky *
16249423Sdim * $FreeBSD: head/sys/net/if_tun.c 71959 2001-02-03 11:46:35Z phk $
17234353Sdim */
18207618Srdivacky
19249423Sdim#include "opt_inet.h"
20199989Srdivacky
21199989Srdivacky#include <sys/param.h>
22199989Srdivacky#include <sys/proc.h>
23199989Srdivacky#include <sys/systm.h>
24249423Sdim#include <sys/mbuf.h>
25249423Sdim#include <sys/module.h>
26249423Sdim#include <sys/socket.h>
27249423Sdim#include <sys/filio.h>
28249423Sdim#include <sys/sockio.h>
29249423Sdim#include <sys/ttycom.h>
30249423Sdim#include <sys/poll.h>
31249423Sdim#include <sys/signalvar.h>
32249423Sdim#include <sys/filedesc.h>
33249423Sdim#include <sys/kernel.h>
34249423Sdim#include <sys/sysctl.h>
35199989Srdivacky#include <sys/conf.h>
36199989Srdivacky#include <sys/uio.h>
37199989Srdivacky#include <sys/vnode.h>
38249423Sdim#include <sys/malloc.h>
39199989Srdivacky
40199989Srdivacky#include <net/if.h>
41199989Srdivacky#include <net/if_types.h>
42199989Srdivacky#include <net/route.h>
43199989Srdivacky#include <net/intrq.h>
44199989Srdivacky
45207618Srdivacky#ifdef INET
46207618Srdivacky#include <netinet/in.h>
47199989Srdivacky#endif
48207618Srdivacky
49207618Srdivacky#include <net/bpf.h>
50210299Sed
51210299Sed#include <net/if_tunvar.h>
52210299Sed#include <net/if_tun.h>
53199989Srdivacky
54210299Sedstatic MALLOC_DEFINE(M_TUN, "tun", "Tunnel Interface");
55199989Srdivacky
56199989Srdivackystatic void tuncreate __P((dev_t dev));
57199989Srdivacky
58263508Sdim#define TUNDEBUG	if (tundebug) printf
59263508Sdimstatic int tundebug = 0;
60199989SrdivackySYSCTL_INT(_debug, OID_AUTO, if_tun_debug, CTLFLAG_RW, &tundebug, 0, "");
61199989Srdivacky
62199989Srdivackystatic int tunoutput __P((struct ifnet *, struct mbuf *, struct sockaddr *,
63199989Srdivacky	    struct rtentry *rt));
64199989Srdivackystatic int tunifioctl __P((struct ifnet *, u_long, caddr_t));
65210299Sedstatic int tuninit __P((struct ifnet *));
66210299Sedstatic void tunstart __P((struct ifnet *));
67263508Sdim
68263508Sdimstatic	d_open_t	tunopen;
69263508Sdimstatic	d_close_t	tunclose;
70263508Sdimstatic	d_read_t	tunread;
71210299Sedstatic	d_write_t	tunwrite;
72199989Srdivackystatic	d_ioctl_t	tunioctl;
73199989Srdivackystatic	d_poll_t	tunpoll;
74199989Srdivacky
75207618Srdivacky#define CDEV_MAJOR 52
76207618Srdivackystatic struct cdevsw tun_cdevsw = {
77207618Srdivacky	/* open */	tunopen,
78207618Srdivacky	/* close */	tunclose,
79226633Sdim	/* read */	tunread,
80263508Sdim	/* write */	tunwrite,
81199989Srdivacky	/* ioctl */	tunioctl,
82263508Sdim	/* poll */	tunpoll,
83199989Srdivacky	/* mmap */	nommap,
84199989Srdivacky	/* strategy */	nostrategy,
85199989Srdivacky	/* name */	"tun",
86199989Srdivacky	/* maj */	CDEV_MAJOR,
87212904Sdim	/* dump */	nodump,
88212904Sdim	/* psize */	nopsize,
89212904Sdim	/* flags */	0,
90212904Sdim	/* bmaj */	-1
91212904Sdim};
92212904Sdim
93234353Sdimstatic void tun_clone __P((void *arg, char *name, int namelen, dev_t *dev));
94212904Sdim
95199989Srdivackystatic void
96234353Sdimtun_clone(arg, name, namelen, dev)
97243830Sdim	void *arg;
98199989Srdivacky	char *name;
99199989Srdivacky	int namelen;
100199989Srdivacky	dev_t *dev;
101234353Sdim{
102234353Sdim	int u;
103212904Sdim
104212904Sdim	if (*dev != NODEV)
105207618Srdivacky		return;
106199989Srdivacky	if (dev_stdclone(name, NULL, "tun", &u) != 1)
107199989Srdivacky		return;
108199989Srdivacky	*dev = make_dev(&tun_cdevsw, unit2minor(u),
109199989Srdivacky	    UID_ROOT, GID_WHEEL, 0600, "tun%d", u);
110212904Sdim
111212904Sdim}
112212904Sdim
113212904Sdimstatic int
114212904Sdimtun_modevent(module_t mod, int type, void *data)
115263508Sdim{
116263508Sdim	switch (type) {
117263508Sdim	case MOD_LOAD:
118212904Sdim		EVENTHANDLER_REGISTER(dev_clone, tun_clone, 0, 1000);
119263508Sdim		cdevsw_add(&tun_cdevsw);
120212904Sdim		break;
121212904Sdim	case MOD_UNLOAD:
122212904Sdim		printf("if_tun module unload - not possible for this module type\n");
123212904Sdim		return EINVAL;
124212904Sdim	}
125212904Sdim	return 0;
126212904Sdim}
127212904Sdim
128212904Sdimstatic moduledata_t tun_mod = {
129212904Sdim	"if_tun",
130212904Sdim	tun_modevent,
131212904Sdim	0
132212904Sdim};
133212904Sdim
134212904SdimDECLARE_MODULE(if_tun, tun_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
135212904Sdim
136212904Sdimstatic void
137212904Sdimtunstart(ifp)
138212904Sdim	struct ifnet *ifp;
139212904Sdim{
140212904Sdim	struct tun_softc *tp = ifp->if_softc;
141212904Sdim
142199989Srdivacky	if (tp->tun_flags & TUN_RWAIT) {
143199989Srdivacky		tp->tun_flags &= ~TUN_RWAIT;
144199989Srdivacky		wakeup((caddr_t)tp);
145207618Srdivacky	}
146199989Srdivacky	if (tp->tun_flags & TUN_ASYNC && tp->tun_sigio)
147199989Srdivacky		pgsigio(tp->tun_sigio, SIGIO, 0);
148199989Srdivacky	selwakeup(&tp->tun_rsel);
149199989Srdivacky}
150199989Srdivacky
151199989Srdivackystatic void
152199989Srdivackytuncreate(dev)
153199989Srdivacky	dev_t dev;
154199989Srdivacky{
155199989Srdivacky	struct tun_softc *sc;
156199989Srdivacky	struct ifnet *ifp;
157199989Srdivacky
158207618Srdivacky	dev = make_dev(&tun_cdevsw, minor(dev),
159207618Srdivacky	    UID_UUCP, GID_DIALER, 0600, "tun%d", dev2unit(dev));
160207618Srdivacky
161199989Srdivacky	MALLOC(sc, struct tun_softc *, sizeof(*sc), M_TUN, M_WAITOK | M_ZERO);
162223017Sdim	sc->tun_flags = TUN_INITED;
163223017Sdim
164223017Sdim	ifp = &sc->tun_if;
165223017Sdim	ifp->if_unit = dev2unit(dev);
166207618Srdivacky	ifp->if_name = "tun";
167199989Srdivacky	ifp->if_mtu = TUNMTU;
168199989Srdivacky	ifp->if_ioctl = tunifioctl;
169199989Srdivacky	ifp->if_output = tunoutput;
170199989Srdivacky	ifp->if_start = tunstart;
171263508Sdim	ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
172199989Srdivacky	ifp->if_type = IFT_PPP;
173199989Srdivacky	ifp->if_snd.ifq_maxlen = ifqmaxlen;
174263508Sdim	ifp->if_softc = sc;
175199989Srdivacky	if_attach(ifp);
176199989Srdivacky	bpfattach(ifp, DLT_NULL, sizeof(u_int));
177203954Srdivacky	dev->si_drv1 = sc;
178199989Srdivacky}
179199989Srdivacky
180199989Srdivacky/*
181199989Srdivacky * tunnel open - must be superuser & the device must be
182207618Srdivacky * configured in
183207618Srdivacky */
184207618Srdivackystatic	int
185207618Srdivackytunopen(dev, flag, mode, p)
186207618Srdivacky	dev_t	dev;
187199989Srdivacky	int	flag, mode;
188199989Srdivacky	struct proc *p;
189199989Srdivacky{
190199989Srdivacky	struct ifnet	*ifp;
191199989Srdivacky	struct tun_softc *tp;
192199989Srdivacky
193207618Srdivacky	tp = dev->si_drv1;
194207618Srdivacky	if (!tp) {
195207618Srdivacky		tuncreate(dev);
196199989Srdivacky		tp = dev->si_drv1;
197199989Srdivacky	}
198199989Srdivacky	if (tp->tun_flags & TUN_OPEN)
199199989Srdivacky		return EBUSY;
200199989Srdivacky	tp->tun_pid = p->p_pid;
201199989Srdivacky	ifp = &tp->tun_if;
202199989Srdivacky	tp->tun_flags |= TUN_OPEN;
203199989Srdivacky	TUNDEBUG("%s%d: open\n", ifp->if_name, ifp->if_unit);
204219077Sdim	return (0);
205207618Srdivacky}
206212904Sdim
207210299Sed/*
208199989Srdivacky * tunclose - close the device - mark i/f down & delete
209199989Srdivacky * routing info
210210299Sed */
211249423Sdimstatic	int
212263508Sdimtunclose(dev, foo, bar, p)
213263508Sdim	dev_t dev;
214199989Srdivacky	int foo;
215199989Srdivacky	int bar;
216210299Sed	struct proc *p;
217199989Srdivacky{
218199989Srdivacky	register int	s;
219199989Srdivacky	struct tun_softc *tp;
220199989Srdivacky	struct ifnet	*ifp;
221199989Srdivacky
222199989Srdivacky	tp = dev->si_drv1;
223226633Sdim	ifp = &tp->tun_if;
224263508Sdim
225263508Sdim	tp->tun_flags &= ~TUN_OPEN;
226199989Srdivacky	tp->tun_pid = 0;
227263508Sdim
228199989Srdivacky	/*
229199989Srdivacky	 * junk all pending output
230199989Srdivacky	 */
231199989Srdivacky	IF_DRAIN(&ifp->if_snd);
232263508Sdim
233199989Srdivacky	if (ifp->if_flags & IFF_UP) {
234263508Sdim		s = splimp();
235199989Srdivacky		if_down(ifp);
236210299Sed		splx(s);
237199989Srdivacky	}
238199989Srdivacky
239199989Srdivacky	if (ifp->if_flags & IFF_RUNNING) {
240199989Srdivacky		register struct ifaddr *ifa;
241199989Srdivacky
242199989Srdivacky		s = splimp();
243219077Sdim		/* find internet addresses and delete routes */
244219077Sdim		for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa;
245219077Sdim		    ifa = TAILQ_NEXT(ifa, ifa_link))
246219077Sdim			if (ifa->ifa_addr->sa_family == AF_INET)
247219077Sdim				rtinit(ifa, (int)RTM_DELETE,
248219077Sdim				    tp->tun_flags & TUN_DSTADDR ? RTF_HOST : 0);
249219077Sdim		ifp->if_flags &= ~IFF_RUNNING;
250219077Sdim		splx(s);
251219077Sdim	}
252219077Sdim
253219077Sdim	funsetown(tp->tun_sigio);
254219077Sdim	selwakeup(&tp->tun_rsel);
255219077Sdim
256219077Sdim	TUNDEBUG ("%s%d: closed\n", ifp->if_name, ifp->if_unit);
257219077Sdim	return (0);
258219077Sdim}
259219077Sdim
260219077Sdimstatic int
261219077Sdimtuninit(ifp)
262219077Sdim	struct ifnet *ifp;
263219077Sdim{
264219077Sdim	struct tun_softc *tp = ifp->if_softc;
265219077Sdim	register struct ifaddr *ifa;
266219077Sdim	int error = 0;
267219077Sdim
268219077Sdim	TUNDEBUG("%s%d: tuninit\n", ifp->if_name, ifp->if_unit);
269226633Sdim
270219077Sdim	ifp->if_flags |= IFF_UP | IFF_RUNNING;
271219077Sdim	getmicrotime(&ifp->if_lastchange);
272219077Sdim
273263508Sdim	for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa;
274263508Sdim	     ifa = TAILQ_NEXT(ifa, ifa_link)) {
275219077Sdim		if (ifa->ifa_addr == NULL)
276263508Sdim			error = EFAULT;
277219077Sdim			/* XXX: Should maybe return straight off? */
278219077Sdim		else {
279219077Sdim#ifdef INET
280219077Sdim			if (ifa->ifa_addr->sa_family == AF_INET) {
281263508Sdim			    struct sockaddr_in *si;
282219077Sdim
283263508Sdim			    si = (struct sockaddr_in *)ifa->ifa_addr;
284219077Sdim			    if (si->sin_addr.s_addr)
285219077Sdim				    tp->tun_flags |= TUN_IASET;
286219077Sdim
287219077Sdim			    si = (struct sockaddr_in *)ifa->ifa_dstaddr;
288219077Sdim			    if (si && si->sin_addr.s_addr)
289219077Sdim				    tp->tun_flags |= TUN_DSTADDR;
290219077Sdim			}
291219077Sdim#endif
292219077Sdim		}
293219077Sdim	}
294219077Sdim	return (error);
295219077Sdim}
296219077Sdim
297219077Sdim/*
298219077Sdim * Process an ioctl request.
299219077Sdim */
300219077Sdimint
301219077Sdimtunifioctl(ifp, cmd, data)
302219077Sdim	struct ifnet *ifp;
303219077Sdim	u_long	cmd;
304219077Sdim	caddr_t	data;
305219077Sdim{
306219077Sdim	struct ifreq *ifr = (struct ifreq *)data;
307219077Sdim	struct tun_softc *tp = ifp->if_softc;
308219077Sdim	struct ifstat *ifs;
309219077Sdim	int		error = 0, s;
310219077Sdim
311219077Sdim	s = splimp();
312219077Sdim	switch(cmd) {
313219077Sdim	case SIOCGIFSTATUS:
314219077Sdim		ifs = (struct ifstat *)data;
315219077Sdim		if (tp->tun_pid)
316219077Sdim			sprintf(ifs->ascii + strlen(ifs->ascii),
317219077Sdim			    "\tOpened by PID %d\n", tp->tun_pid);
318219077Sdim		break;
319219077Sdim	case SIOCSIFADDR:
320219077Sdim		error = tuninit(ifp);
321219077Sdim		TUNDEBUG("%s%d: address set, error=%d\n",
322219077Sdim			 ifp->if_name, ifp->if_unit, error);
323219077Sdim		break;
324219077Sdim	case SIOCSIFDSTADDR:
325219077Sdim		error = tuninit(ifp);
326219077Sdim		TUNDEBUG("%s%d: destination address set, error=%d\n",
327219077Sdim			 ifp->if_name, ifp->if_unit, error);
328219077Sdim		break;
329219077Sdim	case SIOCSIFMTU:
330219077Sdim		ifp->if_mtu = ifr->ifr_mtu;
331219077Sdim		TUNDEBUG("%s%d: mtu set\n", ifp->if_name, ifp->if_unit);
332219077Sdim		break;
333223017Sdim	case SIOCADDMULTI:
334219077Sdim	case SIOCDELMULTI:
335219077Sdim		break;
336219077Sdim	default:
337219077Sdim		error = EINVAL;
338219077Sdim	}
339219077Sdim	splx(s);
340219077Sdim	return (error);
341219077Sdim}
342219077Sdim
343219077Sdim/*
344219077Sdim * tunoutput - queue packets from higher level ready to put out.
345219077Sdim */
346219077Sdimint
347219077Sdimtunoutput(ifp, m0, dst, rt)
348219077Sdim	struct ifnet   *ifp;
349219077Sdim	struct mbuf    *m0;
350219077Sdim	struct sockaddr *dst;
351219077Sdim	struct rtentry *rt;
352219077Sdim{
353219077Sdim	struct tun_softc *tp = ifp->if_softc;
354219077Sdim
355219077Sdim	TUNDEBUG ("%s%d: tunoutput\n", ifp->if_name, ifp->if_unit);
356219077Sdim
357219077Sdim	if ((tp->tun_flags & TUN_READY) != TUN_READY) {
358219077Sdim		TUNDEBUG ("%s%d: not ready 0%o\n", ifp->if_name,
359219077Sdim			  ifp->if_unit, tp->tun_flags);
360219077Sdim		m_freem (m0);
361219077Sdim		return EHOSTDOWN;
362226633Sdim	}
363212904Sdim
364212904Sdim	/* BPF write needs to be handled specially */
365226633Sdim	if (dst->sa_family == AF_UNSPEC) {
366234353Sdim		dst->sa_family = *(mtod(m0, int *));
367212904Sdim		m0->m_len -= sizeof(int);
368212904Sdim		m0->m_pkthdr.len -= sizeof(int);
369223017Sdim		m0->m_data += sizeof(int);
370226633Sdim	}
371212904Sdim
372212904Sdim	if (ifp->if_bpf) {
373226633Sdim		/*
374223017Sdim		 * We need to prepend the address family as
375212904Sdim		 * a four byte field.  Cons up a dummy header
376212904Sdim		 * to pacify bpf.  This is safe because bpf
377212904Sdim		 * will only read from the mbuf (i.e., it won't
378234353Sdim		 * try to free it or keep a pointer to it).
379212904Sdim		 */
380212904Sdim		struct mbuf m;
381212904Sdim		uint32_t af = dst->sa_family;
382234353Sdim
383234353Sdim		m.m_next = m0;
384234353Sdim		m.m_len = 4;
385234353Sdim		m.m_data = (char *)&af;
386234353Sdim
387234353Sdim		bpf_mtap(ifp, &m);
388234353Sdim	}
389234353Sdim
390234353Sdim	/* prepend sockaddr? this may abort if the mbuf allocation fails */
391234353Sdim	if (tp->tun_flags & TUN_LMODE) {
392234353Sdim		/* allocate space for sockaddr */
393234353Sdim		M_PREPEND(m0, dst->sa_len, M_DONTWAIT);
394234353Sdim
395234353Sdim		/* if allocation failed drop packet */
396234353Sdim		if (m0 == NULL) {
397234353Sdim			ifp->if_iqdrops++;
398234353Sdim			ifp->if_oerrors++;
399234353Sdim			return (ENOBUFS);
400234353Sdim		} else {
401234353Sdim			bcopy(dst, m0->m_data, dst->sa_len);
402234353Sdim		}
403234353Sdim	}
404234353Sdim
405234353Sdim	if (tp->tun_flags & TUN_IFHEAD) {
406199989Srdivacky		/* Prepend the address family */
407199989Srdivacky		M_PREPEND(m0, 4, M_DONTWAIT);
408207618Srdivacky
409199989Srdivacky		/* if allocation failed drop packet */
410199989Srdivacky		if (m0 == NULL) {
411210299Sed			ifp->if_iqdrops++;
412199989Srdivacky			ifp->if_oerrors++;
413199989Srdivacky			return ENOBUFS;
414199989Srdivacky		} else
415199989Srdivacky			*(u_int32_t *)m0->m_data = htonl(dst->sa_family);
416199989Srdivacky	} else {
417199989Srdivacky#ifdef INET
418199989Srdivacky		if (dst->sa_family != AF_INET)
419207618Srdivacky#endif
420210299Sed		{
421199989Srdivacky			m_freem(m0);
422210299Sed			return EAFNOSUPPORT;
423210299Sed		}
424199989Srdivacky	}
425199989Srdivacky
426210299Sed	if (! IF_HANDOFF(&ifp->if_snd, m0, ifp)) {
427199989Srdivacky		ifp->if_collisions++;
428199989Srdivacky		return ENOBUFS;
429199989Srdivacky	}
430199989Srdivacky	ifp->if_opackets++;
431210299Sed	return 0;
432199989Srdivacky}
433199989Srdivacky
434199989Srdivacky/*
435199989Srdivacky * the cdevsw interface is now pretty minimal.
436199989Srdivacky */
437199989Srdivackystatic	int
438199989Srdivackytunioctl(dev, cmd, data, flag, p)
439199989Srdivacky	dev_t		dev;
440199989Srdivacky	u_long		cmd;
441199989Srdivacky	caddr_t		data;
442199989Srdivacky	int		flag;
443210299Sed	struct proc	*p;
444199989Srdivacky{
445199989Srdivacky	int		s;
446199989Srdivacky	int		error;
447199989Srdivacky	struct tun_softc *tp = dev->si_drv1;
448199989Srdivacky 	struct tuninfo *tunp;
449199989Srdivacky
450199989Srdivacky	switch (cmd) {
451199989Srdivacky 	case TUNSIFINFO:
452210299Sed 		tunp = (struct tuninfo *)data;
453210299Sed		if (tunp->mtu < IF_MINMTU)
454210299Sed			return (EINVAL);
455210299Sed 		if (tp->tun_if.if_mtu != tunp->mtu && (error = suser(p)) != 0)
456199989Srdivacky			return (error);
457199989Srdivacky 		tp->tun_if.if_mtu = tunp->mtu;
458199989Srdivacky 		tp->tun_if.if_type = tunp->type;
459199989Srdivacky 		tp->tun_if.if_baudrate = tunp->baudrate;
460226633Sdim 		break;
461226633Sdim 	case TUNGIFINFO:
462226633Sdim 		tunp = (struct tuninfo *)data;
463226633Sdim 		tunp->mtu = tp->tun_if.if_mtu;
464226633Sdim 		tunp->type = tp->tun_if.if_type;
465226633Sdim 		tunp->baudrate = tp->tun_if.if_baudrate;
466226633Sdim 		break;
467226633Sdim	case TUNSDEBUG:
468226633Sdim		tundebug = *(int *)data;
469226633Sdim		break;
470226633Sdim	case TUNGDEBUG:
471226633Sdim		*(int *)data = tundebug;
472226633Sdim		break;
473226633Sdim	case TUNSLMODE:
474226633Sdim		if (*(int *)data) {
475226633Sdim			tp->tun_flags |= TUN_LMODE;
476226633Sdim			tp->tun_flags &= ~TUN_IFHEAD;
477226633Sdim		} else
478226633Sdim			tp->tun_flags &= ~TUN_LMODE;
479226633Sdim		break;
480226633Sdim	case TUNSIFHEAD:
481226633Sdim		if (*(int *)data) {
482226633Sdim			tp->tun_flags |= TUN_IFHEAD;
483226633Sdim			tp->tun_flags &= ~TUN_LMODE;
484226633Sdim		} else
485226633Sdim			tp->tun_flags &= ~TUN_IFHEAD;
486226633Sdim		break;
487226633Sdim	case TUNGIFHEAD:
488226633Sdim		*(int *)data = (tp->tun_flags & TUN_IFHEAD) ? 1 : 0;
489226633Sdim		break;
490	case TUNSIFMODE:
491		/* deny this if UP */
492		if (tp->tun_if.if_flags & IFF_UP)
493			return(EBUSY);
494
495		switch (*(int *)data) {
496		case IFF_POINTOPOINT:
497			tp->tun_if.if_flags |= IFF_POINTOPOINT;
498			tp->tun_if.if_flags &= ~IFF_BROADCAST;
499			break;
500		case IFF_BROADCAST:
501			tp->tun_if.if_flags &= ~IFF_POINTOPOINT;
502			tp->tun_if.if_flags |= IFF_BROADCAST;
503			break;
504		default:
505			return(EINVAL);
506		}
507		break;
508	case TUNSIFPID:
509		tp->tun_pid = curproc->p_pid;
510		break;
511	case FIONBIO:
512		break;
513	case FIOASYNC:
514		if (*(int *)data)
515			tp->tun_flags |= TUN_ASYNC;
516		else
517			tp->tun_flags &= ~TUN_ASYNC;
518		break;
519	case FIONREAD:
520		s = splimp();
521		if (tp->tun_if.if_snd.ifq_head) {
522			struct mbuf *mb = tp->tun_if.if_snd.ifq_head;
523			for( *(int *)data = 0; mb != 0; mb = mb->m_next)
524				*(int *)data += mb->m_len;
525		} else
526			*(int *)data = 0;
527		splx(s);
528		break;
529	case FIOSETOWN:
530		return (fsetown(*(int *)data, &tp->tun_sigio));
531
532	case FIOGETOWN:
533		*(int *)data = fgetown(tp->tun_sigio);
534		return (0);
535
536	/* This is deprecated, FIOSETOWN should be used instead. */
537	case TIOCSPGRP:
538		return (fsetown(-(*(int *)data), &tp->tun_sigio));
539
540	/* This is deprecated, FIOGETOWN should be used instead. */
541	case TIOCGPGRP:
542		*(int *)data = -fgetown(tp->tun_sigio);
543		return (0);
544
545	default:
546		return (ENOTTY);
547	}
548	return (0);
549}
550
551/*
552 * The cdevsw read interface - reads a packet at a time, or at
553 * least as much of a packet as can be read.
554 */
555static	int
556tunread(dev, uio, flag)
557	dev_t dev;
558	struct uio *uio;
559	int flag;
560{
561	struct tun_softc *tp = dev->si_drv1;
562	struct ifnet	*ifp = &tp->tun_if;
563	struct mbuf	*m, *m0;
564	int		error=0, len, s;
565
566	TUNDEBUG ("%s%d: read\n", ifp->if_name, ifp->if_unit);
567	if ((tp->tun_flags & TUN_READY) != TUN_READY) {
568		TUNDEBUG ("%s%d: not ready 0%o\n", ifp->if_name,
569			  ifp->if_unit, tp->tun_flags);
570		return EHOSTDOWN;
571	}
572
573	tp->tun_flags &= ~TUN_RWAIT;
574
575	s = splimp();
576	do {
577		IF_DEQUEUE(&ifp->if_snd, m0);
578		if (m0 == 0) {
579			if (flag & IO_NDELAY) {
580				splx(s);
581				return EWOULDBLOCK;
582			}
583			tp->tun_flags |= TUN_RWAIT;
584			if((error = tsleep((caddr_t)tp, PCATCH | (PZERO + 1),
585					"tunread", 0)) != 0) {
586				splx(s);
587				return error;
588			}
589		}
590	} while (m0 == 0);
591	splx(s);
592
593	while (m0 && uio->uio_resid > 0 && error == 0) {
594		len = min(uio->uio_resid, m0->m_len);
595		if (len == 0)
596			break;
597		error = uiomove(mtod(m0, caddr_t), len, uio);
598		MFREE(m0, m);
599		m0 = m;
600	}
601
602	if (m0) {
603		TUNDEBUG("Dropping mbuf\n");
604		m_freem(m0);
605	}
606	return error;
607}
608
609/*
610 * the cdevsw write interface - an atomic write is a packet - or else!
611 */
612static	int
613tunwrite(dev, uio, flag)
614	dev_t dev;
615	struct uio *uio;
616	int flag;
617{
618	struct tun_softc *tp = dev->si_drv1;
619	struct ifnet	*ifp = &tp->tun_if;
620	struct mbuf	*top, **mp, *m;
621	int		error=0, tlen, mlen;
622	uint32_t	family;
623
624	TUNDEBUG("%s%d: tunwrite\n", ifp->if_name, ifp->if_unit);
625
626	if (uio->uio_resid == 0)
627		return 0;
628
629	if (uio->uio_resid < 0 || uio->uio_resid > TUNMRU) {
630		TUNDEBUG("%s%d: len=%d!\n", ifp->if_name, ifp->if_unit,
631		    uio->uio_resid);
632		return EIO;
633	}
634	tlen = uio->uio_resid;
635
636	/* get a header mbuf */
637	MGETHDR(m, M_DONTWAIT, MT_DATA);
638	if (m == NULL)
639		return ENOBUFS;
640	mlen = MHLEN;
641
642	top = 0;
643	mp = &top;
644	while (error == 0 && uio->uio_resid > 0) {
645		m->m_len = min(mlen, uio->uio_resid);
646		error = uiomove(mtod (m, caddr_t), m->m_len, uio);
647		*mp = m;
648		mp = &m->m_next;
649		if (uio->uio_resid > 0) {
650			MGET (m, M_DONTWAIT, MT_DATA);
651			if (m == 0) {
652				error = ENOBUFS;
653				break;
654			}
655			mlen = MLEN;
656		}
657	}
658	if (error) {
659		if (top)
660			m_freem (top);
661		ifp->if_ierrors++;
662		return error;
663	}
664
665	top->m_pkthdr.len = tlen;
666	top->m_pkthdr.rcvif = ifp;
667
668	if (ifp->if_bpf) {
669		if (tp->tun_flags & TUN_IFHEAD) {
670			/*
671			 * Conveniently, we already have a 4-byte address
672			 * family prepended to our packet !
673			 * Inconveniently, it's in the wrong byte order !
674			 */
675			if ((top = m_pullup(top, sizeof(family))) == NULL)
676				return ENOBUFS;
677			*mtod(top, u_int32_t *) =
678			    ntohl(*mtod(top, u_int32_t *));
679			bpf_mtap(ifp, top);
680			*mtod(top, u_int32_t *) =
681			    htonl(*mtod(top, u_int32_t *));
682		} else {
683			/*
684			 * We need to prepend the address family as
685			 * a four byte field.  Cons up a dummy header
686			 * to pacify bpf.  This is safe because bpf
687			 * will only read from the mbuf (i.e., it won't
688			 * try to free it or keep a pointer to it).
689			 */
690			struct mbuf m;
691			uint32_t af = AF_INET;
692
693			m.m_next = top;
694			m.m_len = 4;
695			m.m_data = (char *)&af;
696
697			bpf_mtap(ifp, &m);
698		}
699	}
700
701	if (tp->tun_flags & TUN_IFHEAD) {
702		if (top->m_len < sizeof(family) &&
703		    (top = m_pullup(top, sizeof(family))) == NULL)
704				return ENOBUFS;
705		family = ntohl(*mtod(top, u_int32_t *));
706		m_adj(top, sizeof(family));
707	} else
708		family = AF_INET;
709
710	ifp->if_ibytes += top->m_pkthdr.len;
711	ifp->if_ipackets++;
712
713	return family_enqueue(family, top);
714}
715
716/*
717 * tunpoll - the poll interface, this is only useful on reads
718 * really. The write detect always returns true, write never blocks
719 * anyway, it either accepts the packet or drops it.
720 */
721static	int
722tunpoll(dev, events, p)
723	dev_t dev;
724	int events;
725	struct proc *p;
726{
727	int		s;
728	struct tun_softc *tp = dev->si_drv1;
729	struct ifnet	*ifp = &tp->tun_if;
730	int		revents = 0;
731
732	s = splimp();
733	TUNDEBUG("%s%d: tunpoll\n", ifp->if_name, ifp->if_unit);
734
735	if (events & (POLLIN | POLLRDNORM)) {
736		if (ifp->if_snd.ifq_len > 0) {
737			TUNDEBUG("%s%d: tunpoll q=%d\n", ifp->if_name,
738			    ifp->if_unit, ifp->if_snd.ifq_len);
739			revents |= events & (POLLIN | POLLRDNORM);
740		} else {
741			TUNDEBUG("%s%d: tunpoll waiting\n", ifp->if_name,
742			    ifp->if_unit);
743			selrecord(p, &tp->tun_rsel);
744		}
745	}
746	if (events & (POLLOUT | POLLWRNORM))
747		revents |= events & (POLLOUT | POLLWRNORM);
748
749	splx(s);
750	return (revents);
751}
752