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