From e4ac7162eb1c3b1543af70fda9084d2fad896892 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Tue, 3 Jun 2025 13:33:49 -0700 Subject: [PATCH] [mle] introduce `AnnounceHandler` class (#11558) This commit introduces the `AnnounceHandler` class within `Mle` to encapsulate logic for handling Announce messages. This change simplifies the `Mle` module and makes the code easier to read and follow. The `AnnounceHandler` class handles received Announce messages with a newer timestamp and different channel and/or PAN ID. It can delay processing to collect and handle subsequent Announce messages. It also manages starting the "announce attach" process, where the device attempts to attach using the parameters from a processed Announce message. - If the attach is successful, this class sends an Announce on the old channel to inform other devices. This is done immediately after attaching as a MTD child or after a router transition attempt completes (on FTD). - If the attach fails, the class ensures the channel and PAN ID are restored to their original values. In particular, the new `AnnounceHandler` uses its own `Timer` to delay the start of an announce attach. Previously, the `AttachTimer` was repurposed for this, in addition to its use for attach state management. --- src/core/thread/mle.cpp | 118 ++++++++++++++++++++++++------------ src/core/thread/mle.hpp | 75 +++++++++++++++++++---- src/core/thread/mle_ftd.cpp | 6 +- 3 files changed, 145 insertions(+), 54 deletions(-) diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index c98343c6a..00dbaa559 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -67,21 +67,19 @@ Mle::Mle(Instance &aInstance) , mChildUpdateAttempts(0) , mDataRequestAttempts(0) , mAnnounceChannel(0) - , mAlternateChannel(0) , mRloc16(kInvalidRloc16) , mPreviousParentRloc(kInvalidRloc16) , mAttachCounter(0) , mAnnounceDelay(kAnnounceTimeout) - , mAlternatePanId(Mac::kPanIdBroadcast) , mStoreFrameCounterAhead(kDefaultStoreFrameCounterAhead) , mTimeout(kDefaultChildTimeout) #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE , mCslTimeout(kDefaultCslTimeout) #endif - , mAlternateTimestamp(0) , mNeighborTable(aInstance) , mDelayedSender(aInstance) , mSocket(aInstance, *this) + , mAnnounceHandler(aInstance) #if OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE , mParentSearch(aInstance) #endif @@ -270,6 +268,7 @@ void Mle::Stop(StopMode aMode) VerifyOrExit(!IsDisabled()); mDelayedSender.Stop(); + mAnnounceHandler.Stop(); Get().Stop(); SetStateDetached(); Get().UnsubscribeMulticast(mRealmLocalAllThreadNodes); @@ -793,8 +792,10 @@ void Mle::SetStateChild(uint16_t aRloc16) } #endif - // send announce after attached if needed - InformPreviousChannel(); + if (mAnnounceHandler.IsAnnounceAttaching()) + { + mAnnounceHandler.HandleAnnounceAttachSuccess(); + } #if OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE mParentSearch.UpdateState(); @@ -812,16 +813,31 @@ void Mle::SetStateChild(uint16_t aRloc16) mPreviousParentRloc = mParent.GetRloc16(); } -void Mle::InformPreviousChannel(void) +void Mle::AnnounceHandler::HandleAnnounceAttachSuccess(void) { - VerifyOrExit(mAlternatePanId != Mac::kPanIdBroadcast); - VerifyOrExit(IsChild() || IsRouter()); + // Clear state and send announce on previous channel. + + VerifyOrExit(mState == kStateAnnounceAttaching); + mState = kStateToInformPreviousChannel; #if OPENTHREAD_FTD - VerifyOrExit(!IsFullThreadDevice() || IsRouter() || !IsRouterRoleTransitionPending()); + if (Get().IsFullThreadDevice() && !Get().IsRouter() && Get().IsRouterRoleTransitionPending()) + { + ExitNow(); + } #endif - mAlternatePanId = Mac::kPanIdBroadcast; + InformPreviousChannel(); + +exit: + return; +} + +void Mle::AnnounceHandler::InformPreviousChannel(void) +{ + VerifyOrExit(mState == kStateToInformPreviousChannel); + + mState = kStateIdle; Get().SendAnnounce(1 << mAlternateChannel); exit: @@ -1504,10 +1520,6 @@ void Mle::HandleAttachTimer(void) mAttachCounter = 0; break; - case kAttachStateProcessAnnounce: - ProcessAnnounce(); - break; - case kAttachStateStart: LogNote("Attach attempt %d, %s %s", mAttachCounter, AttachModeToString(mAttachMode), ReattachStateToString(mReattachState)); @@ -1640,11 +1652,9 @@ uint32_t Mle::Reattach(void) case kSelectedParent: if (!IsChild()) { - if (mAlternatePanId != Mac::kPanIdBroadcast) + if (mAnnounceHandler.IsAnnounceAttaching()) { - IgnoreError(Get().SetPanChannel(mAlternateChannel)); - Get().SetPanId(mAlternatePanId); - mAlternatePanId = Mac::kPanIdBroadcast; + mAnnounceHandler.HandleAnnounceAttachFailure(); IgnoreError(BecomeDetached()); } #if OPENTHREAD_FTD @@ -2559,7 +2569,7 @@ void Mle::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageIn break; case kCommandAnnounce: - HandleAnnounce(rxInfo); + mAnnounceHandler.HandleAnnounce(rxInfo); break; case kCommandChildUpdateRequest: @@ -3678,7 +3688,7 @@ exit: LogProcessError(kTypeChildUpdateResponseAsChild, error); } -void Mle::HandleAnnounce(RxInfo &aRxInfo) +void Mle::AnnounceHandler::HandleAnnounce(RxInfo &aRxInfo) { Error error = kErrorNone; ChannelTlvValue channelTlvValue; @@ -3711,10 +3721,10 @@ void Mle::HandleAnnounce(RxInfo &aRxInfo) VerifyOrExit(!channelAndPanIdMatch); } - SendAnnounce(channel); + Get().SendAnnounce(channel); #if OPENTHREAD_CONFIG_MLE_SEND_UNICAST_ANNOUNCE_RESPONSE - SendAnnounce(channel, aRxInfo.mMessageInfo.GetPeerAddr()); + Get().SendAnnounce(channel, aRxInfo.mMessageInfo.GetPeerAddr()); #endif } else if (timestampCompare > 0) @@ -3723,7 +3733,7 @@ void Mle::HandleAnnounce(RxInfo &aRxInfo) // channel and pan-id match the values from the received MLE // Announce message. - if (IsDetached()) + if (Get().IsDetached()) { VerifyOrExit(!channelAndPanIdMatch); } @@ -3746,7 +3756,7 @@ void Mle::HandleAnnounce(RxInfo &aRxInfo) } } - if (mAttachState == kAttachStateProcessAnnounce) + if (mState == kStateToAnnounceAttach) { VerifyOrExit(mAlternateTimestamp < timestamp.GetSeconds()); } @@ -3754,9 +3764,8 @@ void Mle::HandleAnnounce(RxInfo &aRxInfo) mAlternateTimestamp = timestamp.GetSeconds(); mAlternateChannel = channel; mAlternatePanId = panId; - SetAttachState(kAttachStateProcessAnnounce); - mAttachTimer.Start(kAnnounceProcessTimeout); - mAttachCounter = 0; + mState = kStateToAnnounceAttach; + mTimer.Start(kAnnounceProcessTimeout); LogNote("Delay processing Announce - channel %d, panid 0x%02x", channel, panId); } @@ -3854,16 +3863,16 @@ exit: } #endif -void Mle::ProcessAnnounce(void) +void Mle::AnnounceHandler::StartAnnounceAttach(void) { uint8_t newChannel = mAlternateChannel; uint16_t newPanId = mAlternatePanId; - OT_ASSERT(mAttachState == kAttachStateProcessAnnounce); + VerifyOrExit(mState == kStateToAnnounceAttach); - LogNote("Processing Announce - channel %d, panid 0x%02x", newChannel, newPanId); + LogNote("Starting Announce attach - channel %d, panid 0x%02x", newChannel, newPanId); - Stop(kKeepNetworkDatasets); + Get().Stop(kKeepNetworkDatasets); // Save the current/previous channel and pan-id mAlternateChannel = Get().GetPanChannel(); @@ -3873,7 +3882,11 @@ void Mle::ProcessAnnounce(void) IgnoreError(Get().SetPanChannel(newChannel)); Get().SetPanId(newPanId); - IgnoreError(Start(kAnnounceAttach)); + mState = kStateAnnounceAttaching; + IgnoreError(Get().Start(kAnnounceAttach)); + +exit: + return; } uint16_t Mle::GetParentRloc16(void) const { return (mParent.IsStateValid() ? mParent.GetRloc16() : kInvalidRloc16); } @@ -4341,19 +4354,17 @@ const char *Mle::AttachModeToString(AttachMode aMode) const char *Mle::AttachStateToString(AttachState aState) { static const char *const kAttachStateStrings[] = { - "Idle", // (0) kAttachStateIdle - "ProcessAnnounce", // (1) kAttachStateProcessAnnounce - "Start", // (2) kAttachStateStart - "ParentReq", // (3) kAttachStateParent - "Announce", // (4) kAttachStateAnnounce - "ChildIdReq", // (5) kAttachStateChildIdRequest + "Idle", // (0) kAttachStateIdle + "Start", // (1) kAttachStateStart + "ParentReq", // (2) kAttachStateParent + "Announce", // (3) kAttachStateAnnounce + "ChildIdReq", // (4) kAttachStateChildIdRequest }; struct EnumCheck { InitEnumValidatorCounter(); ValidateNextEnum(kAttachStateIdle); - ValidateNextEnum(kAttachStateProcessAnnounce); ValidateNextEnum(kAttachStateStart); ValidateNextEnum(kAttachStateParentRequest); ValidateNextEnum(kAttachStateAnnounce); @@ -5594,5 +5605,34 @@ void Mle::ParentCandidate::CopyTo(Parent &aParent) const aParent = *candidateAsParent; } +//--------------------------------------------------------------------------------------------------------------------- +// AnnounceHanlder + +Mle::AnnounceHandler::AnnounceHandler(Instance &aInstance) + : InstanceLocator(aInstance) + , mState(kStateIdle) + , mTimer(aInstance) +{ +} + +void Mle::AnnounceHandler::Stop(void) +{ + mTimer.Stop(); + mState = kStateIdle; +} + +void Mle::AnnounceHandler::HandleAnnounceAttachFailure(void) +{ + VerifyOrExit(mState == kStateAnnounceAttaching); + mState = kStateIdle; + IgnoreError(Get().SetPanChannel(mAlternateChannel)); + Get().SetPanId(mAlternatePanId); + +exit: + return; +} + +void Mle::AnnounceHandler::HandleTimer(void) { StartAnnounceAttach(); } + } // namespace Mle } // namespace ot diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index cb2fb9756..f8168e9c2 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -1318,12 +1318,11 @@ private: enum AttachState : uint8_t { - kAttachStateIdle, // Not currently searching for a parent. - kAttachStateProcessAnnounce, // Waiting to process a received Announce (to switch channel/pan-id). - kAttachStateStart, // Starting to look for a parent. - kAttachStateParentRequest, // Send Parent Request (current number tracked by `mParentRequestCounter`). - kAttachStateAnnounce, // Send Announce messages - kAttachStateChildIdRequest, // Sending a Child ID Request message. + kAttachStateIdle, // Not currently searching for a parent. + kAttachStateStart, // Starting to look for a parent. + kAttachStateParentRequest, // Send Parent Request (current number tracked by `mParentRequestCounter`). + kAttachStateAnnounce, // Send Announce messages + kAttachStateChildIdRequest, // Sending a Child ID Request message. }; enum ReattachState : uint8_t @@ -1733,6 +1732,63 @@ private: //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + void HandleAnnounceHandlerTimer(void) { mAnnounceHandler.HandleTimer(); } + + class AnnounceHandler : public InstanceLocator + { + // Handles received Announce messages with a newer timestamp on + // a different channel and/or PAN ID. It may delay processing + // to collect and handle subsequent Announce messages. + // + // This class also manages an 'announce attach' process, where + // the device tries to attach using the parameters (channel and + // PAN ID) from a processed Announce message. + // + // If the 'announce attach' is successful, this class handles + // sending an Announce on the old channel to inform other + // devices. This is done immediately after attaching as a child + // or after an attempt to transition to the router role is + // complete (whether successful or not). + // + // If the 'announce attach' fails, the class ensures the channel + // and PAN ID are restored to their original values. + + public: + explicit AnnounceHandler(Instance &aInstance); + + void Stop(void); + void HandleAnnounce(RxInfo &aRxInfo); + bool IsAnnounceAttaching(void) const { return mState == kStateAnnounceAttaching; } + void HandleAnnounceAttachSuccess(void); + void HandleAnnounceAttachFailure(void); +#if OPENTHREAD_FTD + void HandleRouterRoleTransitionAttemptDone(void) { InformPreviousChannel(); } +#endif + void HandleTimer(void); + + private: + enum State : uint8_t + { + kStateIdle, + kStateToAnnounceAttach, + kStateAnnounceAttaching, + kStateToInformPreviousChannel, + }; + + void StartAnnounceAttach(void); + void InformPreviousChannel(void); + + using AnnouceTimer = TimerMilliIn; + + State mState; + uint8_t mAlternateChannel; + uint16_t mAlternatePanId; + uint64_t mAlternateTimestamp; + AnnouceTimer mTimer; + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + #if OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE void HandleParentSearchTimer(void) { mParentSearch.HandleTimer(); } @@ -1865,7 +1921,6 @@ private: void SetLeaderData(const LeaderData &aLeaderData); void SetTimeout(uint32_t aTimeout, TimeoutAction aAction); void InformPreviousChannel(void); - bool IsAnnounceAttach(void) const { return mAlternatePanId != Mac::kPanIdBroadcast; } void ScheduleMessageTransmissionTimer(void); void HandleAttachTimer(void); void HandleMessageTransmissionTimer(void); @@ -1878,9 +1933,7 @@ private: void HandleChildUpdateResponseOnChild(RxInfo &aRxInfo); void HandleDataResponse(RxInfo &aRxInfo); void HandleParentResponse(RxInfo &aRxInfo); - void HandleAnnounce(RxInfo &aRxInfo); Error HandleLeaderData(RxInfo &aRxInfo); - void ProcessAnnounce(void); bool HasUnregisteredAddress(void); uint32_t GetAttachStartDelay(void) const; void SendParentRequest(ParentRequestType aType); @@ -2084,12 +2137,10 @@ private: uint8_t mChildUpdateAttempts; uint8_t mDataRequestAttempts; uint8_t mAnnounceChannel; - uint8_t mAlternateChannel; uint16_t mRloc16; uint16_t mPreviousParentRloc; uint16_t mAttachCounter; uint16_t mAnnounceDelay; - uint16_t mAlternatePanId; uint32_t mStoreFrameCounterAhead; uint32_t mTimeout; #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE @@ -2097,7 +2148,6 @@ private: #endif uint32_t mLastAttachTime; uint64_t mLastUpdatedTimestamp; - uint64_t mAlternateTimestamp; LeaderData mLeaderData; Parent mParent; @@ -2107,6 +2157,7 @@ private: ParentCandidate mParentCandidate; MleSocket mSocket; Counters mCounters; + AnnounceHandler mAnnounceHandler; #if OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE ParentSearch mParentSearch; #endif diff --git a/src/core/thread/mle_ftd.cpp b/src/core/thread/mle_ftd.cpp index 7161d8c12..f0a3d9aa1 100644 --- a/src/core/thread/mle_ftd.cpp +++ b/src/core/thread/mle_ftd.cpp @@ -343,7 +343,7 @@ void Mle::HandleChildStart(AttachMode aMode) // decision to become router is determined based on the new // partition's status. - if (IsAnnounceAttach() && HasChildren()) + if (mAnnounceHandler.IsAnnounceAttaching() && HasChildren()) { RemoveChildren(); } @@ -1562,7 +1562,7 @@ void Mle::HandleTimeTick(void) } else { - InformPreviousChannel(); + mAnnounceHandler.HandleRouterRoleTransitionAttemptDone(); } if (!mAdvertiseTrickleTimer.IsRunning()) @@ -3460,7 +3460,7 @@ void Mle::HandleAddressSolicitResponse(Coap::Message *aMessage, const Ip6::Messa } exit: - InformPreviousChannel(); + mAnnounceHandler.HandleRouterRoleTransitionAttemptDone(); } Error Mle::SetChildRouterLinks(uint8_t aChildRouterLinks)