[mle] ignore "Child Update Request" from a child not yet in valid state (#6539)

This commit updates `MleRouter::HandleChildUpdateRequest()` related to
how a "Child Update Request" message from a child is processed on a
parent. If the child is present in the parent's child table but it is
not yet in valid state, the parent ignores the received "Child Update
Request". This applies to a child being restored due to parent's reset
(child is in `kStateRestored`) or a child which is in the middle of
attach process (e.g., child is in `kStateParentRequest`). If a
matching child entry cannot be found in the parent's child table, the
behavior remains as before (i.e., parent sends a response with an
error Status TLV to notify the child to re-attach).

This change ensures that after a parent reset to restore a child, the
parent node is the one initiating and sending a "Child Update Request"
to the child and then receives a "Child Update Response" from it. Such
an exchange between the parent and the child will then include a
random challenge and response (authenticating the child and providing
replay protection). Also in this exchange the "Child Update Response"
from the child will include the the child's current MAC and MLE frame
counters, therefore ensuring that the parent correctly learns and
tracks the frame counters being used by the child.
This commit is contained in:
Abtin Keshavarzian
2021-05-10 21:24:02 -07:00
committed by GitHub
parent 7721a5119f
commit 18097192ca
3 changed files with 25 additions and 29 deletions
+1 -1
View File
@@ -2796,7 +2796,7 @@ void Mle::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageIn
#if OPENTHREAD_FTD
if (IsRouterOrLeader())
{
Get<MleRouter>().HandleChildUpdateRequest(aMessage, aMessageInfo, keySequence);
Get<MleRouter>().HandleChildUpdateRequest(aMessage, aMessageInfo);
}
else
#endif
+16 -20
View File
@@ -2314,9 +2314,7 @@ exit:
LogProcessError(kTypeChildIdRequest, error);
}
void MleRouter::HandleChildUpdateRequest(const Message & aMessage,
const Ip6::MessageInfo &aMessageInfo,
uint32_t aKeySequence)
void MleRouter::HandleChildUpdateRequest(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
static const uint8_t kMaxResponseTlvs = 10;
@@ -2354,17 +2352,15 @@ void MleRouter::HandleChildUpdateRequest(const Message & aMessage,
ExitNow(error = kErrorParse);
}
// Find Child
tlvs[tlvslength++] = Tlv::kSourceAddress;
aMessageInfo.GetPeerAddr().GetIid().ConvertToExtAddress(extAddr);
child = mChildTable.FindChild(extAddr, Child::kInStateAnyExceptInvalid);
tlvs[tlvslength++] = Tlv::kSourceAddress;
// Not proceed if the Child Update Request is from the peer which is not the device's child or
// which was the device's child but becomes invalid.
if (child == nullptr || child->IsStateInvalid())
if (child == nullptr)
{
// For invalid non-sleepy child, Send Child Update Response with status TLV (error)
// For invalid non-sleepy child, send Child Update Response with
// Status TLV (error).
if (mode.IsRxOnWhenIdle())
{
tlvs[tlvslength++] = Tlv::kStatus;
@@ -2374,6 +2370,14 @@ void MleRouter::HandleChildUpdateRequest(const Message & aMessage,
ExitNow();
}
// Ignore "Child Update Request" from a child that is present in the
// child table but it is not yet in valid state. For example, a
// child which is being restored (due to parent reset) or is in the
// middle of the attach process (in `kStateParentRequest` or
// `kStateChildIdRequest`).
VerifyOrExit(child->IsStateValid());
oldMode = child->GetDeviceMode();
child->SetDeviceMode(mode);
@@ -2493,17 +2497,9 @@ void MleRouter::HandleChildUpdateRequest(const Message & aMessage,
Get<IndirectSender>().HandleChildModeChange(*child, oldMode);
}
if (child->IsStateRestoring())
if (childDidChange)
{
SetChildStateToValid(*child);
child->SetKeySequence(aKeySequence);
}
else if (child->IsStateValid())
{
if (childDidChange)
{
IgnoreError(mChildTable.StoreChild(*child));
}
IgnoreError(mChildTable.StoreChild(*child));
}
#if OPENTHREAD_CONFIG_MULTI_RADIO
+8 -8
View File
@@ -586,14 +586,14 @@ private:
Error HandleAdvertisement(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo, Neighbor *);
void HandleParentRequest(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
void HandleChildIdRequest(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo, uint32_t aKeySequence);
void HandleChildUpdateRequest(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo, uint32_t aKeySequence);
void HandleChildUpdateResponse(const Message & aMessage,
const Ip6::MessageInfo &aMessageInfo,
uint32_t aKeySequence,
Neighbor * aNeighbor);
void HandleDataRequest(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo, const Neighbor *aNeighbor);
void HandleNetworkDataUpdateRouter(void);
void HandleDiscoveryRequest(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
void HandleChildUpdateRequest(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
void HandleChildUpdateResponse(const Message & aMessage,
const Ip6::MessageInfo &aMessageInfo,
uint32_t aKeySequence,
Neighbor * aNeighbor);
void HandleDataRequest(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo, const Neighbor *aNeighbor);
void HandleNetworkDataUpdateRouter(void);
void HandleDiscoveryRequest(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
void HandleTimeSync(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo, const Neighbor *aNeighbor);
#endif