2 * Copyright (c) 2009-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@
30 * Copyright (C) 2000 WIDE Project.
31 * All rights reserved.
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
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.
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
58 #include <sys/param.h>
59 #include <sys/malloc.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>
67 #include <net/route.h>
70 #include <netinet/in.h>
72 #include <netinet6/in6_var.h>
73 #include <netinet6/scope6_var.h>
75 #ifdef ENABLE_DEFAULT_SCOPE
76 int ip6_use_defzone
= 1;
78 int ip6_use_defzone
= 0;
81 decl_lck_mtx_data(static, scope6_lock
);
82 static struct scope6_id sid_default
;
84 #define SID(ifp) &IN6_IFEXTRA(ifp)->scope6_id
87 scope6_init(lck_grp_t
*grp
, lck_attr_t
*attr
)
89 bzero(&sid_default
, sizeof(sid_default
));
90 lck_mtx_init(&scope6_lock
, grp
, attr
);
94 scope6_ifattach(struct ifnet
*ifp
)
96 struct scope6_id
*sid
;
98 VERIFY(IN6_IFEXTRA(ifp
) != NULL
);
99 if_inet6data_lock_exclusive(ifp
);
101 /* N.B.: the structure is already zero'ed */
103 * XXX: IPV6_ADDR_SCOPE_xxx macros are not standard.
104 * Should we rather hardcode here?
106 sid
->s6id_list
[IPV6_ADDR_SCOPE_INTFACELOCAL
] = ifp
->if_index
;
107 sid
->s6id_list
[IPV6_ADDR_SCOPE_LINKLOCAL
] = ifp
->if_index
;
109 /* by default, we don't care about scope boundary for these scopes. */
110 sid
->s6id_list
[IPV6_ADDR_SCOPE_SITELOCAL
] = 1;
111 sid
->s6id_list
[IPV6_ADDR_SCOPE_ORGLOCAL
] = 1;
113 if_inet6data_lock_done(ifp
);
117 * Get a scope of the address. Node-local, link-local, site-local or global.
120 in6_addrscope(struct in6_addr
*addr
)
124 if (addr
->s6_addr8
[0] == 0xfe) {
125 scope
= addr
->s6_addr8
[1] & 0xc0;
129 return IPV6_ADDR_SCOPE_LINKLOCAL
;
131 return IPV6_ADDR_SCOPE_SITELOCAL
;
133 return IPV6_ADDR_SCOPE_GLOBAL
; /* just in case */
137 if (addr
->s6_addr8
[0] == 0xff) {
138 scope
= addr
->s6_addr8
[1] & 0x0f;
141 * due to other scope such as reserved,
142 * return scope doesn't work.
145 case IPV6_ADDR_SCOPE_INTFACELOCAL
:
146 return IPV6_ADDR_SCOPE_INTFACELOCAL
;
147 case IPV6_ADDR_SCOPE_LINKLOCAL
:
148 return IPV6_ADDR_SCOPE_LINKLOCAL
;
149 case IPV6_ADDR_SCOPE_SITELOCAL
:
150 return IPV6_ADDR_SCOPE_SITELOCAL
;
152 return IPV6_ADDR_SCOPE_GLOBAL
;
157 * Regard loopback and unspecified addresses as global, since
158 * they have no ambiguity.
160 if (bcmp(&in6addr_loopback
, addr
, sizeof(*addr
) - 1) == 0) {
161 if (addr
->s6_addr8
[15] == 1) { /* loopback */
162 return IPV6_ADDR_SCOPE_LINKLOCAL
;
164 if (addr
->s6_addr8
[15] == 0) { /* unspecified */
165 return IPV6_ADDR_SCOPE_GLOBAL
; /* XXX: correct? */
169 return IPV6_ADDR_SCOPE_GLOBAL
;
173 in6_addr2scopeid(struct ifnet
*ifp
, struct in6_addr
*addr
)
175 int scope
= in6_addrscope(addr
);
177 struct scope6_id
*sid
;
179 if_inet6data_lock_shared(ifp
);
180 if (IN6_IFEXTRA(ifp
) == NULL
) {
185 case IPV6_ADDR_SCOPE_NODELOCAL
:
186 retid
= -1; /* XXX: is this an appropriate value? */
188 case IPV6_ADDR_SCOPE_LINKLOCAL
:
189 retid
= sid
->s6id_list
[IPV6_ADDR_SCOPE_LINKLOCAL
];
191 case IPV6_ADDR_SCOPE_SITELOCAL
:
192 retid
= sid
->s6id_list
[IPV6_ADDR_SCOPE_SITELOCAL
];
194 case IPV6_ADDR_SCOPE_ORGLOCAL
:
195 retid
= sid
->s6id_list
[IPV6_ADDR_SCOPE_ORGLOCAL
];
198 break; /* XXX: value 0, treat as global. */
201 if_inet6data_lock_done(ifp
);
207 * Validate the specified scope zone ID in the sin6_scope_id field. If the ID
208 * is unspecified (=0), needs to be specified, and the default zone ID can be
209 * used, the default value will be used.
210 * This routine then generates the kernel-internal form: if the address scope
211 * of is interface-local or link-local, embed the interface index in the
215 sa6_embedscope(struct sockaddr_in6
*sin6
, int defaultok
)
220 if ((zoneid
= sin6
->sin6_scope_id
) == 0 && defaultok
) {
221 zoneid
= scope6_addr2default(&sin6
->sin6_addr
);
225 (IN6_IS_SCOPE_LINKLOCAL(&sin6
->sin6_addr
) ||
226 IN6_IS_ADDR_MC_INTFACELOCAL(&sin6
->sin6_addr
))) {
228 * At this moment, we only check interface-local and
229 * link-local scope IDs, and use interface indices as the
230 * zone IDs assuming a one-to-one mapping between interfaces
233 if (if_index
< zoneid
) {
236 ifnet_head_lock_shared();
237 ifp
= ifindex2ifnet
[zoneid
];
238 if (ifp
== NULL
) { /* XXX: this can happen for some OS */
243 /* XXX assignment to 16bit from 32bit variable */
244 sin6
->sin6_addr
.s6_addr16
[1] = htons(zoneid
& 0xffff);
246 sin6
->sin6_scope_id
= 0;
253 rtkey_to_sa6(struct rtentry
*rt
, struct sockaddr_in6
*sin6
)
255 VERIFY(rt_key(rt
)->sa_family
== AF_INET6
);
257 *sin6
= *((struct sockaddr_in6
*)(void *)rt_key(rt
));
258 sin6
->sin6_scope_id
= 0;
262 rtgw_to_sa6(struct rtentry
*rt
, struct sockaddr_in6
*sin6
)
264 VERIFY(rt
->rt_flags
& RTF_GATEWAY
);
266 *sin6
= *((struct sockaddr_in6
*)(void *)rt
->rt_gateway
);
267 sin6
->sin6_scope_id
= 0;
271 * generate standard sockaddr_in6 from embedded form.
274 sa6_recoverscope(struct sockaddr_in6
*sin6
, boolean_t attachcheck
)
278 if (sin6
->sin6_scope_id
!= 0) {
280 "sa6_recoverscope: assumption failure (non 0 ID): %s%%%d\n",
281 ip6_sprintf(&sin6
->sin6_addr
), sin6
->sin6_scope_id
);
282 /* XXX: proceed anyway... */
284 if (IN6_IS_SCOPE_LINKLOCAL(&sin6
->sin6_addr
) ||
285 IN6_IS_ADDR_MC_INTFACELOCAL(&sin6
->sin6_addr
)) {
287 * KAME assumption: link id == interface id
289 zoneid
= ntohs(sin6
->sin6_addr
.s6_addr16
[1]);
292 if (if_index
< zoneid
) {
296 * We use the attachcheck parameter to skip the
297 * interface attachment check.
298 * Some callers might hold the ifnet_head lock in
299 * exclusive mode. This means that:
300 * 1) the interface can't go away -- hence we don't
301 * need to perform this check
302 * 2) we can't perform this check because the lock is
303 * in exclusive mode and trying to lock it in shared
304 * mode would cause a deadlock.
307 ifnet_head_lock_shared();
308 if (ifindex2ifnet
[zoneid
] == NULL
) {
314 sin6
->sin6_addr
.s6_addr16
[1] = 0;
315 sin6
->sin6_scope_id
= zoneid
;
323 scope6_setdefault(struct ifnet
*ifp
)
326 * Currently, this function just set the default "link" according to
327 * the given interface.
328 * We might eventually have to separate the notion of "link" from
329 * "interface" and provide a user interface to set the default.
331 lck_mtx_lock(&scope6_lock
);
333 sid_default
.s6id_list
[IPV6_ADDR_SCOPE_INTFACELOCAL
] =
335 sid_default
.s6id_list
[IPV6_ADDR_SCOPE_LINKLOCAL
] =
338 sid_default
.s6id_list
[IPV6_ADDR_SCOPE_INTFACELOCAL
] = 0;
339 sid_default
.s6id_list
[IPV6_ADDR_SCOPE_LINKLOCAL
] = 0;
341 lck_mtx_unlock(&scope6_lock
);
346 scope6_addr2default(struct in6_addr
*addr
)
349 int index
= in6_addrscope(addr
);
352 * special case: The loopback address should be considered as
353 * link-local, but there's no ambiguity in the syntax.
355 if (IN6_IS_ADDR_LOOPBACK(addr
)) {
359 lck_mtx_lock(&scope6_lock
);
360 id
= sid_default
.s6id_list
[index
];
361 lck_mtx_unlock(&scope6_lock
);
367 * Determine the appropriate scope zone ID for in6 and ifp. If ret_id is
368 * non NULL, it is set to the zone ID. If the zone ID needs to be embedded
369 * in the in6_addr structure, in6 will be modified.
371 * ret_id - unnecessary?
374 in6_setscope(struct in6_addr
*in6
, struct ifnet
*ifp
, u_int32_t
*ret_id
)
377 u_int32_t zoneid
= 0;
378 struct scope6_id
*sid
;
381 * special case: the loopback address can only belong to a loopback
384 if (IN6_IS_ADDR_LOOPBACK(in6
)) {
385 if (!(ifp
->if_flags
& IFF_LOOPBACK
)) {
388 if (ret_id
!= NULL
) {
389 *ret_id
= 0; /* there's no ambiguity */
395 scope
= in6_addrscope(in6
);
397 if_inet6data_lock_shared(ifp
);
398 if (IN6_IFEXTRA(ifp
) == NULL
) {
399 if_inet6data_lock_done(ifp
);
407 case IPV6_ADDR_SCOPE_INTFACELOCAL
: /* should be interface index */
408 zoneid
= sid
->s6id_list
[IPV6_ADDR_SCOPE_INTFACELOCAL
];
411 case IPV6_ADDR_SCOPE_LINKLOCAL
:
412 zoneid
= sid
->s6id_list
[IPV6_ADDR_SCOPE_LINKLOCAL
];
415 case IPV6_ADDR_SCOPE_SITELOCAL
:
416 zoneid
= sid
->s6id_list
[IPV6_ADDR_SCOPE_SITELOCAL
];
419 case IPV6_ADDR_SCOPE_ORGLOCAL
:
420 zoneid
= sid
->s6id_list
[IPV6_ADDR_SCOPE_ORGLOCAL
];
423 zoneid
= 0; /* XXX: treat as global. */
426 if_inet6data_lock_done(ifp
);
428 if (ret_id
!= NULL
) {
432 if (IN6_IS_SCOPE_LINKLOCAL(in6
) || IN6_IS_ADDR_MC_INTFACELOCAL(in6
)) {
433 in6
->s6_addr16
[1] = htons(zoneid
& 0xffff); /* XXX */
439 * Just clear the embedded scope identifier. Return 0 if the original address
440 * is intact; return non 0 if the address is modified.
443 in6_clearscope(struct in6_addr
*in6
)
447 if (IN6_IS_SCOPE_LINKLOCAL(in6
) || IN6_IS_ADDR_MC_INTFACELOCAL(in6
)) {
448 if (in6
->s6_addr16
[1] != 0) {
451 in6
->s6_addr16
[1] = 0;