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)