# 2.11BSD#431 - /usr/src/sys/netinet/if_ether.c

##### Functions

    arpinput          X
    arpioctl          X
    arpresolve        X
    arptfree          X
    arptimer          X
    arptnew           X
    arpwhohas         X
    ether_sprintf     X
    in_arpinput       X

##### Variables

    arptab            X
    arptab_size       X
    etherbroadcastaddrX
    useloopback       X

##### Macros

    ARPTAB_BSIZ       X
    ARPTAB_HASH       X
    ARPTAB_LOOK       X
    ARPTAB_NB         X
    ARPTAB_SIZE       X
    ARPT_AGE          X
    ARPT_KILLC        X
    ARPT_KILLI        X
    ETHERTYPE_IPTRAILERSX

       1: /*
       2:  * Copyright (c) 1982, 1986 Regents of the University of California.
       3:  * All rights reserved.
       4:  *
       5:  * Redistribution and use in source and binary forms are permitted
       6:  * provided that this notice is preserved and that due credit is given
       7:  * to the University of California at Berkeley. The name of the University
       8:  * may not be used to endorse or promote products derived from this
       9:  * software without specific prior written permission. This software
      10:  * is provided ``as is'' without express or implied warranty.
      11:  *
      12:  *	@(#)if_ether.c	7.6 (Berkeley) 12/7/87
      13:  */
      14:
      15: /*
      16:  * Ethernet address resolution protocol.
      17:  * TODO:
      18:  *	run at splnet (add ARP protocol intr.)
      19:  *	link entries onto hash chains, keep free list
      20:  *	add "inuse/lock" bit (or ref. count) along with valid bit
      21:  */
      22:
      23: #include "ether.h"
      24: #if NETHER > 0
      25:
      26: #include "param.h"
      27: #include "systm.h"
      28: #include "mbuf.h"
      29: #include "socket.h"
      30: #include "time.h"
      31: #include "kernel.h"
      32: #include "errno.h"
      33: #include "ioctl.h"
      34: #include "syslog.h"
      35:
      36: #include "domain.h"
      37: #include "protosw.h"
      38: #include "../net/if.h"
      39: #include "in.h"
      40: #include "in_systm.h"
      41: #include "ip.h"
      42: #include "if_ether.h"
      43:
      44: #define ARPTAB_BSIZ 5       /* bucket size */
      45: #define ARPTAB_NB   13      /* number of buckets */
      46: #define ARPTAB_SIZE (ARPTAB_BSIZ * ARPTAB_NB)
      47: struct  arptab arptab[ARPTAB_SIZE];
      48: int arptab_size = ARPTAB_SIZE;  /* for arp command */
      49:
      50: /*
      51:  * ARP trailer negotiation.  Trailer protocol is not IP specific,
      52:  * but ARP request/response use IP addresses.
      53:  */
      54: #define ETHERTYPE_IPTRAILERS ETHERTYPE_TRAIL
      55:
      56: #define ARPTAB_HASH(a) \
      57:     ((short)((((a) >> 16) ^ (a)) & 0x7fff) % ARPTAB_NB)
      58:
      59: #define ARPTAB_LOOK(at,addr) { \
      60:     register n; \
      61:     at = &arptab[ARPTAB_HASH(addr) * ARPTAB_BSIZ]; \
      62:     for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) \
      63:         if (at->at_iaddr.s_addr == addr) \
      64:             break; \
      65:     if (n >= ARPTAB_BSIZ) \
      66:         at = 0; \
      67: }
      68:
      69: /* timer values */
      70: #define ARPT_AGE    (60*1)  /* aging timer, 1 min. */
      71: #define ARPT_KILLC  20  /* kill completed entry in 20 mins. */
      72: #define ARPT_KILLI  3   /* kill incomplete entry in 3 minutes */
      73:
      74: u_char  etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
      75: extern struct ifnet loif;
      76: extern int hz;
      77:
      78: /*
      79:  * Timeout routine.  Age arp_tab entries once a minute.
      80:  */
      81: arptimer()
      82: {
      83:     register struct arptab *at;
      84:     register i;
      85:
      86:     TIMEOUT(arptimer, (caddr_t)0, ARPT_AGE * hz);
      87:     at = &arptab[0];
      88:     for (i = 0; i < ARPTAB_SIZE; i++, at++) {
      89:         if (at->at_flags == 0 || (at->at_flags & ATF_PERM))
      90:             continue;
      91:         if (++at->at_timer < ((at->at_flags&ATF_COM) ?
      92:             ARPT_KILLC : ARPT_KILLI))
      93:             continue;
      94:         /* timer has expired, clear entry */
      95:         arptfree(at);
      96:     }
      97: }
      98:
      99: /*
     100:  * Broadcast an ARP packet, asking who has addr on interface ac.
     101:  */
     102: arpwhohas(ac, addr)
     103:     register struct arpcom *ac;
     104:     struct in_addr *addr;
     105: {
     106:     register struct mbuf *m;
     107:     register struct ether_header *eh;
     108:     register struct ether_arp *ea;
     109:     struct sockaddr sa;
     110:
     111:     if ((m = m_get(M_DONTWAIT, MT_DATA)) == NULL)
     112:         return;
     113:     m->m_len = sizeof *ea;
     114:     m->m_off = MMAXOFF - m->m_len;
     115:     ea = mtod(m, struct ether_arp *);
     116:     eh = (struct ether_header *)sa.sa_data;
     117:     bzero((caddr_t)ea, sizeof (*ea));
     118:     bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
     119:         sizeof(eh->ether_dhost));
     120:     eh->ether_type = ETHERTYPE_ARP;     /* if_output will swap */
     121:     ea->arp_hrd = htons(ARPHRD_ETHER);
     122:     ea->arp_pro = htons(ETHERTYPE_IP);
     123:     ea->arp_hln = sizeof(ea->arp_sha);  /* hardware address length */
     124:     ea->arp_pln = sizeof(ea->arp_spa);  /* protocol address length */
     125:     ea->arp_op = htons(ARPOP_REQUEST);
     126:     bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
     127:        sizeof(ea->arp_sha));
     128:     bcopy((caddr_t)&ac->ac_ipaddr, (caddr_t)ea->arp_spa,
     129:        sizeof(ea->arp_spa));
     130:     bcopy((caddr_t)addr, (caddr_t)ea->arp_tpa, sizeof(ea->arp_tpa));
     131:     sa.sa_family = AF_UNSPEC;
     132:     (*ac->ac_if.if_output)(&ac->ac_if, m, &sa);
     133: }
     134:
     135: int useloopback = 1;    /* use loopback interface for local traffic */
     136:
     137: /*
     138:  * Resolve an IP address into an ethernet address.  If success,
     139:  * desten is filled in.  If there is no entry in arptab,
     140:  * set one up and broadcast a request for the IP address.
     141:  * Hold onto this mbuf and resend it once the address
     142:  * is finally resolved.  A return value of 1 indicates
     143:  * that desten has been filled in and the packet should be sent
     144:  * normally; a 0 return indicates that the packet has been
     145:  * taken over here, either now or for later transmission.
     146:  *
     147:  * We do some (conservative) locking here at splimp, since
     148:  * arptab is also altered from input interrupt service (ecintr/ilintr
     149:  * calls arpinput when ETHERTYPE_ARP packets come in).
     150:  */
     151: arpresolve(ac, m, destip, desten, usetrailers)
     152:     register struct arpcom *ac;
     153:     struct mbuf *m;
     154:     register struct in_addr *destip;
     155:     register u_char *desten;
     156:     int *usetrailers;
     157: {
     158:     register struct arptab *at;
     159:     struct sockaddr_in sin;
     160:     u_long lna;
     161:     int s;
     162:
     163:     *usetrailers = 0;
     164:     if (in_broadcast(*destip)) {    /* broadcast address */
     165:         bcopy((caddr_t)etherbroadcastaddr, (caddr_t)desten,
     166:             sizeof(etherbroadcastaddr));
     167:         return (1);
     168:     }
     169:     lna = in_lnaof(*destip);
     170:     /* if for us, use software loopback driver if up */
     171:     if (destip->s_addr == ac->ac_ipaddr.s_addr) {
     172:         /*
     173: 		 * This test used to be
     174: 		 *	if (loif.if_flags & IFF_UP)
     175: 		 * It allowed local traffic to be forced
     176: 		 * through the hardware by configuring the loopback down.
     177: 		 * However, it causes problems during network configuration
     178: 		 * for boards that can't receive packets they send.
     179: 		 * It is now necessary to clear "useloopback"
     180: 		 * to force traffic out to the hardware.
     181: 		 */
     182:         if (useloopback) {
     183:             sin.sin_family = AF_INET;
     184:             sin.sin_addr = *destip;
     185:             (void) looutput(&loif, m, (struct sockaddr *)&sin);
     186:             /*
     187: 			 * The packet has already been sent and freed.
     188: 			 */
     189:             return (0);
     190:         } else {
     191:             bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten,
     192:                 sizeof(ac->ac_enaddr));
     193:             return (1);
     194:         }
     195:     }
     196:     s = splimp();
     197:     ARPTAB_LOOK(at, destip->s_addr);
     198:     if (at == 0) {          /* not found */
     199:         if (ac->ac_if.if_flags & IFF_NOARP) {
     200:             bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten, 3);
     201:             desten[3] = (lna >> 16) & 0x7f;
     202:             desten[4] = (lna >> 8) & 0xff;
     203:             desten[5] = lna & 0xff;
     204:             splx(s);
     205:             return (1);
     206:         } else {
     207:             at = arptnew(destip);
     208:             if (at == 0)
     209:                 panic("arpresolve: no free entry");
     210:             at->at_hold = m;
     211:             arpwhohas(ac, destip);
     212:             splx(s);
     213:             return (0);
     214:         }
     215:     }
     216:     at->at_timer = 0;       /* restart the timer */
     217:     if (at->at_flags & ATF_COM) {   /* entry IS complete */
     218:         bcopy((caddr_t)at->at_enaddr, (caddr_t)desten,
     219:             sizeof(at->at_enaddr));
     220: #ifdef I_WANT_MY_MACHINE_TO_CRASH
     221:         if (at->at_flags & ATF_USETRAILERS)
     222:             *usetrailers = 1;
     223: #endif
     224:         splx(s);
     225:         return (1);
     226:     }
     227:     /*
     228: 	 * There is an arptab entry, but no ethernet address
     229: 	 * response yet.  Replace the held mbuf with this
     230: 	 * latest one.
     231: 	 */
     232:     if (at->at_hold)
     233:         m_freem(at->at_hold);
     234:     at->at_hold = m;
     235:     arpwhohas(ac, destip);      /* ask again */
     236:     splx(s);
     237:     return (0);
     238: }
     239:
     240: /*
     241:  * Called from 10 Mb/s Ethernet interrupt handlers
     242:  * when ether packet type ETHERTYPE_ARP
     243:  * is received.  Common length and type checks are done here,
     244:  * then the protocol-specific routine is called.
     245:  */
     246: arpinput(ac, m)
     247:     struct arpcom *ac;
     248:     struct mbuf *m;
     249: {
     250:     register struct arphdr *ar;
     251:
     252:     if (ac->ac_if.if_flags & IFF_NOARP)
     253:         goto out;
     254:     IF_ADJ(m);
     255:     if (m->m_len < sizeof(struct arphdr))
     256:         goto out;
     257:     ar = mtod(m, struct arphdr *);
     258:     if (ntohs(ar->ar_hrd) != ARPHRD_ETHER)
     259:         goto out;
     260:     if (m->m_len < sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln)
     261:         goto out;
     262:
     263:     switch (ntohs(ar->ar_pro)) {
     264:
     265:     case ETHERTYPE_IP:
     266:     case ETHERTYPE_IPTRAILERS:
     267:         in_arpinput(ac, m);
     268:         return;
     269:
     270:     default:
     271:         break;
     272:     }
     273: out:
     274:     m_freem(m);
     275: }
     276:
     277: /*
     278:  * ARP for Internet protocols on 10 Mb/s Ethernet.
     279:  * Algorithm is that given in RFC 826.
     280:  * In addition, a sanity check is performed on the sender
     281:  * protocol address, to catch impersonators.
     282:  * We also handle negotiations for use of trailer protocol:
     283:  * ARP replies for protocol type ETHERTYPE_TRAIL are sent
     284:  * along with IP replies if we want trailers sent to us,
     285:  * and also send them in response to IP replies.
     286:  * This allows either end to announce the desire to receive
     287:  * trailer packets.
     288:  * We reply to requests for ETHERTYPE_TRAIL protocol as well,
     289:  * but don't normally send requests.
     290:  */
     291: in_arpinput(ac, m)
     292:     register struct arpcom *ac;
     293:     struct mbuf *m;
     294: {
     295:     register struct ether_arp *ea;
     296:     struct ether_header *eh;
     297:     register struct arptab *at;  /* same as "merge" flag */
     298:     struct mbuf *mcopy = 0;
     299:     struct sockaddr_in sin;
     300:     struct sockaddr sa;
     301:     struct in_addr isaddr, itaddr, myaddr;
     302:     int proto, op, s, completed = 0;
     303:
     304:     myaddr = ac->ac_ipaddr;
     305:     ea = mtod(m, struct ether_arp *);
     306:     proto = ntohs(ea->arp_pro);
     307:     op = ntohs(ea->arp_op);
     308:     bcopy((caddr_t)ea->arp_spa, (caddr_t)&isaddr, sizeof (isaddr));
     309:     bcopy((caddr_t)ea->arp_tpa, (caddr_t)&itaddr, sizeof (itaddr));
     310:     if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr,
     311:       sizeof (ea->arp_sha)))
     312:         goto out;   /* it's from me, ignore it. */
     313:     if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)etherbroadcastaddr,
     314:         sizeof (ea->arp_sha))) {
     315:         printf("arp: ether address is broadcast for IP address %x!\n",
     316:             ntohl(isaddr.s_addr));
     317:         goto out;
     318:     }
     319:     if (isaddr.s_addr == myaddr.s_addr) {
     320:         printf("%s: %s\n",
     321:             "duplicate IP address!! sent from ethernet address",
     322:             ether_sprintf(ea->arp_sha));
     323:         itaddr = myaddr;
     324:         if (op == ARPOP_REQUEST)
     325:             goto reply;
     326:         goto out;
     327:     }
     328:     s = splimp();
     329:     ARPTAB_LOOK(at, isaddr.s_addr);
     330:     if (at) {
     331:         bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
     332:             sizeof(ea->arp_sha));
     333:         if ((at->at_flags & ATF_COM) == 0)
     334:             completed = 1;
     335:         at->at_flags |= ATF_COM;
     336:         if (at->at_hold) {
     337:             sin.sin_family = AF_INET;
     338:             sin.sin_addr = isaddr;
     339:             (*ac->ac_if.if_output)(&ac->ac_if,
     340:                 at->at_hold, (struct sockaddr *)&sin);
     341:             at->at_hold = 0;
     342:         }
     343:     }
     344:     if (at == 0 && itaddr.s_addr == myaddr.s_addr) {
     345:         /* ensure we have a table entry */
     346:         if (at = arptnew(&isaddr)) {
     347:             bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
     348:                 sizeof(ea->arp_sha));
     349:             completed = 1;
     350:             at->at_flags |= ATF_COM;
     351:         }
     352:     }
     353:     splx(s);
     354: reply:
     355:     switch (proto) {
     356:
     357:     case ETHERTYPE_IPTRAILERS:
     358:         /* partner says trailers are OK */
     359:         if (at)
     360:             at->at_flags |= ATF_USETRAILERS;
     361:         /*
     362: 		 * Reply to request iff we want trailers.
     363: 		 */
     364:         if (op != ARPOP_REQUEST || ac->ac_if.if_flags & IFF_NOTRAILERS)
     365:             goto out;
     366:         break;
     367:
     368:     case ETHERTYPE_IP:
     369:         /*
     370: 		 * Reply if this is an IP request,
     371: 		 * or if we want to send a trailer response.
     372: 		 * Send the latter only to the IP response
     373: 		 * that completes the current ARP entry.
     374: 		 */
     375:         if (op != ARPOP_REQUEST &&
     376:             (completed == 0 || ac->ac_if.if_flags & IFF_NOTRAILERS))
     377:             goto out;
     378:     }
     379:     if (itaddr.s_addr == myaddr.s_addr) {
     380:         /* I am the target */
     381:         bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
     382:             sizeof(ea->arp_sha));
     383:         bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
     384:             sizeof(ea->arp_sha));
     385:     } else {
     386:         ARPTAB_LOOK(at, itaddr.s_addr);
     387:         if (at == NULL || (at->at_flags & ATF_PUBL) == 0)
     388:             goto out;
     389:         bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
     390:             sizeof(ea->arp_sha));
     391:         bcopy((caddr_t)at->at_enaddr, (caddr_t)ea->arp_sha,
     392:             sizeof(ea->arp_sha));
     393:     }
     394:
     395:     bcopy((caddr_t)ea->arp_spa, (caddr_t)ea->arp_tpa,
     396:         sizeof(ea->arp_spa));
     397:     bcopy((caddr_t)&itaddr, (caddr_t)ea->arp_spa,
     398:         sizeof(ea->arp_spa));
     399:     ea->arp_op = htons(ARPOP_REPLY);
     400:     /*
     401: 	 * If incoming packet was an IP reply,
     402: 	 * we are sending a reply for type IPTRAILERS.
     403: 	 * If we are sending a reply for type IP
     404: 	 * and we want to receive trailers,
     405: 	 * send a trailer reply as well.
     406: 	 */
     407:     if (op == ARPOP_REPLY)
     408:         ea->arp_pro = htons(ETHERTYPE_IPTRAILERS);
     409:     else if (proto == ETHERTYPE_IP &&
     410:         (ac->ac_if.if_flags & IFF_NOTRAILERS) == 0)
     411:         mcopy = m_copy(m, 0, (int)M_COPYALL);
     412:     eh = (struct ether_header *)sa.sa_data;
     413:     bcopy((caddr_t)ea->arp_tha, (caddr_t)eh->ether_dhost,
     414:         sizeof(eh->ether_dhost));
     415:     eh->ether_type = ETHERTYPE_ARP;
     416:     sa.sa_family = AF_UNSPEC;
     417:     (*ac->ac_if.if_output)(&ac->ac_if, m, &sa);
     418:     if (mcopy) {
     419:         ea = mtod(mcopy, struct ether_arp *);
     420:         ea->arp_pro = htons(ETHERTYPE_IPTRAILERS);
     421:         (*ac->ac_if.if_output)(&ac->ac_if, mcopy, &sa);
     422:     }
     423:     return;
     424: out:
     425:     m_freem(m);
     426:     return;
     427: }
     428:
     429: /*
     430:  * Free an arptab entry.
     431:  */
     432: arptfree(at)
     433:     register struct arptab *at;
     434: {
     435:     int s = splimp();
     436:
     437:     if (at->at_hold)
     438:         m_freem(at->at_hold);
     439:     at->at_hold = 0;
     440:     at->at_timer = at->at_flags = 0;
     441:     at->at_iaddr.s_addr = 0;
     442:     splx(s);
     443: }
     444:
     445: /*
     446:  * Enter a new address in arptab, pushing out the oldest entry
     447:  * from the bucket if there is no room.
     448:  * This always succeeds since no bucket can be completely filled
     449:  * with permanent entries (except from arpioctl when testing whether
     450:  * another permanent entry will fit).
     451:  * MUST BE CALLED AT SPLIMP.
     452:  */
     453: struct arptab *
     454: arptnew(addr)
     455:     struct in_addr *addr;
     456: {
     457:     register n;
     458:     int oldest = -1;
     459:     register struct arptab *at, *ato = NULL;
     460:     static int first = 1;
     461:
     462:     if (first) {
     463:         first = 0;
     464:         TIMEOUT(arptimer, (caddr_t)0, hz);
     465:     }
     466:     at = &arptab[ARPTAB_HASH(addr->s_addr) * ARPTAB_BSIZ];
     467:     for (n = 0; n < ARPTAB_BSIZ; n++,at++) {
     468:         if (at->at_flags == 0)
     469:             goto out;    /* found an empty entry */
     470:         if (at->at_flags & ATF_PERM)
     471:             continue;
     472:         if ((int) at->at_timer > oldest) {
     473:             oldest = at->at_timer;
     474:             ato = at;
     475:         }
     476:     }
     477:     if (ato == NULL)
     478:         return (NULL);
     479:     at = ato;
     480:     arptfree(at);
     481: out:
     482:     at->at_iaddr = *addr;
     483:     at->at_flags = ATF_INUSE;
     484:     return (at);
     485: }
     486:
     487: arpioctl(cmd, data)
     488:     int cmd;
     489:     caddr_t data;
     490: {
     491:     register struct arpreq *ar = (struct arpreq *)data;
     492:     register struct arptab *at;
     493:     register struct sockaddr_in *sin;
     494:     int s;
     495:
     496:     if (ar->arp_pa.sa_family != AF_INET ||
     497:         ar->arp_ha.sa_family != AF_UNSPEC)
     498:         return (EAFNOSUPPORT);
     499:     sin = (struct sockaddr_in *)&ar->arp_pa;
     500:     s = splimp();
     501:     ARPTAB_LOOK(at, sin->sin_addr.s_addr);
     502:     if (at == NULL) {       /* not found */
     503:         if (cmd != SIOCSARP) {
     504:             splx(s);
     505:             return (ENXIO);
     506:         }
     507:         if (ifa_ifwithnet(&ar->arp_pa) == NULL) {
     508:             splx(s);
     509:             return (ENETUNREACH);
     510:         }
     511:     }
     512:     switch (cmd) {
     513:
     514:     case SIOCSARP:      /* set entry */
     515:         if (at == NULL) {
     516:             at = arptnew(&sin->sin_addr);
     517:             if (at == NULL) {
     518:                 splx(s);
     519:                 return (EADDRNOTAVAIL);
     520:             }
     521:             if (ar->arp_flags & ATF_PERM) {
     522:             /* never make all entries in a bucket permanent */
     523:                 register struct arptab *tat;
     524:
     525:                 /* try to re-allocate */
     526:                 tat = arptnew(&sin->sin_addr);
     527:                 if (tat == NULL) {
     528:                     arptfree(at);
     529:                     splx(s);
     530:                     return (EADDRNOTAVAIL);
     531:                 }
     532:                 arptfree(tat);
     533:             }
     534:         }
     535:         bcopy((caddr_t)ar->arp_ha.sa_data, (caddr_t)at->at_enaddr,
     536:             sizeof(at->at_enaddr));
     537:         at->at_flags = ATF_COM | ATF_INUSE |
     538:             (ar->arp_flags & (ATF_PERM|ATF_PUBL|ATF_USETRAILERS));
     539:         at->at_timer = 0;
     540:         break;
     541:
     542:     case SIOCDARP:      /* delete entry */
     543:         arptfree(at);
     544:         break;
     545:
     546:     case SIOCGARP:      /* get entry */
     547:         bcopy((caddr_t)at->at_enaddr, (caddr_t)ar->arp_ha.sa_data,
     548:             sizeof(at->at_enaddr));
     549:         ar->arp_flags = at->at_flags;
     550:         break;
     551:     }
     552:     splx(s);
     553:     return (0);
     554: }
     555:
     556: /*
     557:  * Convert Ethernet address to printable (loggable) representation.
     558:  */
     559: char *
     560: ether_sprintf(ap)
     561:     register u_char *ap;
     562: {
     563:     register i;
     564:     static char etherbuf[18];
     565:     register char *cp = etherbuf;
     566:     static char digits[] = "0123456789abcdef";
     567:
     568:     for (i = 0; i < 6; i++) {
     569:         *cp++ = digits[*ap >> 4];
     570:         *cp++ = digits[*ap++ & 0xf];
     571:         *cp++ = ':';
     572:     }
     573:     *--cp = 0;
     574:     return (etherbuf);
     575: }
     576: #endif

