From 3166f6a0ed9cd7a5aa4ecea90605ef39dd5547bf Mon Sep 17 00:00:00 2001 From: Jing Ma Date: Sat, 19 Dec 2020 12:24:49 +0800 Subject: [PATCH] [thread-cert] add case 9.2.6 DatasetDissemination using pktverify (#5972) --- .../Cert_9_2_06_DatasetDissemination.py | 875 ++++++++++++++++++ tests/scripts/thread-cert/Makefile.am | 2 + 2 files changed, 877 insertions(+) create mode 100755 tests/scripts/thread-cert/Cert_9_2_06_DatasetDissemination.py diff --git a/tests/scripts/thread-cert/Cert_9_2_06_DatasetDissemination.py b/tests/scripts/thread-cert/Cert_9_2_06_DatasetDissemination.py new file mode 100755 index 000000000..8f7a3a64c --- /dev/null +++ b/tests/scripts/thread-cert/Cert_9_2_06_DatasetDissemination.py @@ -0,0 +1,875 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2020, 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 unittest + +import command +import config +import mesh_cop +import thread_cert +from pktverify.consts import MLE_CHILD_ID_RESPONSE, MLE_CHILD_UPDATE_REQUEST, MLE_DATA_RESPONSE, MLE_DATA_REQUEST, MGMT_COMMISSIONER_SET_URI, MGMT_ACTIVE_SET_URI, MGMT_PENDING_SET_URI, TLV_REQUEST_TLV, SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV, PENDING_TIMESTAMP_TLV, ACTIVE_OPERATION_DATASET_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, NM_STEERING_DATA_TLV, NWD_COMMISSIONING_DATA_TLV, LEADER_ALOC +from pktverify.packet_verifier import PacketVerifier +from pktverify.layer_fields import nullField + +CHANNEL_INIT = 19 +PANID_INIT = 0xface +TIMESTAMP_INIT = 10 +CHANNEL_SECOND = 21 + +COMM_ACTIVE_TIMESTAMP = 15 +COMM_ACTIVE_NET_NAME = 'Thread' +COMM_ACTIVE_PSKC = '10b95765596ab9d0b86cebdd0fa24da3' + +COMM_PENDING_TIMESTAMP = 30 +COMM_PENDING_ACTIVE_TIMESTAMP = 75 +COMM_DELAY_TIMER = 60000 + +COMMISSIONER = 1 +LEADER = 2 +ROUTER = 3 +MED = 4 +SED = 5 + +# Test Purpose and Description: +# ----------------------------- +# DUT as Leader: +# The purpose of this test case is to verify that the Leader device properly +# collects and disseminates Operational Datasets through a Thread network. +# DUT as Router: +# The purpose of this test case is to show that the Router device correctly +# sets the Commissioning information propagated by the Leader device and sends +# it properly to devices already attached to it. +# DUT as MED/SED: +# MED - requires full network data +# SED - requires only stable network data +# Set on Leader: Active TimeStamp = 10s +# +# Test Topology: +# ------------- +# Commissioner +# | +# Leader +# | +# Router +# / \ +# MED SED +# +# DUT Types: +# ---------- +# Leader +# Router +# MED +# SED + + +class Cert_9_2_06_DatasetDissemination(thread_cert.TestCase): + SUPPORT_NCP = False + + TOPOLOGY = { + COMMISSIONER: { + 'name': 'COMMISSIONER', + 'active_dataset': { + 'timestamp': TIMESTAMP_INIT, + 'panid': PANID_INIT, + 'channel': CHANNEL_INIT + }, + 'mode': 'rdn', + 'router_selection_jitter': 1, + 'allowlist': [LEADER] + }, + LEADER: { + 'name': 'LEADER', + 'active_dataset': { + 'timestamp': TIMESTAMP_INIT, + 'panid': PANID_INIT, + 'channel': CHANNEL_INIT + }, + 'mode': 'rdn', + 'router_selection_jitter': 1, + 'allowlist': [COMMISSIONER, ROUTER] + }, + ROUTER: { + 'name': 'ROUTER', + 'active_dataset': { + 'timestamp': TIMESTAMP_INIT, + 'panid': PANID_INIT, + 'channel': CHANNEL_INIT + }, + 'mode': 'rdn', + 'router_selection_jitter': 1, + 'allowlist': [LEADER, MED, SED] + }, + MED: { + 'name': 'MED', + 'channel': CHANNEL_INIT, + 'is_mtd': True, + 'mode': 'rn', + 'panid': PANID_INIT, + 'allowlist': [ROUTER] + }, + SED: { + 'name': 'SED', + 'channel': CHANNEL_INIT, + 'is_mtd': True, + 'mode': '-', + 'panid': PANID_INIT, + 'timeout': config.DEFAULT_CHILD_TIMEOUT, + 'allowlist': [ROUTER] + }, + } + + def test(self): + self.nodes[LEADER].start() + self.simulator.go(5) + self.assertEqual(self.nodes[LEADER].get_state(), 'leader') + + self.nodes[COMMISSIONER].start() + self.simulator.go(5) + self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'router') + self.simulator.get_messages_sent_by(LEADER) + self.nodes[COMMISSIONER].commissioner_start() + self.simulator.go(3) + + leader_messages = self.simulator.get_messages_sent_by(LEADER) + msg = leader_messages.next_coap_message('2.04', assert_enabled=True) + self.nodes[ROUTER].start() + self.simulator.go(5) + self.assertEqual(self.nodes[ROUTER].get_state(), 'router') + + self.nodes[MED].start() + self.simulator.go(5) + self.assertEqual(self.nodes[MED].get_state(), 'child') + + self.nodes[SED].start() + self.simulator.go(5) + self.assertEqual(self.nodes[SED].get_state(), 'child') + + commissioner_session_id_tlv = command.get_sub_tlv(msg.coap.payload, mesh_cop.CommissionerSessionId) + steering_data_tlv = mesh_cop.SteeringData(bytes([0xff])) + # Step 2 + self.nodes[COMMISSIONER].commissioner_mgmtset_with_tlvs([steering_data_tlv, commissioner_session_id_tlv]) + self.simulator.go(10) + + # Step 7 + self.nodes[COMMISSIONER].send_mgmt_active_set( + active_timestamp=COMM_ACTIVE_TIMESTAMP, + network_name=COMM_ACTIVE_NET_NAME, + binary='0410' + COMM_ACTIVE_PSKC, + ) + self.simulator.go(10) + + # Step 18 + self.nodes[COMMISSIONER].send_mgmt_pending_set( + pending_timestamp=COMM_PENDING_TIMESTAMP, + active_timestamp=COMM_PENDING_ACTIVE_TIMESTAMP, + delay_timer=COMM_DELAY_TIMER, + channel=CHANNEL_SECOND, + ) + self.simulator.go(120) + + self.collect_rlocs() + ed_rloc = self.nodes[MED].get_rloc() + sed_rloc = self.nodes[SED].get_rloc() + leader_rloc = self.nodes[LEADER].get_rloc() + router_rloc = self.nodes[ROUTER].get_rloc() + for rloc in (leader_rloc, router_rloc, ed_rloc, sed_rloc): + self.assertTrue(self.nodes[COMMISSIONER].ping(rloc)) + self.simulator.go(10) + + def verify(self, pv): + pkts = pv.pkts + pv.summary.show() + + LEADER = pv.vars['LEADER'] + COMMISSIONER = pv.vars['COMMISSIONER'] + ROUTER = pv.vars['ROUTER'] + MED = pv.vars['MED'] + SED = pv.vars['SED'] + LEADER_RLOC = pv.vars['LEADER_RLOC'] + COMMISSIONER_RLOC = pv.vars['COMMISSIONER_RLOC'] + ROUTER_RLOC = pv.vars['ROUTER_RLOC'] + MED_RLOC = pv.vars['MED_RLOC'] + SED_RLOC = pv.vars['SED_RLOC'] + + # Step 1: Ensure the topology is formed correctly + for node in ('COMMISSIONER', 'ROUTER'): + pv.verify_attached(node, 'LEADER') + for node in ('MED', 'SED'): + pv.verify_attached(node, 'ROUTER', 'MTD') + _pkt = pkts.last() + + # Step 3: Leader sends MGMT_COMMISSIONER_SET.rsp to the Commissioner: + # CoAP Response Code + # 2.04 Changed + # CoAP Payload + # - State TLV (value = Accept) + pkts.filter_coap_ack(MGMT_COMMISSIONER_SET_URI).\ + filter_wpan_src64(LEADER).\ + filter_ipv6_dst(COMMISSIONER_RLOC).\ + must_next().\ + must_verify(lambda p: p.thread_meshcop.tlv.state == 1) + + # Step 4: Leader MUST multicast MLE Data Response to the Link-Local + # All Nodes multicast address (FF02::1) with the new information + # including the following TLVs: + # - Source Address TLV + # - Leader Data TLV: + # Data Version field incremented + # Stable Version field NOT incremented + # - Network Data TLV: + # - Commissioner Data TLV: + # Stable flag set to 0 + # Border Agent Locator TLV + # Commissioner Session ID TLV + # Steering Data TLV + # - Active Timestamp TLV + pkts.filter_mle_cmd(MLE_DATA_RESPONSE). \ + filter_wpan_src64(LEADER). \ + filter_LLANMA(). \ + filter(lambda p: p.mle.tlv.active_tstamp == TIMESTAMP_INIT and \ + (p.mle.tlv.leader_data.data_version - + _pkt.mle.tlv.leader_data.data_version) % 256 <= 127 and \ + p.mle.tlv.leader_data.stable_data_version == + _pkt.mle.tlv.leader_data.stable_data_version and \ + p.thread_nwd.tlv.stable == [0] and \ + NWD_COMMISSIONING_DATA_TLV in p.thread_nwd.tlv.type and \ + NM_COMMISSIONER_SESSION_ID_TLV in p.thread_meshcop.tlv.type and \ + NM_STEERING_DATA_TLV in p.thread_meshcop.tlv.type and \ + NM_BORDER_AGENT_LOCATOR_TLV in p.thread_meshcop.tlv.type + ). \ + must_next() + idx_start = pkts.index + + # Step 5: Router MUST multicast MLE Data Response to the Link-Local + # All Nodes multicast address (FF02::1) with the new information + # including the following TLVs: + # - Source Address TLV + # - Leader Data TLV: + # Data Version field incremented + # Stable Version field NOT incremented + # - Network Data TLV: + # - Commissioner Data TLV: + # Stable flag set to 0 + # Border Agent Locator TLV + # Commissioner Session ID TLV + # Steering Data TLV + # - Active Timestamp TLV + pkts.filter_mle_cmd(MLE_DATA_RESPONSE). \ + filter_wpan_src64(ROUTER). \ + filter_LLANMA(). \ + filter(lambda p: p.mle.tlv.active_tstamp == TIMESTAMP_INIT and \ + (p.mle.tlv.leader_data.data_version - + _pkt.mle.tlv.leader_data.data_version) % 256 <= 127 and \ + p.mle.tlv.leader_data.stable_data_version == + _pkt.mle.tlv.leader_data.stable_data_version and \ + p.thread_nwd.tlv.stable == [0] and \ + NWD_COMMISSIONING_DATA_TLV in p.thread_nwd.tlv.type and \ + NM_COMMISSIONER_SESSION_ID_TLV in p.thread_meshcop.tlv.type and \ + NM_STEERING_DATA_TLV in p.thread_meshcop.tlv.type and \ + NM_BORDER_AGENT_LOCATOR_TLV in p.thread_meshcop.tlv.type + ). \ + must_next() + + # Step 8: Leader sends MGMT_ACTIVE_SET.rsp to the Commissioner: + # CoAP Response Code + # 2.04 Changed + # CoAP Payload + # - State TLV (value = Accept) + pkts.filter_coap_ack(MGMT_ACTIVE_SET_URI). \ + filter_wpan_src64(LEADER). \ + filter_ipv6_dst(COMMISSIONER_RLOC). \ + must_next(). \ + must_verify(lambda p: p.thread_meshcop.tlv.state == 1) + idx_end = pkts.index + + # Step 6: Router MUST NOT send a unicast MLE Data Response or MLE Child + # Update Request to SED_1 + pkts.range(idx_start, idx_end).\ + filter_mle_cmd(MLE_DATA_RESPONSE).\ + filter_wpan_src64(ROUTER).\ + filter_wpan_dst64(SED).\ + must_not_next() + + # Step 9: Leader MUST multicast MLE Data Response to the Link-Local + # All Nodes multicast address (FF02::1) with the new information + # including the following TLVs: + # - Source Address TLV + # - Leader Data TLV: + # Data Version field incremented + # Stable Version field incremented + # - Network Data TLV: + # - Commissioner Data TLV: + # Stable flag set to 0 + # Border Agent Locator TLV + # Commissioner Session ID TLV + # Steering Data TLV + # - Active Timestamp TLV: 15s + _pkt9 = pkts.filter_mle_cmd(MLE_DATA_RESPONSE). \ + filter_wpan_src64(LEADER). \ + filter_LLANMA(). \ + filter(lambda p: p.mle.tlv.active_tstamp == COMM_ACTIVE_TIMESTAMP and \ + (p.mle.tlv.leader_data.data_version - + _pkt.mle.tlv.leader_data.data_version) % 256 <= 127 and \ + (p.mle.tlv.leader_data.stable_data_version - + _pkt.mle.tlv.leader_data.stable_data_version) % 256 <= 127 and \ + p.thread_nwd.tlv.stable == [0] and \ + NWD_COMMISSIONING_DATA_TLV in p.thread_nwd.tlv.type and \ + NM_COMMISSIONER_SESSION_ID_TLV in p.thread_meshcop.tlv.type and \ + NM_STEERING_DATA_TLV in p.thread_meshcop.tlv.type and \ + NM_BORDER_AGENT_LOCATOR_TLV in p.thread_meshcop.tlv.type + ). \ + must_next() + + # Step 10: Router MUST send a unicast MLE Data Request to the Leader, including the + # following TLVs: + # - TLV Request TLV: + # - Network Data TLV + # - Active Timestamp TLV + pkts.filter_wpan_src64(ROUTER).\ + filter_wpan_dst64(LEADER).\ + filter_mle_cmd(MLE_DATA_REQUEST).\ + filter(lambda p: { + TLV_REQUEST_TLV, + NETWORK_DATA_TLV, + ACTIVE_TIMESTAMP_TLV + } <= set(p.mle.tlv.type) and\ + p.thread_meshcop.tlv.type is nullField + ).\ + must_next() + + # Step 11: Leader sends a MLE Data Response to Router_1 including the following TLVs: + # - Source Address TLV + # - Leader Data TLV + # Data version numbers should be + # the same as the ones sent in the + # multicast data response in step 9 + # - Network Data TLV + # - Commissioner Data TLV: + # Stable flag set to 0 + # Border Agent Locator TLV + # Commissioner Session ID TLV + # Steering Data TLV + # - Active Timestamp TLV: + # - Active Operational Dataset TLV + # - Network Name TLV + # - Channel TLV + # - PAN ID TLV + # - PSKc TLV + # MUST NOT contain the Active Timestamp TLV + pkts.filter_mle_cmd(MLE_DATA_RESPONSE). \ + filter_wpan_src64(LEADER). \ + filter_wpan_dst64(ROUTER). \ + filter(lambda p: { + SOURCE_ADDRESS_TLV, + LEADER_DATA_TLV, + ACTIVE_TIMESTAMP_TLV, + ACTIVE_OPERATION_DATASET_TLV + } <= set(p.mle.tlv.type) and \ + { + NM_COMMISSIONER_SESSION_ID_TLV, + NM_BORDER_AGENT_LOCATOR_TLV, + NM_STEERING_DATA_TLV + } <= set(p.thread_meshcop.tlv.type) and \ + p.mle.tlv.leader_data.data_version == + _pkt9.mle.tlv.leader_data.data_version and \ + p.mle.tlv.leader_data.stable_data_version == + _pkt9.mle.tlv.leader_data.stable_data_version and \ + NWD_COMMISSIONING_DATA_TLV in p.thread_nwd.tlv.type and \ + NM_ACTIVE_TIMESTAMP_TLV not in p.thread_meshcop.tlv.type and \ + p.thread_nwd.tlv.stable == [0] and \ + p.mle.tlv.active_tstamp == COMM_ACTIVE_TIMESTAMP and \ + p.thread_meshcop.tlv.channel == [CHANNEL_INIT] and \ + p.thread_meshcop.tlv.net_name == [COMM_ACTIVE_NET_NAME] and \ + p.thread_meshcop.tlv.pskc == COMM_ACTIVE_PSKC and \ + p.thread_meshcop.tlv.pan_id == [PANID_INIT] + ). \ + must_next() + + # Step 12: Router MUST multicast MLE Data Response to the Link-Local + # All Nodes multicast address (FF02::1) with the new information + # including the following TLVs: + # - Source Address TLV + # - Leader Data TLV: + # Data version numbers should be + # the same as the ones sent in the + # multicast data response in step 9 + # - Network Data TLV: + # - Commissioner Data TLV: + # Stable flag set to 0 + # Border Agent Locator TLV + # Commissioner Session ID TLV + # Steering Data TLV + # - Active Timestamp TLV: 15s + with pkts.save_index(): + pkts.filter_mle_cmd(MLE_DATA_RESPONSE). \ + filter_wpan_src64(ROUTER). \ + filter_LLANMA(). \ + filter(lambda p: p.mle.tlv.active_tstamp == COMM_ACTIVE_TIMESTAMP and \ + p.mle.tlv.leader_data.data_version == + _pkt9.mle.tlv.leader_data.data_version and \ + p.mle.tlv.leader_data.stable_data_version == + _pkt9.mle.tlv.leader_data.stable_data_version and \ + p.thread_nwd.tlv.stable == [0] and \ + NWD_COMMISSIONING_DATA_TLV in p.thread_nwd.tlv.type and \ + NM_COMMISSIONER_SESSION_ID_TLV in p.thread_meshcop.tlv.type and \ + NM_STEERING_DATA_TLV in p.thread_meshcop.tlv.type and \ + NM_BORDER_AGENT_LOCATOR_TLV in p.thread_meshcop.tlv.type + ). \ + must_next() + + # Step 13: MED MUST send a unicast MLE Data Request to the Router, including the + # following TLVs: + # - TLV Request TLV: + # - Network Data TLV + # - Active Timestamp TLV + + # Step 14: Router sends a MLE Data Response to MED including the following TLVs: + # - Source Address TLV + # - Leader Data TLV + # Data version numbers should be + # the same as the ones sent in the + # multicast data response in step 9 + # - Network Data TLV + # - Commissioner Data TLV: + # Stable flag set to 0 + # Border Agent Locator TLV + # Commissioner Session ID TLV + # Steering Data TLV + # - Active Timestamp TLV: + # - Active Operational Dataset TLV + # - Network Name TLV + # - Channel TLV + # - PAN ID TLV + # MUST NOT contain the Active Timestamp TLV + with pkts.save_index(): + pkts.filter_wpan_src64(MED). \ + filter_wpan_dst64(ROUTER). \ + filter_mle_cmd(MLE_DATA_REQUEST). \ + filter(lambda p: { + TLV_REQUEST_TLV, + NETWORK_DATA_TLV, + ACTIVE_TIMESTAMP_TLV + } <= set(p.mle.tlv.type) and \ + p.thread_meshcop.tlv.type is nullField + ). \ + must_next() + + pkts.filter_mle_cmd(MLE_DATA_RESPONSE). \ + filter_wpan_src64(ROUTER). \ + filter_wpan_dst64(MED). \ + filter(lambda p: { + SOURCE_ADDRESS_TLV, + LEADER_DATA_TLV, + ACTIVE_TIMESTAMP_TLV, + ACTIVE_OPERATION_DATASET_TLV + } <= set(p.mle.tlv.type) and \ + { + NM_COMMISSIONER_SESSION_ID_TLV, + NM_BORDER_AGENT_LOCATOR_TLV, + NM_STEERING_DATA_TLV + } <= set(p.thread_meshcop.tlv.type) and \ + p.mle.tlv.leader_data.data_version == + _pkt9.mle.tlv.leader_data.data_version and \ + p.mle.tlv.leader_data.stable_data_version == + _pkt9.mle.tlv.leader_data.stable_data_version and \ + NWD_COMMISSIONING_DATA_TLV in p.thread_nwd.tlv.type and \ + NM_ACTIVE_TIMESTAMP_TLV not in p.thread_meshcop.tlv.type and \ + p.thread_nwd.tlv.stable == [0] and \ + p.mle.tlv.active_tstamp == COMM_ACTIVE_TIMESTAMP and \ + p.thread_meshcop.tlv.channel == [CHANNEL_INIT] and \ + p.thread_meshcop.tlv.net_name == [COMM_ACTIVE_NET_NAME] and \ + p.thread_meshcop.tlv.pskc == COMM_ACTIVE_PSKC and \ + p.thread_meshcop.tlv.pan_id == [PANID_INIT] + ). \ + must_next() + + # Step 15: Router MUST send MLE Child Update Request or MLE Data Response + # to SED, including the following TLVs: + # - Source Address TLV + # - Leader Data TLV: + # Data version numbers should be + # the same as the ones sent in the + # multicast data response in step 9 + # - Network Data TLV + # - Active Timestamp TLV: 15s + pkts.filter_wpan_src64(ROUTER). \ + filter_wpan_dst64(SED). \ + filter_mle_cmd2(MLE_CHILD_UPDATE_REQUEST, MLE_DATA_RESPONSE). \ + filter(lambda p: p.mle.tlv.active_tstamp == COMM_ACTIVE_TIMESTAMP and \ + p.mle.tlv.leader_data.data_version == + _pkt9.mle.tlv.leader_data.data_version and \ + p.mle.tlv.leader_data.stable_data_version == + _pkt9.mle.tlv.leader_data.stable_data_version and \ + NETWORK_DATA_TLV in p.mle.tlv.type and\ + SOURCE_ADDRESS_TLV in p.mle.tlv.type + ). \ + must_next() + + # Step 16: SED MUST send a unicast MLE Data Request to the Router, including the + # following TLVs: + # - TLV Request TLV: + # - Network Data TLV + # - Active Timestamp TLV + pkts.filter_wpan_src64(SED). \ + filter_wpan_dst64(ROUTER). \ + filter_mle_cmd(MLE_DATA_REQUEST). \ + filter(lambda p: { + TLV_REQUEST_TLV, + NETWORK_DATA_TLV, + ACTIVE_TIMESTAMP_TLV + } <= set(p.mle.tlv.type) and \ + p.thread_meshcop.tlv.type is nullField + ). \ + must_next() + + # Step 17: Router sends a MLE Data Response to SED including the following TLVs: + # - Source Address TLV + # - Leader Data TLV + # Data version numbers should be + # the same as the ones sent in the + # multicast data response in step 9 + # - Network Data TLV + # - Active Timestamp TLV: <15s> + # - Active Operational Dataset TLV + # - Network Name TLV + # - Channel TLV + # - PAN ID TLV + # MUST NOT contain the Active Timestamp TLV + pkts.filter_mle_cmd(MLE_DATA_RESPONSE). \ + filter_wpan_src64(ROUTER). \ + filter_wpan_dst64(SED). \ + filter(lambda p: { + SOURCE_ADDRESS_TLV, + LEADER_DATA_TLV, + ACTIVE_TIMESTAMP_TLV, + ACTIVE_OPERATION_DATASET_TLV + } <= set(p.mle.tlv.type) and \ + p.mle.tlv.leader_data.data_version == + _pkt9.mle.tlv.leader_data.data_version and \ + p.mle.tlv.leader_data.stable_data_version == + _pkt9.mle.tlv.leader_data.stable_data_version and \ + NM_ACTIVE_TIMESTAMP_TLV not in p.thread_meshcop.tlv.type and \ + p.mle.tlv.active_tstamp == COMM_ACTIVE_TIMESTAMP and \ + p.thread_meshcop.tlv.channel == [CHANNEL_INIT] and \ + p.thread_meshcop.tlv.net_name == [COMM_ACTIVE_NET_NAME] and \ + p.thread_meshcop.tlv.pskc == COMM_ACTIVE_PSKC and \ + p.thread_meshcop.tlv.pan_id == [PANID_INIT] + ). \ + must_next() + + # Step 19: Leader sends MGMT_PENDING_SET.rsp to the Commissioner: + # CoAP Response Code + # 2.04 Changed + # CoAP Payload + # - State TLV (value = Accept) + pkts.filter_coap_ack(MGMT_PENDING_SET_URI). \ + filter_wpan_src64(LEADER). \ + filter_ipv6_dst(COMMISSIONER_RLOC). \ + must_next(). \ + must_verify(lambda p: p.thread_meshcop.tlv.state == 1) + + # Step 20: Leader MUST multicast MLE Data Response to the Link-Local + # All Nodes multicast address (FF02::1) with the new information + # including the following TLVs: + # - Source Address TLV + # - Leader Data TLV: + # Data Version field incremented + # Stable Version field incremented + # - Network Data TLV: + # - Commissioner Data TLV: + # Stable flag set to 0 + # Border Agent Locator TLV + # Commissioner Session ID TLV + # Steering Data TLV + # - Active Timestamp TLV + # - Pending Timestamp TLV + _pkt20 = pkts.filter_mle_cmd(MLE_DATA_RESPONSE). \ + filter_wpan_src64(LEADER). \ + filter_LLANMA(). \ + filter(lambda p: { + SOURCE_ADDRESS_TLV, + LEADER_DATA_TLV, + ACTIVE_TIMESTAMP_TLV, + PENDING_TIMESTAMP_TLV + } <= set(p.mle.tlv.type) and \ + { + NM_COMMISSIONER_SESSION_ID_TLV, + NM_BORDER_AGENT_LOCATOR_TLV, + NM_STEERING_DATA_TLV + } <= set(p.thread_meshcop.tlv.type) and \ + (p.mle.tlv.leader_data.data_version - + _pkt9.mle.tlv.leader_data.data_version) % 256 <= 127 and \ + (p.mle.tlv.leader_data.stable_data_version - + _pkt9.mle.tlv.leader_data.stable_data_version) % 256 <= 127 and \ + p.thread_nwd.tlv.stable == [0] and \ + NWD_COMMISSIONING_DATA_TLV in p.thread_nwd.tlv.type + ). \ + must_next() + + # Step 21: Router MUST send a unicast MLE Data Request to the Leader, including the + # following TLVs: + # - TLV Request TLV: + # - Network Data TLV + # - Active Timestamp TLV + pkts.filter_wpan_src64(ROUTER). \ + filter_wpan_dst64(LEADER). \ + filter_mle_cmd(MLE_DATA_REQUEST). \ + filter(lambda p: { + TLV_REQUEST_TLV, + NETWORK_DATA_TLV, + ACTIVE_TIMESTAMP_TLV + } <= set(p.mle.tlv.type) and \ + p.thread_meshcop.tlv.type is nullField + ). \ + must_next() + + # Step 22: Leader sends a MLE Data Response to Router including the following TLVs: + # - Source Address TLV + # - Leader Data TLV + # - Network Data TLV + # - Commissioner Data TLV: + # Stable flag set to 0 + # Border Agent Locator TLV + # Commissioner Session ID TLV + # Steering Data TLV + # - Active Timestamp TLV + # - Pending Timestamp TLV + # - Pending Operational Dataset TLV + + pkts.filter_mle_cmd(MLE_DATA_RESPONSE). \ + filter_wpan_src64(LEADER). \ + filter_wpan_dst64(ROUTER). \ + filter(lambda p: { + SOURCE_ADDRESS_TLV, + LEADER_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_STEERING_DATA_TLV + } <= set(p.thread_meshcop.tlv.type) and \ + p.thread_nwd.tlv.stable == [0] and \ + NWD_COMMISSIONING_DATA_TLV in p.thread_nwd.tlv.type and \ + p.mle.tlv.active_tstamp == COMM_ACTIVE_TIMESTAMP and \ + p.mle.tlv.pending_tstamp == COMM_PENDING_TIMESTAMP and \ + p.thread_meshcop.tlv.delay_timer < COMM_DELAY_TIMER and \ + p.thread_meshcop.tlv.active_tstamp == COMM_PENDING_ACTIVE_TIMESTAMP and \ + p.thread_meshcop.tlv.channel == [CHANNEL_SECOND] and \ + p.thread_meshcop.tlv.pan_id == [PANID_INIT] + ). \ + must_next() + + # Step 23: Router MUST multicast MLE Data Response to the Link-Local + # All Nodes multicast address (FF02::1) with the new information + # including the following TLVs: + # - Source Address TLV + # - Leader Data TLV: + # Data version numbers should be + # the same as the ones sent in the + # multicast data response in step 20 + # - Network Data TLV: + # - Commissioner Data TLV: + # Stable flag set to 0 + # Border Agent Locator TLV + # Commissioner Session ID TLV + # Steering Data TLV + # - Active Timestamp TLV: 15s + # - Pending Timestamp TLV: 30s + with pkts.save_index(): + pkts.filter_mle_cmd(MLE_DATA_RESPONSE). \ + filter_wpan_src64(ROUTER). \ + filter_LLANMA(). \ + filter(lambda p: { + NM_COMMISSIONER_SESSION_ID_TLV, + NM_BORDER_AGENT_LOCATOR_TLV, + NM_STEERING_DATA_TLV + } <= set(p.thread_meshcop.tlv.type) and \ + p.mle.tlv.active_tstamp == COMM_ACTIVE_TIMESTAMP and \ + p.mle.tlv.pending_tstamp == COMM_PENDING_TIMESTAMP and \ + p.mle.tlv.leader_data.data_version == + _pkt20.mle.tlv.leader_data.data_version and \ + p.mle.tlv.leader_data.stable_data_version == + _pkt20.mle.tlv.leader_data.stable_data_version and \ + p.thread_nwd.tlv.stable == [0] and \ + NWD_COMMISSIONING_DATA_TLV in p.thread_nwd.tlv.type and \ + NM_COMMISSIONER_SESSION_ID_TLV in p.thread_meshcop.tlv.type and \ + NM_STEERING_DATA_TLV in p.thread_meshcop.tlv.type and \ + NM_BORDER_AGENT_LOCATOR_TLV in p.thread_meshcop.tlv.type + ). \ + must_next() + + # Step 24: MED MUST send a unicast MLE Data Request to the Router, including the + # following TLVs: + # - TLV Request TLV: + # - Network Data TLV + # - Active Timestamp TLV + + # Step 25: Router sends a MLE Data Response to MED including the following TLVs: + # - Source Address TLV + # - Leader Data TLV + # Data version numbers should be + # the same as the ones sent in the + # multicast data response in step 20 + # - Network Data TLV + # - Commissioner Data TLV: + # Stable flag set to 0 + # Border Agent Locator TLV + # Commissioner Session ID TLV + # Steering Data TLV + # - Active Timestamp TLV + # - Pending Timestamp TLV + # - Pending Operational Dataset TLV + # - Network Name TLV + # - Channel TLV + # - PAN ID TLV + with pkts.save_index(): + pkts.filter_wpan_src64(MED). \ + filter_wpan_dst64(ROUTER). \ + filter_mle_cmd(MLE_DATA_REQUEST). \ + filter(lambda p: { + TLV_REQUEST_TLV, + NETWORK_DATA_TLV, + ACTIVE_TIMESTAMP_TLV + } <= set(p.mle.tlv.type) and \ + p.thread_meshcop.tlv.type is nullField + ). \ + must_next() + + pkts.filter_mle_cmd(MLE_DATA_RESPONSE). \ + filter_wpan_src64(ROUTER). \ + filter_wpan_dst64(MED). \ + filter(lambda p: { + SOURCE_ADDRESS_TLV, + LEADER_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_STEERING_DATA_TLV + } <= set(p.thread_meshcop.tlv.type) and \ + p.mle.tlv.leader_data.data_version == + _pkt20.mle.tlv.leader_data.data_version and \ + p.mle.tlv.leader_data.stable_data_version == + _pkt20.mle.tlv.leader_data.stable_data_version and \ + p.thread_nwd.tlv.stable == [0] + ). \ + must_next() + + # Step 26: Router MUST send MLE Child Update Request or MLE Data Response + # to SED, including the following TLVs: + # - Source Address TLV + # - Leader Data TLV: + # Data version numbers should be + # the same as the ones sent in the + # multicast data response in step 20 + # - Network Data TLV + # - Active Timestamp TLV: 15s + # - Pending Timestamp TLV: 30s + pkts.filter_wpan_src64(ROUTER). \ + filter_wpan_dst64(SED). \ + filter_mle_cmd2(MLE_CHILD_UPDATE_REQUEST, MLE_DATA_RESPONSE). \ + filter(lambda p: p.mle.tlv.active_tstamp == + COMM_ACTIVE_TIMESTAMP and \ + p.mle.tlv.pending_tstamp == + COMM_PENDING_TIMESTAMP and \ + p.mle.tlv.leader_data.data_version == + _pkt20.mle.tlv.leader_data.data_version and \ + p.mle.tlv.leader_data.stable_data_version == + _pkt20.mle.tlv.leader_data.stable_data_version and \ + NETWORK_DATA_TLV in p.mle.tlv.type + ). \ + must_next() + + # Step 27: SED MUST send a unicast MLE Data Request to the Router, including the + # following TLVs: + # - TLV Request TLV: + # - Network Data TLV + # - Active Timestamp TLV + pkts.filter_wpan_src64(SED). \ + filter_wpan_dst64(ROUTER). \ + filter_mle_cmd(MLE_DATA_REQUEST). \ + filter(lambda p: { + TLV_REQUEST_TLV, + NETWORK_DATA_TLV, + ACTIVE_TIMESTAMP_TLV + } <= set(p.mle.tlv.type) and \ + p.thread_meshcop.tlv.type is nullField + ). \ + must_next() + + # Step 28: Router sends a MLE Data Response to SED including the following TLVs: + # - Source Address TLV + # - Leader Data TLV + # Data version numbers should be + # the same as the ones sent in the + # multicast data response in step 20 + # - Network Data TLV + # - Active Timestamp TLV: 15s + # - Pending Timestamp TLV: 30s + # - Pending Operational Dataset TLV + # - Network Name TLV + # - Channel TLV + # - PAN ID TLV + pkts.filter_mle_cmd(MLE_DATA_RESPONSE). \ + filter_wpan_src64(ROUTER). \ + filter_wpan_dst64(SED). \ + filter(lambda p: { + SOURCE_ADDRESS_TLV, + LEADER_DATA_TLV, + ACTIVE_TIMESTAMP_TLV, + PENDING_TIMESTAMP_TLV, + PENDING_OPERATION_DATASET_TLV + } <= set(p.mle.tlv.type) and \ + p.mle.tlv.leader_data.data_version == + _pkt20.mle.tlv.leader_data.data_version and \ + p.mle.tlv.leader_data.stable_data_version == + _pkt20.mle.tlv.leader_data.stable_data_version and \ + p.mle.tlv.active_tstamp == COMM_ACTIVE_TIMESTAMP and \ + p.mle.tlv.pending_tstamp == COMM_PENDING_TIMESTAMP + ). \ + must_next() + + # Step 30: The DUT MUST respond with an ICMPv6 Echo Reply + for DUT_RLOC in (LEADER_RLOC, ROUTER_RLOC, MED_RLOC, SED_RLOC): + _pkt = pkts.filter_ping_request().\ + filter_ipv6_src_dst(COMMISSIONER_RLOC, DUT_RLOC).\ + must_next() + pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\ + filter_ipv6_src_dst(DUT_RLOC, COMMISSIONER_RLOC).\ + must_next() + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/scripts/thread-cert/Makefile.am b/tests/scripts/thread-cert/Makefile.am index 5aaf1a58a..b7e9ff862 100644 --- a/tests/scripts/thread-cert/Makefile.am +++ b/tests/scripts/thread-cert/Makefile.am @@ -116,6 +116,7 @@ EXTRA_DIST = \ Cert_9_2_03_ActiveDatasetGet.py \ Cert_9_2_04_ActiveDataset.py \ Cert_9_2_05_ActiveDataset.py \ + Cert_9_2_06_DatasetDissemination.py \ Cert_9_2_07_DelayTimer.py \ Cert_9_2_08_PersistentDatasets.py \ Cert_9_2_09_PendingPartition.py \ @@ -302,6 +303,7 @@ check_SCRIPTS = \ Cert_9_2_03_ActiveDatasetGet.py \ Cert_9_2_04_ActiveDataset.py \ Cert_9_2_05_ActiveDataset.py \ + Cert_9_2_06_DatasetDissemination.py \ Cert_9_2_07_DelayTimer.py \ Cert_9_2_08_PersistentDatasets.py \ Cert_9_2_09_PendingPartition.py \