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 mle 34import network_layer 35import thread_cert 36from 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 37from pktverify.packet_verifier import PacketVerifier 38 39LEADER = 1 40ROUTER1 = 2 41ROUTER2 = 3 42 43# Test Purpose and Description: 44# ----------------------------- 45# The purpose of this test case is to verify that after the removal of the 46# Leader from the network, the DUT will first attempt to reattach to the 47# original partition, then attach to a new partition and request its 48# original short address. 49# 50# Test Topology: 51# ------------- 52# Leader Router_2 53# / \ -> | 54# Router_1 - Router_2 Router_1[DUT] 55# 56# DUT Types: 57# ---------- 58# Router 59 60 61class Cert_5_1_03_RouterAddressReallocation(thread_cert.TestCase): 62 USE_MESSAGE_FACTORY = False 63 64 TOPOLOGY = { 65 LEADER: { 66 'name': 'LEADER', 67 'mode': 'rdn', 68 'allowlist': [ROUTER1, ROUTER2] 69 }, 70 ROUTER1: { 71 'name': 'ROUTER_1', 72 'mode': 'rdn', 73 'allowlist': [LEADER, ROUTER2] 74 }, 75 ROUTER2: { 76 'name': 'ROUTER_2', 77 'mode': 'rdn', 78 'allowlist': [LEADER, ROUTER1] 79 }, 80 } 81 82 def test(self): 83 self.nodes[LEADER].start() 84 self.simulator.go(config.LEADER_STARTUP_DELAY) 85 self.assertEqual(self.nodes[LEADER].get_state(), 'leader') 86 87 self.nodes[ROUTER1].start() 88 self.simulator.go(config.ROUTER_STARTUP_DELAY) 89 self.assertEqual(self.nodes[ROUTER1].get_state(), 'router') 90 91 self.nodes[ROUTER2].start() 92 self.simulator.go(config.ROUTER_STARTUP_DELAY) 93 self.assertEqual(self.nodes[ROUTER2].get_state(), 'router') 94 95 self.nodes[ROUTER2].set_network_id_timeout(110) 96 self.nodes[LEADER].stop() 97 self.simulator.go(140) 98 99 self.assertEqual(self.nodes[ROUTER2].get_state(), 'leader') 100 self.assertEqual(self.nodes[ROUTER1].get_state(), 'router') 101 self.collect_rloc16s() 102 103 def verify(self, pv): 104 pkts = pv.pkts 105 pv.summary.show() 106 107 LEADER = pv.vars['LEADER'] 108 LEADER_RLOC16 = pv.vars['LEADER_RLOC16'] 109 ROUTER_1 = pv.vars['ROUTER_1'] 110 ROUTER_2 = pv.vars['ROUTER_2'] 111 ROUTER_2_RLOC16 = pv.vars['ROUTER_2_RLOC16'] 112 113 # Step 2: Verify topology is formed correctly. 114 pv.verify_attached('ROUTER_1') 115 _pkt_as = pkts.filter_wpan_src64(LEADER).\ 116 filter_coap_ack(ADDR_SOL_URI).\ 117 must_next() 118 119 pv.verify_attached('ROUTER_2') 120 _pkt_pt = pkts.filter_wpan_src64(ROUTER_2).\ 121 filter_LLANMA().\ 122 filter_mle_cmd(MLE_ADVERTISEMENT).\ 123 must_next() 124 125 # Step 5: Router_1 MUST attempt to reattach to its original partition 126 # by sending a MLE Parent Request with a hop limit of 255 to 127 # the All-Routers multicast address (FF02::2). 128 # The following TLVs MUST be present in the MLE Parent Request: 129 # - Challenge TLV 130 # - Mode TLV 131 # - Scan Mask TLV (MUST have E and R flags set) 132 # - Version TLV 133 # The DUT MUST make two separate attempts to reconnect to its 134 # original partition in this manner 135 136 with pkts.save_index(): 137 for i in range(2): 138 pkts.filter_wpan_src64(ROUTER_1).\ 139 filter_LLARMA().\ 140 filter_mle_cmd(MLE_PARENT_REQUEST).\ 141 filter(lambda p: { 142 CHALLENGE_TLV, 143 MODE_TLV, 144 SCAN_MASK_TLV, 145 VERSION_TLV 146 } <= set(p.mle.tlv.type) and\ 147 p.ipv6.hlim == 255 and\ 148 p.mle.tlv.scan_mask.r == 1 and\ 149 p.mle.tlv.scan_mask.e == 1).\ 150 must_next() 151 152 # Step 6: Router_1 MUST attempt to attach to any other partition 153 # within range by sending a MLE Parent Request. 154 # The following TLVs MUST be present in the MLE Parent Request: 155 # - Challenge TLV 156 # - Mode TLV 157 # - Scan Mask TLV 158 # - Version TLV 159 160 pkts.filter_wpan_src64(ROUTER_2).\ 161 filter_mle_cmd(MLE_ADVERTISEMENT).\ 162 filter_LLANMA().\ 163 filter(lambda p:\ 164 p.mle.tlv.leader_data.partition_id != 165 _pkt_pt.mle.tlv.leader_data.partition_id).\ 166 must_next() 167 168 pkts.filter_wpan_src64(ROUTER_1).\ 169 filter_LLARMA().\ 170 filter_mle_cmd(MLE_PARENT_REQUEST).\ 171 filter(lambda p: { 172 CHALLENGE_TLV, 173 MODE_TLV, 174 SCAN_MASK_TLV, 175 VERSION_TLV 176 } <= set(p.mle.tlv.type) and\ 177 p.mle.tlv.scan_mask.r == 1 and\ 178 p.mle.tlv.scan_mask.e == 0 and\ 179 p.ipv6.hlim == 255).\ 180 must_next() 181 182 # Step 7: Router_1 sends a MLE Child ID Request to Router_2. 183 # The following TLVs MUST be present in the MLE Child ID Request: 184 # - Link-layer Frame Counter TLV 185 # - Mode TLV 186 # - Response TLV 187 # - Timeout TLV 188 # - TLV Request TLV 189 # - Version TLV 190 # - MLE Frame Counter TLV (optional) 191 # The following TLV MUST NOT be present in the MLE Child ID Request: 192 # - Address Registration TLV 193 194 _pkt = pkts.filter_wpan_src64(ROUTER_1).\ 195 filter_wpan_dst64(ROUTER_2).\ 196 filter_mle_cmd(MLE_CHILD_ID_REQUEST).\ 197 filter(lambda p: { 198 LINK_LAYER_FRAME_COUNTER_TLV, 199 MODE_TLV, 200 RESPONSE_TLV, 201 TIMEOUT_TLV, 202 TLV_REQUEST_TLV, 203 VERSION_TLV 204 } <= set(p.mle.tlv.type)).\ 205 must_next() 206 _pkt.must_not_verify(lambda p: (ADDRESS_REGISTRATION_TLV) in p.mle.tlv.type) 207 208 # Step 8: Router_1 sends an Address Solicit Request. 209 # Ensure the Address Solicit Request is properly formatted: 210 # CoAP Request URI 211 # coap://<leader address>:MM/a/as 212 # CoAP Payload 213 # - MAC Extended Address TLV 214 # - Status TLV 215 # - RLOC16 TLV 216 217 _pkt = pkts.filter_wpan_src64(ROUTER_1).\ 218 filter_wpan_dst16(ROUTER_2_RLOC16).\ 219 filter_coap_request(ADDR_SOL_URI).\ 220 filter(lambda p: { 221 NL_MAC_EXTENDED_ADDRESS_TLV, 222 NL_STATUS_TLV, 223 NL_RLOC16_TLV 224 } <= set(p.coap.tlv.type) and\ 225 p.thread_address.tlv.rloc16 == 226 _pkt_as.thread_address.tlv.rloc16).\ 227 must_next() 228 229 # Step 9: Router_2 automatically sends an Address Solicit Response. 230 231 pkts.filter_wpan_src64(ROUTER_2).\ 232 filter_wpan_dst16(_pkt.wpan.src16).\ 233 filter_coap_ack(ADDR_SOL_URI).\ 234 filter(lambda p: p.thread_address.tlv.rloc16 == 235 _pkt_as.thread_address.tlv.rloc16 and\ 236 p.thread_address.tlv.status == 0).\ 237 must_next() 238 239 240if __name__ == '__main__': 241 unittest.main() 242