]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/netsrc.c
xnu-3248.20.55.tar.gz
[apple/xnu.git] / bsd / net / netsrc.c
1 /*
2 * Copyright (c) 2011-2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
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>
36
37 #include <kern/debug.h>
38
39 #include <libkern/libkern.h>
40
41 #include <net/if.h>
42 #include <net/route.h>
43
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>
50
51 #include <net/netsrc.h>
52
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 *);
57
58 static kern_ctl_ref netsrc_ctlref = NULL;
59
60 __private_extern__ void
61 netsrc_init(void)
62 {
63 errno_t error;
64 struct kern_ctl_reg netsrc_ctl = {
65 .ctl_connect = netsrc_ctlconnect,
66 .ctl_send = netsrc_ctlsend,
67 };
68
69 strlcpy(netsrc_ctl.ctl_name, NETSRC_CTLNAME, sizeof(NETSRC_CTLNAME));
70
71 if ((error = ctl_register(&netsrc_ctl, &netsrc_ctlref)))
72 printf("%s: ctl_register failed %d\n", __func__, error);
73 }
74
75 static errno_t
76 netsrc_ctlconnect(kern_ctl_ref kctl, struct sockaddr_ctl *sac, void **uinfo)
77 {
78 #pragma unused(kctl, sac, uinfo)
79
80 /*
81 * We don't need to do anything here. This callback is only necessary
82 * for ctl_register() to succeed.
83 */
84 return (0);
85 }
86
87 static errno_t
88 netsrc_ctlsend(kern_ctl_ref kctl, uint32_t unit, void *uinfo, mbuf_t m,
89 int flags)
90 {
91 #pragma unused(uinfo, flags)
92 errno_t error;
93 struct netsrc_req *nrq, storage;
94
95 if (mbuf_pkthdr_len(m) < sizeof(*nrq)) {
96 error = EINVAL;
97 goto out;
98 }
99 if (mbuf_len(m) >= sizeof(*nrq))
100 nrq = mbuf_data(m);
101 else {
102 mbuf_copydata(m, 0, sizeof(storage), &storage);
103 nrq = &storage;
104 }
105 /* We only have one version right now. */
106 if (nrq->nrq_ver != NETSRC_VERSION1) {
107 error = EINVAL;
108 goto out;
109 }
110 switch (nrq->nrq_sin.sin_family) {
111 case AF_INET:
112 error = netsrc_ipv4(kctl, unit, nrq);
113 break;
114 case AF_INET6:
115 error = netsrc_ipv6(kctl, unit, nrq);
116 break;
117 default:
118 printf("%s: invalid family\n", __func__);
119 error = EINVAL;
120 }
121 out:
122 mbuf_freem(m);
123
124 return (error);
125
126 }
127
128 static errno_t
129 netsrc_ipv4(kern_ctl_ref kctl, uint32_t unit, struct netsrc_req *nrq)
130 {
131 errno_t error = EHOSTUNREACH;
132 struct sockaddr_in *dstsin;
133 struct rtentry *rt;
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,
140 };
141 struct in6_addrpolicy *policy;
142
143 dstsin = &nrq->nrq_sin;
144
145 if (dstsin->sin_len < sizeof (*dstsin) ||
146 dstsin->sin_addr.s_addr == INADDR_ANY)
147 return (EINVAL);
148
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);
153 if (!rt)
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;
171 }
172 error = ctl_enqueuedata(kctl, unit, &nrp,
173 sizeof(nrp), CTL_DATA_EOR);
174 break;
175 }
176 IFA_UNLOCK(&ia->ia_ifa);
177 }
178 lck_rw_done(in_ifaddr_rwlock);
179 if (rt)
180 rtfree(rt);
181
182 return (error);
183 }
184
185 static errno_t
186 netsrc_ipv6(kern_ctl_ref kctl, uint32_t unit, struct netsrc_req *nrq)
187 {
188 struct sockaddr_in6 *dstsin6;
189 struct in6_addr *in6, storage;
190 struct in6_ifaddr *ia;
191 struct route_in6 ro;
192 int error = EHOSTUNREACH;
193 struct netsrc_rep nrp;
194
195 dstsin6 = &nrq->nrq_sin6;
196
197 if (dstsin6->sin6_len < sizeof (*dstsin6) ||
198 IN6_IS_ADDR_UNSPECIFIED(&dstsin6->sin6_addr))
199 return (EINVAL);
200
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);
206 if (!ro.ro_rt)
207 return (EHOSTUNREACH);
208 in6 = in6_selectsrc(dstsin6, NULL, NULL, &ro, NULL, &storage,
209 nrq->nrq_ifscope, &error);
210 ROUTE_RELEASE(&ro);
211 if (!in6 || error)
212 return (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;
222
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;
240 }
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;
247 }
248 break;
249 }
250 }
251 lck_rw_done(&in6_ifaddr_rwlock);
252 error = ctl_enqueuedata(kctl, unit, &nrp, sizeof(nrp),
253 CTL_DATA_EOR);
254
255 return (error);
256 }