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 command 33import config 34import mle 35import thread_cert 36import thread_cert 37from pktverify.consts import MLE_PARENT_REQUEST, MLE_CHILD_ID_REQUEST, ADDR_REL_URI, SOURCE_ADDRESS_TLV, 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, CONNECTIVITY_TLV, LINK_MARGIN_TLV, VERSION_TLV, ADDRESS_REGISTRATION_TLV, NL_MAC_EXTENDED_ADDRESS_TLV, NL_RLOC16_TLV, COAP_CODE_ACK 38from pktverify.packet_verifier import PacketVerifier 39from pktverify.null_field import nullField 40 41LEADER = 1 42DUT_ROUTER1 = 2 43ROUTER2 = 3 44ROUTER23 = 24 45 46# Test Purpose and Description: 47# ----------------------------- 48# The purpose of this test case is to verify that the DUT will downgrade 49# to a REED when the network becomes too dense and the Router Downgrade 50# Threshold conditions are met. 51# 52# Test Topology: 53# ------------- 54# Leader 55# / \ 56# Router_1 [DUT] ... Router_23 57# 58# DUT Types: 59# ---------- 60# Router 61 62 63class Cert_5_2_06_RouterDowngrade(thread_cert.TestCase): 64 USE_MESSAGE_FACTORY = False 65 66 TOPOLOGY = { 67 LEADER: { 68 'name': 'LEADER', 69 'mode': 'rdn', 70 'router_downgrade_threshold': 32, 71 'router_upgrade_threshold': 32 72 }, 73 DUT_ROUTER1: { 74 'name': 'ROUTER_1', 75 'mode': 'rdn', 76 }, 77 ROUTER2: { 78 'name': 'ROUTER_2', 79 'mode': 'rdn', 80 'router_downgrade_threshold': 32, 81 'router_upgrade_threshold': 32 82 }, 83 4: { 84 'name': 'ROUTER_3', 85 'mode': 'rdn', 86 'router_downgrade_threshold': 32, 87 'router_upgrade_threshold': 32 88 }, 89 5: { 90 'name': 'ROUTER_4', 91 'mode': 'rdn', 92 'router_downgrade_threshold': 32, 93 'router_upgrade_threshold': 32 94 }, 95 6: { 96 'name': 'ROUTER_5', 97 'mode': 'rdn', 98 'router_downgrade_threshold': 32, 99 'router_upgrade_threshold': 32 100 }, 101 7: { 102 'name': 'ROUTER_6', 103 'mode': 'rdn', 104 'router_downgrade_threshold': 32, 105 'router_upgrade_threshold': 32 106 }, 107 8: { 108 'name': 'ROUTER_7', 109 'mode': 'rdn', 110 'router_downgrade_threshold': 32, 111 'router_upgrade_threshold': 32 112 }, 113 9: { 114 'name': 'ROUTER_8', 115 'mode': 'rdn', 116 'router_downgrade_threshold': 32, 117 'router_upgrade_threshold': 32 118 }, 119 10: { 120 'name': 'ROUTER_9', 121 'mode': 'rdn', 122 'router_downgrade_threshold': 32, 123 'router_upgrade_threshold': 32 124 }, 125 11: { 126 'name': 'ROUTER_10', 127 'mode': 'rdn', 128 'router_downgrade_threshold': 32, 129 'router_upgrade_threshold': 32 130 }, 131 12: { 132 'name': 'ROUTER_11', 133 'mode': 'rdn', 134 'router_downgrade_threshold': 32, 135 'router_upgrade_threshold': 32 136 }, 137 13: { 138 'name': 'ROUTER_12', 139 'mode': 'rdn', 140 'router_downgrade_threshold': 32, 141 'router_upgrade_threshold': 32 142 }, 143 14: { 144 'name': 'ROUTER_13', 145 'mode': 'rdn', 146 'router_downgrade_threshold': 32, 147 'router_upgrade_threshold': 32 148 }, 149 15: { 150 'name': 'ROUTER_14', 151 'mode': 'rdn', 152 'router_downgrade_threshold': 32, 153 'router_upgrade_threshold': 32 154 }, 155 16: { 156 'name': 'ROUTER_15', 157 'mode': 'rdn', 158 'router_downgrade_threshold': 32, 159 'router_upgrade_threshold': 32 160 }, 161 17: { 162 'name': 'ROUTER_16', 163 'mode': 'rdn', 164 'router_downgrade_threshold': 32, 165 'router_upgrade_threshold': 32 166 }, 167 18: { 168 'name': 'ROUTER_17', 169 'mode': 'rdn', 170 'router_downgrade_threshold': 32, 171 'router_upgrade_threshold': 32 172 }, 173 19: { 174 'name': 'ROUTER_18', 175 'mode': 'rdn', 176 'router_downgrade_threshold': 32, 177 'router_upgrade_threshold': 32 178 }, 179 20: { 180 'name': 'ROUTER_19', 181 'mode': 'rdn', 182 'router_downgrade_threshold': 32, 183 'router_upgrade_threshold': 32 184 }, 185 21: { 186 'name': 'ROUTER_20', 187 'mode': 'rdn', 188 'router_downgrade_threshold': 32, 189 'router_upgrade_threshold': 32 190 }, 191 22: { 192 'name': 'ROUTER_21', 193 'mode': 'rdn', 194 'router_downgrade_threshold': 32, 195 'router_upgrade_threshold': 32 196 }, 197 23: { 198 'name': 'ROUTER_22', 199 'mode': 'rdn', 200 'router_downgrade_threshold': 32, 201 'router_upgrade_threshold': 32 202 }, 203 ROUTER23: { 204 'name': 'ROUTER_23', 205 'mode': 'rdn', 206 'router_downgrade_threshold': 32, 207 'router_upgrade_threshold': 32 208 }, 209 } 210 211 def test(self): 212 # 1 Ensure topology is formed correctly without ROUTER23. 213 self.nodes[LEADER].start() 214 self.simulator.go(config.LEADER_STARTUP_DELAY) 215 self.assertEqual(self.nodes[LEADER].get_state(), 'leader') 216 217 for i in range(2, 24): 218 self.nodes[i].start() 219 self.simulator.go(config.ROUTER_STARTUP_DELAY) 220 self.assertEqual(self.nodes[i].get_state(), 'router') 221 self.collect_rloc16s() 222 223 # All reference testbed devices have been configured with downgrade threshold as 32 except DUT_ROUTER1, 224 # so we don't need to ensure ROUTER23 has a better link quality on 225 # posix. 226 self.nodes[ROUTER23].start() 227 self.simulator.go(config.ROUTER_STARTUP_DELAY) 228 self.assertEqual(self.nodes[ROUTER23].get_state(), 'router') 229 230 self.simulator.go(10) 231 self.assertEqual(self.nodes[DUT_ROUTER1].get_state(), 'child') 232 self.collect_rlocs() 233 234 router1_rloc = self.nodes[DUT_ROUTER1].get_ip6_address(config.ADDRESS_TYPE.RLOC) 235 self.assertTrue(self.nodes[LEADER].ping(router1_rloc)) 236 237 def verify(self, pv): 238 pkts = pv.pkts 239 pv.summary.show() 240 241 LEADER = pv.vars['LEADER'] 242 LEADER_RLOC = pv.vars['LEADER_RLOC'] 243 ROUTER_1 = pv.vars['ROUTER_1'] 244 ROUTER_1_RLOC = pv.vars['ROUTER_1_RLOC'] 245 ROUTER_1_RLOC16 = pv.vars['ROUTER_1_RLOC16'] 246 247 # Step 1: Ensure topology is formed correctly 248 249 for i in range(1, 24): 250 pv.verify_attached('ROUTER_%d' % i) 251 252 # Step 3: Allow enough time for the DUT to get Network Data Updates 253 # and resign its Router ID. 254 # The DUT MUST first reconnect to the network as a Child by 255 # sending properly formatted Parent Request and Child ID Request 256 # messages. 257 # Once the DUT attaches as a Child, it MUST send an Address 258 # Release Message to the Leader: 259 # CoAP Request URI 260 # coap://[<leader address>]:MM/a/ar 261 # CoAP Payload 262 # MAC Extended Address TLV 263 # RLOC16 TLV 264 265 pkts.filter_wpan_src64(ROUTER_1).\ 266 filter_LLARMA().\ 267 filter_mle_cmd(MLE_PARENT_REQUEST).\ 268 filter(lambda p: { 269 CHALLENGE_TLV, 270 MODE_TLV, 271 SCAN_MASK_TLV, 272 VERSION_TLV 273 } <= set(p.mle.tlv.type) and\ 274 p.ipv6.hlim == 255 and\ 275 p.mle.tlv.scan_mask.r == 1 and\ 276 p.mle.tlv.scan_mask.e == 0 277 ).\ 278 must_next() 279 280 _pkt = pkts.filter_wpan_src64(ROUTER_1).\ 281 filter_mle_cmd(MLE_CHILD_ID_REQUEST).\ 282 filter(lambda p: { 283 LINK_LAYER_FRAME_COUNTER_TLV, 284 MODE_TLV, 285 RESPONSE_TLV, 286 TIMEOUT_TLV, 287 TLV_REQUEST_TLV, 288 ADDRESS16_TLV, 289 NETWORK_DATA_TLV, 290 VERSION_TLV 291 } <= set(p.mle.tlv.type) and\ 292 p.mle.tlv.addr16 is nullField and\ 293 p.thread_nwd.tlv.type is nullField 294 ).\ 295 must_next() 296 _pkt.must_not_verify(lambda p: (ADDRESS_REGISTRATION_TLV) in p.mle.tlv.type) 297 298 pkts.filter_wpan_src64(ROUTER_1).\ 299 filter_ipv6_dst(LEADER_RLOC).\ 300 filter_coap_request(ADDR_REL_URI).\ 301 filter(lambda p: { 302 NL_MAC_EXTENDED_ADDRESS_TLV, 303 NL_RLOC16_TLV 304 } <= set(p.coap.tlv.type) and\ 305 p.thread_address.tlv.rloc16 == ROUTER_1_RLOC16 306 ).\ 307 must_next() 308 309 # Step 4: Leader receives Address Release messages and sends a2.04 310 # Changed CoAP response. 311 312 pkts.filter_wpan_src64(LEADER).\ 313 filter_ipv6_dst(ROUTER_1_RLOC).\ 314 filter_coap_ack(ADDR_REL_URI).\ 315 must_next() 316 317 # Step 5: ROUTER_1 responds with ICMPv6 Echo Reply 318 _pkt = pkts.filter_ipv6_src_dst(LEADER_RLOC, ROUTER_1_RLOC).\ 319 filter_ping_request().\ 320 must_next() 321 pkts.filter_ipv6_src_dst(ROUTER_1_RLOC, LEADER_RLOC).\ 322 filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\ 323 must_next() 324 325 326if __name__ == '__main__': 327 unittest.main() 328