if_tun.c revision 64880
1185573Srwatson/*	$NetBSD: if_tun.c,v 1.14 1994/06/29 06:36:25 cgd Exp $	*/
2191273Srwatson
3155131Srwatson/*
4155131Srwatson * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk>
5155131Srwatson * Nottingham University 1987.
6155131Srwatson *
7155131Srwatson * This source may be freely distributed, however I would be interested
8155131Srwatson * in any changes that are made.
9155131Srwatson *
10155131Srwatson * This driver takes packets off the IP i/f and hands them up to a
11155131Srwatson * user process to have its wicked way with. This driver has it's
12155131Srwatson * roots in a similar driver written by Phil Cockcroft (formerly) at
13185573Srwatson * UCL. This driver is based much more on read/write/poll mode of
14155131Srwatson * operation though.
15155131Srwatson *
16155131Srwatson * $FreeBSD: head/sys/net/if_tun.c 64880 2000-08-20 21:34:39Z phk $
17155131Srwatson */
18155131Srwatson
19155131Srwatson#include "opt_inet.h"
20155131Srwatson#include "opt_devfs.h"
21155131Srwatson
22155131Srwatson#include <sys/param.h>
23155131Srwatson#include <sys/proc.h>
24155131Srwatson#include <sys/systm.h>
25155131Srwatson#include <sys/mbuf.h>
26155131Srwatson#include <sys/socket.h>
27155131Srwatson#include <sys/filio.h>
28155131Srwatson#include <sys/sockio.h>
29155131Srwatson#include <sys/ttycom.h>
30155518Srwatson#include <sys/poll.h>
31155518Srwatson#include <sys/signalvar.h>
32155518Srwatson#include <sys/filedesc.h>
33155518Srwatson#include <sys/kernel.h>
34155131Srwatson#include <sys/sysctl.h>
35155131Srwatson#include <sys/conf.h>
36156283Srwatson#include <sys/uio.h>
37156283Srwatson#include <sys/vnode.h>
38156283Srwatson#include <sys/malloc.h>
39156283Srwatson
40156283Srwatson#include <net/if.h>
41155131Srwatson#include <net/if_types.h>
42155131Srwatson#include <net/route.h>
43155131Srwatson#include <net/intrq.h>
44155131Srwatson
45155131Srwatson#ifdef INET
46155131Srwatson#include <netinet/in.h>
47159248Srwatson#endif
48155131Srwatson
49155131Srwatson#include <net/bpf.h>
50155131Srwatson
51155131Srwatson#include <net/if_tunvar.h>
52155131Srwatson#include <net/if_tun.h>
53155131Srwatson
54155131Srwatson#ifdef DEVFS
55159248Srwatson#include <sys/eventhandler.h>
56159248Srwatson#include <fs/devfs/devfs.h>
57159248Srwatson#endif
58155131Srwatson
59159248Srwatsonstatic MALLOC_DEFINE(M_TUN, "tun", "Tunnel Interface");
60159248Srwatson
61159248Srwatsonstatic void tunattach __P((void *));
62159248SrwatsonPSEUDO_SET(tunattach, if_tun);
63159248Srwatson
64191273Srwatsonstatic void tuncreate __P((dev_t dev));
65159248Srwatson
66159248Srwatson#define TUNDEBUG	if (tundebug) printf
67168777Srwatsonstatic int tundebug = 0;
68159248SrwatsonSYSCTL_INT(_debug, OID_AUTO, if_tun_debug, CTLFLAG_RW, &tundebug, 0, "");
69168777Srwatson
70186647Srwatsonstatic int tunoutput __P((struct ifnet *, struct mbuf *, struct sockaddr *,
71159248Srwatson	    struct rtentry *rt));
72191273Srwatsonstatic int tunifioctl __P((struct ifnet *, u_long, caddr_t));
73159248Srwatsonstatic int tuninit __P((struct ifnet *));
74159248Srwatson
75159248Srwatsonstatic	d_open_t	tunopen;
76159248Srwatsonstatic	d_close_t	tunclose;
77159248Srwatsonstatic	d_read_t	tunread;
78159248Srwatsonstatic	d_write_t	tunwrite;
79159248Srwatsonstatic	d_ioctl_t	tunioctl;
80159248Srwatsonstatic	d_poll_t	tunpoll;
81159248Srwatson
82159248Srwatson#define CDEV_MAJOR 52
83159248Srwatsonstatic struct cdevsw tun_cdevsw = {
84159248Srwatson	/* open */	tunopen,
85159248Srwatson	/* close */	tunclose,
86159248Srwatson	/* read */	tunread,
87159248Srwatson	/* write */	tunwrite,
88159248Srwatson	/* ioctl */	tunioctl,
89159248Srwatson	/* poll */	tunpoll,
90159248Srwatson	/* mmap */	nommap,
91159248Srwatson	/* strategy */	nostrategy,
92159248Srwatson	/* name */	"tun",
93159248Srwatson	/* maj */	CDEV_MAJOR,
94159248Srwatson	/* dump */	nodump,
95168777Srwatson	/* psize */	nopsize,
96186647Srwatson	/* flags */	0,
97186647Srwatson	/* bmaj */	-1
98168777Srwatson};
99168777Srwatson
100186647Srwatson#ifdef DEVFS
101186647Srwatsonstatic void tun_clone __P((void *arg, char *name, int namelen, dev_t *dev));
102186647Srwatson
103186647Srwatsonstatic void
104186647Srwatsontun_clone(arg, name, namelen, dev)
105186647Srwatson	void *arg;
106186647Srwatson	char *name;
107186647Srwatson	int namelen;
108186647Srwatson	dev_t *dev;
109186647Srwatson{
110186647Srwatson	int u;
111186647Srwatson
112186647Srwatson	if (*dev != NODEV)
113186647Srwatson		return;
114186647Srwatson	if (devfs_stdclone(name, NULL, "tun", &u) != 1)
115186647Srwatson		return;
116186647Srwatson	/* XXX: minor encoding if u > 255 */
117186647Srwatson	*dev = make_dev(&tun_cdevsw, u,
118186647Srwatson	    UID_UUCP, GID_DIALER, 0600, "tun%d", u);
119186647Srwatson
120186647Srwatson}
121186647Srwatson#endif
122159248Srwatson
123186647Srwatson
124159248Srwatsonstatic void
125159248Srwatsontunattach(dummy)
126159248Srwatson	void *dummy;
127159248Srwatson{
128186647Srwatson
129186647Srwatson#ifdef DEVFS
130186647Srwatson	EVENTHANDLER_REGISTER(devfs_clone, tun_clone, 0, 1000);
131186647Srwatson#else
132186647Srwatson	cdevsw_add(&tun_cdevsw);
133186647Srwatson#endif
134159248Srwatson}
135186647Srwatson
136186647Srwatsonstatic void
137186647Srwatsontuncreate(dev)
138168777Srwatson	dev_t dev;
139186647Srwatson{
140186647Srwatson	struct tun_softc *sc;
141168777Srwatson	struct ifnet *ifp;
142168777Srwatson
143159248Srwatson	dev = make_dev(&tun_cdevsw, minor(dev),
144159248Srwatson	    UID_UUCP, GID_DIALER, 0600, "tun%d", lminor(dev));
145159248Srwatson
146159248Srwatson	MALLOC(sc, struct tun_softc *, sizeof(*sc), M_TUN, M_WAITOK);
147159248Srwatson	bzero(sc, sizeof *sc);
148159248Srwatson	sc->tun_flags = TUN_INITED;
149159248Srwatson
150159248Srwatson	ifp = &sc->tun_if;
151159248Srwatson	ifp->if_unit = lminor(dev);
152159248Srwatson	ifp->if_name = "tun";
153159248Srwatson	ifp->if_mtu = TUNMTU;
154159248Srwatson	ifp->if_ioctl = tunifioctl;
155159248Srwatson	ifp->if_output = tunoutput;
156159248Srwatson	ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
157159248Srwatson	ifp->if_type = IFT_PPP;
158159248Srwatson	ifp->if_snd.ifq_maxlen = ifqmaxlen;
159159248Srwatson	ifp->if_softc = sc;
160159248Srwatson	if_attach(ifp);
161159248Srwatson	bpfattach(ifp, DLT_NULL, sizeof(u_int));
162159248Srwatson	dev->si_drv1 = sc;
163159248Srwatson}
164159248Srwatson
165159248Srwatson/*
166159248Srwatson * tunnel open - must be superuser & the device must be
167159248Srwatson * configured in
168159248Srwatson */
169159248Srwatsonstatic	int
170159248Srwatsontunopen(dev, flag, mode, p)
171159248Srwatson	dev_t	dev;
172159248Srwatson	int	flag, mode;
173159248Srwatson	struct proc *p;
174159248Srwatson{
175159248Srwatson	struct ifnet	*ifp;
176159248Srwatson	struct tun_softc *tp;
177159248Srwatson	register int	error;
178159248Srwatson
179191273Srwatson	error = suser(p);
180159248Srwatson	if (error)
181159248Srwatson		return (error);
182243750Srwatson
183159248Srwatson	tp = dev->si_drv1;
184159248Srwatson	if (!tp) {
185159248Srwatson		tuncreate(dev);
186159248Srwatson		tp = dev->si_drv1;
187159248Srwatson	}
188159248Srwatson	if (tp->tun_flags & TUN_OPEN)
189159248Srwatson		return EBUSY;
190159248Srwatson	tp->tun_pid = p->p_pid;
191159248Srwatson	ifp = &tp->tun_if;
192159248Srwatson	tp->tun_flags |= TUN_OPEN;
193159248Srwatson	TUNDEBUG("%s%d: open\n", ifp->if_name, ifp->if_unit);
194159248Srwatson	return (0);
195159248Srwatson}
196159248Srwatson
197159248Srwatson/*
198159248Srwatson * tunclose - close the device - mark i/f down & delete
199159248Srwatson * routing info
200159248Srwatson */
201159248Srwatsonstatic	int
202159248Srwatsontunclose(dev, foo, bar, p)
203159248Srwatson	dev_t dev;
204159248Srwatson	int foo;
205155131Srwatson	int bar;
206155131Srwatson	struct proc *p;
207155131Srwatson{
208155131Srwatson	register int	s;
209155131Srwatson	struct tun_softc *tp;
210155131Srwatson	struct ifnet	*ifp;
211155131Srwatson	struct mbuf	*m;
212156283Srwatson
213155131Srwatson	tp = dev->si_drv1;
214156283Srwatson	ifp = &tp->tun_if;
215156283Srwatson
216156283Srwatson	tp->tun_flags &= ~TUN_OPEN;
217155131Srwatson	tp->tun_pid = 0;
218155131Srwatson
219155131Srwatson	/*
220155131Srwatson	 * junk all pending output
221155131Srwatson	 */
222155131Srwatson	do {
223155131Srwatson		s = splimp();
224155131Srwatson		IF_DEQUEUE(&ifp->if_snd, m);
225155131Srwatson		splx(s);
226155131Srwatson		if (m)
227155131Srwatson			m_freem(m);
228155131Srwatson	} while (m);
229155131Srwatson
230155131Srwatson	if (ifp->if_flags & IFF_UP) {
231155131Srwatson		s = splimp();
232155131Srwatson		if_down(ifp);
233155131Srwatson		splx(s);
234155131Srwatson	}
235155131Srwatson
236155131Srwatson	if (ifp->if_flags & IFF_RUNNING) {
237155131Srwatson		register struct ifaddr *ifa;
238156283Srwatson
239156283Srwatson		s = splimp();
240155131Srwatson		/* find internet addresses and delete routes */
241155131Srwatson		for (ifa = ifp->if_addrhead.tqh_first; ifa;
242155131Srwatson		    ifa = ifa->ifa_link.tqe_next)
243155131Srwatson			if (ifa->ifa_addr->sa_family == AF_INET)
244155131Srwatson				rtinit(ifa, (int)RTM_DELETE,
245155131Srwatson				    tp->tun_flags & TUN_DSTADDR ? RTF_HOST : 0);
246155131Srwatson		ifp->if_flags &= ~IFF_RUNNING;
247155131Srwatson		splx(s);
248155131Srwatson	}
249155131Srwatson
250155131Srwatson	funsetown(tp->tun_sigio);
251155131Srwatson	selwakeup(&tp->tun_rsel);
252156283Srwatson
253156283Srwatson	TUNDEBUG ("%s%d: closed\n", ifp->if_name, ifp->if_unit);
254156283Srwatson	return (0);
255156283Srwatson}
256155131Srwatson
257155131Srwatsonstatic int
258155131Srwatsontuninit(ifp)
259155131Srwatson	struct ifnet *ifp;
260155131Srwatson{
261155131Srwatson	struct tun_softc *tp = ifp->if_softc;
262155131Srwatson	register struct ifaddr *ifa;
263155131Srwatson
264155131Srwatson	TUNDEBUG("%s%d: tuninit\n", ifp->if_name, ifp->if_unit);
265155131Srwatson
266155131Srwatson	ifp->if_flags |= IFF_UP | IFF_RUNNING;
267155131Srwatson	getmicrotime(&ifp->if_lastchange);
268155131Srwatson
269155131Srwatson	for (ifa = ifp->if_addrhead.tqh_first; ifa;
270155131Srwatson	     ifa = ifa->ifa_link.tqe_next) {
271155131Srwatson#ifdef INET
272155131Srwatson		if (ifa->ifa_addr->sa_family == AF_INET) {
273155131Srwatson		    struct sockaddr_in *si;
274155131Srwatson
275155131Srwatson		    si = (struct sockaddr_in *)ifa->ifa_addr;
276155131Srwatson		    if (si && si->sin_addr.s_addr)
277155131Srwatson			    tp->tun_flags |= TUN_IASET;
278155131Srwatson
279155131Srwatson		    si = (struct sockaddr_in *)ifa->ifa_dstaddr;
280155131Srwatson		    if (si && si->sin_addr.s_addr)
281159248Srwatson			    tp->tun_flags |= TUN_DSTADDR;
282155131Srwatson		}
283155131Srwatson#endif
284155131Srwatson	}
285155131Srwatson	return 0;
286155131Srwatson}
287155131Srwatson
288155131Srwatson/*
289155131Srwatson * Process an ioctl request.
290155131Srwatson */
291155131Srwatsonint
292155131Srwatsontunifioctl(ifp, cmd, data)
293155131Srwatson	struct ifnet *ifp;
294155131Srwatson	u_long	cmd;
295155131Srwatson	caddr_t	data;
296155131Srwatson{
297155131Srwatson	struct ifreq *ifr = (struct ifreq *)data;
298155131Srwatson	struct tun_softc *tp = ifp->if_softc;
299155131Srwatson	struct ifstat *ifs;
300155131Srwatson	int		error = 0, s;
301155131Srwatson
302155131Srwatson	s = splimp();
303155131Srwatson	switch(cmd) {
304155131Srwatson	case SIOCGIFSTATUS:
305155131Srwatson		ifs = (struct ifstat *)data;
306155131Srwatson		if (tp->tun_pid)
307185573Srwatson			sprintf(ifs->ascii + strlen(ifs->ascii),
308155131Srwatson			    "\tOpened by PID %d\n", tp->tun_pid);
309155131Srwatson		return(0);
310155131Srwatson	case SIOCSIFADDR:
311155131Srwatson		tuninit(ifp);
312155131Srwatson		TUNDEBUG("%s%d: address set\n",
313155131Srwatson			 ifp->if_name, ifp->if_unit);
314155131Srwatson		break;
315159248Srwatson	case SIOCSIFDSTADDR:
316155131Srwatson		tuninit(ifp);
317155131Srwatson		TUNDEBUG("%s%d: destination address set\n",
318155131Srwatson			 ifp->if_name, ifp->if_unit);
319155131Srwatson		break;
320155131Srwatson	case SIOCSIFMTU:
321155131Srwatson		ifp->if_mtu = ifr->ifr_mtu;
322159248Srwatson		TUNDEBUG("%s%d: mtu set\n",
323155131Srwatson			 ifp->if_name, ifp->if_unit);
324155131Srwatson		break;
325155131Srwatson	case SIOCADDMULTI:
326155131Srwatson	case SIOCDELMULTI:
327155131Srwatson		break;
328155131Srwatson
329159248Srwatson
330155131Srwatson	default:
331155131Srwatson		error = EINVAL;
332155131Srwatson	}
333155131Srwatson	splx(s);
334155131Srwatson	return (error);
335159248Srwatson}
336155131Srwatson
337155131Srwatson/*
338159248Srwatson * tunoutput - queue packets from higher level ready to put out.
339155131Srwatson */
340155131Srwatsonint
341155131Srwatsontunoutput(ifp, m0, dst, rt)
342155131Srwatson	struct ifnet   *ifp;
343155131Srwatson	struct mbuf    *m0;
344155131Srwatson	struct sockaddr *dst;
345155131Srwatson	struct rtentry *rt;
346155131Srwatson{
347155131Srwatson	struct tun_softc *tp = ifp->if_softc;
348155131Srwatson	int		s;
349155131Srwatson
350155131Srwatson	TUNDEBUG ("%s%d: tunoutput\n", ifp->if_name, ifp->if_unit);
351155131Srwatson
352155131Srwatson	if ((tp->tun_flags & TUN_READY) != TUN_READY) {
353155131Srwatson		TUNDEBUG ("%s%d: not ready 0%o\n", ifp->if_name,
354155131Srwatson			  ifp->if_unit, tp->tun_flags);
355155131Srwatson		m_freem (m0);
356155131Srwatson		return EHOSTDOWN;
357155131Srwatson	}
358155131Srwatson
359155131Srwatson	/* BPF write needs to be handled specially */
360155131Srwatson	if (dst->sa_family == AF_UNSPEC) {
361155131Srwatson		dst->sa_family = *(mtod(m0, int *));
362155131Srwatson		m0->m_len -= sizeof(int);
363155131Srwatson		m0->m_pkthdr.len -= sizeof(int);
364155131Srwatson		m0->m_data += sizeof(int);
365155131Srwatson	}
366155131Srwatson
367155131Srwatson	if (ifp->if_bpf) {
368155131Srwatson		/*
369155131Srwatson		 * We need to prepend the address family as
370155131Srwatson		 * a four byte field.  Cons up a dummy header
371155131Srwatson		 * to pacify bpf.  This is safe because bpf
372155131Srwatson		 * will only read from the mbuf (i.e., it won't
373155131Srwatson		 * try to free it or keep a pointer to it).
374155131Srwatson		 */
375155131Srwatson		struct mbuf m;
376155131Srwatson		u_int af = dst->sa_family;
377155131Srwatson
378155131Srwatson		m.m_next = m0;
379155131Srwatson		m.m_len = 4;
380155131Srwatson		m.m_data = (char *)&af;
381155131Srwatson
382155131Srwatson		bpf_mtap(ifp, &m);
383155131Srwatson	}
384155131Srwatson
385155131Srwatson	/* prepend sockaddr? this may abort if the mbuf allocation fails */
386155131Srwatson	if (tp->tun_flags & TUN_LMODE) {
387155131Srwatson		/* allocate space for sockaddr */
388155131Srwatson		M_PREPEND(m0, dst->sa_len, M_DONTWAIT);
389155131Srwatson
390155131Srwatson		/* if allocation failed drop packet */
391155131Srwatson		if (m0 == NULL){
392155131Srwatson			s = splimp();	/* spl on queue manipulation */
393155131Srwatson			IF_DROP(&ifp->if_snd);
394155131Srwatson			splx(s);
395155131Srwatson			ifp->if_oerrors++;
396155131Srwatson			return (ENOBUFS);
397155131Srwatson		} else {
398155131Srwatson			bcopy(dst, m0->m_data, dst->sa_len);
399155131Srwatson		}
400155131Srwatson	}
401155131Srwatson
402155131Srwatson	if (tp->tun_flags & TUN_IFHEAD) {
403155131Srwatson		/* Prepend the address family */
404155131Srwatson		M_PREPEND(m0, 4, M_DONTWAIT);
405155131Srwatson
406155131Srwatson		/* if allocation failed drop packet */
407155131Srwatson		if (m0 == NULL){
408155131Srwatson			s = splimp();	/* spl on queue manipulation */
409155131Srwatson			IF_DROP(&ifp->if_snd);
410155131Srwatson			splx(s);
411155131Srwatson			ifp->if_oerrors++;
412155131Srwatson			return ENOBUFS;
413155131Srwatson		} else
414155131Srwatson			*(u_int32_t *)m0->m_data = htonl(dst->sa_family);
415155131Srwatson	} else {
416155131Srwatson#ifdef INET
417155131Srwatson		if (dst->sa_family != AF_INET)
418155131Srwatson#endif
419155131Srwatson		{
420155131Srwatson			m_freem(m0);
421155131Srwatson			return EAFNOSUPPORT;
422155131Srwatson		}
423155131Srwatson	}
424155131Srwatson
425155131Srwatson	s = splimp();
426155131Srwatson	if (IF_QFULL(&ifp->if_snd)) {
427155131Srwatson		IF_DROP(&ifp->if_snd);
428155131Srwatson		m_freem(m0);
429155131Srwatson		splx(s);
430155131Srwatson		ifp->if_collisions++;
431155131Srwatson		return ENOBUFS;
432155131Srwatson	}
433155131Srwatson	ifp->if_obytes += m0->m_pkthdr.len;
434155131Srwatson	IF_ENQUEUE(&ifp->if_snd, m0);
435155131Srwatson	splx(s);
436155131Srwatson	ifp->if_opackets++;
437155131Srwatson
438155131Srwatson	if (tp->tun_flags & TUN_RWAIT) {
439155131Srwatson		tp->tun_flags &= ~TUN_RWAIT;
440155131Srwatson		wakeup((caddr_t)tp);
441155131Srwatson	}
442155131Srwatson	if (tp->tun_flags & TUN_ASYNC && tp->tun_sigio)
443155131Srwatson		pgsigio(tp->tun_sigio, SIGIO, 0);
444155131Srwatson	selwakeup(&tp->tun_rsel);
445155131Srwatson	return 0;
446155131Srwatson}
447155131Srwatson
448155131Srwatson/*
449155131Srwatson * the cdevsw interface is now pretty minimal.
450155131Srwatson */
451155131Srwatsonstatic	int
452155131Srwatsontunioctl(dev, cmd, data, flag, p)
453155131Srwatson	dev_t		dev;
454155131Srwatson	u_long		cmd;
455155131Srwatson	caddr_t		data;
456155131Srwatson	int		flag;
457155131Srwatson	struct proc	*p;
458155131Srwatson{
459155131Srwatson	int		s;
460155131Srwatson	struct tun_softc *tp = dev->si_drv1;
461155131Srwatson 	struct tuninfo *tunp;
462155131Srwatson
463155131Srwatson	switch (cmd) {
464155131Srwatson 	case TUNSIFINFO:
465155131Srwatson 		tunp = (struct tuninfo *)data;
466155131Srwatson		if (tunp->mtu < IF_MINMTU)
467155131Srwatson			return (EINVAL);
468155131Srwatson 		tp->tun_if.if_mtu = tunp->mtu;
469155131Srwatson 		tp->tun_if.if_type = tunp->type;
470155131Srwatson 		tp->tun_if.if_baudrate = tunp->baudrate;
471155131Srwatson 		break;
472155131Srwatson 	case TUNGIFINFO:
473155131Srwatson 		tunp = (struct tuninfo *)data;
474155131Srwatson 		tunp->mtu = tp->tun_if.if_mtu;
475155131Srwatson 		tunp->type = tp->tun_if.if_type;
476155131Srwatson 		tunp->baudrate = tp->tun_if.if_baudrate;
477155131Srwatson 		break;
478155131Srwatson	case TUNSDEBUG:
479155131Srwatson		tundebug = *(int *)data;
480155131Srwatson		break;
481155131Srwatson	case TUNGDEBUG:
482155131Srwatson		*(int *)data = tundebug;
483155131Srwatson		break;
484155131Srwatson	case TUNSLMODE:
485155131Srwatson		if (*(int *)data) {
486155131Srwatson			tp->tun_flags |= TUN_LMODE;
487155131Srwatson			tp->tun_flags &= ~TUN_IFHEAD;
488155131Srwatson		} else
489191273Srwatson			tp->tun_flags &= ~TUN_LMODE;
490191273Srwatson		break;
491191273Srwatson	case TUNSIFHEAD:
492191273Srwatson		if (*(int *)data) {
493191273Srwatson			tp->tun_flags |= TUN_IFHEAD;
494191273Srwatson			tp->tun_flags &= ~TUN_LMODE;
495191273Srwatson		} else
496191273Srwatson			tp->tun_flags &= ~TUN_IFHEAD;
497191273Srwatson		break;
498191273Srwatson	case TUNGIFHEAD:
499191273Srwatson		*(int *)data = (tp->tun_flags & TUN_IFHEAD) ? 1 : 0;
500191273Srwatson		break;
501191273Srwatson	case TUNSIFMODE:
502191273Srwatson		/* deny this if UP */
503191273Srwatson		if (tp->tun_if.if_flags & IFF_UP)
504191273Srwatson			return(EBUSY);
505191273Srwatson
506191273Srwatson		switch (*(int *)data) {
507191273Srwatson		case IFF_POINTOPOINT:
508191273Srwatson			tp->tun_if.if_flags |= IFF_POINTOPOINT;
509191273Srwatson			tp->tun_if.if_flags &= ~IFF_BROADCAST;
510191273Srwatson			break;
511191273Srwatson		case IFF_BROADCAST:
512191273Srwatson			tp->tun_if.if_flags &= ~IFF_POINTOPOINT;
513191273Srwatson			tp->tun_if.if_flags |= IFF_BROADCAST;
514191273Srwatson			break;
515191273Srwatson		default:
516191273Srwatson			return(EINVAL);
517191273Srwatson		}
518191273Srwatson		break;
519191273Srwatson	case TUNSIFPID:
520191273Srwatson		tp->tun_pid = curproc->p_pid;
521191273Srwatson		break;
522191273Srwatson	case FIONBIO:
523191273Srwatson		break;
524191273Srwatson	case FIOASYNC:
525191273Srwatson		if (*(int *)data)
526191273Srwatson			tp->tun_flags |= TUN_ASYNC;
527191273Srwatson		else
528191273Srwatson			tp->tun_flags &= ~TUN_ASYNC;
529191273Srwatson		break;
530191273Srwatson	case FIONREAD:
531191273Srwatson		s = splimp();
532191273Srwatson		if (tp->tun_if.if_snd.ifq_head) {
533191273Srwatson			struct mbuf *mb = tp->tun_if.if_snd.ifq_head;
534191273Srwatson			for( *(int *)data = 0; mb != 0; mb = mb->m_next)
535191273Srwatson				*(int *)data += mb->m_len;
536191273Srwatson		} else
537191273Srwatson			*(int *)data = 0;
538191273Srwatson		splx(s);
539191273Srwatson		break;
540191273Srwatson	case FIOSETOWN:
541191273Srwatson		return (fsetown(*(int *)data, &tp->tun_sigio));
542191273Srwatson
543191273Srwatson	case FIOGETOWN:
544191273Srwatson		*(int *)data = fgetown(tp->tun_sigio);
545191273Srwatson		return (0);
546191273Srwatson
547191273Srwatson	/* This is deprecated, FIOSETOWN should be used instead. */
548191273Srwatson	case TIOCSPGRP:
549191273Srwatson		return (fsetown(-(*(int *)data), &tp->tun_sigio));
550191273Srwatson
551191273Srwatson	/* This is deprecated, FIOGETOWN should be used instead. */
552191273Srwatson	case TIOCGPGRP:
553191273Srwatson		*(int *)data = -fgetown(tp->tun_sigio);
554191273Srwatson		return (0);
555191273Srwatson
556191273Srwatson	default:
557191273Srwatson		return (ENOTTY);
558191273Srwatson	}
559191273Srwatson	return (0);
560191273Srwatson}
561191273Srwatson
562191273Srwatson/*
563191273Srwatson * The cdevsw read interface - reads a packet at a time, or at
564191273Srwatson * least as much of a packet as can be read.
565191273Srwatson */
566191273Srwatsonstatic	int
567191273Srwatsontunread(dev, uio, flag)
568191273Srwatson	dev_t dev;
569191273Srwatson	struct uio *uio;
570191273Srwatson	int flag;
571191273Srwatson{
572191273Srwatson	struct tun_softc *tp = dev->si_drv1;
573191273Srwatson	struct ifnet	*ifp = &tp->tun_if;
574191273Srwatson	struct mbuf	*m, *m0;
575191273Srwatson	int		error=0, len, s;
576191273Srwatson
577191273Srwatson	TUNDEBUG ("%s%d: read\n", ifp->if_name, ifp->if_unit);
578191273Srwatson	if ((tp->tun_flags & TUN_READY) != TUN_READY) {
579191273Srwatson		TUNDEBUG ("%s%d: not ready 0%o\n", ifp->if_name,
580191273Srwatson			  ifp->if_unit, tp->tun_flags);
581191273Srwatson		return EHOSTDOWN;
582191273Srwatson	}
583191273Srwatson
584191273Srwatson	tp->tun_flags &= ~TUN_RWAIT;
585191273Srwatson
586191273Srwatson	s = splimp();
587191273Srwatson	do {
588191273Srwatson		IF_DEQUEUE(&ifp->if_snd, m0);
589191273Srwatson		if (m0 == 0) {
590191273Srwatson			if (flag & IO_NDELAY) {
591191273Srwatson				splx(s);
592191273Srwatson				return EWOULDBLOCK;
593191273Srwatson			}
594191273Srwatson			tp->tun_flags |= TUN_RWAIT;
595191273Srwatson			if((error = tsleep((caddr_t)tp, PCATCH | (PZERO + 1),
596191273Srwatson					"tunread", 0)) != 0) {
597191273Srwatson				splx(s);
598191273Srwatson				return error;
599191273Srwatson			}
600191273Srwatson		}
601191273Srwatson	} while (m0 == 0);
602191273Srwatson	splx(s);
603191273Srwatson
604191273Srwatson	while (m0 && uio->uio_resid > 0 && error == 0) {
605191273Srwatson		len = min(uio->uio_resid, m0->m_len);
606191273Srwatson		if (len == 0)
607191273Srwatson			break;
608191273Srwatson		error = uiomove(mtod(m0, caddr_t), len, uio);
609191273Srwatson		MFREE(m0, m);
610191273Srwatson		m0 = m;
611191273Srwatson	}
612191273Srwatson
613191273Srwatson	if (m0) {
614191273Srwatson		TUNDEBUG("Dropping mbuf\n");
615191273Srwatson		m_freem(m0);
616191273Srwatson	}
617191273Srwatson	return error;
618191273Srwatson}
619191273Srwatson
620191273Srwatson/*
621191273Srwatson * the cdevsw write interface - an atomic write is a packet - or else!
622191273Srwatson */
623191273Srwatsonstatic	int
624191273Srwatsontunwrite(dev, uio, flag)
625191273Srwatson	dev_t dev;
626191273Srwatson	struct uio *uio;
627191273Srwatson	int flag;
628191273Srwatson{
629191273Srwatson	struct tun_softc *tp = dev->si_drv1;
630191273Srwatson	struct ifnet	*ifp = &tp->tun_if;
631191273Srwatson	struct mbuf	*top, **mp, *m;
632191273Srwatson	int		error=0, tlen, mlen;
633191273Srwatson	u_int32_t	family;
634191273Srwatson
635191273Srwatson	TUNDEBUG("%s%d: tunwrite\n", ifp->if_name, ifp->if_unit);
636191273Srwatson
637191273Srwatson	if (uio->uio_resid == 0)
638191273Srwatson		return 0;
639191273Srwatson
640191273Srwatson	if (uio->uio_resid < 0 || uio->uio_resid > TUNMRU) {
641191273Srwatson		TUNDEBUG("%s%d: len=%d!\n", ifp->if_name, ifp->if_unit,
642191273Srwatson		    uio->uio_resid);
643191273Srwatson		return EIO;
644191273Srwatson	}
645191273Srwatson	tlen = uio->uio_resid;
646191273Srwatson
647191273Srwatson	/* get a header mbuf */
648191273Srwatson	MGETHDR(m, M_DONTWAIT, MT_DATA);
649191273Srwatson	if (m == NULL)
650191273Srwatson		return ENOBUFS;
651191273Srwatson	mlen = MHLEN;
652191273Srwatson
653191273Srwatson	top = 0;
654191273Srwatson	mp = &top;
655191273Srwatson	while (error == 0 && uio->uio_resid > 0) {
656191273Srwatson		m->m_len = min(mlen, uio->uio_resid);
657191273Srwatson		error = uiomove(mtod (m, caddr_t), m->m_len, uio);
658191273Srwatson		*mp = m;
659191273Srwatson		mp = &m->m_next;
660191273Srwatson		if (uio->uio_resid > 0) {
661191273Srwatson			MGET (m, M_DONTWAIT, MT_DATA);
662191273Srwatson			if (m == 0) {
663191273Srwatson				error = ENOBUFS;
664191273Srwatson				break;
665191273Srwatson			}
666191273Srwatson			mlen = MLEN;
667191273Srwatson		}
668191273Srwatson	}
669191273Srwatson	if (error) {
670191273Srwatson		if (top)
671191273Srwatson			m_freem (top);
672191273Srwatson		ifp->if_ierrors++;
673191273Srwatson		return error;
674191273Srwatson	}
675191273Srwatson
676191273Srwatson	top->m_pkthdr.len = tlen;
677191273Srwatson	top->m_pkthdr.rcvif = ifp;
678191273Srwatson
679191273Srwatson	if (ifp->if_bpf) {
680191273Srwatson		if (tp->tun_flags & TUN_IFHEAD)
681191273Srwatson			/*
682191273Srwatson			 * Conveniently, we already have a 4-byte address
683191273Srwatson			 * family prepended to our packet !
684191273Srwatson			 */
685191273Srwatson			bpf_mtap(ifp, top);
686191273Srwatson		else {
687191273Srwatson			/*
688191273Srwatson			 * We need to prepend the address family as
689191273Srwatson			 * a four byte field.  Cons up a dummy header
690191273Srwatson			 * to pacify bpf.  This is safe because bpf
691191273Srwatson			 * will only read from the mbuf (i.e., it won't
692191273Srwatson			 * try to free it or keep a pointer to it).
693191273Srwatson			 */
694191273Srwatson			struct mbuf m;
695191273Srwatson			u_int af = AF_INET;
696191273Srwatson
697191273Srwatson			m.m_next = top;
698191273Srwatson			m.m_len = 4;
699191273Srwatson			m.m_data = (char *)&af;
700191273Srwatson
701191273Srwatson			bpf_mtap(ifp, &m);
702191273Srwatson		}
703191273Srwatson	}
704191273Srwatson
705191273Srwatson	if (tp->tun_flags & TUN_IFHEAD) {
706191273Srwatson		if (top->m_len < sizeof(family) &&
707191273Srwatson		    (top = m_pullup(top, sizeof(family))) == NULL)
708191273Srwatson				return ENOBUFS;
709191273Srwatson		family = ntohl(*mtod(top, u_int32_t *));
710191273Srwatson		m_adj(top, sizeof(family));
711191273Srwatson	} else
712191273Srwatson		family = AF_INET;
713191273Srwatson
714191273Srwatson	ifp->if_ibytes += top->m_pkthdr.len;
715191273Srwatson	ifp->if_ipackets++;
716191273Srwatson
717191273Srwatson	return family_enqueue(family, top);
718191273Srwatson}
719191273Srwatson
720191273Srwatson/*
721191273Srwatson * tunpoll - the poll interface, this is only useful on reads
722191273Srwatson * really. The write detect always returns true, write never blocks
723191273Srwatson * anyway, it either accepts the packet or drops it.
724191273Srwatson */
725191273Srwatsonstatic	int
726191273Srwatsontunpoll(dev, events, p)
727191273Srwatson	dev_t dev;
728191273Srwatson	int events;
729191273Srwatson	struct proc *p;
730191273Srwatson{
731191273Srwatson	int		s;
732191273Srwatson	struct tun_softc *tp = dev->si_drv1;
733191273Srwatson	struct ifnet	*ifp = &tp->tun_if;
734191273Srwatson	int		revents = 0;
735191273Srwatson
736191273Srwatson	s = splimp();
737191273Srwatson	TUNDEBUG("%s%d: tunpoll\n", ifp->if_name, ifp->if_unit);
738191273Srwatson
739191273Srwatson	if (events & (POLLIN | POLLRDNORM)) {
740191273Srwatson		if (ifp->if_snd.ifq_len > 0) {
741191273Srwatson			TUNDEBUG("%s%d: tunpoll q=%d\n", ifp->if_name,
742191273Srwatson			    ifp->if_unit, ifp->if_snd.ifq_len);
743191273Srwatson			revents |= events & (POLLIN | POLLRDNORM);
744191273Srwatson		} else {
745191273Srwatson			TUNDEBUG("%s%d: tunpoll waiting\n", ifp->if_name,
746191273Srwatson			    ifp->if_unit);
747191273Srwatson			selrecord(p, &tp->tun_rsel);
748191273Srwatson		}
749191273Srwatson	}
750191273Srwatson	if (events & (POLLOUT | POLLWRNORM))
751191273Srwatson		revents |= events & (POLLOUT | POLLWRNORM);
752191273Srwatson
753191273Srwatson	splx(s);
754191273Srwatson	return (revents);
755191273Srwatson}
756191273Srwatson