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