diff --git a/tests/nexus/CMakeLists.txt b/tests/nexus/CMakeLists.txt index 65651bd24..bc81e7a3e 100644 --- a/tests/nexus/CMakeLists.txt +++ b/tests/nexus/CMakeLists.txt @@ -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") diff --git a/tests/nexus/run_nexus_tests.sh b/tests/nexus/run_nexus_tests.sh index 76b626180..a909d72c1 100755 --- a/tests/nexus/run_nexus_tests.sh +++ b/tests/nexus/run_nexus_tests.sh @@ -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" diff --git a/tests/nexus/test_1_3_DPR_TC_2.cpp b/tests/nexus/test_1_3_DPR_TC_2.cpp new file mode 100644 index 000000000..d05825def --- /dev/null +++ b/tests/nexus/test_1_3_DPR_TC_2.cpp @@ -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 + +#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 BR’s 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().SetMeshLocalPrefix(networkPrefix); + br2.Get().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().Read(datasetInfo)); + nexus.AddNetworkKey(datasetInfo.Get()); + } + + nexus.AdvanceTime(kFormNetworkTime); + VerifyOrQuit(br1.Get().IsLeader()); + + ed1.Join(br1, Node::kAsFed); + nexus.AdvanceTime(kJoinNetworkTime); + VerifyOrQuit(ed1.Get().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 DUT’s SRP Server information MUST appear in the Thread Network Data of the first Thread network. + */ + + 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); + + 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 + * AAAA 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().EnableAutoStartMode(nullptr, nullptr); + SuccessOrQuit(ed1.Get().SetHostName("host-test-1")); + + ed1Addresses[0] = ed1.Get().GetMeshLocalEid(); + ed1Addresses[1] = ed1.FindGlobalAddress(); + SuccessOrQuit(ed1.Get().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().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().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().Read(datasetInfo)); + nexus.AddNetworkKey(datasetInfo.Get()); + } + + nexus.AdvanceTime(kFormNetworkTime); + VerifyOrQuit(br2.Get().IsLeader()); + + ed2.Join(br2, Node::kAsFed); + nexus.AdvanceTime(kJoinNetworkTime); + VerifyOrQuit(ed2.Get().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_2’s SRP Server information MUST appear in the Thread Network Data of the second Thread network. + */ + + br2.Get().Init(kInfraIfIndex, true); + br2.Get().Init(); + SuccessOrQuit(br2.Get().SetEnabled(true)); + + SuccessOrQuit(br2.Get().SetAddressMode(Srp::Server::kAddressModeUnicast)); + br2.Get().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 + * - Pass Criteria: + * - N/A + */ + + ed2.Get().EnableAutoStartMode(nullptr, nullptr); + SuccessOrQuit(ed2.Get().SetHostName("host-test-2")); + SuccessOrQuit(ed2.Get().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().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().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().GetMeshLocalEid(); + queryConfig.mServerSockAddr.mPort = Dns::ServiceDiscovery::Server::kPort; + + SuccessOrQuit( + ed1.Get().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 isn’t 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 + */ + + 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().GetMeshLocalEid(); + queryConfig.mServerSockAddr.mPort = Dns::ServiceDiscovery::Server::kPort; + + SuccessOrQuit( + ed2.Get().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 + * - 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 + */ + + // 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().GetMeshLocalEid(); + queryConfig.mServerSockAddr.mPort = Dns::ServiceDiscovery::Server::kPort; + + SuccessOrQuit(ed1.Get().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 isn’t 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 + */ + + 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; +} diff --git a/tests/nexus/verify_1_3_DPR_TC_2.py b/tests/nexus/verify_1_3_DPR_TC_2.py new file mode 100644 index 000000000..bef853ab1 --- /dev/null +++ b/tests/nexus/verify_1_3_DPR_TC_2.py @@ -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 BR’s 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 DUT’s 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 + # AAAA 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_2’s 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 + # - 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 isn’t 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 + 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 + # - 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 + 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 isn’t 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 + 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)