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