[nexus] add 1_3_DPR_TC_1 for Service Discovery of services (#12793)

This commit adds the Nexus test case 1_3_DPR_TC_1 which verifies
Discovery Proxy functionality on a Border Router, as per the
Thread 1.3 test specification.

The implementation includes:
- tests/nexus/test_1_3_DPR_TC_1.cpp: Implements the test sequence.
  It sets up a topology with a Border Router (BR_1), a Thread End
  Device (ED_1), and an infrastructure node (Eth_1). It simulates
  Eth_1 advertising services via mDNS and ED_1 querying for those
  services through the BR's Discovery Proxy.
- tests/nexus/verify_1_3_DPR_TC_1.py: Performs automated packet
  verification. It ensures the BR correctly adds SRP Server info
  to Network Data, Eth_1 advertises services, and ED_1 receives
  a valid DNS response from the BR containing the discovered
  infrastructure services.
- tests/nexus/openthread-core-nexus-config.h: Enables the
  OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE configuration to
  support Discovery Proxy testing in the Nexus environment.
- 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 from the infrastructure
link to Thread devices.
This commit is contained in:
Jonathan Hui
2026-03-30 16:23:21 -05:00
committed by GitHub
parent 0883176d31
commit 1b78d18c13
6 changed files with 553 additions and 3 deletions
+1
View File
@@ -264,6 +264,7 @@ ot_nexus_test(1_3_DBR_TC_7B "cert;nexus")
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_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 -1
View File
@@ -69,7 +69,7 @@
#define OPENTHREAD_CONFIG_DIAG_ENABLE 0
#define OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE 1
#define OPENTHREAD_CONFIG_DNS_DSO_ENABLE 0
#define OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE 0
#define OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE 1
#define OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE 1
#define OPENTHREAD_CONFIG_ECDSA_ENABLE 1
#define OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE 1
+1
View File
@@ -199,6 +199,7 @@ DEFAULT_TESTS=(
"1_3_DBR_TC_7C"
"1_3_DBR_TC_8"
"1_3_DBR_TC_10"
"1_3_DPR_TC_1"
"1_3_SRP_TC_1"
"1_3_SRP_TC_2"
"1_3_SRP_TC_3"
+370
View File
@@ -0,0 +1,370 @@
/*
* 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 "net/mdns.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 = 20 * 1000;
/**
* Time to wait for SRP registration to complete.
*/
static constexpr uint32_t kSrpRegistrationTime = 5 * 1000;
/**
* Time to wait for DNS response.
*/
static constexpr uint32_t kDnsResponseTime = 20 * 1000;
/**
* Infrastructure interface index.
*/
static constexpr uint32_t kInfraIfIndex = 1;
/**
* Service and Host names.
*/
static const char kInfraServiceType[] = "_infra-test._udp";
static const char kInfraHostName[] = "host-test-eth";
static const char kDiscoveryProxyType[] = "_infra-test._udp.default.service.arpa.";
struct ServiceInfo
{
const char *mInstanceName;
uint16_t mPort;
const char *mTxtData;
};
static const ServiceInfo kInfraServices[] = {
{"service-test-1", 55551, "\x0Adummy=abcd\x0Fthread-test=a49"},
{"service-test-2", 55552, "\x04a=2\x12thread-test=b50_test"},
{"service-test-3", 55553, "\x0Ba_dummy=42\x0Cthread-test="},
{"service-test-4", 55554, "\x0Dthread-test=1\x15ignorethis=thread-test="},
{"service-test-5", 55555,
"\x0B"
"a88=thread-\x10THREAD-TEST=C51\x14ignorethis=thread-test"},
};
static void RegisterMdnsServices(Node &aEth1)
{
Dns::Multicast::Core &mdns = aEth1.Get<Dns::Multicast::Core>();
SuccessOrQuit(mdns.SetEnabled(true, kInfraIfIndex));
{
Dns::Multicast::Core::Host host;
ClearAllBytes(host);
host.mHostName = kInfraHostName;
host.mAddresses = &aEth1.mInfraIf.GetAddresses()[1]; // ULA address
host.mAddressesLength = 1;
SuccessOrQuit(mdns.RegisterHost(host, 0, nullptr));
}
for (const ServiceInfo &info : kInfraServices)
{
Dns::Multicast::Core::Service service;
ClearAllBytes(service);
service.mServiceInstance = info.mInstanceName;
service.mServiceType = kInfraServiceType;
service.mHostName = kInfraHostName;
service.mPort = info.mPort;
service.mTxtData = reinterpret_cast<const uint8_t *>(info.mTxtData);
service.mTxtDataLength = static_cast<uint16_t>(strlen(info.mTxtData));
SuccessOrQuit(mdns.RegisterService(service, 0, nullptr));
}
}
void Test_1_3_DPR_TC_1(const char *aJsonFileName)
{
/**
* 5.1. [1.3] [CERT] Service discovery of services on Thread and Infrastructure - Single BR
*
* 5.1.1 Purpose
* To test the following:
* 1. Discovery proxy on the BR to perform mDNS query on the infrastructure link in the case where it doesnt have
* any answer.
* 2. Respond to unicast DNS queries made by a Thread Device on the Thread interface.
* 3. Thread Device can discover services advertised by infrastructure device (mDNS) via BR DUT.
* 4. Single BR case
*
* 5.1.2 Topology
* - BR_1 (DUT) - Thread Border Router, and the Leader
* - ED_1 - Test Bed device operating as a Thread End Device, attached to BR_1
* - Eth_1 - Test Bed border router device on an Adjacent Infrastructure Link
*
* Spec Reference | V1.1 Section | V1.3.0 Section
* --------------------|--------------|---------------
* Discovery Proxy | N/A | 5.1
*/
Core nexus;
Node &br1 = nexus.CreateNode();
Node &ed1 = nexus.CreateNode();
Node &eth1 = nexus.CreateNode();
Srp::Client::Service service;
Dns::TxtEntry txtEntry;
br1.SetName("BR_1");
ed1.SetName("ED_1");
eth1.SetName("Eth_1");
nexus.AdvanceTime(0);
SuccessOrQuit(Instance::SetGlobalLogLevel(kLogLevelNote));
Log("---------------------------------------------------------------------------------------");
Log("Step 1: Device: BR_1 (DUT) Description (DPR-5.1): Enable");
/**
* Step 1
* - Device: BR_1 (DUT)
* - Description (DPR-5.1): Enable
* - Pass Criteria: N/A
*/
br1.Form();
nexus.AdvanceTime(kFormNetworkTime);
VerifyOrQuit(br1.Get<Mle::Mle>().IsLeader());
Log("---------------------------------------------------------------------------------------");
Log("Step 2: Device: Eth_1, ED_1 Description (DPR-5.1): Enable");
/**
* Step 2
* - Device: Eth_1, ED_1
* - Description (DPR-5.1): Enable
* - Pass Criteria: N/A
*/
eth1.mInfraIf.Init(eth1);
ed1.Join(br1, Node::kAsFed);
nexus.AdvanceTime(kJoinNetworkTime);
VerifyOrQuit(ed1.Get<Mle::Mle>().IsAttached());
Log("---------------------------------------------------------------------------------------");
Log("Step 3: Device: BR_1 (DUT) Description (DPR-5.1): Automatically adds its SRP Server information...");
/**
* Step 3
* - Device: BR_1 (DUT)
* - Description (DPR-5.1): Automatically adds its SRP Server information in the Thread Network Data.
* Automatically configures an OMR prefix on the Thread Network. Automatically configures a ULA prefix on the AIL.
* - Pass Criteria:
* - The DUTs SRP Server information MUST appear in the Thread Network Data.
* - It MUST be a DNS/SRP Unicast Dataset, or DNS/SRP Anycast Dataset, or both.
*/
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);
Ip6::Prefix omrPrefix;
SuccessOrQuit(br1.Get<BorderRouter::RoutingManager>().GetOmrPrefix(omrPrefix));
nexus.AddTestVar("OMR_PREFIX", omrPrefix.ToString().AsCString());
Ip6::Prefix pre1Prefix;
SuccessOrQuit(br1.Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(pre1Prefix));
nexus.AddTestVar("PRE_1_PREFIX", pre1Prefix.ToString().AsCString());
Log("---------------------------------------------------------------------------------------");
Log("Step 4: Device: Eth_1 Description (DPR-5.1): Harness instructs device to advertise N=5 services...");
/**
* Step 4
* - Device: Eth_1
* - Description (DPR-5.1): Harness instructs device to advertise N=5 services using mDNS.
* - Pass Criteria: N/A
*/
RegisterMdnsServices(eth1);
nexus.AdvanceTime(kDnsResponseTime);
Log("---------------------------------------------------------------------------------------");
Log("Step 5: Device: ED_1 Description (DPR-5.1): Harness instructs the device to send an SRP Update...");
/**
* Step 5
* - Device: ED_1
* - Description (DPR-5.1): Harness instructs the device to send an SRP Update to DUT as follows:
* $ORIGIN default.service.arpa. service-test-6._thread-test._udp ( SRV 0 0 55551 host-test-1 TXT
* thread-te=trick=value ) host-test-1 AAAA <OMR address of ED_1>
* - Pass Criteria: N/A
*/
ed1.Get<Srp::Client>().EnableAutoStartMode(nullptr, nullptr);
SuccessOrQuit(ed1.Get<Srp::Client>().SetHostName("host-test-1"));
SuccessOrQuit(ed1.Get<Srp::Client>().EnableAutoHostAddress());
ClearAllBytes(service);
service.mName = "_thread-test._udp";
service.mInstanceName = "service-test-6";
service.mPort = 55551;
txtEntry.mKey = "thread-te";
txtEntry.mValue = reinterpret_cast<const uint8_t *>("trick=value");
txtEntry.mValueLength = 11;
service.mTxtEntries = &txtEntry;
service.mNumTxtEntries = 1;
SuccessOrQuit(ed1.Get<Srp::Client>().AddService(service));
nexus.AdvanceTime(kSrpRegistrationTime);
Log("---------------------------------------------------------------------------------------");
Log("Step 6: Device: BR_1 (DUT) Description (DPR-5.1): Automatically sends SRP Update Response with SUCCESS");
/**
* Step 6
* - Device: BR_1 (DUT)
* - Description (DPR-5.1): Automatically sends SRP Update Response with “SUCCESS”.
* - Pass Criteria:
* - The DUT MUST send SRP Update Response with status 0 ( “NoError” ).
*/
VerifyOrQuit(ed1.Get<Srp::Client>().GetHostInfo().GetState() == Srp::Client::kRegistered);
Log("---------------------------------------------------------------------------------------");
Log("Step 7: Device: ED_1 Description (DPR-5.1): Harness instructs the device to unicast DNS query QType=PTR...");
/**
* Step 7
* - Device: ED_1
* - Description (DPR-5.1): Harness instructs the device to unicast DNS query QType=PTR to the DUT for services
* of type “_infra-test._udp.default.service.arpa.”
* - Pass Criteria: N/A
*/
const Ip6::Address &br1Mleid = br1.Get<Mle::Mle>().GetMeshLocalEid();
Dns::Client::QueryConfig queryConfig;
queryConfig.Clear();
AsCoreType(&queryConfig.mServerSockAddr.mAddress) = br1Mleid;
queryConfig.mServerSockAddr.mPort = Dns::ServiceDiscovery::Server::kPort;
SuccessOrQuit(ed1.Get<Dns::Client>().Browse(kDiscoveryProxyType, nullptr, nullptr, &queryConfig));
Log("---------------------------------------------------------------------------------------");
Log("Step 8: Device: BR_1 (DUT) Description (DPR-5.1): Automatically MAY send mDNS query...");
/**
* Step 8
* - Device: BR_1 (DUT)
* - Description (DPR-5.1): Automatically MAY send mDNS query on the infrastructure link.
* - Pass Criteria: N/A
*/
nexus.AdvanceTime(1000);
Log("---------------------------------------------------------------------------------------");
Log("Step 9: Device: Eth_1 Description (DPR-5.1): In case DUT queried in step 8, it automatically sends mDNS...");
/**
* Step 9
* - Device: Eth_1
* - Description (DPR-5.1): In case DUT queried in step 8, it automatically sends mDNS response with its active
* services.
* - Pass Criteria: N/A
*/
nexus.AdvanceTime(kDnsResponseTime);
Log("---------------------------------------------------------------------------------------");
Log("Step 10: Device: BR_1 (DUT) Description (DPR-5.1): Automatically sends a DNS response to ED_1");
/**
* Step 10
* - Device: BR_1 (DUT)
* - Description (DPR-5.1): Automatically sends a DNS response to ED_1.
* - Pass Criteria: N/A (validation of response in the next step)
*/
Log("---------------------------------------------------------------------------------------");
Log("Step 11: Device: ED_1 Description (DPR-5.1): Receives the DNS response with at least one of the N services");
/**
* Step 11
* - Device: ED_1
* - Description (DPR-5.1): Receives the DNS response with at least one of the N services.
* - Pass Criteria:
* - The DUT must send a valid DNS Response, containing in the Answer records section at least one of the services
* advertised by Eth_1, specifically the below where N is a number out of 1, 2, 3, 4, 5:
* $ORIGIN default.service.arpa. _infra-test._udp ( PTR service-test-N._infra-test._udp )
* - It MAY contain in the Additional records section one or more of the below services identified by number N
* plus the host (AAAA) record:
* $ORIGIN default.service.arpa. service-test-1._infra-test._udp ( SRV 0 0 55551 host-test-eth TXT
* dummy=abcd;thread-test=a49 ) ... host-test-eth AAAA <ULA address of Eth_1>
* - Response MUST NOT contain any AAAA record with a link-local address.
* - Response MUST NOT contain “service-test-6” records.
* - Response MUST NOT contain any “host-test-1” records.
*/
nexus.SaveTestInfo(aJsonFileName);
}
} // namespace Nexus
} // namespace ot
int main(int argc, char *argv[])
{
const char *jsonFile = (argc > 1) ? argv[argc - 1] : "test_1_3_DPR_TC_1.json";
ot::Nexus::Test_1_3_DPR_TC_1(jsonFile);
printf("All tests passed\n");
return 0;
}
+2 -2
View File
@@ -109,6 +109,8 @@ void Test_1_3_SRPC_TC_7(const char *aJsonFileName)
Node &td1 = nexus.CreateNode();
Node &eth1 = nexus.CreateNode();
Srp::Client::Service service;
br1.SetName("BR_1");
router1.SetName("Router_1");
td1.SetName("TD_1");
@@ -174,7 +176,6 @@ void Test_1_3_SRPC_TC_7(const char *aJsonFileName)
td1.Get<Srp::Client>().SetKeyLeaseInterval(kSrpKeyLease1d);
{
Srp::Client::Service service;
ClearAllBytes(service);
service.mName = kSrpServiceType;
service.mInstanceName = kSrpInstanceName;
@@ -221,7 +222,6 @@ void Test_1_3_SRPC_TC_7(const char *aJsonFileName)
td1.Get<Srp::Client>().SetKeyLeaseInterval(kSrpKeyLease1d);
{
Srp::Client::Service service;
ClearAllBytes(service);
service.mName = kSrpServiceType;
service.mInstanceName = kSrpInstanceName;
+178
View File
@@ -0,0 +1,178 @@
#!/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.1. [1.3] [CERT] Service discovery of services on Thread and Infrastructure - Single BR
#
# 5.1.1 Purpose
# To test the following:
# 1. Discovery proxy on the BR to perform mDNS query on the infrastructure link in the case where it doesnt have
# any answer.
# 2. Respond to unicast DNS queries made by a Thread Device on the Thread interface.
# 3. Thread Device can discover services advertised by infrastructure device (mDNS) via BR DUT.
# 4. Single BR case
#
# 5.1.2 Topology
# - BR_1 (DUT) - Thread Border Router, and the Leader
# - ED_1 - Test Bed device operating as a Thread End Device, attached to BR_1
# - Eth_1 - Test Bed border router device on an Adjacent Infrastructure Link
#
# Spec Reference | V1.1 Section | V1.3.0 Section
# --------------------|--------------|---------------
# Discovery Proxy | N/A | 5.1
pkts = pv.pkts
pv.summary.show()
BR_1 = pv.vars['BR_1']
BR_1_MLEID = pv.vars['BR_1_MLEID']
ED_1 = pv.vars['ED_1']
ED_1_MLEID = pv.vars['ED_1_MLEID']
Eth_1_ETH = pv.vars['Eth_1_ETH']
# Step 1: Device: BR_1 (DUT) Description (DPR-5.1): Enable
# - Pass Criteria: N/A
print("Step 1: BR_1 (DUT) enabled and became Leader.")
# Step 2: Device: Eth_1, ED_1 Description (DPR-5.1): Enable
# - Pass Criteria: N/A
print("Step 2: Eth_1 and ED_1 enabled and joined the network.")
# Step 3: Device: BR_1 (DUT) Description (DPR-5.1): Automatically adds its SRP Server information...
# - Pass Criteria:
# - The DUTs SRP Server information MUST appear in the Thread Network Data.
# - It MUST be a DNS/SRP Unicast Dataset, or DNS/SRP Anycast Dataset, or both.
print("Step 3: BR_1 (DUT) adds its SRP Server information to the Thread Network Data.")
pkts.filter_wpan_src64(BR_1).\
filter_mle_cmd(consts.MLE_DATA_RESPONSE).\
filter(lambda p: {
consts.NWD_SERVICE_TLV,
consts.NWD_SERVER_TLV
} <= set(p.thread_nwd.tlv.type)).\
must_next()
# Step 4: Device: Eth_1 Description (DPR-5.1): Harness instructs device to advertise N=5 services...
# - Pass Criteria: N/A
print("Step 4: Eth_1 advertises 5 services using mDNS.")
pkts.filter_eth_src(Eth_1_ETH).\
filter(lambda p: p.mdns).\
filter(lambda p: p.mdns.count.answers > 0).\
must_next()
# Step 5: Device: ED_1 Description (DPR-5.1): Harness instructs the device to send an SRP Update...
# - Pass Criteria: N/A
print("Step 5: ED_1 sends an SRP Update to BR_1 (DUT).")
pkts.filter_ipv6_src(ED_1_MLEID).\
filter_ipv6_dst(BR_1_MLEID).\
filter(lambda p: p.dns).\
filter(lambda p: p.dns.flags.opcode == 5).\
must_next()
# Step 6: Device: BR_1 (DUT) Description (DPR-5.1): Automatically sends SRP Update Response with SUCCESS
# - Pass Criteria:
# - The DUT MUST send SRP Update Response with status 0 ( “NoError” ).
print("Step 6: BR_1 (DUT) sends SRP Update Response with SUCCESS.")
pkts.filter_ipv6_src(BR_1_MLEID).\
filter_ipv6_dst(ED_1_MLEID).\
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 7: Device: ED_1 Description (DPR-5.1): Harness instructs the device to unicast DNS query QType=PTR...
# - Pass Criteria: N/A
print("Step 7: ED_1 sends unicast DNS query QType=PTR to BR_1 (DUT).")
pkts.filter_ipv6_src(ED_1_MLEID).\
filter_ipv6_dst(BR_1_MLEID).\
filter(lambda p: p.dns).\
filter(lambda p: p.dns.flags.response == 0).\
filter(lambda p: "_infra-test._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 8: Device: BR_1 (DUT) Description (DPR-5.1): Automatically MAY send mDNS query...
# - Pass Criteria: N/A
print("Step 8: BR_1 (DUT) MAY send mDNS query on the infrastructure link.")
# Step 9: Device: Eth_1 Description (DPR-5.1): In case DUT queried in step 8, it automatically sends mDNS...
# - Pass Criteria: N/A
print("Step 9: Eth_1 sends mDNS response with its active services.")
pkts.filter_eth_src(Eth_1_ETH).\
filter(lambda p: p.mdns).\
filter(lambda p: p.mdns.count.answers > 0).\
must_next()
# Step 10: Device: BR_1 (DUT) Description (DPR-5.1): Automatically sends a DNS response to ED_1
# - Pass Criteria: N/A
print("Step 10: BR_1 (DUT) sends a DNS response to ED_1.")
# Step 11: Device: ED_1 Description (DPR-5.1): Receives the DNS response with at least one of the N services
# - Pass Criteria:
# - The DUT must send a valid DNS Response, containing in the Answer records section at least one of the services
# advertised by Eth_1, specifically the below where N is a number out of 1, 2, 3, 4, 5:
# $ORIGIN default.service.arpa. _infra-test._udp ( PTR service-test-N._infra-test._udp )
# - It MAY contain in the Additional records section one or more of the below services identified by number N
# plus the host (AAAA) record:
# $ORIGIN default.service.arpa. service-test-1._infra-test._udp ( SRV 0 0 55551 host-test-eth TXT
# dummy=abcd;thread-test=a49 ) ... host-test-eth AAAA <ULA address of Eth_1>
# - Response MUST NOT contain any AAAA record with a link-local address.
# - Response MUST NOT contain “service-test-6” records.
# - Response MUST NOT contain any “host-test-1” records.
print("Step 11: ED_1 receives the DNS response with at least one of the 5 services.")
pkts.filter_ipv6_src(BR_1_MLEID).\
filter_ipv6_dst(ED_1_MLEID).\
filter(lambda p: p.dns).\
filter(lambda p: p.dns.flags.response == 1).\
filter(lambda p: p.dns.count.answers > 0).\
filter(lambda p: any(name.startswith("service-test-")
for name in verify_utils.as_list(p.dns.ptr.domain_name))).\
filter(lambda p: any(name.endswith("._infra-test._udp.default.service.arpa")
for name in verify_utils.as_list(p.dns.ptr.domain_name))).\
filter(lambda p: not any(addr.startswith("fe80")
for addr in verify_utils.as_list(p.dns.aaaa))).\
filter(lambda p: all("service-test-6" not in str(name)
for name in verify_utils.as_list(p.dns.ptr.domain_name))).\
filter(lambda p: all("host-test-1" not in str(name)
for name in verify_utils.as_list(p.dns.resp.name))).\
must_next()
if __name__ == '__main__':
verify_utils.run_main(verify)