]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet/in_arp.c
xnu-1228.15.4.tar.gz
[apple/xnu.git] / bsd / netinet / in_arp.c
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
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 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
430 arp_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
443 arp_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
508 errno_t
509 arp_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
633 errno_t
634 arp_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
879 respond:
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
927 void
928 arp_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 }