From b0b2591bc02868f47437e0cb1b80dccf059b1a10 Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Fri, 29 May 2020 17:01:46 -0700 Subject: [PATCH] [mle] fix bug in leader active/pending dataset synchronization (#5021) The leader is the authoritative source when propagating active/pending operational datasets. When the leader reboots, it is possible for the leader to become out-of-sync. In particular, after the leader resets, it restores its network data and active/pending operational datasets using MLE Data Request/Response to retrieve them from a neighboring device. If the neighboring device has an older active/pending operational dataset, the leader will retrieve the older datasets and never attempt to propagate the newer datasets that it may have stored locally. This commit makes the following changes: - The leader does not accept any changes to the active/pending operational datasets. - After retrieving the latest network data from a neighboring device (as part of resynchronizing after reset), the leader will increment the full and stable network data versions to ensure that the leader propagates the latest active/pending operational datasets. --- src/core/thread/mle.cpp | 43 +++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index a5c3d9c6c..71e177bcf 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -3024,7 +3024,7 @@ otError Mle::HandleLeaderData(const Message &aMessage, const Ip6::MessageInfo &a // if received timestamp does not match the local value and message does not contain the dataset, // send MLE Data Request - if ((timestamp == NULL || timestamp->Compare(activeTimestamp) != 0) && + if (!IsLeader() && ((timestamp == NULL) || (timestamp->Compare(activeTimestamp) != 0)) && (Tlv::FindTlvOffset(aMessage, Tlv::kActiveDataset, activeDatasetOffset) != OT_ERROR_NONE)) { ExitNow(dataRequest = true); @@ -3045,7 +3045,7 @@ otError Mle::HandleLeaderData(const Message &aMessage, const Ip6::MessageInfo &a // if received timestamp does not match the local value and message does not contain the dataset, // send MLE Data Request - if ((timestamp == NULL || timestamp->Compare(pendingTimestamp) != 0) && + if (!IsLeader() && ((timestamp == NULL) || (timestamp->Compare(pendingTimestamp) != 0)) && (Tlv::FindTlvOffset(aMessage, Tlv::kPendingDataset, pendingDatasetOffset) != OT_ERROR_NONE)) { ExitNow(dataRequest = true); @@ -3068,25 +3068,34 @@ otError Mle::HandleLeaderData(const Message &aMessage, const Ip6::MessageInfo &a ExitNow(dataRequest = true); } - // Active Dataset - if (activeTimestamp.GetLength() > 0) +#if OPENTHREAD_FTD + if (IsLeader()) { - if (activeDatasetOffset > 0) - { - aMessage.Read(activeDatasetOffset, sizeof(tlv), &tlv); - IgnoreError(Get().Save(activeTimestamp, aMessage, activeDatasetOffset + sizeof(tlv), - tlv.GetLength())); - } + Get().IncrementVersionAndStableVersion(); } - - // Pending Dataset - if (pendingTimestamp.GetLength() > 0) + else +#endif { - if (pendingDatasetOffset > 0) + // Active Dataset + if (activeTimestamp.GetLength() > 0) { - aMessage.Read(pendingDatasetOffset, sizeof(tlv), &tlv); - IgnoreError(Get().Save(pendingTimestamp, aMessage, - pendingDatasetOffset + sizeof(tlv), tlv.GetLength())); + if (activeDatasetOffset > 0) + { + aMessage.Read(activeDatasetOffset, sizeof(tlv), &tlv); + IgnoreError(Get().Save(activeTimestamp, aMessage, + activeDatasetOffset + sizeof(tlv), tlv.GetLength())); + } + } + + // Pending Dataset + if (pendingTimestamp.GetLength() > 0) + { + if (pendingDatasetOffset > 0) + { + aMessage.Read(pendingDatasetOffset, sizeof(tlv), &tlv); + IgnoreError(Get().Save(pendingTimestamp, aMessage, + pendingDatasetOffset + sizeof(tlv), tlv.GetLength())); + } } }