#### Defined functions

arpinput defined in line 246; never used
arpioctl defined in line 487; never used
arpresolve defined in line 151; never used
arptfree defined in line 432; used 5 times

- in line 95, 480, 528-532(2), 543

arptimer defined in line 81; used 2 times

- in line 86, 464

arptnew defined in line 453; used 4 times

- in line 207, 346, 516, 526

arpwhohas defined in line 102; used 2 times

- in line 211, 235

ether_sprintf defined in line 559; used 1 times

- in line 322

in_arpinput defined in line 291; used 1 times

- in line 267

#### Defined variables

arptab defined in line 47; used 3 times

- in line 61, 87, 466

arptab_size defined in line 48; never used
etherbroadcastaddr defined in line 74; used 4 times

- in line 118, 165-166(2), 313

useloopback defined in line 135; used 1 times

- in line 182

#### Defined macros

ARPTAB_BSIZ defined in line 44; used 6 times

- in line 46, 61-65(3), 466-467(2)

ARPTAB_HASH defined in line 56; used 2 times

- in line 61, 466

ARPTAB_LOOK defined in line 59; used 4 times

- in line 197, 329, 386, 501

ARPTAB_NB defined in line 45; used 2 times

- in line 46, 57

ARPTAB_SIZE defined in line 46; used 3 times

- in line 47-48(2), 88

ARPT_AGE defined in line 70; used 1 times

- in line 86

ARPT_KILLC defined in line 71; used 1 times

- in line 92

ARPT_KILLI defined in line 72; used 1 times

- in line 92

ETHERTYPE_IPTRAILERS defined in line 54; used 2 times

- in line 408, 420

Last modified: 1989-01-06 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 2066 |