[nexus] add SRPC-TC-1 for SRP client re-registration (#12779)

This commit adds the Nexus test case 1_3_SRPC_TC_1 which verifies
that the SRP client correctly handles re-registration with active
SRP servers, especially when multiple Border Routers are present,
as per the Thread 1.3 test specification.

The implementation includes:
- tests/nexus/test_1_3_SRPC_TC_1.cpp: Executes the test sequence
  by configuring two Border Routers (BR_1 and BR_2), a Router,
  and an End Device (ED_1 as DUT). It simulates BR_1 (the initial
  SRP server) becoming unresponsive and verifies that the DUT
  correctly switches to BR_2. It also verifies that the DUT
  stays with its current server (BR_2) even when a numerically
  lower server (BR_1) is re-enabled.
- tests/nexus/verify_1_3_SRPC_TC_1.py: Performs automated
  verification of the captured traffic (PCAP). It checks for
  correct SRP Update packets to the expected SRP servers and
  validates that the DUT behavior matches the specification
  criteria.
- Integrated the new test into tests/nexus/CMakeLists.txt and
  tests/nexus/run_nexus_tests.sh.

The test ensures robust SRP client behavior in dynamic networks
with multiple SRP servers.
This commit is contained in:
Jonathan Hui
2026-03-27 16:54:22 -05:00
committed by GitHub
parent c5108df3e3
commit 51353a9c9e
4 changed files with 670 additions and 0 deletions
+1
View File
@@ -275,6 +275,7 @@ ot_nexus_test(1_3_SRP_TC_11 "cert;nexus")
ot_nexus_test(1_3_SRP_TC_12 "cert;nexus")
ot_nexus_test(1_3_SRP_TC_13 "cert;nexus")
ot_nexus_test(1_3_SRP_TC_15 "cert;nexus")
ot_nexus_test(1_3_SRPC_TC_1 "cert;nexus")
# Misc tests
ot_nexus_test(border_admitter "core;nexus")
+1
View File
@@ -210,6 +210,7 @@ DEFAULT_TESTS=(
"1_3_SRP_TC_12"
"1_3_SRP_TC_13"
"1_3_SRP_TC_15"
"1_3_SRPC_TC_1"
)
# Use provided arguments or the default test list
+430
View File
@@ -0,0 +1,430 @@
/*
* Copyright (c) 2026, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include "platform/nexus_core.hpp"
#include "platform/nexus_node.hpp"
namespace ot {
namespace Nexus {
/**
* Time to advance for a node to form a network and become leader, in milliseconds.
*/
static constexpr uint32_t kFormNetworkTime = 13 * 1000;
/**
* Time to advance for a node to join as a child and upgrade to a router, in milliseconds.
*/
static constexpr uint32_t kAttachToRouterTime = 200 * 1000;
/**
* Time to advance for the network to stabilize after routers have attached.
*/
static constexpr uint32_t kStabilizationTime = 10 * 1000;
/**
* Time to wait for SRP registration to complete.
*/
static constexpr uint32_t kSrpRegistrationTime = 5 * 1000;
/**
* Time to wait for SRP renewal.
*/
static constexpr uint32_t kSrpRenewalTime = 30 * 1000;
/**
* SRP Lease time in seconds.
*/
static constexpr uint32_t kSrpLease = 30;
/**
* SRP Key Lease time in seconds.
*/
static constexpr uint32_t kSrpKeyLease = 600;
/**
* SRP service port.
*/
static constexpr uint16_t kSrpServicePort = 33333;
/**
* Time to wait for SRP server switch.
*/
static constexpr uint32_t kSrpServerSwitchTime = 300 * 1000;
void Test_1_3_SRPC_TC_1(const char *aJsonFileName)
{
Srp::Client::Service service;
/**
* 3.1. [1.3] [CERT] [COMPONENT] Re-register service with active SRP server - Multiple BRs - No AIL
*
* 3.1.1. Purpose
* To test the following:
* - DNS/SRP Unicast Dataset(s) offered in the Thread network
* - Detects unresponsiveness of the SRP server and sends SRP update to another active SRP server
* - Detects a second, numerically lower, SRP server and DUT stays with its current SRP server and does not switch
* to the numerically lowest SRP server
* - Registered service is automatically re-registered with active SRP server before timeout
* - In the absence of an OMR prefix, mesh-local (ML-EID) address will be used by SRP client.
*
* Spec Reference | V1.1 Section | V1.3.0 Section
* -----------------|--------------|---------------
* SRP Client | N/A | 2.3.2
*/
Core nexus;
Node &br1 = nexus.CreateNode();
Node &br2 = nexus.CreateNode();
Node &ed1 = nexus.CreateNode();
Node &router1 = nexus.CreateNode();
br1.SetName("BR_1");
br2.SetName("BR_2");
ed1.SetName("ED_1");
router1.SetName("Router_1");
// Set Mesh-Local IID to be deterministic and ensure BR_1 has a numerically lower ML-EID than BR_2.
{
Ip6::InterfaceIdentifier iid;
iid.Clear();
iid.mFields.m8[7] = 1;
SuccessOrQuit(br1.Get<Mle::Mle>().SetMeshLocalIid(iid));
iid.mFields.m8[7] = 2;
SuccessOrQuit(br2.Get<Mle::Mle>().SetMeshLocalIid(iid));
}
SuccessOrQuit(Instance::SetGlobalLogLevel(kLogLevelNote));
Log("---------------------------------------------------------------------------------------");
Log("Step 0: Router 1 Enable. Automatically, becomes Leader.");
/**
* Step 0
* - Device: Router 1
* - Description (SRPC-3.1): Enable. Automatically, becomes Leader.
* - Pass Criteria:
* - N/A
*/
router1.Form();
nexus.AdvanceTime(kFormNetworkTime);
VerifyOrQuit(router1.Get<Mle::Mle>().IsLeader());
Log("---------------------------------------------------------------------------------------");
Log("Step 1: BR_1 Enable: Harness configures the device with a numerically lower ML-EID.");
/**
* Step 1
* - Device: BR_1
* - Description (SRPC-3.1): Enable: Harness configures the device with a numerically lower ML-EID address than
* BR_2 will have. Note: due to absence of adjacent infrastructure link (AIL), no OMR address is configured by
* the BR.
* - Pass Criteria:
* - N/A
*/
/** Use AllowList to specify links between nodes. */
br1.AllowList(br2);
br1.AllowList(router1);
br2.AllowList(br1);
br2.AllowList(router1);
router1.AllowList(br1);
router1.AllowList(br2);
router1.AllowList(ed1);
ed1.AllowList(router1);
br1.Join(router1);
nexus.AdvanceTime(kAttachToRouterTime * 2);
VerifyOrQuit(br1.Get<Mle::Mle>().IsRouter());
Log("---------------------------------------------------------------------------------------");
Log("Step 2: ED 1 (DUT) Enable; automatically connects to Router_1.");
/**
* Step 2
* - Device: ED 1 (DUT)
* - Description (SRPC-3.1): Enable; automatically connects to Router_1.
* - Pass Criteria:
* - N/A
*/
ed1.Join(router1, Node::kAsFed);
nexus.AdvanceTime(kAttachToRouterTime);
VerifyOrQuit(ed1.Get<Mle::Mle>().IsAttached());
Log("---------------------------------------------------------------------------------------");
Log("Step 3: BR 1 Automatically adds its SRP Server information in the Thread Network Data.");
/**
* Step 3
* - Device: BR 1
* - Description (SRPC-3.1): Automatically adds its SRP Server information in the Thread Network Data by using a
* DNS/SRP Unicast Dataset, indicating its ML-EID address.
* - Pass Criteria:
* - N/A
*/
SuccessOrQuit(br1.Get<Srp::Server>().SetAddressMode(Srp::Server::kAddressModeUnicast));
br1.Get<Srp::Server>().SetEnabled(true);
nexus.AdvanceTime(kStabilizationTime);
/** Add SRP port to test variables for Python script. */
String<6> portString;
portString.Append("%u", br1.Get<Srp::Server>().GetPort());
nexus.AddTestVar("BR_1_SRP_PORT", portString.AsCString());
Log("---------------------------------------------------------------------------------------");
Log("Step 4: ED 1 (DUT) Harness instructs DUT to add a service to the device.");
/**
* Step 4
* - Device: ED 1 (DUT)
* - Description (SRPC-3.1): Harness instructs DUT to add a service to the device: $ORIGIN default.service.arpa.
* service-test-1._thread-test._udp ( SRV 33333 host-test-1 ) host-test-1 AAAA <ML-EID address of ED_1> with the
* following options: Update Lease Option Lease: 30 seconds Key Lease: 10 minutes
* - Pass Criteria:
* - The DUT ED_1 MUST send SRP Update to BR_1 containing the service-test-1.
* - The IPv6 address in the AAAA record of the SRP Update MUST be an ML-EID, specifically the ML-EID of the DUT.
* - It MUST NOT contain any other IPv6 addresses in AAAA records.
*/
ed1.Get<Srp::Client>().EnableAutoStartMode(nullptr, nullptr);
SuccessOrQuit(ed1.Get<Srp::Client>().SetHostName("host-test-1"));
SuccessOrQuit(ed1.Get<Srp::Client>().EnableAutoHostAddress());
ed1.Get<Srp::Client>().SetLeaseInterval(kSrpLease);
ed1.Get<Srp::Client>().SetKeyLeaseInterval(kSrpKeyLease);
ClearAllBytes(service);
service.mName = "_thread-test._udp";
service.mInstanceName = "service-test-1";
service.mPort = kSrpServicePort;
SuccessOrQuit(ed1.Get<Srp::Client>().AddService(service));
nexus.AdvanceTime(kSrpRegistrationTime);
Log("---------------------------------------------------------------------------------------");
Log("Step 5: BR_1 Automatically sends DNS Response (Rcode=0, NoError).");
/**
* Step 5
* - Device: BR_1
* - Description (SRPC-3.1): Automatically sends DNS Response (Rcode=0, NoError).
* - Pass Criteria:
* - N/A
*/
VerifyOrQuit(ed1.Get<Srp::Client>().GetHostInfo().GetState() == Srp::Client::kRegistered);
Log("---------------------------------------------------------------------------------------");
Log("Step 6: BR 2 Enable. Harness configures device with a numerically higher ML-EID.");
/**
* Step 6
* - Device: BR 2
* - Description (SRPC-3.1): Enable. Harness configures device with a numerically higher ML-EID address than BR 1.
* This ensures that the BR 2 SRP service will be less preferred to the DUT. Note: due to absence of adjacent
* infrastructure link (AIL), no OMR address is configured by the BR.
* - Pass Criteria:
* - N/A
*/
br2.Join(router1);
nexus.AdvanceTime(kAttachToRouterTime);
VerifyOrQuit(br2.Get<Mle::Mle>().IsRouter());
/** Verify BR_1 has a numerically lower ML-EID than BR_2. */
VerifyOrQuit(br1.Get<Mle::Mle>().GetMeshLocalEid() < br2.Get<Mle::Mle>().GetMeshLocalEid());
Log("---------------------------------------------------------------------------------------");
Log("Step 7: BR 2 Harness instructs the device to add its SRP Server information.");
/**
* Step 7
* - Device: BR 2
* - Description (SRPC-3.1): Harness instructs the device to add its SRP Server information in the Thread Network
* Data using a DNS/SRP Unicast Dataset. Note: normally BR_2 does not add this information, since an SRP server
* is already advertised on the Thread Network. The Harness overrides this behavior.
* - Pass Criteria:
* - The DUT MUST NOT send SRP Update to BR_2.
*/
SuccessOrQuit(br2.Get<Srp::Server>().SetAddressMode(Srp::Server::kAddressModeUnicast));
br2.Get<Srp::Server>().SetEnabled(true);
nexus.AdvanceTime(30 * 1000);
/** Add SRP port to test variables for Python script. */
portString.Clear().Append("%u", br2.Get<Srp::Server>().GetPort());
nexus.AddTestVar("BR_2_SRP_PORT", portString.AsCString());
Log("---------------------------------------------------------------------------------------");
Log("Step 8: BR 1 Harness deactivates the device.");
/**
* Step 8
* - Device: BR 1
* - Description (SRPC-3.1): Harness deactivates the device.
* - Pass Criteria:
* - N/A
*/
br1.Get<Srp::Server>().SetEnabled(false);
br1.Get<Mle::Mle>().Stop();
br1.Get<ThreadNetif>().Down();
Log("---------------------------------------------------------------------------------------");
Log("Step 8b: Harness waits 30 seconds. Within this time, the next step must happen.");
/**
* Step 8b
* - Device: N/A
* - Description (SRPC-3.1): Harness waits 30 seconds. Within this time, the next step must happen.
* - Pass Criteria:
* - N/A
*/
nexus.AdvanceTime(kSrpRenewalTime);
Log("---------------------------------------------------------------------------------------");
Log("Step 9: ED 1 (DUT) Automatically sends SRP Update to BR_1 to renew service.");
/**
* Step 9
* - Device: ED 1 (DUT)
* - Description (SRPC-3.1): Automatically sends SRP Update to BR_1 to renew service.
* - Pass Criteria:
* - The DUT MUST send SRP Update to BR_1 as in step 4.
*/
nexus.AdvanceTime(kSrpRegistrationTime);
Log("---------------------------------------------------------------------------------------");
Log("Step 10: BR 1 Does not respond.");
/**
* Step 10
* - Device: BR 1
* - Description (SRPC-3.1): Does not respond.
* - Pass Criteria:
* - N/A
*/
Log("---------------------------------------------------------------------------------------");
Log("Step 11: ED 1 (DUT) Automatically sends SRP Update to BR_2");
/**
* Step 11
* - Device: ED 1 (DUT)
* - Description (SRPC-3.1): Automatically sends SRP Update to BR_2
* - Pass Criteria:
* - The DUT MUST send SRP Update like in step 4 but now to BR_2
*/
nexus.AdvanceTime(kSrpServerSwitchTime);
Log("---------------------------------------------------------------------------------------");
Log("Step 12: BR 2 Automatically sends SRP Update Response (Rcode=0, NoError).");
/**
* Step 12
* - Device: BR 2
* - Description (SRPC-3.1): Automatically sends SRP Update Response (Rcode=0, NoError).
* - Pass Criteria:
* - N/A
*/
VerifyOrQuit(!AsConst(br2.Get<Srp::Server>()).GetHosts().IsEmpty());
Log("---------------------------------------------------------------------------------------");
Log("Step 13: BR_1 Harness re-enables the device.");
/**
* Step 13
* - Device: BR_1
* - Description (SRPC-3.1): Harness re-enables the device.
* - Pass Criteria:
* - N/A
*/
br1.Get<ThreadNetif>().Up();
SuccessOrQuit(br1.Get<Mle::Mle>().Start());
br1.Join(router1);
nexus.AdvanceTime(kAttachToRouterTime);
Log("---------------------------------------------------------------------------------------");
Log("Step 14: BR_1 Harness instructs the device to add its SRP Server information.");
/**
* Step 14
* - Device: BR_1
* - Description (SRPC-3.1): Harness instructs the device to add its SRP Server information in the Thread Network
* Data using a DNS/SRP Unicast Dataset. Note: normally BR_1 does not add this information, since an SRP server
* is already advertised on the Thread Network. The Harness overrides this behavior.
* - Pass Criteria:
* - N/A
*/
SuccessOrQuit(br1.Get<Srp::Server>().SetAddressMode(Srp::Server::kAddressModeUnicastForceAdd));
br1.Get<Srp::Server>().SetEnabled(true);
nexus.AdvanceTime(kStabilizationTime);
Log("---------------------------------------------------------------------------------------");
Log("Step 15: ED 1 (DUT) Does not send SRP Update to BR_1, but stays with its current server.");
/**
* Step 15
* - Device: ED 1 (DUT)
* - Description (SRPC-3.1): Does not send SRP Update to BR_1, but stays with its current SRP server BR 2..
* - Pass Criteria:
* - The DUT MUST NOT send SRP Update to BR_1.
*/
nexus.AdvanceTime(kSrpRegistrationTime);
Log("---------------------------------------------------------------------------------------");
nexus.SaveTestInfo(aJsonFileName);
}
} // namespace Nexus
} // namespace ot
int main(int argc, char *argv[])
{
ot::Nexus::Test_1_3_SRPC_TC_1((argc > 2) ? argv[2] : "test_1_3_SRPC_TC_1.json");
printf("All tests passed\n");
return 0;
}
+238
View File
@@ -0,0 +1,238 @@
#!/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):
# 3.1. [1.3] [CERT] [COMPONENT] Re-register service with active SRP server - Multiple BRs - No AIL
#
# 3.1.1. Purpose
# To test the following:
# - DNS/SRP Unicast Dataset(s) offered in the Thread network
# - Detects unresponsiveness of the SRP server and sends SRP update to another active SRP server
# - Detects a second, numerically lower, SRP server and DUT stays with its current SRP server and does not switch
# to the numerically lowest SRP server
# - Registered service is automatically re-registered with active SRP server before timeout
# - In the absence of an OMR prefix, mesh-local (ML-EID) address will be used by SRP client.
#
# Spec Reference | V1.1 Section | V1.3.0 Section
# -----------------|--------------|---------------
# SRP Client | N/A | 2.3.2
pkts = pv.pkts
pv.summary.show()
BR_1_MLEID = pv.vars['BR_1_MLEID']
BR_2_MLEID = pv.vars['BR_2_MLEID']
ED_1 = pv.vars['ED_1']
ED_1_MLEID = pv.vars['ED_1_MLEID']
SRP_SERVICE_NAME = '_thread-test._udp.default.service.arpa'
SRP_INSTANCE_NAME = 'service-test-1.' + SRP_SERVICE_NAME
# Step 0
# Device: Router 1
# Description (SRPC-3.1): Enable. Automatically, becomes Leader.
# Pass Criteria:
# N/A
print("Step 0: Router 1 becomes Leader.")
# Step 1
# Device: BR_1
# Description (SRPC-3.1): Enable: Harness configures the device with a numerically lower ML-EID address than
# BR_2 will have. Note: due to absence of adjacent infrastructure link (AIL), no OMR address is configured by
# the BR.
# Pass Criteria:
# N/A
print("Step 1: BR_1 joins the network.")
# Step 2
# Device: ED 1 (DUT)
# Description (SRPC-3.1): Enable; automatically connects to Router_1.
# Pass Criteria:
# N/A
print("Step 2: ED_1 joins the network.")
# Step 3
# Device: BR 1
# Description (SRPC-3.1): Automatically adds its SRP Server information in the Thread Network Data by using a
# DNS/SRP Unicast Dataset, indicating its ML-EID address.
# Pass Criteria:
# N/A
print("Step 3: BR_1 adds its SRP Server information.")
# Step 4
# Device: ED 1 (DUT)
# Description (SRPC-3.1): Harness instructs DUT to add a service to the device: $ORIGIN default.service.arpa.
# service-test-1._thread-test._udp ( SRV 33333 host-test-1 ) host-test-1 AAAA <ML-EID address of ED_1> with the
# following options: Update Lease Option Lease: 30 seconds Key Lease: 10 minutes
# Pass Criteria:
# - The DUT ED_1 MUST send SRP Update to BR_1 containing the service-test-1.
# - The IPv6 address in the AAAA record of the SRP Update MUST be an ML-EID, specifically the ML-EID of the DUT.
# - It MUST NOT contain any other IPv6 addresses in AAAA records.
print("Step 4: ED_1 sends SRP Update to BR_1.")
pkts.filter_wpan_src64(ED_1).\
filter_ipv6_dst(BR_1_MLEID).\
filter(lambda p: p.dns.flags.opcode == consts.DNS_OPCODE_UPDATE).\
filter(lambda p: SRP_INSTANCE_NAME in verify_utils.as_list(p.dns.resp.name)).\
filter(lambda p: ED_1_MLEID in verify_utils.as_list(p.dns.aaaa)).\
filter(lambda p: len(verify_utils.as_list(p.dns.aaaa)) == 1).\
must_next()
# Step 5
# Device: BR_1
# Description (SRPC-3.1): Automatically sends DNS Response (Rcode=0, NoError).
# Pass Criteria:
# N/A
print("Step 5: BR_1 sends DNS Response.")
pkts.filter_ipv6_src(BR_1_MLEID).\
filter_ipv6_dst(ED_1_MLEID).\
filter(lambda p: p.dns.flags.response == 1).\
must_next()
# Step 6
# Device: BR 2
# Description (SRPC-3.1): Enable. Harness configures device with a numerically higher ML-EID address than BR 1.
# This ensures that the BR 2 SRP service will be less preferred to the DUT. Note: due to absence of adjacent
# infrastructure link (AIL), no OMR address is configured by the BR.
# Pass Criteria:
# N/A
print("Step 6: BR_2 joins the network.")
# Step 7
# Device: BR 2
# Description (SRPC-3.1): Harness instructs the device to add its SRP Server information in the Thread Network
# Data using a DNS/SRP Unicast Dataset. Note: normally BR_2 does not add this information, since an SRP server
# is already advertised on the Thread Network. The Harness overrides this behavior.
# Pass Criteria:
# - The DUT MUST NOT send SRP Update to BR_2.
print("Step 7: BR_2 adds its SRP Server information. MUST NOT send SRP Update to BR_2.")
# Step 8
# Device: BR 1
# Description (SRPC-3.1): Harness deactivates the device.
# Pass Criteria:
# N/A
print("Step 8: BR_1 is deactivated.")
# Step 8b
# Device: N/A
# Description (SRPC-3.1): Harness waits 30 seconds. Within this time, the next step must happen.
# Pass Criteria:
# N/A
print("Step 8b: Wait 30 seconds.")
# Step 9
# Device: ED 1 (DUT)
# Description (SRPC-3.1): Automatically sends SRP Update to BR_1 to renew service.
# Pass Criteria:
# - The DUT MUST send SRP Update to BR_1 as in step 4.
print("Step 9: ED_1 sends SRP Update to BR_1 to renew service.")
# To verify Step 7 and Step 9:
# We ensure that the NEXT SRP Update from ED_1 is indeed to BR_1, not BR_2.
pkts.filter_wpan_src64(ED_1).\
filter(lambda p: p.dns.flags.opcode == consts.DNS_OPCODE_UPDATE).\
must_next().\
must_verify(lambda p: p.ipv6.dst == BR_1_MLEID).\
must_verify(lambda p: SRP_INSTANCE_NAME in verify_utils.as_list(p.dns.resp.name)).\
must_verify(lambda p: ED_1_MLEID in verify_utils.as_list(p.dns.aaaa)).\
must_verify(lambda p: len(verify_utils.as_list(p.dns.aaaa)) == 1)
# Step 10
# Device: BR 1
# Description (SRPC-3.1): Does not respond.
# Pass Criteria:
# N/A
print("Step 10: BR_1 does not respond.")
# Step 11
# Device: ED 1 (DUT)
# Description (SRPC-3.1): Automatically sends SRP Update to BR_2
# Pass Criteria:
# - The DUT MUST send SRP Update like in step 4 but now to BR_2
print("Step 11: ED_1 sends SRP Update to BR_2.")
pkts.filter_wpan_src64(ED_1).\
filter_ipv6_dst(BR_2_MLEID).\
filter(lambda p: p.dns.flags.opcode == consts.DNS_OPCODE_UPDATE).\
filter(lambda p: SRP_INSTANCE_NAME in verify_utils.as_list(p.dns.resp.name)).\
filter(lambda p: ED_1_MLEID in verify_utils.as_list(p.dns.aaaa)).\
filter(lambda p: len(verify_utils.as_list(p.dns.aaaa)) == 1).\
must_next()
# Step 12
# Device: BR 2
# Description (SRPC-3.1): Automatically sends SRP Update Response (Rcode=0, NoError).
# Pass Criteria:
# N/A
print("Step 12: BR_2 sends SRP Update Response.")
pkts.filter_ipv6_src(BR_2_MLEID).\
filter_ipv6_dst(ED_1_MLEID).\
filter(lambda p: p.dns.flags.response == 1).\
must_next()
# Step 13
# Device: BR_1
# Description (SRPC-3.1): Harness re-enables the device.
# Pass Criteria:
# - N/A
print("Step 13: BR_1 is re-enabled.")
# Step 14
# Device: BR_1
# Description (SRPC-3.1): Harness instructs the device to add its SRP Server information in the Thread Network
# Data using a DNS/SRP Unicast Dataset. Note: normally BR_1 does not add this information, since an SRP server
# is already advertised on the Thread Network. The Harness overrides this behavior.
# Pass Criteria:
# - N/A
print("Step 14: BR_1 adds its SRP Server information.")
# Step 15
# Device: ED 1 (DUT)
# Description (SRPC-3.1): Does not send SRP Update to BR_1, but stays with its current SRP server BR 2..
# Pass Criteria:
# - The DUT MUST NOT send SRP Update to BR_1.
print("Step 15: ED_1 stays with BR_2. MUST NOT send SRP Update to BR_1.")
pkts.filter_wpan_src64(ED_1).\
filter_ipv6_dst(BR_1_MLEID).\
filter(lambda p: p.dns.flags.opcode == consts.DNS_OPCODE_UPDATE).\
must_not_next()
if __name__ == '__main__':
verify_utils.run_main(verify)