1#!/usr/bin/env python3 2# 3# Copyright (c) 2016, The OpenThread Authors. 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions are met: 8# 1. Redistributions of source code must retain the above copyright 9# notice, this list of conditions and the following disclaimer. 10# 2. Redistributions in binary form must reproduce the above copyright 11# notice, this list of conditions and the following disclaimer in the 12# documentation and/or other materials provided with the distribution. 13# 3. Neither the name of the copyright holder nor the 14# names of its contributors may be used to endorse or promote products 15# derived from this software without specific prior written permission. 16# 17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27# POSSIBILITY OF SUCH DAMAGE. 28# 29 30import unittest 31 32import config 33import thread_cert 34from pktverify.consts import MLE_ADVERTISEMENT, MLE_LINK_REQUEST, MLE_PARENT_REQUEST, MLE_PARENT_RESPONSE, MLE_CHILD_ID_REQUEST, MLE_CHILD_ID_RESPONSE, ADDR_SOL_URI, VERSION_TLV, TLV_REQUEST_TLV, SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, CHALLENGE_TLV, LINK_MARGIN_TLV, NL_MAC_EXTENDED_ADDRESS_TLV, NL_STATUS_TLV 35from pktverify.packet_verifier import PacketVerifier 36 37LEADER = 1 38ROUTER1 = 2 39ROUTER2 = 3 40ROUTER3 = 4 41ROUTER15 = 16 42REED1 = 17 43 44 45class Cert_5_5_5_SplitMergeREED(thread_cert.TestCase): 46 TOPOLOGY = { 47 LEADER: { 48 'name': 'LEADER', 49 'mode': 'rdn', 50 'allowlist': [ROUTER2, ROUTER3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, ROUTER15] 51 }, 52 ROUTER1: { 53 'name': 'ROUTER_1', 54 'mode': 'rdn', 55 'allowlist': [ROUTER3] 56 }, 57 ROUTER2: { 58 'name': 'ROUTER_2', 59 'mode': 'rdn', 60 'allowlist': [LEADER, REED1] 61 }, 62 ROUTER3: { 63 'name': 'ROUTER_3', 64 'mode': 'rdn', 65 'allowlist': [LEADER, ROUTER1] 66 }, 67 5: { 68 'mode': 'rdn', 69 'allowlist': [LEADER] 70 }, 71 6: { 72 'mode': 'rdn', 73 'allowlist': [LEADER] 74 }, 75 7: { 76 'mode': 'rdn', 77 'allowlist': [LEADER] 78 }, 79 8: { 80 'mode': 'rdn', 81 'allowlist': [LEADER] 82 }, 83 9: { 84 'mode': 'rdn', 85 'allowlist': [LEADER] 86 }, 87 10: { 88 'mode': 'rdn', 89 'allowlist': [LEADER] 90 }, 91 11: { 92 'mode': 'rdn', 93 'allowlist': [LEADER] 94 }, 95 12: { 96 'mode': 'rdn', 97 'allowlist': [LEADER] 98 }, 99 13: { 100 'mode': 'rdn', 101 'allowlist': [LEADER] 102 }, 103 14: { 104 'mode': 'rdn', 105 'allowlist': [LEADER] 106 }, 107 15: { 108 'mode': 'rdn', 109 'allowlist': [LEADER] 110 }, 111 ROUTER15: { 112 'mode': 'rdn', 113 'allowlist': [LEADER] 114 }, 115 REED1: { 116 'name': 'REED', 117 'mode': 'rdn', 118 'allowlist': [ROUTER2] 119 }, 120 } 121 122 def test(self): 123 self.nodes[LEADER].start() 124 self.simulator.go(config.LEADER_STARTUP_DELAY) 125 self.assertEqual(self.nodes[LEADER].get_state(), 'leader') 126 127 for i in range(ROUTER2, ROUTER15 + 1): 128 self.nodes[i].start() 129 self.simulator.go(config.ROUTER_STARTUP_DELAY) 130 self.assertEqual(self.nodes[i].get_state(), 'router') 131 132 self.nodes[ROUTER1].start() 133 self.simulator.go(config.ROUTER_STARTUP_DELAY) 134 self.assertEqual(self.nodes[ROUTER1].get_state(), 'router') 135 136 self.nodes[REED1].start() 137 self.simulator.go(5) 138 self.assertEqual(self.nodes[REED1].get_state(), 'child') 139 140 self.nodes[ROUTER1].add_allowlist(self.nodes[REED1].get_addr64()) 141 self.nodes[REED1].add_allowlist(self.nodes[ROUTER1].get_addr64()) 142 143 self.nodes[ROUTER3].stop() 144 self.simulator.go(140) 145 146 self.assertEqual(self.nodes[ROUTER1].get_state(), 'child') 147 self.assertEqual(self.nodes[REED1].get_state(), 'router') 148 149 self.collect_ipaddrs() 150 151 addrs = self.nodes[LEADER].get_addrs() 152 for addr in addrs: 153 if addr[0:4] != 'fe80': 154 self.assertTrue(self.nodes[ROUTER1].ping(addr)) 155 156 def verify(self, pv): 157 pkts = pv.pkts 158 pv.summary.show() 159 160 LEADER = pv.vars['LEADER'] 161 ROUTER_1 = pv.vars['ROUTER_1'] 162 ROUTER_2 = pv.vars['ROUTER_2'] 163 ROUTER_3 = pv.vars['ROUTER_3'] 164 REED = pv.vars['REED'] 165 router1_pkts = pkts.filter_wpan_src64(ROUTER_1) 166 router2_pkts = pkts.filter_wpan_src64(ROUTER_2) 167 reed_pkts = pkts.filter_wpan_src64(REED) 168 169 router2_pkts.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).filter_wpan_dst64(REED).must_next() 170 _start_idx = router2_pkts.index 171 reed_pkts.index = _start_idx 172 173 # Step 3: Remove Router_3 from the network 174 # Router_1 attempt to re-attach to partition. 175 # Sends multicast Parent Request to Routers and REEDs 176 router1_pkts.range(_start_idx).must_next() 177 router1_pkts.filter_mle_cmd(MLE_PARENT_REQUEST).must_next() 178 179 # filter MLE_ADVERTISEMENT with 16 routing table entry: 180 # 1 byte ID Sequence + 8 bytes ID Mask + 16 bytes Routing Table Entry = 181 # 25 (Router64 tlv length) 182 pkts.range(_start_idx).filter_mle_cmd(MLE_ADVERTISEMENT).filter(lambda p: 25 in p.mle.tlv.len).must_next() 183 _end_idx = pkts.index 184 185 # Step 2: The DUT MUST NOT attempt to become an active router by sending an Address Solicit Request 186 reed_pkts.range(_start_idx, _end_idx).filter_coap_request(ADDR_SOL_URI).must_not_next() 187 188 # Step 4: The DUT send a Parent Response to Router_1 189 reed_pkts.filter_mle_cmd(MLE_PARENT_RESPONSE).must_next().must_verify(lambda p: p.wpan.dst64 == ROUTER_1) 190 191 # Step 5: Router_1 Send MLE Child ID Request to the DUT 192 router1_pkts.range(reed_pkts.index).filter_mle_cmd(MLE_CHILD_ID_REQUEST).must_next() 193 194 # Step 6: DUT send an Address Solicit Request to Leader, 195 # receives short address and becomes a router 196 pkts.range(_end_idx).filter_wpan_src64(REED).filter_coap_request(ADDR_SOL_URI).must_next().must_verify( 197 lambda p: {NL_MAC_EXTENDED_ADDRESS_TLV, NL_STATUS_TLV} <= set(p.coap.tlv.type)) 198 199 # Step 7: DUT send a Multicast Link Request 200 pkts.filter_wpan_src64(REED).filter_mle_cmd(MLE_LINK_REQUEST).must_next().must_verify(lambda p: { 201 VERSION_TLV, TLV_REQUEST_TLV, SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, CHALLENGE_TLV, LINK_MARGIN_TLV 202 } <= set(p.mle.tlv.type)) 203 204 # Step 8: DUT send Child ID Response to Router_1 205 reed_pkts.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).must_next().must_verify(lambda p: p.wpan.dst64 == ROUTER_1) 206 207 # Step 9: The DUT MUST route the ICMPv6 Echo request to the Leader. 208 # The DUT MUST route the ICMPv6 Echo reply back to Router_1 209 leader_mleid = pv.vars['LEADER_MLEID'] 210 router1_mleid = pv.vars['ROUTER_1_MLEID'] 211 reed_pkts.filter_ipv6_src_dst(router1_mleid, leader_mleid).filter_ping_request().must_next() 212 reed_pkts.filter_ipv6_src_dst(leader_mleid, router1_mleid).filter_ping_reply().must_next() 213 214 215if __name__ == '__main__': 216 unittest.main() 217