1/* 2 * Copyright (c) 2004-2008 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* 29 * Copyright (c) 1982, 1989, 1993 30 * The Regents of the University of California. All rights reserved. 31 * 32 * Redistribution and use in source and binary forms, with or without 33 * modification, are permitted provided that the following conditions 34 * are met: 35 * 1. Redistributions of source code must retain the above copyright 36 * notice, this list of conditions and the following disclaimer. 37 * 2. Redistributions in binary form must reproduce the above copyright 38 * notice, this list of conditions and the following disclaimer in the 39 * documentation and/or other materials provided with the distribution. 40 * 3. All advertising materials mentioning features or use of this software 41 * must display the following acknowledgement: 42 * This product includes software developed by the University of 43 * California, Berkeley and its contributors. 44 * 4. Neither the name of the University nor the names of its contributors 45 * may be used to endorse or promote products derived from this software 46 * without specific prior written permission. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 * SUCH DAMAGE. 59 * 60 */ 61 62#include <kern/debug.h> 63#include <netinet/in_arp.h> 64#include <sys/types.h> 65#include <sys/param.h> 66#include <sys/kernel_types.h> 67#include <sys/syslog.h> 68#include <sys/systm.h> 69#include <sys/time.h> 70#include <sys/kernel.h> 71#include <sys/mbuf.h> 72#include <sys/sysctl.h> 73#include <string.h> 74#include <net/if_arp.h> 75#include <net/if_dl.h> 76#include <net/dlil.h> 77#include <net/route.h> 78#include <netinet/if_ether.h> 79#include <netinet/in_var.h> 80 81#define SIN(s) ((struct sockaddr_in *)s) 82#define CONST_LLADDR(s) ((const u_char*)((s)->sdl_data + (s)->sdl_nlen)) 83#define rt_expire rt_rmx.rmx_expire 84 85static const size_t MAX_HW_LEN = 10; 86 87SYSCTL_DECL(_net_link_ether); 88SYSCTL_NODE(_net_link_ether, PF_INET, inet, CTLFLAG_RW|CTLFLAG_LOCKED, 0, ""); 89 90/* timer values */ 91static int arpt_prune = (5*60*1); /* walk list every 5 minutes */ 92static int arpt_keep = (20*60); /* once resolved, good for 20 more minutes */ 93static int arpt_down = 20; /* once declared down, don't send for 20 sec */ 94 95/* Apple Hardware SUM16 checksuming */ 96int apple_hwcksum_tx = 1; 97int apple_hwcksum_rx = 1; 98 99SYSCTL_INT(_net_link_ether_inet, OID_AUTO, prune_intvl, CTLFLAG_RW, 100 &arpt_prune, 0, ""); 101SYSCTL_INT(_net_link_ether_inet, OID_AUTO, max_age, CTLFLAG_RW, 102 &arpt_keep, 0, ""); 103SYSCTL_INT(_net_link_ether_inet, OID_AUTO, host_down_time, CTLFLAG_RW, 104 &arpt_down, 0, ""); 105SYSCTL_INT(_net_link_ether_inet, OID_AUTO, apple_hwcksum_tx, CTLFLAG_RW, 106 &apple_hwcksum_tx, 0, ""); 107SYSCTL_INT(_net_link_ether_inet, OID_AUTO, apple_hwcksum_rx, CTLFLAG_RW, 108 &apple_hwcksum_rx, 0, ""); 109 110struct llinfo_arp { 111 LIST_ENTRY(llinfo_arp) la_le; 112 struct rtentry *la_rt; 113 struct mbuf *la_hold; /* last packet until resolved/timeout */ 114 long la_asked; /* last time we QUERIED for this addr */ 115}; 116 117static LIST_HEAD(, llinfo_arp) llinfo_arp; 118 119static int arp_inuse, arp_allocated; 120 121static int arp_maxtries = 5; 122static int useloopback = 1; /* use loopback interface for local traffic */ 123static int arp_proxyall = 0; 124static int arp_sendllconflict = 0; 125 126SYSCTL_INT(_net_link_ether_inet, OID_AUTO, maxtries, CTLFLAG_RW, 127 &arp_maxtries, 0, ""); 128SYSCTL_INT(_net_link_ether_inet, OID_AUTO, useloopback, CTLFLAG_RW, 129 &useloopback, 0, ""); 130SYSCTL_INT(_net_link_ether_inet, OID_AUTO, proxyall, CTLFLAG_RW, 131 &arp_proxyall, 0, ""); 132SYSCTL_INT(_net_link_ether_inet, OID_AUTO, sendllconflict, CTLFLAG_RW, 133 &arp_sendllconflict, 0, ""); 134 135static int log_arp_warnings = 0; 136 137SYSCTL_INT(_net_link_ether_inet, OID_AUTO, log_arp_warnings, CTLFLAG_RW, 138 &log_arp_warnings, 0, 139 "log arp warning messages"); 140 141static int keep_announcements = 1; 142SYSCTL_INT(_net_link_ether_inet, OID_AUTO, keep_announcements, CTLFLAG_RW, 143 &keep_announcements, 0, 144 "keep arp announcements"); 145 146static int send_conflicting_probes = 1; 147SYSCTL_INT(_net_link_ether_inet, OID_AUTO, send_conflicting_probes, CTLFLAG_RW, 148 &send_conflicting_probes, 0, 149 "send conflicting link-local arp probes"); 150 151extern u_int32_t ipv4_ll_arp_aware; 152 153/* 154 * Free an arp entry. 155 */ 156static void 157arptfree( 158 struct llinfo_arp *la) 159{ 160 struct rtentry *rt = la->la_rt; 161 struct sockaddr_dl *sdl; 162 lck_mtx_assert(rt_mtx, LCK_MTX_ASSERT_OWNED); 163 if (rt == 0) 164 panic("arptfree"); 165 if (rt->rt_refcnt > 0 && (sdl = SDL(rt->rt_gateway)) && 166 sdl->sdl_family == AF_LINK) { 167 sdl->sdl_alen = 0; 168 la->la_asked = 0; 169 rt->rt_flags &= ~RTF_REJECT; 170 return; 171 } 172 rtrequest_locked(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt), 173 0, (struct rtentry **)0); 174} 175 176/* 177 * Timeout routine. Age arp_tab entries periodically. 178 */ 179/* ARGSUSED */ 180static void 181arptimer(void *ignored_arg) 182{ 183#pragma unused (ignored_arg) 184 struct llinfo_arp *la, *ola; 185 struct timeval timenow; 186 187 lck_mtx_lock(rt_mtx); 188 la = llinfo_arp.lh_first; 189 getmicrotime(&timenow); 190 while ((ola = la) != 0) { 191 struct rtentry *rt = la->la_rt; 192 la = la->la_le.le_next; 193 if (rt->rt_expire && rt->rt_expire <= timenow.tv_sec) 194 arptfree(ola); /* timer has expired, clear */ 195 } 196 lck_mtx_unlock(rt_mtx); 197 timeout(arptimer, (caddr_t)0, arpt_prune * hz); 198} 199 200/* 201 * Parallel to llc_rtrequest. 202 */ 203static void 204arp_rtrequest( 205 int req, 206 struct rtentry *rt, 207 __unused struct sockaddr *sa) 208{ 209 struct sockaddr *gate = rt->rt_gateway; 210 struct llinfo_arp *la = (struct llinfo_arp *)rt->rt_llinfo; 211 static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK, 0, 0, 0, 0, 0, {0}}; 212 static int arpinit_done; 213 struct timeval timenow; 214 215 if (!arpinit_done) { 216 arpinit_done = 1; 217 LIST_INIT(&llinfo_arp); 218 timeout(arptimer, (caddr_t)0, hz); 219 } 220 lck_mtx_assert(rt_mtx, LCK_MTX_ASSERT_OWNED); 221 222 if (rt->rt_flags & RTF_GATEWAY) 223 return; 224 getmicrotime(&timenow); 225 switch (req) { 226 227 case RTM_ADD: 228 /* 229 * XXX: If this is a manually added route to interface 230 * such as older version of routed or gated might provide, 231 * restore cloning bit. 232 */ 233 if ((rt->rt_flags & RTF_HOST) == 0 && 234 SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff) 235 rt->rt_flags |= RTF_CLONING; 236 if (rt->rt_flags & RTF_CLONING) { 237 /* 238 * Case 1: This route should come from a route to iface. 239 */ 240 rt_setgate(rt, rt_key(rt), 241 (struct sockaddr *)&null_sdl); 242 gate = rt->rt_gateway; 243 SDL(gate)->sdl_type = rt->rt_ifp->if_type; 244 SDL(gate)->sdl_index = rt->rt_ifp->if_index; 245 /* In case we're called before 1.0 sec. has elapsed */ 246 rt->rt_expire = MAX(timenow.tv_sec, 1); 247 break; 248 } 249 /* Announce a new entry if requested. */ 250 if (rt->rt_flags & RTF_ANNOUNCE) 251 dlil_send_arp(rt->rt_ifp, ARPOP_REQUEST, SDL(gate), rt_key(rt), (struct sockaddr_dl *)rt_key(rt), NULL); 252 /*FALLTHROUGH*/ 253 case RTM_RESOLVE: 254 if (gate->sa_family != AF_LINK || 255 gate->sa_len < sizeof(null_sdl)) { 256 if (log_arp_warnings) 257 log(LOG_DEBUG, "arp_rtrequest: bad gateway value\n"); 258 break; 259 } 260 SDL(gate)->sdl_type = rt->rt_ifp->if_type; 261 SDL(gate)->sdl_index = rt->rt_ifp->if_index; 262 if (la != 0) 263 break; /* This happens on a route change */ 264 /* 265 * Case 2: This route may come from cloning, or a manual route 266 * add with a LL address. 267 */ 268 R_Malloc(la, struct llinfo_arp *, sizeof(*la)); 269 rt->rt_llinfo = (caddr_t)la; 270 if (la == 0) { 271 if ( log_arp_warnings) 272 log(LOG_DEBUG, "arp_rtrequest: malloc failed\n"); 273 break; 274 } 275 arp_inuse++, arp_allocated++; 276 Bzero(la, sizeof(*la)); 277 la->la_rt = rt; 278 rt->rt_flags |= RTF_LLINFO; 279 LIST_INSERT_HEAD(&llinfo_arp, la, la_le); 280 281#if INET 282 /* 283 * This keeps the multicast addresses from showing up 284 * in `arp -a' listings as unresolved. It's not actually 285 * functional. Then the same for broadcast. 286 */ 287 if (IN_MULTICAST(ntohl(SIN(rt_key(rt))->sin_addr.s_addr))) { 288 dlil_resolve_multi(rt->rt_ifp, rt_key(rt), gate, sizeof(struct sockaddr_dl)); 289 rt->rt_expire = 0; 290 } 291 else if (in_broadcast(SIN(rt_key(rt))->sin_addr, rt->rt_ifp)) { 292 struct sockaddr_dl *gate_ll = SDL(gate); 293 size_t broadcast_len; 294 ifnet_llbroadcast_copy_bytes(rt->rt_ifp, LLADDR(gate_ll), 295 sizeof(gate_ll->sdl_data), 296 &broadcast_len); 297 gate_ll->sdl_alen = broadcast_len; 298 gate_ll->sdl_family = AF_LINK; 299 gate_ll->sdl_len = sizeof(struct sockaddr_dl); 300 /* In case we're called before 1.0 sec. has elapsed */ 301 rt->rt_expire = MAX(timenow.tv_sec, 1); 302 } 303#endif 304 305 if (SIN(rt_key(rt))->sin_addr.s_addr == 306 (IA_SIN(rt->rt_ifa))->sin_addr.s_addr) { 307 /* 308 * This test used to be 309 * if (loif.if_flags & IFF_UP) 310 * It allowed local traffic to be forced 311 * through the hardware by configuring the loopback down. 312 * However, it causes problems during network configuration 313 * for boards that can't receive packets they send. 314 * It is now necessary to clear "useloopback" and remove 315 * the route to force traffic out to the hardware. 316 */ 317 rt->rt_expire = 0; 318 ifnet_lladdr_copy_bytes(rt->rt_ifp, LLADDR(SDL(gate)), SDL(gate)->sdl_alen = 6); 319 if (useloopback) 320 rt->rt_ifp = lo_ifp; 321 322 } 323 break; 324 325 case RTM_DELETE: 326 if (la == 0) 327 break; 328 arp_inuse--; 329 LIST_REMOVE(la, la_le); 330 rt->rt_llinfo = NULL; 331 rt->rt_flags &= ~RTF_LLINFO; 332 if (la->la_hold) { 333 m_freem(la->la_hold); 334 } 335 la->la_hold = NULL; 336 R_Free((caddr_t)la); 337 } 338} 339 340/* 341 * convert hardware address to hex string for logging errors. 342 */ 343static const char * 344sdl_addr_to_hex(const struct sockaddr_dl *sdl, char * orig_buf, int buflen) 345{ 346 char * buf = orig_buf; 347 int i; 348 const u_char * lladdr = (u_char *)sdl->sdl_data; 349 int maxbytes = buflen / 3; 350 351 if (maxbytes > sdl->sdl_alen) { 352 maxbytes = sdl->sdl_alen; 353 } 354 *buf = '\0'; 355 for (i = 0; i < maxbytes; i++) { 356 snprintf(buf, 3, "%02x", lladdr[i]); 357 buf += 2; 358 *buf = (i == maxbytes - 1) ? '\0' : ':'; 359 buf++; 360 } 361 return (orig_buf); 362} 363 364/* 365 * arp_lookup_route will lookup the route for a given address. 366 * 367 * The routing lock must be held. The address must be for a 368 * host on a local network on this interface. 369 */ 370static errno_t 371arp_lookup_route( 372 const struct in_addr *addr, 373 int create, 374 int proxy, 375 route_t *route, 376 unsigned int ifscope) 377{ 378 struct sockaddr_inarp sin = {sizeof(sin), AF_INET, 0, {0}, {0}, 0, 0}; 379 const char *why = NULL; 380 errno_t error = 0; 381 382 // Caller is responsible for taking the routing lock 383 lck_mtx_assert(rt_mtx, LCK_MTX_ASSERT_OWNED); 384 385 sin.sin_addr.s_addr = addr->s_addr; 386 sin.sin_other = proxy ? SIN_PROXY : 0; 387 388 *route = rtalloc1_scoped_locked((struct sockaddr*)&sin, 389 create, 0, ifscope); 390 if (*route == NULL) 391 return ENETUNREACH; 392 393 rtunref(*route); 394 395 if ((*route)->rt_flags & RTF_GATEWAY) { 396 why = "host is not on local network"; 397 398 /* If there are no references to this route, purge it */ 399 if ((*route)->rt_refcnt <= 0 && ((*route)->rt_flags & RTF_WASCLONED) != 0) { 400 rtrequest_locked(RTM_DELETE, 401 (struct sockaddr *)rt_key(*route), 402 (*route)->rt_gateway, rt_mask(*route), 403 (*route)->rt_flags, 0); 404 } 405 *route = NULL; 406 error = ENETUNREACH; 407 } 408 else if (((*route)->rt_flags & RTF_LLINFO) == 0) { 409 why = "could not allocate llinfo"; 410 *route = NULL; 411 error = ENOMEM; 412 } 413 else if ((*route)->rt_gateway->sa_family != AF_LINK) { 414 why = "gateway route is not ours"; 415 *route = NULL; 416 error = EPROTONOSUPPORT; 417 } 418 419 if (why && create && log_arp_warnings) { 420 char tmp[MAX_IPv4_STR_LEN]; 421 log(LOG_DEBUG, "arplookup link#%d %s failed: %s\n", ifscope, 422 inet_ntop(AF_INET, addr, tmp, sizeof(tmp)), why); 423 } 424 425 return error; 426} 427 428 429__private_extern__ errno_t 430arp_route_to_gateway_route( 431 const struct sockaddr *net_dest, 432 route_t hint, 433 route_t *out_route); 434/* 435 * arp_route_to_gateway_route will find the gateway route for a given route. 436 * 437 * If the route is down, look the route up again. 438 * If the route goes through a gateway, get the route to the gateway. 439 * If the gateway route is down, look it up again. 440 * If the route is set to reject, verify it hasn't expired. 441 */ 442__private_extern__ errno_t 443arp_route_to_gateway_route( 444 const struct sockaddr *net_dest, 445 route_t hint, 446 route_t *out_route) 447{ 448 struct timeval timenow; 449 route_t route = hint; 450 *out_route = NULL; 451 452 /* If we got a hint from the higher layers, check it out */ 453 if (route) { 454 lck_mtx_lock(rt_mtx); 455 456 if ((route->rt_flags & RTF_UP) == 0) { 457 /* route is down, find a new one */ 458 hint = route = rtalloc1_scoped_locked(net_dest, 459 1, 0, route->rt_ifp->if_index); 460 if (hint) { 461 rtunref(hint); 462 } 463 else { 464 /* No route to host */ 465 lck_mtx_unlock(rt_mtx); 466 return EHOSTUNREACH; 467 } 468 } 469 470 if (route->rt_flags & RTF_GATEWAY) { 471 /* 472 * We need the gateway route. If it is NULL or down, 473 * look it up. 474 */ 475 if (route->rt_gwroute == 0 || 476 (route->rt_gwroute->rt_flags & RTF_UP) == 0) { 477 if (route->rt_gwroute != 0) 478 rtfree_locked(route->rt_gwroute); 479 480 route->rt_gwroute = rtalloc1_scoped_locked( 481 route->rt_gateway, 1, 0, 482 route->rt_ifp->if_index); 483 if (route->rt_gwroute == 0) { 484 lck_mtx_unlock(rt_mtx); 485 return EHOSTUNREACH; 486 } 487 } 488 489 route = route->rt_gwroute; 490 } 491 492 if (route->rt_flags & RTF_REJECT) { 493 getmicrotime(&timenow); 494 if (route->rt_rmx.rmx_expire == 0 || 495 timenow.tv_sec < route->rt_rmx.rmx_expire) { 496 lck_mtx_unlock(rt_mtx); 497 return route == hint ? EHOSTDOWN : EHOSTUNREACH; 498 } 499 } 500 501 lck_mtx_unlock(rt_mtx); 502 } 503 504 *out_route = route; 505 return 0; 506} 507 508errno_t 509arp_lookup_ip( 510 ifnet_t ifp, 511 const struct sockaddr_in *net_dest, 512 struct sockaddr_dl *ll_dest, 513 size_t ll_dest_len, 514 route_t hint, 515 mbuf_t packet) 516{ 517 route_t route = NULL; 518 errno_t result = 0; 519 struct sockaddr_dl *gateway; 520 struct llinfo_arp *llinfo; 521 struct timeval timenow; 522 523 if (net_dest->sin_family != AF_INET) 524 return EAFNOSUPPORT; 525 526 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 527 return ENETDOWN; 528 529 /* 530 * If we were given a route, verify the route and grab the gateway 531 */ 532 if (hint) { 533 result = arp_route_to_gateway_route((const struct sockaddr*)net_dest, 534 hint, &route); 535 if (result != 0) 536 return result; 537 } 538 539 if (packet->m_flags & M_BCAST) { 540 u_long broadcast_len; 541 bzero(ll_dest, ll_dest_len); 542 result = ifnet_llbroadcast_copy_bytes(ifp, LLADDR(ll_dest), ll_dest_len 543 - offsetof(struct sockaddr_dl, 544 sdl_data), &broadcast_len); 545 if (result != 0) { 546 return result; 547 } 548 549 ll_dest->sdl_alen = broadcast_len; 550 ll_dest->sdl_family = AF_LINK; 551 ll_dest->sdl_len = sizeof(struct sockaddr_dl); 552 553 return 0; 554 } 555 if (packet->m_flags & M_MCAST) { 556 return dlil_resolve_multi(ifp, (const struct sockaddr*)net_dest, 557 (struct sockaddr*)ll_dest, ll_dest_len); 558 } 559 560 lck_mtx_lock(rt_mtx); 561 562 /* 563 * If we didn't find a route, or the route doesn't have 564 * link layer information, trigger the creation of the 565 * route and link layer information. 566 */ 567 if (route == NULL || route->rt_llinfo == NULL) 568 result = arp_lookup_route(&net_dest->sin_addr, 1, 0, &route, 569 ifp->if_index); 570 571 if (result || route == NULL || route->rt_llinfo == NULL) { 572 char tmp[MAX_IPv4_STR_LEN]; 573 lck_mtx_unlock(rt_mtx); 574 if (log_arp_warnings) 575 log(LOG_DEBUG, "arpresolve: can't allocate llinfo for %s\n", 576 inet_ntop(AF_INET, &net_dest->sin_addr, tmp, sizeof(tmp))); 577 return result; 578 } 579 580 /* 581 * Now that we have the right route, is it filled in? 582 */ 583 gateway = SDL(route->rt_gateway); 584 getmicrotime(&timenow); 585 if ((route->rt_rmx.rmx_expire == 0 || route->rt_rmx.rmx_expire > timenow.tv_sec) && 586 gateway != NULL && gateway->sdl_family == AF_LINK && gateway->sdl_alen != 0) { 587 bcopy(gateway, ll_dest, MIN(gateway->sdl_len, ll_dest_len)); 588 lck_mtx_unlock(rt_mtx); 589 return 0; 590 } 591 592 /* 593 * Route wasn't complete/valid. We need to arp. 594 */ 595 if (ifp->if_flags & IFF_NOARP) { 596 lck_mtx_unlock(rt_mtx); 597 return ENOTSUP; 598 } 599 600 llinfo = (struct llinfo_arp*)route->rt_llinfo; 601 if (packet) { 602 if (llinfo->la_hold) { 603 m_freem(llinfo->la_hold); 604 } 605 llinfo->la_hold = packet; 606 } 607 608 if (route->rt_rmx.rmx_expire) { 609 route->rt_flags &= ~RTF_REJECT; 610 if (llinfo->la_asked == 0 || route->rt_rmx.rmx_expire != timenow.tv_sec) { 611 route->rt_rmx.rmx_expire = timenow.tv_sec; 612 if (llinfo->la_asked++ < arp_maxtries) { 613 lck_mtx_unlock(rt_mtx); 614 dlil_send_arp(ifp, ARPOP_REQUEST, NULL, route->rt_ifa->ifa_addr, 615 NULL, (const struct sockaddr*)net_dest); 616 return EJUSTRETURN; 617 } 618 else { 619 route->rt_flags |= RTF_REJECT; 620 route->rt_rmx.rmx_expire += arpt_down; 621 llinfo->la_asked = 0; 622 llinfo->la_hold = NULL; 623 lck_mtx_unlock(rt_mtx); 624 return EHOSTUNREACH; 625 } 626 } 627 } 628 lck_mtx_unlock(rt_mtx); 629 630 return EJUSTRETURN; 631} 632 633errno_t 634arp_ip_handle_input( 635 ifnet_t ifp, 636 u_short arpop, 637 const struct sockaddr_dl *sender_hw, 638 const struct sockaddr_in *sender_ip, 639 const struct sockaddr_in *target_ip) 640{ 641 char ipv4str[MAX_IPv4_STR_LEN]; 642 struct sockaddr_dl *gateway; 643 struct in_ifaddr *ia; 644 struct in_ifaddr *best_ia = NULL; 645 route_t route = NULL; 646 char buf[3 * MAX_HW_LEN]; // enough for MAX_HW_LEN byte hw address 647 struct llinfo_arp *llinfo; 648 errno_t error; 649 int created_announcement = 0; 650 651 /* Do not respond to requests for 0.0.0.0 */ 652 if (target_ip->sin_addr.s_addr == 0 && arpop == ARPOP_REQUEST) { 653 return 0; 654 } 655 656 /* 657 * Determine if this ARP is for us 658 */ 659 lck_mtx_lock(rt_mtx); 660 for (ia = in_ifaddrhead.tqh_first; ia; ia = ia->ia_link.tqe_next) { 661 /* do_bridge should be tested here for bridging */ 662 if (ia->ia_ifp == ifp) { 663 best_ia = ia; 664 if (target_ip->sin_addr.s_addr == ia->ia_addr.sin_addr.s_addr || 665 sender_ip->sin_addr.s_addr == ia->ia_addr.sin_addr.s_addr) { 666 break; 667 } 668 } 669 } 670 671 /* If we don't have an IP address on this interface, ignore the packet */ 672 if (best_ia == 0) { 673 lck_mtx_unlock(rt_mtx); 674 return 0; 675 } 676 677 /* If the packet is from this interface, ignore the packet */ 678 if (!bcmp(CONST_LLADDR(sender_hw), ifnet_lladdr(ifp), sender_hw->sdl_len)) { 679 lck_mtx_unlock(rt_mtx); 680 return 0; 681 } 682 683 /* Check for a conflict */ 684 if (sender_ip->sin_addr.s_addr == best_ia->ia_addr.sin_addr.s_addr) { 685 struct kev_msg ev_msg; 686 struct kev_in_collision *in_collision; 687 u_char storage[sizeof(struct kev_in_collision) + MAX_HW_LEN]; 688 in_collision = (struct kev_in_collision*)storage; 689 log(LOG_ERR, "%s%d duplicate IP address %s sent from address %s\n", 690 ifp->if_name, ifp->if_unit, 691 inet_ntop(AF_INET, &sender_ip->sin_addr, ipv4str, sizeof(ipv4str)), 692 sdl_addr_to_hex(sender_hw, buf, sizeof(buf))); 693 694 /* Send a kernel event so anyone can learn of the conflict */ 695 in_collision->link_data.if_family = ifp->if_family; 696 in_collision->link_data.if_unit = ifp->if_unit; 697 strncpy(&in_collision->link_data.if_name[0], ifp->if_name, IFNAMSIZ); 698 in_collision->ia_ipaddr = sender_ip->sin_addr; 699 in_collision->hw_len = sender_hw->sdl_alen < MAX_HW_LEN ? sender_hw->sdl_alen : MAX_HW_LEN; 700 bcopy(CONST_LLADDR(sender_hw), (caddr_t)in_collision->hw_addr, in_collision->hw_len); 701 ev_msg.vendor_code = KEV_VENDOR_APPLE; 702 ev_msg.kev_class = KEV_NETWORK_CLASS; 703 ev_msg.kev_subclass = KEV_INET_SUBCLASS; 704 ev_msg.event_code = KEV_INET_ARPCOLLISION; 705 ev_msg.dv[0].data_ptr = in_collision; 706 ev_msg.dv[0].data_length = sizeof(struct kev_in_collision) + in_collision->hw_len; 707 ev_msg.dv[1].data_length = 0; 708 kev_post_msg(&ev_msg); 709 710 goto respond; 711 } 712 713 /* 714 * Look up the routing entry. If it doesn't exist and we are the 715 * target, and the sender isn't 0.0.0.0, go ahead and create one. 716 */ 717 error = arp_lookup_route(&sender_ip->sin_addr, 718 (target_ip->sin_addr.s_addr == best_ia->ia_addr.sin_addr.s_addr && 719 sender_ip->sin_addr.s_addr != 0), 0, &route, ifp->if_index); 720 if (error || route == 0 || route->rt_gateway == 0) { 721 if (arpop != ARPOP_REQUEST) { 722 goto respond; 723 } 724 if (arp_sendllconflict 725 && send_conflicting_probes != 0 726 && (ifp->if_eflags & IFEF_ARPLL) != 0 727 && IN_LINKLOCAL(ntohl(target_ip->sin_addr.s_addr)) 728 && sender_ip->sin_addr.s_addr == 0) { 729 /* 730 * Verify this ARP probe doesn't conflict with an IPv4LL we know of 731 * on another interface. 732 */ 733 error = arp_lookup_route(&target_ip->sin_addr, 0, 0, 734 &route, ifp->if_index); 735 if (error == 0 && route && route->rt_gateway) { 736 gateway = SDL(route->rt_gateway); 737 if (route->rt_ifp != ifp && gateway->sdl_alen != 0 738 && (gateway->sdl_alen != sender_hw->sdl_alen 739 || bcmp(CONST_LLADDR(gateway), CONST_LLADDR(sender_hw), 740 gateway->sdl_alen) != 0)) { 741 /* 742 * A node is probing for an IPv4LL we know exists on a 743 * different interface. We respond with a conflicting probe 744 * to force the new device to pick a different IPv4LL 745 * address. 746 */ 747 if (log_arp_warnings) { 748 log(LOG_INFO, 749 "arp: %s on %s%d sent probe for %s, already on %s%d\n", 750 sdl_addr_to_hex(sender_hw, buf, sizeof(buf)), 751 ifp->if_name, ifp->if_unit, 752 inet_ntop(AF_INET, &target_ip->sin_addr, ipv4str, 753 sizeof(ipv4str)), 754 route->rt_ifp->if_name, route->rt_ifp->if_unit); 755 log(LOG_INFO, 756 "arp: sending conflicting probe to %s on %s%d\n", 757 sdl_addr_to_hex(sender_hw, buf, sizeof(buf)), 758 ifp->if_name, ifp->if_unit); 759 } 760 /* 761 * Send a conservative unicast "ARP probe". 762 * This should force the other device to pick a new number. 763 * This will not force the device to pick a new number if the device 764 * has already assigned that number. 765 * This will not imply to the device that we own that address. 766 */ 767 dlil_send_arp_internal(ifp, ARPOP_REQUEST, 768 (struct sockaddr_dl*)TAILQ_FIRST(&ifp->if_addrhead)->ifa_addr, 769 (const struct sockaddr*)sender_ip, sender_hw, 770 (const struct sockaddr*)target_ip); 771 } 772 } 773 goto respond; 774 } else if (keep_announcements != 0 775 && target_ip->sin_addr.s_addr == sender_ip->sin_addr.s_addr) { 776 /* don't create entry if link-local address and link-local is disabled */ 777 if (!IN_LINKLOCAL(ntohl(sender_ip->sin_addr.s_addr)) 778 || (ifp->if_eflags & IFEF_ARPLL) != 0) { 779 error = arp_lookup_route(&sender_ip->sin_addr, 780 1, 0, &route, ifp->if_index); 781 if (error == 0 && route != NULL && route->rt_gateway != NULL) { 782 created_announcement = 1; 783 } 784 } 785 if (created_announcement == 0) { 786 goto respond; 787 } 788 } else { 789 goto respond; 790 } 791 } 792 793 gateway = SDL(route->rt_gateway); 794 if (route->rt_ifp != ifp) { 795 if (!IN_LINKLOCAL(ntohl(sender_ip->sin_addr.s_addr)) || (ifp->if_eflags & IFEF_ARPLL) == 0) { 796 if (log_arp_warnings) 797 log(LOG_ERR, "arp: %s is on %s%d but got reply from %s on %s%d\n", 798 inet_ntop(AF_INET, &sender_ip->sin_addr, ipv4str, 799 sizeof(ipv4str)), 800 route->rt_ifp->if_name, 801 route->rt_ifp->if_unit, 802 sdl_addr_to_hex(sender_hw, buf, sizeof(buf)), 803 ifp->if_name, ifp->if_unit); 804 goto respond; 805 } 806 else { 807 /* Don't change a permanent address */ 808 if (route->rt_rmx.rmx_expire == 0) { 809 goto respond; 810 } 811 812 /* 813 * Don't change the cloned route away from the parent's interface 814 * if the address did resolve. 815 */ 816 if (gateway->sdl_alen != 0 && route->rt_parent && 817 route->rt_parent->rt_ifp == route->rt_ifp) { 818 goto respond; 819 } 820 821 /* Change the interface when the existing route is on */ 822 route->rt_ifp = ifp; 823 rtsetifa(route, &best_ia->ia_ifa); 824 gateway->sdl_index = ifp->if_index; 825 } 826 } 827 828 if (gateway->sdl_alen && bcmp(LLADDR(gateway), CONST_LLADDR(sender_hw), gateway->sdl_alen)) { 829 if (route->rt_rmx.rmx_expire && log_arp_warnings) { 830 char buf2[3 * MAX_HW_LEN]; 831 log(LOG_INFO, "arp: %s moved from %s to %s on %s%d\n", 832 inet_ntop(AF_INET, &sender_ip->sin_addr, ipv4str, 833 sizeof(ipv4str)), 834 sdl_addr_to_hex(gateway, buf, sizeof(buf)), 835 sdl_addr_to_hex(sender_hw, buf2, sizeof(buf2)), 836 ifp->if_name, ifp->if_unit); 837 } 838 else if (route->rt_rmx.rmx_expire == 0) { 839 if (log_arp_warnings) { 840 log(LOG_ERR, "arp: %s attempts to modify " 841 "permanent entry for %s on %s%d\n", 842 sdl_addr_to_hex(sender_hw, buf, 843 sizeof(buf)), 844 inet_ntop(AF_INET, &sender_ip->sin_addr, 845 ipv4str, sizeof(ipv4str)), 846 ifp->if_name, ifp->if_unit); 847 } 848 goto respond; 849 } 850 } 851 852 /* Copy the sender hardware address in to the route's gateway address */ 853 gateway->sdl_alen = sender_hw->sdl_alen; 854 bcopy(CONST_LLADDR(sender_hw), LLADDR(gateway), gateway->sdl_alen); 855 856 /* Update the expire time for the route and clear the reject flag */ 857 if (route->rt_rmx.rmx_expire) { 858 struct timeval timenow; 859 860 getmicrotime(&timenow); 861 route->rt_rmx.rmx_expire = timenow.tv_sec + arpt_keep; 862 } 863 route->rt_flags &= ~RTF_REJECT; 864 865 /* update the llinfo, send a queued packet if there is one */ 866 llinfo = (struct llinfo_arp*)route->rt_llinfo; 867 llinfo->la_asked = 0; 868 if (llinfo->la_hold) { 869 struct mbuf *m0; 870 m0 = llinfo->la_hold; 871 llinfo->la_hold = 0; 872 873 /* Should we a reference on the route first? */ 874 lck_mtx_unlock(rt_mtx); 875 dlil_output(ifp, PF_INET, m0, (caddr_t)route, rt_key(route), 0); 876 lck_mtx_lock(rt_mtx); 877 } 878 879respond: 880 if (arpop != ARPOP_REQUEST) { 881 lck_mtx_unlock(rt_mtx); 882 return 0; 883 } 884 885 /* If we are not the target, check if we should proxy */ 886 if (target_ip->sin_addr.s_addr != best_ia->ia_addr.sin_addr.s_addr) { 887 888 /* Find a proxy route */ 889 error = arp_lookup_route(&target_ip->sin_addr, 0, SIN_PROXY, 890 &route, ifp->if_index); 891 if (error || route == NULL) { 892 893 /* We don't have a route entry indicating we should use proxy */ 894 /* If we aren't supposed to proxy all, we are done */ 895 if (!arp_proxyall) { 896 lck_mtx_unlock(rt_mtx); 897 return 0; 898 } 899 900 /* See if we have a route to the target ip before we proxy it */ 901 route = rtalloc1_scoped_locked( 902 (const struct sockaddr *)target_ip, 0, 0, 903 ifp->if_index); 904 if (!route) { 905 lck_mtx_unlock(rt_mtx); 906 return 0; 907 } 908 909 /* 910 * Don't proxy for hosts already on the same interface. 911 */ 912 if (route->rt_ifp == ifp) { 913 rtfree_locked(route); 914 lck_mtx_unlock(rt_mtx); 915 return 0; 916 } 917 } 918 } 919 lck_mtx_unlock(rt_mtx); 920 921 dlil_send_arp(ifp, ARPOP_REPLY, NULL, (const struct sockaddr*)target_ip, 922 sender_hw, (const struct sockaddr*)sender_ip); 923 924 return 0; 925} 926 927void 928arp_ifinit( 929 struct ifnet *ifp, 930 struct ifaddr *ifa) 931{ 932 ifa->ifa_rtrequest = arp_rtrequest; 933 ifa->ifa_flags |= RTF_CLONING; 934 dlil_send_arp(ifp, ARPOP_REQUEST, NULL, ifa->ifa_addr, NULL, ifa->ifa_addr); 935} 936