2  * Copyright (c) 2009-2010 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@ 
  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 $ */ 
  33  * Copyright (C) 2000 WIDE Project. 
  34  * All rights reserved. 
  36  * Redistribution and use in source and binary forms, with or without 
  37  * modification, are permitted provided that the following conditions 
  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. 
  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 
  61 #include <sys/param.h> 
  62 #include <sys/malloc.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> 
  70 #include <net/route.h> 
  73 #include <netinet/in.h> 
  75 #include <netinet6/in6_var.h> 
  76 #include <netinet6/scope6_var.h> 
  78 extern lck_mtx_t 
*scope6_mutex
; 
  80 #ifdef ENABLE_DEFAULT_SCOPE 
  81 int ip6_use_defzone 
= 1; 
  83 int ip6_use_defzone 
= 0; 
  86 static size_t if_scope_indexlim 
= 8; 
  87 struct scope6_id 
*scope6_ids 
= NULL
; 
  94          * We have some arrays that should be indexed by if_index. 
  95          * since if_index will grow dynamically, they should grow too. 
  97         lck_mtx_lock(scope6_mutex
); 
  98         if (scope6_ids 
== NULL 
|| if_index 
>= if_scope_indexlim
) { 
 101                 int newlim 
= if_scope_indexlim
; 
 103                 while (if_index 
>= newlim
) 
 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
); 
 111                         lck_mtx_unlock(scope6_mutex
); 
 114                 if_scope_indexlim 
= newlim
; 
 117                         bcopy((caddr_t
)scope6_ids
, q
, n
/2); 
 118                         FREE((caddr_t
)scope6_ids
, M_IFADDR
); 
 120                 scope6_ids 
