mirror of
https://github.com/espressif/openthread.git
synced 2026-08-11 13:17:48 +00:00
[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.
This commit is contained in:
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#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<Mle::Mle>().IsLeader());
|
||||
|
||||
router1.Join(leader1);
|
||||
nexus.AdvanceTime(kAttachToRouterTime);
|
||||
VerifyOrQuit(router1.Get<Mle::Mle>().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<NetworkData::Local>().AddOnMeshPrefix(omrPrefixConfig));
|
||||
leader1.Get<NetworkData::Notifier>().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<Mle::Mle>().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<Mle::Mle>().GetMeshLocalPrefix(), td1.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(leader1.Get<NetworkDiagnostic::Client>().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<NetworkDiagnostic::Client>().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;
|
||||
}
|
||||
@@ -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)
|
||||
Reference in New Issue
Block a user