2 * Copyright (c) 2011-2013 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <sys/param.h>
30 #include <sys/types.h>
31 #include <sys/kpi_mbuf.h>
32 #include <sys/socket.h>
33 #include <sys/kern_control.h>
34 #include <sys/mcache.h>
35 #include <sys/socketvar.h>
37 #include <kern/debug.h>
39 #include <libkern/libkern.h>
42 #include <net/route.h>
44 #include <netinet/in.h>
45 #include <netinet/ip.h>
46 #include <netinet/ip_var.h>
47 #include <netinet/in_var.h>
48 #include <netinet/ip6.h>
49 #include <netinet6/ip6_var.h>
51 #include <net/netsrc.h>
53 static errno_t
netsrc_ctlsend(kern_ctl_ref
, uint32_t, void *, mbuf_t
, int);
54 static errno_t
netsrc_ctlconnect(kern_ctl_ref
, struct sockaddr_ctl
*, void **);
55 static errno_t
netsrc_ipv4(kern_ctl_ref
, uint32_t, struct netsrc_req
*);
56 static errno_t
netsrc_ipv6(kern_ctl_ref
, uint32_t, struct netsrc_req
*);
58 static kern_ctl_ref netsrc_ctlref
= NULL
;
60 __private_extern__
void
64 struct kern_ctl_reg netsrc_ctl
= {
65 .ctl_connect
= netsrc_ctlconnect
,
66 .ctl_send
= netsrc_ctlsend
,
69 strlcpy(netsrc_ctl
.ctl_name
, NETSRC_CTLNAME
, sizeof(NETSRC_CTLNAME
));
71 if ((error
= ctl_register(&netsrc_ctl
, &netsrc_ctlref
)))
72 printf("%s: ctl_register failed %d\n", __func__
, error
);
76 netsrc_ctlconnect(kern_ctl_ref kctl
, struct sockaddr_ctl
*sac
, void **uinfo
)
78 #pragma unused(kctl, sac, uinfo)
81 * We don't need to do anything here. This callback is only necessary
82 * for ctl_register() to succeed.
88 netsrc_ctlsend(kern_ctl_ref kctl
, uint32_t unit
, void *uinfo
, mbuf_t m
,
91 #pragma unused(uinfo, flags)
93 struct netsrc_req
*nrq
, storage
;
95 if (mbuf_pkthdr_len(m
) < sizeof(*nrq
)) {
99 if (mbuf_len(m
) >= sizeof(*nrq
))
102 mbuf_copydata(m
, 0, sizeof(storage
), &storage
);
105 /* We only have one version right now. */
106 if (nrq
->nrq_ver
!= NETSRC_VERSION1
) {
110 switch (nrq
->nrq_sin
.sin_family
) {
112 error
= netsrc_ipv4(kctl
, unit
, nrq
);
115 error
= netsrc_ipv6(kctl
, unit
, nrq
);
118 printf("%s: invalid family\n", __func__
);
129 netsrc_ipv4(kern_ctl_ref kctl
, uint32_t unit
, struct netsrc_req
*nrq
)
131 errno_t error
= EHOSTUNREACH
;
132 struct sockaddr_in
*dstsin
;
134 struct in_ifaddr
*ia
;
135 struct netsrc_rep nrp
;
136 struct sockaddr_in6 v4entry
= {
137 .sin6_family
= AF_INET6
,
138 .sin6_len
= sizeof(struct sockaddr_in6
),
139 .sin6_addr
= IN6ADDR_V4MAPPED_INIT
,
141 struct in6_addrpolicy
*policy
;
143 dstsin
= &nrq
->nrq_sin
;
145 if (dstsin
->sin_len
< sizeof (*dstsin
) ||
146 dstsin
->sin_addr
.s_addr
== INADDR_ANY
)
149 lck_mtx_lock(rnh_lock
);
150 rt
= rt_lookup(TRUE
, (struct sockaddr
*)dstsin
, NULL
,
151 rt_tables
[AF_INET
], nrq
->nrq_ifscope
);
152 lck_mtx_unlock(rnh_lock
);
154 return (EHOSTUNREACH
);
155 lck_rw_lock_shared(in_ifaddr_rwlock
);
156 TAILQ_FOREACH(ia
, &in_ifaddrhead
, ia_link
) {
157 IFA_LOCK_SPIN(&ia
->ia_ifa
);
158 if (ia
->ia_ifp
== rt
->rt_ifp
) {
159 memset(&nrp
, 0, sizeof(nrp
));
160 memcpy(&nrp
.nrp_sin
, IA_SIN(ia
), sizeof(nrp
.nrp_sin
));
161 IFA_UNLOCK(&ia
->ia_ifa
);
162 v4entry
.sin6_addr
.s6_addr32
[3] =
163 nrp
.nrp_sin
.sin_addr
.s_addr
;
164 policy
= in6_addrsel_lookup_policy(&v4entry
);
165 if (policy
->label
!= -1) {
166 nrp
.nrp_label
= policy
->label
;
167 nrp
.nrp_precedence
= policy
->preced
;
168 /* XXX might not be true */
169 nrp
.nrp_dstlabel
= policy
->label
;
170 nrp
.nrp_dstprecedence
= policy
->preced
;
172 error
= ctl_enqueuedata(kctl
, unit
, &nrp
,
173 sizeof(nrp
), CTL_DATA_EOR
);
176 IFA_UNLOCK(&ia
->ia_ifa
);
178 lck_rw_done(in_ifaddr_rwlock
);
186 netsrc_ipv6(kern_ctl_ref kctl
, uint32_t unit
, struct netsrc_req
*nrq
)
188 struct sockaddr_in6
*dstsin6
;
189 struct in6_addr
*in6
, storage
;
190 struct in6_ifaddr
*ia
;
192 int error
= EHOSTUNREACH
;
193 struct netsrc_rep nrp
;
195 dstsin6
= &nrq
->nrq_sin6
;
197 if (dstsin6
->sin6_len
< sizeof (*dstsin6
) ||
198 IN6_IS_ADDR_UNSPECIFIED(&dstsin6
->sin6_addr
))
201 memset(&ro
, 0, sizeof(ro
));
202 lck_mtx_lock(rnh_lock
);
203 ro
.ro_rt
= rt_lookup(TRUE
, (struct sockaddr
*)dstsin6
, NULL
,
204 rt_tables
[AF_INET6
], nrq
->nrq_ifscope
);
205 lck_mtx_unlock(rnh_lock
);
207 return (EHOSTUNREACH
);
208 in6
= in6_selectsrc(dstsin6
, NULL
, NULL
, &ro
, NULL
, &storage
,
209 nrq
->nrq_ifscope
, &error
);
213 memset(&nrp
, 0, sizeof(nrp
));
214 nrp
.nrp_sin6
.sin6_family
= AF_INET6
;
215 nrp
.nrp_sin6
.sin6_len
= sizeof(nrp
.nrp_sin6
);
216 memcpy(&nrp
.nrp_sin6
.sin6_addr
, in6
, sizeof(nrp
.nrp_sin6
.sin6_addr
));
217 lck_rw_lock_shared(&in6_ifaddr_rwlock
);
218 for (ia
= in6_ifaddrs
; ia
; ia
= ia
->ia_next
) {
219 if (memcmp(&ia
->ia_addr
.sin6_addr
, in6
, sizeof(*in6
)) == 0) {
220 struct sockaddr_in6 sin6
;
221 struct in6_addrpolicy
*policy
;
223 if (ia
->ia6_flags
& IN6_IFF_TEMPORARY
)
224 nrp
.nrp_flags
|= NETSRC_IP6_FLAG_TEMPORARY
;
225 if (ia
->ia6_flags
& IN6_IFF_TENTATIVE
)
226 nrp
.nrp_flags
|= NETSRC_IP6_FLAG_TENTATIVE
;
227 if (ia
->ia6_flags
& IN6_IFF_DEPRECATED
)
228 nrp
.nrp_flags
|= NETSRC_IP6_FLAG_DEPRECATED
;
229 if (ia
->ia6_flags
& IN6_IFF_OPTIMISTIC
)
230 nrp
.nrp_flags
|= NETSRC_IP6_FLAG_OPTIMISTIC
;
231 if (ia
->ia6_flags
& IN6_IFF_SECURED
)
232 nrp
.nrp_flags
|= NETSRC_IP6_FLAG_SECURED
;
233 sin6
.sin6_family
= AF_INET6
;
234 sin6
.sin6_len
= sizeof(sin6
);
235 memcpy(&sin6
.sin6_addr
, in6
, sizeof(*in6
));
236 policy
= in6_addrsel_lookup_policy(&sin6
);
237 if (policy
->label
!= -1) {
238 nrp
.nrp_label
= policy
->label
;
239 nrp
.nrp_precedence
= policy
->preced
;
241 memcpy(&sin6
.sin6_addr
, &dstsin6
->sin6_addr
,
242 sizeof(dstsin6
->sin6_addr
));
243 policy
= in6_addrsel_lookup_policy(&sin6
);
244 if (policy
->label
!= -1) {
245 nrp
.nrp_dstlabel
= policy
->label
;
246 nrp
.nrp_dstprecedence
= policy
->preced
;
251 lck_rw_done(&in6_ifaddr_rwlock
);
252 error
= ctl_enqueuedata(kctl
, unit
, &nrp
, sizeof(nrp
),