/* * 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/net_diag.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)); AllowLinkBetween(leader1, router1); AllowLinkBetween(router1, td1); 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 = td1.Get().GetMeshLocalRloc(); uint8_t tlvTypesStep2[] = { NetDiag::Tlv::kMaxChildTimeout, NetDiag::Tlv::kEui64, NetDiag::Tlv::kVersion, NetDiag::Tlv::kVendorName, NetDiag::Tlv::kVendorModel, NetDiag::Tlv::kVendorSwVersion, NetDiag::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[] = {NetDiag::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; }