scope6.c revision 120941
1198090Srdivacky/* $FreeBSD: head/sys/netinet6/scope6.c 120941 2003-10-09 16:13:47Z ume $ */ 2198090Srdivacky/* $KAME: scope6.c,v 1.10 2000/07/24 13:29:31 itojun Exp $ */ 3198090Srdivacky 4198090Srdivacky/* 5198090Srdivacky * Copyright (C) 2000 WIDE Project. 6198090Srdivacky * All rights reserved. 7198090Srdivacky * 8198090Srdivacky * Redistribution and use in source and binary forms, with or without 9198090Srdivacky * modification, are permitted provided that the following conditions 10198090Srdivacky * are met: 11218893Sdim * 1. Redistributions of source code must retain the above copyright 12218893Sdim * notice, this list of conditions and the following disclaimer. 13198090Srdivacky * 2. Redistributions in binary form must reproduce the above copyright 14218893Sdim * notice, this list of conditions and the following disclaimer in the 15218893Sdim * documentation and/or other materials provided with the distribution. 16218893Sdim * 3. Neither the name of the project nor the names of its contributors 17198090Srdivacky * may be used to endorse or promote products derived from this software 18198090Srdivacky * without specific prior written permission. 19198090Srdivacky * 20198090Srdivacky * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21198090Srdivacky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22198090Srdivacky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23198090Srdivacky * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24198090Srdivacky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25198090Srdivacky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26198090Srdivacky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27218893Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28198090Srdivacky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29198090Srdivacky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30198090Srdivacky * SUCH DAMAGE. 31198090Srdivacky */ 32198090Srdivacky 33198090Srdivacky#include <sys/param.h> 34198090Srdivacky#include <sys/malloc.h> 35198090Srdivacky#include <sys/mbuf.h> 36198090Srdivacky#include <sys/socket.h> 37198090Srdivacky#include <sys/systm.h> 38198090Srdivacky#include <sys/queue.h> 39198090Srdivacky 40198090Srdivacky#include <net/route.h> 41198090Srdivacky#include <net/if.h> 42198090Srdivacky 43198090Srdivacky#include <netinet/in.h> 44198090Srdivacky 45198090Srdivacky#include <netinet6/in6_var.h> 46198090Srdivacky#include <netinet6/scope6_var.h> 47198090Srdivacky 48198090Srdivackystruct scope6_id { 49198090Srdivacky /* 50198090Srdivacky * 16 is correspondent to 4bit multicast scope field. 51198090Srdivacky * i.e. from node-local to global with some reserved/unassigned types. 52198090Srdivacky */ 53198090Srdivacky u_int32_t s6id_list[16]; 54198090Srdivacky}; 55198090Srdivackystatic size_t if_indexlim = 8; 56198090Srdivackystruct scope6_id *scope6_ids = NULL; 57198090Srdivacky 58198090Srdivackyvoid 59198090Srdivackyscope6_ifattach(ifp) 60198090Srdivacky struct ifnet *ifp; 61198090Srdivacky{ 62198090Srdivacky int s = splnet(); 63198090Srdivacky 64198090Srdivacky /* 65198090Srdivacky * We have some arrays that should be indexed by if_index. 66198090Srdivacky * since if_index will grow dynamically, they should grow too. 67198090Srdivacky */ 68198090Srdivacky if (scope6_ids == NULL || if_index >= if_indexlim) { 69198090Srdivacky size_t n; 70198090Srdivacky caddr_t q; 71198090Srdivacky 72198090Srdivacky while (if_index >= if_indexlim) 73198090Srdivacky if_indexlim <<= 1; 74198090Srdivacky 75218893Sdim /* grow scope index array */ 76218893Sdim n = if_indexlim * sizeof(struct scope6_id); 77218893Sdim /* XXX: need new malloc type? */ 78218893Sdim q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK); 79218893Sdim bzero(q, n); 80245431Sdim if (scope6_ids) { 81218893Sdim bcopy((caddr_t)scope6_ids, q, n/2); 82218893Sdim free((caddr_t)scope6_ids, M_IFADDR); 83218893Sdim } 84218893Sdim scope6_ids = (struct scope6_id *)q; 85218893Sdim } 86218893Sdim 87218893Sdim#define SID scope6_ids[ifp->if_index] 88218893Sdim 89218893Sdim /* don't initialize if called twice */ 90218893Sdim if (SID.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL]) { 91221345Sdim splx(s); 92218893Sdim return; 93218893Sdim } 94218893Sdim 95218893Sdim /* 96218893Sdim * XXX: IPV6_ADDR_SCOPE_xxx macros are not standard. 97198090Srdivacky * Should we rather hardcode here? 98198090Srdivacky */ 99198090Srdivacky SID.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = ifp->if_index; 100198090Srdivacky#ifdef MULTI_SCOPE 101218893Sdim /* by default, we don't care about scope boundary for these scopes. */ 102252723Sdim SID.s6id_list[IPV6_ADDR_SCOPE_SITELOCAL] = 1; 103218893Sdim SID.s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL] = 1; 104198090Srdivacky#endif 105198090Srdivacky#undef SID 106198090Srdivacky 107198090Srdivacky splx(s); 108235633Sdim} 109226890Sdim 110226890Sdimint 111245431Sdimscope6_set(ifp, idlist) 112263509Sdim struct ifnet *ifp; 113245431Sdim u_int32_t *idlist; 114245431Sdim{ 115263509Sdim int i, s; 116198090Srdivacky int error = 0; 117198090Srdivacky 118263509Sdim if (scope6_ids == NULL) /* paranoid? */ 119198090Srdivacky return (EINVAL); 120198090Srdivacky 121198090Srdivacky /* 122198090Srdivacky * XXX: We need more consistency checks of the relationship among 123198090Srdivacky * scopes (e.g. an organization should be larger than a site). 124198090Srdivacky */ 125198090Srdivacky 126218893Sdim /* 127212904Sdim * TODO(XXX): after setting, we should reflect the changes to 128212904Sdim * interface addresses, routing table entries, PCB entries... 129263509Sdim */ 130263509Sdim 131263509Sdim s = splnet(); 132263509Sdim 133263509Sdim for (i = 0; i < 16; i++) { 134263509Sdim if (idlist[i] && 135263509Sdim idlist[i] != scope6_ids[ifp->if_index].s6id_list[i]) { 136245431Sdim if (i == IPV6_ADDR_SCOPE_LINKLOCAL && 137245431Sdim idlist[i] > if_index) { 138245431Sdim /* 139245431Sdim * XXX: theoretically, there should be no 140245431Sdim * relationship between link IDs and interface 141245431Sdim * IDs, but we check the consistency for 142245431Sdim * safety in later use. 143245431Sdim */ 144198090Srdivacky splx(s); 145198090Srdivacky return (EINVAL); 146198090Srdivacky } 147198090Srdivacky 148198090Srdivacky /* 149198090Srdivacky * XXX: we must need lots of work in this case, 150198090Srdivacky * but we simply set the new value in this initial 151198090Srdivacky * implementation. 152198090Srdivacky */ 153198090Srdivacky scope6_ids[ifp->if_index].s6id_list[i] = idlist[i]; 154198090Srdivacky } 155198090Srdivacky } 156198090Srdivacky splx(s); 157198090Srdivacky 158198090Srdivacky return (error); 159198090Srdivacky} 160198090Srdivacky 161198090Srdivackyint 162198090Srdivackyscope6_get(ifp, idlist) 163198090Srdivacky struct ifnet *ifp; 164198090Srdivacky u_int32_t *idlist; 165198090Srdivacky{ 166198090Srdivacky if (scope6_ids == NULL) /* paranoid? */ 167198090Srdivacky return (EINVAL); 168198090Srdivacky 169198090Srdivacky bcopy(scope6_ids[ifp->if_index].s6id_list, idlist, 170198090Srdivacky sizeof(scope6_ids[ifp->if_index].s6id_list)); 171198090Srdivacky 172198090Srdivacky return (0); 173198090Srdivacky} 174198090Srdivacky 175198090Srdivacky 176198090Srdivacky/* 177198090Srdivacky * Get a scope of the address. Node-local, link-local, site-local or global. 178198090Srdivacky */ 179198090Srdivackyint 180198090Srdivackyin6_addrscope(addr) 181198090Srdivacky struct in6_addr *addr; 182198090Srdivacky{ 183198090Srdivacky int scope; 184198090Srdivacky 185198090Srdivacky if (addr->s6_addr8[0] == 0xfe) { 186198090Srdivacky scope = addr->s6_addr8[1] & 0xc0; 187198090Srdivacky 188198090Srdivacky switch (scope) { 189198090Srdivacky case 0x80: 190198090Srdivacky return IPV6_ADDR_SCOPE_LINKLOCAL; 191218893Sdim break; 192218893Sdim case 0xc0: 193218893Sdim return IPV6_ADDR_SCOPE_SITELOCAL; 194218893Sdim break; 195198090Srdivacky default: 196263509Sdim return IPV6_ADDR_SCOPE_GLOBAL; /* just in case */ 197198090Srdivacky break; 198245431Sdim } 199245431Sdim } 200198090Srdivacky 201198090Srdivacky 202198090Srdivacky if (addr->s6_addr8[0] == 0xff) { 203198090Srdivacky scope = addr->s6_addr8[1] & 0x0f; 204198090Srdivacky 205198090Srdivacky /* 206198090Srdivacky * due to other scope such as reserved, 207198090Srdivacky * return scope doesn't work. 208198090Srdivacky */ 209198090Srdivacky switch (scope) { 210198090Srdivacky case IPV6_ADDR_SCOPE_NODELOCAL: 211245431Sdim return IPV6_ADDR_SCOPE_NODELOCAL; 212198090Srdivacky break; 213198090Srdivacky case IPV6_ADDR_SCOPE_LINKLOCAL: 214198090Srdivacky return IPV6_ADDR_SCOPE_LINKLOCAL; 215198090Srdivacky break; 216198090Srdivacky case IPV6_ADDR_SCOPE_SITELOCAL: 217198090Srdivacky return IPV6_ADDR_SCOPE_SITELOCAL; 218198090Srdivacky break; 219198090Srdivacky default: 220198090Srdivacky return IPV6_ADDR_SCOPE_GLOBAL; 221198090Srdivacky break; 222198090Srdivacky } 223198090Srdivacky } 224263509Sdim 225263509Sdim if (bcmp(&in6addr_loopback, addr, sizeof(*addr) - 1) == 0) { 226218893Sdim if (addr->s6_addr8[15] == 1) /* loopback */ 227198090Srdivacky return IPV6_ADDR_SCOPE_NODELOCAL; 228263509Sdim if (addr->s6_addr8[15] == 0) /* unspecified */ 229198090Srdivacky return IPV6_ADDR_SCOPE_LINKLOCAL; 230198090Srdivacky } 231198090Srdivacky 232198090Srdivacky return IPV6_ADDR_SCOPE_GLOBAL; 233198090Srdivacky} 234198090Srdivacky 235198090Srdivackyint 236198090Srdivackyin6_addr2scopeid(ifp, addr) 237198090Srdivacky struct ifnet *ifp; /* must not be NULL */ 238198090Srdivacky struct in6_addr *addr; /* must not be NULL */ 239198090Srdivacky{ 240198090Srdivacky int scope = in6_addrscope(addr); 241198090Srdivacky 242198090Srdivacky if (scope6_ids == NULL) /* paranoid? */ 243198090Srdivacky return (0); /* XXX */ 244198090Srdivacky if (ifp->if_index >= if_indexlim) 245198090Srdivacky return (0); /* XXX */ 246218893Sdim 247198090Srdivacky#define SID scope6_ids[ifp->if_index] 248198090Srdivacky switch(scope) { 249198090Srdivacky case IPV6_ADDR_SCOPE_NODELOCAL: 250245431Sdim return (-1); /* XXX: is this an appropriate value? */ 251198090Srdivacky 252198090Srdivacky case IPV6_ADDR_SCOPE_LINKLOCAL: 253198090Srdivacky return (SID.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL]); 254198090Srdivacky 255198090Srdivacky case IPV6_ADDR_SCOPE_SITELOCAL: 256198090Srdivacky return (SID.s6id_list[IPV6_ADDR_SCOPE_SITELOCAL]); 257198090Srdivacky 258198090Srdivacky case IPV6_ADDR_SCOPE_ORGLOCAL: 259198090Srdivacky return (SID.s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL]); 260198090Srdivacky 261198090Srdivacky default: 262198090Srdivacky return (0); /* XXX: treat as global. */ 263198090Srdivacky } 264198090Srdivacky#undef SID 265198090Srdivacky} 266198090Srdivacky 267208599Srdivackyvoid 268208599Srdivackyscope6_setdefault(ifp) 269208599Srdivacky struct ifnet *ifp; /* note that this might be NULL */ 270198090Srdivacky{ 271198090Srdivacky /* 272198090Srdivacky * Currently, this function just set the default "link" according to 273198090Srdivacky * the given interface. 274198090Srdivacky * We might eventually have to separate the notion of "link" from 275198090Srdivacky * "interface" and provide a user interface to set the default. 276235633Sdim */ 277198090Srdivacky if (ifp) { 278198090Srdivacky scope6_ids[0].s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = 279221345Sdim ifp->if_index; 280208599Srdivacky } else { 281210299Sed scope6_ids[0].s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = 0; 282208599Srdivacky } 283210299Sed} 284208599Srdivacky 285208599Srdivackyint 286208599Srdivackyscope6_get_default(idlist) 287198090Srdivacky u_int32_t *idlist; 288198090Srdivacky{ 289198090Srdivacky if (scope6_ids == NULL) /* paranoid? */ 290198090Srdivacky return (EINVAL); 291245431Sdim 292245431Sdim bcopy(scope6_ids[0].s6id_list, idlist, 293245431Sdim sizeof(scope6_ids[0].s6id_list)); 294245431Sdim 295245431Sdim return (0); 296245431Sdim} 297245431Sdim 298245431Sdimu_int32_t 299245431Sdimscope6_addr2default(addr) 300218893Sdim struct in6_addr *addr; 301218893Sdim{ 302218893Sdim return (scope6_ids[0].s6id_list[in6_addrscope(addr)]); 303218893Sdim} 304218893Sdim