Annotation of Net2/net/if_tun.c, revision 1.1.1.1

1.1       root        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 - [email protected]
                     15:  *
                     16:  * $Header: if_tun.c,v 1.13 88/07/11 08:28:51 jpo Exp $
                     17:  * 
                     18:  * $Log:        if_tun.c,v $
                     19:  * Revision 1.13  88/07/11  08:28:51  jpo
                     20:  * Some tidying up
                     21:  * 
                     22:  * Revision 1.12  87/12/10  09:16:29  jpo
                     23:  * Decided the vax/mtpr was unnecessay.
                     24:  * 
                     25:  * Revision 1.11  87/12/10  09:10:36  jpo
                     26:  * Fixed some minor things & 1 major bug.
                     27:  * 
                     28:  * Revision 1.10  87/11/04  14:27:41  jpo
                     29:  * A few sanity checks added.
                     30:  * 
                     31:  * Revision 1.9  87/11/04  14:13:45  jpo
                     32:  * Added some ioctls for non-blocking & async I/O
                     33:  * 
                     34:  * Revision 1.8  87/10/19  10:28:14  jpo
                     35:  * Another touch up (sigh)
                     36:  * 
                     37:  * Revision 1.7  87/10/19  10:25:48  jpo
                     38:  * Touch up.
                     39:  * 
                     40:  * Revision 1.6  87/10/19  09:15:14  jpo
                     41:  * Touch up.
                     42:  * 
                     43:  * Revision 1.5  87/10/19  08:34:51  jpo
                     44:  * General clean up - plus sun specific fixes
                     45:  * 
                     46:  * Revision 1.4  87/10/16  17:10:12  jpo
                     47:  * Purged all ioctl read/writes and non-standard routing stuff.
                     48:  *
                     49:  * Revision 1.3  87/10/05  11:57:09  jpo
                     50:  * More debugging - in error mainly.
                     51:  * 
                     52:  * Revision 1.2  87/10/04  18:29:45  jpo
                     53:  * Select & read/write working.
                     54:  */
                     55: 
                     56: #include "tun.h"
                     57: #if NTUN > 0
                     58: 
                     59: /*
                     60:  * Tunnel driver.
                     61:  *
                     62:  * This driver takes packets off the IP i/f and hands them up to a
                     63:  * user process to have it's wicked way with. This driver has it's
                     64:  * roots in a similar driver written by Phil Cockcroft (formerly) at
                     65:  * UCL. This driver is based much more on read/write/select mode of
                     66:  * operation though.
                     67:  * 
                     68:  * Julian Onions <[email protected]>
                     69:  * Nottingham University 1987.
                     70:  */
                     71: 
                     72: #include "param.h"
                     73: #include "systm.h"
                     74: #include "mbuf.h"
                     75: #include "buf.h"
                     76: #include "protosw.h"
                     77: #include "socket.h"
                     78: #include "ioctl.h"
                     79: #include "errno.h"
                     80: #include "syslog.h"
                     81: 
                     82: #include "net/if.h"
                     83: #include "net/netisr.h"
                     84: #include "net/route.h"
                     85: 
                     86: #ifdef INET
                     87: #include "netinet/in.h"
                     88: #include "netinet/in_systm.h"
                     89: #include "netinet/in_var.h"
                     90: #include "netinet/ip.h"
                     91: #include "netinet/if_ether.h"
                     92: #endif
                     93: 
                     94: #ifdef NS
                     95: #include "netns/ns.h"
                     96: #include "netns/ns_if.h"
                     97: #endif
                     98: 
                     99: #define TUNDEBUG        if (tundebug) printf
                    100: 
                    101: int             tundebug = 0;
                    102: struct tunctl
                    103: {
                    104:         u_short         tun_flags;      /* misc flags */
                    105:         struct ifnet    tun_if;         /* the interface */
                    106:         int             tun_pgrp;       /* the process group - if any */
                    107:         struct proc    *tun_rsel;       /* read select */
                    108:         struct proc    *tun_wsel;       /* write select (not used) */
                    109: }       tunctl[NTUN];
                    110: 
                    111: extern int      ifqmaxlen;
                    112: 
                    113: int             tunoutput (), tunioctl (), tuninit ();
                    114: 
                    115: /* tunnel open - must be superuser & the device must be configured in */
                    116: tunopen (dev, flag)
                    117: dev_t           dev;
                    118: {
                    119:         register int    unit;
                    120:         struct tunctl  *tp;
                    121:         register struct ifnet *ifp;
                    122: 
                    123:         if (!suser ())
                    124:                 return EACCES;
                    125:         if ((unit = minor (dev)) >= NTUN)
                    126:                 return (ENXIO);
                    127:         tp = &tunctl[unit];
                    128:         if (tp->tun_flags & TUN_OPEN)
                    129:                 return ENXIO;
                    130:         if ((tp->tun_flags & TUN_INITED) == 0) {
                    131:                 tp->tun_flags = TUN_INITED;
                    132:                 tunattach (unit);
                    133:         }
                    134:         ifp = &tp->tun_if;
                    135:         tp->tun_flags |= TUN_OPEN;
                    136:         TUNDEBUG ("%s%d: open\n", ifp->if_name, ifp->if_unit);
                    137:         return (0);
                    138: }
                    139: 
                    140: /* tunclose - close the device - mark i/f down & delete routing info */
                    141: tunclose (dev, flag)
                    142: dev_t           dev;
                    143: {
                    144:         int             s;
                    145:         int             rcoll;
                    146:         register int    unit = minor (dev);
                    147:         register struct tunctl *tp = &tunctl[unit];
                    148:         register struct ifnet *ifp = &tp->tun_if;
                    149:         register struct mbuf *m;
                    150: 
                    151:         rcoll = tp->tun_flags & TUN_RCOLL;
                    152:         tp->tun_flags &= TUN_INITED;
                    153: 
                    154:         /*
                    155:          * junk all pending output
                    156:          */
                    157:         do {
                    158:                 s = splimp ();
                    159:                 IF_DEQUEUE (&ifp->if_snd, m);
                    160:                 splx (s);
                    161:                 if (m) /* actually - m_freem checks this - but what the hell */
                    162:                         m_freem (m);
                    163:         } while (m != 0);
                    164:         if (ifp->if_flags & IFF_UP) {
                    165:                 s = splimp ();
                    166:                 if_down (ifp);
                    167:                 if (ifp->if_flags & IFF_RUNNING)
                    168:                         rtinit (ifp->if_addrlist, (int)SIOCDELRT, RTF_HOST);
                    169:                 splx (s);
                    170:         }
                    171:         tp -> tun_pgrp = 0;
                    172:         if (tp -> tun_rsel)
                    173:                 selwakeup (tp->tun_rsel, rcoll);
                    174:                 
                    175:         tp -> tun_rsel = tp -> tun_wsel = (struct proc *)0;
                    176: 
                    177:         TUNDEBUG ("%s%d: closed\n", ifp->if_name, ifp->if_unit);
                    178:         return (0);
                    179: }
                    180: 
                    181: /*
                    182:  * attach an interface N.B. argument is not same as other drivers
                    183:  */
                    184: int
                    185: tunattach (unit)
                    186: int             unit;
                    187: {
                    188:         register struct ifnet *ifp = &tunctl[unit].tun_if;
                    189:         register struct sockaddr_in *sin;
                    190: 
                    191:         ifp->if_unit = unit;
                    192:         ifp->if_name = "tun";
                    193:         ifp->if_mtu = TUNMTU;
                    194:         ifp->if_ioctl = tunioctl;
                    195:         ifp->if_output = tunoutput;
                    196:         ifp->if_init = tuninit;
                    197: #ifndef BSD4_3
                    198:         sin = (struct sockaddr_in *) & ifp->if_addr;
                    199:         sin->sin_family = AF_INET;
                    200: #endif
                    201:         ifp->if_flags = IFF_POINTOPOINT;
                    202:         ifp->if_snd.ifq_maxlen = ifqmaxlen;
                    203:         ifp->if_collisions = ifp->if_ierrors = ifp->if_oerrors = 0;
                    204:         ifp->if_ipackets = ifp->if_opackets = 0;
                    205:         if_attach (ifp);
                    206:         TUNDEBUG ("%s%d: tunattach\n", ifp->if_name, ifp->if_unit);
                    207:         return 0;
                    208: }
                    209: 
                    210: int
                    211: tuninit (unit)
                    212: int             unit;
                    213: {
                    214:         register struct tunctl *tp = &tunctl[unit];
                    215:         register struct ifnet *ifp = &tp->tun_if;
                    216: #ifndef BSD4_3
                    217:         register struct sockaddr_in *sin;
                    218: 
                    219:         sin = (struct sockaddr_in *) & ifp->if_addr;
                    220:         if (sin->sin_addr.s_addr == 0)  /* if address still unknown */
                    221:                 return;
                    222:         if_rtinit (ifp, RTF_UP);
                    223: #endif
                    224:         ifp->if_flags |= IFF_UP | IFF_RUNNING;
                    225:         tp->tun_flags |= TUN_IASET;
                    226:         TUNDEBUG ("%s%d: tuninit\n", ifp->if_name, ifp->if_unit);
                    227:         return 0;
                    228: }
                    229: 
                    230: /*
                    231:  * Process an ioctl request.
                    232:  * The problem here is 4.2 pass a struct ifreq * to this routine,
                    233:  * sun only passes a struct sockaddr * since 3.2 at least. This is
                    234:  * rather upsetting! Also, sun doesn't pass the SIOCDSTADDR ioctl through
                    235:  * so we can't detect this being set directly. This is the reason for
                    236:  * tuncheckready.
                    237:  * Under 4.3 and SunOs 4.0 we now get the SIOCSIFDSTADDR ioctl, and we get a
                    238:  * struct in_ifaddr * for data. (tte)
                    239:  */
                    240: 
                    241: #if !defined(BSD4_3) && defined(sun)
                    242: 
                    243: /*
                    244:  * workaround for not being able to detect DSTADDR being set.
                    245:  */
                    246: 
                    247: tuncheckready (ifp)
                    248: struct ifnet *ifp;
                    249: {
                    250:         struct tunctl *tp = &tunctl[ifp->if_unit];
                    251:         struct sockaddr_in *sin;
                    252: 
                    253:         sin = (struct sockaddr_in *) &ifp->if_dstaddr;
                    254:         if (sin->sin_addr.s_addr == 0)
                    255:                 return 0;
                    256:         tp -> tun_flags |= TUN_DSTADDR;
                    257:         return 1;
                    258: }
                    259: #else
                    260: #define tuncheckready(dummy) 1
                    261: #endif /* !defined(BSD4_3) && defined(sun) */
                    262: 
                    263: int
                    264: tunioctl (ifp, cmd, data)
                    265: register struct ifnet *ifp;
                    266: int             cmd;
                    267: caddr_t         data;
                    268: {
                    269: #ifndef BSD4_3
                    270: #ifdef sun      
                    271:         struct sockaddr_in *sin = (struct sockaddr_in *) data;
                    272: #else
                    273:         struct sockaddr_in *sin;
                    274:         struct ifreq    *ifr = (struct ifreq *) data;
                    275: #endif
                    276: #endif /* BSD4_3 */
                    277: 
                    278:         int             s = splimp (), error = 0;
                    279:         struct tunctl  *tp = &tunctl[ifp->if_unit];
                    280: 
                    281:         switch (cmd)
                    282:         {
                    283:             case SIOCSIFADDR:
                    284: #ifndef BSD4_3
                    285:                 if (ifp->if_flags & IFF_RUNNING)
                    286:                         if_rtinit (ifp, -1);    /* delete previous route */
                    287: #ifndef sun
                    288:                 sin = (struct sockaddr_in *)&ifr -> ifr_addr;
                    289: #endif
                    290:                 ifp->if_addr = *((struct sockaddr *) sin);
                    291:                 ifp->if_net = in_netof (sin->sin_addr);
                    292:                 ifp->if_host[0] = in_lnaof (sin->sin_addr);
                    293: #endif
                    294:                 tuninit (ifp->if_unit);
                    295:                 break;
                    296:             case SIOCSIFDSTADDR:
                    297:                 tp->tun_flags |= TUN_DSTADDR;
                    298: #ifndef BSD4_3
                    299: #ifndef sun
                    300:                 sin = (struct sockaddr_in *)&ifr -> ifr_addr;
                    301: #endif
                    302:                 ifp->if_dstaddr = *((struct sockaddr *)sin);
                    303: #endif BSD4_3
                    304:                 TUNDEBUG ("%s%d: destination addres set\n", ifp->if_name,
                    305:                         ifp -> if_unit);
                    306:                 break;
                    307:             default:
                    308:                 error = EINVAL;
                    309:         }
                    310:         splx (s);
                    311:         return (error);
                    312: }
                    313: 
                    314: /*
                    315:  * tunoutput - queue packets from higher level ready to put out.
                    316:  */
                    317: tunoutput (ifp, m0, dst)
                    318: struct ifnet   *ifp;
                    319: struct mbuf    *m0;
                    320: struct sockaddr *dst;
                    321: {
                    322:         struct tunctl  *tp;
                    323:         struct proc     *p;
                    324:         int             s;
                    325: 
                    326:         TUNDEBUG ("%s%d: tunoutput\n", ifp->if_name, ifp->if_unit);
                    327:         tp = &tunctl[ifp->if_unit];
                    328:         if ((tp->tun_flags & TUN_READY) != TUN_READY) {
                    329:                 if(tuncheckready(ifp) == 0) {
                    330:                         TUNDEBUG ("%s%d: not ready 0%o\n", ifp->if_name,
                    331:                                 ifp->if_unit, tp->tun_flags);
                    332:                         m_freem (m0);
                    333:                         return EHOSTDOWN;
                    334:                 }
                    335:         }
                    336: 
                    337:         switch (dst->sa_family) {
                    338: #ifdef INET
                    339:             case AF_INET:
                    340:                 s = splimp ();
                    341:                 if (IF_QFULL (&ifp->if_snd))
                    342:                 {
                    343:                         IF_DROP (&ifp->if_snd);
                    344:                         m_freem (m0);
                    345:                         splx (s);
                    346:                         ifp->if_collisions++;
                    347:                         return (ENOBUFS);
                    348:                 }
                    349:                 IF_ENQUEUE (&ifp->if_snd, m0);
                    350:                 splx (s);
                    351:                 ifp->if_opackets++;
                    352:                 break;
                    353: #endif
                    354:             default:
                    355:                 m_freem (m0);
                    356:                 return EAFNOSUPPORT;
                    357:         }
                    358: 
                    359:         if (tp->tun_flags & TUN_RWAIT) {
                    360:                 tp->tun_flags &= ~TUN_RWAIT;
                    361:                 wakeup ((caddr_t) tp);
                    362:         }
                    363:         if (tp->tun_flags & TUN_ASYNC && tp -> tun_pgrp != 0) {
                    364:                 if (tp->tun_pgrp > 0)
                    365:                         gsignal (tp->tun_pgrp, SIGIO);
                    366:                 else if ((p = pfind (-tp->tun_pgrp)) != 0)
                    367:                         psignal (p, SIGIO);
                    368:         }
                    369:         if (tp->tun_rsel) {
                    370:                 selwakeup (tp->tun_rsel, tp->tun_flags & TUN_RCOLL);
                    371:                 tp->tun_flags &= ~TUN_RCOLL;
                    372:                 tp->tun_rsel = (struct proc *) 0;
                    373:         }
                    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:                 if (tp->tun_rsel && tp->tun_rsel->p_wchan ==
                    592:                     (caddr_t) & selwait)
                    593:                         tp->tun_flags |= TUN_RCOLL;
                    594:                 else
                    595:                         tp->tun_rsel = u.u_procp;
                    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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.