[thread-cert] refactor case 5.1.9 using pktverify (#5743)
diff --git a/tests/scripts/thread-cert/Cert_5_1_09_REEDAttachConnectivity.py b/tests/scripts/thread-cert/Cert_5_1_09_REEDAttachConnectivity.py
index cea0d98..9482cad 100755
--- a/tests/scripts/thread-cert/Cert_5_1_09_REEDAttachConnectivity.py
+++ b/tests/scripts/thread-cert/Cert_5_1_09_REEDAttachConnectivity.py
@@ -32,44 +32,71 @@
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
-REED0 = 3
-REED1 = 4
+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',
'panid': 0xface,
- 'allowlist': [ROUTER1, REED0, REED1]
+ 'allowlist': [ROUTER1, REED1, REED2]
},
ROUTER1: {
+ 'name': 'ROUTER_1',
'mode': 'rdn',
'panid': 0xface,
'router_selection_jitter': 1,
'allowlist': [LEADER, REED1]
},
- REED0: {
- 'mode': 'rdn',
- 'panid': 0xface,
- 'router_upgrade_threshold': 0,
- 'allowlist': [LEADER, ROUTER2]
- },
REED1: {
+ 'name': 'REED_1',
'mode': 'rdn',
'panid': 0xface,
'router_upgrade_threshold': 0,
'allowlist': [LEADER, ROUTER1, ROUTER2]
},
+ REED2: {
+ 'name': 'REED_2',
+ 'mode': 'rdn',
+ 'panid': 0xface,
+ 'router_upgrade_threshold': 0,
+ 'allowlist': [LEADER, ROUTER2]
+ },
ROUTER2: {
+ 'name': 'ROUTER_2',
'mode': 'rdn',
'panid': 0xface,
'router_selection_jitter': 1,
- 'allowlist': [REED0, REED1]
+ 'allowlist': [REED1, REED2]
},
}
@@ -84,8 +111,8 @@
self.simulator.go(5)
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
- self.assertEqual(self.nodes[REED0].get_state(), 'child')
self.assertEqual(self.nodes[REED1].get_state(), 'child')
+ self.assertEqual(self.nodes[REED2].get_state(), 'child')
self.simulator.go(config.MAX_ADVERTISEMENT_INTERVAL)
@@ -94,65 +121,160 @@
self.assertEqual(self.nodes[ROUTER2].get_state(), 'router')
self.assertEqual(self.nodes[REED1].get_state(), 'router')
- leader_messages = self.simulator.get_messages_sent_by(LEADER)
- router1_messages = self.simulator.get_messages_sent_by(ROUTER1)
- reed0_messages = self.simulator.get_messages_sent_by(REED0)
- reed1_messages = self.simulator.get_messages_sent_by(REED1)
- router2_messages = self.simulator.get_messages_sent_by(ROUTER2)
+ def verify(self, pv):
+ pkts = pv.pkts
+ pv.summary.show()
- # 1 - Leader, Router1, REED1, REED2
- leader_messages.next_mle_message(mle.CommandType.ADVERTISEMENT)
- router1_messages.next_mle_message(mle.CommandType.ADVERTISEMENT)
+ LEADER = pv.vars['LEADER']
+ REED_1 = pv.vars['REED_1']
+ ROUTER_1 = pv.vars['ROUTER_1']
+ ROUTER_2 = pv.vars['ROUTER_2']
- # 2 - Router2
- msg = router2_messages.next_mle_message(mle.CommandType.PARENT_REQUEST)
- msg.assertSentWithHopLimit(255)
- msg.assertSentToDestinationAddress("ff02::2")
- msg.assertMleMessageContainsTlv(mle.Mode)
- msg.assertMleMessageContainsTlv(mle.Challenge)
- msg.assertMleMessageContainsTlv(mle.ScanMask)
- msg.assertMleMessageContainsTlv(mle.Version)
+ # 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')
- scan_mask_tlv = msg.get_mle_message_tlv(mle.ScanMask)
- self.assertEqual(1, scan_mask_tlv.router)
- self.assertEqual(0, scan_mask_tlv.end_device)
+ # 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.
- # 4 - Router2
- msg = router2_messages.next_mle_message(mle.CommandType.PARENT_REQUEST)
- msg.assertSentWithHopLimit(255)
- msg.assertSentToDestinationAddress("ff02::2")
- msg.assertMleMessageContainsTlv(mle.Mode)
- msg.assertMleMessageContainsTlv(mle.Challenge)
- msg.assertMleMessageContainsTlv(mle.ScanMask)
- msg.assertMleMessageContainsTlv(mle.Version)
+ 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
- scan_mask_tlv = msg.get_mle_message_tlv(mle.ScanMask)
- self.assertEqual(1, scan_mask_tlv.router)
- self.assertEqual(1, scan_mask_tlv.end_device)
+ # 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.
- # 5 - REED1, REED2
- msg = reed0_messages.next_mle_message(mle.CommandType.PARENT_RESPONSE)
- connectivity_tlv_reed0 = msg.get_mle_message_tlv(mle.Connectivity)
+ 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
- msg = reed1_messages.next_mle_message(mle.CommandType.PARENT_RESPONSE)
- connectivity_tlv_reed1 = msg.get_mle_message_tlv(mle.Connectivity)
+ # Step 4: REED_1 and REED_2 no response to Parent Request meant for all routers.
- self.assertGreater(
- connectivity_tlv_reed1.link_quality_3,
- connectivity_tlv_reed0.link_quality_3,
- )
+ 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()
- # 6 - Router2
- msg = router2_messages.next_mle_message(mle.CommandType.CHILD_ID_REQUEST)
- msg.assertSentToNode(self.nodes[REED1])
- msg.assertMleMessageContainsTlv(mle.Response)
- msg.assertMleMessageContainsTlv(mle.LinkLayerFrameCounter)
- msg.assertMleMessageContainsOptionalTlv(mle.MleFrameCounter)
- msg.assertMleMessageContainsTlv(mle.Mode)
- msg.assertMleMessageContainsTlv(mle.Timeout)
- msg.assertMleMessageContainsTlv(mle.Version)
- msg.assertMleMessageContainsTlv(mle.TlvRequest)
- msg.assertMleMessageDoesNotContainTlv(mle.AddressRegistration)
+ # 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__':