diff --git a/tests/scripts/thread-cert/Cert_9_2_18_RollBackActiveTimestamp.py b/tests/scripts/thread-cert/Cert_9_2_18_RollBackActiveTimestamp.py index f71f1d337..428aeeac4 100755 --- a/tests/scripts/thread-cert/Cert_9_2_18_RollBackActiveTimestamp.py +++ b/tests/scripts/thread-cert/Cert_9_2_18_RollBackActiveTimestamp.py @@ -31,6 +31,9 @@ import unittest import config import thread_cert +from pktverify.consts import MLE_CHILD_ID_RESPONSE, MLE_CHILD_UPDATE_REQUEST, MLE_DATA_RESPONSE, MLE_DATA_REQUEST, MGMT_ACTIVE_SET_URI, MGMT_PENDING_SET_URI, LINK_LOCAL_ALL_NODES_MULTICAST_ADDRESS, TLV_REQUEST_TLV, SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV, PENDING_TIMESTAMP_TLV, PENDING_OPERATION_DATASET_TLV, NM_COMMISSIONER_SESSION_ID_TLV, NM_BORDER_AGENT_LOCATOR_TLV, NM_ACTIVE_TIMESTAMP_TLV, NM_NETWORK_NAME_TLV, NM_NETWORK_MASTER_KEY_TLV, NM_CHANNEL_TLV, NM_CHANNEL_MASK_TLV, NM_EXTENDED_PAN_ID_TLV, NM_NETWORK_MESH_LOCAL_PREFIX_TLV, NM_PAN_ID_TLV, NM_PSKC_TLV, NM_SECURITY_POLICY_TLV, NM_DELAY_TIMER_TLV +from pktverify.packet_verifier import PacketVerifier +from pktverify.addrs import Ipv6Addr KEY1 = '00112233445566778899aabbccddeeff' KEY2 = 'ffeeddccbbaa99887766554433221100' @@ -41,9 +44,8 @@ PANID_INIT = 0xface COMMISSIONER = 1 LEADER = 2 ROUTER1 = 3 -ROUTER2 = 4 -ED1 = 5 -SED1 = 6 +ED1 = 4 +SED1 = 5 MTDS = [ED1, SED1] @@ -53,22 +55,24 @@ class Cert_9_2_18_RollBackActiveTimestamp(thread_cert.TestCase): TOPOLOGY = { COMMISSIONER: { + 'name': 'COMMISSIONER', 'active_dataset': { 'timestamp': 1, 'panid': PANID_INIT, 'channel': CHANNEL_INIT, - 'master_key': '00112233445566778899aabbccddeeff' + 'master_key': KEY1 }, 'mode': 'rsdn', 'router_selection_jitter': 1, 'whitelist': [LEADER] }, LEADER: { + 'name': 'LEADER', 'active_dataset': { 'timestamp': 1, 'panid': PANID_INIT, 'channel': CHANNEL_INIT, - 'master_key': '00112233445566778899aabbccddeeff' + 'master_key': KEY1 }, 'mode': 'rsdn', 'partition_id': 0xffffffff, @@ -76,39 +80,31 @@ class Cert_9_2_18_RollBackActiveTimestamp(thread_cert.TestCase): 'whitelist': [COMMISSIONER, ROUTER1] }, ROUTER1: { + 'name': 'ROUTER_1', 'active_dataset': { 'timestamp': 1, 'panid': PANID_INIT, 'channel': CHANNEL_INIT, - 'master_key': '00112233445566778899aabbccddeeff' + 'master_key': KEY1 }, 'mode': 'rsdn', 'router_selection_jitter': 1, - 'whitelist': [LEADER, ROUTER2, ED1, SED1] - }, - ROUTER2: { - 'active_dataset': { - 'timestamp': 1, - 'panid': PANID_INIT, - 'channel': CHANNEL_INIT, - 'master_key': '00112233445566778899aabbccddeeff' - }, - 'mode': 'rsdn', - 'router_selection_jitter': 1, - 'whitelist': [ROUTER1] + 'whitelist': [LEADER, ED1, SED1] }, ED1: { + 'name': 'ED', 'channel': CHANNEL_INIT, 'is_mtd': True, - 'masterkey': '00112233445566778899aabbccddeeff', + 'masterkey': KEY1, 'mode': 'rsn', 'panid': PANID_INIT, 'whitelist': [ROUTER1] }, SED1: { + 'name': 'SED', 'channel': CHANNEL_INIT, 'is_mtd': True, - 'masterkey': '00112233445566778899aabbccddeeff', + 'masterkey': KEY1, 'mode': 's', 'panid': PANID_INIT, 'timeout': config.DEFAULT_CHILD_TIMEOUT, @@ -145,15 +141,15 @@ class Cert_9_2_18_RollBackActiveTimestamp(thread_cert.TestCase): self.nodes[COMMISSIONER].send_mgmt_pending_set( pending_timestamp=20, active_timestamp=20, - delay_timer=20000, + delay_timer=20, network_name='Shouldnotbe', ) - self.simulator.go(5) + self.simulator.go(30) self.nodes[COMMISSIONER].send_mgmt_pending_set( pending_timestamp=20, active_timestamp=20, - delay_timer=20000, + delay_timer=300, network_name='MyHouse', master_key=KEY2, ) @@ -164,11 +160,98 @@ class Cert_9_2_18_RollBackActiveTimestamp(thread_cert.TestCase): self.assertEqual(self.nodes[ROUTER1].get_masterkey(), KEY2) self.assertEqual(self.nodes[ED1].get_masterkey(), KEY2) self.assertEqual(self.nodes[SED1].get_masterkey(), KEY2) - self.assertEqual(self.nodes[ROUTER2].get_masterkey(), KEY1) - self.nodes[ROUTER2].start() - self.simulator.go(5) - self.assertEqual(self.nodes[ROUTER2].get_state(), 'leader') + self.collect_rlocs() + ed_rloc = self.nodes[ED1].get_rloc() + sed_rloc = self.nodes[SED1].get_rloc() + self.assertTrue(self.nodes[COMMISSIONER].ping(ed_rloc)) + self.assertTrue(self.nodes[COMMISSIONER].ping(sed_rloc)) + + def verify(self, pv): + pkts = pv.pkts + pv.summary.show() + + LEADER = pv.vars['LEADER'] + COMMISSIONER = pv.vars['COMMISSIONER'] + ROUTER_1 = pv.vars['ROUTER_1'] + SED = pv.vars['SED'] + COMMISSIONER_RLOC = pv.vars['COMMISSIONER_RLOC'] + ED_RLOC = pv.vars['ED_RLOC'] + SED_RLOC = pv.vars['SED_RLOC'] + + # Step 1: Ensure the topology is formed correctly + pkts.filter_wpan_src64(ROUTER_1).filter_wpan_dst64(SED).filter_mle_cmd(MLE_CHILD_ID_RESPONSE).must_next() + + # Step 3: Leader MUST send MGMT_ACTIVE_SET.rsp (Accept) to the Commissioner + pkts.filter_wpan_src64(LEADER).filter_ipv6_dst(COMMISSIONER_RLOC).filter_coap_ack( + MGMT_ACTIVE_SET_URI).must_next().must_verify(lambda p: p.thread_meshcop.tlv.state == 1) + + # Step 5: Leader MUST send MGMT_PENDING_SET.rsp (Reject) to the Commissioner + pkts.filter_wpan_src64(LEADER).filter_ipv6_dst(COMMISSIONER_RLOC).filter_coap_ack( + MGMT_PENDING_SET_URI).must_next().must_verify(lambda p: p.thread_meshcop.tlv.state == -1) + + # Step 7: Leader MUST send MGMT_PENDING_SET.rsp (Accept) to Commissioner + pkts.filter_wpan_src64(LEADER).filter_ipv6_dst(COMMISSIONER_RLOC).filter_coap_ack( + MGMT_PENDING_SET_URI).must_next().must_verify(lambda p: p.thread_meshcop.tlv.state == 1) + + # Step 8: Leader MUST multicast a MLE Data Response to the Link-Local All Nodes multicast address + _pkt = pkts.filter_wpan_src64(LEADER).filter_ipv6_dst(LINK_LOCAL_ALL_NODES_MULTICAST_ADDRESS).filter_mle_cmd( + MLE_DATA_RESPONSE).must_next() + _pkt.must_verify(lambda p: { + SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV, PENDING_TIMESTAMP_TLV + } == set(p.mle.tlv.type) and {NM_COMMISSIONER_SESSION_ID_TLV, NM_BORDER_AGENT_LOCATOR_TLV} <= set( + p.thread_meshcop.tlv.type) and p.thread_nwd.tlv.stable == [0]) + + # Step 9: Router MUST send a unicast MLE Data Request to the Leader + pkts.filter_wpan_src64(ROUTER_1).filter_wpan_dst64(LEADER).filter_mle_cmd(MLE_DATA_REQUEST).must_next( + ).must_verify(lambda p: {TLV_REQUEST_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV} <= set(p.mle.tlv.type)) + + # Step 10: Leader MUST send a unicast MLE Data Response to Router_1 + pkts.filter_wpan_src64(LEADER).filter_wpan_dst64(ROUTER_1).filter_mle_cmd( + MLE_DATA_RESPONSE).must_next().must_verify( + lambda p: { + SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV, PENDING_TIMESTAMP_TLV, + PENDING_OPERATION_DATASET_TLV + } == set(p.mle.tlv.type) and { + NM_COMMISSIONER_SESSION_ID_TLV, NM_BORDER_AGENT_LOCATOR_TLV, NM_ACTIVE_TIMESTAMP_TLV, + NM_NETWORK_NAME_TLV, NM_NETWORK_MASTER_KEY_TLV + } <= set(p.thread_meshcop.tlv.type) and p.thread_nwd.tlv.stable == [0]) + + # Step 11: Router MUST multicast a MLE Data Response with the new information + pkts.filter_wpan_src64(ROUTER_1).filter_ipv6_dst(LINK_LOCAL_ALL_NODES_MULTICAST_ADDRESS).filter_mle_cmd( + MLE_DATA_RESPONSE).must_next().must_verify( + lambda p: { + SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV, PENDING_TIMESTAMP_TLV + } == set(p.mle.tlv.type) and p.mle.tlv.leader_data.data_version == _pkt.mle.tlv.leader_data. + data_version and p.mle.tlv.leader_data.stable_data_version == _pkt.mle.tlv.leader_data. + stable_data_version and {NM_COMMISSIONER_SESSION_ID_TLV, NM_BORDER_AGENT_LOCATOR_TLV} <= set( + p.thread_meshcop.tlv.type) and p.thread_nwd.tlv.stable == [0]) + + # Step 12: Router MUST send MLE Child Update Request to SED_1 + pkts.filter_wpan_src64(ROUTER_1).filter_wpan_dst64(SED).filter_mle_cmd( + MLE_CHILD_UPDATE_REQUEST).must_next().must_verify(lambda p: { + SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV, PENDING_TIMESTAMP_TLV + } == set(p.mle.tlv.type) and p.mle.tlv.leader_data.data_version == _pkt.mle.tlv.leader_data.data_version) + + # Step 13: SED MUST send a unicast MLE Data Request to Router_1 + pkts.filter_wpan_src64(SED).filter_wpan_dst64(ROUTER_1).filter_mle_cmd(MLE_DATA_REQUEST).must_next( + ).must_verify(lambda p: {TLV_REQUEST_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV} <= set(p.mle.tlv.type)) + + # Step 14: Router MUST send a unicast MLE Data Response to SED_1 + pkts.filter_wpan_src64(ROUTER_1).filter_wpan_dst64(SED).filter_mle_cmd( + MLE_DATA_RESPONSE).must_next().must_verify( + lambda p: { + SOURCE_ADDRESS_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV, PENDING_TIMESTAMP_TLV, + PENDING_OPERATION_DATASET_TLV + } <= set(p.mle.tlv.type) and { + NM_CHANNEL_TLV, NM_NETWORK_MESH_LOCAL_PREFIX_TLV, NM_PAN_ID_TLV, NM_DELAY_TIMER_TLV, + NM_ACTIVE_TIMESTAMP_TLV, NM_NETWORK_NAME_TLV, NM_NETWORK_MASTER_KEY_TLV + } <= set(p.thread_meshcop.tlv.type) and p.thread_meshcop.tlv.net_name == "MyHouse" and p.thread_meshcop + .tlv.master_key == KEY2) + + # Step 17: MED and SED MUST respond with an ICMPv6 Echo Reply + pkts.filter_ipv6_src_dst(ED_RLOC, COMMISSIONER_RLOC).filter_ping_reply().must_next() + pkts.filter_ipv6_src_dst(SED_RLOC, COMMISSIONER_RLOC).filter_ping_reply().must_next() if __name__ == '__main__': diff --git a/tests/scripts/thread-cert/pktverify/consts.py b/tests/scripts/thread-cert/pktverify/consts.py index d4e36a0b4..a9f0f1ba6 100644 --- a/tests/scripts/thread-cert/pktverify/consts.py +++ b/tests/scripts/thread-cert/pktverify/consts.py @@ -88,6 +88,7 @@ RLY_RX_URI = '/c/rx' RLY_TX_URI = '/c/tx' MGMT_ACTIVE_SET_URI = '/c/as' MGMT_ACTIVE_GET_URI = '/c/ag' +MGMT_PENDING_SET_URI = '/c/ps' # MLE TLVs SOURCE_ADDRESS_TLV = 0 @@ -140,9 +141,14 @@ NM_NETWORK_MASTER_KEY_TLV = 5 NM_NETWORK_KEY_SEQUENCE_COUNTER_TLV = 6 NM_NETWORK_MESH_LOCAL_PREFIX_TLV = 7 NM_STEERING_DATA_TLV = 8 +NM_BORDER_AGENT_LOCATOR_TLV = 9 +NM_COMMISSIONER_ID_TLV = 10 +NM_COMMISSIONER_SESSION_ID_TLV = 11 NM_SECURITY_POLICY_TLV = 12 +NM_ACTIVE_TIMESTAMP_TLV = 14 NM_COMMISSIONER_UDP_PORT_TLV = 15 NM_JOINER_UDP_PORT_TLV = 18 +NM_DELAY_TIMER_TLV = 52 NM_CHANNEL_MASK_TLV = 53 NM_DISCOVERY_RESPONSE_TLV = 129 @@ -213,12 +219,19 @@ AUTO_SEEK_BACK_MAX_DURATION = 0.01 # Wireshark configs WIRESHARK_OVERRIDE_PREFS = { - '6lowpan.context0': 'fd00:db8::/64', - '6lowpan.context1': 'fd00:7d03:7d03:7d03::/64', - 'wpan.802154_fcs_ok': 'FALSE', - 'wpan.802154_sec_suite': 'AES-128 Encryption, 32-bit Integrity Protection', - 'thread.thr_seq_ctr': '00000000', - 'uat:ieee802154_keys': '"00112233445566778899aabbccddeeff","1","Thread hash"', + '6lowpan.context0': + 'fd00:db8::/64', + '6lowpan.context1': + 'fd00:7d03:7d03:7d03::/64', + 'wpan.802154_fcs_ok': + 'FALSE', + 'wpan.802154_sec_suite': + 'AES-128 Encryption, 32-bit Integrity Protection', + 'thread.thr_seq_ctr': + '00000000', + 'uat:ieee802154_keys': + '''"00112233445566778899aabbccddeeff","1","Thread hash" + "ffeeddccbbaa99887766554433221100","1","Thread hash"''', } WIRESHARK_DECODE_AS_ENTRIES = { diff --git a/tests/scripts/thread-cert/pktverify/packet_verifier.py b/tests/scripts/thread-cert/pktverify/packet_verifier.py index 692b6ca69..c10bfb749 100644 --- a/tests/scripts/thread-cert/pktverify/packet_verifier.py +++ b/tests/scripts/thread-cert/pktverify/packet_verifier.py @@ -144,6 +144,10 @@ class PacketVerifier(object): key = self.test_info.get_node_name(i) + '_RLOC16' self._vars[key] = rloc16 + for i, rloc in self.test_info.rlocs.items(): + key = self.test_info.get_node_name(i) + '_RLOC' + self._vars[key] = rloc + for k, v in self.test_info.extra_vars.items(): assert k not in self._vars, k logging.info("add extra var: %s = %s", k, v) diff --git a/tests/scripts/thread-cert/pktverify/test_info.py b/tests/scripts/thread-cert/pktverify/test_info.py index 9198d2be8..5969de632 100644 --- a/tests/scripts/thread-cert/pktverify/test_info.py +++ b/tests/scripts/thread-cert/pktverify/test_info.py @@ -51,6 +51,7 @@ class TestInfo(object): self.ethaddrs = {int(k): EthAddr(v) for k, v in test_info.get('ethaddrs', {}).items()} self.ipaddrs = {int(k): [Ipv6Addr(x) for x in l] for k, l in test_info.get('ipaddrs', {}).items()} self.mleids = {int(k): Ipv6Addr(v) for k, v in test_info.get('mleids', {}).items()} + self.rlocs = {int(k): Ipv6Addr(v) for k, v in test_info.get('rlocs', {}).items()} self.rloc16s = self._convert_hex_values(self._convert_keys_to_ints(test_info.get('rloc16s', {}))) self.extra_vars = test_info.get('extra_vars', {}) diff --git a/tests/scripts/thread-cert/thread_cert.py b/tests/scripts/thread-cert/thread_cert.py index 4c64de299..753600863 100644 --- a/tests/scripts/thread-cert/thread_cert.py +++ b/tests/scripts/thread-cert/thread_cert.py @@ -259,6 +259,16 @@ class TestCase(NcpSupportMixin, unittest.TestCase): for i, node in self.nodes.items(): test_info['rloc16s'][i] = '0x%04x' % node.get_addr16() + def collect_rlocs(self): + if not self._do_packet_verification: + return + + test_info = self._test_info + test_info['rlocs'] = {} + + for i, node in self.nodes.items(): + test_info['rlocs'][i] = node.get_rloc() + def collect_extra_vars(self, **vars): if not self._do_packet_verification: return