Annotation of XNU/bsd/net/if.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: /*
                     23:  * Copyright (c) 1980, 1986, 1993
                     24:  *     The Regents of the University of California.  All rights reserved.
                     25:  *
                     26:  * Redistribution and use in source and binary forms, with or without
                     27:  * modification, are permitted provided that the following conditions
                     28:  * are met:
                     29:  * 1. Redistributions of source code must retain the above copyright
                     30:  *    notice, this list of conditions and the following disclaimer.
                     31:  * 2. Redistributions in binary form must reproduce the above copyright
                     32:  *    notice, this list of conditions and the following disclaimer in the
                     33:  *    documentation and/or other materials provided with the distribution.
                     34:  * 3. All advertising materials mentioning features or use of this software
                     35:  *    must display the following acknowledgement:
                     36:  *     This product includes software developed by the University of
                     37:  *     California, Berkeley and its contributors.
                     38:  * 4. Neither the name of the University nor the names of its contributors
                     39:  *    may be used to endorse or promote products derived from this software
                     40:  *    without specific prior written permission.
                     41:  *
                     42:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     43:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     44:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     45:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     46:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     47:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     48:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     49:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     50:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     51:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     52:  * SUCH DAMAGE.
                     53:  *
                     54:  *     @(#)if.c        8.3 (Berkeley) 1/4/94
                     55:  */
                     56: 
                     57: /*
                     58: #include "opt_compat.h"
                     59: */
                     60: 
                     61: #include <sys/param.h>
                     62: #include <sys/malloc.h>
                     63: #include <sys/mbuf.h>
                     64: #include <sys/systm.h>
                     65: #include <sys/proc.h>
                     66: #include <sys/socket.h>
                     67: #include <sys/socketvar.h>
                     68: #include <sys/protosw.h>
                     69: #include <sys/kernel.h>
                     70: #include <sys/sockio.h>
                     71: #include <sys/syslog.h>
                     72: #include <sys/sysctl.h>
                     73: #include <net/if.h>
                     74: #include <net/if_dl.h>
                     75: #include <net/radix.h>
                     76: #include <net/if_blue.h>
                     77: #include <netinet/in.h>
                     78: #include <net/dlil.h>
                     79: 
                     80: /*
                     81:  * System initialization
                     82:  */
                     83: 
                     84: static int ifconf __P((u_long, caddr_t));
                     85: static void if_qflush __P((struct ifqueue *));
                     86: static void link_rtrequest __P((int, struct rtentry *, struct sockaddr *));
                     87: 
                     88: MALLOC_DEFINE(M_IFADDR, "ifaddr", "interface address");
                     89: MALLOC_DEFINE(M_IFMADDR, "ether_multi", "link-level multicast address");
                     90: 
                     91: int    ifqmaxlen = IFQ_MAXLEN;
                     92: struct ifnethead ifnet;        /* depend on static init XXX */
                     93: 
                     94: /*
                     95:  * Network interface utility routines.
                     96:  *
                     97:  * Routines with ifa_ifwith* names take sockaddr *'s as
                     98:  * parameters.
                     99:  *
                    100:  * This routine assumes that it will be called at splimp() or higher.
                    101:  */
                    102: /* ARGSUSED*/
                    103: 
                    104: 
                    105: int if_index = 0;
                    106: struct ifaddr **ifnet_addrs;
                    107: 
                    108: 
                    109: /*
                    110:  * Attach an interface to the
                    111:  * list of "active" interfaces.
                    112:  */
                    113: void
                    114: old_if_attach(ifp)
                    115:        struct ifnet *ifp;
                    116: {
                    117:        unsigned socksize, ifasize;
                    118:        int namelen, masklen;
                    119:        char workbuf[64];
                    120:        register struct sockaddr_dl *sdl;
                    121:        register struct ifaddr *ifa;
                    122:        static int if_indexlim = 8;
                    123: 
                    124: 
                    125:        if (ifp->if_snd.ifq_maxlen == 0)
                    126:            ifp->if_snd.ifq_maxlen = ifqmaxlen;
                    127: 
                    128:        TAILQ_INSERT_TAIL(&ifnet, ifp, if_link);
                    129:        ifp->if_index = ++if_index;
                    130:        /*
                    131:         * XXX -
                    132:         * The old code would work if the interface passed a pre-existing
                    133:         * chain of ifaddrs to this code.  We don't trust our callers to
                    134:         * properly initialize the tailq, however, so we no longer allow
                    135:         * this unlikely case.
                    136:         */
                    137:        TAILQ_INIT(&ifp->if_addrhead);
                    138:        LIST_INIT(&ifp->if_multiaddrs);
                    139:        getmicrotime(&ifp->if_lastchange);
                    140:        if (ifnet_addrs == 0 || if_index >= if_indexlim) {
                    141:                unsigned n = (if_indexlim <<= 1) * sizeof(ifa);
                    142:                struct ifaddr **q = (struct ifaddr **)
                    143:                                        _MALLOC(n, M_IFADDR, M_WAITOK);
                    144:                bzero((caddr_t)q, n);
                    145:                if (ifnet_addrs) {
                    146:                        bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2);
                    147:                        FREE((caddr_t)ifnet_addrs, M_IFADDR);
                    148:                }
                    149:                ifnet_addrs = q;
                    150:        }
                    151:        /*
                    152:         * create a Link Level name for this device
                    153:         */
                    154:        namelen = snprintf(workbuf, sizeof(workbuf),
                    155:            "%s%d", ifp->if_name, ifp->if_unit);
                    156: #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
                    157:        masklen = _offsetof(struct sockaddr_dl, sdl_data[0]) + namelen;
                    158:        socksize = masklen + ifp->if_addrlen;
                    159: #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
                    160:        if (socksize < sizeof(*sdl))
                    161:                socksize = sizeof(*sdl);
                    162:        socksize = ROUNDUP(socksize);
                    163:        ifasize = sizeof(*ifa) + 2 * socksize;
                    164:        ifa = (struct ifaddr *) _MALLOC(ifasize, M_IFADDR, M_WAITOK);
                    165:        if (ifa) {
                    166:                bzero((caddr_t)ifa, ifasize);
                    167:                sdl = (struct sockaddr_dl *)(ifa + 1);
                    168:                sdl->sdl_len = socksize;
                    169:                sdl->sdl_family = AF_LINK;
                    170:                bcopy(workbuf, sdl->sdl_data, namelen);
                    171:                sdl->sdl_nlen = namelen;
                    172:                sdl->sdl_index = ifp->if_index;
                    173:                sdl->sdl_type = ifp->if_type;
                    174:                ifnet_addrs[if_index - 1] = ifa;
                    175:                ifa->ifa_ifp = ifp;
                    176:                ifa->ifa_rtrequest = link_rtrequest;
                    177:                ifa->ifa_addr = (struct sockaddr *)sdl;
                    178:                sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl);
                    179:                ifa->ifa_netmask = (struct sockaddr *)sdl;
                    180:                sdl->sdl_len = masklen;
                    181:                while (namelen != 0)
                    182:                        sdl->sdl_data[--namelen] = 0xff;
                    183:                TAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link);
                    184:        }
                    185: }
                    186: /*
                    187:  * Locate an interface based on a complete address.
                    188:  */
                    189: /*ARGSUSED*/
                    190: struct ifaddr *
                    191: ifa_ifwithaddr(addr)
                    192:        register struct sockaddr *addr;
                    193: {
                    194:        register struct ifnet *ifp;
                    195:        register struct ifaddr *ifa;
                    196: 
                    197: #define        equal(a1, a2) \
                    198:   (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
                    199:        for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next)
                    200:            for (ifa = ifp->if_addrhead.tqh_first; ifa; 
                    201:                 ifa = ifa->ifa_link.tqe_next) {
                    202:                if (ifa->ifa_addr->sa_family != addr->sa_family)
                    203:                        continue;
                    204:                if (equal(addr, ifa->ifa_addr))
                    205:                        return (ifa);
                    206:                if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr &&
                    207:                    equal(ifa->ifa_broadaddr, addr))
                    208:                        return (ifa);
                    209:        }
                    210:        return ((struct ifaddr *)0);
                    211: }
                    212: /*
                    213:  * Locate the point to point interface with a given destination address.
                    214:  */
                    215: /*ARGSUSED*/
                    216: struct ifaddr *
                    217: ifa_ifwithdstaddr(addr)
                    218:        register struct sockaddr *addr;
                    219: {
                    220:        register struct ifnet *ifp;
                    221:        register struct ifaddr *ifa;
                    222: 
                    223:        for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next)
                    224:            if (ifp->if_flags & IFF_POINTOPOINT)
                    225:                for (ifa = ifp->if_addrhead.tqh_first; ifa; 
                    226:                     ifa = ifa->ifa_link.tqe_next) {
                    227:                        if (ifa->ifa_addr->sa_family != addr->sa_family)
                    228:                                continue;
                    229:                        if (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr))
                    230:                                return (ifa);
                    231:        }
                    232:        return ((struct ifaddr *)0);
                    233: }
                    234: 
                    235: /*
                    236:  * Find an interface on a specific network.  If many, choice
                    237:  * is most specific found.
                    238:  */
                    239: struct ifaddr *
                    240: ifa_ifwithnet(addr)
                    241:        struct sockaddr *addr;
                    242: {
                    243:        register struct ifnet *ifp;
                    244:        register struct ifaddr *ifa;
                    245:        struct ifaddr *ifa_maybe = (struct ifaddr *) 0;
                    246:        u_int af = addr->sa_family;
                    247:        char *addr_data = addr->sa_data, *cplim;
                    248: 
                    249:        /*
                    250:         * AF_LINK addresses can be looked up directly by their index number,
                    251:         * so do that if we can.
                    252:         */
                    253:        if (af == AF_LINK) {
                    254:            register struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr;
                    255:            if (sdl->sdl_index && sdl->sdl_index <= if_index)
                    256:                return (ifnet_addrs[sdl->sdl_index - 1]);
                    257:        }
                    258: 
                    259:        /* 
                    260:         * Scan though each interface, looking for ones that have
                    261:         * addresses in this address family.
                    262:         */
                    263:        for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) {
                    264:                for (ifa = ifp->if_addrhead.tqh_first; ifa;
                    265:                     ifa = ifa->ifa_link.tqe_next) {
                    266:                        register char *cp, *cp2, *cp3;
                    267: 
                    268:                        if (ifa->ifa_addr->sa_family != af)
                    269: next:                          continue;
                    270:                        if (ifp->if_flags & IFF_POINTOPOINT) {
                    271:                                /*
                    272:                                 * This is a bit broken as it doesn't 
                    273:                                 * take into account that the remote end may 
                    274:                                 * be a single node in the network we are
                    275:                                 * looking for.
                    276:                                 * The trouble is that we don't know the 
                    277:                                 * netmask for the remote end.
                    278:                                 */
                    279:                                if (ifa->ifa_dstaddr != 0
                    280:                                    && equal(addr, ifa->ifa_dstaddr))
                    281:                                        return (ifa);
                    282:                        } else {
                    283:                                /*
                    284:                                 * if we have a special address handler,
                    285:                                 * then use it instead of the generic one.
                    286:                                 */
                    287:                                if (ifa->ifa_claim_addr) {
                    288:                                        if ((*ifa->ifa_claim_addr)(ifa, addr)) {
                    289:                                                return (ifa);
                    290:                                        } else {
                    291:                                                continue;
                    292:                                        }
                    293:                                }
                    294: 
                    295:                                /*
                    296:                                 * Scan all the bits in the ifa's address.
                    297:                                 * If a bit dissagrees with what we are
                    298:                                 * looking for, mask it with the netmask
                    299:                                 * to see if it really matters.
                    300:                                 * (A byte at a time)
                    301:                                 */
                    302:                                if (ifa->ifa_netmask == 0)
                    303:                                        continue;
                    304:                                cp = addr_data;
                    305:                                cp2 = ifa->ifa_addr->sa_data;
                    306:                                cp3 = ifa->ifa_netmask->sa_data;
                    307:                                cplim = ifa->ifa_netmask->sa_len
                    308:                                        + (char *)ifa->ifa_netmask;
                    309:                                while (cp3 < cplim)
                    310:                                        if ((*cp++ ^ *cp2++) & *cp3++)
                    311:                                                goto next; /* next address! */
                    312:                                /*
                    313:                                 * If the netmask of what we just found
                    314:                                 * is more specific than what we had before
                    315:                                 * (if we had one) then remember the new one
                    316:                                 * before continuing to search
                    317:                                 * for an even better one.
                    318:                                 */
                    319:                                if (ifa_maybe == 0 ||
                    320:                                    rn_refines((caddr_t)ifa->ifa_netmask,
                    321:                                    (caddr_t)ifa_maybe->ifa_netmask))
                    322:                                        ifa_maybe = ifa;
                    323:                        }
                    324:                }
                    325:        }
                    326:        return (ifa_maybe);
                    327: }
                    328: 
                    329: /*
                    330:  * Find an interface address specific to an interface best matching
                    331:  * a given address.
                    332:  */
                    333: struct ifaddr *
                    334: ifaof_ifpforaddr(addr, ifp)
                    335:        struct sockaddr *addr;
                    336:        register struct ifnet *ifp;
                    337: {
                    338:        register struct ifaddr *ifa;
                    339:        register char *cp, *cp2, *cp3;
                    340:        register char *cplim;
                    341:        struct ifaddr *ifa_maybe = 0;
                    342:        u_int af = addr->sa_family;
                    343: 
                    344:        if (af >= AF_MAX)
                    345:                return (0);
                    346:        for (ifa = ifp->if_addrhead.tqh_first; ifa; 
                    347:             ifa = ifa->ifa_link.tqe_next) {
                    348:                if (ifa->ifa_addr->sa_family != af)
                    349:                        continue;
                    350:                if (ifa_maybe == 0)
                    351:                        ifa_maybe = ifa;
                    352:                if (ifa->ifa_netmask == 0) {
                    353:                        if (equal(addr, ifa->ifa_addr) ||
                    354:                            (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)))
                    355:                                return (ifa);
                    356:                        continue;
                    357:                }
                    358:                if (ifp->if_flags & IFF_POINTOPOINT) {
                    359:                        if (equal(addr, ifa->ifa_dstaddr))
                    360:                                return (ifa);
                    361:                } else {
                    362:                        cp = addr->sa_data;
                    363:                        cp2 = ifa->ifa_addr->sa_data;
                    364:                        cp3 = ifa->ifa_netmask->sa_data;
                    365:                        cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
                    366:                        for (; cp3 < cplim; cp3++)
                    367:                                if ((*cp++ ^ *cp2++) & *cp3)
                    368:                                        break;
                    369:                        if (cp3 == cplim)
                    370:                                return (ifa);
                    371:                }
                    372:        }
                    373:        return (ifa_maybe);
                    374: }
                    375: 
                    376: #include <net/route.h>
                    377: 
                    378: /*
                    379:  * Default action when installing a route with a Link Level gateway.
                    380:  * Lookup an appropriate real ifa to point to.
                    381:  * This should be moved to /sys/net/link.c eventually.
                    382:  */
                    383: static void
                    384: link_rtrequest(cmd, rt, sa)
                    385:        int cmd;
                    386:        register struct rtentry *rt;
                    387:        struct sockaddr *sa;
                    388: {
                    389:        register struct ifaddr *ifa;
                    390:        struct sockaddr *dst;
                    391:        struct ifnet *ifp;
                    392: 
                    393:        if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
                    394:            ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0))
                    395:                return;
                    396:        ifa = ifaof_ifpforaddr(dst, ifp);
                    397:        if (ifa) {
                    398:                IFAFREE(rt->rt_ifa);
                    399:                rt->rt_ifa = ifa;
                    400:                ifa->ifa_refcnt++;
                    401:                if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest)
                    402:                        ifa->ifa_rtrequest(cmd, rt, sa);
                    403:        }
                    404: }
                    405: 
                    406: /*
                    407:  * Mark an interface down and notify protocols of
                    408:  * the transition.
                    409:  * NOTE: must be called at splnet or eqivalent.
                    410:  */
                    411: void
                    412: if_unroute(ifp, flag, fam)
                    413:        register struct ifnet *ifp;
                    414:        int flag, fam;
                    415: {
                    416:        register struct ifaddr *ifa;
                    417: 
                    418:        ifp->if_flags &= ~flag;
                    419:        getmicrotime(&ifp->if_lastchange);
                    420:        TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
                    421:                if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family))
                    422:                        pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
                    423:        if_qflush(&ifp->if_snd);
                    424:        rt_ifmsg(ifp);
                    425: }
                    426: 
                    427: /*
                    428:  * Mark an interface up and notify protocols of
                    429:  * the transition.
                    430:  * NOTE: must be called at splnet or eqivalent.
                    431:  */
                    432: void
                    433: if_route(ifp, flag, fam)
                    434:        register struct ifnet *ifp;
                    435:        int flag, fam;
                    436: {
                    437:        register struct ifaddr *ifa;
                    438: 
                    439:        ifp->if_flags |= flag;
                    440:        getmicrotime(&ifp->if_lastchange);
                    441:        TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
                    442:                if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family))
                    443:                        pfctlinput(PRC_IFUP, ifa->ifa_addr);
                    444:        rt_ifmsg(ifp);
                    445: }
                    446: 
                    447: /*
                    448:  * Mark an interface down and notify protocols of
                    449:  * the transition.
                    450:  * NOTE: must be called at splnet or eqivalent.
                    451:  */
                    452: void
                    453: if_down(ifp)
                    454:        register struct ifnet *ifp;
                    455: {
                    456: 
                    457:        if_unroute(ifp, IFF_UP, AF_UNSPEC);
                    458: }
                    459: 
                    460: /*
                    461:  * Mark an interface up and notify protocols of
                    462:  * the transition.
                    463:  * NOTE: must be called at splnet or eqivalent.
                    464:  */
                    465: void
                    466: if_up(ifp)
                    467:        register struct ifnet *ifp;
                    468: {
                    469: 
                    470:        if_route(ifp, IFF_UP, AF_UNSPEC);
                    471: }
                    472: 
                    473: /*
                    474:  * Flush an interface queue.
                    475:  */
                    476: static void
                    477: if_qflush(ifq)
                    478:        register struct ifqueue *ifq;
                    479: {
                    480:        register struct mbuf *m, *n;
                    481: 
                    482:        n = ifq->ifq_head;
                    483:        while ((m = n) != 0) {
                    484:                n = m->m_act;
                    485:                m_freem(m);
                    486:        }
                    487:        ifq->ifq_head = 0;
                    488:        ifq->ifq_tail = 0;
                    489:        ifq->ifq_len = 0;
                    490: }
                    491: 
                    492: 
                    493: /*
                    494:  * Map interface name to
                    495:  * interface structure pointer.
                    496:  */
                    497: struct ifnet *
                    498: ifunit(name)
                    499:        register char *name;
                    500: {
                    501:        char namebuf[IFNAMSIZ + 1];
                    502:        register char *cp, *cp2;
                    503:        char *end;
                    504:        register struct ifnet *ifp;
                    505:        int unit;
                    506:        unsigned len;
                    507:        register char c = '\0';
                    508: 
                    509:        /*
                    510:         * Look for a non numeric part
                    511:         */
                    512:        end = name + IFNAMSIZ; 
                    513:        cp2 = namebuf;
                    514:        cp = name; 
                    515:        while ((cp < end) && (c = *cp)) {
                    516:                if (c >= '0' && c <= '9')
                    517:                        break;
                    518:                *cp2++ = c;
                    519:                cp++;
                    520:        }
                    521:        if ((cp == end) || (c == '\0') || (cp == name))
                    522:                return ((struct ifnet *)0);
                    523:        *cp2 = '\0';
                    524:        /*
                    525:         * check we have a legal number (limit to 7 digits?)
                    526:         */
                    527:        len = cp - name + 1;
                    528:        for (unit = 0;
                    529:            ((c = *cp) >= '0') && (c <= '9') && (unit < 1000000); cp++ ) 
                    530:                unit = (unit * 10) + (c - '0');
                    531:        if (*cp != '\0')
                    532:                return 0;       /* no trailing garbage allowed */
                    533:        /*
                    534:         * Now search all the interfaces for this name/number
                    535:         */
                    536:        for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) {
                    537:                if (bcmp(ifp->if_name, namebuf, len))
                    538:                        continue;
                    539:                if (unit == ifp->if_unit)
                    540:                        break;
                    541:        }
                    542:        return (ifp);
                    543: }
                    544: 
                    545: /*
                    546:  * Interface ioctls.
                    547:  */
                    548: int
                    549: ifioctl(so, cmd, data, p)
                    550:        struct socket *so;
                    551:        u_long cmd;
                    552:        caddr_t data;
                    553:        struct proc *p;
                    554: {
                    555:        register struct ifnet *ifp;
                    556:        register struct ifreq *ifr;
                    557:        int error;
                    558:        extern int new_splitter(struct socket *);
                    559:        void if_register(struct BlueFilter *);
                    560: 
                    561:        switch (cmd) {
                    562: 
                    563:        case SIOCGIFCONF:
                    564:        case OSIOCGIFCONF:
                    565:                return (ifconf(cmd, data));
                    566:        }
                    567:        ifr = (struct ifreq *)data;
                    568:        ifp = ifunit(ifr->ifr_name);
                    569:        if (ifp == 0)
                    570:                return (ENXIO);
                    571:        switch (cmd) {
                    572: 
                    573:        case SIOCSSPLITTER:
                    574:                if ((error = new_splitter(so)))
                    575:                        return(error);
                    576:                break;
                    577: 
                    578:        case SIOCGSPLITTER:
                    579:                ifr->ifr_data = (caddr_t)(ifp->if_flags & IFF_SPLITTER);
                    580:                break;
                    581: 
                    582:        case SIOCGIFFLAGS:
                    583:                ifr->ifr_flags = ifp->if_flags;
                    584:                break;
                    585: 
                    586:        case SIOCGIFMETRIC:
                    587:                ifr->ifr_metric = ifp->if_metric;
                    588:                break;
                    589: 
                    590:        case SIOCGIFMTU:
                    591:                ifr->ifr_mtu = ifp->if_mtu;
                    592:                break;
                    593: 
                    594:        case SIOCGIFPHYS:
                    595:                ifr->ifr_phys = ifp->if_physical;
                    596:                break;
                    597: 
                    598:        case SIOCSIFFLAGS:
                    599:                error = suser(p->p_ucred, &p->p_acflag);
                    600:                if (error)
                    601:                        return (error);
                    602:                if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
                    603:                        int s = splimp();
                    604:                        if_down(ifp);
                    605:                        splx(s);
                    606:                }
                    607:                if (ifr->ifr_flags & IFF_UP && (ifp->if_flags & IFF_UP) == 0) {
                    608:                        int s = splimp();
                    609:                        if_up(ifp);
                    610:                        splx(s);
                    611:                }
                    612:                ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
                    613:                        (ifr->ifr_flags &~ IFF_CANTCHANGE);
                    614:                if (ifp->if_ioctl)
                    615:                        dlil_ioctl(0, ifp, cmd, (caddr_t) data);
                    616:                getmicrotime(&ifp->if_lastchange);
                    617:                break;
                    618: 
                    619:        case SIOCSIFMETRIC:
                    620:                error = suser(p->p_ucred, &p->p_acflag);
                    621:                if (error)
                    622:                        return (error);
                    623:                ifp->if_metric = ifr->ifr_metric;
                    624:                getmicrotime(&ifp->if_lastchange);
                    625:                break;
                    626: 
                    627:        case SIOCSIFPHYS:
                    628:                error = suser(p->p_ucred, &p->p_acflag);
                    629:                if (error)
                    630:                        return error;
                    631:                if (!ifp->if_ioctl)
                    632:                        return EOPNOTSUPP;
                    633:                error = dlil_ioctl(0, ifp, cmd, (caddr_t) data);
                    634:                if (error == 0)
                    635:                        getmicrotime(&ifp->if_lastchange);
                    636:                return(error);
                    637: 
                    638:        case SIOCSIFMTU:
                    639:                error = suser(p->p_ucred, &p->p_acflag);
                    640:                if (error)
                    641:                        return (error);
                    642:                if (ifp->if_ioctl == NULL)
                    643:                        return (EOPNOTSUPP);
                    644:                /*
                    645:                 * 72 was chosen below because it is the size of a TCP/IP
                    646:                 * header (40) + the minimum mss (32).
                    647:                 */
                    648:                if (ifr->ifr_mtu < 72 || ifr->ifr_mtu > 65535)
                    649:                        return (EINVAL);
                    650:                error = dlil_ioctl(0, ifp, cmd, (caddr_t) data);
                    651:                if (error == 0)
                    652:                        getmicrotime(&ifp->if_lastchange);
                    653:                return(error);
                    654: 
                    655:        case SIOCADDMULTI:
                    656:        case SIOCDELMULTI:
                    657:                error = suser(p->p_ucred, &p->p_acflag);
                    658:                if (error)
                    659:                        return (error);
                    660: 
                    661:                /* Don't allow group membership on non-multicast interfaces. */
                    662:                if ((ifp->if_flags & IFF_MULTICAST) == 0)
                    663:                        return EOPNOTSUPP;
                    664: 
                    665: #if 0
                    666:                /*
                    667:                 * Don't let users change protocols' entries.
                    668:                 */
                    669:                if (ifr->ifr_addr.sa_family != AF_LINK)
                    670:                        return EINVAL;
                    671: #endif
                    672:                if (cmd == SIOCADDMULTI) {
                    673:                        struct ifmultiaddr *ifma;
                    674:                        error = if_addmulti(ifp, &ifr->ifr_addr, &ifma);
                    675:                } else {
                    676:                        error = if_delmulti(ifp, &ifr->ifr_addr);
                    677:                }
                    678:                if (error == 0)
                    679:                        getmicrotime(&ifp->if_lastchange);
                    680:                return error;
                    681: 
                    682:         case SIOCSIFMEDIA:
                    683:        case SIOCSIFGENERIC:
                    684:                error = suser(p->p_ucred, &p->p_acflag);
                    685:                if (error)
                    686:                        return (error);
                    687:                if (ifp->if_ioctl == 0)
                    688:                        return (EOPNOTSUPP);
                    689:                error = dlil_ioctl(0, ifp, cmd, (caddr_t) data);
                    690:                if (error == 0)
                    691:                        getmicrotime(&ifp->if_lastchange);
                    692:                return error;
                    693: 
                    694:        case SIOCGIFMEDIA:
                    695:        case SIOCGIFGENERIC:
                    696:                if (ifp->if_ioctl == 0)
                    697:                        return (EOPNOTSUPP);
                    698:                return dlil_ioctl(0, ifp, cmd, (caddr_t) data);
                    699: 
                    700:        default:
                    701:                if (so->so_proto == 0)
                    702:                        return (EOPNOTSUPP);
                    703: #if !COMPAT_43
                    704:                return ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd,
                    705:                                                                 data,
                    706:                                                                 ifp, p));
                    707: #else
                    708:            {
                    709:                int ocmd = cmd;
                    710: 
                    711:                switch (cmd) {
                    712: 
                    713:                case SIOCSIFDSTADDR:
                    714:                case SIOCSIFADDR:
                    715:                case SIOCSIFBRDADDR:
                    716:                case SIOCSIFNETMASK:
                    717: #if BYTE_ORDER != BIG_ENDIAN
                    718:                        if (ifr->ifr_addr.sa_family == 0 &&
                    719:                            ifr->ifr_addr.sa_len < 16) {
                    720:                                ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
                    721:                                ifr->ifr_addr.sa_len = 16;
                    722:                        }
                    723: #else
                    724:                        if (ifr->ifr_addr.sa_len == 0)
                    725:                                ifr->ifr_addr.sa_len = 16;
                    726: #endif
                    727: #define IFR2IN(ifr) ((struct in_addr *)&(ifr->ifr_addr))->s_addr
                    728:                        if (ifr->ifr_addr.sa_family == AF_INET)
                    729:                        {       /*
                    730:                                 * If we have an address, and we're 'splitting',
                    731:                                 *  register the address.  Note that this
                    732:                                 *  is to handle the case of addresses
                    733:                                 *  registered after the Blue Box starts.
                    734:                                 */
                    735:                                if ((ifp->if_flags & IFF_SPLITTER) &&
                    736:                                    (IFR2IN(ifr) != 0))
                    737:                                {       struct BlueFilter filter;
                    738: 
                    739:                                        filter.BF_flags = (BF_ALLOC|BF_IP);
                    740:                                        filter.BF_address = IFR2IN(ifr);
                    741:                                        log(LOG_WARNING,
                    742:                                            "[2]IP registering %x",
                    743:                                            filter.BF_address);
                    744:                                        if_register(&filter);
                    745:                                }
                    746:                        }
                    747:                        /* Fall through! */
                    748:                        break;
                    749: 
                    750:                case OSIOCGIFADDR:
                    751:                        cmd = SIOCGIFADDR;
                    752:                        break;
                    753: 
                    754:                case OSIOCGIFDSTADDR:
                    755:                        cmd = SIOCGIFDSTADDR;
                    756:                        break;
                    757: 
                    758:                case OSIOCGIFBRDADDR:
                    759:                        cmd = SIOCGIFBRDADDR;
                    760:                        break;
                    761: 
                    762:                case OSIOCGIFNETMASK:
                    763:                        cmd = SIOCGIFNETMASK;
                    764:                }
                    765:                error =  ((*so->so_proto->pr_usrreqs->pru_control)(so,
                    766:                                                                   cmd,
                    767:                                                                   data,
                    768:                                                                   ifp, p));
                    769:                switch (ocmd) {
                    770: 
                    771:                case OSIOCGIFADDR:
                    772:                case OSIOCGIFDSTADDR:
                    773:                case OSIOCGIFBRDADDR:
                    774:                case OSIOCGIFNETMASK:
                    775:                        *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;
                    776:                }
                    777:                return (error);
                    778: 
                    779:            }
                    780: #endif
                    781:        }
                    782:        return (0);
                    783: }
                    784: 
                    785: /*
                    786:  * Set/clear promiscuous mode on interface ifp based on the truth value
                    787:  * of pswitch.  The calls are reference counted so that only the first
                    788:  * "on" request actually has an effect, as does the final "off" request.
                    789:  * Results are undefined if the "off" and "on" requests are not matched.
                    790:  */
                    791: int
                    792: ifpromisc(ifp, pswitch)
                    793:        struct ifnet *ifp;
                    794:        int pswitch;
                    795: {
                    796:        struct ifreq ifr;
                    797:        int error;
                    798: 
                    799:        if (pswitch) {
                    800:                /*
                    801:                 * If the device is not configured up, we cannot put it in
                    802:                 * promiscuous mode.
                    803:                 */
                    804:                if ((ifp->if_flags & IFF_UP) == 0)
                    805:                        return (ENETDOWN);
                    806:                if (ifp->if_pcount++ != 0)
                    807:                        return (0);
                    808:                ifp->if_flags |= IFF_PROMISC;
                    809:                log(LOG_INFO, "%s%d: promiscuous mode enabled\n",
                    810:                    ifp->if_name, ifp->if_unit);
                    811:        } else {
                    812:                if (--ifp->if_pcount > 0)
                    813:                        return (0);
                    814:                ifp->if_flags &= ~IFF_PROMISC;
                    815:        }
                    816:        ifr.ifr_flags = ifp->if_flags;
                    817:        error = dlil_ioctl(0, ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
                    818:        if (error == 0)
                    819:                rt_ifmsg(ifp);
                    820:        return error;
                    821: }
                    822: 
                    823: /*
                    824:  * Return interface configuration
                    825:  * of system.  List may be used
                    826:  * in later ioctl's (above) to get
                    827:  * other information.
                    828:  */
                    829: /*ARGSUSED*/
                    830: static int
                    831: ifconf(cmd, data)
                    832:        u_long cmd;
                    833:        caddr_t data;
                    834: {
                    835:        register struct ifconf *ifc = (struct ifconf *)data;
                    836:        register struct ifnet *ifp = ifnet.tqh_first;
                    837:        register struct ifaddr *ifa;
                    838:        struct ifreq ifr, *ifrp;
                    839:        int space = ifc->ifc_len, error = 0;
                    840: 
                    841:        ifrp = ifc->ifc_req;
                    842:        for (; space > sizeof (ifr) && ifp; ifp = ifp->if_link.tqe_next) {
                    843:                char workbuf[64];
                    844:                int ifnlen;
                    845: 
                    846:                ifnlen = snprintf(workbuf, sizeof(workbuf),
                    847:                    "%s%d", ifp->if_name, ifp->if_unit);
                    848:                if(ifnlen + 1 > sizeof ifr.ifr_name) {
                    849:                        error = ENAMETOOLONG;
                    850:                } else {
                    851:                        strcpy(ifr.ifr_name, workbuf);
                    852:                }
                    853: 
                    854:                if ((ifa = ifp->if_addrhead.tqh_first) == 0) {
                    855:                        bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
                    856:                        error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
                    857:                            sizeof (ifr));
                    858:                        if (error)
                    859:                                break;
                    860:                        space -= sizeof (ifr), ifrp++;
                    861:                } else
                    862:                    for ( ; space > sizeof (ifr) && ifa; 
                    863:                         ifa = ifa->ifa_link.tqe_next) {
                    864:                        register struct sockaddr *sa = ifa->ifa_addr;
                    865: #if COMPAT_43
                    866:                        if (cmd == OSIOCGIFCONF) {
                    867:                                struct osockaddr *osa =
                    868:                                         (struct osockaddr *)&ifr.ifr_addr;
                    869:                                ifr.ifr_addr = *sa;
                    870:                                osa->sa_family = sa->sa_family;
                    871:                                error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
                    872:                                                sizeof (ifr));
                    873:                                ifrp++;
                    874:                        } else
                    875: #endif
                    876:                        if (sa->sa_len <= sizeof(*sa)) {
                    877:                                ifr.ifr_addr = *sa;
                    878:                                error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
                    879:                                                sizeof (ifr));
                    880:                                ifrp++;
                    881:                        } else {
                    882:                                space -= sa->sa_len - sizeof(*sa);
                    883:                                if (space < sizeof (ifr))
                    884:                                        break;
                    885:                                error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
                    886:                                                sizeof (ifr.ifr_name));
                    887:                                if (error == 0)
                    888:                                    error = copyout((caddr_t)sa,
                    889:                                      (caddr_t)&ifrp->ifr_addr, sa->sa_len);
                    890:                                ifrp = (struct ifreq *)
                    891:                                        (sa->sa_len + (caddr_t)&ifrp->ifr_addr);
                    892:                        }
                    893:                        if (error)
                    894:                                break;
                    895:                        space -= sizeof (ifr);
                    896:                }
                    897:        }
                    898:        ifc->ifc_len -= space;
                    899:        return (error);
                    900: }
                    901: 
                    902: /*
                    903:  * Just like if_promisc(), but for all-multicast-reception mode.
                    904:  */
                    905: int
                    906: if_allmulti(ifp, onswitch)
                    907:        struct ifnet *ifp;
                    908:        int onswitch;
                    909: {
                    910:        int error = 0;
                    911:        int s = splimp();
                    912: 
                    913:        if (onswitch) {
                    914:                if (ifp->if_amcount++ == 0) {
                    915:                        ifp->if_flags |= IFF_ALLMULTI;
                    916:                        error = dlil_ioctl(0, ifp, SIOCSIFFLAGS, (caddr_t) 0);
                    917:                }
                    918:        } else {
                    919:                if (ifp->if_amcount > 1) {
                    920:                        ifp->if_amcount--;
                    921:                } else {
                    922:                        ifp->if_amcount = 0;
                    923:                        ifp->if_flags &= ~IFF_ALLMULTI;
                    924:                        error = dlil_ioctl(0, ifp, SIOCSIFFLAGS, (caddr_t) 0);
                    925:                }
                    926:        }
                    927:        splx(s);
                    928: 
                    929:        if (error == 0)
                    930:                rt_ifmsg(ifp);
                    931:        return error;
                    932: }
                    933: 
                    934: /*
                    935:  * Add a multicast listenership to the interface in question.
                    936:  * The link layer provides a routine which converts 
                    937:  */
                    938: int
                    939: if_addmulti(ifp, sa, retifma)
                    940:        struct ifnet *ifp;      /* interface to manipulate */
                    941:        struct sockaddr *sa;    /* address to add */
                    942:        struct ifmultiaddr **retifma;
                    943: {
                    944:        struct sockaddr *llsa, *dupsa;
                    945:        int error, s;
                    946:        struct ifmultiaddr *ifma;
                    947: 
                    948:        /*
                    949:         * If the matching multicast address already exists
                    950:         * then don't add a new one, just add a reference
                    951:         */
                    952:        for (ifma = ifp->if_multiaddrs.lh_first; ifma; 
                    953:             ifma = ifma->ifma_link.le_next) {
                    954:                if (equal(sa, ifma->ifma_addr)) {
                    955:                        ifma->ifma_refcount++;
                    956:                        if (retifma)
                    957:                                *retifma = ifma;
                    958:                        return 0;
                    959:                }
                    960:        }
                    961: 
                    962:        /*
                    963:         * Give the link layer a chance to accept/reject it, and also
                    964:         * find out which AF_LINK address this maps to, if it isn't one
                    965:         * already.
                    966:         */
                    967:        if (ifp->if_resolvemulti) {
                    968:                error = ifp->if_resolvemulti(ifp, &llsa, sa);
                    969:                if (error) return error;
                    970:        } else {
                    971:                llsa = 0;
                    972:        }
                    973: 
                    974:        MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma, M_IFMADDR, M_WAITOK);
                    975:        MALLOC(dupsa, struct sockaddr *, sa->sa_len, M_IFMADDR, M_WAITOK);
                    976:        bcopy(sa, dupsa, sa->sa_len);
                    977: 
                    978:        ifma->ifma_addr = dupsa;
                    979:        ifma->ifma_lladdr = llsa;
                    980:        ifma->ifma_ifp = ifp;
                    981:        ifma->ifma_refcount = 1;
                    982:        ifma->ifma_protospec = 0;
                    983:        rt_newmaddrmsg(RTM_NEWMADDR, ifma);
                    984: 
                    985:        /*
                    986:         * Some network interfaces can scan the address list at
                    987:         * interrupt time; lock them out.
                    988:         */
                    989:        s = splimp();
                    990:        LIST_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link);
                    991:        splx(s);
                    992:        if (retifma)
                    993:            *retifma = ifma;
                    994: 
                    995:        if (llsa != 0) {
                    996:                for (ifma = ifp->if_multiaddrs.lh_first; ifma;
                    997:                     ifma = ifma->ifma_link.le_next) {
                    998:                        if (equal(ifma->ifma_addr, llsa))
                    999:                                break;
                   1000:                }
                   1001:                if (ifma) {
                   1002:                        ifma->ifma_refcount++;
                   1003:                } else {
                   1004:                        MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma,
                   1005:                               M_IFMADDR, M_WAITOK);
                   1006:                        MALLOC(dupsa, struct sockaddr *, llsa->sa_len,
                   1007:                               M_IFMADDR, M_WAITOK);
                   1008:                        bcopy(llsa, dupsa, llsa->sa_len);
                   1009:                        ifma->ifma_addr = dupsa;
                   1010:                        ifma->ifma_ifp = ifp;
                   1011:                        ifma->ifma_refcount = 1;
                   1012:                        s = splimp();
                   1013:                        LIST_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link);
                   1014:                        splx(s);
                   1015:                }
                   1016:        }
                   1017:        /*
                   1018:         * We are certain we have added something, so call down to the
                   1019:         * interface to let them know about it.
                   1020:         */
                   1021:        s = splimp();
                   1022: 
                   1023:        dlil_ioctl(0, ifp, SIOCADDMULTI, (caddr_t) 0);
                   1024:        splx(s);
                   1025: 
                   1026:        return 0;
                   1027: }
                   1028: 
                   1029: /*
                   1030:  * Remove a reference to a multicast address on this interface.  Yell
                   1031:  * if the request does not match an existing membership.
                   1032:  */
                   1033: int
                   1034: if_delmulti(ifp, sa)
                   1035:        struct ifnet *ifp;
                   1036:        struct sockaddr *sa;
                   1037: {
                   1038:        struct ifmultiaddr *ifma;
                   1039:        int s;
                   1040: 
                   1041:        for (ifma = ifp->if_multiaddrs.lh_first; ifma; 
                   1042:             ifma = ifma->ifma_link.le_next)
                   1043:                if (equal(sa, ifma->ifma_addr))
                   1044:                        break;
                   1045:        if (ifma == 0)
                   1046:                return ENOENT;
                   1047: 
                   1048:        if (ifma->ifma_refcount > 1) {
                   1049:                ifma->ifma_refcount--;
                   1050:                return 0;
                   1051:        }
                   1052: 
                   1053:        rt_newmaddrmsg(RTM_DELMADDR, ifma);
                   1054:        sa = ifma->ifma_lladdr;
                   1055:        s = splimp();
                   1056:        LIST_REMOVE(ifma, ifma_link);
                   1057:        splx(s);
                   1058:        FREE(ifma->ifma_addr, M_IFMADDR);
                   1059:        FREE(ifma, M_IFMADDR);
                   1060:        if (sa == 0)
                   1061:                return 0;
                   1062: 
                   1063:        /*
                   1064:         * Now look for the link-layer address which corresponds to
                   1065:         * this network address.  It had been squirreled away in
                   1066:         * ifma->ifma_lladdr for this purpose (so we don't have
                   1067:         * to call ifp->if_resolvemulti() again), and we saved that
                   1068:         * value in sa above.  If some nasty deleted the
                   1069:         * link-layer address out from underneath us, we can deal because
                   1070:         * the address we stored was is not the same as the one which was
                   1071:         * in the record for the link-layer address.  (So we don't complain
                   1072:         * in that case.)
                   1073:         */
                   1074:        for (ifma = ifp->if_multiaddrs.lh_first; ifma; 
                   1075:             ifma = ifma->ifma_link.le_next)
                   1076:                if (equal(sa, ifma->ifma_addr))
                   1077:                        break;
                   1078:        if (ifma == 0)
                   1079:                return 0;
                   1080: 
                   1081:        if (ifma->ifma_refcount > 1) {
                   1082:                ifma->ifma_refcount--;
                   1083:                return 0;
                   1084:        }
                   1085: 
                   1086:        s = splimp();
                   1087:        LIST_REMOVE(ifma, ifma_link);
                   1088:        dlil_ioctl(0, ifp, SIOCDELMULTI, (caddr_t) 0);
                   1089:        splx(s);
                   1090:        FREE(ifma->ifma_addr, M_IFMADDR);
                   1091:        FREE(sa, M_IFMADDR);
                   1092:        FREE(ifma, M_IFMADDR);
                   1093: 
                   1094:        return 0;
                   1095: }
                   1096: 
                   1097: struct ifmultiaddr *
                   1098: ifmaof_ifpforaddr(sa, ifp)
                   1099:        struct sockaddr *sa;
                   1100:        struct ifnet *ifp;
                   1101: {
                   1102:        struct ifmultiaddr *ifma;
                   1103:        
                   1104:        for (ifma = ifp->if_multiaddrs.lh_first; ifma;
                   1105:             ifma = ifma->ifma_link.le_next)
                   1106:                if (equal(ifma->ifma_addr, sa))
                   1107:                        break;
                   1108: 
                   1109:        return ifma;
                   1110: }
                   1111: 
                   1112: SYSCTL_NODE(_net, PF_LINK, link, CTLFLAG_RW, 0, "Link layers");
                   1113: SYSCTL_NODE(_net_link, 0, generic, CTLFLAG_RW, 0, "Generic link-management");
                   1114: 
                   1115: 
                   1116: /*
                   1117:  * Shutdown all network activity.  Used boot() when halting
                   1118:  * system.
                   1119:  */
                   1120: int if_down_all(void)
                   1121: {
                   1122:        struct ifnet *ifp;
                   1123:        int s;
                   1124: 
                   1125:        s = splnet();
                   1126:        TAILQ_FOREACH(ifp, &ifnet, if_link)
                   1127:                if_down(ifp);
                   1128: 
                   1129:        splx(s);
                   1130:        return(0);              /* Sheesh */
                   1131: }

unix.superglobalmegacorp.com

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