mirror of
https://github.com/espressif/openthread.git
synced 2026-09-05 08:40:06 +00:00
[mle] introduce PrevRoleRestorer to manage role restoration (#11731)
This commit introduces `Mle::PrevRoleRestorer` to consolidate the logic for restoring a device's previous role (child or router/leader) after an MLE restart. This new class replaces and encapsulates the functionality from the now-removed `RouterRoleRestorer` class and `RestorePrevRole()` method. `PrevRoleRestorer` manages its own timer and retransmission logic. It handles sending Child Update Requests to restore a child role, or multicast Link Requests to restore a router/leader role. It also adds a small random delay before the first transmission attempt to avoid synchronized transmissions when multiple devices restart at once. This change simplifies the `Mle` class by centralizing all role restoration logic into a single component, making future enhancements to this process easier.
This commit is contained in:
+156
-54
@@ -74,6 +74,7 @@ Mle::Mle(Instance &aInstance)
|
||||
, mNeighborTable(aInstance)
|
||||
, mDelayedSender(aInstance)
|
||||
, mSocket(aInstance, *this)
|
||||
, mPrevRoleRestorer(aInstance)
|
||||
, mDetacher(aInstance)
|
||||
, mRetxTracker(aInstance)
|
||||
, mAnnounceHandler(aInstance)
|
||||
@@ -114,7 +115,6 @@ Mle::Mle(Instance &aInstance)
|
||||
, mAdvertiseTrickleTimer(aInstance, Mle::HandleAdvertiseTrickleTimer)
|
||||
, mChildTable(aInstance)
|
||||
, mRouterTable(aInstance)
|
||||
, mRouterRoleRestorer(aInstance)
|
||||
#endif // OPENTHREAD_FTD
|
||||
{
|
||||
mParent.Init(aInstance);
|
||||
@@ -231,7 +231,7 @@ Error Mle::Start(StartMode aMode)
|
||||
mReattachState =
|
||||
(Get<MeshCoP::ActiveDatasetManager>().Restore() == kErrorNone) ? kReattachActive : kReattachStop;
|
||||
|
||||
if (RestorePrevRole() == kErrorNone)
|
||||
if (mPrevRoleRestorer.Start() == kErrorNone)
|
||||
{
|
||||
ExitNow();
|
||||
}
|
||||
@@ -258,6 +258,7 @@ void Mle::Stop(StopMode aMode)
|
||||
VerifyOrExit(!IsDisabled());
|
||||
|
||||
mDelayedSender.Stop();
|
||||
mPrevRoleRestorer.Stop();
|
||||
mAnnounceHandler.Stop();
|
||||
Get<KeyManager>().Stop();
|
||||
SetStateDetached();
|
||||
@@ -266,54 +267,12 @@ void Mle::Stop(StopMode aMode)
|
||||
Get<ThreadNetif>().RemoveUnicastAddress(mMeshLocalRloc);
|
||||
Get<ThreadNetif>().RemoveUnicastAddress(mMeshLocalEid);
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
mRouterRoleRestorer.Stop();
|
||||
#endif
|
||||
|
||||
SetRole(kRoleDisabled);
|
||||
|
||||
exit:
|
||||
mDetacher.HandleStop();
|
||||
}
|
||||
|
||||
Error Mle::RestorePrevRole(void)
|
||||
{
|
||||
// Restores the device to its previously saved role after MLE
|
||||
// start.
|
||||
//
|
||||
// Returns `kErrorNone` if the restoration process begins
|
||||
// successfully. An error is returned if:
|
||||
// - No previous role was saved.
|
||||
// - The saved role info is inconsistent (e.g., RLOC16 indicates a
|
||||
// router/leader, but `mLastSavedRole` doesn't match).
|
||||
// - The last role is "Child," but no valid parent is available.
|
||||
|
||||
Error error = kErrorFailed;
|
||||
|
||||
VerifyOrExit(IsDetached());
|
||||
VerifyOrExit(GetRloc16() != kInvalidRloc16);
|
||||
|
||||
if (IsRouterRloc16(GetRloc16()))
|
||||
{
|
||||
#if OPENTHREAD_FTD
|
||||
VerifyOrExit(mLastSavedRole == kRoleRouter || mLastSavedRole == kRoleLeader);
|
||||
VerifyOrExit(IsRouterEligible());
|
||||
Get<MeshForwarder>().SetRxOnWhenIdle(true);
|
||||
mRouterRoleRestorer.Start(mLastSavedRole);
|
||||
error = kErrorNone;
|
||||
#endif
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
VerifyOrExit(mLastSavedRole == kRoleChild);
|
||||
VerifyOrExit(mParent.IsStateValidOrRestoring());
|
||||
IgnoreError(SendChildUpdateRequestToParent());
|
||||
error = kErrorNone;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
const Counters &Mle::GetCounters(void)
|
||||
{
|
||||
UpdateRoleTimeCounters(mRole);
|
||||
@@ -789,6 +748,7 @@ void Mle::SetStateChild(uint16_t aRloc16)
|
||||
mReattachState = kReattachStop;
|
||||
Get<Mac::Mac>().SetBeaconEnabled(false);
|
||||
mRetxTracker.UpdateOnRoleChangeToChild();
|
||||
mPrevRoleRestorer.Stop();
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
if (IsFullThreadDevice())
|
||||
@@ -1471,14 +1431,6 @@ void Mle::HandleAttachTimer(void)
|
||||
bool shouldAnnounce = true;
|
||||
ParentRequestType type;
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
if (IsDetached() && mRouterRoleRestorer.IsActive())
|
||||
{
|
||||
mRouterRoleRestorer.HandleTimer();
|
||||
ExitNow();
|
||||
}
|
||||
#endif
|
||||
|
||||
// First, check if we are waiting to receive parent responses and
|
||||
// found an acceptable parent candidate.
|
||||
|
||||
@@ -1938,11 +1890,19 @@ Error Mle::SendChildUpdateRequestToParent(ChildUpdateRequestMode aMode)
|
||||
mDelayedSender.RemoveScheduledChildUpdateRequestToParent();
|
||||
|
||||
// Track Child Update retx, except when gracefully detaching
|
||||
// i.e., sending Child Update with zero timeout.
|
||||
// i.e., sending Child Update with zero timeout, or restoring
|
||||
// previous child role (re-establishing link with parent).
|
||||
|
||||
if (aMode != kAppendZeroTimeout)
|
||||
switch (aMode)
|
||||
{
|
||||
case kNormalChildUpdateRequest:
|
||||
case kAppendChallengeTlv:
|
||||
mRetxTracker.UpdateOnChildUpdateRequestTx();
|
||||
break;
|
||||
|
||||
case kAppendZeroTimeout:
|
||||
case kToRestoreChildRole:
|
||||
break;
|
||||
}
|
||||
|
||||
VerifyOrExit((message = NewMleMessage(kCommandChildUpdateRequest)) != nullptr, error = kErrorNoBufs);
|
||||
@@ -5330,6 +5290,148 @@ void Mle::ParentCandidate::CopyTo(Parent &aParent) const
|
||||
aParent = *candidateAsParent;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// PrevRoleRestorer
|
||||
|
||||
Mle::PrevRoleRestorer::PrevRoleRestorer(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mState(kIdle)
|
||||
, mAttempts(0)
|
||||
, mTimer(aInstance)
|
||||
{
|
||||
}
|
||||
|
||||
Error Mle::PrevRoleRestorer::Start(void)
|
||||
{
|
||||
// Starts the process of restoring the device to its previously
|
||||
// saved role after MLE start.
|
||||
//
|
||||
// Returns `kErrorNone` if the restoration process begins
|
||||
// successfully. An error is returned if:
|
||||
// - No previous role was saved.
|
||||
// - The saved role info is inconsistent (e.g., RLOC16 indicates a
|
||||
// router/leader, but `mLastSavedRole` doesn't match).
|
||||
|
||||
Error error = kErrorFailed;
|
||||
|
||||
mState = kIdle;
|
||||
mAttempts = 0;
|
||||
VerifyOrExit(Get<Mle>().IsDetached());
|
||||
VerifyOrExit(Get<Mle>().GetRloc16() != kInvalidRloc16);
|
||||
|
||||
if (IsRouterRloc16(Get<Mle>().GetRloc16()))
|
||||
{
|
||||
#if OPENTHREAD_FTD
|
||||
VerifyOrExit((Get<Mle>().mLastSavedRole == kRoleRouter) || (Get<Mle>().mLastSavedRole == kRoleLeader));
|
||||
VerifyOrExit(Get<Mle>().IsRouterEligible());
|
||||
|
||||
Get<MeshForwarder>().SetRxOnWhenIdle(true);
|
||||
SetState(kRestoringRouterOrLeaderRole);
|
||||
DetermineMaxLinkRequestAttempts();
|
||||
mTimer.Start(Get<Mle>().GenerateRandomDelay(kMaxStartDelay));
|
||||
error = kErrorNone;
|
||||
#endif
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
VerifyOrExit(Get<Mle>().mLastSavedRole == kRoleChild);
|
||||
VerifyOrExit(Get<Mle>().mParent.IsStateValidOrRestoring());
|
||||
SetState(kRestoringChildRole);
|
||||
mAttempts = kMaxChildUpdatesToRestoreRole;
|
||||
mTimer.Start(Get<Mle>().GenerateRandomDelay(kMaxStartDelay));
|
||||
error = kErrorNone;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Mle::PrevRoleRestorer::Stop(void)
|
||||
{
|
||||
SetState(kIdle);
|
||||
mTimer.Stop();
|
||||
}
|
||||
|
||||
void Mle::PrevRoleRestorer::SetState(State aState)
|
||||
{
|
||||
mState = aState;
|
||||
|
||||
if (mState != kIdle)
|
||||
{
|
||||
LogInfo("Attempting to restore prev role: %s", RoleToString(Get<Mle>().mLastSavedRole));
|
||||
}
|
||||
}
|
||||
|
||||
void Mle::PrevRoleRestorer::HandleTimer(void)
|
||||
{
|
||||
VerifyOrExit(mState != kIdle);
|
||||
|
||||
if (!Get<Mle>().IsDetached())
|
||||
{
|
||||
Stop();
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
if (mAttempts == 0)
|
||||
{
|
||||
LogInfo("Failed to restore prev role");
|
||||
Stop();
|
||||
IgnoreError(Get<Mle>().BecomeDetached());
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
mAttempts--;
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
if (mState == kRestoringRouterOrLeaderRole)
|
||||
{
|
||||
SendMulticastLinkRequest();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
SendChildUpdate();
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Mle::PrevRoleRestorer::SendChildUpdate(void)
|
||||
{
|
||||
mTimer.Start(Random::NonCrypto::AddJitter(kChildUpdateRetxDelay, kRetxJitter));
|
||||
|
||||
LogDebg("Sending Child Update Request to restore child role, remaining attempts: %u", mAttempts);
|
||||
IgnoreError(Get<Mle>().SendChildUpdateRequestToParent(kToRestoreChildRole));
|
||||
}
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
|
||||
void Mle::PrevRoleRestorer::DetermineMaxLinkRequestAttempts(void)
|
||||
{
|
||||
mAttempts = kMaxCriticalTxCount;
|
||||
|
||||
if ((Get<Mle>().mLastSavedRole == kRoleRouter) &&
|
||||
(Get<Mle>().mChildTable.GetNumChildren(Child::kInStateValidOrRestoring) < kMinCriticalChildrenCount))
|
||||
{
|
||||
mAttempts = kMaxTxCount;
|
||||
}
|
||||
}
|
||||
|
||||
void Mle::PrevRoleRestorer::SendMulticastLinkRequest(void)
|
||||
{
|
||||
uint32_t delay;
|
||||
|
||||
delay = (mAttempts == 0) ? kLinkRequestTimeout
|
||||
: Random::NonCrypto::GetUint32InRange(kMulticastRetxDelayMin, kMulticastRetxDelayMax);
|
||||
|
||||
mTimer.Start(delay);
|
||||
|
||||
LogDebg("Sending multicast Link Request to restore role, remaining attempts: %u", mAttempts);
|
||||
Get<Mle>().SendLinkRequest(nullptr);
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_FTD
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Detacher
|
||||
|
||||
|
||||
+79
-39
@@ -1356,6 +1356,7 @@ private:
|
||||
kNormalChildUpdateRequest, // Normal Child Update Request.
|
||||
kAppendChallengeTlv, // Append Challenge TLV to Child Update Request even if currently attached.
|
||||
kAppendZeroTimeout, // Use zero timeout when appending Timeout TLV (used for graceful detach).
|
||||
kToRestoreChildRole, // To restore previous child role (upon restart), re-establishing link with parent.
|
||||
};
|
||||
|
||||
enum SecuritySuite : uint8_t
|
||||
@@ -1717,6 +1718,71 @@ private:
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
void HandleRoleRestorerTimer(void) { mPrevRoleRestorer.HandleTimer(); }
|
||||
|
||||
class PrevRoleRestorer : public InstanceLocator
|
||||
{
|
||||
// Attempts to restore the device's previously saved role
|
||||
// (child/router/leader) after an MLE restart (e.g., after a
|
||||
// device reboot).
|
||||
//
|
||||
// If the previous role was router/leader, it sends multicast
|
||||
// Link Requests. If the role was child, it sends Child
|
||||
// Update Requests to the parent. It manages message
|
||||
// retransmissions and stops the restoration attempt if the
|
||||
// maximum number of attempts is exhausted, setting the
|
||||
// device to a detached state.
|
||||
//
|
||||
// To prevent synchronized transmissions when multiple devices
|
||||
// reboot at once, it adds a random delay (up to 25 ms)
|
||||
// before sending the first message.
|
||||
|
||||
public:
|
||||
PrevRoleRestorer(Instance &aInstance);
|
||||
|
||||
Error Start(void);
|
||||
void Stop(void);
|
||||
bool IsRestoringChildRole(void) const { return mState == kRestoringChildRole; }
|
||||
bool IsRestoringRouterOrLeaderRole(void) const { return mState == kRestoringRouterOrLeaderRole; }
|
||||
void HandleTimer(void);
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
void GenerateRandomChallenge(void) { mChallenge.GenerateRandom(); }
|
||||
const TxChallenge &GetChallenge(void) const { return mChallenge; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
static constexpr uint32_t kMaxStartDelay = 25;
|
||||
static constexpr uint8_t kMaxChildUpdatesToRestoreRole = kMaxChildKeepAliveAttempts;
|
||||
static constexpr uint32_t kChildUpdateRetxDelay = kUnicastRetxDelay; /// 1000 msec
|
||||
static constexpr uint16_t kRetxJitter = 5;
|
||||
|
||||
enum State : uint8_t
|
||||
{
|
||||
kIdle,
|
||||
kRestoringChildRole,
|
||||
kRestoringRouterOrLeaderRole,
|
||||
};
|
||||
|
||||
void SetState(State aState);
|
||||
void SendChildUpdate(void);
|
||||
#if OPENTHREAD_FTD
|
||||
void DetermineMaxLinkRequestAttempts(void);
|
||||
void SendMulticastLinkRequest(void);
|
||||
#endif
|
||||
|
||||
using DelayTimer = TimerMilliIn<Mle, &Mle::HandleRoleRestorerTimer>;
|
||||
|
||||
State mState;
|
||||
uint8_t mAttempts;
|
||||
DelayTimer mTimer;
|
||||
#if OPENTHREAD_FTD
|
||||
TxChallenge mChallenge;
|
||||
#endif
|
||||
};
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
void HandleDetacherTimer(void) { mDetacher.HandleTimer(); }
|
||||
|
||||
class Detacher : public InstanceLocator
|
||||
@@ -1943,33 +2009,7 @@ private:
|
||||
uint8_t mJitter;
|
||||
};
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
class RouterRoleRestorer : public InstanceLocator
|
||||
{
|
||||
// Attempts to restore the router or leader role after an MLE
|
||||
// restart(e.g., after a device reboot) by sending multicast
|
||||
// Link Requests.
|
||||
|
||||
public:
|
||||
RouterRoleRestorer(Instance &aInstance);
|
||||
|
||||
bool IsActive(void) const { return mAttempts > 0; }
|
||||
void Start(DeviceRole aPreviousRole);
|
||||
void Stop(void) { mAttempts = 0; }
|
||||
void HandleTimer(void);
|
||||
|
||||
void GenerateRandomChallenge(void) { mChallenge.GenerateRandom(); }
|
||||
const TxChallenge &GetChallenge(void) const { return mChallenge; }
|
||||
|
||||
private:
|
||||
void SendMulticastLinkRequest(void);
|
||||
|
||||
uint8_t mAttempts;
|
||||
TxChallenge mChallenge;
|
||||
};
|
||||
|
||||
#endif // OPENTHREAD_FTD
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Methods
|
||||
@@ -2224,17 +2264,18 @@ private:
|
||||
uint32_t mLastAttachTime;
|
||||
uint64_t mLastUpdatedTimestamp;
|
||||
|
||||
LeaderData mLeaderData;
|
||||
Parent mParent;
|
||||
NeighborTable mNeighborTable;
|
||||
DelayedSender mDelayedSender;
|
||||
TxChallenge mParentRequestChallenge;
|
||||
ParentCandidate mParentCandidate;
|
||||
MleSocket mSocket;
|
||||
Counters mCounters;
|
||||
Detacher mDetacher;
|
||||
RetxTracker mRetxTracker;
|
||||
AnnounceHandler mAnnounceHandler;
|
||||
LeaderData mLeaderData;
|
||||
Parent mParent;
|
||||
NeighborTable mNeighborTable;
|
||||
DelayedSender mDelayedSender;
|
||||
TxChallenge mParentRequestChallenge;
|
||||
ParentCandidate mParentCandidate;
|
||||
MleSocket mSocket;
|
||||
Counters mCounters;
|
||||
PrevRoleRestorer mPrevRoleRestorer;
|
||||
Detacher mDetacher;
|
||||
RetxTracker mRetxTracker;
|
||||
AnnounceHandler mAnnounceHandler;
|
||||
#if OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE
|
||||
ParentSearch mParentSearch;
|
||||
#endif
|
||||
@@ -2293,7 +2334,6 @@ private:
|
||||
TrickleTimer mAdvertiseTrickleTimer;
|
||||
ChildTable mChildTable;
|
||||
RouterTable mRouterTable;
|
||||
RouterRoleRestorer mRouterRoleRestorer;
|
||||
RouterRoleTransition mRouterRoleTransition;
|
||||
Ip6::Netif::UnicastAddress mLeaderAloc;
|
||||
#if OPENTHREAD_CONFIG_MLE_DEVICE_PROPERTY_LEADER_WEIGHT_ENABLE
|
||||
|
||||
@@ -392,6 +392,8 @@ void Mle::SetStateRouterOrLeader(DeviceRole aRole, uint16_t aRloc16, LeaderStart
|
||||
|
||||
SetRole(aRole);
|
||||
|
||||
mPrevRoleRestorer.Stop();
|
||||
|
||||
SetAttachState(kAttachStateIdle);
|
||||
mAttachCounter = 0;
|
||||
mAttachTimer.Stop();
|
||||
@@ -595,8 +597,8 @@ void Mle::SendLinkRequest(Router *aRouter)
|
||||
|
||||
if (aRouter == nullptr)
|
||||
{
|
||||
mRouterRoleRestorer.GenerateRandomChallenge();
|
||||
SuccessOrExit(error = message->AppendChallengeTlv(mRouterRoleRestorer.GetChallenge()));
|
||||
mPrevRoleRestorer.GenerateRandomChallenge();
|
||||
SuccessOrExit(error = message->AppendChallengeTlv(mPrevRoleRestorer.GetChallenge()));
|
||||
destination.SetToLinkLocalAllRoutersMulticast();
|
||||
}
|
||||
else
|
||||
@@ -866,10 +868,9 @@ void Mle::HandleLinkAcceptVariant(RxInfo &aRxInfo, MessageType aMessageType)
|
||||
break;
|
||||
|
||||
case Neighbor::kStateInvalid:
|
||||
VerifyOrExit(mRouterRoleRestorer.IsActive() && (response == mRouterRoleRestorer.GetChallenge()),
|
||||
error = kErrorSecurity);
|
||||
|
||||
OT_FALL_THROUGH;
|
||||
VerifyOrExit(mPrevRoleRestorer.IsRestoringRouterOrLeaderRole(), error = kErrorSecurity);
|
||||
VerifyOrExit(response == mPrevRoleRestorer.GetChallenge(), error = kErrorSecurity);
|
||||
break;
|
||||
|
||||
case Neighbor::kStateValid:
|
||||
break;
|
||||
@@ -927,7 +928,6 @@ void Mle::HandleLinkAcceptVariant(RxInfo &aRxInfo, MessageType aMessageType)
|
||||
SetStateRouter(GetRloc16());
|
||||
}
|
||||
|
||||
mRouterRoleRestorer.Stop();
|
||||
mRetrieveNewNetworkData = true;
|
||||
IgnoreError(SendDataRequest(aRxInfo.mMessageInfo.GetPeerAddr()));
|
||||
shouldUpdateRoutes = true;
|
||||
@@ -3929,80 +3929,6 @@ exit:
|
||||
return expired;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// RouterRoleRestorer
|
||||
|
||||
Mle::RouterRoleRestorer::RouterRoleRestorer(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mAttempts(0)
|
||||
{
|
||||
}
|
||||
|
||||
void Mle::RouterRoleRestorer::Start(DeviceRole aPreviousRole)
|
||||
{
|
||||
// If the device was previously the leader or had more than
|
||||
// `kMinCriticalChildrenCount` children, we use more link
|
||||
// request attempts.
|
||||
|
||||
mAttempts = 0;
|
||||
|
||||
switch (aPreviousRole)
|
||||
{
|
||||
case kRoleRouter:
|
||||
if (Get<Mle>().mChildTable.GetNumChildren(Child::kInStateValidOrRestoring) < kMinCriticalChildrenCount)
|
||||
{
|
||||
mAttempts = kMaxTxCount;
|
||||
break;
|
||||
}
|
||||
|
||||
OT_FALL_THROUGH;
|
||||
|
||||
case kRoleLeader:
|
||||
mAttempts = kMaxCriticalTxCount;
|
||||
break;
|
||||
|
||||
case kRoleChild:
|
||||
case kRoleDetached:
|
||||
case kRoleDisabled:
|
||||
break;
|
||||
}
|
||||
|
||||
SendMulticastLinkRequest();
|
||||
}
|
||||
|
||||
void Mle::RouterRoleRestorer::HandleTimer(void)
|
||||
{
|
||||
if (mAttempts > 0)
|
||||
{
|
||||
mAttempts--;
|
||||
}
|
||||
|
||||
SendMulticastLinkRequest();
|
||||
}
|
||||
|
||||
void Mle::RouterRoleRestorer::SendMulticastLinkRequest(void)
|
||||
{
|
||||
uint32_t delay;
|
||||
|
||||
VerifyOrExit(Get<Mle>().IsDetached(), mAttempts = 0);
|
||||
|
||||
if (mAttempts == 0)
|
||||
{
|
||||
IgnoreError(Get<Mle>().BecomeDetached());
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
Get<Mle>().SendLinkRequest(nullptr);
|
||||
|
||||
delay = (mAttempts == 1) ? kLinkRequestTimeout
|
||||
: Random::NonCrypto::GetUint32InRange(kMulticastRetxDelayMin, kMulticastRetxDelayMax);
|
||||
|
||||
Get<Mle>().mAttachTimer.Start(delay);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
} // namespace Mle
|
||||
} // namespace ot
|
||||
|
||||
|
||||
Reference in New Issue
Block a user