mirror of
https://github.com/espressif/openthread.git
synced 2026-09-10 11:10:08 +00:00
[mle] add Mle::Detacher class to manage graceful detach process (#11723)
This commit introduces a new `Mle::Detacher` class to encapsulate all state and logic for the graceful detach process. By managing its own internal state, timer, and completion callback, the `Detacher` class centralizes the detach logic, improving code clarity and maintainability.
This commit is contained in:
+67
-29
@@ -52,7 +52,6 @@ Mle::Mle(Instance &aInstance)
|
|||||||
, mRequestRouteTlv(false)
|
, mRequestRouteTlv(false)
|
||||||
, mHasRestored(false)
|
, mHasRestored(false)
|
||||||
, mReceivedResponseFromParent(false)
|
, mReceivedResponseFromParent(false)
|
||||||
, mDetachingGracefully(false)
|
|
||||||
, mInitiallyAttachedAsSleepy(false)
|
, mInitiallyAttachedAsSleepy(false)
|
||||||
, mRole(kRoleDisabled)
|
, mRole(kRoleDisabled)
|
||||||
, mLastSavedRole(kRoleDisabled)
|
, mLastSavedRole(kRoleDisabled)
|
||||||
@@ -75,6 +74,7 @@ Mle::Mle(Instance &aInstance)
|
|||||||
, mNeighborTable(aInstance)
|
, mNeighborTable(aInstance)
|
||||||
, mDelayedSender(aInstance)
|
, mDelayedSender(aInstance)
|
||||||
, mSocket(aInstance, *this)
|
, mSocket(aInstance, *this)
|
||||||
|
, mDetacher(aInstance)
|
||||||
, mRetxTracker(aInstance)
|
, mRetxTracker(aInstance)
|
||||||
, mAnnounceHandler(aInstance)
|
, mAnnounceHandler(aInstance)
|
||||||
#if OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE
|
#if OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE
|
||||||
@@ -273,11 +273,7 @@ void Mle::Stop(StopMode aMode)
|
|||||||
SetRole(kRoleDisabled);
|
SetRole(kRoleDisabled);
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
if (mDetachingGracefully)
|
mDetacher.HandleStop();
|
||||||
{
|
|
||||||
mDetachingGracefully = false;
|
|
||||||
mDetachGracefullyCallback.InvokeAndClearIfSet();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Error Mle::RestorePrevRole(void)
|
Error Mle::RestorePrevRole(void)
|
||||||
@@ -1465,12 +1461,6 @@ void Mle::HandleAttachTimer(void)
|
|||||||
bool shouldAnnounce = true;
|
bool shouldAnnounce = true;
|
||||||
ParentRequestType type;
|
ParentRequestType type;
|
||||||
|
|
||||||
if (mDetachingGracefully)
|
|
||||||
{
|
|
||||||
Stop();
|
|
||||||
ExitNow();
|
|
||||||
}
|
|
||||||
|
|
||||||
#if OPENTHREAD_FTD
|
#if OPENTHREAD_FTD
|
||||||
if (IsDetached() && mRouterRoleRestorer.IsActive())
|
if (IsDetached() && mRouterRoleRestorer.IsActive())
|
||||||
{
|
{
|
||||||
@@ -3519,14 +3509,8 @@ void Mle::HandleChildUpdateResponseOnChild(RxInfo &aRxInfo)
|
|||||||
switch (Tlv::Find<TimeoutTlv>(aRxInfo.mMessage, timeout))
|
switch (Tlv::Find<TimeoutTlv>(aRxInfo.mMessage, timeout))
|
||||||
{
|
{
|
||||||
case kErrorNone:
|
case kErrorNone:
|
||||||
if (timeout == 0 && mDetachingGracefully)
|
SuccessOrExit(mDetacher.HandleChildUpdateResponse(timeout));
|
||||||
{
|
SetTimeout(timeout, kDoNotSendChildUpdateToParent);
|
||||||
Stop();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SetTimeout(timeout, kDoNotSendChildUpdateToParent);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case kErrorNotFound:
|
case kErrorNotFound:
|
||||||
break;
|
break;
|
||||||
@@ -4264,32 +4248,32 @@ exit:
|
|||||||
}
|
}
|
||||||
#endif // OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
#endif // OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
|
||||||
|
|
||||||
Error Mle::DetachGracefully(DetachCallback aCallback, void *aContext)
|
Error Mle::Detacher::Detach(DetachCallback aCallback, void *aContext)
|
||||||
{
|
{
|
||||||
Error error = kErrorNone;
|
Error error = kErrorNone;
|
||||||
uint32_t timeout = kDetachGracefullyTimeout;
|
uint32_t timeout = kTimeout;
|
||||||
|
|
||||||
VerifyOrExit(!mDetachingGracefully, error = kErrorBusy);
|
VerifyOrExit(mState == kIdle, error = kErrorBusy);
|
||||||
|
|
||||||
mDetachGracefullyCallback.Set(aCallback, aContext);
|
mCallback.Set(aCallback, aContext);
|
||||||
|
|
||||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
|
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
|
||||||
Get<BorderRouter::RoutingManager>().RequestStop();
|
Get<BorderRouter::RoutingManager>().RequestStop();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
switch (mRole)
|
switch (Get<Mle>().GetRole())
|
||||||
{
|
{
|
||||||
case kRoleLeader:
|
case kRoleLeader:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kRoleRouter:
|
case kRoleRouter:
|
||||||
#if OPENTHREAD_FTD
|
#if OPENTHREAD_FTD
|
||||||
SendAddressRelease();
|
Get<Mle>().SendAddressRelease();
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kRoleChild:
|
case kRoleChild:
|
||||||
IgnoreError(SendChildUpdateRequestToParent(kAppendZeroTimeout));
|
IgnoreError(Get<Mle>().SendChildUpdateRequestToParent(kAppendZeroTimeout));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kRoleDisabled:
|
case kRoleDisabled:
|
||||||
@@ -4302,8 +4286,8 @@ Error Mle::DetachGracefully(DetachCallback aCallback, void *aContext)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
mDetachingGracefully = true;
|
mState = kDetaching;
|
||||||
mAttachTimer.Start(timeout);
|
mTimer.Start(timeout);
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
return error;
|
return error;
|
||||||
@@ -5382,6 +5366,60 @@ void Mle::ParentCandidate::CopyTo(Parent &aParent) const
|
|||||||
aParent = *candidateAsParent;
|
aParent = *candidateAsParent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Detacher
|
||||||
|
|
||||||
|
Mle::Detacher::Detacher(Instance &aInstance)
|
||||||
|
: InstanceLocator(aInstance)
|
||||||
|
, mState(kIdle)
|
||||||
|
, mTimer(aInstance)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mle::Detacher::HandleTimer(void)
|
||||||
|
{
|
||||||
|
if (mState == kDetaching)
|
||||||
|
{
|
||||||
|
Get<Mle>().Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Error Mle::Detacher::HandleChildUpdateResponse(uint32_t aTimeout)
|
||||||
|
{
|
||||||
|
// Called while processing a "Child Update Response" from parent
|
||||||
|
//
|
||||||
|
// To gracefully detach as a child, we send a "Child Update
|
||||||
|
// Request" with zero timeout value to the parent. Receiving
|
||||||
|
// a "Child Update Response" confirms the parent has received the
|
||||||
|
// request, allowing the device to then stop its MLE operations.
|
||||||
|
|
||||||
|
// Returns `kErrorDetached` to signal that MLE is stopped and the
|
||||||
|
// incoming response should be ignored. Returns `kErrorNone` if
|
||||||
|
// the response should be processed (i.e., not detaching or if
|
||||||
|
// the conditions for MLE stop are not yet met).
|
||||||
|
|
||||||
|
Error error = kErrorNone;
|
||||||
|
|
||||||
|
VerifyOrExit(mState == kDetaching);
|
||||||
|
VerifyOrExit(aTimeout == 0);
|
||||||
|
Get<Mle>().Stop();
|
||||||
|
error = kErrorDetached;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mle::Detacher::HandleStop(void)
|
||||||
|
{
|
||||||
|
// Called upon `Mle::Stop()` after role change.
|
||||||
|
|
||||||
|
if (mState == kDetaching)
|
||||||
|
{
|
||||||
|
mState = kIdle;
|
||||||
|
mCallback.InvokeAndClearIfSet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
// RetxTracker::RetryInfo
|
// RetxTracker::RetryInfo
|
||||||
|
|
||||||
|
|||||||
+34
-4
@@ -216,7 +216,7 @@ public:
|
|||||||
* @retval kErrorNone Successfully started detaching.
|
* @retval kErrorNone Successfully started detaching.
|
||||||
* @retval kErrorBusy Detaching is already in progress.
|
* @retval kErrorBusy Detaching is already in progress.
|
||||||
*/
|
*/
|
||||||
Error DetachGracefully(DetachCallback aCallback, void *aContext);
|
Error DetachGracefully(DetachCallback aCallback, void *aContext) { return mDetacher.Detach(aCallback, aContext); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether or not the Thread device is attached to a Thread network.
|
* Indicates whether or not the Thread device is attached to a Thread network.
|
||||||
@@ -1182,7 +1182,6 @@ private:
|
|||||||
static constexpr uint32_t kMaxLinkAcceptDelay = 1000; // Max delay to tx Link Accept for multicast Req
|
static constexpr uint32_t kMaxLinkAcceptDelay = 1000; // Max delay to tx Link Accept for multicast Req
|
||||||
static constexpr uint32_t kChildIdRequestTimeout = 5000; // Max delay to rx a Child ID Req after Parent Res
|
static constexpr uint32_t kChildIdRequestTimeout = 5000; // Max delay to rx a Child ID Req after Parent Res
|
||||||
static constexpr uint32_t kLinkRequestTimeout = 2000; // Max delay to rx a Link Accept
|
static constexpr uint32_t kLinkRequestTimeout = 2000; // Max delay to rx a Link Accept
|
||||||
static constexpr uint32_t kDetachGracefullyTimeout = 1000; // Timeout for graceful detach
|
|
||||||
static constexpr uint32_t kUnicastRetxDelay = 1000; // Base delay for MLE unicast retx
|
static constexpr uint32_t kUnicastRetxDelay = 1000; // Base delay for MLE unicast retx
|
||||||
static constexpr uint32_t kMulticastRetxDelay = 5000; // Base delay for MLE multicast retx
|
static constexpr uint32_t kMulticastRetxDelay = 5000; // Base delay for MLE multicast retx
|
||||||
static constexpr uint32_t kMulticastRetxDelayMin = kMulticastRetxDelay * 9 / 10; // 0.9 * base delay
|
static constexpr uint32_t kMulticastRetxDelayMin = kMulticastRetxDelay * 9 / 10; // 0.9 * base delay
|
||||||
@@ -1721,6 +1720,38 @@ private:
|
|||||||
|
|
||||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
void HandleDetacherTimer(void) { mDetacher.HandleTimer(); }
|
||||||
|
|
||||||
|
class Detacher : public InstanceLocator
|
||||||
|
{
|
||||||
|
// Manages graceful detach process.
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Detacher(Instance &aInstance);
|
||||||
|
|
||||||
|
Error Detach(DetachCallback aCallback, void *aContext);
|
||||||
|
void HandleTimer(void);
|
||||||
|
Error HandleChildUpdateResponse(uint32_t aTimeout);
|
||||||
|
void HandleStop(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr uint32_t kTimeout = 1000;
|
||||||
|
|
||||||
|
enum State : uint8_t
|
||||||
|
{
|
||||||
|
kIdle,
|
||||||
|
kDetaching,
|
||||||
|
};
|
||||||
|
|
||||||
|
using DetachTimer = TimerMilliIn<Mle, &Mle::HandleDetacherTimer>;
|
||||||
|
|
||||||
|
State mState;
|
||||||
|
Callback<DetachCallback> mCallback;
|
||||||
|
DetachTimer mTimer;
|
||||||
|
};
|
||||||
|
|
||||||
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
void HandleRetxTrackerTimer(void) { mRetxTracker.HandleTimer(); }
|
void HandleRetxTrackerTimer(void) { mRetxTracker.HandleTimer(); }
|
||||||
|
|
||||||
class RetxTracker : public InstanceLocator
|
class RetxTracker : public InstanceLocator
|
||||||
@@ -2171,7 +2202,6 @@ private:
|
|||||||
bool mRequestRouteTlv : 1;
|
bool mRequestRouteTlv : 1;
|
||||||
bool mHasRestored : 1;
|
bool mHasRestored : 1;
|
||||||
bool mReceivedResponseFromParent : 1;
|
bool mReceivedResponseFromParent : 1;
|
||||||
bool mDetachingGracefully : 1;
|
|
||||||
bool mInitiallyAttachedAsSleepy : 1;
|
bool mInitiallyAttachedAsSleepy : 1;
|
||||||
|
|
||||||
DeviceRole mRole;
|
DeviceRole mRole;
|
||||||
@@ -2204,6 +2234,7 @@ private:
|
|||||||
ParentCandidate mParentCandidate;
|
ParentCandidate mParentCandidate;
|
||||||
MleSocket mSocket;
|
MleSocket mSocket;
|
||||||
Counters mCounters;
|
Counters mCounters;
|
||||||
|
Detacher mDetacher;
|
||||||
RetxTracker mRetxTracker;
|
RetxTracker mRetxTracker;
|
||||||
AnnounceHandler mAnnounceHandler;
|
AnnounceHandler mAnnounceHandler;
|
||||||
#if OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE
|
#if OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE
|
||||||
@@ -2212,7 +2243,6 @@ private:
|
|||||||
#if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
|
#if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
|
||||||
ServiceAloc mServiceAlocs[kMaxServiceAlocs];
|
ServiceAloc mServiceAlocs[kMaxServiceAlocs];
|
||||||
#endif
|
#endif
|
||||||
Callback<DetachCallback> mDetachGracefullyCallback;
|
|
||||||
#if OPENTHREAD_CONFIG_MLE_PARENT_RESPONSE_CALLBACK_API_ENABLE
|
#if OPENTHREAD_CONFIG_MLE_PARENT_RESPONSE_CALLBACK_API_ENABLE
|
||||||
Callback<otThreadParentResponseCallback> mParentResponseCallback;
|
Callback<otThreadParentResponseCallback> mParentResponseCallback;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user