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