mirror of
https://github.com/espressif/openthread.git
synced 2026-08-02 00:57:47 +00:00
[tests] remove thread-cert tests replaced by Nexus (#12443)
This commit removes the Python-based thread-cert tests for sections 5.1, 5.2, and 5.3. These tests have been replaced by C++ Nexus tests in tests/nexus/, which offer better performance, reliability, and integration with the core OpenThread codebase. The following Python scripts have been removed from tests/scripts/thread-cert/: - Cert_5_1_01 through Cert_5_1_13 - Cert_5_2_01, Cert_5_2_03 through Cert_5_2_07 - Cert_5_3_01 through Cert_5_3_11 The corresponding Nexus tests are available in tests/nexus/ along with their respective PCAP verification scripts.
This commit is contained in:
@@ -1,318 +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 mle
|
||||
import network_layer
|
||||
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, 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
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to show that the Leader is able to form
|
||||
# a network and the Router attaches to it with proper steps.
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# Leader
|
||||
# |
|
||||
# Router
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Leader
|
||||
# Router
|
||||
|
||||
|
||||
class Cert_5_1_01_RouterAttach(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [ROUTER]
|
||||
},
|
||||
ROUTER: {
|
||||
'name': 'ROUTER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER]
|
||||
},
|
||||
}
|
||||
|
||||
def test(self):
|
||||
self.nodes[LEADER].start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
|
||||
|
||||
self.nodes[ROUTER].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[ROUTER].get_state(), 'router')
|
||||
|
||||
self.collect_rloc16s()
|
||||
|
||||
leader_addr = self.nodes[LEADER].get_ip6_address(config.ADDRESS_TYPE.LINK_LOCAL)
|
||||
self.assertTrue(self.nodes[ROUTER].ping(leader_addr))
|
||||
self.simulator.go(5)
|
||||
|
||||
router_addr = self.nodes[ROUTER].get_ip6_address(config.ADDRESS_TYPE.LINK_LOCAL)
|
||||
self.assertTrue(self.nodes[LEADER].ping(router_addr))
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
LEADER = pv.vars['LEADER']
|
||||
LEADER_RLOC16 = pv.vars['LEADER_RLOC16']
|
||||
ROUTER = pv.vars['ROUTER']
|
||||
|
||||
# Step 1: Leader is sending properly formatted MLE Advertisements.
|
||||
# Advertisements MUST be sent 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
|
||||
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_LLANMA().\
|
||||
filter_mle_cmd(MLE_ADVERTISEMENT).\
|
||||
filter(lambda p: {
|
||||
LEADER_DATA_TLV,
|
||||
ROUTE64_TLV,
|
||||
SOURCE_ADDRESS_TLV
|
||||
} <= set(p.mle.tlv.type) and\
|
||||
p.ipv6.hlim == 255).\
|
||||
must_next()
|
||||
|
||||
# Step 2: Router 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.
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER).\
|
||||
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).\
|
||||
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(ROUTER).\
|
||||
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
|
||||
# - Mode TLV
|
||||
# - Response TLV
|
||||
# - Timeout TLV
|
||||
# - TLV Request TLV
|
||||
# - Address16 TLV
|
||||
# - Network Data TLV
|
||||
# - Route64 TLV (optional)
|
||||
# - Version TLV
|
||||
# - MLE Frame Counter TLV (optional)
|
||||
# The following TLV MUST NOT be present in the MLE Child ID Request:
|
||||
# - Address Registration TLV
|
||||
|
||||
_pkt = pkts.filter_wpan_src64(ROUTER).\
|
||||
filter_wpan_dst64(LEADER).\
|
||||
filter_mle_cmd(MLE_CHILD_ID_REQUEST).\
|
||||
filter(lambda p: {
|
||||
LINK_LAYER_FRAME_COUNTER_TLV,
|
||||
MODE_TLV,
|
||||
RESPONSE_TLV,
|
||||
TIMEOUT_TLV,
|
||||
TLV_REQUEST_TLV,
|
||||
ADDRESS16_TLV,
|
||||
NETWORK_DATA_TLV,
|
||||
VERSION_TLV
|
||||
} <= set(p.mle.tlv.type) and\
|
||||
p.mle.tlv.addr16 is nullField and\
|
||||
p.thread_nwd.tlv.type is nullField).\
|
||||
must_next()
|
||||
_pkt.must_not_verify(lambda p: (ADDRESS_REGISTRATION_TLV) in p.mle.tlv.type)
|
||||
|
||||
# Step 5: Leader responds with a Child ID Response.
|
||||
# The following TLVs MUST be present in the Child ID Response:
|
||||
# - Address16 TLV
|
||||
# - Leader Data TLV
|
||||
# - Network Data TLV
|
||||
# - Source Address TLV
|
||||
# - Route64 TLV (if requested)
|
||||
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_wpan_dst64(ROUTER).\
|
||||
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) or\
|
||||
{
|
||||
ADDRESS16_TLV,
|
||||
LEADER_DATA_TLV,
|
||||
NETWORK_DATA_TLV,
|
||||
SOURCE_ADDRESS_TLV
|
||||
} <= set(p.mle.tlv.type)).\
|
||||
must_next()
|
||||
|
||||
# Step 6: Router sends an Address Solicit Request.
|
||||
# Ensure the Address Solicit Request is properly formatted:
|
||||
# CoAP Request URI
|
||||
# coap://<leader address>:MM/a/as
|
||||
# CoAP Payload
|
||||
# - MAC Extended Address TLV
|
||||
# - Status TLV
|
||||
|
||||
_pkt = pkts.filter_wpan_src64(ROUTER).\
|
||||
filter_wpan_dst16(LEADER_RLOC16).\
|
||||
filter_coap_request(ADDR_SOL_URI).\
|
||||
filter(lambda p: {
|
||||
NL_MAC_EXTENDED_ADDRESS_TLV,
|
||||
NL_STATUS_TLV
|
||||
} <= set(p.coap.tlv.type)\
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 7: Leader sends an Address Solicit Response.
|
||||
# Ensure the Address Solicit Response is properly formatted:
|
||||
# CoAP Response Code
|
||||
# 2.04 Changed
|
||||
# CoAP Payload
|
||||
# - Status TLV (value = Success)
|
||||
# - RLOC16 TLV
|
||||
# - Router Mask TLV
|
||||
|
||||
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()
|
||||
|
||||
# Steps 8 and 9 are skipped due to change the Link establishment
|
||||
# process (no multicast MLE Link Request by new router).
|
||||
|
||||
# Step 10: Router is sending properly formatted MLE Advertisements.
|
||||
# MLE Advertisements MUST be sent 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
|
||||
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_LLANMA().\
|
||||
filter_mle_cmd(MLE_ADVERTISEMENT).\
|
||||
filter(lambda p: {
|
||||
LEADER_DATA_TLV,
|
||||
ROUTE64_TLV,
|
||||
SOURCE_ADDRESS_TLV
|
||||
} <= set(p.mle.tlv.type) and\
|
||||
p.ipv6.hlim == 255).\
|
||||
must_next()
|
||||
|
||||
# Step 11: DUT responds with ICMPv6 Echo Reply
|
||||
|
||||
_pkt = pkts.filter_ping_request().\
|
||||
filter_wpan_src64(ROUTER).\
|
||||
filter_wpan_dst64(LEADER).\
|
||||
must_next()
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(LEADER).\
|
||||
filter_wpan_dst64(ROUTER).\
|
||||
must_next()
|
||||
|
||||
_pkt = pkts.filter_ping_request().\
|
||||
filter_wpan_src64(LEADER).\
|
||||
filter_wpan_dst64(ROUTER).\
|
||||
must_next()
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(ROUTER).\
|
||||
filter_wpan_dst64(LEADER).\
|
||||
must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,183 +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 mle
|
||||
import thread_cert
|
||||
from pktverify.consts import MLE_CHILD_ID_RESPONSE, ADDR_QRY_URI, ADDR_NTF_URI, NL_TARGET_EID_TLV
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
|
||||
LEADER = 1
|
||||
ROUTER = 2
|
||||
MED = 3
|
||||
SED = 4
|
||||
|
||||
MTDS = [MED, SED]
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of the test case is to verify that when the timer reaches
|
||||
# the value of the Timeout TLV sent by the Child, the Parent stops
|
||||
# responding to Address Query on the Child's behalf
|
||||
#
|
||||
# Test Topology:
|
||||
# --------------
|
||||
# Leader
|
||||
# |
|
||||
# Router
|
||||
# / \
|
||||
# MED SED
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Router
|
||||
|
||||
|
||||
class Cert_5_1_02_ChildAddressTimeout(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',
|
||||
'timeout': config.DEFAULT_CHILD_TIMEOUT,
|
||||
'allowlist': [ROUTER]
|
||||
},
|
||||
SED: {
|
||||
'name': 'SED',
|
||||
'is_mtd': True,
|
||||
'mode': 'n',
|
||||
'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.collect_ipaddrs()
|
||||
|
||||
med_mleid = self.nodes[MED].get_ip6_address(config.ADDRESS_TYPE.ML_EID)
|
||||
sed_mleid = self.nodes[SED].get_ip6_address(config.ADDRESS_TYPE.ML_EID)
|
||||
|
||||
self.nodes[MED].stop()
|
||||
self.nodes[SED].stop()
|
||||
self.simulator.go(config.DEFAULT_CHILD_TIMEOUT + 5)
|
||||
self.assertFalse(self.nodes[LEADER].ping(med_mleid))
|
||||
self.assertFalse(self.nodes[LEADER].ping(sed_mleid))
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
LEADER = pv.vars['LEADER']
|
||||
ROUTER = pv.vars['ROUTER']
|
||||
MED = pv.vars['MED']
|
||||
MED_MLEID = pv.vars['MED_MLEID']
|
||||
SED = pv.vars['SED']
|
||||
SED_MLEID = pv.vars['SED_MLEID']
|
||||
MM = pv.vars['MM_PORT']
|
||||
|
||||
# Step 1: Verify topology is formed correctly
|
||||
|
||||
pv.verify_attached('ROUTER')
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER).\
|
||||
filter_wpan_dst64(MED).\
|
||||
filter_mle_cmd(MLE_CHILD_ID_RESPONSE).\
|
||||
must_next()
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER).\
|
||||
filter_wpan_dst64(SED).\
|
||||
filter_mle_cmd(MLE_CHILD_ID_RESPONSE).\
|
||||
must_next()
|
||||
|
||||
# Step 2: Power off both devices and allow for the keep-alive timeout to expire
|
||||
# Step 3: The Leader sends an ICMPv6 Echo Request to MED and attempts to perform
|
||||
# address resolution by sending an Address Query Request
|
||||
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_RLARMA().\
|
||||
filter_coap_request(ADDR_QRY_URI, port=MM).\
|
||||
filter(lambda p: p.thread_address.tlv.type == [NL_TARGET_EID_TLV] and\
|
||||
p.thread_address.tlv.target_eid == MED_MLEID).\
|
||||
must_next()
|
||||
|
||||
# Step 4: Router MUST NOT respond with an Address Notification Message
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER).\
|
||||
filter_coap_request(ADDR_NTF_URI).\
|
||||
must_not_next()
|
||||
|
||||
# Step 5: The Leader sends an ICMPv6 Echo Request to SED and attempts to perform
|
||||
# address resolution by sending an Address Query Request
|
||||
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_RLARMA().\
|
||||
filter(lambda p: p.thread_address.tlv.type == [NL_TARGET_EID_TLV] and\
|
||||
p.thread_address.tlv.target_eid == SED_MLEID).\
|
||||
filter_coap_request(ADDR_QRY_URI, port=MM).\
|
||||
must_next()
|
||||
|
||||
# Step 6: Router MUST NOT respond with an Address Notification Message
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER).\
|
||||
filter_coap_request(ADDR_NTF_URI).\
|
||||
must_not_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,241 +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 mle
|
||||
import network_layer
|
||||
import thread_cert
|
||||
from pktverify.consts import MLE_ADVERTISEMENT, MLE_PARENT_REQUEST, MLE_CHILD_ID_REQUEST, ADDR_SOL_URI, 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, NL_MAC_EXTENDED_ADDRESS_TLV, NL_STATUS_TLV, NL_RLOC16_TLV
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
|
||||
LEADER = 1
|
||||
ROUTER1 = 2
|
||||
ROUTER2 = 3
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to verify that after the removal of the
|
||||
# Leader from the network, the DUT will first attempt to reattach to the
|
||||
# original partition, then attach to a new partition and request its
|
||||
# original short address.
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# Leader Router_2
|
||||
# / \ -> |
|
||||
# Router_1 - Router_2 Router_1[DUT]
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Router
|
||||
|
||||
|
||||
class Cert_5_1_03_RouterAddressReallocation(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [ROUTER1, ROUTER2]
|
||||
},
|
||||
ROUTER1: {
|
||||
'name': 'ROUTER_1',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER, ROUTER2]
|
||||
},
|
||||
ROUTER2: {
|
||||
'name': 'ROUTER_2',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER, 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[ROUTER2].set_network_id_timeout(110)
|
||||
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.collect_rloc16s()
|
||||
|
||||
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']
|
||||
ROUTER_2_RLOC16 = pv.vars['ROUTER_2_RLOC16']
|
||||
|
||||
# Step 2: Verify topology is formed correctly.
|
||||
pv.verify_attached('ROUTER_1')
|
||||
_pkt_as = pkts.filter_wpan_src64(LEADER).\
|
||||
filter_coap_ack(ADDR_SOL_URI).\
|
||||
must_next()
|
||||
|
||||
pv.verify_attached('ROUTER_2')
|
||||
_pkt_pt = pkts.filter_wpan_src64(ROUTER_2).\
|
||||
filter_LLANMA().\
|
||||
filter_mle_cmd(MLE_ADVERTISEMENT).\
|
||||
must_next()
|
||||
|
||||
# Step 5: Router_1 MUST attempt to reattach to its original partition
|
||||
# by sending a MLE Parent Request with a hop limit of 255 to
|
||||
# the All-Routers multicast address (FF02::2).
|
||||
# The following TLVs MUST be present in the MLE Parent Request:
|
||||
# - Challenge TLV
|
||||
# - Mode TLV
|
||||
# - Scan Mask TLV (MUST have E and R flags set)
|
||||
# - Version TLV
|
||||
# The DUT MUST make two separate attempts to reconnect to its
|
||||
# original partition in this manner
|
||||
|
||||
with pkts.save_index():
|
||||
for i in range(2):
|
||||
pkts.filter_wpan_src64(ROUTER_1).\
|
||||
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).\
|
||||
must_next()
|
||||
|
||||
# Step 6: Router_1 MUST attempt to attach to any other partition
|
||||
# within range by sending a MLE Parent Request.
|
||||
# The following TLVs MUST be present in the MLE Parent Request:
|
||||
# - Challenge TLV
|
||||
# - Mode TLV
|
||||
# - Scan Mask TLV
|
||||
# - Version TLV
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER_2).\
|
||||
filter_mle_cmd(MLE_ADVERTISEMENT).\
|
||||
filter_LLANMA().\
|
||||
filter(lambda p:\
|
||||
p.mle.tlv.leader_data.partition_id !=
|
||||
_pkt_pt.mle.tlv.leader_data.partition_id).\
|
||||
must_next()
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER_1).\
|
||||
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.mle.tlv.scan_mask.r == 1 and\
|
||||
p.mle.tlv.scan_mask.e == 0 and\
|
||||
p.ipv6.hlim == 255).\
|
||||
must_next()
|
||||
|
||||
# Step 7: Router_1 sends a MLE Child ID Request to Router_2.
|
||||
# The following TLVs MUST be present in the MLE Child ID Request:
|
||||
# - Link-layer Frame Counter TLV
|
||||
# - Mode TLV
|
||||
# - Response TLV
|
||||
# - Timeout TLV
|
||||
# - TLV Request TLV
|
||||
# - Version TLV
|
||||
# - MLE Frame Counter TLV (optional)
|
||||
# The following TLV MUST NOT be present in the MLE Child ID Request:
|
||||
# - Address Registration TLV
|
||||
|
||||
_pkt = pkts.filter_wpan_src64(ROUTER_1).\
|
||||
filter_wpan_dst64(ROUTER_2).\
|
||||
filter_mle_cmd(MLE_CHILD_ID_REQUEST).\
|
||||
filter(lambda p: {
|
||||
LINK_LAYER_FRAME_COUNTER_TLV,
|
||||
MODE_TLV,
|
||||
RESPONSE_TLV,
|
||||
TIMEOUT_TLV,
|
||||
TLV_REQUEST_TLV,
|
||||
VERSION_TLV
|
||||
} <= set(p.mle.tlv.type)).\
|
||||
must_next()
|
||||
_pkt.must_not_verify(lambda p: (ADDRESS_REGISTRATION_TLV) in p.mle.tlv.type)
|
||||
|
||||
# Step 8: Router_1 sends an Address Solicit Request.
|
||||
# Ensure the Address Solicit Request is properly formatted:
|
||||
# CoAP Request URI
|
||||
# coap://<leader address>:MM/a/as
|
||||
# CoAP Payload
|
||||
# - MAC Extended Address TLV
|
||||
# - Status TLV
|
||||
# - RLOC16 TLV
|
||||
|
||||
_pkt = pkts.filter_wpan_src64(ROUTER_1).\
|
||||
filter_wpan_dst16(ROUTER_2_RLOC16).\
|
||||
filter_coap_request(ADDR_SOL_URI).\
|
||||
filter(lambda p: {
|
||||
NL_MAC_EXTENDED_ADDRESS_TLV,
|
||||
NL_STATUS_TLV,
|
||||
NL_RLOC16_TLV
|
||||
} <= set(p.coap.tlv.type) and\
|
||||
p.thread_address.tlv.rloc16 ==
|
||||
_pkt_as.thread_address.tlv.rloc16).\
|
||||
must_next()
|
||||
|
||||
# Step 9: Router_2 automatically sends an Address Solicit Response.
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER_2).\
|
||||
filter_wpan_dst16(_pkt.wpan.src16).\
|
||||
filter_coap_ack(ADDR_SOL_URI).\
|
||||
filter(lambda p: p.thread_address.tlv.rloc16 ==
|
||||
_pkt_as.thread_address.tlv.rloc16 and\
|
||||
p.thread_address.tlv.status == 0).\
|
||||
must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,269 +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 mle
|
||||
import network_layer
|
||||
import thread_cert
|
||||
from pktverify.consts import MLE_ADVERTISEMENT, MLE_PARENT_REQUEST, MLE_PARENT_RESPONSE, MLE_CHILD_ID_RESPONSE, ADDR_SOL_URI, MODE_TLV, CHALLENGE_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, CONNECTIVITY_TLV, ROUTE64_TLV, ADDRESS16_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, SCAN_MASK_TLV, VERSION_TLV, LINK_MARGIN_TLV, SOURCE_ADDRESS_TLV, COAP_CODE_ACK, NL_STATUS_TLV, NL_RLOC16_TLV, NL_ROUTER_MASK_TLV
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
|
||||
LEADER = 1
|
||||
ROUTER1 = 2
|
||||
ROUTER2 = 3
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to verify that when the original Leader is
|
||||
# removed from the network, the DUT will create a new partition as Leader and
|
||||
# will assign a router ID if a specific ID is requested.
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# Leader
|
||||
# / \
|
||||
# Router_1 - Router_2
|
||||
# [DUT]
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Router
|
||||
|
||||
|
||||
class Cert_5_1_04_RouterAddressReallocation(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
SUPPORT_NCP = False
|
||||
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'partition_id': 1,
|
||||
'allowlist': [ROUTER1, ROUTER2]
|
||||
},
|
||||
ROUTER1: {
|
||||
'name': 'ROUTER_1',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER, ROUTER2]
|
||||
},
|
||||
ROUTER2: {
|
||||
'name': 'ROUTER_2',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER, 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[ROUTER2].set_network_id_timeout(200)
|
||||
self.nodes[LEADER].stop()
|
||||
self.simulator.go(220)
|
||||
self.assertEqual(self.nodes[ROUTER1].get_state(), 'leader')
|
||||
self.assertEqual(self.nodes[ROUTER2].get_state(), 'router')
|
||||
|
||||
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']
|
||||
MM = pv.vars['MM_PORT']
|
||||
|
||||
# Step 3: Verify topology is formed correctly.
|
||||
|
||||
pv.verify_attached('ROUTER_1')
|
||||
_pkt_pt = pkts.filter_wpan_src64(ROUTER_1).\
|
||||
filter_LLANMA().\
|
||||
filter_mle_cmd(MLE_ADVERTISEMENT).\
|
||||
must_next()
|
||||
with pkts.save_index():
|
||||
_pkt_id = pkts.filter_wpan_src64(ROUTER_1).\
|
||||
filter_wpan_dst64(ROUTER_2).\
|
||||
filter_mle_cmd(MLE_PARENT_RESPONSE).\
|
||||
must_next()
|
||||
|
||||
pv.verify_attached('ROUTER_2')
|
||||
_pkt_as = pkts.filter_wpan_src64(LEADER).\
|
||||
filter_coap_ack(ADDR_SOL_URI, port=MM).\
|
||||
must_next()
|
||||
|
||||
# Step 5: Router_1 MUST attempt to reattach to its original partition
|
||||
# by sending a MLE Parent Request with a hop limit of 255 to
|
||||
# the All-Routers multicast address (FF02::2).
|
||||
# The following TLVs MUST be present in the MLE Parent Request:
|
||||
# - Challenge TLV
|
||||
# - Mode TLV
|
||||
# - Scan Mask TLV (MUST have E and R flags set)
|
||||
# - Version TLV
|
||||
# The DUT MUST make two separate attempts to reconnect to its
|
||||
# original partition in this manner
|
||||
|
||||
with pkts.save_index():
|
||||
for i in range(1, 3):
|
||||
pkts.filter_wpan_src64(ROUTER_1).\
|
||||
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
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 6: Router_1 MUST attempt to attach to any other partition
|
||||
# within range by sending a MLE Parent Request.
|
||||
# The following TLVs MUST be present in the MLE Parent Request:
|
||||
# - Challenge TLV
|
||||
# - Mode TLV
|
||||
# - Scan Mask TLV
|
||||
# - Version TLV
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER_1).\
|
||||
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
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 7: Router_1 MUST create a new partition and update the following
|
||||
# values randomly:
|
||||
# - Partition ID
|
||||
# - Initial VN_version & VN_stable_version
|
||||
# - Initial ID sequence number
|
||||
# Notes: Considerring the randomly created VN_version & VN_stable_version
|
||||
# could equal the previous versions, checking one of them to
|
||||
# reduce case failures
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER_1).\
|
||||
filter_LLANMA().\
|
||||
filter_mle_cmd(MLE_ADVERTISEMENT).\
|
||||
filter(lambda p:\
|
||||
p.mle.tlv.leader_data.partition_id !=
|
||||
_pkt_pt.mle.tlv.leader_data.partition_id and\
|
||||
(p.mle.tlv.leader_data.data_version !=
|
||||
_pkt_pt.mle.tlv.leader_data.data_version or\
|
||||
p.mle.tlv.leader_data.stable_data_version !=
|
||||
_pkt_pt.mle.tlv.leader_data.stable_data_version)
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 9: Router_1 MUST send a properly formatted Parent Response and
|
||||
# Child ID Response to Router_2.
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER_1).\
|
||||
filter_wpan_dst64(ROUTER_2).\
|
||||
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) and\
|
||||
p.mle.tlv.conn.id_seq != _pkt_id.mle.tlv.conn.id_seq
|
||||
).\
|
||||
must_next()
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER_1).\
|
||||
filter_wpan_dst64(ROUTER_2).\
|
||||
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) or\
|
||||
{
|
||||
ADDRESS16_TLV,
|
||||
LEADER_DATA_TLV,
|
||||
NETWORK_DATA_TLV,
|
||||
SOURCE_ADDRESS_TLV
|
||||
} <= set(p.mle.tlv.type)\
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 10: Router_1 MUST send a properly-formatted Address Solicit
|
||||
# Response Message to Router_2.
|
||||
# If a specific router ID is requested, the DUT MUST provide this
|
||||
# router ID:
|
||||
# CoAP Response Code
|
||||
# - 2.04 Changed
|
||||
# CoAP Payload
|
||||
# - Status TLV (value = Success)
|
||||
# - RLOC16 TLV
|
||||
# - Router Mask TLV
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER_1).\
|
||||
filter_coap_ack(ADDR_SOL_URI, port=MM).\
|
||||
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.rloc16 ==
|
||||
_pkt_as.thread_address.tlv.rloc16 and\
|
||||
p.thread_address.tlv.status == 0
|
||||
).\
|
||||
must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,314 +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 mle
|
||||
import network_layer
|
||||
import thread_cert
|
||||
from pktverify.consts import MLE_PARENT_RESPONSE, MLE_CHILD_ID_RESPONSE, MLE_LINK_REQUEST, ADDR_SOL_URI, CHALLENGE_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, CONNECTIVITY_TLV, ROUTE64_TLV, ADDRESS16_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, VERSION_TLV, TLV_REQUEST_TLV, LINK_MARGIN_TLV, SOURCE_ADDRESS_TLV, COAP_CODE_ACK, COAP_CODE_POST, NL_MAC_EXTENDED_ADDRESS_TLV, NL_STATUS_TLV, NL_RLOC16_TLV, NL_ROUTER_MASK_TLV
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
|
||||
LEADER = 1
|
||||
ROUTER1 = 2
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to verify that after deallocating a Router ID,
|
||||
# Leader as a DUT doesn't reassign the Router ID for at least ID_REUSE_DELAY
|
||||
# seconds
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# Leader
|
||||
# |
|
||||
# Router
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Leader
|
||||
|
||||
|
||||
class Cert_5_1_05_RouterAddressTimeout(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [ROUTER1]
|
||||
},
|
||||
ROUTER1: {
|
||||
'name': 'ROUTER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER]
|
||||
},
|
||||
}
|
||||
|
||||
def _setUpRouter1(self):
|
||||
self.nodes[ROUTER1].add_allowlist(self.nodes[LEADER].get_addr64())
|
||||
self.nodes[ROUTER1].enable_allowlist()
|
||||
self.nodes[ROUTER1].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[ROUTER1].reset()
|
||||
self._setUpRouter1()
|
||||
self.simulator.go(200)
|
||||
self.nodes[ROUTER1].start()
|
||||
self.simulator.go(config.ROUTER_RESTORE_DELAY)
|
||||
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
|
||||
|
||||
self.nodes[ROUTER1].reset()
|
||||
self._setUpRouter1()
|
||||
self.simulator.go(300)
|
||||
self.nodes[ROUTER1].start()
|
||||
self.simulator.go(config.ROUTER_RESTORE_DELAY)
|
||||
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
LEADER = pv.vars['LEADER']
|
||||
ROUTER = pv.vars['ROUTER']
|
||||
MM = pv.vars['MM_PORT']
|
||||
|
||||
# Step 1: Verify topology is formed correctly.
|
||||
|
||||
pv.verify_attached('ROUTER')
|
||||
_pkt_as = pkts.filter_wpan_src64(LEADER).\
|
||||
filter_coap_ack(ADDR_SOL_URI, port=MM).\
|
||||
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()
|
||||
|
||||
# Step 3: Router automatically sends a link request, reattaches and
|
||||
# requests its original Router ID after reset within the
|
||||
# ID_REUSE_DELAY interval
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER).\
|
||||
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)\
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 4: Leader MUST send a properly formatted Parent Response and
|
||||
# Child ID Response to Router.
|
||||
# And send Address Solicit Response Message to Router.
|
||||
# The RLOC16 TLV in the Address Solicit Response message MUST
|
||||
# contain a different Router ID then the one allocated in the
|
||||
# original attach because ID_REUSE_DELAY interval has not
|
||||
# timed out.
|
||||
#
|
||||
# CoAP Response Code
|
||||
# - 2.04 Changed
|
||||
# CoAP Payload
|
||||
# - Status TLV (value = Success)
|
||||
# - RLOC16 TLV
|
||||
# - Router Mask TLV
|
||||
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_wpan_dst64(ROUTER).\
|
||||
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(LEADER).\
|
||||
filter_wpan_dst64(ROUTER).\
|
||||
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) or\
|
||||
{
|
||||
ADDRESS16_TLV,
|
||||
LEADER_DATA_TLV,
|
||||
NETWORK_DATA_TLV,
|
||||
SOURCE_ADDRESS_TLV
|
||||
} <= set(p.mle.tlv.type)\
|
||||
).\
|
||||
must_next()
|
||||
|
||||
_pkt_as2 = pkts.filter_wpan_src64(ROUTER).\
|
||||
filter_coap_request(ADDR_SOL_URI, port=MM).\
|
||||
filter(lambda p: {
|
||||
NL_MAC_EXTENDED_ADDRESS_TLV,
|
||||
NL_RLOC16_TLV,
|
||||
NL_STATUS_TLV
|
||||
} <= set(p.coap.tlv.type) and\
|
||||
p.coap.code == COAP_CODE_POST and\
|
||||
p.thread_address.tlv.rloc16 ==
|
||||
_pkt_as.thread_address.tlv.rloc16
|
||||
).\
|
||||
must_next()
|
||||
|
||||
_pkt_as3 = pkts.filter_wpan_src64(LEADER).\
|
||||
filter_coap_ack(ADDR_SOL_URI, port=MM).\
|
||||
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.rloc16 !=
|
||||
_pkt_as2.thread_address.tlv.rloc16 and\
|
||||
p.thread_address.tlv.status == 0
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 6: Router automatically sends a link request, reattaches and
|
||||
# requests its most recent Router ID after reset after the
|
||||
# ID_REUSE_DELAY interval
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER).\
|
||||
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)\
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 7: Leader MUST send a properly formatted Parent Response and
|
||||
# Child ID Response to Router.
|
||||
# And send Address Solicit Response Message to Router.
|
||||
# The RLOC16 TLV in the Address Solicit Response message MUST
|
||||
# contain the requested Router ID
|
||||
#
|
||||
# CoAP Response Code
|
||||
# - 2.04 Changed
|
||||
# CoAP Payload
|
||||
# - Status TLV (value = Success)
|
||||
# - RLOC16 TLV
|
||||
# - Router Mask TLV
|
||||
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_wpan_dst64(ROUTER).\
|
||||
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(LEADER).\
|
||||
filter_wpan_dst64(ROUTER).\
|
||||
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) or\
|
||||
{
|
||||
ADDRESS16_TLV,
|
||||
LEADER_DATA_TLV,
|
||||
NETWORK_DATA_TLV,
|
||||
SOURCE_ADDRESS_TLV
|
||||
} <= set(p.mle.tlv.type)\
|
||||
).\
|
||||
must_next()
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER).\
|
||||
filter_coap_request(ADDR_SOL_URI, port=MM).\
|
||||
filter(lambda p: {
|
||||
NL_MAC_EXTENDED_ADDRESS_TLV,
|
||||
NL_RLOC16_TLV,
|
||||
NL_STATUS_TLV
|
||||
} <= set(p.coap.tlv.type) and\
|
||||
p.coap.code == COAP_CODE_POST and\
|
||||
p.thread_address.tlv.rloc16 ==
|
||||
_pkt_as3.thread_address.tlv.rloc16
|
||||
).\
|
||||
must_next()
|
||||
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_coap_ack(ADDR_SOL_URI, port=MM).\
|
||||
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.rloc16 ==
|
||||
_pkt_as3.thread_address.tlv.rloc16 and\
|
||||
p.thread_address.tlv.status == 0
|
||||
).\
|
||||
must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,199 +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 command
|
||||
import config
|
||||
import mle
|
||||
import thread_cert
|
||||
from command import CheckType
|
||||
from pktverify.consts import MLE_PARENT_REQUEST, MLE_CHILD_ID_REQUEST, ADDR_SOL_URI, MODE_TLV, TIMEOUT_TLV, CHALLENGE_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, ADDRESS16_TLV, NETWORK_DATA_TLV, TLV_REQUEST_TLV, SCAN_MASK_TLV, VERSION_TLV, ADDRESS_REGISTRATION_TLV, NL_MAC_EXTENDED_ADDRESS_TLV, NL_RLOC16_TLV, NL_STATUS_TLV, NL_ROUTER_MASK_TLV, COAP_CODE_POST, COAP_CODE_ACK
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
from pktverify.null_field import nullField
|
||||
|
||||
LEADER = 1
|
||||
ROUTER1 = 2
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to verify that when the Leader
|
||||
# de-allocates a router ID, the DUT, as a router, re-attaches.
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# Leader
|
||||
# |
|
||||
# Router
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Router
|
||||
|
||||
|
||||
class Cert_5_1_06_RemoveRouterId(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [ROUTER1]
|
||||
},
|
||||
ROUTER1: {
|
||||
'name': 'ROUTER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER]
|
||||
},
|
||||
}
|
||||
|
||||
def test(self):
|
||||
self.nodes[LEADER].start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
|
||||
|
||||
self.nodes[ROUTER1].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
|
||||
rloc16 = self.nodes[ROUTER1].get_addr16()
|
||||
self.collect_rloc16s()
|
||||
|
||||
router_lladdr = self.nodes[ROUTER1].get_ip6_address(config.ADDRESS_TYPE.LINK_LOCAL)
|
||||
self.assertTrue(self.nodes[LEADER].ping(router_lladdr))
|
||||
|
||||
self.nodes[LEADER].release_router_id(rloc16 >> 10)
|
||||
self.simulator.go(5)
|
||||
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
|
||||
|
||||
self.assertTrue(self.nodes[LEADER].ping(router_lladdr))
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
LEADER = pv.vars['LEADER']
|
||||
LEADER_RLOC16 = pv.vars['LEADER_RLOC16']
|
||||
ROUTER = pv.vars['ROUTER']
|
||||
MM = pv.vars['MM_PORT']
|
||||
|
||||
# Step 1: Verify topology is formed correctly.
|
||||
|
||||
pv.verify_attached('ROUTER')
|
||||
_pkt_as = pkts.filter_wpan_src64(LEADER).\
|
||||
filter_coap_ack(ADDR_SOL_URI, port=MM).\
|
||||
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()
|
||||
|
||||
# Step 3: Router send a properly formatted
|
||||
# MLE Parent Request,
|
||||
# MLE Child ID Request,
|
||||
# and Address Solicit Request
|
||||
# messages to the Leader.
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER).\
|
||||
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).\
|
||||
must_next()
|
||||
|
||||
_pkt = pkts.filter_wpan_src64(ROUTER).\
|
||||
filter_wpan_dst64(LEADER).\
|
||||
filter_mle_cmd(MLE_CHILD_ID_REQUEST).\
|
||||
filter(lambda p: {
|
||||
LINK_LAYER_FRAME_COUNTER_TLV,
|
||||
MODE_TLV,
|
||||
RESPONSE_TLV,
|
||||
TIMEOUT_TLV,
|
||||
TLV_REQUEST_TLV,
|
||||
ADDRESS16_TLV,
|
||||
NETWORK_DATA_TLV,
|
||||
VERSION_TLV
|
||||
} <= set(p.mle.tlv.type) and\
|
||||
p.mle.tlv.addr16 is nullField and\
|
||||
p.thread_nwd.tlv.type is nullField).\
|
||||
must_next()
|
||||
_pkt.must_not_verify(lambda p: (ADDRESS_REGISTRATION_TLV) in p.mle.tlv.type)
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER).\
|
||||
filter_wpan_dst16(LEADER_RLOC16).\
|
||||
filter_coap_request(ADDR_SOL_URI, port=MM).\
|
||||
filter(lambda p: {
|
||||
NL_MAC_EXTENDED_ADDRESS_TLV,
|
||||
NL_RLOC16_TLV,
|
||||
NL_STATUS_TLV
|
||||
} <= set(p.coap.tlv.type) and\
|
||||
p.coap.code == COAP_CODE_POST and\
|
||||
p.thread_address.tlv.rloc16 ==
|
||||
_pkt_as.thread_address.tlv.rloc16
|
||||
).\
|
||||
must_next()
|
||||
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_coap_ack(ADDR_SOL_URI, port=MM).\
|
||||
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.rloc16 !=
|
||||
_pkt_as.thread_address.tlv.rloc16 and\
|
||||
p.thread_address.tlv.status == 0
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 4: DUT responds with ICMPv6 Echo Reply
|
||||
|
||||
_pkt = pkts.filter_ping_request().\
|
||||
filter_wpan_src64(LEADER).\
|
||||
filter_wpan_dst64(ROUTER).\
|
||||
must_next()
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(ROUTER).\
|
||||
filter_wpan_dst64(LEADER).\
|
||||
must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,279 +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_RESPONSE, MLE_CHILD_ID_RESPONSE, SOURCE_ADDRESS_TLV, CHALLENGE_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, ADDRESS16_TLV, LEADER_DATA_TLV, NETWORK_DATA_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
|
||||
ROUTER = 2
|
||||
SED1 = 7
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to validate the minimum
|
||||
# conformance requirements for router-capable devices:
|
||||
# a)Minimum number of supported children.
|
||||
# b)Minimum MTU requirement when sending/forwarding an
|
||||
# IPv6 datagram to a SED.
|
||||
# c)Minimum number of sent/forwarded IPv6 datagrams to
|
||||
# SED children.
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
#
|
||||
# Leader
|
||||
# |
|
||||
# Router[DUT]
|
||||
# / \
|
||||
# MED1 - MED4 SED1 - SED6
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Router
|
||||
|
||||
|
||||
class Cert_5_1_07_MaxChildCount(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [ROUTER]
|
||||
},
|
||||
ROUTER: {
|
||||
'name': 'ROUTER',
|
||||
'max_children': 10,
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER, 3, 4, 5, 6, SED1, 8, 9, 10, 11, 12]
|
||||
},
|
||||
3: {
|
||||
'name': 'MED1',
|
||||
'is_mtd': True,
|
||||
'mode': 'rn',
|
||||
'timeout': config.DEFAULT_CHILD_TIMEOUT,
|
||||
'allowlist': [ROUTER]
|
||||
},
|
||||
4: {
|
||||
'name': 'MED2',
|
||||
'is_mtd': True,
|
||||
'mode': 'rn',
|
||||
'timeout': config.DEFAULT_CHILD_TIMEOUT,
|
||||
'allowlist': [ROUTER]
|
||||
},
|
||||
5: {
|
||||
'name': 'MED3',
|
||||
'is_mtd': True,
|
||||
'mode': 'rn',
|
||||
'timeout': config.DEFAULT_CHILD_TIMEOUT,
|
||||
'allowlist': [ROUTER]
|
||||
},
|
||||
6: {
|
||||
'name': 'MED4',
|
||||
'is_mtd': True,
|
||||
'mode': 'rn',
|
||||
'timeout': config.DEFAULT_CHILD_TIMEOUT,
|
||||
'allowlist': [ROUTER]
|
||||
},
|
||||
SED1: {
|
||||
'name': 'SED1',
|
||||
'is_mtd': True,
|
||||
'mode': '-',
|
||||
'timeout': config.DEFAULT_CHILD_TIMEOUT,
|
||||
'allowlist': [ROUTER]
|
||||
},
|
||||
8: {
|
||||
'name': 'SED2',
|
||||
'is_mtd': True,
|
||||
'mode': '-',
|
||||
'timeout': config.DEFAULT_CHILD_TIMEOUT,
|
||||
'allowlist': [ROUTER]
|
||||
},
|
||||
9: {
|
||||
'name': 'SED3',
|
||||
'is_mtd': True,
|
||||
'mode': '-',
|
||||
'timeout': config.DEFAULT_CHILD_TIMEOUT,
|
||||
'allowlist': [ROUTER]
|
||||
},
|
||||
10: {
|
||||
'name': 'SED4',
|
||||
'is_mtd': True,
|
||||
'mode': '-',
|
||||
'timeout': config.DEFAULT_CHILD_TIMEOUT,
|
||||
'allowlist': [ROUTER]
|
||||
},
|
||||
11: {
|
||||
'name': 'SED5',
|
||||
'is_mtd': True,
|
||||
'mode': '-',
|
||||
'timeout': config.DEFAULT_CHILD_TIMEOUT,
|
||||
'allowlist': [ROUTER]
|
||||
},
|
||||
12: {
|
||||
'name': 'SED6',
|
||||
'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')
|
||||
|
||||
for i in range(3, 13):
|
||||
self.nodes[i].start()
|
||||
self.simulator.go(7)
|
||||
self.assertEqual(self.nodes[i].get_state(), 'child')
|
||||
|
||||
self.collect_rloc16s()
|
||||
self.collect_ipaddrs()
|
||||
|
||||
ipaddrs = self.nodes[SED1].get_addrs()
|
||||
for addr in ipaddrs:
|
||||
if addr[0:4] != 'fe80' and 'ff:fe00' not in addr:
|
||||
self.assertTrue(self.nodes[LEADER].ping(addr, size=1232))
|
||||
break
|
||||
|
||||
for i in range(3, 13):
|
||||
ipaddrs = self.nodes[i].get_addrs()
|
||||
for addr in ipaddrs:
|
||||
if addr[0:4] != 'fe80' and 'ff:fe00' not in addr:
|
||||
self.assertTrue(self.nodes[LEADER].ping(addr, size=106))
|
||||
break
|
||||
|
||||
def verify(self, pv: PacketVerifier):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
ROUTER = pv.vars['ROUTER']
|
||||
router_pkts = pkts.filter_wpan_src64(ROUTER)
|
||||
|
||||
# Step 1: The DUT MUST send properly formatted MLE Parent Response
|
||||
# and MLE Child ID Response to each child.
|
||||
for i in range(1, 7):
|
||||
_pkts = router_pkts.copy().filter_wpan_dst64(pv.vars['SED%d' % i])
|
||||
_pkts.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_mle_cmd(MLE_CHILD_ID_RESPONSE).\
|
||||
filter(lambda p: {
|
||||
SOURCE_ADDRESS_TLV,
|
||||
LEADER_DATA_TLV,
|
||||
ADDRESS16_TLV,
|
||||
NETWORK_DATA_TLV,
|
||||
ADDRESS_REGISTRATION_TLV
|
||||
} <= set(p.mle.tlv.type) and\
|
||||
p.mle.tlv.addr16 is not nullField and\
|
||||
p.thread_nwd.tlv.type is not None and\
|
||||
p.thread_meshcop.tlv.type is not None
|
||||
).\
|
||||
must_next()
|
||||
|
||||
for i in range(1, 5):
|
||||
_pkts = router_pkts.copy().filter_wpan_dst64(pv.vars['MED%d' % i])
|
||||
_pkts.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_mle_cmd(MLE_CHILD_ID_RESPONSE).\
|
||||
filter(lambda p: {
|
||||
SOURCE_ADDRESS_TLV,
|
||||
LEADER_DATA_TLV,
|
||||
ADDRESS16_TLV,
|
||||
NETWORK_DATA_TLV,
|
||||
ADDRESS_REGISTRATION_TLV
|
||||
} <= set(p.mle.tlv.type) and\
|
||||
p.mle.tlv.addr16 is not nullField and\
|
||||
p.thread_meshcop.tlv.type is not None
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 2: The DUT MUST properly forward ICMPv6 Echo Requests to all MED children
|
||||
# The DUT MUST properly forward ICMPv6 Echo Replies to the Leader
|
||||
leader_rloc16 = pv.vars['LEADER_RLOC16']
|
||||
for i in range(1, 5):
|
||||
rloc16 = pv.vars['MED%d_RLOC16' % i]
|
||||
_pkts = router_pkts.copy()
|
||||
p = _pkts.filter('wpan.dst16 == {rloc16}', rloc16=rloc16).\
|
||||
filter_ping_request().\
|
||||
must_next()
|
||||
_pkts.filter('wpan.dst16 == {rloc16}',
|
||||
rloc16=leader_rloc16).\
|
||||
filter_ping_reply(identifier=p.icmpv6.echo.identifier).\
|
||||
must_next()
|
||||
|
||||
# Step 3: The DUT MUST properly forward ICMPv6 Echo Requests to all SED children
|
||||
# The DUT MUST properly forward ICMPv6 Echo Replies to the Leader
|
||||
for i in range(1, 7):
|
||||
rloc16 = pv.vars['SED%d_RLOC16' % i]
|
||||
_pkts = router_pkts.copy()
|
||||
p = _pkts.filter('wpan.dst16 == {rloc16}', rloc16=rloc16).\
|
||||
filter_ping_request().\
|
||||
must_next()
|
||||
_pkts.filter('wpan.dst16 == {rloc16}',
|
||||
rloc16=leader_rloc16).\
|
||||
filter_ping_reply(identifier=p.icmpv6.echo.identifier).\
|
||||
must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,220 +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 mle
|
||||
import thread_cert
|
||||
from pktverify.consts import MLE_PARENT_REQUEST, MLE_PARENT_RESPONSE, MLE_CHILD_ID_REQUEST, SOURCE_ADDRESS_TLV, MODE_TLV, TIMEOUT_TLV, CHALLENGE_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_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
|
||||
ROUTER1 = 2
|
||||
ROUTER2 = 3
|
||||
ROUTER3 = 4
|
||||
ROUTER4 = 5
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to verify that the DUT chooses
|
||||
# to attach to a router with better connectivity
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# Leader--Router1
|
||||
# / \ /
|
||||
# Router2 Router3
|
||||
# \ /
|
||||
# Router4[DUT]
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Router
|
||||
|
||||
|
||||
class Cert_5_1_08_RouterAttachConnectivity(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
|
||||
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, ROUTER4]
|
||||
},
|
||||
ROUTER3: {
|
||||
'name': 'ROUTER_3',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER, ROUTER1, ROUTER4]
|
||||
},
|
||||
ROUTER4: {
|
||||
'name': 'ROUTER_4',
|
||||
'mode': 'rdn',
|
||||
'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[ROUTER4].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[ROUTER4].get_state(), 'router')
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
ROUTER_2 = pv.vars['ROUTER_2']
|
||||
ROUTER_3 = pv.vars['ROUTER_3']
|
||||
ROUTER_4 = pv.vars['ROUTER_4']
|
||||
|
||||
# Step 1: Verify all routers and Leader are sending MLE advertisements.
|
||||
for i in (1, 2, 3):
|
||||
with pkts.save_index():
|
||||
pv.verify_attached('ROUTER_%d' % i)
|
||||
|
||||
# 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
|
||||
# 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.
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER_4).\
|
||||
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
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 4: Router2 and Router3 respond 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)
|
||||
|
||||
for i in (2, 3):
|
||||
with pkts.save_index():
|
||||
pkts.filter_wpan_src64(pv.vars['ROUTER_%d' % i]).\
|
||||
filter_wpan_dst64(ROUTER_4).\
|
||||
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 Child ID Request to Router3.
|
||||
# The following TLVs MUST be present in the MLE Child ID Request:
|
||||
# - Link-layer Frame Counter TLV
|
||||
# - Mode TLV
|
||||
# - Response TLV
|
||||
# - Timeout TLV
|
||||
# - TLV Request TLV
|
||||
# - Address16 TLV
|
||||
# - Network Data TLV
|
||||
# - Route64 TLV (optional)
|
||||
# - Version TLV
|
||||
# - MLE Frame Counter TLV (optional)
|
||||
# The following TLV MUST NOT be present in the MLE Child ID Request:
|
||||
# - Address Registration TLV
|
||||
|
||||
_pkt = pkts.filter_wpan_src64(ROUTER_4).\
|
||||
filter_wpan_dst64(ROUTER_3).\
|
||||
filter_mle_cmd(MLE_CHILD_ID_REQUEST).\
|
||||
filter(lambda p: {
|
||||
LINK_LAYER_FRAME_COUNTER_TLV,
|
||||
MODE_TLV,
|
||||
RESPONSE_TLV,
|
||||
TIMEOUT_TLV,
|
||||
TLV_REQUEST_TLV,
|
||||
ADDRESS16_TLV,
|
||||
NETWORK_DATA_TLV,
|
||||
VERSION_TLV
|
||||
} <= set(p.mle.tlv.type) and\
|
||||
p.mle.tlv.addr16 is nullField and\
|
||||
p.thread_nwd.tlv.type is nullField
|
||||
).\
|
||||
must_next()
|
||||
_pkt.must_not_verify(lambda p: (ADDRESS_REGISTRATION_TLV) in p.mle.tlv.type)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,274 +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 mle
|
||||
import thread_cert
|
||||
from pktverify.consts import MLE_ADVERTISEMENT, MLE_PARENT_REQUEST, MLE_PARENT_RESPONSE, MLE_CHILD_ID_REQUEST, SOURCE_ADDRESS_TLV, MODE_TLV, TIMEOUT_TLV, CHALLENGE_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_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
|
||||
ROUTER1 = 2
|
||||
REED1 = 3
|
||||
REED2 = 4
|
||||
ROUTER2 = 5
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to verify that the DUT will
|
||||
# pick REED_1 as its parent because of its better connectivity
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# Leader--Router1
|
||||
# / \ /
|
||||
# REED2 REED1
|
||||
# \ /
|
||||
# Router2[DUT]
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Router
|
||||
|
||||
|
||||
class Cert_5_1_09_REEDAttachConnectivity(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [ROUTER1, REED1, REED2]
|
||||
},
|
||||
ROUTER1: {
|
||||
'name': 'ROUTER_1',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER, REED1]
|
||||
},
|
||||
REED1: {
|
||||
'name': 'REED_1',
|
||||
'mode': 'rdn',
|
||||
'router_upgrade_threshold': 0,
|
||||
'allowlist': [LEADER, ROUTER1, ROUTER2]
|
||||
},
|
||||
REED2: {
|
||||
'name': 'REED_2',
|
||||
'mode': 'rdn',
|
||||
'router_upgrade_threshold': 0,
|
||||
'allowlist': [LEADER, ROUTER2]
|
||||
},
|
||||
ROUTER2: {
|
||||
'name': 'ROUTER_2',
|
||||
'mode': 'rdn',
|
||||
'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')
|
||||
|
||||
for i in range(2, 5):
|
||||
self.nodes[i].start()
|
||||
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
|
||||
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
|
||||
self.assertEqual(self.nodes[REED1].get_state(), 'child')
|
||||
self.assertEqual(self.nodes[REED2].get_state(), 'child')
|
||||
|
||||
self.simulator.go(config.MAX_ADVERTISEMENT_INTERVAL)
|
||||
|
||||
self.nodes[ROUTER2].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[ROUTER2].get_state(), 'router')
|
||||
self.assertEqual(self.nodes[REED1].get_state(), 'router')
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
LEADER = pv.vars['LEADER']
|
||||
REED_1 = pv.vars['REED_1']
|
||||
ROUTER_1 = pv.vars['ROUTER_1']
|
||||
ROUTER_2 = pv.vars['ROUTER_2']
|
||||
|
||||
# Step 1: Verify ROUTER_1 and Leader are sending MLE advertisements.
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_mle_cmd(MLE_ADVERTISEMENT).\
|
||||
must_next()
|
||||
pv.verify_attached('ROUTER_1')
|
||||
|
||||
# Step 3: The 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.
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER_2).\
|
||||
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
|
||||
).\
|
||||
must_next()
|
||||
lstart = pkts.index
|
||||
|
||||
# Step 5: The DUT MUST send 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
|
||||
# - The Scan Mask TLV MUST be sent to Routers And REEDs
|
||||
# - Version TLV
|
||||
#
|
||||
# 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(ROUTER_2).\
|
||||
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()
|
||||
lend = pkts.index
|
||||
|
||||
# Step 4: REED_1 and REED_2 no response to Parent Request meant for all routers.
|
||||
|
||||
for i in (1, 2):
|
||||
pkts.range(lstart, lend).\
|
||||
filter_wpan_src64(pv.vars['REED_%d' % i]).\
|
||||
filter_wpan_dst64(ROUTER_2).\
|
||||
filter_mle_cmd(MLE_PARENT_RESPONSE).\
|
||||
must_not_next()
|
||||
|
||||
# Step 6: REED_1 and REED_2 respond 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)
|
||||
|
||||
for i in (1, 2):
|
||||
with pkts.save_index():
|
||||
pkts.filter_wpan_src64(pv.vars['REED_%d' % i]).\
|
||||
filter_wpan_dst64(ROUTER_2).\
|
||||
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) and\
|
||||
p.wpan.aux_sec.key_id_mode == 0x2
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 7: DUT sends a MLE Child ID Request to REED_1.
|
||||
# The following TLVs MUST be present in the MLE Child ID Request:
|
||||
# - Link-layer Frame Counter TLV
|
||||
# - Mode TLV
|
||||
# - Response TLV
|
||||
# - Timeout TLV
|
||||
# - TLV Request TLV
|
||||
# - Address16 TLV
|
||||
# - Network Data TLV
|
||||
# - Route64 TLV (optional)
|
||||
# - Version TLV
|
||||
# - MLE Frame Counter TLV (optional)
|
||||
# The following TLV MUST NOT be present in the MLE Child ID Request:
|
||||
# - Address Registration TLV
|
||||
|
||||
_pkt = pkts.filter_wpan_src64(ROUTER_2).\
|
||||
filter_wpan_dst64(REED_1).\
|
||||
filter_mle_cmd(MLE_CHILD_ID_REQUEST).\
|
||||
filter(lambda p: {
|
||||
LINK_LAYER_FRAME_COUNTER_TLV,
|
||||
MODE_TLV,
|
||||
RESPONSE_TLV,
|
||||
TIMEOUT_TLV,
|
||||
TLV_REQUEST_TLV,
|
||||
ADDRESS16_TLV,
|
||||
NETWORK_DATA_TLV,
|
||||
VERSION_TLV
|
||||
} <= set(p.mle.tlv.type) and\
|
||||
p.mle.tlv.addr16 is nullField and\
|
||||
p.thread_nwd.tlv.type is nullField and\
|
||||
p.wpan.aux_sec.key_id_mode == 0x2
|
||||
).\
|
||||
must_next()
|
||||
_pkt.must_not_verify(lambda p: (ADDRESS_REGISTRATION_TLV) in p.mle.tlv.type)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,214 +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 mle
|
||||
import thread_cert
|
||||
from pktverify.consts import MLE_ADVERTISEMENT, MLE_PARENT_REQUEST, MLE_PARENT_RESPONSE, MLE_CHILD_ID_REQUEST, SOURCE_ADDRESS_TLV, MODE_TLV, TIMEOUT_TLV, CHALLENGE_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_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
|
||||
ROUTER1 = 2
|
||||
ROUTER2 = 3
|
||||
ROUTER3 = 4
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to validate that the DUT
|
||||
# will choose a router with better link quality as its parent.
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# Leader
|
||||
# / \
|
||||
# ROUTER2 ROUTER1
|
||||
# \ /(better link_quality)
|
||||
# Router3[DUT]
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Router
|
||||
|
||||
|
||||
class Cert_5_1_10_RouterAttachLinkQuality(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
|
||||
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, (ROUTER3, -85)]
|
||||
},
|
||||
ROUTER3: {
|
||||
'name': 'ROUTER_3',
|
||||
'mode': 'rdn',
|
||||
'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[ROUTER3].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[ROUTER3].get_state(), 'router')
|
||||
|
||||
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']
|
||||
|
||||
# Step 1: Verify ROUTER_1, Router2 and Leader are sending MLE advertisements.
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_mle_cmd(MLE_ADVERTISEMENT).\
|
||||
must_next()
|
||||
pv.verify_attached('ROUTER_1')
|
||||
pv.verify_attached('ROUTER_2')
|
||||
|
||||
# Step 3: The 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
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER_3).\
|
||||
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
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 4: ROUTER_1 and ROUTER_2 respond 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)
|
||||
|
||||
for i in range(1, 3):
|
||||
with pkts.save_index():
|
||||
pkts.filter_wpan_src64(pv.vars['ROUTER_%d' % i]).\
|
||||
filter_wpan_dst64(ROUTER_3).\
|
||||
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: The DUT MUST initiate the attach process with Router_1 by
|
||||
# sending an MLE Child ID Request; if not, the test fails.
|
||||
# The following TLVs MUST be present in the MLE Child ID Request:
|
||||
# - Link-layer Frame Counter TLV
|
||||
# - Mode TLV
|
||||
# - Response TLV
|
||||
# - Timeout TLV
|
||||
# - TLV Request TLV
|
||||
# - Address16 TLV
|
||||
# - Network Data TLV
|
||||
# - Route64 TLV (optional)
|
||||
# - Version TLV
|
||||
# - MLE Frame Counter TLV (optional)
|
||||
# The following TLV MUST NOT be present in the MLE Child ID Request:
|
||||
# - Address Registration TLV
|
||||
|
||||
_pkt = pkts.filter_wpan_src64(ROUTER_3).\
|
||||
filter_wpan_dst64(ROUTER_1).\
|
||||
filter_mle_cmd(MLE_CHILD_ID_REQUEST).\
|
||||
filter(lambda p: {
|
||||
LINK_LAYER_FRAME_COUNTER_TLV,
|
||||
MODE_TLV,
|
||||
RESPONSE_TLV,
|
||||
TIMEOUT_TLV,
|
||||
TLV_REQUEST_TLV,
|
||||
ADDRESS16_TLV,
|
||||
NETWORK_DATA_TLV,
|
||||
VERSION_TLV
|
||||
} <= set(p.mle.tlv.type) and\
|
||||
p.mle.tlv.addr16 is nullField and\
|
||||
p.thread_nwd.tlv.type is nullField
|
||||
).\
|
||||
must_next()
|
||||
_pkt.must_not_verify(lambda p: (ADDRESS_REGISTRATION_TLV) in p.mle.tlv.type)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,213 +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 mle
|
||||
import thread_cert
|
||||
from pktverify.consts import MLE_ADVERTISEMENT, MLE_PARENT_REQUEST, MLE_PARENT_RESPONSE, MLE_CHILD_ID_REQUEST, SOURCE_ADDRESS_TLV, MODE_TLV, TIMEOUT_TLV, CHALLENGE_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_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
|
||||
REED = 2
|
||||
ROUTER2 = 3
|
||||
ROUTER1 = 4
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to validate that DUT will
|
||||
# attach to a REED with the highest link quality, when routers
|
||||
# with the highest link quality are not available.
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# Leader
|
||||
# / \
|
||||
# Router2 REED1
|
||||
# \ /(better link_quality)
|
||||
# Router1[DUT]
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Router
|
||||
|
||||
|
||||
class Cert_5_1_11_REEDAttachLinkQuality(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [REED, ROUTER2]
|
||||
},
|
||||
REED: {
|
||||
'name': 'REED_1',
|
||||
'mode': 'rdn',
|
||||
'router_upgrade_threshold': 0,
|
||||
'allowlist': [LEADER, ROUTER1]
|
||||
},
|
||||
ROUTER2: {
|
||||
'name': 'ROUTER_2',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER, (ROUTER1, -85)]
|
||||
},
|
||||
ROUTER1: {
|
||||
'name': 'ROUTER_1',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [REED, 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[REED].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[REED].get_state(), 'child')
|
||||
|
||||
self.nodes[ROUTER2].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[ROUTER2].get_state(), 'router')
|
||||
|
||||
self.nodes[ROUTER1].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
|
||||
self.assertEqual(self.nodes[REED].get_state(), 'router')
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
LEADER = pv.vars['LEADER']
|
||||
REED_1 = pv.vars['REED_1']
|
||||
ROUTER_1 = pv.vars['ROUTER_1']
|
||||
ROUTER_2 = pv.vars['ROUTER_2']
|
||||
|
||||
# Step 1: Verify ROUTER_2 and Leader are sending MLE advertisements.
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_mle_cmd(MLE_ADVERTISEMENT).\
|
||||
must_next()
|
||||
pv.verify_attached('ROUTER_2')
|
||||
|
||||
# Step 3: The 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.
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER_1).\
|
||||
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
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 5: The DUT MUST send 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
|
||||
# - The Scan Mask TLV MUST be sent to Routers And REEDs
|
||||
# - Version TLV
|
||||
#
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER_1).\
|
||||
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
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 6: The DUT MUST initiate the attach process with REED_1 by
|
||||
# sending an MLE Child ID Request; if not, the test fails.
|
||||
# The following TLVs MUST be present in the MLE Child ID Request:
|
||||
# - Link-layer Frame Counter TLV
|
||||
# - Mode TLV
|
||||
# - Response TLV
|
||||
# - Timeout TLV
|
||||
# - TLV Request TLV
|
||||
# - Address16 TLV
|
||||
# - Network Data TLV
|
||||
# - Route64 TLV (optional)
|
||||
# - Version TLV
|
||||
# - MLE Frame Counter TLV (optional)
|
||||
# The following TLV MUST NOT be present in the MLE Child ID Request:
|
||||
# - Address Registration TLV
|
||||
|
||||
_pkt = pkts.filter_wpan_src64(ROUTER_1).\
|
||||
filter_wpan_dst64(REED_1).\
|
||||
filter_mle_cmd(MLE_CHILD_ID_REQUEST).\
|
||||
filter(lambda p: {
|
||||
LINK_LAYER_FRAME_COUNTER_TLV,
|
||||
MODE_TLV,
|
||||
RESPONSE_TLV,
|
||||
TIMEOUT_TLV,
|
||||
TLV_REQUEST_TLV,
|
||||
ADDRESS16_TLV,
|
||||
NETWORK_DATA_TLV,
|
||||
VERSION_TLV
|
||||
} <= set(p.mle.tlv.type) and\
|
||||
p.mle.tlv.addr16 is nullField and\
|
||||
p.thread_nwd.tlv.type is nullField
|
||||
).\
|
||||
must_next()
|
||||
_pkt.must_not_verify(lambda p: (ADDRESS_REGISTRATION_TLV) in p.mle.tlv.type)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,208 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2016, The OpenThread Authors.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. Neither the name of the copyright holder nor the
|
||||
# names of its contributors may be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
import unittest
|
||||
|
||||
import config
|
||||
import mle
|
||||
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, 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, 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
|
||||
ROUTER1 = 2
|
||||
ROUTER2 = 3
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to validate that when the DUT sees a new router for the first time, it will synchronize using the New Router Neighbor Synchronization procedure.
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# Leader
|
||||
# / \
|
||||
# Router2 Router1[DUT]
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Router
|
||||
|
||||
|
||||
class Cert_5_1_12_NewRouterSync(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [ROUTER1, ROUTER2]
|
||||
},
|
||||
ROUTER1: {
|
||||
'name': 'ROUTER_1',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER]
|
||||
},
|
||||
ROUTER2: {
|
||||
'name': 'ROUTER_2',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER]
|
||||
},
|
||||
}
|
||||
|
||||
def test(self):
|
||||
self.nodes[LEADER].start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
|
||||
|
||||
self.nodes[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.simulator.go(10)
|
||||
|
||||
self.nodes[ROUTER1].add_allowlist(self.nodes[ROUTER2].get_addr64())
|
||||
self.nodes[ROUTER2].add_allowlist(self.nodes[ROUTER1].get_addr64())
|
||||
|
||||
self.simulator.go(35)
|
||||
|
||||
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']
|
||||
|
||||
# Step 1: Verify topology is formed correctly.
|
||||
|
||||
# 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
|
||||
|
||||
pv.verify_attached('ROUTER_1')
|
||||
pkts.filter_wpan_src64(ROUTER_1).\
|
||||
filter_LLANMA().\
|
||||
filter_mle_cmd(MLE_ADVERTISEMENT).\
|
||||
filter(lambda p: {
|
||||
LEADER_DATA_TLV,
|
||||
ROUTE64_TLV,
|
||||
SOURCE_ADDRESS_TLV
|
||||
} <= set(p.mle.tlv.type) and\
|
||||
p.ipv6.hlim == 255).\
|
||||
must_next()
|
||||
|
||||
pv.verify_attached('ROUTER_2')
|
||||
pkts.filter_wpan_src64(ROUTER_2).\
|
||||
filter_LLANMA().\
|
||||
filter_mle_cmd(MLE_ADVERTISEMENT).\
|
||||
filter(lambda p: {
|
||||
LEADER_DATA_TLV,
|
||||
ROUTE64_TLV,
|
||||
SOURCE_ADDRESS_TLV
|
||||
} <= set(p.mle.tlv.type) and\
|
||||
p.ipv6.hlim == 255).\
|
||||
must_next()
|
||||
|
||||
# Step 4: The DUT and Router_2 exchange unicast Link Request and unicast
|
||||
# Link Accept messages OR Link Accept and Request messages.
|
||||
#
|
||||
# The Link Request Message MUST be unicast and contain
|
||||
# the following TLVs:
|
||||
# - Challenge TLV
|
||||
# - Leader Data TLV
|
||||
# - Source Address TLV
|
||||
# - Version TLV
|
||||
# - TLV Request TLV: Link Margin
|
||||
#
|
||||
# Link Accept or Link Accept And Request Messages MUST be
|
||||
# Unicast.
|
||||
# The following TLVs MUST be present in the Link Accept or
|
||||
# Link Accept And Request Messages :
|
||||
# - Leader Data TLV
|
||||
# - Link-layer Frame Counter TLV
|
||||
# - Link Margin TLV
|
||||
# - Response TLV
|
||||
# - Source Address TLV
|
||||
# - Version TLV
|
||||
# - TLV Request TLV: Link Margin
|
||||
# - Challenge TLV (optional)
|
||||
# - MLE Frame Counter TLV (optional)
|
||||
# The Challenge TLV and TLV Request TLV MUST be included
|
||||
# if the response is an Accept and Request message.
|
||||
|
||||
lq_src = ROUTER_1
|
||||
lq_dst = ROUTER_2
|
||||
_pkt = pkts.filter_mle_cmd(MLE_LINK_REQUEST).\
|
||||
filter(lambda p: {
|
||||
CHALLENGE_TLV,
|
||||
LEADER_DATA_TLV,
|
||||
SOURCE_ADDRESS_TLV,
|
||||
VERSION_TLV,
|
||||
TLV_REQUEST_TLV,
|
||||
LINK_MARGIN_TLV
|
||||
} <= set(p.mle.tlv.type) and\
|
||||
p.mle.tlv.link_margin is nullField and\
|
||||
(p.wpan.src64 == ROUTER_1 or\
|
||||
p.wpan.src64 == ROUTER_2)
|
||||
).\
|
||||
must_next()
|
||||
if _pkt.wpan.src64 != ROUTER_1:
|
||||
_pkt.must_verify(lambda p: p.wpan.dst64 == ROUTER_1)
|
||||
lq_src = ROUTER_2
|
||||
lq_dst = ROUTER_1
|
||||
|
||||
_pkt = pkts.filter_wpan_src64(lq_dst).\
|
||||
filter_wpan_dst64(lq_src).\
|
||||
filter_mle_cmd2(MLE_LINK_ACCEPT, MLE_LINK_ACCEPT_AND_REQUEST).\
|
||||
filter(lambda p: {
|
||||
LEADER_DATA_TLV,
|
||||
LINK_LAYER_FRAME_COUNTER_TLV,
|
||||
LINK_MARGIN_TLV,
|
||||
RESPONSE_TLV,
|
||||
SOURCE_ADDRESS_TLV,
|
||||
VERSION_TLV
|
||||
} <= set(p.mle.tlv.type) and\
|
||||
p.mle.tlv.link_margin is not nullField
|
||||
).\
|
||||
must_next()
|
||||
if _pkt.mle.cmd == MLE_LINK_ACCEPT_AND_REQUEST:
|
||||
_pkt.must_verify(lambda p: {CHALLENGE_TLV, TLV_REQUEST_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 config
|
||||
import mle
|
||||
import thread_cert
|
||||
from pktverify.consts import MLE_ADVERTISEMENT, 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, MLE_MAX_RESPONSE_DELAY
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
from pktverify.null_field import nullField
|
||||
|
||||
LEADER = 1
|
||||
ROUTER = 2
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to validate that when a router resets,
|
||||
# it will synchronize upon returning by using the Router Synchronization
|
||||
# after Reset procedure.
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# Leader
|
||||
# |
|
||||
# Router
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Leader
|
||||
# Router
|
||||
|
||||
|
||||
class Cert_5_1_13_RouterReset(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [ROUTER]
|
||||
},
|
||||
ROUTER: {
|
||||
'name': 'ROUTER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER]
|
||||
},
|
||||
}
|
||||
|
||||
def _setUpRouter(self):
|
||||
self.nodes[ROUTER].add_allowlist(self.nodes[LEADER].get_addr64())
|
||||
self.nodes[ROUTER].enable_allowlist()
|
||||
self.nodes[ROUTER].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.collect_rloc16s()
|
||||
|
||||
self.nodes[ROUTER].reset()
|
||||
self._setUpRouter()
|
||||
self.simulator.go(5)
|
||||
|
||||
self.nodes[ROUTER].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[ROUTER].get_state(), 'router')
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
LEADER = pv.vars['LEADER']
|
||||
ROUTER = pv.vars['ROUTER']
|
||||
ROUTER_RLOC16 = pv.vars['ROUTER_RLOC16']
|
||||
|
||||
# Step 1: Verify topology is formed correctly.
|
||||
|
||||
# Step 2: Devices 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
|
||||
|
||||
pv.verify_attached('ROUTER')
|
||||
pkts.filter_wpan_src64(ROUTER).\
|
||||
filter_LLANMA().\
|
||||
filter_mle_cmd(MLE_ADVERTISEMENT).\
|
||||
filter(lambda p: {
|
||||
LEADER_DATA_TLV,
|
||||
ROUTE64_TLV,
|
||||
SOURCE_ADDRESS_TLV
|
||||
} <= set(p.mle.tlv.type) and\
|
||||
p.ipv6.hlim == 255
|
||||
).\
|
||||
must_next()
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_LLANMA().\
|
||||
filter_mle_cmd(MLE_ADVERTISEMENT).\
|
||||
filter(lambda p: {
|
||||
LEADER_DATA_TLV,
|
||||
ROUTE64_TLV,
|
||||
SOURCE_ADDRESS_TLV
|
||||
} <= set(p.mle.tlv.type) and\
|
||||
p.ipv6.hlim == 255
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 4: Router sends multicast Link Request message
|
||||
#
|
||||
# The Link Request Message MUST be sent to the Link-Local All Routers
|
||||
# Routers multicast address (FF02::2) and contain the following TLVs:
|
||||
# - Challenge TLV
|
||||
# - TLV Request TLV
|
||||
# - Address16 TLV
|
||||
# - Route64 TLV
|
||||
# - Version TLV
|
||||
#
|
||||
|
||||
_pkt_lq = pkts.filter_mle_cmd(MLE_LINK_REQUEST).\
|
||||
filter_LLARMA().\
|
||||
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()
|
||||
|
||||
# Step 5: Leader replies to Router with Link Accept message
|
||||
# The following TLVs MUST be present in the Link Accept message:
|
||||
# - Leader Data TLV
|
||||
# - Link-layer Frame Counter TLV
|
||||
# - Link Margin TLV
|
||||
# - Response TLV
|
||||
# - Source Address TLV
|
||||
# - Version TLV
|
||||
# - TLV Request TLV: Link Margin
|
||||
# - Challenge TLV (optional)
|
||||
# - MLE Frame Counter TLV (optional)
|
||||
# The Challenge TLV MUST be included if the response is an
|
||||
# Accept and Request message.
|
||||
# Responses to multicast Link Requests MUST be delayed by a
|
||||
# random time of up to MLE_MAX_RESPONSE_DELAY (1 second).
|
||||
|
||||
_pkt = pkts.filter_wpan_src64(LEADER).\
|
||||
filter_wpan_dst64(ROUTER).\
|
||||
filter_mle_cmd2(MLE_LINK_ACCEPT, MLE_LINK_ACCEPT_AND_REQUEST).\
|
||||
filter(lambda p: {
|
||||
ADDRESS16_TLV,
|
||||
LEADER_DATA_TLV,
|
||||
LINK_LAYER_FRAME_COUNTER_TLV,
|
||||
RESPONSE_TLV,
|
||||
ROUTE64_TLV,
|
||||
SOURCE_ADDRESS_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 and\
|
||||
p.mle.tlv.addr16 == ROUTER_RLOC16 and\
|
||||
p.sniff_timestamp - _pkt_lq.sniff_timestamp <
|
||||
MLE_MAX_RESPONSE_DELAY + 0.1
|
||||
).\
|
||||
must_next()
|
||||
if _pkt.mle.cmd == MLE_LINK_ACCEPT_AND_REQUEST:
|
||||
_pkt.must_verify(lambda p: [CHALLENGE_TLV] in p.mle.tlv.type)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,305 +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 command
|
||||
import config
|
||||
import mle
|
||||
import thread_cert
|
||||
from pktverify.consts import MLE_ADVERTISEMENT, MLE_PARENT_REQUEST, MLE_PARENT_RESPONSE, MLE_CHILD_ID_RESPONSE, 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, CONNECTIVITY_TLV, LINK_MARGIN_TLV, VERSION_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
|
||||
DUT_ROUTER1 = 2
|
||||
REED1 = 3
|
||||
MED1 = 4
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to show that the DUT is able to attach
|
||||
# a REED and forward address solicits two hops away from the Leader.
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# Leader
|
||||
# |
|
||||
# Router_1
|
||||
# |
|
||||
# REED_1
|
||||
# |
|
||||
# MED_1
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Router
|
||||
|
||||
|
||||
class Cert_5_2_01_REEDAttach(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [DUT_ROUTER1]
|
||||
},
|
||||
DUT_ROUTER1: {
|
||||
'name': 'ROUTER_1',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER, REED1]
|
||||
},
|
||||
REED1: {
|
||||
'name': 'REED_1',
|
||||
'mode': 'rdn',
|
||||
'router_upgrade_threshold': 1,
|
||||
'allowlist': [DUT_ROUTER1, MED1]
|
||||
},
|
||||
MED1: {
|
||||
'name': 'MED_1',
|
||||
'is_mtd': True,
|
||||
'mode': 'rn',
|
||||
'allowlist': [REED1]
|
||||
},
|
||||
}
|
||||
|
||||
def test(self):
|
||||
self.nodes[LEADER].start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[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')
|
||||
|
||||
self.nodes[REED1].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[REED1].get_state(), 'child')
|
||||
|
||||
self.nodes[MED1].start()
|
||||
self.simulator.go(5)
|
||||
self.assertEqual(self.nodes[MED1].get_state(), 'child')
|
||||
|
||||
self.collect_rloc16s()
|
||||
self.collect_ipaddrs()
|
||||
|
||||
self.simulator.go(config.MAX_ADVERTISEMENT_INTERVAL)
|
||||
|
||||
reed_mleid = self.nodes[REED1].get_ip6_address(config.ADDRESS_TYPE.ML_EID)
|
||||
self.assertTrue(self.nodes[LEADER].ping(reed_mleid))
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
LEADER = pv.vars['LEADER']
|
||||
LEADER_MLEID = pv.vars['LEADER_MLEID']
|
||||
LEADER_RLOC16 = pv.vars['LEADER_RLOC16']
|
||||
ROUTER_1 = pv.vars['ROUTER_1']
|
||||
ROUTER_1_RLOC16 = pv.vars['ROUTER_1_RLOC16']
|
||||
REED_1 = pv.vars['REED_1']
|
||||
REED_1_MLEID = pv.vars['REED_1_MLEID']
|
||||
|
||||
# Step 1: Router_1 attaches to Leader and sends properly formatted MLE
|
||||
# advertisements
|
||||
# Advertisements MUST be sent 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
|
||||
|
||||
pv.verify_attached('ROUTER_1')
|
||||
pkts.filter_wpan_src64(ROUTER_1).\
|
||||
filter_LLANMA().\
|
||||
filter_mle_cmd(MLE_ADVERTISEMENT).\
|
||||
filter(lambda p: {
|
||||
LEADER_DATA_TLV,
|
||||
ROUTE64_TLV,
|
||||
SOURCE_ADDRESS_TLV
|
||||
} <= set(p.mle.tlv.type) and\
|
||||
p.ipv6.hlim == 255
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 2: Attach REED_1 to Router_1; REED_1 sends 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
|
||||
|
||||
pkts.filter_wpan_src64(REED_1).\
|
||||
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).\
|
||||
must_next()
|
||||
|
||||
# Step 3: Router_1 must respond 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(ROUTER_1).\
|
||||
filter_wpan_dst64(REED_1).\
|
||||
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_1 must respond with a Child ID Response.
|
||||
# The following TLVs MUST be present in the Child ID Response:
|
||||
# - Address16 TLV
|
||||
# - Leader Data TLV
|
||||
# - Network Data TLV
|
||||
# - Source Address TLV
|
||||
# - Route64 TLV (if requested)
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER_1).\
|
||||
filter_wpan_dst64(REED_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) or\
|
||||
{
|
||||
ADDRESS16_TLV,
|
||||
LEADER_DATA_TLV,
|
||||
NETWORK_DATA_TLV,
|
||||
SOURCE_ADDRESS_TLV
|
||||
} <= set(p.mle.tlv.type)
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 7: REED_1 sends an Address Solicit Request to Router_1.
|
||||
# Ensure the Address Solicit Request is properly formatted:
|
||||
# CoAP Request URI
|
||||
# coap://<leader address>:MM/a/as
|
||||
# CoAP Payload
|
||||
# - MAC Extended Address TLV
|
||||
# - Status TLV
|
||||
|
||||
_pkt1 = pkts.filter_wpan_src64(REED_1).\
|
||||
filter_wpan_dst16(ROUTER_1_RLOC16).\
|
||||
filter_coap_request(ADDR_SOL_URI).\
|
||||
filter(lambda p: {
|
||||
NL_MAC_EXTENDED_ADDRESS_TLV,
|
||||
NL_STATUS_TLV
|
||||
} <= set(p.coap.tlv.type)\
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 8: Router_1 forward the REED_1's Address Solicit Request to
|
||||
# Leader and Leader's Address Solicit Response to REED_1.
|
||||
# Ensure the Address Solicit Response is properly formatted:
|
||||
# CoAP Response Code
|
||||
# 2.04 Changed
|
||||
# CoAP Payload
|
||||
# - Status TLV (value = Success)
|
||||
# - RLOC16 TLV
|
||||
# - Router Mask TLV
|
||||
|
||||
_pkt2 = pkts.filter_wpan_src64(ROUTER_1).\
|
||||
filter_wpan_dst16(LEADER_RLOC16).\
|
||||
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(_pkt2.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()
|
||||
pkts.filter_wpan_src64(ROUTER_1).\
|
||||
filter_wpan_dst16(_pkt1.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()
|
||||
|
||||
# Step 9: REED_1 responds with ICMPv6 Echo Reply
|
||||
_pkt = pkts.filter_ipv6_src_dst(LEADER_MLEID, REED_1_MLEID).\
|
||||
filter_ping_request().\
|
||||
must_next()
|
||||
pkts.filter_ipv6_src_dst(REED_1_MLEID, LEADER_MLEID).\
|
||||
filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,428 +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 mle
|
||||
import network_layer
|
||||
import thread_cert
|
||||
from pktverify.consts import MLE_ADVERTISEMENT, MLE_PARENT_RESPONSE, MLE_CHILD_ID_RESPONSE, ADDR_SOL_URI, SOURCE_ADDRESS_TLV, CHALLENGE_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, ADDRESS16_TLV, ROUTE64_TLV, LEADER_DATA_TLV, NETWORK_DATA_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, ADDR_SOL_NA, ADDR_SOL_SUCCESS
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
from pktverify.null_field import nullField
|
||||
|
||||
DUT_LEADER = 1
|
||||
ROUTER_1 = 2
|
||||
ROUTER_31 = 32
|
||||
ROUTER_32 = 33
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to show that the DUT will
|
||||
# only allow 32 active routers on the network and reject the
|
||||
# Address Solicit Request from a 33rd router - that is
|
||||
# 2-hops away - with a No Address Available status.
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# Leader[DUT]
|
||||
# / \
|
||||
# Router_1 --- Router_31
|
||||
# |
|
||||
# |
|
||||
# Router_32
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Leader
|
||||
|
||||
|
||||
class Cert_5_2_3_LeaderReject2Hops(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
|
||||
TOPOLOGY = {
|
||||
DUT_LEADER: {
|
||||
'name':
|
||||
'LEADER',
|
||||
'mode':
|
||||
'rdn',
|
||||
'panid':
|
||||
0xface,
|
||||
'router_downgrade_threshold':
|
||||
33,
|
||||
'router_upgrade_threshold':
|
||||
32,
|
||||
'allowlist': [
|
||||
ROUTER_1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
|
||||
28, 29, 30, 31, ROUTER_31
|
||||
]
|
||||
},
|
||||
ROUTER_1: {
|
||||
'name': 'ROUTER_1',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER, ROUTER_32]
|
||||
},
|
||||
3: {
|
||||
'name': 'ROUTER_2',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
4: {
|
||||
'name': 'ROUTER_3',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
5: {
|
||||
'name': 'ROUTER_4',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
6: {
|
||||
'name': 'ROUTER_5',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
7: {
|
||||
'name': 'ROUTER_6',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
8: {
|
||||
'name': 'ROUTER_7',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
9: {
|
||||
'name': 'ROUTER_8',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
10: {
|
||||
'name': 'ROUTER_9',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
11: {
|
||||
'name': 'ROUTER_10',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
12: {
|
||||
'name': 'ROUTER_11',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
13: {
|
||||
'name': 'ROUTER_12',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
14: {
|
||||
'name': 'ROUTER_13',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
15: {
|
||||
'name': 'ROUTER_14',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
16: {
|
||||
'name': 'ROUTER_15',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
17: {
|
||||
'name': 'ROUTER_16',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
18: {
|
||||
'name': 'ROUTER_17',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
19: {
|
||||
'name': 'ROUTER_18',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
20: {
|
||||
'name': 'ROUTER_19',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
21: {
|
||||
'name': 'ROUTER_20',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
22: {
|
||||
'name': 'ROUTER_21',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
23: {
|
||||
'name': 'ROUTER_22',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
24: {
|
||||
'name': 'ROUTER_23',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
25: {
|
||||
'name': 'ROUTER_24',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
26: {
|
||||
'name': 'ROUTER_25',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
27: {
|
||||
'name': 'ROUTER_26',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
28: {
|
||||
'name': 'ROUTER_27',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
29: {
|
||||
'name': 'ROUTER_28',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
30: {
|
||||
'name': 'ROUTER_29',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
31: {
|
||||
'name': 'ROUTER_30',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
ROUTER_31: {
|
||||
'name': 'ROUTER_31',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
ROUTER_32: {
|
||||
'name': 'ROUTER_32',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 33,
|
||||
'router_upgrade_threshold': 33,
|
||||
'allowlist': [ROUTER_1]
|
||||
},
|
||||
}
|
||||
|
||||
def test(self):
|
||||
self.nodes[DUT_LEADER].start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[DUT_LEADER].get_state(), 'leader')
|
||||
|
||||
for i in range(2, 32):
|
||||
self.nodes[i].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[i].get_state(), 'router')
|
||||
self.collect_rlocs()
|
||||
|
||||
self.nodes[ROUTER_31].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[ROUTER_31].get_state(), 'router')
|
||||
|
||||
self.nodes[ROUTER_32].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
|
||||
def verify(self, pv: PacketVerifier):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
LEADER = pv.vars['LEADER']
|
||||
LEADER_RLOC = pv.vars['LEADER_RLOC']
|
||||
ROUTER_31 = pv.vars['ROUTER_31']
|
||||
ROUTER_32 = pv.vars['ROUTER_32']
|
||||
|
||||
# Step 1: Topology is created, the DUT is the Leader of the network
|
||||
# and there is a total of 32 active routers, including the Leader.
|
||||
for i in range(1, 32):
|
||||
pv.verify_attached('ROUTER_%d' % i)
|
||||
|
||||
# Step 2: Router_31 to attaches to the network and sends an Address
|
||||
# Solicit Request to become an active router.
|
||||
|
||||
_pkt = pkts.filter_wpan_src64(ROUTER_31).\
|
||||
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()
|
||||
|
||||
# Step 3: Leader sends an Address Solicit Response.
|
||||
# Ensure the Address Solicit Response is properly formatted:
|
||||
# CoAP Response Code
|
||||
# 2.04 Changed
|
||||
# CoAP Payload
|
||||
# - Status TLV (value = Success)
|
||||
# - RLOC16 TLV
|
||||
# - Router Mask TLV
|
||||
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_ipv6_dst(_pkt.ipv6.src).\
|
||||
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 == ADDR_SOL_SUCCESS\
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 4: Leader The DUT sends MLE Advertisements.
|
||||
# The MLE Advertisements from the Leader MUST contain
|
||||
# the Route64 TLV with 32 assigned Router IDs.
|
||||
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_LLANMA().\
|
||||
filter_mle_cmd(MLE_ADVERTISEMENT).\
|
||||
filter(lambda p: {
|
||||
LEADER_DATA_TLV,
|
||||
ROUTE64_TLV,
|
||||
SOURCE_ADDRESS_TLV
|
||||
} <= set(p.mle.tlv.type) and\
|
||||
len(p.mle.tlv.route64.cost) == 32 and\
|
||||
p.ipv6.hlim == 255
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 5: Router_32 to attach to any of the active routers, 2-hops
|
||||
# from the leader, and to send an Address Solicit Request
|
||||
# to become an active router.
|
||||
|
||||
_pkt = pkts.filter_wpan_src64(ROUTER_32).\
|
||||
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()
|
||||
|
||||
# Step 6: Leader sends an Address Solicit Response.
|
||||
# Ensure the Address Solicit Response is properly formatted:
|
||||
# CoAP Response Code
|
||||
# 2.04 Changed
|
||||
# CoAP Payload
|
||||
# - Status TLV (value = No Address Available)
|
||||
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_ipv6_dst(_pkt.ipv6.src).\
|
||||
filter_coap_ack(ADDR_SOL_URI).\
|
||||
filter(lambda p:
|
||||
p.coap.code == COAP_CODE_ACK and\
|
||||
p.thread_address.tlv.status == ADDR_SOL_NA
|
||||
).\
|
||||
must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,386 +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 mle
|
||||
import network_layer
|
||||
import thread_cert
|
||||
from pktverify.consts import MLE_PARENT_REQUEST, MLE_PARENT_RESPONSE, MLE_CHILD_ID_REQUEST, MLE_CHILD_ID_RESPONSE, MLE_LINK_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, 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 = 16
|
||||
DUT_REED = 17
|
||||
MED = 18
|
||||
REED_ADVERTISEMENT_INTERVAL = 570
|
||||
REED_ADVERTISEMENT_MAX_JITTER = 60
|
||||
ROUTER_SELECTION_JITTER = 1
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to:
|
||||
# 1) Verify that the DUT does not attempt to become a router if there
|
||||
# are already 16 active routers on the Thread network AND it is not
|
||||
# bringing children
|
||||
# 2) Verify that the DUT transmits MLE Advertisement messages every
|
||||
# REED_ADVERTISEMENT_INTERVAL (+REED_ADVERTISEMENT_MAX_JITTER) seconds
|
||||
# 3) Verify that the DUT upgrades to a router by sending an Address Solicit
|
||||
# Request when a child attempts to attach to it.
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# Router_15 - Leader
|
||||
# ... / \
|
||||
# Router_n Router_1(DUT)
|
||||
# |
|
||||
# REED(DUT)
|
||||
# |
|
||||
# MED
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# REED
|
||||
|
||||
|
||||
class Cert_5_2_4_REEDUpgrade(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, ROUTER]
|
||||
},
|
||||
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]
|
||||
},
|
||||
ROUTER: {
|
||||
'name': 'ROUTER_15',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER, DUT_REED]
|
||||
},
|
||||
DUT_REED: {
|
||||
'name': 'REED',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [ROUTER, MED]
|
||||
},
|
||||
MED: {
|
||||
'name': 'MED',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [DUT_REED]
|
||||
},
|
||||
}
|
||||
|
||||
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, 17):
|
||||
self.nodes[i].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[i].get_state(), 'router')
|
||||
|
||||
self.nodes[DUT_REED].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.simulator.go(ROUTER_SELECTION_JITTER)
|
||||
|
||||
self.collect_rloc16s()
|
||||
self.collect_rlocs()
|
||||
|
||||
self.simulator.go(REED_ADVERTISEMENT_INTERVAL + REED_ADVERTISEMENT_MAX_JITTER)
|
||||
|
||||
self.nodes[MED].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.collect_ipaddrs()
|
||||
|
||||
mleid = self.nodes[LEADER].get_ip6_address(config.ADDRESS_TYPE.ML_EID)
|
||||
self.assertTrue(self.nodes[MED].ping(mleid))
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
LEADER_RLOC16 = pv.vars['LEADER_RLOC16']
|
||||
LEADER_RLOC = pv.vars['LEADER_RLOC']
|
||||
LEADER_MLEID = pv.vars['LEADER_MLEID']
|
||||
REED = pv.vars['REED']
|
||||
REED_RLOC16 = pv.vars['REED_RLOC16']
|
||||
MED = pv.vars['MED']
|
||||
MED_RLOC16 = pv.vars['MED_RLOC16']
|
||||
MED_MLEID = pv.vars['MED_MLEID']
|
||||
|
||||
# Step 1: Verify topology is formed correctly except REED.
|
||||
|
||||
with pkts.save_index():
|
||||
for i in range(1, 16):
|
||||
pv.verify_attached('ROUTER_%d' % i)
|
||||
|
||||
# Step 2: REED attaches to the network with 2-hops from the Leader
|
||||
# and MUST NOT attempt to become an active router by sending
|
||||
# an Address Solicit Request
|
||||
|
||||
pv.verify_attached('REED')
|
||||
lstart = pkts.index
|
||||
|
||||
# Step 3: REED MUST send properly formatted MLE Advertisements.
|
||||
# MLE Advertisements MUST be sent 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
|
||||
# - Source Address TLV
|
||||
# The following TLV MUST NOT be present in the MLE Advertisements:
|
||||
# - Route64 TLV
|
||||
|
||||
_pkt = pkts.filter_wpan_src64(REED).\
|
||||
filter_mle_advertisement('REED').\
|
||||
must_next()
|
||||
lend = pkts.index
|
||||
|
||||
pkts.range(lstart, lend).filter_wpan_src64(REED).\
|
||||
filter_coap_request(ADDR_SOL_URI).\
|
||||
filter(lambda p: {
|
||||
NL_MAC_EXTENDED_ADDRESS_TLV,
|
||||
NL_STATUS_TLV
|
||||
} <= set(p.coap.tlv.type)
|
||||
).\
|
||||
must_not_next()
|
||||
|
||||
# Step 5: REED MUST send a second MLE Advertisement after
|
||||
# REED_ADVERTISEMENT_INTERVAL+JITTER where
|
||||
# JITTER <= REED_ADVERTISEMENT_MAX_JITTER
|
||||
|
||||
pkts.filter_wpan_src64(REED).\
|
||||
filter_mle_advertisement('REED').\
|
||||
filter(lambda p:
|
||||
REED_ADVERTISEMENT_INTERVAL <
|
||||
p.sniff_timestamp - _pkt.sniff_timestamp <=
|
||||
REED_ADVERTISEMENT_INTERVAL +
|
||||
REED_ADVERTISEMENT_MAX_JITTER
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 6: MED sends multicast MLE Parent Request
|
||||
# First one is to all routers, the second one is to
|
||||
# all routers and reeds
|
||||
|
||||
pkts.filter_wpan_src64(MED).\
|
||||
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).\
|
||||
must_next()
|
||||
pkts.filter_wpan_src64(MED).\
|
||||
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).\
|
||||
must_next()
|
||||
|
||||
# Step 7: REED MUST reply with a properly formatted MLE Parent Response
|
||||
|
||||
pkts.filter_wpan_src64(REED).\
|
||||
filter_wpan_dst64(MED).\
|
||||
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 8: MED sends MLE Child ID Request to REED
|
||||
|
||||
_pkt = pkts.filter_wpan_src64(MED).\
|
||||
filter_wpan_dst64(REED).\
|
||||
filter_mle_cmd(MLE_CHILD_ID_REQUEST).\
|
||||
filter(lambda p: {
|
||||
LINK_LAYER_FRAME_COUNTER_TLV,
|
||||
MODE_TLV,
|
||||
RESPONSE_TLV,
|
||||
TIMEOUT_TLV,
|
||||
TLV_REQUEST_TLV,
|
||||
ADDRESS16_TLV,
|
||||
NETWORK_DATA_TLV,
|
||||
VERSION_TLV
|
||||
} <= set(p.mle.tlv.type) and\
|
||||
p.mle.tlv.addr16 is nullField and\
|
||||
p.thread_nwd.tlv.type is nullField
|
||||
).\
|
||||
must_next()
|
||||
_pkt.must_not_verify(lambda p: (ADDRESS_REGISTRATION_TLV) in p.mle.tlv.type)
|
||||
|
||||
# Step 9: REED sends an Address Solicit Request to the Leader
|
||||
# Ensure the Address Solicit Request is properly formatted:
|
||||
# CoAP Request URI
|
||||
# coap://<leader address>:MM/a/as
|
||||
# CoAP Payload
|
||||
# - MAC Extended Address TLV
|
||||
# - Status TLV
|
||||
|
||||
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()
|
||||
|
||||
# Step 10: REED Sends a Link Request Message.
|
||||
# This step is skipped due to change that new router no
|
||||
# longer send multicast Link Request.
|
||||
|
||||
# Step 11: The REED MLE Child ID Response MUST be properly
|
||||
# formatted with MED_1’s new 16-bit address.
|
||||
|
||||
with pkts.save_index():
|
||||
pkts.filter_wpan_src64(REED).\
|
||||
filter_wpan_dst64(MED).\
|
||||
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) or\
|
||||
{
|
||||
ADDRESS16_TLV,
|
||||
LEADER_DATA_TLV,
|
||||
NETWORK_DATA_TLV,
|
||||
SOURCE_ADDRESS_TLV
|
||||
} <= set(p.mle.tlv.type) and\
|
||||
p.mle.tlv.source_addr != REED_RLOC16 and\
|
||||
p.mle.tlv.addr16 != MED_RLOC16
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 12: The Leader MUST respond with an ICMPv6 Echo Reply
|
||||
|
||||
_pkt = pkts.filter_ipv6_src_dst(MED_MLEID, LEADER_MLEID).\
|
||||
filter_ping_request().\
|
||||
must_next()
|
||||
pkts.filter_ipv6_src_dst(LEADER_MLEID, MED_MLEID).\
|
||||
filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,370 +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 command
|
||||
import config
|
||||
import thread_cert
|
||||
from pktverify.consts import WIRESHARK_OVERRIDE_PREFS, MLE_PARENT_REQUEST, MLE_PARENT_RESPONSE, MLE_CHILD_ID_REQUEST, MLE_CHILD_ID_RESPONSE, MLE_LINK_REQUEST, ADDR_SOL_URI, ADDR_NTF_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_TARGET_EID_TLV, NL_ML_EID_TLV, COAP_CODE_ACK
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
from pktverify.null_field import nullField
|
||||
from pktverify.bytes import Bytes
|
||||
|
||||
LEADER = 1
|
||||
ROUTER1 = 2
|
||||
BR = 3
|
||||
MED = 17
|
||||
DUT_REED = 18
|
||||
ROUTER_SELECTION_JITTER = 1
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to validate that the DUT is able to generate
|
||||
# Address Notification messages in response to Address Query messages.
|
||||
#
|
||||
# - Build a topology that has a total of 16 active routers, including the Leader,
|
||||
# with no communication constraints and
|
||||
# - MED only allows Leader
|
||||
# - DUT only allows Router1
|
||||
# - DUT allows BR later as required in step 5.
|
||||
# - The Leader is configured as a DHCPv6 server for prefix 2001::
|
||||
# - The Border Router is configured as a SLAAC server for prefix 2002::
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# MED
|
||||
# |
|
||||
# Router_15 - Leader
|
||||
# ... / \
|
||||
# Router_2 Router_1
|
||||
# [BR] |
|
||||
# REED(DUT)
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# REED
|
||||
|
||||
|
||||
class Cert_5_2_5_AddressQuery(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [ROUTER1, BR, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, MED]
|
||||
},
|
||||
ROUTER1: {
|
||||
'name': 'ROUTER_1',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER, DUT_REED]
|
||||
},
|
||||
BR: {
|
||||
'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]
|
||||
},
|
||||
16: {
|
||||
'name': 'ROUTER_15',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER]
|
||||
},
|
||||
MED: {
|
||||
'name': 'MED',
|
||||
'is_mtd': True,
|
||||
'mode': 'rn',
|
||||
'allowlist': [LEADER]
|
||||
},
|
||||
DUT_REED: {
|
||||
'name': 'REED',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [ROUTER1]
|
||||
},
|
||||
}
|
||||
|
||||
# override wireshark preferences with case needed parameters
|
||||
CASE_WIRESHARK_PREFS = WIRESHARK_OVERRIDE_PREFS
|
||||
CASE_WIRESHARK_PREFS['6lowpan.context1'] = '2001::/64'
|
||||
CASE_WIRESHARK_PREFS['6lowpan.context2'] = '2002::/64'
|
||||
|
||||
def test(self):
|
||||
# 1. LEADER: DHCPv6 Server for prefix 2001::/64.
|
||||
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::/64', 'pdros')
|
||||
self.nodes[LEADER].register_netdata()
|
||||
|
||||
# 2. BR: SLAAC Server for prefix 2002::/64.
|
||||
self.nodes[BR].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[BR].get_state(), 'router')
|
||||
self.nodes[BR].add_prefix('2002::/64', 'paros')
|
||||
self.nodes[BR].register_netdata()
|
||||
|
||||
# 3. Bring up remaining devices except DUT_REED.
|
||||
for i in range(2, 17):
|
||||
if i == BR:
|
||||
continue
|
||||
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')
|
||||
|
||||
# 4. Bring up DUT_REED.
|
||||
self.nodes[DUT_REED].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.simulator.go(ROUTER_SELECTION_JITTER)
|
||||
|
||||
# 5. Enable a link between the DUT and BR to create a one-way link.
|
||||
self.nodes[DUT_REED].add_allowlist(self.nodes[BR].get_addr64())
|
||||
self.nodes[BR].add_allowlist(self.nodes[DUT_REED].get_addr64())
|
||||
|
||||
self.collect_ipaddrs()
|
||||
self.collect_rlocs()
|
||||
|
||||
# 6. Verify DUT_REED would send Address Notification when ping to its
|
||||
# ML-EID.
|
||||
mleid = self.nodes[DUT_REED].get_ip6_address(config.ADDRESS_TYPE.ML_EID)
|
||||
self.assertTrue(self.nodes[MED].ping(mleid))
|
||||
|
||||
# Wait for sniffer collecting packets
|
||||
self.simulator.go(1)
|
||||
|
||||
# 7 & 8. Verify DUT_REED would send Address Notification when ping to
|
||||
# its 2001::EID and 2002::EID.
|
||||
flag2001 = 0
|
||||
flag2002 = 0
|
||||
for global_address in self.nodes[DUT_REED].get_ip6_address(config.ADDRESS_TYPE.GLOBAL):
|
||||
if global_address[0:4] == '2001':
|
||||
flag2001 += 1
|
||||
elif global_address[0:4] == '2002':
|
||||
flag2002 += 1
|
||||
else:
|
||||
raise "Error: Address is unexpected."
|
||||
self.assertTrue(self.nodes[MED].ping(global_address))
|
||||
|
||||
# Wait for sniffer collecting packets
|
||||
self.simulator.go(1)
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
LEADER_RLOC = pv.vars['LEADER_RLOC']
|
||||
LEADER_MLEID = pv.vars['LEADER_MLEID']
|
||||
ROUTER_1 = pv.vars['ROUTER_1']
|
||||
REED = pv.vars['REED']
|
||||
REED_MLEID = pv.vars['REED_MLEID']
|
||||
REED_RLOC = pv.vars['REED_RLOC']
|
||||
MED = pv.vars['MED']
|
||||
MED_MLEID = pv.vars['MED_MLEID']
|
||||
MM = pv.vars['MM_PORT']
|
||||
REED2001 = ''
|
||||
REED2002 = ''
|
||||
MED2001 = ''
|
||||
MED2002 = ''
|
||||
|
||||
for addr in pv.vars['REED_IPADDRS']:
|
||||
if addr.startswith(Bytes('2001')):
|
||||
REED2001 = addr
|
||||
if addr.startswith(Bytes('2002')):
|
||||
REED2002 = addr
|
||||
|
||||
for addr in pv.vars['MED_IPADDRS']:
|
||||
if addr.startswith(Bytes('2001')):
|
||||
MED2001 = addr
|
||||
if addr.startswith(Bytes('2002')):
|
||||
MED2002 = addr
|
||||
|
||||
# Step 3: Verify topology is formed correctly except REED.
|
||||
|
||||
for i in range(1, 16):
|
||||
with pkts.save_index():
|
||||
pv.verify_attached('ROUTER_%d' % i)
|
||||
|
||||
# Step 4: REED attaches to Router_1 and MUST NOT attempt to become
|
||||
# an active router by sending an Address Solicit Request
|
||||
|
||||
pv.verify_attached('REED', 'ROUTER_1')
|
||||
pkts.filter_wpan_src64(REED).\
|
||||
filter_coap_request(ADDR_SOL_URI).\
|
||||
must_not_next()
|
||||
|
||||
# Step 6: MED sends an ICMPv6 Echo Request from MED to REED using ML-EID.
|
||||
# The DUT MUST send a properly formatted Address Notification message:
|
||||
# CoAP Request URI-PATH
|
||||
# CON POST coap://[<Address Query Source>]:MM/a/an
|
||||
# CoAP Payload
|
||||
# - Target EID TLV
|
||||
# - RLOC16 TLV
|
||||
# - ML-EID TLV
|
||||
# The IPv6 Source address MUST be the RLOC of the originator
|
||||
# The IPv6 Destination address MUST be the RLOC of the destination
|
||||
# The DUT MUST send an ICMPv6 Echo Reply
|
||||
|
||||
_pkt = pkts.filter_ipv6_src_dst(MED_MLEID, REED_MLEID).\
|
||||
filter_ping_request().\
|
||||
must_next()
|
||||
pkts.filter_ipv6_src_dst(REED_RLOC, LEADER_RLOC).\
|
||||
filter_coap_request(ADDR_NTF_URI, port=MM).\
|
||||
filter(lambda p: {
|
||||
NL_TARGET_EID_TLV,
|
||||
NL_RLOC16_TLV,
|
||||
NL_ML_EID_TLV
|
||||
} <= set(p.thread_address.tlv.type)
|
||||
).\
|
||||
must_next()
|
||||
pkts.filter_ipv6_src_dst(REED_MLEID, MED_MLEID).\
|
||||
filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
must_next()
|
||||
|
||||
# Step 7: MED sends an ICMPv6 Echo Request from MED to REED using 2001::EID.
|
||||
# The DUT MUST send a properly formatted Address Notification message:
|
||||
# CoAP Request URI-PATH
|
||||
# CON POST coap://[<Address Query Source>]:MM/a/an
|
||||
# CoAP Payload
|
||||
# - Target EID TLV
|
||||
# - RLOC16 TLV
|
||||
# - ML-EID TLV
|
||||
# The IPv6 Source address MUST be the RLOC of the originator
|
||||
# The IPv6 Destination address MUST be the RLOC of the destination
|
||||
# The DUT MUST send an ICMPv6 Echo Reply
|
||||
|
||||
_pkt = pkts.filter_ipv6_src_dst(MED2001, REED2001).\
|
||||
filter_ping_request().\
|
||||
must_next()
|
||||
pkts.filter_ipv6_src_dst(REED_RLOC, LEADER_RLOC).\
|
||||
filter_coap_request(ADDR_NTF_URI, port=MM).\
|
||||
filter(lambda p: {
|
||||
NL_TARGET_EID_TLV,
|
||||
NL_RLOC16_TLV,
|
||||
NL_ML_EID_TLV
|
||||
} <= set(p.thread_address.tlv.type)
|
||||
).\
|
||||
must_next()
|
||||
pkts.filter_ipv6_src_dst(REED2001, MED2001).\
|
||||
filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
must_next()
|
||||
|
||||
# Step 8: MED sends an ICMPv6 Echo Request from MED to REED using 2002::EID.
|
||||
# The DUT MUST send a properly formatted Address Notification message:
|
||||
# CoAP Request URI-PATH
|
||||
# CON POST coap://[<Address Query Source>]:MM/a/an
|
||||
# CoAP Payload
|
||||
# - Target EID TLV
|
||||
# - RLOC16 TLV
|
||||
# - ML-EID TLV
|
||||
# The IPv6 Source address MUST be the RLOC of the originator
|
||||
# The IPv6 Destination address MUST be the RLOC of the destination
|
||||
# The DUT MUST send an ICMPv6 Echo Reply
|
||||
|
||||
_pkt = pkts.filter_ipv6_src_dst(MED2002, REED2002).\
|
||||
filter_ping_request().\
|
||||
must_next()
|
||||
pkts.filter_ipv6_src_dst(REED_RLOC, LEADER_RLOC).\
|
||||
filter_coap_request(ADDR_NTF_URI, port=MM).\
|
||||
filter(lambda p: {
|
||||
NL_TARGET_EID_TLV,
|
||||
NL_RLOC16_TLV,
|
||||
NL_ML_EID_TLV
|
||||
} <= set(p.thread_address.tlv.type)
|
||||
).\
|
||||
must_next()
|
||||
pkts.filter_ipv6_src_dst(REED2002, MED2002).\
|
||||
filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,327 +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 command
|
||||
import config
|
||||
import mle
|
||||
import thread_cert
|
||||
import thread_cert
|
||||
from pktverify.consts import MLE_PARENT_REQUEST, MLE_CHILD_ID_REQUEST, ADDR_REL_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, CONNECTIVITY_TLV, LINK_MARGIN_TLV, VERSION_TLV, ADDRESS_REGISTRATION_TLV, NL_MAC_EXTENDED_ADDRESS_TLV, NL_RLOC16_TLV, COAP_CODE_ACK
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
from pktverify.null_field import nullField
|
||||
|
||||
LEADER = 1
|
||||
DUT_ROUTER1 = 2
|
||||
ROUTER2 = 3
|
||||
ROUTER23 = 24
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to verify that the DUT will downgrade
|
||||
# to a REED when the network becomes too dense and the Router Downgrade
|
||||
# Threshold conditions are met.
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# Leader
|
||||
# / \
|
||||
# Router_1 [DUT] ... Router_23
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Router
|
||||
|
||||
|
||||
class Cert_5_2_06_RouterDowngrade(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 32,
|
||||
'router_upgrade_threshold': 32
|
||||
},
|
||||
DUT_ROUTER1: {
|
||||
'name': 'ROUTER_1',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
ROUTER2: {
|
||||
'name': 'ROUTER_2',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 32,
|
||||
'router_upgrade_threshold': 32
|
||||
},
|
||||
4: {
|
||||
'name': 'ROUTER_3',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 32,
|
||||
'router_upgrade_threshold': 32
|
||||
},
|
||||
5: {
|
||||
'name': 'ROUTER_4',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 32,
|
||||
'router_upgrade_threshold': 32
|
||||
},
|
||||
6: {
|
||||
'name': 'ROUTER_5',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 32,
|
||||
'router_upgrade_threshold': 32
|
||||
},
|
||||
7: {
|
||||
'name': 'ROUTER_6',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 32,
|
||||
'router_upgrade_threshold': 32
|
||||
},
|
||||
8: {
|
||||
'name': 'ROUTER_7',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 32,
|
||||
'router_upgrade_threshold': 32
|
||||
},
|
||||
9: {
|
||||
'name': 'ROUTER_8',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 32,
|
||||
'router_upgrade_threshold': 32
|
||||
},
|
||||
10: {
|
||||
'name': 'ROUTER_9',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 32,
|
||||
'router_upgrade_threshold': 32
|
||||
},
|
||||
11: {
|
||||
'name': 'ROUTER_10',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 32,
|
||||
'router_upgrade_threshold': 32
|
||||
},
|
||||
12: {
|
||||
'name': 'ROUTER_11',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 32,
|
||||
'router_upgrade_threshold': 32
|
||||
},
|
||||
13: {
|
||||
'name': 'ROUTER_12',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 32,
|
||||
'router_upgrade_threshold': 32
|
||||
},
|
||||
14: {
|
||||
'name': 'ROUTER_13',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 32,
|
||||
'router_upgrade_threshold': 32
|
||||
},
|
||||
15: {
|
||||
'name': 'ROUTER_14',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 32,
|
||||
'router_upgrade_threshold': 32
|
||||
},
|
||||
16: {
|
||||
'name': 'ROUTER_15',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 32,
|
||||
'router_upgrade_threshold': 32
|
||||
},
|
||||
17: {
|
||||
'name': 'ROUTER_16',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 32,
|
||||
'router_upgrade_threshold': 32
|
||||
},
|
||||
18: {
|
||||
'name': 'ROUTER_17',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 32,
|
||||
'router_upgrade_threshold': 32
|
||||
},
|
||||
19: {
|
||||
'name': 'ROUTER_18',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 32,
|
||||
'router_upgrade_threshold': 32
|
||||
},
|
||||
20: {
|
||||
'name': 'ROUTER_19',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 32,
|
||||
'router_upgrade_threshold': 32
|
||||
},
|
||||
21: {
|
||||
'name': 'ROUTER_20',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 32,
|
||||
'router_upgrade_threshold': 32
|
||||
},
|
||||
22: {
|
||||
'name': 'ROUTER_21',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 32,
|
||||
'router_upgrade_threshold': 32
|
||||
},
|
||||
23: {
|
||||
'name': 'ROUTER_22',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 32,
|
||||
'router_upgrade_threshold': 32
|
||||
},
|
||||
ROUTER23: {
|
||||
'name': 'ROUTER_23',
|
||||
'mode': 'rdn',
|
||||
'router_downgrade_threshold': 32,
|
||||
'router_upgrade_threshold': 32
|
||||
},
|
||||
}
|
||||
|
||||
def test(self):
|
||||
# 1 Ensure topology is formed correctly without ROUTER23.
|
||||
self.nodes[LEADER].start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
|
||||
|
||||
for i in range(2, 24):
|
||||
self.nodes[i].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[i].get_state(), 'router')
|
||||
self.collect_rloc16s()
|
||||
|
||||
# All reference testbed devices have been configured with downgrade threshold as 32 except DUT_ROUTER1,
|
||||
# so we don't need to ensure ROUTER23 has a better link quality on
|
||||
# posix.
|
||||
self.nodes[ROUTER23].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[ROUTER23].get_state(), 'router')
|
||||
|
||||
self.simulator.go(10)
|
||||
self.assertEqual(self.nodes[DUT_ROUTER1].get_state(), 'child')
|
||||
self.collect_rlocs()
|
||||
|
||||
router1_rloc = self.nodes[DUT_ROUTER1].get_ip6_address(config.ADDRESS_TYPE.RLOC)
|
||||
self.assertTrue(self.nodes[LEADER].ping(router1_rloc))
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
LEADER = pv.vars['LEADER']
|
||||
LEADER_RLOC = pv.vars['LEADER_RLOC']
|
||||
ROUTER_1 = pv.vars['ROUTER_1']
|
||||
ROUTER_1_RLOC = pv.vars['ROUTER_1_RLOC']
|
||||
ROUTER_1_RLOC16 = pv.vars['ROUTER_1_RLOC16']
|
||||
|
||||
# Step 1: Ensure topology is formed correctly
|
||||
|
||||
for i in range(1, 24):
|
||||
pv.verify_attached('ROUTER_%d' % i)
|
||||
|
||||
# Step 3: Allow enough time for the DUT to get Network Data Updates
|
||||
# and resign its Router ID.
|
||||
# The DUT MUST first reconnect to the network as a Child by
|
||||
# sending properly formatted Parent Request and Child ID Request
|
||||
# messages.
|
||||
# Once the DUT attaches as a Child, it MUST send an Address
|
||||
# Release Message to the Leader:
|
||||
# CoAP Request URI
|
||||
# coap://[<leader address>]:MM/a/ar
|
||||
# CoAP Payload
|
||||
# MAC Extended Address TLV
|
||||
# RLOC16 TLV
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER_1).\
|
||||
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
|
||||
).\
|
||||
must_next()
|
||||
|
||||
_pkt = pkts.filter_wpan_src64(ROUTER_1).\
|
||||
filter_mle_cmd(MLE_CHILD_ID_REQUEST).\
|
||||
filter(lambda p: {
|
||||
LINK_LAYER_FRAME_COUNTER_TLV,
|
||||
MODE_TLV,
|
||||
RESPONSE_TLV,
|
||||
TIMEOUT_TLV,
|
||||
TLV_REQUEST_TLV,
|
||||
ADDRESS16_TLV,
|
||||
NETWORK_DATA_TLV,
|
||||
VERSION_TLV
|
||||
} <= set(p.mle.tlv.type) and\
|
||||
p.mle.tlv.addr16 is nullField and\
|
||||
p.thread_nwd.tlv.type is nullField
|
||||
).\
|
||||
must_next()
|
||||
_pkt.must_not_verify(lambda p: (ADDRESS_REGISTRATION_TLV) in p.mle.tlv.type)
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER_1).\
|
||||
filter_ipv6_dst(LEADER_RLOC).\
|
||||
filter_coap_request(ADDR_REL_URI).\
|
||||
filter(lambda p: {
|
||||
NL_MAC_EXTENDED_ADDRESS_TLV,
|
||||
NL_RLOC16_TLV
|
||||
} <= set(p.coap.tlv.type) and\
|
||||
p.thread_address.tlv.rloc16 == ROUTER_1_RLOC16
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 4: Leader receives Address Release messages and sends a2.04
|
||||
# Changed CoAP response.
|
||||
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_ipv6_dst(ROUTER_1_RLOC).\
|
||||
filter_coap_ack(ADDR_REL_URI).\
|
||||
must_next()
|
||||
|
||||
# Step 5: ROUTER_1 responds with ICMPv6 Echo Reply
|
||||
_pkt = pkts.filter_ipv6_src_dst(LEADER_RLOC, ROUTER_1_RLOC).\
|
||||
filter_ping_request().\
|
||||
must_next()
|
||||
pkts.filter_ipv6_src_dst(ROUTER_1_RLOC, LEADER_RLOC).\
|
||||
filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,263 +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 command
|
||||
import config
|
||||
import ipv6
|
||||
import mle
|
||||
import thread_cert
|
||||
from pktverify.consts import ADDR_SOL_URI, MLE_LINK_REQUEST, MLE_LINK_ACCEPT, MLE_LINK_ACCEPT_AND_REQUEST, SOURCE_ADDRESS_TLV, CHALLENGE_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, LEADER_DATA_TLV, VERSION_TLV
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
from pktverify.null_field import nullField
|
||||
|
||||
LEADER = 1
|
||||
DUT_ROUTER1 = 2
|
||||
ROUTER2 = 3
|
||||
DUT_REED = 17
|
||||
|
||||
MLE_MIN_LINKS = 3
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to validate the REED’s Synchronization
|
||||
# procedure after attaching to a network with multiple Routers. A REED
|
||||
# MUST process incoming Advertisements and perform a one-way frame-counter
|
||||
# synchronization with at least 3 neighboring Routers. When Router receives
|
||||
# unicast MLE Link Request from REED, it replies with MLE Link Accept.
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# Router_15 - Leader
|
||||
# ... / \
|
||||
# Router_n Router_1(DUT)
|
||||
# |
|
||||
# REED(DUT)
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Router
|
||||
# REED
|
||||
|
||||
|
||||
class Cert_5_2_7_REEDSynchronization_Base(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
DUT_ROUTER1: {
|
||||
'name': 'ROUTER_1',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
ROUTER2: {
|
||||
'name': 'ROUTER_2',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
4: {
|
||||
'name': 'ROUTER_3',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
5: {
|
||||
'name': 'ROUTER_4',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
6: {
|
||||
'name': 'ROUTER_5',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
7: {
|
||||
'name': 'ROUTER_6',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
8: {
|
||||
'name': 'ROUTER_7',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
9: {
|
||||
'name': 'ROUTER_8',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
10: {
|
||||
'name': 'ROUTER_9',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
11: {
|
||||
'name': 'ROUTER_10',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
12: {
|
||||
'name': 'ROUTER_11',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
13: {
|
||||
'name': 'ROUTER_12',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
14: {
|
||||
'name': 'ROUTER_13',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
15: {
|
||||
'name': 'ROUTER_14',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
16: {
|
||||
'name': 'ROUTER_15',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
DUT_REED: {
|
||||
'name': 'REED',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
}
|
||||
|
||||
DUT = 0
|
||||
|
||||
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, 17):
|
||||
self.nodes[i].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
|
||||
for i in range(2, 17):
|
||||
self.assertEqual(self.nodes[i].get_state(), 'router')
|
||||
|
||||
# Avoid DUT_REED attach to DUT_ROUTER1.
|
||||
if self.DUT == DUT_REED:
|
||||
self.nodes[DUT_REED].\
|
||||
add_allowlist(self.nodes[DUT_ROUTER1].get_addr64(),
|
||||
config.RSSI['LINK_QULITY_1'])
|
||||
|
||||
if self.DUT == DUT_ROUTER1:
|
||||
self.nodes[DUT_REED].\
|
||||
add_allowlist(self.nodes[DUT_ROUTER1].get_addr64(),
|
||||
config.RSSI['LINK_QULITY_1'])
|
||||
self.nodes[DUT_REED].add_allowlist(self.nodes[ROUTER2].get_addr64())
|
||||
self.nodes[DUT_REED].enable_allowlist()
|
||||
|
||||
self.nodes[DUT_REED].start()
|
||||
self.simulator.go(config.MAX_ADVERTISEMENT_INTERVAL)
|
||||
self.assertEqual(self.nodes[DUT_REED].get_state(), 'child')
|
||||
|
||||
self.simulator.go(config.MAX_ADVERTISEMENT_INTERVAL)
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
LEADER = pv.vars['LEADER']
|
||||
ROUTER_1 = pv.vars['ROUTER_1']
|
||||
REED = pv.vars['REED']
|
||||
|
||||
# Step 1: Verify topology is formed correctly except REED.
|
||||
|
||||
for i in range(1, 16):
|
||||
with pkts.save_index():
|
||||
pv.verify_attached('ROUTER_%d' % i)
|
||||
|
||||
# Step 2: REED attaches to the network and MUST NOT attempt to become
|
||||
# an active router by sending an Address Solicit Request
|
||||
|
||||
pv.verify_attached('REED')
|
||||
pkts.filter_wpan_src64(REED).\
|
||||
filter_coap_request(ADDR_SOL_URI).\
|
||||
filter(lambda p: {
|
||||
NL_MAC_EXTENDED_ADDRESS_TLV,
|
||||
NL_STATUS_TLV
|
||||
} <= set(p.coap.tlv.type)
|
||||
).\
|
||||
must_not_next()
|
||||
|
||||
# Step 3: REED sends a unicast Link Request message to at lease 3 Routers
|
||||
#
|
||||
# The Link Request Message MUST contain the following TLVs:
|
||||
# - Challenge TLV
|
||||
# - Leader Data TLV
|
||||
# - Source Address TLV
|
||||
# - Version TLV
|
||||
|
||||
if self.DUT == DUT_REED:
|
||||
for i in range(0, MLE_MIN_LINKS):
|
||||
pkts.filter_wpan_src64(REED).\
|
||||
filter_mle_cmd(MLE_LINK_REQUEST).\
|
||||
filter(lambda p: {
|
||||
CHALLENGE_TLV,
|
||||
LEADER_DATA_TLV,
|
||||
SOURCE_ADDRESS_TLV,
|
||||
VERSION_TLV
|
||||
} <= set(p.mle.tlv.type)
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 4: Router_1 sends Link Accept message
|
||||
# The following TLVs MUST be present in the Link Accept message:
|
||||
# - Link-layer Frame Counter TLV
|
||||
# - Source Address TLV
|
||||
# - Response TLV
|
||||
# - Version TLV
|
||||
# - MLE Frame Counter TLV (optional)
|
||||
#
|
||||
# The recipient does not make any change to its local state and
|
||||
# MUST NOT reply with a Link Accept And Request message.
|
||||
|
||||
if self.DUT == DUT_ROUTER1:
|
||||
pkts.filter_wpan_dst64(REED).\
|
||||
filter_wpan_src64(ROUTER_1).\
|
||||
filter_mle_cmd(MLE_LINK_ACCEPT).\
|
||||
filter(lambda p: {
|
||||
LINK_LAYER_FRAME_COUNTER_TLV,
|
||||
RESPONSE_TLV,
|
||||
SOURCE_ADDRESS_TLV,
|
||||
VERSION_TLV
|
||||
} <= set(p.mle.tlv.type)
|
||||
).\
|
||||
must_next()
|
||||
pkts.filter_wpan_src64(REED).\
|
||||
filter_mle_cmd(MLE_LINK_ACCEPT_AND_REQUEST).\
|
||||
must_not_next()
|
||||
|
||||
|
||||
class Cert_5_2_7_REEDSynchronization_REED(Cert_5_2_7_REEDSynchronization_Base):
|
||||
DUT = DUT_REED
|
||||
|
||||
|
||||
class Cert_5_2_7_REEDSynchronization_ROUTER(Cert_5_2_7_REEDSynchronization_Base):
|
||||
DUT = DUT_ROUTER1
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,201 +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 LINK_LOCAL_All_THREAD_NODES_MULTICAST_ADDRESS
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
|
||||
LEADER = 1
|
||||
DUT_ROUTER1 = 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
|
||||
# |
|
||||
# Router(DUT)
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Router
|
||||
|
||||
|
||||
class Cert_5_3_1_LinkLocal(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
DUT_ROUTER1: {
|
||||
'name': 'ROUTER',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
}
|
||||
|
||||
def test(self):
|
||||
# 1
|
||||
self.nodes[LEADER].start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[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')
|
||||
|
||||
self.collect_rlocs()
|
||||
self.collect_ipaddrs()
|
||||
|
||||
# 2 & 3
|
||||
link_local = self.nodes[DUT_ROUTER1].get_ip6_address(config.ADDRESS_TYPE.LINK_LOCAL)
|
||||
self.assertTrue(self.nodes[LEADER].ping(link_local, size=FRAGMENTED_DATA_LEN))
|
||||
self.assertTrue(self.nodes[LEADER].ping(link_local))
|
||||
|
||||
# 4 & 5
|
||||
self.assertTrue(self.nodes[LEADER].ping(config.LINK_LOCAL_ALL_NODES_ADDRESS, size=FRAGMENTED_DATA_LEN))
|
||||
self.assertTrue(self.nodes[LEADER].ping(config.LINK_LOCAL_ALL_NODES_ADDRESS))
|
||||
|
||||
# 6 & 7
|
||||
self.assertTrue(self.nodes[LEADER].ping(config.LINK_LOCAL_ALL_ROUTERS_ADDRESS, size=FRAGMENTED_DATA_LEN))
|
||||
self.assertTrue(self.nodes[LEADER].ping(config.LINK_LOCAL_ALL_ROUTERS_ADDRESS))
|
||||
|
||||
# 8
|
||||
self.assertTrue(self.nodes[LEADER].ping(config.LINK_LOCAL_All_THREAD_NODES_MULTICAST_ADDRESS))
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
LEADER = pv.vars['LEADER']
|
||||
LEADER_LLA = pv.vars['LEADER_LLA']
|
||||
ROUTER_LLA = pv.vars['ROUTER_LLA']
|
||||
|
||||
# Step 1: Build the topology as described
|
||||
pv.verify_attached('ROUTER')
|
||||
|
||||
# Step 2: Leader sends a Fragmented ICMPv6 Echo Request to DUT’s
|
||||
# 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, ROUTER_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(ROUTER_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 DUT’s
|
||||
# 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, ROUTER_LLA).\
|
||||
must_next()
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_ipv6_src_dst(ROUTER_LLA, LEADER_LLA).\
|
||||
must_next()
|
||||
|
||||
# Step 4: 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(ROUTER_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 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(ROUTER_LLA, LEADER_LLA).\
|
||||
must_next()
|
||||
|
||||
# Step 6: Leader sends a Fragmented ICMPv6 Echo Request to the
|
||||
# Link-Local All Routers multicast address (FF02::2)
|
||||
# The DUT MUST respond with an ICMPv6 Echo Reply
|
||||
|
||||
_pkt = pkts.filter_ping_request().\
|
||||
filter_wpan_src64(LEADER).\
|
||||
filter_LLARMA().\
|
||||
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(ROUTER_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 Routers multicast address (FF02::2)
|
||||
# The DUT MUST respond with an ICMPv6 Echo Reply
|
||||
|
||||
_pkt = pkts.filter_ping_request().\
|
||||
filter_wpan_src64(LEADER).\
|
||||
filter_LLARMA().\
|
||||
must_next()
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_ipv6_src_dst(ROUTER_LLA, LEADER_LLA).\
|
||||
must_next()
|
||||
|
||||
# Step 8: 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_ipv6_src_dst(LEADER_LLA,
|
||||
LINK_LOCAL_All_THREAD_NODES_MULTICAST_ADDRESS).\
|
||||
must_next()
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_ipv6_src_dst(ROUTER_LLA, LEADER_LLA).\
|
||||
must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,295 +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, REALM_LOCAL_ALL_NODES_ADDRESS, REALM_LOCAL_ALL_ROUTERS_ADDRESS, REALM_LOCAL_All_THREAD_NODES_MULTICAST_ADDRESS
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
|
||||
LEADER = 1
|
||||
ROUTER1 = 2
|
||||
DUT_ROUTER2 = 3
|
||||
SED1 = 4
|
||||
FRAGMENTED_DATA_LEN = 256
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to validate the Realm-Local addresses
|
||||
# that the DUT auto-configures.
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# Leader
|
||||
# |
|
||||
# Router_1 - Router_2(DUT)
|
||||
# |
|
||||
# SED
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Router
|
||||
|
||||
|
||||
class Cert_5_3_2_RealmLocal(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [ROUTER1]
|
||||
},
|
||||
ROUTER1: {
|
||||
'name': 'ROUTER_1',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER, DUT_ROUTER2]
|
||||
},
|
||||
DUT_ROUTER2: {
|
||||
'name': 'ROUTER_2',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [ROUTER1, SED1]
|
||||
},
|
||||
SED1: {
|
||||
'name': 'SED',
|
||||
'is_mtd': True,
|
||||
'mode': 'n',
|
||||
'timeout': config.DEFAULT_CHILD_TIMEOUT,
|
||||
'allowlist': [DUT_ROUTER2]
|
||||
},
|
||||
}
|
||||
|
||||
def test(self):
|
||||
# 1
|
||||
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[DUT_ROUTER2].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[DUT_ROUTER2].get_state(), 'router')
|
||||
|
||||
self.nodes[SED1].start()
|
||||
self.simulator.go(5)
|
||||
self.assertEqual(self.nodes[SED1].get_state(), 'child')
|
||||
|
||||
self.collect_ipaddrs()
|
||||
self.collect_rloc16s()
|
||||
|
||||
# 2 & 3
|
||||
mleid = self.nodes[DUT_ROUTER2].get_ip6_address(config.ADDRESS_TYPE.ML_EID)
|
||||
self.assertTrue(self.nodes[LEADER].ping(mleid, size=FRAGMENTED_DATA_LEN))
|
||||
self.simulator.go(2)
|
||||
self.assertTrue(self.nodes[LEADER].ping(mleid))
|
||||
self.simulator.go(2)
|
||||
|
||||
# 4 & 5
|
||||
self.assertTrue(self.nodes[LEADER].ping('ff03::1', num_responses=2, size=FRAGMENTED_DATA_LEN))
|
||||
self.simulator.go(5)
|
||||
self.assertTrue(self.nodes[LEADER].ping('ff03::1', num_responses=2))
|
||||
self.simulator.go(5)
|
||||
|
||||
# 6 & 7
|
||||
self.assertTrue(self.nodes[LEADER].ping('ff03::2', num_responses=2, size=FRAGMENTED_DATA_LEN))
|
||||
self.simulator.go(5)
|
||||
self.assertTrue(self.nodes[LEADER].ping('ff03::2', num_responses=2))
|
||||
self.simulator.go(5)
|
||||
|
||||
# 8
|
||||
self.assertTrue(self.nodes[LEADER].ping(
|
||||
config.REALM_LOCAL_All_THREAD_NODES_MULTICAST_ADDRESS,
|
||||
num_responses=3,
|
||||
size=FRAGMENTED_DATA_LEN,
|
||||
))
|
||||
self.simulator.go(5)
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
LEADER = pv.vars['LEADER']
|
||||
LEADER_MLEID = pv.vars['LEADER_MLEID']
|
||||
ROUTER_1 = pv.vars['ROUTER_1']
|
||||
ROUTER_2 = pv.vars['ROUTER_2']
|
||||
ROUTER_2_RLOC16 = pv.vars['ROUTER_2_RLOC16']
|
||||
ROUTER_2_MLEID = pv.vars['ROUTER_2_MLEID']
|
||||
SED = pv.vars['SED']
|
||||
SED_RLOC16 = pv.vars['SED_RLOC16']
|
||||
|
||||
# Step 1: Build the topology as described
|
||||
pv.verify_attached('ROUTER_1', 'LEADER')
|
||||
pv.verify_attached('ROUTER_2', 'ROUTER_1')
|
||||
pv.verify_attached('SED', 'ROUTER_2', '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, ROUTER_2_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(ROUTER_2_MLEID, LEADER_MLEID).\
|
||||
filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\
|
||||
must_next()
|
||||
|
||||
# Step 3: Leader sends a Unfragmented 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, ROUTER_2_MLEID).\
|
||||
must_next()
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_ipv6_src_dst(ROUTER_2_MLEID, LEADER_MLEID).\
|
||||
must_next()
|
||||
|
||||
# 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
|
||||
# The DUT MUST NOT forward the ICMPv6 Echo Request to SED
|
||||
|
||||
_pkt1 = pkts.filter_ping_request().\
|
||||
filter_wpan_src64(LEADER).\
|
||||
filter_ipv6_dst(REALM_LOCAL_ALL_NODES_ADDRESS).\
|
||||
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_2_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_2_RLOC16, SED_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
|
||||
# The DUT MUST NOT forward the ICMPv6 Echo Request to SED
|
||||
|
||||
_pkt2 = pkts.filter_ping_request().\
|
||||
filter_wpan_src64(LEADER).\
|
||||
filter_ipv6_dst(REALM_LOCAL_ALL_NODES_ADDRESS).\
|
||||
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_2_MLEID, LEADER_MLEID).\
|
||||
must_next()
|
||||
pkts.filter_ping_request(identifier = _pkt2.icmpv6.echo.identifier).\
|
||||
filter_wpan_src16_dst16(ROUTER_2_RLOC16, SED_RLOC16).\
|
||||
must_not_next()
|
||||
|
||||
# Step 6: Leader sends a Fragmented ICMPv6 Echo Request to the
|
||||
# Realm-Local All Routers multicast address (FF03::2)
|
||||
# The DUT MUST respond with an ICMPv6 Echo Reply
|
||||
# The DUT MUST NOT forward the ICMPv6 Echo Request to SED
|
||||
|
||||
_pkt1 = pkts.filter_ping_request().\
|
||||
filter_wpan_src64(LEADER).\
|
||||
filter_ipv6_dst(REALM_LOCAL_ALL_ROUTERS_ADDRESS).\
|
||||
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_2_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_2_RLOC16, SED_RLOC16).\
|
||||
filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\
|
||||
must_not_next()
|
||||
|
||||
# Step 7: Leader sends an Unfragmented ICMPv6 Echo Request to the
|
||||
# Realm-Local All Routers multicast address (FF03::2)
|
||||
# The DUT MUST respond with an ICMPv6 Echo Reply
|
||||
# The DUT MUST NOT forward the ICMPv6 Echo Request to SED
|
||||
|
||||
_pkt2 = pkts.filter_ping_request().\
|
||||
filter_wpan_src64(LEADER).\
|
||||
filter_ipv6_dst(REALM_LOCAL_ALL_ROUTERS_ADDRESS).\
|
||||
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_2_MLEID, LEADER_MLEID).\
|
||||
must_next()
|
||||
pkts.filter_ping_request(identifier=_pkt2.icmpv6.echo.identifier).\
|
||||
filter_wpan_src16_dst16(ROUTER_2_RLOC16, SED_RLOC16).\
|
||||
must_not_next()
|
||||
|
||||
# Step 8: 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
|
||||
# The Realm-Local All Thread Nodes multicast address
|
||||
# MUST be a realm-local Unicast Prefix-Based Multicast
|
||||
# Address [RFC 3306], with:
|
||||
# - flgs set to 3 (P = 1 and T = 1)
|
||||
# - scop set to 3
|
||||
# - plen set to the Mesh Local Prefix length
|
||||
# - network prefix set to the Mesh Local Prefix
|
||||
# - group ID set to 1
|
||||
# The DUT MUST use IEEE 802.15.4 indirect transmissions
|
||||
# to forward packet to SED
|
||||
|
||||
_pkt = pkts.filter_ping_request().\
|
||||
filter_wpan_src64(LEADER).\
|
||||
filter_ipv6_dst(REALM_LOCAL_All_THREAD_NODES_MULTICAST_ADDRESS).\
|
||||
filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\
|
||||
must_next()
|
||||
with pkts.save_index():
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_ipv6_src_dst(ROUTER_2_MLEID, LEADER_MLEID).\
|
||||
filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\
|
||||
must_next()
|
||||
pkts.filter_ping_request(identifier = _pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src16_dst16(ROUTER_2_RLOC16, SED_RLOC16).\
|
||||
filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\
|
||||
must_next()
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(SED).\
|
||||
filter_ipv6_dst(LEADER_MLEID).\
|
||||
filter(lambda p: p.icmpv6.data.len == FRAGMENTED_DATA_LEN).\
|
||||
must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,352 +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 command
|
||||
import config
|
||||
import thread_cert
|
||||
from pktverify.consts import MLE_CHILD_ID_REQUEST, MLE_CHILD_ID_RESPONSE, ADDR_QRY_URI, ADDR_NTF_URI, NL_ML_EID_TLV, NL_RLOC16_TLV, NL_TARGET_EID_TLV, COAP_CODE_POST
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
|
||||
LEADER = 1
|
||||
ROUTER1 = 2
|
||||
DUT_ROUTER2 = 3
|
||||
ROUTER3 = 4
|
||||
MED1 = 5
|
||||
MED1_TIMEOUT = 3
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to validate that the DUT is able to generate
|
||||
# Address Query messages and properly respond with Address Notification messages.
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# Router_1 - Leader
|
||||
# / \
|
||||
# Router_3 - Router_2(DUT)
|
||||
# |
|
||||
# MED
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Router
|
||||
|
||||
|
||||
class Cert_5_3_3_AddressQuery(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [ROUTER1, DUT_ROUTER2, ROUTER3]
|
||||
},
|
||||
ROUTER1: {
|
||||
'name': 'ROUTER_1',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER]
|
||||
},
|
||||
DUT_ROUTER2: {
|
||||
'name': 'ROUTER_2',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER, ROUTER3, MED1]
|
||||
},
|
||||
ROUTER3: {
|
||||
'name': 'ROUTER_3',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER, DUT_ROUTER2]
|
||||
},
|
||||
MED1: {
|
||||
'name': 'MED',
|
||||
'is_mtd': True,
|
||||
'mode': 'rn',
|
||||
'timeout': 3,
|
||||
'allowlist': [DUT_ROUTER2]
|
||||
},
|
||||
}
|
||||
|
||||
def test(self):
|
||||
# 1
|
||||
self.nodes[LEADER].start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
|
||||
|
||||
self.nodes[ROUTER1].start()
|
||||
self.nodes[DUT_ROUTER2].start()
|
||||
self.nodes[ROUTER3].start()
|
||||
self.nodes[MED1].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
|
||||
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
|
||||
self.assertEqual(self.nodes[DUT_ROUTER2].get_state(), 'router')
|
||||
self.assertEqual(self.nodes[ROUTER3].get_state(), 'router')
|
||||
self.assertEqual(self.nodes[MED1].get_state(), 'child')
|
||||
self.collect_ipaddrs()
|
||||
self.collect_rlocs()
|
||||
self.collect_rloc16s()
|
||||
|
||||
# 2
|
||||
router3_mleid = self.nodes[ROUTER3].get_ip6_address(config.ADDRESS_TYPE.ML_EID)
|
||||
self.assertTrue(self.nodes[MED1].ping(router3_mleid))
|
||||
|
||||
# 3
|
||||
# Wait the finish of address resolution traffic triggered by previous
|
||||
# ping.
|
||||
self.simulator.go(5)
|
||||
|
||||
med1_mleid = self.nodes[MED1].get_ip6_address(config.ADDRESS_TYPE.ML_EID)
|
||||
self.assertTrue(self.nodes[ROUTER1].ping(med1_mleid))
|
||||
|
||||
# 4
|
||||
# Wait the finish of address resolution traffic triggered by previous
|
||||
# ping.
|
||||
self.simulator.go(5)
|
||||
|
||||
self.assertTrue(self.nodes[MED1].ping(router3_mleid))
|
||||
|
||||
# 5
|
||||
# Power off ROUTER3 and wait for leader to expire its Router ID.
|
||||
# In this topology, ROUTER3 has two neighbors (Leader and DUT_ROUTER2),
|
||||
# so the wait time is (MAX_NEIGHBOR_AGE (100s) + worst propagation time (32s * 15) for bad routing +\
|
||||
# INFINITE_COST_TIMEOUT (90s) + transmission time + extra redundancy),
|
||||
# totally ~700s.
|
||||
self.nodes[ROUTER3].stop()
|
||||
self.simulator.go(700)
|
||||
|
||||
self.assertFalse(self.nodes[MED1].ping(router3_mleid))
|
||||
|
||||
# 6
|
||||
self.nodes[MED1].stop()
|
||||
self.simulator.go(MED1_TIMEOUT)
|
||||
|
||||
self.assertFalse(self.nodes[ROUTER1].ping(med1_mleid))
|
||||
self.assertFalse(self.nodes[ROUTER1].ping(med1_mleid))
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
LEADER = pv.vars['LEADER']
|
||||
LEADER_MLEID = pv.vars['LEADER_MLEID']
|
||||
ROUTER_1 = pv.vars['ROUTER_1']
|
||||
ROUTER_1_RLOC = pv.vars['ROUTER_1_RLOC']
|
||||
ROUTER_1_MLEID = pv.vars['ROUTER_1_MLEID']
|
||||
ROUTER_2 = pv.vars['ROUTER_2']
|
||||
ROUTER_2_RLOC16 = pv.vars['ROUTER_2_RLOC16']
|
||||
ROUTER_2_RLOC = pv.vars['ROUTER_2_RLOC']
|
||||
ROUTER_2_MLEID = pv.vars['ROUTER_2_MLEID']
|
||||
MED = pv.vars['MED']
|
||||
MED_RLOC16 = pv.vars['MED_RLOC16']
|
||||
MED_MLEID = pv.vars['MED_MLEID']
|
||||
ROUTER_3 = pv.vars['ROUTER_3']
|
||||
ROUTER_3_MLEID = pv.vars['ROUTER_3_MLEID']
|
||||
MM = pv.vars['MM_PORT']
|
||||
|
||||
# Step 1: Build the topology as described
|
||||
for i in range(1, 4):
|
||||
with pkts.save_index():
|
||||
pv.verify_attached('ROUTER_%d' % i)
|
||||
pkts.filter_wpan_src64(MED).\
|
||||
filter_wpan_dst64(ROUTER_2).\
|
||||
filter_mle_cmd(MLE_CHILD_ID_REQUEST).\
|
||||
must_next()
|
||||
pkts.filter_wpan_src64(ROUTER_2).\
|
||||
filter_wpan_dst64(MED).\
|
||||
filter_mle_cmd(MLE_CHILD_ID_RESPONSE).\
|
||||
must_next()
|
||||
|
||||
# Step 2: MED sends an ICMPv6 Echo Request to Router_3 ML-EID
|
||||
# The DUT MUST generate an Address Query Request on MED’s behalf
|
||||
# to find Router_3 address.
|
||||
# The Address Query Request MUST be sent to the Realm-Local
|
||||
# All-Routers address (FF03::2)
|
||||
# CoAP URI-Path
|
||||
# - NON POST coap://<FF03::2>
|
||||
# CoAP Payload
|
||||
# - Target EID TLV
|
||||
# The DUT MUST receive and process the incoming Address Notification
|
||||
# The DUT MUST then forward the ICMPv6 Echo Request from MED and
|
||||
# forward the ICMPv6 Echo Reply to MED
|
||||
|
||||
_pkt = pkts.filter_ping_request().\
|
||||
filter_wpan_src64(MED).\
|
||||
filter_ipv6_dst(ROUTER_3_MLEID).\
|
||||
must_next()
|
||||
pkts.filter_wpan_src64(ROUTER_2).\
|
||||
filter_RLARMA().\
|
||||
filter_coap_request(ADDR_QRY_URI, port=MM).\
|
||||
filter(lambda p: p.thread_address.tlv.target_eid == ROUTER_3_MLEID).\
|
||||
must_next()
|
||||
_pkt1 = pkts.filter_wpan_src64(ROUTER_3).\
|
||||
filter_ipv6_dst(ROUTER_2_RLOC).\
|
||||
filter_coap_request(ADDR_NTF_URI, port=MM).\
|
||||
filter(lambda p: {
|
||||
NL_ML_EID_TLV,
|
||||
NL_RLOC16_TLV,
|
||||
NL_TARGET_EID_TLV
|
||||
} <= set(p.coap.tlv.type) and\
|
||||
p.thread_address.tlv.target_eid == ROUTER_3_MLEID and\
|
||||
p.coap.code == COAP_CODE_POST
|
||||
).\
|
||||
must_next()
|
||||
pkts.filter_ping_request(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(ROUTER_2).\
|
||||
filter_ipv6_dst(ROUTER_3_MLEID).\
|
||||
must_next()
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(ROUTER_3).\
|
||||
filter_dst16(ROUTER_2_RLOC16).\
|
||||
must_next()
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(ROUTER_2).\
|
||||
filter_wpan_dst16(MED_RLOC16).\
|
||||
must_next()
|
||||
|
||||
# Step 3: Router_1 sends an ICMPv6 Echo Request to the MED ML-EID address
|
||||
# The DUT MUST respond to the Address Query Request with a properly
|
||||
# formatted Address Notification Message:
|
||||
# CoAP URI-Path
|
||||
# - CON POST coap://[<Address Query Source>]:MM/a/an
|
||||
# CoAP Payload
|
||||
# - ML-EID TLV
|
||||
# - RLOC16 TLV
|
||||
# - Target EID TLV
|
||||
# The IPv6 Source address MUST be the RLOC of the originator
|
||||
# The IPv6 Destination address MUST be the RLOC of the destination
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER_1).\
|
||||
filter_RLARMA().\
|
||||
filter_coap_request(ADDR_QRY_URI, port=MM).\
|
||||
filter(lambda p: p.thread_address.tlv.target_eid == MED_MLEID).\
|
||||
must_next()
|
||||
pkts.filter_ipv6_src_dst(ROUTER_2_RLOC, ROUTER_1_RLOC).\
|
||||
filter_coap_request(ADDR_NTF_URI, port=MM).\
|
||||
filter(lambda p: {
|
||||
NL_ML_EID_TLV,
|
||||
NL_RLOC16_TLV,
|
||||
NL_TARGET_EID_TLV
|
||||
} <= set(p.coap.tlv.type) and\
|
||||
p.thread_address.tlv.target_eid == MED_MLEID and\
|
||||
p.coap.code == COAP_CODE_POST
|
||||
).\
|
||||
must_next()
|
||||
_pkt = pkts.filter_ping_request().\
|
||||
filter_wpan_src64(ROUTER_1).\
|
||||
filter_ipv6_dst(MED_MLEID).\
|
||||
must_next()
|
||||
pkts.filter_ping_request(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(ROUTER_2).\
|
||||
filter_ipv6_dst(MED_MLEID).\
|
||||
must_next()
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(MED).\
|
||||
filter_wpan_dst16(ROUTER_2_RLOC16).\
|
||||
must_next()
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(ROUTER_2).\
|
||||
filter_ipv6_dst(ROUTER_1_MLEID).\
|
||||
must_next()
|
||||
|
||||
# Step 4: MED sends an ICMPv6 Echo Request to the Router_3 ML-EID
|
||||
# The DUT MUST NOT send an Address Query, as the Router_3 address
|
||||
# should be cached
|
||||
# The DUT MUST forward the ICMPv6 Echo Reply to MED
|
||||
|
||||
_pkt = pkts.filter_ping_request().\
|
||||
filter_wpan_src64(MED).\
|
||||
filter_ipv6_dst(ROUTER_3_MLEID).\
|
||||
must_next()
|
||||
lstart = pkts.index
|
||||
pkts.filter_ping_request(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(ROUTER_2).\
|
||||
filter_ipv6_dst(ROUTER_3_MLEID).\
|
||||
must_next()
|
||||
lend = pkts.index
|
||||
|
||||
pkts.range(lstart, lend).\
|
||||
filter_wpan_src64(ROUTER_2).\
|
||||
filter_RLARMA().\
|
||||
filter_coap_request(ADDR_QRY_URI).\
|
||||
must_not_next()
|
||||
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(ROUTER_3).\
|
||||
filter_wpan_dst16(ROUTER_2_RLOC16).\
|
||||
must_next()
|
||||
_pkt1 = pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(ROUTER_2).\
|
||||
filter_wpan_dst16(MED_RLOC16).\
|
||||
must_next()
|
||||
|
||||
# Step 5: Power off Router_3 and wait for the Leader to expire its Router ID
|
||||
# Send an ICMPv6 Echo Request from MED to the Router_3 ML-EID address
|
||||
# The DUT MUST update its address cache and removes all entries based
|
||||
# on Router_3’s Router ID.
|
||||
# The DUT MUST send an Address Query to discover Router_3’s RLOC
|
||||
# address.
|
||||
|
||||
_pkt = pkts.filter_ping_request().\
|
||||
filter_wpan_src64(MED).\
|
||||
filter_ipv6_dst(ROUTER_3_MLEID).\
|
||||
filter(lambda p: p.sniff_timestamp - _pkt1.sniff_timestamp >= 700).\
|
||||
must_next()
|
||||
pkts.filter_wpan_src64(ROUTER_2).\
|
||||
filter_RLARMA().\
|
||||
filter_coap_request(ADDR_QRY_URI, port=MM).\
|
||||
filter(lambda p: p.thread_address.tlv.target_eid == ROUTER_3_MLEID and\
|
||||
p.coap.code == COAP_CODE_POST
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 6: Power off MED and wait for the DUT to timeout the child.
|
||||
# Send two ICMPv6 Echo Requests from Router_1 to MED ML-EID
|
||||
# The DUT MUST NOT respond with an Address Notification message
|
||||
|
||||
pkts.filter_ping_request().\
|
||||
filter_wpan_src64(ROUTER_1).\
|
||||
filter_ipv6_dst(MED_MLEID).\
|
||||
must_next()
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER_1).\
|
||||
filter_RLARMA().\
|
||||
filter_coap_request(ADDR_QRY_URI, port=MM).\
|
||||
filter(lambda p: p.thread_address.tlv.target_eid == MED_MLEID and\
|
||||
p.coap.code == COAP_CODE_POST
|
||||
).\
|
||||
must_next()
|
||||
|
||||
pkts.filter_ipv6_src_dst(ROUTER_2_RLOC, ROUTER_1_RLOC).\
|
||||
filter_coap_request(ADDR_NTF_URI).\
|
||||
must_not_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,256 +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 command
|
||||
import config
|
||||
import thread_cert
|
||||
from pktverify.consts import MLE_CHILD_ID_REQUEST, MLE_CHILD_ID_RESPONSE, ADDR_QRY_URI, ADDR_NTF_URI, NL_ML_EID_TLV, NL_RLOC16_TLV, NL_TARGET_EID_TLV, COAP_CODE_POST
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
|
||||
LEADER = 1
|
||||
DUT_ROUTER1 = 2
|
||||
SED1 = 3
|
||||
MED1 = 4
|
||||
MED2 = 5
|
||||
MED3 = 6
|
||||
MED4 = 7
|
||||
|
||||
MTDS = [SED1, MED1, MED2, MED3, MED4]
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to validate that the DUT is able to
|
||||
# maintain an EID-to-RLOC Map Cache for a Sleepy End Device child attached to
|
||||
# it. Each EID-to-RLOC Set MUST support at least four non-link-local unicast
|
||||
# IPv6 addresses.
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# Router_1 - Leader
|
||||
# | / \
|
||||
# SED MED_1 .. MED_4
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Router
|
||||
|
||||
|
||||
class Cert_5_3_4_AddressMapCache(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [DUT_ROUTER1, MED1, MED2, MED3, MED4]
|
||||
},
|
||||
DUT_ROUTER1: {
|
||||
'name': 'ROUTER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER, SED1]
|
||||
},
|
||||
SED1: {
|
||||
'name': 'SED',
|
||||
'is_mtd': True,
|
||||
'mode': '-',
|
||||
'timeout': 5,
|
||||
'allowlist': [DUT_ROUTER1]
|
||||
},
|
||||
MED1: {
|
||||
'name': 'MED_1',
|
||||
'is_mtd': True,
|
||||
'mode': 'rn',
|
||||
'allowlist': [LEADER]
|
||||
},
|
||||
MED2: {
|
||||
'name': 'MED_2',
|
||||
'is_mtd': True,
|
||||
'mode': 'rn',
|
||||
'allowlist': [LEADER]
|
||||
},
|
||||
MED3: {
|
||||
'name': 'MED_3',
|
||||
'is_mtd': True,
|
||||
'mode': 'rn',
|
||||
'allowlist': [LEADER]
|
||||
},
|
||||
MED4: {
|
||||
'name': 'MED_4',
|
||||
'is_mtd': True,
|
||||
'mode': 'rn',
|
||||
'allowlist': [LEADER]
|
||||
},
|
||||
}
|
||||
|
||||
def test(self):
|
||||
# 1
|
||||
self.nodes[LEADER].start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[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')
|
||||
|
||||
for i in MTDS:
|
||||
self.nodes[i].start()
|
||||
self.simulator.go(5)
|
||||
|
||||
for i in MTDS:
|
||||
self.assertEqual(self.nodes[i].get_state(), 'child')
|
||||
|
||||
self.collect_ipaddrs()
|
||||
self.collect_rlocs()
|
||||
self.collect_rloc16s()
|
||||
|
||||
# 2
|
||||
for MED in [MED1, MED2, MED3, MED4]:
|
||||
ed_mleid = self.nodes[MED].get_ip6_address(config.ADDRESS_TYPE.ML_EID)
|
||||
self.assertTrue(self.nodes[SED1].ping(ed_mleid))
|
||||
self.simulator.go(5)
|
||||
|
||||
# 3 & 4
|
||||
for MED in [MED1, MED2, MED3, MED4]:
|
||||
ed_mleid = self.nodes[MED].get_ip6_address(config.ADDRESS_TYPE.ML_EID)
|
||||
self.assertTrue(self.nodes[SED1].ping(ed_mleid))
|
||||
self.simulator.go(5)
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
LEADER = pv.vars['LEADER']
|
||||
LEADER_RLOC16 = pv.vars['LEADER_RLOC16']
|
||||
ROUTER = pv.vars['ROUTER']
|
||||
ROUTER_RLOC = pv.vars['ROUTER_RLOC']
|
||||
SED = pv.vars['SED']
|
||||
SED_RLOC = pv.vars['SED_RLOC']
|
||||
SED_RLOC16 = pv.vars['SED_RLOC16']
|
||||
SED_MLEID = pv.vars['SED_MLEID']
|
||||
MM = pv.vars['MM_PORT']
|
||||
|
||||
# Step 1: Build the topology as described
|
||||
pv.verify_attached('ROUTER')
|
||||
for i in range(1, 5):
|
||||
with pkts.save_index():
|
||||
pkts.filter_wpan_src64(pv.vars['MED_%d' %i]).\
|
||||
filter_wpan_dst64(LEADER).\
|
||||
filter_mle_cmd(MLE_CHILD_ID_REQUEST).\
|
||||
must_next()
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_wpan_dst64(pv.vars['MED_%d' %i]).\
|
||||
filter_mle_cmd(MLE_CHILD_ID_RESPONSE).\
|
||||
must_next()
|
||||
pkts.filter_wpan_src64(pv.vars['SED']).\
|
||||
filter_wpan_dst64(ROUTER).\
|
||||
filter_mle_cmd(MLE_CHILD_ID_REQUEST).\
|
||||
must_next()
|
||||
pkts.filter_wpan_src64(ROUTER).\
|
||||
filter_wpan_dst64(pv.vars['SED']).\
|
||||
filter_mle_cmd(MLE_CHILD_ID_RESPONSE).\
|
||||
must_next()
|
||||
|
||||
# Step 2: SED sends an ICMPv6 Echo Request to MED_1, MED_2, MED_3, MED_4 ML-EID
|
||||
# The DUT MUST generate an Address Query Request on SED’s behalf
|
||||
# to find each node’s RLOC.
|
||||
# The Address Query Request MUST be sent to the Realm-Local
|
||||
# All-Routers address (FF03::2)
|
||||
# CoAP URI-Path
|
||||
# - NON POST coap://<FF03::2>
|
||||
# CoAP Payload
|
||||
# - Target EID TLV
|
||||
|
||||
# Step 3: Leader sends Address Notification Messages with RLOC of MED_1, MED_2, MED_3, MED_4
|
||||
for i in range(1, 5):
|
||||
_pkt = pkts.filter_ping_request().\
|
||||
filter_wpan_src64(SED).\
|
||||
filter_ipv6_dst(pv.vars['MED_%d_MLEID' %i]).\
|
||||
must_next()
|
||||
pkts.filter_wpan_src64(ROUTER).\
|
||||
filter_RLARMA().\
|
||||
filter_coap_request(ADDR_QRY_URI, port=MM).\
|
||||
filter(lambda p: p.thread_address.tlv.target_eid == pv.vars['MED_%d_MLEID' %i]).\
|
||||
must_next()
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_ipv6_dst(ROUTER_RLOC).\
|
||||
filter_coap_request(ADDR_NTF_URI, port=MM).\
|
||||
filter(lambda p: {
|
||||
NL_ML_EID_TLV,
|
||||
NL_RLOC16_TLV,
|
||||
NL_TARGET_EID_TLV
|
||||
} <= set(p.coap.tlv.type) and\
|
||||
p.thread_address.tlv.target_eid == pv.vars['MED_%d_MLEID' %i] and\
|
||||
p.thread_address.tlv.rloc16 == LEADER_RLOC16 and\
|
||||
p.coap.code == COAP_CODE_POST
|
||||
).\
|
||||
must_next()
|
||||
pkts.filter_ping_request(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(ROUTER).\
|
||||
filter_ipv6_dst(pv.vars['MED_%d_MLEID' %i]).\
|
||||
must_next()
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(pv.vars['MED_%d' %i]).\
|
||||
filter_ipv6_dst(SED_MLEID).\
|
||||
must_next()
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(ROUTER).\
|
||||
filter_wpan_dst16(SED_RLOC16).\
|
||||
must_next()
|
||||
|
||||
# Step 4: SED sends another ICMPv6 Echo Request to MED_1, MED_2, MED_3, MED_4 ML-EID
|
||||
# The DUT MUST not send an Address Query during this step; If an address query
|
||||
# message is sent, the test fails
|
||||
# An ICMPv6 Echo Reply MUST be sent for each ICMPv6 Echo Request from SED
|
||||
for i in range(1, 5):
|
||||
_pkt = pkts.filter_ping_request().\
|
||||
filter_wpan_src64(SED).\
|
||||
filter_ipv6_dst(pv.vars['MED_%d_MLEID' %i]).\
|
||||
must_next()
|
||||
pkts.filter_wpan_src64(ROUTER).\
|
||||
filter_RLARMA().\
|
||||
filter_coap_request(ADDR_QRY_URI, port=MM).\
|
||||
must_not_next()
|
||||
pkts.filter_ping_request(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(ROUTER).\
|
||||
filter_ipv6_dst(pv.vars['MED_%d_MLEID' %i]).\
|
||||
must_next()
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(pv.vars['MED_%d' %i]).\
|
||||
filter_ipv6_dst(SED_MLEID).\
|
||||
must_next()
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(ROUTER).\
|
||||
filter_wpan_dst16(SED_RLOC16).\
|
||||
must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,243 +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 command
|
||||
import config
|
||||
import thread_cert
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
|
||||
LEADER = 1
|
||||
DUT_ROUTER1 = 2
|
||||
ROUTER2 = 3
|
||||
ROUTER3 = 4
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to ensure that the DUT routes traffic properly
|
||||
# when link qualities between the nodes are adjusted.
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# Leader
|
||||
# / \
|
||||
# Router_2 - Router_1(DUT)
|
||||
# |
|
||||
# Router_3
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Router
|
||||
|
||||
|
||||
class Cert_5_3_5_RoutingLinkQuality(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [DUT_ROUTER1, ROUTER2]
|
||||
},
|
||||
DUT_ROUTER1: {
|
||||
'name': 'ROUTER_1',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER, ROUTER2, ROUTER3]
|
||||
},
|
||||
ROUTER2: {
|
||||
'name': 'ROUTER_2',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER, DUT_ROUTER1]
|
||||
},
|
||||
ROUTER3: {
|
||||
'name': 'ROUTER_3',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [DUT_ROUTER1]
|
||||
},
|
||||
}
|
||||
|
||||
def test(self):
|
||||
# 1
|
||||
self.nodes[LEADER].start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
|
||||
|
||||
for router in range(DUT_ROUTER1, ROUTER3 + 1):
|
||||
self.nodes[router].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
|
||||
for router in range(DUT_ROUTER1, ROUTER3 + 1):
|
||||
self.assertEqual(self.nodes[router].get_state(), 'router')
|
||||
|
||||
self.collect_rlocs()
|
||||
self.collect_rloc16s()
|
||||
|
||||
# 2 & 3
|
||||
leader_rloc = self.nodes[LEADER].get_ip6_address(config.ADDRESS_TYPE.RLOC)
|
||||
self.assertTrue(self.nodes[ROUTER3].ping(leader_rloc))
|
||||
|
||||
# 4 & 5
|
||||
self.nodes[LEADER].add_allowlist(self.nodes[DUT_ROUTER1].get_addr64(), config.RSSI['LINK_QULITY_1'])
|
||||
self.nodes[DUT_ROUTER1].add_allowlist(self.nodes[LEADER].get_addr64(), config.RSSI['LINK_QULITY_1'])
|
||||
self.simulator.go(3 * config.MAX_ADVERTISEMENT_INTERVAL)
|
||||
|
||||
self.assertTrue(self.nodes[ROUTER3].ping(leader_rloc))
|
||||
|
||||
# 6 & 7
|
||||
self.nodes[LEADER].add_allowlist(self.nodes[DUT_ROUTER1].get_addr64(), config.RSSI['LINK_QULITY_2'])
|
||||
self.nodes[DUT_ROUTER1].add_allowlist(self.nodes[LEADER].get_addr64(), config.RSSI['LINK_QULITY_2'])
|
||||
self.simulator.go(3 * config.MAX_ADVERTISEMENT_INTERVAL)
|
||||
|
||||
self.assertTrue(self.nodes[ROUTER3].ping(leader_rloc))
|
||||
|
||||
# 8 & 9
|
||||
self.nodes[LEADER].add_allowlist(self.nodes[DUT_ROUTER1].get_addr64(), config.RSSI['LINK_QULITY_0'])
|
||||
self.nodes[DUT_ROUTER1].add_allowlist(self.nodes[LEADER].get_addr64(), config.RSSI['LINK_QULITY_0'])
|
||||
self.simulator.go(3 * config.MAX_ADVERTISEMENT_INTERVAL)
|
||||
|
||||
self.assertTrue(self.nodes[ROUTER3].ping(leader_rloc))
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
LEADER = pv.vars['LEADER']
|
||||
LEADER_RLOC = pv.vars['LEADER_RLOC']
|
||||
LEADER_RLOC16 = pv.vars['LEADER_RLOC16']
|
||||
ROUTER_1 = pv.vars['ROUTER_1']
|
||||
ROUTER_1_RLOC = pv.vars['ROUTER_1_RLOC']
|
||||
ROUTER_1_RLOC16 = pv.vars['ROUTER_1_RLOC16']
|
||||
ROUTER_2 = pv.vars['ROUTER_2']
|
||||
ROUTER_2_RLOC16 = pv.vars['ROUTER_2_RLOC16']
|
||||
ROUTER_2_RLOC = pv.vars['ROUTER_2_RLOC']
|
||||
ROUTER_3 = pv.vars['ROUTER_3']
|
||||
ROUTER_3_RLOC = pv.vars['ROUTER_3_RLOC']
|
||||
MM = pv.vars['MM_PORT']
|
||||
|
||||
# Step 1: Ensure topology is formed correctly
|
||||
for i in range(1, 4):
|
||||
with pkts.save_index():
|
||||
pv.verify_attached('ROUTER_%d' % i)
|
||||
|
||||
# Step 2: Modify the link quality between the DUT and the Leader to be 3
|
||||
# Step 3: Router_3 sends an ICMPv6 Echo Request to the Leader
|
||||
# The ICMPv6 Echo Request MUST take the shortest path:
|
||||
# Router_3 -> DUT -> Leader
|
||||
# The hopsLft field of the 6LoWPAN Mesh Header MUST be greater than
|
||||
# the route cost to the destination
|
||||
|
||||
_pkt = pkts.filter_ping_request().\
|
||||
filter_wpan_src64(ROUTER_3).\
|
||||
filter_ipv6_dst(LEADER_RLOC).\
|
||||
must_next()
|
||||
_pkt.must_verify(lambda p: p.lowpan.mesh.hops > 2)
|
||||
pkts.filter_ping_request(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(ROUTER_1).\
|
||||
filter_wpan_dst16(LEADER_RLOC16).\
|
||||
must_next()
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(LEADER).\
|
||||
filter_ipv6_dst(ROUTER_3_RLOC).\
|
||||
must_next()
|
||||
|
||||
# Step 4: Modify the link quality between the DUT and the Leader to be 1
|
||||
# Step 5: Router_3 sends an ICMPv6 Echo Request to the Leader
|
||||
# The ICMPv6 Echo Request MUST take the shortest path:
|
||||
# Router_3 -> DUT -> Router_2 -> Leader
|
||||
# The hopsLft field of the 6LoWPAN Mesh Header MUST be greater than
|
||||
# the route cost to the destination
|
||||
|
||||
_pkt = pkts.filter_ping_request().\
|
||||
filter_wpan_src64(ROUTER_3).\
|
||||
filter_ipv6_dst(LEADER_RLOC).\
|
||||
must_next()
|
||||
_pkt.must_verify(lambda p: p.lowpan.mesh.hops > 3)
|
||||
pkts.filter_ping_request(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(ROUTER_1).\
|
||||
filter_wpan_dst16(ROUTER_2_RLOC16).\
|
||||
must_next()
|
||||
pkts.filter_ping_request(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(ROUTER_2).\
|
||||
filter_wpan_dst16(LEADER_RLOC16).\
|
||||
must_next()
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(LEADER).\
|
||||
filter_ipv6_dst(ROUTER_3_RLOC).\
|
||||
must_next()
|
||||
|
||||
# Step 6: Modify the link quality between the DUT and the Leader to be 2
|
||||
# Step 7: Router_3 sends an ICMPv6 Echo Request to the Leader
|
||||
# The ICMPv6 Echo Request MUST take the shortest path:
|
||||
# Router_3 -> DUT -> Leader
|
||||
# The hopsLft field of the 6LoWPAN Mesh Header MUST be greater than
|
||||
# the route cost to the destination
|
||||
|
||||
_pkt = pkts.filter_ping_request().\
|
||||
filter_wpan_src64(ROUTER_3).\
|
||||
filter_ipv6_dst(LEADER_RLOC).\
|
||||
must_next()
|
||||
_pkt.must_verify(lambda p: p.lowpan.mesh.hops > 2)
|
||||
pkts.filter_ping_request(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(ROUTER_1).\
|
||||
filter_wpan_dst16(LEADER_RLOC16).\
|
||||
must_next()
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(LEADER).\
|
||||
filter_ipv6_dst(ROUTER_3_RLOC).\
|
||||
must_next()
|
||||
|
||||
# Step 8: Modify the link quality between the DUT and the Leader to be 0
|
||||
# Step 9: Router_3 sends an ICMPv6 Echo Request to the Leader
|
||||
# The ICMPv6 Echo Request MUST take the shortest path:
|
||||
# Router_3 -> DUT -> Router_2 -> Leader
|
||||
# The hopsLft field of the 6LoWPAN Mesh Header MUST be greater than
|
||||
# the route cost to the destination
|
||||
|
||||
_pkt = pkts.filter_ping_request().\
|
||||
filter_wpan_src64(ROUTER_3).\
|
||||
filter_ipv6_dst(LEADER_RLOC).\
|
||||
must_next()
|
||||
_pkt.must_verify(lambda p: p.lowpan.mesh.hops > 3)
|
||||
pkts.filter_ping_request(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(ROUTER_1).\
|
||||
filter_wpan_dst16(ROUTER_2_RLOC16).\
|
||||
must_next()
|
||||
pkts.filter_ping_request(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(ROUTER_2).\
|
||||
filter_wpan_dst16(LEADER_RLOC16).\
|
||||
must_next()
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(LEADER).\
|
||||
filter_ipv6_dst(ROUTER_3_RLOC).\
|
||||
must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,229 +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_CHILD_ID_RESPONSE
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
|
||||
DUT_LEADER = 1
|
||||
ROUTER1 = 2
|
||||
ROUTER2 = 3
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to verify that the router ID mask is managed
|
||||
# correctly, as the connectivity to a router or group of routers is lost and / or
|
||||
# a new router is added to network.
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# Leader(DUT)
|
||||
# |
|
||||
# Router_1
|
||||
# |
|
||||
# Router_2
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Leader
|
||||
|
||||
|
||||
class Cert_5_3_6_RouterIdMask(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
|
||||
TOPOLOGY = {
|
||||
DUT_LEADER: {
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [ROUTER1]
|
||||
},
|
||||
ROUTER1: {
|
||||
'name': 'ROUTER_1',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [DUT_LEADER, ROUTER2]
|
||||
},
|
||||
ROUTER2: {
|
||||
'name': 'ROUTER_2',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [ROUTER1]
|
||||
},
|
||||
}
|
||||
|
||||
def _setUpRouter2(self):
|
||||
self.nodes[ROUTER2].add_allowlist(self.nodes[ROUTER1].get_addr64())
|
||||
self.nodes[ROUTER2].enable_allowlist()
|
||||
self.nodes[ROUTER2].set_router_selection_jitter(1)
|
||||
|
||||
def test(self):
|
||||
# 1
|
||||
self.nodes[DUT_LEADER].start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[DUT_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.collect_rloc16s()
|
||||
|
||||
# Wait DUT_LEADER to establish routing to ROUTER2 via ROUTER1's MLE
|
||||
# advertisement.
|
||||
self.simulator.go(config.MAX_ADVERTISEMENT_INTERVAL)
|
||||
|
||||
# 2
|
||||
self.nodes[ROUTER2].reset()
|
||||
self._setUpRouter2()
|
||||
|
||||
# 3 & 4
|
||||
|
||||
self.simulator.go(720)
|
||||
|
||||
# 5
|
||||
|
||||
self.nodes[ROUTER2].start()
|
||||
self.simulator.go(config.ROUTER_RESET_DELAY)
|
||||
self.assertEqual(self.nodes[ROUTER2].get_state(), 'router')
|
||||
|
||||
self.simulator.go(config.MAX_ADVERTISEMENT_INTERVAL)
|
||||
|
||||
# 6
|
||||
self.nodes[ROUTER1].reset()
|
||||
self.nodes[ROUTER2].reset()
|
||||
|
||||
self.simulator.go(720)
|
||||
|
||||
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']
|
||||
|
||||
leader_rid = pv.vars['LEADER_RLOC16'] >> 10
|
||||
router_1_rid = pv.vars['ROUTER_1_RLOC16'] >> 10
|
||||
router_2_rid = pv.vars['ROUTER_2_RLOC16'] >> 10
|
||||
|
||||
# Step 1: Ensure topology is formed correctly
|
||||
pv.verify_attached('ROUTER_1', 'LEADER')
|
||||
pv.verify_attached('ROUTER_2', 'ROUTER_1')
|
||||
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_LLANMA().\
|
||||
filter_mle_cmd(MLE_ADVERTISEMENT).\
|
||||
filter(lambda p:
|
||||
{1,2,1} == set(p.mle.tlv.route64.cost) and\
|
||||
{leader_rid, router_1_rid, router_2_rid} ==
|
||||
p.mle.tlv.route64.id_mask
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 4: The DUT’s routing cost to Router_2 MUST count to infinity
|
||||
# The DUT MUST remove Router_2 ID from its ID set
|
||||
# Verify route data has settled
|
||||
_pkt = pkts.filter_wpan_src64(LEADER).\
|
||||
filter_LLANMA().\
|
||||
filter_mle_cmd(MLE_ADVERTISEMENT).\
|
||||
filter(lambda p: {1,0,1} == set(p.mle.tlv.route64.cost)).\
|
||||
must_next()
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_LLANMA().\
|
||||
filter_mle_cmd(MLE_ADVERTISEMENT).\
|
||||
filter(lambda p:
|
||||
{1,1} == set(p.mle.tlv.route64.cost) and\
|
||||
{leader_rid, router_1_rid} ==
|
||||
p.mle.tlv.route64.id_mask
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 5: Re-attach Router_2 to Router_1.
|
||||
# The DUT MUST reset the MLE Advertisement trickle timer and
|
||||
# send an Advertisement
|
||||
pv.verify_attached('ROUTER_2', 'ROUTER_1')
|
||||
# check trickle timer between the successive advertisements
|
||||
with pkts.save_index():
|
||||
_pkt = pkts.filter_wpan_src64(LEADER).\
|
||||
filter_LLANMA().\
|
||||
filter_mle_cmd(MLE_ADVERTISEMENT).\
|
||||
must_next()
|
||||
# Time between MLE Advertisements after reset can be up to 3.5 seconds
|
||||
# 0.0s: Reset Interval, reset interval to 1 seconds, random interval at 0.5 second
|
||||
# 0.5s: Transmit MLE Advertisement
|
||||
# 1.0s: Set interval to 2 seconds, random interval at 2 seconds
|
||||
# 3.0s: Receive MLE Advertisement, reset interval to 1 second, random interval at 1.0 second
|
||||
# 4.0s: Transmit MLE Advertisement
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_LLANMA().\
|
||||
filter_mle_cmd(MLE_ADVERTISEMENT).\
|
||||
filter(lambda p: p.sniff_timestamp - _pkt.sniff_timestamp <= 4).\
|
||||
must_next()
|
||||
|
||||
# check router cost after the re-attach
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_LLANMA().\
|
||||
filter_mle_cmd(MLE_ADVERTISEMENT).\
|
||||
filter(lambda p: {1,2,1} == set(p.mle.tlv.route64.cost) and\
|
||||
{leader_rid, router_1_rid, router_2_rid} ==
|
||||
p.mle.tlv.route64.id_mask
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 6: The DUT’s routing cost to Router_1 MUST go directly to
|
||||
# infinity as there is no multi-hop cost for Router_1
|
||||
# The DUT MUST remove Router_1 & Router_2 IDs from its ID set
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_LLANMA().\
|
||||
filter_mle_cmd(MLE_ADVERTISEMENT).\
|
||||
filter(lambda p: {0, 0, 1} == set(p.mle.tlv.route64.cost)).\
|
||||
must_next()
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_LLANMA().\
|
||||
filter_mle_cmd(MLE_ADVERTISEMENT).\
|
||||
filter(lambda p: {0, 1} == set(p.mle.tlv.route64.cost)).\
|
||||
must_next()
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_LLANMA().\
|
||||
filter_mle_cmd(MLE_ADVERTISEMENT).\
|
||||
filter(lambda p:
|
||||
[1] == p.mle.tlv.route64.cost and\
|
||||
{leader_rid} ==
|
||||
p.mle.tlv.route64.id_mask
|
||||
).\
|
||||
must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,218 +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 command
|
||||
import config
|
||||
import copy
|
||||
import mle
|
||||
import thread_cert
|
||||
from pktverify.consts import WIRESHARK_OVERRIDE_PREFS, ADDR_ERR_URI, ADDR_QRY_URI, ADDR_NTF_URI, MLE_CHILD_ID_REQUEST, MLE_CHILD_ID_RESPONSE, REALM_LOCAL_ALL_ROUTERS_ADDRESS, NL_TARGET_EID_TLV, NL_RLOC16_TLV, NL_ML_EID_TLV
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
|
||||
DUT_LEADER = 1
|
||||
ROUTER1 = 2
|
||||
ROUTER2 = 3
|
||||
MED1 = 4
|
||||
SED1 = 5
|
||||
MED2 = 6
|
||||
|
||||
MTDS = [MED1, SED1, MED2]
|
||||
ON_MESH_PREFIX = '2001::/64'
|
||||
IPV6_ADDR = '2001::1234'
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to validate the DUT’s ability to perform
|
||||
# duplicate address detection.
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# MED_2 - Leader(DUT)
|
||||
# / \
|
||||
# Router_1 Router_2
|
||||
# | |
|
||||
# MED_1 SED
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Leader
|
||||
|
||||
|
||||
class Cert_5_3_7_DuplicateAddress(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
|
||||
TOPOLOGY = {
|
||||
DUT_LEADER: {
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [ROUTER1, ROUTER2, MED2]
|
||||
},
|
||||
ROUTER1: {
|
||||
'name': 'ROUTER_1',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [DUT_LEADER, MED1]
|
||||
},
|
||||
ROUTER2: {
|
||||
'name': 'ROUTER_2',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [DUT_LEADER, SED1]
|
||||
},
|
||||
MED1: {
|
||||
'name': 'MED_1',
|
||||
'is_mtd': True,
|
||||
'mode': 'rn',
|
||||
'allowlist': [ROUTER1]
|
||||
},
|
||||
SED1: {
|
||||
'name': 'SED',
|
||||
'is_mtd': True,
|
||||
'mode': '-',
|
||||
'allowlist': [ROUTER2]
|
||||
},
|
||||
MED2: {
|
||||
'name': 'MED_2',
|
||||
'is_mtd': True,
|
||||
'mode': 'rn',
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
}
|
||||
|
||||
# override wireshark preferences with case needed parameters
|
||||
CASE_WIRESHARK_PREFS = copy.deepcopy(WIRESHARK_OVERRIDE_PREFS)
|
||||
CASE_WIRESHARK_PREFS['6lowpan.context1'] = ON_MESH_PREFIX
|
||||
|
||||
def test(self):
|
||||
self.nodes[DUT_LEADER].start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[DUT_LEADER].get_state(), 'leader')
|
||||
|
||||
for i in range(ROUTER1, MED2 + 1):
|
||||
self.nodes[i].start()
|
||||
self.simulator.go(5)
|
||||
|
||||
for i in [ROUTER1, ROUTER2]:
|
||||
self.assertEqual(self.nodes[i].get_state(), 'router')
|
||||
|
||||
for i in MTDS:
|
||||
self.assertEqual(self.nodes[i].get_state(), 'child')
|
||||
|
||||
self.collect_ipaddrs()
|
||||
self.collect_rlocs()
|
||||
|
||||
self.nodes[ROUTER2].add_prefix(ON_MESH_PREFIX, 'paros')
|
||||
self.nodes[ROUTER2].register_netdata()
|
||||
|
||||
self.nodes[MED1].add_ipaddr(IPV6_ADDR)
|
||||
self.nodes[SED1].add_ipaddr(IPV6_ADDR)
|
||||
self.simulator.go(5)
|
||||
|
||||
self.nodes[MED2].ping(IPV6_ADDR)
|
||||
self.simulator.go(5)
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
LEADER = pv.vars['LEADER']
|
||||
LEADER_RLOC = pv.vars['LEADER_RLOC']
|
||||
ROUTER_1 = pv.vars['ROUTER_1']
|
||||
ROUTER_2 = pv.vars['ROUTER_2']
|
||||
MED_1 = pv.vars['MED_1']
|
||||
MED_2 = pv.vars['MED_2']
|
||||
SED = pv.vars['SED']
|
||||
MM = pv.vars['MM_PORT']
|
||||
|
||||
# Step 1: Ensure topology is formed correctly
|
||||
for i in (1, 2):
|
||||
pv.verify_attached('ROUTER_%d' % i, 'LEADER')
|
||||
pv.verify_attached('MED_1', 'ROUTER_1', 'MTD')
|
||||
pv.verify_attached('SED', 'ROUTER_2', 'MTD')
|
||||
pv.verify_attached('MED_2', 'LEADER', 'MTD')
|
||||
|
||||
# Step 5: MED_2 sends ICMPv6 Echo Request to address configured on MED_1
|
||||
# and SED_1 with Prefix 2001::
|
||||
# The DUT MUST multicast an Address Query message to the Realm-Local
|
||||
# All Routers address (FF03::2):
|
||||
# CoAP URI-Path
|
||||
# - NON POST coap://<FF03::2>
|
||||
# CoAP Payload
|
||||
# - Target EID TLV
|
||||
|
||||
pkts.filter_ping_request().\
|
||||
filter_wpan_src64(MED_2). \
|
||||
filter_ipv6_dst(IPV6_ADDR). \
|
||||
must_next()
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_RLARMA().\
|
||||
filter_coap_request(ADDR_QRY_URI, port=MM).\
|
||||
filter(lambda p: p.thread_address.tlv.target_eid == IPV6_ADDR).\
|
||||
must_next()
|
||||
|
||||
# Step 6: Router_1 & Router_2 respond with Address Notification message
|
||||
# with matching Target TLVs
|
||||
|
||||
for i in (1, 2):
|
||||
with pkts.save_index():
|
||||
pkts.filter_wpan_src64(pv.vars['ROUTER_%d' %i]).\
|
||||
filter_ipv6_dst(LEADER_RLOC).\
|
||||
filter_coap_request(ADDR_NTF_URI, port=MM).\
|
||||
filter(lambda p: {
|
||||
NL_ML_EID_TLV,
|
||||
NL_RLOC16_TLV,
|
||||
NL_TARGET_EID_TLV
|
||||
} <= set(p.coap.tlv.type) and\
|
||||
p.thread_address.tlv.target_eid == IPV6_ADDR
|
||||
).\
|
||||
must_next()
|
||||
|
||||
# Step 7: The DUT MUST multicast an Address Error Notification to the Realm-Local
|
||||
# All Routers address (FF03::2):
|
||||
# CoAP URI-Path
|
||||
# - NON POST coap://[<peer address>]:MM/a/ae
|
||||
# CoAP Payload
|
||||
# - Target EID TLV
|
||||
# - ML-EID TLV
|
||||
#
|
||||
# The IPv6 Source address MUST be the RLOC of the originator
|
||||
|
||||
pkts.filter_ipv6_src_dst(LEADER_RLOC, REALM_LOCAL_ALL_ROUTERS_ADDRESS).\
|
||||
filter_coap_request(ADDR_ERR_URI, port=MM).\
|
||||
filter(lambda p: {
|
||||
NL_ML_EID_TLV,
|
||||
NL_TARGET_EID_TLV
|
||||
} <= set(p.coap.tlv.type) and\
|
||||
p.thread_address.tlv.target_eid == IPV6_ADDR
|
||||
).\
|
||||
must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,222 +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 command
|
||||
import config
|
||||
import copy
|
||||
import ipv6
|
||||
import mle
|
||||
import thread_cert
|
||||
from pktverify.consts import WIRESHARK_OVERRIDE_PREFS, MLE_ADVERTISEMENT, ADDR_QRY_URI, SOURCE_ADDRESS_TLV, ROUTE64_TLV, LEADER_DATA_TLV
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
from pktverify.bytes import Bytes
|
||||
|
||||
DUT_LEADER = 1
|
||||
BR = 2
|
||||
MED1 = 3
|
||||
MED2 = 4
|
||||
|
||||
MTDS = [MED1, MED2]
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to validate that the DUT MTD Child Address Set
|
||||
# can hold at least 4 IPv6 non-link-local addresses.
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# MED_1
|
||||
# |
|
||||
# BR - Leader(DUT) - MED_2
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Leader
|
||||
|
||||
|
||||
class Cert_5_3_8_ChildAddressSet(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
|
||||
TOPOLOGY = {
|
||||
DUT_LEADER: {
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [BR, MED1, MED2]
|
||||
},
|
||||
BR: {
|
||||
'mode': 'rdn',
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
MED1: {
|
||||
'name': 'MED_1',
|
||||
'is_mtd': True,
|
||||
'mode': 'rn',
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
MED2: {
|
||||
'name': 'MED_2',
|
||||
'is_mtd': True,
|
||||
'mode': 'rn',
|
||||
'allowlist': [DUT_LEADER]
|
||||
},
|
||||
}
|
||||
# override wireshark preferences with case needed parameters
|
||||
CASE_WIRESHARK_PREFS = copy.deepcopy(WIRESHARK_OVERRIDE_PREFS)
|
||||
CASE_WIRESHARK_PREFS['6lowpan.context1'] = '2001::/64'
|
||||
CASE_WIRESHARK_PREFS['6lowpan.context2'] = '2002::/64'
|
||||
CASE_WIRESHARK_PREFS['6lowpan.context3'] = '2003::/64'
|
||||
|
||||
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[BR].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[BR].get_state(), 'router')
|
||||
|
||||
# 1 BR: Configure BR to be a DHCPv6 server
|
||||
self.nodes[BR].add_prefix('2001::/64', 'pdros')
|
||||
self.nodes[BR].add_prefix('2002::/64', 'pdros')
|
||||
self.nodes[BR].add_prefix('2003::/64', 'pdros')
|
||||
self.nodes[BR].register_netdata()
|
||||
|
||||
# 3 MED1, MED2: MED1 and MED2 attach to DUT_LEADER
|
||||
for i in MTDS:
|
||||
self.nodes[i].start()
|
||||
self.simulator.go(5)
|
||||
self.assertEqual(self.nodes[i].get_state(), 'child')
|
||||
self.collect_ipaddrs()
|
||||
|
||||
# 4 MED1: MED1 send an ICMPv6 Echo Request to the MED2 ML-EID
|
||||
med2_ml_eid = self.nodes[MED2].get_ip6_address(config.ADDRESS_TYPE.ML_EID)
|
||||
self.assertTrue(med2_ml_eid is not None)
|
||||
self.assertTrue(self.nodes[MED1].ping(med2_ml_eid))
|
||||
|
||||
# Wait for sniffer got packets
|
||||
self.simulator.go(1)
|
||||
|
||||
# 5 MED1: MED1 send an ICMPv6 Echo Request to the MED2 2001::GUA
|
||||
addr = self.nodes[MED2].get_addr("2001::/64")
|
||||
self.assertTrue(addr is not None)
|
||||
self.assertTrue(self.nodes[MED1].ping(addr))
|
||||
# Wait for sniffer got packets
|
||||
self.simulator.go(1)
|
||||
|
||||
# 6 MED1: MED1 send an ICMPv6 Echo Request to the MED2 2002::GUA
|
||||
addr = self.nodes[MED2].get_addr("2002::/64")
|
||||
self.assertTrue(addr is not None)
|
||||
self.assertTrue(self.nodes[MED1].ping(addr))
|
||||
|
||||
# Wait for sniffer got packets
|
||||
self.simulator.go(1)
|
||||
|
||||
# 7 MED1: MED1 send an ICMPv6 Echo Request to the MED2 2003::GUA
|
||||
addr = self.nodes[MED2].get_addr("2003::/64")
|
||||
self.assertTrue(addr is not None)
|
||||
self.assertTrue(self.nodes[MED1].ping(addr))
|
||||
|
||||
# Wait for sniffer got packets
|
||||
self.simulator.go(1)
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
LEADER = pv.vars['LEADER']
|
||||
MED_1 = pv.vars['MED_1']
|
||||
MED_1_MLEID = pv.vars['MED_1_MLEID']
|
||||
MED_2 = pv.vars['MED_2']
|
||||
MED_2_MLEID = pv.vars['MED_2_MLEID']
|
||||
MED_1_GUA = list()
|
||||
MED_2_GUA = list()
|
||||
MM = pv.vars['MM_PORT']
|
||||
names = locals()
|
||||
|
||||
for i in (1, 2):
|
||||
for addr in pv.vars['MED_%d_IPADDRS' % i]:
|
||||
for j in range(1, 4):
|
||||
if addr.startswith(Bytes('200%d' % j)):
|
||||
names['MED_' + str(i) + '_GUA'].append(addr)
|
||||
|
||||
# Step 2: Leader is sending properly formatted MLE Advertisements.
|
||||
# Advertisements MUST be sent 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
|
||||
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_LLANMA().\
|
||||
filter_mle_cmd(MLE_ADVERTISEMENT).\
|
||||
filter(lambda p: {
|
||||
LEADER_DATA_TLV,
|
||||
ROUTE64_TLV,
|
||||
SOURCE_ADDRESS_TLV
|
||||
} <= set(p.mle.tlv.type) and\
|
||||
p.ipv6.hlim == 255).\
|
||||
must_next()
|
||||
|
||||
# Step 3: Send a ICMPv6 Echo Request to the MED_2 ML-EID
|
||||
# The DUT MUST NOT send an Address Query Request
|
||||
# MED_2 MUST respond with an ICMPv6 Echo Reply
|
||||
|
||||
_pkt = pkts.filter_ipv6_src_dst(MED_1_MLEID, MED_2_MLEID).\
|
||||
filter_ping_request().\
|
||||
must_next()
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_RLARMA().\
|
||||
filter_coap_request(ADDR_QRY_URI, port=MM).\
|
||||
must_not_next()
|
||||
pkts.filter_ipv6_src_dst(MED_2_MLEID, MED_1_MLEID).\
|
||||
filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
must_next()
|
||||
|
||||
# Step 4-6: Send a ICMPv6 Echo Request to the MED_2 each GUA
|
||||
# The DUT MUST NOT send an Address Query Request
|
||||
# MED_2 MUST respond with an ICMPv6 Echo Reply
|
||||
|
||||
for med_1_addr, med_2_addr in zip(MED_1_GUA, MED_2_GUA):
|
||||
_pkt = pkts.filter_ipv6_src_dst(med_1_addr, med_2_addr).\
|
||||
filter_ping_request().\
|
||||
must_next()
|
||||
pkts.filter_wpan_src64(LEADER).\
|
||||
filter_RLARMA().\
|
||||
filter_coap_request(ADDR_QRY_URI, port=MM).\
|
||||
must_not_next()
|
||||
pkts.filter_ipv6_src_dst(med_2_addr, med_1_addr).\
|
||||
filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,328 +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 command
|
||||
import config
|
||||
import copy
|
||||
import ipv6
|
||||
import thread_cert
|
||||
from pktverify.consts import WIRESHARK_OVERRIDE_PREFS, ADDR_QRY_URI, ADDR_NTF_URI, NL_ML_EID_TLV, NL_RLOC16_TLV, NL_TARGET_EID_TLV
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
from pktverify.bytes import Bytes
|
||||
|
||||
LEADER = 1
|
||||
ROUTER1 = 2
|
||||
DUT_ROUTER2 = 3
|
||||
ROUTER3 = 4
|
||||
SED1 = 5
|
||||
PREFIX_1 = '2001::/64'
|
||||
GUA_1_START = '2001'
|
||||
PREFIX_2 = '2002::/64'
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to validate that the DUT is able to generate
|
||||
# Address Query and Address Notification messages properly.
|
||||
# The Leader is configured as a Border Router with DHCPv6 server for prefixes
|
||||
# 2001:: & 2002::
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# Router_1 - Leader
|
||||
# / \
|
||||
# Router_3 Router_2(DUT)
|
||||
# |
|
||||
# SED
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Router
|
||||
|
||||
|
||||
class Cert_5_3_09_AddressQuery(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [ROUTER1, DUT_ROUTER2, ROUTER3]
|
||||
},
|
||||
ROUTER1: {
|
||||
'name': 'ROUTER_1',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER]
|
||||
},
|
||||
DUT_ROUTER2: {
|
||||
'name': 'ROUTER_2',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER, SED1]
|
||||
},
|
||||
ROUTER3: {
|
||||
'name': 'ROUTER_3',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER]
|
||||
},
|
||||
SED1: {
|
||||
'name': 'SED',
|
||||
'is_mtd': True,
|
||||
'mode': '-',
|
||||
'timeout': config.DEFAULT_CHILD_TIMEOUT,
|
||||
'allowlist': [DUT_ROUTER2]
|
||||
},
|
||||
}
|
||||
|
||||
# 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):
|
||||
# 1 & 2 ALL: Build and verify the topology
|
||||
self.nodes[LEADER].start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
|
||||
|
||||
# Configure the LEADER to be a DHCPv6 Border Router for prefixes
|
||||
self.nodes[LEADER].add_prefix(PREFIX_1, 'pdros')
|
||||
self.nodes[LEADER].add_prefix(PREFIX_2, 'pdro')
|
||||
self.nodes[LEADER].register_netdata()
|
||||
|
||||
self.nodes[ROUTER1].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
|
||||
|
||||
self.nodes[DUT_ROUTER2].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[DUT_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[SED1].start()
|
||||
self.simulator.go(5)
|
||||
self.assertEqual(self.nodes[SED1].get_state(), 'child')
|
||||
|
||||
self.collect_rlocs()
|
||||
self.collect_rloc16s()
|
||||
self.collect_ipaddrs()
|
||||
|
||||
# 3 SED1: The SED1 sends an ICMPv6 Echo Request to ROUTER3 using GUA
|
||||
# PREFIX_1 address
|
||||
router3_addr = self.nodes[ROUTER3].get_addr(PREFIX_1)
|
||||
self.assertTrue(router3_addr is not None)
|
||||
self.assertTrue(self.nodes[SED1].ping(router3_addr))
|
||||
|
||||
# 4 ROUTER1: ROUTER1 sends an ICMPv6 Echo Request to the SED1 using GUA
|
||||
# PREFIX_1 address
|
||||
sed1_addr = self.nodes[SED1].get_addr(PREFIX_1)
|
||||
self.assertTrue(sed1_addr is not None)
|
||||
self.assertTrue(self.nodes[ROUTER1].ping(sed1_addr))
|
||||
self.simulator.go(1)
|
||||
|
||||
# 5 SED1: SED1 sends an ICMPv6 Echo Request to the ROUTER3 using GUA
|
||||
# PREFIX_1 address
|
||||
self.assertTrue(self.nodes[SED1].ping(router3_addr))
|
||||
self.simulator.go(1)
|
||||
|
||||
# 6 DUT_ROUTER2: Power off ROUTER3 and wait 580s to allow LEADER to
|
||||
# expire its Router ID
|
||||
self.nodes[ROUTER3].stop()
|
||||
self.simulator.go(580)
|
||||
|
||||
# The SED1 sends an ICMPv6 Echo Request to ROUTER3 GUA PREFIX_1 address
|
||||
self.assertFalse(self.nodes[SED1].ping(router3_addr))
|
||||
self.simulator.go(1)
|
||||
|
||||
# 7 SED1: Power off SED1 and wait to allow DUT_ROUTER2 to timeout the
|
||||
# child
|
||||
self.nodes[SED1].stop()
|
||||
self.simulator.go(3)
|
||||
self.simulator.go(config.DEFAULT_CHILD_TIMEOUT)
|
||||
|
||||
# ROUTER1 sends two ICMPv6 Echo Requests to SED1 GUA PREFIX_1 address
|
||||
self.assertFalse(self.nodes[ROUTER1].ping(sed1_addr))
|
||||
self.assertFalse(self.nodes[ROUTER1].ping(sed1_addr))
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
LEADER = pv.vars['LEADER']
|
||||
ROUTER_1 = pv.vars['ROUTER_1']
|
||||
ROUTER_1_RLOC = pv.vars['ROUTER_1_RLOC']
|
||||
ROUTER_2 = pv.vars['ROUTER_2']
|
||||
ROUTER_2_RLOC = pv.vars['ROUTER_2_RLOC']
|
||||
ROUTER_2_RLOC16 = pv.vars['ROUTER_2_RLOC16']
|
||||
ROUTER_3 = pv.vars['ROUTER_3']
|
||||
SED = pv.vars['SED']
|
||||
SED_RLOC16 = pv.vars['SED_RLOC16']
|
||||
MM = pv.vars['MM_PORT']
|
||||
GUA1 = {}
|
||||
|
||||
for node in ('ROUTER_1', 'ROUTER_3', 'SED'):
|
||||
for addr in pv.vars['%s_IPADDRS' % node]:
|
||||
if addr.startswith(Bytes(GUA_1_START)):
|
||||
GUA1[node] = addr
|
||||
|
||||
# Step 1: Build the topology as described
|
||||
|
||||
for i in range(1, 4):
|
||||
pv.verify_attached('ROUTER_%d' % i, 'LEADER')
|
||||
pv.verify_attached('SED', 'ROUTER_2', 'MTD')
|
||||
|
||||
# Step 2: SED sends an ICMPv6 Echo Request to Router_3 using GUA 2001::
|
||||
# address
|
||||
# The DUT MUST generate an Address Query Request on SED’s behalf
|
||||
# to find each node’s RLOC.
|
||||
# The Address Query Request MUST be sent to the Realm-Local
|
||||
# All-Routers address (FF03::2)
|
||||
# CoAP URI-Path
|
||||
# - NON POST coap://<FF03::2>
|
||||
# CoAP Payload
|
||||
# - Target EID TLV
|
||||
# The DUT MUST receive and process the incoming Address Query
|
||||
# Response and forward the ICMPv6 Echo Reply packet to SED
|
||||
|
||||
_pkt = pkts.filter_ping_request().\
|
||||
filter_wpan_src64(SED).\
|
||||
filter_ipv6_dst(GUA1['ROUTER_3']).\
|
||||
must_next()
|
||||
pkts.filter_wpan_src64(ROUTER_2).\
|
||||
filter_RLARMA().\
|
||||
filter_coap_request(ADDR_QRY_URI, port=MM).\
|
||||
filter(lambda p: p.thread_address.tlv.target_eid == GUA1['ROUTER_3']).\
|
||||
must_next()
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(ROUTER_3).\
|
||||
filter_ipv6_dst(GUA1['SED']).\
|
||||
must_next()
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(ROUTER_2).\
|
||||
filter_wpan_dst16(SED_RLOC16).\
|
||||
must_next()
|
||||
|
||||
# Step 3: Router_1 sends an ICMPv6 Echo Request to SED using GUA 2001::
|
||||
# address
|
||||
# The DUT MUST respond to the Address Query Request with a properly
|
||||
# formatted Address Notification Message:
|
||||
# CoAP URI-Path
|
||||
# - CON POST coap://[<Address Query Source>]:MM/a/an
|
||||
# CoAP Payload
|
||||
# - ML-EID TLV
|
||||
# - RLOC16 TLV
|
||||
# - Target EID TLV
|
||||
# The IPv6 Source address MUST be the RLOC of the originator
|
||||
# The IPv6 Destination address MUST be the RLOC of the destination
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER_1).\
|
||||
filter_RLARMA().\
|
||||
filter_coap_request(ADDR_QRY_URI, port=MM).\
|
||||
filter(lambda p: p.thread_address.tlv.target_eid == GUA1['SED']).\
|
||||
must_next()
|
||||
pkts.filter_ipv6_src_dst(ROUTER_2_RLOC, ROUTER_1_RLOC).\
|
||||
filter_coap_request(ADDR_NTF_URI, port=MM).\
|
||||
filter(lambda p: {
|
||||
NL_ML_EID_TLV,
|
||||
NL_RLOC16_TLV,
|
||||
NL_TARGET_EID_TLV
|
||||
} <= set(p.coap.tlv.type) and\
|
||||
p.thread_address.tlv.target_eid == GUA1['SED'] and\
|
||||
p.thread_address.tlv.rloc16 == ROUTER_2_RLOC16
|
||||
).\
|
||||
must_next()
|
||||
_pkt = pkts.filter_ping_request().\
|
||||
filter_wpan_src64(ROUTER_1).\
|
||||
filter_ipv6_dst(GUA1['SED']).\
|
||||
must_next()
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(SED).\
|
||||
filter_ipv6_dst(GUA1['ROUTER_1']).\
|
||||
must_next()
|
||||
|
||||
# Step 5: SED sends an ICMPv6 Echo Request to Router_3 using GUA 2001::
|
||||
# address
|
||||
# The DUT MUST not send an Address Query as Router_3 address should
|
||||
# be cached.
|
||||
# The DUT MUST forward the ICMPv6 Echo Reply to SED
|
||||
|
||||
_pkt = pkts.filter_ping_request().\
|
||||
filter_wpan_src64(SED).\
|
||||
filter_ipv6_dst(GUA1['ROUTER_3']).\
|
||||
must_next()
|
||||
lstart = pkts.index
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(ROUTER_3).\
|
||||
filter_ipv6_dst(GUA1['SED']).\
|
||||
must_next()
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(ROUTER_2).\
|
||||
filter_wpan_dst16(SED_RLOC16).\
|
||||
must_next()
|
||||
lend = pkts.index
|
||||
pkts.range(lstart, lend).filter_wpan_src64(ROUTER_2).\
|
||||
filter_RLARMA().\
|
||||
filter_coap_request(ADDR_QRY_URI, port=MM).\
|
||||
must_not_next()
|
||||
|
||||
# Step 6: SED sends an ICMPv6 Echo Request to Router_3 using GUA 2001::
|
||||
# address
|
||||
# The DUT MUST update its address cache and remove all entries
|
||||
# based on Router_3’s Router ID.
|
||||
# The DUT MUST send an Address Query to discover Router_3’s RLOC address.
|
||||
pkts.filter_ping_request().\
|
||||
filter_wpan_src64(SED).\
|
||||
filter_ipv6_dst(GUA1['ROUTER_3']).\
|
||||
must_next()
|
||||
pkts.filter_wpan_src64(ROUTER_2).\
|
||||
filter_RLARMA().\
|
||||
filter_coap_request(ADDR_QRY_URI, port=MM).\
|
||||
filter(lambda p: p.thread_address.tlv.target_eid == GUA1['ROUTER_3']).\
|
||||
must_next()
|
||||
|
||||
# Step 7: Router_1 sends two ICMPv6 Echo Requests to SED using GUA 2001::
|
||||
# address
|
||||
# The DUT MUST NOT respond with an Address Notification message
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER_2).\
|
||||
filter_ipv6_dst(ROUTER_1_RLOC).\
|
||||
filter_coap_request(ADDR_NTF_URI, port=MM).\
|
||||
must_not_next()
|
||||
pkts.filter_ping_request().\
|
||||
filter_wpan_src64(ROUTER_1).\
|
||||
filter_ipv6_dst(GUA1['SED']).\
|
||||
must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,335 +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 command
|
||||
import config
|
||||
import copy
|
||||
import ipv6
|
||||
import thread_cert
|
||||
from pktverify.consts import WIRESHARK_OVERRIDE_PREFS, ADDR_QRY_URI, ADDR_NTF_URI, NL_ML_EID_TLV, NL_RLOC16_TLV, NL_TARGET_EID_TLV
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
from pktverify.bytes import Bytes
|
||||
from pktverify.addrs import Ipv6Addr
|
||||
|
||||
LEADER = 1
|
||||
BR = 2
|
||||
ROUTER1 = 3
|
||||
DUT_ROUTER2 = 4
|
||||
MED1 = 5
|
||||
|
||||
PREFIX_1 = '2003::/64'
|
||||
GUA_1_START = '2003'
|
||||
PREFIX_2 = '2004::/64'
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to validate that the DUT is able to generate
|
||||
# Address Query and Address Notification messages
|
||||
# The Border Router is configured as a SLAAC server for prefixes 2003:: & 2004::
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# BorderRouter - Leader
|
||||
# / \
|
||||
# Router_1 - Router_2(DUT)
|
||||
# |
|
||||
# MED
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Router
|
||||
|
||||
|
||||
class Cert_5_3_10_AddressQuery(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
SUPPORT_NCP = False
|
||||
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [BR, ROUTER1, DUT_ROUTER2]
|
||||
},
|
||||
BR: {
|
||||
'name': 'BR',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER]
|
||||
},
|
||||
ROUTER1: {
|
||||
'name': 'ROUTER_1',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER, DUT_ROUTER2]
|
||||
},
|
||||
DUT_ROUTER2: {
|
||||
'name': 'ROUTER_2',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER, ROUTER1, MED1]
|
||||
},
|
||||
MED1: {
|
||||
'name': 'MED',
|
||||
'is_mtd': True,
|
||||
'mode': 'rn',
|
||||
'allowlist': [DUT_ROUTER2]
|
||||
},
|
||||
}
|
||||
# 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):
|
||||
# 1 & 2
|
||||
self.nodes[LEADER].start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
|
||||
|
||||
self.nodes[BR].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[BR].get_state(), 'router')
|
||||
|
||||
# Configure two On-Mesh Prefixes on the BR
|
||||
self.nodes[BR].add_prefix(PREFIX_1, 'paros')
|
||||
self.nodes[BR].add_prefix(PREFIX_2, 'paros')
|
||||
self.nodes[BR].register_netdata()
|
||||
|
||||
self.nodes[DUT_ROUTER2].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[DUT_ROUTER2].get_state(), 'router')
|
||||
|
||||
self.nodes[ROUTER1].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
|
||||
|
||||
self.nodes[MED1].start()
|
||||
self.simulator.go(5)
|
||||
self.assertEqual(self.nodes[MED1].get_state(), 'child')
|
||||
|
||||
self.collect_rlocs()
|
||||
self.collect_rloc16s()
|
||||
self.collect_ipaddrs()
|
||||
|
||||
# 3 MED1: MED1 sends an ICMPv6 Echo Request to Router1 using GUA
|
||||
# PREFIX_1 address
|
||||
router1_addr = self.nodes[ROUTER1].get_addr(PREFIX_1)
|
||||
self.assertTrue(router1_addr is not None)
|
||||
self.assertTrue(self.nodes[MED1].ping(router1_addr))
|
||||
self.simulator.go(1)
|
||||
|
||||
# 4 BR: BR sends an ICMPv6 Echo Request to MED1 using GUA PREFIX_1
|
||||
# address
|
||||
med1_addr = self.nodes[MED1].get_addr(PREFIX_1)
|
||||
self.assertTrue(med1_addr is not None)
|
||||
self.assertTrue(self.nodes[BR].ping(med1_addr))
|
||||
self.simulator.go(1)
|
||||
|
||||
# 5 MED1: MED1 sends an ICMPv6 Echo Request to ROUTER1 using GUA PREFIX_1
|
||||
# address
|
||||
self.assertTrue(self.nodes[MED1].ping(router1_addr))
|
||||
self.simulator.go(1)
|
||||
|
||||
# 6 DUT_ROUTER2: Power off ROUTER1 and wait 580 seconds to allow the
|
||||
# LEADER to expire its Router ID
|
||||
router1_id = self.nodes[ROUTER1].get_router_id()
|
||||
self.nodes[ROUTER1].stop()
|
||||
self.simulator.go(580)
|
||||
|
||||
# Send an ICMPv6 Echo Request from MED1 to ROUTER1 GUA PREFIX_1 address
|
||||
self.assertFalse(self.nodes[MED1].ping(router1_addr))
|
||||
self.simulator.go(1)
|
||||
|
||||
# 7 MED1: Power off MED1 and wait to allow DUT_ROUTER2 to timeout the
|
||||
# child
|
||||
self.nodes[MED1].stop()
|
||||
self.simulator.go(config.MLE_END_DEVICE_TIMEOUT)
|
||||
|
||||
# BR sends two ICMPv6 Echo Requests to MED1 GUA PREFIX_1 address
|
||||
self.assertFalse(self.nodes[BR].ping(med1_addr))
|
||||
self.assertFalse(self.nodes[BR].ping(med1_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_2_RLOC = pv.vars['ROUTER_2_RLOC']
|
||||
ROUTER_2_RLOC16 = pv.vars['ROUTER_2_RLOC16']
|
||||
BR = pv.vars['BR']
|
||||
BR_RLOC = pv.vars['BR_RLOC']
|
||||
MED = pv.vars['MED']
|
||||
MED_RLOC16 = pv.vars['MED_RLOC16']
|
||||
MM = pv.vars['MM_PORT']
|
||||
GUA1 = {}
|
||||
|
||||
for node in ('ROUTER_1', 'BR', 'MED'):
|
||||
for addr in pv.vars['%s_IPADDRS' % node]:
|
||||
if addr.startswith(Bytes(GUA_1_START)):
|
||||
GUA1[node] = addr
|
||||
|
||||
# Step 2: Build the topology as described
|
||||
|
||||
pv.verify_attached('BR', 'LEADER')
|
||||
for i in (2, 1):
|
||||
pv.verify_attached('ROUTER_%d' % i, 'LEADER')
|
||||
pv.verify_attached('MED', 'ROUTER_2', 'MTD')
|
||||
|
||||
# Step 3: MED sends an ICMPv6 Echo Request to Router_1 using GUA 2003::
|
||||
# address
|
||||
# The DUT MUST generate an Address Query Request on MED’s behalf
|
||||
# to find each node’s RLOC.
|
||||
# The Address Query Request MUST be sent to the Realm-Local
|
||||
# All-Routers address (FF03::2)
|
||||
# CoAP URI-Path
|
||||
# - NON POST coap://<FF03::2>
|
||||
# CoAP Payload
|
||||
# - Target EID TLV
|
||||
# The DUT MUST receive and process the incoming Address Query
|
||||
# Response and forward the ICMPv6 Echo Request packet to Router_1
|
||||
|
||||
_pkt = pkts.filter_ping_request().\
|
||||
filter_wpan_src64(MED).\
|
||||
filter_ipv6_dst(GUA1['ROUTER_1']).\
|
||||
must_next()
|
||||
pkts.filter_wpan_src64(ROUTER_2).\
|
||||
filter_RLARMA().\
|
||||
filter_coap_request(ADDR_QRY_URI, port=MM).\
|
||||
filter(lambda p: p.thread_address.tlv.target_eid == GUA1['ROUTER_1']).\
|
||||
must_next()
|
||||
pkts.filter_ping_request(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(ROUTER_2).\
|
||||
filter_ipv6_dst(GUA1['ROUTER_1']).\
|
||||
must_next()
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(ROUTER_1).\
|
||||
filter_ipv6_dst(GUA1['MED']).\
|
||||
must_next()
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(ROUTER_2).\
|
||||
filter_wpan_dst16(MED_RLOC16).\
|
||||
must_next()
|
||||
|
||||
# Step 4: Border Router sends an ICMPv6 Echo Request to MED using GUA 2003::
|
||||
# address
|
||||
# The DUT MUST respond to the Address Query Request with a properly
|
||||
# formatted Address Notification Message:
|
||||
# CoAP URI-Path
|
||||
# - CON POST coap://[<Address Query Source>]:MM/a/an
|
||||
# CoAP Payload
|
||||
# - ML-EID TLV
|
||||
# - RLOC16 TLV
|
||||
# - Target EID TLV
|
||||
# The IPv6 Source address MUST be the RLOC of the originator
|
||||
# The IPv6 Destination address MUST be the RLOC of the destination
|
||||
|
||||
pkts.filter_wpan_src64(BR).\
|
||||
filter_RLARMA().\
|
||||
filter_coap_request(ADDR_QRY_URI, port=MM).\
|
||||
filter(lambda p: p.thread_address.tlv.target_eid == GUA1['MED']).\
|
||||
must_next()
|
||||
pkts.filter_ipv6_src_dst(ROUTER_2_RLOC, BR_RLOC).\
|
||||
filter_coap_request(ADDR_NTF_URI, port=MM).\
|
||||
filter(lambda p: {
|
||||
NL_ML_EID_TLV,
|
||||
NL_RLOC16_TLV,
|
||||
NL_TARGET_EID_TLV
|
||||
} <= set(p.coap.tlv.type) and\
|
||||
p.thread_address.tlv.target_eid == GUA1['MED'] and\
|
||||
p.thread_address.tlv.rloc16 == ROUTER_2_RLOC16
|
||||
).\
|
||||
must_next()
|
||||
_pkt = pkts.filter_ping_request().\
|
||||
filter_wpan_src64(BR).\
|
||||
filter_ipv6_dst(GUA1['MED']).\
|
||||
must_next()
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(MED).\
|
||||
filter_ipv6_dst(GUA1['BR']).\
|
||||
must_next()
|
||||
|
||||
# Step 5: MED sends an ICMPv6 Echo Request to Router_1 using GUA 2003::
|
||||
# address
|
||||
# The DUT MUST not send an Address Query as Router_1 address should
|
||||
# be cached.
|
||||
# The DUT MUST forward the ICMPv6 Echo Reply to MED
|
||||
|
||||
_pkt = pkts.filter_ping_request().\
|
||||
filter_wpan_src64(MED).\
|
||||
filter_ipv6_dst(GUA1['ROUTER_1']).\
|
||||
must_next()
|
||||
lstart = pkts.index
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(ROUTER_1).\
|
||||
filter_ipv6_dst(GUA1['MED']).\
|
||||
must_next()
|
||||
pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
filter_wpan_src64(ROUTER_2).\
|
||||
filter_wpan_dst16(MED_RLOC16).\
|
||||
must_next()
|
||||
lend = pkts.index
|
||||
pkts.range(lstart, lend).filter_wpan_src64(ROUTER_2).\
|
||||
filter_RLARMA().\
|
||||
filter_coap_request(ADDR_QRY_URI, port=MM).\
|
||||
must_not_next()
|
||||
|
||||
# Step 6: MED sends an ICMPv6 Echo Request to Router_1 using GUA 2003::
|
||||
# address
|
||||
# The DUT MUST update its address cache and remove all entries
|
||||
# based on Router_1’s Router ID.
|
||||
# The DUT MUST send an Address Query to discover Router_1’s RLOC address.
|
||||
|
||||
pkts.filter_ping_request().\
|
||||
filter_wpan_src64(MED).\
|
||||
filter_ipv6_dst(GUA1['ROUTER_1']).\
|
||||
must_next()
|
||||
pkts.filter_wpan_src64(ROUTER_2).\
|
||||
filter_RLARMA().\
|
||||
filter_coap_request(ADDR_QRY_URI, port=MM).\
|
||||
filter(lambda p: p.thread_address.tlv.target_eid == GUA1['ROUTER_1']).\
|
||||
must_next()
|
||||
|
||||
# Step 7: Border Router sends two ICMPv6 Echo Requests to MED using GUA 2003::
|
||||
# address
|
||||
# The DUT MUST NOT respond with an Address Notification message
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER_2).\
|
||||
filter_ipv6_dst(BR_RLOC).\
|
||||
filter_coap_request(ADDR_NTF_URI, port=MM).\
|
||||
must_not_next()
|
||||
pkts.filter_ping_request().\
|
||||
filter_wpan_src64(BR).\
|
||||
filter_ipv6_dst(GUA1['MED']).\
|
||||
must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,199 +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 command
|
||||
import config
|
||||
import thread_cert
|
||||
from pktverify.consts import ADDR_QRY_URI, ADDR_NTF_URI, NL_ML_EID_TLV, NL_RLOC16_TLV, NL_TARGET_EID_TLV
|
||||
from pktverify.packet_verifier import PacketVerifier
|
||||
from pktverify.bytes import Bytes
|
||||
from pktverify.addrs import Ipv6Addr
|
||||
|
||||
LEADER = 1
|
||||
DUT_ROUTER1 = 2
|
||||
MED1 = 3
|
||||
X = 'fd00:db8:0000:0000:aa55:aa55:aa55:aa55'
|
||||
|
||||
# Test Purpose and Description:
|
||||
# -----------------------------
|
||||
# The purpose of this test case is to validate the way AQ_TIMEOUT and
|
||||
# AQ_RETRY_TIMEOUT intervals are used in the Address Query transmission
|
||||
# algorithm.
|
||||
#
|
||||
# Test Topology:
|
||||
# -------------
|
||||
# Leader
|
||||
# |
|
||||
# Router(DUT)
|
||||
# |
|
||||
# MED
|
||||
#
|
||||
# DUT Types:
|
||||
# ----------
|
||||
# Router
|
||||
|
||||
|
||||
class Cert_5_3_11_AddressQueryTimeoutIntervals(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [DUT_ROUTER1]
|
||||
},
|
||||
DUT_ROUTER1: {
|
||||
'name': 'ROUTER',
|
||||
'mode': 'rdn',
|
||||
'allowlist': [LEADER, MED1]
|
||||
},
|
||||
MED1: {
|
||||
'name': 'MED',
|
||||
'is_mtd': True,
|
||||
'mode': 'rn',
|
||||
'allowlist': [DUT_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[DUT_ROUTER1].start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(self.nodes[DUT_ROUTER1].get_state(), 'router')
|
||||
|
||||
self.nodes[MED1].start()
|
||||
self.simulator.go(5)
|
||||
self.assertEqual(self.nodes[MED1].get_state(), 'child')
|
||||
|
||||
self.collect_rlocs()
|
||||
|
||||
# 2 MED1: MED1 sends an ICMPv6 Echo Request to a non-existent
|
||||
# mesh-local address X
|
||||
self.assertFalse(self.nodes[MED1].ping(X))
|
||||
|
||||
self.simulator.go(config.AQ_TIMEOUT)
|
||||
|
||||
# 3 MED1: MED1 sends an ICMPv6 Echo Request to a non-existent mesh-local address X before
|
||||
# ADDRESS_QUERY_INITIAL_RETRY_DELAY timeout expires
|
||||
self.assertFalse(self.nodes[MED1].ping(X))
|
||||
|
||||
self.simulator.go(config.ADDRESS_QUERY_INITIAL_RETRY_DELAY)
|
||||
|
||||
# 4 MED1: MED1 sends an ICMPv6 Echo Request to a non-existent mesh-local address X after
|
||||
# ADDRESS_QUERY_INITIAL_RETRY_DELAY timeout expired
|
||||
self.assertFalse(self.nodes[MED1].ping(X))
|
||||
|
||||
def verify(self, pv):
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
LEADER = pv.vars['LEADER']
|
||||
ROUTER = pv.vars['ROUTER']
|
||||
ROUTER_RLOC = pv.vars['ROUTER_RLOC']
|
||||
MED = pv.vars['MED']
|
||||
MM = pv.vars['MM_PORT']
|
||||
|
||||
# Step 1: Build the topology as described
|
||||
|
||||
pv.verify_attached('ROUTER', 'LEADER')
|
||||
pv.verify_attached('MED', 'ROUTER', 'MTD')
|
||||
|
||||
# Step 2: MED sends an ICMPv6 Echo Request to a nonexistent mesh-local
|
||||
# address X
|
||||
# The DUT MUST generate an Address Query Request on MED’s behalf
|
||||
# The Address Query Request MUST be sent to the Realm-Local
|
||||
# All-Routers address (FF03::2)
|
||||
# CoAP URI-Path
|
||||
# - NON POST coap://<FF03::2>
|
||||
# CoAP Payload
|
||||
# - Target EID TLV – non-existent mesh-local
|
||||
# An Address Query Notification MUST NOT be received within
|
||||
# AQ_TIMEOUT interval.
|
||||
|
||||
_pkt = pkts.filter_ping_request().\
|
||||
filter_wpan_src64(MED).\
|
||||
filter_ipv6_dst(Ipv6Addr(X)).\
|
||||
must_next()
|
||||
step2_start = pkts.index
|
||||
|
||||
pkts.filter_wpan_src64(ROUTER).\
|
||||
filter_RLARMA().\
|
||||
filter_coap_request(ADDR_QRY_URI, port=MM).\
|
||||
filter(lambda p: p.thread_address.tlv.target_eid == Ipv6Addr(X)).\
|
||||
must_next()
|
||||
|
||||
# Step 3: MED sends an ICMPv6 Echo Request to a nonexistent mesh-local
|
||||
# address X before ADDRESS_QUERY_INITIAL_RETRY_DELAY timeout
|
||||
# expired
|
||||
# The DUT MUST NOT initiate a new Address Query frame
|
||||
|
||||
pkts.filter_ping_request().\
|
||||
filter_wpan_src64(MED).\
|
||||
filter_ipv6_dst(Ipv6Addr(X)).\
|
||||
must_next()
|
||||
step2_end = pkts.index
|
||||
|
||||
pkts.range(step2_start, step2_end).filter_ipv6_dst(ROUTER_RLOC).\
|
||||
filter_coap_request(ADDR_NTF_URI, port=MM).\
|
||||
must_not_next()
|
||||
|
||||
# Step 4: MED sends an ICMPv6 Echo Request to a nonexistent mesh-local
|
||||
# address X after ADDRESS_QUERY_INITIAL_RETRY_DELAY timeout
|
||||
# expired
|
||||
# The DUT MUST generate an Address Query Request on MED’s behalf
|
||||
# The Address Query Request MUST be sent to the Realm-Local
|
||||
# All-Routers address (FF03::2)
|
||||
# CoAP URI-Path
|
||||
# - NON POST coap://<FF03::2>
|
||||
# CoAP Payload
|
||||
# - Target EID TLV – non-existent mesh-local
|
||||
|
||||
pkts.filter_ping_request().\
|
||||
filter_wpan_src64(MED).\
|
||||
filter_ipv6_dst(Ipv6Addr(X)).\
|
||||
must_next()
|
||||
step3_end = pkts.index
|
||||
pkts.range(step2_end, step3_end).filter_wpan_src64(ROUTER).\
|
||||
filter_RLARMA().\
|
||||
filter_coap_request(ADDR_QRY_URI, port=MM).\
|
||||
must_not_next()
|
||||
pkts.filter_wpan_src64(ROUTER).\
|
||||
filter_RLARMA().\
|
||||
filter_coap_request(ADDR_QRY_URI, port=MM).\
|
||||
filter(lambda p: p.thread_address.tlv.target_eid == Ipv6Addr(X)).\
|
||||
must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user