xref: /xnu-12377.41.6/bsd/net/netsrc.c (revision bbb1b6f9e71b8cdde6e5cd6f4841f207dee3d828)
1*bbb1b6f9SApple OSS Distributions /*
2*bbb1b6f9SApple OSS Distributions  * Copyright (c) 2011-2017 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 // Include netinet/in.h first. net/netsrc.h depends on netinet/in.h but
30*bbb1b6f9SApple OSS Distributions // netinet/in.h doesn't work with -Wpadded, -Wpacked.
31*bbb1b6f9SApple OSS Distributions #include <netinet/in.h>
32*bbb1b6f9SApple OSS Distributions 
33*bbb1b6f9SApple OSS Distributions #pragma clang diagnostic push
34*bbb1b6f9SApple OSS Distributions #pragma clang diagnostic error "-Wpadded"
35*bbb1b6f9SApple OSS Distributions #pragma clang diagnostic error "-Wpacked"
36*bbb1b6f9SApple OSS Distributions // This header defines structures shared with user space, so we need to ensure there is
37*bbb1b6f9SApple OSS Distributions // no compiler inserted padding in case the user space process isn't using the same
38*bbb1b6f9SApple OSS Distributions // architecture as the kernel (example: i386 process with x86_64 kernel).
39*bbb1b6f9SApple OSS Distributions #include <net/netsrc.h>
40*bbb1b6f9SApple OSS Distributions #pragma clang diagnostic pop
41*bbb1b6f9SApple OSS Distributions 
42*bbb1b6f9SApple OSS Distributions #include <sys/param.h>
43*bbb1b6f9SApple OSS Distributions #include <sys/types.h>
44*bbb1b6f9SApple OSS Distributions #include <sys/kpi_mbuf.h>
45*bbb1b6f9SApple OSS Distributions #include <sys/socket.h>
46*bbb1b6f9SApple OSS Distributions #include <sys/kern_control.h>
47*bbb1b6f9SApple OSS Distributions #include <sys/mcache.h>
48*bbb1b6f9SApple OSS Distributions #include <sys/socketvar.h>
49*bbb1b6f9SApple OSS Distributions 
50*bbb1b6f9SApple OSS Distributions #include <kern/debug.h>
51*bbb1b6f9SApple OSS Distributions 
52*bbb1b6f9SApple OSS Distributions #include <libkern/libkern.h>
53*bbb1b6f9SApple OSS Distributions 
54*bbb1b6f9SApple OSS Distributions #include <net/if.h>
55*bbb1b6f9SApple OSS Distributions #include <net/route.h>
56*bbb1b6f9SApple OSS Distributions 
57*bbb1b6f9SApple OSS Distributions #include <netinet/in.h>
58*bbb1b6f9SApple OSS Distributions #include <netinet/ip.h>
59*bbb1b6f9SApple OSS Distributions #include <netinet/ip_var.h>
60*bbb1b6f9SApple OSS Distributions #include <netinet/in_var.h>
61*bbb1b6f9SApple OSS Distributions #include <netinet/ip6.h>
62*bbb1b6f9SApple OSS Distributions #include <netinet6/ip6_var.h>
63*bbb1b6f9SApple OSS Distributions 
64*bbb1b6f9SApple OSS Distributions #include <net/ntstat.h>
65*bbb1b6f9SApple OSS Distributions 
66*bbb1b6f9SApple OSS Distributions static errno_t
netsrc_ctlconnect(kern_ctl_ref kctl,struct sockaddr_ctl * sac,void ** uinfo)67*bbb1b6f9SApple OSS Distributions netsrc_ctlconnect(kern_ctl_ref kctl, struct sockaddr_ctl *sac, void **uinfo)
68*bbb1b6f9SApple OSS Distributions {
69*bbb1b6f9SApple OSS Distributions #pragma unused(kctl, sac, uinfo)
70*bbb1b6f9SApple OSS Distributions 
71*bbb1b6f9SApple OSS Distributions 	/*
72*bbb1b6f9SApple OSS Distributions 	 * We don't need to do anything here. This callback is only necessary
73*bbb1b6f9SApple OSS Distributions 	 * for ctl_register() to succeed.
74*bbb1b6f9SApple OSS Distributions 	 */
75*bbb1b6f9SApple OSS Distributions 	return 0;
76*bbb1b6f9SApple OSS Distributions }
77*bbb1b6f9SApple OSS Distributions 
78*bbb1b6f9SApple OSS Distributions static errno_t
netsrc_reply(kern_ctl_ref kctl,uint32_t unit,unsigned int version,struct netsrc_rep * reply)79*bbb1b6f9SApple OSS Distributions netsrc_reply(kern_ctl_ref kctl, uint32_t unit, unsigned int version,
80*bbb1b6f9SApple OSS Distributions     struct netsrc_rep *reply)
81*bbb1b6f9SApple OSS Distributions {
82*bbb1b6f9SApple OSS Distributions 	switch (version) {
83*bbb1b6f9SApple OSS Distributions 	case NETSRC_CURVERS:
84*bbb1b6f9SApple OSS Distributions 		return ctl_enqueuedata(kctl, unit, reply,
85*bbb1b6f9SApple OSS Distributions 		           sizeof(*reply), CTL_DATA_EOR);
86*bbb1b6f9SApple OSS Distributions 	case NETSRC_VERSION1: {
87*bbb1b6f9SApple OSS Distributions 		if ((reply->nrp_flags & NETSRC_FLAG_ROUTEABLE) == 0) {
88*bbb1b6f9SApple OSS Distributions 			return EHOSTUNREACH;
89*bbb1b6f9SApple OSS Distributions 		}
90*bbb1b6f9SApple OSS Distributions #define NETSRC_FLAG_V1_MASK (NETSRC_IP6_FLAG_TENTATIVE | \
91*bbb1b6f9SApple OSS Distributions 	                                                 NETSRC_IP6_FLAG_TEMPORARY | \
92*bbb1b6f9SApple OSS Distributions 	                                                 NETSRC_IP6_FLAG_DEPRECATED | \
93*bbb1b6f9SApple OSS Distributions 	                                                 NETSRC_IP6_FLAG_OPTIMISTIC | \
94*bbb1b6f9SApple OSS Distributions 	                                                 NETSRC_IP6_FLAG_SECURED)
95*bbb1b6f9SApple OSS Distributions 		struct netsrc_repv1 v1 = {
96*bbb1b6f9SApple OSS Distributions 			.nrp_src = reply->nrp_src,
97*bbb1b6f9SApple OSS Distributions 			.nrp_flags = (reply->nrp_flags & NETSRC_FLAG_V1_MASK),
98*bbb1b6f9SApple OSS Distributions 			.nrp_label = reply->nrp_label,
99*bbb1b6f9SApple OSS Distributions 			.nrp_precedence = reply->nrp_precedence,
100*bbb1b6f9SApple OSS Distributions 			.nrp_dstlabel = reply->nrp_dstlabel,
101*bbb1b6f9SApple OSS Distributions 			.nrp_dstprecedence = reply->nrp_dstprecedence
102*bbb1b6f9SApple OSS Distributions 		};
103*bbb1b6f9SApple OSS Distributions 		return ctl_enqueuedata(kctl, unit, &v1, sizeof(v1), CTL_DATA_EOR);
104*bbb1b6f9SApple OSS Distributions 	}
105*bbb1b6f9SApple OSS Distributions 	}
106*bbb1b6f9SApple OSS Distributions 	return EINVAL;
107*bbb1b6f9SApple OSS Distributions }
108*bbb1b6f9SApple OSS Distributions 
109*bbb1b6f9SApple OSS Distributions static void
netsrc_common(struct rtentry * rt,struct netsrc_rep * reply)110*bbb1b6f9SApple OSS Distributions netsrc_common(struct rtentry *rt, struct netsrc_rep *reply)
111*bbb1b6f9SApple OSS Distributions {
112*bbb1b6f9SApple OSS Distributions 	if (!rt) {
113*bbb1b6f9SApple OSS Distributions 		return;
114*bbb1b6f9SApple OSS Distributions 	}
115*bbb1b6f9SApple OSS Distributions 
116*bbb1b6f9SApple OSS Distributions 	// Gather statistics information
117*bbb1b6f9SApple OSS Distributions 	struct nstat_counts     *rt_stats = rt->rt_stats;
118*bbb1b6f9SApple OSS Distributions 	if (rt_stats) {
119*bbb1b6f9SApple OSS Distributions 		reply->nrp_min_rtt = rt_stats->nstat_min_rtt;
120*bbb1b6f9SApple OSS Distributions 		reply->nrp_connection_attempts = rt_stats->nstat_connectattempts;
121*bbb1b6f9SApple OSS Distributions 		reply->nrp_connection_successes = rt_stats->nstat_connectsuccesses;
122*bbb1b6f9SApple OSS Distributions 	}
123*bbb1b6f9SApple OSS Distributions 
124*bbb1b6f9SApple OSS Distributions 	// If this route didn't have any stats, check its parent
125*bbb1b6f9SApple OSS Distributions 	if (reply->nrp_min_rtt == 0) {
126*bbb1b6f9SApple OSS Distributions 		// Is this lock necessary?
127*bbb1b6f9SApple OSS Distributions 		RT_LOCK(rt);
128*bbb1b6f9SApple OSS Distributions 		if (rt->rt_parent) {
129*bbb1b6f9SApple OSS Distributions 			rt_stats = rt->rt_parent->rt_stats;
130*bbb1b6f9SApple OSS Distributions 			if (rt_stats) {
131*bbb1b6f9SApple OSS Distributions 				reply->nrp_min_rtt = rt_stats->nstat_min_rtt;
132*bbb1b6f9SApple OSS Distributions 				reply->nrp_connection_attempts = rt_stats->nstat_connectattempts;
133*bbb1b6f9SApple OSS Distributions 				reply->nrp_connection_successes = rt_stats->nstat_connectsuccesses;
134*bbb1b6f9SApple OSS Distributions 			}
135*bbb1b6f9SApple OSS Distributions 		}
136*bbb1b6f9SApple OSS Distributions 		RT_UNLOCK(rt);
137*bbb1b6f9SApple OSS Distributions 	}
138*bbb1b6f9SApple OSS Distributions 	reply->nrp_ifindex = rt->rt_ifp ? rt->rt_ifp->if_index : 0;
139*bbb1b6f9SApple OSS Distributions 
140*bbb1b6f9SApple OSS Distributions 	if (rt->rt_ifp != NULL && (rt->rt_ifp->if_eflags & IFEF_AWDL)) {
141*bbb1b6f9SApple OSS Distributions 		reply->nrp_flags |= NETSRC_FLAG_AWDL;
142*bbb1b6f9SApple OSS Distributions 	}
143*bbb1b6f9SApple OSS Distributions 	if (rt->rt_flags & RTF_LOCAL) {
144*bbb1b6f9SApple OSS Distributions 		reply->nrp_flags |= NETSRC_FLAG_DIRECT;
145*bbb1b6f9SApple OSS Distributions 	} else if (!(rt->rt_flags & RTF_GATEWAY) &&
146*bbb1b6f9SApple OSS Distributions 	    (rt->rt_ifa && rt->rt_ifa->ifa_ifp &&
147*bbb1b6f9SApple OSS Distributions 	    !(rt->rt_ifa->ifa_ifp->if_flags & IFF_POINTOPOINT))) {
148*bbb1b6f9SApple OSS Distributions 		reply->nrp_flags |= NETSRC_FLAG_DIRECT;
149*bbb1b6f9SApple OSS Distributions 	}
150*bbb1b6f9SApple OSS Distributions }
151*bbb1b6f9SApple OSS Distributions 
152*bbb1b6f9SApple OSS Distributions static struct in6_addrpolicy *
lookup_policy(struct sockaddr * sa)153*bbb1b6f9SApple OSS Distributions lookup_policy(struct sockaddr* sa)
154*bbb1b6f9SApple OSS Distributions {
155*bbb1b6f9SApple OSS Distributions 	// alignment fun - if sa_family is AF_INET or AF_INET6, this is one of those
156*bbb1b6f9SApple OSS Distributions 	// addresses and it should be aligned, so this should be safe.
157*bbb1b6f9SApple OSS Distributions 	union sockaddr_in_4_6 *addr = (union sockaddr_in_4_6 *)(void*)sa;
158*bbb1b6f9SApple OSS Distributions 	if (addr->sa.sa_family == AF_INET6) {
159*bbb1b6f9SApple OSS Distributions 		return in6_addrsel_lookup_policy(&addr->sin6);
160*bbb1b6f9SApple OSS Distributions 	} else if (sa->sa_family == AF_INET) {
161*bbb1b6f9SApple OSS Distributions 		struct sockaddr_in6 mapped = {
162*bbb1b6f9SApple OSS Distributions 			.sin6_family = AF_INET6,
163*bbb1b6f9SApple OSS Distributions 			.sin6_len = sizeof(mapped),
164*bbb1b6f9SApple OSS Distributions 			.sin6_addr = IN6ADDR_V4MAPPED_INIT,
165*bbb1b6f9SApple OSS Distributions 		};
166*bbb1b6f9SApple OSS Distributions 		mapped.sin6_addr.s6_addr32[3] = addr->sin.sin_addr.s_addr;
167*bbb1b6f9SApple OSS Distributions 		return in6_addrsel_lookup_policy(&mapped);
168*bbb1b6f9SApple OSS Distributions 	}
169*bbb1b6f9SApple OSS Distributions 	return NULL;
170*bbb1b6f9SApple OSS Distributions }
171*bbb1b6f9SApple OSS Distributions 
172*bbb1b6f9SApple OSS Distributions static void
netsrc_policy_common(struct netsrc_req * request,struct netsrc_rep * reply)173*bbb1b6f9SApple OSS Distributions netsrc_policy_common(struct netsrc_req *request, struct netsrc_rep *reply)
174*bbb1b6f9SApple OSS Distributions {
175*bbb1b6f9SApple OSS Distributions 	// Destination policy
176*bbb1b6f9SApple OSS Distributions 	struct in6_addrpolicy *policy = lookup_policy(SA(&request->nrq_dst.sa));
177*bbb1b6f9SApple OSS Distributions 	if (policy != NULL && policy->label != -1) {
178*bbb1b6f9SApple OSS Distributions 		/* Explicit cast because both policy and netsrc are public APIs
179*bbb1b6f9SApple OSS Distributions 		 * and apps might rely on it.
180*bbb1b6f9SApple OSS Distributions 		 */
181*bbb1b6f9SApple OSS Distributions 		reply->nrp_dstlabel = (uint16_t)policy->label;
182*bbb1b6f9SApple OSS Distributions 		reply->nrp_dstprecedence = (uint16_t)policy->preced;
183*bbb1b6f9SApple OSS Distributions 	}
184*bbb1b6f9SApple OSS Distributions 
185*bbb1b6f9SApple OSS Distributions 	// Source policy
186*bbb1b6f9SApple OSS Distributions 	policy = lookup_policy(SA(&reply->nrp_src.sa));
187*bbb1b6f9SApple OSS Distributions 	if (policy != NULL && policy->label != -1) {
188*bbb1b6f9SApple OSS Distributions 		/* Explicit cast because both policy and netsrc are public APIs
189*bbb1b6f9SApple OSS Distributions 		 * and apps might rely on it.
190*bbb1b6f9SApple OSS Distributions 		 */
191*bbb1b6f9SApple OSS Distributions 		reply->nrp_label = (uint16_t)policy->label;
192*bbb1b6f9SApple OSS Distributions 		reply->nrp_precedence = (uint16_t)policy->preced;
193*bbb1b6f9SApple OSS Distributions 	}
194*bbb1b6f9SApple OSS Distributions }
195*bbb1b6f9SApple OSS Distributions 
196*bbb1b6f9SApple OSS Distributions static errno_t
netsrc_ipv6(kern_ctl_ref kctl,uint32_t unit,struct netsrc_req * request)197*bbb1b6f9SApple OSS Distributions netsrc_ipv6(kern_ctl_ref kctl, uint32_t unit, struct netsrc_req *request)
198*bbb1b6f9SApple OSS Distributions {
199*bbb1b6f9SApple OSS Distributions 	struct route_in6 ro = {
200*bbb1b6f9SApple OSS Distributions 		.ro_dst = request->nrq_sin6,
201*bbb1b6f9SApple OSS Distributions 	};
202*bbb1b6f9SApple OSS Distributions 
203*bbb1b6f9SApple OSS Distributions 	int error = 0;
204*bbb1b6f9SApple OSS Distributions 	struct in6_addr storage, *in6 = in6_selectsrc(&request->nrq_sin6, NULL,
205*bbb1b6f9SApple OSS Distributions 	    NULL, &ro, NULL, &storage,
206*bbb1b6f9SApple OSS Distributions 	    request->nrq_ifscope, &error);
207*bbb1b6f9SApple OSS Distributions 	struct netsrc_rep reply = {
208*bbb1b6f9SApple OSS Distributions 		.nrp_sin6.sin6_family = AF_INET6,
209*bbb1b6f9SApple OSS Distributions 		.nrp_sin6.sin6_len = sizeof(reply.nrp_sin6),
210*bbb1b6f9SApple OSS Distributions 		.nrp_sin6.sin6_addr = in6 ? *in6 : (struct in6_addr){},
211*bbb1b6f9SApple OSS Distributions 	};
212*bbb1b6f9SApple OSS Distributions 	netsrc_common(ro.ro_rt, &reply);
213*bbb1b6f9SApple OSS Distributions 	if (ro.ro_srcia == NULL && in6 != NULL) {
214*bbb1b6f9SApple OSS Distributions 		ro.ro_srcia = (struct ifaddr*)(ifa_foraddr6_scoped(in6, reply.nrp_ifindex));
215*bbb1b6f9SApple OSS Distributions 	}
216*bbb1b6f9SApple OSS Distributions 	if (ro.ro_srcia) {
217*bbb1b6f9SApple OSS Distributions 		struct in6_ifaddr *ia = ifatoia6(ro.ro_srcia);
218*bbb1b6f9SApple OSS Distributions #define IA_TO_NRP_FLAG(flag)    \
219*bbb1b6f9SApple OSS Distributions 	        if (ia->ia6_flags & IN6_IFF_##flag) {                   \
220*bbb1b6f9SApple OSS Distributions 	                reply.nrp_flags |= NETSRC_FLAG_IP6_##flag;      \
221*bbb1b6f9SApple OSS Distributions 	        }
222*bbb1b6f9SApple OSS Distributions 		IA_TO_NRP_FLAG(TENTATIVE);
223*bbb1b6f9SApple OSS Distributions 		IA_TO_NRP_FLAG(TEMPORARY);
224*bbb1b6f9SApple OSS Distributions 		IA_TO_NRP_FLAG(DEPRECATED);
225*bbb1b6f9SApple OSS Distributions 		IA_TO_NRP_FLAG(OPTIMISTIC);
226*bbb1b6f9SApple OSS Distributions 		IA_TO_NRP_FLAG(SECURED);
227*bbb1b6f9SApple OSS Distributions 		IA_TO_NRP_FLAG(DYNAMIC);
228*bbb1b6f9SApple OSS Distributions 		IA_TO_NRP_FLAG(AUTOCONF);
229*bbb1b6f9SApple OSS Distributions #undef IA_TO_NRP_FLAG
230*bbb1b6f9SApple OSS Distributions 		reply.nrp_flags |= NETSRC_FLAG_ROUTEABLE;
231*bbb1b6f9SApple OSS Distributions 	}
232*bbb1b6f9SApple OSS Distributions 	ROUTE_RELEASE(&ro);
233*bbb1b6f9SApple OSS Distributions 	netsrc_policy_common(request, &reply);
234*bbb1b6f9SApple OSS Distributions 	return netsrc_reply(kctl, unit, request->nrq_ver, &reply);
235*bbb1b6f9SApple OSS Distributions }
236*bbb1b6f9SApple OSS Distributions 
237*bbb1b6f9SApple OSS Distributions static errno_t
netsrc_ipv4(kern_ctl_ref kctl,uint32_t unit,struct netsrc_req * request)238*bbb1b6f9SApple OSS Distributions netsrc_ipv4(kern_ctl_ref kctl, uint32_t unit, struct netsrc_req *request)
239*bbb1b6f9SApple OSS Distributions {
240*bbb1b6f9SApple OSS Distributions 	// Unfortunately, IPv4 doesn't have a function like in6_selectsrc
241*bbb1b6f9SApple OSS Distributions 	// Look up the route
242*bbb1b6f9SApple OSS Distributions 	lck_mtx_lock(rnh_lock);
243*bbb1b6f9SApple OSS Distributions 	struct rtentry *rt = rt_lookup(TRUE, SA(&request->nrq_dst.sa),
244*bbb1b6f9SApple OSS Distributions 	    NULL, rt_tables[AF_INET],
245*bbb1b6f9SApple OSS Distributions 	    request->nrq_ifscope);
246*bbb1b6f9SApple OSS Distributions 	lck_mtx_unlock(rnh_lock);
247*bbb1b6f9SApple OSS Distributions 
248*bbb1b6f9SApple OSS Distributions 	// Look up the ifa
249*bbb1b6f9SApple OSS Distributions 	struct netsrc_rep reply = {};
250*bbb1b6f9SApple OSS Distributions 	if (rt) {
251*bbb1b6f9SApple OSS Distributions 		struct in_ifaddr *ia = NULL;
252*bbb1b6f9SApple OSS Distributions 		lck_rw_lock_shared(&in_ifaddr_rwlock);
253*bbb1b6f9SApple OSS Distributions 		TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {
254*bbb1b6f9SApple OSS Distributions 			IFA_LOCK_SPIN(&ia->ia_ifa);
255*bbb1b6f9SApple OSS Distributions 			if (ia->ia_ifp == rt->rt_ifp) {
256*bbb1b6f9SApple OSS Distributions 				ifa_addref(&ia->ia_ifa);
257*bbb1b6f9SApple OSS Distributions 				break;
258*bbb1b6f9SApple OSS Distributions 			}
259*bbb1b6f9SApple OSS Distributions 			IFA_UNLOCK(&ia->ia_ifa);
260*bbb1b6f9SApple OSS Distributions 		}
261*bbb1b6f9SApple OSS Distributions 		lck_rw_done(&in_ifaddr_rwlock);
262*bbb1b6f9SApple OSS Distributions 
263*bbb1b6f9SApple OSS Distributions 		if (ia) {
264*bbb1b6f9SApple OSS Distributions 			reply.nrp_sin = ia->ia_addr;
265*bbb1b6f9SApple OSS Distributions 			IFA_UNLOCK(&ia->ia_ifa);
266*bbb1b6f9SApple OSS Distributions 			ifa_remref(&ia->ia_ifa);
267*bbb1b6f9SApple OSS Distributions 			reply.nrp_flags |= NETSRC_FLAG_ROUTEABLE;
268*bbb1b6f9SApple OSS Distributions 		}
269*bbb1b6f9SApple OSS Distributions 		netsrc_common(rt, &reply);
270*bbb1b6f9SApple OSS Distributions 		rtfree(rt);
271*bbb1b6f9SApple OSS Distributions 	}
272*bbb1b6f9SApple OSS Distributions 	netsrc_policy_common(request, &reply);
273*bbb1b6f9SApple OSS Distributions 	return netsrc_reply(kctl, unit, request->nrq_ver, &reply);
274*bbb1b6f9SApple OSS Distributions }
275*bbb1b6f9SApple OSS Distributions 
276*bbb1b6f9SApple OSS Distributions static errno_t
netsrc_ctlsend(kern_ctl_ref kctl,uint32_t unit,void * uinfo,mbuf_t m,int flags)277*bbb1b6f9SApple OSS Distributions netsrc_ctlsend(kern_ctl_ref kctl, uint32_t unit, void *uinfo, mbuf_t m,
278*bbb1b6f9SApple OSS Distributions     int flags)
279*bbb1b6f9SApple OSS Distributions {
280*bbb1b6f9SApple OSS Distributions #pragma unused(uinfo, flags)
281*bbb1b6f9SApple OSS Distributions 	errno_t error;
282*bbb1b6f9SApple OSS Distributions 	struct netsrc_req *__single nrq, storage;
283*bbb1b6f9SApple OSS Distributions 
284*bbb1b6f9SApple OSS Distributions 	if (mbuf_pkthdr_len(m) < sizeof(*nrq)) {
285*bbb1b6f9SApple OSS Distributions 		error = EINVAL;
286*bbb1b6f9SApple OSS Distributions 		goto out;
287*bbb1b6f9SApple OSS Distributions 	}
288*bbb1b6f9SApple OSS Distributions 	if (mbuf_len(m) >= sizeof(*nrq)) {
289*bbb1b6f9SApple OSS Distributions 		nrq = mtod(m, struct netsrc_req *);
290*bbb1b6f9SApple OSS Distributions 	} else {
291*bbb1b6f9SApple OSS Distributions 		mbuf_copydata(m, 0, sizeof(storage), &storage);
292*bbb1b6f9SApple OSS Distributions 		nrq = &storage;
293*bbb1b6f9SApple OSS Distributions 	}
294*bbb1b6f9SApple OSS Distributions 	if (nrq->nrq_ver > NETSRC_CURVERS) {
295*bbb1b6f9SApple OSS Distributions 		error = EINVAL;
296*bbb1b6f9SApple OSS Distributions 		goto out;
297*bbb1b6f9SApple OSS Distributions 	}
298*bbb1b6f9SApple OSS Distributions 	switch (nrq->nrq_sin.sin_family) {
299*bbb1b6f9SApple OSS Distributions 	case AF_INET:
300*bbb1b6f9SApple OSS Distributions 		if (nrq->nrq_sin.sin_len < sizeof(nrq->nrq_sin) ||
301*bbb1b6f9SApple OSS Distributions 		    nrq->nrq_sin.sin_addr.s_addr == INADDR_ANY) {
302*bbb1b6f9SApple OSS Distributions 			error = EINVAL;
303*bbb1b6f9SApple OSS Distributions 		} else {
304*bbb1b6f9SApple OSS Distributions 			error = netsrc_ipv4(kctl, unit, nrq);
305*bbb1b6f9SApple OSS Distributions 		}
306*bbb1b6f9SApple OSS Distributions 		break;
307*bbb1b6f9SApple OSS Distributions 	case AF_INET6:
308*bbb1b6f9SApple OSS Distributions 		if (nrq->nrq_sin6.sin6_len < sizeof(nrq->nrq_sin6) ||
309*bbb1b6f9SApple OSS Distributions 		    IN6_IS_ADDR_UNSPECIFIED(&nrq->nrq_sin6.sin6_addr)) {
310*bbb1b6f9SApple OSS Distributions 			error = EINVAL;
311*bbb1b6f9SApple OSS Distributions 		} else {
312*bbb1b6f9SApple OSS Distributions 			error = netsrc_ipv6(kctl, unit, nrq);
313*bbb1b6f9SApple OSS Distributions 		}
314*bbb1b6f9SApple OSS Distributions 		break;
315*bbb1b6f9SApple OSS Distributions 	default:
316*bbb1b6f9SApple OSS Distributions 		printf("%s: invalid family\n", __func__);
317*bbb1b6f9SApple OSS Distributions 		error = EINVAL;
318*bbb1b6f9SApple OSS Distributions 	}
319*bbb1b6f9SApple OSS Distributions out:
320*bbb1b6f9SApple OSS Distributions 	mbuf_freem(m);
321*bbb1b6f9SApple OSS Distributions 
322*bbb1b6f9SApple OSS Distributions 	return error;
323*bbb1b6f9SApple OSS Distributions }
324*bbb1b6f9SApple OSS Distributions 
325*bbb1b6f9SApple OSS Distributions __private_extern__ void
netsrc_init(void)326*bbb1b6f9SApple OSS Distributions netsrc_init(void)
327*bbb1b6f9SApple OSS Distributions {
328*bbb1b6f9SApple OSS Distributions 	struct kern_ctl_reg netsrc_ctl = {
329*bbb1b6f9SApple OSS Distributions 		.ctl_connect = netsrc_ctlconnect,
330*bbb1b6f9SApple OSS Distributions 		.ctl_send    = netsrc_ctlsend,
331*bbb1b6f9SApple OSS Distributions 	};
332*bbb1b6f9SApple OSS Distributions 
333*bbb1b6f9SApple OSS Distributions 	strlcpy(netsrc_ctl.ctl_name, NETSRC_CTLNAME, sizeof(netsrc_ctl.ctl_name));
334*bbb1b6f9SApple OSS Distributions 
335*bbb1b6f9SApple OSS Distributions 	static kern_ctl_ref     netsrc_ctlref = NULL;
336*bbb1b6f9SApple OSS Distributions 	errno_t error = ctl_register(&netsrc_ctl, &netsrc_ctlref);
337*bbb1b6f9SApple OSS Distributions 	if (error != 0) {
338*bbb1b6f9SApple OSS Distributions 		printf("%s: ctl_register failed %d\n", __func__, error);
339*bbb1b6f9SApple OSS Distributions 	}
340*bbb1b6f9SApple OSS Distributions }
341