diff --git a/tests/nexus/CMakeLists.txt b/tests/nexus/CMakeLists.txt index b478c74aa..65651bd24 100644 --- a/tests/nexus/CMakeLists.txt +++ b/tests/nexus/CMakeLists.txt @@ -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") diff --git a/tests/nexus/openthread-core-nexus-config.h b/tests/nexus/openthread-core-nexus-config.h index c7fda4d2e..f964d7cb8 100644 --- a/tests/nexus/openthread-core-nexus-config.h +++ b/tests/nexus/openthread-core-nexus-config.h @@ -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 diff --git a/tests/nexus/run_nexus_tests.sh b/tests/nexus/run_nexus_tests.sh index 523412787..76b626180 100755 --- a/tests/nexus/run_nexus_tests.sh +++ b/tests/nexus/run_nexus_tests.sh @@ -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" diff --git a/tests/nexus/test_1_3_DPR_TC_1.cpp b/tests/nexus/test_1_3_DPR_TC_1.cpp new file mode 100644 index 000000000..da74c21d4 --- /dev/null +++ b/tests/nexus/test_1_3_DPR_TC_1.cpp @@ -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 + +#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(); + + 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(info.mTxtData); + service.mTxtDataLength = static_cast(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 doesn’t 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 ð1 = 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().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().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 DUT’s 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().Init(kInfraIfIndex, true); + br1.Get().Init(); + SuccessOrQuit(br1.Get().SetEnabled(true)); + + SuccessOrQuit(br1.Get().SetAddressMode(Srp::Server::kAddressModeUnicast)); + br1.Get().SetEnabled(true); + + nexus.AdvanceTime(kBrActionTime); + + Ip6::Prefix omrPrefix; + SuccessOrQuit(br1.Get().GetOmrPrefix(omrPrefix)); + nexus.AddTestVar("OMR_PREFIX", omrPrefix.ToString().AsCString()); + + Ip6::Prefix pre1Prefix; + SuccessOrQuit(br1.Get().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 + * - Pass Criteria: N/A + */ + + ed1.Get().EnableAutoStartMode(nullptr, nullptr); + SuccessOrQuit(ed1.Get().SetHostName("host-test-1")); + SuccessOrQuit(ed1.Get().EnableAutoHostAddress()); + + ClearAllBytes(service); + service.mName = "_thread-test._udp"; + service.mInstanceName = "service-test-6"; + service.mPort = 55551; + + txtEntry.mKey = "thread-te"; + txtEntry.mValue = reinterpret_cast("trick=value"); + txtEntry.mValueLength = 11; + + service.mTxtEntries = &txtEntry; + service.mNumTxtEntries = 1; + + SuccessOrQuit(ed1.Get().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().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().GetMeshLocalEid(); + Dns::Client::QueryConfig queryConfig; + + queryConfig.Clear(); + AsCoreType(&queryConfig.mServerSockAddr.mAddress) = br1Mleid; + queryConfig.mServerSockAddr.mPort = Dns::ServiceDiscovery::Server::kPort; + + SuccessOrQuit(ed1.Get().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 + * - 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; +} diff --git a/tests/nexus/test_1_3_SRPC_TC_7.cpp b/tests/nexus/test_1_3_SRPC_TC_7.cpp index 80abda937..5d107bf21 100644 --- a/tests/nexus/test_1_3_SRPC_TC_7.cpp +++ b/tests/nexus/test_1_3_SRPC_TC_7.cpp @@ -109,6 +109,8 @@ void Test_1_3_SRPC_TC_7(const char *aJsonFileName) Node &td1 = nexus.CreateNode(); Node ð1 = 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().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().SetKeyLeaseInterval(kSrpKeyLease1d); { - Srp::Client::Service service; ClearAllBytes(service); service.mName = kSrpServiceType; service.mInstanceName = kSrpInstanceName; diff --git a/tests/nexus/verify_1_3_DPR_TC_1.py b/tests/nexus/verify_1_3_DPR_TC_1.py new file mode 100644 index 000000000..73a1c9270 --- /dev/null +++ b/tests/nexus/verify_1_3_DPR_TC_1.py @@ -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 doesn’t 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 DUT’s 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 + # - 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)