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

Defined functions

arpioctl defined in line 447; used 1 times
arptfree defined in line 393; used 5 times
arptimer defined in line 65; used 2 times
arptnew defined in line 413; used 5 times
in_arpinput defined in line 260; used 1 times

Defined variables

arptab defined in line 32; used 3 times
arptab_size defined in line 33; never used
etherbroadcastaddr defined in line 59; used 4 times

Defined macros

ARPTAB_BSIZ defined in line 29; used 6 times
ARPTAB_HASH defined in line 41; used 2 times
ARPTAB_LOOK defined in line 44; used 4 times
ARPTAB_NB defined in line 30; used 2 times
ARPTAB_SIZE defined in line 31; used 3 times
ARPT_AGE defined in line 55; used 1 times
  • in line 70
ARPT_KILLC defined in line 56; used 1 times
  • in line 76
ARPT_KILLI defined in line 57; used 1 times
  • in line 76
ETHERTYPE_IPTRAILERS defined in line 39; used 2 times
Last modified: 1986-06-05
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2293
Valid CSS Valid XHTML 1.0 Strict