scope6.c revision 171259
162587Sitojun/* $FreeBSD: head/sys/netinet6/scope6.c 171259 2007-07-05 16:23:49Z delphij $ */ 278064Sume/* $KAME: scope6.c,v 1.10 2000/07/24 13:29:31 itojun Exp $ */ 362587Sitojun 4139826Simp/*- 562587Sitojun * Copyright (C) 2000 WIDE Project. 662587Sitojun * All rights reserved. 7120941Sume * 862587Sitojun * Redistribution and use in source and binary forms, with or without 962587Sitojun * modification, are permitted provided that the following conditions 1062587Sitojun * are met: 1162587Sitojun * 1. Redistributions of source code must retain the above copyright 1262587Sitojun * notice, this list of conditions and the following disclaimer. 1362587Sitojun * 2. Redistributions in binary form must reproduce the above copyright 1462587Sitojun * notice, this list of conditions and the following disclaimer in the 1562587Sitojun * documentation and/or other materials provided with the distribution. 1662587Sitojun * 3. Neither the name of the project nor the names of its contributors 1762587Sitojun * may be used to endorse or promote products derived from this software 1862587Sitojun * without specific prior written permission. 19120941Sume * 2062587Sitojun * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2162587Sitojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2262587Sitojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2362587Sitojun * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2462587Sitojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2562587Sitojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2662587Sitojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2762587Sitojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2862587Sitojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2962587Sitojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3062587Sitojun * SUCH DAMAGE. 3162587Sitojun */ 3262587Sitojun 3362587Sitojun#include <sys/param.h> 3462587Sitojun#include <sys/malloc.h> 3562587Sitojun#include <sys/mbuf.h> 3662587Sitojun#include <sys/socket.h> 3762587Sitojun#include <sys/systm.h> 3878064Sume#include <sys/queue.h> 39148385Sume#include <sys/syslog.h> 4062587Sitojun 4162587Sitojun#include <net/route.h> 4262587Sitojun#include <net/if.h> 4362587Sitojun 4462587Sitojun#include <netinet/in.h> 4562587Sitojun 4662587Sitojun#include <netinet6/in6_var.h> 4762587Sitojun#include <netinet6/scope6_var.h> 4862587Sitojun 49148385Sume#ifdef ENABLE_DEFAULT_SCOPE 50148385Sumeint ip6_use_defzone = 1; 51148385Sume#else 52148385Sumeint ip6_use_defzone = 0; 53148385Sume#endif 54148385Sume 55121343Sume/* 56138184Sgnn * The scope6_lock protects the global sid default stored in 57138184Sgnn * sid_default below. 58121343Sume */ 59121343Sumestatic struct mtx scope6_lock; 60121343Sume#define SCOPE6_LOCK_INIT() mtx_init(&scope6_lock, "scope6_lock", NULL, MTX_DEF) 61121343Sume#define SCOPE6_LOCK() mtx_lock(&scope6_lock) 62121343Sume#define SCOPE6_UNLOCK() mtx_unlock(&scope6_lock) 63121343Sume#define SCOPE6_LOCK_ASSERT() mtx_assert(&scope6_lock, MA_OWNED) 64121343Sume 65121161Sumestatic struct scope6_id sid_default; 66121161Sume#define SID(ifp) \ 67121161Sume (((struct in6_ifextra *)(ifp)->if_afdata[AF_INET6])->scope6_id) 6862587Sitojun 6962587Sitojunvoid 70171259Sdelphijscope6_init(void) 71121161Sume{ 72121161Sume 73121343Sume SCOPE6_LOCK_INIT(); 74121161Sume bzero(&sid_default, sizeof(sid_default)); 75121161Sume} 76121161Sume 77121161Sumestruct scope6_id * 78171259Sdelphijscope6_ifattach(struct ifnet *ifp) 7962587Sitojun{ 80121161Sume struct scope6_id *sid; 8162587Sitojun 82121161Sume sid = (struct scope6_id *)malloc(sizeof(*sid), M_IFADDR, M_WAITOK); 83121161Sume bzero(sid, sizeof(*sid)); 8462587Sitojun 8562587Sitojun /* 8662587Sitojun * XXX: IPV6_ADDR_SCOPE_xxx macros are not standard. 8762587Sitojun * Should we rather hardcode here? 8862587Sitojun */ 89121315Sume sid->s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] = ifp->if_index; 90121161Sume sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = ifp->if_index; 9162587Sitojun#ifdef MULTI_SCOPE 9262587Sitojun /* by default, we don't care about scope boundary for these scopes. */ 93121161Sume sid->s6id_list[IPV6_ADDR_SCOPE_SITELOCAL] = 1; 94121161Sume sid->s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL] = 1; 9562587Sitojun#endif 9662587Sitojun 97121161Sume return sid; 9862587Sitojun} 9962587Sitojun 100121161Sumevoid 101171259Sdelphijscope6_ifdetach(struct scope6_id *sid) 102121161Sume{ 103121161Sume 104121161Sume free(sid, M_IFADDR); 105121161Sume} 106121161Sume 10762587Sitojunint 108171259Sdelphijscope6_set(struct ifnet *ifp, struct scope6_id *idlist) 10962587Sitojun{ 110138184Sgnn int i; 11162587Sitojun int error = 0; 112138184Sgnn struct scope6_id *sid = NULL; 11362587Sitojun 114138184Sgnn IF_AFDATA_LOCK(ifp); 115138184Sgnn sid = SID(ifp); 116138184Sgnn 117138184Sgnn if (!sid) { /* paranoid? */ 118138184Sgnn IF_AFDATA_UNLOCK(ifp); 119120856Sume return (EINVAL); 120138184Sgnn } 12162587Sitojun 12262587Sitojun /* 12362587Sitojun * XXX: We need more consistency checks of the relationship among 12462587Sitojun * scopes (e.g. an organization should be larger than a site). 12562587Sitojun */ 12662587Sitojun 12762587Sitojun /* 12862587Sitojun * TODO(XXX): after setting, we should reflect the changes to 129120941Sume * interface addresses, routing table entries, PCB entries... 13062587Sitojun */ 13162587Sitojun 132121343Sume SCOPE6_LOCK(); 13362587Sitojun for (i = 0; i < 16; i++) { 134121161Sume if (idlist->s6id_list[i] && 135121161Sume idlist->s6id_list[i] != sid->s6id_list[i]) { 136121315Sume /* 137121315Sume * An interface zone ID must be the corresponding 138121315Sume * interface index by definition. 139121315Sume */ 140121315Sume if (i == IPV6_ADDR_SCOPE_INTFACELOCAL && 141121315Sume idlist->s6id_list[i] != ifp->if_index) { 142138184Sgnn IF_AFDATA_UNLOCK(ifp); 143138184Sgnn SCOPE6_UNLOCK(); 144121315Sume return (EINVAL); 145121315Sume } 146121315Sume 14762587Sitojun if (i == IPV6_ADDR_SCOPE_LINKLOCAL && 148121161Sume idlist->s6id_list[i] > if_index) { 14962587Sitojun /* 15062587Sitojun * XXX: theoretically, there should be no 15162587Sitojun * relationship between link IDs and interface 15262587Sitojun * IDs, but we check the consistency for 15362587Sitojun * safety in later use. 15462587Sitojun */ 155138184Sgnn IF_AFDATA_UNLOCK(ifp); 156138184Sgnn SCOPE6_UNLOCK(); 157120856Sume return (EINVAL); 15862587Sitojun } 15962587Sitojun 16062587Sitojun /* 16162587Sitojun * XXX: we must need lots of work in this case, 16262587Sitojun * but we simply set the new value in this initial 16362587Sitojun * implementation. 16462587Sitojun */ 165121161Sume sid->s6id_list[i] = idlist->s6id_list[i]; 16662587Sitojun } 16762587Sitojun } 168121343Sume SCOPE6_UNLOCK(); 169138184Sgnn IF_AFDATA_UNLOCK(ifp); 17062587Sitojun 171120856Sume return (error); 17262587Sitojun} 17362587Sitojun 17462587Sitojunint 175171259Sdelphijscope6_get(struct ifnet *ifp, struct scope6_id *idlist) 17662587Sitojun{ 177138184Sgnn /* We only need to lock the interface's afdata for SID() to work. */ 178138184Sgnn IF_AFDATA_LOCK(ifp); 179121161Sume struct scope6_id *sid = SID(ifp); 180121161Sume 181138184Sgnn if (sid == NULL) { /* paranoid? */ 182138184Sgnn IF_AFDATA_UNLOCK(ifp); 183120856Sume return (EINVAL); 184138184Sgnn } 18562587Sitojun 186121343Sume SCOPE6_LOCK(); 187121161Sume *idlist = *sid; 188121343Sume SCOPE6_UNLOCK(); 18962587Sitojun 190138184Sgnn IF_AFDATA_UNLOCK(ifp); 191120856Sume return (0); 19262587Sitojun} 19362587Sitojun 19462587Sitojun 19562587Sitojun/* 19662587Sitojun * Get a scope of the address. Node-local, link-local, site-local or global. 19762587Sitojun */ 19862587Sitojunint 199171259Sdelphijin6_addrscope(struct in6_addr *addr) 20062587Sitojun{ 20162587Sitojun int scope; 20262587Sitojun 203121315Sume if (addr->s6_addr[0] == 0xfe) { 204121315Sume scope = addr->s6_addr[1] & 0xc0; 20562587Sitojun 20662587Sitojun switch (scope) { 20762587Sitojun case 0x80: 20862587Sitojun return IPV6_ADDR_SCOPE_LINKLOCAL; 20962587Sitojun break; 21062587Sitojun case 0xc0: 21162587Sitojun return IPV6_ADDR_SCOPE_SITELOCAL; 21262587Sitojun break; 21362587Sitojun default: 21462587Sitojun return IPV6_ADDR_SCOPE_GLOBAL; /* just in case */ 21562587Sitojun break; 21662587Sitojun } 21762587Sitojun } 21862587Sitojun 21962587Sitojun 220121315Sume if (addr->s6_addr[0] == 0xff) { 221121315Sume scope = addr->s6_addr[1] & 0x0f; 22262587Sitojun 22362587Sitojun /* 22462587Sitojun * due to other scope such as reserved, 22562587Sitojun * return scope doesn't work. 22662587Sitojun */ 22762587Sitojun switch (scope) { 228121315Sume case IPV6_ADDR_SCOPE_INTFACELOCAL: 229121315Sume return IPV6_ADDR_SCOPE_INTFACELOCAL; 23062587Sitojun break; 23162587Sitojun case IPV6_ADDR_SCOPE_LINKLOCAL: 23262587Sitojun return IPV6_ADDR_SCOPE_LINKLOCAL; 23362587Sitojun break; 23462587Sitojun case IPV6_ADDR_SCOPE_SITELOCAL: 23562587Sitojun return IPV6_ADDR_SCOPE_SITELOCAL; 23662587Sitojun break; 23762587Sitojun default: 23862587Sitojun return IPV6_ADDR_SCOPE_GLOBAL; 23962587Sitojun break; 24062587Sitojun } 24162587Sitojun } 24262587Sitojun 243121315Sume /* 244121315Sume * Regard loopback and unspecified addresses as global, since 245121315Sume * they have no ambiguity. 246121315Sume */ 24793128Sume if (bcmp(&in6addr_loopback, addr, sizeof(*addr) - 1) == 0) { 248121315Sume if (addr->s6_addr[15] == 1) /* loopback */ 24962587Sitojun return IPV6_ADDR_SCOPE_LINKLOCAL; 250121315Sume if (addr->s6_addr[15] == 0) /* unspecified */ 251121315Sume return IPV6_ADDR_SCOPE_GLOBAL; /* XXX: correct? */ 25262587Sitojun } 25362587Sitojun 25462587Sitojun return IPV6_ADDR_SCOPE_GLOBAL; 25562587Sitojun} 25662587Sitojun 257171259Sdelphij/* 258171259Sdelphij * ifp - note that this might be NULL 259171259Sdelphij */ 260171259Sdelphij 26162587Sitojunvoid 262171259Sdelphijscope6_setdefault(struct ifnet *ifp) 26362587Sitojun{ 26462587Sitojun /* 265138184Sgnn * Currently, this function just sets the default "interfaces" 266121161Sume * and "links" according to the given interface. 26762587Sitojun * We might eventually have to separate the notion of "link" from 26862587Sitojun * "interface" and provide a user interface to set the default. 26962587Sitojun */ 270121343Sume SCOPE6_LOCK(); 27162587Sitojun if (ifp) { 272121315Sume sid_default.s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] = 27362587Sitojun ifp->if_index; 274121161Sume sid_default.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = 275121161Sume ifp->if_index; 276120941Sume } else { 277121315Sume sid_default.s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] = 0; 278121161Sume sid_default.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = 0; 27962587Sitojun } 280121343Sume SCOPE6_UNLOCK(); 28162587Sitojun} 28262587Sitojun 28362587Sitojunint 284171259Sdelphijscope6_get_default(struct scope6_id *idlist) 28562587Sitojun{ 286121343Sume 287121343Sume SCOPE6_LOCK(); 288121161Sume *idlist = sid_default; 289121343Sume SCOPE6_UNLOCK(); 29062587Sitojun 291120856Sume return (0); 29262587Sitojun} 29362587Sitojun 29462587Sitojunu_int32_t 295171259Sdelphijscope6_addr2default(struct in6_addr *addr) 29662587Sitojun{ 297121343Sume u_int32_t id; 298121343Sume 299121161Sume /* 300121161Sume * special case: The loopback address should be considered as 301121161Sume * link-local, but there's no ambiguity in the syntax. 302121161Sume */ 303121161Sume if (IN6_IS_ADDR_LOOPBACK(addr)) 304121161Sume return (0); 305121161Sume 306121343Sume /* 307121343Sume * XXX: 32-bit read is atomic on all our platforms, is it OK 308121343Sume * not to lock here? 309121343Sume */ 310121343Sume SCOPE6_LOCK(); 311121343Sume id = sid_default.s6id_list[in6_addrscope(addr)]; 312121343Sume SCOPE6_UNLOCK(); 313121343Sume return (id); 31462587Sitojun} 315148385Sume 316148385Sume/* 317148385Sume * Validate the specified scope zone ID in the sin6_scope_id field. If the ID 318148385Sume * is unspecified (=0), needs to be specified, and the default zone ID can be 319148385Sume * used, the default value will be used. 320148385Sume * This routine then generates the kernel-internal form: if the address scope 321148385Sume * of is interface-local or link-local, embed the interface index in the 322148385Sume * address. 323148385Sume */ 324148385Sumeint 325171259Sdelphijsa6_embedscope(struct sockaddr_in6 *sin6, int defaultok) 326148385Sume{ 327148385Sume struct ifnet *ifp; 328148385Sume u_int32_t zoneid; 329148385Sume 330148385Sume if ((zoneid = sin6->sin6_scope_id) == 0 && defaultok) 331148385Sume zoneid = scope6_addr2default(&sin6->sin6_addr); 332148385Sume 333148385Sume if (zoneid != 0 && 334148385Sume (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) || 335148385Sume IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr))) { 336148385Sume /* 337148385Sume * At this moment, we only check interface-local and 338148385Sume * link-local scope IDs, and use interface indices as the 339148385Sume * zone IDs assuming a one-to-one mapping between interfaces 340148385Sume * and links. 341148385Sume */ 342148385Sume if (if_index < zoneid) 343148385Sume return (ENXIO); 344148385Sume ifp = ifnet_byindex(zoneid); 345148385Sume if (ifp == NULL) /* XXX: this can happen for some OS */ 346148385Sume return (ENXIO); 347148385Sume 348148385Sume /* XXX assignment to 16bit from 32bit variable */ 349148385Sume sin6->sin6_addr.s6_addr16[1] = htons(zoneid & 0xffff); 350148385Sume 351148385Sume sin6->sin6_scope_id = 0; 352148385Sume } 353148385Sume 354148385Sume return 0; 355148385Sume} 356148385Sume 357148385Sume/* 358148385Sume * generate standard sockaddr_in6 from embedded form. 359148385Sume */ 360148385Sumeint 361171259Sdelphijsa6_recoverscope(struct sockaddr_in6 *sin6) 362148385Sume{ 363165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 364148385Sume u_int32_t zoneid; 365148385Sume 366148385Sume if (sin6->sin6_scope_id != 0) { 367148385Sume log(LOG_NOTICE, 368148385Sume "sa6_recoverscope: assumption failure (non 0 ID): %s%%%d\n", 369165118Sbz ip6_sprintf(ip6buf, &sin6->sin6_addr), sin6->sin6_scope_id); 370148385Sume /* XXX: proceed anyway... */ 371148385Sume } 372148385Sume if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) || 373148385Sume IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) { 374148385Sume /* 375148385Sume * KAME assumption: link id == interface id 376148385Sume */ 377148385Sume zoneid = ntohs(sin6->sin6_addr.s6_addr16[1]); 378148385Sume if (zoneid) { 379148385Sume /* sanity check */ 380148385Sume if (zoneid < 0 || if_index < zoneid) 381148385Sume return (ENXIO); 382148385Sume if (!ifnet_byindex(zoneid)) 383148385Sume return (ENXIO); 384148385Sume sin6->sin6_addr.s6_addr16[1] = 0; 385148385Sume sin6->sin6_scope_id = zoneid; 386148385Sume } 387148385Sume } 388148385Sume 389148385Sume return 0; 390148385Sume} 391148385Sume 392148385Sume/* 393148385Sume * Determine the appropriate scope zone ID for in6 and ifp. If ret_id is 394148385Sume * non NULL, it is set to the zone ID. If the zone ID needs to be embedded 395148385Sume * in the in6_addr structure, in6 will be modified. 396171259Sdelphij * 397171259Sdelphij * ret_id - unnecessary? 398148385Sume */ 399148385Sumeint 400171259Sdelphijin6_setscope(struct in6_addr *in6, struct ifnet *ifp, u_int32_t *ret_id) 401148385Sume{ 402148385Sume int scope; 403148385Sume u_int32_t zoneid = 0; 404148396Sume struct scope6_id *sid; 405148385Sume 406148396Sume IF_AFDATA_LOCK(ifp); 407148396Sume 408148396Sume sid = SID(ifp); 409148396Sume 410148385Sume#ifdef DIAGNOSTIC 411148385Sume if (sid == NULL) { /* should not happen */ 412148385Sume panic("in6_setscope: scope array is NULL"); 413148385Sume /* NOTREACHED */ 414148385Sume } 415148385Sume#endif 416148385Sume 417148385Sume /* 418148385Sume * special case: the loopback address can only belong to a loopback 419148385Sume * interface. 420148385Sume */ 421148385Sume if (IN6_IS_ADDR_LOOPBACK(in6)) { 422148399Sume if (!(ifp->if_flags & IFF_LOOPBACK)) { 423148396Sume IF_AFDATA_UNLOCK(ifp); 424148385Sume return (EINVAL); 425148399Sume } else { 426148385Sume if (ret_id != NULL) 427148385Sume *ret_id = 0; /* there's no ambiguity */ 428148396Sume IF_AFDATA_UNLOCK(ifp); 429148385Sume return (0); 430148385Sume } 431148385Sume } 432148385Sume 433148385Sume scope = in6_addrscope(in6); 434148385Sume 435148396Sume SCOPE6_LOCK(); 436148385Sume switch (scope) { 437148385Sume case IPV6_ADDR_SCOPE_INTFACELOCAL: /* should be interface index */ 438148385Sume zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL]; 439148385Sume break; 440148385Sume 441148385Sume case IPV6_ADDR_SCOPE_LINKLOCAL: 442148385Sume zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL]; 443148385Sume break; 444148385Sume 445148385Sume case IPV6_ADDR_SCOPE_SITELOCAL: 446148385Sume zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_SITELOCAL]; 447148385Sume break; 448148385Sume 449148385Sume case IPV6_ADDR_SCOPE_ORGLOCAL: 450148385Sume zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL]; 451148385Sume break; 452148385Sume 453148385Sume default: 454148385Sume zoneid = 0; /* XXX: treat as global. */ 455148385Sume break; 456148385Sume } 457148396Sume SCOPE6_UNLOCK(); 458148396Sume IF_AFDATA_UNLOCK(ifp); 459148385Sume 460148385Sume if (ret_id != NULL) 461148385Sume *ret_id = zoneid; 462148385Sume 463148385Sume if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6)) 464148385Sume in6->s6_addr16[1] = htons(zoneid & 0xffff); /* XXX */ 465148385Sume 466148385Sume return (0); 467148385Sume} 468148385Sume 469148385Sume/* 470148385Sume * Just clear the embedded scope identifier. Return 0 if the original address 471148385Sume * is intact; return non 0 if the address is modified. 472148385Sume */ 473148385Sumeint 474171259Sdelphijin6_clearscope(struct in6_addr *in6) 475148385Sume{ 476148385Sume int modified = 0; 477148385Sume 478148385Sume if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6)) { 479148385Sume if (in6->s6_addr16[1] != 0) 480148385Sume modified = 1; 481148385Sume in6->s6_addr16[1] = 0; 482148385Sume } 483148385Sume 484148385Sume return (modified); 485148385Sume} 486