diff options
Diffstat (limited to 'sys/netinet6/scope6.c')
-rw-r--r-- | sys/netinet6/scope6.c | 78 |
1 files changed, 56 insertions, 22 deletions
diff --git a/sys/netinet6/scope6.c b/sys/netinet6/scope6.c index fbb681a..39531d4 100644 --- a/sys/netinet6/scope6.c +++ b/sys/netinet6/scope6.c @@ -70,7 +70,7 @@ scope6_ifattach(ifp) * XXX: IPV6_ADDR_SCOPE_xxx macros are not standard. * Should we rather hardcode here? */ - sid->s6id_list[IPV6_ADDR_SCOPE_NODELOCAL] = ifp->if_index; + sid->s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] = ifp->if_index; sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = ifp->if_index; #ifdef MULTI_SCOPE /* by default, we don't care about scope boundary for these scopes. */ @@ -117,6 +117,16 @@ scope6_set(ifp, idlist) for (i = 0; i < 16; i++) { if (idlist->s6id_list[i] && idlist->s6id_list[i] != sid->s6id_list[i]) { + /* + * An interface zone ID must be the corresponding + * interface index by definition. + */ + if (i == IPV6_ADDR_SCOPE_INTFACELOCAL && + idlist->s6id_list[i] != ifp->if_index) { + splx(s); + return (EINVAL); + } + if (i == IPV6_ADDR_SCOPE_LINKLOCAL && idlist->s6id_list[i] > if_index) { /* @@ -167,8 +177,8 @@ in6_addrscope(addr) { int scope; - if (addr->s6_addr8[0] == 0xfe) { - scope = addr->s6_addr8[1] & 0xc0; + if (addr->s6_addr[0] == 0xfe) { + scope = addr->s6_addr[1] & 0xc0; switch (scope) { case 0x80: @@ -184,16 +194,16 @@ in6_addrscope(addr) } - if (addr->s6_addr8[0] == 0xff) { - scope = addr->s6_addr8[1] & 0x0f; + if (addr->s6_addr[0] == 0xff) { + scope = addr->s6_addr[1] & 0x0f; /* * due to other scope such as reserved, * return scope doesn't work. */ switch (scope) { - case IPV6_ADDR_SCOPE_NODELOCAL: - return IPV6_ADDR_SCOPE_NODELOCAL; + case IPV6_ADDR_SCOPE_INTFACELOCAL: + return IPV6_ADDR_SCOPE_INTFACELOCAL; break; case IPV6_ADDR_SCOPE_LINKLOCAL: return IPV6_ADDR_SCOPE_LINKLOCAL; @@ -207,22 +217,33 @@ in6_addrscope(addr) } } + /* + * Regard loopback and unspecified addresses as global, since + * they have no ambiguity. + */ if (bcmp(&in6addr_loopback, addr, sizeof(*addr) - 1) == 0) { - if (addr->s6_addr8[15] == 1) /* loopback */ - return IPV6_ADDR_SCOPE_NODELOCAL; - if (addr->s6_addr8[15] == 0) /* unspecified */ + if (addr->s6_addr[15] == 1) /* loopback */ return IPV6_ADDR_SCOPE_LINKLOCAL; + if (addr->s6_addr[15] == 0) /* unspecified */ + return IPV6_ADDR_SCOPE_GLOBAL; /* XXX: correct? */ } return IPV6_ADDR_SCOPE_GLOBAL; } +/* + * When we introduce the "4+28" split semantics in sin6_scope_id, + * a 32bit integer is not enough to tell a large ID from an error (-1). + * So, we intentionally use a large type as the return value. + */ int -in6_addr2scopeid(ifp, addr) +in6_addr2zoneid(ifp, addr, ret_id) struct ifnet *ifp; /* must not be NULL */ struct in6_addr *addr; /* must not be NULL */ + u_int32_t *ret_id; /* must not be NULL */ { int scope; + u_int32_t zoneid = 0; struct scope6_id *sid = SID(ifp); #ifdef DIAGNOSTIC @@ -230,6 +251,10 @@ in6_addr2scopeid(ifp, addr) panic("in6_addr2zoneid: scope array is NULL"); /* NOTREACHED */ } + if (ret_id == NULL) { + panic("in6_addr2zoneid: return ID is null"); + /* NOTREACHED */ + } #endif /* @@ -239,28 +264,37 @@ in6_addr2scopeid(ifp, addr) if (IN6_IS_ADDR_LOOPBACK(addr)) { if (!(ifp->if_flags & IFF_LOOPBACK)) return (-1); - else - return (0); /* there's no ambiguity */ + else { + *ret_id = 0; /* there's no ambiguity */ + return (0); + } } scope = in6_addrscope(addr); - switch(scope) { - case IPV6_ADDR_SCOPE_NODELOCAL: - return (-1); /* XXX: is this an appropriate value? */ + switch (scope) { + case IPV6_ADDR_SCOPE_INTFACELOCAL: /* should be interface index */ + zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL]; + break; case IPV6_ADDR_SCOPE_LINKLOCAL: - return (sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL]); + zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL]; + break; case IPV6_ADDR_SCOPE_SITELOCAL: - return (sid->s6id_list[IPV6_ADDR_SCOPE_SITELOCAL]); + zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_SITELOCAL]; + break; case IPV6_ADDR_SCOPE_ORGLOCAL: - return (sid->s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL]); + zoneid = sid->s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL]; + break; default: - return (0); /* XXX: treat as global. */ + zoneid = 0; /* XXX: treat as global. */ + break; } + *ret_id = zoneid; + return (0); } void @@ -274,12 +308,12 @@ scope6_setdefault(ifp) * "interface" and provide a user interface to set the default. */ if (ifp) { - sid_default.s6id_list[IPV6_ADDR_SCOPE_NODELOCAL] = + sid_default.s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] = ifp->if_index; sid_default.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = ifp->if_index; } else { - sid_default.s6id_list[IPV6_ADDR_SCOPE_NODELOCAL] = 0; + sid_default.s6id_list[IPV6_ADDR_SCOPE_INTFACELOCAL] = 0; sid_default.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = 0; } } |