diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index f21cef38a..91a73e979 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -269,7 +269,7 @@ Error MleRouter::BecomeLeader(void) Get().Reset(); Get().SetEmptyCommissionerData(); - SetStateLeader(Rloc16FromRouterId(leaderId)); + SetStateLeader(Rloc16FromRouterId(leaderId), kStartingAsLeader); exit: return error; @@ -401,7 +401,7 @@ void MleRouter::SetStateRouter(uint16_t aRloc16) } } -void MleRouter::SetStateLeader(uint16_t aRloc16) +void MleRouter::SetStateLeader(uint16_t aRloc16, LeaderStartMode aStartMode) { IgnoreError(Get().Restore()); IgnoreError(Get().Restore()); @@ -421,7 +421,7 @@ void MleRouter::SetStateLeader(uint16_t aRloc16) mPreviousPartitionIdRouter = mLeaderData.GetPartitionId(); Get().RegisterReceiver(TimeTicker::kMleRouter); - Get().Start(); + Get().Start(aStartMode); Get().StartLeader(); Get().StartLeader(); Get().AddResource(mAddressSolicit); @@ -938,7 +938,7 @@ Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest) if (mLeaderData.GetLeaderRouterId() == RouterIdFromRloc16(GetRloc16())) { - SetStateLeader(GetRloc16()); + SetStateLeader(GetRloc16(), kRestoringLeaderRoleAfterReset); } else { diff --git a/src/core/thread/mle_router.hpp b/src/core/thread/mle_router.hpp index 6493c512b..87af6de57 100644 --- a/src/core/thread/mle_router.hpp +++ b/src/core/thread/mle_router.hpp @@ -635,7 +635,7 @@ private: const Message * aRequestMessage = nullptr); Error SendDiscoveryResponse(const Ip6::Address &aDestination, const Message &aDiscoverRequestMessage); void SetStateRouter(uint16_t aRloc16); - void SetStateLeader(uint16_t aRloc16); + void SetStateLeader(uint16_t aRloc16, LeaderStartMode aStartMode); void StopLeader(void); void SynchronizeChildNetworkData(void); Error UpdateChildAddresses(const Message &aMessage, uint16_t aOffset, Child &aChild); diff --git a/src/core/thread/mle_types.hpp b/src/core/thread/mle_types.hpp index 0dfdf9348..fbc92a63e 100644 --- a/src/core/thread/mle_types.hpp +++ b/src/core/thread/mle_types.hpp @@ -218,6 +218,18 @@ constexpr uint16_t kAloc16NeighborDiscoveryAgentEnd = 0xfc4e; constexpr uint8_t kServiceMinId = 0x00; ///< Minimal Service ID. constexpr uint8_t kServiceMaxId = 0x0f; ///< Maximal Service ID. +/** + * This enumeration specifies the leader role start mode. + * + * The start mode indicates whether device is starting normally as leader or restoring its role after reset. + * + */ +enum LeaderStartMode : uint8_t +{ + kStartingAsLeader, ///< Starting as leader normally. + kRestoringLeaderRoleAfterReset, ///< Restoring leader role after reset. +}; + #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 /* diff --git a/src/core/thread/network_data_leader.cpp b/src/core/thread/network_data_leader.cpp index 8c2884201..0207c390f 100644 --- a/src/core/thread/network_data_leader.cpp +++ b/src/core/thread/network_data_leader.cpp @@ -394,10 +394,9 @@ Error LeaderBase::SetNetworkData(uint8_t aVersion, } #if OPENTHREAD_FTD - // Synchronize internal 6LoWPAN Context ID Set with recently obtained Network Data. if (Get().IsLeader()) { - Get().UpdateContextsAfterReset(); + Get().HandleNetworkDataRestoredAfterReset(); } #endif diff --git a/src/core/thread/network_data_leader_ftd.cpp b/src/core/thread/network_data_leader_ftd.cpp index 770c2413b..dac504d76 100644 --- a/src/core/thread/network_data_leader_ftd.cpp +++ b/src/core/thread/network_data_leader_ftd.cpp @@ -60,6 +60,7 @@ RegisterLogModule("NetworkData"); Leader::Leader(Instance &aInstance) : LeaderBase(aInstance) + , mWaitingForNetDataSync(false) , mTimer(aInstance, Leader::HandleTimer) , mServerData(UriPath::kServerData, &Leader::HandleServerData, this) , mCommissioningDataGet(UriPath::kCommissionerGet, &Leader::HandleCommissioningGet, this) @@ -77,8 +78,15 @@ void Leader::Reset(void) mContextIdReuseDelay = kContextIdReuseDelay; } -void Leader::Start(void) +void Leader::Start(Mle::LeaderStartMode aStartMode) { + mWaitingForNetDataSync = (aStartMode == Mle::kRestoringLeaderRoleAfterReset); + + if (mWaitingForNetDataSync) + { + mTimer.Start(kMaxNetDataSyncWait); + } + Get().AddResource(mServerData); Get().AddResource(mCommissioningDataGet); Get().AddResource(mCommissioningDataSet); @@ -146,6 +154,8 @@ void Leader::HandleServerData(Coap::Message &aMessage, const Ip6::MessageInfo &a LogInfo("Received network data registration"); + VerifyOrExit(!mWaitingForNetDataSync); + VerifyOrExit(aMessageInfo.GetPeerAddr().GetIid().IsRoutingLocator()); switch (Tlv::Find(aMessage, rloc16)) @@ -1296,11 +1306,16 @@ void Leader::RemoveContext(PrefixTlv &aPrefix, uint8_t aContextId) } } -void Leader::UpdateContextsAfterReset(void) +void Leader::HandleNetworkDataRestoredAfterReset(void) { const PrefixTlv *prefix; TlvIterator tlvIterator(GetTlvsStart(), GetTlvsEnd()); + mWaitingForNetDataSync = false; + + // Synchronize internal 6LoWPAN Context ID Set with the + // recently obtained Network Data. + while ((prefix = tlvIterator.Iterate()) != nullptr) { const ContextTlv *context = prefix->FindSubTlv(); @@ -1332,6 +1347,13 @@ void Leader::HandleTimer(void) { bool contextsWaiting = false; + if (mWaitingForNetDataSync) + { + LogInfo("Timed out waiting for netdata on restoring leader role after reset"); + IgnoreError(Get().BecomeDetached()); + ExitNow(); + } + for (uint8_t i = 0; i < kNumContextIds; i++) { if (mContextLastUsed[i].GetValue() == 0) @@ -1353,6 +1375,9 @@ void Leader::HandleTimer(void) { mTimer.Start(kStateUpdatePeriod); } + +exit: + return; } Error Leader::RemoveStaleChildEntries(Coap::ResponseHandler aHandler, void *aContext) diff --git a/src/core/thread/network_data_leader_ftd.hpp b/src/core/thread/network_data_leader_ftd.hpp index c1f57644d..1ca969f67 100644 --- a/src/core/thread/network_data_leader_ftd.hpp +++ b/src/core/thread/network_data_leader_ftd.hpp @@ -95,8 +95,15 @@ public: /** * This method starts the Leader services. * + * The start mode indicates whether device is starting normally as leader or restoring its role as leader after + * reset. In the latter case, we do not accept any new registrations (`HandleServerData()`) and wait for + * `HandleNetworkDataRestoredAfterReset()` to indicate that the leader has successfully recovered the Network Data + * before allowing new Network Data registrations. + * + * @param[in] aStartMode The start mode. + * */ - void Start(void); + void Start(Mle::LeaderStartMode aStartMode); /** * This method stops the Leader services. @@ -149,7 +156,7 @@ public: * Note that this method should be called only by the Leader once after reset. * */ - void UpdateContextsAfterReset(void); + void HandleNetworkDataRestoredAfterReset(void); /** * This method scans network data for given Service ID and returns pointer to the respective TLV, if present. @@ -305,7 +312,9 @@ private: static constexpr uint8_t kNumContextIds = 15; // Maximum Context ID static constexpr uint32_t kContextIdReuseDelay = 48 * 60 * 60; // in seconds static constexpr uint32_t kStateUpdatePeriod = 60 * 1000; // State update period in milliseconds + static constexpr uint32_t kMaxNetDataSyncWait = 60 * 1000; // Maximum time to wait for netdata sync. + bool mWaitingForNetDataSync; uint16_t mContextUsed; TimeMilli mContextLastUsed[kNumContextIds]; uint32_t mContextIdReuseDelay;