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