[mle] allow processing of "Child Update Request" while restoring child role (#12007)

This change modifies `HandleChildUpdateRequest()` to allow a detached
child that is restoring its previous role to process a "Child Update
Request" from its former parent.

When in this state, the device will respond to the request but will
not save any of the content (TLVs) from the message, as the child has
not yet established trust with any device (including its former
parent) and therefore cannot authenticate the freshness of the
received request.

This change handles the scenario where a child and its parent may be
reset simultaneously. It allows the parent to first restore its link
with the child through a "Child Update" exchange, which can then be
followed by the child sending its own "Child Update Request" to
re-establish the link. Without this change, a communication impasse
could occur where the parent rejects the child's request (as the
child is not yet valid), and the child ignores the parent's request
(as it is not yet attached). This change prevents devices from
resorting to a full re-attachment, thereby improving network
resilience and recovery time.

A new test is added to emulate this scenario and verify that the child
restores its role correctly without performing a full attach.
This commit is contained in:
Abtin Keshavarzian
2025-10-14 16:31:53 +02:00
committed by GitHub
parent 1f20dbc0af
commit ef058d5bbb
3 changed files with 155 additions and 19 deletions
+31 -19
View File
@@ -2181,31 +2181,40 @@ exit:
void Mle::HandleChildUpdateRequest(RxInfo &aRxInfo)
{
VerifyOrExit(IsAttached());
#if OPENTHREAD_FTD
if (IsRouterOrLeader())
{
HandleChildUpdateRequestOnParent(aRxInfo);
ExitNow();
}
else
#endif
HandleChildUpdateRequestOnChild(aRxInfo);
exit:
return;
{
HandleChildUpdateRequestOnChild(aRxInfo);
}
}
void Mle::HandleChildUpdateRequestOnChild(RxInfo &aRxInfo)
{
Error error = kErrorNone;
Error error = kErrorNone;
bool canTrustMessage = aRxInfo.IsNeighborStateValid();
uint16_t sourceAddress;
RxChallenge challenge;
TlvList requestedTlvList;
TlvList tlvList;
uint8_t linkMarginOut;
if (!IsAttached())
{
// If detached and trying to restore our role as a child, we
// allow processing of a received "Child Update Request"
// and send a response. But since we have not yet established
// trust with any device (including our former parent),
// we will not save any of the content (TLVs) from the
// message (`canTrustMessage` will be `false`).
VerifyOrExit(mPrevRoleRestorer.IsRestoringChildRole());
}
SuccessOrExit(error = Tlv::Find<SourceAddressTlv>(aRxInfo.mMessage, sourceAddress));
Log(kMessageReceive, kTypeChildUpdateRequestAsChild, aRxInfo.mMessageInfo.GetPeerAddr(), sourceAddress);
@@ -2245,17 +2254,20 @@ void Mle::HandleChildUpdateRequestOnChild(RxInfo &aRxInfo)
ExitNow();
}
SuccessOrExit(error = HandleLeaderData(aRxInfo));
switch (Tlv::Find<LinkMarginTlv>(aRxInfo.mMessage, linkMarginOut))
if (canTrustMessage)
{
case kErrorNone:
mParent.SetLinkQualityOut(LinkQualityForLinkMargin(linkMarginOut));
break;
case kErrorNotFound:
break;
default:
ExitNow(error = kErrorParse);
SuccessOrExit(error = HandleLeaderData(aRxInfo));
switch (Tlv::Find<LinkMarginTlv>(aRxInfo.mMessage, linkMarginOut))
{
case kErrorNone:
mParent.SetLinkQualityOut(LinkQualityForLinkMargin(linkMarginOut));
break;
case kErrorNotFound:
break;
default:
ExitNow(error = kErrorParse);
}
}
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE