Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet6/nd6.c
Show First 20 Lines • Show All 725 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Timer-dependent part of nd state machine. | * Timer-dependent part of nd state machine. | ||||
* | * | ||||
* Set noinline to be dtrace-friendly | * Set noinline to be dtrace-friendly | ||||
*/ | */ | ||||
static __noinline void | static __noinline void | ||||
nd6_llinfo_timer(void *arg) | nd6_llinfo_timer(void *arg) | ||||
{ | { | ||||
struct epoch_tracker et; | |||||
struct llentry *ln; | struct llentry *ln; | ||||
struct in6_addr *dst, *pdst, *psrc, src; | struct in6_addr *dst, *pdst, *psrc, src; | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
struct nd_ifinfo *ndi; | struct nd_ifinfo *ndi; | ||||
int do_switch, send_ns; | int do_switch, send_ns; | ||||
long delay; | long delay; | ||||
KASSERT(arg != NULL, ("%s: arg NULL", __func__)); | KASSERT(arg != NULL, ("%s: arg NULL", __func__)); | ||||
Show All 20 Lines | if (callout_pending(&ln->lle_timer)) { | ||||
* by nd6_llinfo_settimer_locked above since canceled | * by nd6_llinfo_settimer_locked above since canceled | ||||
* would have been 1. | * would have been 1. | ||||
*/ | */ | ||||
LLE_WUNLOCK(ln); | LLE_WUNLOCK(ln); | ||||
ND6_RUNLOCK(); | ND6_RUNLOCK(); | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
return; | return; | ||||
} | } | ||||
NET_EPOCH_ENTER(et); | |||||
ndi = ND_IFINFO(ifp); | ndi = ND_IFINFO(ifp); | ||||
send_ns = 0; | send_ns = 0; | ||||
dst = &ln->r_l3addr.addr6; | dst = &ln->r_l3addr.addr6; | ||||
pdst = dst; | pdst = dst; | ||||
if (ln->ln_ntick > 0) { | if (ln->ln_ntick > 0) { | ||||
if (ln->ln_ntick > INT_MAX) { | if (ln->ln_ntick > INT_MAX) { | ||||
ln->ln_ntick -= INT_MAX; | ln->ln_ntick -= INT_MAX; | ||||
▲ Show 20 Lines • Show All 99 Lines • ▼ Show 20 Lines | if (ln != NULL) | ||||
ND6_RUNLOCK(); | ND6_RUNLOCK(); | ||||
if (send_ns != 0) { | if (send_ns != 0) { | ||||
nd6_llinfo_settimer_locked(ln, (long)ndi->retrans * hz / 1000); | nd6_llinfo_settimer_locked(ln, (long)ndi->retrans * hz / 1000); | ||||
psrc = nd6_llinfo_get_holdsrc(ln, &src); | psrc = nd6_llinfo_get_holdsrc(ln, &src); | ||||
LLE_FREE_LOCKED(ln); | LLE_FREE_LOCKED(ln); | ||||
ln = NULL; | ln = NULL; | ||||
nd6_ns_output(ifp, psrc, pdst, dst, NULL); | nd6_ns_output(ifp, psrc, pdst, dst, NULL); | ||||
} | } | ||||
if (ln != NULL) | if (ln != NULL) | ||||
LLE_FREE_LOCKED(ln); | LLE_FREE_LOCKED(ln); | ||||
NET_EPOCH_EXIT(et); | |||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
} | } | ||||
/* | /* | ||||
* ND6 timer routine to expire default route list and prefix list | * ND6 timer routine to expire default route list and prefix list | ||||
*/ | */ | ||||
void | void | ||||
nd6_timer(void *arg) | nd6_timer(void *arg) | ||||
{ | { | ||||
CURVNET_SET((struct vnet *) arg); | CURVNET_SET((struct vnet *) arg); | ||||
struct epoch_tracker et; | |||||
struct nd_drhead drq; | struct nd_drhead drq; | ||||
struct nd_prhead prl; | struct nd_prhead prl; | ||||
struct nd_defrouter *dr, *ndr; | struct nd_defrouter *dr, *ndr; | ||||
struct nd_prefix *pr, *npr; | struct nd_prefix *pr, *npr; | ||||
struct in6_ifaddr *ia6, *nia6; | struct in6_ifaddr *ia6, *nia6; | ||||
uint64_t genid; | uint64_t genid; | ||||
TAILQ_INIT(&drq); | TAILQ_INIT(&drq); | ||||
Show All 13 Lines | nd6_timer(void *arg) | ||||
/* | /* | ||||
* expire interface addresses. | * expire interface addresses. | ||||
* in the past the loop was inside prefix expiry processing. | * in the past the loop was inside prefix expiry processing. | ||||
* However, from a stricter speci-confrmance standpoint, we should | * However, from a stricter speci-confrmance standpoint, we should | ||||
* rather separate address lifetimes and prefix lifetimes. | * rather separate address lifetimes and prefix lifetimes. | ||||
* | * | ||||
* XXXRW: in6_ifaddrhead locking. | * XXXRW: in6_ifaddrhead locking. | ||||
*/ | */ | ||||
NET_EPOCH_ENTER(et); | |||||
addrloop: | addrloop: | ||||
CK_STAILQ_FOREACH_SAFE(ia6, &V_in6_ifaddrhead, ia_link, nia6) { | CK_STAILQ_FOREACH_SAFE(ia6, &V_in6_ifaddrhead, ia_link, nia6) { | ||||
/* check address lifetime */ | /* check address lifetime */ | ||||
if (IFA6_IS_INVALID(ia6)) { | if (IFA6_IS_INVALID(ia6)) { | ||||
int regen = 0; | int regen = 0; | ||||
/* | /* | ||||
* If the expiring address is temporary, try | * If the expiring address is temporary, try | ||||
▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | if (IFA6_IS_INVALID(ia6)) { | ||||
} | } | ||||
/* | /* | ||||
* A new RA might have made a deprecated address | * A new RA might have made a deprecated address | ||||
* preferred. | * preferred. | ||||
*/ | */ | ||||
ia6->ia6_flags &= ~IN6_IFF_DEPRECATED; | ia6->ia6_flags &= ~IN6_IFF_DEPRECATED; | ||||
} | } | ||||
} | } | ||||
NET_EPOCH_EXIT(et); | |||||
ND6_WLOCK(); | ND6_WLOCK(); | ||||
restart: | restart: | ||||
LIST_FOREACH_SAFE(pr, &V_nd_prefix, ndpr_entry, npr) { | LIST_FOREACH_SAFE(pr, &V_nd_prefix, ndpr_entry, npr) { | ||||
/* | /* | ||||
* Expire prefixes. Since the pltime is only used for | * Expire prefixes. Since the pltime is only used for | ||||
* autoconfigured addresses, pltime processing for prefixes is | * autoconfigured addresses, pltime processing for prefixes is | ||||
* not necessary. | * not necessary. | ||||
Show All 39 Lines | |||||
} | } | ||||
/* | /* | ||||
* ia6 - deprecated/invalidated temporary address | * ia6 - deprecated/invalidated temporary address | ||||
*/ | */ | ||||
static int | static int | ||||
regen_tmpaddr(struct in6_ifaddr *ia6) | regen_tmpaddr(struct in6_ifaddr *ia6) | ||||
{ | { | ||||
struct epoch_tracker et; | |||||
struct ifaddr *ifa; | struct ifaddr *ifa; | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
struct in6_ifaddr *public_ifa6 = NULL; | struct in6_ifaddr *public_ifa6 = NULL; | ||||
NET_EPOCH_ASSERT(); | |||||
ifp = ia6->ia_ifa.ifa_ifp; | ifp = ia6->ia_ifa.ifa_ifp; | ||||
NET_EPOCH_ENTER(et); | |||||
CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { | CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { | ||||
struct in6_ifaddr *it6; | struct in6_ifaddr *it6; | ||||
if (ifa->ifa_addr->sa_family != AF_INET6) | if (ifa->ifa_addr->sa_family != AF_INET6) | ||||
continue; | continue; | ||||
it6 = (struct in6_ifaddr *)ifa; | it6 = (struct in6_ifaddr *)ifa; | ||||
Show All 24 Lines | CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { | ||||
* loop here, because there may be a still-preferred temporary | * loop here, because there may be a still-preferred temporary | ||||
* address with the prefix. | * address with the prefix. | ||||
*/ | */ | ||||
if (!IFA6_IS_DEPRECATED(it6)) | if (!IFA6_IS_DEPRECATED(it6)) | ||||
public_ifa6 = it6; | public_ifa6 = it6; | ||||
} | } | ||||
if (public_ifa6 != NULL) | if (public_ifa6 != NULL) | ||||
ifa_ref(&public_ifa6->ia_ifa); | ifa_ref(&public_ifa6->ia_ifa); | ||||
NET_EPOCH_EXIT(et); | |||||
if (public_ifa6 != NULL) { | if (public_ifa6 != NULL) { | ||||
int e; | int e; | ||||
if ((e = in6_tmpifadd(public_ifa6, 0, 0)) != 0) { | if ((e = in6_tmpifadd(public_ifa6, 0, 0)) != 0) { | ||||
ifa_free(&public_ifa6->ia_ifa); | ifa_free(&public_ifa6->ia_ifa); | ||||
log(LOG_NOTICE, "regen_tmpaddr: failed to create a new" | log(LOG_NOTICE, "regen_tmpaddr: failed to create a new" | ||||
" tmp addr,errno=%d\n", e); | " tmp addr,errno=%d\n", e); | ||||
▲ Show 20 Lines • Show All 254 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Detect if a given IPv6 address identifies a neighbor on a given link. | * Detect if a given IPv6 address identifies a neighbor on a given link. | ||||
* XXX: should take care of the destination of a p2p link? | * XXX: should take care of the destination of a p2p link? | ||||
*/ | */ | ||||
int | int | ||||
nd6_is_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp) | nd6_is_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp) | ||||
{ | { | ||||
struct epoch_tracker et; | |||||
struct llentry *lle; | struct llentry *lle; | ||||
int rc = 0; | int rc = 0; | ||||
NET_EPOCH_ASSERT(); | |||||
IF_AFDATA_UNLOCK_ASSERT(ifp); | IF_AFDATA_UNLOCK_ASSERT(ifp); | ||||
if (nd6_is_new_addr_neighbor(addr, ifp)) | if (nd6_is_new_addr_neighbor(addr, ifp)) | ||||
return (1); | return (1); | ||||
/* | /* | ||||
* Even if the address matches none of our addresses, it might be | * Even if the address matches none of our addresses, it might be | ||||
* in the neighbor cache. | * in the neighbor cache. | ||||
*/ | */ | ||||
NET_EPOCH_ENTER(et); | |||||
if ((lle = nd6_lookup(&addr->sin6_addr, 0, ifp)) != NULL) { | if ((lle = nd6_lookup(&addr->sin6_addr, 0, ifp)) != NULL) { | ||||
LLE_RUNLOCK(lle); | LLE_RUNLOCK(lle); | ||||
rc = 1; | rc = 1; | ||||
} | } | ||||
NET_EPOCH_EXIT(et); | |||||
return (rc); | return (rc); | ||||
} | } | ||||
/* | /* | ||||
* Free an nd6 llinfo entry. | * Free an nd6 llinfo entry. | ||||
* Since the function would cause significant changes in the kernel, DO NOT | * Since the function would cause significant changes in the kernel, DO NOT | ||||
* make it global, unless you have a strong reason for the change, and are sure | * make it global, unless you have a strong reason for the change, and are sure | ||||
* that the change is safe. | * that the change is safe. | ||||
▲ Show 20 Lines • Show All 267 Lines • ▼ Show 20 Lines | case SIOCSIFINFO_IN6: | ||||
if (ND.chlim != 0) | if (ND.chlim != 0) | ||||
ND_IFINFO(ifp)->chlim = ND.chlim; | ND_IFINFO(ifp)->chlim = ND.chlim; | ||||
/* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
case SIOCSIFINFO_FLAGS: | case SIOCSIFINFO_FLAGS: | ||||
{ | { | ||||
struct ifaddr *ifa; | struct ifaddr *ifa; | ||||
struct in6_ifaddr *ia; | struct in6_ifaddr *ia; | ||||
NET_EPOCH_ENTER(et); | |||||
if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) && | if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) && | ||||
!(ND.flags & ND6_IFF_IFDISABLED)) { | !(ND.flags & ND6_IFF_IFDISABLED)) { | ||||
/* ifdisabled 1->0 transision */ | /* ifdisabled 1->0 transision */ | ||||
/* | /* | ||||
* If the interface is marked as ND6_IFF_IFDISABLED and | * If the interface is marked as ND6_IFF_IFDISABLED and | ||||
* has an link-local address with IN6_IFF_DUPLICATED, | * has an link-local address with IN6_IFF_DUPLICATED, | ||||
* do not clear ND6_IFF_IFDISABLED. | * do not clear ND6_IFF_IFDISABLED. | ||||
* See RFC 4862, Section 5.4.5. | * See RFC 4862, Section 5.4.5. | ||||
*/ | */ | ||||
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; | ||||
ia = (struct in6_ifaddr *)ifa; | ia = (struct in6_ifaddr *)ifa; | ||||
if ((ia->ia6_flags & IN6_IFF_DUPLICATED) && | if ((ia->ia6_flags & IN6_IFF_DUPLICATED) && | ||||
IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia))) | IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia))) | ||||
break; | break; | ||||
} | } | ||||
NET_EPOCH_EXIT(et); | |||||
if (ifa != NULL) { | if (ifa != NULL) { | ||||
/* LLA is duplicated. */ | /* LLA is duplicated. */ | ||||
ND.flags |= ND6_IFF_IFDISABLED; | ND.flags |= ND6_IFF_IFDISABLED; | ||||
log(LOG_ERR, "Cannot enable an interface" | log(LOG_ERR, "Cannot enable an interface" | ||||
" with a link-local address marked" | " with a link-local address marked" | ||||
" duplicate.\n"); | " duplicate.\n"); | ||||
} else { | } else { | ||||
ND_IFINFO(ifp)->flags &= ~ND6_IFF_IFDISABLED; | ND_IFINFO(ifp)->flags &= ~ND6_IFF_IFDISABLED; | ||||
if (ifp->if_flags & IFF_UP) | if (ifp->if_flags & IFF_UP) | ||||
in6_if_up(ifp); | in6_if_up(ifp); | ||||
} | } | ||||
} else if (!(ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) && | } else if (!(ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) && | ||||
(ND.flags & ND6_IFF_IFDISABLED)) { | (ND.flags & ND6_IFF_IFDISABLED)) { | ||||
/* ifdisabled 0->1 transision */ | /* ifdisabled 0->1 transision */ | ||||
/* Mark all IPv6 address as tentative. */ | /* Mark all IPv6 address as tentative. */ | ||||
ND_IFINFO(ifp)->flags |= ND6_IFF_IFDISABLED; | ND_IFINFO(ifp)->flags |= ND6_IFF_IFDISABLED; | ||||
if (V_ip6_dad_count > 0 && | if (V_ip6_dad_count > 0 && | ||||
(ND_IFINFO(ifp)->flags & ND6_IFF_NO_DAD) == 0) { | (ND_IFINFO(ifp)->flags & ND6_IFF_NO_DAD) == 0) { | ||||
NET_EPOCH_ENTER(et); | |||||
CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, | CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, | ||||
ifa_link) { | ifa_link) { | ||||
if (ifa->ifa_addr->sa_family != | if (ifa->ifa_addr->sa_family != | ||||
AF_INET6) | AF_INET6) | ||||
continue; | continue; | ||||
ia = (struct in6_ifaddr *)ifa; | ia = (struct in6_ifaddr *)ifa; | ||||
ia->ia6_flags |= IN6_IFF_TENTATIVE; | ia->ia6_flags |= IN6_IFF_TENTATIVE; | ||||
} | } | ||||
NET_EPOCH_EXIT(et); | |||||
} | } | ||||
} | } | ||||
if (ND.flags & ND6_IFF_AUTO_LINKLOCAL) { | if (ND.flags & ND6_IFF_AUTO_LINKLOCAL) { | ||||
if (!(ND_IFINFO(ifp)->flags & ND6_IFF_AUTO_LINKLOCAL)) { | if (!(ND_IFINFO(ifp)->flags & ND6_IFF_AUTO_LINKLOCAL)) { | ||||
/* auto_linklocal 0->1 transision */ | /* auto_linklocal 0->1 transision */ | ||||
/* If no link-local address on ifp, configure */ | /* If no link-local address on ifp, configure */ | ||||
ND_IFINFO(ifp)->flags |= ND6_IFF_AUTO_LINKLOCAL; | ND_IFINFO(ifp)->flags |= ND6_IFF_AUTO_LINKLOCAL; | ||||
in6_ifattach(ifp, NULL); | in6_ifattach(ifp, NULL); | ||||
} else if (!(ND.flags & ND6_IFF_IFDISABLED) && | } else if (!(ND.flags & ND6_IFF_IFDISABLED) && | ||||
ifp->if_flags & IFF_UP) { | ifp->if_flags & IFF_UP) { | ||||
/* | /* | ||||
* When the IF already has | * When the IF already has | ||||
* ND6_IFF_AUTO_LINKLOCAL, no link-local | * ND6_IFF_AUTO_LINKLOCAL, no link-local | ||||
* address is assigned, and IFF_UP, try to | * address is assigned, and IFF_UP, try to | ||||
* assign one. | * assign one. | ||||
*/ | */ | ||||
NET_EPOCH_ENTER(et); | |||||
CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, | CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, | ||||
ifa_link) { | ifa_link) { | ||||
if (ifa->ifa_addr->sa_family != | if (ifa->ifa_addr->sa_family != | ||||
AF_INET6) | AF_INET6) | ||||
continue; | continue; | ||||
ia = (struct in6_ifaddr *)ifa; | ia = (struct in6_ifaddr *)ifa; | ||||
if (IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia))) | if (IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia))) | ||||
break; | break; | ||||
} | } | ||||
NET_EPOCH_EXIT(et); | |||||
if (ifa != NULL) | if (ifa != NULL) | ||||
/* No LLA is configured. */ | /* No LLA is configured. */ | ||||
in6_ifattach(ifp, NULL); | in6_ifattach(ifp, NULL); | ||||
} | } | ||||
} | } | ||||
} | |||||
ND_IFINFO(ifp)->flags = ND.flags; | ND_IFINFO(ifp)->flags = ND.flags; | ||||
NET_EPOCH_EXIT(et); | |||||
break; | break; | ||||
} | |||||
#undef ND | #undef ND | ||||
case SIOCSNDFLUSH_IN6: /* XXX: the ioctl name is confusing... */ | case SIOCSNDFLUSH_IN6: /* XXX: the ioctl name is confusing... */ | ||||
/* sync kernel routing table with the default router list */ | /* sync kernel routing table with the default router list */ | ||||
defrouter_reset(); | defrouter_reset(); | ||||
defrouter_select(); | defrouter_select(); | ||||
break; | break; | ||||
case SIOCSPFXFLUSH_IN6: | case SIOCSPFXFLUSH_IN6: | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 179 Lines • ▼ Show 20 Lines | nd6_cache_lladdr(struct ifnet *ifp, struct in6_addr *from, char *lladdr, | ||||
struct llentry *ln = NULL, *ln_tmp; | struct llentry *ln = NULL, *ln_tmp; | ||||
int is_newentry; | int is_newentry; | ||||
int do_update; | int do_update; | ||||
int olladdr; | int olladdr; | ||||
int llchange; | int llchange; | ||||
int flags; | int flags; | ||||
uint16_t router = 0; | uint16_t router = 0; | ||||
struct sockaddr_in6 sin6; | struct sockaddr_in6 sin6; | ||||
struct epoch_tracker et; | |||||
struct mbuf *chain = NULL; | struct mbuf *chain = NULL; | ||||
u_char linkhdr[LLE_MAX_LINKHDR]; | u_char linkhdr[LLE_MAX_LINKHDR]; | ||||
size_t linkhdrsize; | size_t linkhdrsize; | ||||
int lladdr_off; | int lladdr_off; | ||||
NET_EPOCH_ASSERT(); | |||||
IF_AFDATA_UNLOCK_ASSERT(ifp); | IF_AFDATA_UNLOCK_ASSERT(ifp); | ||||
KASSERT(ifp != NULL, ("%s: ifp == NULL", __func__)); | KASSERT(ifp != NULL, ("%s: ifp == NULL", __func__)); | ||||
KASSERT(from != NULL, ("%s: from == NULL", __func__)); | KASSERT(from != NULL, ("%s: from == NULL", __func__)); | ||||
/* nothing must be updated for unspecified address */ | /* nothing must be updated for unspecified address */ | ||||
if (IN6_IS_ADDR_UNSPECIFIED(from)) | if (IN6_IS_ADDR_UNSPECIFIED(from)) | ||||
return; | return; | ||||
/* | /* | ||||
* Validation about ifp->if_addrlen and lladdrlen must be done in | * Validation about ifp->if_addrlen and lladdrlen must be done in | ||||
* the caller. | * the caller. | ||||
* | * | ||||
* XXX If the link does not have link-layer adderss, what should | * XXX If the link does not have link-layer adderss, what should | ||||
* we do? (ifp->if_addrlen == 0) | * we do? (ifp->if_addrlen == 0) | ||||
* Spec says nothing in sections for RA, RS and NA. There's small | * Spec says nothing in sections for RA, RS and NA. There's small | ||||
* description on it in NS section (RFC 2461 7.2.3). | * description on it in NS section (RFC 2461 7.2.3). | ||||
*/ | */ | ||||
flags = lladdr ? LLE_EXCLUSIVE : 0; | flags = lladdr ? LLE_EXCLUSIVE : 0; | ||||
NET_EPOCH_ENTER(et); | |||||
ln = nd6_lookup(from, flags, ifp); | ln = nd6_lookup(from, flags, ifp); | ||||
NET_EPOCH_EXIT(et); | |||||
is_newentry = 0; | is_newentry = 0; | ||||
if (ln == NULL) { | if (ln == NULL) { | ||||
flags |= LLE_EXCLUSIVE; | flags |= LLE_EXCLUSIVE; | ||||
ln = nd6_alloc(from, 0, ifp); | ln = nd6_alloc(from, 0, ifp); | ||||
if (ln == NULL) | if (ln == NULL) | ||||
return; | return; | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 242 Lines • ▼ Show 20 Lines | |||||
* - EWOULDBLOCK (no local error, but address is still unresolved) | * - EWOULDBLOCK (no local error, but address is still unresolved) | ||||
* - other errors (alloc failure, etc) | * - other errors (alloc failure, etc) | ||||
*/ | */ | ||||
int | int | ||||
nd6_resolve(struct ifnet *ifp, int is_gw, struct mbuf *m, | nd6_resolve(struct ifnet *ifp, int is_gw, struct mbuf *m, | ||||
const struct sockaddr *sa_dst, u_char *desten, uint32_t *pflags, | const struct sockaddr *sa_dst, u_char *desten, uint32_t *pflags, | ||||
struct llentry **plle) | struct llentry **plle) | ||||
{ | { | ||||
struct epoch_tracker et; | |||||
struct llentry *ln = NULL; | struct llentry *ln = NULL; | ||||
const struct sockaddr_in6 *dst6; | const struct sockaddr_in6 *dst6; | ||||
NET_EPOCH_ASSERT(); | |||||
if (pflags != NULL) | if (pflags != NULL) | ||||
*pflags = 0; | *pflags = 0; | ||||
dst6 = (const struct sockaddr_in6 *)sa_dst; | dst6 = (const struct sockaddr_in6 *)sa_dst; | ||||
/* discard the packet if IPv6 operation is disabled on the interface */ | /* discard the packet if IPv6 operation is disabled on the interface */ | ||||
if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)) { | if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)) { | ||||
m_freem(m); | m_freem(m); | ||||
Show All 9 Lines | case IFT_BRIDGE: | ||||
desten); | desten); | ||||
return (0); | return (0); | ||||
default: | default: | ||||
m_freem(m); | m_freem(m); | ||||
return (EAFNOSUPPORT); | return (EAFNOSUPPORT); | ||||
} | } | ||||
} | } | ||||
NET_EPOCH_ENTER(et); | |||||
ln = nd6_lookup(&dst6->sin6_addr, plle ? LLE_EXCLUSIVE : LLE_UNLOCKED, | ln = nd6_lookup(&dst6->sin6_addr, plle ? LLE_EXCLUSIVE : LLE_UNLOCKED, | ||||
ifp); | ifp); | ||||
if (ln != NULL && (ln->r_flags & RLLE_VALID) != 0) { | if (ln != NULL && (ln->r_flags & RLLE_VALID) != 0) { | ||||
/* Entry found, let's copy lle info */ | /* Entry found, let's copy lle info */ | ||||
bcopy(ln->r_linkdata, desten, ln->r_hdrlen); | bcopy(ln->r_linkdata, desten, ln->r_hdrlen); | ||||
if (pflags != NULL) | if (pflags != NULL) | ||||
*pflags = LLE_VALID | (ln->r_flags & RLLE_IFADDR); | *pflags = LLE_VALID | (ln->r_flags & RLLE_IFADDR); | ||||
/* Check if we have feedback request from nd6 timer */ | /* Check if we have feedback request from nd6 timer */ | ||||
if (ln->r_skip_req != 0) { | if (ln->r_skip_req != 0) { | ||||
LLE_REQ_LOCK(ln); | LLE_REQ_LOCK(ln); | ||||
ln->r_skip_req = 0; /* Notify that entry was used */ | ln->r_skip_req = 0; /* Notify that entry was used */ | ||||
ln->lle_hittime = time_uptime; | ln->lle_hittime = time_uptime; | ||||
LLE_REQ_UNLOCK(ln); | LLE_REQ_UNLOCK(ln); | ||||
} | } | ||||
if (plle) { | if (plle) { | ||||
LLE_ADDREF(ln); | LLE_ADDREF(ln); | ||||
*plle = ln; | *plle = ln; | ||||
LLE_WUNLOCK(ln); | LLE_WUNLOCK(ln); | ||||
} | } | ||||
NET_EPOCH_EXIT(et); | |||||
return (0); | return (0); | ||||
} else if (plle && ln) | } else if (plle && ln) | ||||
LLE_WUNLOCK(ln); | LLE_WUNLOCK(ln); | ||||
NET_EPOCH_EXIT(et); | |||||
return (nd6_resolve_slow(ifp, 0, m, dst6, desten, pflags, plle)); | return (nd6_resolve_slow(ifp, 0, m, dst6, desten, pflags, plle)); | ||||
} | } | ||||
/* | /* | ||||
* Do L2 address resolution for @sa_dst address. Stores found | * Do L2 address resolution for @sa_dst address. Stores found | ||||
* address in @desten buffer. Copy of lle ln_flags can be also | * address in @desten buffer. Copy of lle ln_flags can be also | ||||
Show All 10 Lines | nd6_resolve_slow(struct ifnet *ifp, int flags, struct mbuf *m, | ||||
const struct sockaddr_in6 *dst, u_char *desten, uint32_t *pflags, | const struct sockaddr_in6 *dst, u_char *desten, uint32_t *pflags, | ||||
struct llentry **plle) | struct llentry **plle) | ||||
{ | { | ||||
struct llentry *lle = NULL, *lle_tmp; | struct llentry *lle = NULL, *lle_tmp; | ||||
struct in6_addr *psrc, src; | struct in6_addr *psrc, src; | ||||
int send_ns, ll_len; | int send_ns, ll_len; | ||||
char *lladdr; | char *lladdr; | ||||
NET_EPOCH_ASSERT(); | |||||
/* | /* | ||||
* Address resolution or Neighbor Unreachability Detection | * Address resolution or Neighbor Unreachability Detection | ||||
* for the next hop. | * for the next hop. | ||||
* At this point, the destination of the packet must be a unicast | * At this point, the destination of the packet must be a unicast | ||||
* or an anycast address(i.e. not a multicast). | * or an anycast address(i.e. not a multicast). | ||||
*/ | */ | ||||
if (lle == NULL) { | if (lle == NULL) { | ||||
struct epoch_tracker et; | |||||
NET_EPOCH_ENTER(et); | |||||
lle = nd6_lookup(&dst->sin6_addr, LLE_EXCLUSIVE, ifp); | lle = nd6_lookup(&dst->sin6_addr, LLE_EXCLUSIVE, ifp); | ||||
NET_EPOCH_EXIT(et); | |||||
if ((lle == NULL) && nd6_is_addr_neighbor(dst, ifp)) { | if ((lle == NULL) && nd6_is_addr_neighbor(dst, ifp)) { | ||||
/* | /* | ||||
* Since nd6_is_addr_neighbor() internally calls nd6_lookup(), | * Since nd6_is_addr_neighbor() internally calls nd6_lookup(), | ||||
* the condition below is not very efficient. But we believe | * the condition below is not very efficient. But we believe | ||||
* it is tolerable, because this should be a rare case. | * it is tolerable, because this should be a rare case. | ||||
*/ | */ | ||||
lle = nd6_alloc(&dst->sin6_addr, 0, ifp); | lle = nd6_alloc(&dst->sin6_addr, 0, ifp); | ||||
if (lle == NULL) { | if (lle == NULL) { | ||||
▲ Show 20 Lines • Show All 399 Lines • Show Last 20 Lines |