Home | History | Annotate | Line # | Download | only in net
if_tun.c revision 1.5.2.1
      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.2.1 1993/11/03 21:31:40 mycroft 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 #ifndef BSD4_3
    163         sin = (struct sockaddr_in *) & ifp->if_addr;
    164         sin->sin_family = AF_INET;
    165 #endif
    166         ifp->if_flags = IFF_POINTOPOINT;
    167         ifp->if_snd.ifq_maxlen = ifqmaxlen;
    168         ifp->if_collisions = ifp->if_ierrors = ifp->if_oerrors = 0;
    169         ifp->if_ipackets = ifp->if_opackets = 0;
    170         if_attach (ifp);
    171         TUNDEBUG ("%s%d: tunattach\n", ifp->if_name, ifp->if_unit);
    172         return 0;
    173 }
    174 
    175 int
    176 tuninit (unit)
    177 int             unit;
    178 {
    179         register struct tunctl *tp = &tunctl[unit];
    180         register struct ifnet *ifp = &tp->tun_if;
    181 #ifndef BSD4_3
    182         register struct sockaddr_in *sin;
    183 
    184         sin = (struct sockaddr_in *) & ifp->if_addr;
    185         if (sin->sin_addr.s_addr == 0)  /* if address still unknown */
    186                 return;
    187         if_rtinit (ifp, RTF_UP);
    188 #endif
    189         ifp->if_flags |= IFF_UP | IFF_RUNNING;
    190         tp->tun_flags |= TUN_IASET;
    191         TUNDEBUG ("%s%d: tuninit\n", ifp->if_name, ifp->if_unit);
    192         return 0;
    193 }
    194 
    195 /*
    196  * Process an ioctl request.
    197  * The problem here is 4.2 pass a struct ifreq * to this routine,
    198  * sun only passes a struct sockaddr * since 3.2 at least. This is
    199  * rather upsetting! Also, sun doesn't pass the SIOCDSTADDR ioctl through
    200  * so we can't detect this being set directly. This is the reason for
    201  * tuncheckready.
    202  * Under 4.3 and SunOs 4.0 we now get the SIOCSIFDSTADDR ioctl, and we get a
    203  * struct in_ifaddr * for data. (tte)
    204  */
    205 
    206 #if !defined(BSD4_3) && defined(sun)
    207 
    208 /*
    209  * workaround for not being able to detect DSTADDR being set.
    210  */
    211 
    212 tuncheckready (ifp)
    213 struct ifnet *ifp;
    214 {
    215         struct tunctl *tp = &tunctl[ifp->if_unit];
    216         struct sockaddr_in *sin;
    217 
    218         sin = (struct sockaddr_in *) &ifp->if_dstaddr;
    219         if (sin->sin_addr.s_addr == 0)
    220                 return 0;
    221         tp -> tun_flags |= TUN_DSTADDR;
    222         return 1;
    223 }
    224 #else
    225 #define tuncheckready(dummy) 1
    226 #endif /* !defined(BSD4_3) && defined(sun) */
    227 
    228 int
    229 tunioctl (ifp, cmd, data)
    230 register struct ifnet *ifp;
    231 int             cmd;
    232 caddr_t         data;
    233 {
    234 #ifndef BSD4_3
    235 #ifdef sun
    236         struct sockaddr_in *sin = (struct sockaddr_in *) data;
    237 #else
    238         struct sockaddr_in *sin;
    239         struct ifreq    *ifr = (struct ifreq *) data;
    240 #endif
    241 #endif /* BSD4_3 */
    242 
    243         int             s = splimp (), error = 0;
    244         struct tunctl  *tp = &tunctl[ifp->if_unit];
    245 
    246         switch (cmd)
    247         {
    248             case SIOCSIFADDR:
    249 #ifndef BSD4_3
    250                 if (ifp->if_flags & IFF_RUNNING)
    251                         if_rtinit (ifp, -1);    /* delete previous route */
    252 #ifndef sun
    253                 sin = (struct sockaddr_in *)&ifr -> ifr_addr;
    254 #endif
    255                 ifp->if_addr = *((struct sockaddr *) sin);
    256                 ifp->if_net = in_netof (sin->sin_addr);
    257                 ifp->if_host[0] = in_lnaof (sin->sin_addr);
    258 #endif
    259                 tuninit (ifp->if_unit);
    260                 break;
    261             case SIOCSIFDSTADDR:
    262                 tp->tun_flags |= TUN_DSTADDR;
    263 #ifndef BSD4_3
    264 #ifndef sun
    265                 sin = (struct sockaddr_in *)&ifr -> ifr_addr;
    266 #endif
    267                 ifp->if_dstaddr = *((struct sockaddr *)sin);
    268 #endif BSD4_3
    269                 TUNDEBUG ("%s%d: destination addres set\n", ifp->if_name,
    270                         ifp -> if_unit);
    271                 break;
    272             default:
    273                 error = EINVAL;
    274         }
    275         splx (s);
    276         return (error);
    277 }
    278 
    279 /*
    280  * tunoutput - queue packets from higher level ready to put out.
    281  */
    282 tunoutput (ifp, m0, dst)
    283 struct ifnet   *ifp;
    284 struct mbuf    *m0;
    285 struct sockaddr *dst;
    286 {
    287         struct tunctl  *tp;
    288         struct proc     *p;
    289         int             s;
    290 
    291         TUNDEBUG ("%s%d: tunoutput\n", ifp->if_name, ifp->if_unit);
    292         tp = &tunctl[ifp->if_unit];
    293         if ((tp->tun_flags & TUN_READY) != TUN_READY) {
    294                 if(tuncheckready(ifp) == 0) {
    295                         TUNDEBUG ("%s%d: not ready 0%o\n", ifp->if_name,
    296                                 ifp->if_unit, tp->tun_flags);
    297                         m_freem (m0);
    298                         return EHOSTDOWN;
    299                 }
    300         }
    301 
    302         switch (dst->sa_family) {
    303 #ifdef INET
    304             case AF_INET:
    305                 s = splimp ();
    306                 if (IF_QFULL (&ifp->if_snd))
    307                 {
    308                         IF_DROP (&ifp->if_snd);
    309                         m_freem (m0);
    310                         splx (s);
    311                         ifp->if_collisions++;
    312                         return (ENOBUFS);
    313                 }
    314                 IF_ENQUEUE (&ifp->if_snd, m0);
    315                 splx (s);
    316                 ifp->if_opackets++;
    317                 break;
    318 #endif
    319             default:
    320                 m_freem (m0);
    321                 return EAFNOSUPPORT;
    322         }
    323 
    324         if (tp->tun_flags & TUN_RWAIT) {
    325                 tp->tun_flags &= ~TUN_RWAIT;
    326                 wakeup ((caddr_t) tp);
    327         }
    328         if (tp->tun_flags & TUN_ASYNC && tp -> tun_pgrp != 0) {
    329                 if (tp->tun_pgrp > 0)
    330                         gsignal (tp->tun_pgrp, SIGIO);
    331                 else if ((p = pfind (-tp->tun_pgrp)) != 0)
    332                         psignal (p, SIGIO);
    333         }
    334 	selwakeup (&tp->tun_rsel);
    335         return 0;
    336 }
    337 
    338 /*
    339  * the cdevsw interface is now pretty minimal.
    340  */
    341 
    342 tuncioctl (dev, cmd, data, flag)
    343 dev_t           dev;
    344 caddr_t         data;
    345 {
    346         int     unit = minor(dev);
    347         struct tunctl *tp = &tunctl[unit];
    348         int     s;
    349 
    350         switch (cmd) {
    351             case TUNSDEBUG:
    352                 tundebug = *(int *)data;
    353                 break;
    354 
    355             case TUNGDEBUG:
    356                 *(int *)data = tundebug;
    357                 break;
    358 
    359             case FIONBIO:
    360                 if (*(int *)data)
    361                         tp->tun_flags |= TUN_NBIO;
    362                 else
    363                         tp->tun_flags &= ~TUN_NBIO;
    364                 break;
    365 
    366             case FIOASYNC:
    367                 if (*(int *)data)
    368                         tp->tun_flags |= TUN_ASYNC;
    369                 else
    370                         tp->tun_flags &= ~TUN_ASYNC;
    371                 break;
    372 
    373             case FIONREAD:
    374                 s = splimp ();
    375                 if (tp->tun_if.if_snd.ifq_head)
    376                         *(int *)data = tp->tun_if.if_snd.ifq_head->m_len;
    377                 else    *(int *)data = 0;
    378                 splx (s);
    379                 break;
    380 
    381             case TIOCSPGRP:
    382                 tp->tun_pgrp = *(int *)data;
    383                 break;
    384 
    385             case TIOCGPGRP:
    386                 *(int *)data = tp->tun_pgrp;
    387                 break;
    388 
    389             default:
    390                 return (ENOTTY);
    391         }
    392         return (0);
    393 }
    394 
    395 /*
    396  * The cdevsw read interface - reads a packet at a time, or at least as much
    397  * of a packet as can be read.
    398  */
    399 tunread (dev, uio)
    400 dev_t           dev;
    401 struct uio     *uio;
    402 {
    403         register struct ifnet *ifp;
    404         register struct mbuf *m, *m0;
    405         int             unit = minor (dev);
    406         int             len, s;
    407         int             error = 0;
    408         struct tunctl  *tp;
    409 
    410         tp = &tunctl[unit];
    411         ifp = &tp->tun_if;
    412         TUNDEBUG ("%s%d: read\n", ifp->if_name, ifp->if_unit);
    413         if ((tp->tun_flags & TUN_READY) != TUN_READY) {
    414                 if(tuncheckready(ifp) == 0) {
    415                         TUNDEBUG ("%s%d: not ready 0%o\n", ifp->if_name,
    416                                 ifp->if_unit, tp->tun_flags);
    417                         return EHOSTDOWN;
    418                 }
    419         }
    420 
    421         tp->tun_flags &= ~TUN_RWAIT;
    422 
    423         s = splimp ();
    424         do {
    425                 IF_DEQUEUE (&ifp->if_snd, m0);
    426                 if (m0 == 0) {
    427                         if (tp -> tun_flags & TUN_NBIO) {
    428                                 splx (s);
    429                                 return EWOULDBLOCK;
    430                         }
    431                         tp->tun_flags |= TUN_RWAIT;
    432                         tsleep ((caddr_t) tp, PZERO + 1, "tunread", 0);
    433                 }
    434         } while (m0 == 0);
    435         splx (s);
    436 
    437         while (m0 && uio->uio_resid > 0 && error == 0) {
    438                 len = MIN (uio->uio_resid, m0->m_len);
    439                 if (len == 0)
    440                         break;
    441                 error = uiomove (mtod (m0, caddr_t), len,
    442                                  UIO_READ, uio);
    443                 MFREE (m0, m);
    444                 m0 = m;
    445         }
    446 
    447         if (m0 != 0) {
    448                 TUNDEBUG ("Dropping mbuf\n");
    449                 m_freem (m0);
    450         }
    451         return error;
    452 }
    453 
    454 /*
    455  * the cdevsw write interface - an atomic write is a packet - or else!
    456  */
    457 
    458 tunwrite (dev, uio)
    459 int             dev;
    460 struct uio     *uio;
    461 {
    462         int             error = 0;
    463         int             unit = minor (dev);
    464         struct mbuf    *top, **mp, *m;
    465         struct ifnet   *ifp = &(tunctl[unit].tun_if);
    466         int             s;
    467 
    468         TUNDEBUG ("%s%d: tunwrite\n", ifp->if_name, ifp->if_unit);
    469 
    470         if (uio->uio_resid < 0 || uio->uio_resid > TUNMTU) {
    471                 TUNDEBUG ("%s%d: len=%d!\n", ifp->if_name, ifp->if_unit,
    472                           uio->uio_resid);
    473                 return EIO;
    474         }
    475         top = 0;
    476         mp = &top;
    477         while (error == 0 && uio->uio_resid > 0) {
    478                 MGET (m, M_DONTWAIT, MT_DATA);
    479                 if (m == 0) {
    480                         error = ENOBUFS;
    481                         break;
    482                 }
    483                 m->m_len = MIN (MLEN, uio->uio_resid);
    484                 error = uiomove (mtod (m, caddr_t), m->m_len, UIO_WRITE, uio);
    485                 *mp = m;
    486                 mp = &m->m_next;
    487         }
    488         if (error) {
    489                 if (top)
    490                         m_freem (top);
    491                 return error;
    492         }
    493 
    494 #ifdef BSD4_3
    495         /*
    496          * Place interface pointer before the data
    497          * for the receiving protocol.
    498          */
    499         if (top->m_off <= MMAXOFF &&
    500             top->m_off >= MMINOFF + sizeof(struct ifnet *)) {
    501                 top->m_off -= sizeof(struct ifnet *);
    502                 top->m_len += sizeof(struct ifnet *);
    503         } else {
    504                 MGET(m, M_DONTWAIT, MT_HEADER);
    505                 if (m == (struct mbuf *)0)
    506                         return (ENOBUFS);
    507                 m->m_len = sizeof(struct ifnet *);
    508                 m->m_next = top;
    509                 top = m;
    510         }
    511         *(mtod(top, struct ifnet **)) = ifp;
    512 #endif /* BSD4_3 */
    513 
    514         s = splimp ();
    515         if (IF_QFULL (&ipintrq)) {
    516                 IF_DROP (&ipintrq);
    517                 splx (s);
    518                 ifp->if_collisions++;
    519                 m_freem (top);
    520                 return ENOBUFS;
    521         }
    522         IF_ENQUEUE (&ipintrq, top);
    523         splx (s);
    524         ifp->if_ipackets++;
    525         schednetisr (NETISR_IP);
    526         return error;
    527 }
    528 
    529 /*
    530  * tunselect - the select interface, this is only useful on reads really.
    531  * The write detect always returns true, write never blocks anyway, it either
    532  * accepts the packet or drops it.
    533  */
    534 tunselect (dev, rw)
    535 dev_t           dev;
    536 int             rw;
    537 {
    538         int             unit = minor (dev);
    539         register struct tunctl *tp = &tunctl[unit];
    540         struct ifnet   *ifp = &tp->tun_if;
    541         int             s = splimp ();
    542 
    543         TUNDEBUG ("%s%d: tunselect\n", ifp->if_name, ifp->if_unit);
    544         switch (rw) {
    545             case FREAD:
    546                 if (ifp->if_snd.ifq_len > 0) {
    547                         splx (s);
    548                         TUNDEBUG ("%s%d: tunselect q=%d\n", ifp->if_name,
    549                                   ifp->if_unit, ifp->if_snd.ifq_len);
    550                         return 1;
    551                 }
    552                 selrecord(p, &tp->tun_rsel);
    553                 break;
    554             case FWRITE:
    555                 splx (s);
    556                 return 1;
    557         }
    558         splx (s);
    559         TUNDEBUG ("%s%d: tunselect waiting\n", ifp->if_name, ifp->if_unit);
    560         return 0;
    561 }
    562 #endif  NTUN
    563