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