From 0883176d316003144677d5f620b79f669c0e561b Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Mon, 30 Mar 2026 12:24:45 -0700 Subject: [PATCH] [nexus] add 1_3_DIAG_TC_2 for Get Diagnostics - End Device (#12791) This commit adds the Nexus test case 1_3_DIAG_TC_2 which verifies that an End Device correctly reports its diagnostic information and MLE counters via Network Diagnostic queries, as per the Thread 1.4 test specification. The implementation includes: - tests/nexus/test_1_3_DIAG_TC_2.cpp: Sets up a topology with a Leader, a Router, and a TD_1 (DUT) configured as a MED. It triggers Network Diagnostic Get queries from the Leader to the DUT for various TLVs including Max Child Timeout, EUI-64, Version, Vendor info, and MLE Counters. - tests/nexus/verify_1_3_DIAG_TC_2.py: Performs automated verification of the captured traffic. It validates the presence and values of requested TLVs (Type 19, 23-28) and ensures that MLE Counters (Type 34) reflect the expected role changes and tracking time. - Integrated the new test into tests/nexus/CMakeLists.txt and tests/nexus/run_nexus_tests.sh. The test ensures the correctness of Thread 1.4 End Device Diagnostic and MLE Counter reporting, facilitating network health monitoring and troubleshooting in a Thread network. --- tests/nexus/CMakeLists.txt | 1 + tests/nexus/run_nexus_tests.sh | 1 + tests/nexus/test_1_3_DIAG_TC_2.cpp | 267 +++++++++++++++++++++++ tests/nexus/verify_1_3_DIAG_TC_2.py | 315 ++++++++++++++++++++++++++++ 4 files changed, 584 insertions(+) create mode 100644 tests/nexus/test_1_3_DIAG_TC_2.cpp create mode 100644 tests/nexus/verify_1_3_DIAG_TC_2.py diff --git a/tests/nexus/CMakeLists.txt b/tests/nexus/CMakeLists.txt index 488750245..b478c74aa 100644 --- a/tests/nexus/CMakeLists.txt +++ b/tests/nexus/CMakeLists.txt @@ -280,6 +280,7 @@ ot_nexus_test(1_3_SRPC_TC_4 "cert;nexus") ot_nexus_test(1_3_SRPC_TC_5 "cert;nexus") ot_nexus_test(1_3_SRPC_TC_7 "cert;nexus") ot_nexus_test(1_3_DIAG_TC_1 "cert;nexus") +ot_nexus_test(1_3_DIAG_TC_2 "cert;nexus") # Misc tests ot_nexus_test(border_admitter "core;nexus") diff --git a/tests/nexus/run_nexus_tests.sh b/tests/nexus/run_nexus_tests.sh index 63db5f2aa..523412787 100755 --- a/tests/nexus/run_nexus_tests.sh +++ b/tests/nexus/run_nexus_tests.sh @@ -215,6 +215,7 @@ DEFAULT_TESTS=( "1_3_SRPC_TC_5" "1_3_SRPC_TC_7" "1_3_DIAG_TC_1" + "1_3_DIAG_TC_2" ) # Use provided arguments or the default test list diff --git a/tests/nexus/test_1_3_DIAG_TC_2.cpp b/tests/nexus/test_1_3_DIAG_TC_2.cpp new file mode 100644 index 000000000..d032a306f --- /dev/null +++ b/tests/nexus/test_1_3_DIAG_TC_2.cpp @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2026, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include "platform/nexus_core.hpp" +#include "platform/nexus_node.hpp" +#include "thread/network_diagnostic.hpp" + +namespace ot { +namespace Nexus { + +/** + * Time to advance for a node to form a network and become leader, in milliseconds. + */ +static constexpr uint32_t kFormNetworkTime = 15 * 1000; + +/** + * Time to advance for a node to join as a child and upgrade to a router, in milliseconds. + */ +static constexpr uint32_t kAttachToRouterTime = 200 * 1000; + +/** + * Time to advance for the diagnostic response to be received. + */ +static constexpr uint32_t kDiagResponseTime = 5 * 1000; + +/** + * Time to wait in Step 4, in milliseconds. + */ +static constexpr uint32_t kWaitTime = 4 * 1000; + +void TestDiagTc2(const char *aJsonFile) +{ + /** + * 4.2. [1.4] [CERT] Get Diagnostics – End Device + * + * 4.2.2. Topology + * - Leader_1 + * - Router_1 + * - TD_1 (DUT) + * + * Spec Reference | Section + * -----------------|--------- + * Thread 1.4 | 4.2 + */ + + Core nexus; + + Node &leader1 = nexus.CreateNode(); + Node &router1 = nexus.CreateNode(); + Node &td1 = nexus.CreateNode(); + + leader1.SetName("Leader_1"); + router1.SetName("Router_1"); + td1.SetName("TD_1"); + + nexus.AdvanceTime(0); + + SuccessOrQuit(Instance::SetGlobalLogLevel(kLogLevelNote)); + + /** + * - Leader_1 and Router_1 + * - Router_1 and TD_1 + */ + leader1.AllowList(router1); + router1.AllowList(leader1); + + router1.AllowList(td1); + td1.AllowList(router1); + + Log("---------------------------------------------------------------------------------------"); + Log("Step 1: Enable the devices in order. Leader configures its Network Data with an OMR prefix."); + + /** + * Step 1 + * - Device: Leader, Router_1 + * - Description (DIAG-4.2): Enable the devices in order. The DUT is not yet activated. Leader + * configures its Network Data with an OMR prefix. Note: the OMR prefix can be added using an + * OT CLI command such as: "prefix add 2001:dead:beef:cafe::/64 paros med" + * - Pass Criteria: + * - Single Thread Network is formed with Leader and Router_1. + */ + leader1.Form(); + nexus.AdvanceTime(kFormNetworkTime); + VerifyOrQuit(leader1.Get().IsLeader()); + + router1.Join(leader1); + nexus.AdvanceTime(kAttachToRouterTime); + VerifyOrQuit(router1.Get().IsRouter()); + + NetworkData::OnMeshPrefixConfig omrPrefixConfig; + SuccessOrQuit(omrPrefixConfig.GetPrefix().FromString("2001:dead:beef:cafe::/64")); + omrPrefixConfig.mPreferred = true; + omrPrefixConfig.mSlaac = true; + omrPrefixConfig.mDhcp = false; + omrPrefixConfig.mDefaultRoute = true; + omrPrefixConfig.mOnMesh = true; + omrPrefixConfig.mStable = true; + omrPrefixConfig.mPreference = NetworkData::kRoutePreferenceMedium; + SuccessOrQuit(leader1.Get().AddOnMeshPrefix(omrPrefixConfig)); + leader1.Get().HandleServerDataUpdated(); + + nexus.AdvanceTime(30 * 1000); // Wait for network data propagation + + Log("---------------------------------------------------------------------------------------"); + Log("Step 1b: TD_1 (DUT) Enable."); + + /** + * Step 1b + * - Device: TD_1 (DUT) + * - Description (DIAG-4.2): Enable. + * - Pass Criteria: + * - N/A + */ + td1.Join(router1, Node::kAsMed); + nexus.AdvanceTime(kAttachToRouterTime); + VerifyOrQuit(td1.Get().IsChild()); + + Log("---------------------------------------------------------------------------------------"); + Log("Step 2: Leader instructs device to send DIAG_GET.req to DUT's RLOC for Diagnostic TLV types."); + + /** + * Step 2 + * - Device: Leader + * - Description (DIAG-4.2): Harness instructs device to send DIAG_GET.req to DUT's RLOC for the + * following Diagnostic TLV types: Type 19: Max Child Timeout TLV, Type 23: EUI-64 TLV, Type + * 24: Version TLV, Type 25: Vendor Name TLV, Type 26: Vendor Model TLV, Type 27: Vendor SW + * Version TLV, Type 28: Thread Stack Version TLV + * - Pass Criteria: + * - N/A + */ + Ip6::Address td1Rloc; + td1Rloc.SetToRoutingLocator(leader1.Get().GetMeshLocalPrefix(), td1.Get().GetRloc16()); + + uint8_t tlvTypesStep2[] = { + NetworkDiagnostic::Tlv::kMaxChildTimeout, + NetworkDiagnostic::Tlv::kEui64, + NetworkDiagnostic::Tlv::kVersion, + NetworkDiagnostic::Tlv::kVendorName, + NetworkDiagnostic::Tlv::kVendorModel, + NetworkDiagnostic::Tlv::kVendorSwVersion, + NetworkDiagnostic::Tlv::kThreadStackVersion, + }; + SuccessOrQuit(leader1.Get().SendDiagnosticGet(td1Rloc, tlvTypesStep2, + sizeof(tlvTypesStep2), nullptr, nullptr)); + + Log("---------------------------------------------------------------------------------------"); + Log("Step 3: TD_1 (DUT) Automatically responds either with 1. DIAG_GET.rsp or 2. CoAP response 4.04."); + + /** + * Step 3 + * - Device: TD_1 (DUT) + * - Description (DIAG-4.2): Automatically responds either with 1. DIAG_GET.rsp containing the + * requested Diagnostic TLVs, or a particular subset of those TLVs; 2. CoAP response 4.04 Not + * Found in case no diagnostics are supported at all. + * - Pass Criteria: + * - For case 1, the CoAP status code MUST be 2.04 Changed. + * - Each TLV (as requested in step 2) that is present in the response MUST be validated. Any + * number of TLVs MAY be present, from 0 to 7, depending on DUT's diagnostics support level. + * - The Max Child Timeout TLV (Type 19) is not expected to be present. However, if present it + * MUST be '0' (zero). + * - Value of EUI-64 TLV (Type 23) MUST be non-zero. + * - Value of Version TLV (Type 24) MUST be >= '5'. + * - Value of Vendor Name TLV (Type 25) MUST have length >= 1. + * - Value of Vendor Model TLV (Type 26) MUST have length >= 1. + * - Value of Vendor SW Version TLV (Type 27) MUST have length >= 5. + * - Value of Thread Stack Version TLV (Type 28) MUST have length >= 5. + * - For case 2, the CoAP status code is 4.04 and TLVs MUST NOT be present. + */ + nexus.AdvanceTime(kDiagResponseTime); + + Log("---------------------------------------------------------------------------------------"); + Log("Step 4: Harness waits for 4 seconds."); + + /** + * Step 4 + * - Device: N/A + * - Description (DIAG-4.2): Harness waits for 4 seconds. Note: this is done only to influence + * diagnostic Time fields that are verified in later steps. + * - Pass Criteria: + * - N/A + */ + nexus.AdvanceTime(kWaitTime); + + Log("---------------------------------------------------------------------------------------"); + Log("Step 4: Leader instructs device to send DIAG_GET.req unicast to DUT's RLOC for MLE Counters TLV."); + + /** + * Step 4 + * - Device: Leader + * - Description (DIAG-4.2): Harness instructs device to send DIAG_GET.req unicast to DUT's RLOC + * for the following Diagnostic TLV types: Type 34: MLE Counters TLV + * - Pass Criteria: + * - N/A + */ + uint8_t tlvTypesStep4[] = {NetworkDiagnostic::Tlv::kMleCounters}; + SuccessOrQuit(leader1.Get().SendDiagnosticGet(td1Rloc, tlvTypesStep4, + sizeof(tlvTypesStep4), nullptr, nullptr)); + + Log("---------------------------------------------------------------------------------------"); + Log("Step 5: TD_1 (DUT) Automatically responds with DIAG_GET.rsp containing the requested Diagnostic TLVs."); + + /** + * Step 5 + * - Device: TD_1 (DUT) + * - Description (DIAG-4.2): Automatically responds with DIAG_GET.rsp containing the requested + * Diagnostic TLVs. + * - Pass Criteria: + * - The DUT must send DIAG_GET.rsp + * - The presence of each TLV (as requested in the previous step) MUST be validated. + * - In the MLE Counters TLV (Type 34): + * - Radio Disabled Counter MUST be '0' + * - Detached Role Counter MUST be '1' + * - Child Role Counter MUST be '1' + * - Router Role Counter MUST be '0' + * - Leader Role Counter MUST be '0' + * - Attach Attempts Counter MUST be >= 1 + * - Partition ID Changes Counter MUST be '1' + * - New Parent Counter MUST be '0' + * - Total Tracking Time MUST be > 4000 + * - Child Role Time MUST be >= 1 + * - Router Role Time MUST be '0' + * - Leader Role Time MUST be '0' + */ + nexus.AdvanceTime(kDiagResponseTime); + + nexus.SaveTestInfo(aJsonFile); +} + +} // namespace Nexus +} // namespace ot + +int main(int argc, char *argv[]) +{ + const char *jsonFile = (argc > 1) ? argv[argc - 1] : "test_1_3_DIAG_TC_2.json"; + + ot::Nexus::TestDiagTc2(jsonFile); + printf("All tests passed\n"); + return 0; +} diff --git a/tests/nexus/verify_1_3_DIAG_TC_2.py b/tests/nexus/verify_1_3_DIAG_TC_2.py new file mode 100644 index 000000000..51a318b7a --- /dev/null +++ b/tests/nexus/verify_1_3_DIAG_TC_2.py @@ -0,0 +1,315 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2026, The OpenThread Authors. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +import sys +import os + +# Add the current directory to sys.path to find verify_utils +CUR_DIR = os.path.dirname(os.path.abspath(__file__)) +sys.path.append(CUR_DIR) + +import verify_utils +from pktverify import consts +from pktverify.bytes import Bytes + +# Diagnostic TLV Types +DG_EUI64_TLV = 23 +DG_VERSION_TLV = 24 +DG_VENDOR_NAME_TLV = 25 +DG_VENDOR_MODEL_TLV = 26 +DG_VENDOR_SW_VERSION_TLV = 27 +DG_THREAD_STACK_VERSION_TLV = 28 +DG_MLE_COUNTERS_TLV = 34 + +COAP_CODE_NOT_FOUND = 132 + + +def read_uint16(b, offset): + return (b[offset] << 8) | b[offset + 1] + + +def read_uint32(b, offset): + return (b[offset] << 24) | (b[offset + 1] << 16) | (b[offset + 2] << 8) | b[offset + 3] + + +def read_uint64(b, offset): + val = 0 + for i in range(8): + val = (val << 8) | b[offset + i] + return val + + +def get_diag_tlvs(p): + """ + Parses Thread Diagnostic TLVs from CoAP payload. + Returns a list of (type, value) tuples. + """ + payload = p.coap.payload + tlvs = [] + offset = 0 + while offset < len(payload): + t = payload[offset] + l = payload[offset + 1] + v = Bytes(payload[offset + 2:offset + 2 + l]) + tlvs.append((t, v)) + offset += 2 + l + return tlvs + + +def get_tlv_value(tlvs, tlv_type): + """ + Returns the value of the first TLV of a given type. + """ + for t, v in tlvs: + if t == tlv_type: + return v + return None + + +def verify(pv): + """ + 4.2. [1.4] [CERT] Get Diagnostics – End Device + + 4.2.2. Topology + - Leader_1 + - Router_1 + - TD_1 (DUT) + + Spec Reference | Section + ---------------|-------- + Thread 1.4 | 4.2 + """ + pkts = pv.pkts + pv.summary.show() + + Leader_1_RLOC = pv.vars['Leader_1_RLOC'] + + # Step 1 + # Device: Leader, Router_1 + # Description (DIAG-4.2): Enable the devices in order. The DUT is not yet activated. Leader + # configures its Network Data with an OMR prefix. Note: the OMR prefix can be added using + # an OT CLI command such as: "prefix add 2001:dead:beef:cafe::/64 paros med" + # Pass Criteria: + # - Single Thread Network is formed with Leader and Router_1. + print("Step 1: Single Thread Network is formed with Leader and Router_1.") + + # Step 1b + # Device: TD_1 (DUT) + # Description (DIAG-4.2): Enable. + # Pass Criteria: + # - N/A + print("Step 1b: TD_1 (DUT) Enable.") + + # Step 2 + # Device: Leader + # Description (DIAG-4.2): Harness instructs device to send DIAG_GET.req to DUT's RLOC for the + # following Diagnostic TLV types: Type 19: Max Child Timeout TLV, Type 23: EUI-64 TLV, Type + # 24: Version TLV, Type 25: Vendor Name TLV, Type 26: Vendor Model TLV, Type 27: Vendor SW + # Version TLV, Type 28: Thread Stack Version TLV + # Pass Criteria: + # - N/A + print("Step 2: Leader sends DIAG_GET.req to DUT's RLOC.") + + # Step 3 + # Device: TD_1 (DUT) + # Description (DIAG-4.2): Automatically responds either with 1. DIAG_GET.rsp containing the + # requested Diagnostic TLVs, or a particular subset of those TLVs; 2. CoAP response 4.04 Not + # Found in case no diagnostics are supported at all. + # Pass Criteria: + # - For case 1, the CoAP status code MUST be 2.04 Changed. + # - Each TLV (as requested in step 2) that is present in the response MUST be validated. Any + # number of TLVs MAY be present, from 0 to 7, depending on DUT's diagnostics support level. + # - The Max Child Timeout TLV (Type 19) is not expected to be present. However, if present it + # MUST be '0' (zero). + # - Value of EUI-64 TLV (Type 23) MUST be non-zero. + # - Value of Version TLV (Type 24) MUST be >= '5'. + # - Value of Vendor Name TLV (Type 25) MUST have length >= 1. + # - Value of Vendor Model TLV (Type 26) MUST have length >= 1. + # - Value of Vendor SW Version TLV (Type 27) MUST have length >= 5. + # - Value of Thread Stack Version TLV (Type 28) MUST have length >= 5. + # - For case 2, the CoAP status code is 4.04 and TLVs MUST NOT be present. + print("Step 3: TD_1 (DUT) responds either with 1. DIAG_GET.rsp or 2. CoAP response 4.04.") + + def check_step3(p): + if p.coap.code == COAP_CODE_NOT_FOUND: + return len(p.coap.payload) == 0 + + if p.coap.code != consts.COAP_CODE_ACK: + return False + + tlvs = get_diag_tlvs(p) + types = {t for t, v in tlvs} + + # Case 1 validation + # Each TLV that is present in the response MUST be validated. + if consts.DG_MAX_CHILD_TIMEOUT_TLV in types: + val = get_tlv_value(tlvs, consts.DG_MAX_CHILD_TIMEOUT_TLV) + if read_uint32(val, 0) != 0: + return False + + if DG_EUI64_TLV in types: + val = get_tlv_value(tlvs, DG_EUI64_TLV) + if read_uint64(val, 0) == 0: + return False + + if DG_VERSION_TLV in types: + val = get_tlv_value(tlvs, DG_VERSION_TLV) + if read_uint16(val, 0) < 5: + return False + + if DG_VENDOR_NAME_TLV in types: + val = get_tlv_value(tlvs, DG_VENDOR_NAME_TLV) + if len(val) < 1: + return False + + if DG_VENDOR_MODEL_TLV in types: + val = get_tlv_value(tlvs, DG_VENDOR_MODEL_TLV) + if len(val) < 1: + return False + + if DG_VENDOR_SW_VERSION_TLV in types: + val = get_tlv_value(tlvs, DG_VENDOR_SW_VERSION_TLV) + if len(val) < 5: + return False + + if DG_THREAD_STACK_VERSION_TLV in types: + val = get_tlv_value(tlvs, DG_THREAD_STACK_VERSION_TLV) + if len(val) < 5: + return False + + return True + + pkts.filter_ipv6_dst(Leader_1_RLOC).\ + filter(lambda p: ( + p.coap.code in (consts.COAP_CODE_ACK, COAP_CODE_NOT_FOUND) and + p.coap.opt.uri_path_recon == consts.DIAG_GET_URI + )).\ + filter(lambda p: ( + check_step3(p) + )).\ + must_next() + + # Step 4 + # Device: N/A + # Description (DIAG-4.2): Harness waits for 4 seconds. Note: this is done only to influence + # diagnostic Time fields that are verified in later steps. + # Pass Criteria: + # - N/A + print("Step 4: Harness waits for 4 seconds.") + + # Step 4 + # Device: Leader + # Description (DIAG-4.2): Harness instructs device to send DIAG_GET.req unicast to DUT's RLOC + # for the following Diagnostic TLV types: Type 34: MLE Counters TLV + # Pass Criteria: + # - N/A + print("Step 4: Leader sends DIAG_GET.req unicast to DUT's RLOC for MLE Counters TLV.") + + # Step 5 + # Device: TD_1 (DUT) + # Description (DIAG-4.2): Automatically responds with DIAG_GET.rsp containing the requested + # Diagnostic TLVs. + # Pass Criteria: + # - The DUT must send DIAG_GET.rsp + # - The presence of each TLV (as requested in the previous step) MUST be validated. + # - In the MLE Counters TLV (Type 34): + # - Radio Disabled Counter MUST be '0' + # - Detached Role Counter MUST be '1' + # - Child Role Counter MUST be '1' + # - Router Role Counter MUST be '0' + # - Leader Role Counter MUST be '0' + # - Attach Attempts Counter MUST be >= 1 + # - Partition ID Changes Counter MUST be '1' + # - New Parent Counter MUST be '0' + # - Total Tracking Time MUST be > 4000 + # - Child Role Time MUST be >= 1 + # - Router Role Time MUST be '0' + # - Leader Role Time MUST be '0' + print("Step 5: TD_1 (DUT) responds with DIAG_GET.rsp.") + + def check_step5(p): + tlvs = get_diag_tlvs(p) + types = {t for t, v in tlvs} + + if DG_MLE_COUNTERS_TLV not in types: + return False + + val = get_tlv_value(tlvs, DG_MLE_COUNTERS_TLV) + if len(val) < 66: + return False + + # Radio Disabled Counter MUST be '0' + if read_uint16(val, 0) != 0: + return False + # Detached Role Counter MUST be '1' + if read_uint16(val, 2) != 1: + return False + # Child Role Counter MUST be '1' + if read_uint16(val, 4) != 1: + return False + # Router Role Counter MUST be '0' + if read_uint16(val, 6) != 0: + return False + # Leader Role Counter MUST be '0' + if read_uint16(val, 8) != 0: + return False + # Attach Attempts Counter MUST be >= 1 + if read_uint16(val, 10) < 1: + return False + # Partition ID Changes Counter MUST be '1' + if read_uint16(val, 12) != 1: + return False + # New Parent Counter MUST be '0' + if read_uint16(val, 16) != 0: + return False + # Total Tracking Time MUST be > 4000 + if read_uint64(val, 18) <= 4000: + return False + # Child Role Time MUST be >= 1 + if read_uint64(val, 42) < 1: + return False + # Router Role Time MUST be '0' + if read_uint64(val, 50) != 0: + return False + # Leader Role Time MUST be '0' + if read_uint64(val, 58) != 0: + return False + + return True + + pkts.filter_ipv6_dst(Leader_1_RLOC).\ + filter_coap_ack(consts.DIAG_GET_URI).\ + filter(lambda p: ( + check_step5(p) + )).\ + must_next() + + +if __name__ == '__main__': + verify_utils.run_main(verify)