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_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 37from pktverify.packet_verifier import PacketVerifier 38 39LEADER = 1 40ROUTER1 = 2 41 42# Test Purpose and Description: 43# ----------------------------- 44# The purpose of this test case is to verify that after deallocating a Router ID, 45# Leader as a DUT doesn't reassign the Router ID for at least ID_REUSE_DELAY 46# seconds 47# 48# Test Topology: 49# ------------- 50# Leader 51# | 52# Router 53# 54# DUT Types: 55# ---------- 56# Leader 57 58 59class Cert_5_1_05_RouterAddressTimeout(thread_cert.TestCase): 60 USE_MESSAGE_FACTORY = False 61 62 TOPOLOGY = { 63 LEADER: { 64 'name': 'LEADER', 65 'mode': 'rdn', 66 'allowlist': [ROUTER1] 67 }, 68 ROUTER1: { 69 'name': 'ROUTER', 70 'mode': 'rdn', 71 'allowlist': [LEADER] 72 }, 73 } 74 75 def _setUpRouter1(self): 76 self.nodes[ROUTER1].add_allowlist(self.nodes[LEADER].get_addr64()) 77 self.nodes[ROUTER1].enable_allowlist() 78 self.nodes[ROUTER1].set_router_selection_jitter(1) 79 80 def test(self): 81 self.nodes[LEADER].start() 82 self.simulator.go(config.LEADER_STARTUP_DELAY) 83 self.assertEqual(self.nodes[LEADER].get_state(), 'leader') 84 85 self.nodes[ROUTER1].start() 86 self.simulator.go(config.ROUTER_STARTUP_DELAY) 87 self.assertEqual(self.nodes[ROUTER1].get_state(), 'router') 88 89 self.nodes[ROUTER1].reset() 90 self._setUpRouter1() 91 self.simulator.go(200) 92 self.nodes[ROUTER1].start() 93 self.simulator.go(15) 94 self.assertEqual(self.nodes[ROUTER1].get_state(), 'router') 95 96 self.nodes[ROUTER1].reset() 97 self._setUpRouter1() 98 self.simulator.go(300) 99 self.nodes[ROUTER1].start() 100 self.simulator.go(15) 101 self.assertEqual(self.nodes[ROUTER1].get_state(), 'router') 102 103 def verify(self, pv): 104 pkts = pv.pkts 105 pv.summary.show() 106 107 LEADER = pv.vars['LEADER'] 108 ROUTER = pv.vars['ROUTER'] 109 MM = pv.vars['MM_PORT'] 110 111 # Step 1: Verify topology is formed correctly. 112 113 pv.verify_attached('ROUTER') 114 _pkt_as = pkts.filter_wpan_src64(LEADER).\ 115 filter_coap_ack(ADDR_SOL_URI, port=MM).\ 116 filter(lambda p: { 117 NL_STATUS_TLV, 118 NL_RLOC16_TLV, 119 NL_ROUTER_MASK_TLV 120 } <= set(p.coap.tlv.type) and\ 121 p.coap.code == COAP_CODE_ACK and\ 122 p.thread_address.tlv.status == 0 123 ).\ 124 must_next() 125 126 # Step 3: Router automatically sends a link request, reattaches and 127 # requests its original Router ID after reset within the 128 # ID_REUSE_DELAY interval 129 130 pkts.filter_wpan_src64(ROUTER).\ 131 filter_LLARMA().\ 132 filter_mle_cmd(MLE_LINK_REQUEST).\ 133 filter(lambda p: { 134 CHALLENGE_TLV, 135 VERSION_TLV, 136 TLV_REQUEST_TLV, 137 ADDRESS16_TLV, 138 ROUTE64_TLV 139 } <= set(p.mle.tlv.type)\ 140 ).\ 141 must_next() 142 143 # Step 4: Leader MUST send a properly formatted Parent Response and 144 # Child ID Response to Router. 145 # And send Address Solicit Response Message to Router. 146 # The RLOC16 TLV in the Address Solicit Response message MUST 147 # contain a different Router ID then the one allocated in the 148 # original attach because ID_REUSE_DELAY interval has not 149 # timed out. 150 # 151 # CoAP Response Code 152 # - 2.04 Changed 153 # CoAP Payload 154 # - Status TLV (value = Success) 155 # - RLOC16 TLV 156 # - Router Mask TLV 157 158 pkts.filter_wpan_src64(LEADER).\ 159 filter_wpan_dst64(ROUTER).\ 160 filter_mle_cmd(MLE_PARENT_RESPONSE).\ 161 filter(lambda p: { 162 CHALLENGE_TLV, 163 CONNECTIVITY_TLV, 164 LEADER_DATA_TLV, 165 LINK_LAYER_FRAME_COUNTER_TLV, 166 LINK_MARGIN_TLV, 167 RESPONSE_TLV, 168 SOURCE_ADDRESS_TLV, 169 VERSION_TLV 170 } <= set(p.mle.tlv.type) 171 ).\ 172 must_next() 173 174 pkts.filter_wpan_src64(LEADER).\ 175 filter_wpan_dst64(ROUTER).\ 176 filter_mle_cmd(MLE_CHILD_ID_RESPONSE).\ 177 filter(lambda p: { 178 ADDRESS16_TLV, 179 LEADER_DATA_TLV, 180 NETWORK_DATA_TLV, 181 SOURCE_ADDRESS_TLV, 182 ROUTE64_TLV 183 } <= set(p.mle.tlv.type) or\ 184 { 185 ADDRESS16_TLV, 186 LEADER_DATA_TLV, 187 NETWORK_DATA_TLV, 188 SOURCE_ADDRESS_TLV 189 } <= set(p.mle.tlv.type)\ 190 ).\ 191 must_next() 192 193 _pkt_as2 = pkts.filter_wpan_src64(ROUTER).\ 194 filter_coap_request(ADDR_SOL_URI, port=MM).\ 195 filter(lambda p: { 196 NL_MAC_EXTENDED_ADDRESS_TLV, 197 NL_RLOC16_TLV, 198 NL_STATUS_TLV 199 } <= set(p.coap.tlv.type) and\ 200 p.coap.code == COAP_CODE_POST and\ 201 p.thread_address.tlv.rloc16 == 202 _pkt_as.thread_address.tlv.rloc16 203 ).\ 204 must_next() 205 206 _pkt_as3 = pkts.filter_wpan_src64(LEADER).\ 207 filter_coap_ack(ADDR_SOL_URI, port=MM).\ 208 filter(lambda p: { 209 NL_STATUS_TLV, 210 NL_RLOC16_TLV, 211 NL_ROUTER_MASK_TLV 212 } <= set(p.coap.tlv.type) and\ 213 p.coap.code == COAP_CODE_ACK and\ 214 p.thread_address.tlv.rloc16 != 215 _pkt_as2.thread_address.tlv.rloc16 and\ 216 p.thread_address.tlv.status == 0 217 ).\ 218 must_next() 219 220 # Step 6: Router automatically sends a link request, reattaches and 221 # requests its most recent Router ID after reset after the 222 # ID_REUSE_DELAY interval 223 224 pkts.filter_wpan_src64(ROUTER).\ 225 filter_LLARMA().\ 226 filter_mle_cmd(MLE_LINK_REQUEST).\ 227 filter(lambda p: { 228 CHALLENGE_TLV, 229 VERSION_TLV, 230 TLV_REQUEST_TLV, 231 ADDRESS16_TLV, 232 ROUTE64_TLV 233 } <= set(p.mle.tlv.type)\ 234 ).\ 235 must_next() 236 237 # Step 7: Leader MUST send a properly formatted Parent Response and 238 # Child ID Response to Router. 239 # And send Address Solicit Response Message to Router. 240 # The RLOC16 TLV in the Address Solicit Response message MUST 241 # contain the requested Router ID 242 # 243 # CoAP Response Code 244 # - 2.04 Changed 245 # CoAP Payload 246 # - Status TLV (value = Success) 247 # - RLOC16 TLV 248 # - Router Mask TLV 249 250 pkts.filter_wpan_src64(LEADER).\ 251 filter_wpan_dst64(ROUTER).\ 252 filter_mle_cmd(MLE_PARENT_RESPONSE).\ 253 filter(lambda p: { 254 CHALLENGE_TLV, 255 CONNECTIVITY_TLV, 256 LEADER_DATA_TLV, 257 LINK_LAYER_FRAME_COUNTER_TLV, 258 LINK_MARGIN_TLV, 259 RESPONSE_TLV, 260 SOURCE_ADDRESS_TLV, 261 VERSION_TLV 262 } <= set(p.mle.tlv.type) 263 ).\ 264 must_next() 265 266 pkts.filter_wpan_src64(LEADER).\ 267 filter_wpan_dst64(ROUTER).\ 268 filter_mle_cmd(MLE_CHILD_ID_RESPONSE).\ 269 filter(lambda p: { 270 ADDRESS16_TLV, 271 LEADER_DATA_TLV, 272 NETWORK_DATA_TLV, 273 SOURCE_ADDRESS_TLV, 274 ROUTE64_TLV 275 } <= set(p.mle.tlv.type) or\ 276 { 277 ADDRESS16_TLV, 278 LEADER_DATA_TLV, 279 NETWORK_DATA_TLV, 280 SOURCE_ADDRESS_TLV 281 } <= set(p.mle.tlv.type)\ 282 ).\ 283 must_next() 284 285 pkts.filter_wpan_src64(ROUTER).\ 286 filter_coap_request(ADDR_SOL_URI, port=MM).\ 287 filter(lambda p: { 288 NL_MAC_EXTENDED_ADDRESS_TLV, 289 NL_RLOC16_TLV, 290 NL_STATUS_TLV 291 } <= set(p.coap.tlv.type) and\ 292 p.coap.code == COAP_CODE_POST and\ 293 p.thread_address.tlv.rloc16 == 294 _pkt_as3.thread_address.tlv.rloc16 295 ).\ 296 must_next() 297 298 pkts.filter_wpan_src64(LEADER).\ 299 filter_coap_ack(ADDR_SOL_URI, port=MM).\ 300 filter(lambda p: { 301 NL_STATUS_TLV, 302 NL_RLOC16_TLV, 303 NL_ROUTER_MASK_TLV 304 } <= set(p.coap.tlv.type) and\ 305 p.coap.code == COAP_CODE_ACK and\ 306 p.thread_address.tlv.rloc16 == 307 _pkt_as3.thread_address.tlv.rloc16 and\ 308 p.thread_address.tlv.status == 0 309 ).\ 310 must_next() 311 312 313if __name__ == '__main__': 314 unittest.main() 315