]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet/in_arp.c
xnu-1486.2.11.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 #include <kern/zalloc.h>
81
82 #define SA(p) ((struct sockaddr *)(p))
83 #define SIN(s) ((struct sockaddr_in *)s)
84 #define CONST_LLADDR(s) ((const u_char*)((s)->sdl_data + (s)->sdl_nlen))
85 #define rt_expire rt_rmx.rmx_expire
86 #define equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0)
87
88 static const size_t MAX_HW_LEN = 10;
89
90 SYSCTL_DECL(_net_link_ether);
91 SYSCTL_NODE(_net_link_ether, PF_INET, inet, CTLFLAG_RW|CTLFLAG_LOCKED, 0, "");
92
93 /* timer values */
94 static int arpt_prune = (5*60*1); /* walk list every 5 minutes */
95 static int arpt_keep = (20*60); /* once resolved, good for 20 more minutes */
96 static int arpt_down = 20; /* once declared down, don't send for 20 sec */
97
98 /* Apple Hardware SUM16 checksuming */
99 int apple_hwcksum_tx = 1;
100 int apple_hwcksum_rx = 1;
101
102 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, prune_intvl, CTLFLAG_RW,
103 &arpt_prune, 0, "");
104 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, max_age, CTLFLAG_RW,
105 &arpt_keep, 0, "");
106 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, host_down_time, CTLFLAG_RW,
107 &arpt_down, 0, "");
108 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, apple_hwcksum_tx, CTLFLAG_RW,
109 &apple_hwcksum_tx, 0, "");
110 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, apple_hwcksum_rx, CTLFLAG_RW,
111 &apple_hwcksum_rx, 0, "");
112
113 struct llinfo_arp {
114 /*
115 * The following are protected by rnh_lock
116 */
117 LIST_ENTRY(llinfo_arp) la_le;
118 struct rtentry *la_rt;
119 /*
120 * The following are protected by rt_lock
121 */
122 struct mbuf *la_hold; /* last packet until resolved/timeout */
123 int32_t la_asked; /* last time we QUERIED for this addr */
124 };
125
126 /*
127 * Synchronization notes:
128 *
129 * The global list of ARP entries are stored in llinfo_arp; an entry
130 * gets inserted into the list when the route is created and gets
131 * removed from the list when it is deleted; this is done as part
132 * of RTM_ADD/RTM_RESOLVE/RTM_DELETE in arp_rtrequest().
133 *
134 * Because rnh_lock and rt_lock for the entry are held during those
135 * operations, the same locks (and thus lock ordering) must be used
136 * elsewhere to access the relevant data structure fields:
137 *
138 * la_le.{le_next,le_prev}, la_rt
139 *
140 * - Routing lock (rnh_lock)
141 *
142 * la_hold, la_asked
143 *
144 * - Routing entry lock (rt_lock)
145 *
146 * Due to the dependency on rt_lock, llinfo_arp has the same lifetime
147 * as the route entry itself. When a route is deleted (RTM_DELETE),
148 * it is simply removed from the global list but the memory is not
149 * freed until the route itself is freed.
150 */
151 static LIST_HEAD(, llinfo_arp) llinfo_arp;
152
153 static int arp_inuse, arp_allocated;
154
155 static int arp_maxtries = 5;
156 static int useloopback = 1; /* use loopback interface for local traffic */
157 static int arp_proxyall = 0;
158 static int arp_sendllconflict = 0;
159
160 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, maxtries, CTLFLAG_RW,
161 &arp_maxtries, 0, "");
162 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, useloopback, CTLFLAG_RW,
163 &useloopback, 0, "");
164 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, proxyall, CTLFLAG_RW,
165 &arp_proxyall, 0, "");
166 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, sendllconflict, CTLFLAG_RW,
167 &arp_sendllconflict, 0, "");
168
169 static int log_arp_warnings = 0;
170
171 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, log_arp_warnings, CTLFLAG_RW,
172 &log_arp_warnings, 0,
173 "log arp warning messages");
174
175 static int keep_announcements = 1;
176 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, keep_announcements, CTLFLAG_RW,
177 &keep_announcements, 0,
178 "keep arp announcements");
179
180 static int send_conflicting_probes = 1;
181 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, send_conflicting_probes, CTLFLAG_RW,
182 &send_conflicting_probes, 0,
183 "send conflicting link-local arp probes");
184
185 static errno_t arp_lookup_route(const struct in_addr *, int,
186 int, route_t *, unsigned int);
187 static void arptimer(void *);
188 static struct llinfo_arp *arp_llinfo_alloc(void);
189 static void arp_llinfo_free(void *);
190
191 extern u_int32_t ipv4_ll_arp_aware;
192
193 static int arpinit_done;
194
195 static struct zone *llinfo_arp_zone;
196 #define LLINFO_ARP_ZONE_MAX 256 /* maximum elements in zone */
197 #define LLINFO_ARP_ZONE_NAME "llinfo_arp" /* name for zone */
198
199 void
200 arp_init(void)
201 {
202 if (arpinit_done) {
203 log(LOG_NOTICE, "arp_init called more than once (ignored)\n");
204 return;
205 }
206
207 LIST_INIT(&llinfo_arp);
208
209 llinfo_arp_zone = zinit(sizeof (struct llinfo_arp),
210 LLINFO_ARP_ZONE_MAX * sizeof (struct llinfo_arp), 0,
211 LLINFO_ARP_ZONE_NAME);
212 if (llinfo_arp_zone == NULL)
213 panic("%s: failed allocating llinfo_arp_zone", __func__);
214
215 zone_change(llinfo_arp_zone, Z_EXPAND, TRUE);
216
217 arpinit_done = 1;
218
219 /* start timer */
220 timeout(arptimer, (caddr_t)0, hz);
221 }
222
223 static struct llinfo_arp *
224 arp_llinfo_alloc(void)
225 {
226 return (zalloc(llinfo_arp_zone));
227 }
228
229 static void
230 arp_llinfo_free(void *arg)
231 {
232 struct llinfo_arp *la = arg;
233
234 if (la->la_le.le_next != NULL || la->la_le.le_prev != NULL) {
235 panic("%s: trying to free %p when it is in use", __func__, la);
236 /* NOTREACHED */
237 }
238
239 /* Just in case there's anything there, free it */
240 if (la->la_hold != NULL) {
241 m_freem(la->la_hold);
242 la->la_hold = NULL;
243 }
244
245 zfree(llinfo_arp_zone, la);
246 }
247
248 /*
249 * Free an arp entry.
250 */
251 static void
252 arptfree(struct llinfo_arp *la)
253 {
254 struct rtentry *rt = la->la_rt;
255 struct sockaddr_dl *sdl;
256
257 lck_mtx_assert(rnh_lock, LCK_MTX_ASSERT_OWNED);
258 RT_LOCK_ASSERT_HELD(rt);
259
260 if (rt->rt_refcnt > 0 && (sdl = SDL(rt->rt_gateway)) &&
261 sdl->sdl_family == AF_LINK) {
262 sdl->sdl_alen = 0;
263 la->la_asked = 0;
264 rt->rt_flags &= ~RTF_REJECT;
265 RT_UNLOCK(rt);
266 } else {
267 /*
268 * Safe to drop rt_lock and use rt_key, since holding
269 * rnh_lock here prevents another thread from calling
270 * rt_setgate() on this route.
271 */
272 RT_UNLOCK(rt);
273 rtrequest_locked(RTM_DELETE, rt_key(rt), NULL, rt_mask(rt),
274 0, NULL);
275 }
276 }
277
278 /*
279 * Timeout routine. Age arp_tab entries periodically.
280 */
281 /* ARGSUSED */
282 static void
283 arptimer(void *ignored_arg)
284 {
285 #pragma unused (ignored_arg)
286 struct llinfo_arp *la, *ola;
287 struct timeval timenow;
288
289 lck_mtx_lock(rnh_lock);
290 la = llinfo_arp.lh_first;
291 getmicrotime(&timenow);
292 while ((ola = la) != 0) {
293 struct rtentry *rt = la->la_rt;
294 la = la->la_le.le_next;
295 RT_LOCK(rt);
296 if (rt->rt_expire && rt->rt_expire <= timenow.tv_sec)
297 arptfree(ola); /* timer has expired, clear */
298 else
299 RT_UNLOCK(rt);
300 }
301 lck_mtx_unlock(rnh_lock);
302 timeout(arptimer, (caddr_t)0, arpt_prune * hz);
303 }
304
305 /*
306 * Parallel to llc_rtrequest.
307 */
308 static void
309 arp_rtrequest(
310 int req,
311 struct rtentry *rt,
312 __unused struct sockaddr *sa)
313 {
314 struct sockaddr *gate = rt->rt_gateway;
315 struct llinfo_arp *la = rt->rt_llinfo;
316 static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK, 0, 0, 0, 0, 0, {0}};
317 struct timeval timenow;
318
319 if (!arpinit_done) {
320 panic("%s: ARP has not been initialized", __func__);
321 /* NOTREACHED */
322 }
323 lck_mtx_assert(rnh_lock, LCK_MTX_ASSERT_OWNED);
324 RT_LOCK_ASSERT_HELD(rt);
325
326 if (rt->rt_flags & RTF_GATEWAY)
327 return;
328 getmicrotime(&timenow);
329 switch (req) {
330
331 case RTM_ADD:
332 /*
333 * XXX: If this is a manually added route to interface
334 * such as older version of routed or gated might provide,
335 * restore cloning bit.
336 */
337 if ((rt->rt_flags & RTF_HOST) == 0 &&
338 SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff)
339 rt->rt_flags |= RTF_CLONING;
340 if (rt->rt_flags & RTF_CLONING) {
341 /*
342 * Case 1: This route should come from a route to iface.
343 */
344 if (rt_setgate(rt, rt_key(rt),
345 (struct sockaddr *)&null_sdl) == 0) {
346 gate = rt->rt_gateway;
347 SDL(gate)->sdl_type = rt->rt_ifp->if_type;
348 SDL(gate)->sdl_index = rt->rt_ifp->if_index;
349 /*
350 * In case we're called before 1.0 sec.
351 * has elapsed.
352 */
353 rt->rt_expire = MAX(timenow.tv_sec, 1);
354 }
355 break;
356 }
357 /* Announce a new entry if requested. */
358 if (rt->rt_flags & RTF_ANNOUNCE) {
359 RT_UNLOCK(rt);
360 dlil_send_arp(rt->rt_ifp, ARPOP_REQUEST,
361 SDL(gate), rt_key(rt), NULL, rt_key(rt));
362 RT_LOCK(rt);
363 }
364 /*FALLTHROUGH*/
365 case RTM_RESOLVE:
366 if (gate->sa_family != AF_LINK ||
367 gate->sa_len < sizeof(null_sdl)) {
368 if (log_arp_warnings)
369 log(LOG_DEBUG, "arp_rtrequest: bad gateway value\n");
370 break;
371 }
372 SDL(gate)->sdl_type = rt->rt_ifp->if_type;
373 SDL(gate)->sdl_index = rt->rt_ifp->if_index;
374 if (la != 0)
375 break; /* This happens on a route change */
376 /*
377 * Case 2: This route may come from cloning, or a manual route
378 * add with a LL address.
379 */
380 rt->rt_llinfo = la = arp_llinfo_alloc();
381 if (la == NULL) {
382 if (log_arp_warnings)
383 log(LOG_DEBUG, "%s: malloc failed\n", __func__);
384 break;
385 }
386 rt->rt_llinfo_free = arp_llinfo_free;
387
388 arp_inuse++, arp_allocated++;
389 Bzero(la, sizeof(*la));
390 la->la_rt = rt;
391 rt->rt_flags |= RTF_LLINFO;
392 LIST_INSERT_HEAD(&llinfo_arp, la, la_le);
393
394 /*
395 * This keeps the multicast addresses from showing up
396 * in `arp -a' listings as unresolved. It's not actually
397 * functional. Then the same for broadcast.
398 */
399 if (IN_MULTICAST(ntohl(SIN(rt_key(rt))->sin_addr.s_addr))) {
400 RT_UNLOCK(rt);
401 dlil_resolve_multi(rt->rt_ifp, rt_key(rt), gate,
402 sizeof(struct sockaddr_dl));
403 RT_LOCK(rt);
404 rt->rt_expire = 0;
405 }
406 else if (in_broadcast(SIN(rt_key(rt))->sin_addr, rt->rt_ifp)) {
407 struct sockaddr_dl *gate_ll = SDL(gate);
408 size_t broadcast_len;
409 ifnet_llbroadcast_copy_bytes(rt->rt_ifp,
410 LLADDR(gate_ll), sizeof(gate_ll->sdl_data),
411 &broadcast_len);
412 gate_ll->sdl_alen = broadcast_len;
413 gate_ll->sdl_family = AF_LINK;
414 gate_ll->sdl_len = sizeof(struct sockaddr_dl);
415 /* In case we're called before 1.0 sec. has elapsed */
416 rt->rt_expire = MAX(timenow.tv_sec, 1);
417 }
418
419 if (SIN(rt_key(rt))->sin_addr.s_addr ==
420 (IA_SIN(rt->rt_ifa))->sin_addr.s_addr) {
421 /*
422 * This test used to be
423 * if (loif.if_flags & IFF_UP)
424 * It allowed local traffic to be forced
425 * through the hardware by configuring the loopback down.
426 * However, it causes problems during network configuration
427 * for boards that can't receive packets they send.
428 * It is now necessary to clear "useloopback" and remove
429 * the route to force traffic out to the hardware.
430 */
431 rt->rt_expire = 0;
432 ifnet_lladdr_copy_bytes(rt->rt_ifp, LLADDR(SDL(gate)), SDL(gate)->sdl_alen = 6);
433 if (useloopback)
434 rt->rt_ifp = lo_ifp;
435
436 }
437 break;
438
439 case RTM_DELETE:
440 if (la == 0)
441 break;
442 arp_inuse--;
443 /*
444 * Unchain it but defer the actual freeing until the route
445 * itself is to be freed. rt->rt_llinfo still points to
446 * llinfo_arp, and likewise, la->la_rt still points to this
447 * route entry, except that RTF_LLINFO is now cleared.
448 */
449 LIST_REMOVE(la, la_le);
450 la->la_le.le_next = NULL;
451 la->la_le.le_prev = NULL;
452 rt->rt_flags &= ~RTF_LLINFO;
453 if (la->la_hold != NULL)
454 m_freem(la->la_hold);
455 la->la_hold = NULL;
456 }
457 }
458
459 /*
460 * convert hardware address to hex string for logging errors.
461 */
462 static const char *
463 sdl_addr_to_hex(const struct sockaddr_dl *sdl, char * orig_buf, int buflen)
464 {
465 char * buf = orig_buf;
466 int i;
467 const u_char * lladdr = (u_char *)(size_t)sdl->sdl_data;
468 int maxbytes = buflen / 3;
469
470 if (maxbytes > sdl->sdl_alen) {
471 maxbytes = sdl->sdl_alen;
472 }
473 *buf = '\0';
474 for (i = 0; i < maxbytes; i++) {
475 snprintf(buf, 3, "%02x", lladdr[i]);
476 buf += 2;
477 *buf = (i == maxbytes - 1) ? '\0' : ':';
478 buf++;
479 }
480 return (orig_buf);
481 }
482
483 /*
484 * arp_lookup_route will lookup the route for a given address.
485 *
486 * The address must be for a host on a local network on this interface.
487 * If the returned route is non-NULL, the route is locked and the caller
488 * is responsible for unlocking it and releasing its reference.
489 */
490 static errno_t
491 arp_lookup_route(const struct in_addr *addr, int create, int proxy,
492 route_t *route, unsigned int ifscope)
493 {
494 struct sockaddr_inarp sin = {sizeof(sin), AF_INET, 0, {0}, {0}, 0, 0};
495 const char *why = NULL;
496 errno_t error = 0;
497 route_t rt;
498
499 *route = NULL;
500
501 sin.sin_addr.s_addr = addr->s_addr;
502 sin.sin_other = proxy ? SIN_PROXY : 0;
503
504 rt = rtalloc1_scoped((struct sockaddr*)&sin, create, 0, ifscope);
505 if (rt == NULL)
506 return (ENETUNREACH);
507
508 RT_LOCK(rt);
509
510 if (rt->rt_flags & RTF_GATEWAY) {
511 why = "host is not on local network";
512 error = ENETUNREACH;
513 } else if (!(rt->rt_flags & RTF_LLINFO)) {
514 why = "could not allocate llinfo";
515 error = ENOMEM;
516 } else if (rt->rt_gateway->sa_family != AF_LINK) {
517 why = "gateway route is not ours";
518 error = EPROTONOSUPPORT;
519 }
520
521 if (error != 0) {
522 if (create && log_arp_warnings) {
523 char tmp[MAX_IPv4_STR_LEN];
524 log(LOG_DEBUG, "arplookup link#%d %s failed: %s\n",
525 ifscope, inet_ntop(AF_INET, addr, tmp,
526 sizeof (tmp)), why);
527 }
528
529 /*
530 * If there are no references to this route, and it is
531 * a cloned route, and not static, and ARP had created
532 * the route, then purge it from the routing table as
533 * it is probably bogus.
534 */
535 if (rt->rt_refcnt == 1 &&
536 (rt->rt_flags & (RTF_WASCLONED | RTF_STATIC)) ==
537 RTF_WASCLONED) {
538 /*
539 * Prevent another thread from modiying rt_key,
540 * rt_gateway via rt_setgate() after rt_lock is
541 * dropped by marking the route as defunct.
542 */
543 rt->rt_flags |= RTF_CONDEMNED;
544 RT_UNLOCK(rt);
545 rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway,
546 rt_mask(rt), rt->rt_flags, 0);
547 rtfree(rt);
548 } else {
549 RT_REMREF_LOCKED(rt);
550 RT_UNLOCK(rt);
551 }
552 return (error);
553 }
554
555 /*
556 * Caller releases reference and does RT_UNLOCK(rt).
557 */
558 *route = rt;
559 return (0);
560 }
561
562 /*
563 * arp_route_to_gateway_route will find the gateway route for a given route.
564 *
565 * If the route is down, look the route up again.
566 * If the route goes through a gateway, get the route to the gateway.
567 * If the gateway route is down, look it up again.
568 * If the route is set to reject, verify it hasn't expired.
569 *
570 * If the returned route is non-NULL, the caller is responsible for
571 * releasing the reference and unlocking the route.
572 */
573 #define senderr(e) { error = (e); goto bad; }
574 __private_extern__ errno_t
575 arp_route_to_gateway_route(const struct sockaddr *net_dest, route_t hint0,
576 route_t *out_route)
577 {
578 struct timeval timenow;
579 route_t rt = hint0, hint = hint0;
580 errno_t error = 0;
581
582 *out_route = NULL;
583
584 /*
585 * Next hop determination. Because we may involve the gateway route
586 * in addition to the original route, locking is rather complicated.
587 * The general concept is that regardless of whether the route points
588 * to the original route or to the gateway route, this routine takes
589 * an extra reference on such a route. This extra reference will be
590 * released at the end.
591 *
592 * Care must be taken to ensure that the "hint0" route never gets freed
593 * via rtfree(), since the caller may have stored it inside a struct
594 * route with a reference held for that placeholder.
595 */
596 if (rt != NULL) {
597 unsigned int ifindex;
598
599 RT_LOCK_SPIN(rt);
600 ifindex = rt->rt_ifp->if_index;
601 RT_ADDREF_LOCKED(rt);
602 if (!(rt->rt_flags & RTF_UP)) {
603 RT_REMREF_LOCKED(rt);
604 RT_UNLOCK(rt);
605 /* route is down, find a new one */
606 hint = rt = rtalloc1_scoped((struct sockaddr *)
607 (size_t)net_dest, 1, 0, ifindex);
608 if (hint != NULL) {
609 RT_LOCK_SPIN(rt);
610 ifindex = rt->rt_ifp->if_index;
611 } else {
612 senderr(EHOSTUNREACH);
613 }
614 }
615
616 /*
617 * We have a reference to "rt" by now; it will either
618 * be released or freed at the end of this routine.
619 */
620 RT_LOCK_ASSERT_HELD(rt);
621 if (rt->rt_flags & RTF_GATEWAY) {
622 struct rtentry *gwrt = rt->rt_gwroute;
623 struct sockaddr_in gw;
624
625 /* If there's no gateway rt, look it up */
626 if (gwrt == NULL) {
627 gw = *((struct sockaddr_in *)rt->rt_gateway);
628 RT_UNLOCK(rt);
629 goto lookup;
630 }
631 /* Become a regular mutex */
632 RT_CONVERT_LOCK(rt);
633
634 /*
635 * Take gwrt's lock while holding route's lock;
636 * this is okay since gwrt never points back
637 * to "rt", so no lock ordering issues.
638 */
639 RT_LOCK_SPIN(gwrt);
640 if (!(gwrt->rt_flags & RTF_UP)) {
641 struct rtentry *ogwrt;
642
643 rt->rt_gwroute = NULL;
644 RT_UNLOCK(gwrt);
645 gw = *((struct sockaddr_in *)rt->rt_gateway);
646 RT_UNLOCK(rt);
647 rtfree(gwrt);
648 lookup:
649 gwrt = rtalloc1_scoped(
650 (struct sockaddr *)&gw, 1, 0, ifindex);
651
652 RT_LOCK(rt);
653 /*
654 * Bail out if the route is down, no route
655 * to gateway, circular route, or if the
656 * gateway portion of "rt" has changed.
657 */
658 if (!(rt->rt_flags & RTF_UP) ||
659 gwrt == NULL || gwrt == rt ||
660 !equal(SA(&gw), rt->rt_gateway)) {
661 if (gwrt == rt) {
662 RT_REMREF_LOCKED(gwrt);
663 gwrt = NULL;
664 }
665 RT_UNLOCK(rt);
666 if (gwrt != NULL)
667 rtfree(gwrt);
668 senderr(EHOSTUNREACH);
669 }
670
671 /* Remove any existing gwrt */
672 ogwrt = rt->rt_gwroute;
673 if ((rt->rt_gwroute = gwrt) != NULL)
674 RT_ADDREF(gwrt);
675
676 /* Clean up "rt" now while we can */
677 if (rt == hint0) {
678 RT_REMREF_LOCKED(rt);
679 RT_UNLOCK(rt);
680 } else {
681 RT_UNLOCK(rt);
682 rtfree(rt);
683 }
684 rt = gwrt;
685 /* Now free the replaced gwrt */
686 if (ogwrt != NULL)
687 rtfree(ogwrt);
688 /* If still no route to gateway, bail out */
689 if (rt == NULL)
690 senderr(EHOSTUNREACH);
691 } else {
692 RT_ADDREF_LOCKED(gwrt);
693 RT_UNLOCK(gwrt);
694 /* Clean up "rt" now while we can */
695 if (rt == hint0) {
696 RT_REMREF_LOCKED(rt);
697 RT_UNLOCK(rt);
698 } else {
699 RT_UNLOCK(rt);
700 rtfree(rt);
701 }
702 rt = gwrt;
703 }
704
705 /* rt == gwrt; if it is now down, give up */
706 RT_LOCK_SPIN(rt);
707 if (!(rt->rt_flags & RTF_UP)) {
708 RT_UNLOCK(rt);
709 senderr(EHOSTUNREACH);
710 }
711 }
712
713 if (rt->rt_flags & RTF_REJECT) {
714 getmicrotime(&timenow);
715 if (rt->rt_rmx.rmx_expire == 0 ||
716 timenow.tv_sec < rt->rt_rmx.rmx_expire) {
717 RT_UNLOCK(rt);
718 senderr(rt == hint ? EHOSTDOWN : EHOSTUNREACH);
719 }
720 }
721
722 /* Become a regular mutex */
723 RT_CONVERT_LOCK(rt);
724
725 /* Caller is responsible for cleaning up "rt" */
726 *out_route = rt;
727 }
728 return (0);
729
730 bad:
731 /* Clean up route (either it is "rt" or "gwrt") */
732 if (rt != NULL) {
733 RT_LOCK_SPIN(rt);
734 if (rt == hint0) {
735 RT_REMREF_LOCKED(rt);
736 RT_UNLOCK(rt);
737 } else {
738 RT_UNLOCK(rt);
739 rtfree(rt);
740 }
741 }
742 return (error);
743 }
744 #undef senderr
745
746 /*
747 * This is the ARP pre-output routine; care must be taken to ensure that
748 * the "hint" route never gets freed via rtfree(), since the caller may
749 * have stored it inside a struct route with a reference held for that
750 * placeholder.
751 */
752 errno_t
753 arp_lookup_ip(ifnet_t ifp, const struct sockaddr_in *net_dest,
754 struct sockaddr_dl *ll_dest, size_t ll_dest_len, route_t hint,
755 mbuf_t packet)
756 {
757 route_t route = NULL; /* output route */
758 errno_t result = 0;
759 struct sockaddr_dl *gateway;
760 struct llinfo_arp *llinfo;
761 struct timeval timenow;
762
763 if (net_dest->sin_family != AF_INET)
764 return (EAFNOSUPPORT);
765
766 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
767 return (ENETDOWN);
768
769 /*
770 * If we were given a route, verify the route and grab the gateway
771 */
772 if (hint != NULL) {
773 /*
774 * Callee holds a reference on the route and returns
775 * with the route entry locked, upon success.
776 */
777 result = arp_route_to_gateway_route((const struct sockaddr*)
778 net_dest, hint, &route);
779 if (result != 0)
780 return (result);
781 if (route != NULL)
782 RT_LOCK_ASSERT_HELD(route);
783 }
784
785 if (packet->m_flags & M_BCAST) {
786 size_t broadcast_len;
787 bzero(ll_dest, ll_dest_len);
788 result = ifnet_llbroadcast_copy_bytes(ifp, LLADDR(ll_dest),
789 ll_dest_len - offsetof(struct sockaddr_dl, sdl_data),
790 &broadcast_len);
791 if (result == 0) {
792 ll_dest->sdl_alen = broadcast_len;
793 ll_dest->sdl_family = AF_LINK;
794 ll_dest->sdl_len = sizeof(struct sockaddr_dl);
795 }
796 goto release;
797 }
798 if (packet->m_flags & M_MCAST) {
799 if (route != NULL)
800 RT_UNLOCK(route);
801 result = dlil_resolve_multi(ifp,
802 (const struct sockaddr*)net_dest,
803 (struct sockaddr*)ll_dest, ll_dest_len);
804 if (route != NULL)
805 RT_LOCK(route);
806 goto release;
807 }
808
809 /*
810 * If we didn't find a route, or the route doesn't have
811 * link layer information, trigger the creation of the
812 * route and link layer information.
813 */
814 if (route == NULL || route->rt_llinfo == NULL) {
815 /* Clean up now while we can */
816 if (route != NULL) {
817 if (route == hint) {
818 RT_REMREF_LOCKED(route);
819 RT_UNLOCK(route);
820 } else {
821 RT_UNLOCK(route);
822 rtfree(route);
823 }
824 }
825 /*
826 * Callee holds a reference on the route and returns
827 * with the route entry locked, upon success.
828 */
829 result = arp_lookup_route(&net_dest->sin_addr, 1, 0, &route,
830 ifp->if_index);
831 if (result == 0)
832 RT_LOCK_ASSERT_HELD(route);
833 }
834
835 if (result || route == NULL || route->rt_llinfo == NULL) {
836 char tmp[MAX_IPv4_STR_LEN];
837
838 /* In case result is 0 but no route, return an error */
839 if (result == 0)
840 result = EHOSTUNREACH;
841
842 if (log_arp_warnings &&
843 route != NULL && route->rt_llinfo == NULL)
844 log(LOG_DEBUG, "arpresolve: can't allocate llinfo "
845 "for %s\n", inet_ntop(AF_INET, &net_dest->sin_addr,
846 tmp, sizeof(tmp)));
847 goto release;
848 }
849
850 /*
851 * Now that we have the right route, is it filled in?
852 */
853 gateway = SDL(route->rt_gateway);
854 getmicrotime(&timenow);
855 if ((route->rt_rmx.rmx_expire == 0 ||
856 route->rt_rmx.rmx_expire > timenow.tv_sec) && gateway != NULL &&
857 gateway->sdl_family == AF_LINK && gateway->sdl_alen != 0) {
858 bcopy(gateway, ll_dest, MIN(gateway->sdl_len, ll_dest_len));
859 result = 0;
860 goto release;
861 }
862
863 if (ifp->if_flags & IFF_NOARP) {
864 result = ENOTSUP;
865 goto release;
866 }
867
868 /*
869 * Route wasn't complete/valid. We need to arp.
870 */
871 llinfo = route->rt_llinfo;
872 if (packet != NULL) {
873 if (llinfo->la_hold != NULL)
874 m_freem(llinfo->la_hold);
875 llinfo->la_hold = packet;
876 }
877
878 if (route->rt_rmx.rmx_expire) {
879 route->rt_flags &= ~RTF_REJECT;
880 if (llinfo->la_asked == 0 ||
881 route->rt_rmx.rmx_expire != timenow.tv_sec) {
882 route->rt_rmx.rmx_expire = timenow.tv_sec;
883 if (llinfo->la_asked++ < arp_maxtries) {
884 struct ifaddr *rt_ifa = route->rt_ifa;
885 ifaref(rt_ifa);
886 RT_UNLOCK(route);
887 dlil_send_arp(ifp, ARPOP_REQUEST, NULL,
888 rt_ifa->ifa_addr, NULL,
889 (const struct sockaddr*)net_dest);
890 ifafree(rt_ifa);
891 RT_LOCK(route);
892 result = EJUSTRETURN;
893 goto release;
894 } else {
895 route->rt_flags |= RTF_REJECT;
896 route->rt_rmx.rmx_expire += arpt_down;
897 llinfo->la_asked = 0;
898 llinfo->la_hold = NULL;
899 result = EHOSTUNREACH;
900 goto release;
901 }
902 }
903 }
904
905 /* The packet is now held inside la_hold (can "packet" be NULL?) */
906 result = EJUSTRETURN;
907
908 release:
909 if (route != NULL) {
910 if (route == hint) {
911 RT_REMREF_LOCKED(route);
912 RT_UNLOCK(route);
913 } else {
914 RT_UNLOCK(route);
915 rtfree(route);
916 }
917 }
918 return (result);
919 }
920
921 errno_t
922 arp_ip_handle_input(
923 ifnet_t ifp,
924 u_short arpop,
925 const struct sockaddr_dl *sender_hw,
926 const struct sockaddr_in *sender_ip,
927 const struct sockaddr_in *target_ip)
928 {
929 char ipv4str[MAX_IPv4_STR_LEN];
930 struct sockaddr_dl proxied;
931 struct sockaddr_dl *gateway, *target_hw = NULL;
932 struct ifaddr *ifa;
933 struct in_ifaddr *ia;
934 struct in_ifaddr *best_ia = NULL;
935 route_t route = NULL;
936 char buf[3 * MAX_HW_LEN]; // enough for MAX_HW_LEN byte hw address
937 struct llinfo_arp *llinfo;
938 errno_t error;
939 int created_announcement = 0;
940
941 /* Do not respond to requests for 0.0.0.0 */
942 if (target_ip->sin_addr.s_addr == 0 && arpop == ARPOP_REQUEST)
943 goto done;
944
945 /*
946 * Determine if this ARP is for us
947 */
948 lck_rw_lock_shared(in_ifaddr_rwlock);
949 TAILQ_FOREACH(ia, INADDR_HASH(target_ip->sin_addr.s_addr), ia_hash) {
950 /* do_bridge should be tested here for bridging */
951 if (ia->ia_ifp == ifp &&
952 ia->ia_addr.sin_addr.s_addr == target_ip->sin_addr.s_addr) {
953 best_ia = ia;
954 ifaref(&best_ia->ia_ifa);
955 lck_rw_done(in_ifaddr_rwlock);
956 goto match;
957 }
958 }
959
960 TAILQ_FOREACH(ia, INADDR_HASH(sender_ip->sin_addr.s_addr), ia_hash) {
961 /* do_bridge should be tested here for bridging */
962 if (ia->ia_ifp == ifp &&
963 ia->ia_addr.sin_addr.s_addr == sender_ip->sin_addr.s_addr) {
964 best_ia = ia;
965 ifaref(&best_ia->ia_ifa);
966 lck_rw_done(in_ifaddr_rwlock);
967 goto match;
968 }
969 }
970 lck_rw_done(in_ifaddr_rwlock);
971
972 /*
973 * No match, use the first inet address on the receive interface
974 * as a dummy address for the rest of the function; we may be
975 * proxying for another address.
976 */
977 ifnet_lock_shared(ifp);
978 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
979 if (ifa->ifa_addr->sa_family != AF_INET)
980 continue;
981 best_ia = (struct in_ifaddr *)ifa;
982 ifaref(&best_ia->ia_ifa);
983 break;
984 }
985 ifnet_lock_done(ifp);
986
987 /* If we don't have an IP address on this interface, ignore the packet */
988 if (best_ia == NULL)
989 goto done;
990
991 match:
992 /* If the packet is from this interface, ignore the packet */
993 if (!bcmp(CONST_LLADDR(sender_hw), ifnet_lladdr(ifp), sender_hw->sdl_len)) {
994 goto done;
995 }
996
997 /* Check for a conflict */
998 if (sender_ip->sin_addr.s_addr == best_ia->ia_addr.sin_addr.s_addr) {
999 struct kev_msg ev_msg;
1000 struct kev_in_collision *in_collision;
1001 u_char storage[sizeof(struct kev_in_collision) + MAX_HW_LEN];
1002 in_collision = (struct kev_in_collision*)storage;
1003 log(LOG_ERR, "%s%d duplicate IP address %s sent from address %s\n",
1004 ifp->if_name, ifp->if_unit,
1005 inet_ntop(AF_INET, &sender_ip->sin_addr, ipv4str, sizeof(ipv4str)),
1006 sdl_addr_to_hex(sender_hw, buf, sizeof(buf)));
1007
1008 /* Send a kernel event so anyone can learn of the conflict */
1009 in_collision->link_data.if_family = ifp->if_family;
1010 in_collision->link_data.if_unit = ifp->if_unit;
1011 strncpy(&in_collision->link_data.if_name[0], ifp->if_name, IFNAMSIZ);
1012 in_collision->ia_ipaddr = sender_ip->sin_addr;
1013 in_collision->hw_len = sender_hw->sdl_alen < MAX_HW_LEN ? sender_hw->sdl_alen : MAX_HW_LEN;
1014 bcopy(CONST_LLADDR(sender_hw), (caddr_t)in_collision->hw_addr, in_collision->hw_len);
1015 ev_msg.vendor_code = KEV_VENDOR_APPLE;
1016 ev_msg.kev_class = KEV_NETWORK_CLASS;
1017 ev_msg.kev_subclass = KEV_INET_SUBCLASS;
1018 ev_msg.event_code = KEV_INET_ARPCOLLISION;
1019 ev_msg.dv[0].data_ptr = in_collision;
1020 ev_msg.dv[0].data_length = sizeof(struct kev_in_collision) + in_collision->hw_len;
1021 ev_msg.dv[1].data_length = 0;
1022 kev_post_msg(&ev_msg);
1023
1024 goto respond;
1025 }
1026
1027 /*
1028 * Look up the routing entry. If it doesn't exist and we are the
1029 * target, and the sender isn't 0.0.0.0, go ahead and create one.
1030 * Callee holds a reference on the route and returns with the route
1031 * entry locked, upon success.
1032 */
1033 error = arp_lookup_route(&sender_ip->sin_addr,
1034 (target_ip->sin_addr.s_addr == best_ia->ia_addr.sin_addr.s_addr &&
1035 sender_ip->sin_addr.s_addr != 0), 0, &route, ifp->if_index);
1036
1037 if (error == 0)
1038 RT_LOCK_ASSERT_HELD(route);
1039
1040 if (error || route == 0 || route->rt_gateway == 0) {
1041 if (arpop != ARPOP_REQUEST) {
1042 goto respond;
1043 }
1044 if (arp_sendllconflict
1045 && send_conflicting_probes != 0
1046 && (ifp->if_eflags & IFEF_ARPLL) != 0
1047 && IN_LINKLOCAL(ntohl(target_ip->sin_addr.s_addr))
1048 && sender_ip->sin_addr.s_addr == 0) {
1049 /*
1050 * Verify this ARP probe doesn't conflict with an IPv4LL we know of
1051 * on another interface.
1052 */
1053 if (route != NULL) {
1054 RT_REMREF_LOCKED(route);
1055 RT_UNLOCK(route);
1056 route = NULL;
1057 }
1058 /*
1059 * Callee holds a reference on the route and returns
1060 * with the route entry locked, upon success.
1061 */
1062 error = arp_lookup_route(&target_ip->sin_addr, 0, 0,
1063 &route, ifp->if_index);
1064
1065 if (error == 0)
1066 RT_LOCK_ASSERT_HELD(route);
1067
1068 if (error == 0 && route && route->rt_gateway) {
1069 gateway = SDL(route->rt_gateway);
1070 if (route->rt_ifp != ifp && gateway->sdl_alen != 0
1071 && (gateway->sdl_alen != sender_hw->sdl_alen
1072 || bcmp(CONST_LLADDR(gateway), CONST_LLADDR(sender_hw),
1073 gateway->sdl_alen) != 0)) {
1074 /*
1075 * A node is probing for an IPv4LL we know exists on a
1076 * different interface. We respond with a conflicting probe
1077 * to force the new device to pick a different IPv4LL
1078 * address.
1079 */
1080 if (log_arp_warnings) {
1081 log(LOG_INFO,
1082 "arp: %s on %s%d sent probe for %s, already on %s%d\n",
1083 sdl_addr_to_hex(sender_hw, buf, sizeof(buf)),
1084 ifp->if_name, ifp->if_unit,
1085 inet_ntop(AF_INET, &target_ip->sin_addr, ipv4str,
1086 sizeof(ipv4str)),
1087 route->rt_ifp->if_name, route->rt_ifp->if_unit);
1088 log(LOG_INFO,
1089 "arp: sending conflicting probe to %s on %s%d\n",
1090 sdl_addr_to_hex(sender_hw, buf, sizeof(buf)),
1091 ifp->if_name, ifp->if_unit);
1092 }
1093 /* We're done with the route */
1094 RT_REMREF_LOCKED(route);
1095 RT_UNLOCK(route);
1096 route = NULL;
1097 /*
1098 * Send a conservative unicast "ARP probe".
1099 * This should force the other device to pick a new number.
1100 * This will not force the device to pick a new number if the device
1101 * has already assigned that number.
1102 * This will not imply to the device that we own that address.
1103 */
1104 ifnet_lock_shared(ifp);
1105 ifa = TAILQ_FIRST(&ifp->if_addrhead);
1106 if (ifa != NULL)
1107 ifaref(ifa);
1108 ifnet_lock_done(ifp);
1109 dlil_send_arp_internal(ifp, ARPOP_REQUEST,
1110 ifa != NULL ? SDL(ifa->ifa_addr) : NULL,
1111 (const struct sockaddr*)sender_ip, sender_hw,
1112 (const struct sockaddr*)target_ip);
1113 if (ifa != NULL) {
1114 ifafree(ifa);
1115 ifa = NULL;
1116 }
1117 }
1118 }
1119 goto respond;
1120 } else if (keep_announcements != 0
1121 && target_ip->sin_addr.s_addr == sender_ip->sin_addr.s_addr) {
1122 /* don't create entry if link-local address and link-local is disabled */
1123 if (!IN_LINKLOCAL(ntohl(sender_ip->sin_addr.s_addr))
1124 || (ifp->if_eflags & IFEF_ARPLL) != 0) {
1125 if (route != NULL) {
1126 RT_REMREF_LOCKED(route);
1127 RT_UNLOCK(route);
1128 route = NULL;
1129 }
1130 /*
1131 * Callee holds a reference on the route and
1132 * returns with the route entry locked, upon
1133 * success.
1134 */
1135 error = arp_lookup_route(&sender_ip->sin_addr,
1136 1, 0, &route, ifp->if_index);
1137
1138 if (error == 0)
1139 RT_LOCK_ASSERT_HELD(route);
1140
1141 if (error == 0 && route != NULL && route->rt_gateway != NULL) {
1142 created_announcement = 1;
1143 }
1144 }
1145 if (created_announcement == 0) {
1146 goto respond;
1147 }
1148 } else {
1149 goto respond;
1150 }
1151 }
1152
1153 RT_LOCK_ASSERT_HELD(route);
1154 gateway = SDL(route->rt_gateway);
1155 if (route->rt_ifp != ifp) {
1156 if (!IN_LINKLOCAL(ntohl(sender_ip->sin_addr.s_addr)) || (ifp->if_eflags & IFEF_ARPLL) == 0) {
1157 if (log_arp_warnings)
1158 log(LOG_ERR, "arp: %s is on %s%d but got reply from %s on %s%d\n",
1159 inet_ntop(AF_INET, &sender_ip->sin_addr, ipv4str,
1160 sizeof(ipv4str)),
1161 route->rt_ifp->if_name,
1162 route->rt_ifp->if_unit,
1163 sdl_addr_to_hex(sender_hw, buf, sizeof(buf)),
1164 ifp->if_name, ifp->if_unit);
1165 goto respond;
1166 }
1167 else {
1168 /* Don't change a permanent address */
1169 if (route->rt_rmx.rmx_expire == 0) {
1170 goto respond;
1171 }
1172
1173 /*
1174 * We're about to check and/or change the route's ifp
1175 * and ifa, so do the lock dance: drop rt_lock, hold
1176 * rnh_lock and re-hold rt_lock to avoid violating the
1177 * lock ordering. We have an extra reference on the
1178 * route, so it won't go away while we do this.
1179 */
1180 RT_UNLOCK(route);
1181 lck_mtx_lock(rnh_lock);
1182 RT_LOCK(route);
1183 /*
1184 * Don't change the cloned route away from the
1185 * parent's interface if the address did resolve
1186 * or if the route is defunct. rt_ifp on both
1187 * the parent and the clone can now be freely
1188 * accessed now that we have acquired rnh_lock.
1189 */
1190 gateway = SDL(route->rt_gateway);
1191 if ((gateway->sdl_alen != 0 && route->rt_parent &&
1192 route->rt_parent->rt_ifp == route->rt_ifp) ||
1193 (route->rt_flags & RTF_CONDEMNED)) {
1194 RT_REMREF_LOCKED(route);
1195 RT_UNLOCK(route);
1196 route = NULL;
1197 lck_mtx_unlock(rnh_lock);
1198 goto respond;
1199 }
1200 /* Change the interface when the existing route is on */
1201 route->rt_ifp = ifp;
1202 rtsetifa(route, &best_ia->ia_ifa);
1203 gateway->sdl_index = ifp->if_index;
1204 RT_UNLOCK(route);
1205 lck_mtx_unlock(rnh_lock);
1206 RT_LOCK(route);
1207 /* Don't bother if the route is down */
1208 if (!(route->rt_flags & RTF_UP))
1209 goto respond;
1210 /* Refresh gateway pointer */
1211 gateway = SDL(route->rt_gateway);
1212 }
1213 RT_LOCK_ASSERT_HELD(route);
1214 }
1215
1216 if (gateway->sdl_alen && bcmp(LLADDR(gateway), CONST_LLADDR(sender_hw), gateway->sdl_alen)) {
1217 if (route->rt_rmx.rmx_expire && log_arp_warnings) {
1218 char buf2[3 * MAX_HW_LEN];
1219 log(LOG_INFO, "arp: %s moved from %s to %s on %s%d\n",
1220 inet_ntop(AF_INET, &sender_ip->sin_addr, ipv4str,
1221 sizeof(ipv4str)),
1222 sdl_addr_to_hex(gateway, buf, sizeof(buf)),
1223 sdl_addr_to_hex(sender_hw, buf2, sizeof(buf2)),
1224 ifp->if_name, ifp->if_unit);
1225 }
1226 else if (route->rt_rmx.rmx_expire == 0) {
1227 if (log_arp_warnings) {
1228 log(LOG_ERR, "arp: %s attempts to modify "
1229 "permanent entry for %s on %s%d\n",
1230 sdl_addr_to_hex(sender_hw, buf,
1231 sizeof(buf)),
1232 inet_ntop(AF_INET, &sender_ip->sin_addr,
1233 ipv4str, sizeof(ipv4str)),
1234 ifp->if_name, ifp->if_unit);
1235 }
1236 goto respond;
1237 }
1238 }
1239
1240 /* Copy the sender hardware address in to the route's gateway address */
1241 gateway->sdl_alen = sender_hw->sdl_alen;
1242 bcopy(CONST_LLADDR(sender_hw), LLADDR(gateway), gateway->sdl_alen);
1243
1244 /* Update the expire time for the route and clear the reject flag */
1245 if (route->rt_rmx.rmx_expire) {
1246 struct timeval timenow;
1247
1248 getmicrotime(&timenow);
1249 route->rt_rmx.rmx_expire = timenow.tv_sec + arpt_keep;
1250 }
1251 route->rt_flags &= ~RTF_REJECT;
1252
1253 /* update the llinfo, send a queued packet if there is one */
1254 llinfo = route->rt_llinfo;
1255 llinfo->la_asked = 0;
1256 if (llinfo->la_hold) {
1257 struct mbuf *m0;
1258 m0 = llinfo->la_hold;
1259 llinfo->la_hold = 0;
1260
1261 RT_UNLOCK(route);
1262 dlil_output(ifp, PF_INET, m0, (caddr_t)route, rt_key(route), 0);
1263 RT_REMREF(route);
1264 route = NULL;
1265 }
1266
1267 respond:
1268 if (route != NULL) {
1269 RT_REMREF_LOCKED(route);
1270 RT_UNLOCK(route);
1271 route = NULL;
1272 }
1273
1274 if (arpop != ARPOP_REQUEST)
1275 goto done;
1276
1277 /* If we are not the target, check if we should proxy */
1278 if (target_ip->sin_addr.s_addr != best_ia->ia_addr.sin_addr.s_addr) {
1279 /*
1280 * Find a proxy route; callee holds a reference on the
1281 * route and returns with the route entry locked, upon
1282 * success.
1283 */
1284 error = arp_lookup_route(&target_ip->sin_addr, 0, SIN_PROXY,
1285 &route, ifp->if_index);
1286
1287 if (error == 0) {
1288 RT_LOCK_ASSERT_HELD(route);
1289 proxied = *SDL(route->rt_gateway);
1290 target_hw = &proxied;
1291 } else {
1292 /*
1293 * We don't have a route entry indicating we should
1294 * use proxy. If we aren't supposed to proxy all,
1295 * we are done.
1296 */
1297 if (!arp_proxyall)
1298 goto done;
1299
1300 /*
1301 * See if we have a route to the target ip before
1302 * we proxy it.
1303 */
1304 route = rtalloc1_scoped((struct sockaddr *)
1305 (size_t)target_ip, 0, 0, ifp->if_index);
1306 if (!route)
1307 goto done;
1308
1309 /*
1310 * Don't proxy for hosts already on the same interface.
1311 */
1312 RT_LOCK(route);
1313 if (route->rt_ifp == ifp) {
1314 RT_UNLOCK(route);
1315 rtfree(route);
1316 goto done;
1317 }
1318 }
1319 RT_REMREF_LOCKED(route);
1320 RT_UNLOCK(route);
1321 }
1322
1323 dlil_send_arp(ifp, ARPOP_REPLY,
1324 target_hw, (const struct sockaddr*)target_ip,
1325 sender_hw, (const struct sockaddr*)sender_ip);
1326
1327 done:
1328 if (best_ia != NULL)
1329 ifafree(&best_ia->ia_ifa);
1330 return 0;
1331 }
1332
1333 void
1334 arp_ifinit(
1335 struct ifnet *ifp,
1336 struct ifaddr *ifa)
1337 {
1338 ifa->ifa_rtrequest = arp_rtrequest;
1339 ifa->ifa_flags |= RTF_CLONING;
1340 dlil_send_arp(ifp, ARPOP_REQUEST, NULL, ifa->ifa_addr, NULL, ifa->ifa_addr);
1341 }