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