Annotation of 42BSD/sys/vaxif/if_un.c, revision 1.1

1.1     ! root        1: /*     if_un.c 6.1     83/07/29        */
        !             2: 
        !             3: #include "un.h"
        !             4: #if NUN > 0
        !             5: /*
        !             6:  * Ungermann-Bass network/DR11-W interface driver
        !             7:  */
        !             8: #include "../machine/pte.h"
        !             9: 
        !            10: #include "../h/param.h"
        !            11: #include "../h/systm.h"
        !            12: #include "../h/mbuf.h"
        !            13: #include "../h/buf.h"
        !            14: #include "../h/protosw.h"
        !            15: #include "../h/socket.h"
        !            16: #include "../h/vmmac.h"
        !            17: #include "../h/errno.h"
        !            18: #include "../h/time.h"
        !            19: #include "../h/kernel.h"
        !            20: #include "../h/ioctl.h"
        !            21: 
        !            22: #include "../net/if.h"
        !            23: #include "../net/netisr.h"
        !            24: #include "../net/route.h"
        !            25: #include "../netinet/in.h"
        !            26: #include "../netinet/in_systm.h"
        !            27: #include "../netinet/ip.h"
        !            28: #include "../netinet/ip_var.h"
        !            29: 
        !            30: #include "../vax/cpu.h"
        !            31: #include "../vax/mtpr.h"
        !            32: #include "../vaxif/if_un.h"
        !            33: #include "../vaxif/if_unreg.h"
        !            34: #include "../vaxif/if_uba.h"
        !            35: #include "../vaxuba/ubareg.h"
        !            36: #include "../vaxuba/ubavar.h"
        !            37: 
        !            38: #define        UNMTU           (600-sizeof (struct un_header))
        !            39: 
        !            40: #define        US_NULL         0       /* not doing anything state */
        !            41: #define        US_IDLE         1       /* waiting to transfer state */
        !            42: #define        US_READ         2       /* reading state */
        !            43: #define        US_WRITE        3       /* writing state */
        !            44: #define        US_RESET        4       /* waiting for reset state */
        !            45: 
        !            46: int    unprobe(), unattach(), unintr();
        !            47: struct uba_device *uninfo[NUN];
        !            48: u_short        unstd[] = { 0 };
        !            49: struct uba_driver undriver =
        !            50:        { unprobe, 0, unattach, 0, unstd, "un", uninfo };
        !            51: #define        UNUNIT(dev)     (minor(dev))
        !            52: 
        !            53: int    uninit(), unioctl(), unoutput(), unreset();
        !            54: int    unrestart();
        !            55: 
        !            56: /*
        !            57:  * Ungermann-Bass software status per interface.
        !            58:  *
        !            59:  * Each interface is referenced by a network interface structure,
        !            60:  * us_if, which the routing code uses to locate the interface.
        !            61:  * This structure contains the output queue for the interface, its address,
        !            62:  * etc.  We also have, for each interface, a UBA interface structure, which
        !            63:  * contains information about the UNIBUS resources held by the interface:
        !            64:  * map registers, buffered data paths, etc.  Information is cached in this
        !            65:  * structure for use by the if_uba.c routines in running the interface
        !            66:  * efficiently.
        !            67:  */
        !            68: struct un_softc {
        !            69:        struct  ifnet us_if;            /* network-visible interface */
        !            70:        struct  ifuba us_ifuba;         /* UNIBUS resources */
        !            71:        short   us_state;               /* device state */
        !            72:        short   us_errcnt;              /* number of errors since time set */
        !            73:        short   us_restart;             /* restart interval */
        !            74:        u_char  us_maxtime;             /* interval for error counting */
        !            75:        u_char  us_maxerr;              /* errors allowed in interval */
        !            76:        time_t  us_errtime;             /* time for error counting */
        !            77: } un_softc[NUN];
        !            78: 
        !            79: /*
        !            80:  * Cause an interrupt to determine interface presence and
        !            81:  * interrupt vector.
        !            82:  */
        !            83: unprobe(reg)
        !            84:        caddr_t reg;
        !            85: {
        !            86:        register int br, cvec;          /* r11, r10 value-result */
        !            87:        register struct undevice *addr = (struct undevice *)reg;
        !            88: 
        !            89: #ifdef lint
        !            90:        br = 0; cvec = br; br = cvec;
        !            91:        unintr(0);
        !            92: #endif
        !            93:        addr->csr = IE|UNRESET;
        !            94:        addr->csr = IE|UNRESET|GO;
        !            95:        DELAY(100000);
        !            96:        addr->csr = 0;
        !            97:        return (1);
        !            98: }
        !            99: 
        !           100: /*
        !           101:  * Interface exists: make available by filling in network interface
        !           102:  * record.  System will initialize the interface when it is ready
        !           103:  * to accept packets.
        !           104:  */
        !           105: unattach(ui)
        !           106:        struct uba_device *ui;
        !           107: {
        !           108:        register struct un_softc *us = &un_softc[ui->ui_unit];
        !           109: 
        !           110:        us->us_if.if_unit = ui->ui_unit;
        !           111:        us->us_if.if_name = "un";
        !           112:        us->us_if.if_mtu = UNMTU;
        !           113:        us->us_if.if_init = uninit;
        !           114:        us->us_if.if_ioctl = unioctl;
        !           115:        us->us_if.if_output = unoutput;
        !           116:        us->us_if.if_reset = unreset;
        !           117:        us->us_if.if_watchdog = unrestart;
        !           118:        us->us_maxtime = 3;
        !           119:        us->us_maxerr = 10;
        !           120:        us->us_restart = 5 * 60;
        !           121:        us->us_ifuba.ifu_flags = UBA_CANTWAIT;
        !           122: #ifdef notdef
        !           123:        us->us_ifuba.ifu_flags |= UBA_NEEDBDP;
        !           124: #endif
        !           125:        if_attach(&us->us_if);
        !           126: }
        !           127: 
        !           128: /*
        !           129:  * Reset of interface after UNIBUS reset.
        !           130:  * If interface is on specified uba, reset its state.
        !           131:  */
        !           132: unreset(unit, uban)
        !           133:        int unit, uban;
        !           134: {
        !           135:        register struct uba_device *ui;
        !           136: 
        !           137:        if (unit >= NUN || (ui = uninfo[unit]) == 0 || ui->ui_alive == 0 ||
        !           138:            ui->ui_ubanum != uban)
        !           139:                return;
        !           140:        printf(" un%d", unit);
        !           141:        uninit(unit);
        !           142: }
        !           143: 
        !           144: /*
        !           145:  * Initialization of interface; clear recorded pending
        !           146:  * operations, and reinitialize UNIBUS usage.
        !           147:  */
        !           148: uninit(unit)
        !           149:        int unit;
        !           150: {
        !           151:        register struct un_softc *us = &un_softc[unit];
        !           152:        register struct uba_device *ui = uninfo[unit];
        !           153:        register struct undevice *addr;
        !           154:        struct sockaddr_in *sin;
        !           155:        int s;
        !           156: 
        !           157:        sin = (struct sockaddr_in *)&us->us_if.if_addr;
        !           158:        if (in_netof(sin->sin_addr) == 0)
        !           159:                return;
        !           160:        if (if_ubainit(&us->us_ifuba, ui->ui_ubanum,
        !           161:            sizeof (struct un_header), (int)btoc(UNMTU)) == 0) {
        !           162:                printf("un%d: can't initialize\n", unit);
        !           163:                us->us_if.if_flags &= ~IFF_UP;
        !           164:                return;
        !           165:        }
        !           166:        us->us_if.if_flags |= IFF_RUNNING;
        !           167:        us->us_errcnt = 0;
        !           168:        us->us_errtime = time.tv_sec;
        !           169:        unwhoami(unit);
        !           170: 
        !           171:        /*
        !           172:         * Reset U-B interface, thus causing an interrupt which
        !           173:         * will start things going.
        !           174:         */
        !           175:        addr = (struct undevice *)ui->ui_addr;
        !           176:        s = splimp();
        !           177:        addr->csr = IE|UNRESET;
        !           178:        addr->csr = IE|UNRESET|GO;
        !           179:        us->us_state = US_RESET;
        !           180:        splx(s);
        !           181: }
        !           182: 
        !           183: /*
        !           184:  * Try to start a write operation.
        !           185:  * If interface is busy, it must be in idle state, so issue a reset.
        !           186:  * Otherwise, get the datagram from the output queue, map it onto
        !           187:  * the UNIBUS, and start the write.  This routine should not be
        !           188:  * called if the output queue is empty.
        !           189:  */
        !           190: unstart(dev)
        !           191:        dev_t dev;
        !           192: {
        !           193:        int unit = UNUNIT(dev);
        !           194:        struct uba_device *ui = uninfo[unit];
        !           195:        register struct un_softc *us = &un_softc[unit];
        !           196:        register struct undevice *addr = (struct undevice *)ui->ui_addr;
        !           197:        struct mbuf *m;
        !           198:        int dataaddr, datalen;
        !           199:        register short cmdcsr;
        !           200: 
        !           201:        if (us->us_state != US_NULL) {
        !           202:                addr->csr = IE|UNRESET;
        !           203:                addr->csr = IE|UNRESET|GO;
        !           204:                us->us_state = US_RESET;
        !           205:        } else {
        !           206:                IF_DEQUEUE(&us->us_if.if_snd, m);
        !           207:                if (m == 0)
        !           208:                        return;
        !           209:                us->us_state = US_WRITE;
        !           210:                datalen = if_wubaput(&us->us_ifuba, m);
        !           211:                if (us->us_ifuba.ifu_flags & UBA_NEEDBDP)
        !           212:                        UBAPURGE(us->us_ifuba.ifu_uba,
        !           213:                                us->us_ifuba.ifu_w.ifrw_bdp);
        !           214:                dataaddr = us->us_ifuba.ifu_w.ifrw_info;
        !           215:                addr->bar = dataaddr & 0xffff;
        !           216:                addr->wcr = -(((datalen + 1) >> 1) + 1);
        !           217:                cmdcsr = ((dataaddr >> 12) & 0x30) | IE | UNOUT;
        !           218:                addr->csr = cmdcsr;
        !           219:                addr->csr = cmdcsr | GO;
        !           220:        }
        !           221: }
        !           222: 
        !           223: /*
        !           224:  * Ungermann-Bass interface interrupt handler.
        !           225:  * Determines reason for interrupt and acts accordingly.
        !           226:  */
        !           227: unintr(unit)
        !           228:        int unit;
        !           229: {
        !           230:        register struct un_softc *us = &un_softc[unit];
        !           231:        struct undevice *addr = (struct undevice *)uninfo[unit]->ui_addr;
        !           232:        register struct un_header *un;
        !           233:        struct mbuf *m;
        !           234:        int len;
        !           235:        register struct ifqueue *inq;
        !           236:        int cmdcsr;
        !           237: 
        !           238:        if ((addr->dar & RESETACK) && us->us_state != US_RESET) {
        !           239:                if ((us->us_if.if_flags & IFF_UP) == 0)
        !           240:                        return;
        !           241:                printf("un%d: unexpected reset\n", unit);
        !           242:                unerror(unit);
        !           243:        }
        !           244:                
        !           245:        switch (us->us_state) {
        !           246: 
        !           247:        case US_NULL:
        !           248:                printf("un%d: stray interrupt\n", unit);
        !           249:                break;
        !           250: 
        !           251:        case US_RESET:
        !           252:                if (!(addr->dar & RESETACK)) {
        !           253:                        addr->csr = IE|UNRESET;
        !           254:                        addr->csr = IE|UNRESET|GO;
        !           255:                        return;
        !           256:                }
        !           257:                break;
        !           258: 
        !           259:        case US_IDLE:
        !           260:                break;
        !           261: 
        !           262:        case US_READ:
        !           263:                us->us_if.if_ipackets++;
        !           264:                if (us->us_ifuba.ifu_flags & UBA_NEEDBDP)
        !           265:                        UBAPURGE(us->us_ifuba.ifu_uba,
        !           266:                                us->us_ifuba.ifu_r.ifrw_bdp);
        !           267:                if (addr->csr & STATA) {
        !           268:                        if ((us->us_if.if_flags & IFF_UP) == 0)
        !           269:                                return;
        !           270:                        printf("un%d: input error csr=%b\n", unit,
        !           271:                                addr->csr&0xffff, UNBITS);
        !           272:                        us->us_if.if_ierrors++;
        !           273:                        unerror(unit);
        !           274:                        break;
        !           275:                }
        !           276:                un = (struct un_header *)(us->us_ifuba.ifu_r.ifrw_addr);
        !           277:                switch (un->un_ptype) {
        !           278: #ifdef INET
        !           279:                case UNTYPE_IP:
        !           280:                        len = htons((u_short)((struct ip *) (un+1))->ip_len);
        !           281:                        schednetisr(NETISR_IP);
        !           282:                        inq = &ipintrq;
        !           283:                        break;
        !           284: #endif
        !           285:                case UNTYPE_INQUIRE: {
        !           286:                        struct sockaddr_in *sin;
        !           287: 
        !           288:                        us->us_if.if_host[0] =
        !           289:                            un->un_dport << 16 | htons(un->un_dniu);
        !           290:                        sin = (struct sockaddr_in *)&us->us_if.if_addr;
        !           291:                        sin->sin_addr = if_makeaddr(us->us_if.if_net,
        !           292:                                us->us_if.if_host[0]);
        !           293:                        us->us_if.if_flags |= IFF_UP;
        !           294:                        if_rtinit(&us->us_if, RTF_UP);
        !           295:                        goto setup;
        !           296:                }
        !           297: 
        !           298:                default:
        !           299:                        printf("un%d: bad packet type %d\n", un->un_ptype);
        !           300:                        goto setup;
        !           301:                }
        !           302: 
        !           303:                m = if_rubaget(&us->us_ifuba, len, 0);
        !           304:                if (m != 0)
        !           305:                        if (IF_QFULL(inq)) {
        !           306:                                IF_DROP(inq);
        !           307:                                m_freem(m);
        !           308:                        } else
        !           309:                                IF_ENQUEUE(inq, m);
        !           310:                break;
        !           311: 
        !           312:        case US_WRITE:
        !           313:                us->us_if.if_opackets++;
        !           314:                if (addr->csr & STATA) {
        !           315:                        if ((us->us_if.if_flags & IFF_UP) == 0)
        !           316:                                return;
        !           317:                        printf("un%d: output error csr=%b\n",
        !           318:                            unit, addr->csr, UNBITS);
        !           319:                        us->us_if.if_oerrors++;
        !           320:                        unerror(unit);
        !           321:                }
        !           322:                if (us->us_ifuba.ifu_xtofree) {
        !           323:                        m_freem(us->us_ifuba.ifu_xtofree);
        !           324:                        us->us_ifuba.ifu_xtofree = 0;
        !           325:                }
        !           326:                break;
        !           327: 
        !           328:        default:
        !           329:                printf("un%d: invalid state %d csr=%b\n",
        !           330:                    us->us_state, addr->csr, UNBITS);
        !           331:        }
        !           332: 
        !           333: setup:
        !           334:        us->us_state = US_NULL;
        !           335:        if (addr->csr & STATB) {
        !           336:                us->us_state = US_READ;
        !           337:                addr->wcr = -((sizeof (struct un_header) + UNMTU + 1)/2+1);
        !           338:                addr->bar = us->us_ifuba.ifu_r.ifrw_info & 0xffff;
        !           339:                cmdcsr = ((us->us_ifuba.ifu_r.ifrw_info >> 12) & 0x30);
        !           340:                cmdcsr |= IE|UNRDDG;
        !           341:                addr->csr = cmdcsr;
        !           342:                addr->csr = cmdcsr | GO;
        !           343:        } else if (us->us_if.if_snd.ifq_head != 0 && (addr->csr & STATC))
        !           344:                unstart(unit);
        !           345:        
        !           346:        if (us->us_state == US_NULL) {
        !           347:                us->us_state = US_IDLE;
        !           348:                addr->csr = IE|UNIDLE;
        !           349:                addr->csr = IE|UNIDLE|GO;
        !           350:        }
        !           351: }
        !           352: 
        !           353: /*
        !           354:  * Ungermann-Bass output routine.
        !           355:  * Encapsulate a packet destined for dst for the local net.
        !           356:  */
        !           357: unoutput(ifp, m0, dst)
        !           358:        struct ifnet *ifp;
        !           359:        struct mbuf *m0;
        !           360:        struct sockaddr *dst;
        !           361: {
        !           362:        int type, destniu, destport, len;
        !           363:        register struct mbuf *m = m0;
        !           364:        register struct un_header *un;
        !           365:        register struct un_softc *us = &un_softc[ifp->if_unit];
        !           366:        int s;
        !           367: 
        !           368:        if ((us->us_if.if_flags & IFF_UP) == 0)
        !           369:                return (ENETDOWN);
        !           370:        switch (dst->sa_family) {
        !           371: 
        !           372: #ifdef INET
        !           373:        case AF_INET: {
        !           374:                struct sockaddr_in *sin = (struct sockaddr_in *)dst;
        !           375:                struct ip *ip = mtod(m, struct ip *);
        !           376: 
        !           377:                if (sin->sin_addr.s_addr & 0xffffff00) {
        !           378:                        destniu = sin->sin_addr.s_addr >> 24;
        !           379:                        destport = (sin->sin_addr.s_addr >> 8) & 0xff;
        !           380:                } else {
        !           381:                        destniu = 0xffff;
        !           382:                        destport = 0xff;
        !           383:                }
        !           384:                len = htons((u_short) ip->ip_len);
        !           385:                type = UNTYPE_IP;
        !           386:                break;
        !           387:        }
        !           388: #endif
        !           389:        default:
        !           390:                printf("un%d: can't handle af%d\n", ifp->if_unit,
        !           391:                        dst->sa_family);
        !           392:                m_freem(m0);
        !           393:                return (EAFNOSUPPORT);
        !           394:        }
        !           395:        
        !           396:        /*
        !           397:         * Add local net header.  If no space in first mbuf,
        !           398:         * allocate another.
        !           399:         */
        !           400:        if (m->m_off > MMAXOFF ||
        !           401:            MMINOFF + sizeof (struct un_header) > m->m_off) {
        !           402:                m = m_get(M_DONTWAIT, MT_HEADER);
        !           403:                if (m == 0) {
        !           404:                        m_freem(m0);
        !           405:                        return (ENOBUFS);
        !           406:                }
        !           407:                m->m_next = m0;
        !           408:                m->m_off = MMINOFF;
        !           409:                m->m_len = sizeof (struct un_header);
        !           410:        } else {
        !           411:                m->m_off -= sizeof (struct un_header);
        !           412:                m->m_len += sizeof (struct un_header);
        !           413:        }
        !           414:        un = mtod(m, struct un_header *);
        !           415:        bzero((caddr_t)un, sizeof (struct un_header));
        !           416:        un->un_length = htons((u_short)(len + sizeof (struct un_header)));
        !           417:        un->un_dniu = htons((u_short)destniu);
        !           418:        un->un_dport = destport;
        !           419:        un->un_dtype = 5;
        !           420:        un->un_sniu = htons((u_short)(ifp->if_host[0] >> 24));
        !           421:        un->un_sport = (ifp->if_host[0] >> 8) & 0xff;
        !           422:        un->un_stype = 5;
        !           423:        un->un_ptype = type;
        !           424: 
        !           425:        /*
        !           426:         * Queue message on interface, and start output if interface
        !           427:         * not yet active.
        !           428:         */
        !           429:        s = splimp();
        !           430:        if (IF_QFULL(&ifp->if_snd)) {
        !           431:                IF_DROP(&ifp->if_snd);
        !           432:                m_freem(m);
        !           433:                splx(s);
        !           434:                return (ENOBUFS);
        !           435:        }
        !           436:        IF_ENQUEUE(&ifp->if_snd, m);
        !           437:        if (us->us_state == US_IDLE)
        !           438:                unstart(ifp->if_unit);
        !           439:        splx(s);
        !           440:        return (0);
        !           441: }
        !           442: 
        !           443: /*
        !           444:  * U-B error handler, if maxerr errors have occured
        !           445:  * in maxtime seconds, disable the interface.
        !           446:  */
        !           447: unerror(unit)
        !           448:        int unit;
        !           449: {
        !           450:        register struct un_softc *us = &un_softc[unit];
        !           451:        struct undevice *addr = (struct undevice *)uninfo[unit]->ui_addr;
        !           452: 
        !           453:        if (time.tv_sec - us->us_errtime > us->us_maxtime) {
        !           454:                us->us_errtime = time.tv_sec;
        !           455:                us->us_errcnt = 1;
        !           456:        } else if (++us->us_errcnt >= us->us_maxerr) {
        !           457:                printf("un%d: error limit exceeded\n", unit);
        !           458:                us->us_if.if_flags &= ~IFF_UP;
        !           459:                addr->csr = 0;
        !           460:                us->us_if.if_timer = us->us_restart;
        !           461:        }
        !           462: }
        !           463: 
        !           464: unrestart(unit)
        !           465:        int unit;
        !           466: {
        !           467:        register struct un_softc *us = &un_softc[unit];
        !           468:        struct undevice *addr = (struct undevice *)uninfo[unit]->ui_addr;
        !           469:        int s;
        !           470: 
        !           471:        us->us_if.if_flags |= IFF_UP;
        !           472:        printf("un%d: restarting\n", unit);
        !           473:        unwhoami(unit);
        !           474:        s = splimp();
        !           475:        addr->csr = IE|UNRESET;
        !           476:        addr->csr = IE|UNRESET|GO;
        !           477:        us->us_state = US_RESET;
        !           478:        splx(s);
        !           479: }
        !           480: 
        !           481: /*
        !           482:  * Send a "Who am I?" message to the interface. 
        !           483:  * Interface should respond with an copy of the
        !           484:  * packet with its real address filled in.  The
        !           485:  * message is placed at the head of the output queue.
        !           486:  * An interface reset should be done next to start
        !           487:  * things rolling.
        !           488:  */
        !           489: unwhoami(unit)             
        !           490:        int unit;
        !           491: {
        !           492:        register struct mbuf *m;
        !           493:        register struct un_softc *us = &un_softc[unit];
        !           494:        register struct un_header *un;
        !           495:        int s;
        !           496: 
        !           497:        if ((m = m_get(M_DONTWAIT, MT_HEADER)) == 0) 
        !           498:                return;
        !           499:        m->m_off = MMINOFF;
        !           500:        m->m_len = sizeof(struct un_header);
        !           501:        un = mtod(m, struct un_header *);
        !           502:        bzero((caddr_t)un, sizeof (struct un_header));
        !           503:        un->un_length = htons(sizeof (struct un_header));
        !           504:        un->un_dtype = un->un_stype = 5;
        !           505:        un->un_ptype = UNTYPE_INQUIRE;
        !           506:        s = splimp();
        !           507:        IF_PREPEND(&us->us_if.if_snd, m);
        !           508:        splx(s);
        !           509: }
        !           510: 
        !           511: /*
        !           512:  * Process an ioctl request.
        !           513:  */
        !           514: unioctl(ifp, cmd, data)
        !           515:        register struct ifnet *ifp;
        !           516:        int cmd;
        !           517:        caddr_t data;
        !           518: {
        !           519:        struct ifreq *ifr = (struct ifreq *)data;
        !           520:        int s = splimp(), error = 0;
        !           521: 
        !           522:        switch (cmd) {
        !           523: 
        !           524:        case SIOCSIFADDR:
        !           525:                if (ifp->if_flags & IFF_RUNNING)
        !           526:                        if_rtinit(ifp, -1);     /* delete previous route */
        !           527:                unsetaddr(ifp, (struct sockaddr_in *)&ifr->ifr_addr);
        !           528:                if (ifp->if_flags & IFF_RUNNING)
        !           529:                        if_rtinit(ifp, RTF_UP);
        !           530:                else
        !           531:                        uninit(ifp->if_unit);
        !           532:                break;
        !           533: 
        !           534:        default:
        !           535:                error = EINVAL;
        !           536:        }
        !           537:        splx(s);
        !           538:        return (error);
        !           539: }
        !           540: 
        !           541: unsetaddr(ifp, sin)
        !           542:        register struct ifnet *ifp;
        !           543:        register struct sockaddr_in *sin;
        !           544: {
        !           545: 
        !           546:        ifp->if_net = in_netof(sin->sin_addr);
        !           547:        sin = (struct sockaddr_in *)&ifp->if_addr;
        !           548:        sin->sin_family = AF_INET;
        !           549:        /* host number filled in already, or filled in later */
        !           550:        sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]);
        !           551:        sin = (struct sockaddr_in *)&ifp->if_broadaddr;
        !           552:        sin->sin_family = AF_INET;
        !           553:        sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY);
        !           554:        ifp->if_flags |= IFF_BROADCAST;
        !           555: }
        !           556: #endif

unix.superglobalmegacorp.com

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