Home | History | Annotate | Line # | Download | only in net
if_tun.c revision 1.6
      1 /*
      2  * Copyright (c) 1988, Julian Onions.
      3  *
      4  * This source may be freely distributed, however I would be interested
      5  * in any changes that are made.
      6  *
      7  *  if_tun.c - tunnel interface module & driver
      8  *
      9  * $Id: if_tun.c,v 1.6 1993/11/14 20:07:20 deraadt Exp $
     10  */
     11 
     12 #include "tun.h"
     13 #if NTUN > 0
     14 
     15 /*
     16  * Tunnel driver.
     17  *
     18  * This driver takes packets off the IP i/f and hands them up to a
     19  * user process to have it's wicked way with. This driver has it's
     20  * roots in a similar driver written by Phil Cockcroft (formerly) at
     21  * UCL. This driver is based much more on read/write/select mode of
     22  * operation though.
     23  *
     24  * Julian Onions <jpo (at) cs.nott.ac.uk>
     25  * Nottingham University 1987.
     26  */
     27 
     28 #include <sys/param.h>
     29 #include <sys/systm.h>
     30 #include <sys/mbuf.h>
     31 #include <sys/buf.h>
     32 #include <sys/protosw.h>
     33 #include <sys/socket.h>
     34 #include <sys/ioctl.h>
     35 #include <sys/errno.h>
     36 #include <sys/syslog.h>
     37 #include <sys/select.h>
     38 
     39 #include <net/if.h>
     40 #include <net/if_tun.h>
     41 #include <net/netisr.h>
     42 #include <net/route.h>
     43 
     44 #ifdef INET
     45 #include <netinet/in.h>
     46 #include <netinet/in_systm.h>
     47 #include <netinet/in_var.h>
     48 #include <netinet/ip.h>
     49 #include <netinet/if_ether.h>
     50 #endif
     51 
     52 #ifdef NS
     53 #include <netns/ns.h>
     54 #include <netns/ns_if.h>
     55 #endif
     56 
     57 #define TUNDEBUG	if (tundebug) printf
     58 int	tundebug = 0;
     59 
     60 struct tun_softc tunctl[NTUN];
     61 extern int ifqmaxlen;
     62 
     63 int	tunoutput __P((dev_t, int, int, struct proc *));
     64 int	tunclose __P((dev_t, int));
     65 int	tunoutput __P((struct ifnet *, struct mbuf *, struct sockaddr *));
     66 int	tunread __P((dev_t, struct uio *));
     67 int	tunwrite __P((dev_t, struct uio *));
     68 int	tuncioctl __P((dev_t, int, caddr_t, data);
     69 int	tunioctl __P((struct ifnet *, int, caddr_t, int));
     70 int	tunselect __P((dev_t, int);
     71 
     72 static int tunattach __P((int));
     73 static int tuninit __P((int));
     74 
     75 /*
     76  * tunnel open - must be superuser & the device must be
     77  * configured in
     78  */
     79 int
     80 tunopen(dev, flag, mode, p)
     81 	dev_t	dev;
     82 	int	flag, mode;
     83 	struct proc *p;
     84 {
     85 	struct ifnet	*ifp;
     86 	struct tunctl	*tp;
     87 	register int	unit, error;
     88 
     89 	if (error = suser(p->p_ucred, &p->p_acflag))
     90 		return (error);
     91 
     92 	if ((unit = minor(dev)) >= NTUN)
     93 		return (ENXIO);
     94 	tp = &tunctl[unit];
     95 	if (tp->tun_flags & TUN_OPEN)
     96 		return ENXIO;
     97 	if ((tp->tun_flags & TUN_INITED) == 0) {
     98 		tp->tun_flags = TUN_INITED;
     99 		tunattach(unit);
    100 	}
    101 	ifp = &tp->tun_if;
    102 	tp->tun_flags |= TUN_OPEN;
    103 	TUNDEBUG("%s%d: open\n", ifp->if_name, ifp->if_unit);
    104 	return (0);
    105 }
    106 
    107 /*
    108  * tunclose - close the device - mark i/f down & delete
    109  * routing info
    110  */
    111 int
    112 tunclose(dev, flag)
    113 	dev_t	dev;
    114 	int	flag;
    115 {
    116 	struct tunctl	*tp = &tunctl[unit];
    117 	struct ifnet	*ifp = &tp->tun_if;
    118 	struct mbuf	*m;
    119 	register int	unit = minor(dev), s;
    120 
    121 	tp->tun_flags &= TUN_INITED;
    122 
    123 	/*
    124 	 * junk all pending output
    125 	 */
    126 	do {
    127 		s = splimp();
    128 		IF_DEQUEUE(&ifp->if_snd, m);
    129 		splx(s);
    130 		if (m)
    131 			m_freem(m);
    132 	} while (m);
    133 
    134 	if (ifp->if_flags & IFF_UP) {
    135 		s = splimp();
    136 		if_down(ifp);
    137 		if (ifp->if_flags & IFF_RUNNING)
    138 			rtinit(ifp->if_addrlist, (int)SIOCDELRT, RTF_HOST);
    139 		splx(s);
    140 	}
    141 	tp->tun_pgrp = 0;
    142 	if (tp->tun_rsel)
    143 		selwakeup(&tp->tun_rsel);
    144 
    145 	tp->tun_rsel = tp->tun_wsel = (struct proc *)0;
    146 
    147 	TUNDEBUG ("%s%d: closed\n", ifp->if_name, ifp->if_unit);
    148 	return (0);
    149 }
    150 
    151 /*
    152  * attach an interface N.B. argument is not same as other drivers
    153  */
    154 static int
    155 tunattach(unit)
    156 	int	unit;
    157 {
    158 	struct ifnet	*ifp = &tunctl[unit].tun_if;
    159 	struct sockaddr_in *sin;
    160 
    161 	ifp->if_unit = unit;
    162 	ifp->if_name = "tun";
    163 	ifp->if_mtu = TUNMTU;
    164 	ifp->if_ioctl = tunioctl;
    165 	ifp->if_output = tunoutput;
    166 	ifp->if_flags = IFF_POINTOPOINT;
    167 	ifp->if_snd.ifq_maxlen = ifqmaxlen;
    168 	ifp->if_collisions = 0;
    169 	ifp->if_ierrors = 0;
    170 	ifp->if_oerrors = 0;
    171 	ifp->if_ipackets = 0;
    172 	ifp->if_opackets = 0;
    173 	if_attach(ifp);
    174 	TUNDEBUG("%s%d: tunattach\n", ifp->if_name, ifp->if_unit);
    175 	return 0;
    176 }
    177 
    178 static int
    179 tuninit(unit)
    180 	int	unit;
    181 {
    182 	struct tunctl	*tp = &tunctl[unit];
    183 	struct ifnet	*ifp = &tp->tun_if;
    184 
    185 	ifp->if_flags |= IFF_UP | IFF_RUNNING;
    186 	tp->tun_flags |= TUN_IASET;
    187 	TUNDEBUG("%s%d: tuninit\n", ifp->if_name, ifp->if_unit);
    188 	return 0;
    189 }
    190 
    191 /*
    192  * Process an ioctl request.
    193  */
    194 int
    195 tunioctl(ifp, cmd, data, flag)
    196 	struct ifnet *ifp;
    197 	int	cmd;
    198 	caddr_t	data;
    199 	int	flag;
    200 {
    201 	int		error = 0, s;
    202 	struct tunctl	*tp = &tunctl[ifp->if_unit];
    203 
    204 	s = splimp();
    205 	switch(cmd) {
    206 	case SIOCSIFADDR:
    207 		tuninit(ifp->if_unit);
    208 		break;
    209 	case SIOCSIFDSTADDR:
    210 		tp->tun_flags |= TUN_DSTADDR;
    211 		TUNDEBUG("%s%d: destination address set\n", ifp->if_name,
    212 		    ifp->if_unit);
    213 		break;
    214 	default:
    215 		error = EINVAL;
    216 	}
    217 	splx(s);
    218 	return (error);
    219 }
    220 
    221 /*
    222  * tunoutput - queue packets from higher level ready to put out.
    223  */
    224 int
    225 tunoutput(ifp, m0, dst)
    226 	struct ifnet   *ifp;
    227 	struct mbuf    *m0;
    228 	struct sockaddr *dst;
    229 {
    230 	struct tunctl	*tp = &tunctl[ifp->if_unit];
    231 	struct proc	*p;
    232 	int		s;
    233 
    234 	TUNDEBUG ("%s%d: tunoutput\n", ifp->if_name, ifp->if_unit);
    235 
    236 	switch(dst->sa_family) {
    237 #ifdef INET
    238 	case AF_INET:
    239 		s = splimp();
    240 		if (IF_QFULL(&ifp->if_snd)) {
    241 			IF_DROP(&ifp->if_snd);
    242 			m_freem(m0);
    243 			splx(s);
    244 			ifp->if_collisions++;
    245 			return (ENOBUFS);
    246 		}
    247 		IF_ENQUEUE(&ifp->if_snd, m0);
    248 		splx(s);
    249 		ifp->if_opackets++;
    250 		break;
    251 #endif
    252 	default:
    253 		m_freem(m0);
    254 		return EAFNOSUPPORT;
    255 	}
    256 
    257 	if (tp->tun_flags & TUN_RWAIT) {
    258 		tp->tun_flags &= ~TUN_RWAIT;
    259 		wakeup((caddr_t)tp);
    260 	}
    261 	if (tp->tun_flags & TUN_ASYNC && tp->tun_pgrp) {
    262 		if (tp->tun_pgrp > 0)
    263 			gsignal(tp->tun_pgrp, SIGIO);
    264 		else if (p = pfind(-tp->tun_pgrp))
    265 			psignal(p, SIGIO);
    266 	}
    267 	selwakeup(&tp->tun_rsel);
    268 	return 0;
    269 }
    270 
    271 /*
    272  * the cdevsw interface is now pretty minimal.
    273  */
    274 int
    275 tuncioctl(dev, cmd, data, flag)
    276 	dev_t		dev;
    277 	int		cmd;
    278 	caddr_t		data;
    279 	int		flag;
    280 {
    281 	int		unit = minor(dev), s;
    282 	struct tunctl	*tp = &tunctl[unit];
    283 
    284 	switch (cmd) {
    285 	case TUNSDEBUG:
    286 		tundebug = *(int *)data;
    287 		break;
    288 	case TUNGDEBUG:
    289 		*(int *)data = tundebug;
    290 		break;
    291 	case FIONBIO:
    292 		if (*(int *)data)
    293 			tp->tun_flags |= TUN_NBIO;
    294 		else
    295 			tp->tun_flags &= ~TUN_NBIO;
    296 		break;
    297 	case FIOASYNC:
    298 		if (*(int *)data)
    299 			tp->tun_flags |= TUN_ASYNC;
    300 		else
    301 			tp->tun_flags &= ~TUN_ASYNC;
    302 		break;
    303 	case FIONREAD:
    304 		s = splimp();
    305 		if (tp->tun_if.if_snd.ifq_head)
    306 			*(int *)data = tp->tun_if.if_snd.ifq_head->m_len;
    307 		else
    308 			*(int *)data = 0;
    309 		splx(s);
    310 		break;
    311 	case TIOCSPGRP:
    312 		tp->tun_pgrp = *(int *)data;
    313 		break;
    314 	case TIOCGPGRP:
    315 		*(int *)data = tp->tun_pgrp;
    316 		break;
    317 	default:
    318 		return (ENOTTY);
    319 	}
    320 	return (0);
    321 }
    322 
    323 /*
    324  * The cdevsw read interface - reads a packet at a time, or at
    325  * least as much of a packet as can be read.
    326  */
    327 int
    328 tunread(dev, uio)
    329 	dev_t		dev;
    330 	struct uio	*uio;
    331 {
    332 	struct ifnet	*ifp = &tp->tun_if;
    333 	struct mbuf	*m, *m0;
    334 	struct tunctl	*tp = &tunctl[unit];
    335 	int		unit = minor(dev);
    336 	int		error=0, len, s;
    337 
    338 	TUNDEBUG ("%s%d: read\n", ifp->if_name, ifp->if_unit);
    339 	tp->tun_flags &= ~TUN_RWAIT;
    340 
    341 	s = splimp();
    342 	do {
    343 		IF_DEQUEUE(&ifp->if_snd, m0);
    344 		if (m0 == 0) {
    345 			if (tp->tun_flags & TUN_NBIO) {
    346 				splx(s);
    347 				return EWOULDBLOCK;
    348 			}
    349 			tp->tun_flags |= TUN_RWAIT;
    350 			tsleep((caddr_t)tp, PZERO + 1, "tunread", 0);
    351 		}
    352 	} while (m0 == 0);
    353 	splx(s);
    354 
    355 	while (m0 && uio->uio_resid > 0 && error == 0) {
    356 		len = MIN(uio->uio_resid, m0->m_len);
    357 		if (len == 0)
    358 			break;
    359 		error = uiomove(mtod(m0, caddr_t), len,
    360 		    UIO_READ, uio);
    361 		MFREE(m0, m);
    362 		m0 = m;
    363 	}
    364 
    365 	if (m0) {
    366 		TUNDEBUG("Dropping mbuf\n");
    367 		m_freem(m0);
    368 	}
    369 	return error;
    370 }
    371 
    372 /*
    373  * the cdevsw write interface - an atomic write is a packet - or else!
    374  */
    375 int
    376 tunwrite(dev, uio)
    377 	int		dev;
    378 	struct uio	*uio;
    379 {
    380 	int		unit = minor (dev);
    381 	struct ifnet	*ifp = &(tunctl[unit].tun_if);
    382 	struct mbuf	*top, **mp, *m;
    383 	int		error=0, s;
    384 
    385 	TUNDEBUG("%s%d: tunwrite\n", ifp->if_name, ifp->if_unit);
    386 
    387 	if (uio->uio_resid < 0 || uio->uio_resid > TUNMTU) {
    388 		TUNDEBUG("%s%d: len=%d!\n", ifp->if_name, ifp->if_unit,
    389 		    uio->uio_resid);
    390 		return EIO;
    391 	}
    392 	top = 0;
    393 	mp = &top;
    394 	while (error == 0 && uio->uio_resid > 0) {
    395 		MGET(m, M_DONTWAIT, MT_DATA);
    396 		if (m == 0) {
    397 			error = ENOBUFS;
    398 			break;
    399 		}
    400 		m->m_len = MIN(MLEN, uio->uio_resid);
    401 		error = uiomove(mtod(m, caddr_t), m->m_len, UIO_WRITE, uio);
    402 		*mp = m;
    403 		mp = &m->m_next;
    404 	}
    405 	if (error) {
    406 		if (top)
    407 			m_freem(top);
    408 		return error;
    409 	}
    410 
    411 	/*
    412 	 * Place interface pointer before the data
    413 	 * for the receiving protocol.
    414 	 */
    415 	if (top->m_off <= MMAXOFF &&
    416 	    top->m_off >= MMINOFF + sizeof(struct ifnet *)) {
    417 		top->m_off -= sizeof(struct ifnet *);
    418 		top->m_len += sizeof(struct ifnet *);
    419 	} else {
    420 		MGET(m, M_DONTWAIT, MT_HEADER);
    421 		if (m == (struct mbuf *)0)
    422 			return (ENOBUFS);
    423 		m->m_len = sizeof(struct ifnet *);
    424 		m->m_next = top;
    425 		top = m;
    426 	}
    427 	*(mtod(top, struct ifnet **)) = ifp;
    428 
    429 	s = splimp();
    430 	if (IF_QFULL (&ipintrq)) {
    431 		IF_DROP(&ipintrq);
    432 		splx(s);
    433 		ifp->if_collisions++;
    434 		m_freem(top);
    435 		return ENOBUFS;
    436 	}
    437 	IF_ENQUEUE(&ipintrq, top);
    438 	splx(s);
    439 	ifp->if_ipackets++;
    440 	schednetisr(NETISR_IP);
    441 	return error;
    442 }
    443 
    444 /*
    445  * tunselect - the select interface, this is only useful on reads
    446  * really. The write detect always returns true, write never blocks
    447  * anyway, it either accepts the packet or drops it.
    448  */
    449 int
    450 tunselect(dev, rw)
    451 	dev_t		dev;
    452 	int		rw;
    453 {
    454 	int		unit = minor(dev), s;
    455 	struct tunctl	*tp = &tunctl[unit];
    456 	struct ifnet	*ifp = &tp->tun_if;
    457 
    458 	s = splimp();
    459 	TUNDEBUG("%s%d: tunselect\n", ifp->if_name, ifp->if_unit);
    460 
    461 	switch (rw) {
    462 	case FREAD:
    463 		if (ifp->if_snd.ifq_len > 0) {
    464 			splx(s);
    465 			TUNDEBUG("%s%d: tunselect q=%d\n", ifp->if_name,
    466 			    ifp->if_unit, ifp->if_snd.ifq_len);
    467 			return 1;
    468 		}
    469 		selrecord(p, &tp->tun_rsel);
    470 		break;
    471 	case FWRITE:
    472 		splx(s);
    473 		return 1;
    474 	}
    475 	splx(s);
    476 	TUNDEBUG("%s%d: tunselect waiting\n", ifp->if_name, ifp->if_unit);
    477 	return 0;
    478 }
    479 #endif  NTUN
    480