From 1e08cea5854f37be1cc43d82e899f11e37c1e0a3 Mon Sep 17 00:00:00 2001 From: Jing Ma Date: Fri, 11 Sep 2020 23:49:48 +0800 Subject: [PATCH] [thread-cert] refactor case 5.6.6 and 5.6.9 using pktverify (#5371) --- ...03_NetworkDataRegisterAfterAttachLeader.py | 2 +- ...04_NetworkDataRegisterAfterAttachRouter.py | 2 +- .../Cert_5_6_06_NetworkDataExpiration.py | 121 ++++++++++++++---- .../Cert_5_6_09_NetworkDataForwarding.py | 112 +++++++++++++++- .../Cert_7_1_02_BorderRouterAsRouter.py | 2 +- .../Cert_7_1_04_BorderRouterAsRouter.py | 2 +- tests/scripts/thread-cert/node.py | 7 +- tests/scripts/thread-cert/pktverify/consts.py | 9 ++ .../thread-cert/pktverify/layer_fields.py | 2 +- 9 files changed, 220 insertions(+), 39 deletions(-) diff --git a/tests/scripts/thread-cert/Cert_5_6_03_NetworkDataRegisterAfterAttachLeader.py b/tests/scripts/thread-cert/Cert_5_6_03_NetworkDataRegisterAfterAttachLeader.py index cae9ba83a..f8a38d7ff 100755 --- a/tests/scripts/thread-cert/Cert_5_6_03_NetworkDataRegisterAfterAttachLeader.py +++ b/tests/scripts/thread-cert/Cert_5_6_03_NetworkDataRegisterAfterAttachLeader.py @@ -148,7 +148,7 @@ class Cert_5_6_3_NetworkDataRegisterAfterAttachLeader(thread_cert.TestCase): p.mle.tlv.type) and {Ipv6Addr('2001:2:0:1::')} == set(p.thread_nwd.tlv.prefix) and p.thread_nwd.tlv. border_router.flag.p == [1] and p.thread_nwd.tlv.border_router.flag.s == [1] and p.thread_nwd.tlv. border_router.flag.r == [1] and p.thread_nwd.tlv.border_router.flag.o == [1] and p.thread_nwd.tlv.stable == - [1, 1, 1] and p.thread_nwd.tlv.border_router_16 == 0xFFFE) + [1, 1, 1] and p.thread_nwd.tlv.border_router_16 == [0xFFFE]) # Step 8: The DUT MUST send a unicast MLE Child Update # Response to SED_1 diff --git a/tests/scripts/thread-cert/Cert_5_6_04_NetworkDataRegisterAfterAttachRouter.py b/tests/scripts/thread-cert/Cert_5_6_04_NetworkDataRegisterAfterAttachRouter.py index e5f132f25..861cadbb2 100755 --- a/tests/scripts/thread-cert/Cert_5_6_04_NetworkDataRegisterAfterAttachRouter.py +++ b/tests/scripts/thread-cert/Cert_5_6_04_NetworkDataRegisterAfterAttachRouter.py @@ -155,7 +155,7 @@ class Cert_5_6_4_NetworkDataRegisterAfterAttachRouter(thread_cert.TestCase): p.mle.tlv.type) and {Ipv6Addr('2001:2:0:1::')} == set(p.thread_nwd.tlv.prefix) and p.thread_nwd.tlv. border_router.flag.p == [1] and p.thread_nwd.tlv.border_router.flag.s == [1] and p.thread_nwd.tlv. border_router.flag.r == [1] and p.thread_nwd.tlv.border_router.flag.o == [1] and p.thread_nwd.tlv.stable == - [1, 1, 1] and p.thread_nwd.tlv.border_router_16 == 0xFFFE) + [1, 1, 1] and p.thread_nwd.tlv.border_router_16 == [0xFFFE]) # Step 11: The DUT MUST send a unicast MLE Child Update # Response to SED_1 diff --git a/tests/scripts/thread-cert/Cert_5_6_06_NetworkDataExpiration.py b/tests/scripts/thread-cert/Cert_5_6_06_NetworkDataExpiration.py index 2dd5235d4..f77e8ae44 100755 --- a/tests/scripts/thread-cert/Cert_5_6_06_NetworkDataExpiration.py +++ b/tests/scripts/thread-cert/Cert_5_6_06_NetworkDataExpiration.py @@ -31,6 +31,9 @@ import unittest import config import thread_cert +from pktverify.consts import MLE_ADVERTISEMENT, SVR_DATA_URI, MLE_DATA_RESPONSE, MLE_CHILD_ID_RESPONSE, MLE_CHILD_UPDATE_REQUEST, MLE_CHILD_UPDATE_RESPONSE, SOURCE_ADDRESS_TLV, MODE_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV, ADDRESS_REGISTRATION_TLV, NWD_SERVICE_TLV, NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV, LINK_LOCAL_ALL_NODES_MULTICAST_ADDRESS +from pktverify.packet_verifier import PacketVerifier +from pktverify.addrs import Ipv6Addr LEADER = 1 ROUTER = 2 @@ -43,28 +46,32 @@ MTDS = [ED1, SED1] class Cert_5_6_6_NetworkDataExpiration(thread_cert.TestCase): TOPOLOGY = { LEADER: { + 'name': 'LEADER', 'mode': 'rsdn', 'panid': 0xface, - 'whitelist': [ROUTER] + 'whitelist': [ROUTER, ED1, SED1] }, ROUTER: { + 'name': 'ROUTER', 'mode': 'rsdn', 'panid': 0xface, 'router_selection_jitter': 1, - 'whitelist': [LEADER, ED1, SED1] + 'whitelist': [LEADER] }, ED1: { + 'name': 'MED', 'is_mtd': True, 'mode': 'rsn', 'panid': 0xface, - 'whitelist': [ROUTER] + 'whitelist': [LEADER] }, SED1: { + 'name': 'SED', 'is_mtd': True, 'mode': 's', 'panid': 0xface, 'timeout': config.DEFAULT_CHILD_TIMEOUT, - 'whitelist': [ROUTER] + 'whitelist': [LEADER] }, } @@ -85,34 +92,15 @@ class Cert_5_6_6_NetworkDataExpiration(thread_cert.TestCase): self.simulator.go(5) self.assertEqual(self.nodes[SED1].get_state(), 'child') + self.collect_rlocs() self.nodes[ROUTER].add_prefix('2001:2:0:1::/64', 'paros') self.nodes[ROUTER].add_prefix('2001:2:0:2::/64', 'paro') + self.nodes[ROUTER].add_prefix('2001:2:0:3::/64', 'paos') self.nodes[ROUTER].register_netdata() # Set lowpan context of sniffer self.simulator.set_lowpan_context(1, '2001:2:0:1::/64') self.simulator.set_lowpan_context(2, '2001:2:0:2::/64') - - self.simulator.go(10) - - addrs = self.nodes[ED1].get_addrs() - self.assertTrue(any('2001:2:0:1' in addr[0:10] for addr in addrs)) - self.assertTrue(any('2001:2:0:2' in addr[0:10] for addr in addrs)) - for addr in addrs: - if addr[0:3] == '200': - self.assertTrue(self.nodes[LEADER].ping(addr)) - - addrs = self.nodes[SED1].get_addrs() - self.assertTrue(any('2001:2:0:1' in addr[0:10] for addr in addrs)) - self.assertFalse(any('2001:2:0:2' in addr[0:10] for addr in addrs)) - for addr in addrs: - if addr[0:3] == '200': - self.assertTrue(self.nodes[LEADER].ping(addr)) - - self.nodes[ROUTER].add_prefix('2001:2:0:3::/64', 'paos') - self.nodes[ROUTER].register_netdata() - - # Set lowpan context of sniffer self.simulator.set_lowpan_context(3, '2001:2:0:3::/64') self.simulator.go(10) @@ -154,6 +142,89 @@ class Cert_5_6_6_NetworkDataExpiration(thread_cert.TestCase): self.assertTrue(self.nodes[LEADER].ping(addr)) self.nodes[ROUTER].stop() + self.simulator.go(10) + + def verify(self, pv): + pkts = pv.pkts + pv.summary.show() + + LEADER = pv.vars['LEADER'] + ROUTER = pv.vars['ROUTER'] + MED = pv.vars['MED'] + SED = pv.vars['SED'] + _lpkts = pkts.filter_wpan_src64(LEADER) + + # Step 1: Ensure the topology is formed correctly + _lpkts.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).filter_wpan_dst64(SED).must_next() + + # Step 4: The DUT Automatically sends a CoAP Response frame to Router_1 + _lpkts.copy().filter_ipv6_dst(pv.vars['ROUTER_RLOC']).filter_coap_ack(SVR_DATA_URI).must_next() + + # Step 5: The DUT MUST send a multicast MLE Data Response with + # the new network information collected from Router_1 + _lpkts.filter_mle_cmd(MLE_DATA_RESPONSE).must_next().must_verify( + lambda p: { + NWD_SERVICE_TLV, NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV, NWD_PREFIX_TLV, + NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV, NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV + } == set(p.thread_nwd.tlv.type) and { + Ipv6Addr('2001:2:0:1::'), Ipv6Addr('2001:2:0:2::'), + Ipv6Addr('2001:2:0:3::') + } == set(p.thread_nwd.tlv.prefix) and p.thread_nwd.tlv.stable == [0, 1, 1, 1, 0, 0, 0, 1, 1, 1]) + _lpkts_med = _lpkts.copy() + _lpkts_sed = _lpkts.copy() + + # Step 7: The DUT MUST send a unicast MLE Child Update Response to MED_1 + _lpkts_med.filter_wpan_dst64(MED).filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).must_next().must_verify( + lambda p: {SOURCE_ADDRESS_TLV, MODE_TLV, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV} < set(p.mle.tlv.type)) + + # Step 8: The DUT MUST send a unicast MLE Child Update Request to SED_1 + _lpkts_sed.filter_wpan_dst64(SED).filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).must_next().must_verify( + lambda p: {SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV} == set( + p.mle.tlv.type) and { + NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV, NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV, + NWD_6LOWPAN_ID_TLV + } == set(p.thread_nwd.tlv.type) and { + Ipv6Addr('2001:2:0:1::'), Ipv6Addr('2001:2:0:3::') + } == set(p.thread_nwd.tlv.prefix) and {0xFFFE, 0xFFFE} == set(p.thread_nwd.tlv.border_router_16)) + + # Step 10: The DUT MUST send a unicast MLE Child Update Response to SED_1 + _pkt = _lpkts_sed.filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).filter_wpan_dst64(SED).must_next() + _pkt.must_verify( + lambda p: {SOURCE_ADDRESS_TLV, MODE_TLV, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV} < set(p.mle.tlv.type)) + + # Step 12: The DUT updates Router ID Set and removes Router_1 + # from Network Data TLV after Router_1 power off + # Step 13: The DUT MUST multicast a MLE Data Response with the + # new network information + _lpkts.filter_mle_cmd(MLE_DATA_RESPONSE).filter_ipv6_dst(LINK_LOCAL_ALL_NODES_MULTICAST_ADDRESS).must_next( + ).must_verify( + lambda p: { + NWD_SERVICE_TLV, NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV, NWD_PREFIX_TLV, + NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV, NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV + } == set(p.thread_nwd.tlv.type) and + {Ipv6Addr('2001:2:0:1::'), Ipv6Addr('2001:2:0:2::'), + Ipv6Addr('2001:2:0:3::')} == set(p.thread_nwd.tlv.prefix) and p.mle.tlv.leader_data.data_version == _pkt. + mle.tlv.leader_data.data_version + 1 and p.mle.tlv.leader_data.stable_data_version == _pkt.mle.tlv. + leader_data.stable_data_version + 1) + + _lpkts_med = _lpkts.copy() + _lpkts_sed = _lpkts.copy() + + # Step 15: The DUT MUST send a unicast MLE Child Update Response to MED_1 + _lpkts_med.filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).filter_wpan_dst64(MED).must_next().must_verify( + lambda p: {SOURCE_ADDRESS_TLV, MODE_TLV, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV} < set( + p.mle.tlv.type) and p.mle.tlv.leader_data.data_version == _pkt.mle.tlv.leader_data.data_version + 1 and + p.mle.tlv.leader_data.stable_data_version == _pkt.mle.tlv.leader_data.stable_data_version + 1) + + # Step 16: The DUT MUST send a unicast MLE Child Update Request to SED_1 + _lpkts_sed.filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).filter_wpan_dst64(SED).must_next().must_verify( + lambda p: {SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV} == set( + p.mle.tlv.type) and p.mle.tlv.leader_data.data_version == _pkt.mle.tlv.leader_data.data_version + 1 and + p.mle.tlv.leader_data.stable_data_version == _pkt.mle.tlv.leader_data.stable_data_version + 1) + + # Step 18: The DUT MUST send a unicast MLE Child Update Response to SED_1 + _lpkts_sed.filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).filter_wpan_dst64(SED).must_next().must_verify( + lambda p: {SOURCE_ADDRESS_TLV, MODE_TLV, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV} < set(p.mle.tlv.type)) if __name__ == '__main__': diff --git a/tests/scripts/thread-cert/Cert_5_6_09_NetworkDataForwarding.py b/tests/scripts/thread-cert/Cert_5_6_09_NetworkDataForwarding.py index 8e4668e64..9bd4f77ce 100755 --- a/tests/scripts/thread-cert/Cert_5_6_09_NetworkDataForwarding.py +++ b/tests/scripts/thread-cert/Cert_5_6_09_NetworkDataForwarding.py @@ -31,6 +31,9 @@ import unittest import config import thread_cert +from pktverify.consts import MLE_ADVERTISEMENT, MLE_DATA_RESPONSE, MLE_CHILD_ID_RESPONSE, MLE_CHILD_UPDATE_REQUEST, MLE_CHILD_UPDATE_RESPONSE, SOURCE_ADDRESS_TLV, MODE_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV, ADDRESS_REGISTRATION_TLV, NWD_SERVICE_TLV, NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV, NWD_HAS_ROUTER_TLV, LINK_LOCAL_ALL_NODES_MULTICAST_ADDRESS +from pktverify.packet_verifier import PacketVerifier +from pktverify.addrs import Ipv6Addr LEADER = 1 ROUTER1 = 2 @@ -44,29 +47,34 @@ MTDS = [ED, SED] class Cert_5_6_9_NetworkDataForwarding(thread_cert.TestCase): TOPOLOGY = { LEADER: { + 'name': 'LEADER', 'mode': 'rsdn', 'panid': 0xface, 'whitelist': [ROUTER1, ROUTER2] }, ROUTER1: { + 'name': 'ROUTER_1', 'mode': 'rsdn', 'panid': 0xface, 'router_selection_jitter': 1, 'whitelist': [LEADER, ED, SED] }, ROUTER2: { + 'name': 'ROUTER_2', 'mode': 'rsdn', 'panid': 0xface, 'router_selection_jitter': 1, 'whitelist': [LEADER] }, ED: { + 'name': 'MED', 'is_mtd': True, 'mode': 'rsn', 'panid': 0xface, 'whitelist': [ROUTER1] }, SED: { + 'name': 'SED', 'is_mtd': True, 'mode': 's', 'panid': 0xface, @@ -96,8 +104,10 @@ class Cert_5_6_9_NetworkDataForwarding(thread_cert.TestCase): self.simulator.go(5) self.assertEqual(self.nodes[SED].get_state(), 'child') - self.nodes[LEADER].add_prefix('2001:2:0:1::/64', 'paros', 'med') - self.nodes[LEADER].add_route('2001:2:0:2::/64', 'med') + self.collect_rloc16s() + self.collect_ipaddrs() + self.nodes[LEADER].add_prefix('2001:2:0:1::/64', 'aros', 'med') + self.nodes[LEADER].add_route('2001:2:0:2::/64', stable=True, prf='med') self.nodes[LEADER].register_netdata() # Set lowpan context of sniffer @@ -105,10 +115,10 @@ class Cert_5_6_9_NetworkDataForwarding(thread_cert.TestCase): self.simulator.go(10) - self.nodes[ROUTER2].add_prefix('2001:2:0:1::/64', 'paros', 'low') - self.nodes[ROUTER2].add_route('2001:2:0:2::/64', 'high') + self.nodes[ROUTER2].add_prefix('2001:2:0:1::/64', 'aos', 'med') + self.nodes[ROUTER2].add_route('2001:2:0:2::/64', stable=True, prf='high') self.nodes[ROUTER2].register_netdata() - self.simulator.go(10) + self.simulator.go(15) self.assertFalse(self.nodes[SED].ping('2001:2:0:2::1')) @@ -117,17 +127,105 @@ class Cert_5_6_9_NetworkDataForwarding(thread_cert.TestCase): self.nodes[ROUTER2].remove_prefix('2001:2:0:1::/64') self.nodes[ROUTER2].add_prefix('2001:2:0:1::/64', 'paros', 'high') self.nodes[ROUTER2].register_netdata() - self.simulator.go(10) + self.simulator.go(15) self.assertFalse(self.nodes[SED].ping('2007::1')) self.nodes[ROUTER2].remove_prefix('2001:2:0:1::/64') self.nodes[ROUTER2].add_prefix('2001:2:0:1::/64', 'paros', 'med') self.nodes[ROUTER2].register_netdata() - self.simulator.go(10) + self.simulator.go(15) self.assertFalse(self.nodes[SED].ping('2007::1')) + def verify(self, pv): + pkts = pv.pkts + pv.summary.show() + + ROUTER_1 = pv.vars['ROUTER_1'] + MED = pv.vars['MED'] + SED = pv.vars['SED'] + _rpkts = pkts.filter_wpan_src64(ROUTER_1) + + # Step 1: Ensure the topology is formed correctly + _rpkts.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).filter_wpan_dst64(SED).must_next() + + # Step 4: The DUT MUST send a multicast MLE Data Response with + # the new network information + _rpkts.filter_mle_cmd(MLE_DATA_RESPONSE).filter_ipv6_dst(LINK_LOCAL_ALL_NODES_MULTICAST_ADDRESS).must_next( + ).must_verify(lambda p: {Ipv6Addr('2001:2:0:1::'), Ipv6Addr('2001:2:0:2::')} == set( + p.thread_nwd.tlv.prefix) and p.thread_nwd.tlv.border_router.flag.p == [0] and p.thread_nwd.tlv. + border_router.flag.s == [1] and p.thread_nwd.tlv.border_router.flag.r == [1] and p.thread_nwd.tlv + .border_router.flag.o == [1] and p.thread_nwd.tlv.stable == [0, 1, 1, 1, 1, 1]) + + # Step 5: The DUT MUST send a unicast MLE Child Update + # Request to SED_1 + _rpkts.filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).filter_wpan_dst64(SED).must_next( + ).must_verify(lambda p: {SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV} == set( + p.mle.tlv.type + ) and {NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV, NWD_PREFIX_TLV, NWD_HAS_ROUTER_TLV} == set( + p.thread_nwd.tlv.type) and {Ipv6Addr('2001:2:0:1::'), Ipv6Addr('2001:2:0:2::')} == set( + p.thread_nwd.tlv.prefix) and {0xFFFE, 0xFFFE} == set(p.thread_nwd.tlv.border_router_16)) + + # Step 6: The DUT MUST forward the SED_1 ICMPv6 Echo Request to Router_2 + # due to higher preference + router1_rloc16 = pv.vars['ROUTER_1_RLOC16'] + leader_rloc16 = pv.vars['LEADER_RLOC16'] + _rpkts.filter_ping_request().filter_ipv6_dst('2001:2:0:2::1').must_next().must_verify( + lambda p: p.wpan.dst16 == leader_rloc16 and p.wpan.src16 == router1_rloc16) + + # Step 7: The DUT MUST forward the MED_1 ICMPv6 Echo Request to the + # Leader due to default route + _rpkts.filter_ping_request().filter_ipv6_dst('2007::1').must_next().must_verify( + lambda p: p.wpan.dst16 == leader_rloc16 and p.wpan.src16 == router1_rloc16) + + # Step 9: The DUT MUST send a multicast MLE Data Response with + # the new network information + _rpkts.filter_mle_cmd(MLE_DATA_RESPONSE).filter_ipv6_dst(LINK_LOCAL_ALL_NODES_MULTICAST_ADDRESS).must_next( + ).must_verify(lambda p: { + NWD_SERVICE_TLV, NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV, NWD_PREFIX_TLV, + NWD_HAS_ROUTER_TLV + } == set(p.thread_nwd.tlv.type) and { + Ipv6Addr('2001:2:0:1::'), Ipv6Addr('2001:2:0:2::') + } == set(p.thread_nwd.tlv.prefix) and p.thread_nwd.tlv.border_router.flag.p == [0, 1] and p.thread_nwd.tlv. + border_router.flag.s == [1, 1] and p.thread_nwd.tlv.border_router.flag.r == [1, 1] and p. + thread_nwd.tlv.border_router.flag.o == [1, 1] and p.thread_nwd.tlv.stable == [0, 1, 1, 1, 1, 1]) + + # Step 10: The DUT MUST send a unicast MLE Child Update Request to SED_1 + _rpkts.filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).filter_wpan_dst64(SED).must_next( + ).must_verify(lambda p: {SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV} == set( + p.mle.tlv.type + ) and {NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV, NWD_PREFIX_TLV, NWD_HAS_ROUTER_TLV} == set( + p.thread_nwd.tlv.type) and {Ipv6Addr('2001:2:0:1::'), Ipv6Addr('2001:2:0:2::')} == set( + p.thread_nwd.tlv.prefix) and {0xFFFE, 0xFFFE} == set(p.thread_nwd.tlv.border_router_16)) + + # Step 11: The DUT MUST forward the SED_1 ICMPv6 Echo Request to Router_2 + # due to higher preference + _rpkts.filter_ping_request().filter_ipv6_dst('2007::1').must_next().must_verify( + lambda p: p.wpan.dst16 == leader_rloc16 and p.wpan.src16 == router1_rloc16) + + # Step 13: The DUT MUST send a multicast MLE Data Response with + # the new network information + _rpkts.filter_mle_cmd(MLE_DATA_RESPONSE).filter_ipv6_dst( + LINK_LOCAL_ALL_NODES_MULTICAST_ADDRESS).must_next().must_verify(lambda p: { + NWD_SERVICE_TLV, NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV, NWD_PREFIX_TLV, + NWD_HAS_ROUTER_TLV + } == set(p.thread_nwd.tlv.type) and {Ipv6Addr('2001:2:0:1::'), + Ipv6Addr('2001:2:0:2::')} == set(p.thread_nwd.tlv.prefix)) + + # Step 14: The DUT MUST send a unicast MLE Child Update Request to SED_1 + _rpkts.filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).filter_wpan_dst64(SED).must_next( + ).must_verify(lambda p: {SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, NETWORK_DATA_TLV, ACTIVE_TIMESTAMP_TLV} == set( + p.mle.tlv.type + ) and {NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV, NWD_PREFIX_TLV, NWD_HAS_ROUTER_TLV} == set( + p.thread_nwd.tlv.type) and {Ipv6Addr('2001:2:0:1::'), Ipv6Addr('2001:2:0:2::')} == set( + p.thread_nwd.tlv.prefix) and {0xFFFE, 0xFFFE} == set(p.thread_nwd.tlv.border_router_16)) + + # Step 15: The DUT MUST forward the SED_1 ICMPv6 Echo Request to Router_2 + # due to higher preference + _rpkts.filter_ping_request().filter_ipv6_dst('2007::1').must_next().must_verify( + lambda p: p.wpan.dst16 == leader_rloc16 and p.wpan.src16 == router1_rloc16) + if __name__ == '__main__': unittest.main() diff --git a/tests/scripts/thread-cert/Cert_7_1_02_BorderRouterAsRouter.py b/tests/scripts/thread-cert/Cert_7_1_02_BorderRouterAsRouter.py index dd0f559d1..2ec6d7f38 100755 --- a/tests/scripts/thread-cert/Cert_7_1_02_BorderRouterAsRouter.py +++ b/tests/scripts/thread-cert/Cert_7_1_02_BorderRouterAsRouter.py @@ -155,7 +155,7 @@ class Cert_7_1_2_BorderRouterAsRouter(thread_cert.TestCase): # Step 8: The DUT MUST send an MLE Child Response to SED_1 _rpkts.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).must_next().must_verify( lambda p: p.wpan.dst64 == SED and {Ipv6Addr('2001:2:0:1::')} == set( - p.thread_nwd.tlv.prefix) and p.thread_nwd.tlv.border_router_16 == 0xFFFE) + p.thread_nwd.tlv.prefix) and p.thread_nwd.tlv.border_router_16 == [0xFFFE]) _rpkts_sed = _rpkts.copy() # Step 9: SED_1 and MED_1 send its configured global address to the DUT diff --git a/tests/scripts/thread-cert/Cert_7_1_04_BorderRouterAsRouter.py b/tests/scripts/thread-cert/Cert_7_1_04_BorderRouterAsRouter.py index 7d4b791ba..ab4bb336f 100755 --- a/tests/scripts/thread-cert/Cert_7_1_04_BorderRouterAsRouter.py +++ b/tests/scripts/thread-cert/Cert_7_1_04_BorderRouterAsRouter.py @@ -156,7 +156,7 @@ class Cert_7_1_4_BorderRouterAsRouter(thread_cert.TestCase): # Step 7: The DUT MUST send an MLE Child Update Request to SED_1 _rpkts_sed.filter_wpan_dst64(SED).filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).must_next().must_verify( lambda p: {Ipv6Addr('2001:2:0:1::')} == set(p.thread_nwd.tlv.prefix - ) and p.thread_nwd.tlv.border_router_16 == 0xFFFE) + ) and p.thread_nwd.tlv.border_router_16 == [0xFFFE]) # Step 8: SED_1 send its configured global address to the DUT # Step 9: The DUT MUST send a Child Update Response to SED_1 diff --git a/tests/scripts/thread-cert/node.py b/tests/scripts/thread-cert/node.py index caff791e0..ac113182f 100755 --- a/tests/scripts/thread-cert/node.py +++ b/tests/scripts/thread-cert/node.py @@ -1003,8 +1003,11 @@ class Node: self.send_command(cmd) self._expect('Done') - def add_route(self, prefix, prf='med'): - cmd = 'route add %s %s' % (prefix, prf) + def add_route(self, prefix, stable=False, prf='med'): + cmd = 'route add %s ' % prefix + if stable: + cmd += 's' + cmd += ' %s' % prf self.send_command(cmd) self._expect('Done') diff --git a/tests/scripts/thread-cert/pktverify/consts.py b/tests/scripts/thread-cert/pktverify/consts.py index 9957e894c..46f42b3ef 100644 --- a/tests/scripts/thread-cert/pktverify/consts.py +++ b/tests/scripts/thread-cert/pktverify/consts.py @@ -171,6 +171,15 @@ CONTENT_CHANGE_CIPHER_SPEC = 20 CONTENT_ALERT = 21 CONTENT_HANDSHAKE = 22 +# Network Data TLVs +NWD_HAS_ROUTER_TLV = 0 +NWD_PREFIX_TLV = 1 +NWD_BORDER_ROUTER_TLV = 2 +NWD_6LOWPAN_ID_TLV = 3 +NWD_SERVICE_TLV = 4 +NWD_SERVER_TLV = 5 +NWD_COMMISSIONING_DATA_TLV = 6 + # DUA related constants ADDRESS_QUERY_INITIAL_RETRY_DELAY = 15 diff --git a/tests/scripts/thread-cert/pktverify/layer_fields.py b/tests/scripts/thread-cert/pktverify/layer_fields.py index 2023cc870..e5f74d7b1 100644 --- a/tests/scripts/thread-cert/pktverify/layer_fields.py +++ b/tests/scripts/thread-cert/pktverify/layer_fields.py @@ -546,7 +546,7 @@ _LAYER_FIELDS = { 'thread_nwd.tlv.service.s_data.rrdelay': _auto, 'thread_nwd.tlv.service.s_data.mlrtimeout': _auto, 'thread_nwd.tlv.server_16': _auto, - 'thread_nwd.tlv.border_router_16': _auto, + 'thread_nwd.tlv.border_router_16': _list(_auto), 'thread_nwd.tlv.sub_tlvs': _list(_str), #TODO: support thread_nwd.tlv.prefix.length and thread_nwd.tlv.prefix.domain_id 'thread_nwd.tlv.prefix': _list(_ipv6_addr),