Implement "last-in wins" duplicate IPv6 address resolution (#1720)

This commit implements "last-in wins" duplicate IPv6 address
resolution policy for children's registered addresses. When a
child registers a new address, it is checked if the same IPv6
address is registered by another child and if so the address is
removed from the other child's registered IPv6 address list.

Duplicate addresses can occur if a previously attached child
attaches to same parent again (after a reset, memory wipe) using
a new random extended address before the old entry in the child
table is timed out and then trying to register its globally unique
IPv6 address as the new child.
This commit is contained in:
Abtin Keshavarzian
2017-05-04 20:21:35 -07:00
committed by Jonathan Hui
parent bb4ffe373c
commit 849dcba11b
3 changed files with 94 additions and 9 deletions
+35 -8
View File
@@ -1965,7 +1965,10 @@ exit:
ThreadError MleRouter::UpdateChildAddresses(const AddressRegistrationTlv &aTlv, Child &aChild)
{
const AddressRegistrationEntry *entry;
Ip6::Address address;
Lowpan::Context context;
Child *child;
uint8_t index;
aChild.ClearIp6Addresses();
@@ -1980,12 +1983,39 @@ ThreadError MleRouter::UpdateChildAddresses(const AddressRegistrationTlv &aTlv,
{
// xxx check if context id exists
mNetif.GetNetworkDataLeader().GetContext(entry->GetContextId(), context);
memcpy(&aChild.GetIp6Address(count), context.mPrefix, BitVectorBytes(context.mPrefixLength));
aChild.GetIp6Address(count).SetIid(entry->GetIid());
memcpy(&address, context.mPrefix, BitVectorBytes(context.mPrefixLength));
address.SetIid(entry->GetIid());
}
else
{
aChild.GetIp6Address(count) = *entry->GetIp6Address();
address = *entry->GetIp6Address();
}
aChild.GetIp6Address(count) = address;
// We check if the same address is in-use by another child, if so
// remove it. This implements "last-in wins" duplicate address
// resolution policy.
//
// Duplicate addresses can occur if a previously attached child
// attaches to same parent again (after a reset, memory wipe) using
// a new random extended address before the old entry in the child
// table is timed out and then trying to register its globally unique
// IPv6 address as the new child.
for (int i = 0; i < mMaxChildrenAllowed; i++)
{
child = &mChildren[i];
if (!child->IsStateValidOrRestoring() || (child == &aChild))
{
continue;
}
if (child->FindIp6Address(address, &index) == kThreadError_None)
{
child->RemoveIp6Address(index);
}
}
}
@@ -3253,12 +3283,9 @@ Neighbor *MleRouter::GetNeighbor(const Ip6::Address &aAddress)
ExitNow(rval = child);
}
for (uint8_t j = 0; j < Child::kMaxIp6AddressPerChild; j++)
if (child->FindIp6Address(aAddress, NULL) == kThreadError_None)
{
if (child->GetIp6Address(j) == aAddress)
{
ExitNow(rval = child);
}
ExitNow(rval = child);
}
}
+36
View File
@@ -54,6 +54,42 @@ void Neighbor::GenerateChallenge(void)
}
}
ThreadError Child::FindIp6Address(const Ip6::Address &aAddress, uint8_t *aIndex) const
{
ThreadError error = kThreadError_NotFound;
for (uint8_t index = 0; index < kMaxIp6AddressPerChild; index++)
{
if (mIp6Address[index] == aAddress)
{
if (aIndex != NULL)
{
*aIndex = index;
}
error = kThreadError_None;
break;
}
}
return error;
}
void Child::RemoveIp6Address(uint8_t aIndex)
{
VerifyOrExit(aIndex < kMaxIp6AddressPerChild);
for (uint8_t i = aIndex; i < kMaxIp6AddressPerChild - 1; i++)
{
mIp6Address[i] = mIp6Address[i + 1];
}
memset(&mIp6Address[kMaxIp6AddressPerChild - 1], 0, sizeof(Ip6::Address));
exit:
return;
}
void Child::GenerateChallenge(void)
{
for (uint8_t i = 0; i < sizeof(mAttachChallenge); i++)
+23 -1
View File
@@ -86,7 +86,7 @@ public:
* Check if the neighbor/child is in valid state or if it is being restored.
* When in these states messages can be sent to and/or received from the neighbor/child.
*
* @returns `true` if the neighbor is in valid, restored, or being restored states, `false` otherwise.
* @returns TRUE if the neighbor is in valid, restored, or being restored states, FALSE otherwise.
*
*/
bool IsStateValidOrRestoring(void) const { return (mState == kStateValid) || (mState == kStateRestored); }
@@ -370,6 +370,28 @@ public:
*/
Ip6::Address &GetIp6Address(uint8_t aIndex) { return mIp6Address[aIndex]; }
/**
* This method searches for a given IPv6 address in the child's IPv6 address list and provides the index of the
* address in the list if it is found.
*
* @param[in] aAddress The IPv6 address to search for in the IPv6 address list.
* @param[out] aIndex Pointer to variable where the index of address is provided if address is found in
* the list. @p aIndex can be set NULL if index is not required.
*
* @retval kThreadError_None Successfully found the address in IPv6 address list and updated @p aIndex.
* @retval kThreadError_NotFound Could not find the address in the list.
*
*/
ThreadError FindIp6Address(const Ip6::Address &aAddress, uint8_t *aIndex) const;
/**
* This method removes the address at index @p aIndex.
*
* @param[in] aIndex The index into the IPv6 address list.
*
*/
void RemoveIp6Address(uint8_t aIndex);
/**
* This method gets the child timeout.
*