mirror of
https://github.com/espressif/openthread.git
synced 2026-08-13 06:07:48 +00:00
[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:
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 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<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 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<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;
|
||||
}
|
||||
@@ -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<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;
|
||||
|
||||
@@ -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 <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)
|
||||
Reference in New Issue
Block a user