Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet6/in6.c
Show First 20 Lines • Show All 1,468 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Find an IPv6 interface link-local address specific to an interface. | * Find an IPv6 interface link-local address specific to an interface. | ||||
* ifaddr is returned referenced. | * ifaddr is returned referenced. | ||||
*/ | */ | ||||
struct in6_ifaddr * | struct in6_ifaddr * | ||||
in6ifa_ifpforlinklocal(struct ifnet *ifp, int ignoreflags) | in6ifa_ifpforlinklocal(struct ifnet *ifp, int ignoreflags) | ||||
{ | { | ||||
struct epoch_tracker et; | |||||
struct ifaddr *ifa; | struct ifaddr *ifa; | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ASSERT(); | ||||
CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { | CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { | ||||
if (ifa->ifa_addr->sa_family != AF_INET6) | if (ifa->ifa_addr->sa_family != AF_INET6) | ||||
continue; | continue; | ||||
if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa))) { | if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa))) { | ||||
if ((((struct in6_ifaddr *)ifa)->ia6_flags & | if ((((struct in6_ifaddr *)ifa)->ia6_flags & | ||||
ignoreflags) != 0) | ignoreflags) != 0) | ||||
continue; | continue; | ||||
ifa_ref(ifa); | ifa_ref(ifa); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
NET_EPOCH_EXIT(et); | |||||
return ((struct in6_ifaddr *)ifa); | return ((struct in6_ifaddr *)ifa); | ||||
} | } | ||||
/* | /* | ||||
* find the interface address corresponding to a given IPv6 address. | * find the interface address corresponding to a given IPv6 address. | ||||
* ifaddr is returned referenced. | * ifaddr is returned referenced. | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/* | /* | ||||
* Find a link-local scoped address on ifp and return it if any. | * Find a link-local scoped address on ifp and return it if any. | ||||
*/ | */ | ||||
struct in6_ifaddr * | struct in6_ifaddr * | ||||
in6ifa_llaonifp(struct ifnet *ifp) | in6ifa_llaonifp(struct ifnet *ifp) | ||||
{ | { | ||||
struct epoch_tracker et; | |||||
struct sockaddr_in6 *sin6; | struct sockaddr_in6 *sin6; | ||||
struct ifaddr *ifa; | struct ifaddr *ifa; | ||||
NET_EPOCH_ASSERT(); | |||||
if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) | if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) | ||||
return (NULL); | return (NULL); | ||||
NET_EPOCH_ENTER(et); | |||||
CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { | CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { | ||||
if (ifa->ifa_addr->sa_family != AF_INET6) | if (ifa->ifa_addr->sa_family != AF_INET6) | ||||
continue; | continue; | ||||
sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; | sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; | ||||
if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) || | if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) || | ||||
IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr) || | IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr) || | ||||
IN6_IS_ADDR_MC_NODELOCAL(&sin6->sin6_addr)) | IN6_IS_ADDR_MC_NODELOCAL(&sin6->sin6_addr)) | ||||
break; | break; | ||||
} | } | ||||
NET_EPOCH_EXIT(et); | |||||
return ((struct in6_ifaddr *)ifa); | return ((struct in6_ifaddr *)ifa); | ||||
} | } | ||||
/* | /* | ||||
* Convert IP6 address to printable (loggable) representation. Caller | * Convert IP6 address to printable (loggable) representation. Caller | ||||
* has to make sure that ip6buf is at least INET6_ADDRSTRLEN long. | * has to make sure that ip6buf is at least INET6_ADDRSTRLEN long. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 120 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Return 1 if an internet address is configured on an interface. | * Return 1 if an internet address is configured on an interface. | ||||
*/ | */ | ||||
int | int | ||||
in6_ifhasaddr(struct ifnet *ifp, struct in6_addr *addr) | in6_ifhasaddr(struct ifnet *ifp, struct in6_addr *addr) | ||||
{ | { | ||||
struct in6_addr in6; | struct in6_addr in6; | ||||
struct epoch_tracker et; | |||||
struct ifaddr *ifa; | struct ifaddr *ifa; | ||||
struct in6_ifaddr *ia6; | struct in6_ifaddr *ia6; | ||||
NET_EPOCH_ASSERT(); | |||||
in6 = *addr; | in6 = *addr; | ||||
if (in6_clearscope(&in6)) | if (in6_clearscope(&in6)) | ||||
return (0); | return (0); | ||||
in6_setscope(&in6, ifp, NULL); | in6_setscope(&in6, ifp, NULL); | ||||
NET_EPOCH_ENTER(et); | |||||
CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { | CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { | ||||
if (ifa->ifa_addr->sa_family != AF_INET6) | if (ifa->ifa_addr->sa_family != AF_INET6) | ||||
continue; | continue; | ||||
ia6 = (struct in6_ifaddr *)ifa; | ia6 = (struct in6_ifaddr *)ifa; | ||||
if (IN6_ARE_ADDR_EQUAL(&ia6->ia_addr.sin6_addr, &in6)) { | if (IN6_ARE_ADDR_EQUAL(&ia6->ia_addr.sin6_addr, &in6)) | ||||
NET_EPOCH_EXIT(et); | |||||
return (1); | return (1); | ||||
} | } | ||||
} | |||||
NET_EPOCH_EXIT(et); | |||||
return (0); | return (0); | ||||
} | } | ||||
int | int | ||||
in6_is_addr_deprecated(struct sockaddr_in6 *sa6) | in6_is_addr_deprecated(struct sockaddr_in6 *sa6) | ||||
{ | { | ||||
struct rm_priotracker in6_ifa_tracker; | struct rm_priotracker in6_ifa_tracker; | ||||
▲ Show 20 Lines • Show All 87 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* return the best address out of the same scope. if no address was | * return the best address out of the same scope. if no address was | ||||
* found, return the first valid address from designated IF. | * found, return the first valid address from designated IF. | ||||
*/ | */ | ||||
struct in6_ifaddr * | struct in6_ifaddr * | ||||
in6_ifawithifp(struct ifnet *ifp, struct in6_addr *dst) | in6_ifawithifp(struct ifnet *ifp, struct in6_addr *dst) | ||||
{ | { | ||||
struct epoch_tracker et; | |||||
int dst_scope = in6_addrscope(dst), blen = -1, tlen; | int dst_scope = in6_addrscope(dst), blen = -1, tlen; | ||||
struct ifaddr *ifa; | struct ifaddr *ifa; | ||||
struct in6_ifaddr *besta = NULL; | struct in6_ifaddr *besta = NULL; | ||||
struct in6_ifaddr *dep[2]; /* last-resort: deprecated */ | struct in6_ifaddr *dep[2]; /* last-resort: deprecated */ | ||||
NET_EPOCH_ASSERT(); | |||||
dep[0] = dep[1] = NULL; | dep[0] = dep[1] = NULL; | ||||
/* | /* | ||||
* We first look for addresses in the same scope. | * We first look for addresses in the same scope. | ||||
* If there is one, return it. | * If there is one, return it. | ||||
* If two or more, return one which matches the dst longest. | * If two or more, return one which matches the dst longest. | ||||
* If none, return one of global addresses assigned other ifs. | * If none, return one of global addresses assigned other ifs. | ||||
*/ | */ | ||||
NET_EPOCH_ENTER(et); | |||||
CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { | CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { | ||||
if (ifa->ifa_addr->sa_family != AF_INET6) | if (ifa->ifa_addr->sa_family != AF_INET6) | ||||
continue; | continue; | ||||
if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST) | if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST) | ||||
continue; /* XXX: is there any case to allow anycast? */ | continue; /* XXX: is there any case to allow anycast? */ | ||||
if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY) | if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY) | ||||
continue; /* don't use this interface */ | continue; /* don't use this interface */ | ||||
if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED) | if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED) | ||||
Show All 17 Lines | if (dst_scope == in6_addrscope(IFA_IN6(ifa))) { | ||||
besta = (struct in6_ifaddr *)ifa; | besta = (struct in6_ifaddr *)ifa; | ||||
} | } | ||||
} else | } else | ||||
besta = (struct in6_ifaddr *)ifa; | besta = (struct in6_ifaddr *)ifa; | ||||
} | } | ||||
} | } | ||||
if (besta) { | if (besta) { | ||||
ifa_ref(&besta->ia_ifa); | ifa_ref(&besta->ia_ifa); | ||||
NET_EPOCH_EXIT(et); | |||||
return (besta); | return (besta); | ||||
} | } | ||||
CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { | CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { | ||||
if (ifa->ifa_addr->sa_family != AF_INET6) | if (ifa->ifa_addr->sa_family != AF_INET6) | ||||
continue; | continue; | ||||
if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST) | if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST) | ||||
continue; /* XXX: is there any case to allow anycast? */ | continue; /* XXX: is there any case to allow anycast? */ | ||||
if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY) | if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY) | ||||
continue; /* don't use this interface */ | continue; /* don't use this interface */ | ||||
if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED) | if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED) | ||||
continue; | continue; | ||||
if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) { | if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) { | ||||
if (V_ip6_use_deprecated) | if (V_ip6_use_deprecated) | ||||
dep[1] = (struct in6_ifaddr *)ifa; | dep[1] = (struct in6_ifaddr *)ifa; | ||||
continue; | continue; | ||||
} | } | ||||
if (ifa != NULL) | if (ifa != NULL) | ||||
ifa_ref(ifa); | ifa_ref(ifa); | ||||
NET_EPOCH_EXIT(et); | |||||
return (struct in6_ifaddr *)ifa; | return (struct in6_ifaddr *)ifa; | ||||
} | } | ||||
/* use the last-resort values, that are, deprecated addresses */ | /* use the last-resort values, that are, deprecated addresses */ | ||||
if (dep[0]) { | if (dep[0]) { | ||||
ifa_ref((struct ifaddr *)dep[0]); | ifa_ref((struct ifaddr *)dep[0]); | ||||
NET_EPOCH_EXIT(et); | |||||
return dep[0]; | return dep[0]; | ||||
} | } | ||||
if (dep[1]) { | if (dep[1]) { | ||||
ifa_ref((struct ifaddr *)dep[1]); | ifa_ref((struct ifaddr *)dep[1]); | ||||
NET_EPOCH_EXIT(et); | |||||
return dep[1]; | return dep[1]; | ||||
} | } | ||||
NET_EPOCH_EXIT(et); | |||||
return NULL; | return NULL; | ||||
} | } | ||||
/* | /* | ||||
* perform DAD when interface becomes IFF_UP. | * perform DAD when interface becomes IFF_UP. | ||||
*/ | */ | ||||
void | void | ||||
in6_if_up(struct ifnet *ifp) | in6_if_up(struct ifnet *ifp) | ||||
Show All 13 Lines | if (ia->ia6_flags & IN6_IFF_TENTATIVE) { | ||||
* beforehand, implicitly indicating the need for DAD. | * beforehand, implicitly indicating the need for DAD. | ||||
* We may be able to skip the random delay in this | * We may be able to skip the random delay in this | ||||
* case, but we impose delays just in case. | * case, but we impose delays just in case. | ||||
*/ | */ | ||||
nd6_dad_start(ifa, | nd6_dad_start(ifa, | ||||
arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz)); | arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz)); | ||||
} | } | ||||
} | } | ||||
NET_EPOCH_EXIT(et); | |||||
/* | /* | ||||
* special cases, like 6to4, are handled in in6_ifattach | * special cases, like 6to4, are handled in in6_ifattach | ||||
*/ | */ | ||||
in6_ifattach(ifp, NULL); | in6_ifattach(ifp, NULL); | ||||
NET_EPOCH_EXIT(et); | |||||
} | } | ||||
int | int | ||||
in6if_do_dad(struct ifnet *ifp) | in6if_do_dad(struct ifnet *ifp) | ||||
{ | { | ||||
if ((ifp->if_flags & IFF_LOOPBACK) != 0) | if ((ifp->if_flags & IFF_LOOPBACK) != 0) | ||||
return (0); | return (0); | ||||
▲ Show 20 Lines • Show All 202 Lines • ▼ Show 20 Lines | in6_lltable_rtcheck(struct ifnet *ifp, | ||||
const struct sockaddr_in6 *sin6; | const struct sockaddr_in6 *sin6; | ||||
struct nhop6_basic nh6; | struct nhop6_basic nh6; | ||||
struct in6_addr dst; | struct in6_addr dst; | ||||
uint32_t scopeid; | uint32_t scopeid; | ||||
int error; | int error; | ||||
char ip6buf[INET6_ADDRSTRLEN]; | char ip6buf[INET6_ADDRSTRLEN]; | ||||
int fibnum; | int fibnum; | ||||
NET_EPOCH_ASSERT(); | |||||
KASSERT(l3addr->sa_family == AF_INET6, | KASSERT(l3addr->sa_family == AF_INET6, | ||||
("sin_family %d", l3addr->sa_family)); | ("sin_family %d", l3addr->sa_family)); | ||||
sin6 = (const struct sockaddr_in6 *)l3addr; | sin6 = (const struct sockaddr_in6 *)l3addr; | ||||
in6_splitscope(&sin6->sin6_addr, &dst, &scopeid); | in6_splitscope(&sin6->sin6_addr, &dst, &scopeid); | ||||
fibnum = V_rt_add_addr_allfibs ? RT_DEFAULT_FIB : ifp->if_fib; | fibnum = V_rt_add_addr_allfibs ? RT_DEFAULT_FIB : ifp->if_fib; | ||||
error = fib6_lookup_nh_basic(fibnum, &dst, scopeid, 0, 0, &nh6); | error = fib6_lookup_nh_basic(fibnum, &dst, scopeid, 0, 0, &nh6); | ||||
if (error != 0 || (nh6.nh_flags & NHF_GATEWAY) || nh6.nh_ifp != ifp) { | if (error != 0 || (nh6.nh_flags & NHF_GATEWAY) || nh6.nh_ifp != ifp) { | ||||
struct epoch_tracker et; | |||||
struct ifaddr *ifa; | struct ifaddr *ifa; | ||||
/* | /* | ||||
* Create an ND6 cache for an IPv6 neighbor | * Create an ND6 cache for an IPv6 neighbor | ||||
* that is not covered by our own prefix. | * that is not covered by our own prefix. | ||||
*/ | */ | ||||
NET_EPOCH_ENTER(et); | |||||
ifa = ifaof_ifpforaddr(l3addr, ifp); | ifa = ifaof_ifpforaddr(l3addr, ifp); | ||||
if (ifa != NULL) { | if (ifa != NULL) { | ||||
NET_EPOCH_EXIT(et); | |||||
return 0; | return 0; | ||||
} | } | ||||
NET_EPOCH_EXIT(et); | |||||
log(LOG_INFO, "IPv6 address: \"%s\" is not on the network\n", | log(LOG_INFO, "IPv6 address: \"%s\" is not on the network\n", | ||||
ip6_sprintf(ip6buf, &sin6->sin6_addr)); | ip6_sprintf(ip6buf, &sin6->sin6_addr)); | ||||
return EINVAL; | return EINVAL; | ||||
} | } | ||||
return 0; | return 0; | ||||
} | } | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 381 Lines • Show Last 20 Lines |