Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet6/nd6_nbr.c
Show First 20 Lines • Show All 610 Lines • ▼ Show 20 Lines | |||||
* - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD) | * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD) | ||||
*/ | */ | ||||
void | void | ||||
nd6_na_input(struct mbuf *m, int off, int icmp6len) | nd6_na_input(struct mbuf *m, int off, int icmp6len) | ||||
{ | { | ||||
struct ifnet *ifp = m->m_pkthdr.rcvif; | struct ifnet *ifp = m->m_pkthdr.rcvif; | ||||
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); | struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); | ||||
struct nd_neighbor_advert *nd_na; | struct nd_neighbor_advert *nd_na; | ||||
struct nd_defrouter *dr; | |||||
struct in6_addr daddr6 = ip6->ip6_dst; | struct in6_addr daddr6 = ip6->ip6_dst; | ||||
struct in6_addr taddr6; | struct in6_addr taddr6; | ||||
int flags; | int flags; | ||||
int is_router; | int is_router; | ||||
int is_solicited; | int is_solicited; | ||||
int is_override; | int is_override; | ||||
char *lladdr = NULL; | char *lladdr = NULL; | ||||
int lladdrlen = 0; | int lladdrlen = 0; | ||||
int checklink = 0; | int checklink = 0; | ||||
struct ifaddr *ifa; | struct ifaddr *ifa; | ||||
struct llentry *ln = NULL; | struct llentry *ln = NULL; | ||||
union nd_opts ndopts; | union nd_opts ndopts; | ||||
struct mbuf *chain = NULL; | struct mbuf *chain = NULL; | ||||
struct sockaddr_in6 sin6; | struct sockaddr_in6 sin6; | ||||
u_char linkhdr[LLE_MAX_LINKHDR]; | u_char linkhdr[LLE_MAX_LINKHDR]; | ||||
size_t linkhdrsize; | size_t linkhdrsize; | ||||
int lladdr_off; | int lladdr_off; | ||||
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; | char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; | ||||
int removed_defrouter = 0; | |||||
int nd6_locked = 0; | |||||
/* RFC 6980: Nodes MUST silently ignore fragments */ | /* RFC 6980: Nodes MUST silently ignore fragments */ | ||||
if(m->m_flags & M_FRAGMENTED) | if(m->m_flags & M_FRAGMENTED) | ||||
goto freeit; | goto freeit; | ||||
if (ip6->ip6_hlim != 255) { | if (ip6->ip6_hlim != 255) { | ||||
nd6log((LOG_ERR, | nd6log((LOG_ERR, | ||||
"nd6_na_input: invalid hlim (%d) from %s to %s on %s\n", | "nd6_na_input: invalid hlim (%d) from %s to %s on %s\n", | ||||
▲ Show 20 Lines • Show All 91 Lines • ▼ Show 20 Lines | if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { | ||||
goto bad; | goto bad; | ||||
} | } | ||||
/* | /* | ||||
* If no neighbor cache entry is found, NA SHOULD silently be | * If no neighbor cache entry is found, NA SHOULD silently be | ||||
* discarded. | * discarded. | ||||
*/ | */ | ||||
IF_AFDATA_RLOCK(ifp); | IF_AFDATA_RLOCK(ifp); | ||||
/* Take nd6 prior to lle lock in case we call defrouter_removed(). */ | |||||
ND6_WLOCK(); | |||||
nd6_locked = true; | |||||
ln = nd6_lookup(&taddr6, LLE_EXCLUSIVE, ifp); | ln = nd6_lookup(&taddr6, LLE_EXCLUSIVE, ifp); | ||||
IF_AFDATA_RUNLOCK(ifp); | IF_AFDATA_RUNLOCK(ifp); | ||||
if (ln == NULL) { | if (ln == NULL) { | ||||
goto freeit; | goto freeit; | ||||
} | } | ||||
if (ln->ln_state == ND6_LLINFO_INCOMPLETE) { | if (ln->ln_state == ND6_LLINFO_INCOMPLETE) { | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 112 Lines • ▼ Show 20 Lines | if (ln->ln_router && !is_router) { | ||||
/* | /* | ||||
* The peer dropped the router flag. | * The peer dropped the router flag. | ||||
* Remove the sender from the Default Router List and | * Remove the sender from the Default Router List and | ||||
* update the Destination Cache entries. | * update the Destination Cache entries. | ||||
*/ | */ | ||||
struct ifnet *nd6_ifp; | struct ifnet *nd6_ifp; | ||||
nd6_ifp = lltable_get_ifp(ln->lle_tbl); | nd6_ifp = lltable_get_ifp(ln->lle_tbl); | ||||
if (!defrouter_remove(&ln->r_l3addr.addr6, nd6_ifp) && | |||||
dr = defrouter_lookup_locked(&ln->r_l3addr.addr6, | |||||
nd6_ifp); | |||||
if (dr != NULL) { | |||||
defrouter_unlink(dr, NULL); | |||||
removed_defrouter = true; | |||||
} | |||||
if (!removed_defrouter && | |||||
(ND_IFINFO(nd6_ifp)->flags & | (ND_IFINFO(nd6_ifp)->flags & | ||||
ND6_IFF_ACCEPT_RTADV) != 0) | ND6_IFF_ACCEPT_RTADV) != 0) | ||||
/* | /* | ||||
* Even if the neighbor is not in the default | * Even if the neighbor is not in the default | ||||
* router list, the neighbor may be used as a | * router list, the neighbor may be used as a | ||||
* next hop for some destinations (e.g. redirect | * next hop for some destinations (e.g. redirect | ||||
* case). So we must call rt6_flush explicitly. | * case). So we must call rt6_flush explicitly. | ||||
*/ | */ | ||||
rt6_flush(&ip6->ip6_src, ifp); | rt6_flush(&ip6->ip6_src, ifp); | ||||
} | } | ||||
ln->ln_router = is_router; | ln->ln_router = is_router; | ||||
} | } | ||||
/* XXX - QL | /* XXX - QL | ||||
* Does this matter? | * Does this matter? | ||||
* rt->rt_flags &= ~RTF_REJECT; | * rt->rt_flags &= ~RTF_REJECT; | ||||
*/ | */ | ||||
ln->la_asked = 0; | ln->la_asked = 0; | ||||
if (ln->la_hold != NULL) | if (ln->la_hold != NULL) | ||||
nd6_grab_holdchain(ln, &chain, &sin6); | nd6_grab_holdchain(ln, &chain, &sin6); | ||||
freeit: | freeit: | ||||
if (ln != NULL) | if (ln != NULL) | ||||
LLE_WUNLOCK(ln); | LLE_WUNLOCK(ln); | ||||
if (nd6_locked) | |||||
ND6_WUNLOCK(); | |||||
if (removed_defrouter && dr != NULL) { | |||||
defrouter_del(dr); | |||||
defrouter_rele(dr); | |||||
} | |||||
if (chain != NULL) | if (chain != NULL) | ||||
nd6_flush_holdchain(ifp, chain, &sin6); | nd6_flush_holdchain(ifp, chain, &sin6); | ||||
if (checklink) | if (checklink) | ||||
pfxlist_onlink_check(); | pfxlist_onlink_check(); | ||||
m_freem(m); | m_freem(m); | ||||
return; | return; | ||||
bad: | bad: | ||||
if (ln != NULL) | if (ln != NULL) | ||||
LLE_WUNLOCK(ln); | LLE_WUNLOCK(ln); | ||||
if (nd6_locked) | |||||
ND6_WUNLOCK(); | |||||
ICMP6STAT_INC(icp6s_badna); | ICMP6STAT_INC(icp6s_badna); | ||||
m_freem(m); | m_freem(m); | ||||
} | } | ||||
/* | /* | ||||
* Neighbor advertisement output handling. | * Neighbor advertisement output handling. | ||||
* | * | ||||
▲ Show 20 Lines • Show All 632 Lines • Show Last 20 Lines |