From 9e87d674057f9e1d8cce175478521c4130d32b85 Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Wed, 18 Mar 2026 17:54:08 -0500 Subject: [PATCH] [nexus] add MATN-TC-26 test case for mcast reg error handling (#12714) This commit adds a new nexus test for MATN-TC-26: Multicast registrations error handling by Thread Device. The test verifies that a Thread Device correctly handles multicast registration errors, such as when a Backbone Router (BBR) runs out of resources or responds with a general failure. Changes: - Implemented test_1_2_MATN_TC_26.cpp to execute the test steps. - Implemented verify_1_2_MATN_TC_26.py to verify pcap output. - Updated CMakeLists.txt and run_nexus_tests.sh to include the new test. - Modified bbr_manager.cpp to correctly include failed addresses in the MLR response when using configured error status for reference devices. The test ensures the DUT retries registration within the Reregistration Delay after receiving an error and does not retry if registration was successful until necessary. --- src/core/backbone_router/bbr_manager.cpp | 34 ++- tests/nexus/CMakeLists.txt | 1 + tests/nexus/run_nexus_tests.sh | 1 + tests/nexus/test_1_2_MATN_TC_26.cpp | 369 +++++++++++++++++++++++ tests/nexus/verify_1_2_MATN_TC_26.py | 288 ++++++++++++++++++ 5 files changed, 681 insertions(+), 12 deletions(-) create mode 100644 tests/nexus/test_1_2_MATN_TC_26.cpp create mode 100644 tests/nexus/verify_1_2_MATN_TC_26.py diff --git a/src/core/backbone_router/bbr_manager.cpp b/src/core/backbone_router/bbr_manager.cpp index 5fdcddf9b..515b392d1 100644 --- a/src/core/backbone_router/bbr_manager.cpp +++ b/src/core/backbone_router/bbr_manager.cpp @@ -151,19 +151,35 @@ void Manager::HandleMulticastListenerRegistration(const Coap::Msg &aMsg) VerifyOrExit(aMsg.IsConfirmable(), error = kErrorParse); + VerifyOrExit(isPrimary, status = kMlrBbrNotPrimary); + + VerifyOrExit(Tlv::FindTlvValueOffsetRange(aMsg.mMessage, Ip6AddressesTlv::kIp6Addresses, offsetRange) == kErrorNone, + error = kErrorParse); + VerifyOrExit(offsetRange.GetLength() % sizeof(Ip6::Address) == 0, status = kMlrGeneralFailure); + VerifyOrExit(offsetRange.GetLength() / sizeof(Ip6::Address) <= Ip6AddressesTlv::kMaxAddresses, + status = kMlrGeneralFailure); + #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE - // Required by Test Specification 5.10.22 DUA-TC-26, only for certification purpose + // Required by Test Specification 5.10.22 MATN-TC-26, only for certification purpose if (mMlrResponseIsSpecified) { mMlrResponseIsSpecified = false; - ExitNow(status = mMlrResponseStatus); + status = mMlrResponseStatus; + + if (status != kMlrSuccess) + { + while (!offsetRange.IsEmpty()) + { + IgnoreError(aMsg.mMessage.Read(offsetRange, address)); + offsetRange.AdvanceOffset(sizeof(Ip6::Address)); + addresses[failedAddressNum++] = address; + } + } + + ExitNow(); } #endif - VerifyOrExit(isPrimary, status = kMlrBbrNotPrimary); - - // TODO: (MLR) send configured MLR response for Reference Device - if (Tlv::Find(aMsg.mMessage, commissionerSessionId) == kErrorNone) { uint16_t localSessionId; @@ -178,12 +194,6 @@ void Manager::HandleMulticastListenerRegistration(const Coap::Msg &aMsg) processTimeoutTlv = hasCommissionerSessionIdTlv && (Tlv::Find(aMsg.mMessage, timeout) == kErrorNone); - VerifyOrExit(Tlv::FindTlvValueOffsetRange(aMsg.mMessage, Ip6AddressesTlv::kIp6Addresses, offsetRange) == kErrorNone, - error = kErrorParse); - VerifyOrExit(offsetRange.GetLength() % sizeof(Ip6::Address) == 0, status = kMlrGeneralFailure); - VerifyOrExit(offsetRange.GetLength() / sizeof(Ip6::Address) <= Ip6AddressesTlv::kMaxAddresses, - status = kMlrGeneralFailure); - if (!processTimeoutTlv) { IgnoreError(Get().GetConfig(config)); diff --git a/tests/nexus/CMakeLists.txt b/tests/nexus/CMakeLists.txt index f32e24128..4e9f86b16 100644 --- a/tests/nexus/CMakeLists.txt +++ b/tests/nexus/CMakeLists.txt @@ -250,6 +250,7 @@ ot_nexus_test(1_2_MATN_TC_20 "cert;nexus") ot_nexus_test(1_2_MATN_TC_21 "cert;nexus") ot_nexus_test(1_2_MATN_TC_22 "cert;nexus") ot_nexus_test(1_2_MATN_TC_23 "cert;nexus") +ot_nexus_test(1_2_MATN_TC_26 "cert;nexus") # Misc tests ot_nexus_test(border_admitter "core;nexus") diff --git a/tests/nexus/run_nexus_tests.sh b/tests/nexus/run_nexus_tests.sh index 7f09b39e5..8a8997df9 100755 --- a/tests/nexus/run_nexus_tests.sh +++ b/tests/nexus/run_nexus_tests.sh @@ -185,6 +185,7 @@ DEFAULT_TESTS=( "1_2_MATN_TC_21" "1_2_MATN_TC_22" "1_2_MATN_TC_23" + "1_2_MATN_TC_26" ) # Use provided arguments or the default test list diff --git a/tests/nexus/test_1_2_MATN_TC_26.cpp b/tests/nexus/test_1_2_MATN_TC_26.cpp new file mode 100644 index 000000000..c0d22df6e --- /dev/null +++ b/tests/nexus/test_1_2_MATN_TC_26.cpp @@ -0,0 +1,369 @@ +/* + * 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 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 = 10 * 1000; + +/** + * Time to advance for a node to join as a router, in milliseconds. + */ +static constexpr uint32_t kAttachToRouterTime = 200 * 1000; + +/** + * Time to advance for the network to stabilize, in milliseconds. + */ +static constexpr uint32_t kStabilizationTime = 10 * 1000; + +/** + * Time to advance for the BBR selection to complete, in milliseconds. + */ +static constexpr uint32_t kBbrSelectionTime = 10 * 1000; + +/** + * Reregistration Delay in seconds. + */ +static constexpr uint16_t kReregistrationDelay = 5; + +/** + * MLR Timeout in seconds. + */ +static constexpr uint32_t kMlrTimeout = 600; + +/** + * Multicast address MA1. + */ +static const char kMA1[] = "ff04::1234:777a:1"; + +void TestMatnTc26(void) +{ + /** + * 5.10.22 MATN-TC-26: Multicast registrations error handling by Thread Device + * + * 5.10.22.1 Topology + * - BR_1: Test bed BR device operating as the Primary BBR + * - TD (DUT): Device operating as a Thread device - FED or Router + * + * 5.10.22.2 Purpose & Description + * The purpose of this test case is to verify that a Thread Device can correctly handle multicast registration + * errors, whether that is due to a BBR running out of resources or a BBR responding with general failure. + * + * Spec Reference | V1.2 Section + * -----------------|------------- + * Multicast | 5.10.1 + */ + + Core nexus; + Node &br1 = nexus.CreateNode(); + Node &td = nexus.CreateNode(); + Ip6::Address ma1; + + br1.SetName("BR_1"); + td.SetName("TD"); + + SuccessOrQuit(ma1.FromString(kMA1)); + + nexus.AddTestVar("MA1", kMA1); + + nexus.AdvanceTime(0); + + Instance::SetLogLevel(kLogLevelNote); + + Log("---------------------------------------------------------------------------------------"); + Log("Step 0: Topology formation – BR_1. Topology formation – TD (DUT)."); + + /** + * Step 0 + * - Device: N/A + * - Description: Topology formation - BR_1. Topology formation - TD (DUT). The DUT must be booted and joined to + * the network. + * - Pass Criteria: + * - N/A + */ + br1.AllowList(td); + td.AllowList(br1); + + br1.Form(); + nexus.AdvanceTime(kFormNetworkTime); + VerifyOrQuit(br1.Get().IsLeader()); + + br1.Get().Init(1, true); + br1.Get().Init(); + SuccessOrQuit(br1.Get().SetEnabled(true)); + br1.Get().SetEnabled(true); + + { + BackboneRouter::Config config; + br1.Get().GetConfig(config); + config.mMlrTimeout = kMlrTimeout; + SuccessOrQuit(br1.Get().SetConfig(config)); + } + + td.Join(br1, Node::kAsFtd); + nexus.AdvanceTime(kAttachToRouterTime); + VerifyOrQuit(td.Get().IsFullThreadDevice()); + + nexus.AdvanceTime(kBbrSelectionTime); + VerifyOrQuit(br1.Get().IsPrimary()); + + Log("Step 1: Harness instructs the device to not update its multicast listener table, and to prepare a MLR.rsp " + "error condition."); + + /** + * Step 1 + * - Device: BR_1 + * - Description: Harness instructs the device to not update its multicast listener table, and to prepare a + * MLE.rsp error condition. + * - Pass Criteria: + * - N/A + */ + br1.Get().ConfigNextMulticastListenerRegistrationResponse(kMlrNoResources); + + Log("Step 2: The DUT must be configured to request registration of Multicast address MA1."); + + /** + * Step 2 + * - Device: TD (DUT) + * - Description: The DUT must be configured to request registration of Multicast address MA1. + * - Pass Criteria: + * - The DUT MUST unicast an MLR.req CoAP request to BR_1 as follows: coap://[]:MM/n/mr + * - Where the payload contains: IPv6 Addresses TLV: MA1 + */ + SuccessOrQuit(td.Get().SubscribeExternalMulticast(ma1)); + nexus.AdvanceTime(kStabilizationTime); + + Log("Step 3: Automatically responds to the Multicast registration with an error."); + + /** + * Step 3 + * - Device: BR_1 + * - Description: Automatically responds to the Multicast registration with an error. Informative: Both the + * actions together: set_next_mlr_status_rsp() Unicasts a MLR.rsp CoAP response to TD: 2.04 Changed Where the + * payload contains: Status TLV: 4 [ST_MLR_NO_RESOURCES] IPv6 Addresses TLV: MA1 + * - Pass Criteria: + * - N/A + */ + + Log("Step 3b: Receives above MLR.rsp CoAP response from BR_1. Within seconds, " + "automatically retries the registration."); + + /** + * Step 3b + * - Device: TD (DUT) + * - Description: Receives above MLR.rsp CoAP response from BR_1. Within seconds, + * automatically retries the registration. + * - Pass Criteria: + * - Within seconds after receiving the MLR.rsp from BR_1, the DUT MUST retry the + * registration using the CoAP message as in step 1 pass criteria. + */ + nexus.AdvanceTime(kReregistrationDelay * 1000); + + Log("Step 3c: Automatically updates its multicast listeners table and responds to the multicast registration."); + + /** + * Step 3c + * - Device: BR_1 + * - Description: Automatically updates its multicast listeners table and responds to the multicast registration. + * Unicasts an MLR.rsp CoAP response to TD as follows: 2.04 changed Where the payload contains: Status TLV: 0 + * [ST_MLR_SUCCESS] + * - Pass Criteria: + * - N/A + */ + + Log("Step 4: Harness instructs the device to not update its multicast listener table, and to prepare a MLR.rsp " + "error condition."); + + /** + * Step 4 + * - Device: BR_1 + * - Description: Harness instructs the device to not update its multicast listener table, and to prepare a + * MLE.rsp error condition. + * - Pass Criteria: + * - N/A + */ + br1.Get().ConfigNextMulticastListenerRegistrationResponse(kMlrGeneralFailure); + + Log("Step 4 (cont.): Harness instructs the device to updates the network data (BBR Dataset)."); + + /** + * Step 4 (cont.) + * - Device: BR_1 + * - Description: Harness instructs the device to updates the network data (BBR Dataset) as follows: BBR Sequence + * number: . The device then automatically starts MLE dissemination of the new + * dataset. + * - Pass Criteria: + * - N/A + */ + { + BackboneRouter::Config config; + br1.Get().GetConfig(config); + config.mSequenceNumber++; + SuccessOrQuit(br1.Get().SetConfig(config)); + } + nexus.AdvanceTime(kStabilizationTime); + + Log("Step 5: After noticing the change in BBR Sequence number, the DUT automatically requests to register " + "multicast address, MA1, at BR_1."); + + /** + * Step 5 + * - Device: TD (DUT) + * - Description: After noticing the change in BBR Sequence number, the DUT automatically requests to register + * multicast address, MA1, at BR_1. + * - Pass Criteria: + * - Within seconds of receiving the new network data, the DUT MUST unicasts an MLR.req + * CoAP request to BR_1 as follows: coap://[]:MM/n/mr + * - Where the payload contains: IPv6 Addresses TLV: MA1 + */ + + Log("Step 7: Automatically responds to the DUT’s Multicast registration with another error."); + + /** + * Step 7 + * - Device: BR_1 + * - Description: Automatically responds to the DUT’s Multicast registration with another error. Informative: + * Both the actions together: set_next_mlr_status_rsp() Automatically unicasts a MLR.rsp CoAP response to TD: + * 2.04 Changed Where the payload contains: Status TLV: 6 [ST_MLR_GENERAL_FAILURE] + * - Pass Criteria: + * - N/A + */ + + Log("Step 7b: The DUT receives above CoAP response from BR_1. Within seconds, it retries " + "the registration."); + + /** + * Step 7b + * - Device: TD (DUT) + * - Description: The DUT receives above CoAP response from BR_1. Within seconds, it + * retries the registration. + * - Pass Criteria: + * - Within seconds after receiving the MLR.rsp from BR_1, the DUT MUST retries the + * registration using the CoAP message as in step 5 of pass criteria. + */ + nexus.AdvanceTime(kReregistrationDelay * 1000); + + Log("Step 7c: Automatically updates its multicast listeners table and responds to the multicast registration."); + + /** + * Step 7c + * - Device: BR_1 + * - Description: Automatically updates its multicast listeners table and responds to the multicast registration. + * Unicasts an MLR.rsp CoAP response to TD as follows: 2.04 changed Where the payload contains: Status TLV: 0 + * [ST_MLR_SUCCESS] + * - Pass Criteria: + * - N/A + */ + + Log("Step 8: Harness instructs the device to Updates the network data (BBR dataset)."); + + /** + * Step 8 + * - Device: BR_1 + * - Description: Harness instructs the device to Updates the network data (BBR dataset) as follows: BBR Sequence + * number: . The device then automatically starts MLE dissemination of the new + * dataset. + * - Pass Criteria: + * - N/A + */ + { + BackboneRouter::Config config; + br1.Get().GetConfig(config); + config.mSequenceNumber++; + SuccessOrQuit(br1.Get().SetConfig(config)); + } + nexus.AdvanceTime(kStabilizationTime); + + Log("Step 9: After noticing the change in BBR Sequence number, the DUT automatically registers for multicast " + "address, MA1, at BR_1."); + + /** + * Step 9 + * - Device: TD (DUT) + * - Description: After noticing the change in BBR Sequence number, the DUT automatically registers for + * multicast address, MA1, at BR_1. + * - Pass Criteria: + * - Within seconds of receiving the new network data, the DUT MUST unicast an MLR.req + * CoAP request to BR_1 as follows: coap://[]:MM/n/mr + * - Where the payload contains: IPv6 Addresses TLV: MA1 + */ + + Log("Step 10: Automatically updates its multicast listener table."); + + /** + * Step 10 + * - Device: BR_1 + * - Description: Automatically updates its multicast listener table. + * - Pass Criteria: + * - N/A + */ + + Log("Step 11: Automatically responds to the multicast registration."); + + /** + * Step 11 + * - Device: BR_1 + * - Description: Automatically responds to the multicast registration. Unicasts an MLR.rsp CoAP response to TD + * as follows: 2.04 changed Where the payload contains: Status TLV: 0 [ST_MLR_SUCCESS] + * - Pass Criteria: + * - N/A + */ + + Log("Step 12: Does not retry the registration within the next (0.5 * MLR Timeout)."); + + /** + * Step 12 + * - Device: TD (DUT) + * - Description: Does not retry the registration within the next (0.5 * MLR Timeout). + * - Pass Criteria: + * - The DUT MUST NOT send an MLR.req message containing MA1 for at least 150 seconds. + */ + nexus.AdvanceTime(150 * 1000); + + nexus.SaveTestInfo("test_1_2_MATN_TC_26.json"); + + Log("TestMatnTc26 passed"); +} + +} // namespace Nexus +} // namespace ot + +int main(void) +{ + ot::Nexus::TestMatnTc26(); + printf("All tests passed\n"); + return 0; +} diff --git a/tests/nexus/verify_1_2_MATN_TC_26.py b/tests/nexus/verify_1_2_MATN_TC_26.py new file mode 100644 index 000000000..790b954ca --- /dev/null +++ b/tests/nexus/verify_1_2_MATN_TC_26.py @@ -0,0 +1,288 @@ +#!/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 +from pktverify.addrs import Ipv6Addr +from pktverify.bytes import Bytes + +# MLR Status values +ST_MLR_SUCCESS = 0 +ST_MLR_NO_RESOURCES = 4 +ST_MLR_GENERAL_FAILURE = 6 + + +def verify(pv): + # 5.10.22 MATN-TC-26: Multicast registrations error handling by Thread Device + # + # 5.10.22.1 Topology + # - BR_1: Test bed BR device operating as the Primary BBR + # - TD (DUT): Device operating as a Thread device - FED or Router + # + # 5.10.22.2 Purpose & Description + # The purpose of this test case is to verify that a Thread Device can correctly handle multicast registration + # errors, whether that is due to a BBR running out of resources or a BBR responding with general failure. + # + # Spec Reference | V1.2 Section + # -----------------|------------- + # Multicast | 5.10.1 + + pkts = pv.pkts + pv.summary.show() + + BR_1 = pv.vars['BR_1'] + TD = pv.vars['TD'] + MA1 = pv.vars['MA1'] + BR_1_RLOC = pv.vars['BR_1_RLOC'] + + # Step 0 + # - Device: N/A + # - Description: Topology formation - BR_1. Topology formation - TD (DUT). The DUT must be booted and joined to + # the network. + # - Pass Criteria: + # - N/A + print("Step 0: Topology formation – BR_1. Topology formation – TD (DUT).") + + # Step 1 + # - Device: BR_1 + # - Description: Harness instructs the device to not update its multicast listener table, and to prepare a + # MLE.rsp error condition. + # - Pass Criteria: + # - N/A + print("Step 1: Harness instructs the device to not update its multicast listener table, and to prepare a MLR.rsp " + "error condition.") + + # Step 2 + # - Device: TD (DUT) + # - Description: The DUT must be configured to request registration of Multicast address MA1. + # - Pass Criteria: + # - The DUT MUST unicast an MLR.req CoAP request to BR_1 as follows: coap://[]:MM/n/mr + # - Where the payload contains: IPv6 Addresses TLV: MA1 + print("Step 2: The DUT must be configured to request registration of Multicast address MA1.") + pkts.filter_wpan_src64(TD).\ + filter_coap_request('/n/mr').\ + filter(lambda p: p.ipv6.dst == Ipv6Addr(BR_1_RLOC) or \ + Ipv6Addr(p.ipv6.dst).endswith(Bytes('000000fffe00fc38'))).\ + filter(lambda p: MA1 in p.coap.tlv.ipv6_address).\ + must_next() + + # Step 3 + # - Device: BR_1 + # - Description: Automatically responds to the Multicast registration with an error. Informative: Both the + # actions together: set_next_mlr_status_rsp() Unicasts a MLR.rsp CoAP response to TD: 2.04 Changed Where the + # payload contains: Status TLV: 4 [ST_MLR_NO_RESOURCES] IPv6 Addresses TLV: MA1 + # - Pass Criteria: + # - N/A + print("Step 3: Automatically responds to the Multicast registration with an error.") + pkts.filter_wpan_src64(BR_1).\ + filter_coap_ack('/n/mr').\ + filter(lambda p: p.coap.code == consts.COAP_CODE_ACK).\ + filter(lambda p: p.coap.tlv.status == ST_MLR_NO_RESOURCES).\ + filter(lambda p: MA1 in p.coap.tlv.ipv6_address).\ + must_next() + + # Step 3b + # - Device: TD (DUT) + # - Description: Receives above MLR.rsp CoAP response from BR_1. Within seconds, + # automatically retries the registration. + # - Pass Criteria: + # - Within seconds after receiving the MLR.rsp from BR_1, the DUT MUST retry the + # registration using the CoAP message as in step 1 pass criteria. + print("Step 3b: Receives above MLR.rsp CoAP response from BR_1. Within seconds, " + "automatically retries the registration.") + pkts.filter_wpan_src64(TD).\ + filter_coap_request('/n/mr').\ + filter(lambda p: p.ipv6.dst == Ipv6Addr(BR_1_RLOC) or \ + Ipv6Addr(p.ipv6.dst).endswith(Bytes('000000fffe00fc38'))).\ + filter(lambda p: MA1 in p.coap.tlv.ipv6_address).\ + must_next() + + # Step 3c + # - Device: BR_1 + # - Description: Automatically updates its multicast listeners table and responds to the multicast registration. + # Unicasts an MLR.rsp CoAP response to TD as follows: 2.04 changed Where the payload contains: Status TLV: 0 + # [ST_MLR_SUCCESS] + # - Pass Criteria: + # - N/A + print("Step 3c: Automatically updates its multicast listeners table and responds to the multicast registration.") + pkts.filter_wpan_src64(BR_1).\ + filter_coap_ack('/n/mr').\ + filter(lambda p: p.coap.code == consts.COAP_CODE_ACK).\ + filter(lambda p: p.coap.tlv.status == ST_MLR_SUCCESS).\ + must_next() + + # Step 4 + # - Device: BR_1 + # - Description: Harness instructs the device to not update its multicast listener table, and to prepare a + # MLE.rsp error condition. + # - Pass Criteria: + # - N/A + print("Step 4: Harness instructs the device to not update its multicast listener table, and to prepare a MLR.rsp " + "error condition.") + + # Step 4 (cont.) + # - Device: BR_1 + # - Description: Harness instructs the device to updates the network data (BBR Dataset) as follows: BBR Sequence + # number: . The device then automatically starts MLE dissemination of the new + # dataset. + # - Pass Criteria: + # - N/A + # - Note: MLDv2 and BLMR.ntf checks are intentionally skipped as they are not the focus of this test. + print("Step 4 (cont.): Harness instructs the device to updates the network data (BBR Dataset).") + + # Step 5 + # - Device: TD (DUT) + # - Description: After noticing the change in BBR Sequence number, the DUT automatically requests to register + # multicast address, MA1, at BR_1. + # - Pass Criteria: + # - Within seconds of receiving the new network data, the DUT MUST unicasts an MLR.req + # CoAP request to BR_1 as follows: coap://[]:MM/n/mr + # - Where the payload contains: IPv6 Addresses TLV: MA1 + print("Step 5: After noticing the change in BBR Sequence number, the DUT automatically requests to register " + "multicast address, MA1, at BR_1.") + pkts.filter_wpan_src64(TD).\ + filter_coap_request('/n/mr').\ + filter(lambda p: p.ipv6.dst == Ipv6Addr(BR_1_RLOC) or \ + Ipv6Addr(p.ipv6.dst).endswith(Bytes('000000fffe00fc38'))).\ + filter(lambda p: MA1 in p.coap.tlv.ipv6_address).\ + must_next() + + # Step 7 + # - Device: BR_1 + # - Description: Automatically responds to the DUT’s Multicast registration with another error. Informative: + # Both the actions together: set_next_mlr_status_rsp() Automatically unicasts a MLR.rsp CoAP response to TD: + # 2.04 Changed Where the payload contains: Status TLV: 6 [ST_MLR_GENERAL_FAILURE] + # - Pass Criteria: + # - N/A + print("Step 7: Automatically responds to the DUT’s Multicast registration with another error.") + pkts.filter_wpan_src64(BR_1).\ + filter_coap_ack('/n/mr').\ + filter(lambda p: p.coap.code == consts.COAP_CODE_ACK).\ + filter(lambda p: p.coap.tlv.status == ST_MLR_GENERAL_FAILURE).\ + filter(lambda p: MA1 in p.coap.tlv.ipv6_address).\ + must_next() + + # Step 7b + # - Device: TD (DUT) + # - Description: The DUT receives above CoAP response from BR_1. Within seconds, it + # retries the registration. + # - Pass Criteria: + # - Within seconds after receiving the MLR.rsp from BR_1, the DUT MUST retries the + # registration using the CoAP message as in step 5 of pass criteria. + print("Step 7b: The DUT receives above CoAP response from BR_1. Within seconds, it retries " + "the registration.") + pkts.filter_wpan_src64(TD).\ + filter_coap_request('/n/mr').\ + filter(lambda p: p.ipv6.dst == Ipv6Addr(BR_1_RLOC) or \ + Ipv6Addr(p.ipv6.dst).endswith(Bytes('000000fffe00fc38'))).\ + filter(lambda p: MA1 in p.coap.tlv.ipv6_address).\ + must_next() + + # Step 7c + # - Device: BR_1 + # - Description: Automatically updates its multicast listeners table and responds to the multicast registration. + # Unicasts an MLR.rsp CoAP response to TD as follows: 2.04 changed Where the payload contains: Status TLV: 0 + # [ST_MLR_SUCCESS] + # - Pass Criteria: + # - N/A + print("Step 7c: Automatically updates its multicast listeners table and responds to the multicast registration.") + pkts.filter_wpan_src64(BR_1).\ + filter_coap_ack('/n/mr').\ + filter(lambda p: p.coap.code == consts.COAP_CODE_ACK).\ + filter(lambda p: p.coap.tlv.status == ST_MLR_SUCCESS).\ + must_next() + + # Step 8 + # - Device: BR_1 + # - Description: Harness instructs the device to Updates the network data (BBR dataset) as follows: BBR Sequence + # number: . The device then automatically starts MLE dissemination of the new + # dataset. + # - Pass Criteria: + # - N/A + print("Step 8: Harness instructs the device to Updates the network data (BBR dataset).") + + # Step 9 + # - Device: TD (DUT) + # - Description: After noticing the change in BBR Sequence number, the DUT automatically registers for + # multicast address, MA1, at BR_1. + # - Pass Criteria: + # - Within seconds of receiving the new network data, the DUT MUST unicast an MLR.req + # CoAP request to BR_1 as follows: coap://[]:MM/n/mr + # - Where the payload contains: IPv6 Addresses TLV: MA1 + print("Step 9: After noticing the change in BBR Sequence number, the DUT automatically registers for multicast " + "address, MA1, at BR_1.") + pkts.filter_wpan_src64(TD).\ + filter_coap_request('/n/mr').\ + filter(lambda p: p.ipv6.dst == Ipv6Addr(BR_1_RLOC) or \ + Ipv6Addr(p.ipv6.dst).endswith(Bytes('000000fffe00fc38'))).\ + filter(lambda p: MA1 in p.coap.tlv.ipv6_address).\ + must_next() + + # Step 10 + # - Device: BR_1 + # - Description: Automatically updates its multicast listener table. + # - Pass Criteria: + # - N/A + print("Step 10: Automatically updates its multicast listener table.") + + # Step 11 + # - Device: BR_1 + # - Description: Automatically responds to the multicast registration. Unicasts an MLR.rsp CoAP response to TD + # as follows: 2.04 changed Where the payload contains: Status TLV: 0 [ST_MLR_SUCCESS] + # - Pass Criteria: + # - N/A + print("Step 11: Automatically responds to the multicast registration.") + pkts.filter_wpan_src64(BR_1).\ + filter_coap_ack('/n/mr').\ + filter(lambda p: p.coap.code == consts.COAP_CODE_ACK).\ + filter(lambda p: p.coap.tlv.status == ST_MLR_SUCCESS).\ + must_next() + + # Step 12 + # - Device: TD (DUT) + # - Description: Does not retry the registration within the next (0.5 * MLR Timeout). + # - Pass Criteria: + # - The DUT MUST NOT send an MLR.req message containing MA1 for at least 150 seconds. + # - Note: MLDv2 and BLMR.ntf checks are intentionally skipped as they are not the focus of this test. + print("Step 12: Does not retry the registration within the next (0.5 * MLR Timeout).") + pkts.filter_wpan_src64(TD).\ + filter_coap_request('/n/mr').\ + filter(lambda p: MA1 in p.coap.tlv.ipv6_address).\ + must_not_next() + + +if __name__ == '__main__': + verify_utils.run_main(verify)