xref: /xnu-12377.41.6/bsd/netinet6/in6_src.c (revision bbb1b6f9e71b8cdde6e5cd6f4841f207dee3d828)
1*bbb1b6f9SApple OSS Distributions /*
2*bbb1b6f9SApple OSS Distributions  * Copyright (c) 2000-2024 Apple Inc. All rights reserved.
3*bbb1b6f9SApple OSS Distributions  *
4*bbb1b6f9SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*bbb1b6f9SApple OSS Distributions  *
6*bbb1b6f9SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*bbb1b6f9SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*bbb1b6f9SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*bbb1b6f9SApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*bbb1b6f9SApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*bbb1b6f9SApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*bbb1b6f9SApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*bbb1b6f9SApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*bbb1b6f9SApple OSS Distributions  *
15*bbb1b6f9SApple OSS Distributions  * Please obtain a copy of the License at
16*bbb1b6f9SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*bbb1b6f9SApple OSS Distributions  *
18*bbb1b6f9SApple OSS Distributions  * The Original Code and all software distributed under the License are
19*bbb1b6f9SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*bbb1b6f9SApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*bbb1b6f9SApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*bbb1b6f9SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*bbb1b6f9SApple OSS Distributions  * Please see the License for the specific language governing rights and
24*bbb1b6f9SApple OSS Distributions  * limitations under the License.
25*bbb1b6f9SApple OSS Distributions  *
26*bbb1b6f9SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*bbb1b6f9SApple OSS Distributions  */
28*bbb1b6f9SApple OSS Distributions 
29*bbb1b6f9SApple OSS Distributions /*
30*bbb1b6f9SApple OSS Distributions  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
31*bbb1b6f9SApple OSS Distributions  * All rights reserved.
32*bbb1b6f9SApple OSS Distributions  *
33*bbb1b6f9SApple OSS Distributions  * Redistribution and use in source and binary forms, with or without
34*bbb1b6f9SApple OSS Distributions  * modification, are permitted provided that the following conditions
35*bbb1b6f9SApple OSS Distributions  * are met:
36*bbb1b6f9SApple OSS Distributions  * 1. Redistributions of source code must retain the above copyright
37*bbb1b6f9SApple OSS Distributions  *    notice, this list of conditions and the following disclaimer.
38*bbb1b6f9SApple OSS Distributions  * 2. Redistributions in binary form must reproduce the above copyright
39*bbb1b6f9SApple OSS Distributions  *    notice, this list of conditions and the following disclaimer in the
40*bbb1b6f9SApple OSS Distributions  *    documentation and/or other materials provided with the distribution.
41*bbb1b6f9SApple OSS Distributions  * 3. Neither the name of the project nor the names of its contributors
42*bbb1b6f9SApple OSS Distributions  *    may be used to endorse or promote products derived from this software
43*bbb1b6f9SApple OSS Distributions  *    without specific prior written permission.
44*bbb1b6f9SApple OSS Distributions  *
45*bbb1b6f9SApple OSS Distributions  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
46*bbb1b6f9SApple OSS Distributions  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47*bbb1b6f9SApple OSS Distributions  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48*bbb1b6f9SApple OSS Distributions  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
49*bbb1b6f9SApple OSS Distributions  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50*bbb1b6f9SApple OSS Distributions  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51*bbb1b6f9SApple OSS Distributions  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52*bbb1b6f9SApple OSS Distributions  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53*bbb1b6f9SApple OSS Distributions  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54*bbb1b6f9SApple OSS Distributions  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55*bbb1b6f9SApple OSS Distributions  * SUCH DAMAGE.
56*bbb1b6f9SApple OSS Distributions  */
57*bbb1b6f9SApple OSS Distributions 
58*bbb1b6f9SApple OSS Distributions /*
59*bbb1b6f9SApple OSS Distributions  * Copyright (c) 1982, 1986, 1991, 1993
60*bbb1b6f9SApple OSS Distributions  *	The Regents of the University of California.  All rights reserved.
61*bbb1b6f9SApple OSS Distributions  *
62*bbb1b6f9SApple OSS Distributions  * Redistribution and use in source and binary forms, with or without
63*bbb1b6f9SApple OSS Distributions  * modification, are permitted provided that the following conditions
64*bbb1b6f9SApple OSS Distributions  * are met:
65*bbb1b6f9SApple OSS Distributions  * 1. Redistributions of source code must retain the above copyright
66*bbb1b6f9SApple OSS Distributions  *    notice, this list of conditions and the following disclaimer.
67*bbb1b6f9SApple OSS Distributions  * 2. Redistributions in binary form must reproduce the above copyright
68*bbb1b6f9SApple OSS Distributions  *    notice, this list of conditions and the following disclaimer in the
69*bbb1b6f9SApple OSS Distributions  *    documentation and/or other materials provided with the distribution.
70*bbb1b6f9SApple OSS Distributions  * 3. All advertising materials mentioning features or use of this software
71*bbb1b6f9SApple OSS Distributions  *    must display the following acknowledgement:
72*bbb1b6f9SApple OSS Distributions  *	This product includes software developed by the University of
73*bbb1b6f9SApple OSS Distributions  *	California, Berkeley and its contributors.
74*bbb1b6f9SApple OSS Distributions  * 4. Neither the name of the University nor the names of its contributors
75*bbb1b6f9SApple OSS Distributions  *    may be used to endorse or promote products derived from this software
76*bbb1b6f9SApple OSS Distributions  *    without specific prior written permission.
77*bbb1b6f9SApple OSS Distributions  *
78*bbb1b6f9SApple OSS Distributions  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
79*bbb1b6f9SApple OSS Distributions  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
80*bbb1b6f9SApple OSS Distributions  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
81*bbb1b6f9SApple OSS Distributions  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
82*bbb1b6f9SApple OSS Distributions  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
83*bbb1b6f9SApple OSS Distributions  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
84*bbb1b6f9SApple OSS Distributions  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
85*bbb1b6f9SApple OSS Distributions  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
86*bbb1b6f9SApple OSS Distributions  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
87*bbb1b6f9SApple OSS Distributions  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
88*bbb1b6f9SApple OSS Distributions  * SUCH DAMAGE.
89*bbb1b6f9SApple OSS Distributions  *
90*bbb1b6f9SApple OSS Distributions  *	@(#)in_pcb.c	8.2 (Berkeley) 1/4/94
91*bbb1b6f9SApple OSS Distributions  */
92*bbb1b6f9SApple OSS Distributions 
93*bbb1b6f9SApple OSS Distributions 
94*bbb1b6f9SApple OSS Distributions #include <sys/param.h>
95*bbb1b6f9SApple OSS Distributions #include <sys/systm.h>
96*bbb1b6f9SApple OSS Distributions #include <sys/malloc.h>
97*bbb1b6f9SApple OSS Distributions #include <sys/mbuf.h>
98*bbb1b6f9SApple OSS Distributions #include <sys/protosw.h>
99*bbb1b6f9SApple OSS Distributions #include <sys/socket.h>
100*bbb1b6f9SApple OSS Distributions #include <sys/socketvar.h>
101*bbb1b6f9SApple OSS Distributions #include <sys/errno.h>
102*bbb1b6f9SApple OSS Distributions #include <sys/time.h>
103*bbb1b6f9SApple OSS Distributions #include <sys/proc.h>
104*bbb1b6f9SApple OSS Distributions #include <sys/sysctl.h>
105*bbb1b6f9SApple OSS Distributions #include <sys/kauth.h>
106*bbb1b6f9SApple OSS Distributions #include <sys/priv.h>
107*bbb1b6f9SApple OSS Distributions #include <kern/locks.h>
108*bbb1b6f9SApple OSS Distributions #include <sys/random.h>
109*bbb1b6f9SApple OSS Distributions 
110*bbb1b6f9SApple OSS Distributions #include <net/if.h>
111*bbb1b6f9SApple OSS Distributions #include <net/if_types.h>
112*bbb1b6f9SApple OSS Distributions #include <net/route.h>
113*bbb1b6f9SApple OSS Distributions #include <net/restricted_in_port.h>
114*bbb1b6f9SApple OSS Distributions 
115*bbb1b6f9SApple OSS Distributions #include <netinet/in.h>
116*bbb1b6f9SApple OSS Distributions #include <netinet/in_var.h>
117*bbb1b6f9SApple OSS Distributions #include <netinet/in_systm.h>
118*bbb1b6f9SApple OSS Distributions #include <netinet/ip.h>
119*bbb1b6f9SApple OSS Distributions #include <netinet/in_pcb.h>
120*bbb1b6f9SApple OSS Distributions 
121*bbb1b6f9SApple OSS Distributions #include <netinet6/in6_var.h>
122*bbb1b6f9SApple OSS Distributions #include <netinet/ip6.h>
123*bbb1b6f9SApple OSS Distributions #include <netinet6/in6_pcb.h>
124*bbb1b6f9SApple OSS Distributions #include <netinet6/ip6_var.h>
125*bbb1b6f9SApple OSS Distributions #include <netinet6/scope6_var.h>
126*bbb1b6f9SApple OSS Distributions #include <netinet6/nd6.h>
127*bbb1b6f9SApple OSS Distributions 
128*bbb1b6f9SApple OSS Distributions #include <net/net_osdep.h>
129*bbb1b6f9SApple OSS Distributions 
130*bbb1b6f9SApple OSS Distributions #include <net/sockaddr_utils.h>
131*bbb1b6f9SApple OSS Distributions 
132*bbb1b6f9SApple OSS Distributions #include "loop.h"
133*bbb1b6f9SApple OSS Distributions 
134*bbb1b6f9SApple OSS Distributions SYSCTL_DECL(_net_inet6_ip6);
135*bbb1b6f9SApple OSS Distributions 
136*bbb1b6f9SApple OSS Distributions static int ip6_select_srcif_debug = 0;
137*bbb1b6f9SApple OSS Distributions SYSCTL_INT(_net_inet6_ip6, OID_AUTO, select_srcif_debug,
138*bbb1b6f9SApple OSS Distributions     CTLFLAG_RW | CTLFLAG_LOCKED, &ip6_select_srcif_debug, 0,
139*bbb1b6f9SApple OSS Distributions     "log source interface selection debug info");
140*bbb1b6f9SApple OSS Distributions 
141*bbb1b6f9SApple OSS Distributions static int ip6_select_srcaddr_debug = 0;
142*bbb1b6f9SApple OSS Distributions SYSCTL_INT(_net_inet6_ip6, OID_AUTO, select_srcaddr_debug,
143*bbb1b6f9SApple OSS Distributions     CTLFLAG_RW | CTLFLAG_LOCKED, &ip6_select_srcaddr_debug, 0,
144*bbb1b6f9SApple OSS Distributions     "log source address selection debug info");
145*bbb1b6f9SApple OSS Distributions 
146*bbb1b6f9SApple OSS Distributions static int ip6_select_src_expensive_secondary_if = 0;
147*bbb1b6f9SApple OSS Distributions SYSCTL_INT(_net_inet6_ip6, OID_AUTO, select_src_expensive_secondary_if,
148*bbb1b6f9SApple OSS Distributions     CTLFLAG_RW | CTLFLAG_LOCKED, &ip6_select_src_expensive_secondary_if, 0,
149*bbb1b6f9SApple OSS Distributions     "allow source interface selection to use expensive secondaries");
150*bbb1b6f9SApple OSS Distributions 
151*bbb1b6f9SApple OSS Distributions static int ip6_select_src_strong_end = 1;
152*bbb1b6f9SApple OSS Distributions SYSCTL_INT(_net_inet6_ip6, OID_AUTO, select_src_strong_end,
153*bbb1b6f9SApple OSS Distributions     CTLFLAG_RW | CTLFLAG_LOCKED, &ip6_select_src_strong_end, 0,
154*bbb1b6f9SApple OSS Distributions     "limit source address selection to outgoing interface");
155*bbb1b6f9SApple OSS Distributions 
156*bbb1b6f9SApple OSS Distributions #define ADDR_LABEL_NOTAPP (-1)
157*bbb1b6f9SApple OSS Distributions struct in6_addrpolicy defaultaddrpolicy;
158*bbb1b6f9SApple OSS Distributions 
159*bbb1b6f9SApple OSS Distributions int ip6_prefer_tempaddr = 1;
160*bbb1b6f9SApple OSS Distributions 
161*bbb1b6f9SApple OSS Distributions int ip6_cga_conflict_retries = IPV6_CGA_CONFLICT_RETRIES_DEFAULT;
162*bbb1b6f9SApple OSS Distributions 
163*bbb1b6f9SApple OSS Distributions extern int      udp_use_randomport;
164*bbb1b6f9SApple OSS Distributions extern int      tcp_use_randomport;
165*bbb1b6f9SApple OSS Distributions 
166*bbb1b6f9SApple OSS Distributions static int selectroute(struct sockaddr_in6 *, struct sockaddr_in6 *,
167*bbb1b6f9SApple OSS Distributions     struct ip6_pktopts *, struct ip6_moptions *, struct in6_ifaddr **,
168*bbb1b6f9SApple OSS Distributions     struct route_in6 *, struct ifnet **, struct rtentry **, int, int,
169*bbb1b6f9SApple OSS Distributions     struct ip6_out_args *ip6oa);
170*bbb1b6f9SApple OSS Distributions static int in6_selectif(struct sockaddr_in6 *, struct ip6_pktopts *,
171*bbb1b6f9SApple OSS Distributions     struct ip6_moptions *, struct route_in6 *ro,
172*bbb1b6f9SApple OSS Distributions     struct ip6_out_args *, struct ifnet **);
173*bbb1b6f9SApple OSS Distributions static void init_policy_queue(void);
174*bbb1b6f9SApple OSS Distributions static int add_addrsel_policyent(const struct in6_addrpolicy *);
175*bbb1b6f9SApple OSS Distributions static int walk_addrsel_policy(int (*)(const struct in6_addrpolicy *, void *),
176*bbb1b6f9SApple OSS Distributions     void *);
177*bbb1b6f9SApple OSS Distributions static int dump_addrsel_policyent(const struct in6_addrpolicy *, void *);
178*bbb1b6f9SApple OSS Distributions static struct in6_addrpolicy *match_addrsel_policy(struct sockaddr_in6 *);
179*bbb1b6f9SApple OSS Distributions void addrsel_policy_init(void);
180*bbb1b6f9SApple OSS Distributions 
181*bbb1b6f9SApple OSS Distributions #define SASEL_DO_DBG(inp) \
182*bbb1b6f9SApple OSS Distributions 	(ip6_select_srcaddr_debug)
183*bbb1b6f9SApple OSS Distributions 
184*bbb1b6f9SApple OSS Distributions #define SASEL_LOG(fmt, ...) \
185*bbb1b6f9SApple OSS Distributions do { \
186*bbb1b6f9SApple OSS Distributions 	if (ip6_select_srcaddr_debug) \
187*bbb1b6f9SApple OSS Distributions 	        os_log(OS_LOG_DEFAULT, "%s:%d " fmt,\
188*bbb1b6f9SApple OSS Distributions 	            __FUNCTION__, __LINE__, ##__VA_ARGS__); \
189*bbb1b6f9SApple OSS Distributions } while (0); \
190*bbb1b6f9SApple OSS Distributions 
191*bbb1b6f9SApple OSS Distributions /*
192*bbb1b6f9SApple OSS Distributions  * Return an IPv6 address, which is the most appropriate for a given
193*bbb1b6f9SApple OSS Distributions  * destination and user specified options.
194*bbb1b6f9SApple OSS Distributions  * If necessary, this function lookups the routing table and returns
195*bbb1b6f9SApple OSS Distributions  * an entry to the caller for later use.
196*bbb1b6f9SApple OSS Distributions  */
197*bbb1b6f9SApple OSS Distributions #define REPLACE(r) do {\
198*bbb1b6f9SApple OSS Distributions 	SASEL_LOG("REPLACE r %s ia %s ifp1 %s\n", \
199*bbb1b6f9SApple OSS Distributions 	    (#r), s_src, ifp1->if_xname); \
200*bbb1b6f9SApple OSS Distributions 	srcrule = (r); \
201*bbb1b6f9SApple OSS Distributions 	goto replace; \
202*bbb1b6f9SApple OSS Distributions } while (0)
203*bbb1b6f9SApple OSS Distributions 
204*bbb1b6f9SApple OSS Distributions #define NEXTSRC(r) do {\
205*bbb1b6f9SApple OSS Distributions 	SASEL_LOG("NEXTSRC r %s ia %s ifp1 %s\n", \
206*bbb1b6f9SApple OSS Distributions 	    (#r), s_src, ifp1->if_xname); \
207*bbb1b6f9SApple OSS Distributions 	goto next;              /* XXX: we can't use 'continue' here */ \
208*bbb1b6f9SApple OSS Distributions } while (0)
209*bbb1b6f9SApple OSS Distributions 
210*bbb1b6f9SApple OSS Distributions #define BREAK(r) do { \
211*bbb1b6f9SApple OSS Distributions 	SASEL_LOG("BREAK r %s ia %s ifp1 %s\n", \
212*bbb1b6f9SApple OSS Distributions 	    (#r), s_src, ifp1->if_xname); \
213*bbb1b6f9SApple OSS Distributions 	srcrule = (r); \
214*bbb1b6f9SApple OSS Distributions 	goto out;               /* XXX: we can't use 'break' here */ \
215*bbb1b6f9SApple OSS Distributions } while (0)
216*bbb1b6f9SApple OSS Distributions 
217*bbb1b6f9SApple OSS Distributions 
218*bbb1b6f9SApple OSS Distributions struct ifaddr *
in6_selectsrc_core_ifa(struct sockaddr_in6 * addr,struct ifnet * ifp)219*bbb1b6f9SApple OSS Distributions in6_selectsrc_core_ifa(struct sockaddr_in6 *addr, struct ifnet *ifp)
220*bbb1b6f9SApple OSS Distributions {
221*bbb1b6f9SApple OSS Distributions 	int err = 0;
222*bbb1b6f9SApple OSS Distributions 	struct ifnet *__single src_ifp = NULL;
223*bbb1b6f9SApple OSS Distributions 	struct in6_addr src_storage = {};
224*bbb1b6f9SApple OSS Distributions 	struct in6_addr *__single in6 = NULL;
225*bbb1b6f9SApple OSS Distributions 	struct ifaddr *__single ifa = NULL;
226*bbb1b6f9SApple OSS Distributions 
227*bbb1b6f9SApple OSS Distributions 	if ((in6 = in6_selectsrc_core(addr,
228*bbb1b6f9SApple OSS Distributions 	    (ip6_prefer_tempaddr ? IPV6_SRCSEL_HINT_PREFER_TMPADDR : 0),
229*bbb1b6f9SApple OSS Distributions 	    ifp, 0, &src_storage, &src_ifp, &err, &ifa, NULL, FALSE)) == NULL) {
230*bbb1b6f9SApple OSS Distributions 		if (err == 0) {
231*bbb1b6f9SApple OSS Distributions 			err = EADDRNOTAVAIL;
232*bbb1b6f9SApple OSS Distributions 		}
233*bbb1b6f9SApple OSS Distributions 		VERIFY(src_ifp == NULL);
234*bbb1b6f9SApple OSS Distributions 		if (ifa != NULL) {
235*bbb1b6f9SApple OSS Distributions 			ifa_remref(ifa);
236*bbb1b6f9SApple OSS Distributions 			ifa = NULL;
237*bbb1b6f9SApple OSS Distributions 		}
238*bbb1b6f9SApple OSS Distributions 		goto done;
239*bbb1b6f9SApple OSS Distributions 	}
240*bbb1b6f9SApple OSS Distributions 
241*bbb1b6f9SApple OSS Distributions 	if (src_ifp != ifp) {
242*bbb1b6f9SApple OSS Distributions 		if (err == 0) {
243*bbb1b6f9SApple OSS Distributions 			err = ENETUNREACH;
244*bbb1b6f9SApple OSS Distributions 		}
245*bbb1b6f9SApple OSS Distributions 		if (ifa != NULL) {
246*bbb1b6f9SApple OSS Distributions 			ifa_remref(ifa);
247*bbb1b6f9SApple OSS Distributions 			ifa = NULL;
248*bbb1b6f9SApple OSS Distributions 		}
249*bbb1b6f9SApple OSS Distributions 		goto done;
250*bbb1b6f9SApple OSS Distributions 	}
251*bbb1b6f9SApple OSS Distributions 
252*bbb1b6f9SApple OSS Distributions 	VERIFY(ifa != NULL);
253*bbb1b6f9SApple OSS Distributions 	ifnet_lock_shared(ifp);
254*bbb1b6f9SApple OSS Distributions 	if ((ifa->ifa_debug & IFD_DETACHING) != 0) {
255*bbb1b6f9SApple OSS Distributions 		err = EHOSTUNREACH;
256*bbb1b6f9SApple OSS Distributions 		ifnet_lock_done(ifp);
257*bbb1b6f9SApple OSS Distributions 		ifa_remref(ifa);
258*bbb1b6f9SApple OSS Distributions 		ifa = NULL;
259*bbb1b6f9SApple OSS Distributions 		goto done;
260*bbb1b6f9SApple OSS Distributions 	}
261*bbb1b6f9SApple OSS Distributions 	ifnet_lock_done(ifp);
262*bbb1b6f9SApple OSS Distributions 
263*bbb1b6f9SApple OSS Distributions done:
264*bbb1b6f9SApple OSS Distributions 	SASEL_LOG("Returned with error: %d", err);
265*bbb1b6f9SApple OSS Distributions 	if (src_ifp != NULL) {
266*bbb1b6f9SApple OSS Distributions 		ifnet_release(src_ifp);
267*bbb1b6f9SApple OSS Distributions 	}
268*bbb1b6f9SApple OSS Distributions 	return ifa;
269*bbb1b6f9SApple OSS Distributions }
270*bbb1b6f9SApple OSS Distributions 
271*bbb1b6f9SApple OSS Distributions struct in6_addr *
in6_selectsrc_core(struct sockaddr_in6 * dstsock,uint32_t hint_mask,struct ifnet * ifp,int srcsel_debug,struct in6_addr * src_storage,struct ifnet ** sifp,int * errorp,struct ifaddr ** ifapp,struct route_in6 * ro,boolean_t is_for_clat46)272*bbb1b6f9SApple OSS Distributions in6_selectsrc_core(struct sockaddr_in6 *dstsock, uint32_t hint_mask,
273*bbb1b6f9SApple OSS Distributions     struct ifnet *ifp, int srcsel_debug, struct in6_addr *src_storage,
274*bbb1b6f9SApple OSS Distributions     struct ifnet **sifp, int *errorp, struct ifaddr **ifapp, struct route_in6 *ro,
275*bbb1b6f9SApple OSS Distributions     boolean_t is_for_clat46)
276*bbb1b6f9SApple OSS Distributions {
277*bbb1b6f9SApple OSS Distributions 	u_int32_t odstzone;
278*bbb1b6f9SApple OSS Distributions 	int bestrule = IP6S_SRCRULE_0;
279*bbb1b6f9SApple OSS Distributions 	struct in6_addrpolicy *__single dst_policy = NULL, *__single best_policy = NULL;
280*bbb1b6f9SApple OSS Distributions 	struct in6_addr dst;
281*bbb1b6f9SApple OSS Distributions 	struct in6_ifaddr *__single ia = NULL, *__single ia_best = NULL;
282*bbb1b6f9SApple OSS Distributions 	char s_src[MAX_IPv6_STR_LEN] = {0};
283*bbb1b6f9SApple OSS Distributions 	char s_dst[MAX_IPv6_STR_LEN] = {0};
284*bbb1b6f9SApple OSS Distributions 	const struct in6_addr *__single  tmp = NULL;
285*bbb1b6f9SApple OSS Distributions 	int dst_scope = -1, best_scope = -1, best_matchlen = -1;
286*bbb1b6f9SApple OSS Distributions 	uint64_t secs = net_uptime();
287*bbb1b6f9SApple OSS Distributions 	struct nd_defrouter *__single dr = NULL;
288*bbb1b6f9SApple OSS Distributions 	uint32_t genid = in6_ifaddrlist_genid;
289*bbb1b6f9SApple OSS Distributions 	VERIFY(dstsock != NULL);
290*bbb1b6f9SApple OSS Distributions 	VERIFY(src_storage != NULL);
291*bbb1b6f9SApple OSS Distributions 	VERIFY(ifp != NULL);
292*bbb1b6f9SApple OSS Distributions 
293*bbb1b6f9SApple OSS Distributions 	if (sifp != NULL) {
294*bbb1b6f9SApple OSS Distributions 		*sifp = NULL;
295*bbb1b6f9SApple OSS Distributions 	}
296*bbb1b6f9SApple OSS Distributions 
297*bbb1b6f9SApple OSS Distributions 	if (ifapp != NULL) {
298*bbb1b6f9SApple OSS Distributions 		*ifapp = NULL;
299*bbb1b6f9SApple OSS Distributions 	}
300*bbb1b6f9SApple OSS Distributions 
301*bbb1b6f9SApple OSS Distributions 	dst = dstsock->sin6_addr; /* make a copy for local operation */
302*bbb1b6f9SApple OSS Distributions 
303*bbb1b6f9SApple OSS Distributions 	if (srcsel_debug) {
304*bbb1b6f9SApple OSS Distributions 		(void) inet_ntop(AF_INET6, &dst, s_dst, sizeof(s_src));
305*bbb1b6f9SApple OSS Distributions 
306*bbb1b6f9SApple OSS Distributions 		tmp = &in6addr_any;
307*bbb1b6f9SApple OSS Distributions 		(void) inet_ntop(AF_INET6, tmp, s_src, sizeof(s_src));
308*bbb1b6f9SApple OSS Distributions 		SASEL_LOG("in src %s dst %s ifp %s\n", s_src, s_dst, ifp->if_xname);
309*bbb1b6f9SApple OSS Distributions 	}
310*bbb1b6f9SApple OSS Distributions 
311*bbb1b6f9SApple OSS Distributions 	*errorp = in6_setscope(&dst, ifp, &odstzone);
312*bbb1b6f9SApple OSS Distributions 	if (*errorp != 0) {
313*bbb1b6f9SApple OSS Distributions 		src_storage = NULL;
314*bbb1b6f9SApple OSS Distributions 		goto done;
315*bbb1b6f9SApple OSS Distributions 	}
316*bbb1b6f9SApple OSS Distributions 
317*bbb1b6f9SApple OSS Distributions 	/*
318*bbb1b6f9SApple OSS Distributions 	 * Determine if the route is an indirect here
319*bbb1b6f9SApple OSS Distributions 	 * and if it is get the default router that would be
320*bbb1b6f9SApple OSS Distributions 	 * used as next hop.
321*bbb1b6f9SApple OSS Distributions 	 * Later in the function it is used to apply rule 5.5 of RFC 6724.
322*bbb1b6f9SApple OSS Distributions 	 */
323*bbb1b6f9SApple OSS Distributions 	if (ro != NULL && ro->ro_rt != NULL &&
324*bbb1b6f9SApple OSS Distributions 	    (ro->ro_rt->rt_flags & RTF_GATEWAY) &&
325*bbb1b6f9SApple OSS Distributions 	    ro->ro_rt->rt_gateway != NULL) {
326*bbb1b6f9SApple OSS Distributions 		struct rtentry *__single rt = ro->ro_rt;
327*bbb1b6f9SApple OSS Distributions 		lck_mtx_lock(nd6_mutex);
328*bbb1b6f9SApple OSS Distributions 		dr = defrouter_lookup(NULL,
329*bbb1b6f9SApple OSS Distributions 		    &SIN6(rt->rt_gateway)->sin6_addr, rt->rt_ifp);
330*bbb1b6f9SApple OSS Distributions 		lck_mtx_unlock(nd6_mutex);
331*bbb1b6f9SApple OSS Distributions 	}
332*bbb1b6f9SApple OSS Distributions 
333*bbb1b6f9SApple OSS Distributions 	lck_rw_lock_shared(&in6_ifaddr_rwlock);
334*bbb1b6f9SApple OSS Distributions addrloop:
335*bbb1b6f9SApple OSS Distributions 	TAILQ_FOREACH(ia, &in6_ifaddrhead, ia6_link) {
336*bbb1b6f9SApple OSS Distributions 		int new_scope = -1, new_matchlen = -1;
337*bbb1b6f9SApple OSS Distributions 		struct in6_addrpolicy *__single new_policy = NULL;
338*bbb1b6f9SApple OSS Distributions 		u_int32_t srczone = 0, osrczone, dstzone;
339*bbb1b6f9SApple OSS Distributions 		struct in6_addr src;
340*bbb1b6f9SApple OSS Distributions 		struct ifnet *__single ifp1 = ia->ia_ifp;
341*bbb1b6f9SApple OSS Distributions 		int srcrule;
342*bbb1b6f9SApple OSS Distributions 
343*bbb1b6f9SApple OSS Distributions 		if (srcsel_debug) {
344*bbb1b6f9SApple OSS Distributions 			(void) inet_ntop(AF_INET6, &ia->ia_addr.sin6_addr,
345*bbb1b6f9SApple OSS Distributions 			    s_src, sizeof(s_src));
346*bbb1b6f9SApple OSS Distributions 		}
347*bbb1b6f9SApple OSS Distributions 
348*bbb1b6f9SApple OSS Distributions 		IFA_LOCK(&ia->ia_ifa);
349*bbb1b6f9SApple OSS Distributions 
350*bbb1b6f9SApple OSS Distributions 		/*
351*bbb1b6f9SApple OSS Distributions 		 * Simply skip addresses reserved for CLAT46
352*bbb1b6f9SApple OSS Distributions 		 */
353*bbb1b6f9SApple OSS Distributions 		if (!is_for_clat46 && (ia->ia6_flags & IN6_IFF_CLAT46)) {
354*bbb1b6f9SApple OSS Distributions 			SASEL_LOG("NEXT ia %s address on ifp1 %s skipped as it is "
355*bbb1b6f9SApple OSS Distributions 			    "reserved for CLAT46\n", s_src, ifp1->if_xname);
356*bbb1b6f9SApple OSS Distributions 			goto next;
357*bbb1b6f9SApple OSS Distributions 		}
358*bbb1b6f9SApple OSS Distributions 
359*bbb1b6f9SApple OSS Distributions 		if (is_for_clat46 && !(ia->ia6_flags & IN6_IFF_CLAT46)) {
360*bbb1b6f9SApple OSS Distributions 			SASEL_LOG("CLAT46: NEXT ia %s address on ifp1 %s skipped as it is "
361*bbb1b6f9SApple OSS Distributions 			    "not reserved for CLAT46\n", s_src, ifp1->if_xname);
362*bbb1b6f9SApple OSS Distributions 			goto next;
363*bbb1b6f9SApple OSS Distributions 		}
364*bbb1b6f9SApple OSS Distributions 
365*bbb1b6f9SApple OSS Distributions 		/*
366*bbb1b6f9SApple OSS Distributions 		 * XXX By default we are strong end system and will
367*bbb1b6f9SApple OSS Distributions 		 * limit candidate set of source address to the ones
368*bbb1b6f9SApple OSS Distributions 		 * configured on the outgoing interface.
369*bbb1b6f9SApple OSS Distributions 		 */
370*bbb1b6f9SApple OSS Distributions 		if (ip6_select_src_strong_end &&
371*bbb1b6f9SApple OSS Distributions 		    ifp1 != ifp) {
372*bbb1b6f9SApple OSS Distributions 			SASEL_LOG("NEXT ia %s ifp1 %s address is not on outgoing "
373*bbb1b6f9SApple OSS Distributions 			    "interface\n", s_src, ifp1->if_xname);
374*bbb1b6f9SApple OSS Distributions 			goto next;
375*bbb1b6f9SApple OSS Distributions 		}
376*bbb1b6f9SApple OSS Distributions 
377*bbb1b6f9SApple OSS Distributions 		/*
378*bbb1b6f9SApple OSS Distributions 		 * We'll never take an address that breaks the scope zone
379*bbb1b6f9SApple OSS Distributions 		 * of the destination. We also skip an address if its zone
380*bbb1b6f9SApple OSS Distributions 		 * does not contain the outgoing interface.
381*bbb1b6f9SApple OSS Distributions 		 * XXX: we should probably use sin6_scope_id here.
382*bbb1b6f9SApple OSS Distributions 		 */
383*bbb1b6f9SApple OSS Distributions 		if (in6_setscope(&dst, ifp1, &dstzone) ||
384*bbb1b6f9SApple OSS Distributions 		    odstzone != dstzone) {
385*bbb1b6f9SApple OSS Distributions 			SASEL_LOG("NEXT ia %s ifp1 %s odstzone %d != dstzone %d\n",
386*bbb1b6f9SApple OSS Distributions 			    s_src, ifp1->if_xname, odstzone, dstzone);
387*bbb1b6f9SApple OSS Distributions 			goto next;
388*bbb1b6f9SApple OSS Distributions 		}
389*bbb1b6f9SApple OSS Distributions 		src = ia->ia_addr.sin6_addr;
390*bbb1b6f9SApple OSS Distributions 		if (in6_setscope(&src, ifp, &osrczone) ||
391*bbb1b6f9SApple OSS Distributions 		    in6_setscope(&src, ifp1, &srczone) ||
392*bbb1b6f9SApple OSS Distributions 		    osrczone != srczone) {
393*bbb1b6f9SApple OSS Distributions 			SASEL_LOG("NEXT ia %s ifp1 %s osrczone %d != srczone %d\n",
394*bbb1b6f9SApple OSS Distributions 			    s_src, ifp1->if_xname, osrczone, srczone);
395*bbb1b6f9SApple OSS Distributions 			goto next;
396*bbb1b6f9SApple OSS Distributions 		}
397*bbb1b6f9SApple OSS Distributions 		/* avoid unusable addresses */
398*bbb1b6f9SApple OSS Distributions 		if ((ia->ia6_flags &
399*bbb1b6f9SApple OSS Distributions 		    (IN6_IFF_NOTREADY | IN6_IFF_ANYCAST | IN6_IFF_DETACHED))) {
400*bbb1b6f9SApple OSS Distributions 			SASEL_LOG("NEXT ia %s ifp1 %s ia6_flags 0x%x\n",
401*bbb1b6f9SApple OSS Distributions 			    s_src, ifp1->if_xname, ia->ia6_flags);
402*bbb1b6f9SApple OSS Distributions 			goto next;
403*bbb1b6f9SApple OSS Distributions 		}
404*bbb1b6f9SApple OSS Distributions 		if (!ip6_use_deprecated && IFA6_IS_DEPRECATED(ia, secs)) {
405*bbb1b6f9SApple OSS Distributions 			SASEL_LOG("NEXT ia %s ifp1 %s IFA6_IS_DEPRECATED\n",
406*bbb1b6f9SApple OSS Distributions 			    s_src, ifp1->if_xname);
407*bbb1b6f9SApple OSS Distributions 			goto next;
408*bbb1b6f9SApple OSS Distributions 		}
409*bbb1b6f9SApple OSS Distributions 		if (!nd6_optimistic_dad &&
410*bbb1b6f9SApple OSS Distributions 		    (ia->ia6_flags & IN6_IFF_OPTIMISTIC) != 0) {
411*bbb1b6f9SApple OSS Distributions 			SASEL_LOG("NEXT ia %s ifp1 %s IN6_IFF_OPTIMISTIC\n",
412*bbb1b6f9SApple OSS Distributions 			    s_src, ifp1->if_xname);
413*bbb1b6f9SApple OSS Distributions 			goto next;
414*bbb1b6f9SApple OSS Distributions 		}
415*bbb1b6f9SApple OSS Distributions 		/* Rule 1: Prefer same address */
416*bbb1b6f9SApple OSS Distributions 		if (in6_are_addr_equal_scoped(&dst, &ia->ia_addr.sin6_addr, dstzone, srczone)) {
417*bbb1b6f9SApple OSS Distributions 			BREAK(IP6S_SRCRULE_1); /* there should be no better candidate */
418*bbb1b6f9SApple OSS Distributions 		}
419*bbb1b6f9SApple OSS Distributions 		if (ia_best == NULL) {
420*bbb1b6f9SApple OSS Distributions 			REPLACE(IP6S_SRCRULE_0);
421*bbb1b6f9SApple OSS Distributions 		}
422*bbb1b6f9SApple OSS Distributions 
423*bbb1b6f9SApple OSS Distributions 		/* Rule 2: Prefer appropriate scope */
424*bbb1b6f9SApple OSS Distributions 		if (dst_scope < 0) {
425*bbb1b6f9SApple OSS Distributions 			dst_scope = in6_addrscope(&dst);
426*bbb1b6f9SApple OSS Distributions 		}
427*bbb1b6f9SApple OSS Distributions 		new_scope = in6_addrscope(&ia->ia_addr.sin6_addr);
428*bbb1b6f9SApple OSS Distributions 		if (IN6_ARE_SCOPE_CMP(best_scope, new_scope) < 0) {
429*bbb1b6f9SApple OSS Distributions 			if (IN6_ARE_SCOPE_CMP(best_scope, dst_scope) < 0) {
430*bbb1b6f9SApple OSS Distributions 				REPLACE(IP6S_SRCRULE_2);
431*bbb1b6f9SApple OSS Distributions 			}
432*bbb1b6f9SApple OSS Distributions 			NEXTSRC(IP6S_SRCRULE_2);
433*bbb1b6f9SApple OSS Distributions 		} else if (IN6_ARE_SCOPE_CMP(new_scope, best_scope) < 0) {
434*bbb1b6f9SApple OSS Distributions 			if (IN6_ARE_SCOPE_CMP(new_scope, dst_scope) < 0) {
435*bbb1b6f9SApple OSS Distributions 				NEXTSRC(IP6S_SRCRULE_2);
436*bbb1b6f9SApple OSS Distributions 			}
437*bbb1b6f9SApple OSS Distributions 			REPLACE(IP6S_SRCRULE_2);
438*bbb1b6f9SApple OSS Distributions 		}
439*bbb1b6f9SApple OSS Distributions 
440*bbb1b6f9SApple OSS Distributions 		/*
441*bbb1b6f9SApple OSS Distributions 		 * Rule 3: Avoid deprecated addresses.  Note that the case of
442*bbb1b6f9SApple OSS Distributions 		 * !ip6_use_deprecated is already rejected above.
443*bbb1b6f9SApple OSS Distributions 		 */
444*bbb1b6f9SApple OSS Distributions 		if (!IFA6_IS_DEPRECATED(ia_best, secs) &&
445*bbb1b6f9SApple OSS Distributions 		    IFA6_IS_DEPRECATED(ia, secs)) {
446*bbb1b6f9SApple OSS Distributions 			NEXTSRC(IP6S_SRCRULE_3);
447*bbb1b6f9SApple OSS Distributions 		}
448*bbb1b6f9SApple OSS Distributions 		if (IFA6_IS_DEPRECATED(ia_best, secs) &&
449*bbb1b6f9SApple OSS Distributions 		    !IFA6_IS_DEPRECATED(ia, secs)) {
450*bbb1b6f9SApple OSS Distributions 			REPLACE(IP6S_SRCRULE_3);
451*bbb1b6f9SApple OSS Distributions 		}
452*bbb1b6f9SApple OSS Distributions 
453*bbb1b6f9SApple OSS Distributions 		/*
454*bbb1b6f9SApple OSS Distributions 		 * RFC 4429 says that optimistic addresses are equivalent to
455*bbb1b6f9SApple OSS Distributions 		 * deprecated addresses, so avoid them here.
456*bbb1b6f9SApple OSS Distributions 		 */
457*bbb1b6f9SApple OSS Distributions 		if ((ia_best->ia6_flags & IN6_IFF_OPTIMISTIC) == 0 &&
458*bbb1b6f9SApple OSS Distributions 		    (ia->ia6_flags & IN6_IFF_OPTIMISTIC) != 0) {
459*bbb1b6f9SApple OSS Distributions 			NEXTSRC(IP6S_SRCRULE_3);
460*bbb1b6f9SApple OSS Distributions 		}
461*bbb1b6f9SApple OSS Distributions 		if ((ia_best->ia6_flags & IN6_IFF_OPTIMISTIC) != 0 &&
462*bbb1b6f9SApple OSS Distributions 		    (ia->ia6_flags & IN6_IFF_OPTIMISTIC) == 0) {
463*bbb1b6f9SApple OSS Distributions 			REPLACE(IP6S_SRCRULE_3);
464*bbb1b6f9SApple OSS Distributions 		}
465*bbb1b6f9SApple OSS Distributions 
466*bbb1b6f9SApple OSS Distributions 		/* Rule 4: Prefer home addresses */
467*bbb1b6f9SApple OSS Distributions 		/*
468*bbb1b6f9SApple OSS Distributions 		 * XXX: This is a TODO.  We should probably merge the MIP6
469*bbb1b6f9SApple OSS Distributions 		 * case above.
470*bbb1b6f9SApple OSS Distributions 		 */
471*bbb1b6f9SApple OSS Distributions 
472*bbb1b6f9SApple OSS Distributions 		/* Rule 5: Prefer outgoing interface */
473*bbb1b6f9SApple OSS Distributions 		/*
474*bbb1b6f9SApple OSS Distributions 		 * XXX By default we are strong end with source address
475*bbb1b6f9SApple OSS Distributions 		 * selection. That means all address selection candidate
476*bbb1b6f9SApple OSS Distributions 		 * addresses will be the ones hosted on the outgoing interface
477*bbb1b6f9SApple OSS Distributions 		 * making the following check redundant.
478*bbb1b6f9SApple OSS Distributions 		 */
479*bbb1b6f9SApple OSS Distributions 		if (ip6_select_src_strong_end == 0) {
480*bbb1b6f9SApple OSS Distributions 			if (ia_best->ia_ifp == ifp && ia->ia_ifp != ifp) {
481*bbb1b6f9SApple OSS Distributions 				NEXTSRC(IP6S_SRCRULE_5);
482*bbb1b6f9SApple OSS Distributions 			}
483*bbb1b6f9SApple OSS Distributions 			if (ia_best->ia_ifp != ifp && ia->ia_ifp == ifp) {
484*bbb1b6f9SApple OSS Distributions 				REPLACE(IP6S_SRCRULE_5);
485*bbb1b6f9SApple OSS Distributions 			}
486*bbb1b6f9SApple OSS Distributions 		}
487*bbb1b6f9SApple OSS Distributions 
488*bbb1b6f9SApple OSS Distributions 		/*
489*bbb1b6f9SApple OSS Distributions 		 * Rule 5.5: Prefer addresses in a prefix advertised by the next-hop.
490*bbb1b6f9SApple OSS Distributions 		 * If SA or SA's prefix is assigned by the selected next-hop that will
491*bbb1b6f9SApple OSS Distributions 		 * be used to send to D and SB or SB's prefix is assigned by a different
492*bbb1b6f9SApple OSS Distributions 		 * next-hop, then prefer SA.  Similarly, if SB or SB's prefix is
493*bbb1b6f9SApple OSS Distributions 		 * assigned by the next-hop that will be used to send to D and SA or
494*bbb1b6f9SApple OSS Distributions 		 * SA's prefix is assigned by a different next-hop, then prefer SB.
495*bbb1b6f9SApple OSS Distributions 		 */
496*bbb1b6f9SApple OSS Distributions 		if (dr != NULL && ia_best->ia6_ndpr != ia->ia6_ndpr) {
497*bbb1b6f9SApple OSS Distributions 			boolean_t ia_best_has_prefix = FALSE;
498*bbb1b6f9SApple OSS Distributions 			boolean_t ia_has_prefix = FALSE;
499*bbb1b6f9SApple OSS Distributions 			struct nd_prefix ia_best_prefix = {};
500*bbb1b6f9SApple OSS Distributions 			struct nd_prefix ia_prefix = {};
501*bbb1b6f9SApple OSS Distributions 			struct nd_prefix *__single p_ia_best_prefix = NULL;
502*bbb1b6f9SApple OSS Distributions 			struct nd_prefix *__single p_ia_prefix = NULL;
503*bbb1b6f9SApple OSS Distributions 
504*bbb1b6f9SApple OSS Distributions 			if (ia_best->ia6_ndpr) {
505*bbb1b6f9SApple OSS Distributions 				ia_best_prefix = *ia_best->ia6_ndpr;
506*bbb1b6f9SApple OSS Distributions 			}
507*bbb1b6f9SApple OSS Distributions 
508*bbb1b6f9SApple OSS Distributions 			if (ia->ia6_ndpr) {
509*bbb1b6f9SApple OSS Distributions 				ia_prefix = *ia->ia6_ndpr;
510*bbb1b6f9SApple OSS Distributions 			}
511*bbb1b6f9SApple OSS Distributions 
512*bbb1b6f9SApple OSS Distributions 			IFA_UNLOCK(&ia->ia_ifa);
513*bbb1b6f9SApple OSS Distributions 			lck_rw_done(&in6_ifaddr_rwlock);
514*bbb1b6f9SApple OSS Distributions 
515*bbb1b6f9SApple OSS Distributions 			p_ia_best_prefix = nd6_prefix_lookup(&ia_best_prefix, ND6_PREFIX_EXPIRY_UNSPEC);
516*bbb1b6f9SApple OSS Distributions 			p_ia_prefix = nd6_prefix_lookup(&ia_prefix, ND6_PREFIX_EXPIRY_UNSPEC);
517*bbb1b6f9SApple OSS Distributions 
518*bbb1b6f9SApple OSS Distributions 			lck_mtx_lock(nd6_mutex);
519*bbb1b6f9SApple OSS Distributions 			if (p_ia_best_prefix != NULL) {
520*bbb1b6f9SApple OSS Distributions 				NDPR_LOCK(p_ia_best_prefix);
521*bbb1b6f9SApple OSS Distributions 				ia_best_has_prefix = (pfxrtr_lookup(p_ia_best_prefix, dr) != NULL);
522*bbb1b6f9SApple OSS Distributions 				NDPR_UNLOCK(p_ia_best_prefix);
523*bbb1b6f9SApple OSS Distributions 				NDPR_REMREF(p_ia_best_prefix);
524*bbb1b6f9SApple OSS Distributions 			}
525*bbb1b6f9SApple OSS Distributions 			if (p_ia_prefix != NULL) {
526*bbb1b6f9SApple OSS Distributions 				NDPR_LOCK(p_ia_prefix);
527*bbb1b6f9SApple OSS Distributions 				ia_has_prefix = (pfxrtr_lookup(p_ia_prefix, dr) != NULL);
528*bbb1b6f9SApple OSS Distributions 				NDPR_UNLOCK(p_ia_prefix);
529*bbb1b6f9SApple OSS Distributions 				NDPR_REMREF(p_ia_prefix);
530*bbb1b6f9SApple OSS Distributions 			}
531*bbb1b6f9SApple OSS Distributions 			lck_mtx_unlock(nd6_mutex);
532*bbb1b6f9SApple OSS Distributions 
533*bbb1b6f9SApple OSS Distributions 			lck_rw_lock_shared(&in6_ifaddr_rwlock);
534*bbb1b6f9SApple OSS Distributions 			if (genid != os_atomic_load(&in6_ifaddrlist_genid, acquire)) {
535*bbb1b6f9SApple OSS Distributions 				SASEL_LOG("Address list seems to have changed. Restarting source "
536*bbb1b6f9SApple OSS Distributions 				    "address selection.\n");
537*bbb1b6f9SApple OSS Distributions 				genid = in6_ifaddrlist_genid;
538*bbb1b6f9SApple OSS Distributions 				/*
539*bbb1b6f9SApple OSS Distributions 				 * We are starting from scratch. Free up the reference
540*bbb1b6f9SApple OSS Distributions 				 * on ia_best and also reset it to NULL.
541*bbb1b6f9SApple OSS Distributions 				 */
542*bbb1b6f9SApple OSS Distributions 				ifa_remref(&ia_best->ia_ifa);
543*bbb1b6f9SApple OSS Distributions 				ia_best = NULL;
544*bbb1b6f9SApple OSS Distributions 				goto addrloop;
545*bbb1b6f9SApple OSS Distributions 			}
546*bbb1b6f9SApple OSS Distributions 			IFA_LOCK(&ia->ia_ifa);
547*bbb1b6f9SApple OSS Distributions 
548*bbb1b6f9SApple OSS Distributions 			if (ia_best_has_prefix && !ia_has_prefix) {
549*bbb1b6f9SApple OSS Distributions 				NEXTSRC(IP6S_SRCRULE_5_5);
550*bbb1b6f9SApple OSS Distributions 			}
551*bbb1b6f9SApple OSS Distributions 
552*bbb1b6f9SApple OSS Distributions 			if (!ia_best_has_prefix && ia_has_prefix) {
553*bbb1b6f9SApple OSS Distributions 				REPLACE(IP6S_SRCRULE_5_5);
554*bbb1b6f9SApple OSS Distributions 			}
555*bbb1b6f9SApple OSS Distributions 		}
556*bbb1b6f9SApple OSS Distributions 
557*bbb1b6f9SApple OSS Distributions 		/*
558*bbb1b6f9SApple OSS Distributions 		 * Rule 6: Prefer matching label
559*bbb1b6f9SApple OSS Distributions 		 * Note that best_policy should be non-NULL here.
560*bbb1b6f9SApple OSS Distributions 		 */
561*bbb1b6f9SApple OSS Distributions 		if (dst_policy == NULL) {
562*bbb1b6f9SApple OSS Distributions 			dst_policy = in6_addrsel_lookup_policy(dstsock);
563*bbb1b6f9SApple OSS Distributions 		}
564*bbb1b6f9SApple OSS Distributions 		if (dst_policy->label != ADDR_LABEL_NOTAPP) {
565*bbb1b6f9SApple OSS Distributions 			new_policy = in6_addrsel_lookup_policy(&ia->ia_addr);
566*bbb1b6f9SApple OSS Distributions 			if (dst_policy->label == best_policy->label &&
567*bbb1b6f9SApple OSS Distributions 			    dst_policy->label != new_policy->label) {
568*bbb1b6f9SApple OSS Distributions 				NEXTSRC(IP6S_SRCRULE_6);
569*bbb1b6f9SApple OSS Distributions 			}
570*bbb1b6f9SApple OSS Distributions 			if (dst_policy->label != best_policy->label &&
571*bbb1b6f9SApple OSS Distributions 			    dst_policy->label == new_policy->label) {
572*bbb1b6f9SApple OSS Distributions 				REPLACE(IP6S_SRCRULE_6);
573*bbb1b6f9SApple OSS Distributions 			}
574*bbb1b6f9SApple OSS Distributions 		}
575*bbb1b6f9SApple OSS Distributions 
576*bbb1b6f9SApple OSS Distributions 		/*
577*bbb1b6f9SApple OSS Distributions 		 * Rule 7: Prefer temporary addresses.
578*bbb1b6f9SApple OSS Distributions 		 * We allow users to reverse the logic by configuring
579*bbb1b6f9SApple OSS Distributions 		 * a sysctl variable, so that transparency conscious users can
580*bbb1b6f9SApple OSS Distributions 		 * always prefer stable addresses.
581*bbb1b6f9SApple OSS Distributions 		 */
582*bbb1b6f9SApple OSS Distributions 		if (!(ia_best->ia6_flags & IN6_IFF_TEMPORARY) &&
583*bbb1b6f9SApple OSS Distributions 		    (ia->ia6_flags & IN6_IFF_TEMPORARY)) {
584*bbb1b6f9SApple OSS Distributions 			if (hint_mask & IPV6_SRCSEL_HINT_PREFER_TMPADDR) {
585*bbb1b6f9SApple OSS Distributions 				REPLACE(IP6S_SRCRULE_7);
586*bbb1b6f9SApple OSS Distributions 			} else {
587*bbb1b6f9SApple OSS Distributions 				NEXTSRC(IP6S_SRCRULE_7);
588*bbb1b6f9SApple OSS Distributions 			}
589*bbb1b6f9SApple OSS Distributions 		}
590*bbb1b6f9SApple OSS Distributions 		if ((ia_best->ia6_flags & IN6_IFF_TEMPORARY) &&
591*bbb1b6f9SApple OSS Distributions 		    !(ia->ia6_flags & IN6_IFF_TEMPORARY)) {
592*bbb1b6f9SApple OSS Distributions 			if (hint_mask & IPV6_SRCSEL_HINT_PREFER_TMPADDR) {
593*bbb1b6f9SApple OSS Distributions 				NEXTSRC(IP6S_SRCRULE_7);
594*bbb1b6f9SApple OSS Distributions 			} else {
595*bbb1b6f9SApple OSS Distributions 				REPLACE(IP6S_SRCRULE_7);
596*bbb1b6f9SApple OSS Distributions 			}
597*bbb1b6f9SApple OSS Distributions 		}
598*bbb1b6f9SApple OSS Distributions 
599*bbb1b6f9SApple OSS Distributions 		/*
600*bbb1b6f9SApple OSS Distributions 		 * Rule 7x: prefer addresses on alive interfaces.
601*bbb1b6f9SApple OSS Distributions 		 * This is a KAME specific rule.
602*bbb1b6f9SApple OSS Distributions 		 */
603*bbb1b6f9SApple OSS Distributions 		if ((ia_best->ia_ifp->if_flags & IFF_UP) &&
604*bbb1b6f9SApple OSS Distributions 		    !(ia->ia_ifp->if_flags & IFF_UP)) {
605*bbb1b6f9SApple OSS Distributions 			NEXTSRC(IP6S_SRCRULE_7x);
606*bbb1b6f9SApple OSS Distributions 		}
607*bbb1b6f9SApple OSS Distributions 		if (!(ia_best->ia_ifp->if_flags & IFF_UP) &&
608*bbb1b6f9SApple OSS Distributions 		    (ia->ia_ifp->if_flags & IFF_UP)) {
609*bbb1b6f9SApple OSS Distributions 			REPLACE(IP6S_SRCRULE_7x);
610*bbb1b6f9SApple OSS Distributions 		}
611*bbb1b6f9SApple OSS Distributions 
612*bbb1b6f9SApple OSS Distributions 		/*
613*bbb1b6f9SApple OSS Distributions 		 * Rule 8: Use longest matching prefix.
614*bbb1b6f9SApple OSS Distributions 		 */
615*bbb1b6f9SApple OSS Distributions 		new_matchlen = in6_matchlen(&ia->ia_addr.sin6_addr, &dst);
616*bbb1b6f9SApple OSS Distributions 		if (best_matchlen < new_matchlen) {
617*bbb1b6f9SApple OSS Distributions 			REPLACE(IP6S_SRCRULE_8);
618*bbb1b6f9SApple OSS Distributions 		}
619*bbb1b6f9SApple OSS Distributions 		if (new_matchlen < best_matchlen) {
620*bbb1b6f9SApple OSS Distributions 			NEXTSRC(IP6S_SRCRULE_8);
621*bbb1b6f9SApple OSS Distributions 		}
622*bbb1b6f9SApple OSS Distributions 
623*bbb1b6f9SApple OSS Distributions 		/*
624*bbb1b6f9SApple OSS Distributions 		 * Last resort: just keep the current candidate.
625*bbb1b6f9SApple OSS Distributions 		 * Or, do we need more rules?
626*bbb1b6f9SApple OSS Distributions 		 */
627*bbb1b6f9SApple OSS Distributions 		if (ifp1 != ifp && (ifp1->if_eflags & IFEF_EXPENSIVE) &&
628*bbb1b6f9SApple OSS Distributions 		    ip6_select_src_expensive_secondary_if == 0) {
629*bbb1b6f9SApple OSS Distributions 			SASEL_LOG("NEXT ia %s ifp1 %s IFEF_EXPENSIVE\n",
630*bbb1b6f9SApple OSS Distributions 			    s_src, ifp1->if_xname);
631*bbb1b6f9SApple OSS Distributions 			ip6stat.ip6s_sources_skip_expensive_secondary_if++;
632*bbb1b6f9SApple OSS Distributions 			goto next;
633*bbb1b6f9SApple OSS Distributions 		}
634*bbb1b6f9SApple OSS Distributions 		SASEL_LOG("NEXT ia %s ifp1 %s last resort\n",
635*bbb1b6f9SApple OSS Distributions 		    s_src, ifp1->if_xname);
636*bbb1b6f9SApple OSS Distributions 		IFA_UNLOCK(&ia->ia_ifa);
637*bbb1b6f9SApple OSS Distributions 		continue;
638*bbb1b6f9SApple OSS Distributions 
639*bbb1b6f9SApple OSS Distributions replace:
640*bbb1b6f9SApple OSS Distributions 		/*
641*bbb1b6f9SApple OSS Distributions 		 * Ignore addresses on secondary interfaces that are marked
642*bbb1b6f9SApple OSS Distributions 		 * expensive
643*bbb1b6f9SApple OSS Distributions 		 */
644*bbb1b6f9SApple OSS Distributions 		if (ifp1 != ifp && (ifp1->if_eflags & IFEF_EXPENSIVE) &&
645*bbb1b6f9SApple OSS Distributions 		    ip6_select_src_expensive_secondary_if == 0) {
646*bbb1b6f9SApple OSS Distributions 			SASEL_LOG("NEXT ia %s ifp1 %s IFEF_EXPENSIVE\n",
647*bbb1b6f9SApple OSS Distributions 			    s_src, ifp1->if_xname);
648*bbb1b6f9SApple OSS Distributions 			ip6stat.ip6s_sources_skip_expensive_secondary_if++;
649*bbb1b6f9SApple OSS Distributions 			goto next;
650*bbb1b6f9SApple OSS Distributions 		}
651*bbb1b6f9SApple OSS Distributions 		bestrule = srcrule;
652*bbb1b6f9SApple OSS Distributions 		best_scope = (new_scope >= 0 ? new_scope :
653*bbb1b6f9SApple OSS Distributions 		    in6_addrscope(&ia->ia_addr.sin6_addr));
654*bbb1b6f9SApple OSS Distributions 		best_policy = (new_policy ? new_policy :
655*bbb1b6f9SApple OSS Distributions 		    in6_addrsel_lookup_policy(&ia->ia_addr));
656*bbb1b6f9SApple OSS Distributions 		best_matchlen = (new_matchlen >= 0 ? new_matchlen :
657*bbb1b6f9SApple OSS Distributions 		    in6_matchlen(&ia->ia_addr.sin6_addr, &dst));
658*bbb1b6f9SApple OSS Distributions 		SASEL_LOG("NEXT ia %s ifp1 %s best_scope %d new_scope %d dst_scope %d\n",
659*bbb1b6f9SApple OSS Distributions 		    s_src, ifp1->if_xname, best_scope, new_scope, dst_scope);
660*bbb1b6f9SApple OSS Distributions 		ifa_addref(&ia->ia_ifa); /* for ia_best */
661*bbb1b6f9SApple OSS Distributions 		IFA_UNLOCK(&ia->ia_ifa);
662*bbb1b6f9SApple OSS Distributions 		if (ia_best != NULL) {
663*bbb1b6f9SApple OSS Distributions 			ifa_remref(&ia_best->ia_ifa);
664*bbb1b6f9SApple OSS Distributions 		}
665*bbb1b6f9SApple OSS Distributions 		ia_best = ia;
666*bbb1b6f9SApple OSS Distributions 		continue;
667*bbb1b6f9SApple OSS Distributions 
668*bbb1b6f9SApple OSS Distributions next:
669*bbb1b6f9SApple OSS Distributions 		IFA_UNLOCK(&ia->ia_ifa);
670*bbb1b6f9SApple OSS Distributions 		continue;
671*bbb1b6f9SApple OSS Distributions 
672*bbb1b6f9SApple OSS Distributions out:
673*bbb1b6f9SApple OSS Distributions 		ifa_addref(&ia->ia_ifa); /* for ia_best */
674*bbb1b6f9SApple OSS Distributions 		IFA_UNLOCK(&ia->ia_ifa);
675*bbb1b6f9SApple OSS Distributions 		if (ia_best != NULL) {
676*bbb1b6f9SApple OSS Distributions 			ifa_remref(&ia_best->ia_ifa);
677*bbb1b6f9SApple OSS Distributions 		}
678*bbb1b6f9SApple OSS Distributions 		ia_best = ia;
679*bbb1b6f9SApple OSS Distributions 		break;
680*bbb1b6f9SApple OSS Distributions 	}
681*bbb1b6f9SApple OSS Distributions 
682*bbb1b6f9SApple OSS Distributions 	lck_rw_done(&in6_ifaddr_rwlock);
683*bbb1b6f9SApple OSS Distributions 
684*bbb1b6f9SApple OSS Distributions 	if ((ia = ia_best) == NULL) {
685*bbb1b6f9SApple OSS Distributions 		if (*errorp == 0) {
686*bbb1b6f9SApple OSS Distributions 			*errorp = EADDRNOTAVAIL;
687*bbb1b6f9SApple OSS Distributions 		}
688*bbb1b6f9SApple OSS Distributions 		src_storage = NULL;
689*bbb1b6f9SApple OSS Distributions 		goto done;
690*bbb1b6f9SApple OSS Distributions 	}
691*bbb1b6f9SApple OSS Distributions 
692*bbb1b6f9SApple OSS Distributions 	if (sifp != NULL) {
693*bbb1b6f9SApple OSS Distributions 		*sifp = ia->ia_ifa.ifa_ifp;
694*bbb1b6f9SApple OSS Distributions 		ifnet_reference(*sifp);
695*bbb1b6f9SApple OSS Distributions 	}
696*bbb1b6f9SApple OSS Distributions 
697*bbb1b6f9SApple OSS Distributions 	IFA_LOCK_SPIN(&ia->ia_ifa);
698*bbb1b6f9SApple OSS Distributions 	if (bestrule < IP6S_SRCRULE_COUNT) {
699*bbb1b6f9SApple OSS Distributions 		ip6stat.ip6s_sources_rule[bestrule]++;
700*bbb1b6f9SApple OSS Distributions 	}
701*bbb1b6f9SApple OSS Distributions 	*src_storage = satosin6(&ia->ia_addr)->sin6_addr;
702*bbb1b6f9SApple OSS Distributions 	IFA_UNLOCK(&ia->ia_ifa);
703*bbb1b6f9SApple OSS Distributions 
704*bbb1b6f9SApple OSS Distributions 	if (ifapp != NULL) {
705*bbb1b6f9SApple OSS Distributions 		*ifapp = &ia->ia_ifa;
706*bbb1b6f9SApple OSS Distributions 	} else {
707*bbb1b6f9SApple OSS Distributions 		ifa_remref(&ia->ia_ifa);
708*bbb1b6f9SApple OSS Distributions 	}
709*bbb1b6f9SApple OSS Distributions 
710*bbb1b6f9SApple OSS Distributions done:
711*bbb1b6f9SApple OSS Distributions 	if (srcsel_debug) {
712*bbb1b6f9SApple OSS Distributions 		(void) inet_ntop(AF_INET6, &dst, s_dst, sizeof(s_src));
713*bbb1b6f9SApple OSS Distributions 
714*bbb1b6f9SApple OSS Distributions 		tmp = (src_storage != NULL) ? src_storage : &in6addr_any;
715*bbb1b6f9SApple OSS Distributions 		(void) inet_ntop(AF_INET6, tmp, s_src, sizeof(s_src));
716*bbb1b6f9SApple OSS Distributions 
717*bbb1b6f9SApple OSS Distributions 		SASEL_LOG("out src %s dst %s dst_scope %d best_scope %d\n",
718*bbb1b6f9SApple OSS Distributions 		    s_src, s_dst, dst_scope, best_scope);
719*bbb1b6f9SApple OSS Distributions 	}
720*bbb1b6f9SApple OSS Distributions 
721*bbb1b6f9SApple OSS Distributions 	if (dr != NULL) {
722*bbb1b6f9SApple OSS Distributions 		NDDR_REMREF(dr);
723*bbb1b6f9SApple OSS Distributions 	}
724*bbb1b6f9SApple OSS Distributions 
725*bbb1b6f9SApple OSS Distributions 	return src_storage;
726*bbb1b6f9SApple OSS Distributions }
727*bbb1b6f9SApple OSS Distributions 
728*bbb1b6f9SApple OSS Distributions /*
729*bbb1b6f9SApple OSS Distributions  * Regardless of error, it will return an ifp with a reference held if the
730*bbb1b6f9SApple OSS Distributions  * caller provides a non-NULL ifpp.  The caller is responsible for checking
731*bbb1b6f9SApple OSS Distributions  * if the returned ifp is valid and release its reference at all times.
732*bbb1b6f9SApple OSS Distributions  */
733*bbb1b6f9SApple OSS Distributions struct in6_addr *
in6_selectsrc(struct sockaddr_in6 * dstsock,struct ip6_pktopts * opts,struct inpcb * inp,struct route_in6 * ro,struct ifnet ** ifpp,struct in6_addr * src_storage,unsigned int ifscope,int * errorp)734*bbb1b6f9SApple OSS Distributions in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
735*bbb1b6f9SApple OSS Distributions     struct inpcb *inp, struct route_in6 *ro,
736*bbb1b6f9SApple OSS Distributions     struct ifnet **ifpp, struct in6_addr *src_storage, unsigned int ifscope,
737*bbb1b6f9SApple OSS Distributions     int *errorp)
738*bbb1b6f9SApple OSS Distributions {
739*bbb1b6f9SApple OSS Distributions 	struct ifnet *__single ifp = NULL;
740*bbb1b6f9SApple OSS Distributions 	struct in6_pktinfo *__single pi = NULL;
741*bbb1b6f9SApple OSS Distributions 	struct ip6_moptions *__single mopts;
742*bbb1b6f9SApple OSS Distributions 	struct ip6_out_args ip6oa;
743*bbb1b6f9SApple OSS Distributions 	boolean_t inp_debug = FALSE;
744*bbb1b6f9SApple OSS Distributions 	uint32_t hint_mask = 0;
745*bbb1b6f9SApple OSS Distributions 	int prefer_tempaddr = 0;
746*bbb1b6f9SApple OSS Distributions 	struct ifnet *__single sifp = NULL;
747*bbb1b6f9SApple OSS Distributions 
748*bbb1b6f9SApple OSS Distributions 	bzero(&ip6oa, sizeof(ip6oa));
749*bbb1b6f9SApple OSS Distributions 	ip6oa.ip6oa_boundif = ifscope;
750*bbb1b6f9SApple OSS Distributions 	ip6oa.ip6oa_flags = IP6OAF_SELECT_SRCIF;
751*bbb1b6f9SApple OSS Distributions 	ip6oa.ip6oa_sotc = SO_TC_UNSPEC;
752*bbb1b6f9SApple OSS Distributions 	ip6oa.ip6oa_netsvctype = _NET_SERVICE_TYPE_UNSPEC;
753*bbb1b6f9SApple OSS Distributions 
754*bbb1b6f9SApple OSS Distributions 	*errorp = 0;
755*bbb1b6f9SApple OSS Distributions 	if (ifpp != NULL) {
756*bbb1b6f9SApple OSS Distributions 		*ifpp = NULL;
757*bbb1b6f9SApple OSS Distributions 	}
758*bbb1b6f9SApple OSS Distributions 
759*bbb1b6f9SApple OSS Distributions 	if (inp != NULL) {
760*bbb1b6f9SApple OSS Distributions 		inp_debug = SASEL_DO_DBG(inp);
761*bbb1b6f9SApple OSS Distributions 		mopts = inp->in6p_moptions;
762*bbb1b6f9SApple OSS Distributions 		if (INP_NO_CELLULAR(inp)) {
763*bbb1b6f9SApple OSS Distributions 			ip6oa.ip6oa_flags |= IP6OAF_NO_CELLULAR;
764*bbb1b6f9SApple OSS Distributions 		}
765*bbb1b6f9SApple OSS Distributions 		if (INP_NO_EXPENSIVE(inp)) {
766*bbb1b6f9SApple OSS Distributions 			ip6oa.ip6oa_flags |= IP6OAF_NO_EXPENSIVE;
767*bbb1b6f9SApple OSS Distributions 		}
768*bbb1b6f9SApple OSS Distributions 		if (INP_NO_CONSTRAINED(inp)) {
769*bbb1b6f9SApple OSS Distributions 			ip6oa.ip6oa_flags |= IP6OAF_NO_CONSTRAINED;
770*bbb1b6f9SApple OSS Distributions 		}
771*bbb1b6f9SApple OSS Distributions 		if (INP_AWDL_UNRESTRICTED(inp)) {
772*bbb1b6f9SApple OSS Distributions 			ip6oa.ip6oa_flags |= IP6OAF_AWDL_UNRESTRICTED;
773*bbb1b6f9SApple OSS Distributions 		}
774*bbb1b6f9SApple OSS Distributions 		if (INP_INTCOPROC_ALLOWED(inp)) {
775*bbb1b6f9SApple OSS Distributions 			ip6oa.ip6oa_flags |= IP6OAF_INTCOPROC_ALLOWED;
776*bbb1b6f9SApple OSS Distributions 		}
777*bbb1b6f9SApple OSS Distributions 		if (INP_MANAGEMENT_ALLOWED(inp)) {
778*bbb1b6f9SApple OSS Distributions 			ip6oa.ip6oa_flags |= IP6OAF_MANAGEMENT_ALLOWED;
779*bbb1b6f9SApple OSS Distributions 		}
780*bbb1b6f9SApple OSS Distributions 		if (INP_ULTRA_CONSTRAINED_ALLOWED(inp)) {
781*bbb1b6f9SApple OSS Distributions 			ip6oa.ip6oa_flags |= IP6OAF_ULTRA_CONSTRAINED_ALLOWED;
782*bbb1b6f9SApple OSS Distributions 		}
783*bbb1b6f9SApple OSS Distributions 	} else {
784*bbb1b6f9SApple OSS Distributions 		mopts = NULL;
785*bbb1b6f9SApple OSS Distributions 		/* Allow the kernel to retransmit packets. */
786*bbb1b6f9SApple OSS Distributions 		ip6oa.ip6oa_flags |= IP6OAF_INTCOPROC_ALLOWED |
787*bbb1b6f9SApple OSS Distributions 		    IP6OAF_AWDL_UNRESTRICTED | IP6OAF_MANAGEMENT_ALLOWED |
788*bbb1b6f9SApple OSS Distributions 		    IP6OAF_ULTRA_CONSTRAINED_ALLOWED;
789*bbb1b6f9SApple OSS Distributions 	}
790*bbb1b6f9SApple OSS Distributions 
791*bbb1b6f9SApple OSS Distributions 	if (ip6oa.ip6oa_boundif != IFSCOPE_NONE) {
792*bbb1b6f9SApple OSS Distributions 		ip6oa.ip6oa_flags |= IP6OAF_BOUND_IF;
793*bbb1b6f9SApple OSS Distributions 	}
794*bbb1b6f9SApple OSS Distributions 
795*bbb1b6f9SApple OSS Distributions 	/*
796*bbb1b6f9SApple OSS Distributions 	 * If the source address is explicitly specified by the caller,
797*bbb1b6f9SApple OSS Distributions 	 * check if the requested source address is indeed a unicast address
798*bbb1b6f9SApple OSS Distributions 	 * assigned to the node, and can be used as the packet's source
799*bbb1b6f9SApple OSS Distributions 	 * address.  If everything is okay, use the address as source.
800*bbb1b6f9SApple OSS Distributions 	 */
801*bbb1b6f9SApple OSS Distributions 	if (opts && (pi = opts->ip6po_pktinfo) &&
802*bbb1b6f9SApple OSS Distributions 	    !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr)) {
803*bbb1b6f9SApple OSS Distributions 		struct sockaddr_in6 srcsock;
804*bbb1b6f9SApple OSS Distributions 		struct in6_ifaddr *__single ia6;
805*bbb1b6f9SApple OSS Distributions 
806*bbb1b6f9SApple OSS Distributions 		/* get the outgoing interface */
807*bbb1b6f9SApple OSS Distributions 		if ((*errorp = in6_selectif(dstsock, opts, mopts, ro, &ip6oa,
808*bbb1b6f9SApple OSS Distributions 		    &ifp)) != 0) {
809*bbb1b6f9SApple OSS Distributions 			src_storage = NULL;
810*bbb1b6f9SApple OSS Distributions 			goto done;
811*bbb1b6f9SApple OSS Distributions 		}
812*bbb1b6f9SApple OSS Distributions 
813*bbb1b6f9SApple OSS Distributions 		/*
814*bbb1b6f9SApple OSS Distributions 		 * determine the appropriate zone id of the source based on
815*bbb1b6f9SApple OSS Distributions 		 * the zone of the destination and the outgoing interface.
816*bbb1b6f9SApple OSS Distributions 		 * If the specified address is ambiguous wrt the scope zone,
817*bbb1b6f9SApple OSS Distributions 		 * the interface must be specified; otherwise, ifa_ifwithaddr()
818*bbb1b6f9SApple OSS Distributions 		 * will fail matching the address.
819*bbb1b6f9SApple OSS Distributions 		 */
820*bbb1b6f9SApple OSS Distributions 		SOCKADDR_ZERO(&srcsock, sizeof(srcsock));
821*bbb1b6f9SApple OSS Distributions 		srcsock.sin6_family = AF_INET6;
822*bbb1b6f9SApple OSS Distributions 		srcsock.sin6_len = sizeof(srcsock);
823*bbb1b6f9SApple OSS Distributions 		srcsock.sin6_addr = pi->ipi6_addr;
824*bbb1b6f9SApple OSS Distributions 		if (ifp != NULL) {
825*bbb1b6f9SApple OSS Distributions 			*errorp = in6_setscope(&srcsock.sin6_addr, ifp, IN6_NULL_IF_EMBEDDED_SCOPE(&srcsock.sin6_scope_id));
826*bbb1b6f9SApple OSS Distributions 			if (*errorp != 0) {
827*bbb1b6f9SApple OSS Distributions 				src_storage = NULL;
828*bbb1b6f9SApple OSS Distributions 				goto done;
829*bbb1b6f9SApple OSS Distributions 			}
830*bbb1b6f9SApple OSS Distributions 		}
831*bbb1b6f9SApple OSS Distributions 		ia6 = ifatoia6(ifa_ifwithaddr(SA(&srcsock)));
832*bbb1b6f9SApple OSS Distributions 		if (ia6 == NULL) {
833*bbb1b6f9SApple OSS Distributions 			*errorp = EADDRNOTAVAIL;
834*bbb1b6f9SApple OSS Distributions 			src_storage = NULL;
835*bbb1b6f9SApple OSS Distributions 			goto done;
836*bbb1b6f9SApple OSS Distributions 		}
837*bbb1b6f9SApple OSS Distributions 		IFA_LOCK_SPIN(&ia6->ia_ifa);
838*bbb1b6f9SApple OSS Distributions 		if ((ia6->ia6_flags & (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY | IN6_IFF_CLAT46)) ||
839*bbb1b6f9SApple OSS Distributions 		    (inp && inp_restricted_send(inp, ia6->ia_ifa.ifa_ifp))) {
840*bbb1b6f9SApple OSS Distributions 			IFA_UNLOCK(&ia6->ia_ifa);
841*bbb1b6f9SApple OSS Distributions 			ifa_remref(&ia6->ia_ifa);
842*bbb1b6f9SApple OSS Distributions 			*errorp = EHOSTUNREACH;
843*bbb1b6f9SApple OSS Distributions 			src_storage = NULL;
844*bbb1b6f9SApple OSS Distributions 			goto done;
845*bbb1b6f9SApple OSS Distributions 		}
846*bbb1b6f9SApple OSS Distributions 
847*bbb1b6f9SApple OSS Distributions 		*src_storage = satosin6(&ia6->ia_addr)->sin6_addr;
848*bbb1b6f9SApple OSS Distributions 		IFA_UNLOCK(&ia6->ia_ifa);
849*bbb1b6f9SApple OSS Distributions 		ifa_remref(&ia6->ia_ifa);
850*bbb1b6f9SApple OSS Distributions 		goto done;
851*bbb1b6f9SApple OSS Distributions 	}
852*bbb1b6f9SApple OSS Distributions 
853*bbb1b6f9SApple OSS Distributions 	/*
854*bbb1b6f9SApple OSS Distributions 	 * Otherwise, if the socket has already bound the source, just use it.
855*bbb1b6f9SApple OSS Distributions 	 */
856*bbb1b6f9SApple OSS Distributions 	if (inp != NULL && !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) {
857*bbb1b6f9SApple OSS Distributions 		src_storage = &inp->in6p_laddr;
858*bbb1b6f9SApple OSS Distributions 		goto done;
859*bbb1b6f9SApple OSS Distributions 	}
860*bbb1b6f9SApple OSS Distributions 
861*bbb1b6f9SApple OSS Distributions 	/*
862*bbb1b6f9SApple OSS Distributions 	 * If the address is not specified, choose the best one based on
863*bbb1b6f9SApple OSS Distributions 	 * the outgoing interface and the destination address.
864*bbb1b6f9SApple OSS Distributions 	 */
865*bbb1b6f9SApple OSS Distributions 	/* get the outgoing interface */
866*bbb1b6f9SApple OSS Distributions 	if ((*errorp = in6_selectif(dstsock, opts, mopts, ro, &ip6oa,
867*bbb1b6f9SApple OSS Distributions 	    &ifp)) != 0) {
868*bbb1b6f9SApple OSS Distributions 		src_storage = NULL;
869*bbb1b6f9SApple OSS Distributions 		goto done;
870*bbb1b6f9SApple OSS Distributions 	}
871*bbb1b6f9SApple OSS Distributions 
872*bbb1b6f9SApple OSS Distributions 	VERIFY(ifp != NULL);
873*bbb1b6f9SApple OSS Distributions 
874*bbb1b6f9SApple OSS Distributions 	if (opts == NULL ||
875*bbb1b6f9SApple OSS Distributions 	    opts->ip6po_prefer_tempaddr == IP6PO_TEMPADDR_SYSTEM) {
876*bbb1b6f9SApple OSS Distributions 		prefer_tempaddr = ip6_prefer_tempaddr;
877*bbb1b6f9SApple OSS Distributions 	} else if (opts->ip6po_prefer_tempaddr == IP6PO_TEMPADDR_NOTPREFER) {
878*bbb1b6f9SApple OSS Distributions 		prefer_tempaddr = 0;
879*bbb1b6f9SApple OSS Distributions 	} else {
880*bbb1b6f9SApple OSS Distributions 		prefer_tempaddr = 1;
881*bbb1b6f9SApple OSS Distributions 	}
882*bbb1b6f9SApple OSS Distributions 
883*bbb1b6f9SApple OSS Distributions 	if (prefer_tempaddr) {
884*bbb1b6f9SApple OSS Distributions 		hint_mask |= IPV6_SRCSEL_HINT_PREFER_TMPADDR;
885*bbb1b6f9SApple OSS Distributions 	}
886*bbb1b6f9SApple OSS Distributions 
887*bbb1b6f9SApple OSS Distributions 	if (in6_selectsrc_core(dstsock, hint_mask, ifp, inp_debug, src_storage,
888*bbb1b6f9SApple OSS Distributions 	    &sifp, errorp, NULL, ro, FALSE) == NULL) {
889*bbb1b6f9SApple OSS Distributions 		src_storage = NULL;
890*bbb1b6f9SApple OSS Distributions 		goto done;
891*bbb1b6f9SApple OSS Distributions 	}
892*bbb1b6f9SApple OSS Distributions 
893*bbb1b6f9SApple OSS Distributions 	VERIFY(sifp != NULL);
894*bbb1b6f9SApple OSS Distributions 
895*bbb1b6f9SApple OSS Distributions 	if (inp && inp_restricted_send(inp, sifp)) {
896*bbb1b6f9SApple OSS Distributions 		src_storage = NULL;
897*bbb1b6f9SApple OSS Distributions 		*errorp = EHOSTUNREACH;
898*bbb1b6f9SApple OSS Distributions 		ifnet_release(sifp);
899*bbb1b6f9SApple OSS Distributions 		goto done;
900*bbb1b6f9SApple OSS Distributions 	} else {
901*bbb1b6f9SApple OSS Distributions 		ifnet_release(sifp);
902*bbb1b6f9SApple OSS Distributions 	}
903*bbb1b6f9SApple OSS Distributions 
904*bbb1b6f9SApple OSS Distributions done:
905*bbb1b6f9SApple OSS Distributions 	if (ifpp != NULL) {
906*bbb1b6f9SApple OSS Distributions 		/* if ifp is non-NULL, refcnt held in in6_selectif() */
907*bbb1b6f9SApple OSS Distributions 		*ifpp = ifp;
908*bbb1b6f9SApple OSS Distributions 	} else if (ifp != NULL) {
909*bbb1b6f9SApple OSS Distributions 		ifnet_release(ifp);
910*bbb1b6f9SApple OSS Distributions 	}
911*bbb1b6f9SApple OSS Distributions 	return src_storage;
912*bbb1b6f9SApple OSS Distributions }
913*bbb1b6f9SApple OSS Distributions 
914*bbb1b6f9SApple OSS Distributions /*
915*bbb1b6f9SApple OSS Distributions  * Given a source IPv6 address (and route, if available), determine the best
916*bbb1b6f9SApple OSS Distributions  * interface to send the packet from.  Checking for (and updating) the
917*bbb1b6f9SApple OSS Distributions  * ROF_SRCIF_SELECTED flag in the pcb-supplied route placeholder is done
918*bbb1b6f9SApple OSS Distributions  * without any locks, based on the assumption that in the event this is
919*bbb1b6f9SApple OSS Distributions  * called from ip6_output(), the output operation is single-threaded per-pcb,
920*bbb1b6f9SApple OSS Distributions  * i.e. for any given pcb there can only be one thread performing output at
921*bbb1b6f9SApple OSS Distributions  * the IPv6 layer.
922*bbb1b6f9SApple OSS Distributions  *
923*bbb1b6f9SApple OSS Distributions  * This routine is analogous to in_selectsrcif() for IPv4.  Regardless of
924*bbb1b6f9SApple OSS Distributions  * error, it will return an ifp with a reference held if the caller provides
925*bbb1b6f9SApple OSS Distributions  * a non-NULL retifp.  The caller is responsible for checking if the
926*bbb1b6f9SApple OSS Distributions  * returned ifp is valid and release its reference at all times.
927*bbb1b6f9SApple OSS Distributions  *
928*bbb1b6f9SApple OSS Distributions  * clone - meaningful only for bsdi and freebsd
929*bbb1b6f9SApple OSS Distributions  */
930*bbb1b6f9SApple OSS Distributions static int
selectroute(struct sockaddr_in6 * srcsock,struct sockaddr_in6 * dstsock,struct ip6_pktopts * opts,struct ip6_moptions * mopts,struct in6_ifaddr ** retsrcia,struct route_in6 * ro,struct ifnet ** retifp,struct rtentry ** retrt,int clone,int norouteok,struct ip6_out_args * ip6oa)931*bbb1b6f9SApple OSS Distributions selectroute(struct sockaddr_in6 *srcsock, struct sockaddr_in6 *dstsock,
932*bbb1b6f9SApple OSS Distributions     struct ip6_pktopts *opts, struct ip6_moptions *mopts,
933*bbb1b6f9SApple OSS Distributions     struct in6_ifaddr **retsrcia, struct route_in6 *ro,
934*bbb1b6f9SApple OSS Distributions     struct ifnet **retifp, struct rtentry **retrt, int clone,
935*bbb1b6f9SApple OSS Distributions     int norouteok, struct ip6_out_args *ip6oa)
936*bbb1b6f9SApple OSS Distributions {
937*bbb1b6f9SApple OSS Distributions 	int error = 0;
938*bbb1b6f9SApple OSS Distributions 	struct ifnet *__single ifp = NULL, *__single ifp0 = NULL;
939*bbb1b6f9SApple OSS Distributions 	struct route_in6 *__single route = NULL;
940*bbb1b6f9SApple OSS Distributions 	struct sockaddr_in6 *__single sin6_next;
941*bbb1b6f9SApple OSS Distributions 	struct in6_pktinfo *__single pi = NULL;
942*bbb1b6f9SApple OSS Distributions 	struct in6_addr *__single dst = &dstsock->sin6_addr;
943*bbb1b6f9SApple OSS Distributions 	struct ifaddr *__single ifa = NULL;
944*bbb1b6f9SApple OSS Distributions 	char s_src[MAX_IPv6_STR_LEN], s_dst[MAX_IPv6_STR_LEN];
945*bbb1b6f9SApple OSS Distributions 	boolean_t select_srcif, proxied_ifa = FALSE, local_dst = FALSE;
946*bbb1b6f9SApple OSS Distributions 	unsigned int ifscope = ((ip6oa != NULL) ?
947*bbb1b6f9SApple OSS Distributions 	    ip6oa->ip6oa_boundif : IFSCOPE_NONE);
948*bbb1b6f9SApple OSS Distributions 	boolean_t is_direct = FALSE;
949*bbb1b6f9SApple OSS Distributions 
950*bbb1b6f9SApple OSS Distributions 	if (retifp != NULL) {
951*bbb1b6f9SApple OSS Distributions 		*retifp = NULL;
952*bbb1b6f9SApple OSS Distributions 	}
953*bbb1b6f9SApple OSS Distributions 
954*bbb1b6f9SApple OSS Distributions 	if (retrt != NULL) {
955*bbb1b6f9SApple OSS Distributions 		*retrt = NULL;
956*bbb1b6f9SApple OSS Distributions 	}
957*bbb1b6f9SApple OSS Distributions 
958*bbb1b6f9SApple OSS Distributions 	if (ip6_select_srcif_debug) {
959*bbb1b6f9SApple OSS Distributions 		struct in6_addr src;
960*bbb1b6f9SApple OSS Distributions 		src = (srcsock != NULL) ? srcsock->sin6_addr : in6addr_any;
961*bbb1b6f9SApple OSS Distributions 		(void) inet_ntop(AF_INET6, &src, s_src, sizeof(s_src));
962*bbb1b6f9SApple OSS Distributions 		(void) inet_ntop(AF_INET6, dst, s_dst, sizeof(s_dst));
963*bbb1b6f9SApple OSS Distributions 	}
964*bbb1b6f9SApple OSS Distributions 
965*bbb1b6f9SApple OSS Distributions 	/*
966*bbb1b6f9SApple OSS Distributions 	 * If the destination address is UNSPECIFIED addr, bail out.
967*bbb1b6f9SApple OSS Distributions 	 */
968*bbb1b6f9SApple OSS Distributions 	if (IN6_IS_ADDR_UNSPECIFIED(dst)) {
969*bbb1b6f9SApple OSS Distributions 		error = EHOSTUNREACH;
970*bbb1b6f9SApple OSS Distributions 		goto done;
971*bbb1b6f9SApple OSS Distributions 	}
972*bbb1b6f9SApple OSS Distributions 
973*bbb1b6f9SApple OSS Distributions 	/*
974*bbb1b6f9SApple OSS Distributions 	 * Perform source interface selection if Scoped Routing
975*bbb1b6f9SApple OSS Distributions 	 * is enabled and a source address that isn't unspecified.
976*bbb1b6f9SApple OSS Distributions 	 */
977*bbb1b6f9SApple OSS Distributions 	select_srcif = (srcsock != NULL &&
978*bbb1b6f9SApple OSS Distributions 	    !IN6_IS_ADDR_UNSPECIFIED(&srcsock->sin6_addr));
979*bbb1b6f9SApple OSS Distributions 
980*bbb1b6f9SApple OSS Distributions 	/*
981*bbb1b6f9SApple OSS Distributions 	 * For scoped routing, if interface scope is 0 or src/dst addr is linklocal
982*bbb1b6f9SApple OSS Distributions 	 * or dst addr is multicast, source interface selection should be performed even
983*bbb1b6f9SApple OSS Distributions 	 * if the destination is directly reachable.
984*bbb1b6f9SApple OSS Distributions 	 */
985*bbb1b6f9SApple OSS Distributions 	if (ifscope != IFSCOPE_NONE &&
986*bbb1b6f9SApple OSS Distributions 	    !(srcsock != NULL && IN6_IS_ADDR_LINKLOCAL(&srcsock->sin6_addr)) &&
987*bbb1b6f9SApple OSS Distributions 	    !IN6_IS_ADDR_MULTICAST(dst) && !IN6_IS_ADDR_LINKLOCAL(dst)) {
988*bbb1b6f9SApple OSS Distributions 		struct rtentry *__single temp_rt = NULL;
989*bbb1b6f9SApple OSS Distributions 
990*bbb1b6f9SApple OSS Distributions 		lck_mtx_lock(rnh_lock);
991*bbb1b6f9SApple OSS Distributions 		temp_rt = rt_lookup(TRUE, SA(dstsock),
992*bbb1b6f9SApple OSS Distributions 		    NULL, rt_tables[AF_INET6], ifscope);
993*bbb1b6f9SApple OSS Distributions 		lck_mtx_unlock(rnh_lock);
994*bbb1b6f9SApple OSS Distributions 
995*bbb1b6f9SApple OSS Distributions 		/*
996*bbb1b6f9SApple OSS Distributions 		 * If the destination is directly reachable, relax
997*bbb1b6f9SApple OSS Distributions 		 * the behavior around select_srcif, i.e. don't force
998*bbb1b6f9SApple OSS Distributions 		 * the packet to go out from the interface that is hosting
999*bbb1b6f9SApple OSS Distributions 		 * the source address.
1000*bbb1b6f9SApple OSS Distributions 		 * It happens when we share v6 with NAT66 and want
1001*bbb1b6f9SApple OSS Distributions 		 * the external interface's v6 address to be reachable
1002*bbb1b6f9SApple OSS Distributions 		 * to the clients we are sharing v6 connectivity with
1003*bbb1b6f9SApple OSS Distributions 		 * using NAT.
1004*bbb1b6f9SApple OSS Distributions 		 */
1005*bbb1b6f9SApple OSS Distributions 		if (temp_rt != NULL) {
1006*bbb1b6f9SApple OSS Distributions 			if ((temp_rt->rt_flags & RTF_GATEWAY) == 0) {
1007*bbb1b6f9SApple OSS Distributions 				select_srcif = FALSE;
1008*bbb1b6f9SApple OSS Distributions 				is_direct = TRUE;
1009*bbb1b6f9SApple OSS Distributions 			}
1010*bbb1b6f9SApple OSS Distributions 			rtfree(temp_rt);
1011*bbb1b6f9SApple OSS Distributions 		}
1012*bbb1b6f9SApple OSS Distributions 	}
1013*bbb1b6f9SApple OSS Distributions 
1014*bbb1b6f9SApple OSS Distributions 	if (ip6_select_srcif_debug) {
1015*bbb1b6f9SApple OSS Distributions 		os_log(OS_LOG_DEFAULT, "%s:%d src %s dst %s ifscope %d "
1016*bbb1b6f9SApple OSS Distributions 		    "is_direct %d select_srcif %d\n",
1017*bbb1b6f9SApple OSS Distributions 		    __func__, __LINE__, s_src, s_dst, ifscope, is_direct, select_srcif);
1018*bbb1b6f9SApple OSS Distributions 	}
1019*bbb1b6f9SApple OSS Distributions 
1020*bbb1b6f9SApple OSS Distributions 	/* If the caller specified the outgoing interface explicitly, use it */
1021*bbb1b6f9SApple OSS Distributions 	if (opts != NULL && (pi = opts->ip6po_pktinfo) != NULL &&
1022*bbb1b6f9SApple OSS Distributions 	    pi->ipi6_ifindex != 0) {
1023*bbb1b6f9SApple OSS Distributions 		/*
1024*bbb1b6f9SApple OSS Distributions 		 * If IPV6_PKTINFO takes precedence over IPV6_BOUND_IF.
1025*bbb1b6f9SApple OSS Distributions 		 */
1026*bbb1b6f9SApple OSS Distributions 		ifscope = pi->ipi6_ifindex;
1027*bbb1b6f9SApple OSS Distributions 		ifnet_head_lock_shared();
1028*bbb1b6f9SApple OSS Distributions 		/* ifp may be NULL if detached or out of range */
1029*bbb1b6f9SApple OSS Distributions 		ifp = ifp0 =
1030*bbb1b6f9SApple OSS Distributions 		    ((ifscope <= if_index) ? ifindex2ifnet[ifscope] : NULL);
1031*bbb1b6f9SApple OSS Distributions 		ifnet_head_done();
1032*bbb1b6f9SApple OSS Distributions 		if (norouteok || retrt == NULL || IN6_IS_ADDR_MC_LINKLOCAL(dst)) {
1033*bbb1b6f9SApple OSS Distributions 			/*
1034*bbb1b6f9SApple OSS Distributions 			 * We do not have to check or get the route for
1035*bbb1b6f9SApple OSS Distributions 			 * multicast.  If the caller didn't ask/care for
1036*bbb1b6f9SApple OSS Distributions 			 * the route and we have no interface to use,
1037*bbb1b6f9SApple OSS Distributions 			 * it's an error.
1038*bbb1b6f9SApple OSS Distributions 			 */
1039*bbb1b6f9SApple OSS Distributions 			if (ifp == NULL) {
1040*bbb1b6f9SApple OSS Distributions 				error = EHOSTUNREACH;
1041*bbb1b6f9SApple OSS Distributions 			}
1042*bbb1b6f9SApple OSS Distributions 			goto done;
1043*bbb1b6f9SApple OSS Distributions 		} else {
1044*bbb1b6f9SApple OSS Distributions 			goto getsrcif;
1045*bbb1b6f9SApple OSS Distributions 		}
1046*bbb1b6f9SApple OSS Distributions 	}
1047*bbb1b6f9SApple OSS Distributions 
1048*bbb1b6f9SApple OSS Distributions 	/*
1049*bbb1b6f9SApple OSS Distributions 	 * If the destination address is a multicast address and the outgoing
1050*bbb1b6f9SApple OSS Distributions 	 * interface for the address is specified by the caller, use it.
1051*bbb1b6f9SApple OSS Distributions 	 */
1052*bbb1b6f9SApple OSS Distributions 	if (IN6_IS_ADDR_MULTICAST(dst) && mopts != NULL) {
1053*bbb1b6f9SApple OSS Distributions 		IM6O_LOCK(mopts);
1054*bbb1b6f9SApple OSS Distributions 		ifp = ifp0 = mopts->im6o_multicast_ifp;
1055*bbb1b6f9SApple OSS Distributions 		if (ifp != NULL && IN6_IS_ADDR_MC_LINKLOCAL(dst)) {
1056*bbb1b6f9SApple OSS Distributions 			IM6O_UNLOCK(mopts);
1057*bbb1b6f9SApple OSS Distributions 			goto done; /* we don't need a route for link-local multicast */
1058*bbb1b6f9SApple OSS Distributions 		}
1059*bbb1b6f9SApple OSS Distributions 		IM6O_UNLOCK(mopts);
1060*bbb1b6f9SApple OSS Distributions 	}
1061*bbb1b6f9SApple OSS Distributions 
1062*bbb1b6f9SApple OSS Distributions getsrcif:
1063*bbb1b6f9SApple OSS Distributions 	/*
1064*bbb1b6f9SApple OSS Distributions 	 * If the outgoing interface was not set via IPV6_BOUND_IF or
1065*bbb1b6f9SApple OSS Distributions 	 * IPV6_PKTINFO, use the scope ID in the destination address.
1066*bbb1b6f9SApple OSS Distributions 	 */
1067*bbb1b6f9SApple OSS Distributions 	if (ifscope == IFSCOPE_NONE) {
1068*bbb1b6f9SApple OSS Distributions 		ifscope = dstsock->sin6_scope_id;
1069*bbb1b6f9SApple OSS Distributions 	}
1070*bbb1b6f9SApple OSS Distributions 
1071*bbb1b6f9SApple OSS Distributions 	/*
1072*bbb1b6f9SApple OSS Distributions 	 * Perform source interface selection; the source IPv6 address
1073*bbb1b6f9SApple OSS Distributions 	 * must belong to one of the addresses of the interface used
1074*bbb1b6f9SApple OSS Distributions 	 * by the route.  For performance reasons, do this only if
1075*bbb1b6f9SApple OSS Distributions 	 * there is no route, or if the routing table has changed,
1076*bbb1b6f9SApple OSS Distributions 	 * or if we haven't done source interface selection on this
1077*bbb1b6f9SApple OSS Distributions 	 * route (for this PCB instance) before.
1078*bbb1b6f9SApple OSS Distributions 	 */
1079*bbb1b6f9SApple OSS Distributions 	if (!select_srcif) {
1080*bbb1b6f9SApple OSS Distributions 		goto getroute;
1081*bbb1b6f9SApple OSS Distributions 	} else if (!ROUTE_UNUSABLE(ro) && ro->ro_srcia != NULL &&
1082*bbb1b6f9SApple OSS Distributions 	    (ro->ro_flags & ROF_SRCIF_SELECTED)) {
1083*bbb1b6f9SApple OSS Distributions 		if (ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK) {
1084*bbb1b6f9SApple OSS Distributions 			local_dst = TRUE;
1085*bbb1b6f9SApple OSS Distributions 		}
1086*bbb1b6f9SApple OSS Distributions 		ifa = ro->ro_srcia;
1087*bbb1b6f9SApple OSS Distributions 		ifa_addref(ifa);        /* for caller */
1088*bbb1b6f9SApple OSS Distributions 		goto getroute;
1089*bbb1b6f9SApple OSS Distributions 	}
1090*bbb1b6f9SApple OSS Distributions 
1091*bbb1b6f9SApple OSS Distributions 	/*
1092*bbb1b6f9SApple OSS Distributions 	 * Given the source IPv6 address, find a suitable source interface
1093*bbb1b6f9SApple OSS Distributions 	 * to use for transmission; if a scope ID has been specified,
1094*bbb1b6f9SApple OSS Distributions 	 * optimize the search by looking at the addresses only for that
1095*bbb1b6f9SApple OSS Distributions 	 * interface.  This is still suboptimal, however, as we need to
1096*bbb1b6f9SApple OSS Distributions 	 * traverse the per-interface list.
1097*bbb1b6f9SApple OSS Distributions 	 */
1098*bbb1b6f9SApple OSS Distributions 	if (ifscope != IFSCOPE_NONE || (ro != NULL && ro->ro_rt != NULL)) {
1099*bbb1b6f9SApple OSS Distributions 		unsigned int scope = ifscope;
1100*bbb1b6f9SApple OSS Distributions 		struct ifnet *__single rt_ifp;
1101*bbb1b6f9SApple OSS Distributions 
1102*bbb1b6f9SApple OSS Distributions 		rt_ifp = (ro->ro_rt != NULL) ? ro->ro_rt->rt_ifp : NULL;
1103*bbb1b6f9SApple OSS Distributions 
1104*bbb1b6f9SApple OSS Distributions 		/*
1105*bbb1b6f9SApple OSS Distributions 		 * If no scope is specified and the route is stale (pointing
1106*bbb1b6f9SApple OSS Distributions 		 * to a defunct interface) use the current primary interface;
1107*bbb1b6f9SApple OSS Distributions 		 * this happens when switching between interfaces configured
1108*bbb1b6f9SApple OSS Distributions 		 * with the same IPv6 address.  Otherwise pick up the scope
1109*bbb1b6f9SApple OSS Distributions 		 * information from the route; the ULP may have looked up a
1110*bbb1b6f9SApple OSS Distributions 		 * correct route and we just need to verify it here and mark
1111*bbb1b6f9SApple OSS Distributions 		 * it with the ROF_SRCIF_SELECTED flag below.
1112*bbb1b6f9SApple OSS Distributions 		 */
1113*bbb1b6f9SApple OSS Distributions 		if (scope == IFSCOPE_NONE) {
1114*bbb1b6f9SApple OSS Distributions 			scope = rt_ifp->if_index;
1115*bbb1b6f9SApple OSS Distributions 			if (scope != get_primary_ifscope(AF_INET6) &&
1116*bbb1b6f9SApple OSS Distributions 			    ROUTE_UNUSABLE(ro)) {
1117*bbb1b6f9SApple OSS Distributions 				scope = get_primary_ifscope(AF_INET6);
1118*bbb1b6f9SApple OSS Distributions 			}
1119*bbb1b6f9SApple OSS Distributions 		}
1120*bbb1b6f9SApple OSS Distributions 
1121*bbb1b6f9SApple OSS Distributions 		ifa = (struct ifaddr *)
1122*bbb1b6f9SApple OSS Distributions 		    ifa_foraddr6_scoped(&srcsock->sin6_addr, scope);
1123*bbb1b6f9SApple OSS Distributions 
1124*bbb1b6f9SApple OSS Distributions 		/*
1125*bbb1b6f9SApple OSS Distributions 		 * If we are forwarding and proxying prefix(es), see if the
1126*bbb1b6f9SApple OSS Distributions 		 * source address is one of ours and is a proxied address;
1127*bbb1b6f9SApple OSS Distributions 		 * if so, use it.
1128*bbb1b6f9SApple OSS Distributions 		 */
1129*bbb1b6f9SApple OSS Distributions 		if (ifa == NULL && ip6_forwarding && nd6_prproxy) {
1130*bbb1b6f9SApple OSS Distributions 			ifa = (struct ifaddr *)
1131*bbb1b6f9SApple OSS Distributions 			    ifa_foraddr6(&srcsock->sin6_addr);
1132*bbb1b6f9SApple OSS Distributions 			if (ifa != NULL && !(proxied_ifa =
1133*bbb1b6f9SApple OSS Distributions 			    nd6_prproxy_ifaddr(ifatoia6(ifa)))) {
1134*bbb1b6f9SApple OSS Distributions 				ifa_remref(ifa);
1135*bbb1b6f9SApple OSS Distributions 				ifa = NULL;
1136*bbb1b6f9SApple OSS Distributions 			}
1137*bbb1b6f9SApple OSS Distributions 		}
1138*bbb1b6f9SApple OSS Distributions 
1139*bbb1b6f9SApple OSS Distributions 		if (ip6_select_srcif_debug && ifa != NULL) {
1140*bbb1b6f9SApple OSS Distributions 			if (ro->ro_rt != NULL) {
1141*bbb1b6f9SApple OSS Distributions 				os_log(OS_LOG_DEFAULT, "%s:%d %s->%s ifscope %d->%d ifa_if %s "
1142*bbb1b6f9SApple OSS Distributions 				    "ro_if %s\n",
1143*bbb1b6f9SApple OSS Distributions 				    __func__, __LINE__,
1144*bbb1b6f9SApple OSS Distributions 				    s_src, s_dst, ifscope,
1145*bbb1b6f9SApple OSS Distributions 				    scope, if_name(ifa->ifa_ifp),
1146*bbb1b6f9SApple OSS Distributions 				    if_name(rt_ifp));
1147*bbb1b6f9SApple OSS Distributions 			} else {
1148*bbb1b6f9SApple OSS Distributions 				os_log(OS_LOG_DEFAULT, "%s:%d %s->%s ifscope %d->%d ifa_if %s\n",
1149*bbb1b6f9SApple OSS Distributions 				    __func__, __LINE__,
1150*bbb1b6f9SApple OSS Distributions 				    s_src, s_dst, ifscope, scope,
1151*bbb1b6f9SApple OSS Distributions 				    if_name(ifa->ifa_ifp));
1152*bbb1b6f9SApple OSS Distributions 			}
1153*bbb1b6f9SApple OSS Distributions 		}
1154*bbb1b6f9SApple OSS Distributions 	}
1155*bbb1b6f9SApple OSS Distributions 
1156*bbb1b6f9SApple OSS Distributions 	/*
1157*bbb1b6f9SApple OSS Distributions 	 * Slow path; search for an interface having the corresponding source
1158*bbb1b6f9SApple OSS Distributions 	 * IPv6 address if the scope was not specified by the caller, and:
1159*bbb1b6f9SApple OSS Distributions 	 *
1160*bbb1b6f9SApple OSS Distributions 	 *   1) There currently isn't any route, or,
1161*bbb1b6f9SApple OSS Distributions 	 *   2) The interface used by the route does not own that source
1162*bbb1b6f9SApple OSS Distributions 	 *	IPv6 address; in this case, the route will get blown away
1163*bbb1b6f9SApple OSS Distributions 	 *	and we'll do a more specific scoped search using the newly
1164*bbb1b6f9SApple OSS Distributions 	 *	found interface.
1165*bbb1b6f9SApple OSS Distributions 	 */
1166*bbb1b6f9SApple OSS Distributions 	if (ifa == NULL && ifscope == IFSCOPE_NONE) {
1167*bbb1b6f9SApple OSS Distributions 		struct ifaddr *__single ifadst;
1168*bbb1b6f9SApple OSS Distributions 
1169*bbb1b6f9SApple OSS Distributions 		/* Check if the destination address is one of ours */
1170*bbb1b6f9SApple OSS Distributions 		ifadst = (struct ifaddr *)ifa_foraddr6(&dstsock->sin6_addr);
1171*bbb1b6f9SApple OSS Distributions 		if (ifadst != NULL) {
1172*bbb1b6f9SApple OSS Distributions 			local_dst = TRUE;
1173*bbb1b6f9SApple OSS Distributions 			ifa_remref(ifadst);
1174*bbb1b6f9SApple OSS Distributions 		}
1175*bbb1b6f9SApple OSS Distributions 
1176*bbb1b6f9SApple OSS Distributions 		ifa = (struct ifaddr *)ifa_foraddr6(&srcsock->sin6_addr);
1177*bbb1b6f9SApple OSS Distributions 
1178*bbb1b6f9SApple OSS Distributions 		if (ip6_select_srcif_debug && ifa != NULL) {
1179*bbb1b6f9SApple OSS Distributions 			os_log(OS_LOG_DEFAULT, "%s:%d %s->%s ifscope %d ifa_if %s\n",
1180*bbb1b6f9SApple OSS Distributions 			    __func__, __LINE__,
1181*bbb1b6f9SApple OSS Distributions 			    s_src, s_dst, ifscope, if_name(ifa->ifa_ifp));
1182*bbb1b6f9SApple OSS Distributions 		} else if (ip6_select_srcif_debug) {
1183*bbb1b6f9SApple OSS Distributions 			os_log(OS_LOG_DEFAULT, "%s:%d %s->%s ifscope %d ifa_if NULL\n",
1184*bbb1b6f9SApple OSS Distributions 			    __func__, __LINE__,
1185*bbb1b6f9SApple OSS Distributions 			    s_src, s_dst, ifscope);
1186*bbb1b6f9SApple OSS Distributions 		}
1187*bbb1b6f9SApple OSS Distributions 	}
1188*bbb1b6f9SApple OSS Distributions 
1189*bbb1b6f9SApple OSS Distributions getroute:
1190*bbb1b6f9SApple OSS Distributions 	if (ifa != NULL && !proxied_ifa && !local_dst) {
1191*bbb1b6f9SApple OSS Distributions 		ifscope = ifa->ifa_ifp->if_index;
1192*bbb1b6f9SApple OSS Distributions 	}
1193*bbb1b6f9SApple OSS Distributions 
1194*bbb1b6f9SApple OSS Distributions 	/*
1195*bbb1b6f9SApple OSS Distributions 	 * If the next hop address for the packet is specified by the caller,
1196*bbb1b6f9SApple OSS Distributions 	 * use it as the gateway.
1197*bbb1b6f9SApple OSS Distributions 	 */
1198*bbb1b6f9SApple OSS Distributions 	if (opts != NULL && opts->ip6po_nexthop != NULL) {
1199*bbb1b6f9SApple OSS Distributions 		struct route_in6 *__single ron;
1200*bbb1b6f9SApple OSS Distributions 
1201*bbb1b6f9SApple OSS Distributions 		sin6_next = satosin6(opts->ip6po_nexthop);
1202*bbb1b6f9SApple OSS Distributions 
1203*bbb1b6f9SApple OSS Distributions 		/* at this moment, we only support AF_INET6 next hops */
1204*bbb1b6f9SApple OSS Distributions 		if (sin6_next->sin6_family != AF_INET6) {
1205*bbb1b6f9SApple OSS Distributions 			error = EAFNOSUPPORT; /* or should we proceed? */
1206*bbb1b6f9SApple OSS Distributions 			goto done;
1207*bbb1b6f9SApple OSS Distributions 		}
1208*bbb1b6f9SApple OSS Distributions 
1209*bbb1b6f9SApple OSS Distributions 		/*
1210*bbb1b6f9SApple OSS Distributions 		 * If the next hop is an IPv6 address, then the node identified
1211*bbb1b6f9SApple OSS Distributions 		 * by that address must be a neighbor of the sending host.
1212*bbb1b6f9SApple OSS Distributions 		 */
1213*bbb1b6f9SApple OSS Distributions 		ron = &opts->ip6po_nextroute;
1214*bbb1b6f9SApple OSS Distributions 		if (ron->ro_rt != NULL) {
1215*bbb1b6f9SApple OSS Distributions 			RT_LOCK(ron->ro_rt);
1216*bbb1b6f9SApple OSS Distributions 		}
1217*bbb1b6f9SApple OSS Distributions 		if (ROUTE_UNUSABLE(ron) || (ron->ro_rt != NULL &&
1218*bbb1b6f9SApple OSS Distributions 		    (!(ron->ro_rt->rt_flags & RTF_LLINFO) ||
1219*bbb1b6f9SApple OSS Distributions 		    (select_srcif && (ifa == NULL ||
1220*bbb1b6f9SApple OSS Distributions 		    (ifa->ifa_ifp != ron->ro_rt->rt_ifp && !proxied_ifa))))) ||
1221*bbb1b6f9SApple OSS Distributions 		    !in6_are_addr_equal_scoped(&satosin6(&ron->ro_dst)->sin6_addr,
1222*bbb1b6f9SApple OSS Distributions 		    &sin6_next->sin6_addr, ron->ro_rt->rt_ifp->if_index, sin6_next->sin6_scope_id)) {
1223*bbb1b6f9SApple OSS Distributions 			if (ron->ro_rt != NULL) {
1224*bbb1b6f9SApple OSS Distributions 				RT_UNLOCK(ron->ro_rt);
1225*bbb1b6f9SApple OSS Distributions 			}
1226*bbb1b6f9SApple OSS Distributions 
1227*bbb1b6f9SApple OSS Distributions 			ROUTE_RELEASE(ron);
1228*bbb1b6f9SApple OSS Distributions 			*satosin6(&ron->ro_dst) = *sin6_next;
1229*bbb1b6f9SApple OSS Distributions 		}
1230*bbb1b6f9SApple OSS Distributions 		if (ron->ro_rt == NULL) {
1231*bbb1b6f9SApple OSS Distributions 			rtalloc_scoped((struct route *)ron, ifscope);
1232*bbb1b6f9SApple OSS Distributions 			if (ron->ro_rt != NULL) {
1233*bbb1b6f9SApple OSS Distributions 				RT_LOCK(ron->ro_rt);
1234*bbb1b6f9SApple OSS Distributions 			}
1235*bbb1b6f9SApple OSS Distributions 			if (ROUTE_UNUSABLE(ron) ||
1236*bbb1b6f9SApple OSS Distributions 			    !(ron->ro_rt->rt_flags & RTF_LLINFO) ||
1237*bbb1b6f9SApple OSS Distributions 			    !in6_are_addr_equal_scoped(&satosin6(rt_key(ron->ro_rt))->
1238*bbb1b6f9SApple OSS Distributions 			    sin6_addr, &sin6_next->sin6_addr, ron->ro_rt->rt_ifp->if_index, sin6_next->sin6_scope_id)) {
1239*bbb1b6f9SApple OSS Distributions 				if (ron->ro_rt != NULL) {
1240*bbb1b6f9SApple OSS Distributions 					RT_UNLOCK(ron->ro_rt);
1241*bbb1b6f9SApple OSS Distributions 				}
1242*bbb1b6f9SApple OSS Distributions 
1243*bbb1b6f9SApple OSS Distributions 				ROUTE_RELEASE(ron);
1244*bbb1b6f9SApple OSS Distributions 				error = EHOSTUNREACH;
1245*bbb1b6f9SApple OSS Distributions 				goto done;
1246*bbb1b6f9SApple OSS Distributions 			}
1247*bbb1b6f9SApple OSS Distributions 		}
1248*bbb1b6f9SApple OSS Distributions 		route = ron;
1249*bbb1b6f9SApple OSS Distributions 		ifp = ifp0 = ron->ro_rt->rt_ifp;
1250*bbb1b6f9SApple OSS Distributions 
1251*bbb1b6f9SApple OSS Distributions 		/*
1252*bbb1b6f9SApple OSS Distributions 		 * When cloning is required, try to allocate a route to the
1253*bbb1b6f9SApple OSS Distributions 		 * destination so that the caller can store path MTU
1254*bbb1b6f9SApple OSS Distributions 		 * information.
1255*bbb1b6f9SApple OSS Distributions 		 */
1256*bbb1b6f9SApple OSS Distributions 		if (!clone) {
1257*bbb1b6f9SApple OSS Distributions 			if (select_srcif) {
1258*bbb1b6f9SApple OSS Distributions 				/* Keep the route locked */
1259*bbb1b6f9SApple OSS Distributions 				goto validateroute;
1260*bbb1b6f9SApple OSS Distributions 			}
1261*bbb1b6f9SApple OSS Distributions 			RT_UNLOCK(ron->ro_rt);
1262*bbb1b6f9SApple OSS Distributions 			goto done;
1263*bbb1b6f9SApple OSS Distributions 		}
1264*bbb1b6f9SApple OSS Distributions 		RT_UNLOCK(ron->ro_rt);
1265*bbb1b6f9SApple OSS Distributions 	}
1266*bbb1b6f9SApple OSS Distributions 
1267*bbb1b6f9SApple OSS Distributions 	/*
1268*bbb1b6f9SApple OSS Distributions 	 * Use a cached route if it exists and is valid, else try to allocate
1269*bbb1b6f9SApple OSS Distributions 	 * a new one.  Note that we should check the address family of the
1270*bbb1b6f9SApple OSS Distributions 	 * cached destination, in case of sharing the cache with IPv4.
1271*bbb1b6f9SApple OSS Distributions 	 */
1272*bbb1b6f9SApple OSS Distributions 	if (ro == NULL) {
1273*bbb1b6f9SApple OSS Distributions 		goto done;
1274*bbb1b6f9SApple OSS Distributions 	}
1275*bbb1b6f9SApple OSS Distributions 	if (ro->ro_rt != NULL) {
1276*bbb1b6f9SApple OSS Distributions 		RT_LOCK_SPIN(ro->ro_rt);
1277*bbb1b6f9SApple OSS Distributions 	}
1278*bbb1b6f9SApple OSS Distributions 	if (ROUTE_UNUSABLE(ro) || (ro->ro_rt != NULL &&
1279*bbb1b6f9SApple OSS Distributions 	    (satosin6(&ro->ro_dst)->sin6_family != AF_INET6 ||
1280*bbb1b6f9SApple OSS Distributions 	    !in6_are_addr_equal_scoped(&satosin6(&ro->ro_dst)->sin6_addr, dst, ro->ro_rt->rt_ifp->if_index, dstsock->sin6_scope_id) ||
1281*bbb1b6f9SApple OSS Distributions 	    (select_srcif && (ifa == NULL ||
1282*bbb1b6f9SApple OSS Distributions 	    (ifa->ifa_ifp != ro->ro_rt->rt_ifp && !proxied_ifa)))))) {
1283*bbb1b6f9SApple OSS Distributions 		if (ro->ro_rt != NULL) {
1284*bbb1b6f9SApple OSS Distributions 			RT_UNLOCK(ro->ro_rt);
1285*bbb1b6f9SApple OSS Distributions 		}
1286*bbb1b6f9SApple OSS Distributions 
1287*bbb1b6f9SApple OSS Distributions 		ROUTE_RELEASE(ro);
1288*bbb1b6f9SApple OSS Distributions 	}
1289*bbb1b6f9SApple OSS Distributions 	if (ro->ro_rt == NULL) {
1290*bbb1b6f9SApple OSS Distributions 		struct sockaddr_in6 *__single sa6;
1291*bbb1b6f9SApple OSS Distributions 
1292*bbb1b6f9SApple OSS Distributions 		/* No route yet, so try to acquire one */
1293*bbb1b6f9SApple OSS Distributions 		SOCKADDR_ZERO(&ro->ro_dst, sizeof(struct sockaddr_in6));
1294*bbb1b6f9SApple OSS Distributions 		sa6 = SIN6(&ro->ro_dst);
1295*bbb1b6f9SApple OSS Distributions 		sa6->sin6_family = AF_INET6;
1296*bbb1b6f9SApple OSS Distributions 		sa6->sin6_len = sizeof(struct sockaddr_in6);
1297*bbb1b6f9SApple OSS Distributions 		sa6->sin6_addr = *dst;
1298*bbb1b6f9SApple OSS Distributions 		if (IN6_IS_ADDR_MC_LINKLOCAL(dst)) {
1299*bbb1b6f9SApple OSS Distributions 			ro->ro_rt = rtalloc1_scoped(
1300*bbb1b6f9SApple OSS Distributions 				SA(&((struct route *)ro)->ro_dst), 0, 0, ifscope);
1301*bbb1b6f9SApple OSS Distributions 		} else {
1302*bbb1b6f9SApple OSS Distributions 			rtalloc_scoped((struct route *)ro, ifscope);
1303*bbb1b6f9SApple OSS Distributions 		}
1304*bbb1b6f9SApple OSS Distributions 		if (ro->ro_rt != NULL) {
1305*bbb1b6f9SApple OSS Distributions 			RT_LOCK_SPIN(ro->ro_rt);
1306*bbb1b6f9SApple OSS Distributions 		}
1307*bbb1b6f9SApple OSS Distributions 	}
1308*bbb1b6f9SApple OSS Distributions 
1309*bbb1b6f9SApple OSS Distributions 	/*
1310*bbb1b6f9SApple OSS Distributions 	 * Do not care about the result if we have the nexthop
1311*bbb1b6f9SApple OSS Distributions 	 * explicitly specified (in case we're asked to clone.)
1312*bbb1b6f9SApple OSS Distributions 	 */
1313*bbb1b6f9SApple OSS Distributions 	if (opts != NULL && opts->ip6po_nexthop != NULL) {
1314*bbb1b6f9SApple OSS Distributions 		if (ro->ro_rt != NULL) {
1315*bbb1b6f9SApple OSS Distributions 			RT_UNLOCK(ro->ro_rt);
1316*bbb1b6f9SApple OSS Distributions 		}
1317*bbb1b6f9SApple OSS Distributions 		goto done;
1318*bbb1b6f9SApple OSS Distributions 	}
1319*bbb1b6f9SApple OSS Distributions 
1320*bbb1b6f9SApple OSS Distributions 	if (ro->ro_rt != NULL) {
1321*bbb1b6f9SApple OSS Distributions 		RT_LOCK_ASSERT_HELD(ro->ro_rt);
1322*bbb1b6f9SApple OSS Distributions 		ifp = ifp0 = ro->ro_rt->rt_ifp;
1323*bbb1b6f9SApple OSS Distributions 	} else {
1324*bbb1b6f9SApple OSS Distributions 		error = EHOSTUNREACH;
1325*bbb1b6f9SApple OSS Distributions 	}
1326*bbb1b6f9SApple OSS Distributions 	route = ro;
1327*bbb1b6f9SApple OSS Distributions 
1328*bbb1b6f9SApple OSS Distributions validateroute:
1329*bbb1b6f9SApple OSS Distributions 	if (select_srcif) {
1330*bbb1b6f9SApple OSS Distributions 		boolean_t has_route = (route != NULL && route->ro_rt != NULL);
1331*bbb1b6f9SApple OSS Distributions 		boolean_t srcif_selected = FALSE;
1332*bbb1b6f9SApple OSS Distributions 
1333*bbb1b6f9SApple OSS Distributions 		if (has_route) {
1334*bbb1b6f9SApple OSS Distributions 			RT_LOCK_ASSERT_HELD(route->ro_rt);
1335*bbb1b6f9SApple OSS Distributions 		}
1336*bbb1b6f9SApple OSS Distributions 		/*
1337*bbb1b6f9SApple OSS Distributions 		 * If there is a non-loopback route with the wrong interface,
1338*bbb1b6f9SApple OSS Distributions 		 * or if there is no interface configured with such an address,
1339*bbb1b6f9SApple OSS Distributions 		 * blow it away.  Except for local/loopback, we look for one
1340*bbb1b6f9SApple OSS Distributions 		 * with a matching interface scope/index.
1341*bbb1b6f9SApple OSS Distributions 		 */
1342*bbb1b6f9SApple OSS Distributions 		if (has_route && (ifa == NULL ||
1343*bbb1b6f9SApple OSS Distributions 		    (ifa->ifa_ifp != ifp && ifp != lo_ifp) ||
1344*bbb1b6f9SApple OSS Distributions 		    !(route->ro_rt->rt_flags & RTF_UP))) {
1345*bbb1b6f9SApple OSS Distributions 			/*
1346*bbb1b6f9SApple OSS Distributions 			 * If the destination address belongs to a proxied
1347*bbb1b6f9SApple OSS Distributions 			 * prefix, relax the requirement and allow the packet
1348*bbb1b6f9SApple OSS Distributions 			 * to come out of the proxy interface with the source
1349*bbb1b6f9SApple OSS Distributions 			 * address of the real interface.
1350*bbb1b6f9SApple OSS Distributions 			 */
1351*bbb1b6f9SApple OSS Distributions 			if (ifa != NULL && proxied_ifa &&
1352*bbb1b6f9SApple OSS Distributions 			    (route->ro_rt->rt_flags & (RTF_UP | RTF_PROXY)) ==
1353*bbb1b6f9SApple OSS Distributions 			    (RTF_UP | RTF_PROXY)) {
1354*bbb1b6f9SApple OSS Distributions 				srcif_selected = TRUE;
1355*bbb1b6f9SApple OSS Distributions 			} else {
1356*bbb1b6f9SApple OSS Distributions 				if (ip6_select_srcif_debug) {
1357*bbb1b6f9SApple OSS Distributions 					if (ifa != NULL) {
1358*bbb1b6f9SApple OSS Distributions 						os_log(OS_LOG_DEFAULT,
1359*bbb1b6f9SApple OSS Distributions 						    "%s->%s ifscope %d "
1360*bbb1b6f9SApple OSS Distributions 						    "ro_if %s != ifa_if %s "
1361*bbb1b6f9SApple OSS Distributions 						    "(cached route cleared)\n",
1362*bbb1b6f9SApple OSS Distributions 						    s_src, s_dst,
1363*bbb1b6f9SApple OSS Distributions 						    ifscope, if_name(ifp),
1364*bbb1b6f9SApple OSS Distributions 						    if_name(ifa->ifa_ifp));
1365*bbb1b6f9SApple OSS Distributions 					} else {
1366*bbb1b6f9SApple OSS Distributions 						os_log(OS_LOG_DEFAULT,
1367*bbb1b6f9SApple OSS Distributions 						    "%s->%s ifscope %d "
1368*bbb1b6f9SApple OSS Distributions 						    "ro_if %s (no ifa_if "
1369*bbb1b6f9SApple OSS Distributions 						    "found)\n", s_src, s_dst,
1370*bbb1b6f9SApple OSS Distributions 						    ifscope, if_name(ifp));
1371*bbb1b6f9SApple OSS Distributions 					}
1372*bbb1b6f9SApple OSS Distributions 				}
1373*bbb1b6f9SApple OSS Distributions 				RT_UNLOCK(route->ro_rt);
1374*bbb1b6f9SApple OSS Distributions 				ROUTE_RELEASE(route);
1375*bbb1b6f9SApple OSS Distributions 				error = EHOSTUNREACH;
1376*bbb1b6f9SApple OSS Distributions 				/* Undo the settings done above */
1377*bbb1b6f9SApple OSS Distributions 				route = NULL;
1378*bbb1b6f9SApple OSS Distributions 				ifp = NULL;     /* ditch ifp; keep ifp0 */
1379*bbb1b6f9SApple OSS Distributions 				has_route = FALSE;
1380*bbb1b6f9SApple OSS Distributions 			}
1381*bbb1b6f9SApple OSS Distributions 		} else if (has_route) {
1382*bbb1b6f9SApple OSS Distributions 			srcif_selected = TRUE;
1383*bbb1b6f9SApple OSS Distributions 		}
1384*bbb1b6f9SApple OSS Distributions 
1385*bbb1b6f9SApple OSS Distributions 		if (srcif_selected) {
1386*bbb1b6f9SApple OSS Distributions 			VERIFY(has_route);
1387*bbb1b6f9SApple OSS Distributions 			if (ifa != route->ro_srcia ||
1388*bbb1b6f9SApple OSS Distributions 			    !(route->ro_flags & ROF_SRCIF_SELECTED)) {
1389*bbb1b6f9SApple OSS Distributions 				RT_CONVERT_LOCK(route->ro_rt);
1390*bbb1b6f9SApple OSS Distributions 				if (ifa != NULL) {
1391*bbb1b6f9SApple OSS Distributions 					ifa_addref(ifa); /* for route_in6 */
1392*bbb1b6f9SApple OSS Distributions 				}
1393*bbb1b6f9SApple OSS Distributions 				if (route->ro_srcia != NULL) {
1394*bbb1b6f9SApple OSS Distributions 					ifa_remref(route->ro_srcia);
1395*bbb1b6f9SApple OSS Distributions 				}
1396*bbb1b6f9SApple OSS Distributions 				route->ro_srcia = ifa;
1397*bbb1b6f9SApple OSS Distributions 				route->ro_flags |= ROF_SRCIF_SELECTED;
1398*bbb1b6f9SApple OSS Distributions 				RT_GENID_SYNC(route->ro_rt);
1399*bbb1b6f9SApple OSS Distributions 			}
1400*bbb1b6f9SApple OSS Distributions 			RT_UNLOCK(route->ro_rt);
1401*bbb1b6f9SApple OSS Distributions 		}
1402*bbb1b6f9SApple OSS Distributions 	} else {
1403*bbb1b6f9SApple OSS Distributions 		if (ro->ro_rt != NULL) {
1404*bbb1b6f9SApple OSS Distributions 			RT_UNLOCK(ro->ro_rt);
1405*bbb1b6f9SApple OSS Distributions 		}
1406*bbb1b6f9SApple OSS Distributions 		if (ifp != NULL && opts != NULL &&
1407*bbb1b6f9SApple OSS Distributions 		    opts->ip6po_pktinfo != NULL &&
1408*bbb1b6f9SApple OSS Distributions 		    opts->ip6po_pktinfo->ipi6_ifindex != 0) {
1409*bbb1b6f9SApple OSS Distributions 			/*
1410*bbb1b6f9SApple OSS Distributions 			 * Check if the outgoing interface conflicts with the
1411*bbb1b6f9SApple OSS Distributions 			 * interface specified by ipi6_ifindex (if specified).
1412*bbb1b6f9SApple OSS Distributions 			 * Note that loopback interface is always okay.
1413*bbb1b6f9SApple OSS Distributions 			 * (this may happen when we are sending a packet to
1414*bbb1b6f9SApple OSS Distributions 			 * one of our own addresses.)
1415*bbb1b6f9SApple OSS Distributions 			 */
1416*bbb1b6f9SApple OSS Distributions 			if (!(ifp->if_flags & IFF_LOOPBACK) && ifp->if_index !=
1417*bbb1b6f9SApple OSS Distributions 			    opts->ip6po_pktinfo->ipi6_ifindex) {
1418*bbb1b6f9SApple OSS Distributions 				error = EHOSTUNREACH;
1419*bbb1b6f9SApple OSS Distributions 				goto done;
1420*bbb1b6f9SApple OSS Distributions 			}
1421*bbb1b6f9SApple OSS Distributions 		}
1422*bbb1b6f9SApple OSS Distributions 	}
1423*bbb1b6f9SApple OSS Distributions 
1424*bbb1b6f9SApple OSS Distributions done:
1425*bbb1b6f9SApple OSS Distributions 	/*
1426*bbb1b6f9SApple OSS Distributions 	 * Check for interface restrictions.
1427*bbb1b6f9SApple OSS Distributions 	 */
1428*bbb1b6f9SApple OSS Distributions #define CHECK_RESTRICTIONS(_ip6oa, _ifp)                        \
1429*bbb1b6f9SApple OSS Distributions 	((((_ip6oa)->ip6oa_flags & IP6OAF_NO_CELLULAR) &&       \
1430*bbb1b6f9SApple OSS Distributions 	    IFNET_IS_CELLULAR(_ifp)) ||                         \
1431*bbb1b6f9SApple OSS Distributions 	(((_ip6oa)->ip6oa_flags & IP6OAF_NO_EXPENSIVE) &&       \
1432*bbb1b6f9SApple OSS Distributions 	    IFNET_IS_EXPENSIVE(_ifp)) ||                        \
1433*bbb1b6f9SApple OSS Distributions 	(((_ip6oa)->ip6oa_flags & IP6OAF_NO_CONSTRAINED) &&     \
1434*bbb1b6f9SApple OSS Distributions 	    IFNET_IS_CONSTRAINED(_ifp)) ||                      \
1435*bbb1b6f9SApple OSS Distributions 	(!((_ip6oa)->ip6oa_flags & IP6OAF_INTCOPROC_ALLOWED) && \
1436*bbb1b6f9SApple OSS Distributions 	    IFNET_IS_INTCOPROC(_ifp)) ||                        \
1437*bbb1b6f9SApple OSS Distributions 	(!((_ip6oa)->ip6oa_flags & IP6OAF_AWDL_UNRESTRICTED) && \
1438*bbb1b6f9SApple OSS Distributions 	    IFNET_IS_AWDL_RESTRICTED(_ifp)) &&                  \
1439*bbb1b6f9SApple OSS Distributions 	(!((_ip6oa)->ip6oa_flags & IP6OAF_MANAGEMENT_ALLOWED) && \
1440*bbb1b6f9SApple OSS Distributions 	    IFNET_IS_MANAGEMENT(_ifp)) &&                       \
1441*bbb1b6f9SApple OSS Distributions 	(!((_ip6oa)->ip6oa_flags & IP6OAF_ULTRA_CONSTRAINED_ALLOWED) && \
1442*bbb1b6f9SApple OSS Distributions 	    IFNET_IS_ULTRA_CONSTRAINED(_ifp)))
1443*bbb1b6f9SApple OSS Distributions 
1444*bbb1b6f9SApple OSS Distributions 	if (error == 0 && ip6oa != NULL &&
1445*bbb1b6f9SApple OSS Distributions 	    ((ifp && CHECK_RESTRICTIONS(ip6oa, ifp)) ||
1446*bbb1b6f9SApple OSS Distributions 	    (route && route->ro_rt &&
1447*bbb1b6f9SApple OSS Distributions 	    CHECK_RESTRICTIONS(ip6oa, route->ro_rt->rt_ifp)))) {
1448*bbb1b6f9SApple OSS Distributions 		if (route != NULL && route->ro_rt != NULL) {
1449*bbb1b6f9SApple OSS Distributions 			ROUTE_RELEASE(route);
1450*bbb1b6f9SApple OSS Distributions 			route = NULL;
1451*bbb1b6f9SApple OSS Distributions 		}
1452*bbb1b6f9SApple OSS Distributions 		ifp = NULL;     /* ditch ifp; keep ifp0 */
1453*bbb1b6f9SApple OSS Distributions 		error = EHOSTUNREACH;
1454*bbb1b6f9SApple OSS Distributions 		ip6oa->ip6oa_flags |= IP6OAF_R_IFDENIED;
1455*bbb1b6f9SApple OSS Distributions 	}
1456*bbb1b6f9SApple OSS Distributions #undef CHECK_RESTRICTIONS
1457*bbb1b6f9SApple OSS Distributions 
1458*bbb1b6f9SApple OSS Distributions 	/*
1459*bbb1b6f9SApple OSS Distributions 	 * If the interface is disabled for IPv6, then ENETDOWN error.
1460*bbb1b6f9SApple OSS Distributions 	 */
1461*bbb1b6f9SApple OSS Distributions 	if (error == 0 &&
1462*bbb1b6f9SApple OSS Distributions 	    ifp != NULL && (ifp->if_eflags & IFEF_IPV6_DISABLED)) {
1463*bbb1b6f9SApple OSS Distributions 		error = ENETDOWN;
1464*bbb1b6f9SApple OSS Distributions 	}
1465*bbb1b6f9SApple OSS Distributions 
1466*bbb1b6f9SApple OSS Distributions 	if (ifp == NULL && (route == NULL || route->ro_rt == NULL)) {
1467*bbb1b6f9SApple OSS Distributions 		/*
1468*bbb1b6f9SApple OSS Distributions 		 * This can happen if the caller did not pass a cached route
1469*bbb1b6f9SApple OSS Distributions 		 * nor any other hints.  We treat this case an error.
1470*bbb1b6f9SApple OSS Distributions 		 */
1471*bbb1b6f9SApple OSS Distributions 		error = EHOSTUNREACH;
1472*bbb1b6f9SApple OSS Distributions 	}
1473*bbb1b6f9SApple OSS Distributions 	if (error == EHOSTUNREACH || error == ENETDOWN) {
1474*bbb1b6f9SApple OSS Distributions 		ip6stat.ip6s_noroute++;
1475*bbb1b6f9SApple OSS Distributions 	}
1476*bbb1b6f9SApple OSS Distributions 
1477*bbb1b6f9SApple OSS Distributions 	/*
1478*bbb1b6f9SApple OSS Distributions 	 * We'll return ifp regardless of error, so pick it up from ifp0
1479*bbb1b6f9SApple OSS Distributions 	 * in case it was nullified above.  Caller is responsible for
1480*bbb1b6f9SApple OSS Distributions 	 * releasing the ifp if it is non-NULL.
1481*bbb1b6f9SApple OSS Distributions 	 */
1482*bbb1b6f9SApple OSS Distributions 	ifp = ifp0;
1483*bbb1b6f9SApple OSS Distributions 	if (retifp != NULL) {
1484*bbb1b6f9SApple OSS Distributions 		if (ifp != NULL) {
1485*bbb1b6f9SApple OSS Distributions 			ifnet_reference(ifp);   /* for caller */
1486*bbb1b6f9SApple OSS Distributions 		}
1487*bbb1b6f9SApple OSS Distributions 		*retifp = ifp;
1488*bbb1b6f9SApple OSS Distributions 	}
1489*bbb1b6f9SApple OSS Distributions 
1490*bbb1b6f9SApple OSS Distributions 	if (retsrcia != NULL) {
1491*bbb1b6f9SApple OSS Distributions 		if (ifa != NULL) {
1492*bbb1b6f9SApple OSS Distributions 			ifa_addref(ifa);        /* for caller */
1493*bbb1b6f9SApple OSS Distributions 		}
1494*bbb1b6f9SApple OSS Distributions 		*retsrcia = ifatoia6(ifa);
1495*bbb1b6f9SApple OSS Distributions 	}
1496*bbb1b6f9SApple OSS Distributions 
1497*bbb1b6f9SApple OSS Distributions 	if (error == 0) {
1498*bbb1b6f9SApple OSS Distributions 		if (retrt != NULL && route != NULL) {
1499*bbb1b6f9SApple OSS Distributions 			*retrt = route->ro_rt;  /* ro_rt may be NULL */
1500*bbb1b6f9SApple OSS Distributions 		}
1501*bbb1b6f9SApple OSS Distributions 	}
1502*bbb1b6f9SApple OSS Distributions 	if (ip6_select_srcif_debug) {
1503*bbb1b6f9SApple OSS Distributions 		os_log(OS_LOG_DEFAULT,
1504*bbb1b6f9SApple OSS Distributions 		    "%s:%d %s->%s ifscope %d ifa_if %s ro_if %s (error=%d)\n",
1505*bbb1b6f9SApple OSS Distributions 		    __func__, __LINE__,
1506*bbb1b6f9SApple OSS Distributions 		    s_src, s_dst, ifscope,
1507*bbb1b6f9SApple OSS Distributions 		    (ifa != NULL) ? if_name(ifa->ifa_ifp) : "NONE",
1508*bbb1b6f9SApple OSS Distributions 		    (ifp != NULL) ? if_name(ifp) : "NONE", error);
1509*bbb1b6f9SApple OSS Distributions 	}
1510*bbb1b6f9SApple OSS Distributions 
1511*bbb1b6f9SApple OSS Distributions 	if (ifa != NULL) {
1512*bbb1b6f9SApple OSS Distributions 		ifa_remref(ifa);
1513*bbb1b6f9SApple OSS Distributions 	}
1514*bbb1b6f9SApple OSS Distributions 
1515*bbb1b6f9SApple OSS Distributions 	return error;
1516*bbb1b6f9SApple OSS Distributions }
1517*bbb1b6f9SApple OSS Distributions 
1518*bbb1b6f9SApple OSS Distributions /*
1519*bbb1b6f9SApple OSS Distributions  * Regardless of error, it will return an ifp with a reference held if the
1520*bbb1b6f9SApple OSS Distributions  * caller provides a non-NULL retifp.  The caller is responsible for checking
1521*bbb1b6f9SApple OSS Distributions  * if the returned ifp is valid and release its reference at all times.
1522*bbb1b6f9SApple OSS Distributions  */
1523*bbb1b6f9SApple OSS Distributions int
in6_selectif(struct sockaddr_in6 * dstsock,struct ip6_pktopts * opts,struct ip6_moptions * mopts,struct route_in6 * ro,struct ip6_out_args * ip6oa,struct ifnet ** retifp)1524*bbb1b6f9SApple OSS Distributions in6_selectif(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
1525*bbb1b6f9SApple OSS Distributions     struct ip6_moptions *mopts, struct route_in6 *ro,
1526*bbb1b6f9SApple OSS Distributions     struct ip6_out_args *ip6oa, struct ifnet **retifp)
1527*bbb1b6f9SApple OSS Distributions {
1528*bbb1b6f9SApple OSS Distributions 	int err = 0;
1529*bbb1b6f9SApple OSS Distributions 	struct route_in6 sro;
1530*bbb1b6f9SApple OSS Distributions 	struct rtentry *__single rt = NULL;
1531*bbb1b6f9SApple OSS Distributions 
1532*bbb1b6f9SApple OSS Distributions 	if (ro == NULL) {
1533*bbb1b6f9SApple OSS Distributions 		bzero(&sro, sizeof(sro));
1534*bbb1b6f9SApple OSS Distributions 		ro = &sro;
1535*bbb1b6f9SApple OSS Distributions 	}
1536*bbb1b6f9SApple OSS Distributions 
1537*bbb1b6f9SApple OSS Distributions 	if ((err = selectroute(NULL, dstsock, opts, mopts, NULL, ro, retifp,
1538*bbb1b6f9SApple OSS Distributions 	    &rt, 0, 1, ip6oa)) != 0) {
1539*bbb1b6f9SApple OSS Distributions 		goto done;
1540*bbb1b6f9SApple OSS Distributions 	}
1541*bbb1b6f9SApple OSS Distributions 
1542*bbb1b6f9SApple OSS Distributions 	/*
1543*bbb1b6f9SApple OSS Distributions 	 * do not use a rejected or black hole route.
1544*bbb1b6f9SApple OSS Distributions 	 * XXX: this check should be done in the L2 output routine.
1545*bbb1b6f9SApple OSS Distributions 	 * However, if we skipped this check here, we'd see the following
1546*bbb1b6f9SApple OSS Distributions 	 * scenario:
1547*bbb1b6f9SApple OSS Distributions 	 * - install a rejected route for a scoped address prefix
1548*bbb1b6f9SApple OSS Distributions 	 *   (like fe80::/10)
1549*bbb1b6f9SApple OSS Distributions 	 * - send a packet to a destination that matches the scoped prefix,
1550*bbb1b6f9SApple OSS Distributions 	 *   with ambiguity about the scope zone.
1551*bbb1b6f9SApple OSS Distributions 	 * - pick the outgoing interface from the route, and disambiguate the
1552*bbb1b6f9SApple OSS Distributions 	 *   scope zone with the interface.
1553*bbb1b6f9SApple OSS Distributions 	 * - ip6_output() would try to get another route with the "new"
1554*bbb1b6f9SApple OSS Distributions 	 *   destination, which may be valid.
1555*bbb1b6f9SApple OSS Distributions 	 * - we'd see no error on output.
1556*bbb1b6f9SApple OSS Distributions 	 * Although this may not be very harmful, it should still be confusing.
1557*bbb1b6f9SApple OSS Distributions 	 * We thus reject the case here.
1558*bbb1b6f9SApple OSS Distributions 	 */
1559*bbb1b6f9SApple OSS Distributions 	if (rt && (rt->rt_flags & (RTF_REJECT | RTF_BLACKHOLE))) {
1560*bbb1b6f9SApple OSS Distributions 		err = ((rt->rt_flags & RTF_HOST) ? EHOSTUNREACH : ENETUNREACH);
1561*bbb1b6f9SApple OSS Distributions 		goto done;
1562*bbb1b6f9SApple OSS Distributions 	}
1563*bbb1b6f9SApple OSS Distributions 
1564*bbb1b6f9SApple OSS Distributions 	/*
1565*bbb1b6f9SApple OSS Distributions 	 * Adjust the "outgoing" interface.  If we're going to loop the packet
1566*bbb1b6f9SApple OSS Distributions 	 * back to ourselves, the ifp would be the loopback interface.
1567*bbb1b6f9SApple OSS Distributions 	 * However, we'd rather know the interface associated to the
1568*bbb1b6f9SApple OSS Distributions 	 * destination address (which should probably be one of our own
1569*bbb1b6f9SApple OSS Distributions 	 * addresses.)
1570*bbb1b6f9SApple OSS Distributions 	 */
1571*bbb1b6f9SApple OSS Distributions 	if (rt != NULL && rt->rt_ifa != NULL && rt->rt_ifa->ifa_ifp != NULL &&
1572*bbb1b6f9SApple OSS Distributions 	    retifp != NULL) {
1573*bbb1b6f9SApple OSS Distributions 		ifnet_reference(rt->rt_ifa->ifa_ifp);
1574*bbb1b6f9SApple OSS Distributions 		if (*retifp != NULL) {
1575*bbb1b6f9SApple OSS Distributions 			ifnet_release(*retifp);
1576*bbb1b6f9SApple OSS Distributions 		}
1577*bbb1b6f9SApple OSS Distributions 		*retifp = rt->rt_ifa->ifa_ifp;
1578*bbb1b6f9SApple OSS Distributions 	}
1579*bbb1b6f9SApple OSS Distributions 
1580*bbb1b6f9SApple OSS Distributions done:
1581*bbb1b6f9SApple OSS Distributions 	if (ro == &sro) {
1582*bbb1b6f9SApple OSS Distributions 		VERIFY(rt == NULL || rt == ro->ro_rt);
1583*bbb1b6f9SApple OSS Distributions 		ROUTE_RELEASE(ro);
1584*bbb1b6f9SApple OSS Distributions 	}
1585*bbb1b6f9SApple OSS Distributions 
1586*bbb1b6f9SApple OSS Distributions 	/*
1587*bbb1b6f9SApple OSS Distributions 	 * retifp might point to a valid ifp with a reference held;
1588*bbb1b6f9SApple OSS Distributions 	 * caller is responsible for releasing it if non-NULL.
1589*bbb1b6f9SApple OSS Distributions 	 */
1590*bbb1b6f9SApple OSS Distributions 	return err;
1591*bbb1b6f9SApple OSS Distributions }
1592*bbb1b6f9SApple OSS Distributions 
1593*bbb1b6f9SApple OSS Distributions /*
1594*bbb1b6f9SApple OSS Distributions  * Regardless of error, it will return an ifp with a reference held if the
1595*bbb1b6f9SApple OSS Distributions  * caller provides a non-NULL retifp.  The caller is responsible for checking
1596*bbb1b6f9SApple OSS Distributions  * if the returned ifp is valid and release its reference at all times.
1597*bbb1b6f9SApple OSS Distributions  *
1598*bbb1b6f9SApple OSS Distributions  * clone - meaningful only for bsdi and freebsd
1599*bbb1b6f9SApple OSS Distributions  */
1600*bbb1b6f9SApple OSS Distributions int
in6_selectroute(struct sockaddr_in6 * srcsock,struct sockaddr_in6 * dstsock,struct ip6_pktopts * opts,struct ip6_moptions * mopts,struct in6_ifaddr ** retsrcia,struct route_in6 * ro,struct ifnet ** retifp,struct rtentry ** retrt,int clone,struct ip6_out_args * ip6oa)1601*bbb1b6f9SApple OSS Distributions in6_selectroute(struct sockaddr_in6 *srcsock, struct sockaddr_in6 *dstsock,
1602*bbb1b6f9SApple OSS Distributions     struct ip6_pktopts *opts, struct ip6_moptions *mopts,
1603*bbb1b6f9SApple OSS Distributions     struct in6_ifaddr **retsrcia, struct route_in6 *ro, struct ifnet **retifp,
1604*bbb1b6f9SApple OSS Distributions     struct rtentry **retrt, int clone, struct ip6_out_args *ip6oa)
1605*bbb1b6f9SApple OSS Distributions {
1606*bbb1b6f9SApple OSS Distributions 	return selectroute(srcsock, dstsock, opts, mopts, retsrcia, ro, retifp,
1607*bbb1b6f9SApple OSS Distributions 	           retrt, clone, 0, ip6oa);
1608*bbb1b6f9SApple OSS Distributions }
1609*bbb1b6f9SApple OSS Distributions 
1610*bbb1b6f9SApple OSS Distributions /*
1611*bbb1b6f9SApple OSS Distributions  * Default hop limit selection. The precedence is as follows:
1612*bbb1b6f9SApple OSS Distributions  * 1. Hoplimit value specified via socket option.
1613*bbb1b6f9SApple OSS Distributions  * 2. (If the outgoing interface is detected) the current
1614*bbb1b6f9SApple OSS Distributions  *     hop limit of the interface specified by router advertisement.
1615*bbb1b6f9SApple OSS Distributions  * 3. The system default hoplimit.
1616*bbb1b6f9SApple OSS Distributions  */
1617*bbb1b6f9SApple OSS Distributions uint8_t
in6_selecthlim(struct in6pcb * in6p,struct ifnet * ifp)1618*bbb1b6f9SApple OSS Distributions in6_selecthlim(struct in6pcb *in6p, struct ifnet *ifp)
1619*bbb1b6f9SApple OSS Distributions {
1620*bbb1b6f9SApple OSS Distributions 	if (in6p && in6p->in6p_hops >= 0) {
1621*bbb1b6f9SApple OSS Distributions 		return (uint8_t)in6p->in6p_hops;
1622*bbb1b6f9SApple OSS Distributions 	} else if (NULL != ifp) {
1623*bbb1b6f9SApple OSS Distributions 		uint8_t chlim;
1624*bbb1b6f9SApple OSS Distributions 		struct nd_ifinfo *__single ndi = ND_IFINFO(ifp);
1625*bbb1b6f9SApple OSS Distributions 		if (ndi && ndi->initialized) {
1626*bbb1b6f9SApple OSS Distributions 			/* access chlim without lock, for performance */
1627*bbb1b6f9SApple OSS Distributions 			chlim = ndi->chlim;
1628*bbb1b6f9SApple OSS Distributions 		} else {
1629*bbb1b6f9SApple OSS Distributions 			chlim = (uint8_t)ip6_defhlim;
1630*bbb1b6f9SApple OSS Distributions 		}
1631*bbb1b6f9SApple OSS Distributions 		return chlim;
1632*bbb1b6f9SApple OSS Distributions 	}
1633*bbb1b6f9SApple OSS Distributions 
1634*bbb1b6f9SApple OSS Distributions 	return (uint8_t)ip6_defhlim;
1635*bbb1b6f9SApple OSS Distributions }
1636*bbb1b6f9SApple OSS Distributions 
1637*bbb1b6f9SApple OSS Distributions /*
1638*bbb1b6f9SApple OSS Distributions  * XXX: this is borrowed from in6_pcbbind(). If possible, we should
1639*bbb1b6f9SApple OSS Distributions  * share this function by all *bsd*...
1640*bbb1b6f9SApple OSS Distributions  */
1641*bbb1b6f9SApple OSS Distributions int
in6_pcbsetport(struct in6_addr * laddr,struct sockaddr * remote,struct inpcb * inp,struct proc * p,int locked)1642*bbb1b6f9SApple OSS Distributions in6_pcbsetport(struct in6_addr *laddr, struct sockaddr *remote, struct inpcb *inp, struct proc *p,
1643*bbb1b6f9SApple OSS Distributions     int locked)
1644*bbb1b6f9SApple OSS Distributions {
1645*bbb1b6f9SApple OSS Distributions 	struct socket *__single so = inp->inp_socket;
1646*bbb1b6f9SApple OSS Distributions 	uint16_t lport = 0, first, last, rand_port;
1647*bbb1b6f9SApple OSS Distributions 	uint16_t *__single lastport;
1648*bbb1b6f9SApple OSS Distributions 	int count, error = 0, wild = 0;
1649*bbb1b6f9SApple OSS Distributions 	boolean_t counting_down;
1650*bbb1b6f9SApple OSS Distributions 	bool found, randomport;
1651*bbb1b6f9SApple OSS Distributions 	struct inpcbinfo *__single pcbinfo = inp->inp_pcbinfo;
1652*bbb1b6f9SApple OSS Distributions 	kauth_cred_t __single cred;
1653*bbb1b6f9SApple OSS Distributions #if SKYWALK
1654*bbb1b6f9SApple OSS Distributions 	bool laddr_unspecified = IN6_IS_ADDR_UNSPECIFIED(laddr);
1655*bbb1b6f9SApple OSS Distributions #else
1656*bbb1b6f9SApple OSS Distributions #pragma unused(laddr)
1657*bbb1b6f9SApple OSS Distributions #endif
1658*bbb1b6f9SApple OSS Distributions 	if (!locked) { /* Make sure we don't run into a deadlock: 4052373 */
1659*bbb1b6f9SApple OSS Distributions 		if (!lck_rw_try_lock_exclusive(&pcbinfo->ipi_lock)) {
1660*bbb1b6f9SApple OSS Distributions 			socket_unlock(inp->inp_socket, 0);
1661*bbb1b6f9SApple OSS Distributions 			lck_rw_lock_exclusive(&pcbinfo->ipi_lock);
1662*bbb1b6f9SApple OSS Distributions 			socket_lock(inp->inp_socket, 0);
1663*bbb1b6f9SApple OSS Distributions 		}
1664*bbb1b6f9SApple OSS Distributions 
1665*bbb1b6f9SApple OSS Distributions 		/*
1666*bbb1b6f9SApple OSS Distributions 		 * Check if a local port was assigned to the inp while
1667*bbb1b6f9SApple OSS Distributions 		 * this thread was waiting for the pcbinfo lock
1668*bbb1b6f9SApple OSS Distributions 		 */
1669*bbb1b6f9SApple OSS Distributions 		if (inp->inp_lport != 0) {
1670*bbb1b6f9SApple OSS Distributions 			VERIFY(inp->inp_flags2 & INP2_INHASHLIST);
1671*bbb1b6f9SApple OSS Distributions 			lck_rw_done(&pcbinfo->ipi_lock);
1672*bbb1b6f9SApple OSS Distributions 
1673*bbb1b6f9SApple OSS Distributions 			/*
1674*bbb1b6f9SApple OSS Distributions 			 * It is not an error if another thread allocated
1675*bbb1b6f9SApple OSS Distributions 			 * a port
1676*bbb1b6f9SApple OSS Distributions 			 */
1677*bbb1b6f9SApple OSS Distributions 			return 0;
1678*bbb1b6f9SApple OSS Distributions 		}
1679*bbb1b6f9SApple OSS Distributions 	}
1680*bbb1b6f9SApple OSS Distributions 
1681*bbb1b6f9SApple OSS Distributions 	/* XXX: this is redundant when called from in6_pcbbind */
1682*bbb1b6f9SApple OSS Distributions 	if ((so->so_options & (SO_REUSEADDR | SO_REUSEPORT)) == 0) {
1683*bbb1b6f9SApple OSS Distributions 		wild = INPLOOKUP_WILDCARD;
1684*bbb1b6f9SApple OSS Distributions 	}
1685*bbb1b6f9SApple OSS Distributions 
1686*bbb1b6f9SApple OSS Distributions 	randomport = (so->so_flags & SOF_BINDRANDOMPORT) > 0 ||
1687*bbb1b6f9SApple OSS Distributions 	    (so->so_type == SOCK_STREAM ? tcp_use_randomport :
1688*bbb1b6f9SApple OSS Distributions 	    udp_use_randomport) > 0;
1689*bbb1b6f9SApple OSS Distributions 
1690*bbb1b6f9SApple OSS Distributions 	if (inp->inp_flags & INP_HIGHPORT) {
1691*bbb1b6f9SApple OSS Distributions 		first = (uint16_t)ipport_hifirstauto;     /* sysctl */
1692*bbb1b6f9SApple OSS Distributions 		last  = (uint16_t)ipport_hilastauto;
1693*bbb1b6f9SApple OSS Distributions 		lastport = &pcbinfo->ipi_lasthi;
1694*bbb1b6f9SApple OSS Distributions 	} else if (inp->inp_flags & INP_LOWPORT) {
1695*bbb1b6f9SApple OSS Distributions 		cred = kauth_cred_proc_ref(p);
1696*bbb1b6f9SApple OSS Distributions 		error = priv_check_cred(cred, PRIV_NETINET_RESERVEDPORT, 0);
1697*bbb1b6f9SApple OSS Distributions 		kauth_cred_unref(&cred);
1698*bbb1b6f9SApple OSS Distributions 		if (error != 0) {
1699*bbb1b6f9SApple OSS Distributions 			if (!locked) {
1700*bbb1b6f9SApple OSS Distributions 				lck_rw_done(&pcbinfo->ipi_lock);
1701*bbb1b6f9SApple OSS Distributions 			}
1702*bbb1b6f9SApple OSS Distributions 			return error;
1703*bbb1b6f9SApple OSS Distributions 		}
1704*bbb1b6f9SApple OSS Distributions 		first = (uint16_t)ipport_lowfirstauto;    /* 1023 */
1705*bbb1b6f9SApple OSS Distributions 		last  = (uint16_t)ipport_lowlastauto;     /* 600 */
1706*bbb1b6f9SApple OSS Distributions 		lastport = &pcbinfo->ipi_lastlow;
1707*bbb1b6f9SApple OSS Distributions 	} else {
1708*bbb1b6f9SApple OSS Distributions 		first = (uint16_t)ipport_firstauto;       /* sysctl */
1709*bbb1b6f9SApple OSS Distributions 		last  = (uint16_t)ipport_lastauto;
1710*bbb1b6f9SApple OSS Distributions 		lastport = &pcbinfo->ipi_lastport;
1711*bbb1b6f9SApple OSS Distributions 	}
1712*bbb1b6f9SApple OSS Distributions 
1713*bbb1b6f9SApple OSS Distributions 	if (first == last) {
1714*bbb1b6f9SApple OSS Distributions 		randomport = false;
1715*bbb1b6f9SApple OSS Distributions 	}
1716*bbb1b6f9SApple OSS Distributions 	/*
1717*bbb1b6f9SApple OSS Distributions 	 * Simple check to ensure all ports are not used up causing
1718*bbb1b6f9SApple OSS Distributions 	 * a deadlock here.
1719*bbb1b6f9SApple OSS Distributions 	 */
1720*bbb1b6f9SApple OSS Distributions 	found = false;
1721*bbb1b6f9SApple OSS Distributions 	if (first > last) {
1722*bbb1b6f9SApple OSS Distributions 		/* counting down */
1723*bbb1b6f9SApple OSS Distributions 		if (randomport) {
1724*bbb1b6f9SApple OSS Distributions 			read_frandom(&rand_port, sizeof(rand_port));
1725*bbb1b6f9SApple OSS Distributions 			*lastport = first - (rand_port % (first - last));
1726*bbb1b6f9SApple OSS Distributions 		}
1727*bbb1b6f9SApple OSS Distributions 		count = first - last;
1728*bbb1b6f9SApple OSS Distributions 		counting_down = TRUE;
1729*bbb1b6f9SApple OSS Distributions 	} else {
1730*bbb1b6f9SApple OSS Distributions 		/* counting up */
1731*bbb1b6f9SApple OSS Distributions 		if (randomport) {
1732*bbb1b6f9SApple OSS Distributions 			read_frandom(&rand_port, sizeof(rand_port));
1733*bbb1b6f9SApple OSS Distributions 			*lastport = first + (rand_port % (first - last));
1734*bbb1b6f9SApple OSS Distributions 		}
1735*bbb1b6f9SApple OSS Distributions 		count = last - first;
1736*bbb1b6f9SApple OSS Distributions 		counting_down = FALSE;
1737*bbb1b6f9SApple OSS Distributions 	}
1738*bbb1b6f9SApple OSS Distributions 	do {
1739*bbb1b6f9SApple OSS Distributions 		if (count-- < 0) {      /* completely used? */
1740*bbb1b6f9SApple OSS Distributions 			/*
1741*bbb1b6f9SApple OSS Distributions 			 * Undo any address bind that may have
1742*bbb1b6f9SApple OSS Distributions 			 * occurred above.
1743*bbb1b6f9SApple OSS Distributions 			 */
1744*bbb1b6f9SApple OSS Distributions 			inp->in6p_laddr = in6addr_any;
1745*bbb1b6f9SApple OSS Distributions 			inp->in6p_last_outifp = NULL;
1746*bbb1b6f9SApple OSS Distributions 			inp->inp_lifscope = IFSCOPE_NONE;
1747*bbb1b6f9SApple OSS Distributions #if SKYWALK
1748*bbb1b6f9SApple OSS Distributions 			if (NETNS_TOKEN_VALID(&inp->inp_netns_token)) {
1749*bbb1b6f9SApple OSS Distributions 				netns_set_ifnet(&inp->inp_netns_token,
1750*bbb1b6f9SApple OSS Distributions 				    NULL);
1751*bbb1b6f9SApple OSS Distributions 			}
1752*bbb1b6f9SApple OSS Distributions #endif /* SKYWALK */
1753*bbb1b6f9SApple OSS Distributions 			if (!locked) {
1754*bbb1b6f9SApple OSS Distributions 				lck_rw_done(&pcbinfo->ipi_lock);
1755*bbb1b6f9SApple OSS Distributions 			}
1756*bbb1b6f9SApple OSS Distributions 			return EAGAIN;
1757*bbb1b6f9SApple OSS Distributions 		}
1758*bbb1b6f9SApple OSS Distributions 		if (counting_down) {
1759*bbb1b6f9SApple OSS Distributions 			--*lastport;
1760*bbb1b6f9SApple OSS Distributions 			if (*lastport > first || *lastport < last) {
1761*bbb1b6f9SApple OSS Distributions 				*lastport = first;
1762*bbb1b6f9SApple OSS Distributions 			}
1763*bbb1b6f9SApple OSS Distributions 		} else {
1764*bbb1b6f9SApple OSS Distributions 			++*lastport;
1765*bbb1b6f9SApple OSS Distributions 			if (*lastport < first || *lastport > last) {
1766*bbb1b6f9SApple OSS Distributions 				*lastport = first;
1767*bbb1b6f9SApple OSS Distributions 			}
1768*bbb1b6f9SApple OSS Distributions 		}
1769*bbb1b6f9SApple OSS Distributions 		lport = htons(*lastport);
1770*bbb1b6f9SApple OSS Distributions 
1771*bbb1b6f9SApple OSS Distributions 		/*
1772*bbb1b6f9SApple OSS Distributions 		 * Skip if this is a restricted port as we do not want to
1773*bbb1b6f9SApple OSS Distributions 		 * restricted ports as ephemeral
1774*bbb1b6f9SApple OSS Distributions 		 */
1775*bbb1b6f9SApple OSS Distributions 		if (IS_RESTRICTED_IN_PORT(lport)) {
1776*bbb1b6f9SApple OSS Distributions 			continue;
1777*bbb1b6f9SApple OSS Distributions 		}
1778*bbb1b6f9SApple OSS Distributions 
1779*bbb1b6f9SApple OSS Distributions 		found = (in6_pcblookup_local(pcbinfo, &inp->in6p_laddr,
1780*bbb1b6f9SApple OSS Distributions 		    lport, inp->inp_lifscope, wild) == NULL);
1781*bbb1b6f9SApple OSS Distributions #if SKYWALK
1782*bbb1b6f9SApple OSS Distributions 		if (found &&
1783*bbb1b6f9SApple OSS Distributions 		    (SOCK_PROTO(so) == IPPROTO_TCP ||
1784*bbb1b6f9SApple OSS Distributions 		    SOCK_PROTO(so) == IPPROTO_UDP) &&
1785*bbb1b6f9SApple OSS Distributions 		    !(inp->inp_flags2 & INP2_EXTERNAL_PORT)) {
1786*bbb1b6f9SApple OSS Distributions 			if (laddr_unspecified &&
1787*bbb1b6f9SApple OSS Distributions 			    (inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
1788*bbb1b6f9SApple OSS Distributions 				struct in_addr ip_zero = { .s_addr = 0 };
1789*bbb1b6f9SApple OSS Distributions 
1790*bbb1b6f9SApple OSS Distributions 				netns_release(&inp->inp_wildcard_netns_token);
1791*bbb1b6f9SApple OSS Distributions 				if (netns_reserve_in(
1792*bbb1b6f9SApple OSS Distributions 					    &inp->inp_wildcard_netns_token,
1793*bbb1b6f9SApple OSS Distributions 					    ip_zero,
1794*bbb1b6f9SApple OSS Distributions 					    (uint8_t)SOCK_PROTO(so), lport,
1795*bbb1b6f9SApple OSS Distributions 					    NETNS_BSD, NULL) != 0) {
1796*bbb1b6f9SApple OSS Distributions 					/* port in use in IPv4 namespace */
1797*bbb1b6f9SApple OSS Distributions 					found = false;
1798*bbb1b6f9SApple OSS Distributions 				}
1799*bbb1b6f9SApple OSS Distributions 			}
1800*bbb1b6f9SApple OSS Distributions 			if (found &&
1801*bbb1b6f9SApple OSS Distributions 			    netns_reserve_in6(&inp->inp_netns_token,
1802*bbb1b6f9SApple OSS Distributions 			    inp->in6p_laddr, (uint8_t)SOCK_PROTO(so), lport,
1803*bbb1b6f9SApple OSS Distributions 			    NETNS_BSD, NULL) != 0) {
1804*bbb1b6f9SApple OSS Distributions 				netns_release(&inp->inp_wildcard_netns_token);
1805*bbb1b6f9SApple OSS Distributions 				found = false;
1806*bbb1b6f9SApple OSS Distributions 			}
1807*bbb1b6f9SApple OSS Distributions 		}
1808*bbb1b6f9SApple OSS Distributions #endif /* SKYWALK */
1809*bbb1b6f9SApple OSS Distributions 	} while (!found);
1810*bbb1b6f9SApple OSS Distributions 
1811*bbb1b6f9SApple OSS Distributions 	inp->inp_lport = lport;
1812*bbb1b6f9SApple OSS Distributions 	inp->inp_flags |= INP_ANONPORT;
1813*bbb1b6f9SApple OSS Distributions 
1814*bbb1b6f9SApple OSS Distributions 	if (in_pcbinshash(inp, remote, 1) != 0) {
1815*bbb1b6f9SApple OSS Distributions 		inp->in6p_laddr = in6addr_any;
1816*bbb1b6f9SApple OSS Distributions 		inp->in6p_last_outifp = NULL;
1817*bbb1b6f9SApple OSS Distributions 		inp->inp_lifscope = IFSCOPE_NONE;
1818*bbb1b6f9SApple OSS Distributions #if SKYWALK
1819*bbb1b6f9SApple OSS Distributions 		netns_release(&inp->inp_netns_token);
1820*bbb1b6f9SApple OSS Distributions #endif /* SKYWALK */
1821*bbb1b6f9SApple OSS Distributions 		inp->inp_lport = 0;
1822*bbb1b6f9SApple OSS Distributions 		inp->inp_flags &= ~INP_ANONPORT;
1823*bbb1b6f9SApple OSS Distributions 		if (!locked) {
1824*bbb1b6f9SApple OSS Distributions 			lck_rw_done(&pcbinfo->ipi_lock);
1825*bbb1b6f9SApple OSS Distributions 		}
1826*bbb1b6f9SApple OSS Distributions 		return EAGAIN;
1827*bbb1b6f9SApple OSS Distributions 	}
1828*bbb1b6f9SApple OSS Distributions 
1829*bbb1b6f9SApple OSS Distributions 	if (!locked) {
1830*bbb1b6f9SApple OSS Distributions 		lck_rw_done(&pcbinfo->ipi_lock);
1831*bbb1b6f9SApple OSS Distributions 	}
1832*bbb1b6f9SApple OSS Distributions 	return 0;
1833*bbb1b6f9SApple OSS Distributions }
1834*bbb1b6f9SApple OSS Distributions 
1835*bbb1b6f9SApple OSS Distributions /*
1836*bbb1b6f9SApple OSS Distributions  * The followings are implementation of the policy table using a
1837*bbb1b6f9SApple OSS Distributions  * simple tail queue.
1838*bbb1b6f9SApple OSS Distributions  * XXX such details should be hidden.
1839*bbb1b6f9SApple OSS Distributions  * XXX implementation using binary tree should be more efficient.
1840*bbb1b6f9SApple OSS Distributions  */
1841*bbb1b6f9SApple OSS Distributions struct addrsel_policyent {
1842*bbb1b6f9SApple OSS Distributions 	TAILQ_ENTRY(addrsel_policyent) ape_entry;
1843*bbb1b6f9SApple OSS Distributions 	struct in6_addrpolicy ape_policy;
1844*bbb1b6f9SApple OSS Distributions };
1845*bbb1b6f9SApple OSS Distributions 
1846*bbb1b6f9SApple OSS Distributions TAILQ_HEAD(addrsel_policyhead, addrsel_policyent);
1847*bbb1b6f9SApple OSS Distributions 
1848*bbb1b6f9SApple OSS Distributions struct addrsel_policyhead addrsel_policytab;
1849*bbb1b6f9SApple OSS Distributions 
1850*bbb1b6f9SApple OSS Distributions static void
init_policy_queue(void)1851*bbb1b6f9SApple OSS Distributions init_policy_queue(void)
1852*bbb1b6f9SApple OSS Distributions {
1853*bbb1b6f9SApple OSS Distributions 	TAILQ_INIT(&addrsel_policytab);
1854*bbb1b6f9SApple OSS Distributions }
1855*bbb1b6f9SApple OSS Distributions 
1856*bbb1b6f9SApple OSS Distributions void
addrsel_policy_init(void)1857*bbb1b6f9SApple OSS Distributions addrsel_policy_init(void)
1858*bbb1b6f9SApple OSS Distributions {
1859*bbb1b6f9SApple OSS Distributions 	/*
1860*bbb1b6f9SApple OSS Distributions 	 * Default address selection policy based on RFC 6724.
1861*bbb1b6f9SApple OSS Distributions 	 */
1862*bbb1b6f9SApple OSS Distributions 	static const struct in6_addrpolicy defaddrsel[] = {
1863*bbb1b6f9SApple OSS Distributions 		/* Loopback -- prefix=::1/128, precedence=50, label=0 */
1864*bbb1b6f9SApple OSS Distributions 		{
1865*bbb1b6f9SApple OSS Distributions 			.addr = {
1866*bbb1b6f9SApple OSS Distributions 				.sin6_family = AF_INET6,
1867*bbb1b6f9SApple OSS Distributions 				.sin6_addr   = IN6ADDR_LOOPBACK_INIT,
1868*bbb1b6f9SApple OSS Distributions 				.sin6_len    = sizeof(struct sockaddr_in6)
1869*bbb1b6f9SApple OSS Distributions 			},
1870*bbb1b6f9SApple OSS Distributions 			.addrmask = {
1871*bbb1b6f9SApple OSS Distributions 				.sin6_family = AF_INET6,
1872*bbb1b6f9SApple OSS Distributions 				.sin6_addr   = IN6MASK128,
1873*bbb1b6f9SApple OSS Distributions 				.sin6_len    = sizeof(struct sockaddr_in6)
1874*bbb1b6f9SApple OSS Distributions 			},
1875*bbb1b6f9SApple OSS Distributions 			.preced   = 50,
1876*bbb1b6f9SApple OSS Distributions 			.label    = 0
1877*bbb1b6f9SApple OSS Distributions 		},
1878*bbb1b6f9SApple OSS Distributions 
1879*bbb1b6f9SApple OSS Distributions 		/* Unspecified -- prefix=::/0, precedence=40, label=1 */
1880*bbb1b6f9SApple OSS Distributions 		{
1881*bbb1b6f9SApple OSS Distributions 			.addr = {
1882*bbb1b6f9SApple OSS Distributions 				.sin6_family = AF_INET6,
1883*bbb1b6f9SApple OSS Distributions 				.sin6_addr   = IN6ADDR_ANY_INIT,
1884*bbb1b6f9SApple OSS Distributions 				.sin6_len    = sizeof(struct sockaddr_in6)
1885*bbb1b6f9SApple OSS Distributions 			},
1886*bbb1b6f9SApple OSS Distributions 			.addrmask = {
1887*bbb1b6f9SApple OSS Distributions 				.sin6_family = AF_INET6,
1888*bbb1b6f9SApple OSS Distributions 				.sin6_addr   = IN6MASK0,
1889*bbb1b6f9SApple OSS Distributions 				.sin6_len    = sizeof(struct sockaddr_in6)
1890*bbb1b6f9SApple OSS Distributions 			},
1891*bbb1b6f9SApple OSS Distributions 			.preced   = 40,
1892*bbb1b6f9SApple OSS Distributions 			.label    = 1
1893*bbb1b6f9SApple OSS Distributions 		},
1894*bbb1b6f9SApple OSS Distributions 
1895*bbb1b6f9SApple OSS Distributions 		/* IPv4 Mapped -- prefix=::ffff:0:0/96, precedence=35, label=4 */
1896*bbb1b6f9SApple OSS Distributions 		{
1897*bbb1b6f9SApple OSS Distributions 			.addr = {
1898*bbb1b6f9SApple OSS Distributions 				.sin6_family = AF_INET6,
1899*bbb1b6f9SApple OSS Distributions 				.sin6_addr   = IN6ADDR_V4MAPPED_INIT,
1900*bbb1b6f9SApple OSS Distributions 				.sin6_len    = sizeof(struct sockaddr_in6)
1901*bbb1b6f9SApple OSS Distributions 			},
1902*bbb1b6f9SApple OSS Distributions 			.addrmask = {
1903*bbb1b6f9SApple OSS Distributions 				.sin6_family = AF_INET6,
1904*bbb1b6f9SApple OSS Distributions 				.sin6_addr   = IN6MASK96,
1905*bbb1b6f9SApple OSS Distributions 				.sin6_len    = sizeof(struct sockaddr_in6)
1906*bbb1b6f9SApple OSS Distributions 			},
1907*bbb1b6f9SApple OSS Distributions 			.preced   = 35,
1908*bbb1b6f9SApple OSS Distributions 			.label    = 4
1909*bbb1b6f9SApple OSS Distributions 		},
1910*bbb1b6f9SApple OSS Distributions 
1911*bbb1b6f9SApple OSS Distributions 		/* 6to4 -- prefix=2002::/16, precedence=30, label=2 */
1912*bbb1b6f9SApple OSS Distributions 		{
1913*bbb1b6f9SApple OSS Distributions 			.addr = {
1914*bbb1b6f9SApple OSS Distributions 				.sin6_family = AF_INET6,
1915*bbb1b6f9SApple OSS Distributions 				.sin6_addr   = {{{ 0x20, 0x02 }}},
1916*bbb1b6f9SApple OSS Distributions 				.sin6_len    = sizeof(struct sockaddr_in6)
1917*bbb1b6f9SApple OSS Distributions 			},
1918*bbb1b6f9SApple OSS Distributions 			.addrmask = {
1919*bbb1b6f9SApple OSS Distributions 				.sin6_family = AF_INET6,
1920*bbb1b6f9SApple OSS Distributions 				.sin6_addr   = IN6MASK16,
1921*bbb1b6f9SApple OSS Distributions 				.sin6_len    = sizeof(struct sockaddr_in6)
1922*bbb1b6f9SApple OSS Distributions 			},
1923*bbb1b6f9SApple OSS Distributions 			.preced   = 30,
1924*bbb1b6f9SApple OSS Distributions 			.label    = 2
1925*bbb1b6f9SApple OSS Distributions 		},
1926*bbb1b6f9SApple OSS Distributions 
1927*bbb1b6f9SApple OSS Distributions 		/* Teredo -- prefix=2001::/32, precedence=5, label=5 */
1928*bbb1b6f9SApple OSS Distributions 		{
1929*bbb1b6f9SApple OSS Distributions 			.addr = {
1930*bbb1b6f9SApple OSS Distributions 				.sin6_family = AF_INET6,
1931*bbb1b6f9SApple OSS Distributions 				.sin6_addr   = {{{ 0x20, 0x01 }}},
1932*bbb1b6f9SApple OSS Distributions 				.sin6_len    = sizeof(struct sockaddr_in6)
1933*bbb1b6f9SApple OSS Distributions 			},
1934*bbb1b6f9SApple OSS Distributions 			.addrmask = {
1935*bbb1b6f9SApple OSS Distributions 				.sin6_family = AF_INET6,
1936*bbb1b6f9SApple OSS Distributions 				.sin6_addr   = IN6MASK32,
1937*bbb1b6f9SApple OSS Distributions 				.sin6_len    = sizeof(struct sockaddr_in6)
1938*bbb1b6f9SApple OSS Distributions 			},
1939*bbb1b6f9SApple OSS Distributions 			.preced   = 5,
1940*bbb1b6f9SApple OSS Distributions 			.label    = 5
1941*bbb1b6f9SApple OSS Distributions 		},
1942*bbb1b6f9SApple OSS Distributions 
1943*bbb1b6f9SApple OSS Distributions 		/* Unique Local (ULA) -- prefix=fc00::/7, precedence=3, label=13 */
1944*bbb1b6f9SApple OSS Distributions 		{
1945*bbb1b6f9SApple OSS Distributions 			.addr = {
1946*bbb1b6f9SApple OSS Distributions 				.sin6_family = AF_INET6,
1947*bbb1b6f9SApple OSS Distributions 				.sin6_addr   = {{{ 0xfc }}},
1948*bbb1b6f9SApple OSS Distributions 				.sin6_len    = sizeof(struct sockaddr_in6)
1949*bbb1b6f9SApple OSS Distributions 			},
1950*bbb1b6f9SApple OSS Distributions 			.addrmask = {
1951*bbb1b6f9SApple OSS Distributions 				.sin6_family = AF_INET6,
1952*bbb1b6f9SApple OSS Distributions 				.sin6_addr   = IN6MASK7,
1953*bbb1b6f9SApple OSS Distributions 				.sin6_len    = sizeof(struct sockaddr_in6)
1954*bbb1b6f9SApple OSS Distributions 			},
1955*bbb1b6f9SApple OSS Distributions 			.preced   = 3,
1956*bbb1b6f9SApple OSS Distributions 			.label    = 13
1957*bbb1b6f9SApple OSS Distributions 		},
1958*bbb1b6f9SApple OSS Distributions 
1959*bbb1b6f9SApple OSS Distributions 		/* IPv4 Compatible -- prefix=::/96, precedence=1, label=3 */
1960*bbb1b6f9SApple OSS Distributions 		{
1961*bbb1b6f9SApple OSS Distributions 			.addr = {
1962*bbb1b6f9SApple OSS Distributions 				.sin6_family = AF_INET6,
1963*bbb1b6f9SApple OSS Distributions 				.sin6_addr = IN6ADDR_ANY_INIT,
1964*bbb1b6f9SApple OSS Distributions 				.sin6_len    = sizeof(struct sockaddr_in6)
1965*bbb1b6f9SApple OSS Distributions 			},
1966*bbb1b6f9SApple OSS Distributions 			.addrmask = {
1967*bbb1b6f9SApple OSS Distributions 				.sin6_family = AF_INET6,
1968*bbb1b6f9SApple OSS Distributions 				.sin6_addr = IN6MASK96,
1969*bbb1b6f9SApple OSS Distributions 				.sin6_len    = sizeof(struct sockaddr_in6)
1970*bbb1b6f9SApple OSS Distributions 			},
1971*bbb1b6f9SApple OSS Distributions 			.preced   = 1,
1972*bbb1b6f9SApple OSS Distributions 			.label    = 3
1973*bbb1b6f9SApple OSS Distributions 		},
1974*bbb1b6f9SApple OSS Distributions 
1975*bbb1b6f9SApple OSS Distributions 		/* Site-local (deprecated) -- prefix=fec0::/10, precedence=1, label=11 */
1976*bbb1b6f9SApple OSS Distributions 		{
1977*bbb1b6f9SApple OSS Distributions 			.addr = {
1978*bbb1b6f9SApple OSS Distributions 				.sin6_family = AF_INET6,
1979*bbb1b6f9SApple OSS Distributions 				.sin6_addr = {{{ 0xfe, 0xc0 }}},
1980*bbb1b6f9SApple OSS Distributions 				.sin6_len    = sizeof(struct sockaddr_in6)
1981*bbb1b6f9SApple OSS Distributions 			},
1982*bbb1b6f9SApple OSS Distributions 			.addrmask = {
1983*bbb1b6f9SApple OSS Distributions 				.sin6_family = AF_INET6,
1984*bbb1b6f9SApple OSS Distributions 				.sin6_addr = IN6MASK16,
1985*bbb1b6f9SApple OSS Distributions 				.sin6_len    = sizeof(struct sockaddr_in6)
1986*bbb1b6f9SApple OSS Distributions 			},
1987*bbb1b6f9SApple OSS Distributions 			.preced   = 1,
1988*bbb1b6f9SApple OSS Distributions 			.label    = 11
1989*bbb1b6f9SApple OSS Distributions 		},
1990*bbb1b6f9SApple OSS Distributions 
1991*bbb1b6f9SApple OSS Distributions 		/* 6bone (deprecated) -- prefix=3ffe::/16, precedence=1, label=12 */
1992*bbb1b6f9SApple OSS Distributions 		{
1993*bbb1b6f9SApple OSS Distributions 			.addr = {
1994*bbb1b6f9SApple OSS Distributions 				.sin6_family = AF_INET6,
1995*bbb1b6f9SApple OSS Distributions 				.sin6_addr = {{{ 0x3f, 0xfe }}},
1996*bbb1b6f9SApple OSS Distributions 				.sin6_len    = sizeof(struct sockaddr_in6)
1997*bbb1b6f9SApple OSS Distributions 			},
1998*bbb1b6f9SApple OSS Distributions 			.addrmask = {
1999*bbb1b6f9SApple OSS Distributions 				.sin6_family = AF_INET6,
2000*bbb1b6f9SApple OSS Distributions 				.sin6_addr = IN6MASK16,
2001*bbb1b6f9SApple OSS Distributions 				.sin6_len    = sizeof(struct sockaddr_in6)
2002*bbb1b6f9SApple OSS Distributions 			},
2003*bbb1b6f9SApple OSS Distributions 			.preced   = 1,
2004*bbb1b6f9SApple OSS Distributions 			.label    = 12
2005*bbb1b6f9SApple OSS Distributions 		},
2006*bbb1b6f9SApple OSS Distributions 	};
2007*bbb1b6f9SApple OSS Distributions 	int i;
2008*bbb1b6f9SApple OSS Distributions 
2009*bbb1b6f9SApple OSS Distributions 	init_policy_queue();
2010*bbb1b6f9SApple OSS Distributions 
2011*bbb1b6f9SApple OSS Distributions 	/* initialize the "last resort" policy */
2012*bbb1b6f9SApple OSS Distributions 	bzero(&defaultaddrpolicy, sizeof(defaultaddrpolicy));
2013*bbb1b6f9SApple OSS Distributions 	defaultaddrpolicy.label = ADDR_LABEL_NOTAPP;
2014*bbb1b6f9SApple OSS Distributions 
2015*bbb1b6f9SApple OSS Distributions 	for (i = 0; i < sizeof(defaddrsel) / sizeof(defaddrsel[0]); i++) {
2016*bbb1b6f9SApple OSS Distributions 		add_addrsel_policyent(&defaddrsel[i]);
2017*bbb1b6f9SApple OSS Distributions 	}
2018*bbb1b6f9SApple OSS Distributions }
2019*bbb1b6f9SApple OSS Distributions 
2020*bbb1b6f9SApple OSS Distributions struct in6_addrpolicy *
in6_addrsel_lookup_policy(struct sockaddr_in6 * key)2021*bbb1b6f9SApple OSS Distributions in6_addrsel_lookup_policy(struct sockaddr_in6 *key)
2022*bbb1b6f9SApple OSS Distributions {
2023*bbb1b6f9SApple OSS Distributions 	struct in6_addrpolicy *__single match = NULL;
2024*bbb1b6f9SApple OSS Distributions 
2025*bbb1b6f9SApple OSS Distributions 	match = match_addrsel_policy(key);
2026*bbb1b6f9SApple OSS Distributions 
2027*bbb1b6f9SApple OSS Distributions 	if (match == NULL) {
2028*bbb1b6f9SApple OSS Distributions 		match = &defaultaddrpolicy;
2029*bbb1b6f9SApple OSS Distributions 	} else {
2030*bbb1b6f9SApple OSS Distributions 		match->use++;
2031*bbb1b6f9SApple OSS Distributions 	}
2032*bbb1b6f9SApple OSS Distributions 
2033*bbb1b6f9SApple OSS Distributions 	return match;
2034*bbb1b6f9SApple OSS Distributions }
2035*bbb1b6f9SApple OSS Distributions 
2036*bbb1b6f9SApple OSS Distributions static struct in6_addrpolicy *
match_addrsel_policy(struct sockaddr_in6 * key)2037*bbb1b6f9SApple OSS Distributions match_addrsel_policy(struct sockaddr_in6 *key)
2038*bbb1b6f9SApple OSS Distributions {
2039*bbb1b6f9SApple OSS Distributions 	struct addrsel_policyent *__single pent;
2040*bbb1b6f9SApple OSS Distributions 	struct in6_addrpolicy *__single bestpol = NULL, *__single pol;
2041*bbb1b6f9SApple OSS Distributions 	int matchlen, bestmatchlen = -1;
2042*bbb1b6f9SApple OSS Distributions 	u_char *mp, *ep, *k, *p, m;
2043*bbb1b6f9SApple OSS Distributions 
2044*bbb1b6f9SApple OSS Distributions 	TAILQ_FOREACH(pent, &addrsel_policytab, ape_entry) {
2045*bbb1b6f9SApple OSS Distributions 		matchlen = 0;
2046*bbb1b6f9SApple OSS Distributions 
2047*bbb1b6f9SApple OSS Distributions 		pol = &pent->ape_policy;
2048*bbb1b6f9SApple OSS Distributions 		mp = (u_char *)&pol->addrmask.sin6_addr;
2049*bbb1b6f9SApple OSS Distributions 		ep = mp + 16;   /* XXX: scope field? */
2050*bbb1b6f9SApple OSS Distributions 		k = (u_char *)&key->sin6_addr;
2051*bbb1b6f9SApple OSS Distributions 		p = (u_char *)&pol->addr.sin6_addr;
2052*bbb1b6f9SApple OSS Distributions 		for (; mp < ep && *mp; mp++, k++, p++) {
2053*bbb1b6f9SApple OSS Distributions 			m = *mp;
2054*bbb1b6f9SApple OSS Distributions 			if ((*k & m) != *p) {
2055*bbb1b6f9SApple OSS Distributions 				goto next; /* not match */
2056*bbb1b6f9SApple OSS Distributions 			}
2057*bbb1b6f9SApple OSS Distributions 			if (m == 0xff) { /* short cut for a typical case */
2058*bbb1b6f9SApple OSS Distributions 				matchlen += 8;
2059*bbb1b6f9SApple OSS Distributions 			} else {
2060*bbb1b6f9SApple OSS Distributions 				while (m >= 0x80) {
2061*bbb1b6f9SApple OSS Distributions 					matchlen++;
2062*bbb1b6f9SApple OSS Distributions 					m = (u_char)(m << 1);
2063*bbb1b6f9SApple OSS Distributions 				}
2064*bbb1b6f9SApple OSS Distributions 			}
2065*bbb1b6f9SApple OSS Distributions 		}
2066*bbb1b6f9SApple OSS Distributions 
2067*bbb1b6f9SApple OSS Distributions 		/* matched.  check if this is better than the current best. */
2068*bbb1b6f9SApple OSS Distributions 		if (bestpol == NULL ||
2069*bbb1b6f9SApple OSS Distributions 		    matchlen > bestmatchlen) {
2070*bbb1b6f9SApple OSS Distributions 			bestpol = pol;
2071*bbb1b6f9SApple OSS Distributions 			bestmatchlen = matchlen;
2072*bbb1b6f9SApple OSS Distributions 		}
2073*bbb1b6f9SApple OSS Distributions 
2074*bbb1b6f9SApple OSS Distributions next:
2075*bbb1b6f9SApple OSS Distributions 		continue;
2076*bbb1b6f9SApple OSS Distributions 	}
2077*bbb1b6f9SApple OSS Distributions 
2078*bbb1b6f9SApple OSS Distributions 	return bestpol;
2079*bbb1b6f9SApple OSS Distributions }
2080*bbb1b6f9SApple OSS Distributions 
2081*bbb1b6f9SApple OSS Distributions static int
add_addrsel_policyent(const struct in6_addrpolicy * newpolicy)2082*bbb1b6f9SApple OSS Distributions add_addrsel_policyent(const struct in6_addrpolicy *newpolicy)
2083*bbb1b6f9SApple OSS Distributions {
2084*bbb1b6f9SApple OSS Distributions 	struct addrsel_policyent *__single new, *__single pol;
2085*bbb1b6f9SApple OSS Distributions 
2086*bbb1b6f9SApple OSS Distributions 	new = kalloc_type(struct addrsel_policyent, Z_WAITOK | Z_ZERO);
2087*bbb1b6f9SApple OSS Distributions 
2088*bbb1b6f9SApple OSS Distributions 	/* duplication check */
2089*bbb1b6f9SApple OSS Distributions 	TAILQ_FOREACH(pol, &addrsel_policytab, ape_entry) {
2090*bbb1b6f9SApple OSS Distributions 		if (IN6_ARE_ADDR_EQUAL(&newpolicy->addr.sin6_addr,
2091*bbb1b6f9SApple OSS Distributions 		    &pol->ape_policy.addr.sin6_addr) &&
2092*bbb1b6f9SApple OSS Distributions 		    IN6_ARE_ADDR_EQUAL(&newpolicy->addrmask.sin6_addr,
2093*bbb1b6f9SApple OSS Distributions 		    &pol->ape_policy.addrmask.sin6_addr)) {
2094*bbb1b6f9SApple OSS Distributions 			kfree_type(struct addrsel_policyent, new);
2095*bbb1b6f9SApple OSS Distributions 			return EEXIST;        /* or override it? */
2096*bbb1b6f9SApple OSS Distributions 		}
2097*bbb1b6f9SApple OSS Distributions 	}
2098*bbb1b6f9SApple OSS Distributions 
2099*bbb1b6f9SApple OSS Distributions 	/* XXX: should validate entry */
2100*bbb1b6f9SApple OSS Distributions 	new->ape_policy = *newpolicy;
2101*bbb1b6f9SApple OSS Distributions 
2102*bbb1b6f9SApple OSS Distributions 	TAILQ_INSERT_TAIL(&addrsel_policytab, new, ape_entry);
2103*bbb1b6f9SApple OSS Distributions 
2104*bbb1b6f9SApple OSS Distributions 	return 0;
2105*bbb1b6f9SApple OSS Distributions }
2106*bbb1b6f9SApple OSS Distributions 
2107*bbb1b6f9SApple OSS Distributions int
walk_addrsel_policy(int (* callback)(const struct in6_addrpolicy *,void *),void * w)2108*bbb1b6f9SApple OSS Distributions walk_addrsel_policy(int (*callback)(const struct in6_addrpolicy *, void *),
2109*bbb1b6f9SApple OSS Distributions     void *w)
2110*bbb1b6f9SApple OSS Distributions {
2111*bbb1b6f9SApple OSS Distributions 	struct addrsel_policyent *__single pol;
2112*bbb1b6f9SApple OSS Distributions 	int error = 0;
2113*bbb1b6f9SApple OSS Distributions 
2114*bbb1b6f9SApple OSS Distributions 	TAILQ_FOREACH(pol, &addrsel_policytab, ape_entry) {
2115*bbb1b6f9SApple OSS Distributions 		if ((error = (*callback)(&pol->ape_policy, w)) != 0) {
2116*bbb1b6f9SApple OSS Distributions 			return error;
2117*bbb1b6f9SApple OSS Distributions 		}
2118*bbb1b6f9SApple OSS Distributions 	}
2119*bbb1b6f9SApple OSS Distributions 	return error;
2120*bbb1b6f9SApple OSS Distributions }
2121*bbb1b6f9SApple OSS Distributions /*
2122*bbb1b6f9SApple OSS Distributions  * Subroutines to manage the address selection policy table via sysctl.
2123*bbb1b6f9SApple OSS Distributions  */
2124*bbb1b6f9SApple OSS Distributions struct walkarg {
2125*bbb1b6f9SApple OSS Distributions 	struct sysctl_req *w_req;
2126*bbb1b6f9SApple OSS Distributions };
2127*bbb1b6f9SApple OSS Distributions 
2128*bbb1b6f9SApple OSS Distributions 
2129*bbb1b6f9SApple OSS Distributions static int
dump_addrsel_policyent(const struct in6_addrpolicy * pol,void * arg)2130*bbb1b6f9SApple OSS Distributions dump_addrsel_policyent(const struct in6_addrpolicy *pol, void *arg)
2131*bbb1b6f9SApple OSS Distributions {
2132*bbb1b6f9SApple OSS Distributions 	int error = 0;
2133*bbb1b6f9SApple OSS Distributions 	struct walkarg *__single w = arg;
2134*bbb1b6f9SApple OSS Distributions 
2135*bbb1b6f9SApple OSS Distributions 	error = SYSCTL_OUT(w->w_req, pol, sizeof(*pol));
2136*bbb1b6f9SApple OSS Distributions 
2137*bbb1b6f9SApple OSS Distributions 	return error;
2138*bbb1b6f9SApple OSS Distributions }
2139*bbb1b6f9SApple OSS Distributions 
2140*bbb1b6f9SApple OSS Distributions static int
2141*bbb1b6f9SApple OSS Distributions in6_src_sysctl SYSCTL_HANDLER_ARGS
2142*bbb1b6f9SApple OSS Distributions {
2143*bbb1b6f9SApple OSS Distributions #pragma unused(oidp, arg1, arg2)
2144*bbb1b6f9SApple OSS Distributions 	struct walkarg w;
2145*bbb1b6f9SApple OSS Distributions 
2146*bbb1b6f9SApple OSS Distributions 	if (req->newptr) {
2147*bbb1b6f9SApple OSS Distributions 		return EPERM;
2148*bbb1b6f9SApple OSS Distributions 	}
2149*bbb1b6f9SApple OSS Distributions 	bzero(&w, sizeof(w));
2150*bbb1b6f9SApple OSS Distributions 	w.w_req = req;
2151*bbb1b6f9SApple OSS Distributions 
2152*bbb1b6f9SApple OSS Distributions 	return walk_addrsel_policy(dump_addrsel_policyent, &w);
2153*bbb1b6f9SApple OSS Distributions }
2154*bbb1b6f9SApple OSS Distributions 
2155*bbb1b6f9SApple OSS Distributions 
2156*bbb1b6f9SApple OSS Distributions SYSCTL_NODE(_net_inet6_ip6, IPV6CTL_ADDRCTLPOLICY, addrctlpolicy,
2157*bbb1b6f9SApple OSS Distributions     CTLFLAG_RD | CTLFLAG_LOCKED, in6_src_sysctl, "");
2158*bbb1b6f9SApple OSS Distributions int
in6_src_ioctl(u_long cmd,caddr_t __sized_by (IOCPARM_LEN (cmd))data)2159*bbb1b6f9SApple OSS Distributions in6_src_ioctl(u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)) data)
2160*bbb1b6f9SApple OSS Distributions {
2161*bbb1b6f9SApple OSS Distributions 	int i;
2162*bbb1b6f9SApple OSS Distributions 	struct in6_addrpolicy ent0;
2163*bbb1b6f9SApple OSS Distributions 
2164*bbb1b6f9SApple OSS Distributions 	if (cmd != SIOCAADDRCTL_POLICY && cmd != SIOCDADDRCTL_POLICY) {
2165*bbb1b6f9SApple OSS Distributions 		return EOPNOTSUPP; /* check for safety */
2166*bbb1b6f9SApple OSS Distributions 	}
2167*bbb1b6f9SApple OSS Distributions 	bcopy(data, &ent0, sizeof(ent0));
2168*bbb1b6f9SApple OSS Distributions 
2169*bbb1b6f9SApple OSS Distributions 	if (ent0.label == ADDR_LABEL_NOTAPP) {
2170*bbb1b6f9SApple OSS Distributions 		return EINVAL;
2171*bbb1b6f9SApple OSS Distributions 	}
2172*bbb1b6f9SApple OSS Distributions 	/* check if the prefix mask is consecutive. */
2173*bbb1b6f9SApple OSS Distributions 	if (in6_mask2len(&ent0.addrmask.sin6_addr, NULL) < 0) {
2174*bbb1b6f9SApple OSS Distributions 		return EINVAL;
2175*bbb1b6f9SApple OSS Distributions 	}
2176*bbb1b6f9SApple OSS Distributions 	/* clear trailing garbages (if any) of the prefix address. */
2177*bbb1b6f9SApple OSS Distributions 	for (i = 0; i < 4; i++) {
2178*bbb1b6f9SApple OSS Distributions 		ent0.addr.sin6_addr.s6_addr32[i] &=
2179*bbb1b6f9SApple OSS Distributions 		    ent0.addrmask.sin6_addr.s6_addr32[i];
2180*bbb1b6f9SApple OSS Distributions 	}
2181*bbb1b6f9SApple OSS Distributions 	ent0.use = 0;
2182*bbb1b6f9SApple OSS Distributions 
2183*bbb1b6f9SApple OSS Distributions 	switch (cmd) {
2184*bbb1b6f9SApple OSS Distributions 	case SIOCAADDRCTL_POLICY:
2185*bbb1b6f9SApple OSS Distributions 		return ENOTSUP;
2186*bbb1b6f9SApple OSS Distributions 	case SIOCDADDRCTL_POLICY:
2187*bbb1b6f9SApple OSS Distributions 		return ENOTSUP;
2188*bbb1b6f9SApple OSS Distributions 	}
2189*bbb1b6f9SApple OSS Distributions 
2190*bbb1b6f9SApple OSS Distributions 	return 0;             /* XXX: compromise compilers */
2191*bbb1b6f9SApple OSS Distributions }
2192*bbb1b6f9SApple OSS Distributions 
2193*bbb1b6f9SApple OSS Distributions /*
2194*bbb1b6f9SApple OSS Distributions  * generate kernel-internal form (scopeid embedded into s6_addr16[1]).
2195*bbb1b6f9SApple OSS Distributions  * If the address scope of is link-local, embed the interface index in the
2196*bbb1b6f9SApple OSS Distributions  * address.  The routine determines our precedence
2197*bbb1b6f9SApple OSS Distributions  * between advanced API scope/interface specification and basic API
2198*bbb1b6f9SApple OSS Distributions  * specification.
2199*bbb1b6f9SApple OSS Distributions  *
2200*bbb1b6f9SApple OSS Distributions  * this function should be nuked in the future, when we get rid of
2201*bbb1b6f9SApple OSS Distributions  * embedded scopeid thing.
2202*bbb1b6f9SApple OSS Distributions  *
2203*bbb1b6f9SApple OSS Distributions  * XXX actually, it is over-specification to return ifp against sin6_scope_id.
2204*bbb1b6f9SApple OSS Distributions  * there can be multiple interfaces that belong to a particular scope zone
2205*bbb1b6f9SApple OSS Distributions  * (in specification, we have 1:N mapping between a scope zone and interfaces).
2206*bbb1b6f9SApple OSS Distributions  * we may want to change the function to return something other than ifp.
2207*bbb1b6f9SApple OSS Distributions  */
2208*bbb1b6f9SApple OSS Distributions int
in6_embedscope(struct in6_addr * in6,const struct sockaddr_in6 * sin6,struct in6pcb * in6p,struct ifnet ** ifpp,struct ip6_pktopts * opt,uint32_t * ret_ifscope)2209*bbb1b6f9SApple OSS Distributions in6_embedscope(struct in6_addr *in6, const struct sockaddr_in6 *sin6,
2210*bbb1b6f9SApple OSS Distributions     struct in6pcb *in6p, struct ifnet **ifpp, struct ip6_pktopts *opt, uint32_t *ret_ifscope)
2211*bbb1b6f9SApple OSS Distributions {
2212*bbb1b6f9SApple OSS Distributions 	struct ifnet *__single ifp = NULL;
2213*bbb1b6f9SApple OSS Distributions 	u_int32_t scopeid;
2214*bbb1b6f9SApple OSS Distributions 	struct ip6_pktopts *__single optp = NULL;
2215*bbb1b6f9SApple OSS Distributions 
2216*bbb1b6f9SApple OSS Distributions 	*in6 = sin6->sin6_addr;
2217*bbb1b6f9SApple OSS Distributions 	scopeid = sin6->sin6_scope_id;
2218*bbb1b6f9SApple OSS Distributions 	if (ifpp != NULL) {
2219*bbb1b6f9SApple OSS Distributions 		*ifpp = NULL;
2220*bbb1b6f9SApple OSS Distributions 	}
2221*bbb1b6f9SApple OSS Distributions 
2222*bbb1b6f9SApple OSS Distributions 	/*
2223*bbb1b6f9SApple OSS Distributions 	 * don't try to read sin6->sin6_addr beyond here, since the caller may
2224*bbb1b6f9SApple OSS Distributions 	 * ask us to overwrite existing sockaddr_in6
2225*bbb1b6f9SApple OSS Distributions 	 */
2226*bbb1b6f9SApple OSS Distributions 
2227*bbb1b6f9SApple OSS Distributions #ifdef ENABLE_DEFAULT_SCOPE
2228*bbb1b6f9SApple OSS Distributions 	if (scopeid == 0) {
2229*bbb1b6f9SApple OSS Distributions 		scopeid = scope6_addr2default(in6);
2230*bbb1b6f9SApple OSS Distributions 	}
2231*bbb1b6f9SApple OSS Distributions #endif
2232*bbb1b6f9SApple OSS Distributions 
2233*bbb1b6f9SApple OSS Distributions 	if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6)) {
2234*bbb1b6f9SApple OSS Distributions 		struct in6_pktinfo *__single pi;
2235*bbb1b6f9SApple OSS Distributions 		struct ifnet *__single im6o_multicast_ifp = NULL;
2236*bbb1b6f9SApple OSS Distributions 
2237*bbb1b6f9SApple OSS Distributions 		if (in6p != NULL && IN6_IS_ADDR_MULTICAST(in6) &&
2238*bbb1b6f9SApple OSS Distributions 		    in6p->in6p_moptions != NULL) {
2239*bbb1b6f9SApple OSS Distributions 			IM6O_LOCK(in6p->in6p_moptions);
2240*bbb1b6f9SApple OSS Distributions 			im6o_multicast_ifp =
2241*bbb1b6f9SApple OSS Distributions 			    in6p->in6p_moptions->im6o_multicast_ifp;
2242*bbb1b6f9SApple OSS Distributions 			IM6O_UNLOCK(in6p->in6p_moptions);
2243*bbb1b6f9SApple OSS Distributions 		}
2244*bbb1b6f9SApple OSS Distributions 
2245*bbb1b6f9SApple OSS Distributions 		if (opt != NULL) {
2246*bbb1b6f9SApple OSS Distributions 			optp = opt;
2247*bbb1b6f9SApple OSS Distributions 		} else if (in6p != NULL) {
2248*bbb1b6f9SApple OSS Distributions 			optp = in6p->in6p_outputopts;
2249*bbb1b6f9SApple OSS Distributions 		}
2250*bbb1b6f9SApple OSS Distributions 		/*
2251*bbb1b6f9SApple OSS Distributions 		 * KAME assumption: link id == interface id
2252*bbb1b6f9SApple OSS Distributions 		 */
2253*bbb1b6f9SApple OSS Distributions 		if (in6p != NULL && optp != NULL &&
2254*bbb1b6f9SApple OSS Distributions 		    (pi = optp->ip6po_pktinfo) != NULL &&
2255*bbb1b6f9SApple OSS Distributions 		    pi->ipi6_ifindex != 0) {
2256*bbb1b6f9SApple OSS Distributions 			/* ifp is needed here if only we're returning it */
2257*bbb1b6f9SApple OSS Distributions 			if (ifpp != NULL) {
2258*bbb1b6f9SApple OSS Distributions 				ifnet_head_lock_shared();
2259*bbb1b6f9SApple OSS Distributions 				ifp = ifindex2ifnet[pi->ipi6_ifindex];
2260*bbb1b6f9SApple OSS Distributions 				ifnet_head_done();
2261*bbb1b6f9SApple OSS Distributions 			}
2262*bbb1b6f9SApple OSS Distributions 
2263*bbb1b6f9SApple OSS Distributions 			if (in6_embedded_scope) {
2264*bbb1b6f9SApple OSS Distributions 				in6->s6_addr16[1] = htons((uint16_t)pi->ipi6_ifindex);
2265*bbb1b6f9SApple OSS Distributions 			}
2266*bbb1b6f9SApple OSS Distributions 			if (ret_ifscope != NULL) {
2267*bbb1b6f9SApple OSS Distributions 				*ret_ifscope = pi->ipi6_ifindex;
2268*bbb1b6f9SApple OSS Distributions 			}
2269*bbb1b6f9SApple OSS Distributions 		} else if (in6p != NULL && IN6_IS_ADDR_MULTICAST(in6) &&
2270*bbb1b6f9SApple OSS Distributions 		    in6p->in6p_moptions != NULL && im6o_multicast_ifp != NULL) {
2271*bbb1b6f9SApple OSS Distributions 			ifp = im6o_multicast_ifp;
2272*bbb1b6f9SApple OSS Distributions 			if (in6_embedded_scope) {
2273*bbb1b6f9SApple OSS Distributions 				in6->s6_addr16[1] = htons(ifp->if_index);
2274*bbb1b6f9SApple OSS Distributions 			}
2275*bbb1b6f9SApple OSS Distributions 			if (ret_ifscope != NULL) {
2276*bbb1b6f9SApple OSS Distributions 				*ret_ifscope = ifp->if_index;
2277*bbb1b6f9SApple OSS Distributions 			}
2278*bbb1b6f9SApple OSS Distributions 		} else if (scopeid != 0) {
2279*bbb1b6f9SApple OSS Distributions 			/*
2280*bbb1b6f9SApple OSS Distributions 			 * Since scopeid is unsigned, we only have to check it
2281*bbb1b6f9SApple OSS Distributions 			 * against if_index (ifnet_head_lock not needed since
2282*bbb1b6f9SApple OSS Distributions 			 * if_index is an ever-increasing integer.)
2283*bbb1b6f9SApple OSS Distributions 			 */
2284*bbb1b6f9SApple OSS Distributions 			if (!IF_INDEX_IN_RANGE(scopeid)) {
2285*bbb1b6f9SApple OSS Distributions 				return ENXIO;  /* XXX EINVAL? */
2286*bbb1b6f9SApple OSS Distributions 			}
2287*bbb1b6f9SApple OSS Distributions 			/* ifp is needed here only if we're returning it */
2288*bbb1b6f9SApple OSS Distributions 			if (ifpp != NULL) {
2289*bbb1b6f9SApple OSS Distributions 				ifnet_head_lock_shared();
2290*bbb1b6f9SApple OSS Distributions 				ifp = ifindex2ifnet[scopeid];
2291*bbb1b6f9SApple OSS Distributions 				ifnet_head_done();
2292*bbb1b6f9SApple OSS Distributions 			}
2293*bbb1b6f9SApple OSS Distributions 			if (in6_embedded_scope) {
2294*bbb1b6f9SApple OSS Distributions 				/* XXX assignment to 16bit from 32bit variable */
2295*bbb1b6f9SApple OSS Distributions 				in6->s6_addr16[1] = htons(scopeid & 0xffff);
2296*bbb1b6f9SApple OSS Distributions 			}
2297*bbb1b6f9SApple OSS Distributions 			if (ret_ifscope != NULL) {
2298*bbb1b6f9SApple OSS Distributions 				*ret_ifscope = scopeid;
2299*bbb1b6f9SApple OSS Distributions 			}
2300*bbb1b6f9SApple OSS Distributions 		}
2301*bbb1b6f9SApple OSS Distributions 
2302*bbb1b6f9SApple OSS Distributions 		if (ifpp != NULL) {
2303*bbb1b6f9SApple OSS Distributions 			if (ifp != NULL) {
2304*bbb1b6f9SApple OSS Distributions 				ifnet_reference(ifp);   /* for caller */
2305*bbb1b6f9SApple OSS Distributions 			}
2306*bbb1b6f9SApple OSS Distributions 			*ifpp = ifp;
2307*bbb1b6f9SApple OSS Distributions 		}
2308*bbb1b6f9SApple OSS Distributions 	}
2309*bbb1b6f9SApple OSS Distributions 
2310*bbb1b6f9SApple OSS Distributions 	return 0;
2311*bbb1b6f9SApple OSS Distributions }
2312*bbb1b6f9SApple OSS Distributions 
2313*bbb1b6f9SApple OSS Distributions /*
2314*bbb1b6f9SApple OSS Distributions  * generate standard sockaddr_in6 from embedded form.
2315*bbb1b6f9SApple OSS Distributions  * touches sin6_addr and sin6_scope_id only.
2316*bbb1b6f9SApple OSS Distributions  *
2317*bbb1b6f9SApple OSS Distributions  * this function should be nuked in the future, when we get rid of
2318*bbb1b6f9SApple OSS Distributions  * embedded scopeid thing.
2319*bbb1b6f9SApple OSS Distributions  */
2320*bbb1b6f9SApple OSS Distributions int
in6_recoverscope(struct sockaddr_in6 * sin6,const struct in6_addr * in6,struct ifnet * ifp)2321*bbb1b6f9SApple OSS Distributions in6_recoverscope(
2322*bbb1b6f9SApple OSS Distributions 	struct sockaddr_in6 *sin6,
2323*bbb1b6f9SApple OSS Distributions 	const struct in6_addr *in6,
2324*bbb1b6f9SApple OSS Distributions 	struct ifnet *ifp)
2325*bbb1b6f9SApple OSS Distributions {
2326*bbb1b6f9SApple OSS Distributions 	u_int32_t scopeid;
2327*bbb1b6f9SApple OSS Distributions 
2328*bbb1b6f9SApple OSS Distributions 	sin6->sin6_addr = *in6;
2329*bbb1b6f9SApple OSS Distributions 
2330*bbb1b6f9SApple OSS Distributions 	if (!in6_embedded_scope) {
2331*bbb1b6f9SApple OSS Distributions 		if (ifp != NULL && IN6_IS_SCOPE_EMBED(in6)) {
2332*bbb1b6f9SApple OSS Distributions 			sin6->sin6_scope_id = ifp->if_index;
2333*bbb1b6f9SApple OSS Distributions 		}
2334*bbb1b6f9SApple OSS Distributions 		return 0;
2335*bbb1b6f9SApple OSS Distributions 	}
2336*bbb1b6f9SApple OSS Distributions 	/*
2337*bbb1b6f9SApple OSS Distributions 	 * don't try to read *in6 beyond here, since the caller may
2338*bbb1b6f9SApple OSS Distributions 	 * ask us to overwrite existing sockaddr_in6
2339*bbb1b6f9SApple OSS Distributions 	 */
2340*bbb1b6f9SApple OSS Distributions 
2341*bbb1b6f9SApple OSS Distributions 	sin6->sin6_scope_id = 0;
2342*bbb1b6f9SApple OSS Distributions 	if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6)) {
2343*bbb1b6f9SApple OSS Distributions 		/*
2344*bbb1b6f9SApple OSS Distributions 		 * KAME assumption: link id == interface id
2345*bbb1b6f9SApple OSS Distributions 		 */
2346*bbb1b6f9SApple OSS Distributions 		scopeid = ntohs(sin6->sin6_addr.s6_addr16[1]);
2347*bbb1b6f9SApple OSS Distributions 		if (scopeid) {
2348*bbb1b6f9SApple OSS Distributions 			/*
2349*bbb1b6f9SApple OSS Distributions 			 * sanity check
2350*bbb1b6f9SApple OSS Distributions 			 *
2351*bbb1b6f9SApple OSS Distributions 			 * Since scopeid is unsigned, we only have to check it
2352*bbb1b6f9SApple OSS Distributions 			 * against if_index
2353*bbb1b6f9SApple OSS Distributions 			 */
2354*bbb1b6f9SApple OSS Distributions 			if (!IF_INDEX_IN_RANGE(scopeid)) {
2355*bbb1b6f9SApple OSS Distributions 				return ENXIO;
2356*bbb1b6f9SApple OSS Distributions 			}
2357*bbb1b6f9SApple OSS Distributions 			if (ifp && ifp->if_index != scopeid) {
2358*bbb1b6f9SApple OSS Distributions 				return ENXIO;
2359*bbb1b6f9SApple OSS Distributions 			}
2360*bbb1b6f9SApple OSS Distributions 			sin6->sin6_addr.s6_addr16[1] = 0;
2361*bbb1b6f9SApple OSS Distributions 			sin6->sin6_scope_id = scopeid;
2362*bbb1b6f9SApple OSS Distributions 		}
2363*bbb1b6f9SApple OSS Distributions 	}
2364*bbb1b6f9SApple OSS Distributions 
2365*bbb1b6f9SApple OSS Distributions 	return 0;
2366*bbb1b6f9SApple OSS Distributions }
2367