|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.