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