[tests] remove cert scripts migrated to Nexus (#12516)

This commit removes several Thread certification test scripts from
tests/scripts/thread-cert/ that have been migrated to the Nexus
testing framework. These tests are now implemented as Nexus tests
under tests/nexus/.

The following test scripts were removed:

- Leader Reboot:
  - Cert_5_5_01_LeaderReboot.py
  - Cert_5_5_02_LeaderReboot.py
  - Cert_5_5_03_SplitMergeChildren.py
  - Cert_5_5_04_SplitMergeRouters.py
  - Cert_5_5_05_SplitMergeREED.py
  - Cert_5_5_07_SplitMergeThreeWay.py

- Network Data:
  - Cert_5_6_01_NetworkDataRegisterBeforeAttachLeader.py
  - Cert_5_6_02_NetworkDataRegisterBeforeAttachRouter.py
  - Cert_5_6_03_NetworkDataRegisterAfterAttachLeader.py
  - Cert_5_6_04_NetworkDataRegisterAfterAttachRouter.py
  - Cert_5_6_05_NetworkDataRegisterAfterAttachRouter.py
  - Cert_5_6_06_NetworkDataExpiration.py
  - Cert_5_6_07_NetworkDataRequestREED.py
  - Cert_5_6_09_NetworkDataForwarding.py

- COAP Diag:
  - Cert_5_7_01_CoapDiagCommands.py
  - Cert_5_7_02_CoapDiagCommands.py
  - Cert_5_7_03_CoapDiagCommands.py

- Router/REED Attach:
  - Cert_6_1_01_RouterAttach.py
  - Cert_6_1_02_REEDAttach.py
  - Cert_6_1_03_RouterAttachConnectivity.py
  - Cert_6_1_04_REEDAttachConnectivity.py
  - Cert_6_1_05_REEDAttachConnectivity.py
  - Cert_6_1_06_REEDAttachLinkQuality.py
  - Cert_6_1_07_RouterAttachLinkQuality.py

- Partition and Reattach:
  - Cert_6_2_01_NewPartition.py
  - Cert_6_2_02_NewPartition.py
  - Cert_6_3_01_OrphanReattach.py
  - Cert_6_3_02_NetworkDataUpdate.py
  - Cert_6_4_01_LinkLocal.py
  - Cert_6_4_02_RealmLocal.py
  - Cert_6_5_01_ChildResetReattach.py
  - Cert_6_5_02_ChildResetReattach.py
  - Cert_6_5_03_ChildResetSynchronize.py

- Key Increment:
  - Cert_6_6_01_KeyIncrement.py
  - Cert_6_6_02_KeyIncrementRollOver.py

- Border Router:
  - Cert_7_1_01_BorderRouterAsLeader.py
  - Cert_7_1_02_BorderRouterAsRouter.py
  - Cert_7_1_03_BorderRouterAsLeader.py
  - Cert_7_1_04_BorderRouterAsRouter.py
  - Cert_7_1_05_BorderRouterAsRouter.py
  - Cert_7_1_06_BorderRouterAsLeader.py
  - Cert_7_1_07_BorderRouterAsLeader.py
  - Cert_7_1_08_BorderRouterAsFED.py
This commit is contained in:
Jonathan Hui
2026-02-23 14:05:42 -06:00
committed by GitHub
parent c28002707d
commit 088154d12b
43 changed files with 0 additions and 9424 deletions
@@ -1,216 +0,0 @@
#!/usr/bin/env python3
#
# Copyright (c) 2018, 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 command
import config
import mle
import thread_cert
from pktverify.consts import MLE_PARENT_REQUEST, MLE_LINK_REQUEST, MLE_LINK_ACCEPT, MLE_LINK_ACCEPT_AND_REQUEST, SOURCE_ADDRESS_TLV, CHALLENGE_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, ROUTE64_TLV, ADDRESS16_TLV, LEADER_DATA_TLV, TLV_REQUEST_TLV, VERSION_TLV
from pktverify.packet_verifier import PacketVerifier
from pktverify.null_field import nullField
DUT_LEADER = 1
DUT_ROUTER1 = 2
# Test Purpose and Description:
# -----------------------------
# The purpose of this test case is to show that when the Leader is rebooted for a time period shorter than the leader timeout, it does not trigger network partitioning and remains the leader when it reattaches to the network.
#
# Test Topology:
# -------------
# Leader
# |
# Router
#
# DUT Types:
# ----------
# Leader
# Router
class Cert_5_5_1_LeaderReboot(thread_cert.TestCase):
#USE_MESSAGE_FACTORY = False
TOPOLOGY = {
DUT_LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [DUT_ROUTER1]
},
DUT_ROUTER1: {
'name': 'ROUTER',
'mode': 'rdn',
'allowlist': [DUT_LEADER]
},
}
def _setUpLeader(self):
self.nodes[DUT_LEADER].add_allowlist(self.nodes[DUT_ROUTER1].get_addr64())
self.nodes[DUT_LEADER].enable_allowlist()
def test(self):
self.nodes[DUT_LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[DUT_LEADER].get_state(), 'leader')
self.nodes[DUT_ROUTER1].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[DUT_ROUTER1].get_state(), 'router')
leader_rloc = self.nodes[DUT_LEADER].get_ip6_address(config.ADDRESS_TYPE.RLOC)
leader_rloc16 = self.nodes[DUT_LEADER].get_addr16()
self.nodes[DUT_LEADER].reset()
self.assertFalse(self.nodes[DUT_ROUTER1].ping(leader_rloc))
self._setUpLeader()
self.simulator.go(config.MAX_ADVERTISEMENT_INTERVAL)
self.nodes[DUT_LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[DUT_LEADER].get_state(), 'leader')
self.assertEqual(self.nodes[DUT_LEADER].get_addr16(), leader_rloc16)
router1_link_local_address = self.nodes[DUT_ROUTER1].get_ip6_address(config.ADDRESS_TYPE.LINK_LOCAL)
self.assertTrue(self.nodes[DUT_LEADER].ping(router1_link_local_address))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
ROUTER = pv.vars['ROUTER']
# Step 1: Verify topology is formed correctly.
pv.verify_attached('ROUTER', 'LEADER')
# Step 2: The DUT MUST send properly formatted MLE Advertisements with
# an IP Hop Limit of 255 to the Link-Local All Nodes multicast
# address (FF02::1).
# The following TLVs MUST be present in the MLE Advertisements:
# - Leader Data TLV
# - Route64 TLV
# - Source Address TLV
with pkts.save_index():
pkts.filter_wpan_src64(LEADER).\
filter_mle_advertisement('Leader').\
must_next()
pkts.filter_wpan_src64(ROUTER).\
filter_mle_advertisement('Router').\
must_next()
pkts.filter_ping_request().\
filter_wpan_src64(ROUTER).\
must_next()
lstart = pkts.index
# Step 4: The Leader MUST send a multicast Link Request
# The following TLVs MUST be present in the Link Request:
# - Challenge TLV
# - Version TLV
# - TLV Request TLV: Address16 TLV, Route64 TLV
pkts.filter_wpan_src64(LEADER).\
filter_LLARMA().\
filter_mle_cmd(MLE_LINK_REQUEST).\
filter(lambda p: {
CHALLENGE_TLV,
VERSION_TLV,
TLV_REQUEST_TLV,
ADDRESS16_TLV,
ROUTE64_TLV
} <= set(p.mle.tlv.type) and\
p.mle.tlv.addr16 is nullField and\
p.mle.tlv.route64.id_mask is nullField
).\
must_next()
lend = pkts.index
# Step 3: Reset Leader. The Leader MUST stop sending MLE advertisements.
# The Leader reboot time MUST be less than Leader Timeout value
pkts.range(lstart, lend).\
filter_wpan_src64(LEADER).\
filter_mle_advertisement('Leader').\
must_not_next()
# Step 5: Router MUST reply with a Link Accept
# The following TLVs MUST be present in the Link Accept:
# - Leader Data TLV
# - Link-layer Frame Counter TLV
# - Response TLV
# - Source Address TLV
# - Address16 TLV
# - Route64 TLV
# - Version TLV
# - Challenge TLV (situational)
# - MLE Frame Counter TLV (optional)
# The Challenge TLV MUST be included
# if the response is an Accept and Request message.
_pkt = pkts.filter_wpan_src64(ROUTER).\
filter_wpan_dst64(LEADER).\
filter_mle_cmd2(MLE_LINK_ACCEPT, MLE_LINK_ACCEPT_AND_REQUEST).\
filter(lambda p: {
LEADER_DATA_TLV,
LINK_LAYER_FRAME_COUNTER_TLV,
RESPONSE_TLV,
SOURCE_ADDRESS_TLV,
ADDRESS16_TLV,
ROUTE64_TLV,
VERSION_TLV
} <= set(p.mle.tlv.type) and\
p.mle.tlv.addr16 is not nullField and\
p.mle.tlv.route64.id_mask is not nullField
).\
must_next()
if _pkt.mle.cmd == MLE_LINK_ACCEPT_AND_REQUEST:
_pkt.must_verify(lambda p: {CHALLENGE_TLV} <= set(p.mle.tlv.type))
# Step 7: Router_1 MUST respond with an ICMPv6 Echo Reply
_pkt = pkts.filter_ping_request().\
filter_wpan_src64(LEADER).\
filter_wpan_dst64(ROUTER).\
must_next()
lend2 = pkts.index
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_wpan_src64(ROUTER).\
filter_wpan_dst64(LEADER).\
must_next()
# Step 6: The Leader MUST NOT send a Parent Request after it is re-enabled.
pkts.range(lend, lend2).\
filter_wpan_src64(LEADER).\
filter_mle_cmd(MLE_PARENT_REQUEST).\
must_not_next()
if __name__ == '__main__':
unittest.main()
@@ -1,188 +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_PARENT_RESPONSE, MLE_CHILD_UPDATE_RESPONSE, MLE_CHILD_ID_REQUEST, MLE_CHILD_ID_RESPONSE, MLE_LINK_REQUEST, MLE_LINK_ACCEPT_AND_REQUEST, ADDR_SOL_URI, SOURCE_ADDRESS_TLV, MODE_TLV, TIMEOUT_TLV, CHALLENGE_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, MLE_FRAME_COUNTER_TLV, ROUTE64_TLV, ADDRESS16_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, TLV_REQUEST_TLV, SCAN_MASK_TLV, CONNECTIVITY_TLV, LINK_MARGIN_TLV, VERSION_TLV, ADDRESS_REGISTRATION_TLV, ACTIVE_TIMESTAMP_TLV
from pktverify.packet_verifier import PacketVerifier
from pktverify.null_field import nullField
LEADER = 1
ROUTER = 2
ED = 3
class Cert_5_5_2_LeaderReboot(thread_cert.TestCase):
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER]
},
ROUTER: {
'name': 'ROUTER',
'mode': 'rdn',
'allowlist': [LEADER, ED]
},
ED: {
'name': 'MED',
'is_mtd': True,
'mode': 'rn',
'allowlist': [ROUTER]
},
}
def _setUpLeader(self):
self.nodes[LEADER].add_allowlist(self.nodes[ROUTER].get_addr64())
self.nodes[LEADER].enable_allowlist()
self.nodes[LEADER].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[ROUTER].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER].get_state(), 'router')
self.nodes[ED].start()
self.simulator.go(5)
self.assertEqual(self.nodes[ED].get_state(), 'child')
self.nodes[LEADER].reset()
self._setUpLeader()
self.simulator.go(150)
self.assertEqual(self.nodes[ROUTER].get_state(), 'leader')
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_RESET_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'router')
addrs = self.nodes[ED].get_addrs()
for addr in addrs:
self.assertTrue(self.nodes[ROUTER].ping(addr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
ROUTER = pv.vars['ROUTER']
MED = pv.vars['MED']
leader_pkts = pkts.filter_wpan_src64(LEADER)
_rpkts = pkts.filter_wpan_src64(ROUTER)
# Step 2: The DUT MUST send properly formatted MLE Advertisements
_rpkts.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).must_next()
_lpkts = leader_pkts.range(_rpkts.index)
_lpkts.filter_mle_cmd(MLE_ADVERTISEMENT).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ROUTE64_TLV} <= set(p.mle.tlv.type))
_rpkts.filter_mle_cmd(MLE_ADVERTISEMENT).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ROUTE64_TLV} <= set(p.mle.tlv.type))
# Step 4: Router_1 MUST attempt to reattach to its original partition by
# sending MLE Parent Requests to the All-Routers multicast
# address (FFxx::xx) with a hop limit of 255. MUST make two separate attempts
for i in range(1, 3):
_rpkts.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 == 1)
lreset_start = _rpkts.index
# Step 6:Router_1 MUST attempt to attach to any other Partition
# within range by sending a MLE Parent Request.
_rpkts.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))
lreset_stop = _rpkts.index
# Step 3: The Leader MUST stop sending MLE advertisements.
leader_pkts.range(lreset_start, lreset_stop).filter_mle_cmd(MLE_ADVERTISEMENT).must_not_next()
# Step 5: Leader MUST NOT respond to the MLE Parent Requests
leader_pkts.range(lreset_start, lreset_stop).filter_mle_cmd(MLE_PARENT_RESPONSE).must_not_next()
# Step 7: Take over leader role of a new Partition and
# begin transmitting MLE Advertisements
with _rpkts.save_index():
_rpkts.filter_mle_cmd(MLE_ADVERTISEMENT).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ROUTE64_TLV} <= set(p.mle.tlv.type))
# Step 8: Router_1 MUST respond with an MLE Child Update Response,
# with the updated TLVs of the new partition
_rpkts.filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, MODE_TLV, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV} <= set(p.mle.tlv.type))
# Step 9: The Leader MUST send properly formatted MLE Parent
# Requests to the All-Routers multicast address
_lpkts.range(lreset_stop).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))
# Step 10: Router_1 MUST send an MLE Parent Response
_rpkts.filter_mle_cmd(MLE_PARENT_RESPONSE).must_next().must_verify(
lambda p: {
SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, LINK_LAYER_FRAME_COUNTER_TLV, RESPONSE_TLV, CHALLENGE_TLV,
LINK_MARGIN_TLV, CONNECTIVITY_TLV, VERSION_TLV
} <= set(p.mle.tlv.type))
# Step 11: Leader send MLE Child ID Request
_lpkts.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,
ADDRESS16_TLV, NETWORK_DATA_TLV, ROUTE64_TLV, ACTIVE_TIMESTAMP_TLV
} <= set(p.mle.tlv.type))
#Step 12: Router_1 send MLE Child ID Response
_rpkts.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ADDRESS16_TLV, NETWORK_DATA_TLV, ROUTE64_TLV} <= set(
p.mle.tlv.type))
#Step 13: Leader send an Address Solicit Request
_lpkts.filter_coap_request(ADDR_SOL_URI).must_next().must_verify(
lambda p: p.thread_address.tlv.ext_mac_addr and p.thread_address.tlv.status != 0)
#Step 14: Router_1 send an Address Solicit Response
_rpkts.filter_coap_ack(ADDR_SOL_URI).must_next().must_verify(
lambda p: p.thread_address.tlv.router_mask_assigned and p.thread_address.tlv.rloc16 is not nullField and p.
thread_address.tlv.status == 0)
#Step 15: Leader Send a Multicast Link Request
#Step 16: Router_1 send a Unicast Link Accept
# Steps 15 and 16 are skipped since new router no longer
# send multicast Link Request.
#Step 17: Router_1 MUST respond with an ICMPv6 Echo Reply
_rpkts.filter_ping_request().filter_wpan_dst64(MED).must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,215 +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 thread_cert
import config
from pktverify.consts import MLE_ADVERTISEMENT, MLE_PARENT_REQUEST, MLE_PARENT_RESPONSE, MLE_CHILD_UPDATE_RESPONSE, MLE_CHILD_ID_REQUEST, ADDR_SOL_URI, SOURCE_ADDRESS_TLV, MODE_TLV, TIMEOUT_TLV, CHALLENGE_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, ROUTE64_TLV, ADDRESS16_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, TLV_REQUEST_TLV, SCAN_MASK_TLV, VERSION_TLV, ADDRESS_REGISTRATION_TLV, ACTIVE_TIMESTAMP_TLV, NL_PARENT_PARTITION_CHANGE
from pktverify.packet_verifier import PacketVerifier
from pktverify.null_field import nullField
LEADER = 1
ROUTER1 = 2
ROUTER2 = 3
ED2 = 4
ED3 = 5
MTDS = [ED2, ED3]
class Cert_5_5_3_SplitMergeChildren(thread_cert.TestCase):
SUPPORT_NCP = False
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER1, ROUTER2]
},
ROUTER1: {
'name': 'ROUTER_1',
'mode': 'rdn',
'allowlist': [LEADER, ED2]
},
ROUTER2: {
'name': 'ROUTER_2',
'mode': 'rdn',
'allowlist': [LEADER, ED3]
},
ED2: {
'name': 'MED_2',
'is_mtd': True,
'mode': 'rn',
'allowlist': [ROUTER1]
},
ED3: {
'name': 'MED_3',
'is_mtd': True,
'mode': 'rn',
'allowlist': [ROUTER2]
},
}
def _setUpLeader(self):
self.nodes[LEADER].add_allowlist(self.nodes[ROUTER1].get_addr64())
self.nodes[LEADER].add_allowlist(self.nodes[ROUTER2].get_addr64())
self.nodes[LEADER].enable_allowlist()
self.nodes[LEADER].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[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[ROUTER1].get_state(), 'router')
self.nodes[ED2].start()
self.simulator.go(5)
self.assertEqual(self.nodes[ED2].get_state(), 'child')
self.nodes[ED3].start()
self.simulator.go(5)
self.assertEqual(self.nodes[ED2].get_state(), 'child')
self.nodes[LEADER].reset()
self._setUpLeader()
self.nodes[ROUTER2].set_preferred_partition_id(0xffffffff)
self.simulator.go(150)
self.assertEqual(self.nodes[ROUTER1].get_state(), 'leader')
self.assertEqual(self.nodes[ROUTER2].get_state(), 'leader')
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_RESET_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'router')
self.simulator.go(30)
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
self.assertEqual(self.nodes[ROUTER2].get_state(), 'leader')
self.collect_rloc16s()
addrs = self.nodes[ED3].get_addrs()
for addr in addrs:
if addr[0:4] != 'fe80':
self.assertTrue(self.nodes[ED2].ping(addr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
LEADER_RLOC16 = pv.vars['LEADER_RLOC16']
ROUTER_1 = pv.vars['ROUTER_1']
ROUTER_2 = pv.vars['ROUTER_2']
MED_2 = pv.vars['MED_2']
MED_3 = pv.vars['MED_3']
_lpkts = pkts.filter_wpan_src64(LEADER)
_router1_pkts = pkts.filter_wpan_src64(ROUTER_1)
# Step 2: The Leader and Router_1 MUST send properly formatted MLE Advertisements
pkts.filter_wpan_src64(LEADER).filter_LLANMA().filter_mle_cmd(MLE_ADVERTISEMENT).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ROUTE64_TLV} <= set(p.mle.tlv.type))
_pkt = pkts.filter_wpan_src64(ROUTER_1).filter_LLANMA().filter_mle_cmd(MLE_ADVERTISEMENT).must_next()
_pkt.must_verify(
lambda p: {SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ROUTE64_TLV} <= set(p.mle.tlv.type) and p.ipv6.hlim == 255)
# Step 4: Router_1 MUST attempt to reattach to its original partition by
# sending MLE Parent Requests to the All-Routers multicast address
_router1_pkts.range(pkts.index).filter_LLARMA().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 == 1 and p.ipv6.hlim == 255)
lreset_start = _router1_pkts.index
# Step 6: Router_1 MUST attempt to attach to any other Partition
# within range by sending a MLE Parent Request.
_router1_pkts.filter_LLARMA().filter_mle_cmd(MLE_PARENT_REQUEST).filter(
lambda p: p.mle.tlv.scan_mask.r == 1 and p.mle.tlv.scan_mask.e == 0).must_next().must_verify(
lambda p: {MODE_TLV, CHALLENGE_TLV, SCAN_MASK_TLV, VERSION_TLV} <= set(p.mle.tlv.type
) and p.ipv6.hlim == 255)
lreset_stop = _router1_pkts.index
# Step 3: The Leader MUST stop sending MLE advertisements.
_lpkts.range(lreset_start, lreset_stop).filter_LLARMA().filter_mle_cmd(MLE_ADVERTISEMENT).must_not_next()
# Step 5: Leader MUST NOT respond to the MLE Parent Requests
_lpkts.range(lreset_start,
lreset_stop).filter_wpan_src64(LEADER).filter_mle_cmd(MLE_PARENT_RESPONSE).must_not_next()
# Step 7: Router_1 takes over leader role of a new Partition and
# begin transmitting MLE Advertisements
with _router1_pkts.save_index():
_router1_pkts.filter_LLANMA().filter_mle_cmd(MLE_ADVERTISEMENT).filter(
lambda p: {SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ROUTE64_TLV} <= set(p.mle.tlv.type) and p.mle.tlv.
leader_data.partition_id != _pkt.mle.tlv.leader_data.partition_id 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 p.ipv6.hlim == 255).must_next()
# Step 9: Router_1 MUST respond with an MLE Child Update Response,
# with the updated TLVs of the new partition
_router1_pkts.filter_wpan_dst64(MED_2).filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, MODE_TLV, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV} <= set(p.mle.tlv.type))
# Step 10: The Leader MUST send properly formatted MLE Parent
# Requests to the All-Routers multicast address
_lpkts.filter_LLARMA().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.ipv6.hlim == 255)
# Step 11: Leader send MLE Child ID Request to Router_2
_lpkts.filter_wpan_dst64(ROUTER_2).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,
ADDRESS16_TLV, NETWORK_DATA_TLV, ROUTE64_TLV, ACTIVE_TIMESTAMP_TLV
} <= set(p.mle.tlv.type))
# Step 12: Leader send MLE ADVERTISEMENT
_lpkts.filter_mle_cmd(MLE_ADVERTISEMENT).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ROUTE64_TLV} <= set(p.mle.tlv.type) and p.ipv6.hlim == 255)
# Step 13: Router_1 send an Address Solicit Request
_router1_pkts.filter_coap_request(ADDR_SOL_URI).must_next().must_verify(
lambda p: p.wpan.dst16 == LEADER_RLOC16 and p.thread_address.tlv.ext_mac_addr is not nullField and p.
thread_address.tlv.status == NL_PARENT_PARTITION_CHANGE)
# Step 14: MED_2 MUST receive an ICMPv6 Echo Reply from MED_3
p = pkts.filter_ping_request().filter_wpan_src64(MED_2).must_next()
pkts.filter_ping_reply(identifier=p.icmpv6.echo.identifier).filter_wpan_src64(MED_3).must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,150 +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, SOURCE_ADDRESS_TLV, ROUTE64_TLV, LEADER_DATA_TLV
from pktverify.packet_verifier import PacketVerifier
LEADER = 1
ROUTER1 = 2
ROUTER2 = 3
ROUTER3 = 4
ROUTER4 = 5
class Cert_5_5_4_SplitMergeRouters(thread_cert.TestCase):
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER1, ROUTER2]
},
ROUTER1: {
'name': 'ROUTER_1',
'mode': 'rdn',
'allowlist': [LEADER, ROUTER3]
},
ROUTER2: {
'name': 'ROUTER_2',
'mode': 'rdn',
'allowlist': [LEADER, ROUTER4]
},
ROUTER3: {
'name': 'ROUTER_3',
'mode': 'rdn',
'allowlist': [ROUTER1]
},
ROUTER4: {
'name': 'ROUTER_4',
'mode': 'rdn',
'allowlist': [ROUTER2]
},
}
def _setUpLeader(self):
self.nodes[LEADER].add_allowlist(self.nodes[ROUTER1].get_addr64())
self.nodes[LEADER].add_allowlist(self.nodes[ROUTER2].get_addr64())
self.nodes[LEADER].enable_allowlist()
self.nodes[LEADER].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[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[ROUTER3].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER3].get_state(), 'router')
self.nodes[ROUTER4].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER4].get_state(), 'router')
self.nodes[LEADER].reset()
self._setUpLeader()
self.simulator.go(150)
self.nodes[LEADER].start()
self.simulator.go(50 + config.LEADER_RESET_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'router')
self.collect_ipaddrs()
addrs = self.nodes[ROUTER4].get_addrs()
for addr in addrs:
if addr[0:4] != 'fe80':
self.assertTrue(self.nodes[ROUTER3].ping(addr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
ROUTER_1 = pv.vars['ROUTER_1']
ROUTER_3 = pv.vars['ROUTER_3']
ROUTER_4 = pv.vars['ROUTER_4']
leader_pkts = pkts.filter_wpan_src64(LEADER)
router1_pkts = pkts.filter_wpan_src64(ROUTER_1)
# Step 2: The Leader MUST send properly formatted MLE Advertisements
router1_pkts.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).must_next()
leader_pkts.range(router1_pkts.index).filter_mle_cmd(MLE_ADVERTISEMENT).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, ROUTE64_TLV, LEADER_DATA_TLV} <= set(p.mle.tlv.type))
router1_pkts.filter_mle_cmd(MLE_PARENT_REQUEST).must_next()
lreset_start = router1_pkts.index
router1_pkts.filter_mle_cmd(MLE_ADVERTISEMENT).must_next()
lreset_stop = router1_pkts.index
# Step 3: The Leader MUST stop sending MLE advertisements.
leader_pkts.range(lreset_start, lreset_stop).filter_mle_cmd(MLE_ADVERTISEMENT).must_not_next()
# Step 5: Router_4 MUST send an ICMPv6 Echo Reply to Router_3
router3_mleid = pv.vars['ROUTER_3_MLEID']
router4_mleid = pv.vars['ROUTER_4_MLEID']
pkts.filter_wpan_src64(ROUTER_3).filter(
lambda p: p.ipv6.src == router3_mleid and p.ipv6.dst == router4_mleid).filter_ping_request().must_next()
pkts.filter_wpan_src64(ROUTER_4).filter(
lambda p: p.ipv6.src == router4_mleid and p.ipv6.dst == router3_mleid).filter_ping_reply().must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,215 +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_LINK_REQUEST, MLE_PARENT_REQUEST, MLE_PARENT_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, NL_MAC_EXTENDED_ADDRESS_TLV, NL_STATUS_TLV
from pktverify.packet_verifier import PacketVerifier
LEADER = 1
ROUTER1 = 2
ROUTER2 = 3
ROUTER3 = 4
ROUTER15 = 16
REED1 = 17
class Cert_5_5_5_SplitMergeREED(thread_cert.TestCase):
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER2, ROUTER3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, ROUTER15]
},
ROUTER1: {
'name': 'ROUTER_1',
'mode': 'rdn',
'allowlist': [ROUTER3]
},
ROUTER2: {
'name': 'ROUTER_2',
'mode': 'rdn',
'allowlist': [LEADER, REED1]
},
ROUTER3: {
'name': 'ROUTER_3',
'mode': 'rdn',
'allowlist': [LEADER, ROUTER1]
},
5: {
'mode': 'rdn',
'allowlist': [LEADER]
},
6: {
'mode': 'rdn',
'allowlist': [LEADER]
},
7: {
'mode': 'rdn',
'allowlist': [LEADER]
},
8: {
'mode': 'rdn',
'allowlist': [LEADER]
},
9: {
'mode': 'rdn',
'allowlist': [LEADER]
},
10: {
'mode': 'rdn',
'allowlist': [LEADER]
},
11: {
'mode': 'rdn',
'allowlist': [LEADER]
},
12: {
'mode': 'rdn',
'allowlist': [LEADER]
},
13: {
'mode': 'rdn',
'allowlist': [LEADER]
},
14: {
'mode': 'rdn',
'allowlist': [LEADER]
},
15: {
'mode': 'rdn',
'allowlist': [LEADER]
},
ROUTER15: {
'mode': 'rdn',
'allowlist': [LEADER]
},
REED1: {
'name': 'REED',
'mode': 'rdn',
'allowlist': [ROUTER2]
},
}
def test(self):
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
for i in range(ROUTER2, ROUTER15 + 1):
self.nodes[i].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[i].get_state(), 'router')
self.nodes[ROUTER1].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
self.nodes[REED1].start()
self.simulator.go(5)
self.assertEqual(self.nodes[REED1].get_state(), 'child')
self.nodes[ROUTER1].add_allowlist(self.nodes[REED1].get_addr64())
self.nodes[REED1].add_allowlist(self.nodes[ROUTER1].get_addr64())
self.nodes[ROUTER3].stop()
self.simulator.go(140)
self.assertEqual(self.nodes[ROUTER1].get_state(), 'child')
self.assertEqual(self.nodes[REED1].get_state(), 'router')
self.collect_ipaddrs()
addrs = self.nodes[LEADER].get_addrs()
for addr in addrs:
if addr[0:4] != 'fe80':
self.assertTrue(self.nodes[ROUTER1].ping(addr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
ROUTER_1 = pv.vars['ROUTER_1']
ROUTER_2 = pv.vars['ROUTER_2']
ROUTER_3 = pv.vars['ROUTER_3']
REED = pv.vars['REED']
router1_pkts = pkts.filter_wpan_src64(ROUTER_1)
router2_pkts = pkts.filter_wpan_src64(ROUTER_2)
reed_pkts = pkts.filter_wpan_src64(REED)
router2_pkts.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).filter_wpan_dst64(REED).must_next()
_start_idx = router2_pkts.index
reed_pkts.index = _start_idx
# Step 3: Remove Router_3 from the network
# Router_1 attempt to re-attach to partition.
# Sends multicast Parent Request to Routers and REEDs
router1_pkts.range(_start_idx).must_next()
router1_pkts.filter_mle_cmd(MLE_PARENT_REQUEST).must_next()
# filter MLE_ADVERTISEMENT with 16 routing table entry:
# 1 byte ID Sequence + 8 bytes ID Mask + 16 bytes Routing Table Entry =
# 25 (Router64 tlv length)
pkts.range(_start_idx).filter_mle_cmd(MLE_ADVERTISEMENT).filter(lambda p: 25 in p.mle.tlv.len).must_next()
_end_idx = pkts.index
# Step 2: The DUT MUST NOT attempt to become an active router by sending an Address Solicit Request
reed_pkts.range(_start_idx, _end_idx).filter_coap_request(ADDR_SOL_URI).must_not_next()
# Step 4: The DUT send a Parent Response to Router_1
reed_pkts.filter_mle_cmd(MLE_PARENT_RESPONSE).must_next().must_verify(lambda p: p.wpan.dst64 == ROUTER_1)
# Step 5: Router_1 Send MLE Child ID Request to the DUT
router1_pkts.range(reed_pkts.index).filter_mle_cmd(MLE_CHILD_ID_REQUEST).must_next()
# Step 6: DUT send an Address Solicit Request to Leader,
# receives short address and becomes a router
pkts.range(_end_idx).filter_wpan_src64(REED).filter_coap_request(ADDR_SOL_URI).must_next().must_verify(
lambda p: {NL_MAC_EXTENDED_ADDRESS_TLV, NL_STATUS_TLV} <= set(p.coap.tlv.type))
# Step 7: DUT send a Multicast Link Request
# Step 7 is skipped since new router no longer sends
# multicast Link Request.
# Step 8: DUT send Child ID Response to Router_1
reed_pkts.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).must_next().must_verify(lambda p: p.wpan.dst64 == ROUTER_1)
# Step 9: The DUT MUST route the ICMPv6 Echo request to the Leader.
# The DUT MUST route the ICMPv6 Echo reply back to Router_1
leader_mleid = pv.vars['LEADER_MLEID']
router1_mleid = pv.vars['ROUTER_1_MLEID']
reed_pkts.filter_ipv6_src_dst(router1_mleid, leader_mleid).filter_ping_request().must_next()
reed_pkts.filter_ipv6_src_dst(leader_mleid, router1_mleid).filter_ping_reply().must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,188 +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_PARENT_RESPONSE, MLE_CHILD_ID_REQUEST, MLE_CHILD_ID_RESPONSE, SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ROUTE64_TLV, MODE_TLV, CHALLENGE_TLV, SCAN_MASK_TLV, VERSION_TLV, LINK_LAYER_FRAME_COUNTER_TLV, RESPONSE_TLV, LINK_MARGIN_TLV, CONNECTIVITY_TLV, TIMEOUT_TLV, TLV_REQUEST_TLV, ADDRESS16_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV
from pktverify.packet_verifier import PacketVerifier
LEADER1 = 1
ROUTER1 = 2
ROUTER2 = 3
ROUTER3 = 4
class Cert_5_5_7_SplitMergeThreeWay(thread_cert.TestCase):
TOPOLOGY = {
LEADER1: {
'name': 'LEADER_1',
'mode': 'rdn',
'allowlist': [ROUTER1, ROUTER2, ROUTER3]
},
ROUTER1: {
'name': 'ROUTER_1',
'mode': 'rdn',
'allowlist': [LEADER1]
},
ROUTER2: {
'name': 'ROUTER_2',
'mode': 'rdn',
'allowlist': [LEADER1]
},
ROUTER3: {
'name': 'ROUTER_3',
'mode': 'rdn',
'allowlist': [LEADER1]
},
}
def _setUpLeader1(self):
self.nodes[LEADER1].add_allowlist(self.nodes[ROUTER1].get_addr64())
self.nodes[LEADER1].add_allowlist(self.nodes[ROUTER2].get_addr64())
self.nodes[LEADER1].add_allowlist(self.nodes[ROUTER3].get_addr64())
self.nodes[LEADER1].enable_allowlist()
self.nodes[LEADER1].set_router_selection_jitter(1)
def test(self):
self.nodes[LEADER1].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER1].get_state(), 'leader')
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[ROUTER3].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER3].get_state(), 'router')
self.nodes[LEADER1].reset()
self._setUpLeader1()
self.simulator.go(140)
self.nodes[LEADER1].start()
self.simulator.go(30 + config.LEADER_RESET_DELAY)
addrs = self.nodes[LEADER1].get_addrs()
for addr in addrs:
if addr[0:4] != 'fe80':
self.assertTrue(self.nodes[ROUTER1].ping(addr))
addrs = self.nodes[ROUTER2].get_addrs()
for addr in addrs:
if addr[0:4] != 'fe80':
self.assertTrue(self.nodes[ROUTER1].ping(addr))
addrs = self.nodes[ROUTER3].get_addrs()
for addr in addrs:
if addr[0:4] != 'fe80':
self.assertTrue(self.nodes[ROUTER1].ping(addr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER_1']
ROUTER_1 = pv.vars['ROUTER_1']
ROUTER_2 = pv.vars['ROUTER_2']
ROUTER_3 = pv.vars['ROUTER_3']
leader_pkts = pkts.filter_wpan_src64(LEADER)
router1_pkts = pkts.filter_wpan_src64(ROUTER_1)
router2_pkts = pkts.filter_wpan_src64(ROUTER_2)
router3_pkts = pkts.filter_wpan_src64(ROUTER_3)
# Step 2: The Leader and Router_1 MUST send properly formatted MLE Advertisements
leader_pkts.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).must_next()
_lpkts = leader_pkts.copy()
_lpkts.filter_mle_cmd(MLE_ADVERTISEMENT).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ROUTE64_TLV} <= set(p.mle.tlv.type))
router1_pkts.range(leader_pkts.index).filter_mle_cmd(MLE_ADVERTISEMENT).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ROUTE64_TLV} <= set(p.mle.tlv.type))
# Step 4: Each router forms a partition with the lowest possible partition ID
# Step 5: Router_1 MUST send MLE Parent Requests and MUST make two separate attempts
router1_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 == 1)
lreset_start = router1_pkts.index
router1_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 == 1)
# Step 7: Router_1 MUST attempt to attach to any other Partition
# within range by sending a MLE Parent Request.
router1_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))
lreset_stop = router1_pkts.index
# Step 3: The Leader MUST stop sending MLE advertisements.
leader_pkts.range(lreset_start, lreset_stop).filter_mle_cmd(MLE_ADVERTISEMENT).must_not_next()
# Step 6: The Leader does not respond to the Parent Requests
leader_pkts.range(lreset_start, lreset_stop).filter_mle_cmd(MLE_PARENT_RESPONSE).must_not_next()
# Step 8: Router_1 take over leader role of a new Partition and begin transmitting
# MLE Advertisements
router1_pkts.copy().filter_mle_cmd(MLE_ADVERTISEMENT).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ROUTE64_TLV} <= set(p.mle.tlv.type))
# Step 9: The Leader MUST send properly formatted MLE Parent Requests to the
# All-Routers multicast address
_lpkts.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))
# Step 10: Router_1 MUST send an MLE Parent Response
router1_pkts.filter_mle_cmd(MLE_PARENT_RESPONSE).must_next().must_verify(
lambda p: {
SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, LINK_LAYER_FRAME_COUNTER_TLV, RESPONSE_TLV, CHALLENGE_TLV,
LINK_MARGIN_TLV, CONNECTIVITY_TLV, VERSION_TLV
} <= set(p.mle.tlv.type))
# Step 11: Leader send MLE Child ID Request
_lpkts.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,
ADDRESS16_TLV, NETWORK_DATA_TLV, ROUTE64_TLV, ACTIVE_TIMESTAMP_TLV
} <= set(p.mle.tlv.type))
# Step 12: DUT (Router or Leader) MUST respond with a ICMPv6 Echo Reply
_lpkts.filter_ping_reply().must_next()
router2_pkts.filter_ping_reply().must_next()
router3_pkts.filter_ping_reply().must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,173 +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_LINK_REQUEST, MLE_PARENT_REQUEST, MLE_PARENT_RESPONSE, MLE_CHILD_UPDATE_RESPONSE, MLE_CHILD_ID_REQUEST, MLE_CHILD_ID_RESPONSE, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, MODE_TLV, TIMEOUT_TLV, VERSION_TLV, TLV_REQUEST_TLV, ADDRESS16_TLV, NETWORK_DATA_TLV, ROUTE64_TLV, MODE_TLV, TIMEOUT_TLV, CHALLENGE_TLV, SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV
from pktverify.packet_verifier import PacketVerifier
from pktverify.addrs import Ipv6Addr
LEADER = 1
ROUTER = 2
ED1 = 3
SED1 = 4
MTDS = [ED1, SED1]
class Cert_5_6_1_NetworkDataLeaderAsBr(thread_cert.TestCase):
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER]
},
ROUTER: {
'name': 'ROUTER',
'mode': 'rdn',
'allowlist': [LEADER, ED1, SED1]
},
ED1: {
'name': 'MED',
'is_mtd': True,
'mode': 'rn',
'allowlist': [ROUTER]
},
SED1: {
'name': 'SED',
'is_mtd': True,
'mode': '-',
'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[LEADER].add_prefix('2001:2:0:1::/64', 'paros')
self.nodes[LEADER].add_prefix('2001:2:0:2::/64', 'paro')
self.nodes[LEADER].register_netdata()
# Set lowpan context of sniffer
self.simulator.set_lowpan_context(1, '2001:2:0:1::/64')
self.simulator.set_lowpan_context(2, '2001:2:0:2::/64')
self.simulator.go(5)
self.nodes[ROUTER].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER].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_rloc16s()
addrs = self.nodes[ED1].get_addrs()
self.assertTrue(any('2001:2:0:1' in addr[0:10] for addr in addrs))
self.assertTrue(any('2001:2:0:2' in addr[0:10] for addr in addrs))
for addr in addrs:
if addr[0:10] == '2001:2:0:1' or addr[0:10] == '2001:2:0:2':
self.assertTrue(self.nodes[LEADER].ping(addr))
addrs = self.nodes[SED1].get_addrs()
self.assertTrue(any('2001:2:0:1' in addr[0:10] for addr in addrs))
self.assertFalse(any('2001:2:0:2' in addr[0:10] for addr in addrs))
for addr in addrs:
if addr[0:10] == '2001:2:0:1' or addr[0:10] == '2001:2:0:2':
self.assertTrue(self.nodes[LEADER].ping(addr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
ROUTER = pv.vars['ROUTER']
MED = pv.vars['MED']
SED = pv.vars['SED']
_rpkts = pkts.filter_wpan_src64(ROUTER)
_mpkts = pkts.filter_wpan_src64(MED)
_spkts = pkts.filter_wpan_src64(SED)
# Step 3: The DUT MUST request the Network Data TLV during the
# attaching procedure when sending MLE Child ID Request frame
_rpkts.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,
ADDRESS16_TLV, NETWORK_DATA_TLV, ROUTE64_TLV
} <= set(p.mle.tlv.type))
_rpkts_med = _rpkts.copy()
_rpkts_sed = _rpkts.copy()
# Step 6: The DUT MUST send an MLE Child ID Response to SED_1,
# containing only stable Network Data
_rpkts_sed.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).filter_wpan_dst64(SED).must_next().must_verify(
lambda p: {MODE_TLV, TIMEOUT_TLV, CHALLENGE_TLV} <= set(p.thread_nwd.tlv.type) and
{Ipv6Addr('2001:2:0:1::')} == set(p.thread_nwd.tlv.prefix) and p.thread_nwd.tlv.border_router.flag.p ==
[1] and p.thread_nwd.tlv.border_router.flag.s == [1] and p.thread_nwd.tlv.border_router.flag.r == [1] and p
.thread_nwd.tlv.border_router.flag.o == [1] and p.thread_nwd.tlv.stable == [1, 1, 1])
# Step 8: The DUT MUST send a MLE Child ID Response to MED_1,
# containing the full Network Data
_rpkts_med.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).filter_wpan_dst64(MED).must_next().must_verify(
lambda p: {Ipv6Addr('2001:2:0:1::'), Ipv6Addr('2001:2:0:2::')} == set(
p.thread_nwd.tlv.prefix) and p.thread_nwd.tlv.border_router.flag.p == [1, 1] and p.thread_nwd.tlv.
border_router.flag.s == [1, 1] and p.thread_nwd.tlv.border_router.flag.r == [1, 1] and p.thread_nwd.tlv.
border_router.flag.o == [1, 1] and p.thread_nwd.tlv.stable == [0, 1, 1, 1, 0, 0, 0])
# Step 10: The DUT MUST send a unicast MLE Child Update
# Response to each of MED_1 and SED_1
_rpkts_med.filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).must_next().must_verify(
lambda p: p.wpan.dst64 == MED and
{SOURCE_ADDRESS_TLV, MODE_TLV, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV} <= set(p.mle.tlv.type))
_rpkts_sed.filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).must_next().must_verify(
lambda p: p.wpan.dst64 == SED and
{SOURCE_ADDRESS_TLV, MODE_TLV, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV} <= set(p.mle.tlv.type))
# Step 11: MED_1 and SED_1 MUST respond to each ICMPv6 Echo Request
# with an ICMPv6 Echo Reply
med_rloc16 = pv.vars['MED_RLOC16']
sed_rloc16 = pv.vars['SED_RLOC16']
router_rloc16 = pv.vars['ROUTER_RLOC16']
_mpkts.range(_rpkts_med.index).filter(
lambda p: p.wpan.src16 == med_rloc16 and p.wpan.dst16 == router_rloc16).filter_ping_reply().must_next()
_spkts.range(_rpkts_sed.index).filter(
lambda p: p.wpan.src16 == sed_rloc16 and p.wpan.dst16 == router_rloc16).filter_ping_reply().must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,168 +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_DATA_RESPONSE, MLE_CHILD_ID_RESPONSE, ADDR_SOL_URI, MLE_CHILD_UPDATE_RESPONSE, MODE_TLV, LEADER_DATA_TLV, ROUTE64_TLV, SOURCE_ADDRESS_TLV, ACTIVE_TIMESTAMP_TLV, ADDRESS16_TLV, NETWORK_DATA_TLV, ADDRESS_REGISTRATION_TLV
from pktverify.packet_verifier import PacketVerifier
from pktverify.addrs import Ipv6Addr
LEADER = 1
ROUTER = 2
ED1 = 3
SED1 = 4
MTDS = [ED1, SED1]
class Cert_5_6_2_NetworkDataRouterAsBr(thread_cert.TestCase):
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER, ED1, SED1]
},
ROUTER: {
'name': 'ROUTER',
'mode': 'rdn',
'allowlist': [LEADER]
},
ED1: {
'name': 'MED',
'is_mtd': True,
'mode': 'rn',
'allowlist': [LEADER]
},
SED1: {
'name': 'SED',
'is_mtd': True,
'mode': '-',
'timeout': config.DEFAULT_CHILD_TIMEOUT,
'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.nodes[ROUTER].add_prefix('2001:2:0:1::/64', 'paros')
self.nodes[ROUTER].add_prefix('2001:2:0:2::/64', 'paro')
self.nodes[ROUTER].register_netdata()
# Set lowpan context of sniffer
self.simulator.set_lowpan_context(1, '2001:2:0:1::/64')
self.simulator.set_lowpan_context(2, '2001:2:0:2::/64')
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')
addrs = self.nodes[ED1].get_addrs()
self.assertTrue(any('2001:2:0:1' in addr[0:10] for addr in addrs))
self.assertTrue(any('2001:2:0:2' in addr[0:10] for addr in addrs))
for addr in addrs:
if addr[0:10] == '2001:2:0:1' or addr[0:10] == '2001:2:0:2':
self.assertTrue(self.nodes[LEADER].ping(addr))
addrs = self.nodes[SED1].get_addrs()
self.assertTrue(any('2001:2:0:1' in addr[0:10] for addr in addrs))
self.assertFalse(any('2001:2:0:2' in addr[0:10] for addr in addrs))
for addr in addrs:
if addr[0:10] == '2001:2:0:1' or addr[0:10] == '2001:2:0:2':
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']
MED = pv.vars['MED']
SED = pv.vars['SED']
_lpkts = pkts.filter_wpan_src64(LEADER)
# Step 1: The DUT MUST send properly formatted MLE Advertisements
_lpkts.filter_mle_cmd(MLE_ADVERTISEMENT).must_next().must_verify(
lambda p: {LEADER_DATA_TLV, ROUTE64_TLV, SOURCE_ADDRESS_TLV} <= set(p.mle.tlv.type))
# Step 3: The DUT MUST properly attach Router_1 device to the network,
# and transmit Network Data during the attach phase in the
# Child ID Response frame of the Network Data TLV
_lpkts.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).must_next().must_verify(lambda p: p.wpan.dst64 == ROUTER and {
SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ACTIVE_TIMESTAMP_TLV, ADDRESS16_TLV, NETWORK_DATA_TLV
} <= set(p.mle.tlv.type))
# Step 5: The DUT Automatically sends a CoAP Response frame and
# MLE Data Response message
_lpkts.filter_coap_ack(ADDR_SOL_URI).must_next()
_lpkts.filter_mle_cmd(MLE_DATA_RESPONSE).must_next().must_verify(
lambda p: {Ipv6Addr('2001:2:0:1::'), Ipv6Addr('2001:2:0:2::')} == set(
p.thread_nwd.tlv.prefix) and p.thread_nwd.tlv.border_router.flag.p == [1, 1] and p.thread_nwd.tlv.
border_router.flag.s == [1, 1] and p.thread_nwd.tlv.border_router.flag.r == [1, 1] and p.thread_nwd.tlv.
border_router.flag.o == [1, 1] and p.thread_nwd.tlv.stable == [0, 1, 1, 1, 0, 0, 0])
_lpkts_med = _lpkts.copy()
_lpkts_sed = _lpkts.copy()
# Step 7: The DUT MUST send a MLE Child ID Response to SED_1,
# containing the stable Network Data
_lpkts_sed.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).filter_wpan_dst64(SED).must_next().must_verify(
lambda p: {Ipv6Addr('2001:2:0:1::')} == set(p.thread_nwd.tlv.prefix) and p.thread_nwd.tlv.border_router.
flag.p == [1] and p.thread_nwd.tlv.border_router.flag.s == [1] and p.thread_nwd.tlv.border_router.flag.r ==
[1] and p.thread_nwd.tlv.border_router.flag.o == [1] and p.thread_nwd.tlv.stable == [1, 1, 1])
# Step 9: The DUT MUST send a MLE Child ID Response to MED_1,
# containing the full Network Data
_lpkts_med.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).filter_wpan_dst64(MED).must_next().must_verify(
lambda p: {Ipv6Addr('2001:2:0:1::'), Ipv6Addr('2001:2:0:2::')} == set(
p.thread_nwd.tlv.prefix) and p.thread_nwd.tlv.border_router.flag.p == [1, 1] and p.thread_nwd.tlv.
border_router.flag.s == [1, 1] and p.thread_nwd.tlv.border_router.flag.r == [1, 1] and p.thread_nwd.tlv.
border_router.flag.o == [1, 1] and p.thread_nwd.tlv.stable == [0, 1, 1, 1, 0, 0, 0])
# Step 10: The DUT MUST send a unicast MLE Child Update
# Response to each of MED_1 and SED_1
_lpkts_med.filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).filter_wpan_dst64(MED).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, MODE_TLV, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV} <= set(p.mle.tlv.type))
_lpkts_sed.filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).filter_wpan_dst64(SED).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, MODE_TLV, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV} <= set(p.mle.tlv.type))
if __name__ == '__main__':
unittest.main()
@@ -1,155 +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_DATA_RESPONSE, MLE_CHILD_ID_RESPONSE, MLE_CHILD_UPDATE_REQUEST, ADDR_SOL_URI, MLE_CHILD_UPDATE_RESPONSE, MODE_TLV, LEADER_DATA_TLV, ROUTE64_TLV, SOURCE_ADDRESS_TLV, ACTIVE_TIMESTAMP_TLV, ADDRESS16_TLV, NETWORK_DATA_TLV, ADDRESS_REGISTRATION_TLV, LINK_LOCAL_ALL_NODES_MULTICAST_ADDRESS
from pktverify.packet_verifier import PacketVerifier
from pktverify.addrs import Ipv6Addr
LEADER = 1
ROUTER = 2
ED1 = 3
SED1 = 4
MTDS = [ED1, SED1]
class Cert_5_6_3_NetworkDataRegisterAfterAttachLeader(thread_cert.TestCase):
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER]
},
ROUTER: {
'name': 'ROUTER',
'mode': 'rdn',
'allowlist': [LEADER, ED1, SED1]
},
ED1: {
'name': 'MED',
'is_mtd': True,
'mode': 'rn',
'allowlist': [ROUTER]
},
SED1: {
'name': 'SED',
'is_mtd': True,
'mode': '-',
'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[ROUTER].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER].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[LEADER].add_prefix('2001:2:0:1::/64', 'paros')
self.nodes[LEADER].add_prefix('2001:2:0:2::/64', 'paro')
self.nodes[LEADER].register_netdata()
# Set lowpan context of sniffer
self.simulator.set_lowpan_context(1, '2001:2:0:1::/64')
self.simulator.set_lowpan_context(2, '2001:2:0:2::/64')
self.simulator.go(10)
addrs = self.nodes[ED1].get_addrs()
self.assertTrue(any('2001:2:0:1' in addr[0:10] for addr in addrs))
self.assertTrue(any('2001:2:0:2' in addr[0:10] for addr in addrs))
for addr in addrs:
if addr[0:10] == '2001:2:0:1' or addr[0:10] == '2001:2:0:2':
self.assertTrue(self.nodes[LEADER].ping(addr))
addrs = self.nodes[SED1].get_addrs()
self.assertTrue(any('2001:2:0:1' in addr[0:10] for addr in addrs))
self.assertFalse(any('2001:2:0:2' in addr[0:10] for addr in addrs))
for addr in addrs:
if addr[0:10] == '2001:2:0:1' or addr[0:10] == '2001:2:0:2':
self.assertTrue(self.nodes[LEADER].ping(addr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
ROUTER = pv.vars['ROUTER']
MED = pv.vars['MED']
SED = pv.vars['SED']
_rpkts = pkts.filter_wpan_src64(ROUTER)
_rpkts_med = _rpkts.copy()
_rpkts_sed = _rpkts.copy()
# Step 3: The DUT MUST multicast a MLE Data Response for each
# prefix sent by the Leader (Prefix 1 and Prefix 2)
_rpkts.filter_mle_cmd(MLE_DATA_RESPONSE).filter_ipv6_dst(LINK_LOCAL_ALL_NODES_MULTICAST_ADDRESS).must_next(
).must_verify(lambda p: {Ipv6Addr('2001:2:0:1::'), Ipv6Addr('2001:2:0:2::')} == set(p.thread_nwd.tlv.prefix)
and p.thread_nwd.tlv.border_router.flag.p == [1, 1] and p.thread_nwd.tlv.border_router.flag.s ==
[1, 1] and p.thread_nwd.tlv.border_router.flag.r == [1, 1] and p.thread_nwd.tlv.border_router.
flag.o == [1, 1] and p.thread_nwd.tlv.stable == [0, 1, 1, 1, 0, 0, 0])
# Step 5: The DUT MUST send a unicast MLE Child Update
# Response to MED_1
_rpkts_med.filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).filter_wpan_dst64(MED).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, MODE_TLV, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV} <= set(p.mle.tlv.type))
# Step 6: The DUT MUST send a unicast MLE Child Update
# Request to SED_1
_rpkts_sed.filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).filter_wpan_dst64(SED).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV} <= set(
p.mle.tlv.type) and {Ipv6Addr('2001:2:0:1::')} == set(p.thread_nwd.tlv.prefix) and p.thread_nwd.tlv.
border_router.flag.p == [1] and p.thread_nwd.tlv.border_router.flag.s == [1] and p.thread_nwd.tlv.
border_router.flag.r == [1] and p.thread_nwd.tlv.border_router.flag.o == [1] and p.thread_nwd.tlv.stable ==
[1, 1, 1] and p.thread_nwd.tlv.border_router_16 == [0xFFFE])
# Step 8: The DUT MUST send a unicast MLE Child Update
# Response to SED_1
_rpkts_sed.filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).filter_wpan_dst64(SED).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, MODE_TLV, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV} <= set(p.mle.tlv.type))
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 unittest
import config
import thread_cert
from pktverify.consts import MLE_ADVERTISEMENT, MLE_DATA_RESPONSE, MLE_CHILD_ID_RESPONSE, MLE_CHILD_UPDATE_REQUEST, SVR_DATA_URI, MLE_CHILD_UPDATE_RESPONSE, MODE_TLV, LEADER_DATA_TLV, ROUTE64_TLV, SOURCE_ADDRESS_TLV, ACTIVE_TIMESTAMP_TLV, ADDRESS16_TLV, NETWORK_DATA_TLV, ADDRESS_REGISTRATION_TLV, LINK_LOCAL_ALL_NODES_MULTICAST_ADDRESS
from pktverify.packet_verifier import PacketVerifier
from pktverify.addrs import Ipv6Addr
LEADER = 1
ROUTER = 2
ED1 = 3
SED1 = 4
MTDS = [ED1, SED1]
class Cert_5_6_4_NetworkDataRegisterAfterAttachRouter(thread_cert.TestCase):
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER, ED1, SED1]
},
ROUTER: {
'name': 'ROUTER',
'mode': 'rdn',
'allowlist': [LEADER]
},
ED1: {
'name': 'MED',
'is_mtd': True,
'mode': 'rn',
'allowlist': [LEADER]
},
SED1: {
'name': 'SED',
'is_mtd': True,
'mode': '-',
'timeout': config.DEFAULT_CHILD_TIMEOUT,
'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.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[ROUTER].add_prefix('2001:2:0:1::/64', 'paros')
self.nodes[ROUTER].add_prefix('2001:2:0:2::/64', 'paro')
self.nodes[ROUTER].register_netdata()
# Set lowpan context of sniffer
self.simulator.set_lowpan_context(1, '2001:2:0:1::/64')
self.simulator.set_lowpan_context(2, '2001:2:0:2::/64')
self.simulator.go(10)
addrs = self.nodes[ED1].get_addrs()
self.assertTrue(any('2001:2:0:1' in addr[0:10] for addr in addrs))
self.assertTrue(any('2001:2:0:2' in addr[0:10] for addr in addrs))
for addr in addrs:
if addr[0:10] == '2001:2:0:1' or addr[0:10] == '2001:2:0:2':
self.assertTrue(self.nodes[LEADER].ping(addr))
addrs = self.nodes[SED1].get_addrs()
self.assertTrue(any('2001:2:0:1' in addr[0:10] for addr in addrs))
self.assertFalse(any('2001:2:0:2' in addr[0:10] for addr in addrs))
for addr in addrs:
if addr[0:10] == '2001:2:0:1' or addr[0:10] == '2001:2:0:2':
self.assertTrue(self.nodes[LEADER].ping(addr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
MED = pv.vars['MED']
SED = pv.vars['SED']
_lpkts = pkts.filter_wpan_src64(LEADER)
# Step 1: Ensure the topology is formed correctly
_lpkts.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).filter_wpan_dst64(SED).must_next()
# Step 3: The DUT Automatically sends a CoAP Response frame and
# MLE Data Response message
_lpkts.copy().filter_coap_ack(SVR_DATA_URI).must_next()
_lpkts_med = _lpkts.copy()
_lpkts_sed = _lpkts.copy()
# Step 4: The DUT MUST send a multicast MLE Data Response with
# the new network information collected from Router_1
_lpkts.filter_mle_cmd(MLE_DATA_RESPONSE).filter_ipv6_dst(LINK_LOCAL_ALL_NODES_MULTICAST_ADDRESS).must_next(
).must_verify(lambda p: {Ipv6Addr('2001:2:0:1::'), Ipv6Addr('2001:2:0:2::')} == set(p.thread_nwd.tlv.prefix)
and p.thread_nwd.tlv.border_router.flag.p == [1, 1] and p.thread_nwd.tlv.border_router.flag.s ==
[1, 1] and p.thread_nwd.tlv.border_router.flag.r == [1, 1] and p.thread_nwd.tlv.border_router.
flag.o == [1, 1] and p.thread_nwd.tlv.stable == [0, 1, 1, 1, 0, 0, 0])
# Step 7: The DUT MUST send a unicast MLE Child Update
# Response to MED_1
_lpkts_med.filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).filter_wpan_dst64(MED).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, MODE_TLV, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV} <= set(p.mle.tlv.type))
# Step 9: The DUT MUST send a unicast MLE Child Update
# Request to SED_1
_lpkts_sed.filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).filter_wpan_dst64(SED).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV} <= set(
p.mle.tlv.type) and {Ipv6Addr('2001:2:0:1::')} == set(p.thread_nwd.tlv.prefix) and p.thread_nwd.tlv.
border_router.flag.p == [1] and p.thread_nwd.tlv.border_router.flag.s == [1] and p.thread_nwd.tlv.
border_router.flag.r == [1] and p.thread_nwd.tlv.border_router.flag.o == [1] and p.thread_nwd.tlv.stable ==
[1, 1, 1] and p.thread_nwd.tlv.border_router_16 == [0xFFFE])
# Step 11: The DUT MUST send a unicast MLE Child Update
# Response to SED_1
_lpkts_sed.filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).filter_wpan_dst64(SED).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, MODE_TLV, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV} <= set(p.mle.tlv.type))
if __name__ == '__main__':
unittest.main()
@@ -1,168 +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_DATA_RESPONSE, MLE_CHILD_ID_RESPONSE, MLE_CHILD_UPDATE_REQUEST, SVR_DATA_URI, MLE_CHILD_UPDATE_RESPONSE, MODE_TLV, LEADER_DATA_TLV, ROUTE64_TLV, SOURCE_ADDRESS_TLV, ACTIVE_TIMESTAMP_TLV, ADDRESS16_TLV, NETWORK_DATA_TLV, ADDRESS_REGISTRATION_TLV, LINK_LOCAL_ALL_NODES_MULTICAST_ADDRESS
from pktverify.packet_verifier import PacketVerifier
from pktverify.addrs import Ipv6Addr
LEADER = 1
ROUTER = 2
ED1 = 3
SED1 = 4
MTDS = [ED1, SED1]
class Cert_5_6_5_NetworkDataRegisterAfterAttachRouter(thread_cert.TestCase):
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER, ED1, SED1]
},
ROUTER: {
'name': 'ROUTER',
'mode': 'rdn',
'allowlist': [LEADER]
},
ED1: {
'name': 'MED',
'is_mtd': True,
'mode': 'rn',
'allowlist': [LEADER]
},
SED1: {
'name': 'SED',
'is_mtd': True,
'mode': '-',
'timeout': config.DEFAULT_CHILD_TIMEOUT,
'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.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[ROUTER].add_prefix('2001:2:0:1::/64', 'paros')
self.nodes[ROUTER].add_prefix('2001:2:0:2::/64', 'paro')
self.nodes[ROUTER].add_prefix('2001:2:0:3::/64', 'paos')
self.nodes[ROUTER].register_netdata()
# Set lowpan context of sniffer
self.simulator.set_lowpan_context(1, '2001:2:0:1::/64')
self.simulator.set_lowpan_context(2, '2001:2:0:2::/64')
self.simulator.set_lowpan_context(3, '2001:2:0:3::/64')
self.simulator.go(10)
addrs = self.nodes[ED1].get_addrs()
self.assertTrue(any('2001:2:0:1' in addr[0:10] for addr in addrs))
self.assertTrue(any('2001:2:0:2' in addr[0:10] for addr in addrs))
self.assertTrue(any('2001:2:0:3' in addr[0:10] for addr in addrs))
for addr in addrs:
if addr[0:3] == '200':
self.assertTrue(self.nodes[LEADER].ping(addr))
addrs = self.nodes[SED1].get_addrs()
self.assertTrue(any('2001:2:0:1' in addr[0:10] for addr in addrs))
self.assertFalse(any('2001:2:0:2' in addr[0:10] for addr in addrs))
self.assertTrue(any('2001:2:0:3' in addr[0:10] for addr in addrs))
for addr in addrs:
if addr[0:3] == '200':
self.assertTrue(self.nodes[LEADER].ping(addr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
MED = pv.vars['MED']
SED = pv.vars['SED']
_lpkts = pkts.filter_wpan_src64(LEADER)
# Step 1: Ensure the topology is formed correctly
_lpkts.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).filter_wpan_dst64(SED).must_next()
# Step 3: The DUT Automatically sends a CoAP Response frame and
# MLE Data Response message
_lpkts.copy().filter_coap_ack(SVR_DATA_URI).must_next()
_lpkts_med = _lpkts.copy()
_lpkts_sed = _lpkts.copy()
# Step 4: The DUT MUST send a multicast MLE Data Response with
# the new network information collected from Router_1
_lpkts.filter_mle_cmd(MLE_DATA_RESPONSE).filter_ipv6_dst(LINK_LOCAL_ALL_NODES_MULTICAST_ADDRESS).must_next(
).must_verify(lambda p: {Ipv6Addr('2001:2:0:1::'),
Ipv6Addr('2001:2:0:2::'),
Ipv6Addr('2001:2:0:3::')} == set(p.thread_nwd.tlv.prefix) and p.thread_nwd.tlv.
border_router.flag.p == [1, 1, 1] and p.thread_nwd.tlv.border_router.flag.s == [1, 1, 1] and p.
thread_nwd.tlv.border_router.flag.r == [1, 1, 0] and p.thread_nwd.tlv.border_router.flag.o ==
[1, 1, 1] and p.thread_nwd.tlv.stable == [0, 1, 1, 1, 0, 0, 0, 1, 1, 1])
# Step 7: The DUT MUST send a unicast MLE Child Update
# Response to MED_1
_lpkts_med.filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).filter_wpan_dst64(MED).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, MODE_TLV, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV} <= set(p.mle.tlv.type))
# Step 8: The DUT MUST send a unicast MLE Child Update
# Request to SED_1
_lpkts_sed.filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).filter_wpan_dst64(SED).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV} <= set(
p.mle.tlv.type) and {Ipv6Addr('2001:2:0:1::'), Ipv6Addr('2001:2:0:3::')} == set(
p.thread_nwd.tlv.prefix) and p.thread_nwd.tlv.border_router.flag.p == [1, 1] and p.thread_nwd.tlv.
border_router.flag.s == [1, 1] and p.thread_nwd.tlv.border_router.flag.r == [1, 0] and p.thread_nwd.tlv.
border_router.flag.o == [1, 1] and p.thread_nwd.tlv.stable == [1, 1, 1, 1, 1, 1])
# Step 10: The DUT MUST send a unicast MLE Child Update
# Response to SED_1
_lpkts_sed.filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).filter_wpan_dst64(SED).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, MODE_TLV, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV} <= set(p.mle.tlv.type))
if __name__ == '__main__':
unittest.main()
@@ -1,225 +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, SVR_DATA_URI, MLE_DATA_RESPONSE, MLE_CHILD_ID_RESPONSE, MLE_CHILD_UPDATE_REQUEST, MLE_CHILD_UPDATE_RESPONSE, SOURCE_ADDRESS_TLV, MODE_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV, ADDRESS_REGISTRATION_TLV, NWD_COMMISSIONING_DATA_TLV, NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV, LINK_LOCAL_ALL_NODES_MULTICAST_ADDRESS
from pktverify.packet_verifier import PacketVerifier
from pktverify.addrs import Ipv6Addr
LEADER = 1
ROUTER = 2
ED1 = 3
SED1 = 4
MTDS = [ED1, SED1]
class Cert_5_6_6_NetworkDataExpiration(thread_cert.TestCase):
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER, ED1, SED1]
},
ROUTER: {
'name': 'ROUTER',
'mode': 'rdn',
'allowlist': [LEADER]
},
ED1: {
'name': 'MED',
'is_mtd': True,
'mode': 'rn',
'allowlist': [LEADER]
},
SED1: {
'name': 'SED',
'is_mtd': True,
'mode': '-',
'timeout': config.DEFAULT_CHILD_TIMEOUT,
'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.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.nodes[ROUTER].add_prefix('2001:2:0:1::/64', 'paros')
self.nodes[ROUTER].add_prefix('2001:2:0:2::/64', 'paro')
self.nodes[ROUTER].add_prefix('2001:2:0:3::/64', 'paos')
self.nodes[ROUTER].register_netdata()
# Set lowpan context of sniffer
self.simulator.set_lowpan_context(1, '2001:2:0:1::/64')
self.simulator.set_lowpan_context(2, '2001:2:0:2::/64')
self.simulator.set_lowpan_context(3, '2001:2:0:3::/64')
self.simulator.go(10)
addrs = self.nodes[ED1].get_addrs()
self.assertTrue(any('2001:2:0:1' in addr[0:10] for addr in addrs))
self.assertTrue(any('2001:2:0:2' in addr[0:10] for addr in addrs))
self.assertTrue(any('2001:2:0:3' in addr[0:10] for addr in addrs))
for addr in addrs:
if addr[0:3] == '200':
self.assertTrue(self.nodes[LEADER].ping(addr))
addrs = self.nodes[SED1].get_addrs()
self.assertTrue(any('2001:2:0:1' in addr[0:10] for addr in addrs))
self.assertFalse(any('2001:2:0:2' in addr[0:10] for addr in addrs))
self.assertTrue(any('2001:2:0:3' in addr[0:10] for addr in addrs))
for addr in addrs:
if addr[0:3] == '200':
self.assertTrue(self.nodes[LEADER].ping(addr))
self.nodes[ROUTER].remove_prefix('2001:2:0:3::/64')
self.nodes[ROUTER].register_netdata()
self.simulator.go(310)
addrs = self.nodes[ED1].get_addrs()
self.assertTrue(any('2001:2:0:1' in addr[0:10] for addr in addrs))
self.assertTrue(any('2001:2:0:2' in addr[0:10] for addr in addrs))
self.assertFalse(any('2001:2:0:3' in addr[0:10] for addr in addrs))
for addr in addrs:
if addr[0:3] == '200':
self.assertTrue(self.nodes[LEADER].ping(addr))
addrs = self.nodes[SED1].get_addrs()
self.assertTrue(any('2001:2:0:1' in addr[0:10] for addr in addrs))
self.assertFalse(any('2001:2:0:2' in addr[0:10] for addr in addrs))
self.assertFalse(any('2001:2:0:3' in addr[0:10] for addr in addrs))
for addr in addrs:
if addr[0:3] == '200':
self.assertTrue(self.nodes[LEADER].ping(addr))
self.nodes[ROUTER].stop()
self.simulator.go(10)
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']
_lpkts = pkts.filter_wpan_src64(LEADER)
# Step 1: Ensure the topology is formed correctly
_lpkts.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).filter_wpan_dst64(SED).must_next()
# Step 4: The DUT Automatically sends a CoAP Response frame to Router_1
_lpkts.copy().filter_ipv6_dst(pv.vars['ROUTER_RLOC']).filter_coap_ack(SVR_DATA_URI).must_next()
# Step 5: The DUT MUST send a multicast MLE Data Response with
# the new network information collected from Router_1
_lpkts_med = _lpkts.copy()
_lpkts_sed = _lpkts.copy()
_lpkts.filter_LLANMA().filter_mle_cmd(MLE_DATA_RESPONSE).must_next().must_verify(
lambda p: {
NWD_COMMISSIONING_DATA_TLV, NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV, NWD_PREFIX_TLV,
NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV, NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV
} <= set(p.thread_nwd.tlv.type) and {
Ipv6Addr('2001:2:0:1::'), Ipv6Addr('2001:2:0:2::'),
Ipv6Addr('2001:2:0:3::')
} == set(p.thread_nwd.tlv.prefix) and p.thread_nwd.tlv.stable == [0, 1, 1, 1, 0, 0, 0, 1, 1, 1])
# Step 7: The DUT MUST send a unicast MLE Child Update Response to MED_1
_lpkts_med.filter_wpan_dst64(MED).filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, MODE_TLV, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV} <= set(p.mle.tlv.type))
# Step 8: The DUT MUST send a unicast MLE Child Update Request to SED_1
_lpkts_sed.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} <= set(
p.mle.tlv.type) and {
NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV, NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV,
NWD_6LOWPAN_ID_TLV
} <= set(p.thread_nwd.tlv.type) and {
Ipv6Addr('2001:2:0:1::'), Ipv6Addr('2001:2:0:3::')
} == set(p.thread_nwd.tlv.prefix) and {0xFFFE, 0xFFFE} == set(p.thread_nwd.tlv.border_router_16))
# Step 10: The DUT MUST send a unicast MLE Child Update Response to SED_1
_pkt = _lpkts_sed.filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).filter_wpan_dst64(SED).must_next()
_pkt.must_verify(
lambda p: {SOURCE_ADDRESS_TLV, MODE_TLV, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV} <= set(p.mle.tlv.type))
# Step 12: The DUT updates Router ID Set and removes Router_1
# from Network Data TLV after Router_1 power off
# Step 13: The DUT MUST multicast a MLE Data Response with the
# new network information
_lpkts.filter_LLANMA().filter_mle_cmd(MLE_DATA_RESPONSE).filter_ipv6_dst(
LINK_LOCAL_ALL_NODES_MULTICAST_ADDRESS
).must_next().must_verify(
lambda p: {
NWD_COMMISSIONING_DATA_TLV, NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV, NWD_PREFIX_TLV,
NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV, NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV
} <= set(p.thread_nwd.tlv.type) and
{Ipv6Addr('2001:2:0:1::'), Ipv6Addr('2001:2:0:2::'),
Ipv6Addr('2001:2:0:3::')} == set(p.thread_nwd.tlv.prefix) 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)
# Step 15: The DUT MUST send a unicast MLE Child Update Response to MED_1
_lpkts_med.filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).filter_wpan_dst64(MED).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, MODE_TLV, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV} <= set(p.mle.tlv.type)
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)
# Step 16: The DUT MUST send a unicast MLE Child Update Request to SED_1
_lpkts_sed.filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).filter_wpan_dst64(SED).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV} <= set(
p.mle.tlv.type) 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)
# Step 18: The DUT MUST send a unicast MLE Child Update Response to SED_1
_lpkts_sed.filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).filter_wpan_dst64(SED).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, MODE_TLV, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV} <= set(p.mle.tlv.type))
if __name__ == '__main__':
unittest.main()
@@ -1,181 +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, MLE_DATA_REQUEST, MLE_DATA_RESPONSE, TLV_REQUEST_TLV, NETWORK_DATA_TLV, SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV
from pktverify.packet_verifier import PacketVerifier
LEADER = 1
ROUTER1 = 2
ROUTER2 = 3
ROUTER3 = 4
ROUTER15 = 16
REED1 = 17
class Cert_5_6_7_NetworkDataRequestREED(thread_cert.TestCase):
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER1, ROUTER2, ROUTER3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, ROUTER15]
},
ROUTER1: {
'name': 'ROUTER_1',
'mode': 'rdn',
'allowlist': [LEADER]
},
ROUTER2: {
'name': 'ROUTER_2',
'mode': 'rdn',
'allowlist': [LEADER, REED1]
},
ROUTER3: {
'mode': 'rdn',
'allowlist': [LEADER]
},
5: {
'mode': 'rdn',
'allowlist': [LEADER]
},
6: {
'mode': 'rdn',
'allowlist': [LEADER]
},
7: {
'mode': 'rdn',
'allowlist': [LEADER]
},
8: {
'mode': 'rdn',
'allowlist': [LEADER]
},
9: {
'mode': 'rdn',
'allowlist': [LEADER]
},
10: {
'mode': 'rdn',
'allowlist': [LEADER]
},
11: {
'mode': 'rdn',
'allowlist': [LEADER]
},
12: {
'mode': 'rdn',
'allowlist': [LEADER]
},
13: {
'mode': 'rdn',
'allowlist': [LEADER]
},
14: {
'mode': 'rdn',
'allowlist': [LEADER]
},
15: {
'mode': 'rdn',
'allowlist': [LEADER]
},
ROUTER15: {
'mode': 'rdn',
'allowlist': [LEADER]
},
REED1: {
'name': 'REED',
'mode': 'rdn',
'allowlist': [ROUTER2]
},
}
def test(self):
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
for i in range(ROUTER1, ROUTER15 + 1):
self.nodes[i].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[i].get_state(), 'router')
self.nodes[REED1].start()
self.simulator.go(5)
self.assertEqual(self.nodes[REED1].get_state(), 'child')
self.nodes[ROUTER2].remove_allowlist(self.nodes[REED1].get_addr64())
self.nodes[REED1].remove_allowlist(self.nodes[ROUTER2].get_addr64())
self.nodes[LEADER].add_prefix('2001:2:0:3::/64', 'paros')
self.nodes[LEADER].register_netdata()
# Set lowpan context of sniffer
self.simulator.set_lowpan_context(1, '2001:2:0:3::/64')
self.simulator.go(2)
self.nodes[ROUTER2].add_allowlist(self.nodes[REED1].get_addr64())
self.nodes[REED1].add_allowlist(self.nodes[ROUTER2].get_addr64())
self.simulator.go(30)
self.simulator.go(600)
addrs = self.nodes[REED1].get_addrs()
self.assertTrue(any('2001:2:0:3' in addr[0:10] for addr in addrs))
for addr in addrs:
if addr[0:10] == '2001:2:0:3':
self.assertTrue(self.nodes[LEADER].ping(addr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
REED = pv.vars['REED']
# Step 4: Leader multicasts a MLE Data Response with the new information
_pkt = pkts.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).filter_wpan_dst64(REED).must_next()
pkts.filter_wpan_src64(LEADER).filter_mle_cmd(MLE_DATA_RESPONSE).must_next().must_verify(
lambda p: {NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV} <= set(p.thread_nwd.tlv.type))
# Step 8: REED1 MUST send a MLE Data Request to its parent to get the new Network Dataset.
# MLE Data Request includes a TLV Request TLV for Network Data TLV
pkts.filter_wpan_src64(REED).filter_mle_cmd(MLE_DATA_REQUEST).must_next().must_verify(
lambda p: {TLV_REQUEST_TLV, NETWORK_DATA_TLV} <= set(p.mle.tlv.type))
# Step 10: REED1 send MLE Advertisement
pkts.filter_wpan_src64(REED).filter_mle_cmd(MLE_ADVERTISEMENT).must_next().must_verify(
lambda p: p.mle.tlv.leader_data.data_version == (_pkt.mle.tlv.leader_data.data_version + 1) % 256)
if __name__ == '__main__':
unittest.main()
@@ -1,226 +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_DATA_RESPONSE, MLE_CHILD_ID_RESPONSE, MLE_CHILD_UPDATE_REQUEST, MLE_CHILD_UPDATE_RESPONSE, SOURCE_ADDRESS_TLV, MODE_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV, ADDRESS_REGISTRATION_TLV, NWD_COMMISSIONING_DATA_TLV, NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV, NWD_HAS_ROUTER_TLV, LINK_LOCAL_ALL_NODES_MULTICAST_ADDRESS
from pktverify.packet_verifier import PacketVerifier
from pktverify.addrs import Ipv6Addr
LEADER = 1
ROUTER1 = 2
ROUTER2 = 3
ED = 4
SED = 5
MTDS = [ED, SED]
class Cert_5_6_9_NetworkDataForwarding(thread_cert.TestCase):
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER1, ROUTER2]
},
ROUTER1: {
'name': 'ROUTER_1',
'mode': 'rdn',
'allowlist': [LEADER, ED, SED]
},
ROUTER2: {
'name': 'ROUTER_2',
'mode': 'rdn',
'allowlist': [LEADER]
},
ED: {
'name': 'MED',
'is_mtd': True,
'mode': 'rn',
'allowlist': [ROUTER1]
},
SED: {
'name': 'SED',
'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[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[ED].start()
self.simulator.go(5)
self.assertEqual(self.nodes[ED].get_state(), 'child')
self.nodes[SED].start()
self.simulator.go(5)
self.assertEqual(self.nodes[SED].get_state(), 'child')
self.collect_rloc16s()
self.collect_ipaddrs()
self.nodes[LEADER].add_prefix('2001:2:0:1::/64', 'aros', 'med')
self.nodes[LEADER].add_route('2001:2:0:2::/64', stable=True, prf='med')
self.nodes[LEADER].register_netdata()
# Set lowpan context of sniffer
self.simulator.set_lowpan_context(1, '2001:2:0:1::/64')
self.simulator.go(10)
self.nodes[ROUTER2].add_prefix('2001:2:0:1::/64', 'aos', 'med')
self.nodes[ROUTER2].add_route('2001:2:0:2::/64', stable=True, prf='high')
self.nodes[ROUTER2].register_netdata()
self.simulator.go(15)
self.assertFalse(self.nodes[SED].ping('2001:2:0:2::1', timeout=10))
self.assertFalse(self.nodes[SED].ping('2007::1', timeout=10))
self.nodes[ROUTER2].remove_prefix('2001:2:0:1::/64')
self.nodes[ROUTER2].add_prefix('2001:2:0:1::/64', 'paros', 'high')
self.nodes[ROUTER2].register_netdata()
self.simulator.go(15)
self.assertFalse(self.nodes[SED].ping('2007::1', timeout=10))
self.nodes[ROUTER2].remove_prefix('2001:2:0:1::/64')
self.nodes[ROUTER2].add_prefix('2001:2:0:1::/64', 'paros', 'med')
self.nodes[ROUTER2].register_netdata()
self.simulator.go(15)
self.assertFalse(self.nodes[SED].ping('2007::1', timeout=10))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
ROUTER_1 = pv.vars['ROUTER_1']
MED = pv.vars['MED']
SED = pv.vars['SED']
_rpkts = pkts.filter_wpan_src64(ROUTER_1)
# Step 1: Ensure the topology is formed correctly
_rpkts.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).filter_wpan_dst64(SED).must_next()
# Step 4: The DUT MUST send a multicast MLE Data Response with
# the new network information
_rpkts.filter_mle_cmd(MLE_DATA_RESPONSE).filter_ipv6_dst(LINK_LOCAL_ALL_NODES_MULTICAST_ADDRESS).must_next(
).must_verify(lambda p: {Ipv6Addr('2001:2:0:1::'), Ipv6Addr('2001:2:0:2::')} == set(
p.thread_nwd.tlv.prefix) and p.thread_nwd.tlv.border_router.flag.p == [0] and p.thread_nwd.tlv.
border_router.flag.s == [1] and p.thread_nwd.tlv.border_router.flag.r == [1] and p.thread_nwd.tlv
.border_router.flag.o == [1] and p.thread_nwd.tlv.stable == [0, 1, 1, 1, 1, 1])
# Step 5: The DUT MUST send a unicast MLE Child Update
# Request to SED_1
_rpkts.filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).filter_wpan_dst64(SED).must_next(
).must_verify(lambda p: {SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV} <= set(
p.mle.tlv.type
) and {NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV, NWD_PREFIX_TLV, NWD_HAS_ROUTER_TLV} <= set(
p.thread_nwd.tlv.type) and {Ipv6Addr('2001:2:0:1::'), Ipv6Addr('2001:2:0:2::')} == set(
p.thread_nwd.tlv.prefix) and {0xFFFE, 0xFFFE} == set(p.thread_nwd.tlv.border_router_16))
# Step 6: The DUT MUST forward the SED_1 ICMPv6 Echo Request to Router_2
# due to higher preference
router1_rloc16 = pv.vars['ROUTER_1_RLOC16']
leader_rloc16 = pv.vars['LEADER_RLOC16']
_rpkts.filter_ping_request().filter_ipv6_dst('2001:2:0:2::1').must_next().must_verify(
lambda p: p.wpan.dst16 == leader_rloc16 and p.wpan.src16 == router1_rloc16)
# Step 7: The DUT MUST forward the MED_1 ICMPv6 Echo Request to the
# Leader due to default route
_rpkts.filter_ping_request().filter_ipv6_dst('2007::1').must_next().must_verify(
lambda p: p.wpan.dst16 == leader_rloc16 and p.wpan.src16 == router1_rloc16)
# Step 9: The DUT MUST send a multicast MLE Data Response with
# the new network information
_rpkts.filter_mle_cmd(MLE_DATA_RESPONSE).filter_ipv6_dst(
LINK_LOCAL_ALL_NODES_MULTICAST_ADDRESS).must_next().must_verify(
lambda p: {
NWD_COMMISSIONING_DATA_TLV, NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV,
NWD_PREFIX_TLV, NWD_HAS_ROUTER_TLV
} <= set(p.thread_nwd.tlv.type) and {
Ipv6Addr('2001:2:0:1::'), Ipv6Addr('2001:2:0:2::')
} == set(p.thread_nwd.tlv.prefix) and p.thread_nwd.tlv.border_router.flag.p == [0, 1] and p.thread_nwd.
tlv.border_router.flag.s == [1, 1] and p.thread_nwd.tlv.border_router.flag.r == [1, 1] and p.thread_nwd
.tlv.border_router.flag.o == [1, 1] and p.thread_nwd.tlv.stable == [0, 1, 1, 1, 1, 1])
# Step 10: The DUT MUST send a unicast MLE Child Update Request to SED_1
_rpkts.filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).filter_wpan_dst64(SED).must_next(
).must_verify(lambda p: {SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV} <= set(
p.mle.tlv.type
) and {NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV, NWD_PREFIX_TLV, NWD_HAS_ROUTER_TLV} <= set(
p.thread_nwd.tlv.type) and {Ipv6Addr('2001:2:0:1::'), Ipv6Addr('2001:2:0:2::')} == set(
p.thread_nwd.tlv.prefix) and {0xFFFE, 0xFFFE} == set(p.thread_nwd.tlv.border_router_16))
# Step 11: The DUT MUST forward the SED_1 ICMPv6 Echo Request to Router_2
# due to higher preference
_rpkts.filter_ping_request().filter_ipv6_dst('2007::1').must_next().must_verify(
lambda p: p.wpan.dst16 == leader_rloc16 and p.wpan.src16 == router1_rloc16)
# Step 13: The DUT MUST send a multicast MLE Data Response with
# the new network information
_rpkts.filter_mle_cmd(MLE_DATA_RESPONSE).filter_ipv6_dst(
LINK_LOCAL_ALL_NODES_MULTICAST_ADDRESS).must_next().must_verify(
lambda p: {
NWD_COMMISSIONING_DATA_TLV, NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV,
NWD_PREFIX_TLV, NWD_HAS_ROUTER_TLV
} <= set(p.thread_nwd.tlv.type) and {Ipv6Addr('2001:2:0:1::'),
Ipv6Addr('2001:2:0:2::')} == set(p.thread_nwd.tlv.prefix))
# Step 14: The DUT MUST send a unicast MLE Child Update Request to SED_1
_rpkts.filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).filter_wpan_dst64(SED).must_next(
).must_verify(lambda p: {SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV} <= set(
p.mle.tlv.type
) and {NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV, NWD_PREFIX_TLV, NWD_HAS_ROUTER_TLV} <= set(
p.thread_nwd.tlv.type) and {Ipv6Addr('2001:2:0:1::'), Ipv6Addr('2001:2:0:2::')} == set(
p.thread_nwd.tlv.prefix) and {0xFFFE, 0xFFFE} == set(p.thread_nwd.tlv.border_router_16))
# Step 15: The DUT MUST forward the SED_1 ICMPv6 Echo Request to Router_2
# due to higher preference
_rpkts.filter_ping_request().filter_ipv6_dst('2007::1').must_next().must_verify(
lambda p: p.wpan.dst16 == leader_rloc16 and p.wpan.src16 == router1_rloc16)
if __name__ == '__main__':
unittest.main()
@@ -1,420 +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 copy
import mle
import network_diag
import network_layer
import thread_cert
from network_diag import TlvType
from pktverify.consts import DIAG_RST_URI, DIAG_GET_URI, DG_MAC_EXTENDED_ADDRESS_TLV, DG_MAC_ADDRESS_TLV, DG_MODE_TLV, DG_CONNECTIVITY_TLV, DG_ROUTE64_TLV, DG_LEADER_DATA_TLV, DG_NETWORK_DATA_TLV, DG_IPV6_ADDRESS_LIST_TLV, DG_CHANNEL_PAGES_TLV, DG_TYPE_LIST_TLV, DG_MAC_COUNTERS_TLV, DG_TIMEOUT_TLV, DG_BATTERY_LEVEL_TLV, DG_SUPPLY_VOLTAGE_TLV, DG_CHILD_TABLE_TLV
from pktverify.packet_verifier import PacketVerifier
from pktverify.null_field import nullField
LEADER = 1
ROUTER1 = 2
REED1 = 3
SED1 = 4
MED1 = 5
FED1 = 6
MTDS = [MED1, SED1]
# Test Purpose and Description:
# -----------------------------
# These cases test the Diagnostic Get and Reset Commands as a part of the
# Network Management
#
# Test Topology:
# -------------
# Leader
# |
# FED - Router - REED
# / \
# MED SED
#
# DUT Types:
# ----------
# Router
# FED
class Cert_5_7_01_CoapDiagCommands_Base(thread_cert.TestCase):
USE_MESSAGE_FACTORY = False
SUPPORT_NCP = False
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER1],
},
ROUTER1: {
'mode': 'rdn',
'allowlist': [LEADER, REED1, SED1, MED1, FED1],
},
REED1: {
'name': 'REED',
'mode': 'rdn',
'allowlist': [ROUTER1],
'router_upgrade_threshold': 0
},
SED1: {
'name': 'SED',
'is_mtd': True,
'mode': '-',
'allowlist': [ROUTER1],
'timeout': config.DEFAULT_CHILD_TIMEOUT
},
MED1: {
'name': 'MED',
'is_mtd': True,
'mode': 'rn',
'allowlist': [ROUTER1]
},
FED1: {
'allowlist': [ROUTER1],
'router_upgrade_threshold': 0
},
}
def test(self):
# 1 - Form topology
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER1].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
for i in range(3, 7):
self.nodes[i].start()
self.simulator.go(10)
self.assertEqual(self.nodes[i].get_state(), 'child')
self.simulator.go(config.MAX_ADVERTISEMENT_INTERVAL)
self.collect_rlocs()
self.collect_rloc16s()
self.collect_ipaddrs()
DUT = ROUTER1
if self.TOPOLOGY[FED1]['name'] == 'DUT':
DUT = FED1
dut_rloc = self.nodes[DUT].get_ip6_address(config.ADDRESS_TYPE.RLOC)
# 2 - Leader sends DIAG_GET.req
tlv_types = [
TlvType.EXT_ADDRESS, TlvType.ADDRESS16, TlvType.MODE, TlvType.CONNECTIVITY, TlvType.ROUTE64,
TlvType.LEADER_DATA, TlvType.NETWORK_DATA, TlvType.IPV6_ADDRESS_LIST, TlvType.CHANNEL_PAGES
]
self.nodes[LEADER].send_network_diag_get(dut_rloc, tlv_types)
self.simulator.go(2)
# 3 - Leader sends DIAG_GET.req (MAC Counters TLV type included)
self.nodes[LEADER].send_network_diag_get(dut_rloc, [TlvType.MAC_COUNTERS])
self.simulator.go(2)
# 4 - Leader sends DIAG_GET.req (Timeout/Polling Period TLV type included)
self.nodes[LEADER].send_network_diag_get(dut_rloc, [TlvType.POLLING_PERIOD])
self.simulator.go(2)
# 5 - Leader sends DIAG_GET.req (Battery Level and Supply Voltage TLV types included)
self.nodes[LEADER].send_network_diag_get(dut_rloc, [TlvType.BATTERY_LEVEL, TlvType.SUPPLY_VOLTAGE])
self.simulator.go(2)
# 6 - Leader sends DIAG_GET.req (Child Table TLV types included)
self.nodes[LEADER].send_network_diag_get(dut_rloc, [TlvType.CHILD_TABLE])
self.simulator.go(2)
# 7 - Leader sends DIAG_RST.ntf (MAC Counters TLV type included)
self.nodes[LEADER].send_network_diag_reset(dut_rloc, [TlvType.MAC_COUNTERS])
self.simulator.go(2)
# 8 - Leader Sends DIAG_GET.req (MAC Counters TLV type included)
self.nodes[LEADER].send_network_diag_get(dut_rloc, [TlvType.MAC_COUNTERS])
self.simulator.go(2)
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
LEADER_RLOC = pv.vars['LEADER_RLOC']
DUT = pv.vars['DUT']
DUT_RLOC = pv.vars['DUT_RLOC']
DUT_RLOC16 = pv.vars['DUT_RLOC16']
REED = pv.vars['REED']
REED_RLOC = pv.vars['REED_RLOC']
MED = pv.vars['MED']
MED_RLOC = pv.vars['MED_RLOC']
SED = pv.vars['SED']
SED_RLOC = pv.vars['SED_RLOC']
MM = pv.vars['MM_PORT']
#DUT_IPADDR =
# Step 1: Ensure topology is formed correctly
if self.TOPOLOGY[ROUTER1]['name'] == 'DUT':
FED = pv.vars['FED']
pv.verify_attached('DUT', 'LEADER')
pv.verify_attached('REED', 'DUT')
pv.verify_attached('SED', 'DUT', 'MTD')
pv.verify_attached('MED', 'DUT', 'MTD')
pv.verify_attached('FED', 'DUT', 'FTD-ED')
else:
ROUTER = pv.vars['ROUTER']
pv.verify_attached('ROUTER', 'LEADER')
pv.verify_attached('REED', 'ROUTER')
pv.verify_attached('SED', 'ROUTER', 'MTD')
pv.verify_attached('MED', 'ROUTER', 'MTD')
pv.verify_attached('DUT', 'ROUTER', 'FTD-ED')
# Step 2: Leader to send DIAG_GET.req to DUTs RLOC.
# The DUT MUST respond with a DIAG_GET.rsp response containing
# the requested diagnostic TLVs:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# TLV Type 0 - MAC Extended Address (64- bit)
# TLV Type 1 - MAC Address (16-bit)
# TLV Type 2 - Mode (Capability information)
# TLV Type 4 Connectivity
# TLV Type 5 Route64
# TLV Type 6 Leader Data
# TLV Type 7 Network Data
# TLV Type 8 IPv6 address list
# TLV Type 17 Channel Pages
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(DUT_RLOC).\
filter_coap_request(DIAG_GET_URI).\
filter(lambda p: {
DG_TYPE_LIST_TLV,
DG_MAC_EXTENDED_ADDRESS_TLV,
DG_MAC_ADDRESS_TLV,
DG_MODE_TLV,
DG_CONNECTIVITY_TLV,
DG_ROUTE64_TLV,
DG_LEADER_DATA_TLV,
DG_NETWORK_DATA_TLV,
DG_IPV6_ADDRESS_LIST_TLV,
DG_CHANNEL_PAGES_TLV
} <= set(p.thread_diagnostic.tlv.type)
).\
must_next()
pkts.filter_wpan_src64(DUT).\
filter_ipv6_dst(LEADER_RLOC).\
filter_coap_ack(DIAG_GET_URI).\
filter(lambda p: {
DG_MAC_EXTENDED_ADDRESS_TLV,
DG_MAC_ADDRESS_TLV,
DG_MODE_TLV,
DG_CONNECTIVITY_TLV,
DG_ROUTE64_TLV,
DG_LEADER_DATA_TLV,
DG_NETWORK_DATA_TLV,
DG_IPV6_ADDRESS_LIST_TLV,
DG_CHANNEL_PAGES_TLV
} <= set(p.thread_diagnostic.tlv.type)
).\
must_next()
# Step 3: Leader to send DIAG_GET.req to DUTs RLOC.
# The DUT MUST respond with a DIAG_GET.rsp response containing
# the requested diagnostic TLVs:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# TLV Type 9 - MAC Counters
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(DUT_RLOC).\
filter_coap_request(DIAG_GET_URI).\
filter(lambda p: {
DG_TYPE_LIST_TLV,
DG_MAC_COUNTERS_TLV
} <= set(p.thread_diagnostic.tlv.type)
).\
must_next()
pkts.filter_wpan_src64(DUT).\
filter_ipv6_dst(LEADER_RLOC).\
filter_coap_ack(DIAG_GET_URI).\
filter(lambda p: {
DG_MAC_COUNTERS_TLV
} <= set(p.thread_diagnostic.tlv.type)
).\
must_next()
# Step 4: Leader to send DIAG_GET.req to DUTs RLOC.
# The DUT MUST respond with a DIAG_GET.rsp response containing
# the requested diagnostic TLVs:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# TLV Type 3 - Timeout MUST be omitted from the response
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(DUT_RLOC).\
filter_coap_request(DIAG_GET_URI).\
filter(lambda p: {
DG_TYPE_LIST_TLV,
DG_TIMEOUT_TLV
} <= set(p.thread_diagnostic.tlv.type)
).\
must_next()
pkts.filter_wpan_src64(DUT).\
filter_ipv6_dst(LEADER_RLOC).\
filter_coap_ack(DIAG_GET_URI).\
filter(lambda p: p.thread_diagnostic.tlv.type is nullField).\
must_next()
# Step 5: Leader to send DIAG_GET.req to DUTs RLOC.
# The DUT MUST respond with a DIAG_GET.rsp response containing
# the requested diagnostic TLVs:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# TLV Type 3 - Timeout MUST be omitted from the response
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(DUT_RLOC).\
filter_coap_request(DIAG_GET_URI).\
filter(lambda p: {
DG_TYPE_LIST_TLV,
DG_BATTERY_LEVEL_TLV,
DG_SUPPLY_VOLTAGE_TLV
} <= set(p.thread_diagnostic.tlv.type)
).\
must_next()
pkts.filter_wpan_src64(DUT).\
filter_ipv6_dst(LEADER_RLOC).\
filter_coap_ack(DIAG_GET_URI).\
filter(lambda p: p.thread_diagnostic.tlv.type is nullField).\
must_next()
# Step 6: Leader to send DIAG_GET.req to DUTs RLOC.
# The DUT MUST respond with a DIAG_GET.rsp response containing
# the requested diagnostic TLVs:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# TLV Type 16 - Child Table (is empty if FED is DUT)
#
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(DUT_RLOC).\
filter_coap_request(DIAG_GET_URI).\
filter(lambda p: {
DG_TYPE_LIST_TLV,
DG_CHILD_TABLE_TLV
} <= set(p.thread_diagnostic.tlv.type)
).\
must_next()
if self.TOPOLOGY[ROUTER1]['name'] == 'DUT':
_pkt = pkts.filter_wpan_src64(DUT).\
filter_ipv6_dst(LEADER_RLOC).\
filter_coap_ack(DIAG_GET_URI).\
filter(lambda p: {
DG_CHILD_TABLE_TLV
} <= set(p.thread_diagnostic.tlv.type)
).\
must_next()
else:
pkts.filter_wpan_src64(DUT).\
filter_ipv6_dst(LEADER_RLOC).\
filter_coap_ack(DIAG_GET_URI).\
filter(lambda p: p.thread_diagnostic.tlv.type is nullField).\
must_next()
# Step 7: Leader to send DIAG_RST.req to DUTs RLOC for the following diagnostic
# TLV type:
# TLV Type 9 - MAC Counters
# The DUT MUST respond with a CoAP response
# CoAP Response Code
# 2.04 Changed
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(DUT_RLOC).\
filter_coap_request(DIAG_RST_URI).\
filter(lambda p: {
DG_TYPE_LIST_TLV,
DG_MAC_COUNTERS_TLV
} <= set(p.thread_diagnostic.tlv.type)
).\
must_next()
pkts.filter_wpan_src64(DUT).\
filter_ipv6_dst(LEADER_RLOC).\
filter_coap_ack(DIAG_RST_URI).\
must_next()
# Step 8: Leader to send DIAG_GET.req to DUTs RLOC.
# The DUT MUST respond with a DIAG_GET.rsp response containing
# the requested diagnostic TLVs:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# TLV Type 9 - MAC Counters
# TLV Type 9 - MAC Counters MUST contain a list of MAC Counters
# with 0 value or less than value returned in step 3.
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(DUT_RLOC).\
filter_coap_request(DIAG_GET_URI).\
filter(lambda p: {
DG_TYPE_LIST_TLV,
DG_MAC_COUNTERS_TLV
} <= set(p.thread_diagnostic.tlv.type)
).\
must_next()
pkts.filter_wpan_src64(DUT).\
filter_ipv6_dst(LEADER_RLOC).\
filter_coap_ack(DIAG_GET_URI).\
filter(lambda p: {
DG_MAC_COUNTERS_TLV
} <= set(p.thread_diagnostic.tlv.type)
).\
must_next()
class Cert_5_7_01_CoapDiagCommands_Base_ROUTER(Cert_5_7_01_CoapDiagCommands_Base):
TOPOLOGY = copy.deepcopy(Cert_5_7_01_CoapDiagCommands_Base.TOPOLOGY)
TOPOLOGY[ROUTER1]['name'] = 'DUT'
TOPOLOGY[FED1]['name'] = 'FED'
class Cert_5_7_01_CoapDiagCommands_Base_FED(Cert_5_7_01_CoapDiagCommands_Base):
TOPOLOGY = copy.deepcopy(Cert_5_7_01_CoapDiagCommands_Base.TOPOLOGY)
TOPOLOGY[ROUTER1]['name'] = 'ROUTER'
TOPOLOGY[FED1]['name'] = 'DUT'
del (Cert_5_7_01_CoapDiagCommands_Base)
if __name__ == '__main__':
unittest.main()
@@ -1,421 +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 copy
import mle
import network_diag
import network_layer
import thread_cert
from network_diag import TlvType
from pktverify.consts import DIAG_RST_URI, DIAG_GET_URI, DIAG_GET_QRY_URI, DIAG_GET_ANS_URI, DG_MAC_EXTENDED_ADDRESS_TLV, DG_MAC_ADDRESS_TLV, DG_MODE_TLV, DG_CONNECTIVITY_TLV, DG_ROUTE64_TLV, DG_LEADER_DATA_TLV, DG_NETWORK_DATA_TLV, DG_IPV6_ADDRESS_LIST_TLV, DG_CHANNEL_PAGES_TLV, DG_TYPE_LIST_TLV, DG_MAC_COUNTERS_TLV, DG_TIMEOUT_TLV, DG_BATTERY_LEVEL_TLV, DG_SUPPLY_VOLTAGE_TLV, DG_CHILD_TABLE_TLV, REALM_LOCAL_ALL_THREAD_NODES_MULTICAST_ADDRESS
from pktverify.packet_verifier import PacketVerifier
from pktverify.null_field import nullField
from pktverify.utils import colon_hex
LEADER = 1
ROUTER15 = 16
REED = 17
# Test Purpose and Description:
# -----------------------------
# This test case exercises the Diagnostic Get Query and Answer commands
# as part of the Network Management. This test case topology is specific
# to REED DUTs.
#
# Test Topology:
# -------------
# Leader
# / \
# Router1 .. Router15
# |
# REED
#
# DUT Types:
# ----------
# REED
class Cert_5_7_02_CoapDiagCommands(thread_cert.TestCase):
USE_MESSAGE_FACTORY = False
SUPPORT_NCP = False
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, ROUTER15]
},
2: {
'name': 'ROUTER_1',
'mode': 'rdn',
'allowlist': [LEADER]
},
3: {
'name': 'ROUTER_2',
'mode': 'rdn',
'allowlist': [LEADER]
},
4: {
'name': 'ROUTER_3',
'mode': 'rdn',
'allowlist': [LEADER]
},
5: {
'name': 'ROUTER_4',
'mode': 'rdn',
'allowlist': [LEADER]
},
6: {
'name': 'ROUTER_5',
'mode': 'rdn',
'allowlist': [LEADER]
},
7: {
'name': 'ROUTER_6',
'mode': 'rdn',
'allowlist': [LEADER]
},
8: {
'name': 'ROUTER_7',
'mode': 'rdn',
'allowlist': [LEADER]
},
9: {
'name': 'ROUTER_8',
'mode': 'rdn',
'allowlist': [LEADER]
},
10: {
'name': 'ROUTER_9',
'mode': 'rdn',
'allowlist': [LEADER]
},
11: {
'name': 'ROUTER_10',
'mode': 'rdn',
'allowlist': [LEADER]
},
12: {
'name': 'ROUTER_11',
'mode': 'rdn',
'allowlist': [LEADER]
},
13: {
'name': 'ROUTER_12',
'mode': 'rdn',
'allowlist': [LEADER]
},
14: {
'name': 'ROUTER_13',
'mode': 'rdn',
'allowlist': [LEADER]
},
15: {
'name': 'ROUTER_14',
'mode': 'rdn',
'allowlist': [LEADER]
},
ROUTER15: {
'name': 'ROUTER_15',
'mode': 'rdn',
'allowlist': [LEADER, REED]
},
REED: {
'name': 'DUT',
'mode': 'rdn',
'allowlist': [ROUTER15]
},
}
def test(self):
# 1 - Form topology
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
for i in range(2, 17):
self.nodes[i].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[i].get_state(), 'router')
self.nodes[REED].start()
self.simulator.go(5)
self.assertEqual(self.nodes[REED].get_state(), 'child')
self.simulator.go(config.MAX_ADVERTISEMENT_INTERVAL)
self.collect_rlocs()
self.collect_rloc16s()
dut_rloc = self.nodes[REED].get_ip6_address(config.ADDRESS_TYPE.RLOC)
# 2 - Leader sends DIAG_GET.req
tlv_types = [
TlvType.EXT_ADDRESS, TlvType.ADDRESS16, TlvType.MODE, TlvType.CONNECTIVITY, TlvType.ROUTE64,
TlvType.LEADER_DATA, TlvType.IPV6_ADDRESS_LIST, TlvType.CHANNEL_PAGES
]
self.nodes[LEADER].send_network_diag_get(dut_rloc, tlv_types)
self.simulator.go(2)
# 3 - Leader sends DIAG_GET.req (MAC Counters TLV type included)
self.nodes[LEADER].send_network_diag_get(dut_rloc, [TlvType.MAC_COUNTERS])
self.simulator.go(2)
# 4 - Leader sends DIAG_GET.req (Timeout/Polling Period TLV type included)
self.nodes[LEADER].send_network_diag_get(dut_rloc, [TlvType.POLLING_PERIOD, TlvType.CHILD_TABLE])
self.simulator.go(2)
# 5 - Leader sends DIAG_GET.req (Battery Level and Supply Voltage TLV types included)
self.nodes[LEADER].send_network_diag_get(dut_rloc, [TlvType.BATTERY_LEVEL, TlvType.SUPPLY_VOLTAGE])
self.simulator.go(20)
# 6 - Leader sends DIAG_RST.ntf (MAC Counters TLV type included)
self.nodes[LEADER].send_network_diag_reset(dut_rloc, [TlvType.MAC_COUNTERS])
self.simulator.go(2)
# 7 - Leader Sends DIAG_GET.req (MAC Counters TLV type included)
self.nodes[LEADER].send_network_diag_get(dut_rloc, [TlvType.MAC_COUNTERS])
self.simulator.go(2)
# 8 - Leader sends DIAG_GET.query
self.nodes[LEADER].send_network_diag_get(REALM_LOCAL_ALL_THREAD_NODES_MULTICAST_ADDRESS, tlv_types)
self.simulator.go(2)
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
LEADER_RLOC = pv.vars['LEADER_RLOC']
DUT = pv.vars['DUT']
DUT_RLOC = pv.vars['DUT_RLOC']
DUT_RLOC16 = pv.vars['DUT_RLOC16']
MM = pv.vars['MM_PORT']
dut_addr16 = "%04x" % DUT_RLOC16
dut_payload_tlvs = {
DG_TYPE_LIST_TLV, DG_MAC_EXTENDED_ADDRESS_TLV, DG_MAC_ADDRESS_TLV, DG_MODE_TLV, DG_CONNECTIVITY_TLV,
DG_ROUTE64_TLV, DG_LEADER_DATA_TLV, DG_IPV6_ADDRESS_LIST_TLV, DG_CHANNEL_PAGES_TLV
}
# Step 1: Ensure topology is formed correctly
for i in range(1, 16):
with pkts.save_index():
pv.verify_attached('ROUTER_%d' % i, 'LEADER')
pv.verify_attached('DUT', 'ROUTER_15')
# Step 2: Leader to send DIAG_GET.req to DUTs RLOC.
# The DUT MUST respond with a DIAG_GET.rsp response containing
# the requested diagnostic TLVs:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# TLV Type 0 - MAC Extended Address (64- bit)
# TLV Type 1 - MAC Address (16-bit)
# TLV Type 2 - Mode (Capability information)
# TLV Type 4 Connectivity
# TLV Type 5 Route64(optional)
# TLV Type 6 Leader Data
# TLV Type 8 IPv6 address list
# TLV Type 17 Channel Pages
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(DUT_RLOC).\
filter_coap_request(DIAG_GET_URI).\
filter(lambda p: dut_payload_tlvs <= set(p.thread_diagnostic.tlv.type)).\
must_next()
dut_payload_tlvs.remove(DG_TYPE_LIST_TLV)
dut_payload_tlvs.remove(DG_ROUTE64_TLV)
pkts.filter_wpan_src64(DUT).\
filter_ipv6_dst(LEADER_RLOC).\
filter_coap_ack(DIAG_GET_URI).\
filter(lambda p:
dut_payload_tlvs <= set(p.thread_diagnostic.tlv.type) and\
{str(p.wpan.src64), colon_hex(dut_addr16, 2), '0f'}
< set(p.thread_diagnostic.tlv.general)
).\
must_next()
# Step 3: Leader to send DIAG_GET.req to DUTs RLOC.
# The DUT MUST respond with a DIAG_GET.rsp response containing
# the requested diagnostic TLVs:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# TLV Type 9 - MAC Counters
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(DUT_RLOC).\
filter_coap_request(DIAG_GET_URI).\
filter(lambda p: {
DG_TYPE_LIST_TLV,
DG_MAC_COUNTERS_TLV
} <= set(p.thread_diagnostic.tlv.type)
).\
must_next()
pkts.filter_wpan_src64(DUT).\
filter_ipv6_dst(LEADER_RLOC).\
filter_coap_ack(DIAG_GET_URI).\
filter(lambda p: {
DG_MAC_COUNTERS_TLV
} <= set(p.thread_diagnostic.tlv.type)
).\
must_next()
# Step 4: Leader to send DIAG_GET.req to DUTs RLOC.
# The DUT MUST respond with a DIAG_GET.rsp response containing
# the requested diagnostic TLVs:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# TLV Type 3 - Timeout MUST be omitted from the response
# TLV Type 16 Child Table TLV
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(DUT_RLOC).\
filter_coap_request(DIAG_GET_URI).\
filter(lambda p: {
DG_TYPE_LIST_TLV,
DG_TIMEOUT_TLV,
DG_CHILD_TABLE_TLV
} <= set(p.thread_diagnostic.tlv.type)
).\
must_next()
pkts.filter_wpan_src64(DUT).\
filter_ipv6_dst(LEADER_RLOC).\
filter_coap_ack(DIAG_GET_URI).\
must_next()
# Step 5: Leader to send DIAG_GET.req to DUTs RLOC.
# The DUT MUST respond with a DIAG_GET.rsp response containing
# the requested diagnostic TLVs:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# TLV Type 14 Battery Level (optional)
# TLV Type 15 Supply Voltage (optional)
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(DUT_RLOC).\
filter_coap_request(DIAG_GET_URI).\
filter(lambda p: {
DG_TYPE_LIST_TLV,
DG_BATTERY_LEVEL_TLV,
DG_SUPPLY_VOLTAGE_TLV
} <= set(p.thread_diagnostic.tlv.type)
).\
must_next()
pkts.filter_wpan_src64(DUT).\
filter_ipv6_dst(LEADER_RLOC).\
filter_coap_ack(DIAG_GET_URI).\
must_next()
# Step 6: Leader to send DIAG_RST.req to DUTs RLOC for the following diagnostic
# TLV type:
# TLV Type 9 - MAC Counters
# The DUT MUST respond with a CoAP response
# CoAP Response Code
# 2.04 Changed
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(DUT_RLOC).\
filter_coap_request(DIAG_RST_URI).\
filter(lambda p: {
DG_TYPE_LIST_TLV,
DG_MAC_COUNTERS_TLV
} <= set(p.thread_diagnostic.tlv.type)
).\
must_next()
pkts.filter_wpan_src64(DUT).\
filter_ipv6_dst(LEADER_RLOC).\
filter_coap_ack(DIAG_RST_URI).\
must_next()
# Step 7: Leader to send DIAG_GET.req to DUTs RLOC.
# The DUT MUST respond with a DIAG_GET.rsp response containing
# the requested diagnostic TLVs:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# TLV Type 9 - MAC Counters
# TLV Type 9 - MAC Counters MUST contain a list of MAC Counters
# with 0 value or less than value returned in step 3.
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(DUT_RLOC).\
filter_coap_request(DIAG_GET_URI).\
filter(lambda p: {
DG_TYPE_LIST_TLV,
DG_MAC_COUNTERS_TLV
} <= set(p.thread_diagnostic.tlv.type)
).\
must_next()
pkts.filter_wpan_src64(DUT).\
filter_ipv6_dst(LEADER_RLOC).\
filter_coap_ack(DIAG_GET_URI).\
filter(lambda p: {
DG_MAC_COUNTERS_TLV
} <= set(p.thread_diagnostic.tlv.type)
).\
must_next()
# Step 8: Leader sends DIAG_GET.qry to the Realm-Local All-Thread-Nodes
# multicast address containing the requested diagnostic TLVs:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# TLV Type 0 - MAC Extended Address (64- bit)
# TLV Type 1 - MAC Address (16-bit)
# TLV Type 2 - Mode (Capability information)
# TLV Type 4 Connectivity
# TLV Type 5 Route64(optional)
# TLV Type 6 Leader Data
# TLV Type 7 Network Data
# TLV Type 8 IPv6 address list
# TLV Type 17 Channel Pagesi
dut_payload_tlvs.add(DG_TYPE_LIST_TLV)
dut_payload_tlvs.add(DG_ROUTE64_TLV)
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(REALM_LOCAL_ALL_THREAD_NODES_MULTICAST_ADDRESS).\
filter_coap_request(DIAG_GET_QRY_URI).\
filter(lambda p: dut_payload_tlvs <= set(p.thread_diagnostic.tlv.type)).\
must_next()
dut_payload_tlvs.remove(DG_TYPE_LIST_TLV)
dut_payload_tlvs.remove(DG_ROUTE64_TLV)
pkts.filter_wpan_src64(DUT).\
filter_ipv6_dst(LEADER_RLOC).\
filter_coap_request(DIAG_GET_ANS_URI).\
filter(lambda p:
dut_payload_tlvs <= set(p.thread_diagnostic.tlv.type) and\
{str(p.wpan.src64), colon_hex(dut_addr16, 2), '0f'}
< set(p.thread_diagnostic.tlv.general)
).\
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 copy
import mle
import network_diag
import network_layer
import thread_cert
from network_diag import TlvType
from pktverify.consts import DIAG_GET_QRY_URI, DIAG_GET_ANS_URI, DG_MAC_EXTENDED_ADDRESS_TLV, DG_MAC_ADDRESS_TLV, DG_MODE_TLV, DG_CONNECTIVITY_TLV, DG_ROUTE64_TLV, DG_LEADER_DATA_TLV, DG_NETWORK_DATA_TLV, DG_IPV6_ADDRESS_LIST_TLV, DG_CHANNEL_PAGES_TLV, DG_TYPE_LIST_TLV, DG_MAC_COUNTERS_TLV, DG_TIMEOUT_TLV, DG_CHILD_TABLE_TLV, REALM_LOCAL_ALL_THREAD_NODES_MULTICAST_ADDRESS
from pktverify.packet_verifier import PacketVerifier
from pktverify.utils import colon_hex
LEADER = 1
ROUTER1 = 2
SED1 = 3
MED1 = 4
FED1 = 5
MTDS = [MED1, SED1]
# Test Purpose and Description:
# -----------------------------
# The purpose of this test case is to verify functionality of commands
# Diagnostic_Get.query and Diagnostic_Get.ans. Thread Diagnostic commands
# MUST be supported by FTDs.
#
# Test Topology:
# -------------
# Leader
# |
# FED - Router
# / \
# MED SED
#
# DUT Types:
# ----------
# Router
# FED
class Cert_5_7_03_CoapDiagCommands_Base(thread_cert.TestCase):
USE_MESSAGE_FACTORY = False
SUPPORT_NCP = False
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER1],
},
ROUTER1: {
'mode': 'rdn',
'allowlist': [LEADER, SED1, MED1, FED1],
},
SED1: {
'name': 'SED',
'is_mtd': True,
'mode': '-',
'allowlist': [ROUTER1],
'timeout': config.DEFAULT_CHILD_TIMEOUT
},
MED1: {
'name': 'MED',
'is_mtd': True,
'mode': 'rn',
'allowlist': [ROUTER1]
},
FED1: {
'allowlist': [ROUTER1],
'router_upgrade_threshold': 0
},
}
def test(self):
# 1 - Form topology
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER1].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
for i in range(3, 6):
self.nodes[i].start()
self.simulator.go(10)
self.assertEqual(self.nodes[i].get_state(), 'child')
self.simulator.go(config.MAX_ADVERTISEMENT_INTERVAL)
self.collect_rlocs()
self.collect_rloc16s()
tlv_types = [
TlvType.EXT_ADDRESS, TlvType.ADDRESS16, TlvType.MODE, TlvType.CONNECTIVITY, TlvType.ROUTE64,
TlvType.LEADER_DATA, TlvType.NETWORK_DATA, TlvType.IPV6_ADDRESS_LIST, TlvType.CHILD_TABLE,
TlvType.CHANNEL_PAGES
]
if self.TOPOLOGY[FED1]['name'] == 'DUT':
tlv_types = [
TlvType.EXT_ADDRESS, TlvType.ADDRESS16, TlvType.MODE, TlvType.LEADER_DATA, TlvType.NETWORK_DATA,
TlvType.IPV6_ADDRESS_LIST, TlvType.CHANNEL_PAGES
]
# 2 - Leader sends DIAG_GET.query
self.nodes[LEADER].send_network_diag_get(REALM_LOCAL_ALL_THREAD_NODES_MULTICAST_ADDRESS, tlv_types)
self.simulator.go(2)
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
LEADER_RLOC = pv.vars['LEADER_RLOC']
DUT = pv.vars['DUT']
DUT_RLOC16 = pv.vars['DUT_RLOC16']
SED = pv.vars['SED']
dut_addr16 = "%04x" % DUT_RLOC16
# Step 1: Ensure topology is formed correctly
if self.TOPOLOGY[ROUTER1]['name'] == 'DUT':
FED = pv.vars['FED']
pv.verify_attached('DUT', 'LEADER')
pv.verify_attached('SED', 'DUT', 'MTD')
pv.verify_attached('MED', 'DUT', 'MTD')
pv.verify_attached('FED', 'DUT', 'FTD-ED')
else:
ROUTER = pv.vars['ROUTER']
pv.verify_attached('ROUTER', 'LEADER')
pv.verify_attached('SED', 'ROUTER', 'MTD')
pv.verify_attached('MED', 'ROUTER', 'MTD')
pv.verify_attached('DUT', 'ROUTER', 'FTD-ED')
# Step 2: Leader sends DIAG_GET.qry to the Realm-Local All-Thread-Nodes
# multicast address containing the requested diagnostic TLVs:
# CoAP Response Code
# 2.04 Changed
# CoAP Payload
# TLV Type 0 - MAC Extended Address (64- bit)
# TLV Type 1 - MAC Address (16-bit)
# TLV Type 2 - Mode (Capability information)
# TLV Type 6 Leader Data
# TLV Type 7 Network Data
# TLV Type 8 IPv6 address list
# TLV Type 17 Channel Pagesi
#
# if DUT is Router, containing the following as well:
# TLV Type 4 Connectivity
# TLV Type 5 Route64
# TLV Type 16 Child Table
_qr_pkt = pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(REALM_LOCAL_ALL_THREAD_NODES_MULTICAST_ADDRESS).\
filter_coap_request(DIAG_GET_QRY_URI).\
must_next()
dut_payload_tlvs = {
DG_TYPE_LIST_TLV, DG_MAC_EXTENDED_ADDRESS_TLV, DG_MAC_ADDRESS_TLV, DG_MODE_TLV, DG_LEADER_DATA_TLV,
DG_NETWORK_DATA_TLV, DG_IPV6_ADDRESS_LIST_TLV, DG_CHANNEL_PAGES_TLV
}
if self.TOPOLOGY[ROUTER1]['name'] == 'DUT':
dut_payload_tlvs.update({DG_CONNECTIVITY_TLV, DG_ROUTE64_TLV, DG_CHILD_TABLE_TLV})
_qr_pkt.must_verify(lambda p: dut_payload_tlvs <= set(p.thread_diagnostic.tlv.type))
# Step 3: The DUT automatically responds with a DIAG_GET.ans response
# MUST contain the requested diagnostic TLVs:
# TLV Type 0 - MAC Extended Address (64- bit)
# TLV Type 1 - MAC Address (16-bit)
# TLV Type 2 - Mode (Capability information)
# TLV Type 4 Connectivity
# TLV Type 5 Route64
# TLV Type 6 Leader Data
# TLV Type 7 Network Data
# TLV Type 8 IPv6 address list
# TLV Type 16 Child Table
# TLV Type 17 Channel Pages
dut_payload_tlvs.remove(DG_TYPE_LIST_TLV)
pkts.filter_wpan_src64(DUT).\
filter_ipv6_dst(LEADER_RLOC).\
filter_coap_request(DIAG_GET_ANS_URI).\
filter(lambda p:
dut_payload_tlvs <= set(p.thread_diagnostic.tlv.type) and\
{str(p.wpan.src64), colon_hex(dut_addr16, 2), '0f'}
< set(p.thread_diagnostic.tlv.general)
).\
must_next()
# Step 4: The DUT MUST use IEEE 802.15.4 indirect transmissions to forward
# the DIAG_GET.query to SED
dut_payload_tlvs.add(DG_TYPE_LIST_TLV)
pkts.filter_wpan_src64(DUT).\
filter_ipv6_dst(REALM_LOCAL_ALL_THREAD_NODES_MULTICAST_ADDRESS).\
filter_coap_request(DIAG_GET_QRY_URI).\
filter(lambda p:
dut_payload_tlvs <= set(p.thread_diagnostic.tlv.type)
).\
must_next()
else:
# Step 5: The DUT automatically responds with a DIAG_GET.ans response
# MUST contain the requested diagnostic TLVs:
# TLV Type 0 - MAC Extended Address (64- bit)
# TLV Type 1 - MAC Address (16-bit)
# TLV Type 2 - Mode (Capability information)
# TLV Type 6 Leader Data
# TLV Type 7 Network Data
# TLV Type 8 IPv6 address list
# TLV Type 17 Channel Pages
dut_payload_tlvs.remove(DG_TYPE_LIST_TLV)
pkts.filter_wpan_src64(DUT).\
filter_ipv6_dst(LEADER_RLOC).\
filter_coap_request(DIAG_GET_ANS_URI).\
filter(lambda p:
dut_payload_tlvs <= set(p.thread_diagnostic.tlv.type) and\
{str(p.wpan.src64), colon_hex(dut_addr16, 2), '0f'}
< set(p.thread_diagnostic.tlv.general)
).\
must_next()
class Cert_5_7_03_CoapDiagCommands_Base_ROUTER(Cert_5_7_03_CoapDiagCommands_Base):
TOPOLOGY = copy.deepcopy(Cert_5_7_03_CoapDiagCommands_Base.TOPOLOGY)
TOPOLOGY[ROUTER1]['name'] = 'DUT'
TOPOLOGY[FED1]['name'] = 'FED'
class Cert_5_7_03_CoapDiagCommands_Base_FED(Cert_5_7_03_CoapDiagCommands_Base):
TOPOLOGY = copy.deepcopy(Cert_5_7_03_CoapDiagCommands_Base.TOPOLOGY)
TOPOLOGY[ROUTER1]['name'] = 'ROUTER'
TOPOLOGY[FED1]['name'] = 'DUT'
del (Cert_5_7_03_CoapDiagCommands_Base)
if __name__ == '__main__':
unittest.main()
@@ -1,237 +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 mle
import thread_cert
from pktverify.consts import MLE_PARENT_REQUEST, MLE_PARENT_RESPONSE, MLE_CHILD_UPDATE_RESPONSE, MLE_CHILD_ID_REQUEST, MLE_CHILD_ID_RESPONSE, SOURCE_ADDRESS_TLV, MODE_TLV, TIMEOUT_TLV, CHALLENGE_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, MLE_FRAME_COUNTER_TLV, ROUTE64_TLV, ADDRESS16_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, TLV_REQUEST_TLV, SCAN_MASK_TLV, CONNECTIVITY_TLV, LINK_MARGIN_TLV, VERSION_TLV, ADDRESS_REGISTRATION_TLV
from pktverify.packet_verifier import PacketVerifier
from pktverify.null_field import nullField
LEADER = 1
ED = 2
# Test Purpose and Description:
# -----------------------------
# The purpose of this test case is to validate that the DUT is able to successfully
# attach to a network
#
# Test Topology:
# -------------
# Leader
# |
# DUT
#
# DUT Types:
# ----------
# ED
# SED
class Cert_6_1_1_RouterAttach_Base(thread_cert.TestCase):
USE_MESSAGE_FACTORY = False
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ED]
},
ED: {
'name': 'DUT',
'is_mtd': True,
'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[ED].start()
self.simulator.go(5)
self.assertEqual(self.nodes[ED].get_state(), 'child')
self.collect_ipaddrs()
ed_addr = self.nodes[ED].get_ip6_address(config.ADDRESS_TYPE.LINK_LOCAL)
self.assertTrue(self.nodes[LEADER].ping(ed_addr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
LEADER_LLA = pv.vars['LEADER_LLA']
DUT = pv.vars['DUT']
DUT_LLA = pv.vars['DUT_LLA']
# Step 1: Ensure the Leader is sending MLE Advertisements.
pkts.filter_wpan_src64(LEADER).\
filter_mle_advertisement('Leader').\
must_next()
# Step 2: DUT sends a MLE Parent Request with an IP hop limit of
# 255 to the Link-Local All Routers multicast address (FF02::2).
# The following TLVs MUST be present in the MLE Parent Request:
# - Challenge TLV
# - Mode TLV
# - Scan Mask TLV
# If the DUT sends multiple MLE Parent Requests
# - The first one MUST be sent only to all Routers
# - Subsequent ones MAY be sent to all Routers and REEDS
# - Version TLV
# If the first MLE Parent Request was sent to all Routers and
# REEDS, the test fails.
# In securing the first three messages of the attaching process,
# the full four-byte key sequence number MUST be included in
# the Auxiliary Security Header used for MLE security.
#
# To send the full four-byte key sequence number, the Key
# Identifier Mode of the Security Control Field SHALL be set to
# 0x02, indicating the presence of a four-byte Key Source,
# which SHALL contain the four-byte key sequence number in
# network byte order.
pkts.filter_wpan_src64(DUT).\
filter_LLARMA().\
filter_mle_cmd(MLE_PARENT_REQUEST).\
filter(lambda p: {
CHALLENGE_TLV,
MODE_TLV,
SCAN_MASK_TLV,
VERSION_TLV
} <= set(p.mle.tlv.type) and\
p.ipv6.hlim == 255 and\
p.mle.tlv.scan_mask.r == 1 and\
p.mle.tlv.scan_mask.e == 0 and\
p.wpan.aux_sec.key_id_mode == 0x2
).\
must_next()
# Step 3: Leader responds with a MLE Parent Response.
# The following TLVs MUST be present in the MLE Parent Response:
# - Challenge TLV
# - Connectivity TLV
# - Leader Data TLV
# - Link-layer Frame Counter TLV
# - Link Margin TLV
# - Response TLV
# - Source Address
# - Version TLV
# - MLE Frame Counter TLV (optional)
pkts.filter_wpan_src64(LEADER).\
filter_wpan_dst64(DUT).\
filter_mle_cmd(MLE_PARENT_RESPONSE).\
filter(lambda p: {
CHALLENGE_TLV,
CONNECTIVITY_TLV,
LEADER_DATA_TLV,
LINK_LAYER_FRAME_COUNTER_TLV,
LINK_MARGIN_TLV,
RESPONSE_TLV,
SOURCE_ADDRESS_TLV,
VERSION_TLV
} <= set(p.mle.tlv.type)).\
must_next()
# Step 4: Router sends a MLE Child ID Request.
# The following TLVs MUST be present in the MLE Child ID Request:
# - Link-layer Frame Counter TLV
# - Address Registration TLV
# - Mode TLV
# - Response TLV
# - Timeout TLV
# - TLV Request TLV
# - Version TLV
# - MLE Frame Counter TLV (optional)
pkts.filter_wpan_src64(DUT).\
filter_wpan_dst64(LEADER).\
filter_mle_cmd(MLE_CHILD_ID_REQUEST).\
filter(lambda p: {
ADDRESS_REGISTRATION_TLV,
LINK_LAYER_FRAME_COUNTER_TLV,
MODE_TLV,
RESPONSE_TLV,
TIMEOUT_TLV,
TLV_REQUEST_TLV,
VERSION_TLV
} <= set(p.mle.tlv.type) and\
p.wpan.aux_sec.key_id_mode == 0x2
).\
must_next()
# Step 5: Leader responds with a Child ID Response.
pkts.filter_wpan_src64(LEADER).\
filter_wpan_dst64(DUT).\
filter_mle_cmd(MLE_CHILD_ID_RESPONSE).\
filter(lambda p: {
ADDRESS16_TLV,
LEADER_DATA_TLV,
NETWORK_DATA_TLV,
SOURCE_ADDRESS_TLV
} <= set(p.mle.tlv.type)
).\
must_next()
# Step 6: Verify connectivity by sending an ICMPv6 Echo Request
# to the DUT link local address
# DUT responds with ICMPv6 Echo Reply
_pkt = pkts.filter_ping_request().\
filter_ipv6_src_dst(LEADER_LLA, DUT_LLA).\
must_next()
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_ipv6_src_dst(DUT_LLA, LEADER_LLA).\
must_next()
class Cert_6_1_1_RouterAttach_ED(Cert_6_1_1_RouterAttach_Base):
TOPOLOGY = copy.deepcopy(Cert_6_1_1_RouterAttach_Base.TOPOLOGY)
TOPOLOGY[ED]['mode'] = 'rn'
class Cert_6_1_1_RouterAttach_SED(Cert_6_1_1_RouterAttach_Base):
TOPOLOGY = copy.deepcopy(Cert_6_1_1_RouterAttach_Base.TOPOLOGY)
TOPOLOGY[ED]['mode'] = '-'
TOPOLOGY[ED]['timeout'] = config.DEFAULT_CHILD_TIMEOUT
del (Cert_6_1_1_RouterAttach_Base)
if __name__ == '__main__':
unittest.main()
@@ -1,368 +0,0 @@
#!/usr/bin/env python3
#
# Copyright (c) 2018, 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 thread_cert
import config
from pktverify.consts import WPAN_DATA_REQUEST, WPAN_ACK, MLE_PARENT_REQUEST, MLE_PARENT_RESPONSE, MLE_CHILD_UPDATE_REQUEST, MLE_CHILD_UPDATE_RESPONSE, MLE_CHILD_ID_REQUEST, MLE_CHILD_ID_RESPONSE, ADDR_SOL_URI, SOURCE_ADDRESS_TLV, MODE_TLV, TIMEOUT_TLV, CHALLENGE_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, MLE_FRAME_COUNTER_TLV, ROUTE64_TLV, ADDRESS16_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, TLV_REQUEST_TLV, SCAN_MASK_TLV, CONNECTIVITY_TLV, LINK_MARGIN_TLV, VERSION_TLV, ADDRESS_REGISTRATION_TLV, NL_MAC_EXTENDED_ADDRESS_TLV, NL_RLOC16_TLV, NL_STATUS_TLV, NL_ROUTER_MASK_TLV, COAP_CODE_ACK
from pktverify.packet_verifier import PacketVerifier
from pktverify.null_field import nullField
LEADER = 1
REED = 2
MTD = 3
# Test Purpose and Description:
# -----------------------------
# The purpose of this test case is to validate that the DUT is able to successfully
# attach to a network as an End Device through a REED.
#
# Test Topology:
# -------------
# Leader
# |
# REED
# |
# DUT
#
# DUT Types:
# ----------
# ED
# SED
class Cert_6_1_2_REEDAttach_Base(thread_cert.TestCase):
USE_MESSAGE_FACTORY = False
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [REED]
},
REED: {
'name': 'REED',
'mode': 'rdn',
'router_upgrade_threshold': 0,
'allowlist': [LEADER, MTD]
},
MTD: {
'name': 'DUT',
'is_mtd': True,
'timeout': config.DEFAULT_CHILD_TIMEOUT,
'allowlist': [REED]
},
}
def test(self):
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[REED].start()
self.simulator.go(config.MAX_ADVERTISEMENT_INTERVAL)
self.assertEqual(self.nodes[REED].get_state(), 'child')
self.collect_rloc16s()
self.nodes[MTD].start()
self.simulator.go(5)
self.assertEqual(self.nodes[MTD].get_state(), 'child')
self.assertEqual(self.nodes[REED].get_state(), 'router')
self.collect_ipaddrs()
self.collect_rlocs()
self.simulator.go(config.DEFAULT_CHILD_TIMEOUT)
dut_addr = self.nodes[MTD].get_ip6_address(config.ADDRESS_TYPE.LINK_LOCAL)
self.assertTrue(self.nodes[REED].ping(dut_addr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
LEADER_RLOC = pv.vars['LEADER_RLOC']
REED = pv.vars['REED']
REED_RLOC = pv.vars['REED_RLOC']
REED_LLA = pv.vars['REED_LLA']
REED_RLOC16 = pv.vars['REED_RLOC16']
DUT = pv.vars['DUT']
DUT_RLOC = pv.vars['DUT_RLOC']
DUT_LLA = pv.vars['DUT_LLA']
# Step 1: Ensure the Leader is sending MLE Advertisements and is connected to REED
pkts.filter_wpan_src64(LEADER).\
filter_mle_advertisement('Leader').\
must_next()
pv.verify_attached('REED', 'LEADER')
# Step 2: DUT sends a MLE Parent Request with an IP hop limit of
# 255 to the Link-Local All Routers multicast address (FF02::2).
# The following TLVs MUST be present in the MLE Parent Request:
# - Challenge TLV
# - Mode TLV
# - Scan Mask TLV
# Verify that the first one is sent to routers only
# - Version TLV
# If the first MLE Parent Request was sent to all Routers and
# REEDS, the test fails.
# In securing the first three messages of the attaching process,
# the full four-byte key sequence number MUST be included in
# the Auxiliary Security Header used for MLE security.
#
# To send the full four-byte key sequence number, the Key
# Identifier Mode of the Security Control Field SHALL be set to
# 0x02, indicating the presence of a four-byte Key Source,
# which SHALL contain the four-byte key sequence number in
# network byte order.
pkts.filter_wpan_src64(DUT).\
filter_LLARMA().\
filter_mle_cmd(MLE_PARENT_REQUEST).\
filter(lambda p: {
CHALLENGE_TLV,
MODE_TLV,
SCAN_MASK_TLV,
VERSION_TLV
} <= set(p.mle.tlv.type) and\
p.ipv6.hlim == 255 and\
p.mle.tlv.scan_mask.r == 1 and\
p.mle.tlv.scan_mask.e == 0 and\
p.wpan.aux_sec.key_id_mode == 0x2
).\
must_next()
index1 = pkts.index
# Step 4: DUT sends a MLE Parent Request with an IP hop limit of
# 255 to the Link-Local All Routers multicast address (FF02::2).
# The following TLVs MUST be present in the MLE Parent Request:
# - Challenge TLV
# - Mode TLV
# - Scan Mask TLV
# Verify that it is sent to Routers AND REEDs
# - Version TLV
# If request was not sent to all routers and REEDS, then the test
# has failed.
# In securing the first three messages of the attaching process,
# the full four-byte key sequence number MUST be included in
# the Auxiliary Security Header used for MLE security.
# To send the full four-byte key sequence number, the Key
# Identifier Mode of the Security Control Field SHALL be set to
# 0x02, indicating the presence of a four-byte Key Source,
# which SHALL contain the four-byte key sequence number in
# network byte order.
pkts.filter_wpan_src64(DUT).\
filter_LLARMA().\
filter_mle_cmd(MLE_PARENT_REQUEST).\
filter(lambda p: {
CHALLENGE_TLV,
MODE_TLV,
SCAN_MASK_TLV,
VERSION_TLV
} <= set(p.mle.tlv.type) and\
p.ipv6.hlim == 255 and\
p.mle.tlv.scan_mask.r == 1 and\
p.mle.tlv.scan_mask.e == 1 and\
p.wpan.aux_sec.key_id_mode == 0x2
).\
must_next()
index2 = pkts.index
# Step 3: REED doesn't response to the first Parent Request
pkts.range(index1, index2).\
filter_wpan_src64(REED).\
filter_wpan_dst64(DUT).\
filter_mle_cmd(MLE_PARENT_RESPONSE).\
must_not_next()
# Step 5: REED responds with MLE Parent Response for the second Parent Request
pkts.filter_wpan_src64(REED).\
filter_wpan_dst64(DUT).\
filter_mle_cmd(MLE_PARENT_RESPONSE).\
filter(lambda p: {
CHALLENGE_TLV,
CONNECTIVITY_TLV,
LEADER_DATA_TLV,
LINK_LAYER_FRAME_COUNTER_TLV,
LINK_MARGIN_TLV,
RESPONSE_TLV,
SOURCE_ADDRESS_TLV,
VERSION_TLV
} <= set(p.mle.tlv.type)).\
must_next()
# Step 6: DUT sends a MLE Child ID Request.
# The following TLVs MUST be present in the MLE Child ID Request:
# - Address Registration TLV
# - Link-layer Frame Counter TLV
# - Mode TLV
# - Response TLV
# - Timeout TLV
# - TLV Request TLV
# - Version TLV
# - MLE Frame Counter TLV (optional)
pkts.filter_wpan_src64(DUT).\
filter_wpan_dst64(REED).\
filter_mle_cmd(MLE_CHILD_ID_REQUEST).\
filter(lambda p: {
ADDRESS_REGISTRATION_TLV,
LINK_LAYER_FRAME_COUNTER_TLV,
MODE_TLV,
RESPONSE_TLV,
TIMEOUT_TLV,
TLV_REQUEST_TLV,
VERSION_TLV
} <= set(p.mle.tlv.type) and\
p.wpan.aux_sec.key_id_mode == 0x2
).\
must_next()
# Step 7: REED sends an Address Solicit Request to Leader;
# Leader responds with an Address Solicit Response and REED
# becomes active router;
# REED sends Child ID Response with DUTs new 16-bit Address.
_pkt = pkts.filter_wpan_src64(REED).\
filter_ipv6_dst(LEADER_RLOC).\
filter_coap_request(ADDR_SOL_URI).\
filter(lambda p: {
NL_MAC_EXTENDED_ADDRESS_TLV,
NL_STATUS_TLV
} <= set(p.coap.tlv.type)
).\
must_next()
pkts.filter_wpan_src64(LEADER).\
filter_wpan_dst16(_pkt.wpan.src16).\
filter_coap_ack(ADDR_SOL_URI).\
filter(lambda p: {
NL_STATUS_TLV,
NL_RLOC16_TLV,
NL_ROUTER_MASK_TLV
} <= set(p.coap.tlv.type) and\
p.coap.code == COAP_CODE_ACK and\
p.thread_address.tlv.status == 0\
).\
must_next()
_pkt = pkts.filter_wpan_src64(REED).\
filter_wpan_dst64(DUT).\
filter_mle_cmd(MLE_CHILD_ID_RESPONSE).\
filter(lambda p: {
ADDRESS16_TLV,
LEADER_DATA_TLV,
NETWORK_DATA_TLV,
SOURCE_ADDRESS_TLV
} <= set(p.mle.tlv.type) and\
p.mle.tlv.source_addr != REED_RLOC16
).\
must_next()
if self.TOPOLOGY[MTD]['mode'] == 'rn':
# Step 8: DUT sends periodic Child Update messages as part of the
# keep-alive message
# The DUT MUST send MLE Child Update messages containing
# the following TLVs:
# - Leader Data TLV
# - Mode TLV
# - Source Address TLV
pkts.filter_wpan_src64(DUT).\
filter_wpan_dst64(REED).\
filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).\
filter(lambda p: {
SOURCE_ADDRESS_TLV,
MODE_TLV,
LEADER_DATA_TLV
} <= set(p.mle.tlv.type)
).\
must_next()
# Step 9: REED Respond to Child Update messages with a MLE Update
# Response.
pkts.filter_wpan_src64(REED).\
filter_wpan_dst64(DUT).\
filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).\
filter(lambda p: {
SOURCE_ADDRESS_TLV,
MODE_TLV,
LEADER_DATA_TLV
} <= set(p.mle.tlv.type)
).\
must_next()
# Step 10: Go to Step 12
else:
# Step 11: DUT sends periodic 802.15.4 Data Request messages as part
# of the keep-alive message
# The DUT must send a 802.15.4 Data Request command to the
# parent device and receive an ACK message in response
_pkt2 = pkts.filter_wpan_src64(DUT).\
filter_wpan_dst16(_pkt.mle.tlv.source_addr).\
filter_wpan_cmd(WPAN_DATA_REQUEST).\
must_next()
pkts.filter(lambda p:
p.wpan.seq_no == _pkt2.wpan.seq_no and\
p.wpan.frame_type == WPAN_ACK
).\
must_next()
# Step 12: REED verifies connectivity by sending an ICMPv6 Echo Request
# to the DUT link local address
# DUT responds with ICMPv6 Echo Reply
_pkt = pkts.filter_ping_request().\
filter_ipv6_src_dst(REED_LLA, DUT_LLA).\
must_next()
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_ipv6_src_dst(DUT_LLA, REED_LLA).\
must_next()
class Cert_6_1_2_REEDAttach_ED(Cert_6_1_2_REEDAttach_Base):
TOPOLOGY = copy.deepcopy(Cert_6_1_2_REEDAttach_Base.TOPOLOGY)
TOPOLOGY[MTD]['mode'] = 'rn'
class Cert_6_1_2_REEDAttach_SED(Cert_6_1_2_REEDAttach_Base):
TOPOLOGY = copy.deepcopy(Cert_6_1_2_REEDAttach_Base.TOPOLOGY)
TOPOLOGY[MTD]['mode'] = '-'
del (Cert_6_1_2_REEDAttach_Base)
if __name__ == '__main__':
unittest.main()
@@ -1,132 +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, MODE_TLV, CHALLENGE_TLV, SCAN_MASK_TLV, VERSION_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, MLE_FRAME_COUNTER_TLV, TIMEOUT_TLV, ADDRESS_REGISTRATION_TLV, TLV_REQUEST_TLV, LINK_LOCAL_ALL_ROUTERS_MULTICAST_ADDRESS
from pktverify.packet_verifier import PacketVerifier
LEADER = 1
ROUTER1 = 2
ROUTER2 = 3
ROUTER3 = 4
ED = 5
class Cert_6_1_3_RouterAttachConnectivity(thread_cert.TestCase):
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER1, ROUTER2, ROUTER3]
},
ROUTER1: {
'name': 'ROUTER_1',
'mode': 'rdn',
'allowlist': [LEADER, ROUTER3]
},
ROUTER2: {
'name': 'ROUTER_2',
'mode': 'rdn',
'allowlist': [LEADER, ED]
},
ROUTER3: {
'name': 'ROUTER_3',
'mode': 'rdn',
'allowlist': [LEADER, ROUTER1, ED]
},
ED: {
'name': 'ED',
'is_mtd': True,
'mode': 'rn',
'allowlist': [ROUTER2, ROUTER3]
},
}
def test(self):
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
for i in range(2, 5):
self.nodes[i].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
for i in range(2, 5):
self.assertEqual(self.nodes[i].get_state(), 'router')
self.simulator.go(config.MAX_ADVERTISEMENT_INTERVAL)
self.nodes[ED].start()
self.simulator.go(5)
self.assertEqual(self.nodes[ED].get_state(), 'child')
self.collect_ipaddrs()
addrs = self.nodes[ED].get_addrs()
for addr in addrs:
self.assertTrue(self.nodes[ROUTER3].ping(addr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
ROUTER_3 = pv.vars['ROUTER_3']
ED = pv.vars['ED']
_router3_pkts = pkts.filter_wpan_src64(ROUTER_3)
_ed_pkts = pkts.filter_wpan_src64(ED)
# Step 2: The DUT MUST send a MLE Parent Request to the
# All-Routers multicast address
_ed_pkts.filter_mle_cmd(MLE_PARENT_REQUEST).filter_ipv6_dst(
LINK_LOCAL_ALL_ROUTERS_MULTICAST_ADDRESS).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)
# Step 3: Router_2, Router_3 Respond with MLE Parent Response
# Step 4: DUT Send a Child ID Request to Router_3 due to better connectivity
_ed_pkts.filter_mle_cmd(MLE_CHILD_ID_REQUEST).must_next().must_verify(
lambda p: {
RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, MLE_FRAME_COUNTER_TLV, MODE_TLV, TIMEOUT_TLV, VERSION_TLV,
ADDRESS_REGISTRATION_TLV, TLV_REQUEST_TLV
} <= set(p.mle.tlv.type))
# Step 5: The DUT MUST respond with ICMPv6 Echo Reply
ed_mleid = pv.vars['ED_MLEID']
router3_mleid = pv.vars['ROUTER_3_MLEID']
_pkt = _router3_pkts.filter(
lambda p: p.ipv6.src == router3_mleid and p.ipv6.dst == ed_mleid).filter_ping_request().must_next()
_ed_pkts.filter(lambda p: p.ipv6.src == ed_mleid and p.ipv6.dst == router3_mleid).filter_ping_reply(
identifier=_pkt.icmpv6.echo.identifier).must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,322 +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 copy
import thread_cert
import config
from pktverify.consts import MLE_PARENT_REQUEST, MLE_PARENT_RESPONSE, MLE_CHILD_ID_REQUEST, MLE_CHILD_ID_RESPONSE, ADDR_SOL_URI, SOURCE_ADDRESS_TLV, MODE_TLV, TIMEOUT_TLV, CHALLENGE_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, MLE_FRAME_COUNTER_TLV, ROUTE64_TLV, ADDRESS16_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, TLV_REQUEST_TLV, SCAN_MASK_TLV, CONNECTIVITY_TLV, LINK_MARGIN_TLV, VERSION_TLV, ADDRESS_REGISTRATION_TLV, NL_MAC_EXTENDED_ADDRESS_TLV, NL_RLOC16_TLV, NL_STATUS_TLV, NL_ROUTER_MASK_TLV, COAP_CODE_ACK
from pktverify.packet_verifier import PacketVerifier
LEADER = 1
ROUTER = 2
REED_1 = 3
REED_2 = 4
MTD = 5
# Test Purpose and Description:
# -----------------------------
# The purpose of this test case is to validate that the DUT will pick REED_1
# as its parent because of its better connectivity.
#
# Test Topology:
# -------------
# Router - Leader
# | / |
# REED_1 REED_2
# \ /
# DUT
#
# DUT Types:
# ----------
# ED
# SED
class Cert_6_1_4_REEDAttachConnectivity_Base(thread_cert.TestCase):
USE_MESSAGE_FACTORY = False
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER, REED_1, REED_2]
},
ROUTER: {
'name': 'ROUTER',
'mode': 'rdn',
'allowlist': [LEADER, REED_1]
},
REED_1: {
'name': 'REED_1',
'mode': 'rdn',
'router_upgrade_threshold': 0,
'allowlist': [LEADER, ROUTER, MTD]
},
REED_2: {
'name': 'REED_2',
'mode': 'rdn',
'router_upgrade_threshold': 0,
'allowlist': [LEADER, MTD]
},
MTD: {
'name': 'DUT',
'is_mtd': True,
'timeout': config.DEFAULT_CHILD_TIMEOUT,
'allowlist': [REED_1, REED_2]
},
}
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')
for i in (3, 4):
self.nodes[i].start()
self.simulator.go(5)
self.assertEqual(self.nodes[i].get_state(), 'child')
self.collect_rloc16s()
self.collect_rlocs()
self.nodes[MTD].start()
self.simulator.go(5)
self.assertEqual(self.nodes[MTD].get_state(), 'child')
self.assertEqual(self.nodes[REED_1].get_state(), 'router')
self.simulator.go(config.DEFAULT_CHILD_TIMEOUT)
self.collect_ipaddrs()
dut_addr = self.nodes[MTD].get_ip6_address(config.ADDRESS_TYPE.LINK_LOCAL)
self.assertTrue(self.nodes[REED_1].ping(dut_addr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
LEADER_RLOC = pv.vars['LEADER_RLOC']
ROUTER = pv.vars['ROUTER']
REED_1 = pv.vars['REED_1']
REED_1_RLOC = pv.vars['REED_1_RLOC']
REED_1_LLA = pv.vars['REED_1_LLA']
REED_1_RLOC16 = pv.vars['REED_1_RLOC16']
DUT = pv.vars['DUT']
DUT_RLOC = pv.vars['DUT_RLOC']
DUT_LLA = pv.vars['DUT_LLA']
# Step 1: Setup the topology without the DUT. Ensure all routers and
# leader are sending MLE advertisements
pkts.filter_wpan_src64(LEADER).\
filter_mle_advertisement('Leader').\
must_next()
pv.verify_attached('ROUTER', 'LEADER')
# Step 2: DUT sends a MLE Parent Request with an IP hop limit of
# 255 to the Link-Local All Routers multicast address (FF02::2).
# The following TLVs MUST be present in the MLE Parent Request:
# - Challenge TLV
# - Mode TLV
# - Scan Mask TLV
# Verify that the first one is sent to routers only
# - Version TLV
# If the first MLE Parent Request was sent to all Routers and
# REED_1S, the test fails.
pkts.filter_wpan_src64(DUT).\
filter_LLARMA().\
filter_mle_cmd(MLE_PARENT_REQUEST).\
filter(lambda p: {
CHALLENGE_TLV,
MODE_TLV,
SCAN_MASK_TLV,
VERSION_TLV
} <= set(p.mle.tlv.type) and\
p.ipv6.hlim == 255 and\
p.mle.tlv.scan_mask.r == 1 and\
p.mle.tlv.scan_mask.e == 0 and\
p.wpan.aux_sec.key_id_mode == 0x2
).\
must_next()
index1 = pkts.index
# Step 4: DUT sends a MLE Parent Request with an IP hop limit of
# 255 to the Link-Local All Routers multicast address (FF02::2).
# The following TLVs MUST be present in the MLE Parent Request:
# - Challenge TLV
# - Mode TLV
# - Scan Mask TLV
# Verify that it is sent to Routers AND REED_1s
# - Version TLV
# If request was not sent to all routers and REED_1S, then the test
# has failed.
pkts.filter_wpan_src64(DUT).\
filter_LLARMA().\
filter_mle_cmd(MLE_PARENT_REQUEST).\
filter(lambda p: {
CHALLENGE_TLV,
MODE_TLV,
SCAN_MASK_TLV,
VERSION_TLV
} <= set(p.mle.tlv.type) and\
p.ipv6.hlim == 255 and\
p.mle.tlv.scan_mask.r == 1 and\
p.mle.tlv.scan_mask.e == 1 and\
p.wpan.aux_sec.key_id_mode == 0x2
).\
must_next()
index2 = pkts.index
# Step 3: REED_1 and REED_2 sends no response to Parent Request after
# DUT sent the first Parent Request
for i in (1, 2):
pkts.range(index1, index2).\
filter_wpan_src64(pv.vars['REED_%d' %i]).\
filter_wpan_dst64(DUT).\
filter_mle_cmd(MLE_PARENT_RESPONSE).\
must_not_next()
# Step 5: REED_1 Respond with MLE Parent Response
for i in (1, 2):
with pkts.save_index():
pkts.filter_wpan_src64(pv.vars['REED_%d' %i]).\
filter_wpan_dst64(DUT).\
filter_mle_cmd(MLE_PARENT_RESPONSE).\
filter(lambda p: {
CHALLENGE_TLV,
CONNECTIVITY_TLV,
LEADER_DATA_TLV,
LINK_LAYER_FRAME_COUNTER_TLV,
LINK_MARGIN_TLV,
RESPONSE_TLV,
SOURCE_ADDRESS_TLV,
VERSION_TLV
} <= set(p.mle.tlv.type)).\
must_next()
# Step 6: DUT sends a MLE Child ID Request to REED_1
# The following TLVs MUST be present in the MLE Child ID Request:
# - Address Registration TLV
# - Link-layer Frame Counter TLV
# - Mode TLV
# - Response TLV
# - Timeout TLV
# - TLV Request TLV
# - Version TLV
# - MLE Frame Counter TLV (optional)
pkts.filter_wpan_src64(DUT).\
filter_wpan_dst64(REED_1).\
filter_mle_cmd(MLE_CHILD_ID_REQUEST).\
filter(lambda p: {
ADDRESS_REGISTRATION_TLV,
LINK_LAYER_FRAME_COUNTER_TLV,
MODE_TLV,
RESPONSE_TLV,
TIMEOUT_TLV,
TLV_REQUEST_TLV,
VERSION_TLV
} <= set(p.mle.tlv.type) and\
p.wpan.aux_sec.key_id_mode == 0x2
).\
must_next()
# Step 7: REED_1 sends an Address Solicit Request to Leader;
# Leader responds with an Address Solicit Response and REED_1
# becomes active router;
# REED_1 sends Child ID Response with DUTs new 16-bit Address.
pkts.filter_wpan_src64(REED_1).\
filter_ipv6_dst(LEADER_RLOC).\
filter_coap_request(ADDR_SOL_URI).\
filter(lambda p: {
NL_MAC_EXTENDED_ADDRESS_TLV,
NL_STATUS_TLV
} <= set(p.coap.tlv.type)
).\
must_next()
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(REED_1_RLOC).\
filter_coap_ack(ADDR_SOL_URI).\
filter(lambda p: {
NL_STATUS_TLV,
NL_RLOC16_TLV,
NL_ROUTER_MASK_TLV
} <= set(p.coap.tlv.type) and\
p.thread_address.tlv.status == 0
).\
must_next()
pkts.filter_wpan_src64(REED_1).\
filter_wpan_dst64(DUT).\
filter_mle_cmd(MLE_CHILD_ID_RESPONSE).\
filter(lambda p: {
ADDRESS16_TLV,
LEADER_DATA_TLV,
NETWORK_DATA_TLV,
SOURCE_ADDRESS_TLV
} <= set(p.mle.tlv.type) and\
p.mle.tlv.source_addr != REED_1_RLOC16
).\
must_next()
# Step 8: REED_1 verifies connectivity by sending an ICMPv6 Echo Request
# to the DUT link local address
# DUT responds with ICMPv6 Echo Reply
_pkt = pkts.filter_ping_request().\
filter_ipv6_src_dst(REED_1_LLA, DUT_LLA).\
must_next()
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_ipv6_src_dst(DUT_LLA, REED_1_LLA).\
must_next()
class Cert_6_1_4_REEDAttachConnectivity_ED(Cert_6_1_4_REEDAttachConnectivity_Base):
TOPOLOGY = copy.deepcopy(Cert_6_1_4_REEDAttachConnectivity_Base.TOPOLOGY)
TOPOLOGY[MTD]['mode'] = 'rn'
class Cert_6_1_4_REEDAttachConnectivity_SED(Cert_6_1_4_REEDAttachConnectivity_Base):
TOPOLOGY = copy.deepcopy(Cert_6_1_4_REEDAttachConnectivity_Base.TOPOLOGY)
TOPOLOGY[MTD]['mode'] = '-'
del (Cert_6_1_4_REEDAttachConnectivity_Base)
if __name__ == '__main__':
unittest.main()
@@ -1,146 +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, MODE_TLV, CHALLENGE_TLV, SCAN_MASK_TLV, VERSION_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, MLE_FRAME_COUNTER_TLV, TIMEOUT_TLV, ADDRESS_REGISTRATION_TLV, TLV_REQUEST_TLV, LINK_LOCAL_ALL_ROUTERS_MULTICAST_ADDRESS
from pktverify.packet_verifier import PacketVerifier
LEADER = 1
ROUTER1 = 2
REED1 = 3
REED2 = 4
ED = 5
class Cert_6_1_5_REEDAttachConnectivity(thread_cert.TestCase):
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER1, REED1, REED2]
},
ROUTER1: {
'name': 'ROUTER_1',
'mode': 'rdn',
'allowlist': [LEADER, REED2]
},
REED1: {
'name': 'REED_1',
'mode': 'rdn',
'router_upgrade_threshold': 0,
'allowlist': [LEADER, ROUTER1, ED]
},
REED2: {
'name': 'REED_2',
'mode': 'rdn',
'router_upgrade_threshold': 0,
'allowlist': [LEADER, (ED, -85)]
},
ED: {
'name': 'ED',
'is_mtd': True,
'mode': 'rn',
'allowlist': [REED1, REED2]
},
}
def test(self):
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ROUTER1].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
self.nodes[REED1].start()
self.simulator.go(5)
self.assertEqual(self.nodes[REED1].get_state(), 'child')
self.nodes[REED2].start()
self.simulator.go(5)
self.assertEqual(self.nodes[REED2].get_state(), 'child')
self.nodes[ED].start()
self.simulator.go(10)
self.assertEqual(self.nodes[ED].get_state(), 'child')
self.assertEqual(self.nodes[REED1].get_state(), 'router')
self.num_parent_requests = 1 if self.nodes[ED].version in ['1.1', '1.2'] else 2
self.collect_ipaddrs()
addrs = self.nodes[ED].get_addrs()
for addr in addrs:
self.assertTrue(self.nodes[REED1].ping(addr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
REED_1 = pv.vars['REED_1']
ED = pv.vars['ED']
_reed1_pkts = pkts.filter_wpan_src64(REED_1)
_ed_pkts = pkts.filter_wpan_src64(ED)
# Step 2: The DUT MUST send MLE Parent Requests to the
# All-Routers multicast address
for num in range(self.num_parent_requests):
_ed_pkts.filter_mle_cmd(MLE_PARENT_REQUEST).filter_ipv6_dst(
LINK_LOCAL_ALL_ROUTERS_MULTICAST_ADDRESS).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)
# Step 3: REED_1 and REED_2 No response to Parent Request
# Step 4: DUT Send MLE Parent Request with Scan Mask set to Routers AND REEDs
_ed_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 == 1)
# Step 5: The DUT MUST send a MLE Child ID Request
_ed_pkts.filter_wpan_dst64(REED_1).filter_mle_cmd(MLE_CHILD_ID_REQUEST).must_next().must_verify(
lambda p: {
RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, MLE_FRAME_COUNTER_TLV, MODE_TLV, TIMEOUT_TLV, VERSION_TLV,
ADDRESS_REGISTRATION_TLV, TLV_REQUEST_TLV
} <= set(p.mle.tlv.type))
# Step 8: The DUT MUST respond with ICMPv6 Echo Reply
ed_mleid = pv.vars['ED_MLEID']
reed1_mleid = pv.vars['REED_1_MLEID']
_pkt = _reed1_pkts.filter(
lambda p: p.ipv6.src == reed1_mleid and p.ipv6.dst == ed_mleid).filter_ping_request().must_next()
_ed_pkts.filter(lambda p: p.ipv6.src == ed_mleid and p.ipv6.dst == reed1_mleid).filter_ping_reply(
identifier=_pkt.icmpv6.echo.identifier).must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,254 +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 config
import copy
import mle
import thread_cert
from pktverify.consts import MLE_PARENT_REQUEST, MLE_PARENT_RESPONSE, MLE_CHILD_ID_REQUEST, MLE_CHILD_ID_RESPONSE, SOURCE_ADDRESS_TLV, MODE_TLV, TIMEOUT_TLV, CHALLENGE_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, MLE_FRAME_COUNTER_TLV, ROUTE64_TLV, ADDRESS16_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, TLV_REQUEST_TLV, SCAN_MASK_TLV, CONNECTIVITY_TLV, LINK_MARGIN_TLV, VERSION_TLV, ADDRESS_REGISTRATION_TLV
from pktverify.packet_verifier import PacketVerifier
LEADER = 1
REED = 2
ROUTER = 3
MTD = 4
# Test Purpose and Description:
# -----------------------------
# The purpose of this test is to verify that the DUT sends a second Parent Request
# to the all-routers and all-reeds multicast address if it gets a reply from the
# first Parent Request to the all-routers address with a bad link quality.
#
# Test Topology:
# -------------
# Leader
# / \
# REED ROUTER
# \ /
# DUT
#
# DUT Types:
# ----------
# ED
# SED
class Cert_6_1_6_REEDAttachLinkQuality_Base(thread_cert.TestCase):
USE_MESSAGE_FACTORY = False
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [REED, ROUTER]
},
REED: {
'name': 'REED',
'mode': 'rdn',
'router_upgrade_threshold': 0,
'allowlist': [LEADER, MTD]
},
ROUTER: {
'name': 'ROUTER',
'mode': 'rdn',
'allowlist': [LEADER, (MTD, -85)]
},
MTD: {
'name': 'DUT',
'is_mtd': True,
'timeout': config.DEFAULT_CHILD_TIMEOUT,
'allowlist': [REED, 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[REED].start()
self.simulator.go(5)
self.assertEqual(self.nodes[REED].get_state(), 'child')
self.nodes[ROUTER].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER].get_state(), 'router')
self.nodes[MTD].start()
self.simulator.go(10)
self.assertEqual(self.nodes[MTD].get_state(), 'child')
self.assertEqual(self.nodes[REED].get_state(), 'router')
self.collect_ipaddrs()
self.collect_rlocs()
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
REED = pv.vars['REED']
ROUTER = pv.vars['ROUTER']
DUT = pv.vars['DUT']
# Step 1: Setup the topology without the DUT. Ensure all routers and leader
# are sending MLE advertisements
pkts.filter_wpan_src64(LEADER).\
filter_mle_advertisement('Leader').\
must_next()
pv.verify_attached('REED', 'LEADER')
pv.verify_attached('ROUTER', 'LEADER')
# Step 3: DUT sends a MLE Parent Request with an IP hop limit of
# 255 to the Link-Local All Routers multicast address (FF02::2).
# The following TLVs MUST be present in the MLE Parent Request:
# - Challenge TLV
# - Mode TLV
# - Scan Mask TLV
# Verify sent to routers only
# - Version TLV
# If the first Request was sent to all routers and REEDS, then
# the test has failed.
pkts.filter_wpan_src64(DUT).\
filter_LLARMA().\
filter_mle_cmd(MLE_PARENT_REQUEST).\
filter(lambda p: {
CHALLENGE_TLV,
MODE_TLV,
SCAN_MASK_TLV,
VERSION_TLV
} <= set(p.mle.tlv.type) and\
p.ipv6.hlim == 255 and\
p.mle.tlv.scan_mask.r == 1 and\
p.mle.tlv.scan_mask.e == 0 and\
p.wpan.aux_sec.key_id_mode == 0x2
).\
must_next()
# Step 4: Router responds with MLE Parent Response
pkts.filter_wpan_src64(ROUTER).\
filter_wpan_dst64(DUT).\
filter_mle_cmd(MLE_PARENT_RESPONSE).\
filter(lambda p: {
CHALLENGE_TLV,
CONNECTIVITY_TLV,
LEADER_DATA_TLV,
LINK_LAYER_FRAME_COUNTER_TLV,
LINK_MARGIN_TLV,
RESPONSE_TLV,
SOURCE_ADDRESS_TLV,
VERSION_TLV
} <= set(p.mle.tlv.type)).\
must_next()
# Step 5: DUT sends a MLE Parent Request with an IP hop limit of
# 255 to the Link-Local All Routers multicast address (FF02::2).
# The following TLVs MUST be present in the MLE Parent Request:
# - Challenge TLV
# - Mode TLV
# - Scan Mask TLV
# Verify that it is sent to Routers AND REEDs
# - Version TLV
pkts.filter_wpan_src64(DUT).\
filter_LLARMA().\
filter_mle_cmd(MLE_PARENT_REQUEST).\
filter(lambda p: {
CHALLENGE_TLV,
MODE_TLV,
SCAN_MASK_TLV,
VERSION_TLV
} <= set(p.mle.tlv.type) and\
p.ipv6.hlim == 255 and\
p.mle.tlv.scan_mask.r == 1 and\
p.mle.tlv.scan_mask.e == 1 and\
p.wpan.aux_sec.key_id_mode == 0x2
).\
must_next()
index2 = pkts.index
# Step 6: REED sends MLE Parent Response to DUT
pkts.filter_wpan_src64(REED).\
filter_wpan_dst64(DUT).\
filter_mle_cmd(MLE_PARENT_RESPONSE).\
filter(lambda p: {
CHALLENGE_TLV,
CONNECTIVITY_TLV,
LEADER_DATA_TLV,
LINK_LAYER_FRAME_COUNTER_TLV,
LINK_MARGIN_TLV,
RESPONSE_TLV,
SOURCE_ADDRESS_TLV,
VERSION_TLV
} <= set(p.mle.tlv.type)).\
must_next()
# Step 6: DUT sends a MLE Child ID Request to REED
# The following TLVs MUST be present in the MLE Child ID Request:
# - Address Registration TLV
# - Link-layer Frame Counter TLV
# - Mode TLV
# - Response TLV
# - Timeout TLV
# - TLV Request TLV
# - Version TLV
# - MLE Frame Counter TLV (optional)
pkts.filter_wpan_src64(DUT).\
filter_wpan_dst64(REED).\
filter_mle_cmd(MLE_CHILD_ID_REQUEST).\
filter(lambda p: {
ADDRESS_REGISTRATION_TLV,
LINK_LAYER_FRAME_COUNTER_TLV,
MODE_TLV,
RESPONSE_TLV,
TIMEOUT_TLV,
TLV_REQUEST_TLV,
VERSION_TLV
} <= set(p.mle.tlv.type) and\
p.wpan.aux_sec.key_id_mode == 0x2
).\
must_next()
class Cert_6_1_6_REEDAttachLinkQuality_ED(Cert_6_1_6_REEDAttachLinkQuality_Base):
TOPOLOGY = copy.deepcopy(Cert_6_1_6_REEDAttachLinkQuality_Base.TOPOLOGY)
TOPOLOGY[MTD]['mode'] = 'rn'
class Cert_6_1_6_REEDAttachLinkQuality_SED(Cert_6_1_6_REEDAttachLinkQuality_Base):
TOPOLOGY = copy.deepcopy(Cert_6_1_6_REEDAttachLinkQuality_Base.TOPOLOGY)
TOPOLOGY[MTD]['mode'] = '-'
del (Cert_6_1_6_REEDAttachLinkQuality_Base)
if __name__ == '__main__':
unittest.main()
@@ -1,122 +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, MODE_TLV, CHALLENGE_TLV, SCAN_MASK_TLV, VERSION_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, MLE_FRAME_COUNTER_TLV, TIMEOUT_TLV, ADDRESS_REGISTRATION_TLV, TLV_REQUEST_TLV, LINK_LOCAL_ALL_ROUTERS_MULTICAST_ADDRESS
from pktverify.packet_verifier import PacketVerifier
LEADER = 1
ROUTER1 = 2
ROUTER2 = 3
ED = 4
class Cert_6_1_7_RouterAttachLinkQuality(thread_cert.TestCase):
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER1, ROUTER2]
},
ROUTER1: {
'name': 'ROUTER_1',
'mode': 'rdn',
'allowlist': [LEADER, ED]
},
ROUTER2: {
'name': 'ROUTER_2',
'mode': 'rdn',
'allowlist': [LEADER, (ED, -85)]
},
ED: {
'name': 'ED',
'is_mtd': True,
'mode': 'rn',
'allowlist': [ROUTER1, ROUTER2]
},
}
def test(self):
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
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[ED].start()
self.simulator.go(5)
self.assertEqual(self.nodes[ED].get_state(), 'child')
self.collect_ipaddrs()
addrs = self.nodes[ED].get_addrs()
for addr in addrs:
self.assertTrue(self.nodes[ROUTER1].ping(addr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
ROUTER_1 = pv.vars['ROUTER_1']
ED = pv.vars['ED']
_ed_pkts = pkts.filter_wpan_src64(ED)
# Step 3: The DUT MUST send a MLE Parent Request to the
# All-Routers multicast address
_ed_pkts.filter_mle_cmd(MLE_PARENT_REQUEST).filter_ipv6_dst(
LINK_LOCAL_ALL_ROUTERS_MULTICAST_ADDRESS).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 5: The DUT MUST send a MLE Child ID Request to Router_1
_ed_pkts.filter_wpan_dst64(ROUTER_1).filter_mle_cmd(MLE_CHILD_ID_REQUEST).must_next().must_verify(
lambda p: {
RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, MLE_FRAME_COUNTER_TLV, MODE_TLV, TIMEOUT_TLV, VERSION_TLV,
ADDRESS_REGISTRATION_TLV, TLV_REQUEST_TLV
} <= set(p.mle.tlv.type))
# Step 6: The DUT MUST respond with ICMPv6 Echo Reply
ed_mleid = pv.vars['ED_MLEID']
router1_mleid = pv.vars['ROUTER_1_MLEID']
_pkt = pkts.range(_ed_pkts.index).filter_ipv6_src_dst(router1_mleid,
ed_mleid).filter_ping_request().must_next()
_ed_pkts.filter_ipv6_src_dst(
ed_mleid, router1_mleid).filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,159 +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
from pktverify.packet_verifier import PacketVerifier
LEADER = 1
ROUTER1 = 2
MTD = 3
# Test Purpose and Description:
# -----------------------------
# The purpose of this test case is to show that the DUT upholds connectivity, or
# reattaches with its parent, when the Leader is removed and the Router creates a
# new partition
#
# Test Topology:
# -------------
# Leader
# |
# Router
# |
# DUT
#
# DUT Types:
# ----------
# ED
# SED
class Cert_6_2_1_NewPartition_Base(thread_cert.TestCase):
USE_MESSAGE_FACTORY = False
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER1]
},
ROUTER1: {
'name': 'ROUTER',
'mode': 'rdn',
'allowlist': [LEADER, MTD]
},
MTD: {
'name': 'DUT',
'is_mtd': True,
'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[ROUTER1].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
self.nodes[MTD].start()
self.simulator.go(5)
self.assertEqual(self.nodes[MTD].get_state(), 'child')
self.nodes[LEADER].stop()
self.simulator.go(150)
self.assertEqual(self.nodes[ROUTER1].get_state(), 'leader')
self.assertEqual(self.nodes[MTD].get_state(), 'child')
self.collect_ipaddrs()
dut_addr = self.nodes[MTD].get_ip6_address(config.ADDRESS_TYPE.LINK_LOCAL)
self.assertTrue(self.nodes[ROUTER1].ping(dut_addr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
ROUTER = pv.vars['ROUTER']
ROUTER_LLA = pv.vars['ROUTER_LLA']
DUT = pv.vars['DUT']
DUT_LLA = pv.vars['DUT_LLA']
# Step 1: Ensure topology is formed correctly
pkts.filter_wpan_src64(LEADER).\
filter_mle_advertisement('Leader').\
must_next()
pv.verify_attached('ROUTER', 'LEADER')
pv.verify_attached('DUT', 'ROUTER', 'MTD')
# Step 3: Router automatically creates new partition and begins transmitting
# MLE Advertisements
pkts.filter_wpan_src64(ROUTER).\
filter_LLARMA().\
filter_mle_cmd(MLE_PARENT_REQUEST).\
must_next()
pkts.filter_wpan_src64(ROUTER).\
filter_mle_advertisement('Router').\
must_next()
# Step 5: Router verifies connectivity by sending an ICMPv6 Echo Request
# to the DUT link local address
# DUT responds with ICMPv6 Echo Reply
_pkt = pkts.filter_ping_request().\
filter_ipv6_src_dst(ROUTER_LLA, DUT_LLA).\
must_next()
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_ipv6_src_dst(DUT_LLA, ROUTER_LLA).\
must_next()
class Cert_6_2_1_NewPartition_ED(Cert_6_2_1_NewPartition_Base):
TOPOLOGY = copy.deepcopy(Cert_6_2_1_NewPartition_Base.TOPOLOGY)
TOPOLOGY[MTD]['mode'] = 'rn'
class Cert_6_2_1_NewPartition_SED(Cert_6_2_1_NewPartition_Base):
TOPOLOGY = copy.deepcopy(Cert_6_2_1_NewPartition_Base.TOPOLOGY)
TOPOLOGY[MTD]['mode'] = '-'
del (Cert_6_2_1_NewPartition_Base)
if __name__ == '__main__':
unittest.main()
@@ -1,122 +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_ADVERTISEMENT, MLE_CHILD_UPDATE_REQUEST, SOURCE_ADDRESS_TLV, MODE_TLV, LEADER_DATA_TLV
from pktverify.packet_verifier import PacketVerifier
LEADER = 1
ROUTER1 = 2
ROUTER2 = 3
ED = 4
class Cert_6_2_2_NewPartition(thread_cert.TestCase):
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER1, ROUTER2]
},
ROUTER1: {
'name': 'ROUTER_1',
'mode': 'rdn',
'allowlist': [LEADER, ROUTER2, ED]
},
ROUTER2: {
'name': 'ROUTER_2',
'mode': 'rdn',
'network_id_timeout': 110,
'allowlist': [LEADER, ROUTER1]
},
ED: {
'name': 'ED',
'is_mtd': True,
'mode': 'rn',
'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[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[ED].start()
self.simulator.go(5)
self.assertEqual(self.nodes[ED].get_state(), 'child')
self.nodes[LEADER].stop()
self.simulator.go(140)
self.assertEqual(self.nodes[ROUTER2].get_state(), 'leader')
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
self.assertEqual(self.nodes[ED].get_state(), 'child')
self.collect_ipaddrs()
addrs = self.nodes[ED].get_addrs()
for addr in addrs:
self.assertTrue(self.nodes[ROUTER1].ping(addr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
ROUTER_1 = pv.vars['ROUTER_1']
ED = pv.vars['ED']
_router1_pkts = pkts.filter_wpan_src64(ROUTER_1)
_ed_pkts = pkts.filter_wpan_src64(ED)
# Step 1: Ensure that the DUT successfully attached to Router_1
_ed_pkts.filter_mle_cmd(MLE_CHILD_ID_REQUEST).filter_wpan_dst64(ROUTER_1).must_next()
# Step 2-6 : remove Leader and make ROUTER_2 as new Leader
# Step 7: The DUT MUST send a MLE Child Update Request to Router_1
_ed_pkts.filter_mle_cmd(MLE_ADVERTISEMENT).must_not_next()
_ed_pkts.filter_mle_cmd(MLE_CHILD_ID_REQUEST).must_not_next()
_ed_pkts.filter_wpan_dst64(ROUTER_1).filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).must_next().must_verify(
lambda p: {MODE_TLV, SOURCE_ADDRESS_TLV, LEADER_DATA_TLV} <= set(p.mle.tlv.type))
# Step 8: The DUT MUST respond with ICMPv6 Echo Reply
_ed_pkts.filter('ipv6.dst == {ROUTER_1_MLEID} and ipv6.src == {ED_MLEID}',
**pv.vars).filter_ping_reply().must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,115 +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_CHILD_ID_REQUEST, MLE_CHILD_UPDATE_REQUEST, SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, MODE_TLV
from pktverify.packet_verifier import PacketVerifier
LEADER = 1
ROUTER = 2
ED = 3
class Cert_6_3_1_OrphanReattach(thread_cert.TestCase):
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER]
},
ROUTER: {
'name': 'ROUTER',
'mode': 'rdn',
'allowlist': [LEADER, ED]
},
ED: {
'name': 'ED',
'is_mtd': True,
'mode': 'rn',
'timeout': 10,
'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[ED].start()
self.simulator.go(5)
self.assertEqual(self.nodes[ED].get_state(), 'child')
self.collect_ipaddrs()
self.nodes[ROUTER].stop()
self.nodes[LEADER].add_allowlist(self.nodes[ED].get_addr64())
self.nodes[ED].add_allowlist(self.nodes[LEADER].get_addr64())
self.simulator.go(20)
self.assertEqual(self.nodes[ED].get_state(), 'child')
addrs = self.nodes[ED].get_addrs()
for addr in addrs:
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']
ED = pv.vars['ED']
_epkts = pkts.filter_wpan_src64(ED)
_epkts.filter_mle_cmd(MLE_CHILD_ID_REQUEST).must_next()
# Step 2: Remove Router from the network
# Step 3: The DUT MUST send three MLE Child Update Requests to its parent
for i in range(1, 3):
_epkts.filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).filter_wpan_dst64(ROUTER).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, MODE_TLV} <= set(p.mle.tlv.type))
# Step 5: The DUT MUST perform the attach procedure with the Leader
_epkts.filter_mle_cmd(MLE_PARENT_REQUEST).must_next()
_epkts.filter_mle_cmd(MLE_CHILD_ID_REQUEST).filter_wpan_dst64(LEADER).must_next()
# Step 6: The DUT MUST respond with ICMPv6 Echo Reply
_epkts.filter('ipv6.src == {ED_MLEID} and ipv6.dst == {LEADER_MLEID}',
**pv.vars).filter_ping_reply().must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,129 +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_REQUEST, MLE_CHILD_UPDATE_REQUEST, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV, MODE_TLV, TIMEOUT_TLV, TLV_REQUEST_TLV, NETWORK_DATA_TLV
from pktverify.packet_verifier import PacketVerifier
LEADER = 1
ED = 2
class Cert_6_3_2_NetworkDataUpdate(thread_cert.TestCase):
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ED]
},
ED: {
'name': 'MED',
'is_mtd': True,
'mode': 'rn',
'timeout': 10,
'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[ED].start()
self.simulator.go(5)
self.assertEqual(self.nodes[ED].get_state(), 'child')
self.nodes[LEADER].add_prefix('2001:2:0:1::/64', 'paros')
self.nodes[LEADER].register_netdata()
# Set lowpan context of sniffer
self.simulator.set_lowpan_context(1, '2001:2:0:1::/64')
self.simulator.go(5)
addrs = self.nodes[ED].get_addrs()
self.assertTrue(any('2001:2:0:1' in addr[0:10] for addr in addrs))
for addr in addrs:
if addr[0:10] == '2001:2:0:1':
self.assertTrue(self.nodes[LEADER].ping(addr))
self.nodes[LEADER].remove_allowlist(self.nodes[ED].get_addr64())
self.nodes[ED].remove_allowlist(self.nodes[LEADER].get_addr64())
self.nodes[LEADER].add_prefix('2001:2:0:2::/64', 'paros')
self.nodes[LEADER].register_netdata()
# Set lowpan context of sniffer
self.simulator.set_lowpan_context(2, '2001:2:0:2::/64')
self.simulator.go(5)
self.nodes[LEADER].add_allowlist(self.nodes[ED].get_addr64())
self.nodes[ED].add_allowlist(self.nodes[LEADER].get_addr64())
self.simulator.go(10)
addrs = self.nodes[ED].get_addrs()
self.assertTrue(any('2001:2:0:1' in addr[0:10] for addr in addrs))
self.assertTrue(any('2001:2:0:2' in addr[0:10] for addr in addrs))
for addr in addrs:
if addr[0:10] == '2001:2:0:1' or addr[0:10] == '2001:2:0:2':
self.assertTrue(self.nodes[LEADER].ping(addr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
MED = pv.vars['MED']
_epkts = pkts.filter_wpan_src64(MED)
# Step 1: Ensure the topology is formed correctly
pkts.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).filter_wpan_src64(LEADER).must_next()
# Step 3: The DUT MUST send a MLE Child Update Request to the Leader
_epkts.range(pkts.index).filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).must_next().must_verify(
lambda p: p.wpan.dst64 == LEADER and {LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV, MODE_TLV, TIMEOUT_TLV
} <= set(p.mle.tlv.type))
# Step 10: The DUT MUST send a MLE Data Request frame to
# request the updated Network Data
_epkts.filter_mle_cmd(MLE_DATA_REQUEST).must_next().must_verify(
lambda p: {TLV_REQUEST_TLV, NETWORK_DATA_TLV} <= set(p.mle.tlv.type))
# Step 12: The DUT MUST send a MLE Child Update Request to the Leader
_epkts.filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).filter_wpan_dst64(LEADER).must_next().must_verify(
lambda p: {ADDRESS_REGISTRATION_TLV, MODE_TLV, TIMEOUT_TLV} <= set(p.mle.tlv.type))
if __name__ == '__main__':
unittest.main()
@@ -1,206 +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 LINK_LOCAL_ALL_THREAD_NODES_MULTICAST_ADDRESS
from pktverify.packet_verifier import PacketVerifier
LEADER = 1
MTD = 2
FRAGMENTED_DATA_LEN = 256
# Test Purpose and Description:
# -----------------------------
# The purpose of this test case is to validate the Link-Local addresses
# that the DUT auto-configures.
#
# Test Topology:
# -------------
# Leader
# |
# DUT
#
# DUT Types:
# ----------
# ED
# SED
class Cert_6_4_1_LinkLocal_Base(thread_cert.TestCase):
USE_MESSAGE_FACTORY = False
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [MTD]
},
MTD: {
'name': 'DUT',
'is_mtd': True,
'timeout': config.DEFAULT_CHILD_TIMEOUT,
'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[MTD].start()
self.simulator.go(5)
self.assertEqual(self.nodes[MTD].get_state(), 'child')
self.collect_ipaddrs()
dut_addr = self.nodes[MTD].get_ip6_address(config.ADDRESS_TYPE.LINK_LOCAL)
self.assertTrue(self.nodes[LEADER].ping(dut_addr, size=FRAGMENTED_DATA_LEN))
self.simulator.go(1)
self.assertTrue(self.nodes[LEADER].ping(dut_addr))
self.simulator.go(1)
self.assertTrue(self.nodes[LEADER].ping(config.LINK_LOCAL_ALL_THREAD_NODES_MULTICAST_ADDRESS,
size=FRAGMENTED_DATA_LEN))
self.simulator.go(1)
self.assertTrue(self.nodes[LEADER].ping(config.LINK_LOCAL_ALL_THREAD_NODES_MULTICAST_ADDRESS))
self.simulator.go(1)
if self.TOPOLOGY[MTD]['mode'] == 'rn':
self.assertTrue(self.nodes[LEADER].ping(config.LINK_LOCAL_ALL_NODES_ADDRESS, size=FRAGMENTED_DATA_LEN))
self.simulator.go(1)
self.assertTrue(self.nodes[LEADER].ping(config.LINK_LOCAL_ALL_NODES_ADDRESS))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
LEADER_LLA = pv.vars['LEADER_LLA']
DUT_LLA = pv.vars['DUT_LLA']
# Step 1: Ensure topology is formed correctly
pv.verify_attached('DUT', 'LEADER', 'MTD')
# Step 2: Leader sends a Fragmented ICMPv6 Echo Request to DUTs
# MAC extended address based Link-Local address
# The DUT MUST respond with an ICMPv6 Echo Reply
_pkt = pkts.filter_ping_request().\
filter_ipv6_src_dst(LEADER_LLA, DUT_LLA).\
filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\
must_next()
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_ipv6_src_dst(DUT_LLA, LEADER_LLA).\
filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\
must_next()
# Step 3: Leader sends an Unfragmented ICMPv6 Echo Request to DUTs
# MAC extended address based Link-Local address
# The DUT MUST respond with an ICMPv6 Echo Reply
_pkt = pkts.filter_ping_request().\
filter_ipv6_src_dst(LEADER_LLA, DUT_LLA).\
must_next()
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_ipv6_src_dst(DUT_LLA, LEADER_LLA).\
must_next()
# Step 4: Leader sends a Fragmented ICMPv6 Echo Request to the
# Link-Local All thread nodes multicast address
# The DUT MUST respond with an ICMPv6 Echo Reply
_pkt = pkts.filter_ping_request().\
filter_wpan_src64(LEADER).\
filter_LLATNMA().\
filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\
must_next()
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_ipv6_src_dst(DUT_LLA, LEADER_LLA).\
filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\
must_next()
# Step 5: Leader sends an Unfragmented ICMPv6 Echo Request to the
# Link-Local All thread nodes multicast address
# The DUT MUST respond with an ICMPv6 Echo Reply
_pkt = pkts.filter_ping_request().\
filter_wpan_src64(LEADER).\
filter_LLATNMA().\
must_next()
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_ipv6_src_dst(DUT_LLA, LEADER_LLA).\
must_next()
if self.TOPOLOGY[MTD]['mode'] == 'rn':
# Step 6: Leader sends a Fragmented ICMPv6 Echo Request to the
# Link-Local All Nodes multicast address (FF02::1)
# The DUT MUST respond with an ICMPv6 Echo Reply
_pkt = pkts.filter_ping_request().\
filter_wpan_src64(LEADER).\
filter_LLANMA().\
filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\
must_next()
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_ipv6_src_dst(DUT_LLA, LEADER_LLA).\
filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\
must_next()
# Step 7: Leader sends an Unfragmented ICMPv6 Echo Request to the
# Link-Local All Nodes multicast address (FF02::1)
# The DUT MUST respond with an ICMPv6 Echo Reply
_pkt = pkts.filter_ping_request().\
filter_wpan_src64(LEADER).\
filter_LLANMA().\
must_next()
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_ipv6_src_dst(DUT_LLA, LEADER_LLA).\
must_next()
class Cert_6_4_1_LinkLocal_ED(Cert_6_4_1_LinkLocal_Base):
TOPOLOGY = copy.deepcopy(Cert_6_4_1_LinkLocal_Base.TOPOLOGY)
TOPOLOGY[MTD]['mode'] = 'rn'
class Cert_6_4_1_LinkLocal_SED(Cert_6_4_1_LinkLocal_Base):
TOPOLOGY = copy.deepcopy(Cert_6_4_1_LinkLocal_Base.TOPOLOGY)
TOPOLOGY[MTD]['mode'] = '-'
del (Cert_6_4_1_LinkLocal_Base)
if __name__ == '__main__':
unittest.main()
@@ -1,250 +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.packet_verifier import PacketVerifier
LEADER = 1
ROUTER = 2
MTD = 3
FRAGMENTED_DATA_LEN = 256
# Test Purpose and Description:
# -----------------------------
# The purpose of this test case is to validate the Realm-Local addresses
# that the DUT configures.
#
# Test Topology:
# -------------
# Leader
# |
# Router
# |
# DUT
#
# DUT Types:
# ----------
# ED
# SED
class Cert_6_4_2_RealmLocal_Base(thread_cert.TestCase):
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER]
},
ROUTER: {
'name': 'ROUTER',
'mode': 'rdn',
'allowlist': [LEADER, MTD]
},
MTD: {
'name': 'DUT',
'is_mtd': True,
'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[ROUTER].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER].get_state(), 'router')
self.nodes[MTD].start()
self.simulator.go(5)
self.assertEqual(self.nodes[MTD].get_state(), 'child')
self.collect_ipaddrs()
self.collect_rloc16s()
dut_addr = self.nodes[MTD].get_ip6_address(config.ADDRESS_TYPE.ML_EID)
self.assertTrue(self.nodes[LEADER].\
ping(dut_addr,
size=FRAGMENTED_DATA_LEN))
self.simulator.go(1)
self.assertTrue(self.nodes[LEADER].\
ping(dut_addr))
self.simulator.go(1)
if self.TOPOLOGY[MTD]['mode'] == 'rn':
self.assertTrue(self.nodes[LEADER].\
ping(config.REALM_LOCAL_ALL_NODES_ADDRESS,
num_responses=2,
size=FRAGMENTED_DATA_LEN))
self.simulator.go(2)
self.assertTrue(self.nodes[LEADER].\
ping(config.REALM_LOCAL_ALL_NODES_ADDRESS,
num_responses=2))
self.simulator.go(2)
self.assertTrue(self.nodes[LEADER].\
ping(config.REALM_LOCAL_ALL_THREAD_NODES_MULTICAST_ADDRESS,
num_responses=2,
size=FRAGMENTED_DATA_LEN))
self.simulator.go(2)
self.assertTrue(self.nodes[LEADER].\
ping(config.REALM_LOCAL_ALL_THREAD_NODES_MULTICAST_ADDRESS,
num_responses=2))
self.simulator.go(2)
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
LEADER_MLEID = pv.vars['LEADER_MLEID']
ROUTER = pv.vars['ROUTER']
ROUTER_MLEID = pv.vars['ROUTER_MLEID']
ROUTER_RLOC16 = pv.vars['ROUTER_RLOC16']
DUT = pv.vars['DUT']
DUT_MLEID = pv.vars['DUT_MLEID']
DUT_RLOC16 = pv.vars['DUT_RLOC16']
# Step 1: Ensure topology is formed correctly
pv.verify_attached('ROUTER', 'LEADER')
pv.verify_attached('DUT', 'ROUTER', 'MTD')
# Step 2: Leader sends a Fragmented ICMPv6 Echo Request to
# DUT's ML-EID
# The DUT MUST respond with an ICMPv6 Echo Reply
_pkt = pkts.filter_ping_request().\
filter_ipv6_src_dst(LEADER_MLEID, DUT_MLEID).\
filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\
must_next()
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_ipv6_src_dst(DUT_MLEID, LEADER_MLEID).\
filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\
must_next()
# Step 3: Leader sends an Unfragmented ICMPv6 Echo Request to
# DUTs ML-EID
# The DUT MUST respond with an ICMPv6 Echo Reply
_pkt = pkts.filter_ping_request().\
filter_ipv6_src_dst(LEADER_MLEID, DUT_MLEID).\
must_next()
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_ipv6_src_dst(DUT_MLEID, LEADER_MLEID).\
must_next()
if self.TOPOLOGY[MTD]['mode'] == 'rn':
# Step 4: Leader sends a Fragmented ICMPv6 Echo Request to the
# Realm-Local All Nodes multicast address (FF03::1)
# The DUT MUST respond with an ICMPv6 Echo Reply
_pkt1 = pkts.filter_ping_request().\
filter_wpan_src64(LEADER).\
filter_RLANMA().\
filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\
must_next()
with pkts.save_index():
pkts.filter_ping_reply(identifier=_pkt1.icmpv6.echo.identifier).\
filter_ipv6_src_dst(ROUTER_MLEID, LEADER_MLEID).\
filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\
must_next()
pkts.filter_ping_request(identifier=_pkt1.icmpv6.echo.identifier).\
filter_wpan_src16_dst16(ROUTER_RLOC16, DUT_RLOC16).\
filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\
must_not_next()
# Step 5: Leader sends an Unfragmented ICMPv6 Echo Request to the
# Realm-Local All Nodes multicast address (FF03::1)
# The DUT MUST respond with an ICMPv6 Echo Reply
_pkt2 = pkts.filter_ping_request().\
filter_wpan_src64(LEADER).\
filter_RLANMA().\
filter(lambda p: p.icmpv6.echo.sequence_number !=
_pkt1.icmpv6.echo.sequence_number
).\
must_next()
with pkts.save_index():
pkts.filter_ping_reply(identifier=_pkt2.icmpv6.echo.identifier).\
filter_ipv6_src_dst(ROUTER_MLEID, LEADER_MLEID).\
must_next()
pkts.filter_ping_request(identifier = _pkt2.icmpv6.echo.identifier).\
filter_wpan_src16_dst16(ROUTER_RLOC16, DUT_RLOC16).\
must_not_next()
# Step 6: Leader sends a Fragmented ICMPv6 Echo Request to the
# Realm-Local All Thread Nodes multicast address
# The DUT MUST respond with an ICMPv6 Echo Reply
_pkt = pkts.filter_ping_request().\
filter_wpan_src64(LEADER).\
filter_RLATNMA().\
filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\
must_next()
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_wpan_src64(DUT).\
filter_ipv6_dst(LEADER_MLEID).\
filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\
must_next()
# Step 7: Leader sends an Unfragmented ICMPv6 Echo Request to the
# Realm-Local All Thread Nodes multicast address
# The DUT MUST respond with an ICMPv6 Echo Reply
_pkt = pkts.filter_ping_request().\
filter_wpan_src64(LEADER).\
filter_RLATNMA().\
filter(lambda p: p.icmpv6.data.len != FRAGMENTED_DATA_LEN).\
must_next()
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_wpan_src64(DUT).\
filter_ipv6_dst(LEADER_MLEID).\
must_next()
class Cert_6_4_2_RealmLocal_ED(Cert_6_4_2_RealmLocal_Base):
TOPOLOGY = copy.deepcopy(Cert_6_4_2_RealmLocal_Base.TOPOLOGY)
TOPOLOGY[MTD]['mode'] = 'rn'
class Cert_6_4_2_RealmLocal_SED(Cert_6_4_2_RealmLocal_Base):
TOPOLOGY = copy.deepcopy(Cert_6_4_2_RealmLocal_Base.TOPOLOGY)
TOPOLOGY[MTD]['mode'] = '-'
del (Cert_6_4_2_RealmLocal_Base)
if __name__ == '__main__':
unittest.main()
@@ -1,114 +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_CHILD_ID_REQUEST, MLE_CHILD_UPDATE_REQUEST, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, MLE_FRAME_COUNTER_TLV, MODE_TLV, TIMEOUT_TLV, VERSION_TLV, ADDRESS_REGISTRATION_TLV, TLV_REQUEST_TLV
from pktverify.packet_verifier import PacketVerifier
LEADER = 1
ED = 2
class Cert_6_5_1_ChildResetReattach(thread_cert.TestCase):
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ED]
},
ED: {
'name': 'ED',
'is_mtd': True,
'mode': 'rn',
'allowlist': [LEADER]
},
}
def _setUpEd(self):
self.nodes[ED].add_allowlist(self.nodes[LEADER].get_addr64())
self.nodes[ED].enable_allowlist()
def test(self):
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ED].start()
self.simulator.go(5)
self.assertEqual(self.nodes[ED].get_state(), 'child')
self.nodes[LEADER].remove_allowlist(self.nodes[ED].get_addr64())
self.nodes[ED].remove_allowlist(self.nodes[LEADER].get_addr64())
self.nodes[ED].reset()
self._setUpEd()
self.simulator.go(5)
self.nodes[ED].start()
self.simulator.go(5)
self.nodes[LEADER].add_allowlist(self.nodes[ED].get_addr64())
self.simulator.go(5)
self.assertEqual(self.nodes[ED].get_state(), 'child')
addrs = self.nodes[ED].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']
ED = pv.vars['ED']
_ed_pkts = pkts.filter_wpan_src64(ED)
# Step 2: Reset the DUT for a time greater than
# the Child Timeout Duration.
# Step 3: Send MLE Child Update Request to Leader
_ed_pkts.filter_mle_cmd(MLE_CHILD_ID_REQUEST).must_next()
_ed_pkts.filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).must_next().must_verify(
lambda p: {MODE_TLV} <= set(p.mle.tlv.type))
# Step 5: DUT reattaches to Leader
_ed_pkts.filter_mle_cmd(MLE_CHILD_ID_REQUEST).must_next().must_verify(
lambda p: {
RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, MLE_FRAME_COUNTER_TLV, MODE_TLV, TIMEOUT_TLV, VERSION_TLV,
ADDRESS_REGISTRATION_TLV, TLV_REQUEST_TLV
} <= set(p.mle.tlv.type))
# Step 6: The DUT MUST respond with ICMPv6 Echo Reply
_ed_pkts.filter_ping_reply().filter(lambda p: p.wpan.src64 == ED and p.wpan.dst64 == LEADER).must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,262 +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 thread_cert
import config
from pktverify.consts import WPAN_DATA_REQUEST, MLE_PARENT_REQUEST, MLE_PARENT_RESPONSE, MLE_CHILD_UPDATE_REQUEST, MLE_CHILD_UPDATE_RESPONSE, MLE_CHILD_ID_REQUEST, MLE_CHILD_ID_RESPONSE, ADDR_SOL_URI, SOURCE_ADDRESS_TLV, MODE_TLV, TIMEOUT_TLV, CHALLENGE_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, MLE_FRAME_COUNTER_TLV, ROUTE64_TLV, ADDRESS16_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, TLV_REQUEST_TLV, SCAN_MASK_TLV, CONNECTIVITY_TLV, LINK_MARGIN_TLV, VERSION_TLV, ADDRESS_REGISTRATION_TLV, NL_MAC_EXTENDED_ADDRESS_TLV, NL_RLOC16_TLV, NL_STATUS_TLV, NL_ROUTER_MASK_TLV, COAP_CODE_ACK
from pktverify.packet_verifier import PacketVerifier
from pktverify.null_field import nullField
LEADER = 1
ROUTER = 2
MTD = 3
POLL_PERIOD = 3 # seconds
# Test Purpose and Description:
# -----------------------------
# The purpose of this test case is to validate that after the DUT resets and receives
# no response from its parent, it will reattach to the network through a different parent.
#
# Test Topology:
# -------------
# Leader
# |
# Router
# |
# DUT
#
# DUT Types:
# ----------
# ED
# SED
class Cert_6_5_2_ChildResetReattach_Base(thread_cert.TestCase):
USE_MESSAGE_FACTORY = False
SUPPORT_NCP = False
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER]
},
ROUTER: {
'name': 'ROUTER',
'mode': 'rdn',
'allowlist': [LEADER, MTD]
},
MTD: {
'name': 'DUT',
'is_mtd': True,
'timeout': config.DEFAULT_CHILD_TIMEOUT,
'allowlist': [ROUTER]
},
}
def _setUpMTD(self):
self.nodes[MTD].add_allowlist(self.nodes[LEADER].get_addr64())
self.nodes[MTD].enable_allowlist()
if self.TOPOLOGY[MTD]['mode'] == '-':
self.nodes[MTD].set_pollperiod(POLL_PERIOD * 1000)
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[MTD].start()
self.simulator.go(5)
self.assertEqual(self.nodes[MTD].get_state(), 'child')
self.collect_rloc16s()
self.nodes[LEADER].clear_allowlist()
self.nodes[MTD].clear_allowlist()
self.nodes[ROUTER].stop()
self.nodes[MTD].reset()
self._setUpMTD()
self.simulator.go(5)
self.nodes[LEADER].add_allowlist(self.nodes[MTD].get_addr64())
self.simulator.go(5)
self.nodes[MTD].start()
self.simulator.go(10)
self.assertEqual(self.nodes[MTD].get_state(), 'child')
self.simulator.go(360)
self.collect_ipaddrs()
dut_addr = self.nodes[MTD].get_ip6_address(config.ADDRESS_TYPE.LINK_LOCAL)
self.nodes[LEADER].ping(dut_addr)
self.simulator.go(15)
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
LEADER_LLA = pv.vars['LEADER_LLA']
ROUTER = pv.vars['ROUTER']
ROUTER_RLOC16 = pv.vars['ROUTER_RLOC16']
DUT = pv.vars['DUT']
DUT_LLA = pv.vars['DUT_LLA']
# Step 1: Ensure topology is formed correctly
pv.verify_attached('ROUTER', 'LEADER')
pv.verify_attached('DUT', 'ROUTER', 'MTD')
# Step 4: DUT sends an MLE Child Update Request.
# The following TLVs MUST be included in the Child Update
# Request:
# - Mode TLV
# - Address Registration TLV (optional)
# If the DUT is a SED, it MUST resume polling after sending
# MLE Child Update.
pkts.filter_wpan_src64(DUT).\
filter_wpan_dst64(ROUTER).\
filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).\
filter(lambda p: {
MODE_TLV
} <= set(p.mle.tlv.type)
).\
must_next()
if self.TOPOLOGY[MTD]['mode'] == '-':
_pkt = pkts.filter_wpan_src64(DUT).\
filter_wpan_dst16(ROUTER_RLOC16).\
filter_wpan_cmd(WPAN_DATA_REQUEST).\
must_next()
pkts.filter_wpan_src64(DUT).\
filter_wpan_dst16(ROUTER_RLOC16).\
filter_wpan_cmd(WPAN_DATA_REQUEST).\
filter(lambda p:
p.sniff_timestamp - _pkt.sniff_timestamp <=
POLL_PERIOD + 0.1
).\
must_next()
lstart = pkts.index
# Step 6: The DUT MUST attach to the Leader
pkts.filter_wpan_src64(DUT).\
filter_LLARMA().\
filter_mle_cmd(MLE_PARENT_REQUEST).\
filter(lambda p: {
CHALLENGE_TLV,
MODE_TLV,
SCAN_MASK_TLV,
VERSION_TLV
} <= set(p.mle.tlv.type) and\
p.ipv6.hlim == 255 and\
p.mle.tlv.scan_mask.r == 1 and\
p.mle.tlv.scan_mask.e == 0 and\
p.wpan.aux_sec.key_id_mode == 0x2
).\
must_next()
lend = pkts.index
# Step 5: No response from Router.
pkts.range(lstart, lend).\
filter_wpan_dst64(ROUTER).\
filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).\
must_not_next()
pkts.filter_wpan_src64(LEADER).\
filter_wpan_dst64(DUT).\
filter_mle_cmd(MLE_PARENT_RESPONSE).\
filter(lambda p: {
CHALLENGE_TLV,
CONNECTIVITY_TLV,
LEADER_DATA_TLV,
LINK_LAYER_FRAME_COUNTER_TLV,
LINK_MARGIN_TLV,
RESPONSE_TLV,
SOURCE_ADDRESS_TLV,
VERSION_TLV
} <= set(p.mle.tlv.type)).\
must_next()
pkts.filter_wpan_src64(DUT).\
filter_wpan_dst64(LEADER).\
filter_mle_cmd(MLE_CHILD_ID_REQUEST).\
filter(lambda p: {
ADDRESS_REGISTRATION_TLV,
LINK_LAYER_FRAME_COUNTER_TLV,
MODE_TLV,
RESPONSE_TLV,
TIMEOUT_TLV,
TLV_REQUEST_TLV,
VERSION_TLV
} <= set(p.mle.tlv.type) and\
p.wpan.aux_sec.key_id_mode == 0x2
).\
must_next()
pkts.filter_wpan_src64(LEADER).\
filter_wpan_dst64(DUT).\
filter_mle_cmd(MLE_CHILD_ID_RESPONSE).\
filter(lambda p: {
ADDRESS16_TLV,
LEADER_DATA_TLV,
NETWORK_DATA_TLV,
SOURCE_ADDRESS_TLV
} <= set(p.mle.tlv.type)
).\
must_next()
# Step 7: Leader Verifies connectivity by sending an ICMPv6 Echo Request
# to the DUT link local address
# The End Device MUST respond with ICMPv6 Echo Reply
_pkt = pkts.filter_ping_request().\
filter_ipv6_src_dst(LEADER_LLA, DUT_LLA).\
must_next()
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_ipv6_src_dst(DUT_LLA, LEADER_LLA).\
must_next()
class Cert_6_5_2_ChildResetReattach_ED(Cert_6_5_2_ChildResetReattach_Base):
TOPOLOGY = copy.deepcopy(Cert_6_5_2_ChildResetReattach_Base.TOPOLOGY)
TOPOLOGY[MTD]['mode'] = 'rn'
class Cert_6_5_2_ChildResetReattach_SED(Cert_6_5_2_ChildResetReattach_Base):
TOPOLOGY = copy.deepcopy(Cert_6_5_2_ChildResetReattach_Base.TOPOLOGY)
TOPOLOGY[MTD]['mode'] = '-'
del (Cert_6_5_2_ChildResetReattach_Base)
if __name__ == '__main__':
unittest.main()
@@ -1,109 +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_CHILD_UPDATE_REQUEST, MLE_CHILD_UPDATE_RESPONSE, MODE_TLV
from pktverify.packet_verifier import PacketVerifier
LEADER = 1
ED = 2
class Cert_6_5_3_ChildResetSynchronize(thread_cert.TestCase):
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ED]
},
ED: {
'name': 'ED',
'is_mtd': True,
'mode': 'rn',
'timeout': config.DEFAULT_CHILD_TIMEOUT,
'allowlist': [LEADER]
},
}
def _setUpEd(self):
self.nodes[ED].add_allowlist(self.nodes[LEADER].get_addr64())
self.nodes[ED].enable_allowlist()
def test(self):
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[ED].start()
self.simulator.go(5)
self.assertEqual(self.nodes[ED].get_state(), 'child')
self.nodes[ED].reset()
self._setUpEd()
self.simulator.go(1)
self.nodes[ED].start()
self.simulator.go(1)
self.assertEqual(self.nodes[ED].get_state(), 'child')
addrs = self.nodes[ED].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']
ED = pv.vars['ED']
_leader_pkts = pkts.filter_wpan_src64(LEADER)
_ed_pkts = pkts.filter_wpan_src64(ED)
# Step 2: Reset the DUT for a time shorter than
# the Child Timeout Duration.
# Step 3: Send MLE Child Update Request to Leader
_ed_pkts.filter_mle_cmd(MLE_CHILD_ID_REQUEST).must_next()
_leader_pkts.range(_ed_pkts.index).filter_mle_cmd(MLE_CHILD_ID_RESPONSE).must_next()
_ed_pkts.filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).must_next().must_verify(
lambda p: {MODE_TLV} <= set(p.mle.tlv.type))
# Step 4: Leader send an MLE Child Update Response
_leader_pkts.range(_ed_pkts.index).filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).must_next()
_ed_pkts.range(_leader_pkts.index).filter_mle_cmd(MLE_CHILD_ID_REQUEST).must_not_next()
# Step 5: The DUT MUST respond with ICMPv6 Echo Reply
_ed_pkts.filter_ping_reply().filter(lambda p: p.wpan.src64 == ED and p.wpan.dst64 == LEADER).must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,127 +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_REQUEST
from pktverify.packet_verifier import PacketVerifier
LEADER = 1
ED = 2
class Cert_6_6_1_KeyIncrement(thread_cert.TestCase):
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ED]
},
ED: {
'name': 'ED',
'is_mtd': True,
'mode': 'rn',
'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[ED].start()
self.simulator.go(5)
self.assertEqual(self.nodes[ED].get_state(), "child")
self.collect_rloc16s()
addrs = self.nodes[ED].get_addrs()
for addr in addrs:
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[ED].get_addrs()
for addr in addrs:
self.assertTrue(self.nodes[LEADER].ping(addr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
ED = pv.vars['ED']
_leader_pkts = pkts.filter_wpan_src64(LEADER)
_ed_pkts = pkts.filter_wpan_src64(ED)
# 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
_ed_pkts.filter_mle_cmd(
MLE_CHILD_ID_REQUEST).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 DUT.
# The MAC Auxiliary security header must contain
# KeyIndex = 1, KeyID Mode = 1
lp = _leader_pkts.filter_ping_request().filter(
lambda p: p.wpan.aux_sec.key_index == 1 and p.wpan.aux_sec.key_id_mode == 1 and p.wpan.dst16 == pv.vars[
'ED_RLOC16']).must_next()
# Step 4: DUT send an ICMPv6 Echo Reply to Leader.
# The MAC Auxiliary security header must contain
# KeyIndex = 1, KeyID Mode = 1
_ed_pkts.filter_ping_reply(identifier=lp.icmpv6.echo.identifier).must_next().must_verify(
lambda p: p.wpan.aux_sec.key_index == 1 and p.wpan.aux_sec.key_id_mode == 1)
# Step 5: Leader increment thrKeySequenceCounter by 1 to force a key switch.
# Step 6: Leader Send an ICMPv6 Echo Request to DUT.
# The MAC Auxiliary security header must contain
# KeyIndex = 2, KeyID Mode = 1
lp = _leader_pkts.filter_ping_request().filter(
lambda p: p.wpan.aux_sec.key_index == 2 and p.wpan.aux_sec.key_id_mode == 1 and p.wpan.dst16 == pv.vars[
'ED_RLOC16']).must_next()
# Step 7: DUT send an ICMPv6 Echo Reply to Leader.
# The MAC Auxiliary security header must contain
# KeyIndex = 2, KeyID Mode = 1
_ed_pkts.filter_ping_reply(identifier=lp.icmpv6.echo.identifier).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,128 +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_REQUEST
from pktverify.packet_verifier import PacketVerifier
LEADER = 1
ED = 2
class Cert_6_6_2_KeyIncrement1(thread_cert.TestCase):
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'key_sequence_counter': 127,
'mode': 'rdn',
'allowlist': [ED]
},
ED: {
'name': 'ED',
'is_mtd': True,
'mode': 'rn',
'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[ED].start()
self.simulator.go(5)
self.assertEqual(self.nodes[ED].get_state(), 'child')
self.collect_rloc16s()
addrs = self.nodes[ED].get_addrs()
for addr in addrs:
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[ED].get_addrs()
for addr in addrs:
self.assertTrue(self.nodes[LEADER].ping(addr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
ED = pv.vars['ED']
_leader_pkts = pkts.filter_wpan_src64(LEADER)
_ed_pkts = pkts.filter_wpan_src64(ED)
# Step 1: The DUT must start the network using
# thrKeySequenceCounter = 127
_leader_pkts.filter_mle_cmd(MLE_ADVERTISEMENT).must_next().must_verify(
lambda p: p.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
_ed_pkts.filter_mle_cmd(
MLE_CHILD_ID_REQUEST).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 DUT.
# The MAC Auxiliary security header must contain
# KeyIndex = 128, KeyID Mode = 1
lp = _leader_pkts.filter_ping_request().filter(
lambda p: p.wpan.aux_sec.key_index == 128 and p.wpan.aux_sec.key_id_mode == 1 and p.wpan.dst16 == pv.vars[
'ED_RLOC16']).must_next()
# Step 4: DUT send an ICMPv6 Echo Reply to Leader.
# The MAC Auxiliary security header must contain
# KeyIndex = 128, KeyID Mode = 1
_ed_pkts.filter_ping_reply(identifier=lp.icmpv6.echo.identifier).must_next().must_verify(
lambda p: p.wpan.aux_sec.key_index == 128 and p.wpan.aux_sec.key_id_mode == 1)
# Step 5: Leader increment thrKeySequenceCounter by 1 to force a key switch.
# Step 6: Leader Send an ICMPv6 Echo Request to DUT.
# The MAC Auxiliary security header must contain
# KeyIndex = 1, KeyID Mode = 1
lp = _leader_pkts.filter_ping_request().filter(
lambda p: p.wpan.aux_sec.key_index == 1 and p.wpan.aux_sec.key_id_mode == 1 and p.wpan.dst16 == pv.vars[
'ED_RLOC16']).must_next()
# Step 7: DUT send an ICMPv6 Echo Reply to Leader.
# The MAC Auxiliary security header must contain
# KeyIndex = 1, KeyID Mode = 1
_ed_pkts.filter_ping_reply(identifier=lp.icmpv6.echo.identifier).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,296 +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 WIRESHARK_OVERRIDE_PREFS, MLE_CHILD_UPDATE_REQUEST, MLE_CHILD_UPDATE_RESPONSE, MLE_CHILD_ID_REQUEST, MLE_CHILD_ID_RESPONSE, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, MODE_TLV, TIMEOUT_TLV, VERSION_TLV, TLV_REQUEST_TLV, ADDRESS16_TLV, NETWORK_DATA_TLV, ROUTE64_TLV, MODE_TLV, TIMEOUT_TLV, CHALLENGE_TLV, SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV
from pktverify.packet_verifier import PacketVerifier
from pktverify.addrs import Ipv6Addr
LEADER = 1
ROUTER = 2
SED1 = 3
MED1 = 4
MTDS = [SED1, MED1]
PREFIX_2001 = '2001::/64'
PREFIX_2002 = '2002::/64'
# Test Purpose and Description:
# -----------------------------
# The purpose of this test case is to verify that the DUT, as a Border Router,
# acts properly as a Leader device in a Thread network, correctly sets the
# Network Data (stable/non-stable) and successfully propagates the Network Data
# to the devices that attach to it.
#
# Test Topology:
# -------------
# SED
# |
# ROUTER - Leader(DUT) - MED
#
# DUT Types:
# ----------
# Leader
class Cert_7_1_1_BorderRouterAsLeader(thread_cert.TestCase):
USE_MESSAGE_FACTORY = False
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER, SED1, MED1]
},
ROUTER: {
'name': 'ROUTER',
'mode': 'rdn',
'allowlist': [LEADER]
},
SED1: {
'name': 'SED',
'is_mtd': True,
'mode': '-',
'timeout': config.DEFAULT_CHILD_TIMEOUT,
'allowlist': [LEADER]
},
MED1: {
'name': 'MED',
'is_mtd': True,
'mode': 'rn',
'allowlist': [LEADER]
},
}
# override wireshark preferences with case needed parameters
CASE_WIRESHARK_PREFS = copy.deepcopy(WIRESHARK_OVERRIDE_PREFS)
CASE_WIRESHARK_PREFS['6lowpan.context1'] = PREFIX_2001
CASE_WIRESHARK_PREFS['6lowpan.context2'] = PREFIX_2002
def test(self):
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[LEADER].add_prefix(PREFIX_2001, 'paros')
self.nodes[LEADER].add_prefix(PREFIX_2002, 'paro')
self.nodes[LEADER].register_netdata()
self.nodes[ROUTER].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER].get_state(), 'router')
self.nodes[SED1].start()
self.simulator.go(5)
self.assertEqual(self.nodes[SED1].get_state(), 'child')
self.nodes[MED1].start()
self.simulator.go(5)
self.assertEqual(self.nodes[MED1].get_state(), 'child')
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']
# Step 1: The DUT forms the network properly sends MLE Advertisements
pkts.filter_wpan_src64(LEADER).\
filter_mle_advertisement('Leader').\
must_next()
# Step 3: Router attaches to the Leader (DUT) and requests complete
# network data
pkts.filter_wpan_src64(ROUTER).\
filter_wpan_dst64(LEADER).\
filter_mle_cmd(MLE_CHILD_ID_REQUEST).\
filter(lambda p: {
RESPONSE_TLV,
LINK_LAYER_FRAME_COUNTER_TLV,
MODE_TLV,
TIMEOUT_TLV,
VERSION_TLV,
TLV_REQUEST_TLV,
ADDRESS16_TLV,
NETWORK_DATA_TLV,
ROUTE64_TLV
} <= set(p.mle.tlv.type) and\
p.mle.tlv.mode.network_data == 1
).\
must_next()
# Step 4: The DUT MUST send a MLE Child ID Response to Router,
# including the following TLVs:
# - Network Data TLV
# At least two Prefix TLVs (Prefix 1 and Prefix 2),
# each including:
# - 6LoWPAN ID sub-TLV
# - Border Router sub-TLV
pkts.filter_wpan_src64(LEADER).\
filter_wpan_dst64(ROUTER).\
filter_mle_cmd(MLE_CHILD_ID_RESPONSE).\
filter(lambda p: {
Ipv6Addr(PREFIX_2001[:-3]),
Ipv6Addr(PREFIX_2002[:-3])
} == set(p.thread_nwd.tlv.prefix) and\
p.thread_nwd.tlv.border_router.flag.p == [1, 1] and\
p.thread_nwd.tlv.border_router.flag.s == [1, 1] and\
p.thread_nwd.tlv.border_router.flag.r == [1, 1] and\
p.thread_nwd.tlv.border_router.flag.o == [1, 1] and\
p.thread_nwd.tlv.stable == [0, 1, 1, 1, 0, 0, 0]
).\
must_next()
# Step 5: SED attaches to the Leader (DUT) and requests only stable
# network data
pkts.filter_wpan_src64(SED).\
filter_wpan_dst64(LEADER).\
filter_mle_cmd(MLE_CHILD_ID_REQUEST).\
filter(lambda p: {
RESPONSE_TLV,
LINK_LAYER_FRAME_COUNTER_TLV,
MODE_TLV,
TIMEOUT_TLV,
VERSION_TLV,
TLV_REQUEST_TLV,
ADDRESS16_TLV,
NETWORK_DATA_TLV,
ADDRESS_REGISTRATION_TLV
} <= set(p.mle.tlv.type) and\
p.mle.tlv.mode.network_data == 0
).\
must_next()
# Step 6: The DUT MUST send a MLE Child ID Response to SED,
# including the following TLVs:
# - Network Data TLV
# At least one Prefix TLVs (Prefix 1),including:
# - 6LoWPAN ID sub-TLV
# - Border Router sub-TLV
# - P_border_router_16 <0xFFFE>
# Prefix 2 TLV MUST NOT be included
pkts.filter_wpan_src64(LEADER).\
filter_wpan_dst64(SED).\
filter_mle_cmd(MLE_CHILD_ID_RESPONSE).\
filter(lambda p: {
MODE_TLV,
TIMEOUT_TLV,
CHALLENGE_TLV
} <= set(p.thread_nwd.tlv.type) and\
[Ipv6Addr(PREFIX_2001[:-3])] == p.thread_nwd.tlv.prefix and\
p.thread_nwd.tlv.border_router.flag.p == [1] and\
p.thread_nwd.tlv.border_router.flag.s == [1] and\
p.thread_nwd.tlv.border_router.flag.r == [1] and\
p.thread_nwd.tlv.border_router.flag.o == [1] and\
p.thread_nwd.tlv.stable == [1, 1, 1]
).\
must_next()
lstart = pkts.index
# Step 7: MED attaches to the Leader (DUT) and requests complete
# network data
pkts.filter_wpan_src64(MED).\
filter_wpan_dst64(LEADER).\
filter_mle_cmd(MLE_CHILD_ID_REQUEST).\
filter(lambda p: {
RESPONSE_TLV,
LINK_LAYER_FRAME_COUNTER_TLV,
MODE_TLV,
TIMEOUT_TLV,
VERSION_TLV,
TLV_REQUEST_TLV,
ADDRESS16_TLV,
NETWORK_DATA_TLV,
ADDRESS_REGISTRATION_TLV
} <= set(p.mle.tlv.type) and\
p.mle.tlv.mode.network_data == 1
).\
must_next()
# Step 8: The DUT MUST send a MLE Child ID Response to MED,
# including the following TLVs:
# - Network Data TLV
# At least two Prefix TLVs (Prefix 1 and Prefix 2),
# each including:
# - 6LoWPAN ID sub-TLV
# - Border Router sub-TLV
pkts.filter_wpan_src64(LEADER).\
filter_wpan_dst64(MED).\
filter_mle_cmd(MLE_CHILD_ID_RESPONSE).\
filter(lambda p: {
Ipv6Addr(PREFIX_2001[:-3]),
Ipv6Addr(PREFIX_2002[:-3])
} == set(p.thread_nwd.tlv.prefix) and\
p.thread_nwd.tlv.border_router.flag.p == [1, 1] and\
p.thread_nwd.tlv.border_router.flag.s == [1, 1] and\
p.thread_nwd.tlv.border_router.flag.r == [1, 1] and\
p.thread_nwd.tlv.border_router.flag.o == [1, 1] and\
p.thread_nwd.tlv.stable == [0, 1, 1, 1, 0, 0, 0]
).\
must_next()
# Step 9: After attaching, each Child automatically sends its global address
# configured to the Leader, in the Address Registration TLV from the
# Child Update request command
# Step 10: The DUT MUST send a MLE Child Update Response, each, to MED & SED
# The following TLVs MUST be present in the Child Update Response:
# - Source Address TLV
# - Address Registration TLV
# - Echoes back addresses configured in step 9
# - Mode TLV
for child in (SED, MED):
_pkt = pkts.range(lstart).\
filter_wpan_src64(child).\
filter_wpan_dst64(LEADER).\
filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).\
must_next()
pkts.range(lstart).\
filter_wpan_src64(LEADER).\
filter_wpan_dst64(child).\
filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).\
filter(lambda p: {
SOURCE_ADDRESS_TLV,
MODE_TLV,
ADDRESS_REGISTRATION_TLV
} <= set(p.mle.tlv.type) and\
set(p.mle.tlv.addr_reg_iid) < set(_pkt.mle.tlv.addr_reg_iid)
).\
must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,171 +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_REQUEST, MLE_DATA_RESPONSE, MLE_CHILD_ID_RESPONSE, MLE_CHILD_UPDATE_REQUEST, MLE_CHILD_UPDATE_RESPONSE, SVR_DATA_URI, SOURCE_ADDRESS_TLV, MODE_TLV, ADDRESS_REGISTRATION_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV, ROUTE64_TLV
from pktverify.packet_verifier import PacketVerifier
from pktverify.addrs import Ipv6Addr
LEADER = 1
ROUTER = 2
ED2 = 3
SED2 = 4
MTDS = [ED2, SED2]
class Cert_7_1_2_BorderRouterAsRouter(thread_cert.TestCase):
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER]
},
ROUTER: {
'name': 'ROUTER',
'mode': 'rdn',
'allowlist': [LEADER, ED2, SED2]
},
ED2: {
'name': 'MED',
'is_mtd': True,
'mode': 'rn',
'allowlist': [ROUTER]
},
SED2: {
'name': 'SED',
'is_mtd': True,
'mode': '-',
'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[ROUTER].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER].get_state(), 'router')
self.nodes[ROUTER].add_prefix('2001:2:0:1::/64', 'paros')
self.nodes[ROUTER].add_prefix('2001:2:0:2::/64', 'paro')
self.nodes[ROUTER].register_netdata()
# Set lowpan context of sniffer
self.simulator.set_lowpan_context(1, '2001:2:0:1::/64')
self.simulator.set_lowpan_context(2, '2001:2:0:2::/64')
self.nodes[ED2].start()
self.simulator.go(5)
self.assertEqual(self.nodes[ED2].get_state(), 'child')
self.nodes[SED2].start()
self.simulator.go(5)
self.assertEqual(self.nodes[SED2].get_state(), 'child')
self.collect_rloc16s()
addrs = self.nodes[ED2].get_addrs()
self.assertTrue(any('2001:2:0:1' in addr[0:10] for addr in addrs))
self.assertTrue(any('2001:2:0:2' in addr[0:10] for addr in addrs))
for addr in addrs:
if addr[0:10] == '2001:2:0:1' or addr[0:10] == '2001:2:0:2':
self.assertTrue(self.nodes[LEADER].ping(addr))
addrs = self.nodes[SED2].get_addrs()
self.assertTrue(any('2001:2:0:1' in addr[0:10] for addr in addrs))
self.assertFalse(any('2001:2:0:2' in addr[0:10] for addr in addrs))
for addr in addrs:
if addr[0:10] == '2001:2:0:1' or addr[0:10] == '2001:2:0:2':
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']
MED = pv.vars['MED']
SED = pv.vars['SED']
_rpkts = pkts.filter_wpan_src64(ROUTER)
# Step 2: The DUT MUST send properly formatted MLE Advertisements
# The DUT MUST send a CoAP Server Data Notification message
# with the servers information (Prefix, Border Router) to the Leader
_rpkts.filter_mle_cmd(MLE_CHILD_ID_REQUEST).must_next()
_rpkts.filter_mle_cmd(MLE_ADVERTISEMENT).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ROUTE64_TLV} <= set(p.mle.tlv.type))
_rpkts.filter_coap_request(SVR_DATA_URI).must_next().must_verify(
lambda p: p.wpan.dst16 == pv.vars['LEADER_RLOC16'] and {
Ipv6Addr('2001:2:0:1::'), Ipv6Addr('2001:2:0:2::')
} == set(p.thread_nwd.tlv.prefix) and p.thread_nwd.tlv.border_router.flag.p == [1, 1] and p.thread_nwd.tlv.
border_router.flag.s == [1, 1] and p.thread_nwd.tlv.border_router.flag.r == [1, 1] and p.thread_nwd.tlv.
border_router.flag.o == [1, 1] and p.thread_nwd.tlv.stable == [1, 1, 0, 0])
# Step 3: Automatically transmits a 2.04 Changed CoAP response to the DUT
# Step 4: The DUT MUST multicast the MLE Data Response message sent by the Leader
_rpkts.filter_mle_cmd(MLE_DATA_RESPONSE).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV} <= set(p.mle.tlv.
type))
# Step 5: MED_1 to attach to DUT and request complete network data
# Step 6: The DUT MUST send an MLE Child ID Response to MED_1
p = _rpkts.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).must_next()
p.must_verify(lambda p: p.wpan.dst64 == MED and {Ipv6Addr('2001:2:0:1::'),
Ipv6Addr('2001:2:0:2::')} == set(p.thread_nwd.tlv.prefix))
_rpkts_med = _rpkts.copy()
# Step 7: SED_1 to attach to DUT and request only stable data
# Step 8: The DUT MUST send an MLE Child Response to SED_1
_rpkts.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).must_next().must_verify(
lambda p: p.wpan.dst64 == SED and {Ipv6Addr('2001:2:0:1::')} == set(
p.thread_nwd.tlv.prefix) and p.thread_nwd.tlv.border_router_16 == [0xFFFE])
_rpkts_sed = _rpkts.copy()
# Step 9: SED_1 and MED_1 send its configured global address to the DUT
# Step 10: The DUT MUST send a Child Update Response to MED_1 & SED_1
_med_pkt = pkts.range(
_rpkts_med.index).filter_wpan_src64(MED).filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).must_next()
_sed_pkt = pkts.range(
_rpkts_sed.index).filter_wpan_src64(SED).filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).must_next()
_rpkts_med.filter_wpan_dst64(MED).filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, MODE_TLV, ADDRESS_REGISTRATION_TLV} <= set(p.mle.tlv.type) and p.wpan.dst64
== MED and set(p.mle.tlv.addr_reg_iid) < set(_med_pkt.mle.tlv.addr_reg_iid))
_rpkts_sed.filter_wpan_dst64(SED).filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, MODE_TLV, ADDRESS_REGISTRATION_TLV} <= set(p.mle.tlv.type) and set(
p.mle.tlv.addr_reg_iid) < set(_sed_pkt.mle.tlv.addr_reg_iid))
if __name__ == '__main__':
unittest.main()
@@ -1,239 +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 WIRESHARK_OVERRIDE_PREFS, MLE_CHILD_UPDATE_REQUEST, MLE_CHILD_UPDATE_RESPONSE, MLE_DATA_RESPONSE, MLE_CHILD_ID_REQUEST, MLE_CHILD_ID_RESPONSE, ACTIVE_TIMESTAMP_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, MODE_TLV, TIMEOUT_TLV, VERSION_TLV, TLV_REQUEST_TLV, ADDRESS16_TLV, NETWORK_DATA_TLV, ROUTE64_TLV, MODE_TLV, TIMEOUT_TLV, CHALLENGE_TLV, SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV
from pktverify.packet_verifier import PacketVerifier
from pktverify.addrs import Ipv6Addr
from pktverify.null_field import nullField
LEADER = 1
ROUTER = 2
SED1 = 3
MED1 = 4
MTDS = [SED1, MED1]
PREFIX_2001 = '2001::/64'
PREFIX_2002 = '2002::/64'
# Test Purpose and Description:
# -----------------------------
# The purpose of this test case is to verify that global prefix information can
# be set on the DUT, which is acting as a Leader in the Thread network. The DUT
# must also demonstrate that it correctly sets the Network Data (stable/non-stable)
# and propagates it properly in an already formed network.
#
# Test Topology:
# -------------
# SED
# |
# ROUTER - Leader(DUT) - MED
#
# DUT Types:
# ----------
# Leader
class Cert_7_1_3_BorderRouterAsLeader(thread_cert.TestCase):
USE_MESSAGE_FACTORY = False
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER, SED1, MED1]
},
ROUTER: {
'name': 'ROUTER',
'mode': 'rdn',
'allowlist': [LEADER]
},
SED1: {
'name': 'SED',
'is_mtd': True,
'mode': '-',
'timeout': config.DEFAULT_CHILD_TIMEOUT,
'allowlist': [LEADER]
},
MED1: {
'name': 'MED',
'is_mtd': True,
'mode': 'rn',
'allowlist': [LEADER]
},
}
# override wireshark preferences with case needed parameters
CASE_WIRESHARK_PREFS = copy.deepcopy(WIRESHARK_OVERRIDE_PREFS)
CASE_WIRESHARK_PREFS['6lowpan.context1'] = PREFIX_2001
CASE_WIRESHARK_PREFS['6lowpan.context2'] = PREFIX_2002
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[SED1].start()
self.simulator.go(5)
self.assertEqual(self.nodes[SED1].get_state(), 'child')
self.nodes[MED1].start()
self.simulator.go(5)
self.assertEqual(self.nodes[MED1].get_state(), 'child')
self.nodes[LEADER].add_prefix(PREFIX_2001, 'paros')
self.nodes[LEADER].add_prefix(PREFIX_2002, 'paro')
self.nodes[LEADER].register_netdata()
self.simulator.go(5)
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
ROUTER = pv.vars['ROUTER']
SED = pv.vars['SED']
MED = pv.vars['MED']
# Step 1: Ensure topology is formed correctly
pv.verify_attached('ROUTER', 'LEADER')
pv.verify_attached('SED', 'LEADER', 'MTD')
pv.verify_attached('MED', 'LEADER', 'MTD')
# Step 3: The DUT MUST send a multicast MLE Data Response,
# including the following TLVs:
# - Network Data TLV
# At least two Prefix TLVs (Prefix 1 and Prefix 2),
# each including:
# - 6LoWPAN ID sub-TLV
# - Border Router sub-TLV
pkts.filter_wpan_src64(LEADER).\
filter_LLANMA().\
filter_mle_cmd(MLE_DATA_RESPONSE).\
filter(lambda p: {
Ipv6Addr(PREFIX_2001[:-3]),
Ipv6Addr(PREFIX_2002[:-3])
} == set(p.thread_nwd.tlv.prefix) and\
p.thread_nwd.tlv.border_router.flag.p == [1, 1] and\
p.thread_nwd.tlv.border_router.flag.s == [1, 1] and\
p.thread_nwd.tlv.border_router.flag.r == [1, 1] and\
p.thread_nwd.tlv.border_router.flag.o == [1, 1] and\
p.thread_nwd.tlv.stable == [0, 1, 1, 1, 0, 0, 0]
).\
must_next()
# Step 4: MED automatically sends the global address configured to its parent
# (the DUT), via the Address Registration TLV included in its Child
# Update Request keep-alive message.
# Step 5: The DUT MUST send a MLE Child Update Response to MED
# The following TLVs MUST be present in the Child Update Response:
# - Source Address TLV
# - Address Registration TLV
# - Echoes back addresses configured in step 4
# - Mode TLV
with pkts.save_index():
_pkt = pkts.filter_wpan_src64(MED).\
filter_wpan_dst64(LEADER).\
filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).\
must_next()
pkts.filter_wpan_src64(LEADER).\
filter_wpan_dst64(MED).\
filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).\
filter(lambda p: {
SOURCE_ADDRESS_TLV,
MODE_TLV,
ADDRESS_REGISTRATION_TLV
} <= set(p.mle.tlv.type) and\
p.mle.tlv.addr_reg_iid is not nullField and\
set(_pkt.mle.tlv.addr_reg_iid) > set(p.mle.tlv.addr_reg_iid)
).\
must_next()
# Step 6: The DUT MUST send a MLE Child Update Request or MLE Data
# Response to SED, including the following TLVs:
# - Network Data TLV
# - Source Address TLV
# - Leader Data TLV
# - Active Timestamp TLV
pkts.filter_wpan_src64(LEADER).\
filter_wpan_dst64(SED).\
filter_mle_cmd2(MLE_CHILD_UPDATE_REQUEST, MLE_DATA_RESPONSE).\
filter(lambda p: {
NETWORK_DATA_TLV,
SOURCE_ADDRESS_TLV,
LEADER_DATA_TLV,
ACTIVE_TIMESTAMP_TLV
} <= set(p.mle.tlv.type) and\
[Ipv6Addr(PREFIX_2001[:-3])] == p.thread_nwd.tlv.prefix and\
p.thread_nwd.tlv.border_router.flag.p == [1] and\
p.thread_nwd.tlv.border_router.flag.s == [1] and\
p.thread_nwd.tlv.border_router.flag.r == [1] and\
p.thread_nwd.tlv.border_router.flag.o == [1] and\
p.thread_nwd.tlv.stable == [1, 1, 1]
).\
must_next()
# Step 9: After receiving the MLE Data Response or MLE Child Update Request,
# SED automatically sends its global address configured to the Leader,
# in the Address Registration TLV from the Child Update request command
# Step 10: The DUT MUST send a MLE Child Update Response, each, to SED
# The following TLVs MUST be present in the Child Update Response:
# - Source Address TLV
# - Address Registration TLV
# - Echoes back addresses configured in step 9
# - Mode TLV
_pkt = pkts.filter_wpan_src64(SED).\
filter_wpan_dst64(LEADER).\
filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).\
must_next()
pkts.filter_wpan_src64(LEADER).\
filter_wpan_dst64(SED).\
filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).\
filter(lambda p: {
SOURCE_ADDRESS_TLV,
MODE_TLV,
ADDRESS_REGISTRATION_TLV
} <= set(p.mle.tlv.type) and\
p.mle.tlv.addr_reg_iid is not nullField and\
set(_pkt.mle.tlv.addr_reg_iid) > set(p.mle.tlv.addr_reg_iid)
).\
must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,166 +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_REQUEST, MLE_DATA_RESPONSE, MLE_CHILD_ID_RESPONSE, MLE_CHILD_UPDATE_RESPONSE, MLE_CHILD_UPDATE_REQUEST, SVR_DATA_URI, SOURCE_ADDRESS_TLV, MODE_TLV, ADDRESS_REGISTRATION_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV, ROUTE64_TLV
from pktverify.packet_verifier import PacketVerifier
from pktverify.addrs import Ipv6Addr
LEADER = 1
ROUTER = 2
ED2 = 3
SED2 = 4
MTDS = [SED2, ED2]
class Cert_7_1_4_BorderRouterAsRouter(thread_cert.TestCase):
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER]
},
ROUTER: {
'name': 'ROUTER',
'mode': 'rdn',
'allowlist': [LEADER, ED2, SED2]
},
ED2: {
'name': 'MED',
'is_mtd': True,
'mode': 'rn',
'allowlist': [ROUTER]
},
SED2: {
'name': 'SED',
'is_mtd': True,
'mode': '-',
'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[ROUTER].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[ROUTER].get_state(), 'router')
self.nodes[ED2].start()
self.simulator.go(5)
self.assertEqual(self.nodes[ED2].get_state(), 'child')
self.nodes[SED2].start()
self.simulator.go(5)
self.assertEqual(self.nodes[SED2].get_state(), 'child')
self.collect_rloc16s()
self.nodes[ROUTER].add_prefix('2001:2:0:1::/64', 'paros')
self.nodes[ROUTER].add_prefix('2001:2:0:2::/64', 'paro')
self.nodes[ROUTER].register_netdata()
self.simulator.go(5)
# Set lowpan context of sniffer
self.simulator.set_lowpan_context(1, '2001:2:0:1::/64')
self.simulator.set_lowpan_context(2, '2001:2:0:2::/64')
addrs = self.nodes[ED2].get_addrs()
self.assertTrue(any('2001:2:0:1' in addr[0:10] for addr in addrs))
self.assertTrue(any('2001:2:0:2' in addr[0:10] for addr in addrs))
for addr in addrs:
if addr[0:10] == '2001:2:0:1' or addr[0:10] == '2001:2:0:2':
self.assertTrue(self.nodes[LEADER].ping(addr))
addrs = self.nodes[SED2].get_addrs()
self.assertTrue(any('2001:2:0:1' in addr[0:10] for addr in addrs))
self.assertFalse(any('2001:2:0:2' in addr[0:10] for addr in addrs))
for addr in addrs:
if addr[0:10] == '2001:2:0:1' or addr[0:10] == '2001:2:0:2':
self.assertTrue(self.nodes[LEADER].ping(addr))
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
ROUTER = pv.vars['ROUTER']
MED = pv.vars['MED']
SED = pv.vars['SED']
_rpkts = pkts.filter_wpan_src64(ROUTER)
# Step 3: The DUT MUST send properly formatted MLE Advertisements
# The DUT MUST send a CoAP Server Data Notification message
# with the servers information (Prefix, Border Router) to the Leader
_rpkts.filter_mle_cmd(MLE_CHILD_ID_REQUEST).must_next()
_rpkts.filter_mle_cmd(MLE_ADVERTISEMENT).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ROUTE64_TLV} <= set(p.mle.tlv.type))
_pkt = _rpkts.filter_coap_request(SVR_DATA_URI).must_next()
_pkt.must_verify(lambda p: p.wpan.dst16 == pv.vars['LEADER_RLOC16'] and {
Ipv6Addr('2001:2:0:1::'), Ipv6Addr('2001:2:0:2::')
} == set(p.thread_nwd.tlv.prefix) and p.thread_nwd.tlv.border_router.flag.p == [1, 1] and p.thread_nwd.tlv.
border_router.flag.s == [1, 1] and p.thread_nwd.tlv.border_router.flag.r == [1, 1] and p.
thread_nwd.tlv.border_router.flag.o == [1, 1] and p.thread_nwd.tlv.stable == [1, 1, 0, 0])
_rpkts_med = _rpkts.copy()
_rpkts_sed = _rpkts.copy()
# Step 4: Automatically transmits a 2.04 Changed CoAP response to the DUT
# Step 5: The DUT MUST send a multicast MLE Data Response
_rpkts.filter_mle_cmd(MLE_DATA_RESPONSE).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV} <= set(
p.mle.tlv.type) and {Ipv6Addr('2001:2:0:1::'), Ipv6Addr('2001:2:0:2::')} == set(
p.thread_nwd.tlv.prefix) and p.thread_nwd.tlv.border_router.flag.p == [1, 1] and p.thread_nwd.tlv.
border_router.flag.s == [1, 1] and p.thread_nwd.tlv.border_router.flag.r == [1, 1] and p.thread_nwd.tlv.
border_router.flag.o == [1, 1] and p.thread_nwd.tlv.stable == [0, 1, 1, 1, 0, 0, 0])
# Step 6: The DUT MUST send a Child Update Response to MED_1
_rpkts_med.filter_wpan_dst64(MED).filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, MODE_TLV, ADDRESS_REGISTRATION_TLV} <= set(p.mle.tlv.type))
# Step 7: The DUT MUST send an MLE Child Update Request to SED_1
_rpkts_sed.filter_wpan_dst64(SED).filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).must_next().must_verify(
lambda p: {Ipv6Addr('2001:2:0:1::')} == set(p.thread_nwd.tlv.prefix
) and p.thread_nwd.tlv.border_router_16 == [0xFFFE])
# Step 8: SED_1 send its configured global address to the DUT
# Step 9: The DUT MUST send a Child Update Response to SED_1
_sed_pkt = pkts.range(
_rpkts_sed.index).filter_wpan_src64(SED).filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).must_next()
_rpkts_sed.filter_wpan_dst64(SED).filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).must_next().must_verify(
lambda p: {SOURCE_ADDRESS_TLV, MODE_TLV, ADDRESS_REGISTRATION_TLV} <= set(p.mle.tlv.type) and set(
p.mle.tlv.addr_reg_iid) < set(_sed_pkt.mle.tlv.addr_reg_iid))
if __name__ == '__main__':
unittest.main()
@@ -1,257 +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 WIRESHARK_OVERRIDE_PREFS, MLE_CHILD_UPDATE_REQUEST, MLE_CHILD_UPDATE_RESPONSE, MLE_DATA_RESPONSE, MLE_CHILD_ID_REQUEST, MLE_CHILD_ID_RESPONSE, SVR_DATA_URI, ACTIVE_TIMESTAMP_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, MODE_TLV, TIMEOUT_TLV, VERSION_TLV, TLV_REQUEST_TLV, ADDRESS16_TLV, NETWORK_DATA_TLV, ROUTE64_TLV, MODE_TLV, TIMEOUT_TLV, CHALLENGE_TLV, SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV
from pktverify.packet_verifier import PacketVerifier
from pktverify.addrs import Ipv6Addr
LEADER = 1
ROUTER = 2
MED = 3
SED = 4
MTDS = [MED, SED]
PREFIX_2001 = '2001::/64'
PREFIX_2002 = '2002::/64'
PREFIX_2003 = '2003::/64'
# Test Purpose and Description:
# -----------------------------
# The purpose of this test case is to verify that the DUT sends properly formatted
# Server Data Notification CoAP frame when a third global prefix information is
# set on the DUT. The DUT must also correctly set Network Data aggregated and
# disseminated by the Leader and transmit it properly to all child devices already
# attached to it.
#
# Test Topology:
# -------------
# SED
# |
# Router(DUT) - MED
# |
# Leader
#
# DUT Types:
# ----------
# Router
class Cert_7_1_5_BorderRouterAsRouter(thread_cert.TestCase):
USE_MESSAGE_FACTORY = False
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER]
},
ROUTER: {
'name': 'ROUTER',
'mode': 'rdn',
'allowlist': [LEADER, MED, SED]
},
MED: {
'name': 'MED',
'is_mtd': True,
'mode': 'rn',
'allowlist': [ROUTER]
},
SED: {
'name': 'SED',
'is_mtd': True,
'mode': '-',
'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[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')
self.nodes[ROUTER].add_prefix(PREFIX_2001, 'paros')
self.nodes[ROUTER].add_prefix(PREFIX_2002, 'paro')
self.nodes[ROUTER].add_prefix(PREFIX_2003, 'paos')
self.nodes[ROUTER].register_netdata()
self.simulator.go(10)
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
ROUTER = pv.vars['ROUTER']
SED = pv.vars['SED']
MED = pv.vars['MED']
# Step 1: Ensure topology is formed correctly
pv.verify_attached('ROUTER', 'LEADER')
pv.verify_attached('MED', 'ROUTER', 'MTD')
pv.verify_attached('SED', 'ROUTER', 'MTD')
# Step 3: The DUT MUST send a CoAP Server Data Notification frame
# to the Leader including the servers information(Prefix,
# Border Router) for all three prefixes (Prefix 1, 2 and 3):
# CoAP Request URI
# coap://[<Leader address>]:MM/a/sd
# CoAP Payload
# Thread Network Data TLV
pkts.filter_wpan_src64(ROUTER).\
filter_coap_request(SVR_DATA_URI).\
filter(lambda p: {
Ipv6Addr(PREFIX_2001[:-3]),
Ipv6Addr(PREFIX_2002[:-3]),
Ipv6Addr(PREFIX_2003[:-3])
} == set(p.thread_nwd.tlv.prefix)
).\
must_next()
_index = pkts.index
# Step 5: The DUT MUST send a multicast MLE Data Response,
# including at least three Prefix TLVs (Prefix 1, Prefix2,
# and Prefix 3).
with pkts.save_index():
_dv_pkt = pkts.filter_wpan_src64(ROUTER).\
filter_LLANMA().\
filter_mle_cmd(MLE_DATA_RESPONSE).\
filter(lambda p: {
Ipv6Addr(PREFIX_2001[:-3]),
Ipv6Addr(PREFIX_2002[:-3]),
Ipv6Addr(PREFIX_2003[:-3])
} <= set(p.thread_nwd.tlv.prefix)
).\
must_next()
# Step 6: MED automatically sends MLE Child Update Request to its parent
# (DUT), reporting its configured global addresses in the Address
# Registration TLV
# Step 7: The DUT MUST send a MLE Child Update Response to MED
# The following TLVs MUST be present in the Child Update Response:
# - Source Address TLV
# - Address Registration TLV
# - Echoes back addresses configured in step 4
# - Mode TLV
_pkt = pkts.filter_wpan_src64(MED).\
filter_wpan_dst64(ROUTER).\
filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).\
filter(lambda p: len(p.mle.tlv.addr_reg_iid) >= 4).\
must_next()
pkts.filter_wpan_src64(ROUTER).\
filter_wpan_dst64(MED).\
filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).\
filter(lambda p: {
SOURCE_ADDRESS_TLV,
MODE_TLV,
ADDRESS_REGISTRATION_TLV
} <= set(p.mle.tlv.type) and\
len(p.mle.tlv.addr_reg_iid) >= 3 and\
set(p.mle.tlv.addr_reg_iid) < set(_pkt.mle.tlv.addr_reg_iid)
).\
must_next()
# Step 8: The DUT MUST send a MLE Child Update Request or MLE Data
# Response to SED, including the following TLVs:
# - Network Data TLV
# At least two Prefix TLVs (Prefix 1 and Prefix3)
# - Border Router TLV
# - P_border_router_16<0xFFFE>
# Prefix 2 TLV MUST NOT be included
# - Source Address TLV
# - Leader Data TLV
# Data version numbers should be the same as the ones
# sent in the multicast data response in step 5.
# - Active Timestamp TLV
pkts.range(_index).filter_wpan_src64(ROUTER).\
filter_wpan_dst64(SED).\
filter_mle_cmd2(MLE_CHILD_UPDATE_REQUEST, MLE_DATA_RESPONSE).\
filter(lambda p: {
NETWORK_DATA_TLV,
SOURCE_ADDRESS_TLV,
LEADER_DATA_TLV,
ACTIVE_TIMESTAMP_TLV
} <= set(p.mle.tlv.type) and\
{
Ipv6Addr(PREFIX_2001[:-3]),
Ipv6Addr(PREFIX_2003[:-3])
} == set(p.thread_nwd.tlv.prefix) and\
p.mle.tlv.leader_data.data_version ==
_dv_pkt.mle.tlv.leader_data.data_version and\
[0xFFFE, 0xFFFE] == p.thread_nwd.tlv.border_router_16
).\
must_next()
# Step 9: SED automatically sends its global address configured to the Leader,
# in the Address Registration TLV from the Child Update request command
# Step 10: The DUT MUST send a MLE Child Update Response, each, to SED
# The following TLVs MUST be present in the Child Update Response:
# - Source Address TLV
# - Address Registration TLV
# - Echoes back addresses configured in step 9
# - Mode TLV
_pkt = pkts.filter_wpan_src64(SED).\
filter_wpan_dst64(ROUTER).\
filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).\
filter(lambda p: len(p.mle.tlv.addr_reg_iid) >= 3).\
must_next()
pkts.filter_wpan_src64(ROUTER).\
filter_wpan_dst64(SED).\
filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).\
filter(lambda p: {
SOURCE_ADDRESS_TLV,
MODE_TLV,
ADDRESS_REGISTRATION_TLV
} <= set(p.mle.tlv.type) and\
len(p.mle.tlv.addr_reg_iid) >= 2 and\
set(p.mle.tlv.addr_reg_iid) < set(_pkt.mle.tlv.addr_reg_iid)
).\
must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,485 +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 copy
import config
import thread_cert
from pktverify.consts import WIRESHARK_OVERRIDE_PREFS, MLE_CHILD_UPDATE_REQUEST, MLE_DATA_RESPONSE, MLE_CHILD_ID_RESPONSE, SVR_DATA_URI, ACTIVE_TIMESTAMP_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, VERSION_TLV, TLV_REQUEST_TLV, ADDRESS16_TLV, NETWORK_DATA_TLV, ROUTE64_TLV, CHALLENGE_TLV, SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV
from pktverify.packet_verifier import PacketVerifier
from pktverify.bytes import Bytes
from pktverify.addrs import Ipv6Addr
from pktverify.null_field import nullField
LEADER = 1
ROUTER_1 = 2
ROUTER_2 = 3
MED = 4
SED = 5
MTDS = [MED, SED]
PREFIX_2001 = '2001:0db8:0001::/64'
# Test Purpose and Description:
# -----------------------------
# The purpose of this test case is to verify that network data is properly updated
# when a server from the network leaves and rejoins.
# Router_1 is configured as Border Router for prefix 2001:db8:1::/64.
# Router_2 is configured as Border Router for prefix 2001:db8:1::/64.
# MED is configured to require complete network data.
# SED is configured to request only stable network data.
#
# Test Topology:
# -------------
# SED
# |
# Router_1 - Leader(DUT) - MED
# |
# Router_2
#
# DUT Types:
# ----------
# Leader
class Cert_7_1_6_BorderRouterAsLeader(thread_cert.TestCase):
USE_MESSAGE_FACTORY = False
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER_1, ROUTER_2, MED, SED]
},
ROUTER_1: {
'name': 'ROUTER_1',
'mode': 'rdn',
'allowlist': [LEADER]
},
ROUTER_2: {
'name': 'ROUTER_2',
'mode': 'rdn',
'allowlist': [LEADER]
},
MED: {
'name': 'MED',
'is_mtd': True,
'mode': 'rn',
'allowlist': [LEADER]
},
SED: {
'name': 'SED',
'is_mtd': True,
'mode': '-',
'timeout': config.DEFAULT_CHILD_TIMEOUT,
'allowlist': [LEADER]
},
}
# override wireshark preferences with case needed parameters
CASE_WIRESHARK_PREFS = WIRESHARK_OVERRIDE_PREFS
CASE_WIRESHARK_PREFS['6lowpan.context1'] = PREFIX_2001
def _setUpRouter_1(self):
self.nodes[ROUTER_1].add_allowlist(self.nodes[LEADER].get_addr64())
self.nodes[ROUTER_1].enable_allowlist()
self.nodes[ROUTER_1].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')
for i in (2, 3):
self.nodes[i].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[i].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')
self.collect_rlocs()
self.nodes[ROUTER_1].add_prefix(PREFIX_2001, 'paros')
self.nodes[ROUTER_1].register_netdata()
self.nodes[ROUTER_2].add_prefix(PREFIX_2001, 'paro')
self.nodes[ROUTER_2].register_netdata()
self.simulator.go(10)
self.collect_ipaddrs()
self.nodes[ROUTER_1].reset()
self._setUpRouter_1()
self.simulator.go(720)
self.nodes[ROUTER_1].start()
self.simulator.go(config.ROUTER_RESET_DELAY)
self.assertEqual(self.nodes[ROUTER_1].get_state(), 'router')
self.collect_rloc16s()
self.nodes[ROUTER_1].add_prefix(PREFIX_2001, 'paros')
self.nodes[ROUTER_1].register_netdata()
self.simulator.go(10)
dut_addr = self.nodes[LEADER].get_addr(PREFIX_2001)
self.assertTrue(self.nodes[ROUTER_1].ping(dut_addr))
self.simulator.go(1)
self.assertTrue(self.nodes[SED].ping(dut_addr))
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']
ROUTER_1 = pv.vars['ROUTER_1']
ROUTER_1_RLOC16 = pv.vars['ROUTER_1_RLOC16']
ROUTER_1_RLOC = pv.vars['ROUTER_1_RLOC']
ROUTER_2 = pv.vars['ROUTER_2']
ROUTER_2_RLOC16 = pv.vars['ROUTER_2_RLOC16']
SED = pv.vars['SED']
MED = pv.vars['MED']
GUA = {}
for node in ('LEADER', 'ROUTER_1', 'SED'):
for addr in pv.vars['%s_IPADDRS' % node]:
if addr.startswith(Bytes(PREFIX_2001[:-5])):
GUA[node] = addr
# Step 1: Ensure topology is formed correctly
pv.verify_attached('ROUTER_1', 'LEADER')
pv.verify_attached('ROUTER_2', 'LEADER')
pv.verify_attached('MED', 'LEADER', 'MTD')
pv.verify_attached('SED', 'LEADER', 'MTD')
_pkt = pkts.last()
# Step 2,3: Router_1 and Router_2 MUST send a CoAP Server Data
# Notification frame to the Leader including the servers
# information(Prefix, Border Router):
# CoAP Request URI
# coap://[<Leader address>]:MM/a/sd
# CoAP Payload
# Thread Network Data TLV
# Step 4: Leader sends a CoAP ACK frame to each of Router_1 and
# Router_2
for i in (1, 2):
with pkts.save_index():
pkts.filter_wpan_src64(pv.vars['ROUTER_%d' %i]).\
filter_wpan_dst16(LEADER_RLOC16).\
filter_coap_request(SVR_DATA_URI).\
filter(lambda p:
[Ipv6Addr(PREFIX_2001[:-3])] ==
p.thread_nwd.tlv.prefix and\
[pv.vars['ROUTER_%d_RLOC16' %i]] ==
p.thread_nwd.tlv.border_router_16
).\
must_next()
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(pv.vars['ROUTER_%d_RLOC' %i]).\
filter_coap_ack(SVR_DATA_URI).\
must_next()
# Step 5: Leader MUST multicast MLE Data Response with the new
# information collected from Router_1 and Router_2,
# including the following TLVs:,
# - Source Address TLV
# - Leader Data TLV
# - Data Version field <incremented>
# - Stable Data Version field <incremented>
# - Network Data TLV
# - At least one Prefix TLV (Prefix 1)
# - Two Border Router sub-TLVs
# - 6LoWPAN ID sub-TLV
_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
} <= set(p.mle.tlv.type) and\
p.thread_nwd.tlv.border_router.flag.p == [1] and\
p.thread_nwd.tlv.border_router.flag.s == [1] and\
p.thread_nwd.tlv.border_router.flag.r == [1] and\
p.thread_nwd.tlv.border_router.flag.o == [1] and\
[Ipv6Addr(PREFIX_2001[:-3])] ==
p.thread_nwd.tlv.prefix
).\
must_next()
with pkts.save_index():
_dr_pkt1 = 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
} <= set(p.mle.tlv.type) and\
{
NWD_BORDER_ROUTER_TLV,
NWD_BORDER_ROUTER_TLV,
NWD_6LOWPAN_ID_TLV
} <= set(p.thread_nwd.tlv.type) and\
p.thread_nwd.tlv.border_router.flag.p == [1, 1] and\
p.thread_nwd.tlv.border_router.flag.s == [1, 1] and\
p.thread_nwd.tlv.border_router.flag.r == [1, 1] and\
p.thread_nwd.tlv.border_router.flag.o == [1, 1] and\
p.mle.tlv.leader_data.data_version ==
(_dr_pkt.mle.tlv.leader_data.data_version + 1) % 256 and\
(p.mle.tlv.leader_data.stable_data_version ==
(_dr_pkt.mle.tlv.leader_data.stable_data_version + 1) % 256 or\
p.mle.tlv.leader_data.stable_data_version ==
(_pkt.mle.tlv.leader_data.stable_data_version + 1) % 256) and\
[Ipv6Addr(PREFIX_2001[:-3])] ==
p.thread_nwd.tlv.prefix
).\
must_next()
# Step 6: Leader MUST send a MLE Child Update Request or MLE Data
# Response to SED, including the following TLVs:
# - Network Data TLV
# At least one Prefix TLV (Prefix 1) including:
# - Border Router sub-TLV(corresponding to Router_1)
# - 6LoWPAN ID sub-TLV
# - P_border_router_16<0xFFFE>
# - Source Address TLV
# - Leader Data TLV
# Data version numbers should be the same as the ones
# sent in the multicast data response in step 5.
# - Active Timestamp TLV
pkts.filter_wpan_src64(LEADER).\
filter_wpan_dst64(SED).\
filter_mle_cmd2(MLE_CHILD_UPDATE_REQUEST, MLE_DATA_RESPONSE).\
filter(lambda p: {
NETWORK_DATA_TLV,
SOURCE_ADDRESS_TLV,
LEADER_DATA_TLV,
ACTIVE_TIMESTAMP_TLV
} <= set(p.mle.tlv.type) and\
[Ipv6Addr(PREFIX_2001[:-3])] ==
p.thread_nwd.tlv.prefix and\
p.thread_nwd.tlv.stable == [1, 1, 1] and\
p.mle.tlv.leader_data.data_version ==
_dr_pkt1.mle.tlv.leader_data.data_version and\
p.mle.tlv.leader_data.stable_data_version ==
_dr_pkt1.mle.tlv.leader_data.stable_data_version and\
[0xFFFE] == p.thread_nwd.tlv.border_router_16
).\
must_next()
# Step 8: Leader MUST detect that Router_1 is removed from the network and
# update the Router ID Set. Leader MUST remove the Network Data
# section corresponding to Router_1 and increment the Data Version
# and Stable Data Version
# Step 9: Leader MUST multicast MLE Data Response neighbors and rx-on-when-idle
# Children (MED) including the following TLVs:,
# - Source Address TLV
# - Leader Data TLV
# - Data Version field <incremented>
# - Stable Data Version field <incremented>
# - Network Data TLV
# - Router_1s Network Data section MUST be removed
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,
} <= set(p.mle.tlv.type) and\
[Ipv6Addr(PREFIX_2001[:-3])] ==
p.thread_nwd.tlv.prefix and\
[ROUTER_2_RLOC16] == p.thread_nwd.tlv.border_router_16 and\
p.mle.tlv.leader_data.data_version ==
(_dr_pkt1.mle.tlv.leader_data.data_version + 1) % 256 and\
p.mle.tlv.leader_data.stable_data_version ==
(_dr_pkt1.mle.tlv.leader_data.stable_data_version + 1) % 256
).\
must_next()
# Step 10: The DUT MUST send a MLE Child Update Request or MLE Data
# Response to SED, containing the updated Network Data:
# - Network Data TLV
# - Source Address TLV
# - Active Timestamp TLV
_pkt = pkts.filter_wpan_src64(LEADER).\
filter_wpan_dst64(SED).\
filter_mle_cmd2(MLE_CHILD_UPDATE_REQUEST, MLE_DATA_RESPONSE).\
filter(lambda p: {
NETWORK_DATA_TLV,
SOURCE_ADDRESS_TLV,
LEADER_DATA_TLV,
} <= set(p.mle.tlv.type) and\
[Ipv6Addr(PREFIX_2001[:-3])] ==
p.thread_nwd.tlv.prefix and\
p.thread_nwd.tlv.border_router_16 is nullField and\
p.mle.tlv.leader_data.data_version ==
(_dr_pkt1.mle.tlv.leader_data.data_version + 1) % 256 and\
p.mle.tlv.leader_data.stable_data_version ==
(_dr_pkt1.mle.tlv.leader_data.stable_data_version + 1) % 256
).\
must_next()
# Step 12: Leader MUST send MLE Child ID Response to Router_1, which
# includes the following TLVs:
# - Source Address TLV
# - Leader Data TLV
# - Address16 TLV
# - Route64 TLV
# - Network Data TLV
# - At least one Prefix TLV (Prefix 1)
# including:
# - Border Router sub-tlv corresponding to Router_2
# - 6LoWPAN ID sub-TLV
pkts.filter_wpan_src64(LEADER).\
filter_wpan_dst64(ROUTER_1).\
filter_mle_cmd(MLE_CHILD_ID_RESPONSE).\
filter(lambda p: {
ADDRESS16_TLV,
LEADER_DATA_TLV,
NETWORK_DATA_TLV,
SOURCE_ADDRESS_TLV,
ROUTE64_TLV
} <= set(p.mle.tlv.type) and\
{
NWD_BORDER_ROUTER_TLV,
NWD_6LOWPAN_ID_TLV
} <= set(p.thread_nwd.tlv.type) and\
[Ipv6Addr(PREFIX_2001[:-3])] ==
p.thread_nwd.tlv.prefix and\
[ROUTER_2_RLOC16] == p.thread_nwd.tlv.border_router_16
).\
must_next()
# Step 13: Router_1 MUST send a CoAP Server DataNotification frame to
# the Leader including the servers information(Prefix, Border Router):
# CoAP Request URI
# coap://[<Leader address>]:MM/a/sd
# CoAP Payload
# Thread Network Data TLV
# Step 14: Leader sends a CoAP ACK frame to each of Router_1
with pkts.save_index():
pkts.filter_wpan_src64(ROUTER_1).\
filter_wpan_dst16(LEADER_RLOC16).\
filter_coap_request(SVR_DATA_URI).\
filter(lambda p:
[Ipv6Addr(PREFIX_2001[:-3])] ==
p.thread_nwd.tlv.prefix and\
[ROUTER_1_RLOC16] ==
p.thread_nwd.tlv.border_router_16
).\
must_next()
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(ROUTER_1_RLOC).\
filter_coap_ack(SVR_DATA_URI).\
must_next()
# Step 15: Leader MUST multicast MLE Data Response with the new
# information collected from Router_1 and Router_2,
# including the following TLVs:,
# - Source Address TLV
# - Leader Data TLV
# - Data Version field <incremented>
# - Stable Data Version field <incremented>
# - Network Data TLV
# - At least one Prefix TLV (Prefix 1)
# - Two Border Router sub-TLVs
# corresponding to Router_1 and Router_2
# - 6LoWPAN ID sub-TLV
_dr_pkt2 = 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
} <= set(p.mle.tlv.type) and\
{ROUTER_1_RLOC16, ROUTER_2_RLOC16} ==
set(p.thread_nwd.tlv.border_router_16) and\
[Ipv6Addr(PREFIX_2001[:-3])] ==
p.thread_nwd.tlv.prefix 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
).\
must_next()
# Step 16: Leader MUST send a MLE Child Update Request or MLE Data
# Response to SED, including the following TLVs:
# - Network Data TLV
# At least one Prefix TLV (Prefix 1)
# - Border Router TLV (corresponding to Router_1)
# - 6LoWPAN ID sub-TLV
# - P_border_router_16<0xFFFE>
# - Source Address TLV
# - Leader Data TLV
# Data version numbers should be the same as those
# sent in the multicast data response in step 15.
# - Active Timestamp TLV
pkts.filter_wpan_src64(LEADER).\
filter_wpan_dst64(SED).\
filter_mle_cmd2(MLE_CHILD_UPDATE_REQUEST, MLE_DATA_RESPONSE).\
filter(lambda p: {
NETWORK_DATA_TLV,
SOURCE_ADDRESS_TLV,
LEADER_DATA_TLV,
ACTIVE_TIMESTAMP_TLV
} <= set(p.mle.tlv.type) and\
[Ipv6Addr(PREFIX_2001[:-3])] ==
p.thread_nwd.tlv.prefix and\
p.mle.tlv.leader_data.data_version ==
_dr_pkt2.mle.tlv.leader_data.data_version and\
p.thread_nwd.tlv.stable == [1, 1, 1] and\
[0xFFFE] == p.thread_nwd.tlv.border_router_16
).\
must_next()
# Step 17: Verifies connectivity by sending ICMPv6 Echo Requests from
# Router_1 and SED_1 to the Leader Prefix_1 based address.
# Leader must respond with ICMPv6 Echo Replies
for node in ('ROUTER_1', 'SED'):
_pkt = pkts.filter_ping_request().\
filter_ipv6_src_dst(GUA[node], GUA['LEADER']).\
must_next()
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_ipv6_src_dst(GUA['LEADER'], GUA[node]).\
must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,562 +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 copy
import config
import thread_cert
from pktverify.consts import WIRESHARK_OVERRIDE_PREFS, MLE_CHILD_UPDATE_REQUEST, MLE_DATA_RESPONSE, MLE_CHILD_ID_RESPONSE, SVR_DATA_URI, ACTIVE_TIMESTAMP_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, VERSION_TLV, TLV_REQUEST_TLV, ADDRESS16_TLV, NETWORK_DATA_TLV, ROUTE64_TLV, CHALLENGE_TLV, SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV
from pktverify.packet_verifier import PacketVerifier
from pktverify.bytes import Bytes
from pktverify.addrs import Ipv6Addr
from pktverify.null_field import nullField
from pktverify.utils import is_sublist
LEADER = 1
ROUTER_1 = 2
ROUTER_2 = 3
MED = 4
SED = 5
MTDS = [MED, SED]
PREFIX_1 = '2001:0db8:0001::/64'
PREFIX_2 = '2001:0db8:0002::/64'
# Test Purpose and Description:
# -----------------------------
# The purpose of this test case is to verify that network data is properly updated
# when a server from the network leaves and rejoins.
# Router_1 is configured as Border Router for prefix 2001:db8:1::/64.
# Router_2 is configured as Border Router for prefix 2001:db8:1::/64.
# MED is configured to require complete network data.
# SED is configured to request only stable network data.
#
# Test Topology:
# -------------
# SED
# |
# Router_1 - Leader(DUT) - MED
# |
# Router_2
#
# DUT Types:
# ----------
# Leader
class Cert_7_1_7_BorderRouterAsLeader(thread_cert.TestCase):
USE_MESSAGE_FACTORY = False
SUPPORT_NCP = False
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER_1, ROUTER_2, MED, SED]
},
ROUTER_1: {
'name': 'ROUTER_1',
'mode': 'rdn',
'allowlist': [LEADER]
},
ROUTER_2: {
'name': 'ROUTER_2',
'mode': 'rdn',
'allowlist': [LEADER]
},
MED: {
'name': 'MED',
'is_mtd': True,
'mode': 'rn',
'timeout': config.DEFAULT_CHILD_TIMEOUT,
'allowlist': [LEADER]
},
SED: {
'name': 'SED',
'is_mtd': True,
'mode': '-',
'timeout': config.DEFAULT_CHILD_TIMEOUT,
'allowlist': [LEADER]
},
}
# override wireshark preferences with case needed parameters
CASE_WIRESHARK_PREFS = copy.deepcopy(WIRESHARK_OVERRIDE_PREFS)
CASE_WIRESHARK_PREFS['6lowpan.context1'] = PREFIX_1
CASE_WIRESHARK_PREFS['6lowpan.context2'] = PREFIX_2
def test(self):
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
for i in (2, 3):
self.nodes[i].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[i].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')
self.collect_rlocs()
self.nodes[ROUTER_1].add_prefix(PREFIX_1, 'paosr')
self.nodes[ROUTER_1].register_netdata()
self.simulator.go(5)
self.nodes[ROUTER_2].add_prefix(PREFIX_1, 'paro')
self.nodes[ROUTER_2].register_netdata()
self.simulator.go(5)
self.nodes[ROUTER_2].set_preferred_partition_id(1)
self.nodes[ROUTER_2].set_network_id_timeout(50)
self.nodes[ROUTER_2].remove_allowlist(self.nodes[LEADER].get_addr64())
self.nodes[LEADER].remove_allowlist(self.nodes[ROUTER_2].get_addr64())
# Wait for NETWORK_ID_TIMEOUT taking effect
# Router_2 creates a new partition
self.simulator.go(80)
self.assertEqual(self.nodes[ROUTER_2].get_state(), 'leader')
self.nodes[ROUTER_2].remove_domain_prefix(PREFIX_1)
self.nodes[ROUTER_2].add_prefix(PREFIX_2, 'paros')
self.nodes[ROUTER_2].register_netdata()
# Router_2 reattaches to Leader
self.nodes[ROUTER_2].add_allowlist(self.nodes[LEADER].get_addr64())
self.nodes[LEADER].add_allowlist(self.nodes[ROUTER_2].get_addr64())
# Wait for Router_2 reattachment and network data propagation
# ADVERTISEMENT_I_MAX + DEFAULT_CHILD_TIMEOUT + ATTACH_DELAY + Extra
self.simulator.go(120)
self.assertEqual(self.nodes[ROUTER_2].get_state(), 'router')
self.collect_ipaddrs()
self.collect_rloc16s()
# ping Leader's PREFIX_1 and PREFIX_2 addrs
dut_addrs = []
dut_addrs.append(self.nodes[LEADER].get_addr(PREFIX_1))
dut_addrs.append(self.nodes[LEADER].get_addr(PREFIX_2))
for addr in dut_addrs:
self.assertTrue(self.nodes[ROUTER_1].ping(addr))
self.simulator.go(1)
self.assertTrue(self.nodes[SED].ping(addr))
self.simulator.go(1)
self.nodes[ROUTER_2].remove_domain_prefix(PREFIX_2)
self.nodes[ROUTER_2].register_netdata()
self.simulator.go(5)
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']
ROUTER_1 = pv.vars['ROUTER_1']
ROUTER_1_RLOC16 = pv.vars['ROUTER_1_RLOC16']
ROUTER_1_RLOC = pv.vars['ROUTER_1_RLOC']
ROUTER_2 = pv.vars['ROUTER_2']
ROUTER_2_RLOC16 = pv.vars['ROUTER_2_RLOC16']
ROUTER_2_RLOC = pv.vars['ROUTER_2_RLOC']
SED = pv.vars['SED']
MED = pv.vars['MED']
GUA = [{}, {}]
PREFIXES = [Bytes(PREFIX_1[:-5]), Bytes(PREFIX_2[:-5])]
for i in (0, 1):
for node in ('LEADER', 'ROUTER_1', 'SED'):
for addr in pv.vars['%s_IPADDRS' % node]:
if addr.startswith(PREFIXES[i]):
GUA[i][node] = addr
# Step 1: Ensure topology is formed correctly
pv.verify_attached('ROUTER_1', 'LEADER')
pv.verify_attached('ROUTER_2', 'LEADER')
pv.verify_attached('MED', 'LEADER', 'MTD')
pv.verify_attached('SED', 'LEADER', 'MTD')
_pkt = pkts.last()
# Step 2,3: Router_1 and Router_2 MUST send a CoAP Server Data
# Notification frame to the Leader including the servers
# information(Prefix, Border Router):
# CoAP Request URI
# coap://[<Leader address>]:MM/a/sd
# CoAP Payload
# Thread Network Data TLV
# Step 4: Leader sends a CoAP ACK frame to each of Router_1 and
# Router_2
with pkts.save_index():
for node in ('ROUTER_1', 'ROUTER_2'):
_dn_pkt = pkts.filter_wpan_src64(pv.vars['%s' %node]).\
filter_wpan_dst16(LEADER_RLOC16).\
filter_coap_request(SVR_DATA_URI).\
filter(lambda p:
[Ipv6Addr(PREFIX_1[:-3])] ==
p.thread_nwd.tlv.prefix and\
[pv.vars['%s_RLOC16' %node]] ==
p.thread_nwd.tlv.border_router_16
).\
must_next()
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(pv.vars['%s_RLOC' %node]).\
filter_coap_ack(SVR_DATA_URI).\
filter(lambda p: p.coap.mid == _dn_pkt.coap.mid).\
must_next()
# Step 5: Leader MUST multicast MLE Data Response with the new
# information collected from Router_1 and Router_2,
# including the following TLVs:,
# - Source Address TLV
# - Leader Data TLV
# - Data Version field <incremented>
# - Stable Data Version field <incremented>
# - Network Data TLV
# - Stable Flag set
# - At least one Prefix TLV (Prefix 1)
# - Two Border Router sub-TLVs
# Border Router1 TLV: Stable Flag set
# Border Router2 TLV: Stable Flag not set
# - 6LoWPAN ID sub-TLV
# Stable Flag set
_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
} <= set(p.mle.tlv.type) and\
[Ipv6Addr(PREFIX_1[:-3])] ==
p.thread_nwd.tlv.prefix 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
).\
must_next()
with pkts.save_index():
_dr_pkt1 = 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
} <= set(p.mle.tlv.type) and\
{
NWD_BORDER_ROUTER_TLV,
NWD_6LOWPAN_ID_TLV
} <= set(p.thread_nwd.tlv.type) and\
p.mle.tlv.leader_data.data_version ==
(_dr_pkt.mle.tlv.leader_data.data_version + 1) % 256 and\
p.mle.tlv.leader_data.stable_data_version ==
_dr_pkt.mle.tlv.leader_data.stable_data_version and\
is_sublist([ROUTER_1_RLOC16, ROUTER_2_RLOC16],
p.thread_nwd.tlv.border_router_16) and\
is_sublist([0, 1, 1, 1, 0], p.thread_nwd.tlv.stable) and\
is_sublist([1], getattr(p.thread_nwd.tlv, '6co').flag.c) and\
is_sublist([Ipv6Addr(PREFIX_1[:-3])], p.thread_nwd.tlv.prefix)
).\
must_next()
# Step 6: Leader MUST send a MLE Child Update Request or MLE Data
# Response to SED, including the following TLVs:
# - Network Data TLV
# At least one Prefix TLV (Prefix 1) including:
# - Stable Flag set
# - Border Router sub-TLV(corresponding to Router_1)
# - P_border_router_16<0xFFFE>
# - Stable Flag set
# - 6LoWPAN ID sub-TLV
# - Stable Flag set
# - Source Address TLV
# - Leader Data TLV
# - Active Timestamp TLV
pkts.filter_wpan_src64(LEADER).\
filter_wpan_dst64(SED).\
filter_mle_cmd2(MLE_CHILD_UPDATE_REQUEST, MLE_DATA_RESPONSE).\
filter(lambda p: {
NETWORK_DATA_TLV,
SOURCE_ADDRESS_TLV,
LEADER_DATA_TLV,
ACTIVE_TIMESTAMP_TLV
} <= set(p.mle.tlv.type) and\
is_sublist([Ipv6Addr(PREFIX_1[:-3])], p.thread_nwd.tlv.prefix) and\
is_sublist([1, 1, 1], p.thread_nwd.tlv.stable) and\
is_sublist([1], getattr(p.thread_nwd.tlv, '6co').flag.c) and\
is_sublist([0xFFFE], p.thread_nwd.tlv.border_router_16)
).\
must_next()
# Step 10: Router_2 automatically reattaches to the Leader and sends
# a CoAP Server Data Notification message with the servers
# information (Prefix, Border Router) to the Leader:
# CoAP Request URI
# coap://[<leader address>]:MM/a/sd
# CoAP Payload
# Thread Network Data TLV
# Step 11: Leader sends a CoAP ACK frame to each of Routers
pv.verify_attached('ROUTER_2', 'LEADER')
with pkts.save_index():
_dn_pkt = pkts.filter_wpan_src64(ROUTER_2).\
filter_wpan_dst16(LEADER_RLOC16).\
filter_coap_request(SVR_DATA_URI).\
filter(lambda p:
[Ipv6Addr(PREFIX_2[:-3])] ==
p.thread_nwd.tlv.prefix and\
[ROUTER_2_RLOC16] ==
p.thread_nwd.tlv.border_router_16
).\
must_next()
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(ROUTER_2_RLOC).\
filter_coap_ack(SVR_DATA_URI).\
filter(lambda p: p.coap.mid == _dn_pkt.coap.mid).\
must_next()
# Step 12: Leader MUST multicast MLE Data Response with the new
# information collected from Router_2,
# including the following TLVs:,
# - Source Address TLV
# - Leader Data TLV
# - Data Version field <incremented>
# - Stable Data Version field <incremented>
# - Network Data TLV
# - Stable Flag set
# - At least two Prefix TLVs (Prefix 1 and Prefix 2)
# - Prefix 1 TLV
# - Stable Flag set
# - Only one Border Router sub-TLV
# corresponding to Router_1
# - 6LoWPAN ID sub-TLV
# - Stable Flag set
# - Prefix 2 TLV
# - Stable Flag set
# - Only one Border Router sub-TLV
# corresponding to Router_2
# - 6LoWPAN ID sub-TLV
_dr_pkt2 = 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
} <= set(p.mle.tlv.type) and\
{
NWD_BORDER_ROUTER_TLV,
NWD_6LOWPAN_ID_TLV
} <= set(p.thread_nwd.tlv.type) and\
is_sublist([ROUTER_1_RLOC16, ROUTER_2_RLOC16],
p.thread_nwd.tlv.border_router_16) and\
is_sublist([0, 1, 1, 1, 1, 1, 1],
p.thread_nwd.tlv.stable) and\
is_sublist([1, 1], getattr(p.thread_nwd.tlv, '6co').flag.c) and\
is_sublist([Ipv6Addr(PREFIX_1[:-3]), Ipv6Addr(PREFIX_2[:-3])],
p.thread_nwd.tlv.prefix) and\
p.mle.tlv.leader_data.data_version ==
(_dr_pkt1.mle.tlv.leader_data.data_version + 1) % 256 and\
p.mle.tlv.leader_data.stable_data_version ==
(_dr_pkt1.mle.tlv.leader_data.stable_data_version + 1) % 256
).\
must_next()
# Step 13: Leader MUST send a MLE Child Update Request or MLE Data
# Response to SED, containing the stable Network Data
# including the following TLVs:
# - Source Address TLV
# - Leader Data TLV
# - Network Data TLV
# - At least two Prefix TLVs (Prefix 1 and Prefix 2)
# - Prefix 1 TLV
# - Stable Flag set
# - Border Router sub-TLV
# corresponding to Router_1
# - P_border_router_16 <0xFFFE>
# - Stable flag set
# - 6LoWPAN ID sub-TLV
# - Stable flag set
# - Prefix 2 TLV
# - Stable Flag set
# - Border Router sub-TLV
# corresponding to Router_2
# - P_border_router_16 <0xFFFE>
# - Stable flag set
# - 6LoWPAN ID sub-TLV
# - Stable flag set
# - Active Timestamp TLV
with pkts.save_index():
pkts.filter_wpan_src64(LEADER).\
filter_wpan_dst64(SED).\
filter_mle_cmd2(MLE_CHILD_UPDATE_REQUEST, MLE_DATA_RESPONSE).\
filter(lambda p: {
NETWORK_DATA_TLV,
SOURCE_ADDRESS_TLV,
LEADER_DATA_TLV,
ACTIVE_TIMESTAMP_TLV
} <= set(p.mle.tlv.type) and\
is_sublist([1, 1, 1, 1, 1, 1],
p.thread_nwd.tlv.stable) and\
is_sublist([1, 1], getattr(p.thread_nwd.tlv, '6co').flag.c) and\
is_sublist([Ipv6Addr(PREFIX_1[:-3]), Ipv6Addr(PREFIX_2[:-3])],
p.thread_nwd.tlv.prefix) and\
is_sublist([0xFFFE, 0xFFFE], p.thread_nwd.tlv.border_router_16)
).\
must_next()
# Step 14: Verifies connectivity by sending ICMPv6 Echo Requests from
# Router_1 and SED_1 to the Leader Prefix_1 and Prefix_2-based
# address.
# Leader must respond with ICMPv6 Echo Replies
for i in (0, 1):
for node in ('ROUTER_1', 'SED'):
_pkt = pkts.filter_ping_request().\
filter_ipv6_src_dst(GUA[i][node], GUA[i]['LEADER']).\
must_next()
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
filter_ipv6_src_dst(GUA[i]['LEADER'], GUA[i][node]).\
must_next()
# Step 15: Router_2 sends a CoAP Server Data Notification message with
# the servers information (Prefix, Border Router) to the Leader:
# CoAP Request URI
# coap://[<leader address>]:MM/a/sd
# CoAP Payload
# empty payload
# Step 16: Leader sends a CoAP ACK frame to each of Router_1 and
# Router_2
with pkts.save_index():
_dn_pkt = pkts.filter_wpan_src64(ROUTER_2).\
filter_wpan_dst16(LEADER_RLOC16).\
filter_coap_request(SVR_DATA_URI).\
filter(lambda p:
p.thread_nwd.tlv.border_router_16 is nullField
).\
must_next()
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(ROUTER_2_RLOC).\
filter_coap_ack(SVR_DATA_URI).\
filter(lambda p: p.coap.mid == _dn_pkt.coap.mid).\
must_next()
# Step 17: Leader MUST multicast MLE Data Response with the new
# information collected from Router_2,
# including the following TLVs:,
# - Source Address TLV
# - Leader Data TLV
# - Data Version field <incremented>
# - Stable Data Version field <incremented>
# - Network Data TLV
# - Stable Flag set
# - At least two Prefix TLVs (Prefix 1 and Prefix 2)
# - Prefix 1 TLV
# - Stable Flag set
# - Only one Border Router sub-TLV
# corresponding to Router_1
# - 6LoWPAN ID sub-TLV
# - Stable Flag set
# - Prefix 2 TLV
# - Stable Flag set
# - 6LoWPAN ID sub-TLV
# - Stable Flag set
# - compression flag set to 0
_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
} <= set(p.mle.tlv.type) and\
{
NWD_BORDER_ROUTER_TLV,
NWD_6LOWPAN_ID_TLV
} <= set(p.thread_nwd.tlv.type) and\
p.mle.tlv.leader_data.data_version ==
(_dr_pkt2.mle.tlv.leader_data.data_version + 1) % 256 and\
p.mle.tlv.leader_data.stable_data_version ==
(_dr_pkt2.mle.tlv.leader_data.stable_data_version + 1) % 256 and\
is_sublist([Ipv6Addr(PREFIX_1[:-3]), Ipv6Addr(PREFIX_2[:-3])],
p.thread_nwd.tlv.prefix) and\
is_sublist([1,0], getattr(p.thread_nwd.tlv, '6co').flag.c)
).\
must_next()
# Step 18: Leader MUST send a MLE Child Update Request or MLE Data
# Response to SED, containing the stable Network Data
# including the following TLVs:
# - Source Address TLV
# - Leader Data TLV
# - Network Data TLV
# - At least two Prefix TLVs (Prefix 1 and Prefix 2)
# - Prefix 1 TLV
# - Stable Flag set
# - Border Router sub-TLV
# corresponding to Router_1
# - P_border_router_16 <0xFFFE>
# - Stable flag set
# - 6LoWPAN ID sub-TLV
# - Stable flag set
# - Prefix 2 TLV
# - Stable Flag set
# - 6LoWPAN ID sub-TLV
# - Stable flag set
# - compression flag set to 0
# - Active Timestamp TLV
pkts.filter_wpan_src64(LEADER).\
filter_wpan_dst64(SED).\
filter_mle_cmd2(MLE_CHILD_UPDATE_REQUEST, MLE_DATA_RESPONSE).\
filter(lambda p: {
NETWORK_DATA_TLV,
SOURCE_ADDRESS_TLV,
LEADER_DATA_TLV,
ACTIVE_TIMESTAMP_TLV
} <= set(p.mle.tlv.type) and\
is_sublist([Ipv6Addr(PREFIX_1[:-3]), Ipv6Addr(PREFIX_2[:-3])],
p.thread_nwd.tlv.prefix) and\
is_sublist([1, 1, 1, 1, 1], p.thread_nwd.tlv.stable) and\
is_sublist([0xFFFE], p.thread_nwd.tlv.border_router_16) and\
is_sublist([1,0], getattr(p.thread_nwd.tlv, '6co').flag.c)
).\
must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,210 +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 copy
import config
import thread_cert
from pktverify.consts import WIRESHARK_OVERRIDE_PREFS, MLE_DATA_RESPONSE, SVR_DATA_URI, NWD_6LOWPAN_ID_TLV, NL_RLOC16_TLV
from pktverify.packet_verifier import PacketVerifier
from pktverify.addrs import Ipv6Addr
from pktverify.null_field import nullField
LEADER = 1
ROUTER = 2
FED = 3
PREFIX_2001 = '2001::/64'
PREFIX_2002 = '2002::/64'
# Test Purpose and Description:
# -----------------------------
# The purpose of this test case is to verify that when global prefix information
# is set on the FED, the DUT properly disseminates the associated network data.
# It also verifies that the DUT sends revised server data information to the
# Leader when the FED is removed.
#
# Test Topology:
# -------------
# FED
# |
# Router(DUT)
# |
# Leader
#
# DUT Types:
# ----------
# Router
class Cert_7_1_8_BorderRouterAsFED(thread_cert.TestCase):
USE_MESSAGE_FACTORY = False
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [ROUTER]
},
ROUTER: {
'name': 'ROUTER',
'mode': 'rdn',
'allowlist': [LEADER, FED]
},
FED: {
'name': 'FED',
'mode': 'rdn',
'router_upgrade_threshold': 0,
'allowlist': [ROUTER]
},
}
# override wireshark preferences with case needed parameters
CASE_WIRESHARK_PREFS = copy.deepcopy(WIRESHARK_OVERRIDE_PREFS)
CASE_WIRESHARK_PREFS['6lowpan.context1'] = PREFIX_2001
CASE_WIRESHARK_PREFS['6lowpan.context2'] = PREFIX_2002
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[FED].start()
self.simulator.go(3)
self.assertEqual(self.nodes[FED].get_state(), 'child')
self.collect_rlocs()
self.collect_rloc16s()
self.collect_leader_aloc(LEADER)
self.nodes[FED].add_prefix(PREFIX_2001, 'paros')
self.nodes[FED].add_prefix(PREFIX_2002, 'paro')
self.nodes[FED].register_netdata()
self.simulator.go(10)
self.nodes[FED].stop()
self.simulator.go(250)
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']
ROUTER = pv.vars['ROUTER']
ROUTER_RLOC = pv.vars['ROUTER_RLOC']
ROUTER_RLOC16 = pv.vars['ROUTER_RLOC16']
FED = pv.vars['FED']
FED_RLOC = pv.vars['FED_RLOC']
FED_RLOC16 = pv.vars['FED_RLOC16']
# Step 1: Ensure topology is formed correctly
pv.verify_attached('ROUTER', 'LEADER')
pv.verify_attached('FED', 'ROUTER', 'MTD')
# Step 2: FED automatically sends a CoAP Server Data Notification
# message with the servers information (Prefix, Border Router)
# to the Leader.
pkts.filter_wpan_src64(FED).\
filter_ipv6_dst(LEADER_ALOC).\
filter_coap_request(SVR_DATA_URI).\
filter(lambda p: {
Ipv6Addr(PREFIX_2001[:-3]),
Ipv6Addr(PREFIX_2002[:-3])
} == set(p.thread_nwd.tlv.prefix) and\
p.thread_nwd.tlv.border_router_16 == [FED_RLOC16, FED_RLOC16]
).\
must_next()
# Step 3: Leader transmits a 2.04 Changed CoAP response to the DUT.
# And transmits multicast MLE Data Response with the new information
# collected, adding also 6LoWPAN ID TLV for the prefix set on FED.
with pkts.save_index():
pkts.filter_wpan_src64(LEADER).\
filter_ipv6_dst(FED_RLOC).\
filter_coap_ack(SVR_DATA_URI).\
must_next()
with pkts.save_index():
pkts.filter_wpan_src64(LEADER).\
filter_LLANMA().\
filter_mle_cmd(MLE_DATA_RESPONSE).\
filter(lambda p: {
Ipv6Addr(PREFIX_2001[:-3]),
Ipv6Addr(PREFIX_2002[:-3])
} == set(p.thread_nwd.tlv.prefix) and\
NWD_6LOWPAN_ID_TLV in p.thread_nwd.tlv.type and\
p.thread_nwd.tlv.border_router.flag.p == [1, 1] and\
p.thread_nwd.tlv.border_router.flag.s == [1, 1] and\
p.thread_nwd.tlv.border_router.flag.r == [1, 1] and\
p.thread_nwd.tlv.border_router.flag.o == [1, 1] and\
p.thread_nwd.tlv.stable == [0, 1, 1, 1, 0, 0, 0]
).\
must_next()
# Step 4: The DUT transmits multicast MLE Data Response with the new information
# collected, adding also 6LoWPAN ID TLV for the prefix set on FED.
pkts.filter_wpan_src64(ROUTER).\
filter_LLANMA().\
filter_mle_cmd(MLE_DATA_RESPONSE).\
filter(lambda p: {
Ipv6Addr(PREFIX_2001[:-3]),
Ipv6Addr(PREFIX_2002[:-3])
} == set(p.thread_nwd.tlv.prefix) and\
NWD_6LOWPAN_ID_TLV in p.thread_nwd.tlv.type and\
p.thread_nwd.tlv.border_router.flag.p == [1, 1] and\
p.thread_nwd.tlv.border_router.flag.s == [1, 1] and\
p.thread_nwd.tlv.border_router.flag.r == [1, 1] and\
p.thread_nwd.tlv.border_router.flag.o == [1, 1] and\
p.thread_nwd.tlv.stable == [0, 1, 1, 1, 0, 0, 0]
).\
must_next()
# Step 6: The DUT notifies Leader of removed servers (FEDs) RLOC16.
# The DUT MUST send a CoAP Server Data Notification frame
# to the Leader containing only the removed servers RLOC16:
# CoAP Request URI
# coap://[<Leader address>]:MM/a/sd
# CoAP Payload
# RLOC16 TLV
pkts.filter_wpan_src64(ROUTER).\
filter_coap_request(SVR_DATA_URI).\
filter(lambda p:
p.thread_address.tlv.type == [NL_RLOC16_TLV] and\
p.thread_address.tlv.rloc16 == FED_RLOC16
).\
must_next()
if __name__ == '__main__':
unittest.main()