|
|
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: /* ! 21: * Internet to ethernet address resolution table. ! 22: */ ! 23: struct arptab { ! 24: struct in_addr at_iaddr; /* internet address */ ! 25: u_char at_enaddr[6]; /* ethernet address */ ! 26: struct mbuf *at_hold; /* last packet until resolved/timeout */ ! 27: u_char at_timer; /* minutes since last reference */ ! 28: u_char at_flags; /* flags */ ! 29: }; ! 30: /* at_flags field values */ ! 31: #define ATF_INUSE 1 /* entry in use */ ! 32: #define ATF_COM 2 /* completed entry (enaddr valid) */ ! 33: ! 34: #define ARPTAB_BSIZ 5 /* bucket size */ ! 35: #define ARPTAB_NB 19 /* number of buckets */ ! 36: #define ARPTAB_SIZE (ARPTAB_BSIZ * ARPTAB_NB) ! 37: struct arptab arptab[ARPTAB_SIZE]; ! 38: ! 39: #define ARPTAB_HASH(a) \ ! 40: ((short)((((a) >> 16) ^ (a)) & 0x7fff) % ARPTAB_NB) ! 41: ! 42: #define ARPTAB_LOOK(at,addr) { \ ! 43: register n; \ ! 44: at = &arptab[ARPTAB_HASH(addr) * ARPTAB_BSIZ]; \ ! 45: for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) \ ! 46: if (at->at_iaddr.s_addr == addr) \ ! 47: break; \ ! 48: if (n >= ARPTAB_BSIZ) \ ! 49: at = 0; } ! 50: ! 51: struct arpcom *arpcom; /* chain of active ether interfaces */ ! 52: int arpt_age; /* aging timer */ ! 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: * Local addresses in the range oldmap to infinity are ! 64: * mapped according to the old mapping scheme. That is, ! 65: * mapping of Internet to Ethernet addresses is performed ! 66: * by taking the high three bytes of the network interface's ! 67: * address and the low three bytes of the local address part. ! 68: * This only allows boards from the same manufacturer to ! 69: * communicate unless the on-board address is overridden ! 70: * (not possible in many manufacture's hardware). ! 71: * ! 72: * NB: setting oldmap to zero completely disables ARP ! 73: * (i.e. identical to setting IFF_NOARP with an ioctl). ! 74: */ ! 75: int oldmap = 1024; ! 76: ! 77: /* ! 78: * Attach an ethernet interface to the list "arpcom" where ! 79: * arptimer() can find it. If first time ! 80: * initialization, start arptimer(). ! 81: */ ! 82: arpattach(ac) ! 83: register struct arpcom *ac; ! 84: { ! 85: register struct arpcom *acp; ! 86: ! 87: for (acp = arpcom; acp != (struct arpcom *)0; acp = acp->ac_ac) ! 88: if (acp == ac) /* if already on list */ ! 89: return; ! 90: ac->ac_ac = arpcom; ! 91: arpcom = ac; ! 92: if (arpcom->ac_ac == 0) /* very first time */ ! 93: arptimer(); ! 94: } ! 95: ! 96: /* ! 97: * Timeout routine. Age arp_tab entries once a minute. ! 98: */ ! 99: arptimer() ! 100: { ! 101: register struct arptab *at; ! 102: register i; ! 103: ! 104: timeout(arptimer, (caddr_t)0, hz); ! 105: #ifdef notdef ! 106: if (++arpt_sanity > ARPT_SANITY) { ! 107: register struct arpcom *ac; ! 108: ! 109: /* ! 110: * Randomize sanity timer based on my host address. ! 111: * Ask who has my own address; if someone else replies, ! 112: * then they are impersonating me. ! 113: */ ! 114: arpt_sanity = arpcom->ac_enaddr[5] & 0x3f; ! 115: for (ac = arpcom; ac != (struct arpcom *)-1; ac = ac->ac_ac) ! 116: arpwhohas(ac, &((struct sockaddr_in *) ! 117: &ac->ac_if.if_addr)->sin_addr); ! 118: } ! 119: #endif ! 120: if (++arpt_age > ARPT_AGE) { ! 121: arpt_age = 0; ! 122: at = &arptab[0]; ! 123: for (i = 0; i < ARPTAB_SIZE; i++, at++) { ! 124: if (at->at_flags == 0) ! 125: continue; ! 126: if (++at->at_timer < ((at->at_flags&ATF_COM) ? ! 127: ARPT_KILLC : ARPT_KILLI)) ! 128: continue; ! 129: /* timer has expired, clear entry */ ! 130: arptfree(at); ! 131: } ! 132: } ! 133: } ! 134: ! 135: /* ! 136: * Broadcast an ARP packet, asking who has addr on interface ac. ! 137: */ ! 138: arpwhohas(ac, addr) ! 139: register struct arpcom *ac; ! 140: struct in_addr *addr; ! 141: { ! 142: register struct mbuf *m; ! 143: register struct ether_header *eh; ! 144: register struct ether_arp *ea; ! 145: struct sockaddr sa; ! 146: ! 147: if ((m = m_get(M_DONTWAIT, MT_DATA)) == NULL) ! 148: return; ! 149: m->m_len = sizeof *ea + sizeof *eh; ! 150: m->m_off = MMAXOFF - m->m_len; ! 151: ea = mtod(m, struct ether_arp *); ! 152: eh = (struct ether_header *)sa.sa_data; ! 153: bzero((caddr_t)ea, sizeof (*ea)); ! 154: bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost, ! 155: sizeof (etherbroadcastaddr)); ! 156: eh->ether_type = ETHERPUP_ARPTYPE; /* if_output will swap */ ! 157: ea->arp_hrd = htons(ARPHRD_ETHER); ! 158: ea->arp_pro = htons(ETHERPUP_IPTYPE); ! 159: ea->arp_hln = sizeof ea->arp_sha; /* hardware address length */ ! 160: ea->arp_pln = sizeof ea->arp_spa; /* protocol address length */ ! 161: ea->arp_op = htons(ARPOP_REQUEST); ! 162: bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha, ! 163: sizeof (ea->arp_sha)); ! 164: bcopy((caddr_t)&((struct sockaddr_in *)&ac->ac_if.if_addr)->sin_addr, ! 165: (caddr_t)ea->arp_spa, sizeof (ea->arp_spa)); ! 166: bcopy((caddr_t)addr, (caddr_t)ea->arp_tpa, sizeof (ea->arp_tpa)); ! 167: sa.sa_family = AF_UNSPEC; ! 168: (void) (*ac->ac_if.if_output)(&ac->ac_if, m, &sa); ! 169: } ! 170: ! 171: /* ! 172: * Resolve an IP address into an ethernet address. If success, ! 173: * desten is filled in and 1 is returned. If there is no entry ! 174: * in arptab, set one up and broadcast a request ! 175: * for the IP address; return 0. Hold onto this mbuf and ! 176: * resend it once the address is finally resolved. ! 177: * ! 178: * We do some (conservative) locking here at splimp, since ! 179: * arptab is also altered from input interrupt service (ecintr/ilintr ! 180: * calls arpinput when ETHERPUP_ARPTYPE packets come in). ! 181: */ ! 182: arpresolve(ac, m, destip, desten) ! 183: register struct arpcom *ac; ! 184: struct mbuf *m; ! 185: register struct in_addr *destip; ! 186: register u_char *desten; ! 187: { ! 188: register struct arptab *at; ! 189: register struct ifnet *ifp; ! 190: struct sockaddr_in sin; ! 191: int s, lna; ! 192: ! 193: lna = in_lnaof(*destip); ! 194: if (lna == INADDR_ANY) { /* broadcast address */ ! 195: bcopy((caddr_t)etherbroadcastaddr, (caddr_t)desten, ! 196: sizeof (etherbroadcastaddr)); ! 197: return (1); ! 198: } ! 199: ifp = &ac->ac_if; ! 200: /* if for us, then use software loopback driver */ ! 201: if (destip->s_addr == ! 202: ((struct sockaddr_in *)&ifp->if_addr)-> sin_addr.s_addr) { ! 203: sin.sin_family = AF_INET; ! 204: sin.sin_addr = *destip; ! 205: return (looutput(&loif, m, (struct sockaddr *)&sin)); ! 206: } ! 207: if ((ifp->if_flags & IFF_NOARP) || lna >= oldmap) { ! 208: bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten, 3); ! 209: desten[3] = (lna >> 16) & 0x7f; ! 210: desten[4] = (lna >> 8) & 0xff; ! 211: desten[5] = lna & 0xff; ! 212: return (1); ! 213: } ! 214: s = splimp(); ! 215: ARPTAB_LOOK(at, destip->s_addr); ! 216: if (at == 0) { /* not found */ ! 217: at = arptnew(destip); ! 218: at->at_hold = m; ! 219: arpwhohas(ac, destip); ! 220: splx(s); ! 221: return (0); ! 222: } ! 223: at->at_timer = 0; /* restart the timer */ ! 224: if (at->at_flags & ATF_COM) { /* entry IS complete */ ! 225: bcopy((caddr_t)at->at_enaddr, (caddr_t)desten, 6); ! 226: splx(s); ! 227: return (1); ! 228: } ! 229: /* ! 230: * There is an arptab entry, but no ethernet address ! 231: * response yet. Replace the held mbuf with this ! 232: * latest one. ! 233: */ ! 234: if (at->at_hold) ! 235: m_freem(at->at_hold); ! 236: at->at_hold = m; ! 237: arpwhohas(ac, destip); /* ask again */ ! 238: splx(s); ! 239: return (0); ! 240: } ! 241: ! 242: /* ! 243: * Find my own IP address. It will either be waiting for us in ! 244: * monitor RAM, or can be obtained via broadcast to the file/boot ! 245: * server (not necessarily using the ARP packet format). ! 246: * ! 247: * Unimplemented at present, return 0 and assume that the host ! 248: * will set his own IP address via the SIOCSIFADDR ioctl. ! 249: */ ! 250: /*ARGSUSED*/ ! 251: struct in_addr ! 252: arpmyaddr(ac) ! 253: register struct arpcom *ac; ! 254: { ! 255: static struct in_addr addr; ! 256: ! 257: #ifdef lint ! 258: ac = ac; ! 259: #endif ! 260: addr.s_addr = 0; ! 261: return (addr); ! 262: } ! 263: ! 264: /* ! 265: * Called from ecintr/ilintr when ether packet type ETHERPUP_ARP ! 266: * is received. Algorithm is exactly that given in RFC 826. ! 267: * In addition, a sanity check is performed on the sender ! 268: * protocol address, to catch impersonators. ! 269: */ ! 270: arpinput(ac, m) ! 271: register struct arpcom *ac; ! 272: struct mbuf *m; ! 273: { ! 274: register struct ether_arp *ea; ! 275: struct ether_header *eh; ! 276: register struct arptab *at = 0; /* same as "merge" flag */ ! 277: struct sockaddr_in sin; ! 278: struct sockaddr sa; ! 279: struct mbuf *mhold; ! 280: struct in_addr isaddr,itaddr,myaddr; ! 281: ! 282: if (m->m_len < sizeof *ea) ! 283: goto out; ! 284: myaddr = ((struct sockaddr_in *)&ac->ac_if.if_addr)->sin_addr; ! 285: ea = mtod(m, struct ether_arp *); ! 286: if (ntohs(ea->arp_pro) != ETHERPUP_IPTYPE) ! 287: goto out; ! 288: isaddr.s_addr = ((struct in_addr *)ea->arp_spa)->s_addr; ! 289: itaddr.s_addr = ((struct in_addr *)ea->arp_tpa)->s_addr; ! 290: if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr, ! 291: sizeof (ac->ac_enaddr))) ! 292: goto out; /* it's from me, ignore it. */ ! 293: if (isaddr.s_addr == myaddr.s_addr) { ! 294: printf("duplicate IP address!! sent from ethernet address: "); ! 295: printf("%x %x %x %x %x %x\n", ea->arp_sha[0], ea->arp_sha[1], ! 296: ea->arp_sha[2], ea->arp_sha[3], ! 297: ea->arp_sha[4], ea->arp_sha[5]); ! 298: if (ntohs(ea->arp_op) == ARPOP_REQUEST) ! 299: goto reply; ! 300: goto out; ! 301: } ! 302: ARPTAB_LOOK(at, isaddr.s_addr); ! 303: if (at) { ! 304: bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr, ! 305: sizeof (ea->arp_sha)); ! 306: at->at_flags |= ATF_COM; ! 307: if (at->at_hold) { ! 308: mhold = at->at_hold; ! 309: at->at_hold = 0; ! 310: sin.sin_family = AF_INET; ! 311: sin.sin_addr = isaddr; ! 312: (*ac->ac_if.if_output)(&ac->ac_if, ! 313: mhold, (struct sockaddr *)&sin); ! 314: } ! 315: } ! 316: if (itaddr.s_addr != myaddr.s_addr) ! 317: goto out; /* if I am not the target */ ! 318: if (at == 0) { /* ensure we have a table entry */ ! 319: at = arptnew(&isaddr); ! 320: bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr, ! 321: sizeof (ea->arp_sha)); ! 322: at->at_flags |= ATF_COM; ! 323: } ! 324: if (ntohs(ea->arp_op) != ARPOP_REQUEST) ! 325: goto out; ! 326: reply: ! 327: bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha, ! 328: sizeof (ea->arp_sha)); ! 329: bcopy((caddr_t)ea->arp_spa, (caddr_t)ea->arp_tpa, ! 330: sizeof (ea->arp_spa)); ! 331: bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha, ! 332: sizeof (ea->arp_sha)); ! 333: bcopy((caddr_t)&myaddr, (caddr_t)ea->arp_spa, ! 334: sizeof (ea->arp_spa)); ! 335: ea->arp_op = htons(ARPOP_REPLY); ! 336: eh = (struct ether_header *)sa.sa_data; ! 337: bcopy((caddr_t)ea->arp_tha, (caddr_t)eh->ether_dhost, ! 338: sizeof (eh->ether_dhost)); ! 339: eh->ether_type = ETHERPUP_ARPTYPE; ! 340: sa.sa_family = AF_UNSPEC; ! 341: (*ac->ac_if.if_output)(&ac->ac_if, m, &sa); ! 342: return; ! 343: out: ! 344: m_freem(m); ! 345: return; ! 346: } ! 347: ! 348: /* ! 349: * Free an arptab entry. ! 350: */ ! 351: arptfree(at) ! 352: register struct arptab *at; ! 353: { ! 354: int s = splimp(); ! 355: ! 356: if (at->at_hold) ! 357: m_freem(at->at_hold); ! 358: at->at_hold = 0; ! 359: at->at_timer = at->at_flags = 0; ! 360: at->at_iaddr.s_addr = 0; ! 361: splx(s); ! 362: } ! 363: ! 364: /* ! 365: * Enter a new address in arptab, pushing out the oldest entry ! 366: * from the bucket if there is no room. ! 367: */ ! 368: struct arptab * ! 369: arptnew(addr) ! 370: struct in_addr *addr; ! 371: { ! 372: register n; ! 373: int oldest = 0; ! 374: register struct arptab *at, *ato; ! 375: ! 376: ato = at = &arptab[ARPTAB_HASH(addr->s_addr) * ARPTAB_BSIZ]; ! 377: for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) { ! 378: if (at->at_flags == 0) ! 379: goto out; /* found an empty entry */ ! 380: if (at->at_timer > oldest) { ! 381: oldest = at->at_timer; ! 382: ato = at; ! 383: } ! 384: } ! 385: at = ato; ! 386: arptfree(at); ! 387: out: ! 388: at->at_iaddr = *addr; ! 389: at->at_flags = ATF_INUSE; ! 390: return (at); ! 391: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.