diff --git a/src/core/meshcop/dataset_manager.cpp b/src/core/meshcop/dataset_manager.cpp index a90ae2ef7..af83a25bf 100644 --- a/src/core/meshcop/dataset_manager.cpp +++ b/src/core/meshcop/dataset_manager.cpp @@ -885,6 +885,35 @@ PendingDatasetManager::PendingDatasetManager(Instance &aInstance) { } +Error PendingDatasetManager::ReadActiveTimestamp(Timestamp &aTimestamp) const +{ + Error error = kErrorNotFound; + Dataset dataset; + + SuccessOrExit(Read(dataset)); + + SuccessOrExit(dataset.Read(aTimestamp)); + error = kErrorNone; + +exit: + return error; +} + +Error PendingDatasetManager::ReadRemainingDelay(uint32_t &aRemainingDelay) const +{ + Error error = kErrorNone; + TimeMilli now = TimerMilli::GetNow(); + + aRemainingDelay = 0; + + VerifyOrExit(mDelayTimer.IsRunning(), error = kErrorNotFound); + VerifyOrExit(mDelayTimer.GetFireTime() > now); + aRemainingDelay = mDelayTimer.GetFireTime() - now; + +exit: + return error; +} + void PendingDatasetManager::StartDelayTimer(void) { Dataset dataset; diff --git a/src/core/meshcop/dataset_manager.hpp b/src/core/meshcop/dataset_manager.hpp index 9c76df517..8092f03fe 100644 --- a/src/core/meshcop/dataset_manager.hpp +++ b/src/core/meshcop/dataset_manager.hpp @@ -441,6 +441,28 @@ class PendingDatasetManager : public DatasetManager, private NonCopyable */ explicit PendingDatasetManager(Instance &aInstance); + /** + * Reads the Active Timestamp in the Pending Operational Dataset. + * + * @param[out] aTimestamp A reference to return the read timestamp. + * + * @retval kErrorNone The active timestamp was successfully fetched. + * @retval kErrorNotFound The pending dataset is not currently valid. + * + */ + Error ReadActiveTimestamp(Timestamp &aTimestamp) const; + + /** + * Reads the remaining delay time in ms. + * + * @param[out] aRemainingDelay A reference to return the remaining delay time. + * + * @retval kErrorNone The remaining delay time was successfully fetched. + * @retval kErrorNotFound The pending dataset is not currently valid. + * + */ + Error ReadRemainingDelay(uint32_t &aRemainingDelay) const; + #if OPENTHREAD_FTD /** * Starts the Leader functions for maintaining the Active Operational Dataset. diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index ff90ba098..61313a314 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -3663,6 +3663,7 @@ void Mle::HandleAnnounce(RxInfo &aRxInfo) Error error = kErrorNone; ChannelTlvValue channelTlvValue; MeshCoP::Timestamp timestamp; + MeshCoP::Timestamp pendingActiveTimestamp; uint8_t channel; uint16_t panId; bool isFromOrphan; @@ -3707,6 +3708,24 @@ void Mle::HandleAnnounce(RxInfo &aRxInfo) VerifyOrExit(!channelAndPanIdMatch); } + if (Get().ReadActiveTimestamp(pendingActiveTimestamp) == kErrorNone) + { + // Ignore the Announce and take no action, if a pending + // dataset exists with an equal or more recent timestamp, + // and it will be applied soon. + + if (pendingActiveTimestamp >= timestamp) + { + uint32_t remainingDelay; + + if ((Get().ReadRemainingDelay(remainingDelay) == kErrorNone) && + (remainingDelay < kAnnounceBackoffForPendingDataset)) + { + ExitNow(); + } + } + } + if (mAttachState == kAttachStateProcessAnnounce) { VerifyOrExit(mAlternateTimestamp < timestamp.GetSeconds()); diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index 8cbb4c03a..8c3a6b870 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -811,6 +811,7 @@ class Mle : public InstanceLocator, private NonCopyable 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 kMulticastRetxDelayMax = kMulticastRetxDelay * 11 / 10; // 1.1 * base delay + static constexpr uint32_t kAnnounceBackoffForPendingDataset = 60000; // Max delay left to block Announce processing. static constexpr uint8_t kMaxTxCount = 3; // Max tx count for MLE message static constexpr uint8_t kMaxCriticalTxCount = 6; // Max tx count for critical MLE message