]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet/in_arp.c
174aa7742ce058975a915bd41fbf47c6101e2d8d
[apple/xnu.git] / bsd / netinet / in_arp.c
1 /*
2 * Copyright (c) 2004-2007 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
85 static const size_t MAX_HW_LEN = 10;
86
87 SYSCTL_DECL(_net_link_ether);
88 SYSCTL_NODE(_net_link_ether, PF_INET, inet, CTLFLAG_RW|CTLFLAG_LOCKED, 0, "");
89
90 /* timer values */
91 static int arpt_prune = (5*60*1); /* walk list every 5 minutes */
92 static int arpt_keep = (20*60); /* once resolved, good for 20 more minutes */
93 static int arpt_down = 20; /* once declared down, don't send for 20 sec */
94
95 /* Apple Hardware SUM16 checksuming */
96 int apple_hwcksum_tx = 1;
97 int apple_hwcksum_rx = 1;
98
99 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, prune_intvl, CTLFLAG_RW,
100 &arpt_prune, 0, "");
101 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, max_age, CTLFLAG_RW,
102 &arpt_keep, 0, "");
103 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, host_down_time, CTLFLAG_RW,
104 &arpt_down, 0, "");
105 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, apple_hwcksum_tx, CTLFLAG_RW,
106 &apple_hwcksum_tx, 0, "");
107 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, apple_hwcksum_rx, CTLFLAG_RW,
108 &apple_hwcksum_rx, 0, "");
109
110 struct 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
117 static LIST_HEAD(, llinfo_arp) llinfo_arp;
118
119 static int arp_inuse, arp_allocated;
120
121 static int arp_maxtries = 5;
122 static int useloopback = 1; /* use loopback interface for local traffic */
123 static int arp_proxyall = 0;
124 static int arp_sendllconflict = 0;
125
126 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, maxtries, CTLFLAG_RW,
127 &arp_maxtries, 0, "");
128 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, useloopback, CTLFLAG_RW,
129 &useloopback, 0, "");
130 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, proxyall, CTLFLAG_RW,
131 &arp_proxyall, 0, "");
132 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, sendllconflict, CTLFLAG_RW,
133 &arp_sendllconflict, 0, "");
134
135 static int log_arp_warnings = 0;
136
137 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, log_arp_warnings, CTLFLAG_RW,
138 &log_arp_warnings, 0,
139 "log arp warning messages");
140
141 static int keep_announcements = 1;
142 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, keep_announcements, CTLFLAG_RW,
143 &keep_announcements, 0,
144 "keep arp announcements");
145
146 static int send_conflicting_probes = 1;
147 SYSCTL_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
151 extern u_int32_t ipv4_ll_arp_aware;
152
153 /*
154 * Free an arp entry.
155 */
156 static void
157 arptfree(
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 */
180 static void
181 arptimer(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 */
203 static void
204 arp_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 */
343 static const char *
344 sdl_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 */
370 static errno_t
371 arp_lookup_route(
372 const struct in_addr *addr,
373 int create,
374 int proxy,
375 route_t *route)
376 {
377 struct sockaddr_inarp sin = {sizeof(sin), AF_INET, 0, {0}, {0}, 0, 0};
378 const char *why = NULL;
379 errno_t error = 0;
380
381 // Caller is responsible for taking the routing lock
382 lck_mtx_assert(rt_mtx, LCK_MTX_ASSERT_OWNED);
383
384 sin.sin_addr.s_addr = addr->s_addr;
385 sin.sin_other = proxy ? SIN_PROXY : 0;
386
387 *route = rtalloc1_locked((struct sockaddr*)&sin, create, 0);
388 if (*route == NULL)
389 return ENETUNREACH;
390
391 rtunref(*route);
392
393 if ((*route)->rt_flags & RTF_GATEWAY) {
394 why = "host is not on local network";
395
396 /* If there are no references to this route, purge it */
397 if ((*route)->rt_refcnt <= 0 && ((*route)->rt_flags & RTF_WASCLONED) != 0) {
398 rtrequest_locked(RTM_DELETE,
399 (struct sockaddr *)rt_key(*route),
400 (*route)->rt_gateway, rt_mask(*route),
401 (*route)->rt_flags, 0);
402 }
403 *route = NULL;
404 error = ENETUNREACH;
405 }
406 else if (((*route)->rt_flags & RTF_LLINFO) == 0) {
407 why = "could not allocate llinfo";
408 *route = NULL;
409 error = ENOMEM;
410 }
411 else if ((*route)->rt_gateway->sa_family != AF_LINK) {
412 why = "gateway route is not ours";
413 *route = NULL;
414 error = EPROTONOSUPPORT;
415 }
416
417 if (why && create && log_arp_warnings) {
418 char tmp[MAX_IPv4_STR_LEN];
419 log(LOG_DEBUG, "arplookup %s failed: %s\n",
420 inet_ntop(AF_INET, addr, tmp, sizeof(tmp)), why);
421 }
422
423 return error;
424 }
425
426
427 __private_extern__ errno_t
428 arp_route_to_gateway_route(
429 const struct sockaddr *net_dest,
430 route_t hint,
431 route_t *out_route);
432 /*
433 * arp_route_to_gateway_route will find the gateway route for a given route.
434 *
435 * If the route is down, look the route up again.
436 * If the route goes through a gateway, get the route to the gateway.
437 * If the gateway route is down, look it up again.
438 * If the route is set to reject, verify it hasn't expired.
439 */
440 __private_extern__ errno_t
441 arp_route_to_gateway_route(
442 const struct sockaddr *net_dest,
443 route_t hint,
444 route_t *out_route)
445 {
446 struct timeval timenow;
447 route_t route = hint;
448 *out_route = NULL;
449
450 /* If we got a hint from the higher layers, check it out */
451 if (route) {
452 lck_mtx_lock(rt_mtx);
453
454 if ((route->rt_flags & RTF_UP) == 0) {
455 /* route is down, find a new one */
456 hint = route = rtalloc1_locked(net_dest, 1, 0);
457 if (hint) {
458 rtunref(hint);
459 }
460 else {
461 /* No route to host */
462 lck_mtx_unlock(rt_mtx);
463 return EHOSTUNREACH;
464 }
465 }
466
467 if (route->rt_flags & RTF_GATEWAY) {
468 /*
469 * We need the gateway route. If it is NULL or down,
470 * look it up.
471 */
472 if (route->rt_gwroute == 0 ||
473 (route->rt_gwroute->rt_flags & RTF_UP) == 0) {
474 if (route->rt_gwroute != 0)
475 rtfree_locked(route->rt_gwroute);
476
477 route->rt_gwroute = rtalloc1_locked(route->rt_gateway, 1, 0);
478 if (route->rt_gwroute == 0) {
479 lck_mtx_unlock(rt_mtx);
480 return EHOSTUNREACH;
481 }
482 }
483
484 route = route->rt_gwroute;
485 }
486
487 if (route->rt_flags & RTF_REJECT) {
488 getmicrotime(&timenow);
489 if (route->rt_rmx.rmx_expire == 0 ||
490 timenow.tv_sec < route->rt_rmx.rmx_expire) {
491 lck_mtx_unlock(rt_mtx);
492 return route == hint ? EHOSTDOWN : EHOSTUNREACH;
493 }
494 }
495
496 lck_mtx_unlock(rt_mtx);
497 }
498
499 *out_route = route;
500 return 0;
501 }
502
503 errno_t
504 arp_lookup_ip(
505 ifnet_t ifp,
506 const struct sockaddr_in *net_dest,
507 struct sockaddr_dl *ll_dest,
508 size_t ll_dest_len,
509 route_t hint,
510 mbuf_t packet)
511 {
512 route_t route = NULL;
513 errno_t result = 0;
514 struct sockaddr_dl *gateway;
515 struct llinfo_arp *llinfo;
516 struct timeval timenow;
517
518 if (net_dest->sin_family != AF_INET)
519 return EAFNOSUPPORT;
520
521 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
522 return ENETDOWN;
523
524 /*
525 * If we were given a route, verify the route and grab the gateway
526 */
527 if (hint) {
528 result = arp_route_to_gateway_route((const struct sockaddr*)net_dest,
529 hint, &route);
530 if (result != 0)
531 return result;
532 }
533
534 if (packet->m_flags & M_BCAST) {
535 u_long broadcast_len;
536 bzero(ll_dest, ll_dest_len);
537 result = ifnet_llbroadcast_copy_bytes(ifp, LLADDR(ll_dest), ll_dest_len
538 - offsetof(struct sockaddr_dl,
539 sdl_data), &broadcast_len);
540 if (result != 0) {
541 return result;
542 }
543
544 ll_dest->sdl_alen = broadcast_len;
545 ll_dest->sdl_family = AF_LINK;
546 ll_dest->sdl_len = sizeof(struct sockaddr_dl);
547
548 return 0;
549 }
550 if (packet->m_flags & M_MCAST) {
551 return dlil_resolve_multi(ifp, (const struct sockaddr*)net_dest,
552 (struct sockaddr*)ll_dest, ll_dest_len);
553 }
554
555 lck_mtx_lock(rt_mtx);
556
557 /*
558 * If we didn't find a route, or the route doesn't have
559 * link layer information, trigger the creation of the
560 * route and link layer information.
561 */
562 if (route == NULL || route->rt_llinfo == NULL)
563 result = arp_lookup_route(&net_dest->sin_addr, 1, 0, &route);
564
565 if (result || route == NULL || route->rt_llinfo == NULL) {
566 char tmp[MAX_IPv4_STR_LEN];
567 lck_mtx_unlock(rt_mtx);
568 if (log_arp_warnings)
569 log(LOG_DEBUG, "arpresolve: can't allocate llinfo for %s\n",
570 inet_ntop(AF_INET, &net_dest->sin_addr, tmp, sizeof(tmp)));
571 return result;
572 }
573
574 /*
575 * Now that we have the right route, is it filled in?
576 */
577 gateway = SDL(route->rt_gateway);
578 getmicrotime(&timenow);
579 if ((route->rt_rmx.rmx_expire == 0 || route->rt_rmx.rmx_expire > timenow.tv_sec) &&
580 gateway != NULL && gateway->sdl_family == AF_LINK && gateway->sdl_alen != 0) {
581 bcopy(gateway, ll_dest, MIN(gateway->sdl_len, ll_dest_len));
582 lck_mtx_unlock(rt_mtx);
583 return 0;
584 }
585
586 /*
587 * Route wasn't complete/valid. We need to arp.
588 */
589 if (ifp->if_flags & IFF_NOARP) {
590 lck_mtx_unlock(rt_mtx);
591 return ENOTSUP;
592 }
593
594 llinfo = (struct llinfo_arp*)route->rt_llinfo;
595 if (packet) {
596 if (llinfo->la_hold) {
597 m_freem(llinfo->la_hold);
598 }
599 llinfo->la_hold = packet;
600 }
601
602 if (route->rt_rmx.rmx_expire) {
603 route->rt_flags &= ~RTF_REJECT;
604 if (llinfo->la_asked == 0 || route->rt_rmx.rmx_expire != timenow.tv_sec) {
605 route->rt_rmx.rmx_expire = timenow.tv_sec;
606 if (llinfo->la_asked++ < arp_maxtries) {
607 lck_mtx_unlock(rt_mtx);
608 dlil_send_arp(ifp, ARPOP_REQUEST, NULL, route->rt_ifa->ifa_addr,
609 NULL, (const struct sockaddr*)net_dest);
610 return EJUSTRETURN;
611 }
612 else {
613 route->rt_flags |= RTF_REJECT;
614 route->rt_rmx.rmx_expire += arpt_down;
615 llinfo->la_asked = 0;
616 llinfo->la_hold = NULL;
617 lck_mtx_unlock(rt_mtx);
618 return EHOSTUNREACH;
619 }
620 }
621 }
622 lck_mtx_unlock(rt_mtx);
623
624 return EJUSTRETURN;
625 }
626
627 errno_t
628 arp_ip_handle_input(
629 ifnet_t ifp,
630 u_short arpop,
631 const struct sockaddr_dl *sender_hw,
632 const struct sockaddr_in *sender_ip,
633 const struct sockaddr_in *target_ip)
634 {
635 char ipv4str[MAX_IPv4_STR_LEN];
636 struct sockaddr_dl *gateway;
637 struct in_ifaddr *ia;
638 struct in_ifaddr *best_ia = NULL;
639 route_t route = NULL;
640 char buf[3 * MAX_HW_LEN]; // enough for MAX_HW_LEN byte hw address
641 struct llinfo_arp *llinfo;
642 errno_t error;
643 int created_announcement = 0;
644
645 /* Do not respond to requests for 0.0.0.0 */
646 if (target_ip->sin_addr.s_addr == 0 && arpop == ARPOP_REQUEST) {
647 return 0;
648 }
649
650 /*
651 * Determine if this ARP is for us
652 */
653 lck_mtx_lock(rt_mtx);
654 for (ia = in_ifaddrhead.tqh_first; ia; ia = ia->ia_link.tqe_next) {
655 /* do_bridge should be tested here for bridging */
656 if (ia->ia_ifp == ifp) {
657 best_ia = ia;
658 if (target_ip->sin_addr.s_addr == ia->ia_addr.sin_addr.s_addr ||
659 sender_ip->sin_addr.s_addr == ia->ia_addr.sin_addr.s_addr) {
660 break;
661 }
662 }
663 }
664
665 /* If we don't have an IP address on this interface, ignore the packet */
666 if (best_ia == 0) {
667 lck_mtx_unlock(rt_mtx);
668 return 0;
669 }
670
671 /* If the packet is from this interface, ignore the packet */
672 if (!bcmp(CONST_LLADDR(sender_hw), ifnet_lladdr(ifp), sender_hw->sdl_len)) {
673 lck_mtx_unlock(rt_mtx);
674 return 0;
675 }
676
677 /* Check for a conflict */
678 if (sender_ip->sin_addr.s_addr == best_ia->ia_addr.sin_addr.s_addr) {
679 struct kev_msg ev_msg;
680 struct kev_in_collision *in_collision;
681 u_char storage[sizeof(struct kev_in_collision) + MAX_HW_LEN];
682 in_collision = (struct kev_in_collision*)storage;
683 log(LOG_ERR, "%s%d duplicate IP address %s sent from address %s\n",
684 ifp->if_name, ifp->if_unit,
685 inet_ntop(AF_INET, &sender_ip->sin_addr, ipv4str, sizeof(ipv4str)),
686 sdl_addr_to_hex(sender_hw, buf, sizeof(buf)));
687
688 /* Send a kernel event so anyone can learn of the conflict */
689 in_collision->link_data.if_family = ifp->if_family;
690 in_collision->link_data.if_unit = ifp->if_unit;
691 strncpy(&in_collision->link_data.if_name[0], ifp->if_name, IFNAMSIZ);
692 in_collision->ia_ipaddr = sender_ip->sin_addr;
693 in_collision->hw_len = sender_hw->sdl_alen < MAX_HW_LEN ? sender_hw->sdl_alen : MAX_HW_LEN;
694 bcopy(CONST_LLADDR(sender_hw), (caddr_t)in_collision->hw_addr, in_collision->hw_len);
695 ev_msg.vendor_code = KEV_VENDOR_APPLE;
696 ev_msg.kev_class = KEV_NETWORK_CLASS;
697 ev_msg.kev_subclass = KEV_INET_SUBCLASS;
698 ev_msg.event_code = KEV_INET_ARPCOLLISION;
699 ev_msg.dv[0].data_ptr = in_collision;
700 ev_msg.dv[0].data_length = sizeof(struct kev_in_collision) + in_collision->hw_len;
701 ev_msg.dv[1].data_length = 0;
702 kev_post_msg(&ev_msg);
703
704 goto respond;
705 }
706
707 /*
708 * Look up the routing entry. If it doesn't exist and we are the
709 * target, go ahead and create one.
710 */
711 error = arp_lookup_route(&sender_ip->sin_addr, (target_ip->sin_addr.s_addr ==
712 best_ia->ia_addr.sin_addr.s_addr), 0, &route);
713 if (error || route == 0 || route->rt_gateway == 0) {
714 if (arpop != ARPOP_REQUEST) {
715 goto respond;
716 }
717 if (arp_sendllconflict
718 && send_conflicting_probes != 0
719 && (ifp->if_eflags & IFEF_ARPLL) != 0
720 && IN_LINKLOCAL(ntohl(target_ip->sin_addr.s_addr))
721 && sender_ip->sin_addr.s_addr == 0) {
722 /*
723 * Verify this ARP probe doesn't conflict with an IPv4LL we know of
724 * on another interface.
725 */
726 error = arp_lookup_route(&target_ip->sin_addr, 0, 0, &route);
727 if (error == 0 && route && route->rt_gateway) {
728 gateway = SDL(route->rt_gateway);
729 if (route->rt_ifp != ifp && gateway->sdl_alen != 0
730 && (gateway->sdl_alen != sender_hw->sdl_alen
731 || bcmp(CONST_LLADDR(gateway), CONST_LLADDR(sender_hw),
732 gateway->sdl_alen) != 0)) {
733 /*
734 * A node is probing for an IPv4LL we know exists on a
735 * different interface. We respond with a conflicting probe
736 * to force the new device to pick a different IPv4LL
737 * address.
738 */
739 if (log_arp_warnings) {
740 log(LOG_INFO,
741 "arp: %s on %s%d sent probe for %s, already on %s%d\n",
742 sdl_addr_to_hex(sender_hw, buf, sizeof(buf)),
743 ifp->if_name, ifp->if_unit,
744 inet_ntop(AF_INET, &target_ip->sin_addr, ipv4str,
745 sizeof(ipv4str)),
746 route->rt_ifp->if_name, route->rt_ifp->if_unit);
747 log(LOG_INFO,
748 "arp: sending conflicting probe to %s on %s%d\n",
749 sdl_addr_to_hex(sender_hw, buf, sizeof(buf)),
750 ifp->if_name, ifp->if_unit);
751 }
752 /*
753 * Send a conservative unicast "ARP probe".
754 * This should force the other device to pick a new number.
755 * This will not force the device to pick a new number if the device
756 * has already assigned that number.
757 * This will not imply to the device that we own that address.
758 */
759 dlil_send_arp_internal(ifp, ARPOP_REQUEST,
760 (struct sockaddr_dl*)TAILQ_FIRST(&ifp->if_addrhead)->ifa_addr,
761 (const struct sockaddr*)sender_ip, sender_hw,
762 (const struct sockaddr*)target_ip);
763 }
764 }
765 goto respond;
766 } else if (keep_announcements != 0
767 && target_ip->sin_addr.s_addr == sender_ip->sin_addr.s_addr) {
768 /* don't create entry if link-local address and link-local is disabled */
769 if (!IN_LINKLOCAL(ntohl(sender_ip->sin_addr.s_addr))
770 || (ifp->if_eflags & IFEF_ARPLL) != 0) {
771 error = arp_lookup_route(&sender_ip->sin_addr, 1, 0, &route);
772 if (error == 0 && route != NULL && route->rt_gateway != NULL) {
773 created_announcement = 1;
774 }
775 }
776 if (created_announcement == 0) {
777 goto respond;
778 }
779 } else {
780 goto respond;
781 }
782 }
783
784 gateway = SDL(route->rt_gateway);
785 if (route->rt_ifp != ifp) {
786 if (!IN_LINKLOCAL(ntohl(sender_ip->sin_addr.s_addr)) || (ifp->if_eflags & IFEF_ARPLL) == 0) {
787 if (log_arp_warnings)
788 log(LOG_ERR, "arp: %s is on %s%d but got reply from %s on %s%d\n",
789 inet_ntop(AF_INET, &sender_ip->sin_addr, ipv4str,
790 sizeof(ipv4str)),
791 route->rt_ifp->if_name,
792 route->rt_ifp->if_unit,
793 sdl_addr_to_hex(sender_hw, buf, sizeof(buf)),
794 ifp->if_name, ifp->if_unit);
795 goto respond;
796 }
797 else {
798 /* Don't change a permanent address */
799 if (route->rt_rmx.rmx_expire == 0) {
800 goto respond;
801 }
802
803 /*
804 * Don't change the cloned route away from the parent's interface
805 * if the address did resolve.
806 */
807 if (gateway->sdl_alen != 0 && route->rt_parent &&
808 route->rt_parent->rt_ifp == route->rt_ifp) {
809 goto respond;
810 }
811
812 /* Change the interface when the existing route is on */
813 route->rt_ifp = ifp;
814 rtsetifa(route, &best_ia->ia_ifa);
815 gateway->sdl_index = ifp->if_index;
816 }
817 }
818
819 if (gateway->sdl_alen && bcmp(LLADDR(gateway), CONST_LLADDR(sender_hw), gateway->sdl_alen)) {
820 if (route->rt_rmx.rmx_expire && log_arp_warnings) {
821 char buf2[3 * MAX_HW_LEN];
822 log(LOG_INFO, "arp: %s moved from %s to %s on %s%d\n",
823 inet_ntop(AF_INET, &sender_ip->sin_addr, ipv4str,
824 sizeof(ipv4str)),
825 sdl_addr_to_hex(gateway, buf, sizeof(buf)),
826 sdl_addr_to_hex(sender_hw, buf2, sizeof(buf2)),
827 ifp->if_name, ifp->if_unit);
828 }
829 else if (route->rt_rmx.rmx_expire == 0) {
830 if (log_arp_warnings) {
831 log(LOG_ERR, "arp: %s attempts to modify "
832 "permanent entry for %s on %s%d\n",
833 sdl_addr_to_hex(sender_hw, buf,
834 sizeof(buf)),
835 inet_ntop(AF_INET, &sender_ip->sin_addr,
836 ipv4str, sizeof(ipv4str)),
837 ifp->if_name, ifp->if_unit);
838 }
839 goto respond;
840 }
841 }
842
843 /* Copy the sender hardware address in to the route's gateway address */
844 gateway->sdl_alen = sender_hw->sdl_alen;
845 bcopy(CONST_LLADDR(sender_hw), LLADDR(gateway), gateway->sdl_alen);
846
847 /* Update the expire time for the route and clear the reject flag */
848 if (route->rt_rmx.rmx_expire) {
849 struct timeval timenow;
850
851 getmicrotime(&timenow);
852 route->rt_rmx.rmx_expire = timenow.tv_sec + arpt_keep;
853 }
854 route->rt_flags &= ~RTF_REJECT;
855
856 /* update the llinfo, send a queued packet if there is one */
857 llinfo = (struct llinfo_arp*)route->rt_llinfo;
858 llinfo->la_asked = 0;
859 if (llinfo->la_hold) {
860 struct mbuf *m0;
861 m0 = llinfo->la_hold;
862 llinfo->la_hold = 0;
863
864 /* Should we a reference on the route first? */
865 lck_mtx_unlock(rt_mtx);
866 dlil_output(ifp, PF_INET, m0, (caddr_t)route, rt_key(route), 0);
867 lck_mtx_lock(rt_mtx);
868 }
869
870 respond:
871 if (arpop != ARPOP_REQUEST) {
872 lck_mtx_unlock(rt_mtx);
873 return 0;
874 }
875
876 /* If we are not the target, check if we should proxy */
877 if (target_ip->sin_addr.s_addr != best_ia->ia_addr.sin_addr.s_addr) {
878
879 /* Find a proxy route */
880 error = arp_lookup_route(&target_ip->sin_addr, 0, SIN_PROXY, &route);
881 if (error || route == NULL) {
882
883 /* We don't have a route entry indicating we should use proxy */
884 /* If we aren't supposed to proxy all, we are done */
885 if (!arp_proxyall) {
886 lck_mtx_unlock(rt_mtx);
887 return 0;
888 }
889
890 /* See if we have a route to the target ip before we proxy it */
891 route = rtalloc1_locked((const struct sockaddr*)target_ip, 0, 0);
892 if (!route) {
893 lck_mtx_unlock(rt_mtx);
894 return 0;
895 }
896
897 /*
898 * Don't proxy for hosts already on the same interface.
899 */
900 if (route->rt_ifp == ifp) {
901 rtfree_locked(route);
902 lck_mtx_unlock(rt_mtx);
903 return 0;
904 }
905 }
906 }
907 lck_mtx_unlock(rt_mtx);
908
909 dlil_send_arp(ifp, ARPOP_REPLY, NULL, (const struct sockaddr*)target_ip,
910 sender_hw, (const struct sockaddr*)sender_ip);
911
912 return 0;
913 }
914
915 void
916 arp_ifinit(
917 struct ifnet *ifp,
918 struct ifaddr *ifa)
919 {
920 ifa->ifa_rtrequest = arp_rtrequest;
921 ifa->ifa_flags |= RTF_CLONING;
922 dlil_send_arp(ifp, ARPOP_REQUEST, NULL, ifa->ifa_addr, NULL, ifa->ifa_addr);
923 }