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