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