From 18097192ca410087ed0b389589c0d15486937bca Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Mon, 10 May 2021 21:24:02 -0700 Subject: [PATCH] [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. --- src/core/thread/mle.cpp | 2 +- src/core/thread/mle_router.cpp | 36 +++++++++++++++------------------- src/core/thread/mle_router.hpp | 16 +++++++-------- 3 files changed, 25 insertions(+), 29 deletions(-) diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index c32069872..8910a0647 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -2796,7 +2796,7 @@ void Mle::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageIn #if OPENTHREAD_FTD if (IsRouterOrLeader()) { - Get().HandleChildUpdateRequest(aMessage, aMessageInfo, keySequence); + Get().HandleChildUpdateRequest(aMessage, aMessageInfo); } else #endif diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index dc24b335d..c9b09e8bc 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -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().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 diff --git a/src/core/thread/mle_router.hpp b/src/core/thread/mle_router.hpp index ffb9ea6a9..2ee108097 100644 --- a/src/core/thread/mle_router.hpp +++ b/src/core/thread/mle_router.hpp @@ -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