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 81decl_lck_mtx_data(static, scope6_lock); 82static struct scope6_id sid_default; 83 84#define SID(ifp) &IN6_IFEXTRA(ifp)->scope6_id 85 86void 87scope6_init(lck_grp_t *grp, lck_attr_t *attr) 88{ 89 bzero(&sid_default, sizeof(sid_default)); 90 lck_mtx_init(&scope6_lock, grp, attr); 91} 92 93void 94scope6_ifattach(struct ifnet *ifp) 95{ 96 struct scope6_id *sid; 97 98 VERIFY(IN6_IFEXTRA(ifp) != NULL); 99 if_inet6data_lock_exclusive(ifp); 100 sid = SID(ifp); 101 /* N.B.: the structure is already zero'ed */ 102 /* 103 * XXX: IPV6_ADDR_SCOPE_xxx macros are not standard. 104 * Should we rather hardcode here? 105 */ 106 sid->s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] = ifp->if_index; 107 sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = ifp->if_index; 108#if MULTI_SCOPE 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; 112#endif 113 if_inet6data_lock_done(ifp); 114} 115 116/* 117 * Get a scope of the address. Node-local, link-local, site-local or global. 118 */ 119int 120in6_addrscope(struct in6_addr *addr) 121{ 122 int scope; 123 124 if (addr->s6_addr8[0] == 0xfe) { 125 scope = addr->s6_addr8[1] & 0xc0; 126 127 switch (scope) { 128 case 0x80: 129 return (IPV6_ADDR_SCOPE_LINKLOCAL); 130 case 0xc0: 131 return (IPV6_ADDR_SCOPE_SITELOCAL); 132 default: 133 return (IPV6_ADDR_SCOPE_GLOBAL); /* just in case */ 134 } 135 } 136 137 if (addr->s6_addr8[0] == 0xff) { 138 scope = addr->s6_addr8[1] & 0x0f; 139 140 /* 141 * due to other scope such as reserved, 142 * return scope doesn't work. 143 */ 144 switch (scope) { 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); 151 default: 152 return (IPV6_ADDR_SCOPE_GLOBAL); 153 } 154 } 155 156 /* 157 * Regard loopback and unspecified addresses as global, since 158 * they have no ambiguity. 159 */ 160 if (bcmp(&in6addr_loopback, addr, sizeof (*addr) - 1) == 0) { 161 if (addr->s6_addr8[15] == 1) /* loopback */ 162 return (IPV6_ADDR_SCOPE_LINKLOCAL); 163 if (addr->s6_addr8[15] == 0) /* unspecified */ 164 return (IPV6_ADDR_SCOPE_GLOBAL); /* XXX: correct? */ 165 } 166 167 return (IPV6_ADDR_SCOPE_GLOBAL); 168} 169 170int 171in6_addr2scopeid(struct ifnet *ifp, struct in6_addr *addr) 172{ 173 int scope = in6_addrscope(addr); 174 int retid = 0; 175 struct scope6_id *sid; 176 177 if_inet6data_lock_shared(ifp); 178 if (IN6_IFEXTRA(ifp) == NULL) 179 goto err; 180 sid = SID(ifp); 181 switch (scope) { 182 case IPV6_ADDR_SCOPE_NODELOCAL: 183 retid = -1; /* XXX: is this an appropriate value? */ 184 break; 185 case IPV6_ADDR_SCOPE_LINKLOCAL: 186 retid = sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL]; 187 break; 188 case IPV6_ADDR_SCOPE_SITELOCAL: 189 retid = sid->s6id_list[IPV6_ADDR_SCOPE_SITELOCAL]; 190 break; 191 case IPV6_ADDR_SCOPE_ORGLOCAL: 192 retid = sid->s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL]; 193 break; 194 default: 195 break; /* XXX: value 0, treat as global. */ 196 } 197err: 198 if_inet6data_lock_done(ifp); 199 200 return (retid); 201} 202 203/* 204 * Validate the specified scope zone ID in the sin6_scope_id field. If the ID 205 * is unspecified (=0), needs to be specified, and the default zone ID can be 206 * used, the default value will be used. 207 * This routine then generates the kernel-internal form: if the address scope 208 * of is interface-local or link-local, embed the interface index in the 209 * address. 210 */ 211int 212sa6_embedscope(struct sockaddr_in6 *sin6, int defaultok) 213{ 214 struct ifnet *ifp; 215 u_int32_t zoneid; 216 217 if ((zoneid = sin6->sin6_scope_id) == 0 && defaultok) 218 zoneid = scope6_addr2default(&sin6->sin6_addr); 219 220 if (zoneid != 0 && 221 (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) || 222 IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr))) { 223 /* 224 * At this moment, we only check interface-local and 225 * link-local scope IDs, and use interface indices as the 226 * zone IDs assuming a one-to-one mapping between interfaces 227 * and links. 228 */ 229 if (if_index < zoneid) 230 return (ENXIO); 231 ifnet_head_lock_shared(); 232 ifp = ifindex2ifnet[zoneid]; 233 if (ifp == NULL) { /* XXX: this can happen for some OS */ 234 ifnet_head_done(); 235 return (ENXIO); 236 } 237 ifnet_head_done(); 238 /* XXX assignment to 16bit from 32bit variable */ 239 sin6->sin6_addr.s6_addr16[1] = htons(zoneid & 0xffff); 240 241 sin6->sin6_scope_id = 0; 242 } 243 244 return (0); 245} 246 247void 248rtkey_to_sa6(struct rtentry *rt, struct sockaddr_in6 *sin6) 249{ 250 VERIFY(rt_key(rt)->sa_family == AF_INET6); 251 252 *sin6 = *((struct sockaddr_in6 *)(void *)rt_key(rt)); 253 sin6->sin6_scope_id = 0; 254} 255 256void 257rtgw_to_sa6(struct rtentry *rt, struct sockaddr_in6 *sin6) 258{ 259 VERIFY(rt->rt_flags & RTF_GATEWAY); 260 261 *sin6 = *((struct sockaddr_in6 *)(void *)rt->rt_gateway); 262 sin6->sin6_scope_id = 0; 263} 264 265/* 266 * generate standard sockaddr_in6 from embedded form. 267 */ 268int 269sa6_recoverscope(struct sockaddr_in6 *sin6, boolean_t attachcheck) 270{ 271 u_int32_t zoneid; 272 273 if (sin6->sin6_scope_id != 0) { 274 log(LOG_NOTICE, 275 "sa6_recoverscope: assumption failure (non 0 ID): %s%%%d\n", 276 ip6_sprintf(&sin6->sin6_addr), sin6->sin6_scope_id); 277 /* XXX: proceed anyway... */ 278 } 279 if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) || 280 IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) { 281 /* 282 * KAME assumption: link id == interface id 283 */ 284 zoneid = ntohs(sin6->sin6_addr.s6_addr16[1]); 285 if (zoneid) { 286 /* sanity check */ 287 if (if_index < zoneid) 288 return (ENXIO); 289 /* 290 * We use the attachcheck parameter to skip the 291 * interface attachment check. 292 * Some callers might hold the ifnet_head lock in 293 * exclusive mode. This means that: 294 * 1) the interface can't go away -- hence we don't 295 * need to perform this check 296 * 2) we can't perform this check because the lock is 297 * in exclusive mode and trying to lock it in shared 298 * mode would cause a deadlock. 299 */ 300 if (attachcheck) { 301 ifnet_head_lock_shared(); 302 if (ifindex2ifnet[zoneid] == NULL) { 303 ifnet_head_done(); 304 return (ENXIO); 305 } 306 ifnet_head_done(); 307 } 308 sin6->sin6_addr.s6_addr16[1] = 0; 309 sin6->sin6_scope_id = zoneid; 310 } 311 } 312 313 return (0); 314} 315 316void 317scope6_setdefault(struct ifnet *ifp) 318{ 319 /* 320 * Currently, this function just set the default "link" according to 321 * the given interface. 322 * We might eventually have to separate the notion of "link" from 323 * "interface" and provide a user interface to set the default. 324 */ 325 lck_mtx_lock(&scope6_lock); 326 if (ifp != NULL) { 327 sid_default.s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] = 328 ifp->if_index; 329 sid_default.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = 330 ifp->if_index; 331 } else { 332 sid_default.s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] = 0; 333 sid_default.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = 0; 334 } 335 lck_mtx_unlock(&scope6_lock); 336} 337 338 339u_int32_t 340scope6_addr2default(struct in6_addr *addr) 341{ 342 u_int32_t id = 0; 343 int index = in6_addrscope(addr); 344 345 /* 346 * special case: The loopback address should be considered as 347 * link-local, but there's no ambiguity in the syntax. 348 */ 349 if (IN6_IS_ADDR_LOOPBACK(addr)) 350 return (0); 351 352 lck_mtx_lock(&scope6_lock); 353 id = sid_default.s6id_list[index]; 354 lck_mtx_unlock(&scope6_lock); 355 356 return (id); 357} 358 359/* 360 * Determine the appropriate scope zone ID for in6 and ifp. If ret_id is 361 * non NULL, it is set to the zone ID. If the zone ID needs to be embedded 362 * in the in6_addr structure, in6 will be modified. 363 * 364 * ret_id - unnecessary? 365 */ 366int 367in6_setscope(struct in6_addr *in6, struct ifnet *ifp, u_int32_t *ret_id) 368{ 369 int scope; 370 u_int32_t zoneid = 0; 371 struct scope6_id *sid; 372 373 /* 374 * special case: the loopback address can only belong to a loopback 375 * interface. 376 */ 377 if (IN6_IS_ADDR_LOOPBACK(in6)) { 378 if (!(ifp->if_flags & IFF_LOOPBACK)) { 379 return (EINVAL); 380 } else { 381 if (ret_id != NULL) 382 *ret_id = 0; /* there's no ambiguity */ 383 return (0); 384 } 385 } 386 387 scope = in6_addrscope(in6); 388 389 if_inet6data_lock_shared(ifp); 390 if (IN6_IFEXTRA(ifp) == NULL) { 391 if_inet6data_lock_done(ifp); 392 if (ret_id) 393 *ret_id = 0; 394 return (EINVAL); 395 } 396 sid = SID(ifp); 397 switch (scope) { 398 case IPV6_ADDR_SCOPE_INTFACELOCAL: /* should be interface index */ 399 zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL]; 400 break; 401 402 case IPV6_ADDR_SCOPE_LINKLOCAL: 403 zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL]; 404 break; 405 406 case IPV6_ADDR_SCOPE_SITELOCAL: 407 zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_SITELOCAL]; 408 break; 409 410 case IPV6_ADDR_SCOPE_ORGLOCAL: 411 zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL]; 412 break; 413 default: 414 zoneid = 0; /* XXX: treat as global. */ 415 break; 416 } 417 if_inet6data_lock_done(ifp); 418 419 if (ret_id != NULL) 420 *ret_id = zoneid; 421 422 if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6)) 423 in6->s6_addr16[1] = htons(zoneid & 0xffff); /* XXX */ 424 425 return (0); 426} 427 428/* 429 * Just clear the embedded scope identifier. Return 0 if the original address 430 * is intact; return non 0 if the address is modified. 431 */ 432int 433in6_clearscope(struct in6_addr *in6) 434{ 435 int modified = 0; 436 437 if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6)) { 438 if (in6->s6_addr16[1] != 0) 439 modified = 1; 440 in6->s6_addr16[1] = 0; 441 } 442 443 return (modified); 444} 445