Append default Active Dataset sub-tlvs when Leader forms a partition. (#1039)
* if any Active Dataset sub-tlvs missed, append it with default value.
* if any tlv that would affect the network connectivity included in
MGMT_ACTIVE_SET.req, but the value is identical with current one,
take this change as a immediate update.
* update auto-test 9.2.7.
diff --git a/src/core/meshcop/dataset_manager.cpp b/src/core/meshcop/dataset_manager.cpp
index fd347aa..6089518 100644
--- a/src/core/meshcop/dataset_manager.cpp
+++ b/src/core/meshcop/dataset_manager.cpp
@@ -330,14 +330,20 @@
Tlv::Type type;
bool isUpdateFromCommissioner = false;
bool isUpdateAffectConnectivity = false;
+ bool isUpdateIdenticalValue = true;
StateTlv::State state = StateTlv::kAccept;
ActiveTimestampTlv activeTimestamp;
NetworkMasterKeyTlv masterKey;
ChannelTlv channel;
+ MeshLocalPrefixTlv meshLocalPrefix;
+ PanIdTlv panId;
activeTimestamp.SetLength(0);
masterKey.SetLength(0);
+ channel.SetLength(0);
+ meshLocalPrefix.SetLength(0);
+ panId.SetLength(0);
VerifyOrExit(mMle.GetDeviceState() == Mle::kDeviceStateLeader, state = StateTlv::kReject);
@@ -352,7 +358,7 @@
if (tlvType == type)
{
- aMessage.Read(offset + sizeof(Tlv), sizeof(timestamp), ×tamp);
+ aMessage.Read(offset + sizeof(tlv), sizeof(timestamp), ×tamp);
}
switch (tlvType)
@@ -369,6 +375,15 @@
aMessage.Read(offset, sizeof(channel), &channel);
VerifyOrExit(channel.GetChannel() >= kPhyMinChannel && channel.GetChannel() <= kPhyMaxChannel,
state = StateTlv::kReject);
+ break;
+
+ case Tlv::kMeshLocalPrefix:
+ aMessage.Read(offset, sizeof(meshLocalPrefix), &meshLocalPrefix);
+ break;
+
+ case Tlv::kPanId:
+ aMessage.Read(offset, sizeof(panId), &panId);
+ break;
default:
break;
@@ -418,8 +433,22 @@
offset += sizeof(tlv) + tlv.GetLength();
}
+ // verify whether or not tlv value is identical with current one
+ if (isUpdateAffectConnectivity &&
+ (channel.GetChannel() != mNetif.GetMac().GetChannel() ||
+ panId.GetPanId() != mNetif.GetMac().GetPanId() ||
+ memcmp(meshLocalPrefix.GetMeshLocalPrefix(), mNetif.GetMle().GetMeshLocalPrefix(),
+ meshLocalPrefix.GetLength()) != 0 ||
+ memcmp(masterKey.GetNetworkMasterKey(), mNetif.GetKeyManager().GetMasterKey(NULL),
+ masterKey.GetLength()) != 0))
+ {
+ isUpdateIdenticalValue = false;
+ otLogInfoMeshCoP("Request includes tlv that affects connectivity.");
+ }
+
// verify the update from commissioner should not contain tlv would affect connectivity
- VerifyOrExit(!isUpdateFromCommissioner || !isUpdateAffectConnectivity, state = StateTlv::kReject);
+ VerifyOrExit(!isUpdateFromCommissioner || !(isUpdateAffectConnectivity && !isUpdateIdenticalValue),
+ state = StateTlv::kReject);
// verify the request includes a timestamp that is ahead of the locally stored value
VerifyOrExit(offset == aMessage.GetLength() && (mLocal.GetTimestamp() == NULL ||
@@ -446,7 +475,7 @@
mLocal.Set(mNetif.GetActiveDataset().GetNetwork());
}
- if (!isUpdateAffectConnectivity)
+ if (!isUpdateAffectConnectivity || isUpdateIdenticalValue)
{
offset = aMessage.GetOffset();
diff --git a/src/core/meshcop/dataset_manager_ftd.cpp b/src/core/meshcop/dataset_manager_ftd.cpp
index 3171ecd..1435f68 100644
--- a/src/core/meshcop/dataset_manager_ftd.cpp
+++ b/src/core/meshcop/dataset_manager_ftd.cpp
@@ -65,62 +65,128 @@
mCoapServer.AddResource(mResourceGet);
}
+bool ActiveDataset::IsTlvInitialized(Tlv::Type aType)
+{
+ bool rval = false;
+ const Tlv *cur = reinterpret_cast<const Tlv *>(mLocal.GetBytes());
+ const Tlv *end = reinterpret_cast<const Tlv *>(mLocal.GetBytes() + mLocal.GetSize());
+
+ while (cur < end)
+ {
+ if (aType == cur->GetType())
+ {
+ ExitNow(rval = true);
+ }
+
+ cur = cur->GetNext();
+ }
+
+exit:
+ return rval;
+}
+
ThreadError ActiveDataset::GenerateLocal(void)
{
ThreadError error = kThreadError_None;
otOperationalDataset dataset;
- VerifyOrExit(mNetif.GetMle().IsAttached() && mLocal.GetTimestamp() == NULL, error = kThreadError_InvalidState);
+ VerifyOrExit(mNetif.GetMle().IsAttached(), error = kThreadError_InvalidState);
memset(&dataset, 0, sizeof(dataset));
// Active Timestamp
- dataset.mActiveTimestamp = 0;
- dataset.mIsActiveTimestampSet = true;
+ if (!IsTlvInitialized(Tlv::kActiveTimestamp))
+ {
+ ActiveTimestampTlv activeTimestampTlv;
+ activeTimestampTlv.Init();
+ activeTimestampTlv.SetSeconds(0);
+ activeTimestampTlv.SetTicks(0);
+ mLocal.Set(activeTimestampTlv);
+ }
// Channel
- dataset.mChannel = mNetif.GetMac().GetChannel();
- dataset.mIsChannelSet = true;
+ if (!IsTlvInitialized(Tlv::kChannel))
+ {
+ ChannelTlv tlv;
+ tlv.Init();
+ tlv.SetChannelPage(0);
+ tlv.SetChannel(mNetif.GetMac().GetChannel());
+ mLocal.Set(tlv);
+ }
// channelMask
- dataset.mChannelMaskPage0 = kPhySupportedChannelMask;
- dataset.mIsChannelMaskPage0Set = true;
+ if (!IsTlvInitialized(Tlv::kChannelMask))
+ {
+ ChannelMask0Tlv tlv;
+ tlv.Init();
+ tlv.SetMask(kPhySupportedChannelMask);
+ mLocal.Set(tlv);
+ }
// Extended PAN ID
- memcpy(dataset.mExtendedPanId.m8, mNetif.GetMac().GetExtendedPanId(), sizeof(dataset.mExtendedPanId));
- dataset.mIsExtendedPanIdSet = true;
+ if (!IsTlvInitialized(Tlv::kExtendedPanId))
+ {
+ ExtendedPanIdTlv tlv;
+ tlv.Init();
+ tlv.SetExtendedPanId(mNetif.GetMac().GetExtendedPanId());
+ mLocal.Set(tlv);
+ }
// Mesh-Local Prefix
- memcpy(dataset.mMeshLocalPrefix.m8, mNetif.GetMle().GetMeshLocalPrefix(), sizeof(dataset.mMeshLocalPrefix));
- dataset.mIsMeshLocalPrefixSet = true;
+ if (!IsTlvInitialized(Tlv::kMeshLocalPrefix))
+ {
+ MeshLocalPrefixTlv tlv;
+ tlv.Init();
+ tlv.SetMeshLocalPrefix(mNetif.GetMle().GetMeshLocalPrefix());
+ mLocal.Set(tlv);
+ }
// Master Key
- const uint8_t *key;
- uint8_t keyLength;
- key = mNetif.GetKeyManager().GetMasterKey(&keyLength);
- memcpy(dataset.mMasterKey.m8, key, keyLength);
- dataset.mIsMasterKeySet = true;
+ if (!IsTlvInitialized(Tlv::kNetworkMasterKey))
+ {
+ NetworkMasterKeyTlv tlv;
+ tlv.Init();
+ tlv.SetNetworkMasterKey(mNetif.GetKeyManager().GetMasterKey(NULL));
+ mLocal.Set(tlv);
+ }
// Network Name
- const char *name;
- name = mNetif.GetMac().GetNetworkName();
- memcpy(dataset.mNetworkName.m8, name, strlen(name));
- dataset.mIsNetworkNameSet = true;
+ if (!IsTlvInitialized(Tlv::kNetworkMasterKey))
+ {
+ NetworkNameTlv tlv;
+ tlv.Init();
+ tlv.SetNetworkName(mNetif.GetMac().GetNetworkName());
+ mLocal.Set(tlv);
+ }
// Pan ID
- dataset.mPanId = mNetif.GetMac().GetPanId();
- dataset.mIsPanIdSet = true;
+ if (!IsTlvInitialized(Tlv::kPanId))
+ {
+ PanIdTlv tlv;
+ tlv.Init();
+ tlv.SetPanId(mNetif.GetMac().GetPanId());
+ mLocal.Set(tlv);
+ }
// PSKc
- memset(dataset.mPSKc.m8, 0, OT_PSKC_MAX_SIZE);
- dataset.mIsPSKcSet = true;
+ if (!IsTlvInitialized(Tlv::kPSKc))
+ {
+ const uint8_t PSKc[16] = {0};
+ PSKcTlv tlv;
+ tlv.Init();
+ tlv.SetPSKc(PSKc);
+ mLocal.Set(tlv);
+ }
// Security Policy
- dataset.mSecurityPolicy.mRotationTime = static_cast<uint16_t>(mNetif.GetKeyManager().GetKeyRotation());
- dataset.mSecurityPolicy.mFlags = mNetif.GetKeyManager().GetSecurityPolicyFlags();
- dataset.mIsSecurityPolicySet = true;
-
- mLocal.Set(dataset);
+ if (!IsTlvInitialized(Tlv::kSecurityPolicy))
+ {
+ SecurityPolicyTlv tlv;
+ tlv.Init();
+ tlv.SetRotationTime(static_cast<uint16_t>(mNetif.GetKeyManager().GetKeyRotation()));
+ tlv.SetFlags(mNetif.GetKeyManager().GetSecurityPolicyFlags());
+ mLocal.Set(tlv);
+ }
exit:
return error;
@@ -128,10 +194,7 @@
void ActiveDataset::StartLeader(void)
{
- if (mLocal.GetTimestamp() == NULL)
- {
- GenerateLocal();
- }
+ GenerateLocal();
mLocal.Store();
mNetwork = mLocal;
diff --git a/src/core/meshcop/dataset_manager_ftd.hpp b/src/core/meshcop/dataset_manager_ftd.hpp
index 9d94a44..8e7efe0 100644
--- a/src/core/meshcop/dataset_manager_ftd.hpp
+++ b/src/core/meshcop/dataset_manager_ftd.hpp
@@ -65,6 +65,8 @@
const otMessageInfo *aMessageInfo);
void HandleSet(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
+ bool IsTlvInitialized(Tlv::Type aType);
+
Coap::Resource mResourceGet;
Coap::Resource mResourceSet;
};
diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp
index 0ae1fd0..3e66386 100644
--- a/src/core/thread/mle.cpp
+++ b/src/core/thread/mle.cpp
@@ -2522,7 +2522,7 @@
}
else
{
- mNetif.GetPendingDataset().Clear(false);
+ mNetif.GetPendingDataset().Clear(true);
}
// Parent Attach Success
diff --git a/tests/scripts/thread-cert/Cert_9_2_07_DelayTimer.py b/tests/scripts/thread-cert/Cert_9_2_07_DelayTimer.py
index 95b354e..5d2c861 100755
--- a/tests/scripts/thread-cert/Cert_9_2_07_DelayTimer.py
+++ b/tests/scripts/thread-cert/Cert_9_2_07_DelayTimer.py
@@ -41,7 +41,7 @@
LEADER_ACTIVE_TIMESTAMP = 10
ROUTER_ACTIVE_TIMESTAMP = 20
ROUTER_PENDING_TIMESTAMP = 30
-ROUTER_PENDING_ACTIVE_TIMESTAMP = 21
+ROUTER_PENDING_ACTIVE_TIMESTAMP = 25
COMMISSIONER_PENDING_CHANNEL = 20
COMMISSIONER_PENDING_PANID = 0xafce
@@ -59,7 +59,6 @@
self.nodes[COMMISSIONER].enable_whitelist()
self.nodes[COMMISSIONER].set_router_selection_jitter(1)
- self.nodes[LEADER].set_active_dataset(LEADER_ACTIVE_TIMESTAMP)
self.nodes[LEADER].set_mode('rsdn')
self.nodes[LEADER].set_panid(PANID_INIT)
self.nodes[LEADER].set_partition_id(0xffffffff)
@@ -88,6 +87,8 @@
self.nodes[COMMISSIONER].start()
time.sleep(5)
self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'router')
+ self.nodes[COMMISSIONER].commissioner_start()
+ time.sleep(20)
self.nodes[ROUTER].start()
time.sleep(10)