mirror of
https://github.com/espressif/openthread.git
synced 2026-07-26 13:59:05 +00:00
[nexus] add SRPC-TC-4 for service removal by SRP client (#12780)
This commit adds the Nexus test case 1_3_SRPC_TC_4 which verifies that an SRP client can correctly remove one service while leaving other services registered, as per the Thread 1.3 test specification. The implementation includes: - tests/nexus/test_1_3_SRPC_TC_4.cpp: Executes the test sequence by configuring a Border Router (BR_1) and an End Device (TD_1 as DUT). It instructs the DUT to register two services and then remove the first service. It verifies that the SRP server handles the removal correctly and only provides the remaining service in subsequent DNS PTR queries. - tests/nexus/verify_1_3_SRPC_TC_4.py: Performs automated verification of the captured traffic (PCAP). It validates the SRP Update messages for service registration and removal, and checks that the DNS response from BR_1 only contains the expected service. - Integrated the new test into tests/nexus/CMakeLists.txt and tests/nexus/run_nexus_tests.sh. The test ensures the correctness of SRP client service removal logic and SRP server state management.
This commit is contained in:
@@ -276,6 +276,7 @@ ot_nexus_test(1_3_SRP_TC_12 "cert;nexus")
|
||||
ot_nexus_test(1_3_SRP_TC_13 "cert;nexus")
|
||||
ot_nexus_test(1_3_SRP_TC_15 "cert;nexus")
|
||||
ot_nexus_test(1_3_SRPC_TC_1 "cert;nexus")
|
||||
ot_nexus_test(1_3_SRPC_TC_4 "cert;nexus")
|
||||
|
||||
# Misc tests
|
||||
ot_nexus_test(border_admitter "core;nexus")
|
||||
|
||||
@@ -211,6 +211,7 @@ DEFAULT_TESTS=(
|
||||
"1_3_SRP_TC_13"
|
||||
"1_3_SRP_TC_15"
|
||||
"1_3_SRPC_TC_1"
|
||||
"1_3_SRPC_TC_4"
|
||||
)
|
||||
|
||||
# Use provided arguments or the default test list
|
||||
|
||||
@@ -0,0 +1,351 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
namespace ot {
|
||||
namespace Nexus {
|
||||
|
||||
/**
|
||||
* Time to advance for a node to form a network and become leader, in milliseconds.
|
||||
*/
|
||||
static constexpr uint32_t kFormNetworkTime = 13 * 1000;
|
||||
|
||||
/**
|
||||
* Time to advance for a node to join a network, in milliseconds.
|
||||
*/
|
||||
static constexpr uint32_t kJoinNetworkTime = 10 * 1000;
|
||||
|
||||
/**
|
||||
* Time to advance for the network to stabilize, in milliseconds.
|
||||
*/
|
||||
static constexpr uint32_t kStabilizationTime = 10 * 1000;
|
||||
|
||||
/**
|
||||
* Time to wait for SRP registration to complete.
|
||||
*/
|
||||
static constexpr uint32_t kSrpRegistrationTime = 5 * 1000;
|
||||
|
||||
/**
|
||||
* Time to advance for DNS query processing.
|
||||
*/
|
||||
static constexpr uint32_t kDnsQueryTime = 5 * 1000;
|
||||
|
||||
/**
|
||||
* Infrastructure interface index.
|
||||
*/
|
||||
static constexpr uint32_t kInfraIfIndex = 1;
|
||||
|
||||
/**
|
||||
* SRP Lease time in seconds.
|
||||
*/
|
||||
static constexpr uint32_t kSrpLease5m = 300;
|
||||
static constexpr uint32_t kSrpLease3m = 180;
|
||||
|
||||
/**
|
||||
* SRP Key Lease time in seconds.
|
||||
*/
|
||||
static constexpr uint32_t kSrpKeyLease10m = 600;
|
||||
|
||||
/**
|
||||
* SRP service port.
|
||||
*/
|
||||
static constexpr uint16_t kSrpServicePort1 = 55555;
|
||||
static constexpr uint16_t kSrpServicePort2 = 55556;
|
||||
|
||||
/**
|
||||
* SRP service and host names.
|
||||
*/
|
||||
static const char kSrpServiceType[] = "_thread-test._udp";
|
||||
static const char kSrpFullServiceType[] = "_thread-test._udp.default.service.arpa.";
|
||||
static const char kSrpInstanceName1[] = "service-test-1";
|
||||
static const char kSrpInstanceName2[] = "service-test-2";
|
||||
static const char kSrpHostName1[] = "host-test-1";
|
||||
|
||||
void Test_1_3_SRPC_TC_4(const char *aJsonFileName)
|
||||
{
|
||||
Srp::Client::Service service1;
|
||||
Srp::Client::Service service2;
|
||||
|
||||
/**
|
||||
* 3.4. [1.3] [CERT] [COMPONENT] Remove one service only by SRP client
|
||||
*
|
||||
* 3.4.1. Purpose
|
||||
* To test the following:
|
||||
* - SRP client needs to remove one service while other service remains registered.
|
||||
* - Correct usage of SRP Update to remove 1 service.
|
||||
* - Note: a Thread Product DUT must skip this test. Thread Product DUTs do not have a test case equivalent to this
|
||||
* one, since they would then need to be instructed to register 2 services and then remove 1 service again. This
|
||||
* seems unlikely to be practical.
|
||||
*
|
||||
* 3.4.2. Topology
|
||||
* - BR_1 - Test Bed border router device operating as a Thread Border Router, and the Leader
|
||||
* - Eth_1 - Test Bed border router device on an Adjacent Infrastructure Link
|
||||
* - TD_1 (DUT) - Thread End Device or Thread Router Component DUT
|
||||
*
|
||||
* Spec Reference | V1.1 Section | V1.3.0 Section
|
||||
* -----------------|--------------|---------------
|
||||
* SRP Client | N/A | 2.3.2
|
||||
*/
|
||||
|
||||
Core nexus;
|
||||
|
||||
Node &br1 = nexus.CreateNode();
|
||||
Node ð1 = nexus.CreateNode();
|
||||
Node &td1 = nexus.CreateNode();
|
||||
|
||||
br1.SetName("BR_1");
|
||||
eth1.SetName("Eth_1");
|
||||
td1.SetName("TD_1");
|
||||
|
||||
SuccessOrQuit(Instance::SetGlobalLogLevel(kLogLevelNote));
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("Step 1: Device: BR_1 Description (SRPC-3.4): Enable");
|
||||
|
||||
/**
|
||||
* Step 1
|
||||
* - Device: BR_1
|
||||
* - Description (SRPC-3.4): Enable
|
||||
* - Pass Criteria:
|
||||
* - N/A
|
||||
*/
|
||||
|
||||
br1.Form();
|
||||
nexus.AdvanceTime(kFormNetworkTime);
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("Step 2: Device: TD_1 (DUT) Description (SRPC-3.4): Enable");
|
||||
|
||||
/**
|
||||
* Step 2
|
||||
* - Device: TD_1 (DUT)
|
||||
* - Description (SRPC-3.4): Enable
|
||||
* - Pass Criteria:
|
||||
* - N/A
|
||||
*/
|
||||
|
||||
td1.Join(br1, Node::kAsFed);
|
||||
nexus.AdvanceTime(kJoinNetworkTime);
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("Step 3: Device: BR 1 Description (SRPC-3.4): Automatically adds its SRP Server information");
|
||||
|
||||
/**
|
||||
* Step 3
|
||||
* - Device: BR 1
|
||||
* - Description (SRPC-3.4): Automatically adds its SRP Server information in the DNSSRP/ Unicast Dataset in the
|
||||
* Thread Network Data. Automatically configures an OMR prefix in Thread Network Data.
|
||||
* - Pass Criteria:
|
||||
* - N/A
|
||||
*/
|
||||
|
||||
eth1.mInfraIf.Init(eth1);
|
||||
br1.Get<BorderRouter::InfraIf>().Init(kInfraIfIndex, true);
|
||||
br1.Get<BorderRouter::RoutingManager>().Init();
|
||||
SuccessOrQuit(br1.Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
||||
|
||||
SuccessOrQuit(br1.Get<Srp::Server>().SetAddressMode(Srp::Server::kAddressModeUnicast));
|
||||
br1.Get<Srp::Server>().SetEnabled(true);
|
||||
|
||||
nexus.AdvanceTime(kStabilizationTime);
|
||||
|
||||
/** Add test variables for Python script. */
|
||||
nexus.AddTestVar("BR_1_MLEID_ADDR", br1.Get<Mle::Mle>().GetMeshLocalEid().ToString().AsCString());
|
||||
nexus.AddTestVar("TD_1_MLEID_ADDR", td1.Get<Mle::Mle>().GetMeshLocalEid().ToString().AsCString());
|
||||
nexus.AddTestVar("TD_1_OMR_ADDR", td1.FindGlobalAddress().ToString().AsCString());
|
||||
|
||||
String<6> portString;
|
||||
portString.Append("%u", br1.Get<Srp::Server>().GetPort());
|
||||
nexus.AddTestVar("BR_1_SRP_PORT", portString.AsCString());
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("Step 4: Device: TD 1 (DUT) Description (SRPC-3.4): Harness instructs device to register a new service");
|
||||
|
||||
/**
|
||||
* Step 4
|
||||
* - Device: TD 1 (DUT)
|
||||
* - Description (SRPC-3.4): Harness instructs device to register a new service: $ORIGIN default.service.arpa.
|
||||
* service-test-1. thread-test._udp ( SRV 1 1 55555 host-test-1 ) host-test-1 AAAA <OMR address of TD_1> with
|
||||
* the following options: Update Lease Option Lease: 5 minutes Key Lease: 10 minutes.
|
||||
* - Pass Criteria:
|
||||
* - N/A (see step 5 instead)
|
||||
*/
|
||||
|
||||
td1.Get<Srp::Client>().EnableAutoStartMode(nullptr, nullptr);
|
||||
SuccessOrQuit(td1.Get<Srp::Client>().SetHostName(kSrpHostName1));
|
||||
SuccessOrQuit(td1.Get<Srp::Client>().EnableAutoHostAddress());
|
||||
td1.Get<Srp::Client>().SetLeaseInterval(kSrpLease5m);
|
||||
td1.Get<Srp::Client>().SetKeyLeaseInterval(kSrpKeyLease10m);
|
||||
|
||||
ClearAllBytes(service1);
|
||||
service1.mName = kSrpServiceType;
|
||||
service1.mInstanceName = kSrpInstanceName1;
|
||||
service1.mPort = kSrpServicePort1;
|
||||
service1.mPriority = 1;
|
||||
service1.mWeight = 1;
|
||||
SuccessOrQuit(td1.Get<Srp::Client>().AddService(service1));
|
||||
|
||||
nexus.AdvanceTime(kSrpRegistrationTime);
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("Step 5: Device: BR 1 Description (SRPC-3.4): Automatically responds 'SUCCESS'");
|
||||
|
||||
/**
|
||||
* Step 5
|
||||
* - Device: BR 1
|
||||
* - Description (SRPC-3.4): Automatically responds 'SUCCESS'.
|
||||
* - Pass Criteria:
|
||||
* - MUST respond 'SUCCESS'.
|
||||
* - Note: this verification step is done on the BR 1 response to ensure that the DUT in step 4 sent a correct
|
||||
* SRP Update. This is a quick way to verify the Update was correct.
|
||||
*/
|
||||
|
||||
VerifyOrQuit(!AsConst(br1.Get<Srp::Server>()).GetHosts().IsEmpty());
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("Step 6: Device: TD 1 (DUT) Description (SRPC-3.4): Harness instructs device to register a new, second "
|
||||
"service");
|
||||
|
||||
/**
|
||||
* Step 6
|
||||
* - Device: TD 1 (DUT)
|
||||
* - Description (SRPC-3.4): Harness instructs device to register a new, second service: $ORIGIN
|
||||
* default.service.arpa. service-test-2._thread-test._udp ( SRV 1 1 55556 host-test-1 ) host-test-1 AAAA <OMR
|
||||
* address of TD 1> with the following options: Update Lease Option Lease: 3 minutes Key Lease: 10 minutes
|
||||
* - Pass Criteria:
|
||||
* - N/A (see step 7 instead)
|
||||
*/
|
||||
|
||||
td1.Get<Srp::Client>().SetLeaseInterval(kSrpLease3m);
|
||||
|
||||
ClearAllBytes(service2);
|
||||
service2.mName = kSrpServiceType;
|
||||
service2.mInstanceName = kSrpInstanceName2;
|
||||
service2.mPort = kSrpServicePort2;
|
||||
service2.mPriority = 1;
|
||||
service2.mWeight = 1;
|
||||
SuccessOrQuit(td1.Get<Srp::Client>().AddService(service2));
|
||||
|
||||
nexus.AdvanceTime(kSrpRegistrationTime);
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("Step 7: Device: BR 1 Description (SRPC-3.4): Automatically responds SUCCESS");
|
||||
|
||||
/**
|
||||
* Step 7
|
||||
* - Device: BR 1
|
||||
* - Description (SRPC-3.4): Automatically responds SUCCESS.
|
||||
* - Pass Criteria:
|
||||
* - MUST respond 'SUCCESS'.
|
||||
* - Note: this verification step is done on the BR_1 response to ensure that the DUT in step 6 sent a correct
|
||||
* SRP Update. This is a quick way to verify the Update was correct.
|
||||
*/
|
||||
|
||||
VerifyOrQuit(td1.Get<Srp::Client>().GetHostInfo().GetState() == Srp::Client::kRegistered);
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("Step 8: Device: TD 1 (DUT) Description (SRPC-3.4): Harness instructs device to remove its first service");
|
||||
|
||||
/**
|
||||
* Step 8
|
||||
* - Device: TD 1 (DUT)
|
||||
* - Description (SRPC-3.4): Harness instructs device to remove its first service.
|
||||
* - Pass Criteria:
|
||||
* - The DUT MUST send an SRP Update message such that the Service Discovery Instruction contains a single Delete
|
||||
* an RR from an RRset ([RFC 2136], Section 2.5.4) update that deletes named records: $ORIGIN
|
||||
* default.service.arpa. service-test-1._thread-test. udp ANY <ttl=0>
|
||||
* - Note: if this is difficult to verify here then instead the SRP server response in step 11 can be used as
|
||||
* validation that the correct service was removed.
|
||||
*/
|
||||
|
||||
SuccessOrQuit(td1.Get<Srp::Client>().RemoveService(service1));
|
||||
|
||||
nexus.AdvanceTime(kSrpRegistrationTime);
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("Step 9: Device: BR_1 Description (SRPC-3.4): Automatically responds 'SUCCESS'");
|
||||
|
||||
/**
|
||||
* Step 9
|
||||
* - Device: BR_1
|
||||
* - Description (SRPC-3.4): Automatically responds 'SUCCESS'.
|
||||
* - Pass Criteria:
|
||||
* - MUST respond 'SUCCESS'.
|
||||
*/
|
||||
|
||||
VerifyOrQuit(td1.Get<Srp::Client>().GetHostInfo().GetState() == Srp::Client::kRegistered);
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("Step 10: Device: TD 1 (DUT) Description (SRPC-3.4): Harness instructs device via TH API to send unicast DNS "
|
||||
"query QType PTR");
|
||||
|
||||
/**
|
||||
* Step 10
|
||||
* - Device: TD 1 (DUT)
|
||||
* - Description (SRPC-3.4): Harness instructs device via TH API to send unicast DNS query QType PTR to BR_1 for
|
||||
* any services of type_thread-test._udp.default.service.arpa.". Note: this is done to validate that the SRP
|
||||
* server removed the first service and kept the second service.
|
||||
* - Pass Criteria:
|
||||
* - N/A
|
||||
*/
|
||||
|
||||
SuccessOrQuit(td1.Get<Dns::Client>().Browse(kSrpFullServiceType, nullptr, nullptr));
|
||||
|
||||
nexus.AdvanceTime(kDnsQueryTime);
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("Step 11: Device: BR_1 Description (SRPC-3.4): Responds with the second service only");
|
||||
|
||||
/**
|
||||
* Step 11
|
||||
* - Device: BR_1
|
||||
* - Description (SRPC-3.4): Responds with the second service only, not the first service.
|
||||
* - Pass Criteria:
|
||||
* - MUST respond with the following service DNS-SD response to requesting client in the Answer records section:
|
||||
* $ORIGIN default.service.arpa. _thread-test._udp ( PTR service-test-2._thread-test._udp )
|
||||
* - DUT MUST NOT respond with further records in the Answer records section.
|
||||
* - Response MAY contain in the Additional records section: $ORIGIN default.service.arpa.
|
||||
* service-test-2._thread-test._udp ( SRV 1 1 55556 host-test-1 ) host-test-1 AAAA <OMR address of TD_1>
|
||||
*/
|
||||
|
||||
nexus.SaveTestInfo(aJsonFileName);
|
||||
}
|
||||
|
||||
} // namespace Nexus
|
||||
} // namespace ot
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
ot::Nexus::Test_1_3_SRPC_TC_4((argc > 2) ? argv[2] : "test_1_3_SRPC_TC_4.json");
|
||||
printf("All tests passed\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
#!/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
|
||||
import struct
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
def verify(pv):
|
||||
# 3.4. [1.3] [CERT] [COMPONENT] Remove one service only by SRP client
|
||||
#
|
||||
# 3.4.1. Purpose
|
||||
# To test the following:
|
||||
# - SRP client needs to remove one service while other service remains registered.
|
||||
# - Correct usage of SRP Update to remove 1 service.
|
||||
# - Note: a Thread Product DUT must skip this test. Thread Product DUTs do not have a test case equivalent to this
|
||||
# one, since they would then need to be instructed to register 2 services and then remove 1 service again. This
|
||||
# seems unlikely to be practical.
|
||||
#
|
||||
# 3.4.2. Topology
|
||||
# - BR_1 - Test Bed border router device operating as a Thread Border Router, and the Leader
|
||||
# - Eth_1 - Test Bed border router device on an Adjacent Infrastructure Link
|
||||
# - TD_1 (DUT) - Thread End Device or Thread Router Component DUT
|
||||
#
|
||||
# Spec Reference | V1.1 Section | V1.3.0 Section
|
||||
# -----------------|--------------|---------------
|
||||
# SRP Client | N/A | 2.3.2
|
||||
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
BR_1_MLEID = Ipv6Addr(pv.vars['BR_1_MLEID_ADDR'])
|
||||
TD_1_MLEID = Ipv6Addr(pv.vars['TD_1_MLEID_ADDR'])
|
||||
TD_1_OMR_ADDR = Ipv6Addr(pv.vars['TD_1_OMR_ADDR'])
|
||||
BR_1_SRP_PORT = int(pv.vars['BR_1_SRP_PORT'])
|
||||
|
||||
SRP_SERVICE_NAME = '_thread-test._udp.default.service.arpa'
|
||||
SRP_INSTANCE_NAME1 = 'service-test-1.' + SRP_SERVICE_NAME
|
||||
SRP_INSTANCE_NAME2 = 'service-test-2.' + SRP_SERVICE_NAME
|
||||
SRP_HOST_NAME1 = 'host-test-1.default.service.arpa'
|
||||
|
||||
SRP_SERVICE_PORT1 = 55555
|
||||
SRP_SERVICE_PORT2 = 55556
|
||||
|
||||
SRP_LEASE_5M_10M = Bytes(struct.pack('>II', 300, 600).hex())
|
||||
SRP_LEASE_3M_10M = Bytes(struct.pack('>II', 180, 600).hex())
|
||||
|
||||
# Step 1
|
||||
# - Device: BR_1
|
||||
# - Description (SRPC-3.4): Enable
|
||||
# - Pass Criteria:
|
||||
# - N/A
|
||||
print("Step 1: BR_1 enable.")
|
||||
|
||||
# Step 2
|
||||
# - Device: TD_1 (DUT)
|
||||
# - Description (SRPC-3.4): Enable
|
||||
# - Pass Criteria:
|
||||
# - N/A
|
||||
print("Step 2: TD_1 enable.")
|
||||
|
||||
# Step 3
|
||||
# - Device: BR 1
|
||||
# - Description (SRPC-3.4): Automatically adds its SRP Server information in the DNSSRP/ Unicast Dataset in the
|
||||
# Thread Network Data. Automatically configures an OMR prefix in Thread Network Data.
|
||||
# - Pass Criteria:
|
||||
# - N/A
|
||||
print("Step 3: BR_1 adds SRP Server information and OMR prefix.")
|
||||
|
||||
# Step 4
|
||||
# - Device: TD 1 (DUT)
|
||||
# - Description (SRPC-3.4): Harness instructs device to register a new service: $ORIGIN default.service.arpa.
|
||||
# service-test-1. thread-test._udp ( SRV 1 1 55555 host-test-1 ) host-test-1 AAAA <OMR address of TD_1> with the
|
||||
# following options: Update Lease Option Lease: 5 minutes Key Lease: 10 minutes.
|
||||
# - Pass Criteria:
|
||||
# - N/A (see step 5 instead)
|
||||
print("Step 4: TD_1 registers service 1.")
|
||||
pkts.filter_ipv6_dst(BR_1_MLEID).\
|
||||
filter_ipv6_src(TD_1_MLEID).\
|
||||
filter(lambda p: p.udp.dstport == BR_1_SRP_PORT).\
|
||||
filter(lambda p: p.dns.flags.opcode == 5).\
|
||||
filter(lambda p: SRP_INSTANCE_NAME1 in verify_utils.as_list(p.dns.resp.name)).\
|
||||
filter(lambda p: SRP_SERVICE_PORT1 in verify_utils.as_list(p.dns.srv.port)).\
|
||||
filter(lambda p: 1 in verify_utils.as_list(p.dns.srv.priority)).\
|
||||
filter(lambda p: 1 in verify_utils.as_list(p.dns.srv.weight)).\
|
||||
filter(lambda p: TD_1_OMR_ADDR in verify_utils.as_list(p.dns.aaaa)).\
|
||||
filter(lambda p: p.dns.opt.data is not None).\
|
||||
filter(lambda p: any(data.format_compact() == SRP_LEASE_5M_10M.format_compact() for data in p.dns.opt.data)).\
|
||||
must_next()
|
||||
|
||||
# Step 5
|
||||
# - Device: BR 1
|
||||
# - Description (SRPC-3.4): Automatically responds 'SUCCESS'.
|
||||
# - Pass Criteria:
|
||||
# - MUST respond 'SUCCESS'.
|
||||
# - Note: this verification step is done on the BR 1 response to ensure that the DUT in step 4 sent a correct SRP
|
||||
# Update. This is a quick way to verify the Update was correct.
|
||||
print("Step 5: BR_1 responds SUCCESS.")
|
||||
pkts.filter_ipv6_src(BR_1_MLEID).\
|
||||
filter_ipv6_dst(TD_1_MLEID).\
|
||||
filter(lambda p: p.udp.srcport == BR_1_SRP_PORT).\
|
||||
filter(lambda p: p.dns.flags.response == 1).\
|
||||
filter(lambda p: p.dns.flags.rcode == 0).\
|
||||
must_next()
|
||||
|
||||
# Step 6
|
||||
# - Device: TD 1 (DUT)
|
||||
# - Description (SRPC-3.4): Harness instructs device to register a new, second service: $ORIGIN
|
||||
# default.service.arpa. service-test-2._thread-test._udp ( SRV 1 1 55556 host-test-1 ) host-test-1 AAAA <OMR
|
||||
# address of TD 1> with the following options: Update Lease Option Lease: 3 minutes Key Lease: 10 minutes
|
||||
# - Pass Criteria:
|
||||
# - N/A (see step 7 instead)
|
||||
print("Step 6: TD_1 registers service 2.")
|
||||
pkts.filter_ipv6_dst(BR_1_MLEID).\
|
||||
filter_ipv6_src(TD_1_MLEID).\
|
||||
filter(lambda p: p.udp.dstport == BR_1_SRP_PORT).\
|
||||
filter(lambda p: p.dns.flags.opcode == 5).\
|
||||
filter(lambda p: SRP_INSTANCE_NAME2 in verify_utils.as_list(p.dns.resp.name)).\
|
||||
filter(lambda p: SRP_SERVICE_PORT2 in verify_utils.as_list(p.dns.srv.port)).\
|
||||
filter(lambda p: 1 in verify_utils.as_list(p.dns.srv.priority)).\
|
||||
filter(lambda p: 1 in verify_utils.as_list(p.dns.srv.weight)).\
|
||||
filter(lambda p: TD_1_OMR_ADDR in verify_utils.as_list(p.dns.aaaa)).\
|
||||
filter(lambda p: p.dns.opt.data is not None).\
|
||||
filter(lambda p: any(data.format_compact() == SRP_LEASE_3M_10M.format_compact() for data in p.dns.opt.data)).\
|
||||
must_next()
|
||||
|
||||
# Step 7
|
||||
# - Device: BR 1
|
||||
# - Description (SRPC-3.4): Automatically responds SUCCESS.
|
||||
# - Pass Criteria:
|
||||
# - MUST respond 'SUCCESS'.
|
||||
# - Note: this verification step is done on the BR_1 response to ensure that the DUT in step 6 sent a correct SRP
|
||||
# Update. This is a quick way to verify the Update was correct.
|
||||
print("Step 7: BR_1 responds SUCCESS.")
|
||||
pkts.filter_ipv6_src(BR_1_MLEID).\
|
||||
filter_ipv6_dst(TD_1_MLEID).\
|
||||
filter(lambda p: p.udp.srcport == BR_1_SRP_PORT).\
|
||||
filter(lambda p: p.dns.flags.response == 1).\
|
||||
filter(lambda p: p.dns.flags.rcode == 0).\
|
||||
must_next()
|
||||
|
||||
# Step 8
|
||||
# - Device: TD 1 (DUT)
|
||||
# - Description (SRPC-3.4): Harness instructs device to remove its first service.
|
||||
# - Pass Criteria:
|
||||
# - The DUT MUST send an SRP Update message such that the Service Discovery Instruction contains a single Delete
|
||||
# an RR from an RRset ([RFC 2136], Section 2.5.4) update that deletes named records: $ORIGIN
|
||||
# default.service.arpa. service-test-1._thread-test. udp ANY <ttl=0>
|
||||
# - Note: if this is difficult to verify here then instead the SRP server response in step 11 can be used as
|
||||
# validation that the correct service was removed.
|
||||
print("Step 8: TD_1 removes service 1.")
|
||||
pkts.filter_ipv6_dst(BR_1_MLEID).\
|
||||
filter_ipv6_src(TD_1_MLEID).\
|
||||
filter(lambda p: p.udp.dstport == BR_1_SRP_PORT).\
|
||||
filter(lambda p: p.dns.flags.opcode == 5).\
|
||||
filter(lambda p: SRP_INSTANCE_NAME1 in verify_utils.as_list(p.dns.resp.name)).\
|
||||
filter(lambda p: any(ttl == 0 for ttl in verify_utils.as_list(p.dns.resp.ttl))).\
|
||||
must_next()
|
||||
|
||||
# Step 9
|
||||
# - Device: BR_1
|
||||
# - Description (SRPC-3.4): Automatically responds 'SUCCESS'.
|
||||
# - Pass Criteria:
|
||||
# - MUST respond 'SUCCESS'.
|
||||
print("Step 9: BR_1 responds SUCCESS.")
|
||||
pkts.filter_ipv6_src(BR_1_MLEID).\
|
||||
filter_ipv6_dst(TD_1_MLEID).\
|
||||
filter(lambda p: p.udp.srcport == BR_1_SRP_PORT).\
|
||||
filter(lambda p: p.dns.flags.response == 1).\
|
||||
filter(lambda p: p.dns.flags.rcode == 0).\
|
||||
must_next()
|
||||
|
||||
# Step 10
|
||||
# - Device: TD 1 (DUT)
|
||||
# - Description (SRPC-3.4): Harness instructs device via TH API to send unicast DNS query QType PTR to BR_1 for any
|
||||
# services of type_thread-test._udp.default.service.arpa.". Note: this is done to validate that the SRP server
|
||||
# removed the first service and kept the second service.
|
||||
# - Pass Criteria:
|
||||
# - N/A
|
||||
print("Step 10: TD_1 sends DNS query PTR.")
|
||||
pkts.filter_ipv6_dst(BR_1_MLEID).\
|
||||
filter_ipv6_src(TD_1_MLEID).\
|
||||
filter(lambda p: p.udp.dstport == 53).\
|
||||
filter(lambda p: p.dns.flags.response == 0).\
|
||||
filter(lambda p: SRP_SERVICE_NAME in verify_utils.as_list(p.dns.qry.name)).\
|
||||
must_next()
|
||||
|
||||
# Step 11
|
||||
# - Device: BR_1
|
||||
# - Description (SRPC-3.4): Responds with the second service only, not the first service.
|
||||
# - Pass Criteria:
|
||||
# - MUST respond with the following service DNS-SD response to requesting client in the Answer records section:
|
||||
# $ORIGIN default.service.arpa. _thread-test._udp ( PTR service-test-2._thread-test._udp )
|
||||
# - DUT MUST NOT respond with further records in the Answer records section.
|
||||
# - Response MAY contain in the Additional records section: $ORIGIN default.service.arpa.
|
||||
# service-test-2._thread-test._udp ( SRV 1 1 55556 host-test-1 ) host-test-1 AAAA <OMR address of TD_1>
|
||||
print("Step 11: BR_1 responds with service 2 only.")
|
||||
pkts.filter_ipv6_src(BR_1_MLEID).\
|
||||
filter_ipv6_dst(TD_1_MLEID).\
|
||||
filter(lambda p: p.udp.srcport == 53).\
|
||||
filter(lambda p: p.dns.flags.response == 1).\
|
||||
filter(lambda p: p.dns.flags.rcode == 0).\
|
||||
filter(lambda p: SRP_SERVICE_NAME in verify_utils.as_list(p.dns.resp.name)).\
|
||||
filter(lambda p: SRP_INSTANCE_NAME2 in verify_utils.as_list(p.dns.ptr.domain_name)).\
|
||||
filter(lambda p: int(p.dns.count.answers) == 1).\
|
||||
must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
verify_utils.run_main(verify)
|
||||
Reference in New Issue
Block a user