1#!/usr/bin/env python3 2# 3# Copyright (c) 2020, 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 copy 34import mle 35import network_diag 36import network_layer 37import thread_cert 38from network_diag import TlvType 39from pktverify.consts import DIAG_RST_URI, DIAG_GET_URI, DIAG_GET_QRY_URI, DIAG_GET_ANS_URI, DG_MAC_EXTENDED_ADDRESS_TLV, DG_MAC_ADDRESS_TLV, DG_MODE_TLV, DG_CONNECTIVITY_TLV, DG_ROUTE64_TLV, DG_LEADER_DATA_TLV, DG_NETWORK_DATA_TLV, DG_IPV6_ADDRESS_LIST_TLV, DG_CHANNEL_PAGES_TLV, DG_TYPE_LIST_TLV, DG_MAC_COUNTERS_TLV, DG_TIMEOUT_TLV, DG_BATTERY_LEVEL_TLV, DG_SUPPLY_VOLTAGE_TLV, DG_CHILD_TABLE_TLV, DG_CHILD_TABLE_TLV, REALM_LOCAL_All_THREAD_NODES_MULTICAST_ADDRESS 40from pktverify.packet_verifier import PacketVerifier 41from pktverify.null_field import nullField 42from pktverify.utils import colon_hex 43 44LEADER = 1 45ROUTER15 = 16 46REED = 17 47 48# Test Purpose and Description: 49# ----------------------------- 50# This test case exercises the Diagnostic Get Query and Answer commands 51# as part of the Network Management. This test case topology is specific 52# to REED DUTs. 53# 54# Test Topology: 55# ------------- 56# Leader 57# / \ 58# Router1 .. Router15 59# | 60# REED 61# 62# DUT Types: 63# ---------- 64# REED 65 66 67class Cert_5_7_02_CoapDiagCommands(thread_cert.TestCase): 68 USE_MESSAGE_FACTORY = False 69 SUPPORT_NCP = False 70 71 TOPOLOGY = { 72 LEADER: { 73 'name': 'LEADER', 74 'mode': 'rdn', 75 'allowlist': [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, ROUTER15] 76 }, 77 2: { 78 'name': 'ROUTER_1', 79 'mode': 'rdn', 80 'allowlist': [LEADER] 81 }, 82 3: { 83 'name': 'ROUTER_2', 84 'mode': 'rdn', 85 'allowlist': [LEADER] 86 }, 87 4: { 88 'name': 'ROUTER_3', 89 'mode': 'rdn', 90 'allowlist': [LEADER] 91 }, 92 5: { 93 'name': 'ROUTER_4', 94 'mode': 'rdn', 95 'allowlist': [LEADER] 96 }, 97 6: { 98 'name': 'ROUTER_5', 99 'mode': 'rdn', 100 'allowlist': [LEADER] 101 }, 102 7: { 103 'name': 'ROUTER_6', 104 'mode': 'rdn', 105 'allowlist': [LEADER] 106 }, 107 8: { 108 'name': 'ROUTER_7', 109 'mode': 'rdn', 110 'allowlist': [LEADER] 111 }, 112 9: { 113 'name': 'ROUTER_8', 114 'mode': 'rdn', 115 'allowlist': [LEADER] 116 }, 117 10: { 118 'name': 'ROUTER_9', 119 'mode': 'rdn', 120 'allowlist': [LEADER] 121 }, 122 11: { 123 'name': 'ROUTER_10', 124 'mode': 'rdn', 125 'allowlist': [LEADER] 126 }, 127 12: { 128 'name': 'ROUTER_11', 129 'mode': 'rdn', 130 'allowlist': [LEADER] 131 }, 132 13: { 133 'name': 'ROUTER_12', 134 'mode': 'rdn', 135 'allowlist': [LEADER] 136 }, 137 14: { 138 'name': 'ROUTER_13', 139 'mode': 'rdn', 140 'allowlist': [LEADER] 141 }, 142 15: { 143 'name': 'ROUTER_14', 144 'mode': 'rdn', 145 'allowlist': [LEADER] 146 }, 147 ROUTER15: { 148 'name': 'ROUTER_15', 149 'mode': 'rdn', 150 'allowlist': [LEADER, REED] 151 }, 152 REED: { 153 'name': 'DUT', 154 'mode': 'rdn', 155 'allowlist': [ROUTER15] 156 }, 157 } 158 159 def test(self): 160 # 1 - Form topology 161 self.nodes[LEADER].start() 162 self.simulator.go(config.LEADER_STARTUP_DELAY) 163 self.assertEqual(self.nodes[LEADER].get_state(), 'leader') 164 165 for i in range(2, 17): 166 self.nodes[i].start() 167 self.simulator.go(config.ROUTER_STARTUP_DELAY) 168 self.assertEqual(self.nodes[i].get_state(), 'router') 169 170 self.nodes[REED].start() 171 self.simulator.go(5) 172 self.assertEqual(self.nodes[REED].get_state(), 'child') 173 174 self.simulator.go(config.MAX_ADVERTISEMENT_INTERVAL) 175 176 self.collect_rlocs() 177 self.collect_rloc16s() 178 179 dut_rloc = self.nodes[REED].get_ip6_address(config.ADDRESS_TYPE.RLOC) 180 181 # 2 - Leader sends DIAG_GET.req 182 tlv_types = [ 183 TlvType.EXT_ADDRESS, TlvType.ADDRESS16, TlvType.MODE, TlvType.CONNECTIVITY, TlvType.ROUTE64, 184 TlvType.LEADER_DATA, TlvType.IPV6_ADDRESS_LIST, TlvType.CHANNEL_PAGES 185 ] 186 self.nodes[LEADER].send_network_diag_get(dut_rloc, tlv_types) 187 self.simulator.go(2) 188 189 # 3 - Leader sends DIAG_GET.req (MAC Counters TLV type included) 190 self.nodes[LEADER].send_network_diag_get(dut_rloc, [TlvType.MAC_COUNTERS]) 191 self.simulator.go(2) 192 193 # 4 - Leader sends DIAG_GET.req (Timeout/Polling Period TLV type included) 194 self.nodes[LEADER].send_network_diag_get(dut_rloc, [TlvType.POLLING_PERIOD, TlvType.CHILD_TABLE]) 195 self.simulator.go(2) 196 197 # 5 - Leader sends DIAG_GET.req (Battery Level and Supply Voltage TLV types included) 198 self.nodes[LEADER].send_network_diag_get(dut_rloc, [TlvType.BATTERY_LEVEL, TlvType.SUPPLY_VOLTAGE]) 199 self.simulator.go(20) 200 201 # 6 - Leader sends DIAG_RST.ntf (MAC Counters TLV type included) 202 self.nodes[LEADER].send_network_diag_reset(dut_rloc, [TlvType.MAC_COUNTERS]) 203 self.simulator.go(2) 204 205 # 7 - Leader Sends DIAG_GET.req (MAC Counters TLV type included) 206 self.nodes[LEADER].send_network_diag_get(dut_rloc, [TlvType.MAC_COUNTERS]) 207 self.simulator.go(2) 208 209 # 8 - Leader sends DIAG_GET.query 210 self.nodes[LEADER].send_network_diag_get(REALM_LOCAL_All_THREAD_NODES_MULTICAST_ADDRESS, tlv_types) 211 self.simulator.go(2) 212 213 def verify(self, pv): 214 pkts = pv.pkts 215 pv.summary.show() 216 217 LEADER = pv.vars['LEADER'] 218 LEADER_RLOC = pv.vars['LEADER_RLOC'] 219 DUT = pv.vars['DUT'] 220 DUT_RLOC = pv.vars['DUT_RLOC'] 221 DUT_RLOC16 = pv.vars['DUT_RLOC16'] 222 MM = pv.vars['MM_PORT'] 223 224 dut_addr16 = "%04x" % DUT_RLOC16 225 dut_payload_tlvs = { 226 DG_TYPE_LIST_TLV, DG_MAC_EXTENDED_ADDRESS_TLV, DG_MAC_ADDRESS_TLV, DG_MODE_TLV, DG_CONNECTIVITY_TLV, 227 DG_ROUTE64_TLV, DG_LEADER_DATA_TLV, DG_IPV6_ADDRESS_LIST_TLV, DG_CHANNEL_PAGES_TLV 228 } 229 230 # Step 1: Ensure topology is formed correctly 231 for i in range(1, 16): 232 with pkts.save_index(): 233 pv.verify_attached('ROUTER_%d' % i, 'LEADER') 234 pv.verify_attached('DUT', 'ROUTER_15') 235 236 # Step 2: Leader to send DIAG_GET.req to DUT’s RLOC. 237 # The DUT MUST respond with a DIAG_GET.rsp response containing 238 # the requested diagnostic TLVs: 239 # CoAP Response Code 240 # 2.04 Changed 241 # CoAP Payload 242 # TLV Type 0 - MAC Extended Address (64- bit) 243 # TLV Type 1 - MAC Address (16-bit) 244 # TLV Type 2 - Mode (Capability information) 245 # TLV Type 4 – Connectivity 246 # TLV Type 5 – Route64(optional) 247 # TLV Type 6 – Leader Data 248 # TLV Type 8 – IPv6 address list 249 # TLV Type 17 – Channel Pages 250 pkts.filter_wpan_src64(LEADER).\ 251 filter_ipv6_dst(DUT_RLOC).\ 252 filter_coap_request(DIAG_GET_URI).\ 253 filter(lambda p: dut_payload_tlvs <= set(p.thread_diagnostic.tlv.type)).\ 254 must_next() 255 dut_payload_tlvs.remove(DG_TYPE_LIST_TLV) 256 dut_payload_tlvs.remove(DG_ROUTE64_TLV) 257 pkts.filter_wpan_src64(DUT).\ 258 filter_ipv6_dst(LEADER_RLOC).\ 259 filter_coap_ack(DIAG_GET_URI).\ 260 filter(lambda p: 261 dut_payload_tlvs <= set(p.thread_diagnostic.tlv.type) and\ 262 {str(p.wpan.src64), colon_hex(dut_addr16, 2), '0f'} 263 < set(p.thread_diagnostic.tlv.general) 264 ).\ 265 must_next() 266 267 # Step 3: Leader to send DIAG_GET.req to DUT’s RLOC. 268 # The DUT MUST respond with a DIAG_GET.rsp response containing 269 # the requested diagnostic TLVs: 270 # CoAP Response Code 271 # 2.04 Changed 272 # CoAP Payload 273 # TLV Type 9 - MAC Counters 274 pkts.filter_wpan_src64(LEADER).\ 275 filter_ipv6_dst(DUT_RLOC).\ 276 filter_coap_request(DIAG_GET_URI).\ 277 filter(lambda p: { 278 DG_TYPE_LIST_TLV, 279 DG_MAC_COUNTERS_TLV 280 } <= set(p.thread_diagnostic.tlv.type) 281 ).\ 282 must_next() 283 pkts.filter_wpan_src64(DUT).\ 284 filter_ipv6_dst(LEADER_RLOC).\ 285 filter_coap_ack(DIAG_GET_URI).\ 286 filter(lambda p: { 287 DG_MAC_COUNTERS_TLV 288 } <= set(p.thread_diagnostic.tlv.type) 289 ).\ 290 must_next() 291 292 # Step 4: Leader to send DIAG_GET.req to DUT’s RLOC. 293 # The DUT MUST respond with a DIAG_GET.rsp response containing 294 # the requested diagnostic TLVs: 295 # CoAP Response Code 296 # 2.04 Changed 297 # CoAP Payload 298 # TLV Type 3 - Timeout MUST be omitted from the response 299 # TLV Type 16 – Child Table TLV 300 pkts.filter_wpan_src64(LEADER).\ 301 filter_ipv6_dst(DUT_RLOC).\ 302 filter_coap_request(DIAG_GET_URI).\ 303 filter(lambda p: { 304 DG_TYPE_LIST_TLV, 305 DG_TIMEOUT_TLV, 306 DG_CHILD_TABLE_TLV 307 } <= set(p.thread_diagnostic.tlv.type) 308 ).\ 309 must_next() 310 pkts.filter_wpan_src64(DUT).\ 311 filter_ipv6_dst(LEADER_RLOC).\ 312 filter_coap_ack(DIAG_GET_URI).\ 313 must_next() 314 315 # Step 5: Leader to send DIAG_GET.req to DUT’s RLOC. 316 # The DUT MUST respond with a DIAG_GET.rsp response containing 317 # the requested diagnostic TLVs: 318 # CoAP Response Code 319 # 2.04 Changed 320 # CoAP Payload 321 # TLV Type 14 – Battery Level (optional) 322 # TLV Type 15 – Supply Voltage (optional) 323 pkts.filter_wpan_src64(LEADER).\ 324 filter_ipv6_dst(DUT_RLOC).\ 325 filter_coap_request(DIAG_GET_URI).\ 326 filter(lambda p: { 327 DG_TYPE_LIST_TLV, 328 DG_BATTERY_LEVEL_TLV, 329 DG_SUPPLY_VOLTAGE_TLV 330 } <= set(p.thread_diagnostic.tlv.type) 331 ).\ 332 must_next() 333 pkts.filter_wpan_src64(DUT).\ 334 filter_ipv6_dst(LEADER_RLOC).\ 335 filter_coap_ack(DIAG_GET_URI).\ 336 must_next() 337 338 # Step 6: Leader to send DIAG_RST.req to DUT’s RLOC for the following diagnostic 339 # TLV type: 340 # TLV Type 9 - MAC Counters 341 # The DUT MUST respond with a CoAP response 342 # CoAP Response Code 343 # 2.04 Changed 344 pkts.filter_wpan_src64(LEADER).\ 345 filter_ipv6_dst(DUT_RLOC).\ 346 filter_coap_request(DIAG_RST_URI).\ 347 filter(lambda p: { 348 DG_TYPE_LIST_TLV, 349 DG_MAC_COUNTERS_TLV 350 } <= set(p.thread_diagnostic.tlv.type) 351 ).\ 352 must_next() 353 pkts.filter_wpan_src64(DUT).\ 354 filter_ipv6_dst(LEADER_RLOC).\ 355 filter_coap_ack(DIAG_RST_URI).\ 356 must_next() 357 358 # Step 7: Leader to send DIAG_GET.req to DUT’s RLOC. 359 # The DUT MUST respond with a DIAG_GET.rsp response containing 360 # the requested diagnostic TLVs: 361 # CoAP Response Code 362 # 2.04 Changed 363 # CoAP Payload 364 # TLV Type 9 - MAC Counters 365 # TLV Type 9 - MAC Counters MUST contain a list of MAC Counters 366 # with 0 value or less than value returned in step 3. 367 pkts.filter_wpan_src64(LEADER).\ 368 filter_ipv6_dst(DUT_RLOC).\ 369 filter_coap_request(DIAG_GET_URI).\ 370 filter(lambda p: { 371 DG_TYPE_LIST_TLV, 372 DG_MAC_COUNTERS_TLV 373 } <= set(p.thread_diagnostic.tlv.type) 374 ).\ 375 must_next() 376 pkts.filter_wpan_src64(DUT).\ 377 filter_ipv6_dst(LEADER_RLOC).\ 378 filter_coap_ack(DIAG_GET_URI).\ 379 filter(lambda p: { 380 DG_MAC_COUNTERS_TLV 381 } <= set(p.thread_diagnostic.tlv.type) 382 ).\ 383 must_next() 384 385 # Step 8: Leader sends DIAG_GET.qry to the Realm-Local All-Thread-Nodes 386 # multicast address containing the requested diagnostic TLVs: 387 # CoAP Response Code 388 # 2.04 Changed 389 # CoAP Payload 390 # TLV Type 0 - MAC Extended Address (64- bit) 391 # TLV Type 1 - MAC Address (16-bit) 392 # TLV Type 2 - Mode (Capability information) 393 # TLV Type 4 – Connectivity 394 # TLV Type 5 – Route64(optional) 395 # TLV Type 6 – Leader Data 396 # TLV Type 7 – Network Data 397 # TLV Type 8 – IPv6 address list 398 # TLV Type 17 – Channel Pagesi 399 dut_payload_tlvs.add(DG_TYPE_LIST_TLV) 400 dut_payload_tlvs.add(DG_ROUTE64_TLV) 401 pkts.filter_wpan_src64(LEADER).\ 402 filter_ipv6_dst(REALM_LOCAL_All_THREAD_NODES_MULTICAST_ADDRESS).\ 403 filter_coap_request(DIAG_GET_QRY_URI).\ 404 filter(lambda p: dut_payload_tlvs <= set(p.thread_diagnostic.tlv.type)).\ 405 must_next() 406 407 dut_payload_tlvs.remove(DG_TYPE_LIST_TLV) 408 dut_payload_tlvs.remove(DG_ROUTE64_TLV) 409 pkts.filter_wpan_src64(DUT).\ 410 filter_ipv6_dst(LEADER_RLOC).\ 411 filter_coap_request(DIAG_GET_ANS_URI).\ 412 filter(lambda p: 413 dut_payload_tlvs <= set(p.thread_diagnostic.tlv.type) and\ 414 {str(p.wpan.src64), colon_hex(dut_addr16, 2), '0f'} 415 < set(p.thread_diagnostic.tlv.general) 416 ).\ 417 must_next() 418 419 420if __name__ == '__main__': 421 unittest.main() 422