[nexus] add 1_3_DPR_TC_2 for Service Discovery - Multiple BRs (#12798)

This commit adds the Nexus test case 1_3_DPR_TC_2 which verifies
Service discovery of services on Thread and Infrastructure with
multiple Border Routers and multiple Thread networks, as per the
Thread 1.3 test specification.

The implementation includes:
- tests/nexus/test_1_3_DPR_TC_2.cpp: Implements the test sequence.
  It sets up two isolated Thread networks, each with its own Border
  Router (BR_1/DUT and BR_2) and End Device (ED_1 and ED_2),
  attached via a shared infrastructure link. It simulates SRP
  registration on both networks and verifies that services can be
  discovered across networks using the Discovery Proxy function.
- tests/nexus/verify_1_3_DPR_TC_2.py: Performs automated packet
  verification. It ensures both BRs correctly add SRP Server info
  to their respective Network Data, SRP updates are successful,
  and DNS queries (PTR and SRV) from one network successfully
  discover services in the other network through the Discovery
  Proxy and mDNS on the infrastructure link.
- Integrated the new test into tests/nexus/CMakeLists.txt and
  tests/nexus/run_nexus_tests.sh.

The test validates that the Border Router's Discovery Proxy can
successfully discover and report services advertised by another
Border Router's Advertising Proxy function across an adjacent
infrastructure link.
This commit is contained in:
Jonathan Hui
2026-03-30 16:18:13 -07:00
committed by GitHub
parent 1b78d18c13
commit 59411c85f6
4 changed files with 769 additions and 0 deletions
+1
View File
@@ -265,6 +265,7 @@ ot_nexus_test(1_3_DBR_TC_7C "cert;nexus")
ot_nexus_test(1_3_DBR_TC_8 "cert;nexus")
ot_nexus_test(1_3_DBR_TC_10 "cert;nexus")
ot_nexus_test(1_3_DPR_TC_1 "cert;nexus")
ot_nexus_test(1_3_DPR_TC_2 "cert;nexus")
ot_nexus_test(1_3_SRP_TC_1 "cert;nexus")
ot_nexus_test(1_3_SRP_TC_2 "cert;nexus")
ot_nexus_test(1_3_SRP_TC_3 "cert;nexus")
+1
View File
@@ -200,6 +200,7 @@ DEFAULT_TESTS=(
"1_3_DBR_TC_8"
"1_3_DBR_TC_10"
"1_3_DPR_TC_1"
"1_3_DPR_TC_2"
"1_3_SRP_TC_1"
"1_3_SRP_TC_2"
"1_3_SRP_TC_3"
+484
View File
@@ -0,0 +1,484 @@
/*
* 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 as a child and upgrade to a router, in milliseconds.
*/
static constexpr uint32_t kJoinNetworkTime = 200 * 1000;
/**
* Time to advance for the BR to perform automatic actions (RA, Network Data), in milliseconds.
*/
static constexpr uint32_t kBrActionTime = 30 * 1000;
/**
* Time to wait for SRP registration to complete.
*/
static constexpr uint32_t kSrpRegistrationTime = 10 * 1000;
/**
* Time to wait for DNS response.
*/
static constexpr uint32_t kDnsResponseTime = 20 * 1000;
/**
* Time to wait for mDNS query.
*/
static constexpr uint32_t kMdnsQueryTime = 1 * 1000;
/**
* Infrastructure interface index.
*/
static constexpr uint32_t kInfraIfIndex = 1;
/**
* Service Port.
*/
static constexpr uint16_t kServicePort = 55555;
/**
* SRP Service Weight.
*/
static constexpr uint16_t kSrpWeight = 4;
void Test_1_3_DPR_TC_2(void)
{
/**
* 5.2. 1.3 CERT Service discovery of services on Thread and Infrastructure - Multiple BRs - Multiple Thread -
* Single infrastructure
*
* 5.2.1. Purpose
* To test the following:
* - 1. Discovery of on-mesh services between multiple Thread networks attached via an adjacent
* infrastructure link.
* - 2. BR Discovery Proxy function can discover services advertised by another BRs Advertising Proxy
* function, and vice-versa.
* - 3. Test both PTR and SRV queries from Thread Network, and finding service in other Network.
*
* 5.2.2. Topology
* - BR_1 (DUT) - Thread Border Router, and Leader
* - BR_2 - Test Bed border router device operating as a Thread Border Router and Leader of an adjacent
* Thread network
* - ED_1 - Test Bed device operating as a Thread End Device, attached to BR_1
* - ED_2 - Test Bed device operating as a Thread End Device, attached to BR_2
*
* Spec Reference | V1.1 Section | V1.3.0 Section
* -----------------|--------------|---------------
* Discovery Proxy | N/A | 5.2
*/
Core nexus;
Node &br1 = nexus.CreateNode();
Node &br2 = nexus.CreateNode();
Node &ed1 = nexus.CreateNode();
Node &ed2 = nexus.CreateNode();
Srp::Client::Service service1;
Srp::Client::Service service2;
Ip6::Address ed1Addresses[2];
br1.SetName("BR_1");
br2.SetName("BR_2");
ed1.SetName("ED_1");
ed2.SetName("ED_2");
nexus.AdvanceTime(0);
SuccessOrQuit(Instance::SetGlobalLogLevel(kLogLevelNote));
{
Ip6::Prefix prefix;
Ip6::NetworkPrefix networkPrefix;
SuccessOrQuit(prefix.FromString("fd00:db8::/64"));
SuccessOrQuit(networkPrefix.SetFrom(prefix));
br1.Get<Mle::Mle>().SetMeshLocalPrefix(networkPrefix);
br2.Get<Mle::Mle>().SetMeshLocalPrefix(networkPrefix);
}
Log("---------------------------------------------------------------------------------------");
Log("Step 1: Device: BR_1 (DUT), ED_1 Description (DPR-5.2): Enable");
/**
* Step 1
* - Device: BR_1 (DUT), ED_1
* - Description (DPR-5.2): Enable
* - Pass Criteria:
* - N/A
*/
br1.AllowList(ed1);
ed1.AllowList(br1);
br1.Form();
{
MeshCoP::Dataset::Info datasetInfo;
SuccessOrQuit(br1.Get<MeshCoP::ActiveDatasetManager>().Read(datasetInfo));
nexus.AddNetworkKey(datasetInfo.Get<MeshCoP::Dataset::kNetworkKey>());
}
nexus.AdvanceTime(kFormNetworkTime);
VerifyOrQuit(br1.Get<Mle::Mle>().IsLeader());
ed1.Join(br1, Node::kAsFed);
nexus.AdvanceTime(kJoinNetworkTime);
VerifyOrQuit(ed1.Get<Mle::Mle>().IsAttached());
Log("---------------------------------------------------------------------------------------");
Log("Step 2: Device: BR_1 (DUT) Description (DPR-5.2): Automatically adds its SRP Server information...");
/**
* Step 2
* - Device: BR_1 (DUT)
* - Description (DPR-5.2): Automatically adds its SRP Server information in the Thread Network Data of first
* Thread network.
* - Pass Criteria:
* - The DUTs SRP Server information MUST appear in the Thread Network Data of the first Thread network.
*/
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(kBrActionTime);
Log("---------------------------------------------------------------------------------------");
Log("Step 3: Device: ED_1 Description (DPR-5.2): Harness instructs the device to send SRP Update...");
/**
* Step 3
* - Device: ED_1
* - Description (DPR-5.2): Harness instructs the device to send SRP Update $ORIGIN default.service.arpa.
* service-test-1._thread-type-1._udp ( SRV 0 4 55555 host-test-1 ) host-test-1 AAAA <ML-EID address of ED_1>
* AAAA <OMR address of ED_1> Note: normally an SRP client would only register the OMR address in this case.
* For testing purposes, both OMR/ML-EID are registered which deviates from usual client behavior.
* - Pass Criteria:
* - N/A
*/
ed1.Get<Srp::Client>().EnableAutoStartMode(nullptr, nullptr);
SuccessOrQuit(ed1.Get<Srp::Client>().SetHostName("host-test-1"));
ed1Addresses[0] = ed1.Get<Mle::Mle>().GetMeshLocalEid();
ed1Addresses[1] = ed1.FindGlobalAddress();
SuccessOrQuit(ed1.Get<Srp::Client>().SetHostAddresses(ed1Addresses, 2));
ClearAllBytes(service1);
service1.mName = "_thread-type-1._udp";
service1.mInstanceName = "service-test-1";
service1.mPort = kServicePort;
service1.mPriority = 0;
service1.mWeight = kSrpWeight;
SuccessOrQuit(ed1.Get<Srp::Client>().AddService(service1));
nexus.AdvanceTime(kSrpRegistrationTime);
Log("---------------------------------------------------------------------------------------");
Log("Step 4: Device: BR_1 (DUT) Description (DPR-5.2): Automatically sends SRP Update Response");
/**
* Step 4
* - Device: BR_1 (DUT)
* - Description (DPR-5.2): Automatically sends SRP Update Response.
* - Pass Criteria:
* - The DUT MUST send a valid SRP Update Response with RCODE=0 (NoError).
*/
VerifyOrQuit(ed1.Get<Srp::Client>().GetHostInfo().GetState() == Srp::Client::kRegistered);
Log("---------------------------------------------------------------------------------------");
Log("Step 5: Device: BR_2, ED_2 Description (DPR-5.2): Enable");
/**
* Step 5
* - Device: BR_2, ED_2
* - Description (DPR-5.2): Enable
* - Pass Criteria:
* - N/A
*/
br2.AllowList(ed2);
ed2.AllowList(br2);
br1.UnallowList(br2);
br2.UnallowList(br1);
br1.UnallowList(ed2);
ed1.UnallowList(br2);
ed1.UnallowList(ed2);
br2.Form();
{
MeshCoP::Dataset::Info datasetInfo;
SuccessOrQuit(br2.Get<MeshCoP::ActiveDatasetManager>().Read(datasetInfo));
nexus.AddNetworkKey(datasetInfo.Get<MeshCoP::Dataset::kNetworkKey>());
}
nexus.AdvanceTime(kFormNetworkTime);
VerifyOrQuit(br2.Get<Mle::Mle>().IsLeader());
ed2.Join(br2, Node::kAsFed);
nexus.AdvanceTime(kJoinNetworkTime);
VerifyOrQuit(ed2.Get<Mle::Mle>().IsAttached());
Log("---------------------------------------------------------------------------------------");
Log("Step 6: Device: BR_2 Description (DPR-5.2): Automatically adds its SRP Server information...");
/**
* Step 6
* - Device: BR_2
* - Description (DPR-5.2): Automatically adds its SRP Server information in the Thread Network Data of the
* second Thread network.
* - Pass Criteria:
* - BR_2s SRP Server information MUST appear in the Thread Network Data of the second Thread network.
*/
br2.Get<BorderRouter::InfraIf>().Init(kInfraIfIndex, true);
br2.Get<BorderRouter::RoutingManager>().Init();
SuccessOrQuit(br2.Get<BorderRouter::RoutingManager>().SetEnabled(true));
SuccessOrQuit(br2.Get<Srp::Server>().SetAddressMode(Srp::Server::kAddressModeUnicast));
br2.Get<Srp::Server>().SetEnabled(true);
nexus.AdvanceTime(kBrActionTime);
Log("---------------------------------------------------------------------------------------");
Log("Step 7: Device: ED_2 Description (DPR-5.2): Harness instructs the device to send SRP Update...");
/**
* Step 7
* - Device: ED_2
* - Description (DPR-5.2): Harness instructs the device to send SRP Update $ORIGIN default.service.arpa.
* service-test-2._thread-type-2._udp ( SRV 0 0 55555 host-test-2 ) host-test-2 AAAA <OMR address of ED_2>
* - Pass Criteria:
* - N/A
*/
ed2.Get<Srp::Client>().EnableAutoStartMode(nullptr, nullptr);
SuccessOrQuit(ed2.Get<Srp::Client>().SetHostName("host-test-2"));
SuccessOrQuit(ed2.Get<Srp::Client>().EnableAutoHostAddress());
ClearAllBytes(service2);
service2.mName = "_thread-type-2._udp";
service2.mInstanceName = "service-test-2";
service2.mPort = kServicePort;
service2.mPriority = 0;
service2.mWeight = 0;
SuccessOrQuit(ed2.Get<Srp::Client>().AddService(service2));
nexus.AdvanceTime(kSrpRegistrationTime);
Log("---------------------------------------------------------------------------------------");
Log("Step 8: Device: BR_2 Description (DPR-5.2): Automatically sends SRP Update Response");
/**
* Step 8
* - Device: BR_2
* - Description (DPR-5.2): Automatically sends SRP Update Response.
* - Pass Criteria:
* - SRP Update Response is valid and reports NoError (RCODE=0).
*/
VerifyOrQuit(ed2.Get<Srp::Client>().GetHostInfo().GetState() == Srp::Client::kRegistered);
Log("---------------------------------------------------------------------------------------");
Log("Step 9: Device: ED_1 Description (DPR-5.2): Harness instructs the device to unicast DNS query...");
/**
* Step 9
* - Device: ED_1
* - Description (DPR-5.2): Harness instructs the device to unicast DNS query QType=PTR to the DUT for all
* services of type “_thread-type-2._udp.default.service.arpa.”.
* - Pass Criteria:
* - N/A
*/
{
Dns::Client::QueryConfig queryConfig;
queryConfig.Clear();
AsCoreType(&queryConfig.mServerSockAddr.mAddress) = br1.Get<Mle::Mle>().GetMeshLocalEid();
queryConfig.mServerSockAddr.mPort = Dns::ServiceDiscovery::Server::kPort;
SuccessOrQuit(
ed1.Get<Dns::Client>().Browse("_thread-type-2._udp.default.service.arpa.", nullptr, nullptr, &queryConfig));
}
Log("---------------------------------------------------------------------------------------");
Log("Step 10: Device: BR_1 (DUT) Description (DPR-5.2): Automatically sends DNS Response");
/**
* Step 10
* - Device: BR_1 (DUT)
* - Description (DPR-5.2): Automatically sends DNS Response. Note: during this step, DUT performs mDNS query to
* BR_2 which responds with service-test-2. This isnt shown in detail.
* - Pass Criteria:
* - The DUT MUST send a valid DNS Response, containing service-test-2 as Answer record: $ORIGIN
* default.service.arpa. _thread-type-2._udp ( PTR service-test-2._thread-type-2._udp )
* - It MAY contain in the Additional records section: $ORIGIN default.service.arpa.
* service-test-2._thread-type-2._udp ( SRV 0 0 55555 host-test-2 ) host-test-2 AAAA <OMR address of ED_2>
*/
nexus.AdvanceTime(kDnsResponseTime);
Log("---------------------------------------------------------------------------------------");
Log("Step 11: Device: ED_2 Description (DPR-5.2): Harness instructs the device to unicast DNS query...");
/**
* Step 11
* - Device: ED_2
* - Description (DPR-5.2): Harness instructs the device to unicast DNS query QType=PTR to BR_2 for all services
* of type “_thread-type-1._udp.default.service.arpa.”.
* - Pass Criteria:
* - N/A
*/
{
Dns::Client::QueryConfig queryConfig;
queryConfig.Clear();
AsCoreType(&queryConfig.mServerSockAddr.mAddress) = br2.Get<Mle::Mle>().GetMeshLocalEid();
queryConfig.mServerSockAddr.mPort = Dns::ServiceDiscovery::Server::kPort;
SuccessOrQuit(
ed2.Get<Dns::Client>().Browse("_thread-type-1._udp.default.service.arpa.", nullptr, nullptr, &queryConfig));
}
Log("---------------------------------------------------------------------------------------");
Log("Step 12: Device: BR_2 Description (DPR-5.2): Automatically sends mDNS query");
/**
* Step 12
* - Device: BR_2
* - Description (DPR-5.2): Automatically sends mDNS query.
* - Pass Criteria:
* - N/A
*/
nexus.AdvanceTime(kMdnsQueryTime);
Log("---------------------------------------------------------------------------------------");
Log("Step 13: Device: BR_1 (DUT) Description (DPR-5.2): Automatically responds to mDNS query...");
/**
* Step 13
* - Device: BR_1 (DUT)
* - Description (DPR-5.2): Automatically responds to mDNS query with “service-test-1”.
* - Pass Criteria:
* - N/A (verified in step 14)
*/
nexus.AdvanceTime(kDnsResponseTime);
Log("---------------------------------------------------------------------------------------");
Log("Step 14: Device: BR_2 Description (DPR-5.2): Automatically sends a DNS response to ED_2");
/**
* Step 14
* - Device: BR_2
* - Description (DPR-5.2): Automatically sends a DNS response to ED_2.
* - Pass Criteria:
* - The DNS Response is received at ED_2, is valid and contains only service-test-1 in the Answers section:
* $ORIGIN default.service.arpa. _thread-type-1._udp ( PTR service-test-1._thread-type-1._udp )
* - It MAY contain in the Additional records section: $ORIGIN default.service.arpa.
* service-test-1._thread-type-1._udp ( SRV 0 4 55555 host-test-1 ) host-test-1 AAAA <OMR address of ED_1>
* - Also it MAY contain in the Additional records section, but only if the above Additional records are also
* included: $ORIGIN default.service.arpa. host-test-1 AAAA <ML-EID address of ED_1>
*/
// Note: verification of DNS response from BR_2 to ED_2 is handled in Step 14.
Log("---------------------------------------------------------------------------------------");
Log("Step 15: Device: ED_1 Description (DPR-5.2): Harness instructs the device to unicast DNS query...");
/**
* Step 15
* - Device: ED_1
* - Description (DPR-5.2): Harness instructs the device to unicast DNS query QType=SRV to the DUT for service
* “service-test-2._thread-type-2._udp.default.service.arpa.”.
* - Pass Criteria:
* - N/A
*/
{
Dns::Client::QueryConfig queryConfig;
queryConfig.Clear();
AsCoreType(&queryConfig.mServerSockAddr.mAddress) = br1.Get<Mle::Mle>().GetMeshLocalEid();
queryConfig.mServerSockAddr.mPort = Dns::ServiceDiscovery::Server::kPort;
SuccessOrQuit(ed1.Get<Dns::Client>().ResolveService(
"service-test-2", "_thread-type-2._udp.default.service.arpa.", nullptr, &queryConfig));
}
Log("---------------------------------------------------------------------------------------");
Log("Step 16: Device: BR_1 (DUT) Description (DPR-5.2): Automatically sends DNS Response");
/**
* Step 16
* - Device: BR_1 (DUT)
* - Description (DPR-5.2): Automatically sends DNS Response. Note: during this step, DUT MAY perform mDNS query
* to BR_2 which responds with service-test-2. This isnt shown in detail.
* - Pass Criteria:
* - The DUT MUST send a valid DNS Response is valid, containing service-test-2 answer record: $ORIGIN
* default.service.arpa. service-test-2._thread-type-2._udp ( SRV 0 0 55555 host-test-2 )
* - It MAY contain in the Additional records section: host-test-2 AAAA <OMR address of ED_2>
*/
nexus.AdvanceTime(kDnsResponseTime);
nexus.AddTestVar("ED_1_OMR", ed1.FindGlobalAddress().ToString().AsCString());
nexus.AddTestVar("ED_2_OMR", ed2.FindGlobalAddress().ToString().AsCString());
nexus.SaveTestInfo("test_1_3_DPR_TC_2.json", &br1);
}
} // namespace Nexus
} // namespace ot
int main(void)
{
ot::Nexus::Test_1_3_DPR_TC_2();
printf("All tests passed\n");
return 0;
}
+283
View File
@@ -0,0 +1,283 @@
#!/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
def verify(pv):
# 5.2. 1.3 CERT Service discovery of services on Thread and Infrastructure - Multiple BRs - Multiple Thread -
# Single infrastructure
#
# 5.2.1. Purpose
# To test the following:
# - 1. Discovery of on-mesh services between multiple Thread networks attached via an adjacent
# infrastructure link.
# - 2. BR Discovery Proxy function can discover services advertised by another BRs Advertising Proxy
# function, and vice versa.
# - 3. Test both PTR and SRV queries from Thread Network, and finding service in other Network.
#
# 5.2.2. Topology
# - BR_1 (DUT) - Thread Border Router, and Leader
# - BR_2 - Test Bed border router device operating as a Thread Border Router and Leader of an adjacent Thread
# network
# - ED_1 - Test Bed device operating as a Thread End Device, attached to BR_1
# - ED_2 - Test Bed device operating as a Thread End Device, attached to BR_2
#
# Spec Reference | V1.1 Section | V1.3.0 Section
# -----------------|--------------|---------------
# Discovery Proxy | N/A | 5.2
pkts = pv.pkts
pv.summary.show()
BR_1 = pv.vars['BR_1']
BR_2 = pv.vars['BR_2']
BR_1_ETH = pv.vars['BR_1_ETH']
BR_2_ETH = pv.vars['BR_2_ETH']
ED_1 = pv.vars['ED_1']
ED_2 = pv.vars['ED_2']
# Step 1
# - Device: BR_1 (DUT), ED_1
# - Description (DPR-5.2): Enable
# - Pass Criteria:
# - N/A
print("Step 1: Device: BR_1 (DUT), ED_1 Description (DPR-5.2): Enable")
# Step 2
# - Device: BR_1 (DUT)
# - Description (DPR-5.2): Automatically adds its SRP Server information in the Thread Network Data of first
# Thread network.
# - Pass Criteria:
# - The DUTs SRP Server information MUST appear in the Thread Network Data of the first Thread network.
print("Step 2: Device: BR_1 (DUT) Description (DPR-5.2): Automatically adds its SRP Server information...")
pkts.filter_wpan_src64(BR_1). \
filter_mle_cmd(consts.MLE_DATA_RESPONSE). \
filter(lambda p: consts.NWD_SERVICE_TLV in p.thread_nwd.tlv.type). \
filter(lambda p: consts.NWD_SERVER_TLV in p.thread_nwd.tlv.type). \
must_next()
# Step 3
# - Device: ED_1
# - Description (DPR-5.2): Harness instructs the device to send SRP Update $ORIGIN default.service.arpa.
# service-test-1._thread-type-1._udp ( SRV 0 4 55555 host-test-1 ) host-test-1 AAAA <ML-EID address of ED_1>
# AAAA <OMR address of ED_1> Note: normally an SRP client would only register the OMR address in this case.
# For testing purposes, both OMR/ML-EID are registered which deviates from usual client behavior.
# - Pass Criteria:
# - N/A
print("Step 3: Device: ED_1 Description (DPR-5.2): Harness instructs the device to send SRP Update...")
pkts.filter_wpan_src64(ED_1). \
filter(lambda p: p.dns). \
filter(lambda p: p.dns.flags.opcode == 5). \
must_next()
# Step 4
# - Device: BR_1 (DUT)
# - Description (DPR-5.2): Automatically sends SRP Update Response.
# - Pass Criteria:
# - The DUT MUST send a valid SRP Update Response with RCODE=0 (NoError).
print("Step 4: Device: BR_1 (DUT) Description (DPR-5.2): Automatically sends SRP Update Response")
pkts.filter_wpan_src64(BR_1). \
filter(lambda p: p.dns). \
filter(lambda p: p.dns.flags.opcode == 5). \
filter(lambda p: p.dns.flags.rcode == consts.DNS_RCODE_NOERROR). \
must_next()
# Step 5
# - Device: BR_2, ED_2
# - Description (DPR-5.2): Enable
# - Pass Criteria:
# - N/A
print("Step 5: Device: BR_2, ED_2 Description (DPR-5.2): Enable")
# Step 6
# - Device: BR_2
# - Description (DPR-5.2): Automatically adds its SRP Server information in the Thread Network Data of the
# second Thread network.
# - Pass Criteria:
# - BR_2s SRP Server information MUST appear in the Thread Network Data of the second Thread network.
print("Step 6: Device: BR_2 Description (DPR-5.2): Automatically adds its SRP Server information...")
pkts.filter_wpan_src64(BR_2). \
filter_mle_cmd(consts.MLE_DATA_RESPONSE). \
filter(lambda p: consts.NWD_SERVICE_TLV in p.thread_nwd.tlv.type). \
filter(lambda p: consts.NWD_SERVER_TLV in p.thread_nwd.tlv.type). \
must_next()
# Step 7
# - Device: ED_2
# - Description (DPR-5.2): Harness instructs the device to send SRP Update $ORIGIN default.service.arpa.
# service-test-2._thread-type-2._udp ( SRV 0 0 55555 host-test-2 ) host-test-2 AAAA <OMR address of ED_2>
# - Pass Criteria:
# - N/A
print("Step 7: Device: ED_2 Description (DPR-5.2): Harness instructs the device to send SRP Update...")
pkts.filter_wpan_src64(ED_2). \
filter(lambda p: p.dns). \
filter(lambda p: p.dns.flags.opcode == 5). \
must_next()
# Step 8
# - Device: BR_2
# - Description (DPR-5.2): Automatically sends SRP Update Response.
# - Pass Criteria:
# - SRP Update Response is valid and reports NoError (RCODE=0).
print("Step 8: Device: BR_2 Description (DPR-5.2): Automatically sends SRP Update Response")
pkts.filter_wpan_src64(BR_2). \
filter(lambda p: p.dns). \
filter(lambda p: p.dns.flags.opcode == 5). \
filter(lambda p: p.dns.flags.rcode == consts.DNS_RCODE_NOERROR). \
must_next()
# Step 9
# - Device: ED_1
# - Description (DPR-5.2): Harness instructs the device to unicast DNS query QType=PTR to the DUT for all
# services of type “_thread-type-2._udp.default.service.arpa.”.
# - Pass Criteria:
# - N/A
print("Step 9: Device: ED_1 Description (DPR-5.2): Harness instructs the device to unicast DNS query...")
pkts.filter_wpan_src64(ED_1). \
filter(lambda p: p.dns). \
filter(lambda p: p.dns.flags.response == 0). \
filter(lambda p: "_thread-type-2._udp.default.service.arpa" in verify_utils.as_list(p.dns.qry.name)). \
filter(lambda p: any(t == consts.DNS_TYPE_PTR for t in verify_utils.as_list(p.dns.qry.type))). \
must_next()
# Step 10
# - Device: BR_1 (DUT)
# - Description (DPR-5.2): Automatically sends DNS Response. Note: during this step, DUT performs mDNS query to
# BR_2 which responds with service-test-2. This isnt shown in detail.
# - Pass Criteria:
# - The DUT MUST send a valid DNS Response, containing service-test-2 as Answer record: $ORIGIN
# default.service.arpa. _thread-type-2._udp ( PTR service-test-2._thread-type-2._udp )
# - It MAY contain in the Additional records section: $ORIGIN default.service.arpa.
# service-test-2._thread-type-2._udp ( SRV 0 0 55555 host-test-2 ) host-test-2 AAAA <OMR address of ED_2>
print("Step 10: Device: BR_1 (DUT) Description (DPR-5.2): Automatically sends DNS Response")
pkts.filter_wpan_src64(BR_1). \
filter(lambda p: p.dns). \
filter(lambda p: p.dns.flags.response == 1). \
filter(lambda p: any("service-test-2" in str(name)
for name in verify_utils.as_list(p.dns.ptr.domain_name))). \
must_next()
# Step 11
# - Device: ED_2
# - Description (DPR-5.2): Harness instructs the device to unicast DNS query QType=PTR to BR_2 for all services
# of type “_thread-type-1._udp.default.service.arpa.”.
# - Pass Criteria:
# - N/A
print("Step 11: Device: ED_2 Description (DPR-5.2): Harness instructs the device to unicast DNS query...")
pkts.filter_wpan_src64(ED_2). \
filter(lambda p: p.dns). \
filter(lambda p: p.dns.flags.response == 0). \
filter(lambda p: "_thread-type-1._udp.default.service.arpa" in verify_utils.as_list(p.dns.qry.name)). \
filter(lambda p: any(t == consts.DNS_TYPE_PTR for t in verify_utils.as_list(p.dns.qry.type))). \
must_next()
# Step 12
# - Device: BR_2
# - Description (DPR-5.2): Automatically sends mDNS query.
# - Pass Criteria:
# - N/A
print("Step 12: Device: BR_2 Description (DPR-5.2): Automatically sends mDNS query")
pkts.filter_eth_src(BR_2_ETH). \
filter(lambda p: p.mdns). \
filter(lambda p: "_thread-type-1._udp.local" in verify_utils.as_list(p.mdns.qry.name)). \
must_next()
# Step 13
# - Device: BR_1 (DUT)
# - Description (DPR-5.2): Automatically responds to mDNS query with “service-test-1”.
# - Pass Criteria:
# - N/A (verified in step 14)
print("Step 13: Device: BR_1 (DUT) Description (DPR-5.2): Automatically responds to mDNS query...")
pkts.filter_eth_src(BR_1_ETH). \
filter(lambda p: p.mdns). \
filter(lambda p: any("service-test-1" in str(name)
for name in verify_utils.as_list(p.mdns.resp.name))). \
must_next()
# Step 14
# - Device: BR_2
# - Description (DPR-5.2): Automatically sends a DNS response to ED_2.
# - Pass Criteria:
# - The DNS Response is received at ED_2, is valid and contains only service-test-1 in the Answers section:
# $ORIGIN default.service.arpa. _thread-type-1._udp ( PTR service-test-1._thread-type-1._udp )
# - It MAY contain in the Additional records section: $ORIGIN default.service.arpa.
# service-test-1._thread-type-1._udp ( SRV 0 4 55555 host-test-1 ) host-test-1 AAAA <OMR address of ED_1>
# - Also it MAY contain in the Additional records section, but only if the above Additional records are also
# included: $ORIGIN default.service.arpa. host-test-1 AAAA <ML-EID address of ED_1>
print("Step 14: Device: BR_2 Description (DPR-5.2): Automatically sends a DNS response to ED_2")
pkts.filter_wpan_src64(BR_2). \
filter(lambda p: p.dns). \
filter(lambda p: p.dns.flags.response == 1). \
filter(lambda p: any("service-test-1" in str(name)
for name in verify_utils.as_list(p.dns.ptr.domain_name))). \
must_next()
# Step 15
# - Device: ED_1
# - Description (DPR-5.2): Harness instructs the device to unicast DNS query QType=SRV to the DUT for service
# “service-test-2._thread-type-2._udp.default.service.arpa.”.
# - Pass Criteria:
# - N/A
print("Step 15: Device: ED_1 Description (DPR-5.2): Harness instructs the device to unicast DNS query...")
pkts.filter_wpan_src64(ED_1). \
filter(lambda p: p.dns). \
filter(lambda p: p.dns.flags.response == 0). \
filter(lambda p: "service-test-2._thread-type-2._udp.default.service.arpa"
in verify_utils.as_list(p.dns.qry.name)). \
filter(lambda p: any(t == consts.DNS_TYPE_SRV for t in verify_utils.as_list(p.dns.qry.type))). \
must_next()
# Step 16
# - Device: BR_1 (DUT)
# - Description (DPR-5.2): Automatically sends DNS Response. Note: during this step, DUT MAY perform mDNS query
# to BR_2 which responds with service-test-2. This isnt shown in detail.
# - Pass Criteria:
# - The DUT MUST send a valid DNS Response is valid, containing service-test-2 answer record: $ORIGIN
# default.service.arpa. service-test-2._thread-type-2._udp ( SRV 0 0 55555 host-test-2 )
# - It MAY contain in the Additional records section: host-test-2 AAAA <OMR address of ED_2>
print("Step 16: Device: BR_1 (DUT) Description (DPR-5.2): Automatically sends DNS Response")
pkts.filter_wpan_src64(BR_1). \
filter(lambda p: p.dns). \
filter(lambda p: p.dns.flags.response == 1). \
filter(lambda p: any("service-test-2" in str(name)
for name in verify_utils.as_list(p.dns.resp.name))). \
must_next()
if __name__ == '__main__':
verify_utils.run_main(verify)