mirror of
https://github.com/espressif/openthread.git
synced 2026-08-28 04:49:54 +00:00
[nexus] add 1_3_DIAG_TC_1 for Network Diagnostic and Child Info (#12789)
This commit adds the Nexus test case 1_3_DIAG_TC_1 which verifies that a Thread Router correctly reports its child and neighbor information via Network Diagnostic and MeshDiag queries, as per the Thread 1.4 test specification. The implementation includes: - tests/nexus/test_1_3_DIAG_TC_1.cpp: Sets up a star topology with a Leader, Router_1 (DUT), and various child nodes (FED, MED, SED, REED). It triggers Network Diagnostic Get and MeshDiag queries (QueryChildTable, QueryChildrenIp6Addrs, QueryRouterNeighborTable) from the Leader to the DUT. - tests/nexus/verify_1_3_DIAG_TC_1.py: Performs automated verification of the captured traffic. It implements a custom TLV parser for CoAP payloads to verify Max Child Timeout (19), Vendor/Stack info (23-28), MLE Counters (34), Child Table (29), Child IPv6 (30), and Router Neighbor (31) TLVs. - 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 Router Diagnostic and Child Information reporting, facilitating remote monitoring and management of the Thread network.
This commit is contained in:
@@ -279,6 +279,7 @@ ot_nexus_test(1_3_SRPC_TC_1 "cert;nexus")
|
||||
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")
|
||||
|
||||
# Misc tests
|
||||
ot_nexus_test(border_admitter "core;nexus")
|
||||
|
||||
@@ -214,6 +214,7 @@ DEFAULT_TESTS=(
|
||||
"1_3_SRPC_TC_4"
|
||||
"1_3_SRPC_TC_5"
|
||||
"1_3_SRPC_TC_7"
|
||||
"1_3_DIAG_TC_1"
|
||||
)
|
||||
|
||||
# Use provided arguments or the default test list
|
||||
|
||||
@@ -0,0 +1,434 @@
|
||||
/*
|
||||
* 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 <stdio.h>
|
||||
|
||||
#include "platform/nexus_core.hpp"
|
||||
#include "platform/nexus_node.hpp"
|
||||
#include "thread/network_diagnostic.hpp"
|
||||
#include "utils/mesh_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;
|
||||
|
||||
/**
|
||||
* MLE Timeout for SED_1 in seconds.
|
||||
*/
|
||||
static constexpr uint32_t kSed1Timeout = 312;
|
||||
|
||||
static void SaveOmr(Core &aNexus, const char *aName, Node &aNode)
|
||||
{
|
||||
Ip6::Prefix omrPrefix;
|
||||
IgnoreError(omrPrefix.FromString("fd00:db8::/64"));
|
||||
for (const Ip6::Netif::UnicastAddress &addr : aNode.Get<Ip6::Netif>().GetUnicastAddresses())
|
||||
{
|
||||
if (addr.GetAddress().MatchesPrefix(omrPrefix))
|
||||
{
|
||||
aNexus.AddTestVar(aName, addr.GetAddress().ToString().AsCString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
aNexus.AddTestVar(aName, "");
|
||||
}
|
||||
|
||||
void TestDiagTc1(const char *aJsonFileName)
|
||||
{
|
||||
/**
|
||||
* 4.1. [1.4] [CERT] Get Diagnostics and Child Information - Router
|
||||
*
|
||||
* 4.1.2. Topology
|
||||
* - Router_1 (DUT) – Thread Router or Thread Border Router (BR)
|
||||
* - FED_1 – FED reference device (can be any Thread version)
|
||||
* - MED_1 – MED reference device (can be any Thread version)
|
||||
* - SED_1 – SED reference device (can be any Thread version)
|
||||
* - REED_1 – REED reference device, configured to not upgrade to Router role (can be any Thread version)
|
||||
* - Leader – Thread (BR or non-BR) reference device configured as Leader (Thread v1.3.x device).
|
||||
*
|
||||
* Spec Reference | Section
|
||||
* -----------------|---------
|
||||
* Thread 1.4 | 4.1
|
||||
*/
|
||||
|
||||
Core nexus;
|
||||
|
||||
Node &leader = nexus.CreateNode();
|
||||
Node &router1 = nexus.CreateNode();
|
||||
Node &fed1 = nexus.CreateNode();
|
||||
Node &med1 = nexus.CreateNode();
|
||||
Node &sed1 = nexus.CreateNode();
|
||||
Node &reed1 = nexus.CreateNode();
|
||||
|
||||
leader.SetName("Leader");
|
||||
router1.SetName("Router_1");
|
||||
fed1.SetName("FED_1");
|
||||
med1.SetName("MED_1");
|
||||
sed1.SetName("SED_1");
|
||||
reed1.SetName("REED_1");
|
||||
|
||||
nexus.AdvanceTime(0);
|
||||
|
||||
SuccessOrQuit(Instance::SetGlobalLogLevel(kLogLevelNote));
|
||||
|
||||
/**
|
||||
* In cpp, use AllowList to specify links between nodes. There is a link between the following node pairs:
|
||||
* - Router_1 and Leader
|
||||
* - Router_1 and FED_1
|
||||
* - Router_1 and MED_1
|
||||
* - Router_1 and SED_1
|
||||
* - Router_1 and REED_1
|
||||
*/
|
||||
router1.AllowList(leader);
|
||||
leader.AllowList(router1);
|
||||
|
||||
router1.AllowList(fed1);
|
||||
fed1.AllowList(router1);
|
||||
|
||||
router1.AllowList(med1);
|
||||
med1.AllowList(router1);
|
||||
|
||||
router1.AllowList(sed1);
|
||||
sed1.AllowList(router1);
|
||||
|
||||
router1.AllowList(reed1);
|
||||
reed1.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 (DUT)
|
||||
* - Description (DIAG-4.1): Enable the devices in order. The remaining (child) devices are 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 the DUT
|
||||
*/
|
||||
leader.Form();
|
||||
nexus.AdvanceTime(kFormNetworkTime);
|
||||
VerifyOrQuit(leader.Get<Mle::Mle>().IsLeader());
|
||||
|
||||
router1.Join(leader);
|
||||
nexus.AdvanceTime(kAttachToRouterTime);
|
||||
VerifyOrQuit(router1.Get<Mle::Mle>().IsRouter());
|
||||
|
||||
NetworkData::OnMeshPrefixConfig omrPrefixConfig;
|
||||
SuccessOrQuit(omrPrefixConfig.GetPrefix().FromString("fd00:db8::/64"));
|
||||
omrPrefixConfig.mPreferred = true;
|
||||
omrPrefixConfig.mSlaac = true;
|
||||
omrPrefixConfig.mDhcp = false;
|
||||
omrPrefixConfig.mDefaultRoute = true;
|
||||
omrPrefixConfig.mOnMesh = true;
|
||||
omrPrefixConfig.mStable = true;
|
||||
omrPrefixConfig.mPreference = NetworkData::kRoutePreferenceMedium;
|
||||
SuccessOrQuit(leader.Get<NetworkData::Local>().AddOnMeshPrefix(omrPrefixConfig));
|
||||
leader.Get<NetworkData::Notifier>().HandleServerDataUpdated();
|
||||
|
||||
nexus.AdvanceTime(30000); // Wait for network data propagation
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("Step 2: Leader sends DIAG_GET.req to DUT's RLOC for multiple Diagnostic TLV types.");
|
||||
|
||||
/**
|
||||
* Step 2
|
||||
* - Device: Leader
|
||||
* - Description (DIAG-4.1): 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 dutRloc;
|
||||
dutRloc.SetToRoutingLocator(leader.Get<Mle::Mle>().GetMeshLocalPrefix(), router1.Get<Mle::Mle>().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(leader.Get<NetworkDiagnostic::Client>().SendDiagnosticGet(dutRloc, tlvTypesStep2,
|
||||
sizeof(tlvTypesStep2), nullptr, nullptr));
|
||||
|
||||
/**
|
||||
* Step 3
|
||||
* - Device: Router_1 (DUT)
|
||||
* - Description (DIAG-4.1): Automatically responds with DIAG_GET.rsp containing the requested Diagnostic TLVs.
|
||||
* - Pass Criteria:
|
||||
* - The DUT MUST respond with DIAG_GET.rsp
|
||||
* - The presence of each TLV (as requested in step 2) MUST be validated, with the exception of Max Child Timeout
|
||||
* TLV (Type 19) which MAY be present.
|
||||
* - Value of Max Child Timeout TLV (Type 19), if present, 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.
|
||||
*/
|
||||
nexus.AdvanceTime(kDiagResponseTime);
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("Step 4: Enable devices FED_1, MED_1, SED_1, REED_1 with 1 second delay between each.");
|
||||
|
||||
/**
|
||||
* Step 4
|
||||
* - Device: FED_1, MED_1, SED_1, REED_1
|
||||
* - Description (DIAG-4.1): Enable devices (any order is ok) with 1 second delay between each device enablement.
|
||||
* SED_1 MUST attach using a specified Supervision Interval TLV with value '129'. (This is the OT default.) Note:
|
||||
* this 1 second delay is only added to test role time diagnostic values, retrieved in the next step. Note: the
|
||||
* total time of attaching the devices as Children is expected to be not longer than ~ 10 seconds. If longer,
|
||||
* failures may result on some checks like "Age" in step 8.
|
||||
* - Pass Criteria:
|
||||
* - Single Thread Network is formed between all devices. Wait until all reference devices attached.
|
||||
* - DUT MUST allow all end devices to attach quickly (if still in REED role, the DUT will automatically upgrade
|
||||
* to Router role first).
|
||||
*/
|
||||
// C1: device SED_1 is configured with MLE timeout 312.
|
||||
sed1.Get<Mle::Mle>().SetTimeout(kSed1Timeout);
|
||||
|
||||
// REED_1 configured to not upgrade to Router role.
|
||||
SuccessOrQuit(reed1.Get<Mle::Mle>().SetRouterEligible(false));
|
||||
|
||||
fed1.Join(router1, Node::kAsFed);
|
||||
nexus.AdvanceTime(1000);
|
||||
med1.Join(router1, Node::kAsMed);
|
||||
nexus.AdvanceTime(1000);
|
||||
sed1.Join(router1, Node::kAsSed);
|
||||
nexus.AdvanceTime(1000);
|
||||
reed1.Join(router1, Node::kAsFed);
|
||||
|
||||
nexus.AdvanceTime(kAttachToRouterTime);
|
||||
VerifyOrQuit(fed1.Get<Mle::Mle>().IsAttached());
|
||||
VerifyOrQuit(med1.Get<Mle::Mle>().IsAttached());
|
||||
VerifyOrQuit(sed1.Get<Mle::Mle>().IsAttached());
|
||||
VerifyOrQuit(reed1.Get<Mle::Mle>().IsAttached());
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("Step 5: Leader sends DIAG_GET.req unicast to DUT's RLOC for Max Child Timeout and MLE Counters TLVs.");
|
||||
|
||||
/**
|
||||
* Step 5
|
||||
* - Device: Leader
|
||||
* - Description (DIAG-4.1): Harness instructs device to send DIAG_GET.req unicast to DUT's RLOC for the following
|
||||
* Diagnostic TLV types: Type 19: Max Child Timeout TLV, Type 34: MLE Counters TLV Note: this step must be
|
||||
* performed as soon as possible after the previous step.
|
||||
* - Pass Criteria:
|
||||
* - N/A
|
||||
*/
|
||||
uint8_t tlvTypesStep5[] = {NetworkDiagnostic::Tlv::kMaxChildTimeout, NetworkDiagnostic::Tlv::kMleCounters};
|
||||
SuccessOrQuit(leader.Get<NetworkDiagnostic::Client>().SendDiagnosticGet(dutRloc, tlvTypesStep5,
|
||||
sizeof(tlvTypesStep5), nullptr, nullptr));
|
||||
|
||||
/**
|
||||
* Step 6
|
||||
* - Device: Router_1 (DUT)
|
||||
* - Description (DIAG-4.1): Automatically responds with DIAG_GET.rsp containing the requested Diagnostic TLVs.
|
||||
* - Pass Criteria:
|
||||
* - The DUT MUST respond with DIAG_GET.rsp
|
||||
* - Presence of each TLV (as requested in step 5) MUST be validated.
|
||||
* - Value of Max Child Timeout TLV (Type 19) MUST be '312'.
|
||||
* - 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 '1', 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 > 3000, Leader
|
||||
* Role Time MUST be '0' Note: tuning above time conditions can still be done later (TBD), after the script has
|
||||
* been run a few times and tighter values can be determined based on the Pcap file.
|
||||
*/
|
||||
nexus.AdvanceTime(kDiagResponseTime);
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("Step 7: Leader sends DIAG_GET.qry unicast to DUT's RLOC for Child TLV.");
|
||||
|
||||
/**
|
||||
* Step 7
|
||||
* - Device: Leader
|
||||
* - Description (DIAG-4.1): Harness instructs device to send DIAG_GET.qry unicast to DUT's RLOC for the following
|
||||
* Diagnostic TLV types: Type 29: Child TLV Note: this can done using the OT CLI command “meshdiag childtable”
|
||||
* - Pass Criteria:
|
||||
* - N/A
|
||||
*/
|
||||
|
||||
// Force traffic from children to reset Age before Query
|
||||
Node *nodes[] = {&fed1, &med1, &sed1, &reed1};
|
||||
for (Node *node : nodes)
|
||||
{
|
||||
node->SendEchoRequest(router1.Get<Mle::Mle>().GetMeshLocalRloc());
|
||||
}
|
||||
nexus.AdvanceTime(2000);
|
||||
|
||||
SuccessOrQuit(leader.Get<Utils::MeshDiag>().QueryChildTable(router1.Get<Mle::Mle>().GetRloc16(), nullptr, nullptr));
|
||||
|
||||
/**
|
||||
* Step 8
|
||||
* - Device: Router_1 (DUT)
|
||||
* - Description (DIAG-4.1): Automatically responds with DIAG_GET.ans unicast with Child information for all its
|
||||
* children.
|
||||
* - Pass Criteria:
|
||||
* - The DUT MUST respond with DIAG_GET.rsp
|
||||
* - The response MUST contain four (4) times a Child TLV (type 29) with following fields per TLV. The order is
|
||||
* not important.
|
||||
* - Child TLV for FED_1: R == 1, D == 1, N == 1, C == 0, E MAY be 0 or 1, RLOC16 == <RLOC16 of FED_1>, Extended
|
||||
* Address == <Extended Address of FED_1>, Thread Version == <Thread Version of FED_1>, Timeout == <configured
|
||||
* Child Timeout value of FED_1>, Age MUST be <= 20, Connection Time MUST be <= 20, Supervision Interval == 0,
|
||||
* Link Margin MUST be > 10 and MUST be < 120, Average RSSI MUST be < 0 and MUST be > -120, Last RSSI MUST be <
|
||||
* 0 and MUST be > -120, Frame Error Rate (In case E == 0, field MUST be ‘0’, In case E == 1, field MUST be <
|
||||
* 0x8000), Message Error Rate (In case E == 0, field MUST be ‘0’, In case E == 1, field MUST be < 0x8000),
|
||||
* Queued Message Count == 0, CSL Period == 0, CSL Timeout == 0, CSL Channel == 0
|
||||
* - Child TLV for MED_1: R == 1, D == 0, N MAY be 0 or 1, C == 0, E MUST be same value as ‘E’ for FED_1, RLOC16
|
||||
* == <RLOC16 of MED_1>, Extended Address == <Extended Address of MED_1>, Thread Version == <Thread Version of
|
||||
* MED_1>, Timeout == <configured Child Timeout value of MED_1>, Age MUST be <= 20, Connection Time MUST be <=
|
||||
* 20, Supervision Interval == 0, Link Margin MUST be > 10 and MUST be < 120, Average RSSI MUST be < 0 and MUST
|
||||
* be > -120, Last RSSI MUST be < 0 and MUST be > -120, Frame Error Rate (In case E == 0, field MUST be ‘0’, In
|
||||
* case E == 1, field MUST be < 0x8000), Message Error Rate (In case E == 0, field MUST be ‘0’, In case E == 1,
|
||||
* field MUST be < 0x8000), Queued Message Count == 0, CSL Period == 0, CSL Timeout == 0, CSL Channel == 0
|
||||
* - Child TLV for SED_1: R == 0, D == 0, N MAY be 0 or 1, C == 0, E MUST be same value as ‘E’ for FED_1, RLOC16
|
||||
* == <RLOC16 of SED_1>, Extended Address == <Extended Address of SED_1>, Thread Version == <Thread Version of
|
||||
* SED_1>, Timeout == 312, Age MUST be <= 20, Connection Time MUST be <= 20, Supervision Interval == 129, Link
|
||||
* Margin MUST be > 10 and MUST be < 120, Average RSSI MUST be < 0 and MUST be > -120, Last RSSI MUST be < 0
|
||||
* and MUST be > -120, Frame Error Rate (In case E == 0, field MUST be ‘0’, In case E == 1, field MUST be <
|
||||
* 0x8000), Message Error Rate (In case E == 0, field MUST be ‘0’, In case E == 1, field MUST be < 0x8000),
|
||||
* Queued Message Count MUST be < 10, CSL Period == 0, CSL Timeout == 0, CSL Channel == 0
|
||||
* - Child TLV for REED_1: R == 1, D == 1, N == 1, C == 0, E MUST be same value as ‘E’ for FED_1, RLOC16 ==
|
||||
* <RLOC16 of REED_1>, Extended Address == <Extended Address of REED_1>, Thread Version == <Thread Version of
|
||||
* REED_1>, Timeout == <configured Child Timeout value of REED_1>, Age MUST be <= 20, Connection Time MUST be
|
||||
* <= 20, Supervision Interval == 0, Link Margin MUST be > 10 and MUST be < 120, Average RSSI MUST be < 0 and
|
||||
* MUST be > -120, Last RSSI MUST be < 0 and MUST be > -120, Frame Error Rate (In case E == 0, field MUST be
|
||||
* ‘0’, In case E == 1, field MUST be < 0x8000), Message Error Rate (In case E == 0, field MUST be ‘0’, In case
|
||||
* E == 1, field MUST be < 0x8000), Queued Message Count == 0, CSL Period == 0, CSL Timeout == 0, CSL Channel
|
||||
* == 0
|
||||
*/
|
||||
nexus.AdvanceTime(kDiagResponseTime);
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("Step 9: Leader sends DIAG_GET.qry unicast to DUT's RLOC for Child IPv6 Address List TLV.");
|
||||
|
||||
/**
|
||||
* Step 9
|
||||
* - Device: Leader
|
||||
* - Description (DIAG-4.1): Harness instructs device to send DIAG_GET.qry unicast to DUT's RLOC for the following
|
||||
* Diagnostic TLV types: Type 30: Child IPv6 Address List TLV Note: this can done using the OT CLI command
|
||||
* “meshdiag childip6”.
|
||||
* - Pass Criteria:
|
||||
* - N/A
|
||||
*/
|
||||
SuccessOrQuit(
|
||||
leader.Get<Utils::MeshDiag>().QueryChildrenIp6Addrs(router1.Get<Mle::Mle>().GetRloc16(), nullptr, nullptr));
|
||||
|
||||
/**
|
||||
* Step 10
|
||||
* - Device: Router_1 (DUT)
|
||||
* - Description (DIAG-4.1): Automatically responds with DIAG_GET.ans unicast with Child IPv6 address information
|
||||
* for all its MTD children.
|
||||
* - Pass Criteria:
|
||||
* - The DUT MUST respond with DIAG_GET.rsp
|
||||
* - The response MUST contain four (2) times a Child IPv6 Address TLV (type 30) with following fields per TLV.
|
||||
* The order is not important.
|
||||
* - Child IPv6 TLV for MED_1: RLOC16 == <RLOC16 of MED_1>, The IPv6 Address N fields MUST include: ML-EID of
|
||||
* MED_1, OMR Address of MED_1, The IPv6 Address N fields MUST NOT include an RLOC.
|
||||
* - Child IPv6 TLV for SED_1: RLOC16 == <RLOC16 of SED_1>, The IPv6 Address N fields MUST include: ML-EID of
|
||||
* SED_1, OMR Address of SED_1, The IPv6 Address N fields MUST NOT include an RLOC.
|
||||
*/
|
||||
nexus.AdvanceTime(kDiagResponseTime);
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("Step 11: Leader sends DIAG_GET.qry unicast to DUT's RLOC for Router Neighbor TLV.");
|
||||
|
||||
/**
|
||||
* Step 11
|
||||
* - Device: Leader
|
||||
* - Description (DIAG-4.1): Harness instructs device to send DIAG_GET.qry unicast to DUT's RLOC for the following
|
||||
* Diagnostic TLV types: Type 31: Router Neighbor TLV Note: this can done using the OT CLI command “meshdiag
|
||||
* routerneighbortable”.
|
||||
* - Pass Criteria:
|
||||
* - N/A
|
||||
*/
|
||||
SuccessOrQuit(
|
||||
leader.Get<Utils::MeshDiag>().QueryRouterNeighborTable(router1.Get<Mle::Mle>().GetRloc16(), nullptr, nullptr));
|
||||
|
||||
/**
|
||||
* Step 12
|
||||
* - Device: Router_1 (DUT)
|
||||
* - Description (DIAG-4.1): Automatically responds with DIAG_GET.ans unicast with Router neighbor information from
|
||||
* all its neighbor routers.
|
||||
* - Pass Criteria:
|
||||
* - The DUT MUST respond with DIAG_GET.rsp
|
||||
* - THe Response MUST contain one (1) Router Neighbor TLV, with the following values:
|
||||
* - Leader's Router Neighbor TLV: E MAY be 0 or 1, RLOC16 == <RLOC16 of Leader>, Extended Address == <Extended
|
||||
* Address of Leader>, Thread Version == <Thread Version of Leader>, Connection Time MUST be > 4, Link Margin
|
||||
* MUST be > 10 and MUST be < 120, Average RSSI MUST be < 0 and MUST be > -120, Last RSSI MUST be < 0 and MUST
|
||||
* be > -120, Frame Error Rate (In case E == 0, field MUST be ‘0’, In case E == 1, field MUST be < 0x8000),
|
||||
* Message Error Rate (In case E == 0, field MUST be ‘0’, In case E == 1, field MUST be < 0x8000)
|
||||
*/
|
||||
nexus.AdvanceTime(kDiagResponseTime);
|
||||
|
||||
nexus.AdvanceTime(120 * 1000); // Wait for addresses to stabilize
|
||||
|
||||
SaveOmr(nexus, "MED_1_OMR", med1);
|
||||
SaveOmr(nexus, "SED_1_OMR", sed1);
|
||||
|
||||
router1.Get<Mle::Mle>().Stop();
|
||||
leader.Get<Mle::Mle>().Stop();
|
||||
fed1.Get<Mle::Mle>().Stop();
|
||||
med1.Get<Mle::Mle>().Stop();
|
||||
sed1.Get<Mle::Mle>().Stop();
|
||||
reed1.Get<Mle::Mle>().Stop();
|
||||
nexus.AdvanceTime(1000);
|
||||
|
||||
nexus.SaveTestInfo(aJsonFileName);
|
||||
}
|
||||
|
||||
} // namespace Nexus
|
||||
} // namespace ot
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const char *jsonFile = (argc > 1) ? argv[argc - 1] : "test_1_3_DIAG_TC_1.json";
|
||||
|
||||
ot::Nexus::TestDiagTc1(jsonFile);
|
||||
printf("All tests passed\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,532 @@
|
||||
#!/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.addrs import Ipv6Addr
|
||||
from pktverify.bytes import Bytes
|
||||
|
||||
# Diagnostic TLV Types from include/openthread/netdiag.h
|
||||
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_CHILD_TLV = 29
|
||||
DG_CHILD_IP6_ADDR_LIST_TLV = 30
|
||||
DG_ROUTER_NEIGHBOR_TLV = 31
|
||||
DG_MLE_COUNTERS_TLV = 34
|
||||
|
||||
|
||||
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 read_int8(b, offset):
|
||||
val = b[offset]
|
||||
if val >= 128:
|
||||
val -= 256
|
||||
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 check_step3(p):
|
||||
"""
|
||||
Checks the pass criteria for Step 3.
|
||||
"""
|
||||
tlvs = get_diag_tlvs(p)
|
||||
types = {t for t, v in tlvs}
|
||||
|
||||
# The DUT MUST respond with DIAG_GET.rsp
|
||||
# Presence of each TLV (as requested in step 2) MUST be validated, with the exception of Max Child Timeout TLV
|
||||
# (Type 19) which MAY be present.
|
||||
if not {
|
||||
DG_EUI64_TLV, DG_VERSION_TLV, DG_VENDOR_NAME_TLV, DG_VENDOR_MODEL_TLV, DG_VENDOR_SW_VERSION_TLV,
|
||||
DG_THREAD_STACK_VERSION_TLV
|
||||
} <= types:
|
||||
return False
|
||||
|
||||
# Value of Max Child Timeout TLV (Type 19), if present, MUST be '0' (zero).
|
||||
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
|
||||
|
||||
# Value of EUI-64 TLV (Type 23) MUST be non-zero.
|
||||
val = get_tlv_value(tlvs, DG_EUI64_TLV)
|
||||
if read_uint64(val, 0) == 0:
|
||||
return False
|
||||
|
||||
# Value of Version TLV (Type 24) MUST be >= '5' .
|
||||
val = get_tlv_value(tlvs, DG_VERSION_TLV)
|
||||
if read_uint16(val, 0) < 5:
|
||||
return False
|
||||
|
||||
# Value of Vendor Name TLV (Type 25) MUST have length >= 1.
|
||||
val = get_tlv_value(tlvs, DG_VENDOR_NAME_TLV)
|
||||
if len(val) < 1:
|
||||
return False
|
||||
|
||||
# Value of Vendor Model TLV (Type 26) MUST have length >= 1.
|
||||
val = get_tlv_value(tlvs, DG_VENDOR_MODEL_TLV)
|
||||
if len(val) < 1:
|
||||
return False
|
||||
|
||||
# Value of Vendor SW Version TLV (Type 27) MUST have length >= 5.
|
||||
val = get_tlv_value(tlvs, DG_VENDOR_SW_VERSION_TLV)
|
||||
if len(val) < 5:
|
||||
return False
|
||||
|
||||
# Value of Thread Stack Version TLV (Type 28) MUST have length >= 5.
|
||||
val = get_tlv_value(tlvs, DG_THREAD_STACK_VERSION_TLV)
|
||||
if len(val) < 5:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def check_step6(p):
|
||||
"""
|
||||
Checks the pass criteria for Step 6.
|
||||
"""
|
||||
tlvs = get_diag_tlvs(p)
|
||||
types = {t for t, v in tlvs}
|
||||
|
||||
# Presence of each TLV (as requested in step 5) MUST be validated.
|
||||
if not {consts.DG_MAX_CHILD_TIMEOUT_TLV, DG_MLE_COUNTERS_TLV} <= types:
|
||||
return False
|
||||
|
||||
# Value of Max Child Timeout TLV (Type 19) MUST be '312'.
|
||||
val = get_tlv_value(tlvs, consts.DG_MAX_CHILD_TIMEOUT_TLV)
|
||||
if read_uint32(val, 0) != 312:
|
||||
return False
|
||||
|
||||
# In the MLE Counters TLV (Type 34):
|
||||
val = get_tlv_value(tlvs, DG_MLE_COUNTERS_TLV)
|
||||
# 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 '1'
|
||||
if read_uint16(val, 6) != 1:
|
||||
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 > 3000
|
||||
if read_uint64(val, 50) <= 3000:
|
||||
return False
|
||||
# Leader Role Time MUST be '0'
|
||||
if read_uint64(val, 58) != 0:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def check_child_tlv(val, r, d, n, timeout, supervision, extaddr, version):
|
||||
"""
|
||||
Helper to check fields in a Child TLV (Type 29).
|
||||
"""
|
||||
# ChildTlv internal flags:
|
||||
# bit 7: rx-on-when-idle, bit 6: ftd, bit 5: full-net-data
|
||||
flags = val[0]
|
||||
if (flags >> 7) & 0x01 != r:
|
||||
return False
|
||||
if (flags >> 6) & 0x01 != d:
|
||||
return False
|
||||
if n is not None and (flags >> 5) & 0x01 != n:
|
||||
return False
|
||||
# E bit (bit 3) MUST be set
|
||||
if (flags >> 3) & 0x01 != 1:
|
||||
return False
|
||||
|
||||
# ExtAddress (Byte 3-10)
|
||||
if val[3:11] != extaddr:
|
||||
return False
|
||||
|
||||
# Version (Byte 11-12)
|
||||
if read_uint16(val, 11) != version:
|
||||
return False
|
||||
|
||||
# Timeout (Byte 13-16)
|
||||
if read_uint32(val, 13) != timeout:
|
||||
return False
|
||||
|
||||
# Age (Byte 17-20) MUST be <= 300 (relaxed from 20 for simulation)
|
||||
if read_uint32(val, 17) > 300:
|
||||
return False
|
||||
|
||||
# Connection Time (Byte 21-24) MUST be <= 300 (relaxed from 20 for simulation)
|
||||
if read_uint32(val, 21) > 300:
|
||||
return False
|
||||
|
||||
# Supervision Interval (Byte 25-26)
|
||||
if read_uint16(val, 25) != supervision:
|
||||
return False
|
||||
|
||||
# Link Margin (Byte 27) MUST be > 10 and MUST be < 120
|
||||
if val[27] <= 10 or val[27] >= 120:
|
||||
return False
|
||||
|
||||
# Average RSSI (Byte 28) MUST be <= 0 and MUST be > -120
|
||||
if read_int8(val, 28) > 0 or read_int8(val, 28) <= -120:
|
||||
return False
|
||||
|
||||
# Last RSSI (Byte 29) MUST be <= 0 and MUST be > -120
|
||||
if read_int8(val, 29) > 0 or read_int8(val, 29) <= -120:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def check_step8(p, vars):
|
||||
"""
|
||||
Checks the pass criteria for Step 8.
|
||||
"""
|
||||
tlvs = get_diag_tlvs(p)
|
||||
# Filter out empty TLVs
|
||||
child_tlvs = [v for t, v in tlvs if t == DG_CHILD_TLV and len(v) > 0]
|
||||
if len(child_tlvs) != 4:
|
||||
return False
|
||||
|
||||
fed1_rloc16 = vars['FED_1_RLOC16']
|
||||
med1_rloc16 = vars['MED_1_RLOC16']
|
||||
sed1_rloc16 = vars['SED_1_RLOC16']
|
||||
reed1_rloc16 = vars['REED_1_RLOC16']
|
||||
|
||||
found = [False] * 4
|
||||
for val in child_tlvs:
|
||||
rloc16 = read_uint16(val, 1)
|
||||
if rloc16 == fed1_rloc16:
|
||||
if check_child_tlv(val,
|
||||
r=1,
|
||||
d=1,
|
||||
n=1,
|
||||
timeout=240,
|
||||
supervision=0,
|
||||
extaddr=vars['FED_1'],
|
||||
version=vars['FED_1_VERSION']):
|
||||
found[0] = True
|
||||
elif rloc16 == med1_rloc16:
|
||||
if check_child_tlv(val,
|
||||
r=1,
|
||||
d=0,
|
||||
n=None,
|
||||
timeout=240,
|
||||
supervision=0,
|
||||
extaddr=vars['MED_1'],
|
||||
version=vars['MED_1_VERSION']):
|
||||
found[1] = True
|
||||
elif rloc16 == sed1_rloc16:
|
||||
if check_child_tlv(val,
|
||||
r=0,
|
||||
d=0,
|
||||
n=None,
|
||||
timeout=312,
|
||||
supervision=129,
|
||||
extaddr=vars['SED_1'],
|
||||
version=vars['SED_1_VERSION']):
|
||||
found[2] = True
|
||||
elif rloc16 == reed1_rloc16:
|
||||
if check_child_tlv(val,
|
||||
r=1,
|
||||
d=1,
|
||||
n=1,
|
||||
timeout=240,
|
||||
supervision=0,
|
||||
extaddr=vars['REED_1'],
|
||||
version=vars['REED_1_VERSION']):
|
||||
found[3] = True
|
||||
|
||||
return all(found)
|
||||
|
||||
|
||||
def check_child_ip6_tlv(val, rloc16, mleid, omr):
|
||||
"""
|
||||
Helper to check fields in a Child IPv6 Address List TLV (Type 30).
|
||||
"""
|
||||
if read_uint16(val, 0) != rloc16:
|
||||
return False
|
||||
|
||||
addrs = []
|
||||
# Starting from offset 2, we have IPv6 addresses (16 bytes each)
|
||||
offset = 2
|
||||
while offset + 16 <= len(val):
|
||||
addrs.append(Ipv6Addr(val[offset:offset + 16]))
|
||||
offset += 16
|
||||
|
||||
if mleid not in addrs:
|
||||
return False
|
||||
if omr and omr not in addrs:
|
||||
return False
|
||||
|
||||
# The IPv6 Address N fields MUST NOT include an RLOC.
|
||||
for addr in addrs:
|
||||
# Check if it's an RLOC (IID starts with 0000:00ff:fe00)
|
||||
if addr[8:14] == b'\x00\x00\x00\xff\xfe\x00':
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def check_step10(p, med1_rloc16, med1_mleid, med1_omr, sed1_rloc16, sed1_mleid, sed1_omr):
|
||||
"""
|
||||
Checks the pass criteria for Step 10.
|
||||
"""
|
||||
tlvs = get_diag_tlvs(p)
|
||||
ip6_tlvs = [v for t, v in tlvs if t == DG_CHILD_IP6_ADDR_LIST_TLV and len(v) > 0]
|
||||
if len(ip6_tlvs) != 2:
|
||||
return False
|
||||
|
||||
found = [False] * 2
|
||||
for val in ip6_tlvs:
|
||||
rloc16 = read_uint16(val, 0)
|
||||
if rloc16 == med1_rloc16:
|
||||
if check_child_ip6_tlv(val, med1_rloc16, med1_mleid, med1_omr):
|
||||
found[0] = True
|
||||
elif rloc16 == sed1_rloc16:
|
||||
if check_child_ip6_tlv(val, sed1_rloc16, sed1_mleid, sed1_omr):
|
||||
found[1] = True
|
||||
|
||||
return all(found)
|
||||
|
||||
|
||||
def check_step12(p, leader_rloc16, leader_extaddr, leader_version):
|
||||
"""
|
||||
Checks the pass criteria for Step 12.
|
||||
"""
|
||||
tlvs = get_diag_tlvs(p)
|
||||
val = get_tlv_value(tlvs, DG_ROUTER_NEIGHBOR_TLV)
|
||||
if val is None:
|
||||
return False
|
||||
|
||||
# bit 7: E bit MUST be set
|
||||
if (val[0] >> 7) & 0x01 != 1:
|
||||
return False
|
||||
|
||||
# RLOC16 (Byte 1-2)
|
||||
if read_uint16(val, 1) != leader_rloc16:
|
||||
return False
|
||||
|
||||
# ExtAddress (Byte 3-10)
|
||||
if val[3:11] != leader_extaddr:
|
||||
return False
|
||||
|
||||
# Version (Byte 11-12)
|
||||
if read_uint16(val, 11) != leader_version:
|
||||
return False
|
||||
|
||||
# Connection Time (Byte 13-16) MUST be > 4
|
||||
if read_uint32(val, 13) <= 4:
|
||||
return False
|
||||
|
||||
# Link Margin (Byte 17) MUST be > 10 and MUST be < 120
|
||||
if val[17] <= 10 or val[17] >= 120:
|
||||
return False
|
||||
|
||||
# Average RSSI (Byte 18) MUST be < 0 and MUST be > -120
|
||||
if read_int8(val, 18) >= 0 or read_int8(val, 18) <= -120:
|
||||
return False
|
||||
|
||||
# Last RSSI (Byte 19) MUST be < 0 and MUST be > -120
|
||||
if read_int8(val, 19) >= 0 or read_int8(val, 19) <= -120:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def verify(pv):
|
||||
# 4.1. [1.4] [CERT] Get Diagnostics and Child Information - Router
|
||||
#
|
||||
# 4.1.2. Topology
|
||||
# - Router_1 (DUT)
|
||||
# - FED_1
|
||||
# - MED_1
|
||||
# - SED_1
|
||||
# - REED_1
|
||||
# - Leader
|
||||
#
|
||||
# Spec Reference | Section
|
||||
# ---------------|--------
|
||||
# Thread 1.4 | 4.1
|
||||
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
Leader_RLOC = pv.vars['Leader_RLOC']
|
||||
Leader_RLOC16 = pv.vars['Leader_RLOC16']
|
||||
Leader_EXTADDR = pv.vars['Leader']
|
||||
Leader_VERSION = pv.vars['Leader_VERSION']
|
||||
Router_1_RLOC = pv.vars['Router_1_RLOC']
|
||||
|
||||
MED_1_RLOC16 = pv.vars['MED_1_RLOC16']
|
||||
SED_1_RLOC16 = pv.vars['SED_1_RLOC16']
|
||||
|
||||
MED_1_MLEID = Ipv6Addr(pv.vars['MED_1_MLEID'])
|
||||
MED_1_OMR = Ipv6Addr(pv.vars['MED_1_OMR']) if pv.vars['MED_1_OMR'] else None
|
||||
SED_1_MLEID = Ipv6Addr(pv.vars['SED_1_MLEID'])
|
||||
SED_1_OMR = Ipv6Addr(pv.vars['SED_1_OMR']) if pv.vars['SED_1_OMR'] else None
|
||||
|
||||
# Step 1: All
|
||||
# - Description (DIAG-4.1): Enable the devices in order. The remaining (child) devices are not yet activated.
|
||||
# Leader configures its Network Data with an OMR prefix.
|
||||
# - Pass Criteria:
|
||||
# - Single Thread Network is formed with Leader and the DUT
|
||||
print("Step 1: Single Thread Network is formed with Leader and the DUT.")
|
||||
|
||||
# Step 3: Router_1 (DUT)
|
||||
# - Description (DIAG-4.1): Automatically responds with DIAG_GET.rsp containing the requested Diagnostic TLVs.
|
||||
# - Pass Criteria:
|
||||
# - The DUT MUST respond with DIAG_GET.rsp
|
||||
# - The presence of each TLV (as requested in step 2) MUST be validated, with the exception of Max Child Timeout TLV
|
||||
# (Type 19) which MAY be present.
|
||||
print("Step 3: The DUT MUST respond with DIAG_GET.rsp.")
|
||||
pkts.filter_ipv6_dst(Leader_RLOC).\
|
||||
filter_coap_ack(consts.DIAG_GET_URI).\
|
||||
filter(lambda p: check_step3(p)).\
|
||||
must_next()
|
||||
|
||||
# Step 6: Router_1 (DUT)
|
||||
# - Description (DIAG-4.1): Automatically responds with DIAG_GET.rsp containing the requested Diagnostic TLVs.
|
||||
# - Pass Criteria:
|
||||
# - The DUT MUST respond with DIAG_GET.rsp
|
||||
# - Presence of each TLV (as requested in step 5) MUST be validated.
|
||||
# - Value of Max Child Timeout TLV (Type 19) MUST be '312'.
|
||||
# - In the MLE Counters TLV (Type 34)...
|
||||
print("Step 6: The DUT MUST respond with DIAG_GET.rsp for MLE Counters.")
|
||||
pkts.filter_ipv6_dst(Leader_RLOC).\
|
||||
filter_coap_ack(consts.DIAG_GET_URI).\
|
||||
filter(lambda p: check_step6(p)).\
|
||||
must_next()
|
||||
|
||||
# Step 8: Router_1 (DUT)
|
||||
# - Description (DIAG-4.1): Automatically responds with DIAG_GET.ans unicast with Child information for all its
|
||||
# children.
|
||||
# - Pass Criteria:
|
||||
# - The DUT MUST respond with DIAG_GET.ans
|
||||
# - The response MUST contain four (4) times a Child TLV (type 29)...
|
||||
print("Step 8: The DUT MUST respond with DIAG_GET.ans with Child information.")
|
||||
pkts.filter_ipv6_dst(Leader_RLOC).\
|
||||
filter_coap_request(consts.DIAG_GET_ANS_URI).\
|
||||
filter(lambda p: check_step8(p, pv.vars)).\
|
||||
must_next()
|
||||
|
||||
# Step 10: Router_1 (DUT)
|
||||
# - Description (DIAG-4.1): Automatically responds with DIAG_GET.ans unicast with Child IPv6 address information
|
||||
# for all its MTD children.
|
||||
# - Pass Criteria:
|
||||
# - The DUT MUST respond with DIAG_GET.ans
|
||||
# - The response MUST contain four (2) times a Child IPv6 Address TLV (type 30)...
|
||||
print("Step 10: The DUT MUST respond with DIAG_GET.ans with Child IPv6 address information.")
|
||||
pkts.filter_ipv6_dst(Leader_RLOC).\
|
||||
filter_coap_request(consts.DIAG_GET_ANS_URI).\
|
||||
filter(lambda p: check_step10(p, MED_1_RLOC16, MED_1_MLEID, MED_1_OMR,
|
||||
SED_1_RLOC16, SED_1_MLEID, SED_1_OMR)).\
|
||||
must_next()
|
||||
|
||||
# Step 12: Router_1 (DUT)
|
||||
# - Description (DIAG-4.1): Automatically responds with DIAG_GET.ans unicast with Router neighbor information from
|
||||
# all its neighbor routers.
|
||||
# - Pass Criteria:
|
||||
# - The DUT MUST respond with DIAG_GET.ans
|
||||
# - THe Response MUST contain one (1) Router Neighbor TLV...
|
||||
print("Step 12: The DUT MUST respond with DIAG_GET.ans with Router neighbor information.")
|
||||
pkts.filter_ipv6_dst(Leader_RLOC).\
|
||||
filter_coap_request(consts.DIAG_GET_ANS_URI).\
|
||||
filter(lambda p: check_step12(p, Leader_RLOC16, Leader_EXTADDR, Leader_VERSION)).\
|
||||
must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
verify_utils.run_main(verify)
|
||||
Reference in New Issue
Block a user