xref: /xnu-11417.140.69/bsd/netinet6/nd6_prproxy.c (revision 43a90889846e00bfb5cf1d255cdc0a701a1e05a4)
1*43a90889SApple OSS Distributions /*
2*43a90889SApple OSS Distributions  * Copyright (c) 2011-2020 Apple Inc. All rights reserved.
3*43a90889SApple OSS Distributions  *
4*43a90889SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*43a90889SApple OSS Distributions  *
6*43a90889SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*43a90889SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*43a90889SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*43a90889SApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*43a90889SApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*43a90889SApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*43a90889SApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*43a90889SApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*43a90889SApple OSS Distributions  *
15*43a90889SApple OSS Distributions  * Please obtain a copy of the License at
16*43a90889SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*43a90889SApple OSS Distributions  *
18*43a90889SApple OSS Distributions  * The Original Code and all software distributed under the License are
19*43a90889SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*43a90889SApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*43a90889SApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*43a90889SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*43a90889SApple OSS Distributions  * Please see the License for the specific language governing rights and
24*43a90889SApple OSS Distributions  * limitations under the License.
25*43a90889SApple OSS Distributions  *
26*43a90889SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*43a90889SApple OSS Distributions  */
28*43a90889SApple OSS Distributions 
29*43a90889SApple OSS Distributions /*
30*43a90889SApple OSS Distributions  * Prefix-based Neighbor Discovery Proxy
31*43a90889SApple OSS Distributions  *
32*43a90889SApple OSS Distributions  * When an interface is marked with the ND6_IFF_PROXY_PREFIXES flag, all
33*43a90889SApple OSS Distributions  * of current and future non-scoped on-link prefixes configured on the
34*43a90889SApple OSS Distributions  * interface will be shared with the scoped variant of such prefixes on
35*43a90889SApple OSS Distributions  * other interfaces.  This allows for one or more prefixes to be shared
36*43a90889SApple OSS Distributions  * across multiple links, with full support for Duplicate Addres Detection,
37*43a90889SApple OSS Distributions  * Address Resolution and Neighbor Unreachability Detection.
38*43a90889SApple OSS Distributions  *
39*43a90889SApple OSS Distributions  * A non-scoped prefix may be configured statically, or dynamically via
40*43a90889SApple OSS Distributions  * Router Advertisement.  An interface is said to be an "upstream" interface
41*43a90889SApple OSS Distributions  * when it is marked with ND6_IFF_PROXY_PREFIXES and has at least one prefix
42*43a90889SApple OSS Distributions  * that is non-scoped (global, not scoped.)  Such prefixes are marked with
43*43a90889SApple OSS Distributions  * the NDPRF_PRPROXY flag.
44*43a90889SApple OSS Distributions  *
45*43a90889SApple OSS Distributions  * A scoped prefix typically gets configured by way of adding an address
46*43a90889SApple OSS Distributions  * to a "downstream" interface, when the added address is part of an existing
47*43a90889SApple OSS Distributions  * prefix that is allowed to be shared (i.e. NDPRF_PRPROXY prefixes.)  Unlike
48*43a90889SApple OSS Distributions  * non-scoped prefixes, however, scoped prefixes will never be marked with
49*43a90889SApple OSS Distributions  * the NDPRF_PRPROXY flag.
50*43a90889SApple OSS Distributions  *
51*43a90889SApple OSS Distributions  * The setting of NDPRF_PRPROXY depends on whether the prefix is on-link;
52*43a90889SApple OSS Distributions  * an off-link prefix on an interface marked with ND6_IFF_PROXY_PREFIXES
53*43a90889SApple OSS Distributions  * will not cause NDPRF_PRPROXY to be set (it will only happen when that
54*43a90889SApple OSS Distributions  * prefix goes on-link.)  Likewise, a previously on-link prefix that has
55*43a90889SApple OSS Distributions  * transitioned to off-link will cause its NDPRF_PRPROXY flag to be cleared.
56*43a90889SApple OSS Distributions  *
57*43a90889SApple OSS Distributions  * Prefix proxying relies on IPv6 Scoped Routing to be in effect, as it would
58*43a90889SApple OSS Distributions  * otherwise be impossible to install scoped prefix route entries in the
59*43a90889SApple OSS Distributions  * routing table.  By default, such cloning prefix routes will generate cloned
60*43a90889SApple OSS Distributions  * routes that are scoped according to their interfaces.  Because prefix
61*43a90889SApple OSS Distributions  * proxying is essentially creating a larger network comprised of multiple
62*43a90889SApple OSS Distributions  * links sharing a prefix, we need to treat the cloned routes as if they
63*43a90889SApple OSS Distributions  * weren't scoped route entries.  This requires marking such cloning prefix
64*43a90889SApple OSS Distributions  * routes with the RTF_PROXY flag, which serves as an indication that the
65*43a90889SApple OSS Distributions  * route entry (and its clones) are part of a proxied prefix, and that the
66*43a90889SApple OSS Distributions  * entries are non-scoped.
67*43a90889SApple OSS Distributions  *
68*43a90889SApple OSS Distributions  * In order to handle solicited-node destined ND packets (Address Resolution,
69*43a90889SApple OSS Distributions  * Neighbor Unreachability Detection), prefix proxying also requires that the
70*43a90889SApple OSS Distributions  * "upstream" and "downstream" interfaces be configured for all-multicast mode.
71*43a90889SApple OSS Distributions  *
72*43a90889SApple OSS Distributions  * The setting and clearing of RTF_PROXY flag, as well as the entering and
73*43a90889SApple OSS Distributions  * exiting of all-multicast mode on those interfaces happen when a prefix
74*43a90889SApple OSS Distributions  * transitions between on-link and off-link (vice versa.)
75*43a90889SApple OSS Distributions  *
76*43a90889SApple OSS Distributions  * Note that this is not a strict implementation of RFC 4389, but rather a
77*43a90889SApple OSS Distributions  * derivative based on similar concept.  In particular, we only proxy NS and
78*43a90889SApple OSS Distributions  * NA packets; RA packets are never proxied.  Care should be taken to enable
79*43a90889SApple OSS Distributions  * prefix proxying only on non-looping network topology.
80*43a90889SApple OSS Distributions  */
81*43a90889SApple OSS Distributions 
82*43a90889SApple OSS Distributions #include <sys/param.h>
83*43a90889SApple OSS Distributions #include <sys/systm.h>
84*43a90889SApple OSS Distributions #include <sys/malloc.h>
85*43a90889SApple OSS Distributions #include <sys/mbuf.h>
86*43a90889SApple OSS Distributions #include <sys/errno.h>
87*43a90889SApple OSS Distributions #include <sys/syslog.h>
88*43a90889SApple OSS Distributions #include <sys/sysctl.h>
89*43a90889SApple OSS Distributions #include <sys/mcache.h>
90*43a90889SApple OSS Distributions #include <sys/protosw.h>
91*43a90889SApple OSS Distributions 
92*43a90889SApple OSS Distributions #include <kern/queue.h>
93*43a90889SApple OSS Distributions #include <kern/zalloc.h>
94*43a90889SApple OSS Distributions 
95*43a90889SApple OSS Distributions #include <net/if.h>
96*43a90889SApple OSS Distributions #include <net/if_var.h>
97*43a90889SApple OSS Distributions #include <net/if_types.h>
98*43a90889SApple OSS Distributions #include <net/route.h>
99*43a90889SApple OSS Distributions 
100*43a90889SApple OSS Distributions #include <netinet/in.h>
101*43a90889SApple OSS Distributions #include <netinet/in_var.h>
102*43a90889SApple OSS Distributions #include <netinet6/in6_var.h>
103*43a90889SApple OSS Distributions #include <netinet/ip6.h>
104*43a90889SApple OSS Distributions #include <netinet6/ip6_var.h>
105*43a90889SApple OSS Distributions #include <netinet/icmp6.h>
106*43a90889SApple OSS Distributions #include <netinet6/nd6.h>
107*43a90889SApple OSS Distributions #include <netinet6/scope6_var.h>
108*43a90889SApple OSS Distributions 
109*43a90889SApple OSS Distributions struct nd6_prproxy_prelist {
110*43a90889SApple OSS Distributions 	SLIST_ENTRY(nd6_prproxy_prelist) ndprl_le;
111*43a90889SApple OSS Distributions 	struct nd_prefix *ndprl_pr;             /* prefix */
112*43a90889SApple OSS Distributions 	struct nd_prefix *ndprl_up;             /* non-NULL for upstream */
113*43a90889SApple OSS Distributions 	struct ifnet    *ndprl_fwd_ifp;         /* outgoing interface */
114*43a90889SApple OSS Distributions 	boolean_t       ndprl_sol;              /* unicast solicitor? */
115*43a90889SApple OSS Distributions 	struct in6_addr ndprl_sol_saddr;        /* solicitor's address */
116*43a90889SApple OSS Distributions };
117*43a90889SApple OSS Distributions 
118*43a90889SApple OSS Distributions /*
119*43a90889SApple OSS Distributions  * Soliciting node (source) record.
120*43a90889SApple OSS Distributions  */
121*43a90889SApple OSS Distributions struct nd6_prproxy_solsrc {
122*43a90889SApple OSS Distributions 	TAILQ_ENTRY(nd6_prproxy_solsrc) solsrc_tqe;
123*43a90889SApple OSS Distributions 	struct in6_addr solsrc_saddr;           /* soliciting (src) address */
124*43a90889SApple OSS Distributions 	struct ifnet    *solsrc_ifp;            /* iface where NS arrived on */
125*43a90889SApple OSS Distributions };
126*43a90889SApple OSS Distributions 
127*43a90889SApple OSS Distributions /*
128*43a90889SApple OSS Distributions  * Solicited node (target) record.
129*43a90889SApple OSS Distributions  */
130*43a90889SApple OSS Distributions struct nd6_prproxy_soltgt {
131*43a90889SApple OSS Distributions 	RB_ENTRY(nd6_prproxy_soltgt) soltgt_link; /* RB tree links */
132*43a90889SApple OSS Distributions 	struct soltgt_key_s {
133*43a90889SApple OSS Distributions 		struct in6_addr taddr;          /* solicited (tgt) address */
134*43a90889SApple OSS Distributions 	} soltgt_key;
135*43a90889SApple OSS Distributions 	u_int64_t       soltgt_expire;          /* expiration time */
136*43a90889SApple OSS Distributions 	u_int32_t       soltgt_cnt;             /* total # of solicitors */
137*43a90889SApple OSS Distributions 	TAILQ_HEAD(, nd6_prproxy_solsrc) soltgt_q;
138*43a90889SApple OSS Distributions };
139*43a90889SApple OSS Distributions 
140*43a90889SApple OSS Distributions SLIST_HEAD(nd6_prproxy_prelist_head, nd6_prproxy_prelist);
141*43a90889SApple OSS Distributions 
142*43a90889SApple OSS Distributions static void nd6_prproxy_prelist_setroute(boolean_t enable,
143*43a90889SApple OSS Distributions     struct nd6_prproxy_prelist_head *, struct nd6_prproxy_prelist_head *);
144*43a90889SApple OSS Distributions static struct nd6_prproxy_prelist *nd6_ndprl_alloc(zalloc_flags_t);
145*43a90889SApple OSS Distributions static void nd6_ndprl_free(struct nd6_prproxy_prelist *);
146*43a90889SApple OSS Distributions static struct nd6_prproxy_solsrc *nd6_solsrc_alloc(int);
147*43a90889SApple OSS Distributions static void nd6_solsrc_free(struct nd6_prproxy_solsrc *);
148*43a90889SApple OSS Distributions static boolean_t nd6_solsrc_enq(struct nd_prefix *, struct ifnet *,
149*43a90889SApple OSS Distributions     struct in6_addr *, struct in6_addr *);
150*43a90889SApple OSS Distributions static boolean_t nd6_solsrc_deq(struct nd_prefix *, struct in6_addr *,
151*43a90889SApple OSS Distributions     struct in6_addr *, struct ifnet **);
152*43a90889SApple OSS Distributions static struct nd6_prproxy_soltgt *nd6_soltgt_alloc(int);
153*43a90889SApple OSS Distributions static void nd6_soltgt_free(struct nd6_prproxy_soltgt *);
154*43a90889SApple OSS Distributions static void nd6_soltgt_prune(struct nd6_prproxy_soltgt *, u_int32_t);
155*43a90889SApple OSS Distributions static __inline int soltgt_cmp(const struct nd6_prproxy_soltgt *,
156*43a90889SApple OSS Distributions     const struct nd6_prproxy_soltgt *);
157*43a90889SApple OSS Distributions static void nd6_prproxy_sols_purge(struct nd_prefix *, u_int64_t);
158*43a90889SApple OSS Distributions 
159*43a90889SApple OSS Distributions RB_PROTOTYPE_SC_PREV(__private_extern__, prproxy_sols_tree, nd6_prproxy_soltgt,
160*43a90889SApple OSS Distributions     soltgt_link, soltgt_cmp);
161*43a90889SApple OSS Distributions 
162*43a90889SApple OSS Distributions /*
163*43a90889SApple OSS Distributions  * Time (in seconds) before a target record expires (is idle).
164*43a90889SApple OSS Distributions  */
165*43a90889SApple OSS Distributions #define ND6_TGT_SOLS_EXPIRE                     5
166*43a90889SApple OSS Distributions 
167*43a90889SApple OSS Distributions /*
168*43a90889SApple OSS Distributions  * Maximum number of queued soliciting (source) records per target.
169*43a90889SApple OSS Distributions  */
170*43a90889SApple OSS Distributions #define ND6_MAX_SRC_SOLS_DEFAULT                4
171*43a90889SApple OSS Distributions 
172*43a90889SApple OSS Distributions /*
173*43a90889SApple OSS Distributions  * Maximum number of queued solicited (target) records per prefix.
174*43a90889SApple OSS Distributions  */
175*43a90889SApple OSS Distributions #define ND6_MAX_TGT_SOLS_DEFAULT                8
176*43a90889SApple OSS Distributions 
177*43a90889SApple OSS Distributions static u_int32_t nd6_max_tgt_sols = ND6_MAX_TGT_SOLS_DEFAULT;
178*43a90889SApple OSS Distributions static u_int32_t nd6_max_src_sols = ND6_MAX_SRC_SOLS_DEFAULT;
179*43a90889SApple OSS Distributions 
180*43a90889SApple OSS Distributions static KALLOC_TYPE_DEFINE(ndprl_zone,
181*43a90889SApple OSS Distributions     struct nd6_prproxy_prelist, NET_KT_DEFAULT);    /* nd6_prproxy_prelist zone */
182*43a90889SApple OSS Distributions 
183*43a90889SApple OSS Distributions static KALLOC_TYPE_DEFINE(solsrc_zone,
184*43a90889SApple OSS Distributions     struct nd6_prproxy_solsrc, NET_KT_DEFAULT);     /* nd6_prproxy_solsrc zone */
185*43a90889SApple OSS Distributions 
186*43a90889SApple OSS Distributions static KALLOC_TYPE_DEFINE(soltgt_zone,
187*43a90889SApple OSS Distributions     struct nd6_prproxy_soltgt, NET_KT_DEFAULT);     /* nd6_prproxy_soltgt zone */
188*43a90889SApple OSS Distributions 
189*43a90889SApple OSS Distributions /* The following is protected by ndpr_lock */
190*43a90889SApple OSS Distributions RB_GENERATE_PREV(prproxy_sols_tree, nd6_prproxy_soltgt,
191*43a90889SApple OSS Distributions     soltgt_link, soltgt_cmp);
192*43a90889SApple OSS Distributions 
193*43a90889SApple OSS Distributions /* The following is protected by proxy6_lock (for updates) */
194*43a90889SApple OSS Distributions u_int32_t nd6_prproxy;
195*43a90889SApple OSS Distributions 
196*43a90889SApple OSS Distributions SYSCTL_DECL(_net_inet6_icmp6);
197*43a90889SApple OSS Distributions 
198*43a90889SApple OSS Distributions SYSCTL_UINT(_net_inet6_icmp6, OID_AUTO, nd6_maxsolstgt,
199*43a90889SApple OSS Distributions     CTLFLAG_RW | CTLFLAG_LOCKED, &nd6_max_tgt_sols, ND6_MAX_TGT_SOLS_DEFAULT,
200*43a90889SApple OSS Distributions     "maximum number of outstanding solicited targets per prefix");
201*43a90889SApple OSS Distributions 
202*43a90889SApple OSS Distributions SYSCTL_UINT(_net_inet6_icmp6, OID_AUTO, nd6_maxproxiedsol,
203*43a90889SApple OSS Distributions     CTLFLAG_RW | CTLFLAG_LOCKED, &nd6_max_src_sols, ND6_MAX_SRC_SOLS_DEFAULT,
204*43a90889SApple OSS Distributions     "maximum number of outstanding solicitations per target");
205*43a90889SApple OSS Distributions 
206*43a90889SApple OSS Distributions SYSCTL_UINT(_net_inet6_icmp6, OID_AUTO, prproxy_cnt,
207*43a90889SApple OSS Distributions     CTLFLAG_RD | CTLFLAG_LOCKED, &nd6_prproxy, 0,
208*43a90889SApple OSS Distributions     "total number of proxied prefixes");
209*43a90889SApple OSS Distributions 
210*43a90889SApple OSS Distributions static struct nd6_prproxy_prelist *
nd6_ndprl_alloc(zalloc_flags_t how)211*43a90889SApple OSS Distributions nd6_ndprl_alloc(zalloc_flags_t how)
212*43a90889SApple OSS Distributions {
213*43a90889SApple OSS Distributions 	return zalloc_flags(ndprl_zone, how | Z_ZERO);
214*43a90889SApple OSS Distributions }
215*43a90889SApple OSS Distributions 
216*43a90889SApple OSS Distributions static void
nd6_ndprl_free(struct nd6_prproxy_prelist * ndprl)217*43a90889SApple OSS Distributions nd6_ndprl_free(struct nd6_prproxy_prelist *ndprl)
218*43a90889SApple OSS Distributions {
219*43a90889SApple OSS Distributions 	zfree(ndprl_zone, ndprl);
220*43a90889SApple OSS Distributions }
221*43a90889SApple OSS Distributions 
222*43a90889SApple OSS Distributions /*
223*43a90889SApple OSS Distributions  * Apply routing function on the affected upstream and downstream prefixes,
224*43a90889SApple OSS Distributions  * i.e. either set or clear RTF_PROXY on the cloning prefix route; all route
225*43a90889SApple OSS Distributions  * entries that were cloned off these prefixes will be blown away.  Caller
226*43a90889SApple OSS Distributions  * must have acquired proxy6_lock and must not be holding nd6_mutex.
227*43a90889SApple OSS Distributions  */
228*43a90889SApple OSS Distributions static void
nd6_prproxy_prelist_setroute(boolean_t enable,struct nd6_prproxy_prelist_head * up_head,struct nd6_prproxy_prelist_head * down_head)229*43a90889SApple OSS Distributions nd6_prproxy_prelist_setroute(boolean_t enable,
230*43a90889SApple OSS Distributions     struct nd6_prproxy_prelist_head *up_head,
231*43a90889SApple OSS Distributions     struct nd6_prproxy_prelist_head *down_head)
232*43a90889SApple OSS Distributions {
233*43a90889SApple OSS Distributions 	struct nd6_prproxy_prelist *__single up, *__single down, *__single ndprl_tmp;
234*43a90889SApple OSS Distributions 	struct nd_prefix *__single pr;
235*43a90889SApple OSS Distributions 
236*43a90889SApple OSS Distributions 	LCK_MTX_ASSERT(&proxy6_lock, LCK_MTX_ASSERT_OWNED);
237*43a90889SApple OSS Distributions 	LCK_MTX_ASSERT(nd6_mutex, LCK_MTX_ASSERT_NOTOWNED);
238*43a90889SApple OSS Distributions 
239*43a90889SApple OSS Distributions 	SLIST_FOREACH_SAFE(up, up_head, ndprl_le, ndprl_tmp) {
240*43a90889SApple OSS Distributions 		rtentry_ref_t rt;
241*43a90889SApple OSS Distributions 		boolean_t prproxy, set_allmulti = FALSE;
242*43a90889SApple OSS Distributions 		int allmulti_sw = FALSE;
243*43a90889SApple OSS Distributions 		ifnet_ref_t ifp = NULL;
244*43a90889SApple OSS Distributions 
245*43a90889SApple OSS Distributions 		SLIST_REMOVE(up_head, up, nd6_prproxy_prelist, ndprl_le);
246*43a90889SApple OSS Distributions 		pr = up->ndprl_pr;
247*43a90889SApple OSS Distributions 		VERIFY(up->ndprl_up == NULL);
248*43a90889SApple OSS Distributions 
249*43a90889SApple OSS Distributions 		NDPR_LOCK(pr);
250*43a90889SApple OSS Distributions 		ifp = pr->ndpr_ifp;
251*43a90889SApple OSS Distributions 		prproxy = (pr->ndpr_stateflags & NDPRF_PRPROXY);
252*43a90889SApple OSS Distributions 		VERIFY(!prproxy || ((pr->ndpr_stateflags & NDPRF_ONLINK) &&
253*43a90889SApple OSS Distributions 		    !(pr->ndpr_stateflags & NDPRF_IFSCOPE)));
254*43a90889SApple OSS Distributions 
255*43a90889SApple OSS Distributions 		nd6_prproxy_sols_reap(pr);
256*43a90889SApple OSS Distributions 		VERIFY(pr->ndpr_prproxy_sols_cnt == 0);
257*43a90889SApple OSS Distributions 		VERIFY(RB_EMPTY(&pr->ndpr_prproxy_sols));
258*43a90889SApple OSS Distributions 
259*43a90889SApple OSS Distributions 		if (enable && pr->ndpr_allmulti_cnt == 0) {
260*43a90889SApple OSS Distributions 			nd6_prproxy++;
261*43a90889SApple OSS Distributions 			pr->ndpr_allmulti_cnt++;
262*43a90889SApple OSS Distributions 			set_allmulti = TRUE;
263*43a90889SApple OSS Distributions 			allmulti_sw = TRUE;
264*43a90889SApple OSS Distributions 		} else if (!enable && pr->ndpr_allmulti_cnt > 0) {
265*43a90889SApple OSS Distributions 			nd6_prproxy--;
266*43a90889SApple OSS Distributions 			pr->ndpr_allmulti_cnt--;
267*43a90889SApple OSS Distributions 			set_allmulti = TRUE;
268*43a90889SApple OSS Distributions 			allmulti_sw = FALSE;
269*43a90889SApple OSS Distributions 		}
270*43a90889SApple OSS Distributions 
271*43a90889SApple OSS Distributions 		if ((rt = pr->ndpr_rt) != NULL) {
272*43a90889SApple OSS Distributions 			if ((enable && prproxy) || (!enable && !prproxy)) {
273*43a90889SApple OSS Distributions 				RT_ADDREF(rt);
274*43a90889SApple OSS Distributions 			} else {
275*43a90889SApple OSS Distributions 				rt = NULL;
276*43a90889SApple OSS Distributions 			}
277*43a90889SApple OSS Distributions 			NDPR_UNLOCK(pr);
278*43a90889SApple OSS Distributions 		} else {
279*43a90889SApple OSS Distributions 			NDPR_UNLOCK(pr);
280*43a90889SApple OSS Distributions 		}
281*43a90889SApple OSS Distributions 
282*43a90889SApple OSS Distributions 		/* Call the following ioctl after releasing NDPR lock */
283*43a90889SApple OSS Distributions 		if (set_allmulti && ifp != NULL) {
284*43a90889SApple OSS Distributions 			if_allmulti(ifp, allmulti_sw);
285*43a90889SApple OSS Distributions 		}
286*43a90889SApple OSS Distributions 
287*43a90889SApple OSS Distributions 
288*43a90889SApple OSS Distributions 		NDPR_REMREF(pr);
289*43a90889SApple OSS Distributions 		if (rt != NULL) {
290*43a90889SApple OSS Distributions 			rt_set_proxy(rt, enable);
291*43a90889SApple OSS Distributions 			rtfree(rt);
292*43a90889SApple OSS Distributions 		}
293*43a90889SApple OSS Distributions 		nd6_ndprl_free(up);
294*43a90889SApple OSS Distributions 	}
295*43a90889SApple OSS Distributions 
296*43a90889SApple OSS Distributions 	SLIST_FOREACH_SAFE(down, down_head, ndprl_le, ndprl_tmp) {
297*43a90889SApple OSS Distributions 		struct nd_prefix *__single pr_up;
298*43a90889SApple OSS Distributions 		rtentry_ref_t rt;
299*43a90889SApple OSS Distributions 		boolean_t prproxy, set_allmulti = FALSE;
300*43a90889SApple OSS Distributions 		int allmulti_sw = FALSE;
301*43a90889SApple OSS Distributions 		ifnet_ref_t ifp = NULL;
302*43a90889SApple OSS Distributions 
303*43a90889SApple OSS Distributions 		SLIST_REMOVE(down_head, down, nd6_prproxy_prelist, ndprl_le);
304*43a90889SApple OSS Distributions 		pr = down->ndprl_pr;
305*43a90889SApple OSS Distributions 		pr_up = down->ndprl_up;
306*43a90889SApple OSS Distributions 		VERIFY(pr_up != NULL);
307*43a90889SApple OSS Distributions 
308*43a90889SApple OSS Distributions 		NDPR_LOCK(pr_up);
309*43a90889SApple OSS Distributions 		ifp = pr->ndpr_ifp;
310*43a90889SApple OSS Distributions 		prproxy = (pr_up->ndpr_stateflags & NDPRF_PRPROXY);
311*43a90889SApple OSS Distributions 		VERIFY(!prproxy || ((pr_up->ndpr_stateflags & NDPRF_ONLINK) &&
312*43a90889SApple OSS Distributions 		    !(pr_up->ndpr_stateflags & NDPRF_IFSCOPE)));
313*43a90889SApple OSS Distributions 		NDPR_UNLOCK(pr_up);
314*43a90889SApple OSS Distributions 
315*43a90889SApple OSS Distributions 		NDPR_LOCK(pr);
316*43a90889SApple OSS Distributions 		if (enable && pr->ndpr_allmulti_cnt == 0) {
317*43a90889SApple OSS Distributions 			pr->ndpr_allmulti_cnt++;
318*43a90889SApple OSS Distributions 			set_allmulti = TRUE;
319*43a90889SApple OSS Distributions 			allmulti_sw = TRUE;
320*43a90889SApple OSS Distributions 		} else if (!enable && pr->ndpr_allmulti_cnt > 0) {
321*43a90889SApple OSS Distributions 			pr->ndpr_allmulti_cnt--;
322*43a90889SApple OSS Distributions 			set_allmulti = TRUE;
323*43a90889SApple OSS Distributions 			allmulti_sw = FALSE;
324*43a90889SApple OSS Distributions 		}
325*43a90889SApple OSS Distributions 
326*43a90889SApple OSS Distributions 		if ((rt = pr->ndpr_rt) != NULL) {
327*43a90889SApple OSS Distributions 			if ((enable && prproxy) || (!enable && !prproxy)) {
328*43a90889SApple OSS Distributions 				RT_ADDREF(rt);
329*43a90889SApple OSS Distributions 			} else {
330*43a90889SApple OSS Distributions 				rt = NULL;
331*43a90889SApple OSS Distributions 			}
332*43a90889SApple OSS Distributions 			NDPR_UNLOCK(pr);
333*43a90889SApple OSS Distributions 		} else {
334*43a90889SApple OSS Distributions 			NDPR_UNLOCK(pr);
335*43a90889SApple OSS Distributions 		}
336*43a90889SApple OSS Distributions 		if (set_allmulti && ifp != NULL) {
337*43a90889SApple OSS Distributions 			if_allmulti(ifp, allmulti_sw);
338*43a90889SApple OSS Distributions 		}
339*43a90889SApple OSS Distributions 
340*43a90889SApple OSS Distributions 		NDPR_REMREF(pr);
341*43a90889SApple OSS Distributions 		NDPR_REMREF(pr_up);
342*43a90889SApple OSS Distributions 		if (rt != NULL) {
343*43a90889SApple OSS Distributions 			rt_set_proxy(rt, enable);
344*43a90889SApple OSS Distributions 			rtfree(rt);
345*43a90889SApple OSS Distributions 		}
346*43a90889SApple OSS Distributions 		nd6_ndprl_free(down);
347*43a90889SApple OSS Distributions 	}
348*43a90889SApple OSS Distributions }
349*43a90889SApple OSS Distributions 
350*43a90889SApple OSS Distributions /*
351*43a90889SApple OSS Distributions  * Enable/disable prefix proxying on an interface; typically called
352*43a90889SApple OSS Distributions  * as part of handling SIOCSIFINFO_FLAGS[SETROUTERMODE_IN6]
353*43a90889SApple OSS Distributions  */
354*43a90889SApple OSS Distributions int
nd6_if_prproxy(struct ifnet * ifp,boolean_t enable)355*43a90889SApple OSS Distributions nd6_if_prproxy(struct ifnet *ifp, boolean_t enable)
356*43a90889SApple OSS Distributions {
357*43a90889SApple OSS Distributions 	SLIST_HEAD(, nd6_prproxy_prelist) up_head;
358*43a90889SApple OSS Distributions 	SLIST_HEAD(, nd6_prproxy_prelist) down_head;
359*43a90889SApple OSS Distributions 	struct nd6_prproxy_prelist *__single up, *__single down;
360*43a90889SApple OSS Distributions 	struct nd_prefix *__single pr;
361*43a90889SApple OSS Distributions 
362*43a90889SApple OSS Distributions 	/* Can't be enabled if we are an advertising router on the interface */
363*43a90889SApple OSS Distributions 	ifnet_lock_shared(ifp);
364*43a90889SApple OSS Distributions 	if (enable && (ifp->if_ipv6_router_mode == IPV6_ROUTER_MODE_EXCLUSIVE)) {
365*43a90889SApple OSS Distributions 		ifnet_lock_done(ifp);
366*43a90889SApple OSS Distributions 		return EBUSY;
367*43a90889SApple OSS Distributions 	}
368*43a90889SApple OSS Distributions 	ifnet_lock_done(ifp);
369*43a90889SApple OSS Distributions 
370*43a90889SApple OSS Distributions 	SLIST_INIT(&up_head);
371*43a90889SApple OSS Distributions 	SLIST_INIT(&down_head);
372*43a90889SApple OSS Distributions 
373*43a90889SApple OSS Distributions 	/*
374*43a90889SApple OSS Distributions 	 * Serialize the clearing/setting of NDPRF_PRPROXY.
375*43a90889SApple OSS Distributions 	 */
376*43a90889SApple OSS Distributions 	lck_mtx_lock(&proxy6_lock);
377*43a90889SApple OSS Distributions 
378*43a90889SApple OSS Distributions 	/*
379*43a90889SApple OSS Distributions 	 * First build a list of upstream prefixes on this interface for
380*43a90889SApple OSS Distributions 	 * which we need to enable/disable prefix proxy functionality.
381*43a90889SApple OSS Distributions 	 */
382*43a90889SApple OSS Distributions 	lck_mtx_lock(nd6_mutex);
383*43a90889SApple OSS Distributions 	for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
384*43a90889SApple OSS Distributions 		NDPR_LOCK(pr);
385*43a90889SApple OSS Distributions 		if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr) ||
386*43a90889SApple OSS Distributions 		    (!enable && !(pr->ndpr_stateflags & NDPRF_PRPROXY)) ||
387*43a90889SApple OSS Distributions 		    (enable && (pr->ndpr_stateflags & NDPRF_PRPROXY)) ||
388*43a90889SApple OSS Distributions 		    (pr->ndpr_stateflags & NDPRF_IFSCOPE) ||
389*43a90889SApple OSS Distributions 		    pr->ndpr_ifp != ifp) {
390*43a90889SApple OSS Distributions 			NDPR_UNLOCK(pr);
391*43a90889SApple OSS Distributions 			continue;
392*43a90889SApple OSS Distributions 		}
393*43a90889SApple OSS Distributions 
394*43a90889SApple OSS Distributions 		/*
395*43a90889SApple OSS Distributions 		 * At present, in order for the prefix to be eligible
396*43a90889SApple OSS Distributions 		 * as a proxying/proxied prefix, we require that the
397*43a90889SApple OSS Distributions 		 * prefix route entry be marked as a cloning route with
398*43a90889SApple OSS Distributions 		 * RTF_PROXY; i.e. nd6_need_cache() needs to return
399*43a90889SApple OSS Distributions 		 * true for the interface type.
400*43a90889SApple OSS Distributions 		 */
401*43a90889SApple OSS Distributions 		if (enable && (pr->ndpr_stateflags & NDPRF_ONLINK) &&
402*43a90889SApple OSS Distributions 		    nd6_need_cache(ifp)) {
403*43a90889SApple OSS Distributions 			pr->ndpr_stateflags |= NDPRF_PRPROXY;
404*43a90889SApple OSS Distributions 			NDPR_ADDREF(pr);
405*43a90889SApple OSS Distributions 			NDPR_UNLOCK(pr);
406*43a90889SApple OSS Distributions 		} else if (!enable) {
407*43a90889SApple OSS Distributions 			pr->ndpr_stateflags &= ~NDPRF_PRPROXY;
408*43a90889SApple OSS Distributions 			NDPR_ADDREF(pr);
409*43a90889SApple OSS Distributions 			NDPR_UNLOCK(pr);
410*43a90889SApple OSS Distributions 		} else {
411*43a90889SApple OSS Distributions 			NDPR_UNLOCK(pr);
412*43a90889SApple OSS Distributions 			pr = NULL;      /* don't go further */
413*43a90889SApple OSS Distributions 		}
414*43a90889SApple OSS Distributions 
415*43a90889SApple OSS Distributions 		if (pr == NULL) {
416*43a90889SApple OSS Distributions 			break;
417*43a90889SApple OSS Distributions 		}
418*43a90889SApple OSS Distributions 
419*43a90889SApple OSS Distributions 		up = nd6_ndprl_alloc(Z_WAITOK);
420*43a90889SApple OSS Distributions 		if (up == NULL) {
421*43a90889SApple OSS Distributions 			NDPR_REMREF(pr);
422*43a90889SApple OSS Distributions 			continue;
423*43a90889SApple OSS Distributions 		}
424*43a90889SApple OSS Distributions 
425*43a90889SApple OSS Distributions 		up->ndprl_pr = pr;      /* keep reference from above */
426*43a90889SApple OSS Distributions 		SLIST_INSERT_HEAD(&up_head, up, ndprl_le);
427*43a90889SApple OSS Distributions 	}
428*43a90889SApple OSS Distributions 
429*43a90889SApple OSS Distributions 	/*
430*43a90889SApple OSS Distributions 	 * Now build a list of matching (scoped) downstream prefixes on other
431*43a90889SApple OSS Distributions 	 * interfaces which need to be enabled/disabled accordingly.  Note that
432*43a90889SApple OSS Distributions 	 * the NDPRF_PRPROXY is never set/cleared on the downstream prefixes.
433*43a90889SApple OSS Distributions 	 */
434*43a90889SApple OSS Distributions 	SLIST_FOREACH(up, &up_head, ndprl_le) {
435*43a90889SApple OSS Distributions 		struct nd_prefix *__single fwd;
436*43a90889SApple OSS Distributions 		struct in6_addr pr_addr;
437*43a90889SApple OSS Distributions 		uint32_t pr_ifscope;
438*43a90889SApple OSS Distributions 		u_char pr_len;
439*43a90889SApple OSS Distributions 
440*43a90889SApple OSS Distributions 		pr = up->ndprl_pr;
441*43a90889SApple OSS Distributions 
442*43a90889SApple OSS Distributions 		NDPR_LOCK(pr);
443*43a90889SApple OSS Distributions 		bcopy(&pr->ndpr_prefix.sin6_addr, &pr_addr, sizeof(pr_addr));
444*43a90889SApple OSS Distributions 		pr_len = pr->ndpr_plen;
445*43a90889SApple OSS Distributions 		pr_ifscope = pr->ndpr_prefix.sin6_scope_id;
446*43a90889SApple OSS Distributions 		NDPR_UNLOCK(pr);
447*43a90889SApple OSS Distributions 
448*43a90889SApple OSS Distributions 		for (fwd = nd_prefix.lh_first; fwd; fwd = fwd->ndpr_next) {
449*43a90889SApple OSS Distributions 			NDPR_LOCK(fwd);
450*43a90889SApple OSS Distributions 			if (!(fwd->ndpr_stateflags & NDPRF_ONLINK) ||
451*43a90889SApple OSS Distributions 			    !(fwd->ndpr_stateflags & NDPRF_IFSCOPE) ||
452*43a90889SApple OSS Distributions 			    fwd->ndpr_plen != pr_len ||
453*43a90889SApple OSS Distributions 			    !in6_are_prefix_equal(&fwd->ndpr_prefix.sin6_addr, fwd->ndpr_prefix.sin6_scope_id,
454*43a90889SApple OSS Distributions 			    &pr_addr, pr_ifscope, pr_len)) {
455*43a90889SApple OSS Distributions 				NDPR_UNLOCK(fwd);
456*43a90889SApple OSS Distributions 				continue;
457*43a90889SApple OSS Distributions 			}
458*43a90889SApple OSS Distributions 			NDPR_UNLOCK(fwd);
459*43a90889SApple OSS Distributions 
460*43a90889SApple OSS Distributions 			down = nd6_ndprl_alloc(Z_WAITOK);
461*43a90889SApple OSS Distributions 			if (down == NULL) {
462*43a90889SApple OSS Distributions 				continue;
463*43a90889SApple OSS Distributions 			}
464*43a90889SApple OSS Distributions 
465*43a90889SApple OSS Distributions 			NDPR_ADDREF(fwd);
466*43a90889SApple OSS Distributions 			down->ndprl_pr = fwd;
467*43a90889SApple OSS Distributions 			NDPR_ADDREF(pr);
468*43a90889SApple OSS Distributions 			down->ndprl_up = pr;
469*43a90889SApple OSS Distributions 			SLIST_INSERT_HEAD(&down_head, down, ndprl_le);
470*43a90889SApple OSS Distributions 		}
471*43a90889SApple OSS Distributions 	}
472*43a90889SApple OSS Distributions 	lck_mtx_unlock(nd6_mutex);
473*43a90889SApple OSS Distributions 
474*43a90889SApple OSS Distributions 	/*
475*43a90889SApple OSS Distributions 	 * Apply routing function on prefixes; callee will free resources.
476*43a90889SApple OSS Distributions 	 */
477*43a90889SApple OSS Distributions 	nd6_prproxy_prelist_setroute(enable,
478*43a90889SApple OSS Distributions 	    (struct nd6_prproxy_prelist_head *)&up_head,
479*43a90889SApple OSS Distributions 	    (struct nd6_prproxy_prelist_head *)&down_head);
480*43a90889SApple OSS Distributions 
481*43a90889SApple OSS Distributions 	VERIFY(SLIST_EMPTY(&up_head));
482*43a90889SApple OSS Distributions 	VERIFY(SLIST_EMPTY(&down_head));
483*43a90889SApple OSS Distributions 
484*43a90889SApple OSS Distributions 	lck_mtx_unlock(&proxy6_lock);
485*43a90889SApple OSS Distributions 
486*43a90889SApple OSS Distributions 	return 0;
487*43a90889SApple OSS Distributions }
488*43a90889SApple OSS Distributions 
489*43a90889SApple OSS Distributions /*
490*43a90889SApple OSS Distributions  * Called from the input path to determine whether the packet is destined
491*43a90889SApple OSS Distributions  * to a proxied node; if so, mark the mbuf with PKTFF_PROXY_DST so that
492*43a90889SApple OSS Distributions  * icmp6_input() knows that this is not to be delivered to socket(s).
493*43a90889SApple OSS Distributions  */
494*43a90889SApple OSS Distributions boolean_t
nd6_prproxy_isours(struct mbuf * m,struct ip6_hdr * ip6,struct route_in6 * ro6,unsigned int ifscope)495*43a90889SApple OSS Distributions nd6_prproxy_isours(struct mbuf *m, struct ip6_hdr *ip6, struct route_in6 *ro6,
496*43a90889SApple OSS Distributions     unsigned int ifscope)
497*43a90889SApple OSS Distributions {
498*43a90889SApple OSS Distributions 	rtentry_ref_t rt;
499*43a90889SApple OSS Distributions 	boolean_t ours = FALSE;
500*43a90889SApple OSS Distributions 
501*43a90889SApple OSS Distributions 	if (ip6->ip6_hlim != IPV6_MAXHLIM || ip6->ip6_nxt != IPPROTO_ICMPV6) {
502*43a90889SApple OSS Distributions 		goto done;
503*43a90889SApple OSS Distributions 	}
504*43a90889SApple OSS Distributions 
505*43a90889SApple OSS Distributions 	if (IN6_IS_ADDR_MC_NODELOCAL(&ip6->ip6_dst) ||
506*43a90889SApple OSS Distributions 	    IN6_IS_ADDR_MC_LINKLOCAL(&ip6->ip6_dst)) {
507*43a90889SApple OSS Distributions 		VERIFY(ro6 == NULL);
508*43a90889SApple OSS Distributions 		ours = TRUE;
509*43a90889SApple OSS Distributions 		goto done;
510*43a90889SApple OSS Distributions 	} else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
511*43a90889SApple OSS Distributions 		goto done;
512*43a90889SApple OSS Distributions 	}
513*43a90889SApple OSS Distributions 
514*43a90889SApple OSS Distributions 	if (ro6 == NULL) {
515*43a90889SApple OSS Distributions 		goto done;
516*43a90889SApple OSS Distributions 	}
517*43a90889SApple OSS Distributions 
518*43a90889SApple OSS Distributions 	if ((rt = ro6->ro_rt) != NULL) {
519*43a90889SApple OSS Distributions 		RT_LOCK(rt);
520*43a90889SApple OSS Distributions 	}
521*43a90889SApple OSS Distributions 
522*43a90889SApple OSS Distributions 	if (ROUTE_UNUSABLE(ro6)) {
523*43a90889SApple OSS Distributions 		if (rt != NULL) {
524*43a90889SApple OSS Distributions 			RT_UNLOCK(rt);
525*43a90889SApple OSS Distributions 		}
526*43a90889SApple OSS Distributions 
527*43a90889SApple OSS Distributions 		ROUTE_RELEASE(ro6);
528*43a90889SApple OSS Distributions 
529*43a90889SApple OSS Distributions 		/* Caller must have ensured this condition (not srcrt) */
530*43a90889SApple OSS Distributions 		VERIFY(in6_are_addr_equal_scoped(&ip6->ip6_dst,
531*43a90889SApple OSS Distributions 		    &ro6->ro_dst.sin6_addr, ip6_input_getdstifscope(m), ro6->ro_dst.sin6_scope_id));
532*43a90889SApple OSS Distributions 
533*43a90889SApple OSS Distributions 		rtalloc_scoped_ign((struct route *)ro6, RTF_PRCLONING, ifscope);
534*43a90889SApple OSS Distributions 		if ((rt = ro6->ro_rt) == NULL) {
535*43a90889SApple OSS Distributions 			goto done;
536*43a90889SApple OSS Distributions 		}
537*43a90889SApple OSS Distributions 
538*43a90889SApple OSS Distributions 		RT_LOCK(rt);
539*43a90889SApple OSS Distributions 	}
540*43a90889SApple OSS Distributions 
541*43a90889SApple OSS Distributions 	ours = (rt->rt_flags & RTF_PROXY) ? TRUE : FALSE;
542*43a90889SApple OSS Distributions 	RT_UNLOCK(rt);
543*43a90889SApple OSS Distributions 
544*43a90889SApple OSS Distributions done:
545*43a90889SApple OSS Distributions 	if (ours) {
546*43a90889SApple OSS Distributions 		m->m_pkthdr.pkt_flags |= PKTF_PROXY_DST;
547*43a90889SApple OSS Distributions 	}
548*43a90889SApple OSS Distributions 
549*43a90889SApple OSS Distributions 	return ours;
550*43a90889SApple OSS Distributions }
551*43a90889SApple OSS Distributions 
552*43a90889SApple OSS Distributions /*
553*43a90889SApple OSS Distributions  * Called from the input path to determine whether or not the proxy
554*43a90889SApple OSS Distributions  * route entry is pointing to the correct interface, and to perform
555*43a90889SApple OSS Distributions  * the necessary route fixups otherwise.
556*43a90889SApple OSS Distributions  */
557*43a90889SApple OSS Distributions void
nd6_proxy_find_fwdroute(struct ifnet * ifp,struct route_in6 * ro6)558*43a90889SApple OSS Distributions nd6_proxy_find_fwdroute(struct ifnet *ifp, struct route_in6 *ro6)
559*43a90889SApple OSS Distributions {
560*43a90889SApple OSS Distributions 	struct in6_addr *__single dst6 = &ro6->ro_dst.sin6_addr;
561*43a90889SApple OSS Distributions 	uint32_t dst_ifscope = ro6->ro_dst.sin6_scope_id;
562*43a90889SApple OSS Distributions 	ifnet_ref_t fwd_ifp = NULL;
563*43a90889SApple OSS Distributions 	struct nd_prefix *__single pr;
564*43a90889SApple OSS Distributions 	rtentry_ref_t rt;
565*43a90889SApple OSS Distributions 
566*43a90889SApple OSS Distributions 	if ((rt = ro6->ro_rt) != NULL) {
567*43a90889SApple OSS Distributions 		RT_LOCK(rt);
568*43a90889SApple OSS Distributions 		if (!(rt->rt_flags & RTF_PROXY) || rt->rt_ifp == ifp) {
569*43a90889SApple OSS Distributions 			nd6log2(debug, "%s: found incorrect prefix "
570*43a90889SApple OSS Distributions 			    "proxy route for dst %s on %s\n", if_name(ifp),
571*43a90889SApple OSS Distributions 			    ip6_sprintf(dst6),
572*43a90889SApple OSS Distributions 			    if_name(rt->rt_ifp));
573*43a90889SApple OSS Distributions 			RT_UNLOCK(rt);
574*43a90889SApple OSS Distributions 			/* look it up below */
575*43a90889SApple OSS Distributions 		} else {
576*43a90889SApple OSS Distributions 			RT_UNLOCK(rt);
577*43a90889SApple OSS Distributions 			/*
578*43a90889SApple OSS Distributions 			 * The route is already marked with RTF_PRPROXY and
579*43a90889SApple OSS Distributions 			 * it isn't pointing back to the inbound interface;
580*43a90889SApple OSS Distributions 			 * optimistically return (see notes below).
581*43a90889SApple OSS Distributions 			 */
582*43a90889SApple OSS Distributions 			return;
583*43a90889SApple OSS Distributions 		}
584*43a90889SApple OSS Distributions 	}
585*43a90889SApple OSS Distributions 
586*43a90889SApple OSS Distributions 	/*
587*43a90889SApple OSS Distributions 	 * Find out where we should forward this packet to, by searching
588*43a90889SApple OSS Distributions 	 * for another interface that is proxying for the prefix.  Our
589*43a90889SApple OSS Distributions 	 * current implementation assumes that the proxied prefix is shared
590*43a90889SApple OSS Distributions 	 * to no more than one downstream interfaces (typically a bridge
591*43a90889SApple OSS Distributions 	 * interface).
592*43a90889SApple OSS Distributions 	 */
593*43a90889SApple OSS Distributions 	lck_mtx_lock(nd6_mutex);
594*43a90889SApple OSS Distributions 	for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
595*43a90889SApple OSS Distributions 		struct in6_addr pr_addr;
596*43a90889SApple OSS Distributions 		struct nd_prefix *__single fwd;
597*43a90889SApple OSS Distributions 		uint32_t pr_ifscope = pr->ndpr_prefix.sin6_scope_id;
598*43a90889SApple OSS Distributions 
599*43a90889SApple OSS Distributions 		u_char pr_len;
600*43a90889SApple OSS Distributions 
601*43a90889SApple OSS Distributions 		NDPR_LOCK(pr);
602*43a90889SApple OSS Distributions 		if (!(pr->ndpr_stateflags & NDPRF_ONLINK) ||
603*43a90889SApple OSS Distributions 		    !(pr->ndpr_stateflags & NDPRF_PRPROXY) ||
604*43a90889SApple OSS Distributions 		    !in6_are_masked_addr_scope_equal(&pr->ndpr_prefix.sin6_addr, pr_ifscope,
605*43a90889SApple OSS Distributions 		    dst6, dst_ifscope, &pr->ndpr_mask)) {
606*43a90889SApple OSS Distributions 			NDPR_UNLOCK(pr);
607*43a90889SApple OSS Distributions 			continue;
608*43a90889SApple OSS Distributions 		}
609*43a90889SApple OSS Distributions 
610*43a90889SApple OSS Distributions 		VERIFY(!(pr->ndpr_stateflags & NDPRF_IFSCOPE));
611*43a90889SApple OSS Distributions 		bcopy(&pr->ndpr_prefix.sin6_addr, &pr_addr, sizeof(pr_addr));
612*43a90889SApple OSS Distributions 		pr_len = pr->ndpr_plen;
613*43a90889SApple OSS Distributions 		NDPR_UNLOCK(pr);
614*43a90889SApple OSS Distributions 
615*43a90889SApple OSS Distributions 		for (fwd = nd_prefix.lh_first; fwd; fwd = fwd->ndpr_next) {
616*43a90889SApple OSS Distributions 			NDPR_LOCK(fwd);
617*43a90889SApple OSS Distributions 			if (!(fwd->ndpr_stateflags & NDPRF_ONLINK) ||
618*43a90889SApple OSS Distributions 			    fwd->ndpr_ifp == ifp ||
619*43a90889SApple OSS Distributions 			    fwd->ndpr_plen != pr_len ||
620*43a90889SApple OSS Distributions 			    !in6_are_prefix_equal(&fwd->ndpr_prefix.sin6_addr, fwd->ndpr_prefix.sin6_scope_id,
621*43a90889SApple OSS Distributions 			    &pr_addr, pr_ifscope, pr_len)) {
622*43a90889SApple OSS Distributions 				NDPR_UNLOCK(fwd);
623*43a90889SApple OSS Distributions 				continue;
624*43a90889SApple OSS Distributions 			}
625*43a90889SApple OSS Distributions 
626*43a90889SApple OSS Distributions 			fwd_ifp = fwd->ndpr_ifp;
627*43a90889SApple OSS Distributions 			NDPR_UNLOCK(fwd);
628*43a90889SApple OSS Distributions 			break;
629*43a90889SApple OSS Distributions 		}
630*43a90889SApple OSS Distributions 		break;
631*43a90889SApple OSS Distributions 	}
632*43a90889SApple OSS Distributions 	lck_mtx_unlock(nd6_mutex);
633*43a90889SApple OSS Distributions 
634*43a90889SApple OSS Distributions 	lck_mtx_lock(rnh_lock);
635*43a90889SApple OSS Distributions 	ROUTE_RELEASE_LOCKED(ro6);
636*43a90889SApple OSS Distributions 
637*43a90889SApple OSS Distributions 	/*
638*43a90889SApple OSS Distributions 	 * Lookup a forwarding route; delete the route if it's incorrect,
639*43a90889SApple OSS Distributions 	 * or return to caller if the correct one got created prior to
640*43a90889SApple OSS Distributions 	 * our acquiring the rnh_lock.
641*43a90889SApple OSS Distributions 	 */
642*43a90889SApple OSS Distributions 	if ((rt = rtalloc1_scoped_locked(SA(&ro6->ro_dst), 0,
643*43a90889SApple OSS Distributions 	    RTF_CLONING | RTF_PRCLONING, IFSCOPE_NONE)) != NULL) {
644*43a90889SApple OSS Distributions 		RT_LOCK(rt);
645*43a90889SApple OSS Distributions 		if (rt->rt_ifp != fwd_ifp || !(rt->rt_flags & RTF_PROXY)) {
646*43a90889SApple OSS Distributions 			rt->rt_flags |= RTF_CONDEMNED;
647*43a90889SApple OSS Distributions 			RT_UNLOCK(rt);
648*43a90889SApple OSS Distributions 			(void) rtrequest_locked(RTM_DELETE, rt_key(rt),
649*43a90889SApple OSS Distributions 			    rt->rt_gateway, rt_mask(rt), rt->rt_flags, NULL);
650*43a90889SApple OSS Distributions 			rtfree_locked(rt);
651*43a90889SApple OSS Distributions 			rt = NULL;
652*43a90889SApple OSS Distributions 		} else {
653*43a90889SApple OSS Distributions 			nd6log2(debug, "%s: found prefix proxy route "
654*43a90889SApple OSS Distributions 			    "for dst %s\n", if_name(rt->rt_ifp),
655*43a90889SApple OSS Distributions 			    ip6_sprintf(dst6));
656*43a90889SApple OSS Distributions 			RT_UNLOCK(rt);
657*43a90889SApple OSS Distributions 			ro6->ro_rt = rt;        /* refcnt held by rtalloc1 */
658*43a90889SApple OSS Distributions 			lck_mtx_unlock(rnh_lock);
659*43a90889SApple OSS Distributions 			return;
660*43a90889SApple OSS Distributions 		}
661*43a90889SApple OSS Distributions 	}
662*43a90889SApple OSS Distributions 	VERIFY(rt == NULL && ro6->ro_rt == NULL);
663*43a90889SApple OSS Distributions 
664*43a90889SApple OSS Distributions 	/*
665*43a90889SApple OSS Distributions 	 * Clone a route from the correct parent prefix route and return it.
666*43a90889SApple OSS Distributions 	 */
667*43a90889SApple OSS Distributions 	if (fwd_ifp != NULL && (rt = rtalloc1_scoped_locked(SA(&ro6->ro_dst), 1,
668*43a90889SApple OSS Distributions 	    RTF_PRCLONING, fwd_ifp->if_index)) != NULL) {
669*43a90889SApple OSS Distributions 		RT_LOCK(rt);
670*43a90889SApple OSS Distributions 		if (!(rt->rt_flags & RTF_PROXY)) {
671*43a90889SApple OSS Distributions 			RT_UNLOCK(rt);
672*43a90889SApple OSS Distributions 			rtfree_locked(rt);
673*43a90889SApple OSS Distributions 			rt = NULL;
674*43a90889SApple OSS Distributions 		} else {
675*43a90889SApple OSS Distributions 			nd6log2(debug, "%s: allocated prefix proxy "
676*43a90889SApple OSS Distributions 			    "route for dst %s\n", if_name(rt->rt_ifp),
677*43a90889SApple OSS Distributions 			    ip6_sprintf(dst6));
678*43a90889SApple OSS Distributions 			RT_UNLOCK(rt);
679*43a90889SApple OSS Distributions 			ro6->ro_rt = rt;        /* refcnt held by rtalloc1 */
680*43a90889SApple OSS Distributions 		}
681*43a90889SApple OSS Distributions 	}
682*43a90889SApple OSS Distributions 	VERIFY(rt != NULL || ro6->ro_rt == NULL);
683*43a90889SApple OSS Distributions 
684*43a90889SApple OSS Distributions 	if (fwd_ifp == NULL || rt == NULL) {
685*43a90889SApple OSS Distributions 		nd6log2(error, "%s: failed to find forwarding prefix "
686*43a90889SApple OSS Distributions 		    "proxy entry for dst %s\n", if_name(ifp),
687*43a90889SApple OSS Distributions 		    ip6_sprintf(dst6));
688*43a90889SApple OSS Distributions 	}
689*43a90889SApple OSS Distributions 	lck_mtx_unlock(rnh_lock);
690*43a90889SApple OSS Distributions }
691*43a90889SApple OSS Distributions 
692*43a90889SApple OSS Distributions /*
693*43a90889SApple OSS Distributions  * Called when a prefix transitions between on-link and off-link.  Perform
694*43a90889SApple OSS Distributions  * routing (RTF_PROXY) and interface (all-multicast) related operations on
695*43a90889SApple OSS Distributions  * the affected prefixes.
696*43a90889SApple OSS Distributions  */
697*43a90889SApple OSS Distributions void
nd6_prproxy_prelist_update(struct nd_prefix * pr_cur,struct nd_prefix * pr_up)698*43a90889SApple OSS Distributions nd6_prproxy_prelist_update(struct nd_prefix *pr_cur, struct nd_prefix *pr_up)
699*43a90889SApple OSS Distributions {
700*43a90889SApple OSS Distributions 	SLIST_HEAD(, nd6_prproxy_prelist) up_head;
701*43a90889SApple OSS Distributions 	SLIST_HEAD(, nd6_prproxy_prelist) down_head;
702*43a90889SApple OSS Distributions 	struct nd6_prproxy_prelist *__single up, *__single down;
703*43a90889SApple OSS Distributions 	struct nd_prefix *__single pr;
704*43a90889SApple OSS Distributions 	struct in6_addr pr_addr;
705*43a90889SApple OSS Distributions 	boolean_t enable;
706*43a90889SApple OSS Distributions 	u_char pr_len;
707*43a90889SApple OSS Distributions 	uint32_t pr_ifscope;
708*43a90889SApple OSS Distributions 
709*43a90889SApple OSS Distributions 	SLIST_INIT(&up_head);
710*43a90889SApple OSS Distributions 	SLIST_INIT(&down_head);
711*43a90889SApple OSS Distributions 	VERIFY(pr_cur != NULL);
712*43a90889SApple OSS Distributions 
713*43a90889SApple OSS Distributions 	LCK_MTX_ASSERT(&proxy6_lock, LCK_MTX_ASSERT_OWNED);
714*43a90889SApple OSS Distributions 
715*43a90889SApple OSS Distributions 	/*
716*43a90889SApple OSS Distributions 	 * Upstream prefix.  If caller did not specify one, search for one
717*43a90889SApple OSS Distributions 	 * based on the information in current prefix.  Caller is expected
718*43a90889SApple OSS Distributions 	 * to have held an extra reference for the passed-in prefixes.
719*43a90889SApple OSS Distributions 	 */
720*43a90889SApple OSS Distributions 	lck_mtx_lock(nd6_mutex);
721*43a90889SApple OSS Distributions 	if (pr_up == NULL) {
722*43a90889SApple OSS Distributions 		NDPR_LOCK(pr_cur);
723*43a90889SApple OSS Distributions 		bcopy(&pr_cur->ndpr_prefix.sin6_addr, &pr_addr,
724*43a90889SApple OSS Distributions 		    sizeof(pr_addr));
725*43a90889SApple OSS Distributions 		pr_len = pr_cur->ndpr_plen;
726*43a90889SApple OSS Distributions 		pr_ifscope = pr_cur->ndpr_prefix.sin6_scope_id;
727*43a90889SApple OSS Distributions 		NDPR_UNLOCK(pr_cur);
728*43a90889SApple OSS Distributions 
729*43a90889SApple OSS Distributions 		for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
730*43a90889SApple OSS Distributions 			NDPR_LOCK(pr);
731*43a90889SApple OSS Distributions 			if (!(pr->ndpr_stateflags & NDPRF_ONLINK) ||
732*43a90889SApple OSS Distributions 			    !(pr->ndpr_stateflags & NDPRF_PRPROXY) ||
733*43a90889SApple OSS Distributions 			    pr->ndpr_plen != pr_len ||
734*43a90889SApple OSS Distributions 			    !in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, pr->ndpr_prefix.sin6_scope_id,
735*43a90889SApple OSS Distributions 			    &pr_addr, pr_ifscope, pr_len)) {
736*43a90889SApple OSS Distributions 				NDPR_UNLOCK(pr);
737*43a90889SApple OSS Distributions 				continue;
738*43a90889SApple OSS Distributions 			}
739*43a90889SApple OSS Distributions 			NDPR_UNLOCK(pr);
740*43a90889SApple OSS Distributions 			break;
741*43a90889SApple OSS Distributions 		}
742*43a90889SApple OSS Distributions 
743*43a90889SApple OSS Distributions 		if ((pr_up = pr) == NULL) {
744*43a90889SApple OSS Distributions 			lck_mtx_unlock(nd6_mutex);
745*43a90889SApple OSS Distributions 			goto done;
746*43a90889SApple OSS Distributions 		}
747*43a90889SApple OSS Distributions 		NDPR_LOCK(pr_up);
748*43a90889SApple OSS Distributions 	} else {
749*43a90889SApple OSS Distributions 		NDPR_LOCK(pr_up);
750*43a90889SApple OSS Distributions 		bcopy(&pr_up->ndpr_prefix.sin6_addr, &pr_addr,
751*43a90889SApple OSS Distributions 		    sizeof(pr_addr));
752*43a90889SApple OSS Distributions 		pr_ifscope = pr_up->ndpr_prefix.sin6_scope_id;
753*43a90889SApple OSS Distributions 		pr_len = pr_up->ndpr_plen;
754*43a90889SApple OSS Distributions 	}
755*43a90889SApple OSS Distributions 	NDPR_LOCK_ASSERT_HELD(pr_up);
756*43a90889SApple OSS Distributions 	/*
757*43a90889SApple OSS Distributions 	 * Upstream prefix could be offlink by now; therefore we cannot
758*43a90889SApple OSS Distributions 	 * assert that NDPRF_PRPROXY is set; however, we can insist that
759*43a90889SApple OSS Distributions 	 * it must not be a scoped prefix.
760*43a90889SApple OSS Distributions 	 */
761*43a90889SApple OSS Distributions 	VERIFY(!(pr_up->ndpr_stateflags & NDPRF_IFSCOPE));
762*43a90889SApple OSS Distributions 	enable = (pr_up->ndpr_stateflags & NDPRF_PRPROXY);
763*43a90889SApple OSS Distributions 	NDPR_UNLOCK(pr_up);
764*43a90889SApple OSS Distributions 
765*43a90889SApple OSS Distributions 	up = nd6_ndprl_alloc(Z_WAITOK);
766*43a90889SApple OSS Distributions 	if (up == NULL) {
767*43a90889SApple OSS Distributions 		lck_mtx_unlock(nd6_mutex);
768*43a90889SApple OSS Distributions 		goto done;
769*43a90889SApple OSS Distributions 	}
770*43a90889SApple OSS Distributions 
771*43a90889SApple OSS Distributions 	NDPR_ADDREF(pr_up);
772*43a90889SApple OSS Distributions 	up->ndprl_pr = pr_up;
773*43a90889SApple OSS Distributions 	SLIST_INSERT_HEAD(&up_head, up, ndprl_le);
774*43a90889SApple OSS Distributions 
775*43a90889SApple OSS Distributions 	/*
776*43a90889SApple OSS Distributions 	 * Now build a list of matching (scoped) downstream prefixes on other
777*43a90889SApple OSS Distributions 	 * interfaces which need to be enabled/disabled accordingly.  Note that
778*43a90889SApple OSS Distributions 	 * the NDPRF_PRPROXY is never set/cleared on the downstream prefixes.
779*43a90889SApple OSS Distributions 	 */
780*43a90889SApple OSS Distributions 	for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
781*43a90889SApple OSS Distributions 		NDPR_LOCK(pr);
782*43a90889SApple OSS Distributions 		if (!(pr->ndpr_stateflags & NDPRF_ONLINK) ||
783*43a90889SApple OSS Distributions 		    !(pr->ndpr_stateflags & NDPRF_IFSCOPE) ||
784*43a90889SApple OSS Distributions 		    pr->ndpr_plen != pr_len ||
785*43a90889SApple OSS Distributions 		    !in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, pr->ndpr_prefix.sin6_scope_id,
786*43a90889SApple OSS Distributions 		    &pr_addr, pr_ifscope, pr_len)) {
787*43a90889SApple OSS Distributions 			NDPR_UNLOCK(pr);
788*43a90889SApple OSS Distributions 			continue;
789*43a90889SApple OSS Distributions 		}
790*43a90889SApple OSS Distributions 		NDPR_UNLOCK(pr);
791*43a90889SApple OSS Distributions 
792*43a90889SApple OSS Distributions 		down = nd6_ndprl_alloc(Z_WAITOK);
793*43a90889SApple OSS Distributions 		if (down == NULL) {
794*43a90889SApple OSS Distributions 			continue;
795*43a90889SApple OSS Distributions 		}
796*43a90889SApple OSS Distributions 
797*43a90889SApple OSS Distributions 		NDPR_ADDREF(pr);
798*43a90889SApple OSS Distributions 		down->ndprl_pr = pr;
799*43a90889SApple OSS Distributions 		NDPR_ADDREF(pr_up);
800*43a90889SApple OSS Distributions 		down->ndprl_up = pr_up;
801*43a90889SApple OSS Distributions 		SLIST_INSERT_HEAD(&down_head, down, ndprl_le);
802*43a90889SApple OSS Distributions 	}
803*43a90889SApple OSS Distributions 	lck_mtx_unlock(nd6_mutex);
804*43a90889SApple OSS Distributions 
805*43a90889SApple OSS Distributions 	/*
806*43a90889SApple OSS Distributions 	 * Apply routing function on prefixes; callee will free resources.
807*43a90889SApple OSS Distributions 	 */
808*43a90889SApple OSS Distributions 	nd6_prproxy_prelist_setroute(enable,
809*43a90889SApple OSS Distributions 	    (struct nd6_prproxy_prelist_head *)&up_head,
810*43a90889SApple OSS Distributions 	    (struct nd6_prproxy_prelist_head *)&down_head);
811*43a90889SApple OSS Distributions 
812*43a90889SApple OSS Distributions done:
813*43a90889SApple OSS Distributions 	VERIFY(SLIST_EMPTY(&up_head));
814*43a90889SApple OSS Distributions 	VERIFY(SLIST_EMPTY(&down_head));
815*43a90889SApple OSS Distributions }
816*43a90889SApple OSS Distributions 
817*43a90889SApple OSS Distributions /*
818*43a90889SApple OSS Distributions  * Given an interface address, determine whether or not the address
819*43a90889SApple OSS Distributions  * is part of of a proxied prefix.
820*43a90889SApple OSS Distributions  */
821*43a90889SApple OSS Distributions boolean_t
nd6_prproxy_ifaddr(struct in6_ifaddr * ia)822*43a90889SApple OSS Distributions nd6_prproxy_ifaddr(struct in6_ifaddr *ia)
823*43a90889SApple OSS Distributions {
824*43a90889SApple OSS Distributions 	struct nd_prefix *__single pr;
825*43a90889SApple OSS Distributions 	struct in6_addr addr;
826*43a90889SApple OSS Distributions 	u_int32_t pr_len;
827*43a90889SApple OSS Distributions 	uint32_t pr_scope_id;
828*43a90889SApple OSS Distributions 	boolean_t proxied = FALSE;
829*43a90889SApple OSS Distributions 
830*43a90889SApple OSS Distributions 	LCK_MTX_ASSERT(nd6_mutex, LCK_MTX_ASSERT_NOTOWNED);
831*43a90889SApple OSS Distributions 
832*43a90889SApple OSS Distributions 	IFA_LOCK(&ia->ia_ifa);
833*43a90889SApple OSS Distributions 	bcopy(&ia->ia_addr.sin6_addr, &addr, sizeof(addr));
834*43a90889SApple OSS Distributions 	pr_len = ia->ia_plen;
835*43a90889SApple OSS Distributions 	pr_scope_id = IA6_SIN6_SCOPE(ia);
836*43a90889SApple OSS Distributions 	IFA_UNLOCK(&ia->ia_ifa);
837*43a90889SApple OSS Distributions 
838*43a90889SApple OSS Distributions 	lck_mtx_lock(nd6_mutex);
839*43a90889SApple OSS Distributions 	for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
840*43a90889SApple OSS Distributions 		NDPR_LOCK(pr);
841*43a90889SApple OSS Distributions 		if ((pr->ndpr_stateflags & NDPRF_ONLINK) &&
842*43a90889SApple OSS Distributions 		    (pr->ndpr_stateflags & NDPRF_PRPROXY) &&
843*43a90889SApple OSS Distributions 		    in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, pr->ndpr_prefix.sin6_scope_id,
844*43a90889SApple OSS Distributions 		    &addr, pr_scope_id, pr_len)) {
845*43a90889SApple OSS Distributions 			NDPR_UNLOCK(pr);
846*43a90889SApple OSS Distributions 			proxied = TRUE;
847*43a90889SApple OSS Distributions 			break;
848*43a90889SApple OSS Distributions 		}
849*43a90889SApple OSS Distributions 		NDPR_UNLOCK(pr);
850*43a90889SApple OSS Distributions 	}
851*43a90889SApple OSS Distributions 	lck_mtx_unlock(nd6_mutex);
852*43a90889SApple OSS Distributions 
853*43a90889SApple OSS Distributions 	return proxied;
854*43a90889SApple OSS Distributions }
855*43a90889SApple OSS Distributions 
856*43a90889SApple OSS Distributions /*
857*43a90889SApple OSS Distributions  * Perform automatic proxy function with NS output.
858*43a90889SApple OSS Distributions  *
859*43a90889SApple OSS Distributions  * If the target address matches a global prefix obtained from a router
860*43a90889SApple OSS Distributions  * advertisement received on an interface with the ND6_IFF_PROXY_PREFIXES
861*43a90889SApple OSS Distributions  * flag set, then we send solicitations for the target address to all other
862*43a90889SApple OSS Distributions  * interfaces where a matching prefix is currently on-link, in addition to
863*43a90889SApple OSS Distributions  * the original interface.
864*43a90889SApple OSS Distributions  */
865*43a90889SApple OSS Distributions void
nd6_prproxy_ns_output(struct ifnet * ifp,struct ifnet * exclifp,struct in6_addr * daddr,struct in6_addr * taddr,struct llinfo_nd6 * ln)866*43a90889SApple OSS Distributions nd6_prproxy_ns_output(struct ifnet *ifp, struct ifnet *exclifp,
867*43a90889SApple OSS Distributions     struct in6_addr *daddr, struct in6_addr *taddr, struct llinfo_nd6 *ln)
868*43a90889SApple OSS Distributions {
869*43a90889SApple OSS Distributions 	SLIST_HEAD(, nd6_prproxy_prelist) ndprl_head;
870*43a90889SApple OSS Distributions 	struct nd6_prproxy_prelist *__single ndprl, *__single ndprl_tmp;
871*43a90889SApple OSS Distributions 	struct nd_prefix *__single pr, *__single fwd;
872*43a90889SApple OSS Distributions 	ifnet_ref_t fwd_ifp;
873*43a90889SApple OSS Distributions 	struct in6_addr pr_addr;
874*43a90889SApple OSS Distributions 	u_char pr_len;
875*43a90889SApple OSS Distributions 	uint32_t pr_scope_id;
876*43a90889SApple OSS Distributions 	uint32_t taddr_ifscope = ifp->if_index;
877*43a90889SApple OSS Distributions 
878*43a90889SApple OSS Distributions 	/*
879*43a90889SApple OSS Distributions 	 * Ignore excluded interface if it's the same as the original;
880*43a90889SApple OSS Distributions 	 * we always send a NS on the original interface down below.
881*43a90889SApple OSS Distributions 	 */
882*43a90889SApple OSS Distributions 	if (exclifp != NULL && exclifp == ifp) {
883*43a90889SApple OSS Distributions 		exclifp = NULL;
884*43a90889SApple OSS Distributions 	}
885*43a90889SApple OSS Distributions 
886*43a90889SApple OSS Distributions 	if (exclifp == NULL) {
887*43a90889SApple OSS Distributions 		nd6log2(debug, "%s: sending NS who has %s on ALL\n",
888*43a90889SApple OSS Distributions 		    if_name(ifp), ip6_sprintf(taddr));
889*43a90889SApple OSS Distributions 	} else {
890*43a90889SApple OSS Distributions 		nd6log2(debug, "%s: sending NS who has %s on ALL "
891*43a90889SApple OSS Distributions 		    "(except %s)\n", if_name(ifp),
892*43a90889SApple OSS Distributions 		    ip6_sprintf(taddr), if_name(exclifp));
893*43a90889SApple OSS Distributions 	}
894*43a90889SApple OSS Distributions 
895*43a90889SApple OSS Distributions 	SLIST_INIT(&ndprl_head);
896*43a90889SApple OSS Distributions 
897*43a90889SApple OSS Distributions 	lck_mtx_lock(nd6_mutex);
898*43a90889SApple OSS Distributions 
899*43a90889SApple OSS Distributions 	for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
900*43a90889SApple OSS Distributions 		NDPR_LOCK(pr);
901*43a90889SApple OSS Distributions 		pr_scope_id = pr->ndpr_prefix.sin6_scope_id;
902*43a90889SApple OSS Distributions 
903*43a90889SApple OSS Distributions 		if (!(pr->ndpr_stateflags & NDPRF_ONLINK) ||
904*43a90889SApple OSS Distributions 		    !(pr->ndpr_stateflags & NDPRF_PRPROXY) ||
905*43a90889SApple OSS Distributions 		    !in6_are_masked_addr_scope_equal(&pr->ndpr_prefix.sin6_addr, pr_scope_id,
906*43a90889SApple OSS Distributions 		    taddr, taddr_ifscope, &pr->ndpr_mask)) {
907*43a90889SApple OSS Distributions 			NDPR_UNLOCK(pr);
908*43a90889SApple OSS Distributions 			continue;
909*43a90889SApple OSS Distributions 		}
910*43a90889SApple OSS Distributions 
911*43a90889SApple OSS Distributions 		VERIFY(!(pr->ndpr_stateflags & NDPRF_IFSCOPE));
912*43a90889SApple OSS Distributions 		bcopy(&pr->ndpr_prefix.sin6_addr, &pr_addr, sizeof(pr_addr));
913*43a90889SApple OSS Distributions 		pr_len = pr->ndpr_plen;
914*43a90889SApple OSS Distributions 		NDPR_UNLOCK(pr);
915*43a90889SApple OSS Distributions 
916*43a90889SApple OSS Distributions 		for (fwd = nd_prefix.lh_first; fwd; fwd = fwd->ndpr_next) {
917*43a90889SApple OSS Distributions 			NDPR_LOCK(fwd);
918*43a90889SApple OSS Distributions 			if (!(fwd->ndpr_stateflags & NDPRF_ONLINK) ||
919*43a90889SApple OSS Distributions 			    fwd->ndpr_ifp == ifp || fwd->ndpr_ifp == exclifp ||
920*43a90889SApple OSS Distributions 			    fwd->ndpr_plen != pr_len ||
921*43a90889SApple OSS Distributions 			    !in6_are_prefix_equal(&fwd->ndpr_prefix.sin6_addr, fwd->ndpr_prefix.sin6_scope_id,
922*43a90889SApple OSS Distributions 			    &pr_addr, pr_scope_id, pr_len)) {
923*43a90889SApple OSS Distributions 				NDPR_UNLOCK(fwd);
924*43a90889SApple OSS Distributions 				continue;
925*43a90889SApple OSS Distributions 			}
926*43a90889SApple OSS Distributions 
927*43a90889SApple OSS Distributions 			fwd_ifp = fwd->ndpr_ifp;
928*43a90889SApple OSS Distributions 			NDPR_UNLOCK(fwd);
929*43a90889SApple OSS Distributions 
930*43a90889SApple OSS Distributions 			ndprl = nd6_ndprl_alloc(Z_WAITOK);
931*43a90889SApple OSS Distributions 			if (ndprl == NULL) {
932*43a90889SApple OSS Distributions 				continue;
933*43a90889SApple OSS Distributions 			}
934*43a90889SApple OSS Distributions 
935*43a90889SApple OSS Distributions 			NDPR_ADDREF(fwd);
936*43a90889SApple OSS Distributions 			ndprl->ndprl_pr = fwd;
937*43a90889SApple OSS Distributions 			ndprl->ndprl_fwd_ifp = fwd_ifp;
938*43a90889SApple OSS Distributions 
939*43a90889SApple OSS Distributions 			SLIST_INSERT_HEAD(&ndprl_head, ndprl, ndprl_le);
940*43a90889SApple OSS Distributions 		}
941*43a90889SApple OSS Distributions 		break;
942*43a90889SApple OSS Distributions 	}
943*43a90889SApple OSS Distributions 
944*43a90889SApple OSS Distributions 	lck_mtx_unlock(nd6_mutex);
945*43a90889SApple OSS Distributions 
946*43a90889SApple OSS Distributions 	SLIST_FOREACH_SAFE(ndprl, &ndprl_head, ndprl_le, ndprl_tmp) {
947*43a90889SApple OSS Distributions 		SLIST_REMOVE(&ndprl_head, ndprl, nd6_prproxy_prelist, ndprl_le);
948*43a90889SApple OSS Distributions 
949*43a90889SApple OSS Distributions 		pr = ndprl->ndprl_pr;
950*43a90889SApple OSS Distributions 		fwd_ifp = ndprl->ndprl_fwd_ifp;
951*43a90889SApple OSS Distributions 
952*43a90889SApple OSS Distributions 		if ((fwd_ifp->if_eflags & IFEF_IPV6_ND6ALT) != 0) {
953*43a90889SApple OSS Distributions 			NDPR_REMREF(pr);
954*43a90889SApple OSS Distributions 			nd6_ndprl_free(ndprl);
955*43a90889SApple OSS Distributions 			continue;
956*43a90889SApple OSS Distributions 		}
957*43a90889SApple OSS Distributions 
958*43a90889SApple OSS Distributions 		NDPR_LOCK(pr);
959*43a90889SApple OSS Distributions 		if (pr->ndpr_stateflags & NDPRF_ONLINK) {
960*43a90889SApple OSS Distributions 			NDPR_UNLOCK(pr);
961*43a90889SApple OSS Distributions 			nd6log2(debug,
962*43a90889SApple OSS Distributions 			    "%s: Sending cloned NS who has %s, originally "
963*43a90889SApple OSS Distributions 			    "on %s\n", if_name(fwd_ifp),
964*43a90889SApple OSS Distributions 			    ip6_sprintf(taddr), if_name(ifp));
965*43a90889SApple OSS Distributions 
966*43a90889SApple OSS Distributions 			nd6_ns_output(fwd_ifp, daddr, taddr, NULL, NULL, 0);
967*43a90889SApple OSS Distributions 		} else {
968*43a90889SApple OSS Distributions 			NDPR_UNLOCK(pr);
969*43a90889SApple OSS Distributions 		}
970*43a90889SApple OSS Distributions 		NDPR_REMREF(pr);
971*43a90889SApple OSS Distributions 
972*43a90889SApple OSS Distributions 		nd6_ndprl_free(ndprl);
973*43a90889SApple OSS Distributions 	}
974*43a90889SApple OSS Distributions 	VERIFY(SLIST_EMPTY(&ndprl_head));
975*43a90889SApple OSS Distributions 
976*43a90889SApple OSS Distributions 	nd6_ns_output(ifp, daddr, taddr, ln, NULL, 0);
977*43a90889SApple OSS Distributions }
978*43a90889SApple OSS Distributions 
979*43a90889SApple OSS Distributions /*
980*43a90889SApple OSS Distributions  * Perform automatic proxy function with NS input.
981*43a90889SApple OSS Distributions  *
982*43a90889SApple OSS Distributions  * If the target address matches a global prefix obtained from a router
983*43a90889SApple OSS Distributions  * advertisement received on an interface with the ND6_IFF_PROXY_PREFIXES
984*43a90889SApple OSS Distributions  * flag set, then we send solicitations for the target address to all other
985*43a90889SApple OSS Distributions  * interfaces where a matching prefix is currently on-link.
986*43a90889SApple OSS Distributions  */
987*43a90889SApple OSS Distributions void
nd6_prproxy_ns_input(struct ifnet * ifp,struct in6_addr * saddr,char * __sized_by (lladdrlen)lladdr,int lladdrlen,struct in6_addr * daddr,struct in6_addr * taddr,uint8_t * __counted_by (noncelen)nonce,size_t noncelen)988*43a90889SApple OSS Distributions nd6_prproxy_ns_input(struct ifnet *ifp, struct in6_addr *saddr,
989*43a90889SApple OSS Distributions     char *__sized_by(lladdrlen)lladdr, int lladdrlen, struct in6_addr *daddr,
990*43a90889SApple OSS Distributions     struct in6_addr *taddr, uint8_t *__counted_by(noncelen) nonce, size_t noncelen)
991*43a90889SApple OSS Distributions {
992*43a90889SApple OSS Distributions 	SLIST_HEAD(, nd6_prproxy_prelist) ndprl_head;
993*43a90889SApple OSS Distributions 	struct nd6_prproxy_prelist *__single ndprl, *__single ndprl_tmp;
994*43a90889SApple OSS Distributions 	struct nd_prefix *__single pr, *__single fwd;
995*43a90889SApple OSS Distributions 	ifnet_ref_t fwd_ifp;
996*43a90889SApple OSS Distributions 	struct in6_addr pr_addr;
997*43a90889SApple OSS Distributions 	u_char pr_len;
998*43a90889SApple OSS Distributions 	boolean_t solrec = FALSE;
999*43a90889SApple OSS Distributions 	uint32_t pr_scope_id;
1000*43a90889SApple OSS Distributions 	uint32_t taddr_ifscope = ifp->if_index;
1001*43a90889SApple OSS Distributions 
1002*43a90889SApple OSS Distributions 	SLIST_INIT(&ndprl_head);
1003*43a90889SApple OSS Distributions 
1004*43a90889SApple OSS Distributions 	lck_mtx_lock(nd6_mutex);
1005*43a90889SApple OSS Distributions 
1006*43a90889SApple OSS Distributions 	for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
1007*43a90889SApple OSS Distributions 		NDPR_LOCK(pr);
1008*43a90889SApple OSS Distributions 		pr_scope_id = pr->ndpr_prefix.sin6_scope_id;
1009*43a90889SApple OSS Distributions 
1010*43a90889SApple OSS Distributions 		if (!(pr->ndpr_stateflags & NDPRF_ONLINK) ||
1011*43a90889SApple OSS Distributions 		    !(pr->ndpr_stateflags & NDPRF_PRPROXY) ||
1012*43a90889SApple OSS Distributions 		    !in6_are_masked_addr_scope_equal(&pr->ndpr_prefix.sin6_addr, pr_scope_id,
1013*43a90889SApple OSS Distributions 		    taddr, taddr_ifscope, &pr->ndpr_mask)) {
1014*43a90889SApple OSS Distributions 			NDPR_UNLOCK(pr);
1015*43a90889SApple OSS Distributions 			continue;
1016*43a90889SApple OSS Distributions 		}
1017*43a90889SApple OSS Distributions 
1018*43a90889SApple OSS Distributions 		VERIFY(!(pr->ndpr_stateflags & NDPRF_IFSCOPE));
1019*43a90889SApple OSS Distributions 		bcopy(&pr->ndpr_prefix.sin6_addr, &pr_addr, sizeof(pr_addr));
1020*43a90889SApple OSS Distributions 		pr_len = pr->ndpr_plen;
1021*43a90889SApple OSS Distributions 
1022*43a90889SApple OSS Distributions 		/*
1023*43a90889SApple OSS Distributions 		 * If this is a NS for NUD/AR, record it so that we know
1024*43a90889SApple OSS Distributions 		 * how to forward the NA reply later on (if/when it arrives.)
1025*43a90889SApple OSS Distributions 		 * Give up if we fail to save the NS info.
1026*43a90889SApple OSS Distributions 		 */
1027*43a90889SApple OSS Distributions 		if ((solrec = !IN6_IS_ADDR_UNSPECIFIED(saddr)) &&
1028*43a90889SApple OSS Distributions 		    !nd6_solsrc_enq(pr, ifp, saddr, taddr)) {
1029*43a90889SApple OSS Distributions 			NDPR_UNLOCK(pr);
1030*43a90889SApple OSS Distributions 			solrec = FALSE;
1031*43a90889SApple OSS Distributions 			break;                  /* bail out */
1032*43a90889SApple OSS Distributions 		} else {
1033*43a90889SApple OSS Distributions 			NDPR_UNLOCK(pr);
1034*43a90889SApple OSS Distributions 		}
1035*43a90889SApple OSS Distributions 
1036*43a90889SApple OSS Distributions 		for (fwd = nd_prefix.lh_first; fwd; fwd = fwd->ndpr_next) {
1037*43a90889SApple OSS Distributions 			NDPR_LOCK(fwd);
1038*43a90889SApple OSS Distributions 			if (!(fwd->ndpr_stateflags & NDPRF_ONLINK) ||
1039*43a90889SApple OSS Distributions 			    fwd->ndpr_ifp == ifp ||
1040*43a90889SApple OSS Distributions 			    fwd->ndpr_plen != pr_len ||
1041*43a90889SApple OSS Distributions 			    !in6_are_prefix_equal(&fwd->ndpr_prefix.sin6_addr, fwd->ndpr_prefix.sin6_scope_id,
1042*43a90889SApple OSS Distributions 			    &pr_addr, pr_scope_id, pr_len)) {
1043*43a90889SApple OSS Distributions 				NDPR_UNLOCK(fwd);
1044*43a90889SApple OSS Distributions 				continue;
1045*43a90889SApple OSS Distributions 			}
1046*43a90889SApple OSS Distributions 
1047*43a90889SApple OSS Distributions 			fwd_ifp = fwd->ndpr_ifp;
1048*43a90889SApple OSS Distributions 			NDPR_UNLOCK(fwd);
1049*43a90889SApple OSS Distributions 
1050*43a90889SApple OSS Distributions 			ndprl = nd6_ndprl_alloc(Z_WAITOK);
1051*43a90889SApple OSS Distributions 			if (ndprl == NULL) {
1052*43a90889SApple OSS Distributions 				continue;
1053*43a90889SApple OSS Distributions 			}
1054*43a90889SApple OSS Distributions 
1055*43a90889SApple OSS Distributions 			NDPR_ADDREF(fwd);
1056*43a90889SApple OSS Distributions 			ndprl->ndprl_pr = fwd;
1057*43a90889SApple OSS Distributions 			ndprl->ndprl_fwd_ifp = fwd_ifp;
1058*43a90889SApple OSS Distributions 			ndprl->ndprl_sol = solrec;
1059*43a90889SApple OSS Distributions 
1060*43a90889SApple OSS Distributions 			SLIST_INSERT_HEAD(&ndprl_head, ndprl, ndprl_le);
1061*43a90889SApple OSS Distributions 		}
1062*43a90889SApple OSS Distributions 		break;
1063*43a90889SApple OSS Distributions 	}
1064*43a90889SApple OSS Distributions 
1065*43a90889SApple OSS Distributions 	lck_mtx_unlock(nd6_mutex);
1066*43a90889SApple OSS Distributions 
1067*43a90889SApple OSS Distributions 	/*
1068*43a90889SApple OSS Distributions 	 * If this is a recorded solicitation (NS for NUD/AR), create
1069*43a90889SApple OSS Distributions 	 * or update the neighbor cache entry for the soliciting node.
1070*43a90889SApple OSS Distributions 	 * Later on, when the NA reply arrives, we will need this cache
1071*43a90889SApple OSS Distributions 	 * entry in order to send the NA back to the original solicitor.
1072*43a90889SApple OSS Distributions 	 * Without a neighbor cache entry, we'd end up with an endless
1073*43a90889SApple OSS Distributions 	 * cycle of NS ping-pong between the us (the proxy) and the node
1074*43a90889SApple OSS Distributions 	 * which is soliciting for the address.
1075*43a90889SApple OSS Distributions 	 */
1076*43a90889SApple OSS Distributions 	if (solrec) {
1077*43a90889SApple OSS Distributions 		VERIFY(!IN6_IS_ADDR_UNSPECIFIED(saddr));
1078*43a90889SApple OSS Distributions 		nd6_cache_lladdr(ifp, saddr, lladdr, lladdrlen,
1079*43a90889SApple OSS Distributions 		    ND_NEIGHBOR_SOLICIT, 0, NULL);
1080*43a90889SApple OSS Distributions 	}
1081*43a90889SApple OSS Distributions 
1082*43a90889SApple OSS Distributions 	SLIST_FOREACH_SAFE(ndprl, &ndprl_head, ndprl_le, ndprl_tmp) {
1083*43a90889SApple OSS Distributions 		SLIST_REMOVE(&ndprl_head, ndprl, nd6_prproxy_prelist, ndprl_le);
1084*43a90889SApple OSS Distributions 
1085*43a90889SApple OSS Distributions 		pr = ndprl->ndprl_pr;
1086*43a90889SApple OSS Distributions 		fwd_ifp = ndprl->ndprl_fwd_ifp;
1087*43a90889SApple OSS Distributions 
1088*43a90889SApple OSS Distributions 		if ((fwd_ifp->if_eflags & IFEF_IPV6_ND6ALT) != 0) {
1089*43a90889SApple OSS Distributions 			NDPR_REMREF(pr);
1090*43a90889SApple OSS Distributions 			nd6_ndprl_free(ndprl);
1091*43a90889SApple OSS Distributions 			continue;
1092*43a90889SApple OSS Distributions 		}
1093*43a90889SApple OSS Distributions 
1094*43a90889SApple OSS Distributions 		NDPR_LOCK(pr);
1095*43a90889SApple OSS Distributions 		if (pr->ndpr_stateflags & NDPRF_ONLINK) {
1096*43a90889SApple OSS Distributions 			NDPR_UNLOCK(pr);
1097*43a90889SApple OSS Distributions 			nd6log2(debug,
1098*43a90889SApple OSS Distributions 			    "%s: Forwarding NS (%s) from %s to %s who "
1099*43a90889SApple OSS Distributions 			    "has %s, originally on %s\n", if_name(fwd_ifp),
1100*43a90889SApple OSS Distributions 			    ndprl->ndprl_sol ? "NUD/AR" :
1101*43a90889SApple OSS Distributions 			    "DAD", ip6_sprintf(saddr), ip6_sprintf(daddr),
1102*43a90889SApple OSS Distributions 			    ip6_sprintf(taddr), if_name(ifp));
1103*43a90889SApple OSS Distributions 
1104*43a90889SApple OSS Distributions 			nd6_ns_output(fwd_ifp, ndprl->ndprl_sol ? taddr : NULL,
1105*43a90889SApple OSS Distributions 			    taddr, NULL, nonce, noncelen);
1106*43a90889SApple OSS Distributions 		} else {
1107*43a90889SApple OSS Distributions 			NDPR_UNLOCK(pr);
1108*43a90889SApple OSS Distributions 		}
1109*43a90889SApple OSS Distributions 		NDPR_REMREF(pr);
1110*43a90889SApple OSS Distributions 
1111*43a90889SApple OSS Distributions 		nd6_ndprl_free(ndprl);
1112*43a90889SApple OSS Distributions 	}
1113*43a90889SApple OSS Distributions 	VERIFY(SLIST_EMPTY(&ndprl_head));
1114*43a90889SApple OSS Distributions }
1115*43a90889SApple OSS Distributions 
1116*43a90889SApple OSS Distributions /*
1117*43a90889SApple OSS Distributions  * Perform automatic proxy function with NA input.
1118*43a90889SApple OSS Distributions  *
1119*43a90889SApple OSS Distributions  * If the target address matches a global prefix obtained from a router
1120*43a90889SApple OSS Distributions  * advertisement received on an interface with the ND6_IFF_PROXY_PREFIXES flag
1121*43a90889SApple OSS Distributions  * set, then we send neighbor advertisements for the target address on all
1122*43a90889SApple OSS Distributions  * other interfaces where a matching prefix is currently on link.
1123*43a90889SApple OSS Distributions  */
1124*43a90889SApple OSS Distributions void
nd6_prproxy_na_input(struct ifnet * ifp,struct in6_addr * saddr,struct in6_addr * daddr0,struct in6_addr * taddr,int flags)1125*43a90889SApple OSS Distributions nd6_prproxy_na_input(struct ifnet *ifp, struct in6_addr *saddr,
1126*43a90889SApple OSS Distributions     struct in6_addr *daddr0, struct in6_addr *taddr, int flags)
1127*43a90889SApple OSS Distributions {
1128*43a90889SApple OSS Distributions 	SLIST_HEAD(, nd6_prproxy_prelist) ndprl_head;
1129*43a90889SApple OSS Distributions 	struct nd6_prproxy_prelist *__single ndprl, *__single ndprl_tmp;
1130*43a90889SApple OSS Distributions 	struct nd_prefix *__single pr;
1131*43a90889SApple OSS Distributions 	ifnet_ref_t fwd_ifp;
1132*43a90889SApple OSS Distributions 	struct in6_addr daddr;
1133*43a90889SApple OSS Distributions 	uint32_t pr_scope_id;
1134*43a90889SApple OSS Distributions 	uint32_t taddr_ifscope = ifp->if_index;
1135*43a90889SApple OSS Distributions 
1136*43a90889SApple OSS Distributions 	SLIST_INIT(&ndprl_head);
1137*43a90889SApple OSS Distributions 
1138*43a90889SApple OSS Distributions 	lck_mtx_lock(nd6_mutex);
1139*43a90889SApple OSS Distributions 
1140*43a90889SApple OSS Distributions 	for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
1141*43a90889SApple OSS Distributions 		NDPR_LOCK(pr);
1142*43a90889SApple OSS Distributions 
1143*43a90889SApple OSS Distributions 		pr_scope_id = pr->ndpr_prefix.sin6_scope_id;
1144*43a90889SApple OSS Distributions 		if (!(pr->ndpr_stateflags & NDPRF_ONLINK) ||
1145*43a90889SApple OSS Distributions 		    !(pr->ndpr_stateflags & NDPRF_PRPROXY) ||
1146*43a90889SApple OSS Distributions 		    !in6_are_masked_addr_scope_equal(&pr->ndpr_prefix.sin6_addr, pr_scope_id,
1147*43a90889SApple OSS Distributions 		    taddr, taddr_ifscope, &pr->ndpr_mask)) {
1148*43a90889SApple OSS Distributions 			NDPR_UNLOCK(pr);
1149*43a90889SApple OSS Distributions 			continue;
1150*43a90889SApple OSS Distributions 		}
1151*43a90889SApple OSS Distributions 
1152*43a90889SApple OSS Distributions 		VERIFY(!(pr->ndpr_stateflags & NDPRF_IFSCOPE));
1153*43a90889SApple OSS Distributions 		/*
1154*43a90889SApple OSS Distributions 		 * If this is a NA for NUD, see if there is a record created
1155*43a90889SApple OSS Distributions 		 * for the corresponding NS; upon success, we get back the
1156*43a90889SApple OSS Distributions 		 * interface where the NS originally arrived on, as well as
1157*43a90889SApple OSS Distributions 		 * the soliciting node's address.  Give up if we can't find it.
1158*43a90889SApple OSS Distributions 		 */
1159*43a90889SApple OSS Distributions 		if (!IN6_IS_ADDR_MULTICAST(daddr0)) {
1160*43a90889SApple OSS Distributions 			fwd_ifp = NULL;
1161*43a90889SApple OSS Distributions 			bzero(&daddr, sizeof(daddr));
1162*43a90889SApple OSS Distributions 			if (!nd6_solsrc_deq(pr, taddr, &daddr, &fwd_ifp)) {
1163*43a90889SApple OSS Distributions 				NDPR_UNLOCK(pr);
1164*43a90889SApple OSS Distributions 				break;          /* bail out */
1165*43a90889SApple OSS Distributions 			}
1166*43a90889SApple OSS Distributions 			VERIFY(!IN6_IS_ADDR_UNSPECIFIED(&daddr) && fwd_ifp);
1167*43a90889SApple OSS Distributions 			NDPR_UNLOCK(pr);
1168*43a90889SApple OSS Distributions 
1169*43a90889SApple OSS Distributions 			ndprl = nd6_ndprl_alloc(Z_WAITOK);
1170*43a90889SApple OSS Distributions 			if (ndprl == NULL) {
1171*43a90889SApple OSS Distributions 				break;          /* bail out */
1172*43a90889SApple OSS Distributions 			}
1173*43a90889SApple OSS Distributions 			ndprl->ndprl_fwd_ifp = fwd_ifp;
1174*43a90889SApple OSS Distributions 			ndprl->ndprl_sol = TRUE;
1175*43a90889SApple OSS Distributions 			ndprl->ndprl_sol_saddr = *(&daddr);
1176*43a90889SApple OSS Distributions 
1177*43a90889SApple OSS Distributions 			SLIST_INSERT_HEAD(&ndprl_head, ndprl, ndprl_le);
1178*43a90889SApple OSS Distributions 		} else {
1179*43a90889SApple OSS Distributions 			struct nd_prefix *__single fwd;
1180*43a90889SApple OSS Distributions 			struct in6_addr pr_addr;
1181*43a90889SApple OSS Distributions 			u_char pr_len;
1182*43a90889SApple OSS Distributions 
1183*43a90889SApple OSS Distributions 			bcopy(&pr->ndpr_prefix.sin6_addr, &pr_addr,
1184*43a90889SApple OSS Distributions 			    sizeof(pr_addr));
1185*43a90889SApple OSS Distributions 			pr_len = pr->ndpr_plen;
1186*43a90889SApple OSS Distributions 			NDPR_UNLOCK(pr);
1187*43a90889SApple OSS Distributions 
1188*43a90889SApple OSS Distributions 			for (fwd = nd_prefix.lh_first; fwd;
1189*43a90889SApple OSS Distributions 			    fwd = fwd->ndpr_next) {
1190*43a90889SApple OSS Distributions 				NDPR_LOCK(fwd);
1191*43a90889SApple OSS Distributions 				if (!(fwd->ndpr_stateflags & NDPRF_ONLINK) ||
1192*43a90889SApple OSS Distributions 				    fwd->ndpr_ifp == ifp ||
1193*43a90889SApple OSS Distributions 				    fwd->ndpr_plen != pr_len ||
1194*43a90889SApple OSS Distributions 				    !in6_are_prefix_equal(
1195*43a90889SApple OSS Distributions 					    &fwd->ndpr_prefix.sin6_addr, fwd->ndpr_prefix.sin6_scope_id,
1196*43a90889SApple OSS Distributions 					    &pr_addr, pr_scope_id, pr_len)) {
1197*43a90889SApple OSS Distributions 					NDPR_UNLOCK(fwd);
1198*43a90889SApple OSS Distributions 					continue;
1199*43a90889SApple OSS Distributions 				}
1200*43a90889SApple OSS Distributions 
1201*43a90889SApple OSS Distributions 				fwd_ifp = fwd->ndpr_ifp;
1202*43a90889SApple OSS Distributions 				NDPR_UNLOCK(fwd);
1203*43a90889SApple OSS Distributions 
1204*43a90889SApple OSS Distributions 				ndprl = nd6_ndprl_alloc(Z_WAITOK);
1205*43a90889SApple OSS Distributions 				if (ndprl == NULL) {
1206*43a90889SApple OSS Distributions 					continue;
1207*43a90889SApple OSS Distributions 				}
1208*43a90889SApple OSS Distributions 
1209*43a90889SApple OSS Distributions 				NDPR_ADDREF(fwd);
1210*43a90889SApple OSS Distributions 				ndprl->ndprl_pr = fwd;
1211*43a90889SApple OSS Distributions 				ndprl->ndprl_fwd_ifp = fwd_ifp;
1212*43a90889SApple OSS Distributions 
1213*43a90889SApple OSS Distributions 				SLIST_INSERT_HEAD(&ndprl_head, ndprl, ndprl_le);
1214*43a90889SApple OSS Distributions 			}
1215*43a90889SApple OSS Distributions 		}
1216*43a90889SApple OSS Distributions 		break;
1217*43a90889SApple OSS Distributions 	}
1218*43a90889SApple OSS Distributions 
1219*43a90889SApple OSS Distributions 	lck_mtx_unlock(nd6_mutex);
1220*43a90889SApple OSS Distributions 
1221*43a90889SApple OSS Distributions 	SLIST_FOREACH_SAFE(ndprl, &ndprl_head, ndprl_le, ndprl_tmp) {
1222*43a90889SApple OSS Distributions 		boolean_t send_na;
1223*43a90889SApple OSS Distributions 
1224*43a90889SApple OSS Distributions 		SLIST_REMOVE(&ndprl_head, ndprl, nd6_prproxy_prelist, ndprl_le);
1225*43a90889SApple OSS Distributions 
1226*43a90889SApple OSS Distributions 		pr = ndprl->ndprl_pr;
1227*43a90889SApple OSS Distributions 		fwd_ifp = ndprl->ndprl_fwd_ifp;
1228*43a90889SApple OSS Distributions 
1229*43a90889SApple OSS Distributions 		if (ndprl->ndprl_sol) {
1230*43a90889SApple OSS Distributions 			VERIFY(pr == NULL);
1231*43a90889SApple OSS Distributions 			daddr = *(&ndprl->ndprl_sol_saddr);
1232*43a90889SApple OSS Distributions 			VERIFY(!IN6_IS_ADDR_UNSPECIFIED(&daddr));
1233*43a90889SApple OSS Distributions 			send_na = (in6_setscope(&daddr, fwd_ifp, NULL) == 0);
1234*43a90889SApple OSS Distributions 		} else {
1235*43a90889SApple OSS Distributions 			VERIFY(pr != NULL);
1236*43a90889SApple OSS Distributions 			daddr = *daddr0;
1237*43a90889SApple OSS Distributions 			NDPR_LOCK(pr);
1238*43a90889SApple OSS Distributions 			send_na = ((pr->ndpr_stateflags & NDPRF_ONLINK) &&
1239*43a90889SApple OSS Distributions 			    in6_setscope(&daddr, fwd_ifp, NULL) == 0);
1240*43a90889SApple OSS Distributions 			NDPR_UNLOCK(pr);
1241*43a90889SApple OSS Distributions 		}
1242*43a90889SApple OSS Distributions 
1243*43a90889SApple OSS Distributions 		if (send_na) {
1244*43a90889SApple OSS Distributions 			if (!ndprl->ndprl_sol) {
1245*43a90889SApple OSS Distributions 				nd6log2(debug,
1246*43a90889SApple OSS Distributions 				    "%s: Forwarding NA (DAD) from %s to %s "
1247*43a90889SApple OSS Distributions 				    "tgt is %s, originally on %s\n",
1248*43a90889SApple OSS Distributions 				    if_name(fwd_ifp),
1249*43a90889SApple OSS Distributions 				    ip6_sprintf(saddr), ip6_sprintf(&daddr),
1250*43a90889SApple OSS Distributions 				    ip6_sprintf(taddr), if_name(ifp));
1251*43a90889SApple OSS Distributions 			} else {
1252*43a90889SApple OSS Distributions 				nd6log2(debug,
1253*43a90889SApple OSS Distributions 				    "%s: Forwarding NA (NUD/AR) from %s to "
1254*43a90889SApple OSS Distributions 				    "%s (was %s) tgt is %s, originally on "
1255*43a90889SApple OSS Distributions 				    "%s\n", if_name(fwd_ifp),
1256*43a90889SApple OSS Distributions 				    ip6_sprintf(saddr),
1257*43a90889SApple OSS Distributions 				    ip6_sprintf(&daddr), ip6_sprintf(daddr0),
1258*43a90889SApple OSS Distributions 				    ip6_sprintf(taddr), if_name(ifp));
1259*43a90889SApple OSS Distributions 			}
1260*43a90889SApple OSS Distributions 
1261*43a90889SApple OSS Distributions 			nd6_na_output(fwd_ifp, &daddr, taddr, flags, 1, NULL);
1262*43a90889SApple OSS Distributions 		}
1263*43a90889SApple OSS Distributions 
1264*43a90889SApple OSS Distributions 		if (pr != NULL) {
1265*43a90889SApple OSS Distributions 			NDPR_REMREF(pr);
1266*43a90889SApple OSS Distributions 		}
1267*43a90889SApple OSS Distributions 
1268*43a90889SApple OSS Distributions 		nd6_ndprl_free(ndprl);
1269*43a90889SApple OSS Distributions 	}
1270*43a90889SApple OSS Distributions 	VERIFY(SLIST_EMPTY(&ndprl_head));
1271*43a90889SApple OSS Distributions }
1272*43a90889SApple OSS Distributions 
1273*43a90889SApple OSS Distributions static struct nd6_prproxy_solsrc *
nd6_solsrc_alloc(int how)1274*43a90889SApple OSS Distributions nd6_solsrc_alloc(int how)
1275*43a90889SApple OSS Distributions {
1276*43a90889SApple OSS Distributions 	return zalloc_flags(solsrc_zone, how | Z_ZERO);
1277*43a90889SApple OSS Distributions }
1278*43a90889SApple OSS Distributions 
1279*43a90889SApple OSS Distributions static void
nd6_solsrc_free(struct nd6_prproxy_solsrc * ssrc)1280*43a90889SApple OSS Distributions nd6_solsrc_free(struct nd6_prproxy_solsrc *ssrc)
1281*43a90889SApple OSS Distributions {
1282*43a90889SApple OSS Distributions 	zfree(solsrc_zone, ssrc);
1283*43a90889SApple OSS Distributions }
1284*43a90889SApple OSS Distributions 
1285*43a90889SApple OSS Distributions static void
nd6_prproxy_sols_purge(struct nd_prefix * pr,u_int64_t max_stgt)1286*43a90889SApple OSS Distributions nd6_prproxy_sols_purge(struct nd_prefix *pr, u_int64_t max_stgt)
1287*43a90889SApple OSS Distributions {
1288*43a90889SApple OSS Distributions 	struct nd6_prproxy_soltgt *__single soltgt, *__single tmp;
1289*43a90889SApple OSS Distributions 	u_int64_t expire = (max_stgt > 0) ? net_uptime() : 0;
1290*43a90889SApple OSS Distributions 
1291*43a90889SApple OSS Distributions 	NDPR_LOCK_ASSERT_HELD(pr);
1292*43a90889SApple OSS Distributions 
1293*43a90889SApple OSS Distributions 	/* Either trim all or those that have expired or are idle */
1294*43a90889SApple OSS Distributions 	RB_FOREACH_SAFE(soltgt, prproxy_sols_tree,
1295*43a90889SApple OSS Distributions 	    &pr->ndpr_prproxy_sols, tmp) {
1296*43a90889SApple OSS Distributions 		VERIFY(pr->ndpr_prproxy_sols_cnt > 0);
1297*43a90889SApple OSS Distributions 		if (expire == 0 || soltgt->soltgt_expire <= expire ||
1298*43a90889SApple OSS Distributions 		    soltgt->soltgt_cnt == 0) {
1299*43a90889SApple OSS Distributions 			pr->ndpr_prproxy_sols_cnt--;
1300*43a90889SApple OSS Distributions 			RB_REMOVE(prproxy_sols_tree,
1301*43a90889SApple OSS Distributions 			    &pr->ndpr_prproxy_sols, soltgt);
1302*43a90889SApple OSS Distributions 			nd6_soltgt_free(soltgt);
1303*43a90889SApple OSS Distributions 		}
1304*43a90889SApple OSS Distributions 	}
1305*43a90889SApple OSS Distributions 
1306*43a90889SApple OSS Distributions 	if (max_stgt == 0 || pr->ndpr_prproxy_sols_cnt < max_stgt) {
1307*43a90889SApple OSS Distributions 		VERIFY(max_stgt != 0 || (pr->ndpr_prproxy_sols_cnt == 0 &&
1308*43a90889SApple OSS Distributions 		    RB_EMPTY(&pr->ndpr_prproxy_sols)));
1309*43a90889SApple OSS Distributions 		return;
1310*43a90889SApple OSS Distributions 	}
1311*43a90889SApple OSS Distributions 
1312*43a90889SApple OSS Distributions 	/* Brute force; mercilessly evict entries until we are under limit */
1313*43a90889SApple OSS Distributions 	RB_FOREACH_SAFE(soltgt, prproxy_sols_tree,
1314*43a90889SApple OSS Distributions 	    &pr->ndpr_prproxy_sols, tmp) {
1315*43a90889SApple OSS Distributions 		VERIFY(pr->ndpr_prproxy_sols_cnt > 0);
1316*43a90889SApple OSS Distributions 		pr->ndpr_prproxy_sols_cnt--;
1317*43a90889SApple OSS Distributions 		RB_REMOVE(prproxy_sols_tree, &pr->ndpr_prproxy_sols, soltgt);
1318*43a90889SApple OSS Distributions 		nd6_soltgt_free(soltgt);
1319*43a90889SApple OSS Distributions 		if (pr->ndpr_prproxy_sols_cnt < max_stgt) {
1320*43a90889SApple OSS Distributions 			break;
1321*43a90889SApple OSS Distributions 		}
1322*43a90889SApple OSS Distributions 	}
1323*43a90889SApple OSS Distributions }
1324*43a90889SApple OSS Distributions 
1325*43a90889SApple OSS Distributions /*
1326*43a90889SApple OSS Distributions  * Purges all solicitation records on a given prefix.
1327*43a90889SApple OSS Distributions  * Caller is responsible for holding prefix lock.
1328*43a90889SApple OSS Distributions  */
1329*43a90889SApple OSS Distributions void
nd6_prproxy_sols_reap(struct nd_prefix * pr)1330*43a90889SApple OSS Distributions nd6_prproxy_sols_reap(struct nd_prefix *pr)
1331*43a90889SApple OSS Distributions {
1332*43a90889SApple OSS Distributions 	nd6_prproxy_sols_purge(pr, 0);
1333*43a90889SApple OSS Distributions }
1334*43a90889SApple OSS Distributions 
1335*43a90889SApple OSS Distributions /*
1336*43a90889SApple OSS Distributions  * Purges expired or idle solicitation records on a given prefix.
1337*43a90889SApple OSS Distributions  * Caller is responsible for holding prefix lock.
1338*43a90889SApple OSS Distributions  */
1339*43a90889SApple OSS Distributions void
nd6_prproxy_sols_prune(struct nd_prefix * pr,u_int32_t max_stgt)1340*43a90889SApple OSS Distributions nd6_prproxy_sols_prune(struct nd_prefix *pr, u_int32_t max_stgt)
1341*43a90889SApple OSS Distributions {
1342*43a90889SApple OSS Distributions 	nd6_prproxy_sols_purge(pr, max_stgt);
1343*43a90889SApple OSS Distributions }
1344*43a90889SApple OSS Distributions 
1345*43a90889SApple OSS Distributions /*
1346*43a90889SApple OSS Distributions  * Enqueue a soliciation record in the target record of a prefix.
1347*43a90889SApple OSS Distributions  */
1348*43a90889SApple OSS Distributions static boolean_t
nd6_solsrc_enq(struct nd_prefix * pr,struct ifnet * ifp,struct in6_addr * saddr,struct in6_addr * taddr)1349*43a90889SApple OSS Distributions nd6_solsrc_enq(struct nd_prefix *pr, struct ifnet *ifp,
1350*43a90889SApple OSS Distributions     struct in6_addr *saddr, struct in6_addr *taddr)
1351*43a90889SApple OSS Distributions {
1352*43a90889SApple OSS Distributions 	struct nd6_prproxy_soltgt find;
1353*43a90889SApple OSS Distributions 	struct nd6_prproxy_soltgt *__single soltgt;
1354*43a90889SApple OSS Distributions 	struct nd6_prproxy_solsrc *__single ssrc;
1355*43a90889SApple OSS Distributions 	u_int32_t max_stgt = nd6_max_tgt_sols;
1356*43a90889SApple OSS Distributions 	u_int32_t max_ssrc = nd6_max_src_sols;
1357*43a90889SApple OSS Distributions 
1358*43a90889SApple OSS Distributions 	NDPR_LOCK_ASSERT_HELD(pr);
1359*43a90889SApple OSS Distributions 	VERIFY(!(pr->ndpr_stateflags & NDPRF_IFSCOPE));
1360*43a90889SApple OSS Distributions 	VERIFY((pr->ndpr_stateflags & (NDPRF_ONLINK | NDPRF_PRPROXY)) ==
1361*43a90889SApple OSS Distributions 	    (NDPRF_ONLINK | NDPRF_PRPROXY));
1362*43a90889SApple OSS Distributions 	VERIFY(!IN6_IS_ADDR_UNSPECIFIED(saddr));
1363*43a90889SApple OSS Distributions 
1364*43a90889SApple OSS Distributions 	ssrc = nd6_solsrc_alloc(M_WAITOK);
1365*43a90889SApple OSS Distributions 	if (ssrc == NULL) {
1366*43a90889SApple OSS Distributions 		return FALSE;
1367*43a90889SApple OSS Distributions 	}
1368*43a90889SApple OSS Distributions 
1369*43a90889SApple OSS Distributions 	ssrc->solsrc_saddr = *saddr;
1370*43a90889SApple OSS Distributions 	ssrc->solsrc_ifp = ifp;
1371*43a90889SApple OSS Distributions 
1372*43a90889SApple OSS Distributions 	find.soltgt_key.taddr = *taddr;         /* search key */
1373*43a90889SApple OSS Distributions 
1374*43a90889SApple OSS Distributions 	soltgt = RB_FIND(prproxy_sols_tree, &pr->ndpr_prproxy_sols, &find);
1375*43a90889SApple OSS Distributions 	if (soltgt == NULL) {
1376*43a90889SApple OSS Distributions 		if (max_stgt != 0 && pr->ndpr_prproxy_sols_cnt >= max_stgt) {
1377*43a90889SApple OSS Distributions 			VERIFY(!RB_EMPTY(&pr->ndpr_prproxy_sols));
1378*43a90889SApple OSS Distributions 			nd6_prproxy_sols_prune(pr, max_stgt);
1379*43a90889SApple OSS Distributions 			VERIFY(pr->ndpr_prproxy_sols_cnt < max_stgt);
1380*43a90889SApple OSS Distributions 		}
1381*43a90889SApple OSS Distributions 
1382*43a90889SApple OSS Distributions 		soltgt = nd6_soltgt_alloc(M_WAITOK);
1383*43a90889SApple OSS Distributions 		if (soltgt == NULL) {
1384*43a90889SApple OSS Distributions 			nd6_solsrc_free(ssrc);
1385*43a90889SApple OSS Distributions 			return FALSE;
1386*43a90889SApple OSS Distributions 		}
1387*43a90889SApple OSS Distributions 
1388*43a90889SApple OSS Distributions 		soltgt->soltgt_key.taddr = *taddr;
1389*43a90889SApple OSS Distributions 		VERIFY(soltgt->soltgt_cnt == 0);
1390*43a90889SApple OSS Distributions 		VERIFY(TAILQ_EMPTY(&soltgt->soltgt_q));
1391*43a90889SApple OSS Distributions 
1392*43a90889SApple OSS Distributions 		pr->ndpr_prproxy_sols_cnt++;
1393*43a90889SApple OSS Distributions 		VERIFY(pr->ndpr_prproxy_sols_cnt != 0);
1394*43a90889SApple OSS Distributions 		RB_INSERT(prproxy_sols_tree, &pr->ndpr_prproxy_sols, soltgt);
1395*43a90889SApple OSS Distributions 	}
1396*43a90889SApple OSS Distributions 
1397*43a90889SApple OSS Distributions 	if (max_ssrc != 0 && soltgt->soltgt_cnt >= max_ssrc) {
1398*43a90889SApple OSS Distributions 		VERIFY(!TAILQ_EMPTY(&soltgt->soltgt_q));
1399*43a90889SApple OSS Distributions 		nd6_soltgt_prune(soltgt, max_ssrc);
1400*43a90889SApple OSS Distributions 		VERIFY(soltgt->soltgt_cnt < max_ssrc);
1401*43a90889SApple OSS Distributions 	}
1402*43a90889SApple OSS Distributions 
1403*43a90889SApple OSS Distributions 	soltgt->soltgt_cnt++;
1404*43a90889SApple OSS Distributions 	VERIFY(soltgt->soltgt_cnt != 0);
1405*43a90889SApple OSS Distributions 	TAILQ_INSERT_TAIL(&soltgt->soltgt_q, ssrc, solsrc_tqe);
1406*43a90889SApple OSS Distributions 	if (soltgt->soltgt_cnt == 1) {
1407*43a90889SApple OSS Distributions 		soltgt->soltgt_expire = net_uptime() + ND6_TGT_SOLS_EXPIRE;
1408*43a90889SApple OSS Distributions 	}
1409*43a90889SApple OSS Distributions 
1410*43a90889SApple OSS Distributions 	return TRUE;
1411*43a90889SApple OSS Distributions }
1412*43a90889SApple OSS Distributions 
1413*43a90889SApple OSS Distributions /*
1414*43a90889SApple OSS Distributions  * Dequeue a solicitation record from a target record of a prefix.
1415*43a90889SApple OSS Distributions  */
1416*43a90889SApple OSS Distributions static boolean_t
nd6_solsrc_deq(struct nd_prefix * pr,struct in6_addr * taddr,struct in6_addr * daddr,struct ifnet ** ifp)1417*43a90889SApple OSS Distributions nd6_solsrc_deq(struct nd_prefix *pr, struct in6_addr *taddr,
1418*43a90889SApple OSS Distributions     struct in6_addr *daddr, struct ifnet **ifp)
1419*43a90889SApple OSS Distributions {
1420*43a90889SApple OSS Distributions 	struct nd6_prproxy_soltgt find;
1421*43a90889SApple OSS Distributions 	struct nd6_prproxy_soltgt *__single soltgt;
1422*43a90889SApple OSS Distributions 	struct nd6_prproxy_solsrc *__single ssrc;
1423*43a90889SApple OSS Distributions 
1424*43a90889SApple OSS Distributions 	NDPR_LOCK_ASSERT_HELD(pr);
1425*43a90889SApple OSS Distributions 	VERIFY(!(pr->ndpr_stateflags & NDPRF_IFSCOPE));
1426*43a90889SApple OSS Distributions 	VERIFY((pr->ndpr_stateflags & (NDPRF_ONLINK | NDPRF_PRPROXY)) ==
1427*43a90889SApple OSS Distributions 	    (NDPRF_ONLINK | NDPRF_PRPROXY));
1428*43a90889SApple OSS Distributions 
1429*43a90889SApple OSS Distributions 	bzero(daddr, sizeof(*daddr));
1430*43a90889SApple OSS Distributions 	*ifp = NULL;
1431*43a90889SApple OSS Distributions 
1432*43a90889SApple OSS Distributions 	find.soltgt_key.taddr = *taddr;         /* search key */
1433*43a90889SApple OSS Distributions 
1434*43a90889SApple OSS Distributions 	soltgt = RB_FIND(prproxy_sols_tree, &pr->ndpr_prproxy_sols, &find);
1435*43a90889SApple OSS Distributions 	if (soltgt == NULL || soltgt->soltgt_cnt == 0) {
1436*43a90889SApple OSS Distributions 		VERIFY(soltgt == NULL || TAILQ_EMPTY(&soltgt->soltgt_q));
1437*43a90889SApple OSS Distributions 		return FALSE;
1438*43a90889SApple OSS Distributions 	}
1439*43a90889SApple OSS Distributions 
1440*43a90889SApple OSS Distributions 	VERIFY(soltgt->soltgt_cnt != 0);
1441*43a90889SApple OSS Distributions 	--soltgt->soltgt_cnt;
1442*43a90889SApple OSS Distributions 	ssrc = TAILQ_FIRST(&soltgt->soltgt_q);
1443*43a90889SApple OSS Distributions 	VERIFY(ssrc != NULL);
1444*43a90889SApple OSS Distributions 	TAILQ_REMOVE(&soltgt->soltgt_q, ssrc, solsrc_tqe);
1445*43a90889SApple OSS Distributions 	*daddr = *(&ssrc->solsrc_saddr);
1446*43a90889SApple OSS Distributions 	*ifp = ssrc->solsrc_ifp;
1447*43a90889SApple OSS Distributions 	nd6_solsrc_free(ssrc);
1448*43a90889SApple OSS Distributions 
1449*43a90889SApple OSS Distributions 	return TRUE;
1450*43a90889SApple OSS Distributions }
1451*43a90889SApple OSS Distributions 
1452*43a90889SApple OSS Distributions static struct nd6_prproxy_soltgt *
nd6_soltgt_alloc(int how)1453*43a90889SApple OSS Distributions nd6_soltgt_alloc(int how)
1454*43a90889SApple OSS Distributions {
1455*43a90889SApple OSS Distributions 	struct nd6_prproxy_soltgt *__single soltgt;
1456*43a90889SApple OSS Distributions 
1457*43a90889SApple OSS Distributions 	soltgt = zalloc_flags(soltgt_zone, how | Z_ZERO);
1458*43a90889SApple OSS Distributions 	if (soltgt != NULL) {
1459*43a90889SApple OSS Distributions 		TAILQ_INIT(&soltgt->soltgt_q);
1460*43a90889SApple OSS Distributions 	}
1461*43a90889SApple OSS Distributions 	return soltgt;
1462*43a90889SApple OSS Distributions }
1463*43a90889SApple OSS Distributions 
1464*43a90889SApple OSS Distributions static void
nd6_soltgt_free(struct nd6_prproxy_soltgt * soltgt)1465*43a90889SApple OSS Distributions nd6_soltgt_free(struct nd6_prproxy_soltgt *soltgt)
1466*43a90889SApple OSS Distributions {
1467*43a90889SApple OSS Distributions 	struct nd6_prproxy_solsrc *__single ssrc, *__single tssrc;
1468*43a90889SApple OSS Distributions 
1469*43a90889SApple OSS Distributions 	TAILQ_FOREACH_SAFE(ssrc, &soltgt->soltgt_q, solsrc_tqe, tssrc) {
1470*43a90889SApple OSS Distributions 		VERIFY(soltgt->soltgt_cnt > 0);
1471*43a90889SApple OSS Distributions 		soltgt->soltgt_cnt--;
1472*43a90889SApple OSS Distributions 		TAILQ_REMOVE(&soltgt->soltgt_q, ssrc, solsrc_tqe);
1473*43a90889SApple OSS Distributions 		nd6_solsrc_free(ssrc);
1474*43a90889SApple OSS Distributions 	}
1475*43a90889SApple OSS Distributions 
1476*43a90889SApple OSS Distributions 	VERIFY(soltgt->soltgt_cnt == 0);
1477*43a90889SApple OSS Distributions 	VERIFY(TAILQ_EMPTY(&soltgt->soltgt_q));
1478*43a90889SApple OSS Distributions 
1479*43a90889SApple OSS Distributions 	zfree(soltgt_zone, soltgt);
1480*43a90889SApple OSS Distributions }
1481*43a90889SApple OSS Distributions 
1482*43a90889SApple OSS Distributions static void
nd6_soltgt_prune(struct nd6_prproxy_soltgt * soltgt,u_int32_t max_ssrc)1483*43a90889SApple OSS Distributions nd6_soltgt_prune(struct nd6_prproxy_soltgt *soltgt, u_int32_t max_ssrc)
1484*43a90889SApple OSS Distributions {
1485*43a90889SApple OSS Distributions 	while (soltgt->soltgt_cnt >= max_ssrc) {
1486*43a90889SApple OSS Distributions 		struct nd6_prproxy_solsrc *__single ssrc;
1487*43a90889SApple OSS Distributions 
1488*43a90889SApple OSS Distributions 		VERIFY(soltgt->soltgt_cnt != 0);
1489*43a90889SApple OSS Distributions 		--soltgt->soltgt_cnt;
1490*43a90889SApple OSS Distributions 		ssrc = TAILQ_FIRST(&soltgt->soltgt_q);
1491*43a90889SApple OSS Distributions 		VERIFY(ssrc != NULL);
1492*43a90889SApple OSS Distributions 		TAILQ_REMOVE(&soltgt->soltgt_q, ssrc, solsrc_tqe);
1493*43a90889SApple OSS Distributions 		nd6_solsrc_free(ssrc);
1494*43a90889SApple OSS Distributions 	}
1495*43a90889SApple OSS Distributions }
1496*43a90889SApple OSS Distributions 
1497*43a90889SApple OSS Distributions /*
1498*43a90889SApple OSS Distributions  * Solicited target tree comparison function.
1499*43a90889SApple OSS Distributions  *
1500*43a90889SApple OSS Distributions  * An ordered predicate is necessary; bcmp() is not documented to return
1501*43a90889SApple OSS Distributions  * an indication of order, memcmp() is, and is an ISO C99 requirement.
1502*43a90889SApple OSS Distributions  */
1503*43a90889SApple OSS Distributions static __inline int
soltgt_cmp(const struct nd6_prproxy_soltgt * a,const struct nd6_prproxy_soltgt * b)1504*43a90889SApple OSS Distributions soltgt_cmp(const struct nd6_prproxy_soltgt *a,
1505*43a90889SApple OSS Distributions     const struct nd6_prproxy_soltgt *b)
1506*43a90889SApple OSS Distributions {
1507*43a90889SApple OSS Distributions 	return memcmp(&a->soltgt_key, &b->soltgt_key, sizeof(a->soltgt_key));
1508*43a90889SApple OSS Distributions }
1509