|
|
1.1 ! root 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.1.1 (Berkeley) 2/27/87 ! 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: int useloopback = 1; /* use loopback interface for local traffic */ ! 120: ! 121: /* ! 122: * Resolve an IP address into an ethernet address. If success, ! 123: * desten is filled in. If there is no entry in arptab, ! 124: * set one up and broadcast a request for the IP address. ! 125: * Hold onto this mbuf and resend it once the address ! 126: * is finally resolved. A return value of 1 indicates ! 127: * that desten has been filled in and the packet should be sent ! 128: * normally; a 0 return indicates that the packet has been ! 129: * taken over here, either now or for later transmission. ! 130: * ! 131: * We do some (conservative) locking here at splimp, since ! 132: * arptab is also altered from input interrupt service (ecintr/ilintr ! 133: * calls arpinput when ETHERTYPE_ARP packets come in). ! 134: */ ! 135: arpresolve(ac, m, destip, desten, usetrailers) ! 136: register struct arpcom *ac; ! 137: struct mbuf *m; ! 138: register struct in_addr *destip; ! 139: register u_char *desten; ! 140: int *usetrailers; ! 141: { ! 142: register struct arptab *at; ! 143: register struct ifnet *ifp; ! 144: struct sockaddr_in sin; ! 145: int s, lna; ! 146: ! 147: *usetrailers = 0; ! 148: if (in_broadcast(*destip)) { /* broadcast address */ ! 149: bcopy((caddr_t)etherbroadcastaddr, (caddr_t)desten, ! 150: sizeof(etherbroadcastaddr)); ! 151: return (1); ! 152: } ! 153: lna = in_lnaof(*destip); ! 154: ifp = &ac->ac_if; ! 155: /* if for us, use software loopback driver if up */ ! 156: if (destip->s_addr == ac->ac_ipaddr.s_addr) { ! 157: if (useloopback) { ! 158: sin.sin_family = AF_INET; ! 159: sin.sin_addr = *destip; ! 160: (void) looutput(&loif, m, (struct sockaddr *)&sin); ! 161: /* ! 162: * The packet has already been sent and freed. ! 163: */ ! 164: return (0); ! 165: } else { ! 166: bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten, ! 167: sizeof(ac->ac_enaddr)); ! 168: return (1); ! 169: } ! 170: } ! 171: s = splimp(); ! 172: ARPTAB_LOOK(at, destip->s_addr); ! 173: if (at == 0) { /* not found */ ! 174: if (ifp->if_flags & IFF_NOARP) { ! 175: bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten, 3); ! 176: desten[3] = (lna >> 16) & 0x7f; ! 177: desten[4] = (lna >> 8) & 0xff; ! 178: desten[5] = lna & 0xff; ! 179: splx(s); ! 180: return (1); ! 181: } else { ! 182: at = arptnew(destip); ! 183: at->at_hold = m; ! 184: arpwhohas(ac, destip); ! 185: splx(s); ! 186: return (0); ! 187: } ! 188: } ! 189: at->at_timer = 0; /* restart the timer */ ! 190: if (at->at_flags & ATF_COM) { /* entry IS complete */ ! 191: bcopy((caddr_t)at->at_enaddr, (caddr_t)desten, ! 192: sizeof(at->at_enaddr)); ! 193: if (at->at_flags & ATF_USETRAILERS) ! 194: *usetrailers = 1; ! 195: splx(s); ! 196: return (1); ! 197: } ! 198: /* ! 199: * There is an arptab entry, but no ethernet address ! 200: * response yet. Replace the held mbuf with this ! 201: * latest one. ! 202: */ ! 203: if (at->at_hold) ! 204: m_freem(at->at_hold); ! 205: at->at_hold = m; ! 206: arpwhohas(ac, destip); /* ask again */ ! 207: splx(s); ! 208: return (0); ! 209: } ! 210: ! 211: /* ! 212: * Called from 10 Mb/s Ethernet interrupt handlers ! 213: * when ether packet type ETHERTYPE_ARP ! 214: * is received. Common length and type checks are done here, ! 215: * then the protocol-specific routine is called. ! 216: */ ! 217: arpinput(ac, m) ! 218: struct arpcom *ac; ! 219: struct mbuf *m; ! 220: { ! 221: register struct arphdr *ar; ! 222: ! 223: if (ac->ac_if.if_flags & IFF_NOARP) ! 224: goto out; ! 225: IF_ADJ(m); ! 226: if (m->m_len < sizeof(struct arphdr)) ! 227: goto out; ! 228: ar = mtod(m, struct arphdr *); ! 229: if (ntohs(ar->ar_hrd) != ARPHRD_ETHER) ! 230: goto out; ! 231: if (m->m_len < sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln) ! 232: goto out; ! 233: ! 234: switch (ntohs(ar->ar_pro)) { ! 235: ! 236: case ETHERTYPE_IP: ! 237: case ETHERTYPE_IPTRAILERS: ! 238: in_arpinput(ac, m); ! 239: return; ! 240: ! 241: default: ! 242: break; ! 243: } ! 244: out: ! 245: m_freem(m); ! 246: } ! 247: ! 248: /* ! 249: * ARP for Internet protocols on 10 Mb/s Ethernet. ! 250: * Algorithm is that given in RFC 826. ! 251: * In addition, a sanity check is performed on the sender ! 252: * protocol address, to catch impersonators. ! 253: * We also handle negotiations for use of trailer protocol: ! 254: * ARP replies for protocol type ETHERTYPE_TRAIL are sent ! 255: * along with IP replies if we want trailers sent to us, ! 256: * and also send them in response to IP replies. ! 257: * This allows either end to announce the desire to receive ! 258: * trailer packets. ! 259: * We reply to requests for ETHERTYPE_TRAIL protocol as well, ! 260: * but don't normally send requests. ! 261: */ ! 262: in_arpinput(ac, m) ! 263: register struct arpcom *ac; ! 264: struct mbuf *m; ! 265: { ! 266: register struct ether_arp *ea; ! 267: struct ether_header *eh; ! 268: register struct arptab *at; /* same as "merge" flag */ ! 269: struct mbuf *mcopy = 0; ! 270: struct sockaddr_in sin; ! 271: struct sockaddr sa; ! 272: struct in_addr isaddr, itaddr, myaddr; ! 273: int proto, op, s; ! 274: ! 275: myaddr = ac->ac_ipaddr; ! 276: ea = mtod(m, struct ether_arp *); ! 277: proto = ntohs(ea->arp_pro); ! 278: op = ntohs(ea->arp_op); ! 279: isaddr.s_addr = ((struct in_addr *)ea->arp_spa)->s_addr; ! 280: itaddr.s_addr = ((struct in_addr *)ea->arp_tpa)->s_addr; ! 281: if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr, ! 282: sizeof (ea->arp_sha))) ! 283: goto out; /* it's from me, ignore it. */ ! 284: if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)etherbroadcastaddr, ! 285: sizeof (ea->arp_sha))) { ! 286: log(LOG_ERR, ! 287: "arp: ether address is broadcast for IP address %x!\n", ! 288: ntohl(isaddr.s_addr)); ! 289: goto out; ! 290: } ! 291: if (isaddr.s_addr == myaddr.s_addr) { ! 292: log(LOG_ERR, "%s: %s\n", ! 293: "duplicate IP address!! sent from ethernet address", ! 294: ether_sprintf(ea->arp_sha)); ! 295: itaddr = myaddr; ! 296: if (op == ARPOP_REQUEST) ! 297: goto reply; ! 298: goto out; ! 299: } ! 300: s = splimp(); ! 301: ARPTAB_LOOK(at, isaddr.s_addr); ! 302: if (at) { ! 303: bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr, ! 304: sizeof(ea->arp_sha)); ! 305: at->at_flags |= ATF_COM; ! 306: if (at->at_hold) { ! 307: sin.sin_family = AF_INET; ! 308: sin.sin_addr = isaddr; ! 309: (*ac->ac_if.if_output)(&ac->ac_if, ! 310: at->at_hold, (struct sockaddr *)&sin); ! 311: at->at_hold = 0; ! 312: } ! 313: } ! 314: if (at == 0 && itaddr.s_addr == myaddr.s_addr) { ! 315: /* ensure we have a table entry */ ! 316: at = arptnew(&isaddr); ! 317: bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr, ! 318: sizeof(ea->arp_sha)); ! 319: at->at_flags |= ATF_COM; ! 320: } ! 321: splx(s); ! 322: reply: ! 323: switch (proto) { ! 324: ! 325: case ETHERTYPE_IPTRAILERS: ! 326: /* partner says trailers are OK */ ! 327: if (at) ! 328: at->at_flags |= ATF_USETRAILERS; ! 329: /* ! 330: * Reply to request iff we want trailers. ! 331: */ ! 332: if (op != ARPOP_REQUEST || ac->ac_if.if_flags & IFF_NOTRAILERS) ! 333: goto out; ! 334: break; ! 335: ! 336: case ETHERTYPE_IP: ! 337: /* ! 338: * Reply if this is an IP request, or if we want to send ! 339: * a trailer response. ! 340: */ ! 341: if (op != ARPOP_REQUEST && ac->ac_if.if_flags & IFF_NOTRAILERS) ! 342: goto out; ! 343: } ! 344: if (itaddr.s_addr == myaddr.s_addr) { ! 345: /* I am the target */ ! 346: bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha, ! 347: sizeof(ea->arp_sha)); ! 348: bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha, ! 349: sizeof(ea->arp_sha)); ! 350: } else { ! 351: ARPTAB_LOOK(at, itaddr.s_addr); ! 352: if (at == NULL || (at->at_flags & ATF_PUBL) == 0) ! 353: goto out; ! 354: bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha, ! 355: sizeof(ea->arp_sha)); ! 356: bcopy((caddr_t)at->at_enaddr, (caddr_t)ea->arp_sha, ! 357: sizeof(ea->arp_sha)); ! 358: } ! 359: ! 360: bcopy((caddr_t)ea->arp_spa, (caddr_t)ea->arp_tpa, ! 361: sizeof(ea->arp_spa)); ! 362: bcopy((caddr_t)&itaddr, (caddr_t)ea->arp_spa, ! 363: sizeof(ea->arp_spa)); ! 364: ea->arp_op = htons(ARPOP_REPLY); ! 365: /* ! 366: * If incoming packet was an IP reply, ! 367: * we are sending a reply for type IPTRAILERS. ! 368: * If we are sending a reply for type IP ! 369: * and we want to receive trailers, ! 370: * send a trailer reply as well. ! 371: */ ! 372: if (op == ARPOP_REPLY) ! 373: ea->arp_pro = htons(ETHERTYPE_IPTRAILERS); ! 374: else if (proto == ETHERTYPE_IP && ! 375: (ac->ac_if.if_flags & IFF_NOTRAILERS) == 0) ! 376: mcopy = m_copy(m, 0, (int)M_COPYALL); ! 377: eh = (struct ether_header *)sa.sa_data; ! 378: bcopy((caddr_t)ea->arp_tha, (caddr_t)eh->ether_dhost, ! 379: sizeof(eh->ether_dhost)); ! 380: eh->ether_type = ETHERTYPE_ARP; ! 381: sa.sa_family = AF_UNSPEC; ! 382: (*ac->ac_if.if_output)(&ac->ac_if, m, &sa); ! 383: if (mcopy) { ! 384: ea = mtod(mcopy, struct ether_arp *); ! 385: ea->arp_pro = htons(ETHERTYPE_IPTRAILERS); ! 386: (*ac->ac_if.if_output)(&ac->ac_if, mcopy, &sa); ! 387: } ! 388: return; ! 389: out: ! 390: m_freem(m); ! 391: return; ! 392: } ! 393: ! 394: /* ! 395: * Free an arptab entry. ! 396: */ ! 397: arptfree(at) ! 398: register struct arptab *at; ! 399: { ! 400: int s = splimp(); ! 401: ! 402: if (at->at_hold) ! 403: m_freem(at->at_hold); ! 404: at->at_hold = 0; ! 405: at->at_timer = at->at_flags = 0; ! 406: at->at_iaddr.s_addr = 0; ! 407: splx(s); ! 408: } ! 409: ! 410: /* ! 411: * Enter a new address in arptab, pushing out the oldest entry ! 412: * from the bucket if there is no room. ! 413: * This always succeeds since no bucket can be completely filled ! 414: * with permanent entries (except from arpioctl when testing whether ! 415: * another permanent entry will fit). ! 416: */ ! 417: struct arptab * ! 418: arptnew(addr) ! 419: struct in_addr *addr; ! 420: { ! 421: register n; ! 422: int oldest = -1; ! 423: register struct arptab *at, *ato = NULL; ! 424: static int first = 1; ! 425: ! 426: if (first) { ! 427: first = 0; ! 428: timeout(arptimer, (caddr_t)0, hz); ! 429: } ! 430: at = &arptab[ARPTAB_HASH(addr->s_addr) * ARPTAB_BSIZ]; ! 431: for (n = 0; n < ARPTAB_BSIZ; n++,at++) { ! 432: if (at->at_flags == 0) ! 433: goto out; /* found an empty entry */ ! 434: if (at->at_flags & ATF_PERM) ! 435: continue; ! 436: if (at->at_timer > oldest) { ! 437: oldest = at->at_timer; ! 438: ato = at; ! 439: } ! 440: } ! 441: if (ato == NULL) ! 442: return (NULL); ! 443: at = ato; ! 444: arptfree(at); ! 445: out: ! 446: at->at_iaddr = *addr; ! 447: at->at_flags = ATF_INUSE; ! 448: return (at); ! 449: } ! 450: ! 451: arpioctl(cmd, data) ! 452: int cmd; ! 453: caddr_t data; ! 454: { ! 455: register struct arpreq *ar = (struct arpreq *)data; ! 456: register struct arptab *at; ! 457: register struct sockaddr_in *sin; ! 458: int s; ! 459: ! 460: if (ar->arp_pa.sa_family != AF_INET || ! 461: ar->arp_ha.sa_family != AF_UNSPEC) ! 462: return (EAFNOSUPPORT); ! 463: sin = (struct sockaddr_in *)&ar->arp_pa; ! 464: s = splimp(); ! 465: ARPTAB_LOOK(at, sin->sin_addr.s_addr); ! 466: if (at == NULL) { /* not found */ ! 467: if (cmd != SIOCSARP) { ! 468: splx(s); ! 469: return (ENXIO); ! 470: } ! 471: if (ifa_ifwithnet(&ar->arp_pa) == NULL) { ! 472: splx(s); ! 473: return (ENETUNREACH); ! 474: } ! 475: } ! 476: switch (cmd) { ! 477: ! 478: case SIOCSARP: /* set entry */ ! 479: if (at == NULL) { ! 480: at = arptnew(&sin->sin_addr); ! 481: if (ar->arp_flags & ATF_PERM) { ! 482: /* never make all entries in a bucket permanent */ ! 483: register struct arptab *tat; ! 484: ! 485: /* try to re-allocate */ ! 486: tat = arptnew(&sin->sin_addr); ! 487: if (tat == NULL) { ! 488: arptfree(at); ! 489: splx(s); ! 490: return (EADDRNOTAVAIL); ! 491: } ! 492: arptfree(tat); ! 493: } ! 494: } ! 495: bcopy((caddr_t)ar->arp_ha.sa_data, (caddr_t)at->at_enaddr, ! 496: sizeof(at->at_enaddr)); ! 497: at->at_flags = ATF_COM | ATF_INUSE | ! 498: (ar->arp_flags & (ATF_PERM|ATF_PUBL)); ! 499: at->at_timer = 0; ! 500: break; ! 501: ! 502: case SIOCDARP: /* delete entry */ ! 503: arptfree(at); ! 504: break; ! 505: ! 506: case SIOCGARP: /* get entry */ ! 507: bcopy((caddr_t)at->at_enaddr, (caddr_t)ar->arp_ha.sa_data, ! 508: sizeof(at->at_enaddr)); ! 509: ar->arp_flags = at->at_flags; ! 510: break; ! 511: } ! 512: splx(s); ! 513: return (0); ! 514: } ! 515: ! 516: /* ! 517: * Convert Ethernet address to printable (loggable) representation. ! 518: */ ! 519: char * ! 520: ether_sprintf(ap) ! 521: register u_char *ap; ! 522: { ! 523: register i; ! 524: static char etherbuf[18]; ! 525: register char *cp = etherbuf; ! 526: static char digits[] = "0123456789abcdef"; ! 527: ! 528: for (i = 0; i < 6; i++) { ! 529: *cp++ = digits[*ap >> 4]; ! 530: *cp++ = digits[*ap++ & 0xf]; ! 531: *cp++ = ':'; ! 532: } ! 533: *--cp = 0; ! 534: return (etherbuf); ! 535: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.