The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet6/scope6.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $FreeBSD: src/sys/netinet6/scope6.c,v 1.1.2.3 2002/04/01 15:29:04 ume Exp $     */
    2 /*      $DragonFly: src/sys/netinet6/scope6.c,v 1.11 2008/01/05 14:02:40 swildner Exp $ */
    3 /*      $KAME: scope6.c,v 1.10 2000/07/24 13:29:31 itojun Exp $ */
    4 
    5 /*
    6  * Copyright (C) 2000 WIDE Project.
    7  * All rights reserved.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 3. Neither the name of the project nor the names of its contributors
   18  *    may be used to endorse or promote products derived from this software
   19  *    without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31  * SUCH DAMAGE.
   32  */
   33 
   34 #include <sys/param.h>
   35 #include <sys/malloc.h>
   36 #include <sys/mbuf.h>
   37 #include <sys/socket.h>
   38 #include <sys/systm.h>
   39 #include <sys/queue.h>
   40 #include <sys/thread2.h>
   41 
   42 #include <net/route.h>
   43 #include <net/if.h>
   44 
   45 #include <netinet/in.h>
   46 
   47 #include <netinet6/in6_var.h>
   48 #include <netinet6/scope6_var.h>
   49 
   50 static struct scope6_id sid_default;
   51 
   52 static __inline
   53 struct scope6_id *
   54 SID(struct ifnet *ifp)
   55 {
   56         struct in6_ifextra *xtra;
   57 
   58         xtra = ifp->if_afdata[AF_INET6];
   59         if (xtra)
   60                 return (xtra->scope6_id);
   61         return(NULL);
   62 }
   63 
   64 void
   65 scope6_init(void)
   66 {
   67         bzero(&sid_default, sizeof(sid_default));
   68 }
   69 
   70 struct scope6_id *
   71 scope6_ifattach(struct ifnet *ifp)
   72 {
   73         struct scope6_id *sid;
   74 
   75         sid = (struct scope6_id *)kmalloc(sizeof(*sid), M_IFADDR,
   76             M_WAITOK | M_ZERO);
   77 
   78         crit_enter();
   79 
   80         /*
   81          * XXX: IPV6_ADDR_SCOPE_xxx macros are not standard.
   82          * Should we rather hardcode here?
   83          */
   84         sid->s6id_list[IPV6_ADDR_SCOPE_NODELOCAL] = ifp->if_index;
   85         sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = ifp->if_index;
   86 #ifdef MULTI_SCOPE
   87         /* by default, we don't care about scope boundary for these scopes. */
   88         sid->s6id_list[IPV6_ADDR_SCOPE_SITELOCAL] = 1;
   89         sid->s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL] = 1;
   90 #endif
   91 
   92         crit_exit();
   93         return sid;
   94 }
   95 
   96 void
   97 scope6_ifdetach(struct scope6_id *sid)
   98 {
   99         kfree(sid, M_IFADDR);
  100 }
  101 
  102 int
  103 scope6_set(struct ifnet *ifp, struct scope6_id *idlist)
  104 {
  105         int i;
  106         int error = 0;
  107         struct scope6_id *sid = SID(ifp);
  108 
  109         if (!sid)       /* paranoid? */
  110                 return (EINVAL);
  111 
  112         /*
  113          * XXX: We need more consistency checks of the relationship among
  114          * scopes (e.g. an organization should be larger than a site).
  115          */
  116 
  117         /*
  118          * TODO(XXX): after setting, we should reflect the changes to
  119          * interface addresses, routing table entries, PCB entries...
  120          */
  121 
  122         crit_enter();
  123 
  124         for (i = 0; i < 16; i++) {
  125                 if (idlist->s6id_list[i] &&
  126                     idlist->s6id_list[i] != sid->s6id_list[i]) {
  127                         if (i == IPV6_ADDR_SCOPE_LINKLOCAL &&
  128                             idlist->s6id_list[i] > if_index) {
  129                                 /*
  130                                  * XXX: theoretically, there should be no
  131                                  * relationship between link IDs and interface
  132                                  * IDs, but we check the consistency for
  133                                  * safety in later use.
  134                                  */
  135                                 crit_exit();
  136                                 return (EINVAL);
  137                         }
  138 
  139                         /*
  140                          * XXX: we must need lots of work in this case,
  141                          * but we simply set the new value in this initial
  142                          * implementation.
  143                          */
  144                         sid->s6id_list[i] = idlist->s6id_list[i];
  145                 }
  146         }
  147         crit_exit();
  148 
  149         return (error);
  150 }
  151 
  152 int
  153 scope6_get(struct ifnet *ifp, struct scope6_id *idlist)
  154 {
  155         struct scope6_id *sid = SID(ifp);
  156 
  157         if (sid == NULL)        /* paranoid? */
  158                 return (EINVAL);
  159 
  160         *idlist = *sid;
  161 
  162         return (0);
  163 }
  164 
  165 
  166 /*
  167  * Get a scope of the address. Node-local, link-local, site-local or global.
  168  */
  169 int
  170 in6_addrscope(struct in6_addr *addr)
  171 {
  172         int scope;
  173 
  174         if (addr->s6_addr8[0] == 0xfe) {
  175                 scope = addr->s6_addr8[1] & 0xc0;
  176 
  177                 switch (scope) {
  178                 case 0x80:
  179                         return IPV6_ADDR_SCOPE_LINKLOCAL;
  180                         break;
  181                 case 0xc0:
  182                         return IPV6_ADDR_SCOPE_SITELOCAL;
  183                         break;
  184                 default:
  185                         return IPV6_ADDR_SCOPE_GLOBAL; /* just in case */
  186                         break;
  187                 }
  188         }
  189 
  190 
  191         if (addr->s6_addr8[0] == 0xff) {
  192                 scope = addr->s6_addr8[1] & 0x0f;
  193 
  194                 /*
  195                  * due to other scope such as reserved,
  196                  * return scope doesn't work.
  197                  */
  198                 switch (scope) {
  199                 case IPV6_ADDR_SCOPE_NODELOCAL:
  200                         return IPV6_ADDR_SCOPE_NODELOCAL;
  201                         break;
  202                 case IPV6_ADDR_SCOPE_LINKLOCAL:
  203                         return IPV6_ADDR_SCOPE_LINKLOCAL;
  204                         break;
  205                 case IPV6_ADDR_SCOPE_SITELOCAL:
  206                         return IPV6_ADDR_SCOPE_SITELOCAL;
  207                         break;
  208                 default:
  209                         return IPV6_ADDR_SCOPE_GLOBAL;
  210                         break;
  211                 }
  212         }
  213 
  214         if (bcmp(&kin6addr_loopback, addr, sizeof(*addr) - 1) == 0) {
  215                 if (addr->s6_addr8[15] == 1) /* loopback */
  216                         return IPV6_ADDR_SCOPE_NODELOCAL;
  217                 if (addr->s6_addr8[15] == 0) /* unspecified */
  218                         return IPV6_ADDR_SCOPE_LINKLOCAL;
  219         }
  220 
  221         return IPV6_ADDR_SCOPE_GLOBAL;
  222 }
  223 
  224 int
  225 in6_addr2scopeid(struct ifnet *ifp,     /* must not be NULL */
  226                  struct in6_addr *addr) /* must not be NULL */
  227 {
  228         int scope;
  229         struct scope6_id *sid = SID(ifp);
  230 
  231 #ifdef DIAGNOSTIC
  232         if (sid == NULL) { /* should not happen */
  233                 panic("in6_addr2zoneid: scope array is NULL");
  234                 /* NOTREACHED */
  235         }
  236 #endif
  237 
  238         /*
  239          * special case: the loopback address can only belong to a loopback
  240          * interface.
  241          */
  242         if (IN6_IS_ADDR_LOOPBACK(addr)) {
  243                 if (!(ifp->if_flags & IFF_LOOPBACK))
  244                         return (-1);
  245                 else
  246                         return (0); /* there's no ambiguity */
  247         }
  248 
  249         scope = in6_addrscope(addr);
  250 
  251         switch(scope) {
  252         case IPV6_ADDR_SCOPE_NODELOCAL:
  253                 return (-1);    /* XXX: is this an appropriate value? */
  254 
  255         case IPV6_ADDR_SCOPE_LINKLOCAL:
  256                 return (sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL]);
  257 
  258         case IPV6_ADDR_SCOPE_SITELOCAL:
  259                 return (sid->s6id_list[IPV6_ADDR_SCOPE_SITELOCAL]);
  260 
  261         case IPV6_ADDR_SCOPE_ORGLOCAL:
  262                 return (sid->s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL]);
  263 
  264         default:
  265                 return (0);     /* XXX: treat as global. */
  266         }
  267 }
  268 
  269 void
  270 scope6_setdefault(struct ifnet *ifp)    /* note that this might be NULL */
  271 {
  272         /*
  273          * Currently, this function just set the default "interfaces"
  274          * and "links" according to the given interface.
  275          * We might eventually have to separate the notion of "link" from
  276          * "interface" and provide a user interface to set the default.
  277          */
  278         if (ifp) {
  279                 sid_default.s6id_list[IPV6_ADDR_SCOPE_NODELOCAL] =
  280                         ifp->if_index;
  281                 sid_default.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] =
  282                         ifp->if_index;
  283         } else {
  284                 sid_default.s6id_list[IPV6_ADDR_SCOPE_NODELOCAL] = 0;
  285                 sid_default.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = 0;
  286         }
  287 }
  288 
  289 int
  290 scope6_get_default(struct scope6_id *idlist)
  291 {
  292         *idlist = sid_default;
  293 
  294         return (0);
  295 }
  296 
  297 u_int32_t
  298 scope6_addr2default(struct in6_addr *addr)
  299 {
  300         /*
  301          * special case: The loopback address should be considered as
  302          * link-local, but there's no ambiguity in the syntax.
  303          */
  304         if (IN6_IS_ADDR_LOOPBACK(addr))
  305                 return (0);
  306 
  307         return (sid_default.s6id_list[in6_addrscope(addr)]);
  308 }
  309 
  310 /*
  311  * Determine the appropriate scope zone ID for in6 and ifp.  If ret_id is
  312  * non NULL, it is set to the zone ID.  If the zone ID needs to be embedded
  313   * in the in6_addr structure, in6 will be modified.
  314  */
  315 int
  316 in6_setscope(struct in6_addr *in6, struct ifnet *ifp, u_int32_t *ret_id)
  317 {
  318         int scope;
  319         u_int32_t zoneid = 0;
  320         struct scope6_id *sid;
  321 
  322         ifnet_serialize_all(ifp);
  323 
  324         sid = SID(ifp);
  325 
  326 #ifdef DIAGNOSTIC
  327         if (sid == NULL) { /* should not happen */
  328                 panic("in6_setscope: scope array is NULL");
  329                 /* NOTREACHED */
  330         }
  331 #endif
  332 
  333         /*
  334          * special case: the loopback address can only belong to a loopback
  335          * interface.
  336          */
  337         if (IN6_IS_ADDR_LOOPBACK(in6)) {
  338                 if (!(ifp->if_flags & IFF_LOOPBACK)) {
  339                         ifnet_deserialize_all(ifp);
  340                         return (EINVAL);
  341                 } else {
  342                         if (ret_id != NULL)
  343                                 *ret_id = 0; /* there's no ambiguity */
  344                         ifnet_deserialize_all(ifp);
  345                         return (0);
  346                 }
  347         }
  348 
  349         scope = in6_addrscope(in6);
  350 
  351         switch (scope) {
  352         case IPV6_ADDR_SCOPE_NODELOCAL: /* should be interface index */
  353                 zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_NODELOCAL];
  354                 break;
  355 
  356         case IPV6_ADDR_SCOPE_LINKLOCAL:
  357                 zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL];
  358                 break;
  359 
  360         case IPV6_ADDR_SCOPE_SITELOCAL:
  361                 zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_SITELOCAL];
  362                 break;
  363 
  364         case IPV6_ADDR_SCOPE_ORGLOCAL:
  365                 zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL];
  366                 break;
  367 
  368         default:
  369                 zoneid = 0;     /* XXX: treat as global. */
  370                 break;
  371         }
  372 
  373         ifnet_deserialize_all(ifp);
  374 
  375         if (ret_id != NULL)
  376                 *ret_id = zoneid;
  377 
  378         if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_NODELOCAL(in6) )
  379                 in6->s6_addr16[1] = htons(zoneid & 0xffff); /* XXX */
  380 
  381         return (0);
  382 }

Cache object: b498470734e8950cc0db7e986143967f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.