From f056d0062f824d46dd1b41a9e19adf7d7af3db25 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Wed, 20 Aug 2025 14:15:01 -0700 Subject: [PATCH] [message] check for potential integer overflows (#11831) This commit adds checks to prevent potential integer overflow issues within the `Message` class. Previously, calculations involving message offset and length, such as `offset + length`, assumed the caller would provide values within a safe range. However, in some edge cases where larger values are given, this addition could wrap around. This could lead to incorrect behavior, potential memory corruption, or assertion failures. To address this, this change introduces a new generic utility function, `CanAddSafely()`, to detect unsigned integer addition overflows. This check is now applied in the following `Message` methods to validate lengths and offsets before performing arithmetic: - `AppendBytes()`: Returns an error if `offset + length` overflows. - `AppendBytesFromMessage()`: Returns an error on overflow. - `GetFirstChunk()`: Safely clamps the read length to the available message length. - `WriteBytes()`: Asserts if `offset + length` overflows. Unit tests for the new `CanAddSafely()` utility are included, covering `uint8_t` and `uint16_t` cases. --- src/core/thread/mle.cpp | 442 +++++++++++++++++++----------------- src/core/thread/mle.hpp | 170 ++++++++------ src/core/thread/mle_ftd.cpp | 16 +- 3 files changed, 346 insertions(+), 282 deletions(-) diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 41a53067e..b580d7b08 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -52,21 +52,12 @@ Mle::Mle(Instance &aInstance) , mRetrieveNewNetworkData(false) , mRequestRouteTlv(false) , mHasRestored(false) - , mReceivedResponseFromParent(false) , mInitiallyAttachedAsSleepy(false) , mRole(kRoleDisabled) , mLastSavedRole(kRoleDisabled) , mDeviceMode(DeviceMode::kModeRxOnWhenIdle) - , mAttachState(kAttachStateIdle) - , mReattachState(kReattachStop) - , mAttachMode(kAnyPartition) - , mAddressRegistrationMode(kAppendAllAddresses) - , mParentRequestCounter(0) - , mAnnounceChannel(0) , mRloc16(kInvalidRloc16) , mPreviousParentRloc(kInvalidRloc16) - , mAttachCounter(0) - , mAnnounceDelay(kAnnounceTimeout) , mStoreFrameCounterAhead(kDefaultStoreFrameCounterAhead) , mTimeout(kDefaultChildTimeout) #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE @@ -76,13 +67,13 @@ Mle::Mle(Instance &aInstance) , mDelayedSender(aInstance) , mSocket(aInstance, *this) , mPrevRoleRestorer(aInstance) + , mAttacher(aInstance) , mDetacher(aInstance) , mRetxTracker(aInstance) , mAnnounceHandler(aInstance) #if OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE , mParentSearch(aInstance) #endif - , mAttachTimer(aInstance) #if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE , mWakeupTxScheduler(aInstance) , mWedAttachState(kWedDetached) @@ -118,11 +109,9 @@ Mle::Mle(Instance &aInstance) #endif // OPENTHREAD_FTD { mParent.Init(aInstance); - mParentCandidate.Init(aInstance); mLeaderData.Clear(); mParent.Clear(); - mParentCandidate.Clear(); ResetCounters(); mLinkLocalAddress.InitAsThreadOrigin(); @@ -221,27 +210,9 @@ Error Mle::Start(StartMode aMode) SetRloc16(GetRloc16()); - mAttachCounter = 0; - Get().Start(); - switch (aMode) - { - case kNormalAttach: - mReattachState = - (Get().Restore() == kErrorNone) ? kReattachActive : kReattachStop; - - if (mPrevRoleRestorer.Start() == kErrorNone) - { - ExitNow(); - } - break; - - case kAnnounceAttach: - break; - } - - Attach(kAnyPartition); + mAttacher.Start(aMode); exit: return error; @@ -383,11 +354,11 @@ exit: return; } -void Mle::SetAttachState(AttachState aState) +void Mle::Attacher::SetState(State aState) { - VerifyOrExit(aState != mAttachState); - LogInfo("AttachState %s -> %s", AttachStateToString(mAttachState), AttachStateToString(aState)); - mAttachState = aState; + VerifyOrExit(aState != mState); + LogInfo("AttachState %s -> %s", StateToString(mState), StateToString(aState)); + mState = aState; exit: return; @@ -558,7 +529,7 @@ Error Mle::BecomeDetached(void) VerifyOrExit(!IsDisabled(), error = kErrorInvalidState); - if (IsDetached() && (mAttachState == kAttachStateStart)) + if (IsDetached() && mAttacher.WillStartAttachSoon()) { // Already detached and waiting to start an attach attempt, so // there is not need to make any changes. @@ -566,7 +537,7 @@ Error Mle::BecomeDetached(void) } // Not in reattach stage after reset - if (mReattachState == kReattachStop) + if (mAttacher.IsReattachWithDatasetDone()) { IgnoreError(Get().Restore()); } @@ -578,7 +549,7 @@ Error Mle::BecomeDetached(void) SetStateDetached(); mParent.SetState(Neighbor::kStateInvalid); SetRloc16(kInvalidRloc16); - Attach(kAnyPartition); + mAttacher.Attach(kAnyPartition); exit: return error; @@ -591,7 +562,7 @@ Error Mle::BecomeChild(void) VerifyOrExit(!IsDisabled(), error = kErrorInvalidState); VerifyOrExit(!IsAttaching(), error = kErrorBusy); - Attach(kAnyPartition); + mAttacher.Attach(kAnyPartition); exit: return error; @@ -602,42 +573,44 @@ Error Mle::SearchForBetterParent(void) Error error = kErrorNone; VerifyOrExit(IsChild(), error = kErrorInvalidState); - Attach(kBetterParent); + mAttacher.Attach(kBetterParent); exit: return error; } -void Mle::Attach(AttachMode aMode) +void Mle::Attacher::Attach(AttachMode aMode) { - VerifyOrExit(!IsDisabled() && !IsAttaching()); + VerifyOrExit(!Get().IsDisabled()); - if (!IsDetached()) + VerifyOrExit(!IsAttaching()); + + if (!Get().IsDetached()) { mAttachCounter = 0; } mParentCandidate.Clear(); - SetAttachState(kAttachStateStart); - mAttachMode = aMode; + SetState(kStateStart); + mMode = aMode; if (aMode != kBetterPartition) { #if OPENTHREAD_FTD - if (IsFullThreadDevice()) + if (Get().IsFullThreadDevice()) { - StopAdvertiseTrickleTimer(); + Get().StopAdvertiseTrickleTimer(); } #endif } else { - mCounters.mBetterPartitionAttachAttempts++; + Get().mCounters.mBetterPartitionAttachAttempts++; } - mAttachTimer.Start(GetAttachStartDelay()); + mTimer.Start(GetStartDelay()); - if (IsDetached()) + if (Get().IsDetached()) { mAttachCounter++; @@ -646,9 +619,9 @@ void Mle::Attach(AttachMode aMode) mAttachCounter--; } - mCounters.mAttachAttempts++; + Get().mCounters.mAttachAttempts++; - if (!IsRxOnWhenIdle()) + if (!Get().IsRxOnWhenIdle()) { Get().SetRxOnWhenIdle(false); } @@ -658,16 +631,16 @@ exit: return; } -uint32_t Mle::GetAttachStartDelay(void) const +uint32_t Mle::Attacher::GetStartDelay(void) const { uint32_t delay = 1; uint32_t jitter; - VerifyOrExit(IsDetached()); + VerifyOrExit(Get().IsDetached()); if (mAttachCounter == 0) { - delay = GenerateRandomDelay(kParentRequestRouterTimeout); + delay = Get().GenerateRandomDelay(kParentRequestRouterTimeout); ExitNow(); } #if OPENTHREAD_CONFIG_MLE_ATTACH_BACKOFF_ENABLE @@ -723,8 +696,7 @@ void Mle::SetStateDetached(void) #endif SetRole(kRoleDetached); - SetAttachState(kAttachStateIdle); - mAttachTimer.Stop(); + mAttacher.CancelAttachOnRoleChange(); mDelayedSender.RemoveScheduledChildUpdateRequestToParent(); mRetxTracker.Stop(); mInitiallyAttachedAsSleepy = false; @@ -747,9 +719,7 @@ void Mle::SetStateChild(uint16_t aRloc16) SetRloc16(aRloc16); SetRole(kRoleChild); - SetAttachState(kAttachStateIdle); - mAttachTimer.Start(kAttachBackoffDelayToResetCounter); - mReattachState = kReattachStop; + mAttacher.CancelAttachOnRoleChange(); Get().SetBeaconEnabled(false); mRetxTracker.UpdateOnRoleChangeToChild(); mPrevRoleRestorer.Stop(); @@ -757,7 +727,7 @@ void Mle::SetStateChild(uint16_t aRloc16) #if OPENTHREAD_FTD if (IsFullThreadDevice()) { - HandleChildStart(mAttachMode); + HandleChildStart(); } #endif @@ -878,7 +848,7 @@ Error Mle::SetDeviceMode(DeviceMode aDeviceMode) if (shouldReattach) { - mAttachCounter = 0; + mAttacher.ResetAttachCounter(); IgnoreError(BecomeDetached()); ExitNow(); } @@ -886,9 +856,9 @@ Error Mle::SetDeviceMode(DeviceMode aDeviceMode) if (IsDetached()) { - mAttachCounter = 0; + mAttacher.ResetAttachCounter(); SetStateDetached(); - Attach(kAnyPartition); + mAttacher.Attach(kAnyPartition); } else if (IsChild()) { @@ -1124,20 +1094,6 @@ void Mle::HandleNotifierEvents(Events aEvents) { VerifyOrExit(!IsDisabled()); - if (aEvents.Contains(kEventThreadRoleChanged)) - { - if (mAddressRegistrationMode == kAppendMeshLocalOnly) - { - // If only mesh-local address was registered in the "Child - // ID Request" message, after device is attached, trigger a - // "Child Update Request" to register the remaining - // addresses. - - mAddressRegistrationMode = kAppendAllAddresses; - ScheduleChildUpdateRequestIfMtdChild(); - } - } - if (aEvents.ContainsAny(kEventIp6AddressAdded | kEventIp6AddressRemoved)) { if (!Get().HasUnicastAddress(mMeshLocalEid.GetAddress())) @@ -1221,10 +1177,10 @@ exit: return; } -Error Mle::DetermineParentRequestType(ParentRequestType &aType) const +Error Mle::Attacher::DetermineParentRequestType(ParentRequestType &aType) const { // This method determines the Parent Request type to use during an - // attach cycle based on `mAttachMode`, `mAttachCounter` and + // attach cycle based on `mMode`, `mAttachCounter` and // `mParentRequestCounter`. This method MUST be used while in // `kAttachStateParentRequest` state. // @@ -1236,9 +1192,9 @@ Error Mle::DetermineParentRequestType(ParentRequestType &aType) const Error error = kErrorNone; - OT_ASSERT(mAttachState == kAttachStateParentRequest); + OT_ASSERT(mState == kStateParentRequest); - if (mAttachMode == kSelectedParent) + if (mMode == kSelectedParent) { aType = kToSelectedRouter; VerifyOrExit(mParentRequestCounter <= 1, error = kErrorNotFound); @@ -1254,14 +1210,14 @@ Error Mle::DetermineParentRequestType(ParentRequestType &aType) const // router trying to attach to a better partition, or a child trying // to find a better parent. - if ((mAttachCounter <= 1) && (mAttachMode != kBetterParent)) + if ((mAttachCounter <= 1) && (mMode != kBetterParent)) { VerifyOrExit(mParentRequestCounter <= kFirstAttachCycleTotalParentRequests, error = kErrorNotFound); // During reattach to the same partition all the Parent // Request are sent to Routers and REEDs. - if ((mAttachMode != kSamePartition) && (mParentRequestCounter <= kFirstAttachCycleNumParentRequestToRouters)) + if ((mMode != kSamePartition) && (mParentRequestCounter <= kFirstAttachCycleNumParentRequestToRouters)) { aType = kToRouters; } @@ -1280,20 +1236,20 @@ exit: return error; } -bool Mle::HasAcceptableParentCandidate(void) const +bool Mle::Attacher::HasAcceptableParentCandidate(void) const { bool hasAcceptableParent = false; ParentRequestType parentReqType; VerifyOrExit(mParentCandidate.IsStateParentResponse()); - switch (mAttachState) + switch (mState) { - case kAttachStateAnnounce: + case kStateAnnounce: VerifyOrExit(!HasMoreChannelsToAnnounce()); break; - case kAttachStateParentRequest: + case kStateParentRequest: SuccessOrAssert(DetermineParentRequestType(parentReqType)); if (parentReqType == kToRouters) @@ -1311,9 +1267,9 @@ bool Mle::HasAcceptableParentCandidate(void) const ExitNow(); } - if (IsChild()) + if (Get().IsChild()) { - switch (mAttachMode) + switch (mMode) { case kBetterPartition: break; @@ -1338,7 +1294,7 @@ exit: return hasAcceptableParent; } -void Mle::HandleAttachTimer(void) +void Mle::Attacher::HandleTimer(void) { uint32_t delay = 0; bool shouldAnnounce = true; @@ -1349,22 +1305,22 @@ void Mle::HandleAttachTimer(void) if (HasAcceptableParentCandidate() && (SendChildIdRequest() == kErrorNone)) { - SetAttachState(kAttachStateChildIdRequest); + SetState(kStateChildIdRequest); delay = kChildIdResponseTimeout; ExitNow(); } - switch (mAttachState) + switch (mState) { - case kAttachStateIdle: + case kStateIdle: mAttachCounter = 0; break; - case kAttachStateStart: - LogNote("Attach attempt %d, %s %s", mAttachCounter, AttachModeToString(mAttachMode), - ReattachStateToString(mReattachState)); + case kStateStart: + LogNote("Attach attempt %d, %s %s", mAttachCounter, AttachModeToString(mMode), + ReattachModeToString(mReattachMode)); - SetAttachState(kAttachStateParentRequest); + SetState(kStateParentRequest); mParentCandidate.SetState(Neighbor::kStateInvalid); mReceivedResponseFromParent = false; mParentRequestCounter = 0; @@ -1372,7 +1328,7 @@ void Mle::HandleAttachTimer(void) OT_FALL_THROUGH; - case kAttachStateParentRequest: + case kStateParentRequest: mParentRequestCounter++; if (DetermineParentRequestType(type) == kErrorNone) { @@ -1397,14 +1353,14 @@ void Mle::HandleAttachTimer(void) if (shouldAnnounce) { // We send an extra "Parent Request" as we switch to - // `kAttachStateAnnounce` and start sending Announce on + // `kStateAnnounce` and start sending Announce on // all channels. This gives an additional chance to find // a parent during this phase. Note that we can stay in - // `kAttachStateAnnounce` for multiple iterations, each + // `kStateAnnounce` for multiple iterations, each // time sending an Announce on a different channel // (with `mAnnounceDelay` wait between them). - SetAttachState(kAttachStateAnnounce); + SetState(kStateAnnounce); SendParentRequest(kToRoutersAndReeds); mAnnounceChannel = Mac::ChannelMask::kChannelIteratorFirst; delay = mAnnounceDelay; @@ -1413,18 +1369,18 @@ void Mle::HandleAttachTimer(void) OT_FALL_THROUGH; - case kAttachStateAnnounce: + case kStateAnnounce: if (shouldAnnounce && (GetNextAnnounceChannel(mAnnounceChannel) == kErrorNone)) { - SendAnnounce(mAnnounceChannel, kOrphanAnnounce); + Get().SendAnnounce(mAnnounceChannel, kOrphanAnnounce); delay = mAnnounceDelay; break; } OT_FALL_THROUGH; - case kAttachStateChildIdRequest: - SetAttachState(kAttachStateIdle); + case kStateChildIdRequest: + SetState(kStateIdle); mParentCandidate.Clear(); delay = Reattach(); break; @@ -1434,17 +1390,17 @@ exit: if (delay != 0) { - mAttachTimer.Start(delay); + mTimer.Start(delay); } } -bool Mle::PrepareAnnounceState(void) +bool Mle::Attacher::PrepareAnnounceState(void) { bool shouldAnnounce = false; Mac::ChannelMask channelMask; - VerifyOrExit(!IsChild() && (mReattachState == kReattachStop) && - (Get().IsPartiallyComplete() || !IsFullThreadDevice())); + VerifyOrExit(!Get().IsChild() && (mReattachMode == kReattachModeStop) && + (Get().IsPartiallyComplete() || !Get().IsFullThreadDevice())); if (Get().GetChannelMask(channelMask) != kErrorNone) { @@ -1459,51 +1415,51 @@ exit: return shouldAnnounce; } -uint32_t Mle::Reattach(void) +uint32_t Mle::Attacher::Reattach(void) { uint32_t delay = 0; - // First, check `mReattachState`. If an attach attempt failed + // First, check `mReattachMode`. If an attach attempt failed // while using the Active Dataset, start a new attach cycle with // the Pending Dataset (if available). If attaching with the // Pending Dataset fails, switch back to the Active Dataset. - switch (mReattachState) + switch (mReattachMode) { - case kReattachActive: + case kReattachModeActive: if (Get().Restore() == kErrorNone) { IgnoreError(Get().ApplyConfiguration()); - mReattachState = kReattachPending; - SetAttachState(kAttachStateStart); - delay = GenerateRandomDelay(kAttachStartJitter); + mReattachMode = kReattachModePending; + SetState(kStateStart); + delay = Get().GenerateRandomDelay(kAttachStartJitter); ExitNow(); } - mReattachState = kReattachStop; + mReattachMode = kReattachModeStop; break; - case kReattachPending: + case kReattachModePending: IgnoreError(Get().Restore()); - mReattachState = kReattachStop; + mReattachMode = kReattachModeStop; break; - case kReattachStop: + case kReattachModeStop: break; } - switch (mAttachMode) + switch (mMode) { case kAnyPartition: case kBetterParent: case kSelectedParent: - if (IsChild()) + if (Get().IsChild()) { // If already attached (e.g., trying to find a better // parent or partition), and attach fails, we revert to // sleepy operation if needed and stop the attach process. - if (!IsRxOnWhenIdle()) + if (!Get().IsRxOnWhenIdle()) { Get().SetAttachMode(false); Get().SetRxOnWhenIdle(false); @@ -1512,21 +1468,21 @@ uint32_t Mle::Reattach(void) ExitNow(); } - if (mAnnounceHandler.IsAnnounceAttaching()) + if (Get().mAnnounceHandler.IsAnnounceAttaching()) { - mAnnounceHandler.HandleAnnounceAttachFailure(); - IgnoreError(BecomeDetached()); + Get().mAnnounceHandler.HandleAnnounceAttachFailure(); + IgnoreError(Get().BecomeDetached()); ExitNow(); } #if OPENTHREAD_FTD - if (IsFullThreadDevice() && BecomeLeader(kIgnoreLeaderWeight) == kErrorNone) + if (Get().IsFullThreadDevice() && Get().BecomeLeader(kIgnoreLeaderWeight) == kErrorNone) { ExitNow(); } #endif - IgnoreError(BecomeDetached()); + IgnoreError(Get().BecomeDetached()); break; case kSamePartition: @@ -1542,7 +1498,7 @@ exit: return delay; } -void Mle::SendParentRequest(ParentRequestType aType) +void Mle::Attacher::SendParentRequest(ParentRequestType aType) { Error error = kErrorNone; TxMessage *message; @@ -1563,8 +1519,8 @@ void Mle::SendParentRequest(ParentRequestType aType) break; } - VerifyOrExit((message = NewMleMessage(kCommandParentRequest)) != nullptr, error = kErrorNoBufs); - SuccessOrExit(error = message->AppendModeTlv(mDeviceMode)); + VerifyOrExit((message = Get().NewMleMessage(kCommandParentRequest)) != nullptr, error = kErrorNoBufs); + SuccessOrExit(error = message->AppendModeTlv(Get().mDeviceMode)); SuccessOrExit(error = message->AppendChallengeTlv(mParentRequestChallenge)); SuccessOrExit(error = message->AppendScanMaskTlv(scanMask)); SuccessOrExit(error = message->AppendVersionTlv()); @@ -1579,7 +1535,7 @@ void Mle::SendParentRequest(ParentRequestType aType) VerifyOrExit(messageToCurParent != nullptr, error = kErrorNoBufs); - destination.SetToLinkLocalAddress(mParent.GetExtAddress()); + destination.SetToLinkLocalAddress(Get().mParent.GetExtAddress()); error = messageToCurParent->SendTo(destination); if (error != kErrorNone) @@ -1590,7 +1546,7 @@ void Mle::SendParentRequest(ParentRequestType aType) Log(kMessageSend, kTypeParentRequestToRouters, destination); - destination.SetToLinkLocalAddress(mParentSearch.GetSelectedParent().GetExtAddress()); + destination.SetToLinkLocalAddress(Get().mParentSearch.GetSelectedParent().GetExtAddress()); } else #endif @@ -1616,22 +1572,22 @@ exit: FreeMessageOnError(message, error); } -void Mle::HandleChildIdRequestTxDone(const otMessage *aMessage, otError aError, void *aContext) +void Mle::Attacher::HandleChildIdRequestTxDone(const otMessage *aMessage, otError aError, void *aContext) { OT_UNUSED_VARIABLE(aError); - static_cast(aContext)->HandleChildIdRequestTxDone(AsCoreType(aMessage)); + static_cast(aContext)->HandleChildIdRequestTxDone(AsCoreType(aMessage)); } -void Mle::HandleChildIdRequestTxDone(const Message &aMessage) +void Mle::Attacher::HandleChildIdRequestTxDone(const Message &aMessage) { - if (aMessage.GetTxSuccess() && !IsRxOnWhenIdle()) + if (aMessage.GetTxSuccess() && !Get().IsRxOnWhenIdle()) { Get().SetAttachMode(true); Get().SetRxOnWhenIdle(false); } - if (aMessage.IsLinkSecurityEnabled() && (mAttachState == kAttachStateChildIdRequest)) + if (aMessage.IsLinkSecurityEnabled() && (mState == kStateChildIdRequest)) { // If the Child ID Request requires fragmentation and therefore // link layer security, the frame transmission will be aborted. @@ -1646,7 +1602,7 @@ void Mle::HandleChildIdRequestTxDone(const Message &aMessage) } } -Error Mle::SendChildIdRequest(void) +Error Mle::Attacher::SendChildIdRequest(void) { static const uint8_t kTlvs[] = {Tlv::kAddress16, Tlv::kNetworkData, Tlv::kRoute}; @@ -1655,9 +1611,9 @@ Error Mle::SendChildIdRequest(void) TxMessage *message = nullptr; Ip6::Address destination; - if (mParent.GetExtAddress() == mParentCandidate.GetExtAddress()) + if (Get().mParent.GetExtAddress() == mParentCandidate.GetExtAddress()) { - if (IsChild()) + if (Get().IsChild()) { LogInfo("Already attached to candidate parent"); ExitNow(error = kErrorAlready); @@ -1673,19 +1629,19 @@ Error Mle::SendChildIdRequest(void) // `FindNeighbor()` returns `mParentCandidate` when // processing the Child ID Response. - mParent.SetState(Neighbor::kStateInvalid); + Get().mParent.SetState(Neighbor::kStateInvalid); } } - VerifyOrExit((message = NewMleMessage(kCommandChildIdRequest)) != nullptr, error = kErrorNoBufs); + VerifyOrExit((message = Get().NewMleMessage(kCommandChildIdRequest)) != nullptr, error = kErrorNoBufs); SuccessOrExit(error = message->AppendResponseTlv(mParentCandidate.mRxChallenge)); SuccessOrExit(error = message->AppendLinkAndMleFrameCounterTlvs()); - SuccessOrExit(error = message->AppendModeTlv(mDeviceMode)); - SuccessOrExit(error = message->AppendTimeoutTlv(mTimeout)); + SuccessOrExit(error = message->AppendModeTlv(Get().mDeviceMode)); + SuccessOrExit(error = message->AppendTimeoutTlv(Get().mTimeout)); SuccessOrExit(error = message->AppendVersionTlv()); SuccessOrExit(error = message->AppendSupervisionIntervalTlvIfSleepyChild()); - if (!IsFullThreadDevice()) + if (!Get().IsFullThreadDevice()) { SuccessOrExit(error = message->AppendAddressRegistrationTlv(mAddressRegistrationMode)); @@ -2011,7 +1967,7 @@ exit: FreeMessageOnError(message, error); } -Error Mle::GetNextAnnounceChannel(uint8_t &aChannel) const +Error Mle::Attacher::GetNextAnnounceChannel(uint8_t &aChannel) const { // This method gets the next channel to send announce on after // `aChannel`. Returns `kErrorNotFound` if no more channel in the @@ -2027,7 +1983,7 @@ Error Mle::GetNextAnnounceChannel(uint8_t &aChannel) const return channelMask.GetNextChannel(aChannel); } -bool Mle::HasMoreChannelsToAnnounce(void) const +bool Mle::Attacher::HasMoreChannelsToAnnounce(void) const { uint8_t channel = mAnnounceChannel; @@ -2351,11 +2307,11 @@ void Mle::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageIn break; case kCommandParentResponse: - HandleParentResponse(rxInfo); + mAttacher.HandleParentResponse(rxInfo); break; case kCommandChildIdResponse: - HandleChildIdResponse(rxInfo); + mAttacher.HandleChildIdResponse(rxInfo); break; case kCommandAnnounce: @@ -2813,11 +2769,11 @@ exit: return error; } -bool Mle::IsBetterParent(uint16_t aRloc16, - uint8_t aTwoWayLinkMargin, - const ConnectivityTlv &aConnectivityTlv, - uint16_t aVersion, - const Mac::CslAccuracy &aCslAccuracy) +bool Mle::Attacher::IsBetterParent(uint16_t aRloc16, + uint8_t aTwoWayLinkMargin, + const ConnectivityTlv &aConnectivityTlv, + uint16_t aVersion, + const Mac::CslAccuracy &aCslAccuracy) { int rval; @@ -2855,10 +2811,10 @@ bool Mle::IsBetterParent(uint16_t aRloc16, #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE // CSL metric - if (!IsRxOnWhenIdle()) + if (!Get().IsRxOnWhenIdle()) { - uint64_t cslMetric = CalcParentCslMetric(aCslAccuracy); - uint64_t candidateCslMetric = CalcParentCslMetric(mParentCandidate.GetCslAccuracy()); + uint64_t cslMetric = Get().CalcParentCslMetric(aCslAccuracy); + uint64_t candidateCslMetric = Get().CalcParentCslMetric(mParentCandidate.GetCslAccuracy()); // Smaller metric is better. rval = ThreeWayCompare(candidateCslMetric, cslMetric); @@ -2874,7 +2830,7 @@ exit: return (rval > 0); } -void Mle::HandleParentResponse(RxInfo &aRxInfo) +void Mle::Attacher::HandleParentResponse(RxInfo &aRxInfo) { Error error = kErrorNone; int8_t rss = aRxInfo.mMessage.GetAverageRss(); @@ -2902,7 +2858,7 @@ void Mle::HandleParentResponse(RxInfo &aRxInfo) extAddress.SetFromIid(aRxInfo.mMessageInfo.GetPeerAddr().GetIid()); - if (IsChild() && mParent.GetExtAddress() == extAddress) + if (Get().IsChild() && Get().mParent.GetExtAddress() == extAddress) { mReceivedResponseFromParent = true; } @@ -2942,7 +2898,7 @@ void Mle::HandleParentResponse(RxInfo &aRxInfo) parentinfo.mLinkQuality3 = connectivityTlv.GetLinkQuality3(); parentinfo.mLinkQuality2 = connectivityTlv.GetLinkQuality2(); parentinfo.mLinkQuality1 = connectivityTlv.GetLinkQuality1(); - parentinfo.mIsAttached = IsAttached(); + parentinfo.mIsAttached = Get().IsAttached(); mParentResponseCallback.Invoke(&parentinfo); } @@ -2951,14 +2907,14 @@ void Mle::HandleParentResponse(RxInfo &aRxInfo) aRxInfo.mClass = RxInfo::kAuthoritativeMessage; #if OPENTHREAD_FTD - if (IsFullThreadDevice() && !IsDetached()) + if (Get().IsFullThreadDevice() && !Get().IsDetached()) { - bool isPartitionIdSame = (leaderData.GetPartitionId() == mLeaderData.GetPartitionId()); + bool isPartitionIdSame = (leaderData.GetPartitionId() == Get().mLeaderData.GetPartitionId()); bool isIdSequenceSame = (connectivityTlv.GetIdSequence() == Get().GetRouterIdSequence()); bool isIdSequenceGreater = SerialNumber::IsGreater(connectivityTlv.GetIdSequence(), Get().GetRouterIdSequence()); - switch (mAttachMode) + switch (mMode) { case kAnyPartition: VerifyOrExit(!isPartitionIdSame || isIdSequenceGreater); @@ -2975,8 +2931,8 @@ void Mle::HandleParentResponse(RxInfo &aRxInfo) case kBetterPartition: VerifyOrExit(!isPartitionIdSame); - VerifyOrExit(Mle::ComparePartitions(connectivityTlv.IsSingleton(), leaderData, IsSingleton(), mLeaderData) > - 0); + VerifyOrExit(ComparePartitions(connectivityTlv.IsSingleton(), leaderData, Get().IsSingleton(), + Get().mLeaderData) > 0); break; case kBetterParent: @@ -2996,10 +2952,10 @@ void Mle::HandleParentResponse(RxInfo &aRxInfo) int compare = 0; #if OPENTHREAD_FTD - if (IsFullThreadDevice()) + if (Get().IsFullThreadDevice()) { - compare = Mle::ComparePartitions(connectivityTlv.IsSingleton(), leaderData, mParentCandidate.mIsSingleton, - mParentCandidate.mLeaderData); + compare = ComparePartitions(connectivityTlv.IsSingleton(), leaderData, mParentCandidate.mIsSingleton, + mParentCandidate.mLeaderData); } // Only consider partitions that are the same or better @@ -3037,7 +2993,7 @@ void Mle::HandleParentResponse(RxInfo &aRxInfo) SuccessOrExit(error = aRxInfo.mMessage.ReadChallengeTlv(mParentCandidate.mRxChallenge)); - InitNeighbor(mParentCandidate, aRxInfo); + Get().InitNeighbor(mParentCandidate, aRxInfo); mParentCandidate.SetRloc16(sourceAddress); mParentCandidate.GetLinkFrameCounters().SetAll(linkFrameCounter); mParentCandidate.SetLinkAckFrameCounter(linkFrameCounter); @@ -3067,7 +3023,7 @@ exit: LogProcessError(kTypeParentResponse, error); } -void Mle::HandleChildIdResponse(RxInfo &aRxInfo) +void Mle::Attacher::HandleChildIdResponse(RxInfo &aRxInfo) { Error error = kErrorNone; LeaderData leaderData; @@ -3081,7 +3037,7 @@ void Mle::HandleChildIdResponse(RxInfo &aRxInfo) VerifyOrExit(aRxInfo.IsNeighborStateValid(), error = kErrorSecurity); - VerifyOrExit(mAttachState == kAttachStateChildIdRequest); + VerifyOrExit(mState == kStateChildIdRequest); SuccessOrExit(error = Tlv::Find(aRxInfo.mMessage, shortAddress)); VerifyOrExit(RouterIdMatch(sourceAddress, shortAddress), error = kErrorRejected); @@ -3106,7 +3062,7 @@ void Mle::HandleChildIdResponse(RxInfo &aRxInfo) } // Clear Pending Dataset if device succeed to reattach using stored Pending Dataset - if (mReattachState == kReattachPending) + if (mReattachMode == kReattachModePending) { Get().Clear(); } @@ -3134,28 +3090,28 @@ void Mle::HandleChildIdResponse(RxInfo &aRxInfo) // Parent Attach Success - SetStateDetached(); + Get().SetStateDetached(); - SetLeaderData(leaderData); + Get().SetLeaderData(leaderData); #if OPENTHREAD_FTD - SuccessOrExit(error = ReadAndProcessRouteTlvOnFtdChild(aRxInfo, RouterIdFromRloc16(sourceAddress))); + SuccessOrExit(error = Get().ReadAndProcessRouteTlvOnFtdChild(aRxInfo, RouterIdFromRloc16(sourceAddress))); #endif - mParentCandidate.CopyTo(mParent); + mParentCandidate.CopyTo(Get().mParent); mParentCandidate.Clear(); #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE - Get().SetCslParentAccuracy(mParent.GetCslAccuracy()); + Get().SetCslParentAccuracy(Get().mParent.GetCslAccuracy()); #endif - mParent.SetRloc16(sourceAddress); + Get().mParent.SetRloc16(sourceAddress); IgnoreError(aRxInfo.mMessage.ReadAndSetNetworkDataTlv(leaderData)); - SetStateChild(shortAddress); + Get().SetStateChild(shortAddress); - if (!IsRxOnWhenIdle()) + if (!Get().IsRxOnWhenIdle()) { Get().SetAttachMode(false); Get().SetRxOnWhenIdle(false); @@ -3654,7 +3610,7 @@ void Mle::ParentSearch::HandleTimer(void) } Get().mCounters.mBetterParentAttachAttempts++; - Get().Attach(attachMode); + Get().mAttacher.Attach(attachMode); exit: StartTimer(); @@ -3978,7 +3934,7 @@ const char *Mle::MessageTypeActionToSuffixString(MessageType aType, MessageActio #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_NOTE) -const char *Mle::AttachModeToString(AttachMode aMode) +const char *Mle::Attacher::AttachModeToString(AttachMode aMode) { static const char *const kAttachModeStrings[] = { "AnyPartition", // (0) kAnyPartition @@ -4003,46 +3959,46 @@ const char *Mle::AttachModeToString(AttachMode aMode) return kAttachModeStrings[aMode]; } -const char *Mle::AttachStateToString(AttachState aState) +const char *Mle::Attacher::StateToString(State aState) { - static const char *const kAttachStateStrings[] = { - "Idle", // (0) kAttachStateIdle - "Start", // (1) kAttachStateStart - "ParentReq", // (2) kAttachStateParent - "Announce", // (3) kAttachStateAnnounce - "ChildIdReq", // (4) kAttachStateChildIdRequest + static const char *const kStateStrings[] = { + "Idle", // (0) kStateIdle + "Start", // (1) kStateStart + "ParentReq", // (2) kStateParent + "Announce", // (3) kStateAnnounce + "ChildIdReq", // (4) kStateChildIdRequest }; struct EnumCheck { InitEnumValidatorCounter(); - ValidateNextEnum(kAttachStateIdle); - ValidateNextEnum(kAttachStateStart); - ValidateNextEnum(kAttachStateParentRequest); - ValidateNextEnum(kAttachStateAnnounce); - ValidateNextEnum(kAttachStateChildIdRequest); + ValidateNextEnum(kStateIdle); + ValidateNextEnum(kStateStart); + ValidateNextEnum(kStateParentRequest); + ValidateNextEnum(kStateAnnounce); + ValidateNextEnum(kStateChildIdRequest); }; - return kAttachStateStrings[aState]; + return kStateStrings[aState]; } -const char *Mle::ReattachStateToString(ReattachState aState) +const char *Mle::Attacher::ReattachModeToString(ReattachMode aMode) { - static const char *const kReattachStateStrings[] = { - "", // (0) kReattachStop - "reattaching with Active Dataset", // (1) kReattachActive - "reattaching with Pending Dataset", // (2) kReattachPending + static const char *const kReattachModeStrings[] = { + "", // (0) kReattachModeStop + "reattaching with Active Dataset", // (1) kReattachModeActive + "reattaching with Pending Dataset", // (2) kReattachModePending }; struct EnumCheck { InitEnumValidatorCounter(); - ValidateNextEnum(kReattachStop); - ValidateNextEnum(kReattachActive); - ValidateNextEnum(kReattachPending); + ValidateNextEnum(kReattachModeStop); + ValidateNextEnum(kReattachModeActive); + ValidateNextEnum(kReattachModePending); }; - return kReattachStateStrings[aState]; + return kReattachModeStrings[aMode]; } #endif // OT_SHOULD_LOG_AT( OT_LOG_LEVEL_NOTE) @@ -5352,6 +5308,80 @@ void Mle::PrevRoleRestorer::SendMulticastLinkRequest(void) #endif // OPENTHREAD_FTD +//--------------------------------------------------------------------------------------------------------------------- +// Attacher + +Mle::Attacher::Attacher(Instance &aInstance) + : InstanceLocator(aInstance) + , mReceivedResponseFromParent(false) + , mState(kStateIdle) + , mMode(kAnyPartition) + , mReattachMode(kReattachModeStop) + , mAddressRegistrationMode(kAppendAllAddresses) + , mParentRequestCounter(0) + , mAnnounceChannel(0) + , mAttachCounter(0) + , mAnnounceDelay(kAnnounceTimeout) + , mTimer(aInstance) +{ + mParentCandidate.Init(aInstance); + mParentCandidate.Clear(); +} + +void Mle::Attacher::Start(StartMode aMode) +{ + mAttachCounter = 0; + + switch (aMode) + { + case kNormalAttach: + mReattachMode = + (Get().Restore() == kErrorNone) ? kReattachModeActive : kReattachModeStop; + + if (Get().mPrevRoleRestorer.Start() == kErrorNone) + { + ExitNow(); + } + + break; + + case kAnnounceAttach: + break; + } + + Get().mAttacher.Attach(kAnyPartition); + +exit: + return; +} + +void Mle::Attacher::CancelAttachOnRoleChange(void) +{ + SetState(kStateIdle); + mTimer.Stop(); + + if (Get().IsChild()) + { + mTimer.Start(kAttachBackoffDelayToResetCounter); + mReattachMode = kReattachModeStop; + + if (mAddressRegistrationMode == kAppendMeshLocalOnly) + { + // If only mesh-local address was registered in the "Child + // ID Request" message, after device is attached, trigger a + // "Child Update Request" to register the remaining + // addresses. + + mAddressRegistrationMode = kAppendAllAddresses; + Get().ScheduleChildUpdateRequestIfMtdChild(); + } + } + else if (Get().IsRouterOrLeader()) + { + mAttachCounter = 0; + } +} + //--------------------------------------------------------------------------------------------------------------------- // Detacher diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index b1e21b017..16ead4937 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -233,7 +233,7 @@ public: * @retval TRUE Device is currently trying to attach. * @retval FALSE Device is not in middle of attach process. */ - bool IsAttaching(void) const { return (mAttachState != kAttachStateIdle); } + bool IsAttaching(void) const { return mAttacher.IsAttaching(); } /** * Returns the current Thread device role. @@ -432,7 +432,7 @@ public: * * The parent candidate is valid when attempting to attach to a new parent. */ - Parent &GetParentCandidate(void) { return mParentCandidate; } + Parent &GetParentCandidate(void) { return mAttacher.GetParentCandidate(); } /** * Starts the process for child to search for a better parent while staying attached to its current @@ -628,7 +628,7 @@ public: */ void RegisterParentResponseStatsCallback(otThreadParentResponseCallback aCallback, void *aContext) { - mParentResponseCallback.Set(aCallback, aContext); + mAttacher.mParentResponseCallback.Set(aCallback, aContext); } #endif @@ -1779,6 +1779,90 @@ private: //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + void HandleAttacherTimer(void) { mAttacher.HandleTimer(); } + + class Attacher : public InstanceLocator + { + public: + explicit Attacher(Instance &aInstance); + + bool IsAttaching(void) const { return mState != kStateIdle; } + bool WillStartAttachSoon(void) const { return mState == kStateStart; } + bool IsReattachWithDatasetDone(void) const { return mReattachMode == kReattachModeStop; } + void Start(StartMode aMode); + void Attach(AttachMode aMode); + void CancelAttachOnRoleChange(void); + void ResetAttachCounter(void) { mAttachCounter = 0; } + AttachMode GetAttachMode(void) const { return mMode; } + ParentCandidate &GetParentCandidate(void) { return mParentCandidate; } + void ClearParentCandidate(void) { mParentCandidate.Clear(); } + void HandleParentResponse(RxInfo &aRxInfo); + void HandleChildIdResponse(RxInfo &aRxInfo); + void HandleTimer(void); + +#if OPENTHREAD_CONFIG_MLE_PARENT_RESPONSE_CALLBACK_API_ENABLE + Callback mParentResponseCallback; +#endif + private: + enum State : uint8_t + { + kStateIdle, // Not currently searching for a parent. + kStateStart, // Starting to look for a parent. + kStateParentRequest, // Send Parent Request (current number tracked by `mParentRequestCounter`). + kStateAnnounce, // Send Announce messages + kStateChildIdRequest, // Sending a Child ID Request message. + }; + + enum ReattachMode : uint8_t + { + kReattachModeStop, // Reattach process is disabled or finished + kReattachModeActive, // Reattach using stored Active Dataset + kReattachModePending, // Reattach using stored Pending Dataset + }; + + void SetState(State aState); + uint32_t GetStartDelay(void) const; + bool HasAcceptableParentCandidate(void) const; + uint32_t Reattach(void); + + Error DetermineParentRequestType(ParentRequestType &aType) const; + Error GetNextAnnounceChannel(uint8_t &aChannel) const; + bool HasMoreChannelsToAnnounce(void) const; + void SendParentRequest(ParentRequestType aType); + Error SendChildIdRequest(void); + void HandleChildIdRequestTxDone(const Message &aMessage); + bool PrepareAnnounceState(void); + bool IsBetterParent(uint16_t aRloc16, + uint8_t aTwoWayLinkMargin, + const ConnectivityTlv &aConnectivityTlv, + uint16_t aVersion, + const Mac::CslAccuracy &aCslAccuracy); + + static void HandleChildIdRequestTxDone(const otMessage *aMessage, otError aError, void *aContext); + + static const char *StateToString(State aState); +#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_NOTE) + static const char *AttachModeToString(AttachMode aMode); + static const char *ReattachModeToString(ReattachMode aMode); +#endif + using AttachTimer = TimerMilliIn; + + bool mReceivedResponseFromParent : 1; + State mState; + AttachMode mMode; + ReattachMode mReattachMode; + AddressRegistrationMode mAddressRegistrationMode; + uint8_t mParentRequestCounter; + uint8_t mAnnounceChannel; + uint16_t mAttachCounter; + uint16_t mAnnounceDelay; + TxChallenge mParentRequestChallenge; + ParentCandidate mParentCandidate; + AttachTimer mTimer; + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + void HandleDetacherTimer(void) { mDetacher.HandleTimer(); } class Detacher : public InstanceLocator @@ -2016,10 +2100,7 @@ private: Error RestorePrevRole(void); TxMessage *NewMleMessage(Command aCommand); void SetRole(DeviceRole aRole); - void Attach(AttachMode aMode); - void SetAttachState(AttachState aState); void InitNeighbor(Neighbor &aNeighbor, const RxInfo &aRxInfo); - void ClearParentCandidate(void) { mParentCandidate.Clear(); } Error SendDataRequestToParent(void); Error SendDataRequest(const Ip6::Address &aDestination); void HandleNotifierEvents(Events aEvents); @@ -2038,35 +2119,18 @@ private: uint32_t GenerateRandomDelay(uint32_t aMaxDelay) const; void InformPreviousChannel(void); void ScheduleMessageTransmissionTimer(void); - void HandleAttachTimer(void); void ProcessKeySequence(RxInfo &aRxInfo); void HandleAdvertisement(RxInfo &aRxInfo); - void HandleChildIdResponse(RxInfo &aRxInfo); void HandleChildUpdateRequest(RxInfo &aRxInfo); void HandleChildUpdateRequestOnChild(RxInfo &aRxInfo); void HandleChildUpdateResponse(RxInfo &aRxInfo); void HandleChildUpdateResponseOnChild(RxInfo &aRxInfo); void HandleDataResponse(RxInfo &aRxInfo); - void HandleParentResponse(RxInfo &aRxInfo); Error HandleLeaderData(RxInfo &aRxInfo); bool HasUnregisteredAddress(void); uint32_t GetAttachStartDelay(void) const; - void SendParentRequest(ParentRequestType aType); - Error SendChildIdRequest(void); - void HandleChildIdRequestTxDone(const Message &aMessage); - Error GetNextAnnounceChannel(uint8_t &aChannel) const; - bool HasMoreChannelsToAnnounce(void) const; - bool PrepareAnnounceState(void); void SendAnnounce(uint8_t aChannel, AnnounceMode aMode); void SendAnnounce(uint8_t aChannel, const Ip6::Address &aDestination, AnnounceMode aMode = kNormalAnnounce); - uint32_t Reattach(void); - bool HasAcceptableParentCandidate(void) const; - Error DetermineParentRequestType(ParentRequestType &aType) const; - bool IsBetterParent(uint16_t aRloc16, - uint8_t aTwoWayLinkMargin, - const ConnectivityTlv &aConnectivityTlv, - uint16_t aVersion, - const Mac::CslAccuracy &aCslAccuracy); bool IsNetworkDataNewer(const LeaderData &aLeaderData); Error ProcessMessageSecurity(Crypto::AesCcm::Mode aMode, Message &aMessage, @@ -2074,8 +2138,6 @@ private: uint16_t aCmdOffset, const SecurityHeader &aHeader); - static void HandleChildIdRequestTxDone(const otMessage *aMessage, otError aError, void *aContext); - #if OPENTHREAD_CONFIG_MLE_INFORM_PREVIOUS_PARENT_ON_REATTACH void InformPreviousParent(void); #endif @@ -2122,12 +2184,6 @@ private: void HandleWedAttachTimer(void); #endif -#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_NOTE) - static const char *AttachModeToString(AttachMode aMode); - static const char *AttachStateToString(AttachState aState); - static const char *ReattachStateToString(ReattachState aState); -#endif - #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN) static void LogError(MessageAction aAction, MessageType aType, Error aError); static const char *MessageActionToString(MessageAction aAction); @@ -2146,7 +2202,7 @@ private: uint8_t SelectLeaderId(void) const; uint32_t SelectPartitionId(void) const; void HandleDetachStart(void); - void HandleChildStart(AttachMode aMode); + void HandleChildStart(void); void HandleSecurityPolicyChanged(void); void HandleLinkRequest(RxInfo &aRxInfo); void HandleLinkAccept(RxInfo &aRxInfo); @@ -2219,61 +2275,43 @@ private: //------------------------------------------------------------------------------------------------------------------ // Variables - using AttachTimer = TimerMilliIn; - using MleSocket = Ip6::Udp::SocketIn; + using MleSocket = Ip6::Udp::SocketIn; #if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE using WedAttachTimer = TimerMicroIn; #endif static const otMeshLocalPrefix kMeshLocalPrefixInit; - bool mRetrieveNewNetworkData : 1; - bool mRequestRouteTlv : 1; - bool mHasRestored : 1; - bool mReceivedResponseFromParent : 1; - bool mInitiallyAttachedAsSleepy : 1; - - DeviceRole mRole; - DeviceRole mLastSavedRole; - DeviceMode mDeviceMode; - AttachState mAttachState; - ReattachState mReattachState; - AttachMode mAttachMode; - AddressRegistrationMode mAddressRegistrationMode; - - uint8_t mParentRequestCounter; - uint8_t mAnnounceChannel; - uint16_t mRloc16; - uint16_t mPreviousParentRloc; - uint16_t mAttachCounter; - uint16_t mAnnounceDelay; - uint32_t mStoreFrameCounterAhead; - uint32_t mTimeout; + bool mRetrieveNewNetworkData : 1; + bool mRequestRouteTlv : 1; + bool mHasRestored : 1; + bool mInitiallyAttachedAsSleepy : 1; + DeviceRole mRole; + DeviceRole mLastSavedRole; + DeviceMode mDeviceMode; + uint16_t mRloc16; + uint16_t mPreviousParentRloc; + uint32_t mStoreFrameCounterAhead; + uint32_t mTimeout; #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE uint32_t mCslTimeout; #endif - uint32_t mLastAttachTime; - uint64_t mLastUpdatedTimestamp; - + uint32_t mLastAttachTime; + uint64_t mLastUpdatedTimestamp; LeaderData mLeaderData; Parent mParent; NeighborTable mNeighborTable; DelayedSender mDelayedSender; - TxChallenge mParentRequestChallenge; - ParentCandidate mParentCandidate; MleSocket mSocket; Counters mCounters; PrevRoleRestorer mPrevRoleRestorer; + Attacher mAttacher; Detacher mDetacher; RetxTracker mRetxTracker; AnnounceHandler mAnnounceHandler; #if OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE ParentSearch mParentSearch; #endif -#if OPENTHREAD_CONFIG_MLE_PARENT_RESPONSE_CALLBACK_API_ENABLE - Callback mParentResponseCallback; -#endif - AttachTimer mAttachTimer; Ip6::NetworkPrefix mMeshLocalPrefix; Ip6::Netif::UnicastAddress mLinkLocalAddress; Ip6::Netif::UnicastAddress mMeshLocalEid; @@ -2297,7 +2335,6 @@ private: bool mCcmEnabled : 1; bool mThreadVersionCheckEnabled : 1; #endif - uint8_t mRouterId; uint8_t mPreviousRouterId; uint8_t mNetworkIdTimeout; @@ -2317,7 +2354,6 @@ private: #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE uint32_t mPreferredLeaderPartitionId; #endif - TrickleTimer mAdvertiseTrickleTimer; ChildTable mChildTable; RouterTable mRouterTable; diff --git a/src/core/thread/mle_ftd.cpp b/src/core/thread/mle_ftd.cpp index e7deff5d2..36b87fd7e 100644 --- a/src/core/thread/mle_ftd.cpp +++ b/src/core/thread/mle_ftd.cpp @@ -305,7 +305,7 @@ void Mle::HandleDetachStart(void) Get().UnregisterReceiver(TimeTicker::kMle); } -void Mle::HandleChildStart(AttachMode aMode) +void Mle::HandleChildStart(void) { mAddressSolicitRejected = false; @@ -323,7 +323,7 @@ void Mle::HandleChildStart(AttachMode aMode) VerifyOrExit(IsRouterIdValid(mPreviousRouterId)); - switch (aMode) + switch (mAttacher.GetAttachMode()) { case kDowngradeToReed: SendAddressRelease(); @@ -411,10 +411,8 @@ void Mle::SetStateRouterOrLeader(DeviceRole aRole, uint16_t aRloc16, LeaderStart SetRole(aRole); mPrevRoleRestorer.Stop(); + mAttacher.CancelAttachOnRoleChange(); - SetAttachState(kAttachStateIdle); - mAttachCounter = 0; - mAttachTimer.Stop(); mRetxTracker.Stop(); StopAdvertiseTrickleTimer(); ResetAdvertiseInterval(); @@ -1213,7 +1211,7 @@ Error Mle::HandleAdvertisementOnFtd(RxInfo &aRxInfo, uint16_t aSourceAddress, co #endif ) { - Attach(kBetterPartition); + mAttacher.Attach(kBetterPartition); } ExitNow(error = kErrorDrop); @@ -1590,13 +1588,13 @@ void Mle::HandleTimeTick(void) if ((mRouterTable.GetActiveRouterCount() > 0) && (mRouterTable.GetLeaderAge() >= mNetworkIdTimeout)) { LogInfo("Leader age timeout"); - Attach(kSamePartition); + mAttacher.Attach(kSamePartition); } if (roleTransitionTimeoutExpired && mRouterTable.GetActiveRouterCount() > mRouterDowngradeThreshold) { LogNote("Downgrade to REED"); - Attach(kDowngradeToReed); + mAttacher.Attach(kDowngradeToReed); } OT_FALL_THROUGH; @@ -3220,7 +3218,7 @@ void Mle::RemoveNeighbor(Neighbor &aNeighbor) } else if (&aNeighbor == &GetParentCandidate()) { - ClearParentCandidate(); + mAttacher.ClearParentCandidate(); } else if (IsChildRloc16(aNeighbor.GetRloc16())) {