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