mirror of
https://github.com/espressif/openthread.git
synced 2026-06-05 21:14:49 +00:00
[nexus] add MATN-TC-19 test case for multicast registration by MTD (#12707)
This commit implements the Thread 1.2 test MATN-TC-19: Multicast registration by MTD in the Nexus simulation framework. The test verifies that an MTD can correctly register multicast addresses through a parent Thread Router and receive multicast traffic from the backbone. Key implementation details: - Created test_1_2_MATN_TC_19.cpp to simulate the network topology (BR_1, BR_2, Router, MTD, and Host) and execute the test steps using direct method calls. - Implemented verify_1_2_MATN_TC_19.py for PCAP-based verification of MLE Child Update exchanges, MLR registrations, and multicast ICMPv6 Echo Request/Reply forwarding. - Configured the test to use Note log level and included 1-line log output for each step to match existing Nexus tests. - Integrated the new test into the Nexus build system via CMakeLists.txt and added it to the default test execution list in run_nexus_tests.sh.
This commit is contained in:
@@ -245,6 +245,7 @@ ot_nexus_test(1_2_MATN_TC_10 "cert;nexus")
|
||||
ot_nexus_test(1_2_MATN_TC_12 "cert;nexus")
|
||||
ot_nexus_test(1_2_MATN_TC_15 "cert;nexus")
|
||||
ot_nexus_test(1_2_MATN_TC_16 "cert;nexus")
|
||||
ot_nexus_test(1_2_MATN_TC_19 "cert;nexus")
|
||||
|
||||
# Misc tests
|
||||
ot_nexus_test(border_admitter "core;nexus")
|
||||
|
||||
@@ -180,6 +180,7 @@ DEFAULT_TESTS=(
|
||||
"1_2_MATN_TC_12"
|
||||
"1_2_MATN_TC_15"
|
||||
"1_2_MATN_TC_16"
|
||||
"1_2_MATN_TC_19"
|
||||
)
|
||||
|
||||
# Use provided arguments or the default test list
|
||||
|
||||
@@ -0,0 +1,391 @@
|
||||
/*
|
||||
* 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 = 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 a node to join as a child, in milliseconds.
|
||||
*/
|
||||
static constexpr uint32_t kAttachAsChildTime = 10 * 1000;
|
||||
|
||||
/**
|
||||
* Time to advance for the network to stabilize, in milliseconds.
|
||||
*/
|
||||
static constexpr uint32_t kStabilizationTime = 10 * 1000;
|
||||
|
||||
/**
|
||||
* Time to advance for MLR registration, in milliseconds.
|
||||
*/
|
||||
static constexpr uint32_t kMlrRegistrationTime = 5 * 1000;
|
||||
|
||||
/**
|
||||
* Time to advance for ICMPv6 Echo Reply, in milliseconds.
|
||||
*/
|
||||
static constexpr uint32_t kEchoReplyWaitTime = 5000;
|
||||
|
||||
/**
|
||||
* Poll period for SED in milliseconds.
|
||||
*/
|
||||
static constexpr uint32_t kSedPollPeriod = 1000;
|
||||
|
||||
/**
|
||||
* Time to allow for a Child Update Request, in milliseconds.
|
||||
*/
|
||||
static constexpr uint32_t kChildUpdateRequestTimeMs = 1000;
|
||||
|
||||
/**
|
||||
* ICMPv6 Echo Request payload size.
|
||||
*/
|
||||
static constexpr uint16_t kEchoPayloadSize = 10;
|
||||
|
||||
/**
|
||||
* ICMPv6 Echo Request identifier.
|
||||
*/
|
||||
static constexpr uint16_t kEchoIdentifier = 0x1234;
|
||||
|
||||
/**
|
||||
* Multicast address MA2.
|
||||
*/
|
||||
static const char kMA2[] = "ff05::2";
|
||||
|
||||
/**
|
||||
* Multicast address MA3.
|
||||
*/
|
||||
static const char kMA3[] = "ff05::3";
|
||||
|
||||
/**
|
||||
* Multicast address MA5.
|
||||
*/
|
||||
static const char kMA5[] = "ff05::5";
|
||||
|
||||
void TestMatnTc19(void)
|
||||
{
|
||||
/**
|
||||
* 5.10.15 MATN-TC-19: Multicast registration by MTD
|
||||
*
|
||||
* Purpose:
|
||||
* The purpose of this test case is to verify that an MTD can register a multicast address through a Parent Thread
|
||||
* Router.
|
||||
*
|
||||
* Spec Reference | V1.2 Section
|
||||
* ---------------|-------------
|
||||
* MATN-TC-19 | 5.10.15
|
||||
*/
|
||||
|
||||
Core nexus;
|
||||
Node &br1 = nexus.CreateNode();
|
||||
Node &br2 = nexus.CreateNode();
|
||||
Node &router = nexus.CreateNode();
|
||||
Node &mtd = nexus.CreateNode();
|
||||
Node &host = nexus.CreateNode();
|
||||
Ip6::Address ma2;
|
||||
Ip6::Address ma3;
|
||||
Ip6::Address ma5;
|
||||
const Ip6::Address *hostUla;
|
||||
|
||||
br1.SetName("BR_1");
|
||||
br2.SetName("BR_2");
|
||||
router.SetName("Router");
|
||||
mtd.SetName("MTD");
|
||||
host.SetName("Host");
|
||||
|
||||
SuccessOrQuit(ma2.FromString(kMA2));
|
||||
SuccessOrQuit(ma3.FromString(kMA3));
|
||||
SuccessOrQuit(ma5.FromString(kMA5));
|
||||
|
||||
nexus.AdvanceTime(0);
|
||||
|
||||
Instance::SetLogLevel(kLogLevelNote);
|
||||
|
||||
Log("Step 0: Topology formation – BR_1, BR_2, Router, MTD");
|
||||
|
||||
/**
|
||||
* Step 0
|
||||
* - Device: N/A
|
||||
* - Description: Topology formation – BR_1, BR_2, Router, MTD
|
||||
* - Pass Criteria:
|
||||
* - N/A
|
||||
*/
|
||||
|
||||
br1.AllowList(br2);
|
||||
br1.AllowList(router);
|
||||
br2.AllowList(br1);
|
||||
br2.AllowList(router);
|
||||
router.AllowList(br1);
|
||||
router.AllowList(br2);
|
||||
router.AllowList(mtd);
|
||||
mtd.AllowList(router);
|
||||
|
||||
br1.Form();
|
||||
nexus.AdvanceTime(kFormNetworkTime);
|
||||
VerifyOrQuit(br1.Get<Mle::Mle>().IsLeader());
|
||||
|
||||
br1.Get<BorderRouter::InfraIf>().Init(1, true);
|
||||
br1.Get<BorderRouter::RoutingManager>().Init();
|
||||
SuccessOrQuit(br1.Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
||||
br1.Get<BackboneRouter::Local>().SetEnabled(true);
|
||||
|
||||
br2.Join(br1, Node::kAsFtd);
|
||||
router.Join(br1, Node::kAsFtd);
|
||||
nexus.AdvanceTime(kAttachToRouterTime);
|
||||
|
||||
VerifyOrQuit(br2.Get<Mle::Mle>().IsRouter());
|
||||
VerifyOrQuit(router.Get<Mle::Mle>().IsRouter());
|
||||
|
||||
br2.Get<BorderRouter::InfraIf>().Init(1, true);
|
||||
br2.Get<BorderRouter::RoutingManager>().Init();
|
||||
SuccessOrQuit(br2.Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
||||
br2.Get<BackboneRouter::Local>().SetEnabled(true);
|
||||
|
||||
SuccessOrQuit(mtd.Get<DataPollSender>().SetExternalPollPeriod(kSedPollPeriod));
|
||||
mtd.Join(router, Node::kAsSed);
|
||||
nexus.AdvanceTime(kAttachAsChildTime);
|
||||
VerifyOrQuit(mtd.Get<Mle::Mle>().IsChild());
|
||||
|
||||
nexus.AdvanceTime(kStabilizationTime);
|
||||
|
||||
VerifyOrQuit(br1.Get<BackboneRouter::Local>().IsPrimary());
|
||||
VerifyOrQuit(router.Get<BackboneRouter::Leader>().HasPrimary());
|
||||
|
||||
hostUla = &host.mInfraIf.FindMatchingAddress("fd00::/8");
|
||||
|
||||
nexus.AddTestVar("TEST_MA2", kMA2);
|
||||
nexus.AddTestVar("TEST_MA3", kMA3);
|
||||
nexus.AddTestVar("TEST_MA5", kMA5);
|
||||
nexus.AddTestVar("HOST_BACKBONE_ULA", hostUla->ToString().AsCString());
|
||||
|
||||
Log("Step 1a: MTD Registers addresses MA2 & MA5 with its parent.");
|
||||
|
||||
/**
|
||||
* Step 1a
|
||||
* - Device: MTD
|
||||
* - Description: Registers addresses MA2 & MA5 with its parent. (MA5 is optional for MEDs)
|
||||
* - Pass Criteria:
|
||||
* - For DUT = MTD:
|
||||
* - The DUT MUST unicast an MLE Child Update Request command to Router, where the payload contains (amongst other
|
||||
* fields):
|
||||
* - Address Registration TLV: MA2
|
||||
* - MA5 (Optional for MED)
|
||||
*/
|
||||
SuccessOrQuit(mtd.Get<Ip6::Netif>().SubscribeExternalMulticast(ma2));
|
||||
SuccessOrQuit(mtd.Get<Ip6::Netif>().SubscribeExternalMulticast(ma5));
|
||||
nexus.AdvanceTime(kChildUpdateRequestTimeMs);
|
||||
|
||||
Log("Step 1b: Router Automatically responds to the registration request.");
|
||||
|
||||
/**
|
||||
* Step 1b
|
||||
* - Device: Router
|
||||
* - Description: Automatically responds to the registration request.
|
||||
* - Pass Criteria:
|
||||
* - For DUT = Router:
|
||||
* - The DUT MUST unicast an MLE Child Update Response command to MTD, where the payload contains (amongst other
|
||||
* fields):
|
||||
* - Address Registration TLV: MA2
|
||||
* - MA5
|
||||
*/
|
||||
|
||||
Log("Step 1c: Router Automatically registers multicast address, MA2 at BR_1");
|
||||
|
||||
/**
|
||||
* Step 1c
|
||||
* - Device: Router
|
||||
* - Description: Automatically registers multicast address, MA2 at BR_1
|
||||
* - Pass Criteria:
|
||||
* - For DUT = Router:
|
||||
* - The DUT MUST unicast an MLR.req CoAP request to BR_1 as follows: coap://[<BR_1 RLOC or PBBR ALOC>]:MM/n/mr
|
||||
* - Where the payload contains:
|
||||
* - IPv6 Addresses TLV: MA2
|
||||
*/
|
||||
nexus.AdvanceTime(kMlrRegistrationTime);
|
||||
|
||||
Log("Step 2: MTD Registers addresses MA2 and MA3 with its parent.");
|
||||
|
||||
/**
|
||||
* Step 2
|
||||
* - Device: MTD
|
||||
* - Description: Registers addresses MA2 and MA3 with its parent.
|
||||
* - Pass Criteria:
|
||||
* - For DUT = MTD:
|
||||
* - The DUT MUST unicast an MLE Child Update Request command to Router_1, where the payload contains (amongst
|
||||
* other fields):
|
||||
* - Address Registration TLV: MA2 and MA3.
|
||||
*/
|
||||
SuccessOrQuit(mtd.Get<Ip6::Netif>().UnsubscribeExternalMulticast(ma5));
|
||||
SuccessOrQuit(mtd.Get<Ip6::Netif>().SubscribeExternalMulticast(ma3));
|
||||
nexus.AdvanceTime(kChildUpdateRequestTimeMs);
|
||||
|
||||
Log("Step 3: Router Automatically responds to the registration request.");
|
||||
|
||||
/**
|
||||
* Step 3
|
||||
* - Device: Router
|
||||
* - Description: Automatically responds to the registration request.
|
||||
* - Pass Criteria:
|
||||
* - For DUT = Router:
|
||||
* - The DUT MUST unicast an MLE Child Update Response command to MTD, where the payload contains (amongst other
|
||||
* fields):
|
||||
* - Address Registration TLV: MA2 and MA3.
|
||||
*/
|
||||
|
||||
Log("Step 4: Router Wait at most PARENT_AGGREGATE_DELAY.");
|
||||
|
||||
/**
|
||||
* Step 4
|
||||
* - Device: Router
|
||||
* - Description: Wait at most PARENT_AGGREGATE_DELAY.
|
||||
* - Pass Criteria:
|
||||
* - The next message (below) is sent not later than PARENT_AGGREGATE_DELAY seconds since step 3.
|
||||
*/
|
||||
|
||||
Log("Step 5: Router Automatically registers multicast addresses, MA2 and MA3 at BR_1.");
|
||||
|
||||
/**
|
||||
* Step 5
|
||||
* - Device: Router
|
||||
* - Description: Automatically registers multicast addresses, MA2 and MA3 at BR_1. Unicasts an MLR.req CoAP request
|
||||
* to BR_1 as follows: coap://[<BR_1 RLOC or PBBR ALOC>]:MM/n/mr Where the payload contains: IPv6 Addresses TLV:
|
||||
* MA3, MA2 (optional).
|
||||
* - Pass Criteria:
|
||||
* - N/A
|
||||
*/
|
||||
nexus.AdvanceTime(kMlrRegistrationTime);
|
||||
|
||||
Log("Step 6: BR_1 Automatically responds to the registration request.");
|
||||
|
||||
/**
|
||||
* Step 6
|
||||
* - Device: BR_1
|
||||
* - Description: Automatically responds to the registration request. Unicasts an MLR.rsp CoAP response to Router_1
|
||||
* as follows: 2.04 changed Where the payload contains: Status TLV: ST_MLR_SUCCESS.
|
||||
* - Pass Criteria:
|
||||
* - N/A
|
||||
*/
|
||||
|
||||
Log("Step 7: Host ICMPv6 Echo (ping) Request packet to multicast address, MA3, on the backbone link.");
|
||||
|
||||
/**
|
||||
* Step 7
|
||||
* - Device: Host
|
||||
* - Description: Harness instructs the device to send ICMPv6 Echo (ping) Request packet to multicast address, MA3,
|
||||
* on the backbone link.
|
||||
* - Pass Criteria:
|
||||
* - N/A
|
||||
*/
|
||||
host.mInfraIf.SendEchoRequest(*hostUla, ma3, kEchoIdentifier, kEchoPayloadSize);
|
||||
nexus.AdvanceTime(0);
|
||||
|
||||
Log("Step 8: BR_1 Automatically forwards the ping request packet to its Thread Network.");
|
||||
|
||||
/**
|
||||
* Step 8
|
||||
* - Device: BR_1
|
||||
* - Description: Automatically forwards the ping request packet to its Thread Network encapsulated in an MPL
|
||||
* packet.
|
||||
* - Pass Criteria:
|
||||
* - N/A
|
||||
*/
|
||||
|
||||
Log("Step 8a: Router Receives the multicast ping request packet.");
|
||||
|
||||
/**
|
||||
* Step 8a
|
||||
* - Device: Router
|
||||
* - Description: Receives the multicast ping request packet and if MTD is a SED then it automatically pends it for
|
||||
* delivery to MTD. If MTD is MED, it automatically forwards the packet as defined in step 10.
|
||||
* - Pass Criteria:
|
||||
* - None.
|
||||
*/
|
||||
|
||||
Log("Step 9: MTD polls for the pending ping request packet.");
|
||||
|
||||
/**
|
||||
* Step 9
|
||||
* - Device: MTD
|
||||
* - Description: If MTD is a SED, it wakes up and/or polls for the pending ping request packet. If MTD is a MED,
|
||||
* this test step is skipped.
|
||||
* - Pass Criteria:
|
||||
* - For DUT = MTD (SED):
|
||||
* - The DUT MUST send a MAC poll request to Router_1.
|
||||
*/
|
||||
nexus.AdvanceTime(kEchoReplyWaitTime);
|
||||
|
||||
Log("Step 10: Router Automatically forwards the ping request packet to MTD.");
|
||||
|
||||
/**
|
||||
* Step 10
|
||||
* - Device: Router
|
||||
* - Description: Automatically forwards the ping request packet to MTD.
|
||||
* - Pass Criteria:
|
||||
* - For DUT = Router:
|
||||
* - The DUT MUST forward the ICMPv6 Echo (ping) Request packet with multicast address, MA3, to MTD using
|
||||
* 802.15.4 unicast.
|
||||
* - The ping request packet MUST NOT be encapsulated in an MPL packet.
|
||||
*/
|
||||
|
||||
Log("Step 11: MTD sends a unicast ICMPv6 Echo Response packet back to Host.");
|
||||
|
||||
/**
|
||||
* Step 11
|
||||
* - Device: MTD
|
||||
* - Description: Receives the multicast ping request packet and sends a unicast ICMPv6 Echo (ping) Response packet
|
||||
* back to Host.
|
||||
* - Pass Criteria:
|
||||
* - For DUT = MTD:
|
||||
* - The DUT MUST unicast a ICMPv6 Echo (ping) Response packet back to Host.
|
||||
*/
|
||||
nexus.AdvanceTime(kEchoReplyWaitTime);
|
||||
|
||||
nexus.SaveTestInfo("test_1_2_MATN_TC_19.json");
|
||||
}
|
||||
|
||||
} /* namespace Nexus */
|
||||
} /* namespace ot */
|
||||
|
||||
int main(void)
|
||||
{
|
||||
ot::Nexus::TestMatnTc19();
|
||||
printf("All tests passed\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
#!/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.null_field import nullField
|
||||
|
||||
ST_MLR_SUCCESS = 0
|
||||
PARENT_AGGREGATE_DELAY = 5
|
||||
|
||||
|
||||
def verify(pv):
|
||||
# 5.10.15 MATN-TC-19: Multicast registration by MTD
|
||||
#
|
||||
# Purpose:
|
||||
# The purpose of this test case is to verify that an MTD can register a multicast address through a Parent Thread
|
||||
# Router.
|
||||
#
|
||||
# Spec Reference | V1.2 Section
|
||||
# ---------------|-------------
|
||||
# MATN-TC-19 | 5.10.15
|
||||
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
BR_1 = pv.vars['BR_1']
|
||||
MTD = pv.vars['MTD']
|
||||
|
||||
# Use the test-specific variables from the core
|
||||
v_MA2 = Ipv6Addr(pv.vars['TEST_MA2'])
|
||||
v_MA3 = Ipv6Addr(pv.vars['TEST_MA3'])
|
||||
v_MA5 = Ipv6Addr(pv.vars['TEST_MA5'])
|
||||
HOST_ULA = Ipv6Addr(pv.vars['HOST_BACKBONE_ULA'])
|
||||
|
||||
# Step 0
|
||||
# - Device: N/A
|
||||
# - Description: Topology formation – BR_1, BR_2, Router, MTD
|
||||
# - Pass Criteria:
|
||||
# - N/A
|
||||
print("Step 0: Topology formation – BR_1, BR_2, Router, MTD")
|
||||
|
||||
# Step 1a
|
||||
# - Device: MTD
|
||||
# - Description: Registers addresses MA2 & MA5 with its parent. (MA5 is optional for MEDs)
|
||||
# - Pass Criteria:
|
||||
# - For DUT = MTD:
|
||||
# - The DUT MUST unicast an MLE Child Update Request command to Router, where the payload contains (amongst other
|
||||
# fields):
|
||||
# - Address Registration TLV: MA2
|
||||
# - MA5 (Optional for MED)
|
||||
print("Step 1a: MTD Registers addresses MA2 & MA5 with its parent.")
|
||||
pkt = pkts.filter_wpan_src64(MTD).\
|
||||
filter_mle_cmd(consts.MLE_CHILD_UPDATE_REQUEST).\
|
||||
filter(lambda p: consts.ADDRESS_REGISTRATION_TLV in p.mle.tlv.type).\
|
||||
filter(lambda p: v_MA2 in p.mle.tlv.addr_reg).\
|
||||
must_next()
|
||||
assert v_MA5 in pkt.mle.tlv.addr_reg
|
||||
|
||||
# Step 1b
|
||||
# - Device: Router
|
||||
# - Description: Automatically responds to the registration request.
|
||||
# - Pass Criteria:
|
||||
# - For DUT = Router:
|
||||
# - The DUT MUST unicast an MLE Child Update Response command to MTD, where the payload contains (amongst other
|
||||
# fields):
|
||||
# - Address Registration TLV: MA2
|
||||
# - MA5
|
||||
print("Step 1b: Router Automatically responds to the registration request.")
|
||||
pkt = pkts.filter_wpan_dst64(MTD).\
|
||||
filter_mle_cmd(consts.MLE_CHILD_UPDATE_RESPONSE).\
|
||||
filter(lambda p: consts.ADDRESS_REGISTRATION_TLV in p.mle.tlv.type).\
|
||||
filter(lambda p: v_MA2 in p.mle.tlv.addr_reg).\
|
||||
must_next()
|
||||
assert v_MA5 in pkt.mle.tlv.addr_reg
|
||||
|
||||
# Step 1c
|
||||
# - Device: Router
|
||||
# - Description: Automatically registers multicast address, MA2 at BR_1
|
||||
# - Pass Criteria:
|
||||
# - For DUT = Router:
|
||||
# - The DUT MUST unicast an MLR.req CoAP request to BR_1 as follows: coap://[<BR_1 RLOC or PBBR ALOC>]:MM/n/mr
|
||||
# - Where the payload contains:
|
||||
# - IPv6 Addresses TLV: MA2
|
||||
print("Step 1c: Router Automatically registers multicast address, MA2 at BR_1")
|
||||
target_pkt = pkts.filter_coap_request('/n/mr').\
|
||||
filter(lambda p: v_MA2 in p.coap.tlv.ipv6_address).\
|
||||
must_next()
|
||||
|
||||
# Step 2
|
||||
# - Device: MTD
|
||||
# - Description: Registers addresses MA2 and MA3 with its parent.
|
||||
# - Pass Criteria:
|
||||
# - For DUT = MTD:
|
||||
# - The DUT MUST unicast an MLE Child Update Request command to Router_1, where the payload contains (amongst
|
||||
# other fields):
|
||||
# - Address Registration TLV: MA2 and MA3.
|
||||
print("Step 2: MTD Registers addresses MA2 and MA3 with its parent.")
|
||||
pkt = pkts.filter_wpan_src64(MTD).\
|
||||
filter_mle_cmd(consts.MLE_CHILD_UPDATE_REQUEST).\
|
||||
filter(lambda p: consts.ADDRESS_REGISTRATION_TLV in p.mle.tlv.type).\
|
||||
filter(lambda p: v_MA3 in p.mle.tlv.addr_reg).\
|
||||
must_next()
|
||||
assert v_MA2 in pkt.mle.tlv.addr_reg and v_MA5 not in pkt.mle.tlv.addr_reg
|
||||
|
||||
# Step 3
|
||||
# - Device: Router
|
||||
# - Description: Automatically responds to the registration request.
|
||||
# - Pass Criteria:
|
||||
# - For DUT = Router:
|
||||
# - The DUT MUST unicast an MLE Child Update Response command to MTD, where the payload contains (amongst other
|
||||
# fields):
|
||||
# - Address Registration TLV: MA2 and MA3.
|
||||
print("Step 3: Router Automatically responds to the registration request.")
|
||||
step3_pkt = pkts.filter_wpan_dst64(MTD).\
|
||||
filter_mle_cmd(consts.MLE_CHILD_UPDATE_RESPONSE).\
|
||||
filter(lambda p: consts.ADDRESS_REGISTRATION_TLV in p.mle.tlv.type).\
|
||||
filter(lambda p: v_MA3 in p.mle.tlv.addr_reg).\
|
||||
must_next()
|
||||
assert v_MA2 in step3_pkt.mle.tlv.addr_reg
|
||||
|
||||
# Step 4
|
||||
# - Device: Router
|
||||
# - Description: Wait at most PARENT_AGGREGATE_DELAY.
|
||||
# - Pass Criteria:
|
||||
# - The next message (below) is sent not later than PARENT_AGGREGATE_DELAY seconds since step 3.
|
||||
print("Step 4: Router Wait at most PARENT_AGGREGATE_DELAY.")
|
||||
|
||||
# Step 5
|
||||
# - Device: Router
|
||||
# - Description: Automatically registers multicast addresses, MA2 and MA3 at BR_1. Unicasts an MLR.req CoAP request
|
||||
# to BR_1 as follows: coap://[<BR_1 RLOC or PBBR ALOC>]:MM/n/mr Where the payload contains: IPv6 Addresses TLV:
|
||||
# MA3, MA2 (optional).
|
||||
# - Pass Criteria:
|
||||
# - N/A
|
||||
print("Step 5: Router Automatically registers multicast addresses, MA2 and MA3 at BR_1.")
|
||||
step5_pkt = pkts.filter_coap_request('/n/mr').\
|
||||
filter(lambda p: v_MA3 in p.coap.tlv.ipv6_address).\
|
||||
must_next()
|
||||
# MA2 is optional in Step 5 as per spec. OpenThread might only send new registrations.
|
||||
# assert v_MA2 in step5_pkt.coap.tlv.ipv6_address, f"MA2 ({v_MA2}) not in {step5_pkt.coap.tlv.ipv6_address}"
|
||||
|
||||
# Verify Step 4 timing
|
||||
assert step5_pkt.sniff_timestamp - step3_pkt.sniff_timestamp <= PARENT_AGGREGATE_DELAY + 2.0, \
|
||||
f"Step 5 sent too late: {step5_pkt.sniff_timestamp - step3_pkt.sniff_timestamp}s > {PARENT_AGGREGATE_DELAY}s"
|
||||
|
||||
# Step 6
|
||||
# - Device: BR_1
|
||||
# - Description: Automatically responds to the registration request. Unicasts an MLR.rsp CoAP response to Router_1
|
||||
# as follows: 2.04 changed Where the payload contains: Status TLV: ST_MLR_SUCCESS.
|
||||
# - Pass Criteria:
|
||||
# - N/A
|
||||
print("Step 6: BR_1 Automatically responds to the registration request.")
|
||||
pkts.filter_coap_ack('/n/mr').\
|
||||
filter(lambda p: p.coap.tlv.status == ST_MLR_SUCCESS).\
|
||||
must_next()
|
||||
|
||||
# Step 7
|
||||
# - Device: Host
|
||||
# - Description: Harness instructs the device to send ICMPv6 Echo (ping) Request packet to multicast address, MA3,
|
||||
# on the backbone link.
|
||||
# - Pass Criteria:
|
||||
# - N/A
|
||||
print("Step 7: Host ICMPv6 Echo (ping) Request packet to multicast address, MA3, on the backbone link.")
|
||||
|
||||
# Step 8
|
||||
# - Device: BR_1
|
||||
# - Description: Automatically forwards the ping request packet to its Thread Network encapsulated in an MPL packet.
|
||||
# - Pass Criteria:
|
||||
# - N/A
|
||||
print("Step 8: BR_1 Automatically forwards the ping request packet to its Thread Network.")
|
||||
pkts.filter_wpan_src64(BR_1).\
|
||||
filter_ping_request().\
|
||||
filter(lambda p: p.ipv6.dst == 'ff03::fc').\
|
||||
must_next()
|
||||
|
||||
# Step 8a
|
||||
# - Device: Router
|
||||
# - Description: Receives the multicast ping request packet and if MTD is a SED then it automatically pends it for
|
||||
# delivery to MTD. If MTD is MED, it automatically forwards the packet as defined in step 10.
|
||||
# - Pass Criteria:
|
||||
# - None.
|
||||
print("Step 8a: Router Receives the multicast ping request packet.")
|
||||
|
||||
# Step 9
|
||||
# - Device: MTD
|
||||
# - Description: If MTD is a SED, it wakes up and/or polls for the pending ping request packet. If MTD is a MED,
|
||||
# this test step is skipped.
|
||||
# - Pass Criteria:
|
||||
# - For DUT = MTD (SED):
|
||||
# - The DUT MUST send a MAC poll request to Router_1.
|
||||
print("Step 9: MTD sends a MAC poll request.")
|
||||
pkts.filter_wpan_src64(MTD).\
|
||||
filter(lambda p: p.wpan.frame_type == consts.MAC_FRAME_TYPE_MAC_CMD and p.wpan.cmd == consts.WPAN_DATA_REQUEST).\
|
||||
must_next()
|
||||
|
||||
# Step 10
|
||||
# - Device: Router
|
||||
# - Description: Automatically forwards the ping request packet to MTD.
|
||||
# - Pass Criteria:
|
||||
# - For DUT = Router:
|
||||
# - The DUT MUST forward the ICMPv6 Echo (ping) Request packet with multicast address, MA3, to MTD using 802.15.4
|
||||
# unicast.
|
||||
# - The ping request packet MUST NOT be encapsulated in an MPL packet.
|
||||
print("Step 10: Router Automatically forwards the ping request packet to MTD.")
|
||||
pkts.filter_ping_request().\
|
||||
filter(lambda p: p.ipv6.dst == v_MA3).\
|
||||
filter(lambda p: p.wpan.dst64 == MTD or (p.wpan.dst16 is not nullField and p.wpan.dst16 != 0xffff)).\
|
||||
filter(lambda p: not p.ipv6inner).\
|
||||
must_next()
|
||||
|
||||
# Step 11
|
||||
# - Device: MTD
|
||||
# - Description: Receives the multicast ping request packet and sends a unicast ICMPv6 Echo (ping) Response packet
|
||||
# back to Host.
|
||||
# - Pass Criteria:
|
||||
# - For DUT = MTD:
|
||||
# - The DUT MUST unicast a ICMPv6 Echo (ping) Response packet back to Host.
|
||||
print("Step 11: MTD sends a unicast ICMPv6 Echo Response packet back to Host.")
|
||||
pkts.filter_wpan_src64(MTD).\
|
||||
filter_ping_reply().\
|
||||
filter(lambda p: p.ipv6.dst == HOST_ULA).\
|
||||
must_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
verify_utils.run_main(verify)
|
||||
@@ -269,6 +269,7 @@ def apply_patches():
|
||||
Layer.get_field = patched_get_field
|
||||
|
||||
layer_fields._LAYER_FIELDS['mle.tlv.link_forward_series'] = layer_fields._list(layer_fields._auto)
|
||||
layer_fields._LAYER_FIELDS['mle.tlv.addr_reg_ipv6'] = layer_fields._list(layer_fields._ipv6_addr)
|
||||
layer_fields._LAYER_FIELDS['mle.tlv.link_forward_series_flags'] = layer_fields._auto
|
||||
layer_fields._LAYER_FIELDS['mle.tlv.link_status_sub_tlv'] = layer_fields._auto
|
||||
layer_fields._LAYER_FIELDS['mle.tlv.query_id'] = layer_fields._auto
|
||||
|
||||
@@ -722,6 +722,9 @@ def get_layer_field(packet: RawPacket, field_uri: str) -> Any:
|
||||
field_uri = '.'.join([layer_name] + secs[1:])
|
||||
layer_depth = 1
|
||||
|
||||
if field_uri == 'mle.tlv.addr_reg':
|
||||
field_uri = 'mle.tlv.addr_reg_ipv6'
|
||||
|
||||
if is_layer_field(field_uri):
|
||||
candidate_layers = _get_candidate_layers(packet, layer_name)
|
||||
for layers in candidate_layers:
|
||||
|
||||
Reference in New Issue
Block a user