Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet6/nd6.c
Show First 20 Lines • Show All 1,215 Lines • ▼ Show 20 Lines | |||||
* to not reenter the routing code from within itself. | * to not reenter the routing code from within itself. | ||||
*/ | */ | ||||
static int | static int | ||||
nd6_is_new_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp) | nd6_is_new_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp) | ||||
{ | { | ||||
struct nd_prefix *pr; | struct nd_prefix *pr; | ||||
struct ifaddr *ifa; | struct ifaddr *ifa; | ||||
struct rt_addrinfo info; | struct rt_addrinfo info; | ||||
struct sockaddr_in6 rt_key; | struct sockaddr_dl gw; | ||||
const struct sockaddr *dst6; | const struct sockaddr *dst6; | ||||
uint64_t genid; | |||||
int error, fibnum; | |||||
/* | /* | ||||
* A link-local address is always a neighbor. | * A link-local address is always a neighbor. | ||||
* XXX: a link does not necessarily specify a single interface. | * XXX: a link does not necessarily specify a single interface. | ||||
*/ | */ | ||||
if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) { | if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) { | ||||
struct sockaddr_in6 sin6_copy; | struct sockaddr_in6 sin6_copy; | ||||
u_int32_t zone; | u_int32_t zone; | ||||
/* | /* | ||||
* We need sin6_copy since sa6_recoverscope() may modify the | * We need sin6_copy since sa6_recoverscope() may modify the | ||||
* content (XXX). | * content (XXX). | ||||
*/ | */ | ||||
sin6_copy = *addr; | sin6_copy = *addr; | ||||
if (sa6_recoverscope(&sin6_copy)) | if (sa6_recoverscope(&sin6_copy)) | ||||
return (0); /* XXX: should be impossible */ | return (0); /* XXX: should be impossible */ | ||||
if (in6_setscope(&sin6_copy.sin6_addr, ifp, &zone)) | if (in6_setscope(&sin6_copy.sin6_addr, ifp, &zone)) | ||||
return (0); | return (0); | ||||
if (sin6_copy.sin6_scope_id == zone) | if (sin6_copy.sin6_scope_id == zone) | ||||
return (1); | return (1); | ||||
else | else | ||||
return (0); | return (0); | ||||
} | } | ||||
bzero(&rt_key, sizeof(rt_key)); | |||||
bzero(&info, sizeof(info)); | bzero(&info, sizeof(info)); | ||||
info.rti_info[RTAX_DST] = (struct sockaddr *)&rt_key; | info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&gw; | ||||
/* | /* | ||||
* If the address matches one of our addresses, | * If the address matches one of our addresses, | ||||
* it should be a neighbor. | * it should be a neighbor. | ||||
* If the address matches one of our on-link prefixes, it should be a | * If the address matches one of our on-link prefixes, it should be a | ||||
* neighbor. | * neighbor. | ||||
*/ | */ | ||||
ND6_RLOCK(); | |||||
restart: | |||||
LIST_FOREACH(pr, &V_nd_prefix, ndpr_entry) { | |||||
if (pr->ndpr_ifp != ifp) | |||||
continue; | |||||
if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) { | /* | ||||
dst6 = (const struct sockaddr *)&pr->ndpr_prefix; | * All on-link prefixes should be installed in the routing table for the | ||||
* interface fib. Query routing table first to ensure deterministic | |||||
* lookup time for the cases with large amount of on-link prefixes. | |||||
*/ | |||||
dst6 = (const struct sockaddr *)addr; | |||||
if (rib_lookup_info(ifp->if_fib, dst6, 0, 0, &info) == 0) { | |||||
if (info.rti_ifp == ifp && (info.rti_flags & RTF_GATEWAY) == 0){ | |||||
/* | /* | ||||
* We only need to check all FIBs if add_addr_allfibs | * Every prefix pointing to the right interface which | ||||
* is unset. If set, checking any FIB will suffice. | * does not contain gateway is eligible. | ||||
* | |||||
* This covers both kernel-installed routes (RTF_PINNED) | |||||
* and user-installed routes (RTF_STATIC) | |||||
* | |||||
* Note that RTF_BLACKHOLE / RTF_REJECT would never point | |||||
* to a non-loopback interface. | |||||
*/ | */ | ||||
fibnum = V_rt_add_addr_allfibs ? rt_numfibs - 1 : 0; | |||||
for (; fibnum < rt_numfibs; fibnum++) { | |||||
genid = V_nd6_list_genid; | |||||
ND6_RUNLOCK(); | |||||
return (1); | |||||
} | |||||
if (gw.sdl_family == AF_LINK && gw.sdl_index == ifp->if_index) { | |||||
/* | /* | ||||
* Restore length field before | * Loopback route for the interface address from the | ||||
* retrying lookup | * interface @ifp. Consider as a neighbor. | ||||
*/ | */ | ||||
rt_key.sin6_len = sizeof(rt_key); | |||||
error = rib_lookup_info(fibnum, dst6, 0, 0, | |||||
&info); | |||||
ND6_RLOCK(); | return (1); | ||||
if (genid != V_nd6_list_genid) | |||||
goto restart; | |||||
if (error == 0) | |||||
break; | |||||
} | } | ||||
if (error != 0) | } | ||||
ND6_RLOCK(); | |||||
LIST_FOREACH(pr, &V_nd_prefix, ndpr_entry) { | |||||
if (pr->ndpr_ifp != ifp) | |||||
continue; | continue; | ||||
if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) { | |||||
/* | /* | ||||
* This is the case where multiple interfaces | * Prefix can be off-link either because | ||||
* have the same prefix, but only one is installed | * 1) it is not installed to the routing table | ||||
* into the routing table and that prefix entry | * because another prefix has been installed. | ||||
* is not the one being examined here. In the case | * or | ||||
* where RADIX_MPATH is enabled, multiple route | * 2) prefix has expired but some addresses from | ||||
* entries (of the same rt_key value) will be | * this prefix are still in use. | ||||
* installed because the interface addresses all | * | ||||
* differ. | * Consider prefix as valid if (2) is not the case. | ||||
*/ | */ | ||||
if (!IN6_ARE_ADDR_EQUAL(&pr->ndpr_prefix.sin6_addr, | if (pr->ndpr_vltime != ND6_INFINITE_LIFETIME && | ||||
&rt_key.sin6_addr)) | time_uptime >= pr->ndpr_lastupdate + pr->ndpr_vltime) | ||||
continue; | continue; | ||||
} | } | ||||
if (IN6_ARE_MASKED_ADDR_EQUAL(&pr->ndpr_prefix.sin6_addr, | if (IN6_ARE_MASKED_ADDR_EQUAL(&pr->ndpr_prefix.sin6_addr, | ||||
&addr->sin6_addr, &pr->ndpr_mask)) { | &addr->sin6_addr, &pr->ndpr_mask)) { | ||||
ND6_RUNLOCK(); | ND6_RUNLOCK(); | ||||
return (1); | return (1); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,340 Lines • Show Last 20 Lines |