1/*
2 * Copyright (c) 2009-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/*
30 * Copyright (C) 2000 WIDE Project.
31 * All rights reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 3. Neither the name of the project nor the names of its contributors
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 */
57
58#include <sys/param.h>
59#include <sys/malloc.h>
60#include <sys/mbuf.h>
61#include <sys/socket.h>
62#include <sys/systm.h>
63#include <sys/queue.h>
64#include <sys/syslog.h>
65#include <sys/mcache.h>
66
67#include <net/route.h>
68#include <net/if.h>
69
70#include <netinet/in.h>
71
72#include <netinet6/in6_var.h>
73#include <netinet6/scope6_var.h>
74
75#ifdef ENABLE_DEFAULT_SCOPE
76int ip6_use_defzone = 1;
77#else
78int ip6_use_defzone = 0;
79#endif
80
81static LCK_MTX_DECLARE_ATTR(scope6_lock, &ip6_mutex_grp, &ip6_mutex_attr);
82static struct scope6_id sid_default;
83
84#define SID(ifp) &IN6_IFEXTRA(ifp)->scope6_id
85
86SYSCTL_DECL(_net_inet6_ip6);
87
88int in6_embedded_scope = 1;
89SYSCTL_INT(_net_inet6_ip6, OID_AUTO,
90 in6_embedded_scope, CTLFLAG_RW | CTLFLAG_LOCKED, &in6_embedded_scope, 0, "");
91
92int in6_embedded_scope_debug = 0;
93SYSCTL_INT(_net_inet6_ip6, OID_AUTO,
94 in6_embedded_scope_debug, CTLFLAG_RW | CTLFLAG_LOCKED, &in6_embedded_scope_debug, 0, "");
95
96void
97scope6_ifattach(struct ifnet *ifp)
98{
99 struct scope6_id *sid;
100
101 VERIFY(IN6_IFEXTRA(ifp) != NULL);
102 if_inet6data_lock_exclusive(ifp);
103 sid = SID(ifp);
104 /* N.B.: the structure is already zero'ed */
105 /*
106 * XXX: IPV6_ADDR_SCOPE_xxx macros are not standard.
107 * Should we rather hardcode here?
108 */
109 sid->s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] = ifp->if_index;
110 sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = ifp->if_index;
111#if MULTI_SCOPE
112 /* by default, we don't care about scope boundary for these scopes. */
113 sid->s6id_list[IPV6_ADDR_SCOPE_SITELOCAL] = 1;
114 sid->s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL] = 1;
115#endif
116 if_inet6data_lock_done(ifp);
117}
118
119/*
120 * Get a scope of the address. Node-local, link-local, site-local or global.
121 */
122int
123in6_addrscope(struct in6_addr *addr)
124{
125 int scope;
126
127 if (addr->s6_addr8[0] == 0xfe) {
128 scope = addr->s6_addr8[1] & 0xc0;
129
130 switch (scope) {
131 case 0x80:
132 return IPV6_ADDR_SCOPE_LINKLOCAL;
133 case 0xc0:
134 return IPV6_ADDR_SCOPE_SITELOCAL;
135 default:
136 return IPV6_ADDR_SCOPE_GLOBAL; /* just in case */
137 }
138 }
139
140 if (addr->s6_addr8[0] == 0xff) {
141 scope = addr->s6_addr8[1] & 0x0f;
142
143 /*
144 * due to other scope such as reserved,
145 * return scope doesn't work.
146 */
147 switch (scope) {
148 case IPV6_ADDR_SCOPE_INTFACELOCAL:
149 return IPV6_ADDR_SCOPE_INTFACELOCAL;
150 case IPV6_ADDR_SCOPE_LINKLOCAL:
151 return IPV6_ADDR_SCOPE_LINKLOCAL;
152 case IPV6_ADDR_SCOPE_SITELOCAL:
153 return IPV6_ADDR_SCOPE_SITELOCAL;
154 default:
155 return IPV6_ADDR_SCOPE_GLOBAL;
156 }
157 }
158
159 /*
160 * Regard loopback and unspecified addresses as global, since
161 * they have no ambiguity.
162 */
163 if (bcmp(s1: &in6addr_loopback, s2: addr, n: sizeof(*addr) - 1) == 0) {
164 if (addr->s6_addr8[15] == 1) { /* loopback */
165 return IPV6_ADDR_SCOPE_LINKLOCAL;
166 }
167 if (addr->s6_addr8[15] == 0) { /* unspecified */
168 return IPV6_ADDR_SCOPE_GLOBAL; /* XXX: correct? */
169 }
170 }
171
172 return IPV6_ADDR_SCOPE_GLOBAL;
173}
174
175int
176in6_addr2scopeid(struct ifnet *ifp, struct in6_addr *addr)
177{
178 int scope = in6_addrscope(addr);
179 int retid = 0;
180 struct scope6_id *sid;
181
182 if_inet6data_lock_shared(ifp);
183 if (IN6_IFEXTRA(ifp) == NULL) {
184 goto err;
185 }
186 sid = SID(ifp);
187 switch (scope) {
188 case IPV6_ADDR_SCOPE_NODELOCAL:
189 retid = sid->s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL];
190 break;
191 case IPV6_ADDR_SCOPE_LINKLOCAL:
192 retid = sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL];
193 break;
194 case IPV6_ADDR_SCOPE_SITELOCAL:
195 retid = sid->s6id_list[IPV6_ADDR_SCOPE_SITELOCAL];
196 break;
197 case IPV6_ADDR_SCOPE_ORGLOCAL:
198 retid = sid->s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL];
199 break;
200 default:
201 break; /* XXX: value 0, treat as global. */
202 }
203err:
204 if_inet6data_lock_done(ifp);
205
206 return retid;
207}
208
209/*
210 * Validate the specified scope zone ID in the sin6_scope_id field. If the ID
211 * is unspecified (=0), needs to be specified, and the default zone ID can be
212 * used, the default value will be used.
213 * This routine then generates the kernel-internal form: if the address scope
214 * of is interface-local or link-local, embed the interface index in the
215 * address.
216 */
217int
218sa6_embedscope(struct sockaddr_in6 *sin6, int defaultok, uint32_t *ret_ifscope)
219{
220 struct ifnet *ifp;
221 u_int32_t zoneid;
222
223 if ((zoneid = sin6->sin6_scope_id) == 0 && defaultok) {
224 zoneid = scope6_addr2default(&sin6->sin6_addr);
225 }
226
227 if (zoneid != 0 &&
228 (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) ||
229 IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr))) {
230 /*
231 * At this moment, we only check interface-local and
232 * link-local scope IDs, and use interface indices as the
233 * zone IDs assuming a one-to-one mapping between interfaces
234 * and links.
235 */
236 if (!IF_INDEX_IN_RANGE(zoneid)) {
237 return ENXIO;
238 }
239 ifnet_head_lock_shared();
240 ifp = ifindex2ifnet[zoneid];
241 if (ifp == NULL) { /* XXX: this can happen for some OS */
242 ifnet_head_done();
243 return ENXIO;
244 }
245 ifnet_head_done();
246 /* XXX assignment to 16bit from 32bit variable */
247 if (in6_embedded_scope) {
248 sin6->sin6_addr.s6_addr16[1] = htons(zoneid & 0xffff);
249 sin6->sin6_scope_id = 0;
250 }
251 if (ret_ifscope != NULL) {
252 *ret_ifscope = zoneid;
253 }
254 }
255
256 return 0;
257}
258
259void
260rtkey_to_sa6(struct rtentry *rt, struct sockaddr_in6 *sin6)
261{
262 VERIFY(rt_key(rt)->sa_family == AF_INET6);
263
264 *sin6 = *((struct sockaddr_in6 *)(void *)rt_key(rt));
265 if (in6_embedded_scope) {
266 sin6->sin6_scope_id = 0;
267 }
268}
269
270void
271rtgw_to_sa6(struct rtentry *rt, struct sockaddr_in6 *sin6)
272{
273 VERIFY(rt->rt_flags & RTF_GATEWAY);
274
275 *sin6 = *((struct sockaddr_in6 *)(void *)rt->rt_gateway);
276 sin6->sin6_scope_id = 0;
277}
278
279/*
280 * generate standard sockaddr_in6 from embedded form.
281 */
282int
283sa6_recoverscope(struct sockaddr_in6 *sin6, boolean_t attachcheck)
284{
285 if (!in6_embedded_scope) {
286 return 0;
287 }
288
289 u_int32_t zoneid;
290
291 if (in6_embedded_scope && sin6->sin6_scope_id != 0) {
292 log(LOG_NOTICE,
293 "sa6_recoverscope: assumption failure (non 0 ID): %s%%%d\n",
294 ip6_sprintf(&sin6->sin6_addr), sin6->sin6_scope_id);
295 /* XXX: proceed anyway... */
296 }
297 if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) ||
298 IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) {
299 /*
300 * KAME assumption: link id == interface id
301 */
302 zoneid = ntohs(sin6->sin6_addr.s6_addr16[1]);
303 if (zoneid) {
304 /* sanity check */
305 if (!IF_INDEX_IN_RANGE(zoneid)) {
306 return ENXIO;
307 }
308 /*
309 * We use the attachcheck parameter to skip the
310 * interface attachment check.
311 * Some callers might hold the ifnet_head lock in
312 * exclusive mode. This means that:
313 * 1) the interface can't go away -- hence we don't
314 * need to perform this check
315 * 2) we can't perform this check because the lock is
316 * in exclusive mode and trying to lock it in shared
317 * mode would cause a deadlock.
318 */
319 if (attachcheck) {
320 ifnet_head_lock_shared();
321 if (ifindex2ifnet[zoneid] == NULL) {
322 ifnet_head_done();
323 return ENXIO;
324 }
325 ifnet_head_done();
326 }
327 sin6->sin6_addr.s6_addr16[1] = 0;
328 sin6->sin6_scope_id = zoneid;
329 }
330 }
331
332 return 0;
333}
334
335void
336scope6_setdefault(struct ifnet *ifp)
337{
338 /*
339 * Currently, this function just set the default "link" according to
340 * the given interface.
341 * We might eventually have to separate the notion of "link" from
342 * "interface" and provide a user interface to set the default.
343 */
344 lck_mtx_lock(lck: &scope6_lock);
345 if (ifp != NULL) {
346 sid_default.s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] =
347 ifp->if_index;
348 sid_default.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] =
349 ifp->if_index;
350 } else {
351 sid_default.s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] = 0;
352 sid_default.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = 0;
353 }
354 lck_mtx_unlock(lck: &scope6_lock);
355}
356
357
358u_int32_t
359scope6_addr2default(struct in6_addr *addr)
360{
361 u_int32_t id = 0;
362 int index = in6_addrscope(addr);
363
364 /*
365 * special case: The loopback address should be considered as
366 * link-local, but there's no ambiguity in the syntax.
367 */
368 if (IN6_IS_ADDR_LOOPBACK(addr)) {
369 return 0;
370 }
371
372 lck_mtx_lock(lck: &scope6_lock);
373 id = sid_default.s6id_list[index];
374 lck_mtx_unlock(lck: &scope6_lock);
375
376 return id;
377}
378
379/*
380 * Determine the appropriate scope zone ID for in6 and ifp. If ret_id is
381 * non NULL, it is set to the zone ID. If the zone ID needs to be embedded
382 * in the in6_addr structure, in6 will be modified.
383 *
384 * ret_id - unnecessary?
385 */
386int
387in6_setscope(struct in6_addr *in6, struct ifnet *ifp, u_int32_t *ret_id)
388{
389 int scope;
390 u_int32_t zoneid = 0;
391 struct scope6_id *sid;
392
393 /*
394 * special case: the loopback address can only belong to a loopback
395 * interface.
396 */
397 if (IN6_IS_ADDR_LOOPBACK(in6)) {
398 if (!(ifp->if_flags & IFF_LOOPBACK)) {
399 return EINVAL;
400 } else {
401 if (ret_id != NULL) {
402 *ret_id = 0; /* there's no ambiguity */
403 }
404 return 0;
405 }
406 }
407
408 scope = in6_addrscope(addr: in6);
409
410 if_inet6data_lock_shared(ifp);
411 if (IN6_IFEXTRA(ifp) == NULL) {
412 if_inet6data_lock_done(ifp);
413 if (ret_id) {
414 *ret_id = 0;
415 }
416 return EINVAL;
417 }
418 sid = SID(ifp);
419 switch (scope) {
420 case IPV6_ADDR_SCOPE_INTFACELOCAL: /* should be interface index */
421 zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL];
422 break;
423
424 case IPV6_ADDR_SCOPE_LINKLOCAL:
425 zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL];
426 break;
427
428 case IPV6_ADDR_SCOPE_SITELOCAL:
429 zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_SITELOCAL];
430 break;
431
432 case IPV6_ADDR_SCOPE_ORGLOCAL:
433 zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL];
434 break;
435 default:
436 zoneid = 0; /* XXX: treat as global. */
437 break;
438 }
439 if_inet6data_lock_done(ifp);
440
441 if (ret_id != NULL) {
442 *ret_id = zoneid;
443 }
444
445 if (in6_embedded_scope && (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6))) {
446 in6->s6_addr16[1] = htons(zoneid & 0xffff); /* XXX */
447 }
448 return 0;
449}
450
451/*
452 * Just clear the embedded scope identifier. Return 0 if the original address
453 * is intact; return non 0 if the address is modified.
454 */
455int
456in6_clearscope(struct in6_addr *in6)
457{
458 if (!in6_embedded_scope) {
459 return 0;
460 }
461
462 int modified = 0;
463
464 if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6)) {
465 if (in6->s6_addr16[1] != 0) {
466 modified = 1;
467 }
468 in6->s6_addr16[1] = 0;
469 }
470
471 return modified;
472}
473
474bool
475in6_are_addr_equal_scoped(const struct in6_addr *addr_a, const struct in6_addr *addr_b, uint32_t ifscope_a, uint32_t ifscope_b)
476{
477 if (!IN6_ARE_ADDR_EQUAL(addr_a, addr_b)) {
478 return false;
479 } else if (IN6_IS_SCOPE_EMBED(addr_a) && !in6_embedded_scope) {
480 return ifscope_a == ifscope_b;
481 }
482
483 return true;
484}
485
486bool
487in6_are_masked_addr_scope_equal(const struct in6_addr *addr_a, uint32_t ifscope_a, const struct in6_addr *addr_b, uint32_t ifscope_b, const struct in6_addr *m)
488{
489 if (!IN6_ARE_MASKED_ADDR_EQUAL(addr_a, addr_b, m)) {
490 return false;
491 } else if (IN6_IS_SCOPE_EMBED(addr_a) && !in6_embedded_scope) {
492 return ifscope_a == ifscope_b;
493 }
494
495 return true;
496}
497
498void
499in6_verify_ifscope(const struct in6_addr *in6, uint32_t ifscope)
500{
501 if (!in6_embedded_scope || !in6_embedded_scope_debug) {
502 return;
503 }
504
505 if (IN6_IS_SCOPE_EMBED(in6)) {
506 VERIFY(ntohs(in6->s6_addr16[1]) == ifscope);
507 }
508}
509