Annotation of cci/sys/netinet/if_ether.c, revision 1.1

1.1     ! root        1: /*     if_ether.c      6.2     83/08/28        */
        !             2: 
        !             3: /*
        !             4:  * Ethernet address resolution protocol.
        !             5:  */
        !             6: 
        !             7: #include "../h/param.h"
        !             8: #include "../h/systm.h"
        !             9: #include "../h/mbuf.h"
        !            10: #include "../h/socket.h"
        !            11: #include "../h/time.h"
        !            12: #include "../h/kernel.h"
        !            13: #include "../h/errno.h"
        !            14: 
        !            15: #include "../net/if.h"
        !            16: #include "../netinet/in.h"
        !            17: #include "../netinet/if_ether.h"
        !            18: 
        !            19: /*
        !            20:  * changes:
        !            21:  *
        !            22:  *     . always return 0 after calling looutput().
        !            23:  *
        !            24:  *     . forces messages going to net if flag gotoether is set.
        !            25:  *       (set this flag through "adb" for debugging purposes).
        !            26:  *
        !            27:  *     . add symbolic return code to arpresolve(). See comments in 
        !            28:  *       arpresolve().
        !            29:  */
        !            30: 
        !            31: /*
        !            32:  * Internet to ethernet address resolution table.
        !            33:  */
        !            34: struct arptab {
        !            35:        struct  in_addr at_iaddr;       /* internet address */
        !            36:        u_char  at_enaddr[6];           /* ethernet address */
        !            37:        struct  mbuf *at_hold;          /* last packet until resolved/timeout */
        !            38:        u_char  at_timer;               /* minutes since last reference */
        !            39:        u_char  at_flags;               /* flags */
        !            40: };
        !            41: /* at_flags field values */
        !            42: #define        ATF_INUSE       1               /* entry in use */
        !            43: #define ATF_COM                2               /* completed entry (enaddr valid) */
        !            44: 
        !            45: #define        ARPTAB_BSIZ     5               /* bucket size */
        !            46: #define        ARPTAB_NB       19              /* number of buckets */
        !            47: #define        ARPTAB_SIZE     (ARPTAB_BSIZ * ARPTAB_NB)
        !            48: struct arptab arptab[ARPTAB_SIZE];
        !            49: 
        !            50: #define        ARPTAB_HASH(a) \
        !            51:        ((short)((((a) >> 16) ^ (a)) & 0x7fff) % ARPTAB_NB)
        !            52: 
        !            53: #define        ARPTAB_LOOK(at,addr) { \
        !            54:        register n; \
        !            55:        at = &arptab[ARPTAB_HASH(addr) * ARPTAB_BSIZ]; \
        !            56:        for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) \
        !            57:                if (at->at_iaddr.s_addr == addr) \
        !            58:                        break; \
        !            59:        if (n >= ARPTAB_BSIZ) \
        !            60:                at = 0; }
        !            61: 
        !            62: struct arpcom *arpcom;         /* chain of active ether interfaces */
        !            63: int    arpt_age;               /* aging timer */
        !            64: int    gotoether;              /* force traffic to Ethernet; no software
        !            65:                                   loopback */
        !            66: 
        !            67: /* timer values */
        !            68: #define        ARPT_AGE        (60*1)  /* aging timer, 1 min. */
        !            69: #define        ARPT_KILLC      20      /* kill completed entry in 20 mins. */
        !            70: #define        ARPT_KILLI      3       /* kill incomplete entry in 3 minutes */
        !            71: 
        !            72: u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
        !            73: extern struct ifnet loif;
        !            74: 
        !            75: /*------------- debug tools ---------------*/
        !            76: #ifdef ARPPRINTFS
        !            77:        int     arpprintfs;
        !            78: #      define ARPTRACE(X)      {if (arpprintfs) X }
        !            79: #else  ARPPRINTFS
        !            80: #      define ARPTRACE(X)
        !            81: #endif ARPPRINTFS
        !            82: 
        !            83: /*
        !            84:  * Local addresses in the range oldmap to infinity are
        !            85:  * mapped according to the old mapping scheme.  That is,
        !            86:  * mapping of Internet to Ethernet addresses is performed
        !            87:  * by taking the high three bytes of the network interface's
        !            88:  * address and the low three bytes of the local address part.
        !            89:  * This only allows boards from the same manufacturer to
        !            90:  * communicate unless the on-board address is overridden
        !            91:  * (not possible in many manufacture's hardware).
        !            92:  *
        !            93:  * NB: setting oldmap to zero completely disables ARP
        !            94:  *     (i.e. identical to setting IFF_NOARP with an ioctl).
        !            95:  */
        !            96: int    oldmap = 0xffffff;
        !            97: 
        !            98: /*
        !            99:  * Attach an ethernet interface to the list "arpcom" where
        !           100:  * arptimer() can find it.  If first time 
        !           101:  * initialization, start arptimer().
        !           102:  */
        !           103: arpattach(ac)
        !           104:        register struct arpcom *ac;
        !           105: {
        !           106:        register struct arpcom *acp;
        !           107: 
        !           108:        for (acp = arpcom; acp != (struct arpcom *)0; acp = acp->ac_ac)
        !           109:                if (acp == ac)          /* if already on list */
        !           110:                        return;
        !           111:        ac->ac_ac = arpcom;
        !           112:        arpcom = ac;
        !           113:        if (arpcom->ac_ac == 0)         /* very first time */
        !           114:                arptimer();
        !           115: }
        !           116: 
        !           117: /*
        !           118:  * Timeout routine.  Age arp_tab entries once a minute.
        !           119:  */
        !           120: arptimer()
        !           121: {
        !           122:        register struct arptab *at;
        !           123:        register i;
        !           124: 
        !           125:        timeout(arptimer, (caddr_t)0, hz);
        !           126: #ifdef notdef
        !           127:        if (++arpt_sanity > ARPT_SANITY) {
        !           128:                register struct arpcom *ac;
        !           129: 
        !           130:                /*
        !           131:                 * Randomize sanity timer based on my host address.
        !           132:                 * Ask who has my own address;  if someone else replies,
        !           133:                 * then they are impersonating me.
        !           134:                 */
        !           135:                arpt_sanity = arpcom->ac_enaddr[5] & 0x3f;
        !           136:                for (ac = arpcom; ac != (struct arpcom *)-1; ac = ac->ac_ac)
        !           137:                        arpwhohas(ac, &((struct sockaddr_in *)
        !           138:                            &ac->ac_if.if_addr)->sin_addr);
        !           139:        }
        !           140: #endif
        !           141:        if (++arpt_age > ARPT_AGE) {
        !           142:                arpt_age = 0;
        !           143:                at = &arptab[0];
        !           144:                for (i = 0; i < ARPTAB_SIZE; i++, at++) {
        !           145:                        if (at->at_flags == 0)
        !           146:                                continue;
        !           147:                        if (++at->at_timer < ((at->at_flags&ATF_COM) ?
        !           148:                            ARPT_KILLC : ARPT_KILLI))
        !           149:                                continue;
        !           150:                        /* timer has expired, clear entry */
        !           151:                        arptfree(at);
        !           152:                }
        !           153:        }
        !           154: }
        !           155: 
        !           156: /*
        !           157:  * Broadcast an ARP packet, asking who has addr on interface ac.
        !           158:  */
        !           159: arpwhohas(ac, addr)
        !           160:        register struct arpcom *ac;
        !           161:        struct in_addr *addr;
        !           162: {
        !           163:        register struct mbuf *m;
        !           164:        register struct ether_header *eh;
        !           165:        register struct ether_arp *ea;
        !           166:        struct sockaddr sa;
        !           167: 
        !           168:        m = m_get(M_DONTWAIT, MT_DATA);
        !           169:        MBUFNULL(5,m);                  /* for debugging */
        !           170:        if (m == NULL)
        !           171:                return;
        !           172:        m->m_len = sizeof *ea + SIZEOF_ETHEADER;
        !           173:        m->m_off = MMAXOFF - m->m_len;
        !           174:        ea = mtod(m, struct ether_arp *);
        !           175:        eh = (struct ether_header *)sa.sa_data;
        !           176:        bzero((caddr_t)ea, sizeof (*ea));
        !           177:        bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
        !           178:           sizeof (etherbroadcastaddr));
        !           179:        eh->ether_type = ETHERPUP_ARPTYPE;      /* if_output will swap */
        !           180:        ea->arp_hrd = htons(ARPHRD_ETHER);
        !           181:        ea->arp_pro = htons(ETHERPUP_IPTYPE);
        !           182:        ea->arp_hln = sizeof ea->arp_sha;       /* hardware address length */
        !           183:        ea->arp_pln = sizeof ea->arp_spa;       /* protocol address length */
        !           184:        ea->arp_op = htons(ARPOP_REQUEST);
        !           185:        bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
        !           186:           sizeof (ea->arp_sha));
        !           187:        bcopy((caddr_t)&((struct sockaddr_in *)&ac->ac_if.if_addr)->sin_addr,
        !           188:           (caddr_t)ea->arp_spa, sizeof (ea->arp_spa));
        !           189:        bcopy((caddr_t)addr, (caddr_t)ea->arp_tpa, sizeof (ea->arp_tpa));
        !           190:        sa.sa_family = AF_UNSPEC;
        !           191:        ARPTRACE(printf("arpwhohas:broadcast through %s%d for addr %lx\n",
        !           192:                ac->ac_if.if_name, ac->ac_if.if_unit, addr->s_addr);)
        !           193:        (void) (*ac->ac_if.if_output)(&ac->ac_if, m, &sa);
        !           194: }
        !           195: 
        !           196: /*
        !           197:  *
        !           198:  * Resolve an IP address into an ethernet address.  If success, 
        !           199:  * desten is filled in and 1 is returned.  If there is no entry
        !           200:  * in arptab, set one up and broadcast a request 
        !           201:  * for the IP address;  return 0.  Hold onto this mbuf and 
        !           202:  * resend it once the address is finally resolved.
        !           203:  *
        !           204:  * We do some (conservative) locking here at splimp, since
        !           205:  * arptab is also altered from input interrupt service (ecintr/ilintr
        !           206:  * calls arpinput when ETHERPUP_ARPTYPE packets come in).
        !           207:  *
        !           208:  * Returns:
        !           209:  *
        !           210:  * ARPRESOLVE_WILLSEND
        !           211:  *             arpresolve() cannot resolve the address. It will send the
        !           212:  *             packet when it the address is resolved. However, if the 
        !           213:  *             destination is same as origination, arpresolve() does not
        !           214:  *             resolve address, it routes the packet to software loopback.
        !           215:  *
        !           216:  * ARPRESOLVE_OK
        !           217:  *             arpresolve() successfully resolves the address. The calling
        !           218:  *             routine is responsible for sending out the packet. Address
        !           219:  *             is not a wild-card (not broadcast).
        !           220:  *
        !           221:  * ARPRESOLVE_BROADCAST
        !           222:  *             arpresovle() successfully resolves the address which is
        !           223:  *             a wildcard. If the controller is NOT capable of listening to
        !           224:  *             its own broadcast, the device driver is responsible for
        !           225:  *             routing a copy of the packet to the software loopback.
        !           226:  *
        !           227:  */
        !           228: arpresolve(ac, m, destip, desten)
        !           229:        register struct arpcom *ac;
        !           230:        struct mbuf *m;
        !           231:        register struct in_addr *destip;
        !           232:        register u_char *desten;
        !           233: {
        !           234:        register struct arptab *at;
        !           235:        register struct ifnet *ifp;
        !           236:        struct sockaddr_in sin;
        !           237:        int s, lna;
        !           238: 
        !           239:        lna = in_lnaof(*destip);
        !           240:        if (lna == INADDR_ANY) {        /* broadcast address */
        !           241:                bcopy((caddr_t)etherbroadcastaddr, (caddr_t)desten,
        !           242:                   sizeof (etherbroadcastaddr));
        !           243:                return (ARPRESOLVE_BROADCAST);
        !           244:        }
        !           245:        ifp = &ac->ac_if;
        !           246:        /* if for us, then use software loopback driver */
        !           247:        if ((destip->s_addr ==
        !           248:            ((struct sockaddr_in *)&ifp->if_addr)-> sin_addr.s_addr) &&
        !           249:            (gotoether==0)) {
        !           250:                sin.sin_family = AF_INET;
        !           251:                sin.sin_addr = *destip;
        !           252:                looutput(&loif, m, (struct sockaddr *)&sin);
        !           253:                return(ARPRESOLVE_WILLSEND);
        !           254:        }
        !           255:        if ((ifp->if_flags & IFF_NOARP) || lna >= oldmap) {
        !           256:                bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten, 3);
        !           257:                desten[3] = (lna >> 16) & 0x7f;
        !           258:                desten[4] = (lna >> 8) & 0xff;
        !           259:                desten[5] = lna & 0xff;
        !           260:                return (ARPRESOLVE_OK);
        !           261:        }
        !           262:        s = splimp();
        !           263:        ARPTAB_LOOK(at, destip->s_addr);
        !           264:        if (at == 0) {                  /* not found */
        !           265:                at = arptnew(destip);
        !           266:                ARPTRACE(printf("arpresolve(%s%d) (m=%lx), arptab empty\n",
        !           267:                        ac->ac_if.if_name, ac->ac_if.if_unit, m);)
        !           268: 
        !           269:                ARPTRACE(if (at->at_hold)
        !           270:                                printf("arpresolve: LOOSE mbuf %lx\n",m);)
        !           271:                at->at_hold = m;
        !           272:                arpwhohas(ac, destip);
        !           273:                splx(s);
        !           274:                return (ARPRESOLVE_WILLSEND);
        !           275:        }
        !           276:        at->at_timer = 0;               /* restart the timer */
        !           277:        if (at->at_flags & ATF_COM) {   /* entry IS complete */
        !           278:                bcopy((caddr_t)at->at_enaddr, (caddr_t)desten, 6);
        !           279:                splx(s);
        !           280:                return (ARPRESOLVE_OK);
        !           281:        }
        !           282:        /*
        !           283:         * There is an arptab entry, but no ethernet address
        !           284:         * response yet.  Replace the held mbuf with this
        !           285:         * latest one.
        !           286:         */
        !           287:        ARPTRACE(printf("arpresolve(%s%d) (m=%lx), arptab not completed\n",
        !           288:                ac->ac_if.if_name, ac->ac_if.if_unit, m);)
        !           289:        if (at->at_hold)
        !           290:                m_freem(at->at_hold);
        !           291:        at->at_hold = m;
        !           292:        arpwhohas(ac, destip);          /* ask again */
        !           293:        splx(s);
        !           294:        return (ARPRESOLVE_WILLSEND);
        !           295: }
        !           296: 
        !           297: /*
        !           298:  * Find my own IP address.  It will either be waiting for us in
        !           299:  * monitor RAM, or can be obtained via broadcast to the file/boot
        !           300:  * server (not necessarily using the ARP packet format).
        !           301:  *
        !           302:  * Unimplemented at present, return 0 and assume that the host
        !           303:  * will set his own IP address via the SIOCSIFADDR ioctl.
        !           304:  */
        !           305: /*ARGSUSED*/
        !           306: struct in_addr
        !           307: arpmyaddr(ac)
        !           308:        register struct arpcom *ac;
        !           309: {
        !           310:        static struct in_addr addr;
        !           311: 
        !           312: #ifdef lint
        !           313:        ac = ac;
        !           314: #endif
        !           315:        addr.s_addr = 0;
        !           316:        return (addr);
        !           317: }
        !           318: 
        !           319: /*
        !           320:  * Called from ecintr/ilintr when ether packet type ETHERPUP_ARP
        !           321:  * is received.  Algorithm is exactly that given in RFC 826.
        !           322:  * In addition, a sanity check is performed on the sender
        !           323:  * protocol address, to catch impersonators.
        !           324:  */
        !           325: arpinput(ac, m)
        !           326:        register struct arpcom *ac;
        !           327:        struct mbuf *m;
        !           328: {
        !           329:        register struct ether_arp *ea;
        !           330:        struct ether_header *eh;
        !           331:        register struct arptab *at = 0;  /* same as "merge" flag */
        !           332:        struct sockaddr_in sin;
        !           333:        struct sockaddr sa;
        !           334:        struct mbuf *mhold;
        !           335:        struct in_addr isaddr,itaddr,myaddr;
        !           336: 
        !           337:        ARPTRACE(printf("arpinput through %s%d (m=%lx)\n",
        !           338:                ac->ac_if.if_name, ac->ac_if.if_unit, m);)
        !           339: 
        !           340:        if (m->m_len < sizeof *ea)
        !           341:                goto out;
        !           342: 
        !           343:        myaddr = ((struct sockaddr_in *)&ac->ac_if.if_addr)->sin_addr;
        !           344:        ea = mtod(m, struct ether_arp *);
        !           345:        if (ntohs(ea->arp_pro) != ETHERPUP_IPTYPE)
        !           346:                goto out;
        !           347:        bcopy((caddr_t)ea->arp_spa, (caddr_t)&isaddr.s_addr,
        !           348:                sizeof (ea->arp_spa));
        !           349: /*     isaddr.s_addr = ((struct in_addr *)ea->arp_spa)->s_addr;*/
        !           350:        bcopy((caddr_t)ea->arp_tpa, (caddr_t)&itaddr.s_addr,
        !           351:                sizeof (ea->arp_spa));
        !           352: /*     itaddr.s_addr = ((struct in_addr *)ea->arp_tpa)->s_addr;*/
        !           353:        if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr,
        !           354:          sizeof (ac->ac_enaddr)))
        !           355:                goto out;       /* it's from me, ignore it. */
        !           356: 
        !           357:        ARPTRACE(printf("\tarpinput (%s%d) sender: %lx, %x.%x.%x.%x.%x.%x, target: %lx, %x.%x.%x.%x.%x.%x\n",
        !           358:                ac->ac_if.if_name, ac->ac_if.if_unit,
        !           359:                isaddr.s_addr, 
        !           360:                ea->arp_sha[0] & 0xff, ea->arp_sha[1] & 0xff,
        !           361:                ea->arp_sha[2] & 0xff, ea->arp_sha[3] & 0xff,
        !           362:                ea->arp_sha[4] & 0xff, ea->arp_sha[5] & 0xff,
        !           363:                itaddr.s_addr, 
        !           364:                ea->arp_tha[0] & 0xff, ea->arp_tha[1] & 0xff,
        !           365:                ea->arp_tha[2] & 0xff, ea->arp_tha[3] & 0xff,
        !           366:                ea->arp_tha[4] & 0xff, ea->arp_tha[5] & 0xff);)
        !           367:                
        !           368:        if (isaddr.s_addr == myaddr.s_addr) {
        !           369:                printf("duplicate IP address!! sent from ethernet address: ");
        !           370:                printf("%x %x %x %x %x %x\n", ea->arp_sha[0], ea->arp_sha[1],
        !           371:                    ea->arp_sha[2], ea->arp_sha[3],
        !           372:                    ea->arp_sha[4], ea->arp_sha[5]);
        !           373:                if (ntohs(ea->arp_op) == ARPOP_REQUEST)
        !           374:                        goto reply;
        !           375:                goto out;
        !           376:        }
        !           377:        ARPTAB_LOOK(at, isaddr.s_addr);
        !           378:        if (at) {
        !           379:                bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
        !           380:                   sizeof (ea->arp_sha));
        !           381:                ARPTRACE(printf("\tarpinput(%s%d). Update sender addr\n",
        !           382:                        ac->ac_if.if_name, ac->ac_if.if_unit);)
        !           383:        
        !           384:                at->at_flags |= ATF_COM;
        !           385:                if (at->at_hold) {
        !           386:                        mhold = at->at_hold;
        !           387:                        at->at_hold = 0;
        !           388:                        sin.sin_family = AF_INET;
        !           389:                        sin.sin_addr = isaddr;
        !           390:                        (*ac->ac_if.if_output)(&ac->ac_if, 
        !           391:                            mhold, (struct sockaddr *)&sin);
        !           392:                }
        !           393:        }
        !           394:        if (itaddr.s_addr != myaddr.s_addr) {
        !           395:                ARPTRACE(printf("\tarpinput(%s%d) Iam not the target\n",
        !           396:                        ac->ac_if.if_name, ac->ac_if.if_unit);)
        !           397:                goto out;       /* if I am not the target */
        !           398:        }
        !           399:        if (at == 0) {          /* ensure we have a table entry */
        !           400:                ARPTRACE(printf("\tarpinput(%s%d). New entry for sender addr\n",
        !           401:                        ac->ac_if.if_name, ac->ac_if.if_unit);)
        !           402:                at = arptnew(&isaddr);
        !           403:                bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
        !           404:                   sizeof (ea->arp_sha));
        !           405:                at->at_flags |= ATF_COM;
        !           406:        }
        !           407:        if (ntohs(ea->arp_op) != ARPOP_REQUEST)
        !           408:                goto out;
        !           409: reply:
        !           410:        bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
        !           411:           sizeof (ea->arp_sha));
        !           412:        bcopy((caddr_t)ea->arp_spa, (caddr_t)ea->arp_tpa,
        !           413:           sizeof (ea->arp_spa));
        !           414:        bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
        !           415:           sizeof (ea->arp_sha));
        !           416:        bcopy((caddr_t)&myaddr, (caddr_t)ea->arp_spa,
        !           417:           sizeof (ea->arp_spa));
        !           418:        ea->arp_op = htons(ARPOP_REPLY);
        !           419:        eh = (struct ether_header *)sa.sa_data;
        !           420:        bcopy((caddr_t)ea->arp_tha, (caddr_t)eh->ether_dhost,
        !           421:           sizeof (eh->ether_dhost));
        !           422:        eh->ether_type = ETHERPUP_ARPTYPE;
        !           423:        sa.sa_family = AF_UNSPEC;
        !           424: 
        !           425:        ARPTRACE(bcopy((caddr_t)ea->arp_tpa, (caddr_t)&itaddr.s_addr,
        !           426:                sizeof (ea->arp_tpa));)
        !           427:        ARPTRACE(printf("\tarpinput(%s%d). Send reply to %lx\n",
        !           428:                ac->ac_if.if_name, ac->ac_if.if_unit,itaddr.s_addr);)
        !           429: 
        !           430:        (*ac->ac_if.if_output)(&ac->ac_if, m, &sa);
        !           431:        return;
        !           432: out:
        !           433:        m_freem(m);
        !           434:        return;
        !           435: }
        !           436: 
        !           437: /*
        !           438:  * Free an arptab entry.
        !           439:  */
        !           440: arptfree(at)
        !           441:        register struct arptab *at;
        !           442: {
        !           443:        int s = splimp();
        !           444: 
        !           445:        if (at->at_hold)
        !           446:                m_freem(at->at_hold);
        !           447:        at->at_hold = 0;
        !           448:        at->at_timer = at->at_flags = 0;
        !           449:        at->at_iaddr.s_addr = 0;
        !           450:        splx(s);
        !           451: }
        !           452: 
        !           453: /*
        !           454:  * Enter a new address in arptab, pushing out the oldest entry 
        !           455:  * from the bucket if there is no room.
        !           456:  */
        !           457: struct arptab *
        !           458: arptnew(addr)
        !           459:        struct in_addr *addr;
        !           460: {
        !           461:        register n;
        !           462:        int oldest = 0;
        !           463:        register struct arptab *at, *ato;
        !           464: 
        !           465:        ato = at = &arptab[ARPTAB_HASH(addr->s_addr) * ARPTAB_BSIZ];
        !           466:        for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) {
        !           467:                if (at->at_flags == 0)
        !           468:                        goto out;        /* found an empty entry */
        !           469:                if (at->at_timer > oldest) {
        !           470:                        oldest = at->at_timer;
        !           471:                        ato = at;
        !           472:                }
        !           473:        }
        !           474:        at = ato;
        !           475:        arptfree(at);
        !           476: out:
        !           477:        at->at_iaddr = *addr;
        !           478:        at->at_flags = ATF_INUSE;
        !           479:        return (at);
        !           480: }
        !           481: 
        !           482: arpremove(addr)
        !           483: struct sockaddr *addr;
        !           484: {
        !           485:        register struct arptab *at;
        !           486:        struct in_addr *idst;
        !           487:        register long x;
        !           488: 
        !           489:        idst = &((struct sockaddr_in *)addr)->sin_addr;
        !           490:        x = splimp();
        !           491:        ARPTAB_LOOK(at, idst->s_addr);
        !           492:        if (at) arptfree(at);
        !           493:        splx(x);
        !           494: }
        !           495: 

unix.superglobalmegacorp.com

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