[tests] remove migrated thread-cert scripts (#12566)

This commit removes the certification test scripts in
tests/scripts/thread-cert/ that have been successfully migrated to
the Nexus test framework.

The following tests were migrated and are now available as Nexus
tests under tests/nexus/:
- 5.8.2, 5.8.3, 5.8.4
- 9.2.1 through 9.2.19

Migrating these tests to Nexus provides faster execution, better
reliability, and easier debugging compared to the old
simulation-based scripts.
This commit is contained in:
Jonathan Hui
2026-02-26 13:13:31 -06:00
committed by GitHub
parent bc4228286a
commit a7c051f07a
22 changed files with 0 additions and 6725 deletions
@@ -1,131 +0,0 @@
#!/usr/bin/env python3
#
# 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 unittest
import config
import thread_cert
from pktverify.consts import MLE_ADVERTISEMENT, MLE_CHILD_ID_RESPONSE
from pktverify.packet_verifier import PacketVerifier
LEADER = 1
ROUTER = 2
class Cert_5_8_2_KeyIncrement(thread_cert.TestCase):
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER]
},
ROUTER: {
'name': 'ROUTER',
'mode': 'rdn',
'allowlist': [LEADER]
},
}
def test(self):
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), "leader")
self.nodes[ROUTER].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER].get_state(), "router")
self.collect_ipaddrs()
addrs = self.nodes[ROUTER].get_addrs()
for addr in addrs:
if addr[0:4] != 'fe80':
self.assertTrue(self.nodes[LEADER].ping(addr))
key_sequence_counter = self.nodes[LEADER].get_key_sequence_counter()
self.nodes[LEADER].set_key_sequence_counter(key_sequence_counter + 1)
addrs = self.nodes[ROUTER].get_addrs()
for addr in addrs:
if addr[0:4] != 'fe80':
self.assertTrue(self.nodes[LEADER].ping(addr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
ROUTER = pv.vars['ROUTER']
leader_pkts = pkts.filter_wpan_src64(LEADER)
router_pkts = pkts.filter_wpan_src64(ROUTER)
# Step 1: The DUT must start the network using
# thrKeySequenceCounter = 0
leader_pkts.filter_mle_cmd(MLE_ADVERTISEMENT).must_next().must_verify(lambda p: p.wpan.aux_sec.key_source == 0)
# Step 2: Verify that the topology described above is created.
# MLE Auxiliary security header shall contain Key Source = 0,
# KeyIndex = 1, KeyID Mode = 2
leader_pkts.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).must_next()
_lpkts = leader_pkts.copy()
_rpkts = router_pkts.range(leader_pkts.index)
_rpkts.filter_mle_cmd(
MLE_ADVERTISEMENT).must_next().must_verify(lambda p: p.wpan.aux_sec.key_index == 1 and p.wpan.aux_sec.
key_id_mode == 2 and p.wpan.aux_sec.key_source == 0)
# Step 3: Leader send an ICMPv6 Echo Request to Router_1.
# The MAC Auxiliary security header must contain
# KeyIndex = 1, KeyID Mode = 1
leader_mleid = pv.vars['LEADER_MLEID']
router_mleid = pv.vars['ROUTER_MLEID']
_lpkts.filter(lambda p: p.ipv6.dst == router_mleid).filter_ping_request().must_next().must_verify(
lambda p: p.wpan.aux_sec.key_index == 1 and p.wpan.aux_sec.key_id_mode == 1)
# Step 4: Router_1 send an ICMPv6 Echo Reply to Leader.
# The MAC Auxiliary security header must contain
# KeyIndex = 1, KeyID Mode = 1
_rpkts.filter(lambda p: p.ipv6.dst == leader_mleid).filter_ping_reply().must_next().must_verify(
lambda p: p.wpan.aux_sec.key_index == 1 and p.wpan.aux_sec.key_id_mode == 1)
# Step 5: The DUT MUST set incoming frame counters to 0 for all existing devices.
# Step 6: Leader Send an ICMPv6 Echo Request to Router_1.
# The MAC Auxiliary security header must contain
# KeyIndex = 2, KeyID Mode = 1
_lpkts.filter(lambda p: p.ipv6.dst == router_mleid).filter_ping_request().must_next().must_verify(
lambda p: p.wpan.aux_sec.key_index == 2 and p.wpan.aux_sec.key_id_mode == 1)
# Step 7: Router_1 send an ICMPv6 Echo Reply to Leader.
# The MAC Auxiliary security header must contain
# KeyIndex = 2, KeyID Mode = 1
_rpkts.filter(lambda p: p.ipv6.dst == leader_mleid).filter_ping_reply().must_next().must_verify(
lambda p: p.wpan.aux_sec.key_index == 2 and p.wpan.aux_sec.key_id_mode == 1)
if __name__ == '__main__':
unittest.main()
@@ -1,134 +0,0 @@
#!/usr/bin/env python3
#
# 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 unittest
import config
import thread_cert
from pktverify.consts import MLE_ADVERTISEMENT, MLE_CHILD_ID_RESPONSE
from pktverify.packet_verifier import PacketVerifier
LEADER = 1
ROUTER = 2
class Cert_5_8_3_KeyIncrementRollOver(thread_cert.TestCase):
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'key_sequence_counter': 127,
'mode': 'rdn',
'allowlist': [ROUTER]
},
ROUTER: {
'name': 'ROUTER',
'mode': 'rdn',
'allowlist': [LEADER]
},
}
def test(self):
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER].get_state(), 'router')
self.collect_ipaddrs()
addrs = self.nodes[ROUTER].get_addrs()
for addr in addrs:
if addr[0:4] != 'fe80':
self.assertTrue(self.nodes[LEADER].ping(addr))
key_sequence_counter = self.nodes[LEADER].get_key_sequence_counter()
self.nodes[LEADER].set_key_sequence_counter(key_sequence_counter + 1)
addrs = self.nodes[ROUTER].get_addrs()
for addr in addrs:
if addr[0:4] != 'fe80':
self.assertTrue(self.nodes[LEADER].ping(addr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
ROUTER = pv.vars['ROUTER']
leader_pkts = pkts.filter_wpan_src64(LEADER)
router_pkts = pkts.filter_wpan_src64(ROUTER)
# Step 1: The DUT must start the network using
# thrKeySequenceCounter = 127
_lpkts = leader_pkts.filter_mle_cmd(MLE_ADVERTISEMENT).must_next()
self.assertTrue(_lpkts.wpan.aux_sec.key_source == 127)
# Step 2: Verify that the topology described above is created.
# MLE Auxiliary security header shall contain Key Source = 127,
# KeyIndex = 128, KeyID Mode = 2
leader_pkts.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).must_next()
_lpkts = leader_pkts.copy()
_rpkts = router_pkts.range(leader_pkts.index)
_rpkts.filter_mle_cmd(
MLE_ADVERTISEMENT).must_next().must_verify(lambda p: p.wpan.aux_sec.key_index == 128 and p.wpan.aux_sec.
key_id_mode == 2 and p.wpan.aux_sec.key_source == 127)
# Step 3: Leader send an ICMPv6 Echo Request to Router_1.
# The MAC Auxiliary security header must contain
# KeyIndex = 128, KeyID Mode = 1
leader_mleid = pv.vars['LEADER_MLEID']
router_mleid = pv.vars['ROUTER_MLEID']
_lpkts.filter(lambda p: p.ipv6.dst == router_mleid).filter_ping_request().must_next().must_verify(
lambda p: p.wpan.aux_sec.key_index == 128 and p.wpan.aux_sec.key_id_mode == 1)
# Step 4: Router_1 send an ICMPv6 Echo Reply to Leader.
# The MAC Auxiliary security header must contain
# KeyIndex = 128, KeyID Mode = 1
_rpkts.filter(lambda p: p.ipv6.dst == leader_mleid).filter_ping_reply().must_next().must_verify(
lambda p: p.wpan.aux_sec.key_index == 128 and p.wpan.aux_sec.key_id_mode == 1)
# Step 5: The DUT MUST implementation specific means increment
# thrKeySequenceCounter by 1 to force a key switch
# Step 6: Leader Send an ICMPv6 Echo Request to Router_1.
# The MAC Auxiliary security header must contain
# KeyIndex = 1, KeyID Mode = 1
_lpkts.filter(lambda p: p.ipv6.dst == router_mleid).filter_ping_request().must_next().must_verify(
lambda p: p.wpan.aux_sec.key_index == 1 and p.wpan.aux_sec.key_id_mode == 1)
# Step 7: Router_1 send an ICMPv6 Echo Reply to Leader.
# The MAC Auxiliary security header must contain
# KeyIndex = 1, KeyID Mode = 1
_rpkts.filter(lambda p: p.ipv6.dst == leader_mleid).filter_ping_reply().must_next().must_verify(
lambda p: p.wpan.aux_sec.key_index == 1 and p.wpan.aux_sec.key_id_mode == 1)
if __name__ == '__main__':
unittest.main()
@@ -1,415 +0,0 @@
#!/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
from mesh_cop import TlvType
import config
import thread_cert
from pktverify.consts import MLE_DATA_RESPONSE, MGMT_ACTIVE_SET_URI, MGMT_ACTIVE_GET_URI, LEADER_ALOC, NM_COMMISSIONER_SESSION_ID_TLV, NM_ACTIVE_TIMESTAMP_TLV, NM_SECURITY_POLICY_TLV, NM_NETWORK_KEY_TLV, MLE_DISCOVERY_RESPONSE
from pktverify.packet_verifier import PacketVerifier
from pktverify.layer_fields import nullField
from pktverify.bytes import Bytes
LEADER = 1
COMMISSIONER_1 = 2
COMMISSIONER_2 = 3
THREAD_NODE = 4
# Test Purpose and Description:
# -----------------------------
# The purpose of this test case is to verify network behavior when Security
# Policy TLV “O”,”N”,”R”,”B” bits are disabled. “C” bit is not tested as it
# requires an External Commissioner which is currently not part of Thread
# Certification.
#
# Notes: Due to the packet parsing compatible issue for supporting Thread 1.2
# and 1.1, the security policy values can be fetched only in the unknown
# field.
#
# Test Topology:
# -------------
# Leader ---- Commissioner_2
# Thread_Node |
# Commissioner_1
#
# Notes: Commissioner_2 is introduced in Step 10 and powoff
# Thread_Node sends scan beacon
#
# DUT Types:
# ----------
# Leader
class Cert_5_8_04_SecurityPolicyTLV(thread_cert.TestCase):
SUPPORT_NCP = False
USE_MESSAGE_FACTORY = False
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'active_dataset': {
'timestamp': 1,
'channel': 19,
'network_key': '00112233445566778899aabbccddeeff',
'security_policy': [3600, 'onrc']
},
'mode': 'rdn',
},
COMMISSIONER_1: {
'name': 'COMMISSIONER_1',
'active_dataset': {
'timestamp': 1,
'channel': 19,
'network_key': '00112233445566778899aabbccddeeff',
'security_policy': [3600, 'onrc']
},
'mode': 'rdn',
'allowlist': [LEADER]
},
COMMISSIONER_2: {
'name': 'COMMISSIONER_2',
'mode': 'rdn',
'allowlist': [LEADER]
},
THREAD_NODE: {
'name': 'THREAD_NODE',
'active_dataset': {
'timestamp': 1,
'channel': 19,
'network_key': '00112233445566778899aabbccddeeff',
'security_policy': [3600, 'onrc']
},
'mode': 'rdn',
},
}
def test(self):
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[COMMISSIONER_1].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[COMMISSIONER_1].get_state(), 'router')
self.nodes[COMMISSIONER_1].commissioner_start()
self.simulator.go(5)
self.nodes[COMMISSIONER_1].commissioner_add_joiner('*', 'PSKD01')
self.collect_rlocs()
leader_rloc = self.nodes[LEADER].get_rloc()
# Step 2
self.nodes[COMMISSIONER_1].send_mgmt_active_get()
self.simulator.go(5)
# Step 5
# Disabling O-Bit security_policy = [3600, 0b01110000]
self.nodes[COMMISSIONER_1].send_mgmt_active_set(
active_timestamp=15,
security_policy=[3600, 'nrc'],
)
self.simulator.go(5)
# Step 7
# Get NetworkKey
self.nodes[COMMISSIONER_1].send_mgmt_active_get(leader_rloc, [TlvType.NETWORK_KEY])
self.simulator.go(5)
# Step 9
# Disabling N-Bit security_policy = [3600, 0b10110000]
self.nodes[COMMISSIONER_1].send_mgmt_active_set(
active_timestamp=20,
security_policy=[3600, 'orc'],
)
self.simulator.go(5)
# Step 10
# Add Native Commissioner
self.nodes[COMMISSIONER_2].interface_up()
self.nodes[COMMISSIONER_2].joiner_start('10DKSP')
self.simulator.go(5)
self.nodes[COMMISSIONER_2].reset()
# Step 13
# Disabling B-Bit security_policy = [3600, 0b11110000]
self.nodes[COMMISSIONER_1].send_mgmt_active_set(
active_timestamp=25,
security_policy=[3600, 'onrc'],
)
self.simulator.go(5)
# Step 15
# send beacons
self.nodes[THREAD_NODE].start()
self.simulator.go(2)
self.nodes[THREAD_NODE].scan(result=0)
self.simulator.go(20)
# Step 17
# Disabling R-Bit security_policy = [3600, 0b11010000]
self.nodes[COMMISSIONER_1].send_mgmt_active_set(
active_timestamp=30,
security_policy=[3600, 'onc'],
)
self.simulator.go(5)
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
LEADER_RLOC = pv.vars['LEADER_RLOC']
COMMISSIONER_1 = pv.vars['COMMISSIONER_1']
COMMISSIONER_1_RLOC = pv.vars['COMMISSIONER_1_RLOC']
COMMISSIONER_2 = pv.vars['COMMISSIONER_2']
# Step 1: Ensure the topology is formed correctly
pv.verify_attached('COMMISSIONER_1', 'LEADER')
# Step 2: Commissioner_1 sends MGMT_ACTIVE_GET.req to Leader
# CoAP Request URI
# coap://[<L>]:MM/c/ag
# CoAP Payload
# <empty>
pkts.filter_wpan_src64(COMMISSIONER_1).\
filter_ipv6_2dsts(LEADER_RLOC, LEADER_ALOC).\
filter_coap_request(MGMT_ACTIVE_GET_URI).\
filter(lambda p: p.thread_meshcop.tlv.type is nullField).\
must_next()
# Step 3: Leader MUST send MGMT_ACTIVE_GET.rsp to the Commissioner_1
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# Security Policy TLV
# Bits “O”,”N”,”R”,”C” should be set to 1
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(COMMISSIONER_1_RLOC).\
filter_coap_ack(MGMT_ACTIVE_GET_URI).\
filter(lambda p: (p.thread_meshcop.tlv.sec_policy_rot == 3600 and
p.thread_meshcop.tlv.sec_policy_o == 1 and
p.thread_meshcop.tlv.sec_policy_n == 1 and
p.thread_meshcop.tlv.sec_policy_r == 1 and
p.thread_meshcop.tlv.sec_policy_c == 1) or
(p.thread_meshcop.tlv.unknown == '0e10f7')).\
must_next()
# Step 5: Commissioner_1 sends MGMT_ACTIVE_SET.req to Leader
# CoAP Request URI
# coap://[<L>]:MM/c/as
# CoAP Payload
# Commissioner Session ID TLV
# Active Timestamp TLV > stored value in step 4
# Security Policy TLV with “O” bit disabled
pkts.filter_wpan_src64(COMMISSIONER_1). \
filter_ipv6_2dsts(LEADER_RLOC, LEADER_ALOC). \
filter_coap_request(MGMT_ACTIVE_SET_URI). \
filter(lambda p: {
NM_COMMISSIONER_SESSION_ID_TLV,
NM_ACTIVE_TIMESTAMP_TLV,
NM_SECURITY_POLICY_TLV
} <= set(p.thread_meshcop.tlv.type) and\
p.thread_meshcop.tlv.active_tstamp == 15 and\
(p.thread_meshcop.tlv.sec_policy_o == 0 or
p.thread_meshcop.tlv.unknown == '0e1077')).\
must_next()
# Step 6: Leader MUST send MGMT_ACTIVE_SET.rsp to the Commissioner_1
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# State TLV (value = Accept (0x01))
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(COMMISSIONER_1_RLOC).\
filter_coap_ack(MGMT_ACTIVE_SET_URI).\
filter(lambda p: p.thread_meshcop.tlv.state == 1).\
must_next()
# Step 7: Commissioner_1 sends MGMT_ACTIVE_GET.req to Leader
# CoAP Request URI
# coap://[<L>]:MM/c/ag
# CoAP Payload
# Network Key TLV
pkts.filter_wpan_src64(COMMISSIONER_1).\
filter_ipv6_2dsts(LEADER_RLOC, LEADER_ALOC).\
filter_coap_request(MGMT_ACTIVE_GET_URI).\
filter(lambda p: NM_NETWORK_KEY_TLV in p.thread_meshcop.tlv.type).\
must_next()
# Step 8: Leader MUST send MGMT_ACTIVE_GET.rsp to the Commissioner_1
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# Network Key TLV MUST NOT be included
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(COMMISSIONER_1_RLOC).\
filter_coap_ack(MGMT_ACTIVE_GET_URI).\
filter(lambda p: p.thread_meshcop.tlv.type is nullField).\
must_next()
# Step 9: Commissioner_1 sends MGMT_ACTIVE_SET.req to Leader
# CoAP Request URI
# coap://[<L>]:MM/c/as
# CoAP Payload
# Commissioner Session ID TLV
# Active Timestamp TLV > stored value in step 5
# Security Policy TLV with “N” bit disabled
pkts.filter_wpan_src64(COMMISSIONER_1). \
filter_ipv6_2dsts(LEADER_RLOC, LEADER_ALOC). \
filter_coap_request(MGMT_ACTIVE_SET_URI). \
filter(lambda p: {
NM_COMMISSIONER_SESSION_ID_TLV,
NM_ACTIVE_TIMESTAMP_TLV,
NM_SECURITY_POLICY_TLV
} <= set(p.thread_meshcop.tlv.type) and\
p.thread_meshcop.tlv.active_tstamp == 20 and\
(p.thread_meshcop.tlv.sec_policy_n == 0 or
p.thread_meshcop.tlv.unknown == '0e10b7')).\
must_next()
# Step 10: Leader MUST send MGMT_ACTIVE_SET.rsp to the Commissioner_1
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# State TLV (value = Accept (0x01))
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(COMMISSIONER_1_RLOC).\
filter_coap_ack(MGMT_ACTIVE_SET_URI).\
filter(lambda p: p.thread_meshcop.tlv.state == 1).\
must_next()
# Step 12: Leader MUST send a Discovery Response with Native Commissioning
# bit set to “Not Allowed”
pkts.filter_wpan_src64(LEADER).\
filter_mle_cmd(MLE_DISCOVERY_RESPONSE).\
filter(lambda p: p.thread_meshcop.tlv.discovery_rsp_n == 0).\
must_next()
# Step 13: Commissioner_1 sends MGMT_ACTIVE_SET.req to Leader
# CoAP Request URI
# coap://[<L>]:MM/c/as
# CoAP Payload
# Commissioner Session ID TLV
# Active Timestamp TLV > stored value in step 9
# Security Policy TLV with “B” bit disabled
pkts.filter_wpan_src64(COMMISSIONER_1). \
filter_ipv6_2dsts(LEADER_RLOC, LEADER_ALOC). \
filter_coap_request(MGMT_ACTIVE_SET_URI). \
filter(lambda p: {
NM_COMMISSIONER_SESSION_ID_TLV,
NM_ACTIVE_TIMESTAMP_TLV,
NM_SECURITY_POLICY_TLV
} <= set(p.thread_meshcop.tlv.type) and\
p.thread_meshcop.tlv.active_tstamp == 25 and\
(p.thread_meshcop.tlv.sec_policy_b == 0 or
p.thread_meshcop.tlv.unknown == '0e10f7')).\
must_next()
# Step 14: Leader MUST send MGMT_ACTIVE_SET.rsp to the Commissioner_1
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# State TLV (value = Accept (0x01))
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(COMMISSIONER_1_RLOC).\
filter_coap_ack(MGMT_ACTIVE_SET_URI).\
filter(lambda p: p.thread_meshcop.tlv.state == 1).\
must_next()
# Step 16: The DUT MUST send beacon response frames.The beacon payload MUST
# either be empty OR the payload format MUST be different from the
# Thread Beacon payload The Protocol ID and Version field values
# MUST be different from the values specified for the Thread beacon
# (Protocol ID= 3, Version = 2)
pkts.filter_wpan_src64(LEADER).\
filter_wpan_beacon().\
filter(lambda p:
(p.thread_bcn.protocol is nullField or\
p.thread_bcn.protocol != 3) and\
(p.thread_bcn.version is nullField or\
p.thread_bcn.version != 2)
).\
must_next()
# Step 17: Commissioner_1 sends MGMT_ACTIVE_SET.req to Leader
# CoAP Request URI
# coap://[<L>]:MM/c/as
# CoAP Payload
# Commissioner Session ID TLV
# Active Timestamp TLV > stored value in step 9
# Security Policy TLV with “R” bit disabled
pkts.filter_wpan_src64(COMMISSIONER_1). \
filter_ipv6_2dsts(LEADER_RLOC, LEADER_ALOC). \
filter_coap_request(MGMT_ACTIVE_SET_URI). \
filter(lambda p: {
NM_COMMISSIONER_SESSION_ID_TLV,
NM_ACTIVE_TIMESTAMP_TLV,
NM_SECURITY_POLICY_TLV
} <= set(p.thread_meshcop.tlv.type) and\
p.thread_meshcop.tlv.active_tstamp == 30 and\
(p.thread_meshcop.tlv.sec_policy_r == 0 or
p.thread_meshcop.tlv.unknown == '0e10d7')).\
must_next()
# Step 18: Leader MUST send MGMT_ACTIVE_SET.rsp to the Commissioner_1
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# State TLV (value = Accept (0x01))
# Leader MUST multicast MLE Data Response to the Link-Local All Nodes
# multicast address (FF02::1) with active timestamp value as set in
# Step 17.
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(COMMISSIONER_1_RLOC).\
filter_coap_ack(MGMT_ACTIVE_SET_URI).\
filter(lambda p: p.thread_meshcop.tlv.state == 1).\
must_next()
pkts.filter_wpan_src64(LEADER).\
filter_LLANMA().\
filter_mle_cmd(MLE_DATA_RESPONSE).\
filter(lambda p: p.mle.tlv.active_tstamp == 30).\
must_next()
# Step 20: The DUT MUST send a unicast MLE Data Response to Commissioner_1.
# The Active Operational Set MUST contain a Security Policy TLV with
# R bit set to 0.
pkts.filter_wpan_src64(LEADER).\
filter_wpan_dst64(COMMISSIONER_1). \
filter_mle_cmd(MLE_DATA_RESPONSE).\
filter(lambda p:
p.mle.tlv.active_tstamp == 30 and\
(p.thread_meshcop.tlv.sec_policy_r == 0 or
p.thread_meshcop.tlv.unknown == '0e10d7')).\
must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,279 +0,0 @@
#!/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 config
import thread_cert
from pktverify.consts import MLE_DATA_RESPONSE, MGMT_COMMISSIONER_GET_URI, NM_CHANNEL_TLV, NM_COMMISSIONER_ID_TLV, NM_COMMISSIONER_SESSION_ID_TLV, NM_STEERING_DATA_TLV, NM_BORDER_AGENT_LOCATOR_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV, SOURCE_ADDRESS_TLV, NWD_COMMISSIONING_DATA_TLV, NM_PAN_ID_TLV, NM_NETWORK_NAME_TLV
from pktverify.packet_verifier import PacketVerifier
from pktverify.null_field import nullField
COMMISSIONER = 1
LEADER = 2
# Test Purpose and Description:
# -----------------------------
# The purpose of this test case is to verify Leader's and active Commissioner's behavior via
# MGMT_COMMISSIONER_GET request and response
#
# Test Topology:
# -------------
# Commissioner
# |
# Leader
#
# DUT Types:
# ----------
# Leader
# Commissioner
class Cert_9_2_01_MGMTCommissionerGet(thread_cert.TestCase):
SUPPORT_NCP = False
USE_MESSAGE_FACTORY = True
TOPOLOGY = {
COMMISSIONER: {
'name': 'COMMISSIONER',
'mode': 'rdn',
'allowlist': [LEADER]
},
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [COMMISSIONER]
},
}
def test(self):
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[COMMISSIONER].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'router')
self.collect_leader_aloc(LEADER)
self.collect_rlocs()
self.collect_rloc16s()
self.nodes[COMMISSIONER].commissioner_start()
self.simulator.go(3)
self.nodes[COMMISSIONER].commissioner_mgmtget()
self.simulator.go(5)
self.nodes[COMMISSIONER].commissioner_mgmtget('0b08')
self.simulator.go(5)
self.nodes[COMMISSIONER].commissioner_mgmtget('0b01')
self.simulator.go(5)
self.nodes[COMMISSIONER].commissioner_mgmtget('0903')
self.simulator.go(5)
leader_rloc = self.nodes[LEADER].get_rloc()
commissioner_rloc = self.nodes[COMMISSIONER].get_rloc()
self.assertTrue(self.nodes[COMMISSIONER].ping(leader_rloc))
self.simulator.go(1)
self.assertTrue(self.nodes[LEADER].ping(commissioner_rloc))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
LEADER_ALOC = pv.vars['LEADER_ALOC']
LEADER_RLOC = pv.vars['LEADER_RLOC']
COMMISSIONER = pv.vars['COMMISSIONER']
COMMISSIONER_RLOC = pv.vars['COMMISSIONER_RLOC']
# Step 1: Ensure topology is formed correctly
pv.verify_attached('COMMISSIONER', 'LEADER')
# Step 2: Commissioner sends a MGMT_COMMISSIONER_GET.req to Leader Anycast
# or Routing Locator:
# CoAP Request URI
# CON POST coap://<L>:MM/c/cg
# CoAP Payload
# <empty> - get all Commissioner Dataset parameters
_pkt = pkts.filter_wpan_src64(COMMISSIONER).\
filter_ipv6_2dsts(LEADER_ALOC, LEADER_RLOC).\
filter_coap_request(MGMT_COMMISSIONER_GET_URI).\
filter(lambda p: p.coap.tlv.type is nullField).\
must_next()
# Step 3: Leader sends a MGMT_COMMISSIONER_GET.rsp to Commissioner with
# the following format:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# (entire Commissioner Dataset)
# Border Agent Locator TLV
# Commissioner Session ID TLV
# Steering Data TLV
pkts.filter_ipv6_src_dst(_pkt.ipv6.dst, COMMISSIONER_RLOC).\
filter_coap_ack(MGMT_COMMISSIONER_GET_URI).\
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.thread_meshcop.tlv.ba_locator is not nullField and\
p.thread_meshcop.tlv.commissioner_sess_id is not nullField and\
p.thread_meshcop.tlv.steering_data is not nullField
).\
must_next()
# Step 4: Commissioner sends a MGMT_COMMISSIONER_GET.req to Leader Anycast
# or Routing Locator:
# CoAP Request URI
# CON POST coap://<L>:MM/c/cg
# CoAP Payload
# Commissioner Session ID TLV
# Steering Data TLV
_mgmt_get_pkt = pkts.filter_wpan_src64(COMMISSIONER).\
filter_ipv6_2dsts(LEADER_ALOC, LEADER_RLOC).\
filter_coap_request(MGMT_COMMISSIONER_GET_URI).\
filter(lambda p: {
NM_COMMISSIONER_SESSION_ID_TLV,
NM_STEERING_DATA_TLV
} <= set(p.thread_meshcop.tlv.type)
).\
must_next()
# Step 5: Leader sends a MGMT_COMMISSIONER_GET.rsp to Commissioner with
# the following format:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# Encoded values for the requested Commissioner Dataset parameters
# Commissioner Session ID TLV
# Steering Data TLV
pkts.filter_ipv6_src_dst(_mgmt_get_pkt.ipv6.dst, COMMISSIONER_RLOC).\
filter_coap_ack(MGMT_COMMISSIONER_GET_URI).\
filter(lambda p: {
NM_COMMISSIONER_SESSION_ID_TLV,
NM_STEERING_DATA_TLV
} <= set(p.thread_meshcop.tlv.type) and\
p.thread_meshcop.tlv.commissioner_sess_id is not nullField and\
p.thread_meshcop.tlv.steering_data is not nullField
).\
must_next()
# Step 6: Commissioner sends a MGMT_COMMISSIONER_GET.req to Leader Anycast
# or Routing Locator:
# CoAP Request URI
# CON POST coap://<L>:MM/c/cg
# CoAP Payload
# Commissioner Session ID TLV
# PAN ID TLV
_mgmt_get_pkt = pkts.filter_wpan_src64(COMMISSIONER).\
filter_ipv6_2dsts(LEADER_ALOC, LEADER_RLOC).\
filter_coap_request(MGMT_COMMISSIONER_GET_URI).\
filter(lambda p: {
NM_COMMISSIONER_SESSION_ID_TLV,
NM_PAN_ID_TLV
} <= set(p.thread_meshcop.tlv.type)
).\
must_next()
# Step 7: Leader sends a MGMT_COMMISSIONER_GET.rsp to Commissioner with
# the following format:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# Encoded values for the requested Commissioner Dataset parameters
# Commissioner Session ID TLV
# (PAN ID TLV in Get TLV is ignored)
pkts.filter_ipv6_src_dst(_mgmt_get_pkt.ipv6.dst, COMMISSIONER_RLOC).\
filter_coap_ack(MGMT_COMMISSIONER_GET_URI).\
filter(lambda p: {
NM_COMMISSIONER_SESSION_ID_TLV
} <= set(p.thread_meshcop.tlv.type) and\
p.thread_meshcop.tlv.commissioner_sess_id is not nullField and\
p.thread_meshcop.tlv.pan_id is nullField
).\
must_next()
# Step 8: Commissioner sends a MGMT_COMMISSIONER_GET.req to Leader Anycast
# or Routing Locator:
# CoAP Request URI
# CON POST coap://<L>:MM/c/cg
# CoAP Payload
# Border Agent Locator TLV
# Network Name TLV
_mgmt_get_pkt = pkts.filter_wpan_src64(COMMISSIONER).\
filter_ipv6_2dsts(LEADER_ALOC, LEADER_RLOC).\
filter_coap_request(MGMT_COMMISSIONER_GET_URI).\
filter(lambda p: {
NM_BORDER_AGENT_LOCATOR_TLV,
NM_NETWORK_NAME_TLV
} <= set(p.thread_meshcop.tlv.type)
).\
must_next()
# Step 9: Leader sends a MGMT_COMMISSIONER_GET.rsp to Commissioner with
# the following format:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# Encoded values for the requested Commissioner Dataset parameters
# Border Agent Locator TLV
# (Network Name TLV in Get TLV is ignored)
pkts.filter_ipv6_src_dst(_mgmt_get_pkt.ipv6.dst, COMMISSIONER_RLOC).\
filter_coap_ack(MGMT_COMMISSIONER_GET_URI).\
filter(lambda p: {
NM_BORDER_AGENT_LOCATOR_TLV
} <= set(p.thread_meshcop.tlv.type) and\
p.thread_meshcop.tlv.ba_locator is not nullField and\
p.thread_meshcop.tlv.net_name is nullField
).\
must_next()
# Step 10: Verify connectivity by sending an ICMPv6 Echo Request to the DUT mesh local address
_pkt = pkts.filter_ping_request().\
filter_ipv6_src_dst(COMMISSIONER_RLOC, LEADER_RLOC).\
must_next()
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_ipv6_src_dst(LEADER_RLOC, COMMISSIONER_RLOC).\
must_next()
_pkt = pkts.filter_ping_request().\
filter_ipv6_src_dst(LEADER_RLOC, COMMISSIONER_RLOC).\
must_next()
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_ipv6_src_dst(COMMISSIONER_RLOC, LEADER_RLOC).\
must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,385 +0,0 @@
#!/usr/bin/env python3
#
# Copyright (c) 2019, 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_DATA_RESPONSE, LEAD_PET_URI, LEAD_KA_URI, MGMT_COMMISSIONER_SET_URI, NM_CHANNEL_TLV, NM_COMMISSIONER_ID_TLV, NM_COMMISSIONER_SESSION_ID_TLV, NM_STATE_TLV, NM_STEERING_DATA_TLV, NM_BORDER_AGENT_LOCATOR_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV, SOURCE_ADDRESS_TLV, NWD_COMMISSIONING_DATA_TLV, MESHCOP_ACCEPT, MESHCOP_REJECT, LEADER_ALOC
from pktverify.packet_verifier import PacketVerifier
from pktverify.bytes import Bytes
COMMISSIONER = 1
LEADER = 2
# Test Purpose and Description:
# -----------------------------
# The purpose of this test case is to verify Leader's and active Commissioner's behavior via
# MGMT_COMMISSIONER_SET request and response
#
# Test Topology:
# -------------
# Commissioner
# |
# Leader
#
# DUT Types:
# ----------
# Leader
# Commissioner
class Cert_9_2_02_MGMTCommissionerSet(thread_cert.TestCase):
SUPPORT_NCP = False
TOPOLOGY = {
COMMISSIONER: {
'name': 'COMMISSIONER',
'mode': 'rdn',
'allowlist': [LEADER]
},
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [COMMISSIONER]
},
}
def test(self):
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[COMMISSIONER].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'router')
self.simulator.get_messages_sent_by(LEADER)
self.collect_rlocs()
self.collect_rloc16s()
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)
commissioner_session_id_tlv = command.get_sub_tlv(msg.coap.payload, mesh_cop.CommissionerSessionId)
steering_data_tlv = mesh_cop.SteeringData(bytes([0xff]))
self.nodes[COMMISSIONER].commissioner_mgmtset_with_tlvs([steering_data_tlv])
self.simulator.go(5)
self.nodes[COMMISSIONER].commissioner_mgmtset_with_tlvs([steering_data_tlv, commissioner_session_id_tlv])
self.simulator.go(5)
border_agent_locator_tlv = mesh_cop.BorderAgentLocator(0x0400)
self.nodes[COMMISSIONER].commissioner_mgmtset_with_tlvs(
[commissioner_session_id_tlv, border_agent_locator_tlv])
self.simulator.go(5)
self.nodes[COMMISSIONER].commissioner_mgmtset_with_tlvs([
steering_data_tlv,
commissioner_session_id_tlv,
border_agent_locator_tlv,
])
self.simulator.go(5)
self.nodes[COMMISSIONER].commissioner_mgmtset_with_tlvs(
[mesh_cop.CommissionerSessionId(0xffff), steering_data_tlv])
self.simulator.go(5)
self.nodes[COMMISSIONER].commissioner_mgmtset_with_tlvs([
commissioner_session_id_tlv,
steering_data_tlv,
mesh_cop.Channel(0x0, 0x0),
])
self.simulator.go(5)
leader_rloc = self.nodes[LEADER].get_rloc()
commissioner_rloc = self.nodes[COMMISSIONER].get_rloc()
self.assertTrue(self.nodes[COMMISSIONER].ping(leader_rloc))
self.simulator.go(1)
self.assertTrue(self.nodes[LEADER].ping(commissioner_rloc))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
LEADER_RLOC = pv.vars['LEADER_RLOC']
LEADER_RLOC16 = pv.vars['LEADER_RLOC16']
COMMISSIONER = pv.vars['COMMISSIONER']
COMMISSIONER_RLOC = pv.vars['COMMISSIONER_RLOC']
# Step 1: Ensure topology is formed correctly
pv.verify_attached('COMMISSIONER', 'LEADER')
# Step 2: Commissioner sends a Set Commissioner Dataset Request (MGMT_COMMISSIONER_SET.req)
# to Leader Anycast or Routing Locator:
# CoAP Request URI
# CON POST coap://<L>:MM/c/cs
# CoAP Payload
# (missing Commissioner Session ID TLV)
# Steering Data TLV (0xFF)
_mgmt_set_pkt = pkts.filter_wpan_src64(COMMISSIONER).\
filter_ipv6_2dsts(LEADER_ALOC, LEADER_RLOC).\
filter_coap_request(MGMT_COMMISSIONER_SET_URI).\
filter(lambda p:
[NM_STEERING_DATA_TLV] == p.coap.tlv.type and\
p.thread_meshcop.tlv.steering_data == Bytes('ff')
).\
must_next()
# Step 3: Leader sends a Set Commissioner Dataset Response (MGMT_COMMISSIONER_SET.rsp) to
# Commissioner:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# State TLV (value = Reject)
pkts.filter_ipv6_src_dst(_mgmt_set_pkt.ipv6.dst, COMMISSIONER_RLOC).\
filter_coap_ack(MGMT_COMMISSIONER_SET_URI).\
filter(lambda p:
[NM_STATE_TLV] == p.coap.tlv.type and\
p.thread_meshcop.tlv.state == MESHCOP_REJECT
).\
must_next()
# Step 4: Commissioner sends a Set Commissioner Dataset Request (MGMT_COMMISSIONER_SET.req)
# to Leader Anycast or Routing Locator:
# CoAP Request URI
# CON POST coap://<L>:MM/c/cs
# CoAP Payload
# Commissioner Session ID TLV
# Steering Data TLV (0xFF)
_mgmt_set_pkt = pkts.filter_wpan_src64(COMMISSIONER).\
filter_ipv6_2dsts(LEADER_ALOC, LEADER_RLOC).\
filter_coap_request(MGMT_COMMISSIONER_SET_URI).\
filter(lambda p: {
NM_COMMISSIONER_SESSION_ID_TLV,
NM_STEERING_DATA_TLV
} <= set(p.thread_meshcop.tlv.type) and\
p.thread_meshcop.tlv.steering_data == Bytes('ff')
).\
must_next()
# Step 5: Leader sends a Set Commissioner Dataset Response (MGMT_COMMISSIONER_SET.rsp) to
# Commissioner:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# State TLV (value = Accept)
pkts.filter_ipv6_src_dst(_mgmt_set_pkt.ipv6.dst, COMMISSIONER_RLOC).\
filter_coap_ack(MGMT_COMMISSIONER_SET_URI).\
filter(lambda p:
[NM_STATE_TLV] == p.coap.tlv.type and\
p.thread_meshcop.tlv.state == MESHCOP_ACCEPT
).\
must_next()
# Step 6: Leader sends a MLE Data Response to the network with the
# following TLVs:
# - Active Timestamp TLV
# - Leader Data TLV
# - Network Data TLV
# - Source Address TLV
pkts.filter_wpan_src64(LEADER).\
filter_LLANMA().\
filter_mle_cmd(MLE_DATA_RESPONSE).\
filter(lambda p: {
NETWORK_DATA_TLV,
SOURCE_ADDRESS_TLV,
ACTIVE_TIMESTAMP_TLV,
LEADER_DATA_TLV
} <= set(p.mle.tlv.type) and\
{
NWD_COMMISSIONING_DATA_TLV
} <= set(p.thread_nwd.tlv.type) and\
{
NM_BORDER_AGENT_LOCATOR_TLV,
NM_COMMISSIONER_SESSION_ID_TLV,
NM_STEERING_DATA_TLV
} <= set(p.thread_meshcop.tlv.type) and\
p.thread_nwd.tlv.stable == [0]
).\
must_next()
# Step 7: Commissioner sends a Set Commissioner Dataset Request (MGMT_COMMISSIONER_SET.req)
# to Leader Anycast or Routing Locator:
# CoAP Request URI
# CON POST coap://<L>:MM/c/cs
# CoAP Payload
# Commissioner Session ID TLV
# Border Agent Locator TLV (0x0400) (not allowed TLV)
_mgmt_set_pkt = pkts.filter_wpan_src64(COMMISSIONER).\
filter_ipv6_2dsts(LEADER_ALOC, LEADER_RLOC).\
filter_coap_request(MGMT_COMMISSIONER_SET_URI).\
filter(lambda p: {
NM_COMMISSIONER_SESSION_ID_TLV,
NM_BORDER_AGENT_LOCATOR_TLV
} <= set(p.thread_meshcop.tlv.type) and\
p.thread_meshcop.tlv.ba_locator == 0x0400
).\
must_next()
# Step 8: Leader sends a Set Commissioner Dataset Response (MGMT_COMMISSIONER_SET.rsp) to
# Commissioner:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# State TLV (value = Reject)
pkts.filter_ipv6_src_dst(_mgmt_set_pkt.ipv6.dst, COMMISSIONER_RLOC).\
filter_coap_ack(MGMT_COMMISSIONER_SET_URI).\
filter(lambda p:
[NM_STATE_TLV] == p.coap.tlv.type and\
p.thread_meshcop.tlv.state == MESHCOP_REJECT
).\
must_next()
# Step 9: Commissioner sends a Set Commissioner Dataset Request (MGMT_COMMISSIONER_SET.req)
# to Leader Anycast or Routing Locator:
# CoAP Request URI
# CON POST coap://<L>:MM/c/cs
# CoAP Payload
# Commissioner Session ID TLV
# Steering Data TLV (0xFF)
# Border Agent Locator TLV (0x0400) (not allowed TLV)
_mgmt_set_pkt = pkts.filter_wpan_src64(COMMISSIONER).\
filter_ipv6_2dsts(LEADER_ALOC, LEADER_RLOC).\
filter_coap_request(MGMT_COMMISSIONER_SET_URI).\
filter(lambda p: {
NM_COMMISSIONER_SESSION_ID_TLV,
NM_STEERING_DATA_TLV,
NM_BORDER_AGENT_LOCATOR_TLV
} <= set(p.thread_meshcop.tlv.type) and\
p.thread_meshcop.tlv.ba_locator == 0x0400 and\
p.thread_meshcop.tlv.steering_data == Bytes('ff')
).\
must_next()
# Step 10: Leader sends a Set Commissioner Dataset Response (MGMT_COMMISSIONER_SET.rsp) to
# Commissioner:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# State TLV (value = Reject)
pkts.filter_ipv6_src_dst(_mgmt_set_pkt.ipv6.dst, COMMISSIONER_RLOC).\
filter_coap_ack(MGMT_COMMISSIONER_SET_URI).\
filter(lambda p:
[NM_STATE_TLV] == p.coap.tlv.type and\
p.thread_meshcop.tlv.state == MESHCOP_REJECT
).\
must_next()
# Step 11: Commissioner sends a Set Commissioner Dataset Request (MGMT_COMMISSIONER_SET.req)
# to Leader Anycast or Routing Locator:
# CoAP Request URI
# CON POST coap://<L>:MM/c/cs
# CoAP Payload
# Commissioner Session ID TLV (0xFFFF) (invalid value)
# Steering Data TLV (0xFF)
_mgmt_set_pkt = pkts.filter_wpan_src64(COMMISSIONER).\
filter_ipv6_2dsts(LEADER_ALOC, LEADER_RLOC).\
filter_coap_request(MGMT_COMMISSIONER_SET_URI).\
filter(lambda p: {
NM_COMMISSIONER_SESSION_ID_TLV,
NM_STEERING_DATA_TLV
} <= set(p.thread_meshcop.tlv.type) and\
p.thread_meshcop.tlv.commissioner_sess_id == 0xFFFF and\
p.thread_meshcop.tlv.steering_data == Bytes('ff')
).\
must_next()
# Step 12: Leader sends a Set Commissioner Dataset Response (MGMT_COMMISSIONER_SET.rsp) to
# Commissioner:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# State TLV (value = Reject)
pkts.filter_ipv6_src_dst(_mgmt_set_pkt.ipv6.dst, COMMISSIONER_RLOC).\
filter_coap_ack(MGMT_COMMISSIONER_SET_URI).\
filter(lambda p:
[NM_STATE_TLV] == p.coap.tlv.type and\
p.thread_meshcop.tlv.state == MESHCOP_REJECT
).\
must_next()
# Step 13: Commissioner sends a Set Commissioner Dataset Request (MGMT_COMMISSIONER_SET.req)
# to Leader Anycast or Routing Locator:
# CoAP Request URI
# CON POST coap://<L>:MM/c/cs
# CoAP Payload
# Commissioner Session ID TLV
# Steering Data TLV (0xFF)
# Channel TLV (not allowed TLV)
_mgmt_set_pkt = pkts.filter_wpan_src64(COMMISSIONER).\
filter_ipv6_2dsts(LEADER_ALOC, LEADER_RLOC).\
filter_coap_request(MGMT_COMMISSIONER_SET_URI).\
filter(lambda p: {
NM_COMMISSIONER_SESSION_ID_TLV,
NM_STEERING_DATA_TLV,
NM_CHANNEL_TLV
} <= set(p.thread_meshcop.tlv.type) and\
p.thread_meshcop.tlv.steering_data == Bytes('ff')
).\
must_next()
# Step 14: Leader sends a Set Commissioner Dataset Response (MGMT_COMMISSIONER_SET.rsp) to
# Commissioner:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# State TLV (value = Accept)
pkts.filter_ipv6_src_dst(_mgmt_set_pkt.ipv6.dst, COMMISSIONER_RLOC).\
filter_coap_ack(MGMT_COMMISSIONER_SET_URI).\
filter(lambda p:
[NM_STATE_TLV] == p.coap.tlv.type and\
p.thread_meshcop.tlv.state == MESHCOP_ACCEPT
).\
must_next()
# Step 15: Verify connectivity by sending an ICMPv6 Echo Request to the DUT mesh local address
_pkt = pkts.filter_ping_request().\
filter_ipv6_src_dst(COMMISSIONER_RLOC, LEADER_RLOC).\
must_next()
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_ipv6_src_dst(LEADER_RLOC, COMMISSIONER_RLOC).\
must_next()
_pkt = pkts.filter_ping_request().\
filter_ipv6_src_dst(LEADER_RLOC, COMMISSIONER_RLOC).\
must_next()
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_ipv6_src_dst(COMMISSIONER_RLOC, LEADER_RLOC).\
must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,265 +0,0 @@
#!/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 config
import mesh_cop
import thread_cert
from pktverify.consts import MLE_DATA_RESPONSE, MGMT_ACTIVE_GET_URI, NM_CHANNEL_TLV, NM_COMMISSIONER_ID_TLV, NM_COMMISSIONER_SESSION_ID_TLV, NM_STEERING_DATA_TLV, NM_BORDER_AGENT_LOCATOR_TLV, NM_PAN_ID_TLV, NM_NETWORK_NAME_TLV, NM_NETWORK_MESH_LOCAL_PREFIX_TLV, NM_PSKC_TLV, NM_SCAN_DURATION, NM_ENERGY_LIST_TLV, NM_ACTIVE_TIMESTAMP_TLV, NM_CHANNEL_MASK_TLV, NM_EXTENDED_PAN_ID_TLV, NM_NETWORK_KEY_TLV, NM_SECURITY_POLICY_TLV, LEADER_ALOC
from pktverify.packet_verifier import PacketVerifier
from pktverify.null_field import nullField
COMMISSIONER = 1
LEADER = 2
# Test Purpose and Description:
# -----------------------------
# The purpose of this test case is to verify Leader's and active Commissioner's behavior via
# MGMT_ACTIVE_GET request and response
#
# Test Topology:
# -------------
# Commissioner
# |
# Leader
#
# DUT Types:
# ----------
# Leader
# Commissioner
class Cert_9_2_03_ActiveDatasetGet(thread_cert.TestCase):
SUPPORT_NCP = False
USE_MESSAGE_FACTORY = False
TOPOLOGY = {
COMMISSIONER: {
'name': 'COMMISSIONER',
'mode': 'rdn',
'allowlist': [LEADER]
},
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [COMMISSIONER]
},
}
def test(self):
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[COMMISSIONER].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'router')
self.collect_rlocs()
self.collect_rloc16s()
leader_rloc = self.nodes[LEADER].get_rloc()
self.nodes[COMMISSIONER].commissioner_start()
self.simulator.go(3)
self.nodes[COMMISSIONER].send_mgmt_active_get()
self.simulator.go(5)
self.nodes[COMMISSIONER].send_mgmt_active_get(
leader_rloc,
[mesh_cop.TlvType.CHANNEL_MASK, mesh_cop.TlvType.NETWORK_MESH_LOCAL_PREFIX, mesh_cop.TlvType.NETWORK_NAME])
self.simulator.go(5)
self.nodes[COMMISSIONER].send_mgmt_active_get(leader_rloc, [
mesh_cop.TlvType.CHANNEL, mesh_cop.TlvType.NETWORK_MESH_LOCAL_PREFIX, mesh_cop.TlvType.NETWORK_NAME,
mesh_cop.TlvType.SCAN_DURATION, mesh_cop.TlvType.ENERGY_LIST
])
self.simulator.go(5)
commissioner_rloc = self.nodes[COMMISSIONER].get_rloc()
self.assertTrue(self.nodes[COMMISSIONER].ping(leader_rloc))
self.simulator.go(1)
self.assertTrue(self.nodes[LEADER].ping(commissioner_rloc))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
LEADER_RLOC = pv.vars['LEADER_RLOC']
COMMISSIONER = pv.vars['COMMISSIONER']
COMMISSIONER_RLOC = pv.vars['COMMISSIONER_RLOC']
# Step 1: Ensure topology is formed correctly
pv.verify_attached('COMMISSIONER', 'LEADER')
# Step 2: Commissioner sends a MGMT_ACTIVE_GET.req to Leader Anycast
# or Routing Locator:
# CoAP Request URI
# CON POST coap://<L>:MM/c/ag
# CoAP Payload
# <empty> - get all Active Operational Dataset parameters
_pkt = pkts.filter_wpan_src64(COMMISSIONER).\
filter_ipv6_2dsts(LEADER_ALOC, LEADER_RLOC).\
filter_coap_request(MGMT_ACTIVE_GET_URI).\
filter(lambda p: p.coap.tlv.type is nullField).\
must_next()
# Step 3: Leader sends a MGMT_ACTIVE_GET.rsp to Commissioner with
# the following format:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# (entire Active Operational Dataset)
# Active Timestamp TLV
# Channel TLV
# Channel Mask TLV
# Extended PAN ID TLV
# Network Mesh-Local Prefix TLV
# Network Key TLV
# Network Name TLV
# PAN ID TLV
# PSKc TLV
# Security Policy TLV
pkts.filter_ipv6_src_dst(_pkt.ipv6.dst, COMMISSIONER_RLOC).\
filter_coap_ack(MGMT_ACTIVE_GET_URI).\
filter(lambda p: {
NM_ACTIVE_TIMESTAMP_TLV,
NM_CHANNEL_TLV,
NM_CHANNEL_MASK_TLV,
NM_EXTENDED_PAN_ID_TLV,
NM_NETWORK_MESH_LOCAL_PREFIX_TLV,
NM_NETWORK_KEY_TLV,
NM_NETWORK_NAME_TLV,
NM_PAN_ID_TLV,
NM_PSKC_TLV,
NM_SECURITY_POLICY_TLV
} <= set(p.thread_meshcop.tlv.type)
).\
must_next()
# Step 4: Commissioner sends a MGMT_ACTIVE_GET.req to Leader Anycast
# or Routing Locator:
# CoAP Request URI
# CON POST coap://<L>:MM/c/ag
# CoAP Payload
# Channel Mask TLV
# Network Mesh-Local Prefix TLV
# Network Name TLV
pkts.filter_wpan_src64(COMMISSIONER).\
filter_ipv6_2dsts(LEADER_ALOC, LEADER_RLOC).\
filter_coap_request(MGMT_ACTIVE_GET_URI).\
filter(lambda p: {
NM_CHANNEL_MASK_TLV,
NM_NETWORK_MESH_LOCAL_PREFIX_TLV,
NM_NETWORK_NAME_TLV
} <= set(p.thread_meshcop.tlv.type)
).\
must_next()
# Step 5: Leader sends a MGMT_ACTIVE_GET.rsp to Commissioner with
# the following format:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# Channel Mask TLV
# Network Mesh-Local Prefix TLV
# Network Name TLV
pkts.filter_ipv6_src_dst(LEADER_RLOC, COMMISSIONER_RLOC).\
filter_coap_ack(MGMT_ACTIVE_GET_URI).\
filter(lambda p: {
NM_CHANNEL_MASK_TLV,
NM_NETWORK_MESH_LOCAL_PREFIX_TLV,
NM_NETWORK_NAME_TLV
} <= set(p.thread_meshcop.tlv.type)
).\
must_next()
# Step 6: Commissioner sends a MGMT_ACTIVE_GET.req to Leader Anycast
# or Routing Locator:
# CoAP Request URI
# CON POST coap://<L>:MM/c/ag
# CoAP Payload
# Channel TLV
# Network Mesh-Local Prefix TLV
# Network Name TLV
# Scan Duration TLV (not allowed TLV)
# Energy List TLV (not allowed TLV)
pkts.filter_wpan_src64(COMMISSIONER).\
filter_ipv6_2dsts(LEADER_ALOC, LEADER_RLOC).\
filter_coap_request(MGMT_ACTIVE_GET_URI).\
filter(lambda p: {
NM_CHANNEL_TLV,
NM_NETWORK_MESH_LOCAL_PREFIX_TLV,
NM_NETWORK_NAME_TLV,
NM_SCAN_DURATION,
NM_ENERGY_LIST_TLV
} <= set(p.thread_meshcop.tlv.type)
).\
must_next()
# Step 7: Leader sends a MGMT_ACTIVE_GET.rsp to Commissioner with
# the following format:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# Channel TLV
# Network Mesh-Local Prefix TLV
# Network Name TLV
pkts.filter_ipv6_src_dst(LEADER_RLOC, COMMISSIONER_RLOC).\
filter_coap_ack(MGMT_ACTIVE_GET_URI).\
filter(lambda p: {
NM_CHANNEL_TLV,
NM_NETWORK_MESH_LOCAL_PREFIX_TLV,
NM_NETWORK_NAME_TLV,
} <= set(p.thread_meshcop.tlv.type)
).\
must_next()
# Step 8: Verify connectivity by sending an ICMPv6 Echo Request to the
# DUT mesh local address
_pkt = pkts.filter_ping_request().\
filter_ipv6_src_dst(COMMISSIONER_RLOC, LEADER_RLOC).\
must_next()
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_ipv6_src_dst(LEADER_RLOC, COMMISSIONER_RLOC).\
must_next()
_pkt = pkts.filter_ping_request().\
filter_ipv6_src_dst(LEADER_RLOC, COMMISSIONER_RLOC).\
must_next()
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_ipv6_src_dst(COMMISSIONER_RLOC, LEADER_RLOC).\
must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,319 +0,0 @@
#!/usr/bin/env python3
#
# 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 unittest
import config
import thread_cert
from pktverify.consts import MLE_CHILD_ID_RESPONSE, MGMT_ACTIVE_SET_URI, MGMT_ACTIVE_GET_URI
from pktverify.packet_verifier import PacketVerifier
from pktverify.bytes import Bytes
COMMISSIONER = 1
LEADER = 2
class Cert_9_2_04_ActiveDataset(thread_cert.TestCase):
SUPPORT_NCP = False
TOPOLOGY = {
COMMISSIONER: {
'name': 'COMMISSIONER',
'active_dataset': {
'timestamp': 10,
'network_key': '00112233445566778899aabbccddeeff'
},
'mode': 'rdn',
'allowlist': [LEADER]
},
LEADER: {
'name': 'LEADER',
'active_dataset': {
'timestamp': 10,
'network_key': '00112233445566778899aabbccddeeff'
},
'mode': 'rdn',
'allowlist': [COMMISSIONER]
},
}
def test(self):
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[COMMISSIONER].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'router')
self.nodes[COMMISSIONER].commissioner_start()
self.simulator.go(5)
self.collect_rlocs()
self.collect_leader_aloc(LEADER)
# Step 2
self.nodes[COMMISSIONER].send_mgmt_active_set(
active_timestamp=101,
channel_mask=0x7fff800,
extended_panid='000db70000000000',
network_name='GRL',
)
self.simulator.go(5)
self.assertEqual(self.nodes[LEADER].get_network_name(), 'GRL')
self.nodes[COMMISSIONER].send_mgmt_active_get()
self.simulator.go(5)
# Step 6
# Attempt to set Channel TLV
self.nodes[COMMISSIONER].send_mgmt_active_set(
active_timestamp=102,
channel=18,
channel_mask=0x7fff800,
extended_panid='000db70000000001',
network_name='threadcert',
)
self.simulator.go(5)
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=0x7fff800,
extended_panid='000db70000000000',
mesh_local='fd00:0db7::',
network_name='UL',
)
self.simulator.go(5)
self.assertEqual(self.nodes[LEADER].get_network_name(), 'GRL')
# Step 10
# Attempt to set Network Key TLV
self.nodes[COMMISSIONER].send_mgmt_active_set(
active_timestamp=104,
channel_mask=0x7fff800,
extended_panid='000db70000000000',
network_key='ffeeddccbbaa99887766554433221100',
mesh_local='fd00:0db7::',
network_name='GRL',
)
self.simulator.go(5)
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=0x7fff800,
extended_panid='000db70000000000',
network_key='00112233445566778899aabbccddeeff',
mesh_local='fd00:0db7::',
network_name='UL',
panid=0xafce,
)
self.simulator.go(5)
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=0x7fff800,
extended_panid='000db70000000000',
network_name='UL',
binary='0b02abcd',
)
self.simulator.go(5)
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=0x01fff800,
extended_panid='000db70000000000',
network_name='UL',
)
self.simulator.go(5)
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=0x7fff800,
extended_panid='000db70000000000',
network_name='UL',
binary='0806113320440000',
)
self.simulator.go(5)
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=0x7fff800,
extended_panid='000db70000000000',
network_name='GRL',
binary='8202aa55',
)
self.simulator.go(5)
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))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
LEADER_RLOC = pv.vars['LEADER_RLOC']
LEADER_ALOC = pv.vars['LEADER_ALOC']
COMMISSIONER = pv.vars['COMMISSIONER']
COMMISSIONER_RLOC = pv.vars['COMMISSIONER_RLOC']
# Step 1: Ensure the topology is formed correctly
pkts.filter_wpan_src64(LEADER).filter_wpan_dst64(COMMISSIONER).filter_mle_cmd(
MLE_CHILD_ID_RESPONSE).must_next()
# Step 2: Commissioner sends MGMT_ACTIVE_SET.req to Leader RLOC or Anycast Locator
pkts.filter_wpan_src64(COMMISSIONER).filter_ipv6_2dsts(LEADER_RLOC, LEADER_ALOC).filter_coap_request(
MGMT_ACTIVE_SET_URI).filter(lambda p: p.thread_meshcop.tlv.xpan_id == '000db70000000000' and p.
thread_meshcop.tlv.net_name == ['GRL'] and p.thread_meshcop.tlv.chan_mask_mask
== '001fffe0' and p.thread_meshcop.tlv.active_tstamp == 101).must_next()
# Step 3: Leader MUST send MGMT_ACTIVE_SET.rsp to the Commissioner
pkts.filter_wpan_src64(LEADER).filter_ipv6_dst(COMMISSIONER_RLOC).filter_coap_ack(MGMT_ACTIVE_SET_URI).filter(
lambda p: p.thread_meshcop.tlv.state == 1).must_next()
# Step 4: Commissioner sends MGMT_ACTIVE_GET.req to Leader
pkts.filter_wpan_src64(COMMISSIONER).filter_ipv6_2dsts(
LEADER_RLOC, LEADER_ALOC).filter_coap_request(MGMT_ACTIVE_GET_URI).must_next()
# Step 5: The Leader MUST send MGMT_ACTIVE_GET.rsp to the Commissioner
pkts.filter_wpan_src64(LEADER).filter_ipv6_dst(COMMISSIONER_RLOC).filter_coap_ack(
MGMT_ACTIVE_GET_URI).filter(lambda p: p.thread_meshcop.tlv.active_tstamp == 101 and p.thread_meshcop.tlv.
xpan_id == '000db70000000000' and p.thread_meshcop.tlv.net_name == ['GRL'] and
p.thread_meshcop.tlv.chan_mask_mask == '001fffe0').must_next()
# Step 6: Commissioner sends MGMT_ACTIVE_SET.req to Leader RLOC or Anycast Locator
pkts.filter_wpan_src64(COMMISSIONER).filter_ipv6_2dsts(
LEADER_RLOC, LEADER_ALOC).filter_coap_request(MGMT_ACTIVE_SET_URI).filter(
lambda p: p.thread_meshcop.tlv.active_tstamp == 102 and p.thread_meshcop.tlv.xpan_id ==
'000db70000000001' and p.thread_meshcop.tlv.net_name == ['threadcert'] and p.thread_meshcop.tlv.
chan_mask_mask == '001fffe0' and p.thread_meshcop.tlv.channel == [18]).must_next()
# Step 7: Leader MUST send MGMT_ACTIVE_SET.rsp to the Commissioner
pkts.filter_wpan_src64(LEADER).filter_ipv6_dst(COMMISSIONER_RLOC).filter_coap_ack(MGMT_ACTIVE_SET_URI).filter(
lambda p: p.thread_meshcop.tlv.state == -1).must_next()
# Step 8: Commissioner sends MGMT_ACTIVE_SET.req to Leader RLOC or Leader Anycast Locator
pkts.filter_wpan_src64(COMMISSIONER).filter_ipv6_2dsts(
LEADER_RLOC, LEADER_ALOC).filter_coap_request(MGMT_ACTIVE_SET_URI).filter(
lambda p: p.thread_meshcop.tlv.active_tstamp == 103 and p.thread_meshcop.tlv.xpan_id ==
'000db70000000000' and p.thread_meshcop.tlv.net_name == ['UL'] and p.thread_meshcop.tlv.chan_mask_mask
== '001fffe0' and p.thread_meshcop.tlv.ml_prefix == 'fd000db700000000').must_next()
# Step 9: Leader MUST send MGMT_ACTIVE_SET.rsp to the Commissioner
pkts.filter_wpan_src64(LEADER).filter_ipv6_dst(COMMISSIONER_RLOC).filter_coap_ack(MGMT_ACTIVE_SET_URI).filter(
lambda p: p.thread_meshcop.tlv.state == -1).must_next()
# Step 10: Commissioner sends MGMT_ACTIVE_SET.req to Leader RLOC or Leader Anycast Locator
pkts.filter_wpan_src64(COMMISSIONER).filter_ipv6_2dsts(
LEADER_RLOC, LEADER_ALOC).filter_coap_request(MGMT_ACTIVE_SET_URI).filter(
lambda p: p.thread_meshcop.tlv.active_tstamp == 104 and p.thread_meshcop.tlv.xpan_id ==
'000db70000000000' and p.thread_meshcop.tlv.net_name == ['GRL'] and p.thread_meshcop.tlv.master_key ==
'ffeeddccbbaa99887766554433221100' and p.thread_meshcop.tlv.chan_mask_mask == '001fffe0' and p.
thread_meshcop.tlv.ml_prefix == 'fd000db700000000').must_next()
# Step 11: Leader MUST send MGMT_ACTIVE_SET.rsp to the Commissioner
pkts.filter_wpan_src64(LEADER).filter_ipv6_dst(COMMISSIONER_RLOC).filter_coap_ack(MGMT_ACTIVE_SET_URI).filter(
lambda p: p.thread_meshcop.tlv.state == -1).must_next()
# Step 12: Commissioner sends MGMT_ACTIVE_SET.req to Leader RLOC or Leader Anycast Locator
pkts.filter_wpan_src64(COMMISSIONER).filter_ipv6_2dsts(
LEADER_RLOC, LEADER_ALOC).filter_coap_request(MGMT_ACTIVE_SET_URI).filter(
lambda p: p.thread_meshcop.tlv.active_tstamp == 105 and p.thread_meshcop.tlv.xpan_id ==
'000db70000000000' and p.thread_meshcop.tlv.net_name == ['UL'] and p.thread_meshcop.tlv.master_key ==
'00112233445566778899aabbccddeeff' and p.thread_meshcop.tlv.pan_id == [0xafce] and p.thread_meshcop.tlv
.chan_mask_mask == '001fffe0' and p.thread_meshcop.tlv.ml_prefix == 'fd000db700000000').must_next()
# Step 13: Leader MUST send MGMT_ACTIVE_SET.rsp to the Commissioner
pkts.filter_wpan_src64(LEADER).filter_ipv6_dst(COMMISSIONER_RLOC).filter_coap_ack(MGMT_ACTIVE_SET_URI).filter(
lambda p: p.thread_meshcop.tlv.state == -1).must_next()
# Step 14: Commissioner sends MGMT_ACTIVE_SET.req to Leader RLOC or Leader Anycast Locator
pkts.filter_wpan_src64(COMMISSIONER).filter_ipv6_2dsts(
LEADER_RLOC, LEADER_ALOC).filter_coap_request(MGMT_ACTIVE_SET_URI).filter(
lambda p: p.thread_meshcop.tlv.active_tstamp == 106 and p.thread_meshcop.tlv.xpan_id ==
'000db70000000000' and p.thread_meshcop.tlv.net_name == ['UL'] and p.thread_meshcop.tlv.
commissioner_sess_id == 0xabcd and p.thread_meshcop.tlv.chan_mask_mask == '001fffe0').must_next()
# Step 15: Leader MUST send MGMT_ACTIVE_SET.rsp to the Commissioner
pkts.filter_wpan_src64(LEADER).filter_ipv6_dst(COMMISSIONER_RLOC).filter_coap_ack(MGMT_ACTIVE_SET_URI).filter(
lambda p: p.thread_meshcop.tlv.state == -1).must_next()
# Step 16: Commissioner sends MGMT_ACTIVE_SET.req to Leader RLOC or Leader Anycast Locator
pkts.filter_wpan_src64(COMMISSIONER).filter_ipv6_2dsts(LEADER_RLOC, LEADER_ALOC).filter_coap_request(
MGMT_ACTIVE_SET_URI).filter(lambda p: p.thread_meshcop.tlv.active_tstamp == 101 and p.thread_meshcop.tlv.
xpan_id == '000db70000000000' and p.thread_meshcop.tlv.net_name == ['UL'] and p
.thread_meshcop.tlv.chan_mask_mask == '001fff80').must_next()
# Step 17: Leader MUST send MGMT_ACTIVE_SET.rsp to the Commissioner
pkts.filter_wpan_src64(LEADER).filter_ipv6_dst(COMMISSIONER_RLOC).filter_coap_ack(MGMT_ACTIVE_SET_URI).filter(
lambda p: p.thread_meshcop.tlv.state == -1).must_next()
# Step 18: Commissioner sends MGMT_ACTIVE_SET.req to Leader RLOC or Leader Anycast Locator
pkts.filter_wpan_src64(COMMISSIONER).filter_ipv6_2dsts(
LEADER_RLOC, LEADER_ALOC).filter_coap_request(MGMT_ACTIVE_SET_URI).filter(
lambda p: p.thread_meshcop.tlv.active_tstamp == 107 and p.thread_meshcop.tlv.xpan_id ==
'000db70000000000' and p.thread_meshcop.tlv.net_name == ['UL'] and p.thread_meshcop.tlv.steering_data
== Bytes('113320440000') and p.thread_meshcop.tlv.chan_mask_mask == '001fffe0').must_next()
# Step 19: Leader MUST send MGMT_ACTIVE_SET.rsp to the Commissioner
pkts.filter_wpan_src64(LEADER).filter_ipv6_dst(COMMISSIONER_RLOC).filter_coap_ack(MGMT_ACTIVE_SET_URI).filter(
lambda p: p.thread_meshcop.tlv.state == 1).must_next()
# Step 20: Commissioner sends MGMT_ACTIVE_SET.req to Leader RLOC or Leader Anycast Locator
pkts.filter_wpan_src64(COMMISSIONER).filter_ipv6_2dsts(
LEADER_RLOC, LEADER_ALOC).filter_coap_request(MGMT_ACTIVE_SET_URI).filter(
lambda p: p.thread_meshcop.tlv.active_tstamp == 108 and p.thread_meshcop.tlv.xpan_id ==
'000db70000000000' and p.thread_meshcop.tlv.net_name == ['GRL'] and p.thread_meshcop.tlv.unknown ==
'aa55' and p.thread_meshcop.tlv.chan_mask_mask == '001fffe0').must_next()
# Step 21: Leader MUST send MGMT_ACTIVE_SET.rsp to the Commissioner
pkts.filter_wpan_src64(LEADER).filter_ipv6_dst(COMMISSIONER_RLOC).filter_coap_ack(MGMT_ACTIVE_SET_URI).filter(
lambda p: p.thread_meshcop.tlv.state == 1).must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,369 +0,0 @@
#!/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 config
import thread_cert
from pktverify.consts import MLE_DATA_RESPONSE, MGMT_ACTIVE_SET_URI, NETWORK_DATA_TLV, SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ACTIVE_TIMESTAMP_TLV, ACTIVE_OPERATION_DATASET_TLV, NM_CHANNEL_TLV, NM_CHANNEL_MASK_TLV, NM_EXTENDED_PAN_ID_TLV, NM_NETWORK_MESH_LOCAL_PREFIX_TLV, NM_NETWORK_KEY_TLV, NM_NETWORK_NAME_TLV, NM_PAN_ID_TLV, NM_PSKC_TLV, NM_SECURITY_POLICY_TLV
from pktverify.packet_verifier import PacketVerifier
ROUTER = 1
LEADER = 2
# Test Purpose and Description:
# -----------------------------
# The purpose of this test case is to verify the DUTs behavior when receiving
# MGMT_ACTIVE_SET.req from an active Thread node.
#
# Test Topology:
# -------------
# Router
# |
# Leader
#
# DUT Types:
# ----------
# Leader
class Cert_9_2_05_ActiveDataset(thread_cert.TestCase):
USE_MESSAGE_FACTORY = False
SUPPORT_NCP = False
TOPOLOGY = {
ROUTER: {
'name': 'ROUTER',
'channel': 11,
'network_key': '00112233445566778899aabbccddeeff',
'mode': 'rdn',
'allowlist': [LEADER]
},
LEADER: {
'name': 'LEADER',
'channel': 11,
'network_key': '00112233445566778899aabbccddeeff',
'mode': 'rdn',
'allowlist': [ROUTER]
},
}
def test(self):
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER].get_state(), 'router')
self.nodes[ROUTER].commissioner_start()
self.simulator.go(5)
self.collect_rlocs()
# Step 2: new, valid Timestamp TLV
# all valid Active Operational Dataset parameters,
# with new values in the TLVs that dont affect connectivity
# binary = new pskc and security policy [3600, 0b11101111]
self.nodes[ROUTER].send_mgmt_active_set(
active_timestamp=100,
channel_mask=0x3fff800,
extended_panid='000db80000000001',
mesh_local='fd00:0db8::',
network_name='TEST_1',
network_key='00112233445566778899aabbccddeeff',
panid=0xface,
channel=11,
binary='0410d2aa9cd8dff7919122d77d37ec3c1b5f0c030e10ef',
)
self.simulator.go(5)
# Step 7: old, invalid Active Timestamp TLV
# all valid Active Operational Dataset parameters, with
# new values in the TLVs that dont affect connectivity
# binary = new pskc and security policy [3600, 0b11111111]
self.nodes[ROUTER].send_mgmt_active_set(
active_timestamp=100,
channel_mask=0x1fff800,
extended_panid='000db80000000002',
mesh_local='fd00:0db8::',
network_name='TEST_2',
network_key='00112233445566778899aabbccddeeff',
panid=0xface,
channel=11,
binary='041017d672be32b0c24a2f8385f2fbaf1d970c030e10ff',
)
self.simulator.go(5)
# Step 9: new, valid Active Timestamp TLV
# all of valid Commissioner Dataset parameters plus one bogus TLV, and
# new values in the TLVs that dont affect connectivity
# binary = new pskc and security policy [3600, 0b11111111] and BogusTLV=0x400
self.nodes[ROUTER].send_mgmt_active_set(
active_timestamp=101,
channel_mask=0xfff800,
extended_panid='000db80000000003',
mesh_local='fd00:0db8::',
network_name='TEST_3',
network_key='00112233445566778899aabbccddeeff',
panid=0xface,
channel=11,
binary='041008f4e9531e8efa8e852d5f4fb951b13e0c030e10ff8202aa55',
)
self.simulator.go(5)
# Step 14: new, valid Active Timestamp TLV
# attempt to set Channel TLV to an unsupported channel + all of other TLVs
# binary = pskc and security policy step 9
self.nodes[ROUTER].send_mgmt_active_set(
active_timestamp=102,
channel_mask=0x1fff800,
extended_panid='000db80000000003',
mesh_local='fd00:0db8::',
network_name='TEST_3',
network_key='00112233445566778899aabbccddeeff',
panid=0xface,
channel=63,
binary='041008f4e9531e8efa8e852d5f4fb951b13e0c030e10f8',
)
self.simulator.go(5)
ipaddr = self.nodes[LEADER].get_rloc()
self.assertTrue(self.nodes[ROUTER].ping(ipaddr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
LEADER_RLOC = pv.vars['LEADER_RLOC']
ROUTER = pv.vars['ROUTER']
ROUTER_RLOC = pv.vars['ROUTER_RLOC']
# Step 1: Ensure the topology is formed correctly
pv.verify_attached('ROUTER', 'LEADER')
_pkt = pkts.last()
# Step 3: Leader MUST send MGMT_ACTIVE_SET.rsp to the Router with
# with the following format:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# State TLV (value = Accept (01))
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(ROUTER_RLOC).\
filter_coap_ack(MGMT_ACTIVE_SET_URI).\
filter(lambda p: p.thread_meshcop.tlv.state == 1).\
must_next()
# Step 4: Leader MUST send a multicast MLE Data Response, including
# the following TLVs:
# - Source Address TLV
# - Leader Data TLV
# Data version field [incremented]
# Stable Version field [incremented]
# - Network Data TLV
# - Active Timestamp TLV [new value set in Step 9]
_dr_pkt = pkts.filter_wpan_src64(LEADER).\
filter_LLANMA().\
filter_mle_cmd(MLE_DATA_RESPONSE).\
filter(lambda p: {
NETWORK_DATA_TLV,
SOURCE_ADDRESS_TLV,
LEADER_DATA_TLV,
ACTIVE_TIMESTAMP_TLV
} <= set(p.mle.tlv.type) and\
p.mle.tlv.active_tstamp == 100 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
).\
must_next()
# Step 6: Leader MUST send a unicast MLE Data Response to Router, including
# the following TLVs:
# - Source Address TLV
# - Leader Data TLV
# - Active Operational Dataset TLV
# - Channel TLV
# - Channel Mask TLV [new value set in Step 2]
# - Extended PAN ID TLV [new value set in Step 2]
# - Network Mesh-Local Prefix TLV
# - Network Key TLV
# - Network Name TLV [new value set in Step 2]
# - PAN ID TLV
# - PSKc TLV [new value set in Step 2]
# - Security Policy TLV [new value set in Step 2]
# - Active Timestamp TLV [new value set in Step 2]
pkts.filter_wpan_src64(LEADER).\
filter_wpan_dst64(ROUTER).\
filter_mle_cmd(MLE_DATA_RESPONSE).\
filter(lambda p: {
NETWORK_DATA_TLV,
SOURCE_ADDRESS_TLV,
LEADER_DATA_TLV,
ACTIVE_OPERATION_DATASET_TLV,
ACTIVE_TIMESTAMP_TLV
} <= set(p.mle.tlv.type) and\
{
NM_CHANNEL_TLV,
NM_CHANNEL_MASK_TLV,
NM_EXTENDED_PAN_ID_TLV,
NM_NETWORK_MESH_LOCAL_PREFIX_TLV,
NM_NETWORK_KEY_TLV,
NM_NETWORK_NAME_TLV,
NM_PAN_ID_TLV,
NM_PSKC_TLV,
NM_SECURITY_POLICY_TLV
} <= set(p.thread_meshcop.tlv.type) and\
p.mle.tlv.active_tstamp == 100 and\
p.thread_meshcop.tlv.chan_mask_mask == '001fffc0' and\
p.thread_meshcop.tlv.xpan_id == '000db80000000001' and\
p.thread_meshcop.tlv.net_name == ['TEST_1'] and\
p.thread_meshcop.tlv.pskc == 'd2aa9cd8dff7919122d77d37ec3c1b5f'
).\
must_next()
# Step 8: Leader MUST send MGMT_ACTIVE_SET.rsp to the Router with
# with the following format:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# State TLV (value = Reject (ff))
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(ROUTER_RLOC).\
filter_coap_ack(MGMT_ACTIVE_SET_URI).\
filter(lambda p: p.thread_meshcop.tlv.state == -1).\
must_next()
# Step 10: Leader MUST send MGMT_ACTIVE_SET.rsp to the Router with
# with the following format:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# State TLV (value = Accept (01))
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(ROUTER_RLOC).\
filter_coap_ack(MGMT_ACTIVE_SET_URI).\
filter(lambda p: p.thread_meshcop.tlv.state == 1).\
must_next()
# Step 11: Leader MUST send a multicast MLE Data Response, including
# the following TLVs:
# - Source Address TLV
# - Leader Data TLV
# Data version field [incremented]
# Stable Version field [incremented]
# - Network Data TLV
# - Active Timestamp TLV [new value set in Step 9]
pkts.filter_wpan_src64(LEADER).\
filter_LLANMA().\
filter_mle_cmd(MLE_DATA_RESPONSE).\
filter(lambda p: {
NETWORK_DATA_TLV,
SOURCE_ADDRESS_TLV,
LEADER_DATA_TLV,
ACTIVE_TIMESTAMP_TLV
} <= set(p.mle.tlv.type) and\
p.mle.tlv.active_tstamp == 101 and\
(p.mle.tlv.leader_data.data_version -
_dr_pkt.mle.tlv.leader_data.data_version) % 256 <= 127 and\
(p.mle.tlv.leader_data.stable_data_version -
_dr_pkt.mle.tlv.leader_data.stable_data_version) % 256 <= 127
).\
must_next()
# Step 13: Leader MUST send a unicast MLE Data Response to Router, including
# the following TLVs:
# - Source Address TLV
# - Leader Data TLV
# - Active Operational Dataset TLV
# - Channel TLV
# - Channel Mask TLV [new value set in Step 9]
# - Extended PAN ID TLV [new value set in Step 9]
# - Network Mesh-Local Prefix TLV
# - Network Key TLV
# - Network Name TLV [new value set in Step 9]
# - PAN ID TLV
# - PSKc TLV [new value set in Step 9]
# - Security Policy TLV [new value set in Step 9]
# - Active Timestamp TLV [new value set in Step 9]
pkts.filter_wpan_src64(LEADER).\
filter_wpan_dst64(ROUTER).\
filter_mle_cmd(MLE_DATA_RESPONSE).\
filter(lambda p: {
NETWORK_DATA_TLV,
SOURCE_ADDRESS_TLV,
LEADER_DATA_TLV,
ACTIVE_OPERATION_DATASET_TLV,
ACTIVE_TIMESTAMP_TLV
} <= set(p.mle.tlv.type) and\
{
NM_CHANNEL_TLV,
NM_CHANNEL_MASK_TLV,
NM_EXTENDED_PAN_ID_TLV,
NM_NETWORK_MESH_LOCAL_PREFIX_TLV,
NM_NETWORK_KEY_TLV,
NM_NETWORK_NAME_TLV,
NM_PAN_ID_TLV,
NM_PSKC_TLV,
NM_SECURITY_POLICY_TLV
} <= set(p.thread_meshcop.tlv.type) and\
p.mle.tlv.active_tstamp == 101 and\
p.thread_meshcop.tlv.chan_mask_mask == '001fff00' and\
p.thread_meshcop.tlv.xpan_id == '000db80000000003' and\
p.thread_meshcop.tlv.net_name == ['TEST_3'] and\
p.thread_meshcop.tlv.pskc == '08f4e9531e8efa8e852d5f4fb951b13e'
).\
must_next()
# Step 15: Leader MUST send MGMT_ACTIVE_SET.rsp to the Router with
# with the following format:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# State TLV (value = Reject (ff)))
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(ROUTER_RLOC).\
filter_coap_ack(MGMT_ACTIVE_SET_URI).\
filter(lambda p: p.thread_meshcop.tlv.state == -1).\
must_next()
# Step 16: The DUT must respond with an ICMPv6 Echo Reply
_pkt = pkts.filter_ping_request().\
filter_ipv6_src_dst(ROUTER_RLOC, LEADER_RLOC).\
must_next()
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_ipv6_src_dst(LEADER_RLOC, ROUTER_RLOC).\
must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,872 +0,0 @@
#!/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_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',
'allowlist': [LEADER]
},
LEADER: {
'name': 'LEADER',
'active_dataset': {
'timestamp': TIMESTAMP_INIT,
'panid': PANID_INIT,
'channel': CHANNEL_INIT
},
'mode': 'rdn',
'allowlist': [COMMISSIONER, ROUTER]
},
ROUTER: {
'name': 'ROUTER',
'active_dataset': {
'timestamp': TIMESTAMP_INIT,
'panid': PANID_INIT,
'channel': CHANNEL_INIT
},
'mode': 'rdn',
'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(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[COMMISSIONER].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
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(config.ROUTER_STARTUP_DELAY)
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: <new value>
# - Active Operational Dataset TLV
# - Network Name TLV <new value>
# - 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: <new value>
# - Active Operational Dataset TLV
# - Network Name TLV <new value>
# - 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 <new value>
# - 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()
@@ -1,228 +0,0 @@
#!/usr/bin/env python3
#
# 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 unittest
import config
import thread_cert
from pktverify.consts import MLE_CHILD_ID_RESPONSE, MLE_DATA_RESPONSE, MGMT_PENDING_SET_URI, MGMT_ACTIVE_SET_URI, MGMT_DATASET_CHANGED_URI, COAP_CODE_ACK, ACTIVE_OPERATION_DATASET_TLV, ACTIVE_TIMESTAMP_TLV, PENDING_TIMESTAMP_TLV, NM_CHANNEL_TLV, NM_CHANNEL_MASK_TLV, NM_EXTENDED_PAN_ID_TLV, NM_NETWORK_KEY_TLV, NM_NETWORK_MESH_LOCAL_PREFIX_TLV, NM_NETWORK_NAME_TLV, NM_PAN_ID_TLV, NM_PSKC_TLV, NM_SECURITY_POLICY_TLV, SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ACTIVE_TIMESTAMP_TLV, NETWORK_DATA_TLV, NM_BORDER_AGENT_LOCATOR_TLV, NM_COMMISSIONER_SESSION_ID_TLV, NM_DELAY_TIMER_TLV, PENDING_OPERATION_DATASET_TLV
from pktverify.packet_verifier import PacketVerifier
PANID_INIT = 0xface
COMMISSIONER = 1
LEADER = 2
ROUTER = 3
LEADER_ACTIVE_TIMESTAMP = 10
ROUTER_ACTIVE_TIMESTAMP = 20
ROUTER_PENDING_TIMESTAMP = 30
ROUTER_PENDING_ACTIVE_TIMESTAMP = 25
ROUTER_DELAY_TIMER = 3600000
COMMISSIONER_PENDING_TIMESTAMP = 40
COMMISSIONER_PENDING_ACTIVE_TIMESTAMP = 80
COMMISSIONER_DELAY_TIMER = 60000
COMMISSIONER_PENDING_CHANNEL = 20
COMMISSIONER_PENDING_PANID = 0xafce
class Cert_9_2_7_DelayTimer(thread_cert.TestCase):
SUPPORT_NCP = False
TOPOLOGY = {
COMMISSIONER: {
'name': 'COMMISSIONER',
'mode': 'rdn',
'allowlist': [LEADER]
},
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'partition_id': 0xffffffff,
'allowlist': [COMMISSIONER]
},
ROUTER: {
'name': 'ROUTER',
'mode': 'rdn',
'partition_id': 1,
},
}
def test(self):
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[COMMISSIONER].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'router')
self.nodes[COMMISSIONER].commissioner_start()
self.simulator.go(3)
self.nodes[COMMISSIONER].send_mgmt_active_set(active_timestamp=LEADER_ACTIVE_TIMESTAMP,)
self.simulator.go(5)
self.nodes[ROUTER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER].get_state(), 'leader')
self.nodes[LEADER].add_allowlist(self.nodes[ROUTER].get_addr64())
self.nodes[ROUTER].add_allowlist(self.nodes[LEADER].get_addr64())
self.simulator.go(35)
self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'router')
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.assertEqual(self.nodes[ROUTER].get_state(), 'router')
self.nodes[ROUTER].commissioner_start()
self.simulator.go(3)
self.nodes[ROUTER].send_mgmt_active_set(active_timestamp=ROUTER_ACTIVE_TIMESTAMP,)
self.simulator.go(30)
self.nodes[ROUTER].send_mgmt_pending_set(
pending_timestamp=ROUTER_PENDING_TIMESTAMP,
active_timestamp=ROUTER_PENDING_ACTIVE_TIMESTAMP,
delay_timer=ROUTER_DELAY_TIMER,
)
self.simulator.go(60)
self.nodes[COMMISSIONER].send_mgmt_pending_set(
pending_timestamp=COMMISSIONER_PENDING_TIMESTAMP,
active_timestamp=COMMISSIONER_PENDING_ACTIVE_TIMESTAMP,
delay_timer=COMMISSIONER_DELAY_TIMER,
channel=COMMISSIONER_PENDING_CHANNEL,
panid=COMMISSIONER_PENDING_PANID,
)
self.simulator.go(120)
self.assertEqual(self.nodes[LEADER].get_panid(), COMMISSIONER_PENDING_PANID)
self.assertEqual(self.nodes[COMMISSIONER].get_panid(), COMMISSIONER_PENDING_PANID)
self.assertEqual(self.nodes[ROUTER].get_panid(), COMMISSIONER_PENDING_PANID)
self.assertEqual(self.nodes[LEADER].get_channel(), COMMISSIONER_PENDING_CHANNEL)
self.assertEqual(
self.nodes[COMMISSIONER].get_channel(),
COMMISSIONER_PENDING_CHANNEL,
)
self.assertEqual(self.nodes[ROUTER].get_channel(), COMMISSIONER_PENDING_CHANNEL)
self.collect_rloc16s()
self.collect_rlocs()
ipaddrs = self.nodes[ROUTER].get_addrs()
for ipaddr in ipaddrs:
if ipaddr[0:4] != 'fe80':
break
self.assertTrue(self.nodes[LEADER].ping(ipaddr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
LEADER_RLOC16 = pv.vars['LEADER_RLOC16']
COMMISSIONER = pv.vars['COMMISSIONER']
COMMISSIONER_RLOC = pv.vars['COMMISSIONER_RLOC']
ROUTER = pv.vars['ROUTER']
ROUTER_RLOC = pv.vars['ROUTER_RLOC']
ROUTER_RLOC16 = pv.vars['ROUTER_RLOC16']
_lpkts = pkts.filter_wpan_src64(LEADER)
# Step 1: Ensure the topology is formed correctly
_lpkts.filter_wpan_dst64(COMMISSIONER).filter_mle_cmd(MLE_CHILD_ID_RESPONSE).must_next()
_lpkts_coap = _lpkts.copy()
# Step 4: Leader MUST send a unicast MLE Child ID Response to the Router
_lpkts.filter_wpan_dst64(ROUTER).filter_mle_cmd(MLE_CHILD_ID_RESPONSE).must_next(
).must_verify(lambda p: {ACTIVE_OPERATION_DATASET_TLV, ACTIVE_TIMESTAMP_TLV} <= set(p.mle.tlv.type) and {
NM_CHANNEL_TLV, NM_CHANNEL_MASK_TLV, NM_EXTENDED_PAN_ID_TLV, NM_NETWORK_KEY_TLV,
NM_NETWORK_MESH_LOCAL_PREFIX_TLV, NM_NETWORK_NAME_TLV, NM_PAN_ID_TLV, NM_PSKC_TLV, NM_SECURITY_POLICY_TLV
} <= set(p.thread_meshcop.tlv.type) and p.mle.tlv.active_tstamp == LEADER_ACTIVE_TIMESTAMP)
# Step 6: Leader automatically sends a MGMT_ACTIVE_SET.rsp to the Router
_lpkts.filter_ipv6_dst(ROUTER_RLOC).filter_coap_ack(MGMT_ACTIVE_SET_URI).must_next().must_verify(
lambda p: p.coap.code == COAP_CODE_ACK and p.thread_meshcop.tlv.state == 1)
# Step 7: Leader multicasts a MLE Data Response with the new information
_lpkts.filter_LLANMA().filter_mle_cmd(MLE_DATA_RESPONSE).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ACTIVE_TIMESTAMP_TLV, NETWORK_DATA_TLV} <= set(
p.mle.tlv.type) and {NM_BORDER_AGENT_LOCATOR_TLV, NM_COMMISSIONER_SESSION_ID_TLV} <= set(
p.thread_meshcop.tlv.type) and p.thread_nwd.tlv.stable == [0] and p.mle.tlv.active_tstamp ==
ROUTER_ACTIVE_TIMESTAMP)
# Step 10: Leader MUST send a unicast MLE Data Response to the Router
_lpkts.filter_wpan_dst64(ROUTER).filter_mle_cmd(MLE_DATA_RESPONSE).must_next(
).must_verify(lambda p: {ACTIVE_OPERATION_DATASET_TLV, ACTIVE_TIMESTAMP_TLV} <= set(p.mle.tlv.type) and {
NM_CHANNEL_TLV, NM_CHANNEL_MASK_TLV, NM_EXTENDED_PAN_ID_TLV, NM_NETWORK_KEY_TLV,
NM_NETWORK_MESH_LOCAL_PREFIX_TLV, NM_NETWORK_NAME_TLV, NM_PAN_ID_TLV, NM_PSKC_TLV, NM_SECURITY_POLICY_TLV
} <= set(p.thread_meshcop.tlv.type) and p.mle.tlv.active_tstamp == ROUTER_ACTIVE_TIMESTAMP)
# Step 12: Leader sends a MGMT_PENDING_SET.rsp to the Router with Status = Accept
_lpkts_coap.filter_ipv6_dst(ROUTER_RLOC).filter_coap_ack(MGMT_PENDING_SET_URI).must_next().must_verify(
lambda p: p.coap.code == COAP_CODE_ACK and p.thread_meshcop.tlv.state == 1)
# Step 13: Leader sends a multicast MLE Data Response
_lpkts.filter_LLANMA().filter_mle_cmd(MLE_DATA_RESPONSE).must_next().must_verify(
lambda p: {
SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ACTIVE_TIMESTAMP_TLV, PENDING_TIMESTAMP_TLV, NETWORK_DATA_TLV
} <= set(p.mle.tlv.type) and p.thread_nwd.tlv.stable == [0] and p.mle.tlv.active_tstamp ==
ROUTER_ACTIVE_TIMESTAMP and p.mle.tlv.pending_tstamp == ROUTER_PENDING_TIMESTAMP)
# Step 14: The DUT MUST send MGMT_DATASET_CHANGED.ntf to the Router
_lpkts_coap.filter_wpan_dst16(ROUTER_RLOC16).filter_coap_request(MGMT_DATASET_CHANGED_URI).must_next()
# Step 16: Leader MUST send a unicast MLE Data Response to the Router
_lpkts.filter_wpan_dst64(ROUTER).filter_mle_cmd(MLE_DATA_RESPONSE).must_next().must_verify(
lambda p: {ACTIVE_TIMESTAMP_TLV, PENDING_TIMESTAMP_TLV} <= set(p.mle.tlv.type) and p.mle.tlv.active_tstamp
== ROUTER_ACTIVE_TIMESTAMP and p.mle.tlv.pending_tstamp == ROUTER_PENDING_TIMESTAMP)
# Step 18: The DUT MUST send MGMT_PENDING_SET.rsp to the Commissioner
_lpkts_coap.filter_ipv6_dst(COMMISSIONER_RLOC).filter_coap_ack(MGMT_PENDING_SET_URI).must_next().must_verify(
lambda p: p.coap.code == COAP_CODE_ACK and p.thread_meshcop.tlv.state == 1)
# Step 19: Leader MUST send a unicast MLE Data Response to the Router
_lpkts.filter_LLANMA().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.thread_nwd.tlv.stable == [0] and p.mle.tlv.active_tstamp ==
ROUTER_ACTIVE_TIMESTAMP and p.mle.tlv.pending_tstamp == COMMISSIONER_PENDING_TIMESTAMP)
# Step 20: Leader MUST send a unicast MLE Data Response to the Router
_lpkts.filter_wpan_dst64(ROUTER).filter_mle_cmd(MLE_DATA_RESPONSE).must_next(
).must_verify(lambda p: {ACTIVE_TIMESTAMP_TLV, PENDING_TIMESTAMP_TLV, PENDING_OPERATION_DATASET_TLV} < set(
p.mle.tlv.type) and {NM_CHANNEL_TLV, NM_COMMISSIONER_SESSION_ID_TLV, NM_PAN_ID_TLV, NM_DELAY_TIMER_TLV} <=
set(p.thread_meshcop.tlv.type) and p.mle.tlv.active_tstamp == ROUTER_ACTIVE_TIMESTAMP and p.mle.
tlv.pending_tstamp == COMMISSIONER_PENDING_TIMESTAMP and p.thread_meshcop.tlv.pan_id ==
[COMMISSIONER_PENDING_PANID] and p.thread_meshcop.tlv.channel == [COMMISSIONER_PENDING_CHANNEL])
# Step 21: Router MUST respond with an ICMPv6 Echo Reply
pkts.filter_wpan_src16_dst16(ROUTER_RLOC16, LEADER_RLOC16).filter_ping_reply().must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,353 +0,0 @@
#!/usr/bin/env python3
#
# 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 unittest
import copy
import config
import thread_cert
from pktverify.consts import MLE_PARENT_REQUEST, MLE_DATA_RESPONSE, MLE_DATA_REQUEST, MLE_CHILD_UPDATE_REQUEST, MGMT_PENDING_SET_URI, ACTIVE_OPERATION_DATASET_TLV, ACTIVE_TIMESTAMP_TLV, PENDING_TIMESTAMP_TLV, TLV_REQUEST_TLV, NETWORK_DATA_TLV, NM_BORDER_AGENT_LOCATOR_TLV, NM_COMMISSIONER_SESSION_ID_TLV, NM_DELAY_TIMER_TLV, PENDING_OPERATION_DATASET_TLV, NWD_COMMISSIONING_DATA_TLV, LEADER_ALOC
from pktverify.packet_verifier import PacketVerifier
from pktverify.null_field import nullField
COMMISSIONER = 1
LEADER = 2
DUT = 3
CHANNEL_INIT = 19
PANID_INIT = 0xface
LEADER_ACTIVE_TIMESTAMP = 10
COMMISSIONER_PENDING_TIMESTAMP = 20
COMMISSIONER_ACTIVE_TIMESTAMP = 70
COMMISSIONER_DELAY_TIMER = 60000
COMMISSIONER_PENDING_CHANNEL = 20
COMMISSIONER_PENDING_PANID = 0xafce
# Test Purpose and Description:
# -----------------------------
# The purpose of this test case is to verify that after a reset, the DUT
# reattaches to the test network using parameters set in Active/Pending
# Operational Datasets.
#
# Test Topology:
# -------------
# Commissioner
# |
# Leader
# |
# DUT
#
# DUT Types:
# ----------
# Router
# ED
# SED
class Cert_9_2_8_PersistentDatasets_Base(thread_cert.TestCase):
USE_MESSAGE_FACTORY = False
SUPPORT_NCP = False
TOPOLOGY = {
COMMISSIONER: {
'name': 'COMMISSIONER',
'mode': 'rdn',
'panid': PANID_INIT,
'channel': CHANNEL_INIT,
'allowlist': [LEADER]
},
LEADER: {
'name': 'LEADER',
'active_dataset': {
'timestamp': LEADER_ACTIVE_TIMESTAMP,
'panid': PANID_INIT,
'channel': CHANNEL_INIT
},
'mode': 'rdn',
'allowlist': [COMMISSIONER, DUT]
},
DUT: {
'name': 'DUT',
'panid': PANID_INIT,
'channel': CHANNEL_INIT,
'allowlist': [LEADER]
},
}
def _setUpDUT(self):
self.nodes[DUT].add_allowlist(self.nodes[LEADER].get_addr64())
self.nodes[DUT].enable_allowlist()
if self.TOPOLOGY[DUT]['mode'] == 'rdn':
self.nodes[DUT].set_router_selection_jitter(1)
else:
self.nodes[DUT].set_timeout(config.DEFAULT_CHILD_TIMEOUT)
def test(self):
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[COMMISSIONER].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'router')
self.nodes[DUT].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
if self.TOPOLOGY[DUT]['mode'] == 'rdn':
self.assertEqual(self.nodes[DUT].get_state(), 'router')
else:
self.assertEqual(self.nodes[DUT].get_state(), 'child')
self.collect_rlocs()
self.nodes[COMMISSIONER].commissioner_start()
self.simulator.go(3)
self.nodes[COMMISSIONER].send_mgmt_pending_set(
pending_timestamp=COMMISSIONER_PENDING_TIMESTAMP,
active_timestamp=COMMISSIONER_ACTIVE_TIMESTAMP,
delay_timer=COMMISSIONER_DELAY_TIMER,
channel=COMMISSIONER_PENDING_CHANNEL,
panid=COMMISSIONER_PENDING_PANID,
)
self.simulator.go(5)
# power down the DUT for 60 seconds
self.nodes[DUT].reset()
self.simulator.go(60)
# the network moves to COMMISSIONER_PENDING_PANID
self.assertEqual(self.nodes[LEADER].get_panid(), COMMISSIONER_PENDING_PANID)
self.assertEqual(self.nodes[COMMISSIONER].get_panid(), COMMISSIONER_PENDING_PANID)
self.assertEqual(self.nodes[LEADER].get_channel(), COMMISSIONER_PENDING_CHANNEL)
self.assertEqual(self.nodes[COMMISSIONER].get_channel(), COMMISSIONER_PENDING_CHANNEL)
# restart the DUT to attach to COMMISSIONER_PENDING_CHANNEL
self.nodes[DUT].reset()
self._setUpDUT()
self.nodes[DUT].start()
self.assertEqual(self.nodes[DUT].get_panid(), PANID_INIT)
self.assertEqual(self.nodes[DUT].get_channel(), CHANNEL_INIT)
self.simulator.go(60)
self.assertEqual(self.nodes[DUT].get_panid(), COMMISSIONER_PENDING_PANID)
self.assertEqual(self.nodes[DUT].get_channel(), COMMISSIONER_PENDING_CHANNEL)
self.collect_ipaddrs()
ipaddr = self.nodes[DUT].get_ip6_address(config.ADDRESS_TYPE.ML_EID)
self.assertTrue(self.nodes[COMMISSIONER].ping(ipaddr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
LEADER_RLOC = pv.vars['LEADER_RLOC']
COMMISSIONER = pv.vars['COMMISSIONER']
COMMISSIONER_MLEID = pv.vars['COMMISSIONER_MLEID']
COMMISSIONER_RLOC = pv.vars['COMMISSIONER_RLOC']
DUT_EXTADDR = pv.vars['DUT']
DUT_MLEID = pv.vars['DUT_MLEID']
# Step 1: Ensure the topology is formed correctly
pv.verify_attached('COMMISSIONER', 'LEADER')
if self.TOPOLOGY[DUT]['mode'] == 'rdn':
pv.verify_attached('DUT', 'LEADER')
else:
pv.verify_attached('DUT', 'LEADER', 'MTD')
_pkt = pkts.last()
# Step 2: Commissioner to send MGMT_PENDING_SET.req to the Leader Anycast
# or Routing Locator:
# CoAP Request URI
# coap://[<L>]:MM/c/ps
# CoAP Payload
# - valid Commissioner Session ID TLV
# - Pending Timestamp TLV : 20s
# - Active Timestamp TLV : 70s
# - Delay Timer TLV : 60s
# - Channel TLV : 20
# - PAN ID TLV: 0xAFCE
pkts.filter_coap_request(MGMT_PENDING_SET_URI).\
filter_ipv6_2dsts(LEADER_RLOC, LEADER_ALOC).\
filter(lambda p: p.thread_meshcop.tlv.active_tstamp ==
COMMISSIONER_ACTIVE_TIMESTAMP and\
p.thread_meshcop.tlv.pending_tstamp ==
COMMISSIONER_PENDING_TIMESTAMP and\
p.thread_meshcop.tlv.delay_timer ==
COMMISSIONER_DELAY_TIMER and\
p.thread_meshcop.tlv.channel ==
[COMMISSIONER_PENDING_CHANNEL] and\
p.thread_meshcop.tlv.pan_id ==
[COMMISSIONER_PENDING_PANID] and\
NM_COMMISSIONER_SESSION_ID_TLV in p.thread_meshcop.tlv.type
).\
must_next()
# Step 3: Leader sends MGMT_PENDING_SET.rsq 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)
if self.TOPOLOGY[DUT]['mode'] != '-':
# Step 4: Leader sends a multicast MLE Data Response with the new network data,
# including the following TLVs:
# - 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
# - Active Timestamp TLV: 70s
# - Pending Timestamp TLV: 20s
pkts.filter_mle_cmd(MLE_DATA_RESPONSE).\
filter_wpan_src64(LEADER).\
filter_LLANMA().\
filter(lambda p: p.mle.tlv.active_tstamp ==
LEADER_ACTIVE_TIMESTAMP and\
p.mle.tlv.pending_tstamp ==
COMMISSIONER_PENDING_TIMESTAMP and\
p.mle.tlv.leader_data.data_version !=
(_pkt.mle.tlv.leader_data.data_version + 1) % 256 and\
p.mle.tlv.leader_data.stable_data_version !=
(_pkt.mle.tlv.leader_data.stable_data_version + 1) % 256 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_BORDER_AGENT_LOCATOR_TLV in p.thread_meshcop.tlv.type
).\
must_next()
else:
# Step 5: Leader MUST send a MLE Child Update Request or MLE Data
# Response to SED, including the following TLVs:
# - Leader Data TLV:
# Data Version field incremented
# Stable Version field incremented
# - Network Data TLV:
# - Active Timestamp TLV: 70s
# - Pending Timestamp TLV: 20s
pkts.filter_wpan_src64(LEADER).\
filter_wpan_dst64(DUT_EXTADDR).\
filter_mle_cmd2(MLE_CHILD_UPDATE_REQUEST, MLE_DATA_RESPONSE).\
filter(lambda p: p.mle.tlv.active_tstamp ==
LEADER_ACTIVE_TIMESTAMP and\
p.mle.tlv.pending_tstamp ==
COMMISSIONER_PENDING_TIMESTAMP and\
p.mle.tlv.leader_data.data_version !=
(_pkt.mle.tlv.leader_data.data_version + 1) % 256 and\
p.mle.tlv.leader_data.stable_data_version !=
(_pkt.mle.tlv.leader_data.stable_data_version + 1) % 256 and\
NETWORK_DATA_TLV in p.mle.tlv.type
).\
must_next()
# Step 6: The DUT MUST send a MLE Data Request to the Leader and include its current
# Active Timestamp
pkts.filter_mle_cmd(MLE_DATA_REQUEST).\
filter_wpan_src64(DUT_EXTADDR).\
filter_wpan_dst64(LEADER).\
filter(lambda p: {
TLV_REQUEST_TLV,
NETWORK_DATA_TLV
} <= set(p.mle.tlv.type) and\
p.thread_nwd.tlv.type is nullField and\
p.mle.tlv.active_tstamp == LEADER_ACTIVE_TIMESTAMP
).\
must_next()
# Step 6: Leader sends a MLE Data Response including the following TLVs:
# - Active Timestamp TLV
# - Pending Timestamp TLV
# - Pending Operational Dataset TLV
pkts.filter_mle_cmd(MLE_DATA_RESPONSE).\
filter_wpan_src64(LEADER).\
filter_wpan_dst64(DUT_EXTADDR).\
filter(lambda p: {
ACTIVE_TIMESTAMP_TLV,
PENDING_TIMESTAMP_TLV,
PENDING_OPERATION_DATASET_TLV
} <= set(p.mle.tlv.type)
).\
must_next()
# Step 9: The DUT MUST attempt to reattach by sending Parent Request using the parameters
# from Active Operational Dataset (Channel ='Primary', PANID: 0xFACE)
# The DUT MUST then attach using the parameters from the Pending Operational
# Dataset (Channel = 'Secondary', PANID:0xAFCE)
for pan_id in (PANID_INIT, COMMISSIONER_PENDING_PANID):
pkts.filter_mle_cmd(MLE_PARENT_REQUEST).\
filter_wpan_src64(DUT_EXTADDR).\
filter_LLARMA().\
filter(lambda p: p.wpan.dst_pan == pan_id).\
must_next()
# Step 10: The DUT MUST respond with an ICMPv6 Echo Reply
_pkt = pkts.filter_ping_request().\
filter_wpan_src64(COMMISSIONER).\
filter_ipv6_dst(DUT_MLEID).\
must_next()
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_wpan_src64(DUT_EXTADDR).\
filter_ipv6_dst(COMMISSIONER_MLEID).\
must_next()
class Cert_9_2_8_PersistentDatasets_ROUTER(Cert_9_2_8_PersistentDatasets_Base):
TOPOLOGY = copy.deepcopy(Cert_9_2_8_PersistentDatasets_Base.TOPOLOGY)
TOPOLOGY[DUT]['mode'] = 'rdn'
class Cert_9_2_8_PersistentDatasets_ED(Cert_9_2_8_PersistentDatasets_Base):
TOPOLOGY = copy.deepcopy(Cert_9_2_8_PersistentDatasets_Base.TOPOLOGY)
TOPOLOGY[DUT]['mode'] = 'rn'
TOPOLOGY[DUT]['is_mtd'] = True
TOPOLOGY[DUT]['timeout'] = config.DEFAULT_CHILD_TIMEOUT
class Cert_9_2_8_PersistentDatasets_SED(Cert_9_2_8_PersistentDatasets_Base):
TOPOLOGY = copy.deepcopy(Cert_9_2_8_PersistentDatasets_Base.TOPOLOGY)
TOPOLOGY[DUT]['mode'] = '-'
TOPOLOGY[DUT]['is_mtd'] = True
TOPOLOGY[DUT]['timeout'] = config.DEFAULT_CHILD_TIMEOUT
del (Cert_9_2_8_PersistentDatasets_Base)
if __name__ == '__main__':
unittest.main()
@@ -1,762 +0,0 @@
#!/usr/bin/env python3
#
# 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 unittest
import config
import thread_cert
from pktverify.consts import MLE_CHILD_ID_REQUEST, MLE_CHILD_ID_RESPONSE, MLE_DATA_RESPONSE, MLE_DATA_REQUEST, MGMT_PENDING_SET_URI, MGMT_ACTIVE_SET_URI, MGMT_DATASET_CHANGED_URI, SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ACTIVE_OPERATION_DATASET_TLV, ACTIVE_TIMESTAMP_TLV, PENDING_TIMESTAMP_TLV, TLV_REQUEST_TLV, NETWORK_DATA_TLV, NM_BORDER_AGENT_LOCATOR_TLV, NM_COMMISSIONER_SESSION_ID_TLV, NM_DELAY_TIMER_TLV, PENDING_OPERATION_DATASET_TLV, NWD_COMMISSIONING_DATA_TLV, LEADER_ALOC, NM_ACTIVE_TIMESTAMP_TLV, NM_CHANNEL_TLV, NM_CHANNEL_MASK_TLV, NM_EXTENDED_PAN_ID_TLV, NM_NETWORK_MESH_LOCAL_PREFIX_TLV, NM_NETWORK_KEY_TLV, NM_NETWORK_NAME_TLV, NM_PAN_ID_TLV, NM_PSKC_TLV, NM_SECURITY_POLICY_TLV
from pktverify.packet_verifier import PacketVerifier
from pktverify.null_field import nullField
CHANNEL_INIT = 19
PANID_INIT = 0xface
TIMESTAMP_INIT = 10
CHANNEL_SECOND = 20
CHANNEL_FINAL = 19
PANID_FINAL = 0xabcd
ROUTER2_ACTIVE_TIMESTAMP = 15
ROUTER2_PENDING_ACTIVE_TIMESTAMP = 410
ROUTER2_PENDING_TIMESTAMP = 50
ROUTER2_DELAY_TIMER = 200000
ROUTER2_NET_NAME = 'TEST'
COMM_PENDING_ACTIVE_TIMESTAMP = 210
COMM_PENDING_TIMESTAMP = 30
COMM_DELAY_TIMER = 1000000
COMMISSIONER = 1
LEADER = 2
ROUTER1 = 3
ROUTER2 = 4
# Test Purpose and Description:
# -----------------------------
# The purpose of this test case is to verify how Pending Operational Datasets
# are synchronized when two partitions merge.
#
# Test Topology:
# -------------
# Commissioner
# |
# Leader
# |
# Router_1
# |
# Router_2
#
# Note: Router_1 and Router_2 will be in&out RF shield box
#
# DUT Types:
# ----------
# Leader
# Router
class Cert_9_2_09_PendingPartition(thread_cert.TestCase):
SUPPORT_NCP = False
TOPOLOGY = {
COMMISSIONER: {
'name': 'COMMISSIONER',
'active_dataset': {
'timestamp': TIMESTAMP_INIT,
'panid': PANID_INIT,
'channel': CHANNEL_INIT
},
'mode': 'rdn',
'allowlist': [LEADER]
},
LEADER: {
'name': 'LEADER',
'active_dataset': {
'timestamp': TIMESTAMP_INIT,
'panid': PANID_INIT,
'channel': CHANNEL_INIT
},
'mode': 'rdn',
'partition_id': 0xffffffff,
'allowlist': [COMMISSIONER, ROUTER1]
},
ROUTER1: {
'name': 'ROUTER_1',
'active_dataset': {
'timestamp': TIMESTAMP_INIT,
'panid': PANID_INIT,
'channel': CHANNEL_INIT
},
'mode': 'rdn',
'allowlist': [LEADER, ROUTER2]
},
ROUTER2: {
'name': 'ROUTER_2',
'active_dataset': {
'timestamp': TIMESTAMP_INIT,
'panid': PANID_INIT,
'channel': CHANNEL_INIT
},
'mode': 'rdn',
'network_id_timeout': 70,
'allowlist': [ROUTER1]
},
}
def test(self):
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[COMMISSIONER].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'router')
self.nodes[COMMISSIONER].commissioner_start()
self.simulator.go(3)
self.nodes[ROUTER1].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
self.nodes[ROUTER2].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER2].get_state(), 'router')
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,
panid=PANID_INIT,
)
self.simulator.go(5)
self.nodes[LEADER].remove_allowlist(self.nodes[ROUTER1].get_addr64())
self.nodes[ROUTER1].remove_allowlist(self.nodes[LEADER].get_addr64())
self.nodes[ROUTER2].set_preferred_partition_id(1)
self.simulator.go(250)
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
self.assertEqual(self.nodes[ROUTER2].get_state(), 'leader')
# Keeping network id timeout at 70 can result in ROUTER2
# occasionally creating its own partition. Reset back to 120
# here to avoid occasional test failures.
self.nodes[ROUTER2].set_network_id_timeout(120)
self.nodes[ROUTER2].commissioner_start()
self.simulator.go(3)
self.nodes[ROUTER2].send_mgmt_active_set(
active_timestamp=ROUTER2_ACTIVE_TIMESTAMP,
network_name=ROUTER2_NET_NAME,
)
self.simulator.go(5)
self.nodes[ROUTER2].send_mgmt_pending_set(
pending_timestamp=ROUTER2_PENDING_TIMESTAMP,
active_timestamp=ROUTER2_PENDING_ACTIVE_TIMESTAMP,
delay_timer=ROUTER2_DELAY_TIMER,
channel=CHANNEL_FINAL,
panid=PANID_FINAL,
)
self.simulator.go(5)
self.nodes[LEADER].add_allowlist(self.nodes[ROUTER1].get_addr64())
self.nodes[ROUTER1].add_allowlist(self.nodes[LEADER].get_addr64())
self.simulator.go(260)
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
self.assertEqual(self.nodes[ROUTER2].get_state(), 'router')
self.collect_rlocs()
self.collect_rloc16s()
self.collect_ipaddrs()
self.assertEqual(self.nodes[COMMISSIONER].get_panid(), PANID_FINAL)
self.assertEqual(self.nodes[LEADER].get_panid(), PANID_FINAL)
self.assertEqual(self.nodes[ROUTER1].get_panid(), PANID_FINAL)
self.assertEqual(self.nodes[ROUTER2].get_panid(), PANID_FINAL)
self.assertEqual(self.nodes[COMMISSIONER].get_channel(), CHANNEL_FINAL)
self.assertEqual(self.nodes[LEADER].get_channel(), CHANNEL_FINAL)
self.assertEqual(self.nodes[ROUTER1].get_channel(), CHANNEL_FINAL)
self.assertEqual(self.nodes[ROUTER2].get_channel(), CHANNEL_FINAL)
leader_addr = self.nodes[LEADER].get_ip6_address(config.ADDRESS_TYPE.ML_EID)
router1_addr = self.nodes[ROUTER1].get_ip6_address(config.ADDRESS_TYPE.ML_EID)
self.assertTrue(self.nodes[ROUTER2].ping(leader_addr, timeout=10))
self.assertTrue(self.nodes[COMMISSIONER].ping(router1_addr, timeout=10))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
LEADER_RLOC = pv.vars['LEADER_RLOC']
LEADER_MLEID = pv.vars['LEADER_MLEID']
COMMISSIONER = pv.vars['COMMISSIONER']
COMMISSIONER_MLEID = pv.vars['COMMISSIONER_MLEID']
COMMISSIONER_RLOC = pv.vars['COMMISSIONER_RLOC']
COMMISSIONER_RLOC16 = pv.vars['COMMISSIONER_RLOC16']
ROUTER_1 = pv.vars['ROUTER_1']
ROUTER_1_RLOC = pv.vars['ROUTER_1_RLOC']
ROUTER_1_MLEID = pv.vars['ROUTER_1_MLEID']
ROUTER_2 = pv.vars['ROUTER_2']
ROUTER_2_RLOC = pv.vars['ROUTER_2_RLOC']
ROUTER_2_MLEID = pv.vars['ROUTER_2_MLEID']
# Step 1: Ensure the topology is formed correctly
for node in ('COMMISSIONER', 'ROUTER_1'):
pv.verify_attached(node, 'LEADER')
pv.verify_attached('ROUTER_2', 'ROUTER_1')
_pkt = pkts.last()
# Step 3: Leader sends MGMT_PENDING_SET.rsq 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 4: Leader MUST multicast MLE Data Response with the new network data,
# 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
# - Active Timestamp TLV: 10s
# - Pending Timestamp TLV: 30s
#
# Router_1 MUST send a unicast MLE Data Request to the Leader, including the
# following TLVs:
# - TLV Request TLV:
# - Network Data TLV
# - Active Timestamp TLV (10s)
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.pending_tstamp == COMM_PENDING_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_BORDER_AGENT_LOCATOR_TLV in p.thread_meshcop.tlv.type
).\
must_next()
pkts.filter_wpan_src64(ROUTER_1).\
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.mle.tlv.active_tstamp == TIMESTAMP_INIT and\
p.thread_meshcop.tlv.type is nullField
).\
must_next()
# Step 5: Leader sends a MLE Data Response to Router_1 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
# - Active Timestamp TLV: 10s
# - Pending Timestamp TLV: 30s
# - Pending Operational Dataset TLV
# - Active Timestamp TLV <210s>
# - Delay Timer TLV <~ 1000s>
# - Channel TLV : Secondary
# - PAN ID TLV : 0xAFCE
_dr_pkt = pkts.filter_mle_cmd(MLE_DATA_RESPONSE).\
filter_wpan_src64(LEADER).\
filter_wpan_dst64(ROUTER_1).\
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.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_BORDER_AGENT_LOCATOR_TLV in p.thread_meshcop.tlv.type and\
p.mle.tlv.active_tstamp == TIMESTAMP_INIT 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 6: Router_1 MUST multicast MLE Data Response with the new network data,
# 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
# - Active Timestamp TLV: 10s
# - Pending Timestamp TLV: 30s
with pkts.save_index():
pkts.filter_mle_cmd(MLE_DATA_RESPONSE).\
filter_wpan_src64(ROUTER_1).\
filter_LLANMA().\
filter(lambda p: p.mle.tlv.active_tstamp == TIMESTAMP_INIT and\
p.mle.tlv.pending_tstamp == COMM_PENDING_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_BORDER_AGENT_LOCATOR_TLV in p.thread_meshcop.tlv.type
).\
must_next()
# Step 8: Router_1 sends a MLE Data Response to Router_2 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
# - Active Timestamp TLV: 10s
# - Pending Timestamp TLV: 30s
# - Pending Operational Dataset TLV
# - Active Timestamp TLV <210s>
# - Delay Timer TLV <~ 1000s>
# - Channel TLV : Secondary
# - PAN ID TLV : 0xAFCE
pkts.filter_mle_cmd(MLE_DATA_RESPONSE).\
filter_wpan_src64(ROUTER_1).\
filter_wpan_dst64(ROUTER_2).\
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.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_BORDER_AGENT_LOCATOR_TLV in p.thread_meshcop.tlv.type and\
p.mle.tlv.active_tstamp == TIMESTAMP_INIT 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 10: Router_1 MUST attach to the new partition formed by Router_2
pv.verify_attached('ROUTER_1', 'ROUTER_2')
_pkt = pkts.last()
# Step 12: Router_1 MUST send a unicast MLE Data Request to the Router_2, including the
# following TLVs:
# - TLV Request TLV:
# - Network Data TLV
# - Active Timestamp TLV (10s)
# - Pending Timestamp TLV (30s)
with pkts.save_index():
pkts.filter_wpan_src64(ROUTER_1).\
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.mle.tlv.active_tstamp == TIMESTAMP_INIT and\
p.mle.tlv.pending_tstamp == COMM_PENDING_TIMESTAMP and\
p.thread_meshcop.tlv.type is nullField
).\
must_next()
# Step 14: Router_1 MUST multicast MLE Data Response with the new network data,
# 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
# - Active Timestamp TLV: 15s
# - Pending Timestamp TLV: 30s
pkts.filter_mle_cmd(MLE_DATA_RESPONSE).\
filter_wpan_src64(ROUTER_1).\
filter_LLANMA().\
filter(lambda p: p.mle.tlv.active_tstamp == ROUTER2_ACTIVE_TIMESTAMP and\
p.mle.tlv.pending_tstamp == COMM_PENDING_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_BORDER_AGENT_LOCATOR_TLV in p.thread_meshcop.tlv.type
).\
must_next()
# Step 17: Router_1 MUST send a unicast MLE Data Request to the Router_2, including the
# following TLVs:
# - TLV Request TLV:
# - Network Data TLV
# - Active Timestamp TLV (15s)
# - Pending Timestamp TLV (30s)
pkts.filter_wpan_src64(ROUTER_1).\
filter_wpan_dst64(ROUTER_2).\
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.mle.tlv.active_tstamp == ROUTER2_ACTIVE_TIMESTAMP and\
p.mle.tlv.pending_tstamp == COMM_PENDING_TIMESTAMP and\
p.thread_meshcop.tlv.type is nullField
).\
must_next()
# Step 19: Router_1 MUST multicast MLE Data Response with the new network data,
# 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
# - Active Timestamp TLV: 15s
# - Pending Timestamp TLV: 50s
pkts.filter_mle_cmd(MLE_DATA_RESPONSE).\
filter_wpan_src64(ROUTER_1).\
filter_LLANMA().\
filter(lambda p: p.mle.tlv.active_tstamp == ROUTER2_ACTIVE_TIMESTAMP and\
p.mle.tlv.pending_tstamp == ROUTER2_PENDING_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_BORDER_AGENT_LOCATOR_TLV in p.thread_meshcop.tlv.type
).\
must_next()
# Step 21: Router_1 MUST go through the attachment process and send MLE Child ID
# Request to the Leader, including the following TLV:
# - Active Timestamp TLV: 15s
pkts.filter_mle_cmd(MLE_CHILD_ID_REQUEST).\
filter_wpan_src64(ROUTER_1).\
filter_wpan_dst64(LEADER).\
filter(lambda p: p.mle.tlv.active_tstamp == ROUTER2_ACTIVE_TIMESTAMP).\
must_next()
# Step 22: Leader MUST send MLE Child ID Response to Router_1, including its current
# active timestamp and active configuration set:
# - Active Timestamp TLV: 10s
# - Active Operational Dataset TLV:
# - Pending Timestamp TLV: 30s
# - Pending Operational Dataset TLV:
# - Active Timestamp TLV:210s
_pkt = pkts.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).\
filter_wpan_src64(LEADER).\
filter_wpan_dst64(ROUTER_1).\
filter(lambda p:
p.mle.tlv.active_tstamp == TIMESTAMP_INIT and\
p.mle.tlv.pending_tstamp == COMM_PENDING_TIMESTAMP and\
p.thread_meshcop.tlv.active_tstamp == COMM_PENDING_ACTIVE_TIMESTAMP
).\
must_next()
# Step 23: Router_1 MUST send MGMT_ACTIVE_SET.req to the Leader RLOC or Anycast Locator:
# CoAP Request URI
# coap://[Leader]:MM/c/as
# CoAP Payload
# - Active Timestamp TLV: 15s
# - Network Name TLV: “TEST”
# - PAN ID TLV
# - Channel TLV
with pkts.save_index():
pkts.filter_wpan_src64(ROUTER_1).\
filter_ipv6_2dsts(LEADER_ALOC, LEADER_RLOC).\
filter_coap_request(MGMT_ACTIVE_SET_URI) .\
filter(lambda p: {
NM_ACTIVE_TIMESTAMP_TLV,
NM_CHANNEL_TLV,
NM_NETWORK_NAME_TLV,
NM_PAN_ID_TLV,
} <= set(p.thread_meshcop.tlv.type) and\
p.thread_meshcop.tlv.active_tstamp == ROUTER2_ACTIVE_TIMESTAMP and\
p.thread_meshcop.tlv.net_name == [ROUTER2_NET_NAME]
).\
must_next()
# Step 24: Leader sends MGMT_ACTIVE_SET.rsp to the Router_1:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# - State TLV (value = Accept)
# TODO: this ack can not be parsed by pktverify
# Step 25: Leader MUST send MGMT_DATASET_CHANGED.ntf to Commissioner:
# CoAP Request URI
# coap://[ Commissioner]:MM/c/dc
# CoAP Payload
# <empty>
with pkts.save_index():
pkts.filter_wpan_src64(LEADER).\
filter_wpan_dst16(COMMISSIONER_RLOC16).\
filter_coap_request(MGMT_DATASET_CHANGED_URI) .\
filter(lambda p: p.thread_meshcop.tlv.type is nullField).\
must_next()
# Step 27: Router_1 MUST send MGMT_PENDING_SET.req to the Leader RLOC or Anycast Locator:
# CoAP Request URI
# coap://[Leader]:MM/c/ps
# CoAP Payload
# - Delay Timer TLV: ~200s
# - Channel TLV : Primary
# - PAN ID TLV : 0xABCD
# - Network Name TLV: TEST
# - Active Timestamp TLV: 410s
# - Pending Timestamp TLV: 50s
with pkts.save_index():
pkts.filter_wpan_src64(ROUTER_1).\
filter_ipv6_2dsts(LEADER_ALOC, LEADER_RLOC).\
filter_coap_request(MGMT_PENDING_SET_URI) .\
filter(lambda p:
p.thread_meshcop.tlv.delay_timer < ROUTER2_DELAY_TIMER and\
p.thread_meshcop.tlv.channel == [CHANNEL_FINAL] and\
p.thread_meshcop.tlv.pan_id == [PANID_FINAL] and\
p.thread_meshcop.tlv.active_tstamp == ROUTER2_PENDING_ACTIVE_TIMESTAMP and\
p.thread_meshcop.tlv.pending_tstamp == ROUTER2_PENDING_TIMESTAMP and\
p.thread_meshcop.tlv.net_name == [ROUTER2_NET_NAME]
).\
must_next()
# Step 28: Leader sends MGMT_PENDING_SET.rsq to the Router_1:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# - State TLV (value = Accept)
# TODO: this ack can not be parsed by pktverify
# Step 29: Leader MUST send MGMT_DATASET_CHANGED.ntf to Commissioner:
# CoAP Request URI
# coap://[ Commissioner]:MM/c/dc
# CoAP Payload
# <empty>
pkts.filter_wpan_src64(LEADER).\
filter_wpan_dst16(COMMISSIONER_RLOC16).\
filter_coap_request(MGMT_DATASET_CHANGED_URI) .\
filter(lambda p: p.thread_meshcop.tlv.type is nullField).\
must_next()
# Step 30: Leader MUST multicast MLE Data Response with the new network data,
# 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
# - Active Timestamp TLV: 15s
# - Pending Timestamp TLV: 50s
pkts.filter_mle_cmd(MLE_DATA_RESPONSE).\
filter_wpan_src64(LEADER).\
filter_LLANMA().\
filter(lambda p: p.mle.tlv.active_tstamp == ROUTER2_ACTIVE_TIMESTAMP and\
p.mle.tlv.pending_tstamp == ROUTER2_PENDING_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_BORDER_AGENT_LOCATOR_TLV in p.thread_meshcop.tlv.type
).\
must_next()
#
# Disable steps 32, 33, and 34 until a solution is
# found. Depending on timing, there may be one MLE Data
# Request/Response exchange for both Active and Pending
# Operational Datasets or individual MLE Data Request/Response
# exchange for each Active and Pending Operational Dataset
# separately.
#
# Step 32: Leader sends a MLE Data Response to Commissioner including the following TLVs:
# - Source Address TLV
# - Leader Data TLV
# - Active Timestamp TLV: 15s
# - Active Operational Dataset TLV:
# - Network Name TLV : TEST
# - Pending Timestamp TLV: 50s
# - Pending Operational Dataset TLV
# - Active Timestamp TLV <410s>
# - Delay Timer TLV <~ 200s>
# - Channel TLV : Primary
# - PAN ID TLV : 0xABCD
# - Network Name TLV : 'TEST'
#with pkts.save_index():
# pkts.filter_mle_cmd(MLE_DATA_RESPONSE).\
# filter_wpan_src64(LEADER).\
# filter_wpan_dst64(COMMISSIONER).\
# 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.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_BORDER_AGENT_LOCATOR_TLV in p.thread_meshcop.tlv.type and\
# p.mle.tlv.active_tstamp == ROUTER2_ACTIVE_TIMESTAMP and\
# p.mle.tlv.pending_tstamp == ROUTER2_PENDING_TIMESTAMP and\
# p.thread_meshcop.tlv.net_name == [ROUTER2_NET_NAME, ROUTER2_NET_NAME] and\
# p.thread_meshcop.tlv.delay_timer < ROUTER2_DELAY_TIMER and\
# p.thread_meshcop.tlv.active_tstamp == ROUTER2_PENDING_ACTIVE_TIMESTAMP and\
# p.thread_meshcop.tlv.channel == [CHANNEL_INIT, CHANNEL_FINAL] and\
# p.thread_meshcop.tlv.pan_id == [PANID_INIT, PANID_FINAL]
# ).\
# must_next()
# Step 33: Router_1 MUST send a unicast MLE Data Request to the Leader, including the
# following TLVs:
# - TLV Request TLV:
# - Network Data TLV
# - Active Timestamp TLV (10s)
# - Pending Timestamp TLV (30s)
#pkts.filter_wpan_src64(ROUTER_1).\
# 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.mle.tlv.active_tstamp == TIMESTAMP_INIT and\
# p.mle.tlv.pending_tstamp == COMM_PENDING_TIMESTAMP and\
# p.thread_meshcop.tlv.type is nullField
# ).\
# must_next()
# Step 34: Leader sends a MLE Data Response to Router_1 including the following TLVs:
# - Source Address TLV
# - Leader Data TLV
# - Active Timestamp TLV: 15s
# - Active Operational Dataset TLV:
# - Network Name TLV : TEST
# - Pending Timestamp TLV: 50s
# - Pending Operational Dataset TLV
# - Active Timestamp TLV <410s>
# - Delay Timer TLV <~ 200s>
# - Channel TLV : Primary
# - PAN ID TLV : 0xABCD
#pkts.filter_mle_cmd(MLE_DATA_RESPONSE).\
# filter_wpan_src64(LEADER).\
# filter_wpan_dst64(ROUTER_1).\
# 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.active_tstamp == ROUTER2_ACTIVE_TIMESTAMP and\
# p.mle.tlv.pending_tstamp == ROUTER2_PENDING_TIMESTAMP and\
# p.thread_meshcop.tlv.delay_timer < ROUTER2_DELAY_TIMER and\
# p.thread_meshcop.tlv.active_tstamp == ROUTER2_PENDING_ACTIVE_TIMESTAMP and\
# p.thread_meshcop.tlv.channel == [CHANNEL_INIT, CHANNEL_FINAL] and\
# p.thread_meshcop.tlv.pan_id == [PANID_INIT, PANID_FINAL]
# ).\
# must_next()
# Step 36: The DUT MUST respond with an ICMPv6 Echo Reply
_pkt = pkts.filter_ping_request().\
filter_ipv6_src_dst(ROUTER_2_MLEID, LEADER_MLEID).\
filter_ipv6_dst(LEADER_MLEID).\
must_next()
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_ipv6_src_dst(LEADER_MLEID, ROUTER_2_MLEID).\
must_next()
_pkt = pkts.filter_ping_request().\
filter_ipv6_src_dst(COMMISSIONER_MLEID, ROUTER_1_MLEID).\
must_next()
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_ipv6_src_dst(ROUTER_1_MLEID, COMMISSIONER_MLEID).\
must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,242 +0,0 @@
#!/usr/bin/env python3
#
# 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 unittest
import config
import thread_cert
from pktverify.consts import MLE_ADVERTISEMENT, MLE_PARENT_REQUEST, MLE_DATA_REQUEST, MLE_DATA_RESPONSE, MLE_CHILD_UPDATE_REQUEST, MLE_CHILD_UPDATE_RESPONSE, MLE_CHILD_ID_REQUEST, MLE_CHILD_ID_RESPONSE, ADDR_SOL_URI, VERSION_TLV, TLV_REQUEST_TLV, SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, CHALLENGE_TLV, LINK_MARGIN_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV, PENDING_TIMESTAMP_TLV, ACTIVE_OPERATION_DATASET_TLV, PENDING_OPERATION_DATASET_TLV, LINK_LOCAL_ALL_NODES_MULTICAST_ADDRESS, LINK_LOCAL_ALL_ROUTERS_MULTICAST_ADDRESS, NM_COMMISSIONER_SESSION_ID_TLV, NM_BORDER_AGENT_LOCATOR_TLV, NM_CHANNEL_TLV, NM_NETWORK_MESH_LOCAL_PREFIX_TLV, NM_PAN_ID_TLV, NM_DELAY_TIMER_TLV, NM_ACTIVE_TIMESTAMP_TLV
from pktverify.packet_verifier import PacketVerifier
CHANNEL_INIT = 19
PANID_INIT = 0xface
CHANNEL_FINAL = 16
PANID_FINAL = 0xafce
COMMISSIONER = 1
LEADER = 2
ROUTER1 = 3
ED1 = 4
SED1 = 5
MTDS = [ED1, SED1]
class Cert_9_2_10_PendingPartition(thread_cert.TestCase):
SUPPORT_NCP = False
TOPOLOGY = {
COMMISSIONER: {
'name': 'COMMISSIONER',
'active_dataset': {
'timestamp': 15,
'channel': 19
},
'mode': 'rdn',
'allowlist': [LEADER]
},
LEADER: {
'name': 'LEADER',
'active_dataset': {
'timestamp': 15,
'channel': 19
},
'mode': 'rdn',
'partition_id': 0xffffffff,
'allowlist': [COMMISSIONER, ROUTER1]
},
ROUTER1: {
'name': 'ROUTER',
'active_dataset': {
'timestamp': 15,
'channel': 19
},
'mode': 'rdn',
'allowlist': [LEADER, ED1, SED1]
},
ED1: {
'name': 'MED',
'channel': 19,
'is_mtd': True,
'mode': 'rn',
'allowlist': [ROUTER1]
},
SED1: {
'name': 'SED',
'channel': 19,
'is_mtd': True,
'mode': '-',
'timeout': config.DEFAULT_CHILD_TIMEOUT,
'allowlist': [ROUTER1]
},
}
def test(self):
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[COMMISSIONER].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'router')
self.nodes[COMMISSIONER].commissioner_start()
self.simulator.go(3)
self.nodes[ROUTER1].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
self.nodes[ED1].start()
self.simulator.go(5)
self.assertEqual(self.nodes[ED1].get_state(), 'child')
self.nodes[SED1].start()
self.simulator.go(5)
self.assertEqual(self.nodes[SED1].get_state(), 'child')
self.nodes[COMMISSIONER].send_mgmt_pending_set(
pending_timestamp=30,
active_timestamp=165,
delay_timer=250,
channel=CHANNEL_FINAL,
panid=PANID_FINAL,
)
self.simulator.go(260)
self.nodes[LEADER].remove_allowlist(self.nodes[ROUTER1].get_addr64())
self.nodes[ROUTER1].remove_allowlist(self.nodes[LEADER].get_addr64())
self.simulator.go(300)
self.assertEqual(self.nodes[ROUTER1].get_state(), 'leader')
self.assertEqual(self.nodes[ED1].get_state(), 'child')
self.assertEqual(self.nodes[SED1].get_state(), 'child')
self.assertEqual(self.nodes[ROUTER1].get_panid(), PANID_FINAL)
self.assertEqual(self.nodes[ED1].get_panid(), PANID_FINAL)
self.assertEqual(self.nodes[SED1].get_panid(), PANID_FINAL)
self.assertEqual(self.nodes[ROUTER1].get_channel(), CHANNEL_FINAL)
self.assertEqual(self.nodes[ED1].get_channel(), CHANNEL_FINAL)
self.assertEqual(self.nodes[SED1].get_channel(), CHANNEL_FINAL)
self.nodes[LEADER].add_allowlist(self.nodes[ROUTER1].get_addr64())
self.nodes[ROUTER1].add_allowlist(self.nodes[LEADER].get_addr64())
self.simulator.go(60)
self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'router')
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
self.assertEqual(self.nodes[ED1].get_state(), 'child')
self.assertEqual(self.nodes[SED1].get_state(), 'child')
ipaddrs = self.nodes[ED1].get_addrs()
for ipaddr in ipaddrs:
if ipaddr[0:4] != 'fe80':
break
self.assertTrue(self.nodes[LEADER].ping(ipaddr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
ROUTER = pv.vars['ROUTER']
MED = pv.vars['MED']
SED = pv.vars['SED']
COMMISSIONER = pv.vars['COMMISSIONER']
_rpkts = pkts.filter_wpan_src64(ROUTER, cascade=False)
# Step 1: Ensure the topology is formed correctly
_rpkts.filter_wpan_dst64(SED).filter_mle_cmd(MLE_CHILD_ID_RESPONSE).must_next()
# Step 5: Router MUST send a unicast MLE Data Request to the Leader
_rpkts.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))
_rpkts_med = _rpkts.copy()
# Step 7: Router MUST multicast a MLE Data Response
_rpkts.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 {NM_COMMISSIONER_SESSION_ID_TLV, NM_BORDER_AGENT_LOCATOR_TLV} <= set(
p.thread_meshcop.tlv.type) and p.thread_nwd.tlv.stable == [0])
# Step 8: MED MUST send a unicast MLE Data Request to Router_1,
with pkts.save_index():
pkts.filter_wpan_src64(MED).filter_wpan_dst64(ROUTER).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 9: Router MUST send a unicast MLE Data Response to MED_1
_rpkts_med.filter_wpan_dst64(MED).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_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
} <= set(p.thread_meshcop.tlv.type) and p.thread_nwd.tlv.stable == [0])
# Step 10: Router MUST send MLE Child Update Request to SED_1
_rpkts.range(pkts.index).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))
# Step 11: SED MUST send a unicast MLE Data Request to Router_1
pkts.filter_wpan_src64(SED).filter_wpan_dst64(ROUTER).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 12: Router MUST send a unicast MLE Data Response to SED_1
_pkt = _rpkts.filter_wpan_dst64(SED).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_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
} <= set(p.thread_meshcop.tlv.type))
# Step 14: After NETWORK_ID_TIMEOUT, Router MUST start a new partition
_rpkts.filter_ipv6_dst(LINK_LOCAL_ALL_ROUTERS_MULTICAST_ADDRESS).filter_mle_cmd(
MLE_PARENT_REQUEST).must_next().must_verify(lambda p: p.sniff_timestamp - _pkt.sniff_timestamp > 300)
_rpkts.filter_mle_cmd(MLE_DATA_RESPONSE).filter(lambda p: p.wpan.dst_pan == PANID_FINAL).must_next()
# Step 16: After the Delay Timer expires, Router MUST move to the Secondary channel
_rpkts.filter_mle_cmd(MLE_ADVERTISEMENT).filter(lambda p: p.wpan.dst_pan == PANID_FINAL).must_next()
# Step 19: Router MUST reattach to the Leader and the partitions MUST merge
pkts.filter_wpan_src64(LEADER).filter_wpan_dst64(ROUTER).filter_mle_cmd(
MLE_CHILD_ID_RESPONSE).must_next().must_verify(lambda p: p.mle.tlv.leader_data.partition_id == 0xffffffff)
# Step 20: MED MUST respond with an ICMPv6 Echo Reply
p = pkts.filter_ping_request().filter_wpan_src64(LEADER).must_next()
pkts.filter_ping_reply(identifier=p.icmpv6.echo.identifier).filter_wpan_src64(MED).must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,390 +0,0 @@
#!/usr/bin/env python3
#
# 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 unittest
import config
import thread_cert
from pktverify.consts import MLE_PARENT_REQUEST, MLE_DATA_RESPONSE, MLE_DATA_REQUEST, MGMT_PENDING_SET_URI, SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ACTIVE_OPERATION_DATASET_TLV, ACTIVE_TIMESTAMP_TLV, PENDING_TIMESTAMP_TLV, TLV_REQUEST_TLV, NETWORK_DATA_TLV, NM_BORDER_AGENT_LOCATOR_TLV, NM_COMMISSIONER_SESSION_ID_TLV, NM_DELAY_TIMER_TLV, PENDING_OPERATION_DATASET_TLV, NWD_COMMISSIONING_DATA_TLV
from pktverify.packet_verifier import PacketVerifier
from pktverify.null_field import nullField
KEY1 = '00112233445566778899aabbccddeeff'
KEY2 = 'ffeeddccbbaa99887766554433221100'
CHANNEL_INIT = 19
PANID_INIT = 0xface
COMMISSIONER = 1
LEADER = 2
ROUTER1 = 3
ED1 = 4
SED1 = 5
# Test Purpose and Description:
# -----------------------------
# The purpose of this test case is to confirm the DUT correctly applies
# DELAY_TIMER_DEFAULT when the network key is changed.
# The Commissioner first tries to set a network key update to happen too
# soon (delay of 60s vs DELAY_TIMER_DEFAULT of 300s); the DUT is expected
# to override the short value and communicate an appropriately longer delay
# to the Router.
# The Commissioner then sets a delay time longer than default; the DUT is
# validated to not artificially clamp the longer time back to the
# DELAY_TIMER_DEFAULT value.
#
# Test Topology:
# -------------
# Commissioner
# |
# Leader
# |
# Router
# / \
# ED SED
#
# DUT Types:
# ----------
# Leader
class Cert_9_2_11_NetworkKey(thread_cert.TestCase):
USE_MESSAGE_FACTORY = False
SUPPORT_NCP = False
TOPOLOGY = {
COMMISSIONER: {
'name': 'COMMISSIONER',
'active_dataset': {
'timestamp': 10,
'panid': PANID_INIT,
'channel': CHANNEL_INIT,
'network_key': KEY1
},
'mode': 'rdn',
'allowlist': [LEADER]
},
LEADER: {
'name': 'LEADER',
'active_dataset': {
'timestamp': 10,
'panid': PANID_INIT,
'channel': CHANNEL_INIT,
'network_key': KEY1
},
'mode': 'rdn',
'allowlist': [COMMISSIONER, ROUTER1]
},
ROUTER1: {
'name': 'ROUTER',
'active_dataset': {
'timestamp': 10,
'panid': PANID_INIT,
'channel': CHANNEL_INIT,
'network_key': KEY1
},
'mode': 'rdn',
'allowlist': [LEADER, ED1, SED1]
},
ED1: {
'name': 'ED',
'channel': CHANNEL_INIT,
'is_mtd': True,
'network_key': KEY1,
'mode': 'rn',
'panid': PANID_INIT,
'allowlist': [ROUTER1]
},
SED1: {
'name': 'SED',
'channel': CHANNEL_INIT,
'is_mtd': True,
'network_key': KEY1,
'mode': '-',
'panid': PANID_INIT,
'timeout': config.DEFAULT_CHILD_TIMEOUT,
'allowlist': [ROUTER1]
},
}
def test(self):
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[COMMISSIONER].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'router')
self.nodes[COMMISSIONER].commissioner_start()
self.simulator.go(3)
self.nodes[ROUTER1].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
self.nodes[ED1].start()
self.simulator.go(5)
self.assertEqual(self.nodes[ED1].get_state(), 'child')
self.nodes[SED1].start()
self.simulator.go(5)
self.assertEqual(self.nodes[SED1].get_state(), 'child')
self.collect_rlocs()
self.collect_ipaddrs()
self.nodes[COMMISSIONER].send_mgmt_pending_set(
pending_timestamp=10,
active_timestamp=70,
delay_timer=60000,
network_key=KEY2,
)
self.simulator.go(310)
self.assertEqual(self.nodes[COMMISSIONER].get_networkkey(), KEY2)
self.assertEqual(self.nodes[LEADER].get_networkkey(), KEY2)
self.assertEqual(self.nodes[ROUTER1].get_networkkey(), KEY2)
self.assertEqual(self.nodes[ED1].get_networkkey(), KEY2)
self.assertEqual(self.nodes[SED1].get_networkkey(), KEY2)
ipaddr = self.nodes[LEADER].get_ip6_address(config.ADDRESS_TYPE.ML_EID)
self.assertTrue(self.nodes[ROUTER1].ping(ipaddr))
self.nodes[COMMISSIONER].send_mgmt_pending_set(
pending_timestamp=20,
active_timestamp=30,
delay_timer=500000,
network_key=KEY1,
)
self.simulator.go(510)
self.assertEqual(self.nodes[COMMISSIONER].get_networkkey(), KEY1)
self.assertEqual(self.nodes[LEADER].get_networkkey(), KEY1)
self.assertEqual(self.nodes[ROUTER1].get_networkkey(), KEY1)
self.assertEqual(self.nodes[ED1].get_networkkey(), KEY1)
self.assertEqual(self.nodes[SED1].get_networkkey(), KEY1)
ipaddr = self.nodes[LEADER].get_ip6_address(config.ADDRESS_TYPE.ML_EID)
self.assertTrue(self.nodes[ROUTER1].ping(ipaddr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
LEADER_MLEID = pv.vars['LEADER_MLEID']
COMMISSIONER = pv.vars['COMMISSIONER']
COMMISSIONER_RLOC = pv.vars['COMMISSIONER_RLOC']
ROUTER = pv.vars['ROUTER']
ROUTER_MLEID = pv.vars['ROUTER_MLEID']
ED = pv.vars['ED']
SED = pv.vars['SED']
# Step 1: Ensure the topology is formed correctly
for node in ('COMMISSIONER', 'ROUTER'):
pv.verify_attached(node, 'LEADER')
for node in ('ED', 'SED'):
pv.verify_attached(node, 'ROUTER', 'MTD')
_pkt = pkts.last()
# Step 3: Leader sends MGMT_PENDING_SET.rsq to the Commissioner:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# - State TLV (value = Accept)
#
# Leader MUST multicast MLE Data Response with the new network data,
# including the following TLVs:
# - 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
# - Active Timestamp TLV: 10s
# - Pending Timestamp TLV: 20s
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)
pkts.filter_mle_cmd(MLE_DATA_RESPONSE).\
filter_wpan_src64(LEADER).\
filter_LLANMA().\
filter(lambda p: p.mle.tlv.active_tstamp == 10 and\
p.mle.tlv.pending_tstamp == 10 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_BORDER_AGENT_LOCATOR_TLV in p.thread_meshcop.tlv.type
).\
must_next()
# Step 5: 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
# - Active Timestamp TLV
# - Pending Timestamp TLV
# - Pending Operational Dataset TLV
# - Delay Timer TLV <greater than 200s>
# - Network Key TLV: New Network Key
# - Active Timestamp TLV <70s>
_dr_pkt = 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\
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_BORDER_AGENT_LOCATOR_TLV in p.thread_meshcop.tlv.type and\
p.thread_meshcop.tlv.delay_timer > 200000 and\
p.thread_meshcop.tlv.master_key == KEY2 and\
p.thread_meshcop.tlv.active_tstamp == 70
).\
must_next()
# Step 8: Verify all devices now use New Network key.
# checked in test()
# Step 9: Verify new MAC key is generated and used when sending ICMPv6 Echo Reply
# is received.
_pkt = pkts.filter_ping_request().\
filter_wpan_src64(ROUTER).\
filter_ipv6_dst(LEADER_MLEID).\
must_next()
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_wpan_src64(LEADER).\
filter_ipv6_dst(ROUTER_MLEID).\
must_next()
# Step 11: Leader sends MGMT_PENDING_SET.rsq to the Commissioner:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# - State TLV (value = Accept)
#
# Leader MUST multicast MLE Data Response with the new network data,
# including the following TLVs:
# - 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
# - Active Timestamp TLV: 70s
# - Pending Timestamp TLV: 20s
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)
pkts.filter_mle_cmd(MLE_DATA_RESPONSE).\
filter_wpan_src64(LEADER).\
filter_LLANMA().\
filter(lambda p: p.mle.tlv.active_tstamp == 70 and\
p.mle.tlv.pending_tstamp == 20 and\
(p.mle.tlv.leader_data.data_version -
_dr_pkt.mle.tlv.leader_data.data_version) % 256 <= 127 and\
(p.mle.tlv.leader_data.stable_data_version -
_dr_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_BORDER_AGENT_LOCATOR_TLV in p.thread_meshcop.tlv.type
).\
must_next()
# Step 13: 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
# - Active Timestamp TLV <70s>
# - Pending Timestamp TLV <20s>
# - Pending Operational Dataset TLV
# - Active Timestamp TLV <30s>
# - Delay Timer TLV <greater than 300s>
# - Network Key TLV: New Network Key
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\
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_BORDER_AGENT_LOCATOR_TLV in p.thread_meshcop.tlv.type and\
p.mle.tlv.active_tstamp == 70 and\
p.mle.tlv.pending_tstamp == 20 and\
p.thread_meshcop.tlv.delay_timer > 300000 and\
p.thread_meshcop.tlv.master_key == KEY1 and\
p.thread_meshcop.tlv.active_tstamp == 30
).\
must_next()
# Step 17: The DUT MUST send an ICMPv6 Echo Reply using the new Network key
_pkt = pkts.filter_ping_request().\
filter_wpan_src64(ROUTER).\
filter_ipv6_dst(LEADER_MLEID).\
must_next()
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_wpan_src64(LEADER).\
filter_ipv6_dst(ROUTER_MLEID).\
must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,174 +0,0 @@
#!/usr/bin/env python3
#
# 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 unittest
import config
import thread_cert
from pktverify.consts import MLE_CHILD_ID_REQUEST, MLE_PARENT_REQUEST, MLE_CHILD_ID_RESPONSE, MLE_ANNOUNCE, CHANNEL_TLV, PAN_ID_TLV, ACTIVE_TIMESTAMP_TLV, LINK_LOCAL_ALL_NODES_MULTICAST_ADDRESS
from pktverify.packet_verifier import PacketVerifier
LEADER1 = 1
ROUTER1 = 2
LEADER2 = 3
MED = 4
DATASET1_TIMESTAMP = 20
DATASET1_CHANNEL = 11
DATASET1_PANID = 0xface
DATASET2_TIMESTAMP = 10
DATASET2_CHANNEL = 12
DATASET2_PANID = 0xafce
class Cert_9_2_12_Announce(thread_cert.TestCase):
SUPPORT_NCP = False
TOPOLOGY = {
LEADER1: {
'name': 'LEADER_1',
'active_dataset': {
'timestamp': DATASET1_TIMESTAMP,
'panid': DATASET1_PANID,
'channel': DATASET1_CHANNEL
},
'mode': 'rdn',
'allowlist': [ROUTER1]
},
ROUTER1: {
'name': 'ROUTER_1',
'active_dataset': {
'timestamp': DATASET1_TIMESTAMP,
'panid': DATASET1_PANID,
'channel': DATASET1_CHANNEL
},
'mode': 'rdn',
'allowlist': [LEADER1, LEADER2]
},
LEADER2: {
'name': 'LEADER_2',
'active_dataset': {
'timestamp': DATASET2_TIMESTAMP,
'panid': DATASET2_PANID,
'channel': DATASET2_CHANNEL
},
'mode': 'rdn',
'allowlist': [MED, ROUTER1]
},
MED: {
'name': 'MED',
'channel': DATASET2_CHANNEL,
'is_mtd': True,
'mode': 'rn',
'panid': DATASET2_PANID,
'allowlist': [LEADER2]
},
}
def test(self):
self.nodes[LEADER1].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER1].get_state(), 'leader')
self.nodes[LEADER1].commissioner_start()
self.simulator.go(3)
self.nodes[ROUTER1].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
self.nodes[LEADER2].start()
self.nodes[LEADER2].set_state('leader')
self.assertEqual(self.nodes[LEADER2].get_state(), 'leader')
self.nodes[MED].start()
self.simulator.go(5)
self.assertEqual(self.nodes[MED].get_state(), 'child')
ipaddrs = self.nodes[ROUTER1].get_addrs()
for ipaddr in ipaddrs:
if ipaddr[0:4] != 'fe80':
break
self.nodes[LEADER1].announce_begin(0x1000, 1, 1000, ipaddr)
self.simulator.go(30)
self.assertEqual(self.nodes[LEADER2].get_state(), 'router')
self.assertEqual(self.nodes[MED].get_state(), 'child')
self.collect_rlocs()
ipaddrs = self.nodes[MED].get_addrs()
for ipaddr in ipaddrs:
if ipaddr[0:4] != 'fe80':
self.assertTrue(self.nodes[LEADER1].ping(ipaddr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER_1 = pv.vars['LEADER_1']
ROUTER_1 = pv.vars['ROUTER_1']
LEADER_2 = pv.vars['LEADER_2']
LEADER_1_RLOC = pv.vars['LEADER_1_RLOC']
MED = pv.vars['MED']
MED_RLOC = pv.vars['MED_RLOC']
# Step 1: Ensure the topology is formed correctly
pkts.filter_wpan_src64(LEADER_1).filter_wpan_dst64(ROUTER_1).filter_mle_cmd(
MLE_CHILD_ID_RESPONSE).must_next().must_verify(lambda p: p.wpan.dst_pan == DATASET1_PANID)
pkts.copy().filter_wpan_src64(LEADER_2).filter_wpan_dst64(MED).filter_mle_cmd(
MLE_CHILD_ID_RESPONSE).must_next().must_verify(lambda p: p.wpan.dst_pan == DATASET2_PANID)
# Step 4: Leader_2 MUST send a MLE Child ID Request on its new channel to Router_1
# LEADER_2 MUST send a MLE Announce Message
# The Destination PAN ID (0xFFFF) in the IEEE 802.15.4 MAC and MUST be secured using Key ID Mode 2.
pkts.filter_wpan_src64(LEADER_2).filter_wpan_dst64(ROUTER_1).filter_mle_cmd(
MLE_CHILD_ID_REQUEST).must_next().must_verify(lambda p: p.wpan.dst_pan == DATASET1_PANID)
pkts.filter_wpan_src64(LEADER_2).filter_ipv6_dst(LINK_LOCAL_ALL_NODES_MULTICAST_ADDRESS).filter_mle_cmd(
MLE_ANNOUNCE).must_next().must_verify(
lambda p: {CHANNEL_TLV, PAN_ID_TLV, ACTIVE_TIMESTAMP_TLV} <= set(p.mle.tlv.type) and p.wpan.dst_pan ==
0xffff and p.wpan.aux_sec.key_id_mode == 0x2 and p.wpan.aux_sec.key_source == 0x00000000ffffffff)
# Step 5: MED MUST send a MLE Child ID Request on its new channel
# MED MUST send a MLE Announce Message
# The Destination PAN ID (0xFFFF) in the IEEE 802.15.4 MAC and MUST be secured using Key ID Mode 2.
pkts.filter_wpan_src64(MED).filter_wpan_dst64(LEADER_2).filter_mle_cmd(
MLE_CHILD_ID_REQUEST).must_next().must_verify(lambda p: p.wpan.dst_pan == DATASET1_PANID)
pkts.filter_wpan_src64(MED).filter_ipv6_dst(LINK_LOCAL_ALL_NODES_MULTICAST_ADDRESS).filter_mle_cmd(
MLE_ANNOUNCE).must_next().must_verify(
lambda p: {CHANNEL_TLV, PAN_ID_TLV, ACTIVE_TIMESTAMP_TLV} <= set(p.mle.tlv.type) and p.wpan.dst_pan ==
0xffff and p.wpan.aux_sec.key_id_mode == 0x2 and p.wpan.aux_sec.key_source == 0x00000000ffffffff)
# Step 6: MED MUST respond with an ICMPv6 Echo Reply
pkts.filter_ping_reply().filter_ipv6_src_dst(MED_RLOC, LEADER_1_RLOC).must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,162 +0,0 @@
#!/usr/bin/env python3
#
# 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 copy
import unittest
import config
import thread_cert
from pktverify.consts import MLE_CHILD_ID_RESPONSE, MGMT_ED_SCAN, MGMT_ED_REPORT, NM_CHANNEL_MASK_TLV, NM_ENERGY_LIST_TLV
from pktverify.packet_verifier import PacketVerifier
COMMISSIONER = 1
LEADER = 2
ROUTER1 = 3
ED = 4
class Cert_9_2_13_EnergyScan_Base(thread_cert.TestCase):
SUPPORT_NCP = False
TOPOLOGY = {
COMMISSIONER: {
'name': 'COMMISSIONER',
'mode': 'rdn',
'allowlist': [LEADER]
},
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [COMMISSIONER, ROUTER1]
},
ROUTER1: {
'name': 'ROUTER',
'mode': 'rdn',
'allowlist': [LEADER, ED]
},
ED: {
'allowlist': [ROUTER1]
},
}
def test(self):
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[COMMISSIONER].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'router')
self.nodes[COMMISSIONER].commissioner_start()
self.simulator.go(5)
self.nodes[ROUTER1].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
self.nodes[ED].start()
self.simulator.go(5)
self.assertEqual(self.nodes[ED].get_state(), 'child')
self.collect_rlocs()
if self.TOPOLOGY[ED]['name'] == 'DUT':
ipaddrs = self.nodes[ED].get_addrs()
else:
ipaddrs = self.nodes[ROUTER1].get_addrs()
for ipaddr in ipaddrs:
if ipaddr[0:4] != 'fe80':
break
self.nodes[COMMISSIONER].energy_scan(0x50000, 0x02, 0x20, 0xc8, ipaddr)
self.simulator.go(3)
self.nodes[COMMISSIONER].energy_scan(0x50000, 0x02, 0x20, 0xc8, 'ff33:0040:fd00:db8:0:0:0:1')
self.simulator.go(3)
self.assertTrue(self.nodes[COMMISSIONER].ping(ipaddr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
DUT = pv.vars['DUT']
DUT_RLOC = pv.vars['DUT_RLOC']
COMMISSIONER_RLOC = pv.vars['COMMISSIONER_RLOC']
_pkts = pkts.filter_wpan_src64(DUT)
# Step 3: The DUT MUST send MGMT_ED_REPORT.ans to the Commissioner and report energy measurements
_pkts.filter_ipv6_dst(COMMISSIONER_RLOC).filter_coap_request(MGMT_ED_REPORT).must_next().must_verify(
lambda p: {NM_CHANNEL_MASK_TLV, NM_ENERGY_LIST_TLV} <= set(p.thread_meshcop.tlv.type) and p.thread_meshcop.
tlv.chan_mask_mask == '0000a000' and len(p.thread_meshcop.tlv.energy_list) == 2)
# Step 5: The DUT MUST send MGMT_ED_REPORT.ans to the Commissioner and report energy measurements
_pkts.filter_ipv6_dst(COMMISSIONER_RLOC).filter_coap_request(MGMT_ED_REPORT).must_next().must_verify(
lambda p: {NM_CHANNEL_MASK_TLV, NM_ENERGY_LIST_TLV} <= set(p.thread_meshcop.tlv.type) and p.thread_meshcop.
tlv.chan_mask_mask == '0000a000' and len(p.thread_meshcop.tlv.energy_list) == 2)
# Step 6: The DUT MUST respond with ICMPv6 Echo Reply
_pkts.filter_ping_reply().filter_ipv6_src_dst(DUT_RLOC, COMMISSIONER_RLOC).must_next()
class Cert_9_2_13_EnergyScan_FED(Cert_9_2_13_EnergyScan_Base):
TOPOLOGY = copy.deepcopy(Cert_9_2_13_EnergyScan_Base.TOPOLOGY)
TOPOLOGY[ROUTER1]['name'] = 'ROUTER'
TOPOLOGY[ED]['name'] = 'DUT'
TOPOLOGY[ED]['router_upgrade_threshold'] = 0
class Cert_9_2_13_EnergyScan_MED(Cert_9_2_13_EnergyScan_Base):
TOPOLOGY = copy.deepcopy(Cert_9_2_13_EnergyScan_Base.TOPOLOGY)
TOPOLOGY[ROUTER1]['name'] = 'ROUTER'
TOPOLOGY[ED]['name'] = 'DUT'
TOPOLOGY[ED]['mode'] = 'rn'
TOPOLOGY[ED]['is_mtd'] = True
class Cert_9_2_13_EnergyScan_ROUTER(Cert_9_2_13_EnergyScan_Base):
TOPOLOGY = copy.deepcopy(Cert_9_2_13_EnergyScan_Base.TOPOLOGY)
TOPOLOGY[ROUTER1]['name'] = 'DUT'
TOPOLOGY[ED]['name'] = 'ED'
TOPOLOGY[ED]['mode'] = 'rn'
TOPOLOGY[ED]['is_mtd'] = True
class Cert_9_2_13_EnergyScan_SED(Cert_9_2_13_EnergyScan_Base):
TOPOLOGY = copy.deepcopy(Cert_9_2_13_EnergyScan_Base.TOPOLOGY)
TOPOLOGY[ROUTER1]['name'] = 'ROUTER'
TOPOLOGY[ED]['name'] = 'DUT'
TOPOLOGY[ED]['mode'] = '-'
TOPOLOGY[ED]['is_mtd'] = True
TOPOLOGY[ED]['timeout'] = config.DEFAULT_CHILD_TIMEOUT
del (Cert_9_2_13_EnergyScan_Base)
if __name__ == '__main__':
unittest.main()
@@ -1,141 +0,0 @@
#!/usr/bin/env python3
#
# 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 unittest
import config
import thread_cert
from pktverify.consts import MLE_CHILD_ID_REQUEST, MGMT_PANID_QUERY, MGMT_PANID_CONFLICT, MGMT_ED_REPORT, NM_COMMISSIONER_SESSION_ID_TLV, NM_CHANNEL_MASK_TLV, NM_PAN_ID_TLV, REALM_LOCAL_ALL_THREAD_NODES_MULTICAST_ADDRESS
from pktverify.packet_verifier import PacketVerifier
COMMISSIONER = 1
LEADER1 = 2
ROUTER1 = 3
LEADER2 = 4
class Cert_9_2_14_PanIdQuery(thread_cert.TestCase):
SUPPORT_NCP = False
TOPOLOGY = {
COMMISSIONER: {
'name': 'COMMISSIONER',
'mode': 'rdn',
'allowlist': [LEADER1]
},
LEADER1: {
'name': 'LEADER_1',
'mode': 'rdn',
'allowlist': [COMMISSIONER, ROUTER1]
},
ROUTER1: {
'name': 'ROUTER',
'mode': 'rdn',
'allowlist': [LEADER1, LEADER2]
},
LEADER2: {
'name': 'LEADER_2',
'mode': 'rdn',
'panid': 0xdead,
'allowlist': [ROUTER1]
},
}
def test(self):
self.nodes[LEADER1].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER1].get_state(), 'leader')
self.nodes[COMMISSIONER].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'router')
self.nodes[COMMISSIONER].commissioner_start()
self.simulator.go(3)
self.nodes[ROUTER1].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
self.nodes[LEADER2].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER2].get_state(), 'leader')
self.collect_rlocs()
ipaddrs = self.nodes[ROUTER1].get_addrs()
for ipaddr in ipaddrs:
if ipaddr[0:4] != 'fe80':
break
self.nodes[COMMISSIONER].panid_query(0xdead, 0xffffffff, ipaddr)
self.nodes[COMMISSIONER].panid_query(0xdead, 0xffffffff, 'ff33:0040:fd00:db8:0:0:0:1')
self.assertTrue(self.nodes[COMMISSIONER].ping(ipaddr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
ROUTER = pv.vars['ROUTER']
COMMISSIONER = pv.vars['COMMISSIONER']
ROUTER_RLOC = pv.vars['ROUTER_RLOC']
COMMISSIONER_RLOC = pv.vars['COMMISSIONER_RLOC']
_rpkts = pkts.filter_wpan_src64(ROUTER)
_cpkts = pkts.filter_wpan_src64(COMMISSIONER)
# Step 1: Ensure the topology is formed correctly
_rpkts.filter_mle_cmd(MLE_CHILD_ID_REQUEST).must_next()
# Step 2: Commissioner MUST send a unicast MGMT_PANID_QUERY.qry unicast to Router_1
_cpkts.filter_ipv6_dst(ROUTER_RLOC).filter_coap_request(MGMT_PANID_QUERY).must_next().must_verify(
lambda p: {NM_COMMISSIONER_SESSION_ID_TLV, NM_CHANNEL_MASK_TLV, NM_PAN_ID_TLV} <= set(p.thread_meshcop.tlv.
type))
# Step 3: Router MUST send MGMT_ED_REPORT.ans to the Commissioner
_rpkts.range(
_cpkts.index).filter_ipv6_dst(COMMISSIONER_RLOC).filter_coap_request(MGMT_PANID_CONFLICT).must_next(
).must_verify(lambda p: {NM_CHANNEL_MASK_TLV, NM_PAN_ID_TLV} <= set(p.thread_meshcop.tlv.type))
# Step 4: Commissioner MUST send a multicast MGMT_PANID_QUERY.qry
_cpkts.filter_ipv6_dst(REALM_LOCAL_ALL_THREAD_NODES_MULTICAST_ADDRESS).filter_coap_request(
MGMT_PANID_QUERY).must_next().must_verify(
lambda p: {NM_COMMISSIONER_SESSION_ID_TLV, NM_CHANNEL_MASK_TLV, NM_PAN_ID_TLV} <= set(p.thread_meshcop.
tlv.type))
# Step 5: Router MUST send MGMT_PANID_CONFLICT.ans to the Commissioner
_rpkts.range(
_cpkts.index).filter_ipv6_dst(COMMISSIONER_RLOC).filter_coap_request(MGMT_PANID_CONFLICT).must_next(
).must_verify(lambda p: {NM_CHANNEL_MASK_TLV, NM_PAN_ID_TLV} <= set(p.thread_meshcop.tlv.type))
# Step 6: Router MUST respond with an ICMPv6 Echo Reply
_rpkts.filter_ipv6_dst(COMMISSIONER_RLOC).filter_ping_reply().must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,198 +0,0 @@
#!/usr/bin/env python3
#
# 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 unittest
import config
import thread_cert
from pktverify.consts import MLE_ADVERTISEMENT, MLE_PARENT_REQUEST, MLE_CHILD_ID_RESPONSE, MLE_CHILD_ID_REQUEST, MGMT_ACTIVE_SET_URI, MGMT_ACTIVE_GET_URI, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, MODE_TLV, TIMEOUT_TLV, VERSION_TLV, TLV_REQUEST_TLV, CHALLENGE_TLV, SCAN_MASK_TLV, ADDRESS_REGISTRATION_TLV
from pktverify.packet_verifier import PacketVerifier
CHANNEL_INIT = 19
PANID_INIT = 0xface
PANID_FINAL = 0xabcd
COMMISSIONER = 1
LEADER = 2
ROUTER1 = 3
ROUTER2 = 4
class Cert_9_2_15_PendingPartition(thread_cert.TestCase):
SUPPORT_NCP = False
TOPOLOGY = {
COMMISSIONER: {
'name': 'COMMISSIONER',
'active_dataset': {
'timestamp': 15,
'panid': PANID_INIT,
'channel': CHANNEL_INIT
},
'mode': 'rdn',
'allowlist': [LEADER]
},
LEADER: {
'name': 'LEADER',
'active_dataset': {
'timestamp': 15,
'panid': PANID_INIT,
'channel': CHANNEL_INIT
},
'mode': 'rdn',
'partition_id': 0xffffffff,
'allowlist': [COMMISSIONER, ROUTER1]
},
ROUTER1: {
'name': 'ROUTER_1',
'active_dataset': {
'timestamp': 15,
'panid': PANID_INIT,
'channel': CHANNEL_INIT
},
'mode': 'rdn',
'allowlist': [LEADER, ROUTER2]
},
ROUTER2: {
'name': 'ROUTER_2',
'active_dataset': {
'timestamp': 15,
'panid': PANID_INIT,
'channel': CHANNEL_INIT
},
'mode': 'rdn',
'allowlist': [ROUTER1]
},
}
def _setUpRouter2(self):
self.nodes[ROUTER2].add_allowlist(self.nodes[ROUTER1].get_addr64())
self.nodes[ROUTER2].enable_allowlist()
self.nodes[ROUTER2].set_router_selection_jitter(1)
def test(self):
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[COMMISSIONER].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'router')
self.nodes[COMMISSIONER].commissioner_start()
self.simulator.go(3)
self.nodes[ROUTER1].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
self.nodes[COMMISSIONER].send_mgmt_pending_set(
pending_timestamp=10,
active_timestamp=70,
delay_timer=600000,
mesh_local='fd00:0db9::',
)
self.simulator.go(5)
self.nodes[ROUTER2].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER2].get_state(), 'router')
self.nodes[ROUTER2].reset()
self._setUpRouter2()
self.simulator.go(100)
self.nodes[COMMISSIONER].send_mgmt_pending_set(
pending_timestamp=20,
active_timestamp=80,
delay_timer=200000,
mesh_local='fd00:0db7::',
panid=PANID_FINAL,
)
self.simulator.go(100)
self.nodes[ROUTER2].start()
self.simulator.go(config.ROUTER_RESET_DELAY)
self.assertEqual(self.nodes[ROUTER2].get_state(), 'router')
self.simulator.go(100)
self.assertEqual(self.nodes[COMMISSIONER].get_panid(), PANID_FINAL)
self.assertEqual(self.nodes[LEADER].get_panid(), PANID_FINAL)
self.assertEqual(self.nodes[ROUTER1].get_panid(), PANID_FINAL)
self.assertEqual(self.nodes[ROUTER2].get_panid(), PANID_FINAL)
ipaddrs = self.nodes[ROUTER2].get_addrs()
for ipaddr in ipaddrs:
if ipaddr[0:4] != 'fe80':
break
self.assertTrue(self.nodes[LEADER].ping(ipaddr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
COMMISSIONER = pv.vars['COMMISSIONER']
ROUTER_1 = pv.vars['ROUTER_1']
ROUTER_2 = pv.vars['ROUTER_2']
_router2_pkts = pkts.filter_wpan_src64(ROUTER_2)
# Step 1: Ensure the topology is formed correctly
# Verify Commissioner, Leader and Router_1 are sending MLE advertisements
pkts.copy().filter_wpan_src64(LEADER).filter_mle_cmd(MLE_ADVERTISEMENT).must_next()
pkts.filter_wpan_dst64(COMMISSIONER).filter_mle_cmd(MLE_CHILD_ID_RESPONSE).must_next()
pkts.copy().filter_wpan_src64(COMMISSIONER).filter_mle_cmd(MLE_ADVERTISEMENT).must_next()
pkts.filter_wpan_dst64(ROUTER_1).filter_mle_cmd(MLE_CHILD_ID_RESPONSE).must_next()
pkts.copy().filter_wpan_src64(ROUTER_1).filter_mle_cmd(MLE_ADVERTISEMENT).must_next()
# Step 5: Router_2 begins attach process by sending a multicast MLE Parent Request
# The first MLE Parent Request sent MUST NOT be sent to all routers and REEDS
_router2_pkts.range(pkts.index).filter_mle_cmd(MLE_PARENT_REQUEST).must_next().must_verify(
lambda p: {MODE_TLV, CHALLENGE_TLV, SCAN_MASK_TLV, VERSION_TLV} <= set(
p.mle.tlv.type) and p.mle.tlv.scan_mask.r == 1 and p.mle.tlv.scan_mask.e == 0)
# Step 7: Router_2 MUST send a MLE Child ID Request to Router_1
_router2_pkts.filter_mle_cmd(MLE_CHILD_ID_REQUEST).must_next().must_verify(lambda p: {
RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, MODE_TLV, TIMEOUT_TLV, VERSION_TLV, TLV_REQUEST_TLV
} <= set(p.mle.tlv.type) and ADDRESS_REGISTRATION_TLV not in p.mle.tlv.type)
# Step 14: Router_2 begins attach process by sending a multicast MLE Parent Request
# The first MLE Parent Request sent MUST NOT be sent to all routers and REEDS
_router2_pkts.filter_mle_cmd(MLE_PARENT_REQUEST).must_next().must_verify(
lambda p: {MODE_TLV, CHALLENGE_TLV, SCAN_MASK_TLV, VERSION_TLV} <= set(
p.mle.tlv.type) and p.mle.tlv.scan_mask.r == 1 and p.mle.tlv.scan_mask.e == 0)
# Step 16: Router_2 MUST send a MLE Child ID Request to Router_1
_router2_pkts.filter_mle_cmd(MLE_CHILD_ID_REQUEST).must_next().must_verify(lambda p: {
RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, MODE_TLV, TIMEOUT_TLV, VERSION_TLV, TLV_REQUEST_TLV
} <= set(p.mle.tlv.type) and ADDRESS_REGISTRATION_TLV not in p.mle.tlv.type)
if __name__ == '__main__':
unittest.main()
@@ -1,208 +0,0 @@
#!/usr/bin/env python3
#
# 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 unittest
import config
import thread_cert
from pktverify.consts import MLE_ADVERTISEMENT, MLE_PARENT_REQUEST, MLE_CHILD_ID_RESPONSE, MLE_CHILD_ID_REQUEST, MGMT_ACTIVE_SET_URI, MGMT_ACTIVE_GET_URI, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, MODE_TLV, TIMEOUT_TLV, VERSION_TLV, TLV_REQUEST_TLV, CHALLENGE_TLV, SCAN_MASK_TLV, ADDRESS_REGISTRATION_TLV
from pktverify.packet_verifier import PacketVerifier
CHANNEL_INIT = 19
PANID_INIT = 0xface
NETWORK_NAME_FINAL = 'threadCert'
PANID_FINAL = 0xabcd
COMMISSIONER = 1
LEADER = 2
ROUTER1 = 3
ROUTER2 = 4
class Cert_9_2_16_ActivePendingPartition(thread_cert.TestCase):
SUPPORT_NCP = False
TOPOLOGY = {
COMMISSIONER: {
'name': 'COMMISSIONER',
'active_dataset': {
'timestamp': 1,
'panid': PANID_INIT,
'channel': CHANNEL_INIT
},
'mode': 'rdn',
'allowlist': [LEADER]
},
LEADER: {
'name': 'LEADER',
'active_dataset': {
'timestamp': 1,
'panid': PANID_INIT,
'channel': CHANNEL_INIT
},
'mode': 'rdn',
'partition_id': 0xffffffff,
'allowlist': [COMMISSIONER, ROUTER1]
},
ROUTER1: {
'name': 'ROUTER_1',
'active_dataset': {
'timestamp': 1,
'panid': PANID_INIT,
'channel': CHANNEL_INIT
},
'mode': 'rdn',
'allowlist': [LEADER, ROUTER2]
},
ROUTER2: {
'name': 'ROUTER_2',
'active_dataset': {
'timestamp': 1,
'panid': PANID_INIT,
'channel': CHANNEL_INIT
},
'mode': 'rdn',
'allowlist': [ROUTER1]
},
}
def _setUpRouter2(self):
self.nodes[ROUTER2].add_allowlist(self.nodes[ROUTER1].get_addr64())
self.nodes[ROUTER2].enable_allowlist()
self.nodes[ROUTER2].set_router_selection_jitter(1)
def test(self):
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[COMMISSIONER].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'router')
self.nodes[COMMISSIONER].commissioner_start()
self.simulator.go(3)
self.nodes[ROUTER1].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
self.nodes[COMMISSIONER].send_mgmt_pending_set(
pending_timestamp=10,
active_timestamp=10,
delay_timer=600000,
mesh_local='fd00:0db9::',
)
self.simulator.go(5)
self.nodes[ROUTER2].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER2].get_state(), 'router')
self.nodes[ROUTER2].reset()
self._setUpRouter2()
self.simulator.go(100)
self.nodes[COMMISSIONER].send_mgmt_pending_set(
pending_timestamp=20,
active_timestamp=20,
delay_timer=200000,
mesh_local='fd00:0db7::',
panid=PANID_FINAL,
)
self.simulator.go(5)
self.nodes[COMMISSIONER].send_mgmt_active_set(active_timestamp=15, network_name='threadCert')
self.simulator.go(100)
self.nodes[ROUTER2].start()
self.simulator.go(config.ROUTER_RESET_DELAY)
self.assertEqual(self.nodes[ROUTER2].get_state(), 'router')
self.assertEqual(self.nodes[COMMISSIONER].get_network_name(), NETWORK_NAME_FINAL)
self.assertEqual(self.nodes[LEADER].get_network_name(), NETWORK_NAME_FINAL)
self.assertEqual(self.nodes[ROUTER1].get_network_name(), NETWORK_NAME_FINAL)
self.assertEqual(self.nodes[ROUTER2].get_network_name(), NETWORK_NAME_FINAL)
self.simulator.go(100)
self.assertEqual(self.nodes[COMMISSIONER].get_panid(), PANID_FINAL)
self.assertEqual(self.nodes[LEADER].get_panid(), PANID_FINAL)
self.assertEqual(self.nodes[ROUTER1].get_panid(), PANID_FINAL)
self.assertEqual(self.nodes[ROUTER2].get_panid(), PANID_FINAL)
ipaddrs = self.nodes[ROUTER2].get_addrs()
for ipaddr in ipaddrs:
if ipaddr[0:4] != 'fe80':
break
self.assertTrue(self.nodes[LEADER].ping(ipaddr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
COMMISSIONER = pv.vars['COMMISSIONER']
ROUTER_1 = pv.vars['ROUTER_1']
ROUTER_2 = pv.vars['ROUTER_2']
_router2_pkts = pkts.filter_wpan_src64(ROUTER_2)
# Step 1: Ensure the topology is formed correctly
# Verify Commissioner, Leader and Router_1 are sending MLE advertisements
pkts.copy().filter_wpan_src64(LEADER).filter_mle_cmd(MLE_ADVERTISEMENT).must_next()
pkts.filter_wpan_dst64(COMMISSIONER).filter_mle_cmd(MLE_CHILD_ID_RESPONSE).must_next()
pkts.copy().filter_wpan_src64(COMMISSIONER).filter_mle_cmd(MLE_ADVERTISEMENT).must_next()
pkts.filter_wpan_dst64(ROUTER_1).filter_mle_cmd(MLE_CHILD_ID_RESPONSE).must_next()
pkts.copy().filter_wpan_src64(ROUTER_1).filter_mle_cmd(MLE_ADVERTISEMENT).must_next()
# Step 5: Router_2 begins attach process by sending a multicast MLE Parent Request
# The first MLE Parent Request sent MUST NOT be sent to all routers and REEDS
_router2_pkts.range(pkts.index).filter_mle_cmd(MLE_PARENT_REQUEST).must_next().must_verify(
lambda p: {MODE_TLV, CHALLENGE_TLV, SCAN_MASK_TLV, VERSION_TLV} <= set(
p.mle.tlv.type) and p.mle.tlv.scan_mask.r == 1 and p.mle.tlv.scan_mask.e == 0)
# Step 7: Router_2 MUST send a MLE Child ID Request to Router_1
_router2_pkts.filter_mle_cmd(MLE_CHILD_ID_REQUEST).must_next().must_verify(lambda p: {
RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, MODE_TLV, TIMEOUT_TLV, VERSION_TLV, TLV_REQUEST_TLV
} <= set(p.mle.tlv.type) and ADDRESS_REGISTRATION_TLV not in p.mle.tlv.type)
# Step 14: Router_2 begins attach process by sending a multicast MLE Parent Request
# The first MLE Parent Request sent MUST NOT be sent to all routers and REEDS
_router2_pkts.filter_mle_cmd(MLE_PARENT_REQUEST).must_next().must_verify(
lambda p: {MODE_TLV, CHALLENGE_TLV, SCAN_MASK_TLV, VERSION_TLV} <= set(
p.mle.tlv.type) and p.mle.tlv.scan_mask.r == 1 and p.mle.tlv.scan_mask.e == 0)
# Step 16: Router_2 MUST send a MLE Child ID Request to Router_1
_router2_pkts.filter_mle_cmd(MLE_CHILD_ID_REQUEST).must_next().must_verify(lambda p: {
RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, MODE_TLV, TIMEOUT_TLV, VERSION_TLV, TLV_REQUEST_TLV
} <= set(p.mle.tlv.type) and ADDRESS_REGISTRATION_TLV not in p.mle.tlv.type)
if __name__ == '__main__':
unittest.main()
@@ -1,147 +0,0 @@
#!/usr/bin/env python3
#
# 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 unittest
import config
import thread_cert
from pktverify.consts import MLE_ADVERTISEMENT, MLE_PARENT_REQUEST, MLE_CHILD_ID_RESPONSE, MLE_ANNOUNCE, CHANNEL_TLV, PAN_ID_TLV, ACTIVE_TIMESTAMP_TLV
from pktverify.packet_verifier import PacketVerifier
CHANNEL1 = 11
CHANNEL2 = 18
CHANNEL_MASK = 1 << 18
PANID_INIT = 0xface
LEADER1 = 1
LEADER2 = 2
ED1 = 3
class Cert_9_2_17_Orphan(thread_cert.TestCase):
SUPPORT_NCP = False
TOPOLOGY = {
LEADER1: {
'name': 'LEADER_1',
'active_dataset': {
'timestamp': 10,
'panid': PANID_INIT,
'channel': CHANNEL1,
'channel_mask': CHANNEL_MASK
},
'mode': 'rdn',
'allowlist': [ED1]
},
LEADER2: {
'name': 'LEADER_2',
'active_dataset': {
'timestamp': 20,
'panid': PANID_INIT,
'channel': CHANNEL2,
'channel_mask': CHANNEL_MASK
},
'mode': 'rdn',
},
ED1: {
'name': 'ED',
'channel': CHANNEL1,
'is_mtd': True,
'mode': 'rn',
'panid': PANID_INIT,
'timeout': config.DEFAULT_CHILD_TIMEOUT,
'allowlist': [LEADER1]
},
}
def test(self):
self.nodes[LEADER1].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER1].get_state(), 'leader')
self.nodes[LEADER2].start()
self.nodes[LEADER2].set_state('leader')
self.assertEqual(self.nodes[LEADER2].get_state(), 'leader')
self.nodes[ED1].start()
self.simulator.go(5)
self.assertEqual(self.nodes[ED1].get_state(), 'child')
self.nodes[LEADER1].stop()
self.nodes[LEADER2].add_allowlist(self.nodes[ED1].get_addr64())
self.nodes[ED1].add_allowlist(self.nodes[LEADER2].get_addr64())
self.simulator.go(20)
self.assertEqual(self.nodes[ED1].get_state(), 'child')
self.assertEqual(self.nodes[ED1].get_channel(), CHANNEL2)
self.collect_ipaddrs()
ipaddrs = self.nodes[ED1].get_addrs()
for ipaddr in ipaddrs:
self.assertTrue(self.nodes[LEADER2].ping(ipaddr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER_1 = pv.vars['LEADER_1']
LEADER_2 = pv.vars['LEADER_2']
ED = pv.vars['ED']
# Step 1: Ensure the topology is formed correctly
# Verify that Leader_1 & Leader_2 are sending MLE Advertisements on separate channels.
pkts.copy().filter_wpan_src64(LEADER_1).filter_mle_cmd(MLE_ADVERTISEMENT).must_next()
pkts.copy().filter_wpan_src64(LEADER_2).filter_mle_cmd(MLE_ADVERTISEMENT).must_next()
pkts.filter_wpan_src64(LEADER_1).filter_mle_cmd(MLE_CHILD_ID_RESPONSE).must_next().must_verify(
lambda p: p.wpan.dst64 == ED and p.thread_meshcop.tlv.channel == [CHANNEL1])
# Step 4: powers-down Leader_1 and enables connectivity between the ED and Leader_2
# ED MUST send a MLE Parent Request
_epkts = pkts.filter_wpan_src64(ED)
_epkts.filter_mle_cmd(MLE_PARENT_REQUEST).must_next()
# Step 6: ED MUST send a MLE Announce Message
# The Destination PAN ID (0xFFFF) in the IEEE 802.15.4 MAC and MUST be secured using Key ID Mode 2.
_epkts.filter_mle_cmd(MLE_ANNOUNCE).must_next().must_verify(
lambda p: {CHANNEL_TLV, PAN_ID_TLV, ACTIVE_TIMESTAMP_TLV} <= set(
p.mle.tlv.type) and p.wpan.dst_pan == 0xffff and p.wpan.aux_sec.key_id_mode == 0x2)
# Step 8: ED MUST attempt to attach on the Secondary channel,
# with the new PAN ID it received in the MLE Announce message from Leader_2
pkts.range(_epkts.index).filter_mle_cmd(MLE_ANNOUNCE).filter_wpan_src64(LEADER_2).filter_wpan_dst64(
ED).must_next().must_verify(lambda p: p.mle.tlv.channel == CHANNEL2)
_epkts.range(pkts.index).filter_mle_cmd(MLE_PARENT_REQUEST).must_next()
# Step 9: ED MUST respond with an ICMPv6 Echo Reply
_epkts.filter('ipv6.dst == {LEADER_2_MLEID} and ipv6.src == {ED_MLEID}',
**pv.vars).filter_ping_reply().must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,258 +0,0 @@
#!/usr/bin/env python3
#
# 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 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_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'
CHANNEL_INIT = 19
PANID_INIT = 0xface
COMMISSIONER = 1
LEADER = 2
ROUTER1 = 3
ED1 = 4
SED1 = 5
MTDS = [ED1, SED1]
class Cert_9_2_18_RollBackActiveTimestamp(thread_cert.TestCase):
SUPPORT_NCP = False
TOPOLOGY = {
COMMISSIONER: {
'name': 'COMMISSIONER',
'active_dataset': {
'timestamp': 1,
'panid': PANID_INIT,
'channel': CHANNEL_INIT,
'network_key': KEY1
},
'mode': 'rdn',
'allowlist': [LEADER]
},
LEADER: {
'name': 'LEADER',
'active_dataset': {
'timestamp': 1,
'panid': PANID_INIT,
'channel': CHANNEL_INIT,
'network_key': KEY1
},
'mode': 'rdn',
'partition_id': 0xffffffff,
'allowlist': [COMMISSIONER, ROUTER1]
},
ROUTER1: {
'name': 'ROUTER_1',
'active_dataset': {
'timestamp': 1,
'panid': PANID_INIT,
'channel': CHANNEL_INIT,
'network_key': KEY1
},
'mode': 'rdn',
'allowlist': [LEADER, ED1, SED1]
},
ED1: {
'name': 'ED',
'channel': CHANNEL_INIT,
'is_mtd': True,
'network_key': KEY1,
'mode': 'rn',
'panid': PANID_INIT,
'allowlist': [ROUTER1]
},
SED1: {
'name': 'SED',
'channel': CHANNEL_INIT,
'is_mtd': True,
'network_key': KEY1,
'mode': '-',
'panid': PANID_INIT,
'timeout': config.DEFAULT_CHILD_TIMEOUT,
'allowlist': [ROUTER1]
},
}
def test(self):
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[COMMISSIONER].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'router')
self.nodes[COMMISSIONER].commissioner_start()
self.simulator.go(3)
self.nodes[ROUTER1].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
self.nodes[ED1].start()
self.simulator.go(5)
self.assertEqual(self.nodes[ED1].get_state(), 'child')
self.nodes[SED1].start()
self.simulator.go(5)
self.assertEqual(self.nodes[SED1].get_state(), 'child')
self.nodes[COMMISSIONER].send_mgmt_active_set(active_timestamp=20000, network_name='GRL')
self.simulator.go(5)
self.nodes[COMMISSIONER].send_mgmt_pending_set(
pending_timestamp=20,
active_timestamp=20,
delay_timer=20,
network_name='Shouldnotbe',
)
self.simulator.go(30)
self.nodes[COMMISSIONER].send_mgmt_pending_set(
pending_timestamp=20,
active_timestamp=20,
delay_timer=300,
network_name='MyHouse',
network_key=KEY2,
)
self.simulator.go(310)
self.assertEqual(self.nodes[COMMISSIONER].get_networkkey(), KEY2)
self.assertEqual(self.nodes[LEADER].get_networkkey(), KEY2)
self.assertEqual(self.nodes[ROUTER1].get_networkkey(), KEY2)
self.assertEqual(self.nodes[ED1].get_networkkey(), KEY2)
self.assertEqual(self.nodes[SED1].get_networkkey(), KEY2)
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_KEY_TLV
} <= set(p.thread_meshcop.tlv.type) and p.thread_nwd.tlv.stable == [0])
# Copy a pv.pkts here to filter SED related packets for potential sequence packets disorder
_pkts_sed = pkts.copy()
# 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_sed.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_sed.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_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__':
unittest.main()
@@ -1,293 +0,0 @@
#!/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 config
import mesh_cop
import thread_cert
from pktverify.consts import MGMT_PENDING_GET_URI, MGMT_PENDING_SET_URI, NM_CHANNEL_TLV, NM_PAN_ID_TLV, NM_NETWORK_NAME_TLV, NM_NETWORK_MESH_LOCAL_PREFIX_TLV, NM_PSKC_TLV, NM_ACTIVE_TIMESTAMP_TLV, NM_CHANNEL_MASK_TLV, NM_EXTENDED_PAN_ID_TLV, NM_NETWORK_KEY_TLV, NM_SECURITY_POLICY_TLV, NM_PENDING_TIMESTAMP_TLV, NM_DELAY_TIMER_TLV, LEADER_ALOC
from pktverify.packet_verifier import PacketVerifier
from pktverify.null_field import nullField
COMMISSIONER = 1
LEADER = 2
# Test Purpose and Description:
# -----------------------------
# The purpose of this test case is to verify Leader's and active Commissioner's behavior via
# MGMT_PENDING_GET request and response
#
# Test Topology:
# -------------
# Commissioner
# |
# Leader
#
# DUT Types:
# ----------
# Leader
# Commissioner
class Cert_9_2_19_PendingDatasetGet(thread_cert.TestCase):
SUPPORT_NCP = False
TOPOLOGY = {
COMMISSIONER: {
'name': 'COMMISSIONER',
'mode': 'rdn',
'allowlist': [LEADER]
},
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [COMMISSIONER]
},
}
def test(self):
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[COMMISSIONER].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'router')
self.simulator.get_messages_sent_by(LEADER)
self.collect_rlocs()
self.collect_rloc16s()
leader_rloc = self.nodes[LEADER].get_rloc()
self.nodes[COMMISSIONER].commissioner_start()
self.simulator.go(3)
self.nodes[COMMISSIONER].send_mgmt_pending_get()
self.simulator.go(2)
self.nodes[COMMISSIONER].send_mgmt_pending_set(
active_timestamp=60,
delay_timer=60000,
panid=0xAFCE,
pending_timestamp=30,
)
self.simulator.go(2)
self.nodes[COMMISSIONER].send_mgmt_pending_get()
self.simulator.go(2)
self.nodes[COMMISSIONER].send_mgmt_pending_get(leader_rloc, [mesh_cop.TlvType.PAN_ID])
self.simulator.go(92)
self.nodes[COMMISSIONER].send_mgmt_pending_get()
self.simulator.go(2)
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
LEADER_RLOC = pv.vars['LEADER_RLOC']
COMMISSIONER = pv.vars['COMMISSIONER']
COMMISSIONER_RLOC = pv.vars['COMMISSIONER_RLOC']
# Step 1: Ensure topology is formed correctly
pv.verify_attached('COMMISSIONER', 'LEADER')
# Step 2: Commissioner sends a MGMT_PENDING_GET.req to Leader Anycast
# or Routing Locator:
# CoAP Request URI
# CON POST coap://<L>:MM/c/pg
# CoAP Payload
# <empty> - get all Active Operational Dataset parameters
_mgmt_get_pkt = pkts.filter_wpan_src64(COMMISSIONER).\
filter_ipv6_2dsts(LEADER_ALOC, LEADER_RLOC).\
filter_coap_request(MGMT_PENDING_GET_URI).\
filter(lambda p: p.coap.tlv.type is nullField).\
must_next()
# Step 3: Leader sends a MGMT_PENDING_GET.rsp to Commissioner with
# the following format:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# <empty> - (no Pending Operational Dataset)
pkts.filter_ipv6_src_dst(_mgmt_get_pkt.ipv6.dst, COMMISSIONER_RLOC).\
filter_coap_ack(MGMT_PENDING_GET_URI).\
filter(lambda p: p.coap.tlv.type is nullField).\
must_next()
# Step 4: Commissioner sends a MGMT_PENDING_SET.req to Leader Anycast
# or Routing Locator:
# CoAP Request URI
# CON POST coap://<L>:MM/c/ps
# CoAP Payload
# Active Timestamp TLV: 60s
# Commissioner Session ID TLV (valid)
# Delay Timer TLV: 1 minute
# Pending Timestamp TLV: 30s
# PAN ID TLV: 0xAFCE (new value)
_mgmt_pending_set_pkt = pkts.filter_wpan_src64(COMMISSIONER).\
filter_ipv6_2dsts(LEADER_ALOC, LEADER_RLOC).\
filter_coap_request(MGMT_PENDING_SET_URI).\
filter(lambda p: {
NM_ACTIVE_TIMESTAMP_TLV,
NM_PENDING_TIMESTAMP_TLV,
NM_DELAY_TIMER_TLV,
NM_PAN_ID_TLV
} <= set(p.thread_meshcop.tlv.type) and\
p.thread_meshcop.tlv.active_tstamp == 60 and\
p.thread_meshcop.tlv.pan_id == [0xafce] and\
p.thread_meshcop.tlv.delay_timer == 60000
).\
must_next()
# Step 5: Leader sends a MGMT_PENDING_SET.rsp to Commissioner with
# the following format:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# State TLV (value = Accept (01))
pkts.filter_ipv6_src_dst(_mgmt_pending_set_pkt.ipv6.dst, COMMISSIONER_RLOC).\
filter_coap_ack(MGMT_PENDING_SET_URI).\
filter(lambda p:
p.thread_meshcop.tlv.state == 1
).\
must_next()
# Step 6: Commissioner sends a MGMT_PENDING_GET.req to Leader Anycast
# or Routing Locator:
# CoAP Request URI
# CON POST coap://<L>:MM/c/pg
# CoAP Payload
# <empty> - get all Active Operational Dataset parameters
_mgmt_pending_get_pkt = pkts.filter_wpan_src64(COMMISSIONER).\
filter_ipv6_2dsts(LEADER_ALOC, LEADER_RLOC).\
filter_coap_request(MGMT_PENDING_GET_URI).\
filter(lambda p: p.coap.tlv.type is nullField).\
must_next()
# Step 7: Leader sends a MGMT_PENDING_GET.rsp to Commissioner with
# the following format:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# (entire Active Operational Dataset)
# Active Timestamp TLV
# Channel TLV
# Channel Mask TLV
# Delay Timer TLV
# Extended PAN ID TLV
# Network Mesh-Local Prefix TLV
# Network Key TLV
# Network Name TLV
# PAN ID TLV
# Pending Timestamp TLV
# PSKc TLV
# Security Policy TLV
pkts.filter_ipv6_src_dst(_mgmt_pending_get_pkt.ipv6.dst, COMMISSIONER_RLOC).\
filter_coap_ack(MGMT_PENDING_GET_URI).\
filter(lambda p: {
NM_ACTIVE_TIMESTAMP_TLV,
NM_CHANNEL_TLV,
NM_CHANNEL_MASK_TLV,
NM_DELAY_TIMER_TLV,
NM_EXTENDED_PAN_ID_TLV,
NM_NETWORK_MESH_LOCAL_PREFIX_TLV,
NM_NETWORK_KEY_TLV,
NM_NETWORK_NAME_TLV,
NM_PAN_ID_TLV,
NM_PENDING_TIMESTAMP_TLV,
NM_PSKC_TLV,
NM_SECURITY_POLICY_TLV
} <= set(p.thread_meshcop.tlv.type)
).\
must_next()
# Step 8: Commissioner sends a MGMT_PENDING_GET.req to Leader Anycast
# or Routing Locator:
# CoAP Request URI
# CON POST coap://<L>:MM/c/pg
# CoAP Payload
# PAN ID TLV
_mgmt_pending_get_pkt = pkts.filter_wpan_src64(COMMISSIONER).\
filter_ipv6_2dsts(LEADER_ALOC, LEADER_RLOC).\
filter_coap_request(MGMT_PENDING_GET_URI).\
filter(lambda p: {
NM_PAN_ID_TLV
} <= set(p.thread_meshcop.tlv.type)
).\
must_next()
# Step 9: Leader sends a MGMT_PENDING_GET.rsp to Commissioner with
# the following format:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# PAN ID TLV
# Delay Timer TLV
pkts.filter_ipv6_src_dst(_mgmt_pending_get_pkt.ipv6.dst, COMMISSIONER_RLOC).\
filter_coap_ack(MGMT_PENDING_GET_URI).\
filter(lambda p: {
NM_DELAY_TIMER_TLV,
NM_PAN_ID_TLV
} <= set(p.coap.tlv.type) and\
p.thread_meshcop.tlv.pan_id == [0xafce] and\
p.thread_meshcop.tlv.delay_timer < 60000
).\
must_next()
# Step 11: Commissioner sends a MGMT_PENDING_GET.req to Leader Anycast
# or Routing Locator:
# CoAP Request URI
# CON POST coap://<L>:MM/c/pg
# CoAP Payload
# <empty> - get all Active Operational Dataset parameters
_mgmt_pending_get_pkt = pkts.filter_wpan_src64(COMMISSIONER).\
filter_ipv6_2dsts(LEADER_ALOC, LEADER_RLOC).\
filter_coap_request(MGMT_PENDING_GET_URI).\
filter(lambda p: p.coap.tlv.type is nullField).\
must_next()
# Step 12: Leader sends a MGMT_PENDING_GET.rsp to Commissioner with
# the following format:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# <empty> - (no Pending Operational Dataset)
pkts.filter_ipv6_src_dst(_mgmt_pending_get_pkt.ipv6.dst, COMMISSIONER_RLOC).\
filter_coap_ack(MGMT_PENDING_GET_URI).\
filter(lambda p: p.thread_meshcop.tlv.type is nullField).\
must_next()
if __name__ == '__main__':
unittest.main()