diff --git a/etc/visual-studio/libopenthread.vcxproj b/etc/visual-studio/libopenthread.vcxproj index 945af97c4..e1e702a6d 100644 --- a/etc/visual-studio/libopenthread.vcxproj +++ b/etc/visual-studio/libopenthread.vcxproj @@ -96,6 +96,7 @@ + @@ -177,6 +178,7 @@ + diff --git a/etc/visual-studio/libopenthread.vcxproj.filters b/etc/visual-studio/libopenthread.vcxproj.filters index dc88bc545..7a7335c39 100644 --- a/etc/visual-studio/libopenthread.vcxproj.filters +++ b/etc/visual-studio/libopenthread.vcxproj.filters @@ -249,6 +249,9 @@ Source Files\thread + + Source Files\thread + Source Files\thread @@ -509,6 +512,9 @@ Header Files\thread + + Header Files\thread + Header Files\thread diff --git a/etc/visual-studio/libopenthread_k.vcxproj b/etc/visual-studio/libopenthread_k.vcxproj index 648b03fca..78cb04e86 100644 --- a/etc/visual-studio/libopenthread_k.vcxproj +++ b/etc/visual-studio/libopenthread_k.vcxproj @@ -103,6 +103,7 @@ + @@ -209,6 +210,7 @@ + diff --git a/etc/visual-studio/libopenthread_k.vcxproj.filters b/etc/visual-studio/libopenthread_k.vcxproj.filters index 6f72961a6..d3a6d1cfc 100644 --- a/etc/visual-studio/libopenthread_k.vcxproj.filters +++ b/etc/visual-studio/libopenthread_k.vcxproj.filters @@ -252,6 +252,9 @@ Source Files\thread + + Source Files\thread + Source Files\thread @@ -509,6 +512,9 @@ Header Files\thread + + Header Files\thread + Header Files\thread diff --git a/src/cli/cli_dataset.cpp b/src/cli/cli_dataset.cpp index 54445ed52..b2fb16138 100644 --- a/src/cli/cli_dataset.cpp +++ b/src/cli/cli_dataset.cpp @@ -232,21 +232,29 @@ otError Dataset::ProcessHelp(otInstance *aInstance, int argc, char *argv[]) otError Dataset::ProcessActive(otInstance *aInstance, int argc, char *argv[]) { otOperationalDataset dataset; - otDatasetGetActive(aInstance, &dataset); + otError error; + SuccessOrExit(error = otDatasetGetActive(aInstance, &dataset)); + error = Print(dataset); + +exit: OT_UNUSED_VARIABLE(argc); OT_UNUSED_VARIABLE(argv); - return Print(dataset); + return error; } otError Dataset::ProcessPending(otInstance *aInstance, int argc, char *argv[]) { otOperationalDataset dataset; - otDatasetGetPending(aInstance, &dataset); + otError error; + SuccessOrExit(error = otDatasetGetPending(aInstance, &dataset)); + error = Print(dataset); + +exit: OT_UNUSED_VARIABLE(argc); OT_UNUSED_VARIABLE(argv); - return Print(dataset); + return error; } #if OPENTHREAD_FTD diff --git a/src/core/Makefile.am b/src/core/Makefile.am index f3ec6e6b9..6833de15a 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -138,6 +138,7 @@ SOURCES_COMMON = \ meshcop/announce_begin_client.cpp \ meshcop/commissioner.cpp \ meshcop/dataset.cpp \ + meshcop/dataset_local.cpp \ meshcop/dataset_manager.cpp \ meshcop/dataset_manager_ftd.cpp \ meshcop/dtls.cpp \ @@ -236,6 +237,7 @@ HEADERS_COMMON = \ meshcop/announce_begin_client.hpp \ meshcop/commissioner.hpp \ meshcop/dataset.hpp \ + meshcop/dataset_local.hpp \ meshcop/dataset_manager.hpp \ meshcop/dataset_manager_ftd.hpp \ meshcop/dataset_manager_mtd.hpp \ diff --git a/src/core/api/dataset_api.cpp b/src/core/api/dataset_api.cpp index 33aaaff5e..bf0a1c719 100644 --- a/src/core/api/dataset_api.cpp +++ b/src/core/api/dataset_api.cpp @@ -60,7 +60,7 @@ otError otDatasetGetActive(otInstance *aInstance, otOperationalDataset *aDataset VerifyOrExit(aDataset != NULL, error = OT_ERROR_INVALID_ARGS); - aInstance->mThreadNetif.GetActiveDataset().GetLocal().Get(*aDataset); + error = aInstance->mThreadNetif.GetActiveDataset().GetLocal().Get(*aDataset); exit: return error; @@ -72,7 +72,7 @@ otError otDatasetGetPending(otInstance *aInstance, otOperationalDataset *aDatase VerifyOrExit(aDataset != NULL, error = OT_ERROR_INVALID_ARGS); - aInstance->mThreadNetif.GetPendingDataset().GetLocal().Get(*aDataset); + error = aInstance->mThreadNetif.GetPendingDataset().GetLocal().Get(*aDataset); exit: return error; diff --git a/src/core/api/link_api.cpp b/src/core/api/link_api.cpp index 84ff8df8c..36e16fbd4 100644 --- a/src/core/api/link_api.cpp +++ b/src/core/api/link_api.cpp @@ -55,8 +55,8 @@ otError otLinkSetChannel(otInstance *aInstance, uint8_t aChannel) error = OT_ERROR_INVALID_STATE); error = aInstance->mThreadNetif.GetMac().SetChannel(aChannel); - aInstance->mThreadNetif.GetActiveDataset().Clear(false); - aInstance->mThreadNetif.GetPendingDataset().Clear(false); + aInstance->mThreadNetif.GetActiveDataset().Clear(); + aInstance->mThreadNetif.GetPendingDataset().Clear(); exit: return error; @@ -117,8 +117,8 @@ otError otLinkSetPanId(otInstance *aInstance, otPanId aPanId) error = OT_ERROR_INVALID_STATE); error = aInstance->mThreadNetif.GetMac().SetPanId(aPanId); - aInstance->mThreadNetif.GetActiveDataset().Clear(false); - aInstance->mThreadNetif.GetPendingDataset().Clear(false); + aInstance->mThreadNetif.GetActiveDataset().Clear(); + aInstance->mThreadNetif.GetPendingDataset().Clear(); exit: return error; diff --git a/src/core/api/thread_api.cpp b/src/core/api/thread_api.cpp index fcb8033f2..f68ce7d5d 100644 --- a/src/core/api/thread_api.cpp +++ b/src/core/api/thread_api.cpp @@ -75,8 +75,8 @@ otError otThreadSetExtendedPanId(otInstance *aInstance, const uint8_t *aExtended mlPrefix[7] = 0x00; aInstance->mThreadNetif.GetMle().SetMeshLocalPrefix(mlPrefix); - aInstance->mThreadNetif.GetActiveDataset().Clear(false); - aInstance->mThreadNetif.GetPendingDataset().Clear(false); + aInstance->mThreadNetif.GetActiveDataset().Clear(); + aInstance->mThreadNetif.GetPendingDataset().Clear(); exit: return error; @@ -165,8 +165,8 @@ otError otThreadSetMasterKey(otInstance *aInstance, const otMasterKey *aKey) error = OT_ERROR_INVALID_STATE); error = aInstance->mThreadNetif.GetKeyManager().SetMasterKey(*aKey); - aInstance->mThreadNetif.GetActiveDataset().Clear(false); - aInstance->mThreadNetif.GetPendingDataset().Clear(false); + aInstance->mThreadNetif.GetActiveDataset().Clear(); + aInstance->mThreadNetif.GetPendingDataset().Clear(); exit: return error; @@ -190,8 +190,8 @@ otError otThreadSetMeshLocalPrefix(otInstance *aInstance, const uint8_t *aMeshLo error = OT_ERROR_INVALID_STATE); error = aInstance->mThreadNetif.GetMle().SetMeshLocalPrefix(aMeshLocalPrefix); - aInstance->mThreadNetif.GetActiveDataset().Clear(false); - aInstance->mThreadNetif.GetPendingDataset().Clear(false); + aInstance->mThreadNetif.GetActiveDataset().Clear(); + aInstance->mThreadNetif.GetPendingDataset().Clear(); exit: return error; @@ -215,8 +215,8 @@ otError otThreadSetNetworkName(otInstance *aInstance, const char *aNetworkName) error = OT_ERROR_INVALID_STATE); error = aInstance->mThreadNetif.GetMac().SetNetworkName(aNetworkName); - aInstance->mThreadNetif.GetActiveDataset().Clear(false); - aInstance->mThreadNetif.GetPendingDataset().Clear(false); + aInstance->mThreadNetif.GetActiveDataset().Clear(); + aInstance->mThreadNetif.GetPendingDataset().Clear(); exit: return error; diff --git a/src/core/api/thread_ftd_api.cpp b/src/core/api/thread_ftd_api.cpp index 7cfa92028..967304f3e 100644 --- a/src/core/api/thread_ftd_api.cpp +++ b/src/core/api/thread_ftd_api.cpp @@ -266,8 +266,8 @@ otError otThreadSetPSKc(otInstance *aInstance, const uint8_t *aPSKc) error = OT_ERROR_INVALID_STATE); aInstance->mThreadNetif.GetKeyManager().SetPSKc(aPSKc); - aInstance->mThreadNetif.GetActiveDataset().Clear(false); - aInstance->mThreadNetif.GetPendingDataset().Clear(false); + aInstance->mThreadNetif.GetActiveDataset().Clear(); + aInstance->mThreadNetif.GetPendingDataset().Clear(); exit: return error; diff --git a/src/core/meshcop/dataset.cpp b/src/core/meshcop/dataset.cpp index ca788c18b..9140b74ea 100644 --- a/src/core/meshcop/dataset.cpp +++ b/src/core/meshcop/dataset.cpp @@ -38,8 +38,6 @@ #include -#include - #include "openthread-instance.h" #include "common/code_utils.hpp" #include "common/settings.hpp" @@ -49,21 +47,16 @@ namespace ot { namespace MeshCoP { -Dataset::Dataset(otInstance *aInstance, const Tlv::Type aType) : - InstanceLocator(aInstance), - mType(aType), - mLength(0) +Dataset::Dataset(const Tlv::Type aType) : + mUpdateTime(0), + mLength(0), + mType(aType) { } -void Dataset::Clear(bool isLocal) +void Dataset::Clear(void) { mLength = 0; - - if (isLocal) - { - otPlatSettingsDelete(GetInstance(), GetSettingsKey(), -1); - } } Tlv *Dataset::Get(Tlv::Type aType) @@ -252,6 +245,8 @@ otError Dataset::Set(const Dataset &aDataset) Remove(Tlv::kDelayTimer); } + mUpdateTime = aDataset.GetUpdateTime(); + return OT_ERROR_NONE; } @@ -362,6 +357,8 @@ otError Dataset::Set(const otOperationalDataset &aDataset) Set(tlv); } + mUpdateTime = Timer::GetNow(); + exit: return error; } @@ -406,60 +403,6 @@ void Dataset::SetTimestamp(const Timestamp &aTimestamp) } } -int Dataset::Compare(const Dataset &aCompare) const -{ - const Timestamp *thisTimestamp = GetTimestamp(); - const Timestamp *compareTimestamp = aCompare.GetTimestamp(); - int rval; - - if (compareTimestamp == NULL && thisTimestamp == NULL) - { - rval = 0; - } - else if (compareTimestamp == NULL && thisTimestamp != NULL) - { - rval = -1; - } - else if (compareTimestamp != NULL && thisTimestamp == NULL) - { - rval = 1; - } - else - { - rval = thisTimestamp->Compare(*compareTimestamp); - } - - return rval; -} - -otError Dataset::Restore(void) -{ - otError error; - uint16_t length = sizeof(mTlvs); - - error = otPlatSettingsGet(GetInstance(), GetSettingsKey(), 0, mTlvs, &length); - mLength = (error == OT_ERROR_NONE) ? length : 0; - - return error; -} - -otError Dataset::Store(void) -{ - otError error; - uint16_t key = GetSettingsKey(); - - if (mLength == 0) - { - error = otPlatSettingsDelete(GetInstance(), key, 0); - } - else - { - error = otPlatSettingsSet(GetInstance(), key, mTlvs, mLength); - } - - return error; -} - otError Dataset::Set(const Tlv &aTlv) { otError error = OT_ERROR_NONE; @@ -483,15 +426,23 @@ otError Dataset::Set(const Tlv &aTlv) memcpy(mTlvs + mLength, &aTlv, sizeof(Tlv) + aTlv.GetLength()); mLength += sizeof(Tlv) + aTlv.GetLength(); + mUpdateTime = Timer::GetNow(); + exit: return error; } otError Dataset::Set(const Message &aMessage, uint16_t aOffset, uint8_t aLength) { - aMessage.Read(aOffset, aLength, mTlvs); + otError error = OT_ERROR_NONE; + + VerifyOrExit(aLength == aMessage.Read(aOffset, aLength, mTlvs), error = OT_ERROR_INVALID_ARGS); mLength = aLength; - return OT_ERROR_NONE; + + mUpdateTime = Timer::GetNow(); + +exit: + return error; } void Dataset::Remove(Tlv::Type aType) @@ -505,13 +456,15 @@ exit: return; } -otError Dataset::AppendMleDatasetTlv(Message &aMessage) +otError Dataset::AppendMleDatasetTlv(Message &aMessage) const { otError error = OT_ERROR_NONE; Mle::Tlv tlv; Mle::Tlv::Type type; - Tlv *cur = reinterpret_cast(mTlvs); - Tlv *end = reinterpret_cast(mTlvs + mLength); + const Tlv *cur = reinterpret_cast(mTlvs); + const Tlv *end = reinterpret_cast(mTlvs + mLength); + + VerifyOrExit(mLength > 0); type = (mType == Tlv::kActiveTimestamp ? Mle::Tlv::kActiveDataset : Mle::Tlv::kPendingDataset); @@ -521,7 +474,29 @@ otError Dataset::AppendMleDatasetTlv(Message &aMessage) while (cur < end) { - if (cur->GetType() != mType) + if (cur->GetType() == mType) + { + ; // skip Active or Pending Timestamp TLV + } + else if (cur->GetType() == Tlv::kDelayTimer) + { + uint32_t elapsed = Timer::GetNow() - mUpdateTime; + DelayTimerTlv delayTimer; + + memcpy(&delayTimer, cur, sizeof(delayTimer)); + + if (delayTimer.GetDelayTimer() > elapsed) + { + delayTimer.SetDelayTimer(delayTimer.GetDelayTimer() - elapsed); + } + else + { + delayTimer.SetDelayTimer(0); + } + + SuccessOrExit(error = aMessage.Append(&delayTimer, sizeof(delayTimer))); + } + else { SuccessOrExit(error = aMessage.Append(cur, sizeof(Tlv) + cur->GetLength())); } diff --git a/src/core/meshcop/dataset.hpp b/src/core/meshcop/dataset.hpp index de2d81d56..c850371d0 100644 --- a/src/core/meshcop/dataset.hpp +++ b/src/core/meshcop/dataset.hpp @@ -42,8 +42,10 @@ namespace ot { namespace MeshCoP { -class Dataset: public InstanceLocator +class Dataset { + friend class DatasetLocal; + public: enum { @@ -54,19 +56,16 @@ public: /** * This constructor initializes the object. * - * @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aType The type of the dataset, active or pending. * */ - Dataset(otInstance *aInstance, const Tlv::Type aType); + Dataset(const Tlv::Type aType); /** * This method clears the Dataset. * - * @param[in] isLocal TRUE to delete the local dataset from non-volatile memory, FALSE not. - * */ - void Clear(bool isLocal); + void Clear(void); /** * This method returns a pointer to the TLV. @@ -106,6 +105,14 @@ public: */ uint16_t GetSize(void) const { return mLength; } + /** + * This method returns the local time the dataset was last updated. + * + * @returns The local time the dataset was last updated. + * + */ + uint32_t GetUpdateTime(void) const { return mUpdateTime; } + /** * This method returns a reference to the Timestamp. * @@ -120,36 +127,6 @@ public: */ void SetTimestamp(const Timestamp &aTimestamp); - /** - * This method compares this dataset to another based on the timestamp. - * - * @param[in] aCompare A reference to the timestamp to compare. - * - * @retval -1 if @p aCompare is older than this dataset. - * @retval 0 if @p aCompare is equal to this dataset. - * @retval 1 if @p aCompare is newer than this dataset. - * - */ - int Compare(const Dataset &aCompare) const; - - /** - * This method restores dataset from non-volatile memory. - * - * @retval OT_ERROR_NONE Successfully restore the dataset. - * @retval OT_ERROR_NOT_FOUND There is no corresponding dataset stored in non-volatile memory. - * - */ - otError Restore(void); - - /** - * This method stores dataset into non-volatile memory. - * - * @retval OT_ERROR_NONE Successfully store the dataset. - * @retval OT_ERROR_NO_BUFS Could not store the dataset due to insufficient memory space. - * - */ - otError Store(void); - /** * This method sets a TLV in the Dataset. * @@ -161,11 +138,41 @@ public: */ otError Set(const Tlv &aTlv); + /** + * This method sets the Dataset using TLVs stored in a message buffer. + * + * @param[in] aMessage The message buffer. + * @param[in] aOffset The message buffer offset where the dataset starts. + * @param[in] aLength The TLVs length in the message buffer in bytes. + * + * @retval OT_ERROR_NONE Successfully set the Dataset. + * @retval OT_ERROR_INVALID_ARGS The values of @p aOffset and @p aLength are not valid for @p aMessage. + * + */ otError Set(const Message &aMessage, uint16_t aOffset, uint8_t aLength); + /** + * This method sets the Dataset using an existing Dataset. + * + * If this Dataset is an Active Dataset, any Pending Timestamp and Delay Timer TLVs will be omitted in the copy + * from @p aDataset. + * + * @param[in] aDataset The input Dataset. + * + * @retval OT_ERROR_NONE Successfully set the Dataset. + * + */ otError Set(const Dataset &aDataset); #if OPENTHREAD_FTD + /** + * This method sets the Dataset. + * + * @param[in] aDataset The input Dataset. + * + * @retval OT_ERROR_NONE Successfully set the Dataset. + * + */ otError Set(const otOperationalDataset &aDataset); #endif @@ -184,16 +191,17 @@ public: * @retval OT_ERROR_NO_BUFS Insufficient available buffers to append the message with MLE Dataset TLV. * */ - otError AppendMleDatasetTlv(Message &aMessage); + otError AppendMleDatasetTlv(Message &aMessage) const; private: uint16_t GetSettingsKey(void); void Remove(uint8_t *aStart, uint8_t aLength); - Tlv::Type mType; ///< Active or Pending uint8_t mTlvs[kMaxSize]; ///< The Dataset buffer + uint32_t mUpdateTime; ///< Local time last updated uint16_t mLength; ///< The number of valid bytes in @var mTlvs + Tlv::Type mType; ///< Active or Pending }; } // namespace MeshCoP diff --git a/src/core/meshcop/dataset_local.cpp b/src/core/meshcop/dataset_local.cpp new file mode 100644 index 000000000..9dedb1362 --- /dev/null +++ b/src/core/meshcop/dataset_local.cpp @@ -0,0 +1,470 @@ +/* + * Copyright (c) 2016-2017, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file implements common methods for manipulating MeshCoP Datasets. + * + */ + +#define WPP_NAME "dataset_local.tmh" + +#include + +#include "dataset_local.hpp" + +#include + +#include + +#include "common/code_utils.hpp" +#include "common/logging.hpp" +#include "common/settings.hpp" +#include "meshcop/dataset.hpp" +#include "meshcop/meshcop_tlvs.hpp" +#include "thread/mle_tlvs.hpp" + +namespace ot { +namespace MeshCoP { + +DatasetLocal::DatasetLocal(otInstance *aInstance, const Tlv::Type aType) : + InstanceLocator(aInstance), + mUpdateTime(0), + mType(aType) +{ +} + +void DatasetLocal::Clear(void) +{ + otPlatSettingsDelete(GetInstance(), GetSettingsKey(), -1); +} + +bool DatasetLocal::IsPresent(void) const +{ + return otPlatSettingsGet(GetInstance(), GetSettingsKey(), 0, NULL, NULL) == OT_ERROR_NONE; +} + +otError DatasetLocal::Get(Dataset &aDataset) +{ + DelayTimerTlv *delayTimer; + uint32_t elapsed; + otError error; + + aDataset.mLength = sizeof(aDataset.mTlvs); + + error = otPlatSettingsGet(GetInstance(), GetSettingsKey(), 0, aDataset.mTlvs, &aDataset.mLength); + SuccessOrExit(error); + + delayTimer = static_cast(aDataset.Get(Tlv::kDelayTimer)); + VerifyOrExit(delayTimer); + + elapsed = Timer::GetNow() - mUpdateTime; + + if (delayTimer->GetDelayTimer() > elapsed) + { + delayTimer->SetDelayTimer(delayTimer->GetDelayTimer() - elapsed); + } + else + { + delayTimer->SetDelayTimer(0); + } + + aDataset.mUpdateTime = Timer::GetNow(); + +exit: + return error; +} + +otError DatasetLocal::Get(otOperationalDataset &aDataset) const +{ + Dataset dataset(mType); + otError error; + const Tlv *cur; + const Tlv *end; + + dataset.mLength = sizeof(dataset.mTlvs); + + error = otPlatSettingsGet(GetInstance(), GetSettingsKey(), 0, dataset.mTlvs, &dataset.mLength); + SuccessOrExit(error); + + cur = reinterpret_cast(dataset.mTlvs); + end = reinterpret_cast(dataset.mTlvs + dataset.mLength); + + memset(&aDataset, 0, sizeof(aDataset)); + + while (cur < end) + { + switch (cur->GetType()) + { + + case Tlv::kActiveTimestamp: + { + const ActiveTimestampTlv *tlv = static_cast(cur); + aDataset.mActiveTimestamp = tlv->GetSeconds(); + aDataset.mIsActiveTimestampSet = true; + break; + } + + case Tlv::kChannel: + { + const ChannelTlv *tlv = static_cast(cur); + aDataset.mChannel = tlv->GetChannel(); + aDataset.mIsChannelSet = true; + break; + } + + case Tlv::kChannelMask: + { + uint8_t tlvLength = cur->GetLength(); + const uint8_t *entry = reinterpret_cast(cur) + sizeof(Tlv); + const uint8_t *entryEnd = entry + tlvLength; + + while (entry < entryEnd) + { + if (reinterpret_cast(entry)->GetChannelPage() == 0) + { + uint8_t i = sizeof(ChannelMaskEntry); + aDataset.mChannelMaskPage0 = static_cast(entry[i] | (entry[i + 1] << 8) | + (entry[i + 2] << 16) | (entry[i + 3] << 24)); + aDataset.mIsChannelMaskPage0Set = true; + break; + } + + entry += (reinterpret_cast(entry)->GetMaskLength() + + sizeof(ChannelMaskEntry)); + } + + break; + } + + case Tlv::kDelayTimer: + { + const DelayTimerTlv *tlv = static_cast(cur); + aDataset.mDelay = tlv->GetDelayTimer(); + aDataset.mIsDelaySet = true; + break; + } + + case Tlv::kExtendedPanId: + { + const ExtendedPanIdTlv *tlv = static_cast(cur); + memcpy(aDataset.mExtendedPanId.m8, tlv->GetExtendedPanId(), sizeof(aDataset.mExtendedPanId)); + aDataset.mIsExtendedPanIdSet = true; + break; + } + + case Tlv::kMeshLocalPrefix: + { + const MeshLocalPrefixTlv *tlv = static_cast(cur); + memcpy(aDataset.mMeshLocalPrefix.m8, tlv->GetMeshLocalPrefix(), sizeof(aDataset.mMeshLocalPrefix)); + aDataset.mIsMeshLocalPrefixSet = true; + break; + } + + case Tlv::kNetworkMasterKey: + { + const NetworkMasterKeyTlv *tlv = static_cast(cur); + aDataset.mMasterKey = tlv->GetNetworkMasterKey(); + aDataset.mIsMasterKeySet = true; + break; + } + + case Tlv::kNetworkName: + { + const NetworkNameTlv *tlv = static_cast(cur); + memcpy(aDataset.mNetworkName.m8, tlv->GetNetworkName(), tlv->GetLength()); + aDataset.mIsNetworkNameSet = true; + break; + } + + case Tlv::kPanId: + { + const PanIdTlv *panid = static_cast(cur); + aDataset.mPanId = panid->GetPanId(); + aDataset.mIsPanIdSet = true; + break; + } + + case Tlv::kPendingTimestamp: + { + const PendingTimestampTlv *tlv = static_cast(cur); + aDataset.mPendingTimestamp = tlv->GetSeconds(); + aDataset.mIsPendingTimestampSet = true; + break; + } + + case Tlv::kPSKc: + { + const PSKcTlv *tlv = static_cast(cur); + memcpy(aDataset.mPSKc.m8, tlv->GetPSKc(), tlv->GetLength()); + aDataset.mIsPSKcSet = true; + break; + } + + case Tlv::kSecurityPolicy: + { + const SecurityPolicyTlv *tlv = static_cast(cur); + aDataset.mSecurityPolicy.mRotationTime = tlv->GetRotationTime(); + aDataset.mSecurityPolicy.mFlags = tlv->GetFlags(); + aDataset.mIsSecurityPolicySet = true; + break; + } + + default: + { + break; + } + } + + cur = cur->GetNext(); + } + +exit: + return error; +} + +#if OPENTHREAD_FTD + +otError DatasetLocal::Set(const otOperationalDataset &aDataset) +{ + otError error = OT_ERROR_NONE; + Dataset dataset(mType); + MeshCoP::ActiveTimestampTlv activeTimestampTlv; + + VerifyOrExit(aDataset.mIsActiveTimestampSet, error = OT_ERROR_INVALID_ARGS); + + activeTimestampTlv.Init(); + activeTimestampTlv.SetSeconds(aDataset.mActiveTimestamp); + activeTimestampTlv.SetTicks(0); + dataset.Set(activeTimestampTlv); + + if (mType == Tlv::kPendingTimestamp) + { + MeshCoP::PendingTimestampTlv pendingTimestampTlv; + + VerifyOrExit(aDataset.mIsPendingTimestampSet, error = OT_ERROR_INVALID_ARGS); + + pendingTimestampTlv.Init(); + pendingTimestampTlv.SetSeconds(aDataset.mPendingTimestamp); + pendingTimestampTlv.SetTicks(0); + dataset.Set(pendingTimestampTlv); + + if (aDataset.mIsDelaySet) + { + MeshCoP::DelayTimerTlv tlv; + tlv.Init(); + tlv.SetDelayTimer(aDataset.mDelay); + dataset.Set(tlv); + } + } + + if (aDataset.mIsChannelSet) + { + MeshCoP::ChannelTlv tlv; + tlv.Init(); + tlv.SetChannelPage(0); + tlv.SetChannel(aDataset.mChannel); + dataset.Set(tlv); + } + + if (aDataset.mIsChannelMaskPage0Set) + { + MeshCoP::ChannelMask0Tlv tlv; + tlv.Init(); + tlv.SetMask(aDataset.mChannelMaskPage0); + dataset.Set(tlv); + } + + if (aDataset.mIsExtendedPanIdSet) + { + MeshCoP::ExtendedPanIdTlv tlv; + tlv.Init(); + tlv.SetExtendedPanId(aDataset.mExtendedPanId.m8); + dataset.Set(tlv); + } + + if (aDataset.mIsMeshLocalPrefixSet) + { + MeshCoP::MeshLocalPrefixTlv tlv; + tlv.Init(); + tlv.SetMeshLocalPrefix(aDataset.mMeshLocalPrefix.m8); + dataset.Set(tlv); + } + + if (aDataset.mIsMasterKeySet) + { + MeshCoP::NetworkMasterKeyTlv tlv; + tlv.Init(); + tlv.SetNetworkMasterKey(aDataset.mMasterKey); + dataset.Set(tlv); + } + + if (aDataset.mIsNetworkNameSet) + { + MeshCoP::NetworkNameTlv tlv; + tlv.Init(); + tlv.SetNetworkName(aDataset.mNetworkName.m8); + dataset.Set(tlv); + } + + if (aDataset.mIsPanIdSet) + { + MeshCoP::PanIdTlv tlv; + tlv.Init(); + tlv.SetPanId(aDataset.mPanId); + dataset.Set(tlv); + } + + if (aDataset.mIsPSKcSet) + { + MeshCoP::PSKcTlv tlv; + tlv.Init(); + tlv.SetPSKc(aDataset.mPSKc.m8); + dataset.Set(tlv); + } + + if (aDataset.mIsSecurityPolicySet) + { + MeshCoP::SecurityPolicyTlv tlv; + tlv.Init(); + tlv.SetRotationTime(aDataset.mSecurityPolicy.mRotationTime); + tlv.SetFlags(aDataset.mSecurityPolicy.mFlags); + dataset.Set(tlv); + } + + if (dataset.GetSize() == 0) + { + error = otPlatSettingsDelete(GetInstance(), GetSettingsKey(), 0); + otLogInfoMeshCoP(GetInstance(), "%s dataset deleted", mType == Tlv::kActiveTimestamp ? "Active" : "Pending"); + } + else + { + error = otPlatSettingsSet(GetInstance(), GetSettingsKey(), dataset.GetBytes(), dataset.GetSize()); + otLogInfoMeshCoP(GetInstance(), "%s dataset set", mType == Tlv::kActiveTimestamp ? "Active" : "Pending"); + } + +exit: + return error; +} + +#endif // OPENTHREAD_FTD + +otError DatasetLocal::Set(const Dataset &aDataset) +{ + Dataset dataset(aDataset); + otError error; + + if (mType == Tlv::kActiveTimestamp) + { + dataset.Remove(Tlv::kPendingTimestamp); + dataset.Remove(Tlv::kDelayTimer); + } + + if (dataset.GetSize() == 0) + { + error = otPlatSettingsDelete(GetInstance(), GetSettingsKey(), 0); + otLogInfoMeshCoP(GetInstance(), "%s dataset deleted", mType == Tlv::kActiveTimestamp ? "Active" : "Pending"); + } + else + { + error = otPlatSettingsSet(GetInstance(), GetSettingsKey(), dataset.GetBytes(), dataset.GetSize()); + otLogInfoMeshCoP(GetInstance(), "%s dataset set", mType == Tlv::kActiveTimestamp ? "Active" : "Pending"); + } + + SuccessOrExit(error); + + mUpdateTime = Timer::GetNow(); + +exit: + return error; +} + +otError DatasetLocal::Restore(void) +{ + Dataset dataset(mType); + otError error; + + dataset.mLength = sizeof(dataset.mTlvs); + error = otPlatSettingsGet(GetInstance(), GetSettingsKey(), 0, dataset.mTlvs, &dataset.mLength); + SuccessOrExit(error); + + mUpdateTime = Timer::GetNow(); + +exit: + return error; +} + +uint16_t DatasetLocal::GetSettingsKey(void) const +{ + uint16_t rval; + + if (mType == Tlv::kActiveTimestamp) + { + rval = static_cast(Settings::kKeyActiveDataset); + } + else + { + rval = static_cast(Settings::kKeyPendingDataset); + } + + return rval; +} + +int DatasetLocal::Compare(const Timestamp *aCompareTimestamp) +{ + const Timestamp *thisTimestamp; + Dataset dataset(mType); + int rval = 1; + + SuccessOrExit(Get(dataset)); + + thisTimestamp = dataset.GetTimestamp(); + + if (aCompareTimestamp == NULL && thisTimestamp == NULL) + { + rval = 0; + } + else if (aCompareTimestamp == NULL && thisTimestamp != NULL) + { + rval = -1; + } + else if (aCompareTimestamp != NULL && thisTimestamp == NULL) + { + rval = 1; + } + else + { + rval = thisTimestamp->Compare(*aCompareTimestamp); + } + +exit: + return rval; +} + +} // namespace MeshCoP +} // namespace ot diff --git a/src/core/meshcop/dataset_local.hpp b/src/core/meshcop/dataset_local.hpp new file mode 100644 index 000000000..16de33106 --- /dev/null +++ b/src/core/meshcop/dataset_local.hpp @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2016-2017, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file includes definitions for managing MeshCoP Datasets. + * + */ + +#ifndef MESHCOP_DATASET_LOCAL_HPP_ +#define MESHCOP_DATASET_LOCAL_HPP_ + +#include "common/locator.hpp" +#include "meshcop/dataset.hpp" +#include "meshcop/meshcop_tlvs.hpp" + +namespace ot { +namespace MeshCoP { + +class DatasetLocal: public InstanceLocator +{ +public: + /** + * This constructor initializes the object. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aType The type of the dataset, active or pending. + * + */ + DatasetLocal(otInstance *aInstance, const Tlv::Type aType); + + /** + * This method indicates whether this is an Active or Pending Dataset. + * + * @retval Tlv::kActiveTimestamp when this is an Active Dataset. + * @retval Tlv::kPendingTimetamp when this is a Pending Dataset. + * + */ + Tlv::Type GetType(void) const { return mType; } + + /** + * This method clears the Dataset. + * + */ + void Clear(void); + + /** + * This method indicates whether or not the dataset is present in non-volatile memory. + * + * @retval TRUE if the dataset is present in non-volatile memory. + * @retval FALSE if the dataset is not present in non-volatile memory. + * + */ + bool IsPresent(void) const; + + /** + * This method returns a pointer to the Active or Pending Timestamp value. + * + * @returns A pointer to the Active or Pending Timestamp value or NULL if the dataset is invalid. + * + */ + const Timestamp *GetTimestamp(void) const; + + /** + * This method retrieves the dataset from non-volatile memory. + * + * @param[out] aDataset Where to place the dataset. + * + * @retval OT_ERROR_NONE Successfully retrieved the dataset. + * @retval OT_ERROR_NOT_FOUND There is no corresponding dataset stored in non-volatile memory. + * + */ + otError Get(Dataset &aDataset); + + /** + * This method retrieves the dataset from non-volatile memory. + * + * @param[out] aDataset Where to place the dataset. + * + * @retval OT_ERROR_NONE Successfully retrieved the dataset. + * @retval OT_ERROR_NOT_FOUND There is no corresponding dataset stored in non-volatile memory. + * + */ + otError Get(otOperationalDataset &aDataset) const; + + /** + * This method returns the local time this dataset was last updated or restored. + * + * @returns The local time this dataset was last updated or restored. + * + */ + uint32_t GetUpdateTime(void) const { return mUpdateTime; } + +#if OPENTHREAD_FTD + /** + * This method stores the dataset into non-volatile memory. + * + * @retval OT_ERROR_NONE Successfully stored the dataset. + * + */ + otError Set(const otOperationalDataset &aDataset); +#endif + + /** + * This method stores the dataset into non-volatile memory. + * + * @retval OT_ERROR_NONE Successfully stored the dataset. + * + */ + otError Set(const Dataset &aDataset); + + /** + * This method restores dataset from non-volatile memory. + * + * @retval OT_ERROR_NONE Successfully restore the dataset. + * @retval OT_ERROR_NOT_FOUND There is no corresponding dataset stored in non-volatile memory. + * + */ + otError Restore(void); + + /** + * This method compares this dataset to another based on the timestamp. + * + * @param[in] aCompare A reference to the timestamp to compare. + * + * @retval -1 if @p aCompare is older than this dataset. + * @retval 0 if @p aCompare is equal to this dataset. + * @retval 1 if @p aCompare is newer than this dataset. + * + */ + int Compare(const Timestamp *aCompare); + +private: + uint16_t GetSettingsKey(void) const; + void SetTimestamp(const Dataset &aDataset); + + uint32_t mUpdateTime; ///< Local time last updated + Tlv::Type mType; ///< Active or Pending +}; + +} // namespace MeshCoP +} // namespace ot + +#endif // MESHCOP_DATASET_LOCAL_HPP_ diff --git a/src/core/meshcop/dataset_manager.cpp b/src/core/meshcop/dataset_manager.cpp index b56082624..86f97c3e3 100644 --- a/src/core/meshcop/dataset_manager.cpp +++ b/src/core/meshcop/dataset_manager.cpp @@ -65,22 +65,59 @@ DatasetManager::DatasetManager(ThreadNetif &aThreadNetif, const Tlv::Type aType, const char *aUriGet, Timer::Handler aTimerHander): ThreadNetifLocator(aThreadNetif), mLocal(aThreadNetif.GetInstance(), aType), - mNetwork(aThreadNetif.GetInstance(), aType), + mNetwork(aType), mTimer(aThreadNetif.GetIp6().mTimerScheduler, aTimerHander, this), mUriSet(aUriSet), mUriGet(aUriGet) { } +const Timestamp *DatasetManager::GetTimestamp(void) const +{ + return mNetwork.GetTimestamp(); +} + +int DatasetManager::Compare(const Timestamp &aTimestamp) const +{ + const Timestamp *timestamp = mNetwork.GetTimestamp(); + int rval = 1; + + if (timestamp) + { + rval = timestamp->Compare(aTimestamp); + } + + return rval; +} + +otError DatasetManager::AppendMleDatasetTlv(Message &aMessage) const +{ + return mNetwork.AppendMleDatasetTlv(aMessage); +} + +const Tlv *DatasetManager::GetTlv(Tlv::Type aType) const +{ + return mNetwork.Get(aType); +} + otError DatasetManager::ApplyConfiguration(void) { ThreadNetif &netif = GetNetif(); otError error = OT_ERROR_NONE; + Dataset datasetLocal(mLocal.GetType()); Dataset *dataset; const Tlv *cur; const Tlv *end; - dataset = netif.GetMle().IsAttached() ? &mNetwork : &mLocal; + if (netif.GetMle().IsAttached()) + { + dataset = &mNetwork; + } + else + { + mLocal.Get(datasetLocal); + dataset = &datasetLocal; + } cur = reinterpret_cast(dataset->GetBytes()); end = reinterpret_cast(dataset->GetBytes() + dataset->GetSize()); @@ -165,15 +202,56 @@ otError DatasetManager::ApplyConfiguration(void) return error; } +otError DatasetManager::Restore(void) +{ + otError error; + + SuccessOrExit(error = mLocal.Restore()); + mLocal.Get(mNetwork); + +exit: + return error; +} + +void DatasetManager::Clear(void) +{ + mNetwork.Clear(); + mLocal.Clear(); + mTimer.Stop(); +} + +void DatasetManager::HandleDetach(void) +{ + mLocal.Get(mNetwork); + mTimer.Stop(); +} + +void DatasetManager::Set(const Dataset &aDataset) +{ + mNetwork.Set(aDataset); + mLocal.Set(aDataset); +} + +otError DatasetManager::Set(const Timestamp &aTimestamp, const Message &aMessage, uint16_t aOffset, uint8_t aLength) +{ + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = mNetwork.Set(aMessage, aOffset, aLength)); + mNetwork.SetTimestamp(aTimestamp); + HandleNetworkUpdate(); + +exit: + return error; +} + #if OPENTHREAD_FTD -otError DatasetManager::Set(const otOperationalDataset &aDataset, uint8_t &aFlags) + +otError DatasetManager::Set(const otOperationalDataset &aDataset) { ThreadNetif &netif = GetNetif(); otError error = OT_ERROR_NONE; SuccessOrExit(error = mLocal.Set(aDataset)); - mLocal.Store(); - aFlags = kFlagLocalUpdated; switch (netif.GetMle().GetRole()) { @@ -183,8 +261,7 @@ otError DatasetManager::Set(const otOperationalDataset &aDataset, uint8_t &aFlag break; case OT_DEVICE_ROLE_LEADER: - mNetwork = mLocal; - aFlags |= kFlagNetworkUpdated; + mLocal.Get(mNetwork); netif.GetNetworkDataLeader().IncrementVersion(); netif.GetNetworkDataLeader().IncrementStableVersion(); break; @@ -196,57 +273,16 @@ otError DatasetManager::Set(const otOperationalDataset &aDataset, uint8_t &aFlag exit: return error; } + #endif // OPENTHREAD_FTD -otError DatasetManager::Clear(uint8_t &aFlags, bool aOnlyClearNetwork) +void DatasetManager::HandleNetworkUpdate(void) { - if (!aOnlyClearNetwork) - { - mLocal.Clear(true); - } - - mNetwork.Clear(false); - HandleNetworkUpdate(aFlags); - return OT_ERROR_NONE; -} - -otError DatasetManager::Set(const Dataset &aDataset) -{ - mNetwork.Set(aDataset); - - if (mLocal.Compare(aDataset) != 0) - { - mLocal.Set(aDataset); - mLocal.Store(); - } - - return OT_ERROR_NONE; -} - -otError DatasetManager::Set(const Timestamp &aTimestamp, const Message &aMessage, - uint16_t aOffset, uint8_t aLength, uint8_t &aFlags) -{ - otError error = OT_ERROR_NONE; - - SuccessOrExit(error = mNetwork.Set(aMessage, aOffset, aLength)); - mNetwork.SetTimestamp(aTimestamp); - HandleNetworkUpdate(aFlags); - -exit: - return error; -} - -void DatasetManager::HandleNetworkUpdate(uint8_t &aFlags) -{ - int compare = mLocal.Compare(mNetwork); - - aFlags = kFlagNetworkUpdated; + int compare = mLocal.Compare(mNetwork.GetTimestamp()); if (compare > 0) { - mLocal = mNetwork; - mLocal.Store(); - aFlags |= kFlagLocalUpdated; + mLocal.Set(mNetwork); } else if (compare < 0) { @@ -257,32 +293,29 @@ void DatasetManager::HandleNetworkUpdate(uint8_t &aFlags) void DatasetManager::HandleTimer(void) { ThreadNetif &netif = GetNetif(); - const Timestamp *localActiveTimestamp; - const Timestamp *pendingActiveTimestamp; - const ActiveTimestampTlv *tlv; - localActiveTimestamp = netif.GetActiveDataset().GetLocal().GetTimestamp(); - VerifyOrExit(localActiveTimestamp != NULL); + VerifyOrExit(netif.GetActiveDataset().GetLocal().IsPresent()); VerifyOrExit(netif.GetMle().IsAttached()); - VerifyOrExit(mLocal.Compare(mNetwork) < 0); + VerifyOrExit(mLocal.Compare(mNetwork.GetTimestamp()) < 0); + + if (mLocal.GetType() == Tlv::kActiveTimestamp) + { + const ActiveTimestampTlv *tlv = static_cast(netif.GetPendingDataset().GetTlv( + Tlv::kActiveTimestamp)); + const Timestamp *pendingActiveTimestamp = static_cast(tlv); + + if (pendingActiveTimestamp != NULL && + netif.GetActiveDataset().GetLocal().Compare(pendingActiveTimestamp) >= 0) + { + // stop registration attempts during dataset transition + ExitNow(); + } + } Register(); - - tlv = static_cast(netif.GetPendingDataset().GetNetwork().Get(Tlv::kActiveTimestamp)); - pendingActiveTimestamp = static_cast(tlv); - - if (pendingActiveTimestamp != NULL && - localActiveTimestamp->Compare(*pendingActiveTimestamp) >= 0) - { - // stop registration attempts during dataset transition - ExitNow(); - } - else - { - mTimer.Start(1000); - } + mTimer.Start(1000); exit: return; @@ -295,21 +328,17 @@ otError DatasetManager::Register(void) Coap::Header header; Message *message; Ip6::MessageInfo messageInfo; + Dataset dataset(mLocal.GetType()); header.Init(OT_COAP_TYPE_CONFIRMABLE, OT_COAP_CODE_POST); header.SetToken(Coap::Header::kDefaultTokenLength); header.AppendUriPathOptions(mUriSet); header.SetPayloadMarker(); - if (strcmp(mUriSet, OT_URI_PATH_PENDING_SET) == 0) - { - PendingDatasetBase *pending = static_cast(this); - pending->UpdateDelayTimer(); - } - VerifyOrExit((message = NewMeshCoPMessage(netif.GetCoap(), header)) != NULL, error = OT_ERROR_NO_BUFS); - SuccessOrExit(error = message->Append(mLocal.GetBytes(), mLocal.GetSize())); + mLocal.Get(dataset); + SuccessOrExit(error = message->Append(dataset.GetBytes(), dataset.GetSize())); messageInfo.SetSockAddr(netif.GetMle().GetMeshLocal16()); netif.GetMle().GetLeaderAloc(messageInfo.GetPeerAddr()); @@ -328,7 +357,8 @@ exit: return error; } -void DatasetManager::Get(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo) +void DatasetManager::Get(const Coap::Header &aHeader, const Message &aMessage, + const Ip6::MessageInfo &aMessageInfo) const { Tlv tlv; uint16_t offset = aMessage.GetOffset(); @@ -414,8 +444,7 @@ otError DatasetManager::Set(Coap::Header &aHeader, Message &aMessage, const Ip6: static_cast(&activeTimestamp) : static_cast(&pendingTimestamp); - VerifyOrExit(mLocal.GetTimestamp() == NULL || mLocal.GetTimestamp()->Compare(*timestamp) > 0, - state = StateTlv::kReject); + VerifyOrExit(mLocal.Compare(timestamp) > 0, state = StateTlv::kReject); // check channel if (Tlv::GetTlv(aMessage, Tlv::kChannel, sizeof(channel), channel) == OT_ERROR_NONE) @@ -461,7 +490,7 @@ otError DatasetManager::Set(Coap::Header &aHeader, Message &aMessage, const Ip6: memcmp(&masterKey.GetNetworkMasterKey(), &netif.GetKeyManager().GetMasterKey(), OT_MASTER_KEY_SIZE) == 0)) { // no change to master key, active timestamp must be ahead - const Timestamp *localActiveTimestamp = netif.GetActiveDataset().GetNetwork().GetTimestamp(); + const Timestamp *localActiveTimestamp = netif.GetActiveDataset().GetTimestamp(); VerifyOrExit(localActiveTimestamp == NULL || localActiveTimestamp->Compare(activeTimestamp) > 0, state = StateTlv::kReject); @@ -488,10 +517,13 @@ otError DatasetManager::Set(Coap::Header &aHeader, Message &aMessage, const Ip6: state = StateTlv::kReject); // update dataset - if (type == Tlv::kPendingTimestamp && isUpdateFromCommissioner) + if (isUpdateFromCommissioner) { - mLocal.Clear(true); - mLocal.Set(netif.GetActiveDataset().GetNetwork()); + mNetwork.Set(netif.GetActiveDataset().GetNetwork()); + } + else + { + mNetwork.Clear(); } if (type == Tlv::kPendingTimestamp || !doesAffectConnectivity) @@ -533,15 +565,14 @@ otError DatasetManager::Set(Coap::Header &aHeader, Message &aMessage, const Ip6: // fall through default: - mLocal.Set(data.tlv); + mNetwork.Set(data.tlv); break; } offset += sizeof(Tlv) + data.tlv.GetLength(); } - mLocal.Store(); - mNetwork = mLocal; + mLocal.Set(mNetwork); netif.GetNetworkDataLeader().IncrementVersion(); netif.GetNetworkDataLeader().IncrementStableVersion(); } @@ -820,15 +851,12 @@ exit: #endif // OPENTHREAD_FTD void DatasetManager::SendGetResponse(const Coap::Header &aRequestHeader, const Ip6::MessageInfo &aMessageInfo, - uint8_t *aTlvs, uint8_t aLength) + uint8_t *aTlvs, uint8_t aLength) const { ThreadNetif &netif = GetNetif(); - Tlv *tlv; otError error = OT_ERROR_NONE; Coap::Header responseHeader; Message *message; - uint8_t index; - responseHeader.SetDefaultResponseHeader(aRequestHeader); responseHeader.SetPayloadMarker(); @@ -853,15 +881,17 @@ void DatasetManager::SendGetResponse(const Coap::Header &aRequestHeader, const I } else { - for (index = 0; index < aLength; index++) + for (uint8_t index = 0; index < aLength; index++) { + const Tlv *tlv; + if (aTlvs[index] == Tlv::kNetworkMasterKey && !(netif.GetKeyManager().GetSecurityPolicyFlags() & OT_SECURITY_POLICY_OBTAIN_MASTER_KEY)) { continue; } - if ((tlv = mNetwork.Get(static_cast(aTlvs[index]))) != NULL) + if ((tlv = mNetwork.Get(static_cast(aTlvs[index]))) != NULL) { SuccessOrExit(error = message->Append(tlv, sizeof(Tlv) + tlv->GetLength())); } @@ -909,31 +939,30 @@ otError ActiveDatasetBase::Restore(void) { otError error = OT_ERROR_NONE; - SuccessOrExit(error = mLocal.Restore()); + SuccessOrExit(error = DatasetManager::Restore()); SuccessOrExit(error = DatasetManager::ApplyConfiguration()); exit: return error; } -otError ActiveDatasetBase::Clear(bool aOnlyClearNetwork) +void ActiveDatasetBase::Clear(void) { - otError error = OT_ERROR_NONE; - uint8_t flags; + DatasetManager::Clear(); +} - SuccessOrExit(error = DatasetManager::Clear(flags, aOnlyClearNetwork)); - -exit: - return error; +void ActiveDatasetBase::HandleDetach(void) +{ + DatasetManager::HandleDetach(); + DatasetManager::ApplyConfiguration(); } #if OPENTHREAD_FTD otError ActiveDatasetBase::Set(const otOperationalDataset &aDataset) { otError error = OT_ERROR_NONE; - uint8_t flags; - SuccessOrExit(error = DatasetManager::Set(aDataset, flags)); + SuccessOrExit(error = DatasetManager::Set(aDataset)); DatasetManager::ApplyConfiguration(); exit: @@ -941,12 +970,11 @@ exit: } #endif // OPENTHREAD_FTD -otError ActiveDatasetBase::Set(const Dataset &aDataset) +void ActiveDatasetBase::Set(const Dataset &aDataset) { ThreadNetif &netif = GetNetif(); - otError error = OT_ERROR_NONE; - SuccessOrExit(error = DatasetManager::Set(aDataset)); + DatasetManager::Set(aDataset); DatasetManager::ApplyConfiguration(); if (netif.GetMle().GetRole() == OT_DEVICE_ROLE_LEADER) @@ -954,18 +982,14 @@ otError ActiveDatasetBase::Set(const Dataset &aDataset) netif.GetNetworkDataLeader().IncrementVersion(); netif.GetNetworkDataLeader().IncrementStableVersion(); } - -exit: - return error; } otError ActiveDatasetBase::Set(const Timestamp &aTimestamp, const Message &aMessage, uint16_t aOffset, uint8_t aLength) { otError error = OT_ERROR_NONE; - uint8_t flags; - SuccessOrExit(error = DatasetManager::Set(aTimestamp, aMessage, aOffset, aLength, flags)); + SuccessOrExit(error = DatasetManager::Set(aTimestamp, aMessage, aOffset, aLength)); DatasetManager::ApplyConfiguration(); exit: @@ -1005,8 +1029,6 @@ PendingDatasetBase::PendingDatasetBase(ThreadNetif &aThreadNetif): DatasetManager(aThreadNetif, Tlv::kPendingTimestamp, OT_URI_PATH_PENDING_SET, OT_URI_PATH_PENDING_GET, &PendingDatasetBase::HandleTimer), mDelayTimer(aThreadNetif.GetIp6().mTimerScheduler, &PendingDatasetBase::HandleDelayTimer, this), - mLocalTime(0), - mNetworkTime(0), mResourceGet(OT_URI_PATH_PENDING_GET, &PendingDatasetBase::HandleGet, this) { aThreadNetif.GetCoap().AddResource(mResourceGet); @@ -1014,129 +1036,69 @@ PendingDatasetBase::PendingDatasetBase(ThreadNetif &aThreadNetif): otError PendingDatasetBase::Restore(void) { - otError error = OT_ERROR_NONE; - - SuccessOrExit(error = mLocal.Restore()); - - ResetDelayTimer(kFlagLocalUpdated); - -exit: - return error; + return DatasetManager::Restore(); } -otError PendingDatasetBase::Clear(bool aOnlyClearNetwork) +void PendingDatasetBase::Clear(void) { - otError error = OT_ERROR_NONE; - uint8_t flags; + DatasetManager::Clear(); + mDelayTimer.Stop(); +} - SuccessOrExit(error = DatasetManager::Clear(flags, aOnlyClearNetwork)); - ResetDelayTimer(flags); +void PendingDatasetBase::ClearNetwork(void) +{ + mNetwork.Clear(); + mDelayTimer.Stop(); +} -exit: - return error; +void PendingDatasetBase::HandleDetach(void) +{ + DatasetManager::HandleDetach(); + StartDelayTimer(); } #if OPENTHREAD_FTD otError PendingDatasetBase::Set(const otOperationalDataset &aDataset) { otError error = OT_ERROR_NONE; - uint8_t flags; - SuccessOrExit(error = DatasetManager::Set(aDataset, flags)); - ResetDelayTimer(flags); + SuccessOrExit(error = DatasetManager::Set(aDataset)); + StartDelayTimer(); exit: return error; } #endif // OPENTHREAD_FTD -otError PendingDatasetBase::Set(const Dataset &aDataset) +void PendingDatasetBase::Set(const Dataset &aDataset) { - otError error = OT_ERROR_NONE; - - SuccessOrExit(error = DatasetManager::Set(aDataset)); - ResetDelayTimer(kFlagLocalUpdated | kFlagNetworkUpdated); - -exit: - return error; + DatasetManager::Set(aDataset); + StartDelayTimer(); } otError PendingDatasetBase::Set(const Timestamp &aTimestamp, const Message &aMessage, uint16_t aOffset, uint8_t aLength) { otError error = OT_ERROR_NONE; - uint8_t flags; - SuccessOrExit(error = DatasetManager::Set(aTimestamp, aMessage, aOffset, aLength, flags)); - ResetDelayTimer(flags); + SuccessOrExit(error = DatasetManager::Set(aTimestamp, aMessage, aOffset, aLength)); + StartDelayTimer(); exit: return error; } -void PendingDatasetBase::ResetDelayTimer(uint8_t aFlags) +void PendingDatasetBase::StartDelayTimer(void) { DelayTimerTlv *delayTimer; - if (aFlags & kFlagLocalUpdated) + mDelayTimer.Stop(); + + if ((delayTimer = static_cast(mNetwork.Get(Tlv::kDelayTimer))) != NULL) { - mLocalTime = Timer::GetNow(); + mDelayTimer.StartAt(mNetwork.GetUpdateTime(), delayTimer->GetDelayTimer()); + otLogInfoMeshCoP(GetInstance(), "delay timer started"); } - - if (aFlags & kFlagNetworkUpdated) - { - mNetworkTime = Timer::GetNow(); - mDelayTimer.Stop(); - - if ((delayTimer = static_cast(mNetwork.Get(Tlv::kDelayTimer))) != NULL) - { - if (delayTimer->GetDelayTimer() == 0) - { - HandleDelayTimer(); - } - else - { - mDelayTimer.Start(delayTimer->GetDelayTimer()); - otLogInfoMeshCoP(GetInstance(), "delay timer started"); - } - } - } -} - -void PendingDatasetBase::UpdateDelayTimer(void) -{ - UpdateDelayTimer(mLocal, mLocalTime); - UpdateDelayTimer(mNetwork, mNetworkTime); -} - -void PendingDatasetBase::UpdateDelayTimer(Dataset &aDataset, uint32_t &aStartTime) -{ - DelayTimerTlv *delayTimer; - uint32_t now = Timer::GetNow(); - uint32_t elapsed; - uint32_t delay; - - VerifyOrExit((delayTimer = static_cast(aDataset.Get(Tlv::kDelayTimer))) != NULL); - - elapsed = now - aStartTime; - - delay = delayTimer->GetDelayTimer(); - - if (delay > elapsed) - { - delay -= elapsed; - } - else - { - delay = 0; - } - - delayTimer->SetDelayTimer(delay); - - aStartTime = now; - -exit: - return; } void PendingDatasetBase::HandleDelayTimer(Timer &aTimer) @@ -1146,22 +1108,11 @@ void PendingDatasetBase::HandleDelayTimer(Timer &aTimer) void PendingDatasetBase::HandleDelayTimer(void) { - DelayTimerTlv *delayTimer; - otLogInfoMeshCoP(GetInstance(), "pending delay timer expired"); - UpdateDelayTimer(); - delayTimer = static_cast(mNetwork.Get(Tlv::kDelayTimer)); - assert(delayTimer != NULL && delayTimer->GetDelayTimer() == 0); - GetNetif().GetActiveDataset().Set(mNetwork); - Clear(false); -} - -void PendingDatasetBase::HandleNetworkUpdate(uint8_t &aFlags) -{ - DatasetManager::HandleNetworkUpdate(aFlags); + Clear(); } void PendingDatasetBase::HandleGet(void *aContext, otCoapHeader *aHeader, otMessage *aMessage, diff --git a/src/core/meshcop/dataset_manager.hpp b/src/core/meshcop/dataset_manager.hpp index 9585f8b02..366a14f5c 100644 --- a/src/core/meshcop/dataset_manager.hpp +++ b/src/core/meshcop/dataset_manager.hpp @@ -41,6 +41,7 @@ #include "common/locator.hpp" #include "common/timer.hpp" #include "meshcop/dataset.hpp" +#include "meshcop/dataset_local.hpp" #include "net/udp6.hpp" #include "thread/mle.hpp" #include "thread/network_data_leader.hpp" @@ -54,34 +55,154 @@ namespace MeshCoP { class DatasetManager: public ThreadNetifLocator { public: - Dataset &GetLocal(void) { return mLocal; } + /** + * This method returns a reference to the Timestamp. + * + * @returns A pointer to the Timestamp. + * + */ + const Timestamp *GetTimestamp(void) const; + + /** + * This method compares @p aTimestamp to the dataset's timestamp value. + * + * @param[in] aCompare A reference to the timestamp to compare. + * + * @retval -1 if @p aCompare is older than this dataset. + * @retval 0 if @p aCompare is equal to this dataset. + * @retval 1 if @p aCompare is newer than this dataset. + * + */ + int Compare(const Timestamp &aTimestamp) const; + + /** + * This method appends the MLE Dataset TLV but excluding MeshCoP Sub Timestamp TLV. + * + * @retval OT_ERROR_NONE Successfully append MLE Dataset TLV without MeshCoP Sub Timestamp TLV. + * @retval OT_ERROR_NO_BUFS Insufficient available buffers to append the message with MLE Dataset TLV. + * + */ + otError AppendMleDatasetTlv(Message &aMessage) const; + + /** + * This method returns a pointer to the TLV. + * + * @returns A pointer to the TLV or NULL if none is found. + * + */ + const Tlv *GetTlv(Tlv::Type aType) const; + + /** + * This method returns the Operational Dataset stored in non-volatile memory. + * + * @retval A reference to the Operational Dataset stored in non-volatile memory. + * + */ + DatasetLocal &GetLocal(void) { return mLocal; } + + /** + * This method returns the Operational Dataset for the attached partition. + * + * When not attached to a partition, the returned dataset is the one stored in non-volatile memory. + * + * @retval A reference to the Operational Dataset for the attached partition. + * + */ Dataset &GetNetwork(void) { return mNetwork; } + /** + * This method applies the Active or Pending Dataset to the Thread interface. + * + * @retval OT_ERROR_NONE Successfully applied configuration. + * + */ otError ApplyConfiguration(void); protected: - enum - { - kFlagLocalUpdated = 1 << 0, - kFlagNetworkUpdated = 1 << 1, - }; + /** + * This constructor initializes the object. + * + * @param[in] aThreadNetif A reference to the Thread network interface. + * @param[in] aType Identifies Active or Pending Operational Dataset. + * @param[in] aUriSet The URI-PATH for setting the Operational Dataset. + * @param[in] aUriGet The URI-PATH for getting the Operational Dataset. + * @param[in] aTimerHandler The registration timer handler. + * + */ DatasetManager(ThreadNetif &aThreadNetif, const Tlv::Type aType, const char *aUriSet, const char *aUriGet, Timer::Handler aTimerHander); - otError Clear(uint8_t &aFlags, bool aOnlyClearNetwork); + /** + * This method restores the Operational Dataset from non-volatile memory. + * + * @retval OT_ERROR_NONE Successfully restore the dataset. + * @retval OT_ERROR_NOT_FOUND There is no corresponding dataset stored in non-volatile memory. + * + */ + otError Restore(void); - otError Set(const Dataset &aDataset); + /** + * This method clears the Operational Dataset. + * + */ + void Clear(void); - otError Set(const Timestamp &aTimestamp, const Message &aMessage, uint16_t aOffset, uint8_t aLength, - uint8_t &aFlags); + /** + * This method updates the Operational Dataset when detaching from the network. + * + * On detach, the Operational Dataset is restored from non-volatile memory. + * + */ + void HandleDetach(void); - void Get(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + /** + * This method sets the Operational Dataset in non-volatile memory. + * + * @param[in] aDataset The Operational Dataset. + * + */ + void Set(const Dataset &aDataset); - void HandleNetworkUpdate(uint8_t &aFlags); + /** + * This method sets the Operational Dataset for the partition. + * + * This method also updates the non-volatile version if the partition's Operational Dataset is newer. + * + * @param[in] aTimestamp The timestamp for the Operational Dataset. + * @param[in] aMessage The message buffer. + * @param[in] aOffset The offset where the Operational Dataset begins. + * @param[in] aLength The length of the Operational Dataset. + * + */ + otError Set(const Timestamp &aTimestamp, const Message &aMessage, uint16_t aOffset, uint8_t aLength); + + /** + * This method handles a MGMT_GET request message. + * + * @param[in] aHeader The CoAP header. + * @param[in] aMessage The CoAP message buffer. + * @parma[in] aMessageInfo The message info. + * + */ + void Get(const Coap::Header &aHeader, const Message &aMessage, const Ip6::MessageInfo &aMessageInfo) const; + + /** + * This method compares the partition's Operational Dataset with that stored in non-volatile memory. + * + * If the partition's Operational Dataset is newer, the non-volatile storage is updated. + * If the partition's Operational Dataset is older, the registration process is started. + * + */ + void HandleNetworkUpdate(void); + + /** + * This method initiates a network data registration message with the Leader. + * + */ void HandleTimer(void); - Dataset mLocal; + DatasetLocal mLocal; Dataset mNetwork; private: @@ -90,7 +211,8 @@ private: otError Register(void); void SendGetResponse(const Coap::Header &aRequestHeader, const Ip6::MessageInfo &aMessageInfo, - uint8_t *aTlvs, uint8_t aLength); + uint8_t *aTlvs, uint8_t aLength) const; + Timer mTimer; const char *mUriSet; @@ -98,11 +220,50 @@ private: #if OPENTHREAD_FTD public: + /** + * This method sends a MGMT_SET request to the Leader. + * + * @parma[in] aDataset The Operational Datset. + * @param[in] aTlvs Any additional raw TLVs to include. + * @param[in] aLength Number of bytes in @p aTlvs. + * + * @retval OT_ERROR_NONE on success. + * + */ otError SendSetRequest(const otOperationalDataset &aDataset, const uint8_t *aTlvs, uint8_t aLength); + + /** + * This method sends a MGMT_GET request. + * + * @param[in] aTlvTypes The list of TLV types to request. + * @param[in] aLength Number of bytes in @p aTlvTypes. + * @parma[in] aAddress The IPv6 destination address for the MGMT_GET request. + * + * @retval OT_ERROR_NONE on success. + * + */ otError SendGetRequest(const uint8_t *aTlvTypes, uint8_t aLength, const otIp6Address *aAddress); protected: - otError Set(const otOperationalDataset &aDataset, uint8_t &aFlags); + /** + * This method sets the Operational Dataset in non-volatile memory. + * + * @parma[in] aDataset The Operational Dataset. + * + */ + otError Set(const otOperationalDataset &aDataset); + + /** + * This method handles the MGMT_SET request message. + * + * @param[in] aHeader The CoAP header. + * @param[in] aMessage The CoAP message buffer. + * @parma[in] aMessageInfo The message info. + * + * @retval OT_ERROR_NONE The MGMT_SET request message was handled successfully. + * @retval OT_ERROR_DROP The MGMT_SET request message was dropped. + * + */ otError Set(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo); private: @@ -113,18 +274,72 @@ private: class ActiveDatasetBase: public DatasetManager { public: + /** + * Constructor. + * + * @param[in] aThreadNetif The Thread network interface. + * + */ ActiveDatasetBase(ThreadNetif &aThreadNetif); + /** + * This method restores the Active Operational Dataset from non-volatile memory. + * + * This method will also configure the Thread interface using the Active Operational Dataset. + * + * @retval OT_ERROR_NONE Successfully restore the dataset. + * @retval OT_ERROR_NOT_FOUND There is no corresponding dataset stored in non-volatile memory. + * + */ otError Restore(void); - otError Clear(bool aOnlyClearNetwork); + /** + * This method clears the Active Operational Dataset. + * + */ + void Clear(void); + + /** + * This method updates the Operational Dataset when detaching from the network. + * + * On detach, the Operational Dataset is restored from non-volatile memory and reconfigures the Thread + * interface. + * + */ + void HandleDetach(void); #if OPENTHREAD_FTD + /** + * This method sets the Operational Dataset in non-volatile memory. + * + * @parma[in] aDataset The Operational Dataset. + * + */ otError Set(const otOperationalDataset &aDataset); #endif - otError Set(const Dataset &aDataset); + /** + * This method sets the Operational Dataset in non-volatile memory. + * + * This method also reconfigures the Thread interface. + * + * @param[in] aDataset The Operational Dataset. + * + */ + void Set(const Dataset &aDataset); + /** + * This method sets the Operational Dataset for the partition. + * + * This method also reconfigures the Thread interface. + * This method also updates the non-volatile version if the partition's Operational Dataset is newer. + * + * @param[in] aTimestamp The timestamp for the Operational Dataset. + * @param[in] aMessage The message buffer. + * @param[in] aOffset The offset where the Operational Dataset begins. + * @param[in] aLength The length of the Operational Dataset. + * + */ otError Set(const Timestamp &aTimestamp, const Message &aMessage, uint16_t aOffset, uint8_t aLength); private: @@ -141,34 +356,93 @@ private: class PendingDatasetBase: public DatasetManager { public: + /** + * Constructor. + * + * @param[in] The Thread network interface. + * + */ PendingDatasetBase(ThreadNetif &aThreadNetif); + /** + * This method restores the Operational Dataset from non-volatile memory. + * + * @retval OT_ERROR_NONE Successfully restore the dataset. + * @retval OT_ERROR_NOT_FOUND There is no corresponding dataset stored in non-volatile memory. + * + */ otError Restore(void); - otError Clear(bool aOnlyClearNetwork); + /** + * This method clears the Pending Operational Dataset. + * + * This method also stops the Delay Timer if it was active. + * + */ + void Clear(void); + + /** + * This method clears the network Pending Operational Dataset. + * + * This method also stops the Delay Timer if it was active. + * + */ + void ClearNetwork(void); + + /** + * This method updates the Operational Dataset when detaching from the network. + * + * On detach, the Operational Dataset is restored from non-volatile memory. + * + * This method also stops the Delay Timer if it was active. + * + */ + void HandleDetach(void); #if OPENTHREAD_FTD + /** + * This method sets the Operational Dataset in non-volatile memory. + * + * This method also starts the Delay Timer. + * + * @parma[in] aDataset The Operational Dataset. + * + */ otError Set(const otOperationalDataset &aDataset); #endif - otError Set(const Dataset &aDataset); + /** + * This method sets the Operational Dataset in non-volatile memory. + * + * This method also starts the Delay Timer. + * + * @param[in] aDataset The Operational Dataset. + * + */ + void Set(const Dataset &aDataset); + /** + * This method sets the Operational Dataset for the partition. + * + * This method also updates the non-volatile version if the partition's Operational Dataset is newer. + * + * This method also starts the Delay Timer. + * + * @param[in] aTimestamp The timestamp for the Operational Dataset. + * @param[in] aMessage The message buffer. + * @param[in] aOffset The offset where the Operational Dataset begins. + * @param[in] aLength The length of the Operational Dataset. + * + */ otError Set(const Timestamp &aTimestamp, const Message &aMessage, uint16_t aOffset, uint8_t aLength); - void UpdateDelayTimer(void); - protected: static void HandleDelayTimer(Timer &aTimer); void HandleDelayTimer(void); - - void ResetDelayTimer(uint8_t aFlags); - void UpdateDelayTimer(Dataset &aDataset, uint32_t &aStartTime); - - void HandleNetworkUpdate(uint8_t &aFlags); + void StartDelayTimer(void); + void HandleNetworkUpdate(void); Timer mDelayTimer; - uint32_t mLocalTime; - uint32_t mNetworkTime; private: static void HandleGet(void *aContext, otCoapHeader *aHeader, otMessage *aMessage, diff --git a/src/core/meshcop/dataset_manager_ftd.cpp b/src/core/meshcop/dataset_manager_ftd.cpp index 12a27b816..a54ca0bcb 100644 --- a/src/core/meshcop/dataset_manager_ftd.cpp +++ b/src/core/meshcop/dataset_manager_ftd.cpp @@ -34,7 +34,7 @@ #if OPENTHREAD_FTD -#define WPP_NAME "dataset_manager.tmh" +#define WPP_NAME "dataset_manager_ftd.tmh" #include @@ -67,114 +67,113 @@ ActiveDataset::ActiveDataset(ThreadNetif &aThreadNetif): { } -bool ActiveDataset::IsTlvInitialized(Tlv::Type aType) -{ - return mLocal.Get(aType) != NULL; -} - otError ActiveDataset::GenerateLocal(void) { ThreadNetif &netif = GetNetif(); otError error = OT_ERROR_NONE; - otOperationalDataset dataset; + Dataset dataset(mLocal.GetType()); VerifyOrExit(netif.GetMle().IsAttached(), error = OT_ERROR_INVALID_STATE); - memset(&dataset, 0, sizeof(dataset)); + mLocal.Get(dataset); // Active Timestamp - if (!IsTlvInitialized(Tlv::kActiveTimestamp)) + if (dataset.Get(Tlv::kActiveTimestamp) == NULL) { ActiveTimestampTlv activeTimestampTlv; activeTimestampTlv.Init(); activeTimestampTlv.SetSeconds(0); activeTimestampTlv.SetTicks(0); - mLocal.Set(activeTimestampTlv); + dataset.Set(activeTimestampTlv); } // Channel - if (!IsTlvInitialized(Tlv::kChannel)) + if (dataset.Get(Tlv::kChannel) == NULL) { ChannelTlv tlv; tlv.Init(); tlv.SetChannelPage(0); tlv.SetChannel(netif.GetMac().GetChannel()); - mLocal.Set(tlv); + dataset.Set(tlv); } // channelMask - if (!IsTlvInitialized(Tlv::kChannelMask)) + if (dataset.Get(Tlv::kChannelMask) == NULL) { ChannelMask0Tlv tlv; tlv.Init(); tlv.SetMask(OT_RADIO_SUPPORTED_CHANNELS); - mLocal.Set(tlv); + dataset.Set(tlv); } // Extended PAN ID - if (!IsTlvInitialized(Tlv::kExtendedPanId)) + if (dataset.Get(Tlv::kExtendedPanId) == NULL) { ExtendedPanIdTlv tlv; tlv.Init(); tlv.SetExtendedPanId(netif.GetMac().GetExtendedPanId()); - mLocal.Set(tlv); + dataset.Set(tlv); } // Mesh-Local Prefix - if (!IsTlvInitialized(Tlv::kMeshLocalPrefix)) + if (dataset.Get(Tlv::kMeshLocalPrefix) == NULL) { MeshLocalPrefixTlv tlv; tlv.Init(); tlv.SetMeshLocalPrefix(netif.GetMle().GetMeshLocalPrefix()); - mLocal.Set(tlv); + dataset.Set(tlv); } // Master Key - if (!IsTlvInitialized(Tlv::kNetworkMasterKey)) + if (dataset.Get(Tlv::kNetworkMasterKey) == NULL) { NetworkMasterKeyTlv tlv; tlv.Init(); tlv.SetNetworkMasterKey(netif.GetKeyManager().GetMasterKey()); - mLocal.Set(tlv); + dataset.Set(tlv); } // Network Name - if (!IsTlvInitialized(Tlv::kNetworkName)) + if (dataset.Get(Tlv::kNetworkName) == NULL) { NetworkNameTlv tlv; tlv.Init(); tlv.SetNetworkName(netif.GetMac().GetNetworkName()); - mLocal.Set(tlv); + dataset.Set(tlv); } // Pan ID - if (!IsTlvInitialized(Tlv::kPanId)) + if (dataset.Get(Tlv::kPanId) == NULL) { PanIdTlv tlv; tlv.Init(); tlv.SetPanId(netif.GetMac().GetPanId()); - mLocal.Set(tlv); + dataset.Set(tlv); } // PSKc - if (!IsTlvInitialized(Tlv::kPSKc)) + if (dataset.Get(Tlv::kPSKc) == NULL) { PSKcTlv tlv; tlv.Init(); tlv.SetPSKc(netif.GetKeyManager().GetPSKc()); - mLocal.Set(tlv); + dataset.Set(tlv); } // Security Policy - if (!IsTlvInitialized(Tlv::kSecurityPolicy)) + if (dataset.Get(Tlv::kSecurityPolicy) == NULL) { SecurityPolicyTlv tlv; tlv.Init(); tlv.SetRotationTime(static_cast(netif.GetKeyManager().GetKeyRotation())); tlv.SetFlags(netif.GetKeyManager().GetSecurityPolicyFlags()); - mLocal.Set(tlv); + dataset.Set(tlv); } + SuccessOrExit(error = mLocal.Set(dataset)); + + otLogInfoMeshCoP(GetInstance(), "Generated local dataset"); + exit: return error; } @@ -183,8 +182,7 @@ void ActiveDataset::StartLeader(void) { GenerateLocal(); - mLocal.Store(); - mNetwork = mLocal; + mLocal.Get(mNetwork); GetNetif().GetCoap().AddResource(mResourceSet); } @@ -218,10 +216,8 @@ PendingDataset::PendingDataset(ThreadNetif &aThreadNetif): void PendingDataset::StartLeader(void) { - UpdateDelayTimer(mLocal, mLocalTime); - mLocal.Store(); - mNetwork = mLocal; - ResetDelayTimer(kFlagNetworkUpdated); + mLocal.Get(mNetwork); + StartDelayTimer(); GetNetif().GetCoap().AddResource(mResourceSet); } @@ -242,7 +238,7 @@ void PendingDataset::HandleSet(void *aContext, otCoapHeader *aHeader, otMessage void PendingDataset::HandleSet(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { SuccessOrExit(DatasetManager::Set(aHeader, aMessage, aMessageInfo)); - ResetDelayTimer(kFlagLocalUpdated | kFlagNetworkUpdated); + StartDelayTimer(); exit: return; @@ -253,7 +249,6 @@ void PendingDataset::ApplyActiveDataset(const Timestamp &aTimestamp, Message &aM ThreadNetif &netif = GetNetif(); uint16_t offset = aMessage.GetOffset(); DelayTimerTlv delayTimer; - uint8_t flags; VerifyOrExit(netif.GetMle().IsAttached()); @@ -279,10 +274,10 @@ void PendingDataset::ApplyActiveDataset(const Timestamp &aTimestamp, Message &aM // add pending timestamp tlv mNetwork.SetTimestamp(aTimestamp); - HandleNetworkUpdate(flags); + DatasetManager::HandleNetworkUpdate(); // reset delay timer - ResetDelayTimer(kFlagNetworkUpdated); + StartDelayTimer(); exit: return; diff --git a/src/core/meshcop/joiner_router.cpp b/src/core/meshcop/joiner_router.cpp index 2222dee6e..a7790e411 100644 --- a/src/core/meshcop/joiner_router.cpp +++ b/src/core/meshcop/joiner_router.cpp @@ -327,7 +327,7 @@ otError JoinerRouter::DelaySendingJoinerEntrust(const Ip6::MessageInfo &aMessage ExtendedPanIdTlv extendedPanId; NetworkNameTlv networkName; NetworkKeySequenceTlv networkKeySequence; - Tlv *tlv; + const Tlv *tlv; DelayedJoinEntHeader delayedMessage; @@ -356,7 +356,7 @@ otError JoinerRouter::DelaySendingJoinerEntrust(const Ip6::MessageInfo &aMessage networkName.SetNetworkName(netif.GetMac().GetNetworkName()); SuccessOrExit(error = message->Append(&networkName, sizeof(Tlv) + networkName.GetLength())); - if ((tlv = netif.GetActiveDataset().GetNetwork().Get(Tlv::kActiveTimestamp)) != NULL) + if ((tlv = netif.GetActiveDataset().GetTlv(Tlv::kActiveTimestamp)) != NULL) { SuccessOrExit(error = message->Append(tlv, sizeof(Tlv) + tlv->GetLength())); } @@ -367,7 +367,7 @@ otError JoinerRouter::DelaySendingJoinerEntrust(const Ip6::MessageInfo &aMessage SuccessOrExit(error = message->Append(&activeTimestamp, sizeof(activeTimestamp))); } - if ((tlv = netif.GetActiveDataset().GetNetwork().Get(Tlv::kChannelMask)) != NULL) + if ((tlv = netif.GetActiveDataset().GetTlv(Tlv::kChannelMask)) != NULL) { SuccessOrExit(error = message->Append(tlv, sizeof(Tlv) + tlv->GetLength())); } @@ -378,7 +378,7 @@ otError JoinerRouter::DelaySendingJoinerEntrust(const Ip6::MessageInfo &aMessage SuccessOrExit(error = message->Append(&channelMask, sizeof(channelMask))); } - if ((tlv = netif.GetActiveDataset().GetNetwork().Get(Tlv::kPSKc)) != NULL) + if ((tlv = netif.GetActiveDataset().GetTlv(Tlv::kPSKc)) != NULL) { SuccessOrExit(error = message->Append(tlv, sizeof(Tlv) + tlv->GetLength())); } @@ -389,7 +389,7 @@ otError JoinerRouter::DelaySendingJoinerEntrust(const Ip6::MessageInfo &aMessage SuccessOrExit(error = message->Append(&pskc, sizeof(pskc))); } - if ((tlv = netif.GetActiveDataset().GetNetwork().Get(Tlv::kSecurityPolicy)) != NULL) + if ((tlv = netif.GetActiveDataset().GetTlv(Tlv::kSecurityPolicy)) != NULL) { SuccessOrExit(error = message->Append(tlv, sizeof(Tlv) + tlv->GetLength())); } diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index edf7b5b29..68073cc85 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -260,8 +260,8 @@ otError Mle::Stop(bool aClearNetworkDatasets) if (aClearNetworkDatasets) { - netif.GetActiveDataset().Clear(true); - netif.GetPendingDataset().Clear(true); + netif.GetActiveDataset().HandleDetach(); + netif.GetPendingDataset().HandleDetach(); } mRole = OT_DEVICE_ROLE_DISABLED; @@ -353,10 +353,9 @@ otError Mle::Store(void) VerifyOrExit(IsAttached(), error = OT_ERROR_INVALID_STATE); - if (netif.GetActiveDataset().GetLocal().GetTimestamp() == NULL) + if (netif.GetActiveDataset().GetTimestamp() == NULL) { netif.GetActiveDataset().GenerateLocal(); - netif.GetActiveDataset().GetLocal().Store(); } memset(&networkInfo, 0, sizeof(networkInfo)); @@ -475,11 +474,7 @@ otError Mle::BecomeDetached(void) VerifyOrExit(mRole != OT_DEVICE_ROLE_DISABLED, error = OT_ERROR_INVALID_STATE); - if (mReattachState == kReattachStop) - { - netif.GetPendingDataset().UpdateDelayTimer(); - netif.GetPendingDataset().Set(netif.GetPendingDataset().GetLocal()); - } + netif.GetPendingDataset().HandleDetach(); SetStateDetached(); SetRloc16(Mac::kShortAddrInvalid); @@ -1201,18 +1196,14 @@ exit: return error; } -otError Mle::AppendActiveTimestamp(Message &aMessage, bool aCouldUseLocal) +otError Mle::AppendActiveTimestamp(Message &aMessage) { ThreadNetif &netif = GetNetif(); otError error; ActiveTimestampTlv timestampTlv; const MeshCoP::Timestamp *timestamp; - if ((timestamp = netif.GetActiveDataset().GetNetwork().GetTimestamp()) == NULL && aCouldUseLocal) - { - timestamp = netif.GetActiveDataset().GetLocal().GetTimestamp(); - } - + timestamp = netif.GetActiveDataset().GetTimestamp(); VerifyOrExit(timestamp, error = OT_ERROR_NONE); timestampTlv.Init(); @@ -1229,7 +1220,7 @@ otError Mle::AppendPendingTimestamp(Message &aMessage) PendingTimestampTlv timestampTlv; const MeshCoP::Timestamp *timestamp; - timestamp = GetNetif().GetPendingDataset().GetNetwork().GetTimestamp(); + timestamp = GetNetif().GetPendingDataset().GetTimestamp(); VerifyOrExit(timestamp && timestamp->GetSeconds() != 0, error = OT_ERROR_NONE); timestampTlv.Init(); @@ -1376,7 +1367,6 @@ void Mle::HandleParentRequestTimer(void) { mReattachState = kReattachStop; netif.GetActiveDataset().Restore(); - netif.GetPendingDataset().Set(netif.GetPendingDataset().GetLocal()); } if (mReattachState == kReattachStop) @@ -1602,7 +1592,7 @@ otError Mle::SendChildIdRequest(void) } SuccessOrExit(error = AppendTlvRequest(*message, tlvs, sizeof(tlvs))); - SuccessOrExit(error = AppendActiveTimestamp(*message, true)); + SuccessOrExit(error = AppendActiveTimestamp(*message)); SuccessOrExit(error = AppendPendingTimestamp(*message)); memset(&destination, 0, sizeof(destination)); @@ -1636,7 +1626,7 @@ otError Mle::SendDataRequest(const Ip6::Address &aDestination, const uint8_t *aT VerifyOrExit((message = NewMleMessage()) != NULL, error = OT_ERROR_NO_BUFS); SuccessOrExit(error = AppendHeader(*message, Header::kCommandDataRequest)); SuccessOrExit(error = AppendTlvRequest(*message, aTlvs, aTlvsLength)); - SuccessOrExit(error = AppendActiveTimestamp(*message, false)); + SuccessOrExit(error = AppendActiveTimestamp(*message)); SuccessOrExit(error = AppendPendingTimestamp(*message)); if (aDelay) @@ -1853,7 +1843,7 @@ otError Mle::SendAnnounce(uint8_t aChannel, bool aOrphanAnnounce) } else { - SuccessOrExit(error = AppendActiveTimestamp(*message, false)); + SuccessOrExit(error = AppendActiveTimestamp(*message)); } panid.Init(); @@ -1879,11 +1869,11 @@ exit: void Mle::SendOrphanAnnounce(void) { - MeshCoP::ChannelMask0Tlv *channelMask; + const MeshCoP::ChannelMask0Tlv *channelMask; uint8_t channel; - channelMask = static_cast(GetNetif().GetActiveDataset().GetNetwork().Get( - MeshCoP::Tlv::kChannelMask)); + channelMask = static_cast(GetNetif().GetActiveDataset().GetTlv( + MeshCoP::Tlv::kChannelMask)); VerifyOrExit(channelMask != NULL); @@ -2432,7 +2422,7 @@ otError Mle::HandleLeaderData(const Message &aMessage, const Ip6::MessageInfo &a const MeshCoP::Timestamp *timestamp; VerifyOrExit(activeTimestamp.IsValid(), error = OT_ERROR_PARSE); - timestamp = netif.GetActiveDataset().GetNetwork().GetTimestamp(); + timestamp = netif.GetActiveDataset().GetTimestamp(); // if received timestamp does not match the local value and message does not contain the dataset, // send MLE Data Request @@ -2453,7 +2443,7 @@ otError Mle::HandleLeaderData(const Message &aMessage, const Ip6::MessageInfo &a const MeshCoP::Timestamp *timestamp; VerifyOrExit(pendingTimestamp.IsValid(), error = OT_ERROR_PARSE); - timestamp = netif.GetPendingDataset().GetNetwork().GetTimestamp(); + timestamp = netif.GetPendingDataset().GetTimestamp(); // if received timestamp does not match the local value and message does not contain the dataset, // send MLE Data Request @@ -2491,10 +2481,6 @@ otError Mle::HandleLeaderData(const Message &aMessage, const Ip6::MessageInfo &a tlv.GetLength()); } } - else - { - netif.GetActiveDataset().Clear(false); - } // Pending Dataset if (pendingTimestamp.GetLength() > 0) @@ -2506,10 +2492,6 @@ otError Mle::HandleLeaderData(const Message &aMessage, const Ip6::MessageInfo &a tlv.GetLength()); } } - else - { - netif.GetPendingDataset().Clear(false); - } mRetrieveNewNetworkData = false; @@ -2768,17 +2750,12 @@ otError Mle::HandleChildIdResponse(const Message &aMessage, const Ip6::MessageIn aMessage.Read(offset, sizeof(tlv), &tlv); netif.GetActiveDataset().Set(activeTimestamp, aMessage, offset + sizeof(tlv), tlv.GetLength()); } - else if (netif.GetActiveDataset().GetNetwork().GetTimestamp() == NULL && - netif.GetActiveDataset().GetLocal().GetTimestamp() != NULL) - { - netif.GetActiveDataset().Set(netif.GetActiveDataset().GetLocal()); - } } - // clear local Pending Dataset if device succeed to reattach using stored Pending Dataset + // clear Pending Dataset if device succeed to reattach using stored Pending Dataset if (mReattachState == kReattachPending) { - netif.GetPendingDataset().GetLocal().Clear(true); + netif.GetPendingDataset().Clear(); } // Pending Timestamp @@ -2795,7 +2772,7 @@ otError Mle::HandleChildIdResponse(const Message &aMessage, const Ip6::MessageIn } else { - netif.GetPendingDataset().Clear(true); + netif.GetPendingDataset().ClearNetwork(); } // Parent Attach Success @@ -3054,7 +3031,7 @@ otError Mle::HandleAnnounce(const Message &aMessage, const Ip6::MessageInfo &aMe SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kPanId, sizeof(panid), panid)); VerifyOrExit(panid.IsValid(), error = OT_ERROR_PARSE); - localTimestamp = netif.GetActiveDataset().GetNetwork().GetTimestamp(); + localTimestamp = netif.GetActiveDataset().GetTimestamp(); if (localTimestamp == NULL || localTimestamp->Compare(timestamp) > 0) { diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index 650d62cd7..43dec0c8f 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -1120,14 +1120,12 @@ protected: * This method appends a Active Timestamp TLV to a message. * * @param[in] aMessage A reference to the message. - * @param[in] aCouldUseLocal True to use local Active Timestamp when network Active Timestamp is not available, - * False not. * * @retval OT_ERROR_NONE Successfully appended the Active Timestamp TLV. * @retval OT_ERROR_NO_BUFS Insufficient buffers available to append the Active Timestamp TLV. * */ - otError AppendActiveTimestamp(Message &aMessage, bool aCouldUseLocal); + otError AppendActiveTimestamp(Message &aMessage); /** * This method appends a Pending Timestamp TLV to a message. diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 8279ee2e9..46c21f507 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -2191,15 +2191,13 @@ otError MleRouter::HandleChildIdRequest(const Message &aMessage, const Ip6::Mess } if (activeTimestamp.GetLength() == 0 || - netif.GetActiveDataset().GetNetwork().GetTimestamp() == NULL || - netif.GetActiveDataset().GetNetwork().GetTimestamp()->Compare(activeTimestamp) != 0) + netif.GetActiveDataset().Compare(activeTimestamp) != 0) { child->SetRequestTlv(numTlvs++, Tlv::kActiveDataset); } if (pendingTimestamp.GetLength() == 0 || - netif.GetPendingDataset().GetNetwork().GetTimestamp() == NULL || - netif.GetPendingDataset().GetNetwork().GetTimestamp()->Compare(pendingTimestamp) != 0) + netif.GetPendingDataset().Compare(pendingTimestamp) != 0) { child->SetRequestTlv(numTlvs++, Tlv::kPendingDataset); } @@ -2465,15 +2463,13 @@ otError MleRouter::HandleDataRequest(const Message &aMessage, const Ip6::Message numTlvs = tlvRequest.GetLength(); if (activeTimestamp.GetLength() == 0 || - netif.GetActiveDataset().GetNetwork().GetTimestamp() == NULL || - netif.GetActiveDataset().GetNetwork().GetTimestamp()->Compare(activeTimestamp) != 0) + netif.GetActiveDataset().Compare(activeTimestamp)) { tlvs[numTlvs++] = Tlv::kActiveDataset; } if (pendingTimestamp.GetLength() == 0 || - netif.GetPendingDataset().GetNetwork().GetTimestamp() == NULL || - netif.GetPendingDataset().GetNetwork().GetTimestamp()->Compare(pendingTimestamp) != 0) + netif.GetPendingDataset().Compare(pendingTimestamp)) { tlvs[numTlvs++] = Tlv::kPendingDataset; } @@ -2747,7 +2743,7 @@ otError MleRouter::SendChildIdResponse(Child *aChild) SuccessOrExit(error = AppendHeader(*message, Header::kCommandChildIdResponse)); SuccessOrExit(error = AppendSourceAddress(*message)); SuccessOrExit(error = AppendLeaderData(*message)); - SuccessOrExit(error = AppendActiveTimestamp(*message, false)); + SuccessOrExit(error = AppendActiveTimestamp(*message)); SuccessOrExit(error = AppendPendingTimestamp(*message)); if (aChild->GetState() != Neighbor::kStateValid) @@ -2852,7 +2848,7 @@ otError MleRouter::SendChildUpdateRequest(Child *aChild) SuccessOrExit(error = AppendSourceAddress(*message)); SuccessOrExit(error = AppendLeaderData(*message)); SuccessOrExit(error = AppendNetworkData(*message, !aChild->IsFullNetworkData())); - SuccessOrExit(error = AppendActiveTimestamp(*message, false)); + SuccessOrExit(error = AppendActiveTimestamp(*message)); SuccessOrExit(error = AppendPendingTimestamp(*message)); SuccessOrExit(error = AppendTlvRequest(*message, tlvs, sizeof(tlvs))); @@ -2915,7 +2911,7 @@ otError MleRouter::SendChildUpdateResponse(Child *aChild, const Ip6::MessageInfo case Tlv::kNetworkData: SuccessOrExit(error = AppendNetworkData(*message, !aChild->IsFullNetworkData())); - SuccessOrExit(error = AppendActiveTimestamp(*message, false)); + SuccessOrExit(error = AppendActiveTimestamp(*message)); SuccessOrExit(error = AppendPendingTimestamp(*message)); break; @@ -2967,7 +2963,7 @@ otError MleRouter::SendDataResponse(const Ip6::Address &aDestination, const uint SuccessOrExit(error = AppendHeader(*message, Header::kCommandDataResponse)); SuccessOrExit(error = AppendSourceAddress(*message)); SuccessOrExit(error = AppendLeaderData(*message)); - SuccessOrExit(error = AppendActiveTimestamp(*message, false)); + SuccessOrExit(error = AppendActiveTimestamp(*message)); SuccessOrExit(error = AppendPendingTimestamp(*message)); for (int i = 0; i < aTlvsLength; i++) @@ -4497,29 +4493,12 @@ exit: otError MleRouter::AppendActiveDataset(Message &aMessage) { - ThreadNetif &netif = GetNetif(); - otError error = OT_ERROR_NONE; - - VerifyOrExit(netif.GetActiveDataset().GetNetwork().GetSize() > 0); - - SuccessOrExit(error = netif.GetActiveDataset().GetNetwork().AppendMleDatasetTlv(aMessage)); - -exit: - return error; + return GetNetif().GetActiveDataset().AppendMleDatasetTlv(aMessage); } otError MleRouter::AppendPendingDataset(Message &aMessage) { - ThreadNetif &netif = GetNetif(); - otError error = OT_ERROR_NONE; - - VerifyOrExit(netif.GetPendingDataset().GetNetwork().GetSize() > 0); - - netif.GetPendingDataset().UpdateDelayTimer(); - SuccessOrExit(error = netif.GetPendingDataset().GetNetwork().AppendMleDatasetTlv(aMessage)); - -exit: - return error; + return GetNetif().GetPendingDataset().AppendMleDatasetTlv(aMessage); } bool MleRouter::HasMinDowngradeNeighborRouters(void) diff --git a/tests/scripts/thread-cert/Cert_9_2_08_PersistentDatasets.py b/tests/scripts/thread-cert/Cert_9_2_08_PersistentDatasets.py index a1a3d3a1a..91a29770f 100755 --- a/tests/scripts/thread-cert/Cert_9_2_08_PersistentDatasets.py +++ b/tests/scripts/thread-cert/Cert_9_2_08_PersistentDatasets.py @@ -45,7 +45,7 @@ LEADER_ACTIVE_TIMESTAMP = 10 COMMISSIONER_PENDING_CHANNEL = 20 COMMISSIONER_PENDING_PANID = 0xafce -class Cert_9_2_8_DelayTimer(unittest.TestCase): +class Cert_9_2_8_PersistentDatasets(unittest.TestCase): def setUp(self): self.nodes = {} for i in range(1,6): @@ -129,11 +129,8 @@ class Cert_9_2_8_DelayTimer(unittest.TestCase): time.sleep(5) self.nodes[ROUTER].reset() - self._setUpRouter() self.nodes[ED].reset() - self._setUpEd() self.nodes[SED].reset() - self._setUpSed() time.sleep(60) @@ -143,8 +140,15 @@ class Cert_9_2_8_DelayTimer(unittest.TestCase): self.assertEqual(self.nodes[LEADER].get_channel(), COMMISSIONER_PENDING_CHANNEL) self.assertEqual(self.nodes[COMMISSIONER].get_channel(), COMMISSIONER_PENDING_CHANNEL) + # reset the devices here again to simulate the fact that the devices were disabled the entire time + self.nodes[ROUTER].reset() + self._setUpRouter() self.nodes[ROUTER].start() + self.nodes[ED].reset() + self._setUpEd() self.nodes[ED].start() + self.nodes[SED].reset() + self._setUpSed() self.nodes[SED].start() self.assertEqual(self.nodes[ROUTER].get_panid(), PANID_INIT)