scope6.c revision 270348
1133064Sdfr/*- 2133064Sdfr * Copyright (C) 2000 WIDE Project. 3133064Sdfr * All rights reserved. 4133064Sdfr * 5133064Sdfr * Redistribution and use in source and binary forms, with or without 6133064Sdfr * modification, are permitted provided that the following conditions 7133064Sdfr * are met: 8133064Sdfr * 1. Redistributions of source code must retain the above copyright 9133064Sdfr * notice, this list of conditions and the following disclaimer. 10133064Sdfr * 2. Redistributions in binary form must reproduce the above copyright 11133064Sdfr * notice, this list of conditions and the following disclaimer in the 12133064Sdfr * documentation and/or other materials provided with the distribution. 13133064Sdfr * 3. Neither the name of the project nor the names of its contributors 14133064Sdfr * may be used to endorse or promote products derived from this software 15133064Sdfr * without specific prior written permission. 16133064Sdfr * 17133064Sdfr * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 18133064Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19133064Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20133064Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 21133064Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22133064Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23133064Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24133064Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25133064Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26133064Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27133064Sdfr * SUCH DAMAGE. 28133064Sdfr * 29133064Sdfr * $KAME: scope6.c,v 1.10 2000/07/24 13:29:31 itojun Exp $ 30133064Sdfr */ 31133064Sdfr 32133064Sdfr#include <sys/cdefs.h> 33133064Sdfr__FBSDID("$FreeBSD: head/sys/netinet6/scope6.c 270348 2014-08-22 19:21:08Z markj $"); 34133064Sdfr 35143921Sdavidxu#include <sys/param.h> 36133754Sdfr#include <sys/malloc.h> 37133754Sdfr#include <sys/mbuf.h> 38133754Sdfr#include <sys/socket.h> 39133754Sdfr#include <sys/sockio.h> 40143921Sdavidxu#include <sys/systm.h> 41133754Sdfr#include <sys/queue.h> 42133064Sdfr#include <sys/sysctl.h> 43133754Sdfr#include <sys/syslog.h> 44133754Sdfr 45143921Sdavidxu#include <net/if.h> 46143921Sdavidxu#include <net/if_var.h> 47143921Sdavidxu#include <net/vnet.h> 48143921Sdavidxu 49143921Sdavidxu#include <netinet/in.h> 50143921Sdavidxu 51143921Sdavidxu#include <netinet/ip6.h> 52143921Sdavidxu#include <netinet6/in6_var.h> 53143921Sdavidxu#include <netinet6/ip6_var.h> 54143921Sdavidxu#include <netinet6/scope6_var.h> 55143921Sdavidxu 56143921Sdavidxu#ifdef ENABLE_DEFAULT_SCOPE 57143921SdavidxuVNET_DEFINE(int, ip6_use_defzone) = 1; 58143921Sdavidxu#else 59143921SdavidxuVNET_DEFINE(int, ip6_use_defzone) = 0; 60143921Sdavidxu#endif 61143921SdavidxuVNET_DEFINE(int, deembed_scopeid) = 1; 62143921SdavidxuSYSCTL_DECL(_net_inet6_ip6); 63133754SdfrSYSCTL_VNET_INT(_net_inet6_ip6, OID_AUTO, deembed_scopeid, CTLFLAG_RW, 64133754Sdfr &VNET_NAME(deembed_scopeid), 0, 65133754Sdfr "Extract embedded zone ID and set it to sin6_scope_id in sockaddr_in6."); 66135686Scognet 67135686Scognet/* 68133754Sdfr * The scope6_lock protects the global sid default stored in 69133754Sdfr * sid_default below. 70133754Sdfr */ 71133754Sdfrstatic struct mtx scope6_lock; 72133754Sdfr#define SCOPE6_LOCK_INIT() mtx_init(&scope6_lock, "scope6_lock", NULL, MTX_DEF) 73133754Sdfr#define SCOPE6_LOCK() mtx_lock(&scope6_lock) 74133754Sdfr#define SCOPE6_UNLOCK() mtx_unlock(&scope6_lock) 75133754Sdfr#define SCOPE6_LOCK_ASSERT() mtx_assert(&scope6_lock, MA_OWNED) 76133754Sdfr 77133754Sdfrstatic VNET_DEFINE(struct scope6_id, sid_default); 78133754Sdfr#define V_sid_default VNET(sid_default) 79133754Sdfr 80133754Sdfr#define SID(ifp) \ 81133754Sdfr (((struct in6_ifextra *)(ifp)->if_afdata[AF_INET6])->scope6_id) 82133754Sdfr 83133754Sdfrstatic int scope6_get(struct ifnet *, struct scope6_id *); 84133064Sdfrstatic int scope6_set(struct ifnet *, struct scope6_id *); 85133064Sdfr 86143921Sdavidxuvoid 87133064Sdfrscope6_init(void) 88133064Sdfr{ 89133064Sdfr 90143921Sdavidxu bzero(&V_sid_default, sizeof(V_sid_default)); 91133064Sdfr 92133064Sdfr if (!IS_DEFAULT_VNET(curvnet)) 93133064Sdfr return; 94133064Sdfr 95133064Sdfr SCOPE6_LOCK_INIT(); 96133064Sdfr} 97133064Sdfr 98143921Sdavidxustruct scope6_id * 99133064Sdfrscope6_ifattach(struct ifnet *ifp) 100133064Sdfr{ 101133064Sdfr struct scope6_id *sid; 102133064Sdfr 103143921Sdavidxu sid = (struct scope6_id *)malloc(sizeof(*sid), M_IFADDR, M_WAITOK); 104143921Sdavidxu bzero(sid, sizeof(*sid)); 105133754Sdfr 106133754Sdfr /* 107142560Sdavidxu * XXX: IPV6_ADDR_SCOPE_xxx macros are not standard. 108142959Sdavidxu * Should we rather hardcode here? 109142560Sdavidxu */ 110133754Sdfr sid->s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] = ifp->if_index; 111143921Sdavidxu sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = ifp->if_index; 112133754Sdfr#ifdef MULTI_SCOPE 113133754Sdfr /* by default, we don't care about scope boundary for these scopes. */ 114133754Sdfr sid->s6id_list[IPV6_ADDR_SCOPE_SITELOCAL] = 1; 115133754Sdfr sid->s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL] = 1; 116133754Sdfr#endif 117133754Sdfr 118133754Sdfr return sid; 119133754Sdfr} 120133754Sdfr 121133754Sdfrvoid 122133754Sdfrscope6_ifdetach(struct scope6_id *sid) 123133064Sdfr{ 124143921Sdavidxu 125133064Sdfr free(sid, M_IFADDR); 126133754Sdfr} 127133754Sdfr 128133754Sdfrint 129133754Sdfrscope6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp) 130133754Sdfr{ 131134212Sdfr struct in6_ifreq *ifr; 132134212Sdfr 133133754Sdfr if (ifp->if_afdata[AF_INET6] == NULL) 134133754Sdfr return (EPFNOSUPPORT); 135133754Sdfr 136133754Sdfr ifr = (struct in6_ifreq *)data; 137143921Sdavidxu switch (cmd) { 138133754Sdfr case SIOCSSCOPE6: 139133754Sdfr return (scope6_set(ifp, 140133754Sdfr (struct scope6_id *)ifr->ifr_ifru.ifru_scope_id)); 141133754Sdfr case SIOCGSCOPE6: 142133754Sdfr return (scope6_get(ifp, 143133754Sdfr (struct scope6_id *)ifr->ifr_ifru.ifru_scope_id)); 144133754Sdfr case SIOCGSCOPE6DEF: 145133754Sdfr return (scope6_get_default( 146133754Sdfr (struct scope6_id *)ifr->ifr_ifru.ifru_scope_id)); 147143921Sdavidxu default: 148133754Sdfr return (EOPNOTSUPP); 149133754Sdfr } 150133754Sdfr} 151133754Sdfr 152133754Sdfrstatic int 153133754Sdfrscope6_set(struct ifnet *ifp, struct scope6_id *idlist) 154143921Sdavidxu{ 155133754Sdfr int i; 156133754Sdfr int error = 0; 157133754Sdfr struct scope6_id *sid = NULL; 158133754Sdfr 159133754Sdfr IF_AFDATA_WLOCK(ifp); 160133754Sdfr sid = SID(ifp); 161133754Sdfr 162133064Sdfr if (!sid) { /* paranoid? */ 163133064Sdfr IF_AFDATA_WUNLOCK(ifp); 164133754Sdfr return (EINVAL); 165133754Sdfr } 166133754Sdfr 167133754Sdfr /* 168133754Sdfr * XXX: We need more consistency checks of the relationship among 169133754Sdfr * scopes (e.g. an organization should be larger than a site). 170133754Sdfr */ 171133064Sdfr 172143921Sdavidxu /* 173133064Sdfr * TODO(XXX): after setting, we should reflect the changes to 174133754Sdfr * interface addresses, routing table entries, PCB entries... 175133754Sdfr */ 176133754Sdfr 177133754Sdfr for (i = 0; i < 16; i++) { 178133754Sdfr if (idlist->s6id_list[i] && 179133754Sdfr idlist->s6id_list[i] != sid->s6id_list[i]) { 180133754Sdfr /* 181133754Sdfr * An interface zone ID must be the corresponding 182133754Sdfr * interface index by definition. 183133754Sdfr */ 184133754Sdfr if (i == IPV6_ADDR_SCOPE_INTFACELOCAL && 185133754Sdfr idlist->s6id_list[i] != ifp->if_index) { 186133754Sdfr IF_AFDATA_WUNLOCK(ifp); 187133754Sdfr return (EINVAL); 188133754Sdfr } 189133064Sdfr 190133754Sdfr if (i == IPV6_ADDR_SCOPE_LINKLOCAL && 191133754Sdfr idlist->s6id_list[i] > V_if_index) { 192133754Sdfr /* 193133754Sdfr * XXX: theoretically, there should be no 194133754Sdfr * relationship between link IDs and interface 195143921Sdavidxu * IDs, but we check the consistency for 196133754Sdfr * safety in later use. 197133754Sdfr */ 198133754Sdfr IF_AFDATA_WUNLOCK(ifp); 199133754Sdfr return (EINVAL); 200133754Sdfr } 201133754Sdfr 202133754Sdfr /* 203133754Sdfr * XXX: we must need lots of work in this case, 204133754Sdfr * but we simply set the new value in this initial 205133754Sdfr * implementation. 206133754Sdfr */ 207133754Sdfr sid->s6id_list[i] = idlist->s6id_list[i]; 208133754Sdfr } 209133754Sdfr } 210133754Sdfr IF_AFDATA_WUNLOCK(ifp); 211133754Sdfr 212133754Sdfr return (error); 213133754Sdfr} 214133754Sdfr 215133754Sdfrstatic int 216133754Sdfrscope6_get(struct ifnet *ifp, struct scope6_id *idlist) 217133754Sdfr{ 218133754Sdfr struct scope6_id *sid; 219133754Sdfr 220133754Sdfr /* We only need to lock the interface's afdata for SID() to work. */ 221133754Sdfr IF_AFDATA_RLOCK(ifp); 222133754Sdfr sid = SID(ifp); 223133754Sdfr if (sid == NULL) { /* paranoid? */ 224133754Sdfr IF_AFDATA_RUNLOCK(ifp); 225133754Sdfr return (EINVAL); 226133754Sdfr } 227133754Sdfr 228133754Sdfr *idlist = *sid; 229133754Sdfr 230133754Sdfr IF_AFDATA_RUNLOCK(ifp); 231133754Sdfr return (0); 232133754Sdfr} 233133754Sdfr 234133754Sdfr/* 235133754Sdfr * Get a scope of the address. Node-local, link-local, site-local or global. 236133754Sdfr */ 237133754Sdfrint 238143921Sdavidxuin6_addrscope(struct in6_addr *addr) 239143921Sdavidxu{ 240143921Sdavidxu int scope; 241143921Sdavidxu 242133754Sdfr if (addr->s6_addr[0] == 0xfe) { 243143921Sdavidxu scope = addr->s6_addr[1] & 0xc0; 244143921Sdavidxu 245143921Sdavidxu switch (scope) { 246143921Sdavidxu case 0x80: 247143921Sdavidxu return IPV6_ADDR_SCOPE_LINKLOCAL; 248133754Sdfr break; 249133754Sdfr case 0xc0: 250133754Sdfr return IPV6_ADDR_SCOPE_SITELOCAL; 251143921Sdavidxu break; 252143921Sdavidxu default: 253143921Sdavidxu return IPV6_ADDR_SCOPE_GLOBAL; /* just in case */ 254143921Sdavidxu break; 255143921Sdavidxu } 256133754Sdfr } 257143921Sdavidxu 258143921Sdavidxu 259143921Sdavidxu if (addr->s6_addr[0] == 0xff) { 260143921Sdavidxu scope = addr->s6_addr[1] & 0x0f; 261133754Sdfr 262133754Sdfr /* 263133754Sdfr * due to other scope such as reserved, 264133754Sdfr * return scope doesn't work. 265133754Sdfr */ 266133754Sdfr switch (scope) { 267133754Sdfr case IPV6_ADDR_SCOPE_INTFACELOCAL: 268133754Sdfr return IPV6_ADDR_SCOPE_INTFACELOCAL; 269133754Sdfr break; 270133949Sdfr case IPV6_ADDR_SCOPE_LINKLOCAL: 271133754Sdfr return IPV6_ADDR_SCOPE_LINKLOCAL; 272133754Sdfr break; 273133754Sdfr case IPV6_ADDR_SCOPE_SITELOCAL: 274133754Sdfr return IPV6_ADDR_SCOPE_SITELOCAL; 275133754Sdfr break; 276133754Sdfr default: 277133754Sdfr return IPV6_ADDR_SCOPE_GLOBAL; 278133754Sdfr break; 279133754Sdfr } 280133754Sdfr } 281133754Sdfr 282133754Sdfr /* 283133754Sdfr * Regard loopback and unspecified addresses as global, since 284133754Sdfr * they have no ambiguity. 285133754Sdfr */ 286133754Sdfr if (bcmp(&in6addr_loopback, addr, sizeof(*addr) - 1) == 0) { 287133754Sdfr if (addr->s6_addr[15] == 1) /* loopback */ 288133754Sdfr return IPV6_ADDR_SCOPE_LINKLOCAL; 289133754Sdfr if (addr->s6_addr[15] == 0) /* unspecified */ 290133754Sdfr return IPV6_ADDR_SCOPE_GLOBAL; /* XXX: correct? */ 291133754Sdfr } 292133754Sdfr 293133754Sdfr return IPV6_ADDR_SCOPE_GLOBAL; 294133754Sdfr} 295133754Sdfr 296143921Sdavidxu/* 297133754Sdfr * ifp - note that this might be NULL 298133754Sdfr */ 299133754Sdfr 300133754Sdfrvoid 301133754Sdfrscope6_setdefault(struct ifnet *ifp) 302133754Sdfr{ 303133754Sdfr 304133754Sdfr /* 305133754Sdfr * Currently, this function just sets the default "interfaces" 306133754Sdfr * and "links" according to the given interface. 307133754Sdfr * We might eventually have to separate the notion of "link" from 308133754Sdfr * "interface" and provide a user interface to set the default. 309133754Sdfr */ 310133754Sdfr SCOPE6_LOCK(); 311133754Sdfr if (ifp) { 312133949Sdfr V_sid_default.s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] = 313133949Sdfr ifp->if_index; 314133754Sdfr V_sid_default.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = 315133949Sdfr ifp->if_index; 316133754Sdfr } else { 317133754Sdfr V_sid_default.s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] = 0; 318 V_sid_default.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = 0; 319 } 320 SCOPE6_UNLOCK(); 321} 322 323int 324scope6_get_default(struct scope6_id *idlist) 325{ 326 327 SCOPE6_LOCK(); 328 *idlist = V_sid_default; 329 SCOPE6_UNLOCK(); 330 331 return (0); 332} 333 334u_int32_t 335scope6_addr2default(struct in6_addr *addr) 336{ 337 u_int32_t id; 338 339 /* 340 * special case: The loopback address should be considered as 341 * link-local, but there's no ambiguity in the syntax. 342 */ 343 if (IN6_IS_ADDR_LOOPBACK(addr)) 344 return (0); 345 346 /* 347 * XXX: 32-bit read is atomic on all our platforms, is it OK 348 * not to lock here? 349 */ 350 SCOPE6_LOCK(); 351 id = V_sid_default.s6id_list[in6_addrscope(addr)]; 352 SCOPE6_UNLOCK(); 353 return (id); 354} 355 356/* 357 * Validate the specified scope zone ID in the sin6_scope_id field. If the ID 358 * is unspecified (=0), needs to be specified, and the default zone ID can be 359 * used, the default value will be used. 360 * This routine then generates the kernel-internal form: if the address scope 361 * of is interface-local or link-local, embed the interface index in the 362 * address. 363 */ 364int 365sa6_embedscope(struct sockaddr_in6 *sin6, int defaultok) 366{ 367 u_int32_t zoneid; 368 369 if ((zoneid = sin6->sin6_scope_id) == 0 && defaultok) 370 zoneid = scope6_addr2default(&sin6->sin6_addr); 371 372 if (zoneid != 0 && 373 (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) || 374 IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr))) { 375 /* 376 * At this moment, we only check interface-local and 377 * link-local scope IDs, and use interface indices as the 378 * zone IDs assuming a one-to-one mapping between interfaces 379 * and links. 380 */ 381 if (V_if_index < zoneid || ifnet_byindex(zoneid) == NULL) 382 return (ENXIO); 383 384 /* XXX assignment to 16bit from 32bit variable */ 385 sin6->sin6_addr.s6_addr16[1] = htons(zoneid & 0xffff); 386 sin6->sin6_scope_id = 0; 387 } 388 389 return 0; 390} 391 392/* 393 * generate standard sockaddr_in6 from embedded form. 394 */ 395int 396sa6_recoverscope(struct sockaddr_in6 *sin6) 397{ 398 char ip6buf[INET6_ADDRSTRLEN]; 399 u_int32_t zoneid; 400 401 if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) || 402 IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) { 403 /* 404 * KAME assumption: link id == interface id 405 */ 406 zoneid = ntohs(sin6->sin6_addr.s6_addr16[1]); 407 if (zoneid) { 408 /* sanity check */ 409 if (V_if_index < zoneid) 410 return (ENXIO); 411#if 0 412 /* XXX: Disabled due to possible deadlock. */ 413 if (!ifnet_byindex(zoneid)) 414 return (ENXIO); 415#endif 416 if (sin6->sin6_scope_id != 0 && 417 zoneid != sin6->sin6_scope_id) { 418 log(LOG_NOTICE, 419 "%s: embedded scope mismatch: %s%%%d. " 420 "sin6_scope_id was overridden.", __func__, 421 ip6_sprintf(ip6buf, &sin6->sin6_addr), 422 sin6->sin6_scope_id); 423 } 424 sin6->sin6_addr.s6_addr16[1] = 0; 425 sin6->sin6_scope_id = zoneid; 426 } 427 } 428 429 return 0; 430} 431 432/* 433 * Determine the appropriate scope zone ID for in6 and ifp. If ret_id is 434 * non NULL, it is set to the zone ID. If the zone ID needs to be embedded 435 * in the in6_addr structure, in6 will be modified. 436 * 437 * ret_id - unnecessary? 438 */ 439int 440in6_setscope(struct in6_addr *in6, struct ifnet *ifp, u_int32_t *ret_id) 441{ 442 int scope; 443 u_int32_t zoneid = 0; 444 struct scope6_id *sid; 445 446 /* 447 * special case: the loopback address can only belong to a loopback 448 * interface. 449 */ 450 if (IN6_IS_ADDR_LOOPBACK(in6)) { 451 if (!(ifp->if_flags & IFF_LOOPBACK)) 452 return (EINVAL); 453 } else { 454 scope = in6_addrscope(in6); 455 if (scope == IPV6_ADDR_SCOPE_INTFACELOCAL || 456 scope == IPV6_ADDR_SCOPE_LINKLOCAL) { 457 /* 458 * Currently we use interface indeces as the 459 * zone IDs for interface-local and link-local 460 * scopes. 461 */ 462 zoneid = ifp->if_index; 463 in6->s6_addr16[1] = htons(zoneid & 0xffff); /* XXX */ 464 } else if (scope != IPV6_ADDR_SCOPE_GLOBAL) { 465 IF_AFDATA_RLOCK(ifp); 466 sid = SID(ifp); 467 zoneid = sid->s6id_list[scope]; 468 IF_AFDATA_RUNLOCK(ifp); 469 } 470 } 471 472 if (ret_id != NULL) 473 *ret_id = zoneid; 474 475 return (0); 476} 477 478/* 479 * Just clear the embedded scope identifier. Return 0 if the original address 480 * is intact; return non 0 if the address is modified. 481 */ 482int 483in6_clearscope(struct in6_addr *in6) 484{ 485 int modified = 0; 486 487 if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6)) { 488 if (in6->s6_addr16[1] != 0) 489 modified = 1; 490 in6->s6_addr16[1] = 0; 491 } 492 493 return (modified); 494} 495 496/* 497 * Return the scope identifier or zero. 498 */ 499uint16_t 500in6_getscope(struct in6_addr *in6) 501{ 502 503 if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6)) 504 return (in6->s6_addr16[1]); 505 506 return (0); 507} 508