From 4538dafd3d11ee39902c70bcc9bde1887a0c4b7e Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Mon, 17 Oct 2016 17:26:58 -0700 Subject: [PATCH] Add Thread Certification 9.2.4 to automated test. (#823) --- src/cli/cli_dataset.cpp | 7 + src/core/thread/meshcop_dataset_manager.cpp | 8 + src/core/thread/meshcop_tlvs.hpp | 21 ++- tests/scripts/Makefile.am | 3 + .../thread-cert/Cert_9_2_04_ActiveDataset.py | 163 ++++++++++++++++++ .../Cert_9_2_10_PendingPartition.py | 2 +- tests/scripts/thread-cert/node.py | 16 +- 7 files changed, 216 insertions(+), 4 deletions(-) create mode 100755 tests/scripts/thread-cert/Cert_9_2_04_ActiveDataset.py diff --git a/src/cli/cli_dataset.cpp b/src/cli/cli_dataset.cpp index 461f72208..40bc5dae5 100644 --- a/src/cli/cli_dataset.cpp +++ b/src/cli/cli_dataset.cpp @@ -527,6 +527,13 @@ ThreadError Dataset::ProcessMgmtSetCommand(otInstance *aInstance, int argc, char SuccessOrExit(error = Interpreter::ParseLong(argv[++index], value)); dataset.mChannel = static_cast(value); } + else if (strcmp(argv[index], "channelmask") == 0) + { + VerifyOrExit(index < argc, error = kThreadError_Parse); + dataset.mIsChannelMaskPage0Set = true; + SuccessOrExit(error = Interpreter::ParseLong(argv[++index], value)); + dataset.mChannelMaskPage0 = static_cast(value); + } else if (strcmp(argv[index], "binary") == 0) { VerifyOrExit((index + 1) < argc, error = kThreadError_Parse); diff --git a/src/core/thread/meshcop_dataset_manager.cpp b/src/core/thread/meshcop_dataset_manager.cpp index f2976da36..eda19e0ff 100644 --- a/src/core/thread/meshcop_dataset_manager.cpp +++ b/src/core/thread/meshcop_dataset_manager.cpp @@ -538,6 +538,14 @@ ThreadError DatasetManager::SendSetRequest(const otOperationalDataset &aDataset, SuccessOrExit(error = message->Append(&channel, sizeof(channel))); } + if (aDataset.mIsChannelMaskPage0Set) + { + ChannelMask0Tlv channelMask; + channelMask.Init(); + channelMask.SetMask(aDataset.mChannelMaskPage0); + SuccessOrExit(error = message->Append(&channelMask, sizeof(channelMask))); + } + if (aLength > 0) { SuccessOrExit(error = message->Append(aTlvs, aLength)); diff --git a/src/core/thread/meshcop_tlvs.hpp b/src/core/thread/meshcop_tlvs.hpp index 05d83591e..b2638633e 100644 --- a/src/core/thread/meshcop_tlvs.hpp +++ b/src/core/thread/meshcop_tlvs.hpp @@ -1357,13 +1357,32 @@ OT_TOOL_PACKED_BEGIN class ChannelMask0Tlv: public ChannelMaskTlv, public ChannelMaskEntry { public: + /** + * This method initializes the TLV. + * + */ + void Init(void) { + SetType(kChannelMask); + SetLength(sizeof(*this) - sizeof(Tlv)); + SetChannelPage(0); + SetMaskLength(sizeof(mMask)); + } + /** * This method returns the Channel Mask value. * * @returns The Channel Mask value. * */ - uint32_t GetMask(void) { return HostSwap32(mMask); } + uint32_t GetMask(void) { return Thread::Encoding::LittleEndian::HostSwap32(mMask); } + + /** + * This method sets the Channel Mask value. + * + * @param[in] aMask The Channel Mask value. + * + */ + void SetMask(uint32_t aMask) { mMask = Thread::Encoding::LittleEndian::HostSwap32(aMask); } private: uint32_t mMask; diff --git a/tests/scripts/Makefile.am b/tests/scripts/Makefile.am index 339b98bc6..1a9578395 100644 --- a/tests/scripts/Makefile.am +++ b/tests/scripts/Makefile.am @@ -107,6 +107,7 @@ EXTRA_DIST = \ thread-cert/Cert_8_1_02_Commissioning.py \ thread-cert/Cert_8_2_01_JoinerRouter.py \ thread-cert/Cert_8_2_02_JoinerRouter.py \ + thread-cert/Cert_9_2_04_ActiveDataset.py \ thread-cert/Cert_9_2_07_DelayTimer.py \ thread-cert/Cert_9_2_09_PendingPartition.py \ thread-cert/Cert_9_2_10_PendingPartition.py \ @@ -237,6 +238,7 @@ check_SCRIPTS += \ thread-cert/Cert_8_1_02_Commissioning.py \ thread-cert/Cert_8_2_01_JoinerRouter.py \ thread-cert/Cert_8_2_02_JoinerRouter.py \ + thread-cert/Cert_9_2_04_ActiveDataset.py \ thread-cert/Cert_9_2_07_DelayTimer.py \ thread-cert/Cert_9_2_09_PendingPartition.py \ thread-cert/Cert_9_2_10_PendingPartition.py \ @@ -268,6 +270,7 @@ XFAIL_NCP_TESTS = \ thread-cert/Cert_8_1_02_Commissioning.py \ thread-cert/Cert_8_2_01_JoinerRouter.py \ thread-cert/Cert_8_2_02_JoinerRouter.py \ + thread-cert/Cert_9_2_04_ActiveDataset.py \ thread-cert/Cert_9_2_07_DelayTimer.py \ thread-cert/Cert_9_2_09_PendingPartition.py \ thread-cert/Cert_9_2_10_PendingPartition.py \ diff --git a/tests/scripts/thread-cert/Cert_9_2_04_ActiveDataset.py b/tests/scripts/thread-cert/Cert_9_2_04_ActiveDataset.py new file mode 100755 index 000000000..a190459e7 --- /dev/null +++ b/tests/scripts/thread-cert/Cert_9_2_04_ActiveDataset.py @@ -0,0 +1,163 @@ +#!/usr/bin/python +# +# Copyright (c) 2016, 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. +# + +import time +import unittest + +import node + +COMMISSIONER = 1 +LEADER = 2 + +class Cert_9_2_15_PendingPartition(unittest.TestCase): + def setUp(self): + self.nodes = {} + for i in range(1,3): + self.nodes[i] = node.Node(i) + + self.nodes[COMMISSIONER].set_active_dataset(10, panid=0xface, master_key='000102030405060708090a0b0c0d0e0f') + self.nodes[COMMISSIONER].set_mode('rsdn') + self.nodes[COMMISSIONER].set_router_selection_jitter(1) + + self.nodes[LEADER].set_active_dataset(10, panid=0xface, master_key='000102030405060708090a0b0c0d0e0f') + self.nodes[LEADER].set_mode('rsdn') + self.nodes[LEADER].set_router_selection_jitter(1) + + def tearDown(self): + for node in list(self.nodes.values()): + node.stop() + del self.nodes + + def test(self): + self.nodes[LEADER].start() + self.nodes[LEADER].set_state('leader') + self.assertEqual(self.nodes[LEADER].get_state(), 'leader') + + self.nodes[COMMISSIONER].start() + time.sleep(5) + self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'router') + + self.nodes[COMMISSIONER].commissioner_start() + time.sleep(3) + + self.nodes[COMMISSIONER].send_mgmt_active_set(active_timestamp=101, + channel_mask=0x001fffe0, + extended_panid='000db70000000000', + network_name='GRL') + time.sleep(3) + self.assertEqual(self.nodes[LEADER].get_network_name(), 'GRL') + + # Step 6 + # Attempt to set Channel TLV + self.nodes[COMMISSIONER].send_mgmt_active_set(active_timestamp=102, + channel=18, + channel_mask=0x001fffe0, + extended_panid='000db70000000001', + network_name='threadcert') + time.sleep(3) + self.assertEqual(self.nodes[LEADER].get_network_name(), 'GRL') + + # Step 8 + # Attempt to set Mesh Local Prefix TLV + self.nodes[COMMISSIONER].send_mgmt_active_set(active_timestamp=103, + channel_mask=0x001ffee0, + extended_panid='000db70000000000', + mesh_local='fd00:0db7::', + network_name='UL') + time.sleep(3) + self.assertEqual(self.nodes[LEADER].get_network_name(), 'GRL') + + # Step 10 + # Attempt to set Network Master Key TLV + self.nodes[COMMISSIONER].send_mgmt_active_set(active_timestamp=104, + channel_mask=0x001fffe0, + extended_panid='000db70000000000', + master_key='00112233445566778899aabbccddeeff', + mesh_local='fd00:0db7::', + network_name='UL') + time.sleep(3) + self.assertEqual(self.nodes[LEADER].get_network_name(), 'GRL') + + # Step 12 + # Attempt to set PAN ID TLV + self.nodes[COMMISSIONER].send_mgmt_active_set(active_timestamp=105, + channel_mask=0x001fffe0, + extended_panid='000db70000000000', + master_key='00112233445566778899aabbccddeeff', + mesh_local='fd00:0db7::', + network_name='UL', + panid=0xafce) + time.sleep(3) + self.assertEqual(self.nodes[LEADER].get_network_name(), 'GRL') + + # Step 14 + # Invalid Commissioner Session ID + self.nodes[COMMISSIONER].send_mgmt_active_set(active_timestamp=106, + channel_mask=0x001fffe0, + extended_panid='000db70000000000', + network_name='UL', + binary='0b02abcd') + time.sleep(3) + self.assertEqual(self.nodes[LEADER].get_network_name(), 'GRL') + + # Step 16 + # Old Active Timestamp + self.nodes[COMMISSIONER].send_mgmt_active_set(active_timestamp=101, + channel_mask=0x001fffe0, + extended_panid='000db70000000000', + network_name='UL') + time.sleep(3) + self.assertEqual(self.nodes[LEADER].get_network_name(), 'GRL') + + # Step 18 + # Unexpected Steering Data TLV + self.nodes[COMMISSIONER].send_mgmt_active_set(active_timestamp=107, + channel_mask=0x001fffe0, + extended_panid='000db70000000000', + network_name='UL', + binary='0806113320440000') + time.sleep(3) + self.assertEqual(self.nodes[LEADER].get_network_name(), 'UL') + + # Step 20 + # Undefined TLV + self.nodes[COMMISSIONER].send_mgmt_active_set(active_timestamp=108, + channel_mask=0x001fffe0, + extended_panid='000db70000000000', + network_name='GRL', + binary='8202aa55') + time.sleep(3) + self.assertEqual(self.nodes[LEADER].get_network_name(), 'GRL') + + ipaddrs = self.nodes[COMMISSIONER].get_addrs() + for ipaddr in ipaddrs: + self.assertTrue(self.nodes[LEADER].ping(ipaddr)) + +if __name__ == '__main__': + unittest.main() diff --git a/tests/scripts/thread-cert/Cert_9_2_10_PendingPartition.py b/tests/scripts/thread-cert/Cert_9_2_10_PendingPartition.py index 65748ee49..1c0dd7643 100755 --- a/tests/scripts/thread-cert/Cert_9_2_10_PendingPartition.py +++ b/tests/scripts/thread-cert/Cert_9_2_10_PendingPartition.py @@ -146,7 +146,7 @@ class Cert_9_2_10_PendingPartition(unittest.TestCase): self.nodes[LEADER].add_whitelist(self.nodes[ROUTER1].get_addr64()) self.nodes[ROUTER1].add_whitelist(self.nodes[LEADER].get_addr64()) - time.sleep(40) + time.sleep(60) self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'router') self.assertEqual(self.nodes[LEADER].get_state(), 'leader') diff --git a/tests/scripts/thread-cert/node.py b/tests/scripts/thread-cert/node.py index 6cb66b6ea..6d9c743f5 100755 --- a/tests/scripts/thread-cert/node.py +++ b/tests/scripts/thread-cert/node.py @@ -523,8 +523,8 @@ class Node: self.send_command(cmd) self.pexpect.expect('Done') - def send_mgmt_active_set(self, active_timestamp=None, channel=None, panid=None, mesh_local=None, - network_name=None): + def send_mgmt_active_set(self, active_timestamp=None, channel=None, channel_mask=None, extended_panid=None, + panid=None, master_key=None, mesh_local=None, network_name=None, binary=None): cmd = 'dataset mgmtsetcommand active ' if active_timestamp != None: @@ -533,15 +533,27 @@ class Node: if channel != None: cmd += 'channel %d ' % channel + if channel_mask != None: + cmd += 'channelmask %d ' % channel_mask + + if extended_panid != None: + cmd += 'extpanid ' + extended_panid + ' ' + if panid != None: cmd += 'panid %d ' % panid + if master_key != None: + cmd += 'masterkey ' + master_key + ' ' + if mesh_local != None: cmd += 'localprefix ' + mesh_local + ' ' if network_name != None: cmd += 'networkname ' + network_name + ' ' + if binary != None: + cmd += 'binary ' + binary + ' ' + self.send_command(cmd) self.pexpect.expect('Done')