= (struct scope6_id 
*)q
; 
 123 #define SID scope6_ids[ifp->if_index] 
 125         /* don't initialize if called twice */ 
 126         if (SID
.s6id_list
[IPV6_ADDR_SCOPE_LINKLOCAL
]) { 
 127                 lck_mtx_unlock(scope6_mutex
); 
 132          * XXX: IPV6_ADDR_SCOPE_xxx macros are not standard. 
 133          * Should we rather hardcode here? 
 135         SID
.s6id_list
[IPV6_ADDR_SCOPE_INTFACELOCAL
] = ifp
->if_index
; 
 136         SID
.s6id_list
[IPV6_ADDR_SCOPE_LINKLOCAL
] = ifp
->if_index
; 
 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; 
 143         lck_mtx_unlock(scope6_mutex
); 
 156         if (scope6_ids 
== NULL
) /* paranoid? */ 
 160          * XXX: We need more consistency checks of the relationship among 
 161          * scopes (e.g. an organization should be larger than a site). 
 165          * TODO(XXX): after setting, we should reflect the changes to 
 166          * interface addresses, routing table entries, PCB entries... 
 169         lck_mtx_lock(scope6_mutex
); 
 170         for (i 
= 0; i 
< 16; i
++) { 
 172                     idlist
[i
] != scope6_ids
[ifp
->if_index
].s6id_list
[i
]) { 
 173                         if (i 
== IPV6_ADDR_SCOPE_INTFACELOCAL 
&& 
 174                             idlist
[i
] > if_index
) { 
 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. 
 181                                 lck_mtx_unlock(scope6_mutex
); 
 186                          * XXX: we must need lots of work in this case, 
 187                          * but we simply set the new value in this initial 
 190                         scope6_ids
[ifp
->if_index
].s6id_list
[i
] = idlist
[i
]; 
 193         lck_mtx_unlock(scope6_mutex
); 
 203         if (scope6_ids 
== NULL
) /* paranoid? */ 
 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
); 
 216  * Get a scope of the address. Node-local, link-local, site-local or global. 
 220 struct in6_addr 
*addr
; 
 224         if (addr
->s6_addr8
[0] == 0xfe) { 
 225                 scope 
= addr
->s6_addr8
[1] & 0xc0; 
 229                         return IPV6_ADDR_SCOPE_LINKLOCAL
; 
 232                         return IPV6_ADDR_SCOPE_SITELOCAL
; 
 235                         return IPV6_ADDR_SCOPE_GLOBAL
; /* just in case */ 
 241         if (addr
->s6_addr8
[0] == 0xff) { 
 242                 scope 
= addr
->s6_addr8
[1] & 0x0f; 
 245                  * due to other scope such as reserved, 
 246                  * return scope doesn't work. 
 249                 case IPV6_ADDR_SCOPE_INTFACELOCAL
: 
 250                         return IPV6_ADDR_SCOPE_INTFACELOCAL
; 
 252                 case IPV6_ADDR_SCOPE_LINKLOCAL
: 
 253                         return IPV6_ADDR_SCOPE_LINKLOCAL
; 
 255                 case IPV6_ADDR_SCOPE_SITELOCAL
: 
 256                         return IPV6_ADDR_SCOPE_SITELOCAL
; 
 259                         return IPV6_ADDR_SCOPE_GLOBAL
; 
 265          * Regard loopback and unspecified addresses as global, since 
 266          * they have no ambiguity. 
 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? */ 
 275         return IPV6_ADDR_SCOPE_GLOBAL
; 
 280         struct ifnet 
*ifp
,      /* must not be NULL */ 
 281         struct in6_addr 
*addr
)  /* must not be NULL */ 
 283         int scope 
= in6_addrscope(addr
); 
 284         int index 
= ifp
->if_index
; 
 287         if (scope6_ids 
== NULL
) /* paranoid? */ 
 290         lck_mtx_lock(scope6_mutex
); 
 291         if (index 
>= if_scope_indexlim
) { 
 292                 lck_mtx_unlock(scope6_mutex
); 
 296 #define SID scope6_ids[index] 
 298         case IPV6_ADDR_SCOPE_NODELOCAL
: 
 299                 retid 
= -1;     /* XXX: is this an appropriate value? */ 
 301         case IPV6_ADDR_SCOPE_LINKLOCAL
: 
 302                 retid
=SID
.s6id_list
[IPV6_ADDR_SCOPE_LINKLOCAL
]; 
 304         case IPV6_ADDR_SCOPE_SITELOCAL
: 
 305                 retid
=SID
.s6id_list
[IPV6_ADDR_SCOPE_SITELOCAL
]; 
 307         case IPV6_ADDR_SCOPE_ORGLOCAL
: 
 308                 retid
=SID
.s6id_list
[IPV6_ADDR_SCOPE_ORGLOCAL
]; 
 311                 break;  /* XXX: value 0, treat as global. */ 
 315         lck_mtx_unlock(scope6_mutex
); 
 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 
 328 sa6_embedscope(struct sockaddr_in6 
*sin6
, int defaultok
) 
 333         if ((zoneid 
= sin6
->sin6_scope_id
) == 0 && defaultok
) 
 334                 zoneid 
= scope6_addr2default(&sin6
->sin6_addr
); 
 337             (IN6_IS_SCOPE_LINKLOCAL(&sin6
->sin6_addr
) || 
 338             IN6_IS_ADDR_MC_INTFACELOCAL(&sin6
->sin6_addr
))) { 
 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 
 345                 if (if_index 
< zoneid
) 
 347                 ifnet_head_lock_shared(); 
 348                 ifp 
= ifindex2ifnet
[zoneid
]; 
 349                 if (ifp 
== NULL
) {/* XXX: this can happen for some OS */ 
 354                 /* XXX assignment to 16bit from 32bit variable */ 
 355                 sin6
->sin6_addr
.s6_addr16
[1] = htons(zoneid 
& 0xffff); 
 357                 sin6
->sin6_scope_id 
= 0; 
 364 rtkey_to_sa6(struct rtentry 
*rt
, struct sockaddr_in6 
*sin6
) 
 366         VERIFY(rt_key(rt
)->sa_family 
== AF_INET6
); 
 368         *sin6 
= *((struct sockaddr_in6 
*)rt_key(rt
)); 
 369         sin6
->sin6_scope_id 
= 0; 
 373 rtgw_to_sa6(struct rtentry 
*rt
, struct sockaddr_in6 
*sin6
) 
 375         VERIFY(rt
->rt_flags 
& RTF_GATEWAY
); 
 377         *sin6 
= *((struct sockaddr_in6 
*)rt
->rt_gateway
); 
 378         sin6
->sin6_scope_id 
= 0; 
 382  * generate standard sockaddr_in6 from embedded form. 
 385 sa6_recoverscope(struct sockaddr_in6 
*sin6
) 
 389         if (sin6
->sin6_scope_id 
!= 0) { 
 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... */ 
 395         if (IN6_IS_SCOPE_LINKLOCAL(&sin6
->sin6_addr
) || 
 396             IN6_IS_ADDR_MC_INTFACELOCAL(&sin6
->sin6_addr
)) { 
 398                  * KAME assumption: link id == interface id 
 400                 zoneid 
= ntohs(sin6
->sin6_addr
.s6_addr16
[1]); 
 403                         if (if_index 
< zoneid
) 
 405                         ifnet_head_lock_shared(); 
 406                         if (ifindex2ifnet
[zoneid
] == NULL
) { 
 411                         sin6
->sin6_addr
.s6_addr16
[1] = 0; 
 412                         sin6
->sin6_scope_id 
= zoneid
; 
 421         struct ifnet 
*ifp
)      /* note that this might be NULL */ 
 424          * Currently, this function just set the default "link" according to 
 425          * the given interface. 
 426          * We might eventually have to separate the notion of "link" from 
 427          * "interface" and provide a user interface to set the default. 
 429         lck_mtx_lock(scope6_mutex
); 
 431                 scope6_ids
[0].s6id_list
[IPV6_ADDR_SCOPE_INTFACELOCAL
] = 
 433                 scope6_ids
[0].s6id_list
[IPV6_ADDR_SCOPE_LINKLOCAL
] = 
 436                 scope6_ids
[0].s6id_list
[IPV6_ADDR_SCOPE_INTFACELOCAL
] = 0; 
 437                 scope6_ids
[0].s6id_list
[IPV6_ADDR_SCOPE_LINKLOCAL
] = 0; 
 439         lck_mtx_unlock(scope6_mutex
); 
 446         if (scope6_ids 
== NULL
) /* paranoid? */ 
 449         lck_mtx_lock(scope6_mutex
); 
 450         bcopy(scope6_ids
[0].s6id_list
, idlist
, 
 451               sizeof(scope6_ids
[0].s6id_list
)); 
 452         lck_mtx_unlock(scope6_mutex
); 
 459         struct in6_addr 
*addr
) 
 462         int index 
= in6_addrscope(addr
); 
 463         lck_mtx_lock(scope6_mutex
); 
 464         id 
= scope6_ids
[0].s6id_list
[index
]; 
 465         lck_mtx_unlock(scope6_mutex
); 
 470  * Determine the appropriate scope zone ID for in6 and ifp.  If ret_id is 
 471  * non NULL, it is set to the zone ID.  If the zone ID needs to be embedded 
 472  * in the in6_addr structure, in6 will be modified. 
 474  * ret_id - unnecessary? 
 477 in6_setscope(struct in6_addr 
*in6
, struct ifnet 
*ifp
, u_int32_t 
*ret_id
) 
 480         u_int32_t zoneid 
= 0; 
 481         int index 
= ifp
->if_index
; 
 484         if (scope6_ids 
== NULL
) { /* should not happen */ 
 485                 panic("in6_setscope: scope array is NULL"); 
 491          * special case: the loopback address can only belong to a loopback 
 494         if (IN6_IS_ADDR_LOOPBACK(in6
)) { 
 495                 if (!(ifp
->if_flags 
& IFF_LOOPBACK
)) { 
 499                                 *ret_id 
= 0; /* there's no ambiguity */ 
 504         scope 
= in6_addrscope(in6
); 
 506 #define SID scope6_ids[index] 
 507         lck_mtx_lock(scope6_mutex
); 
 509         case IPV6_ADDR_SCOPE_INTFACELOCAL
: /* should be interface index */ 
 510                 zoneid 
= SID
.s6id_list
[IPV6_ADDR_SCOPE_INTFACELOCAL
]; 
 513         case IPV6_ADDR_SCOPE_LINKLOCAL
: 
 514                 zoneid 
= SID
.s6id_list
[IPV6_ADDR_SCOPE_LINKLOCAL
]; 
 517         case IPV6_ADDR_SCOPE_SITELOCAL
: 
 518                 zoneid 
= SID
.s6id_list
[IPV6_ADDR_SCOPE_SITELOCAL
]; 
 521         case IPV6_ADDR_SCOPE_ORGLOCAL
: 
 522                 zoneid 
= SID
.s6id_list
[IPV6_ADDR_SCOPE_ORGLOCAL
]; 
 526                 zoneid 
= 0;     /* XXX: treat as global. */ 
 529         lck_mtx_unlock(scope6_mutex
); 
 534         if (IN6_IS_SCOPE_LINKLOCAL(in6
) || IN6_IS_ADDR_MC_INTFACELOCAL(in6
)) 
 535                 in6
->s6_addr16
[1] = htons(zoneid 
& 0xffff); /* XXX */ 
 541  * Just clear the embedded scope identifier.  Return 0 if the original address 
 542  * is intact; return non 0 if the address is modified. 
 545 in6_clearscope(struct in6_addr 
*in6
) 
 549         if (IN6_IS_SCOPE_LINKLOCAL(in6
) || IN6_IS_ADDR_MC_INTFACELOCAL(in6
)) { 
 550                 if (in6
->s6_addr16
[1] != 0) 
 552                 in6
->s6_addr16
[1] = 0;