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), &timestamp);
+            aMessage.Read(offset + sizeof(tlv), sizeof(timestamp), &timestamp);
         }
 
         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)