[mle] add 2 additional retries on child ID request messages to improve attachment robustness (#12025)

In testing I have observed some failures to attach due to a `Child ID
Request` or `Child ID Response` getting lost in the air causing the
attaching device to start it's own new partition (assuming FTD).

When attaching, after selecting a parent candidate from the responses
to a multicast `Parent Request` message, devices only have one shot to
send and receive a response to a `Child ID Request`. There is a higher
rate of failure in this sequence during high traffic periods such as
formation and reset, which will cause more devices than desired to
fail the attachment process (and become their own leader if an FTD).

This commit aims to help address this by adding 2 additional retries
to `Child ID Request` messages, which gives devices a much better
chance of attaching the first time.
This commit is contained in:
Tom Rebbert
2026-03-25 16:47:51 -05:00
committed by GitHub
parent 07cb0ebd5b
commit 361f7311de
2 changed files with 15 additions and 3 deletions
+11 -3
View File
@@ -4431,6 +4431,7 @@ Mle::Attacher::Attacher(Instance &aInstance)
, mAddressRegistrationMode(kAppendAllAddresses)
, mParentRequestCounter(0)
, mAnnounceChannel(0)
, mChildIdRequestsRemaining(kMaxChildIdRequests)
, mAttachCounter(0)
, mAnnounceDelay(kAnnounceTimeout)
, mTimer(aInstance)
@@ -4667,15 +4668,15 @@ bool Mle::Attacher::HasAcceptableParentCandidate(void) const
bool hasAcceptableParent = false;
ParentRequestType parentReqType;
VerifyOrExit(mParentCandidate.IsStateParentResponse());
switch (mState)
{
case kStateAnnounce:
VerifyOrExit(mParentCandidate.IsStateParentResponse());
VerifyOrExit(!HasMoreChannelsToAnnounce());
break;
case kStateParentRequest:
VerifyOrExit(mParentCandidate.IsStateParentResponse());
SuccessOrAssert(DetermineParentRequestType(parentReqType));
if (parentReqType == kToRouters)
@@ -4689,6 +4690,11 @@ bool Mle::Attacher::HasAcceptableParentCandidate(void) const
break;
case kStateChildIdRequest:
VerifyOrExit(mParentCandidate.IsStateValid());
VerifyOrExit(mChildIdRequestsRemaining > 0);
break;
default:
ExitNow();
}
@@ -4732,7 +4738,8 @@ void Mle::Attacher::HandleTimer(void)
if (HasAcceptableParentCandidate() && (SendChildIdRequest() == kErrorNone))
{
SetState(kStateChildIdRequest);
delay = kChildIdResponseTimeout;
mChildIdRequestsRemaining--;
delay = Random::NonCrypto::AddJitter(kChildIdResponseTimeout, kChildIdResponseJitter);
ExitNow();
}
@@ -4750,6 +4757,7 @@ void Mle::Attacher::HandleTimer(void)
mParentCandidate.SetState(Neighbor::kStateInvalid);
mReceivedResponseFromParent = false;
mParentRequestCounter = 0;
mChildIdRequestsRemaining = kMaxChildIdRequests;
Get<MeshForwarder>().SetRxOnWhenIdle(true);
OT_FALL_THROUGH;
+4
View File
@@ -1264,6 +1264,7 @@ private:
static constexpr uint32_t kParentRequestReedTimeout = 1250; // Wait timer after tx of Parent Req to REEDs
static constexpr uint32_t kParentRequestDuplicateTimeout = 700; // Min time to detect duplicate Parent Req rx
static constexpr uint32_t kChildIdResponseTimeout = 1250; // Wait time to receive Child ID Response
static constexpr uint32_t kChildIdResponseJitter = kChildIdResponseTimeout * 1 / 10; // Jitter 10%
static constexpr uint32_t kAttachStartJitter = 50; // Max jitter time added to start of attach
static constexpr uint32_t kAnnounceProcessTimeout = 250; // Delay after Announce rx before processing
static constexpr uint32_t kAnnounceTimeout = 1400; // Total timeout for sending Announce messages
@@ -1941,6 +1942,8 @@ private:
kReattachModePending, // Reattach using stored Pending Dataset
};
static constexpr uint8_t kMaxChildIdRequests = 3;
void SetState(State aState);
uint32_t GetStartDelay(void) const;
bool HasAcceptableParentCandidate(void) const;
@@ -1975,6 +1978,7 @@ private:
AddressRegistrationMode mAddressRegistrationMode;
uint8_t mParentRequestCounter;
uint8_t mAnnounceChannel;
uint8_t mChildIdRequestsRemaining;
uint16_t mAttachCounter;
uint16_t mAnnounceDelay;
TxChallenge mParentRequestChallenge;