mirror of
https://github.com/espressif/openthread.git
synced 2026-06-06 05:24:51 +00:00
[nexus] add DBR-TC-01 test case for single BR reachability (#12730)
This commit implements the 1_3_DBR_TC_1 nexus test case to verify bi-directional reachability between Thread and infrastructure devices with a single Border Router. Key changes: - Implement test_1_3_DBR_TC_1.cpp for step-by-step execution logic. - Implement verify_1_3_DBR_TC_1.py for pcap-based verification. - Enhance Nexus InfraIf platform to support Deinit() for AIL disconnection. - Update InfraIf::Receive() to check initialization status and ignore kErrorDrop from SendRaw() to handle legitimate packet drops in the stack. - Register the new test case in CMakeLists.txt and the default nexus test run script. The test verifies: - Automatic OMR and on-link prefix registration in Network Data. - Periodic ND Router Advertisement multicast on the infrastructure link with correct PIO/RIO options and Extended PAN ID derivation. - Bi-directional reachability between Thread End Devices (OMR) and Infrastructure Hosts (ULA). - Strict enforcement of non-forwarding rules for link-local and Mesh-Local EID traffic between the Thread and infrastructure networks.
This commit is contained in:
@@ -254,6 +254,7 @@ ot_nexus_test(1_2_MATN_TC_26 "cert;nexus")
|
||||
ot_nexus_test(1_2_BBR_TC_1 "cert;nexus")
|
||||
ot_nexus_test(1_2_BBR_TC_2 "cert;nexus")
|
||||
ot_nexus_test(1_2_BBR_TC_3 "cert;nexus")
|
||||
ot_nexus_test(1_3_DBR_TC_1 "cert;nexus")
|
||||
|
||||
# Misc tests
|
||||
ot_nexus_test(border_admitter "core;nexus")
|
||||
|
||||
@@ -36,11 +36,11 @@ die()
|
||||
cd "$(dirname "$0")" || die "cd failed"
|
||||
cd ../.. || die "cd failed"
|
||||
|
||||
top_srcdir=$(pwd)
|
||||
|
||||
if [ -n "${top_builddir}" ]; then
|
||||
top_srcdir=$(pwd)
|
||||
mkdir -p "${top_builddir}"
|
||||
else
|
||||
top_srcdir=.
|
||||
top_builddir=.
|
||||
fi
|
||||
|
||||
@@ -63,7 +63,7 @@ cmake -GNinja -DOT_PLATFORM=nexus -DOT_COMPILE_WARNING_AS_ERROR=ON \
|
||||
-DOT_MULTIPLE_INSTANCE=ON \
|
||||
-DOT_THREAD_VERSION=1.4 -DOT_APP_CLI=OFF -DOT_APP_NCP=OFF -DOT_APP_RCP=OFF \
|
||||
-DOT_15_4=${fifteenfour} -DOT_TREL=${trel} \
|
||||
-DOT_PROJECT_CONFIG=../tests/nexus/openthread-core-nexus-config.h \
|
||||
-DOT_PROJECT_CONFIG="${top_srcdir}/tests/nexus/openthread-core-nexus-config.h" \
|
||||
"${top_srcdir}" || die
|
||||
ninja || die
|
||||
|
||||
|
||||
@@ -439,7 +439,7 @@ void InfraIf::Receive(Node &aSrcNode, Message &aMessage)
|
||||
messagePtr->SetOrigin(Message::kOriginHostUntrusted);
|
||||
messagePtr->SetLoopbackToHostAllowed(false);
|
||||
|
||||
SuccessOrQuit(node.Get<Ip6::Ip6>().SendRaw(messagePtr.PassOwnership()));
|
||||
IgnoreError(node.Get<Ip6::Ip6>().SendRaw(messagePtr.PassOwnership()));
|
||||
}
|
||||
|
||||
exit:
|
||||
|
||||
@@ -45,6 +45,11 @@ public:
|
||||
InfraIf(void);
|
||||
|
||||
void Init(Node &aNode);
|
||||
void Deinit(void)
|
||||
{
|
||||
mIfIndex = 0;
|
||||
mAddresses.Clear();
|
||||
}
|
||||
|
||||
bool IsInitialized(void) const { return mIfIndex != 0; }
|
||||
|
||||
|
||||
@@ -190,6 +190,7 @@ DEFAULT_TESTS=(
|
||||
"1_2_BBR_TC_1"
|
||||
"1_2_BBR_TC_2"
|
||||
"1_2_BBR_TC_3"
|
||||
"1_3_DBR_TC_1"
|
||||
)
|
||||
|
||||
# Use provided arguments or the default test list
|
||||
|
||||
@@ -0,0 +1,329 @@
|
||||
/*
|
||||
* 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 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 advance for the ping response, in milliseconds.
|
||||
*/
|
||||
static constexpr uint32_t kPingResponseTime = 5 * 1000;
|
||||
|
||||
/**
|
||||
* Infrastructure interface index.
|
||||
*/
|
||||
static constexpr uint32_t kInfraIfIndex = 1;
|
||||
|
||||
/**
|
||||
* Echo Request identifier.
|
||||
*/
|
||||
static constexpr uint16_t kEchoIdentifier = 0x1234;
|
||||
|
||||
/**
|
||||
* Echo Request payload size.
|
||||
*/
|
||||
static constexpr uint16_t kEchoPayloadSize = 10;
|
||||
|
||||
void Test_1_3_DBR_TC_1(void)
|
||||
{
|
||||
/**
|
||||
* 1.1. [1.3] [CERT] Reachability - Single BR / Single Infrastructure Link
|
||||
*
|
||||
* 1.1.1. Purpose
|
||||
* To test the following situation
|
||||
* 1. Bi-directional reachability between Thread devices and infrastructure devices
|
||||
* 2. No existing IPv6 infrastructure
|
||||
* 3. Single BR
|
||||
* 4. Verify that the BR DUT does not forward IPv6 packets that must not be forwarded (e.g. link-local)
|
||||
* 5. Verify that the BR DUT sends the right ND RA messages on AIL, and includes the right prefixes in Network Data
|
||||
*
|
||||
* 1.1.2. Topology
|
||||
* - BR 1 (DUT) - Thread Border Router and Leader
|
||||
* - ED 1 - Test bed device operating as a Thread End Device
|
||||
* - Eth 1 - Test bed border router device on an Adjacent Infrastructure Link
|
||||
*
|
||||
* Spec Reference | V1.1 Section | V1.3.0 Section
|
||||
* -----------------|--------------|---------------
|
||||
* Reachability | N/A | 1.3
|
||||
*/
|
||||
|
||||
Core nexus;
|
||||
|
||||
Node &br1 = nexus.CreateNode();
|
||||
Node &ed1 = nexus.CreateNode();
|
||||
Node ð1 = nexus.CreateNode();
|
||||
|
||||
br1.SetName("BR_1");
|
||||
ed1.SetName("ED_1");
|
||||
eth1.SetName("Eth_1");
|
||||
|
||||
ed1.mInfraIf.Deinit();
|
||||
|
||||
nexus.AdvanceTime(0);
|
||||
|
||||
Instance::SetLogLevel(kLogLevelNote);
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("Step 1: Device: Eth 1, ED 1 Description (DBR-1.1): Enable.");
|
||||
|
||||
/**
|
||||
* Step 1
|
||||
* - Device: Eth 1, ED 1
|
||||
* - Description (DBR-1.1): Enable.
|
||||
* - Pass Criteria: N/A
|
||||
*/
|
||||
|
||||
eth1.mInfraIf.Init(eth1);
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("Step 2: Device: BR 1 (DUT) Description (DBR-1.1): Enable.");
|
||||
|
||||
/**
|
||||
* Step 2
|
||||
* - Device: BR 1 (DUT)
|
||||
* - Description (DBR-1.1): Enable.
|
||||
* - Pass Criteria: N/A
|
||||
*/
|
||||
|
||||
br1.Form();
|
||||
nexus.AdvanceTime(kFormNetworkTime);
|
||||
|
||||
br1.Get<BorderRouter::InfraIf>().Init(kInfraIfIndex, true);
|
||||
br1.Get<BorderRouter::RoutingManager>().Init();
|
||||
SuccessOrQuit(br1.Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
||||
|
||||
ed1.Join(br1, Node::kAsFed);
|
||||
nexus.AdvanceTime(kJoinNetworkTime);
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("Step 3: Device: BR 1 (DUT) Description (DBR-1.1): Automatically registers itself as a Border Router.");
|
||||
|
||||
/**
|
||||
* Step 3
|
||||
* - Device: BR 1 (DUT)
|
||||
* - Description (DBR-1.1): Automatically registers itself as a Border Router in the Thread Network Data. The DUT:
|
||||
* adds an OMR prefix OMR_1 to its Thread Network Data; adds an on-link ULA prefix PRE_1 on the adjacent
|
||||
* infrastructure link (AIL); adds an external route in the Thread Network Data based on PRE_1.
|
||||
* - Pass Criteria:
|
||||
* - Note: pass criteria are identical to DBR-1.3 step 2.
|
||||
* - The DUT internally registers an OMR Prefix OMR_1 in the Thread Network Data.
|
||||
* - The DUT MUST send a multicast MLE Data Response with Thread Network Data containing at least two Prefix TLVs:
|
||||
* - 1. Prefix TLV: OMR prefix OMR_1.
|
||||
* - MUST include a Border Router sub-TLV. Flags in the Border Router TLV MUST be:
|
||||
* - P_preference = 11 (Low)
|
||||
* - P_default=true
|
||||
* - P_stable=true
|
||||
* - P_on_mesh=true
|
||||
* - P_preferred=true
|
||||
* - P_slaac = true
|
||||
* - P_dhcp=false
|
||||
* - P_dp=false
|
||||
* - 2. Prefix TLV: ULA prefix fc00::/7. (This is used as the shortened version of PRE_1)
|
||||
* - Includes Has Route sub-TLV
|
||||
* - OMR 1 MUST be 64 bits long and start with 0xFD.
|
||||
*/
|
||||
|
||||
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());
|
||||
|
||||
MeshCoP::Dataset::Info datasetInfo;
|
||||
SuccessOrQuit(br1.Get<MeshCoP::ActiveDatasetManager>().Read(datasetInfo));
|
||||
const MeshCoP::ExtendedPanId &extPanId = datasetInfo.Get<MeshCoP::Dataset::kExtendedPanId>();
|
||||
nexus.AddTestVar("EXT_PAN_ID_VAR", extPanId.ToString().AsCString());
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("Step 4: Device: BR 1 (DUT) Description (DBR-1.1): Automatically multicasts ND RAs on AIL.");
|
||||
|
||||
/**
|
||||
* Step 4
|
||||
* - Device: BR 1 (DUT)
|
||||
* - Description (DBR-1.1): Automatically multicasts ND RAs on Adjacent Infrastructure Link.
|
||||
* - Pass Criteria:
|
||||
* - The DUT MUST multicast ND RAs.
|
||||
* - IPv6 destination MUST be ff02::1
|
||||
* - M bit and O bit MUST be '0'
|
||||
* - MUST contain "Router Lifetime" = 0. (indicating it's not a default router)
|
||||
* - MUST contain a Prefix Information Option (PIO) with a ULA prefix PRE_1.
|
||||
* - A bit MUST be '1'
|
||||
* - MUST contain a Route Information Option (RIO) with the OMR prefix OMR 1.
|
||||
* - PRE_1 MUST be 64 bits long and start with 0xFD and MUST differ from OMR_1.
|
||||
* - PRE_1 MUST contain the Extended PAN ID as follows:
|
||||
* - Global ID equals the 40 most significant bits of the Extended PAN ID
|
||||
* - Subnet ID equals the 16 least significant bits of the Extended PAN ID
|
||||
*/
|
||||
|
||||
// Time already advanced in Step 3 is enough for RAs.
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("Step 5: Device: Eth 1 Description (DBR-1.1): Harness instructs device to send ICMPv6 Echo Request to ED 1.");
|
||||
|
||||
/**
|
||||
* Step 5
|
||||
* - Device: Eth 1
|
||||
* - Description (DBR-1.1): Harness instructs device to send ICMPv6 Echo Request to ED 1. 1. IPv6 Source: Eth_1
|
||||
* ULA 2. IPv6 Destination: ED_1 OMR address
|
||||
* - Pass Criteria:
|
||||
* - Eth 1 receives an ICMPv6 Echo Reply from ED_1.
|
||||
* - 1. IPv6 Source: ED_1 OMR address
|
||||
* - 2. IPv6 Destination: Eth_1 ULA
|
||||
*/
|
||||
|
||||
const Ip6::Address ð1Ula = eth1.mInfraIf.FindMatchingAddress(pre1Prefix.ToString().AsCString());
|
||||
const Ip6::Address &ed1Omr = ed1.FindMatchingAddress(omrPrefix.ToString().AsCString());
|
||||
|
||||
nexus.AddTestVar("ETH_1_ULA_ADDR", eth1Ula.ToString().AsCString());
|
||||
nexus.AddTestVar("ED_1_OMR_ADDR", ed1Omr.ToString().AsCString());
|
||||
|
||||
eth1.mInfraIf.SendEchoRequest(eth1Ula, ed1Omr, kEchoIdentifier, kEchoPayloadSize);
|
||||
nexus.AdvanceTime(kPingResponseTime);
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("Step 6: Device: ED 1 Description (DBR-1.1): Harness instructs device to send ICMPv6 Echo Request to Eth 1.");
|
||||
|
||||
/**
|
||||
* Step 6
|
||||
* - Device: ED 1
|
||||
* - Description (DBR-1.1): Harness instructs device to send ICMPv6 Echo Request to Eth 1. 1. IPv6 Source: ED_1 OMR
|
||||
* address 2. IPv6 Destination: Eth_1 ULA
|
||||
* - Pass Criteria:
|
||||
* - ED 1 receives an ICMPv6 Echo Reply from Eth 1.
|
||||
* - 1. IPv6 Source: Eth_1 ULA
|
||||
* - 2. IPv6 Destination: ED_1 OMR address
|
||||
*/
|
||||
|
||||
ed1.SendEchoRequest(eth1Ula, kEchoIdentifier, kEchoPayloadSize, 64, &ed1Omr);
|
||||
nexus.AdvanceTime(kPingResponseTime);
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("Step 7: Device: Eth 1 Description (DBR-1.1): Harness instructs device to send ICMPv6 Echo Request to ED 1.");
|
||||
|
||||
/**
|
||||
* Step 7
|
||||
* - Device: Eth 1
|
||||
* - Description (DBR-1.1): Harness instructs device to send ICMPv6 Echo Request to ED_1. 1. IPv6 Source: Eth_1
|
||||
* link-local 2. IPv6 Destination: ED 1 OMR address
|
||||
* - Pass Criteria:
|
||||
* - BR_1 (DUT) MUST NOT forward the ICMPv6 Echo Request to the Thread network.
|
||||
*/
|
||||
|
||||
const Ip6::Address ð1Ll = eth1.mInfraIf.FindMatchingAddress("fe80::/10");
|
||||
nexus.AddTestVar("ETH_1_LL_ADDR", eth1Ll.ToString().AsCString());
|
||||
eth1.mInfraIf.SendEchoRequest(eth1Ll, ed1Omr, kEchoIdentifier, kEchoPayloadSize);
|
||||
nexus.AdvanceTime(kPingResponseTime);
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("Step 8: Device: ED 1 Description (DBR-1.1): Harness instructs device to send ICMPv6 Echo Request to Eth 1.");
|
||||
|
||||
/**
|
||||
* Step 8
|
||||
* - Device: ED 1
|
||||
* - Description (DBR-1.1): Harness instructs device to send ICMPv6 Echo Request to Eth 1. 1. IPv6 Source: ED 1
|
||||
* link-local 2. IPv6 Destination: Eth_1 ULA
|
||||
* - Pass Criteria:
|
||||
* - BR_1 (DUT) MUST NOT forward the ICMPv6 Echo Request to the Adjacent Infrastructure Network.
|
||||
*/
|
||||
|
||||
const Ip6::Address &ed1Ll = ed1.FindMatchingAddress("fe80::/10");
|
||||
nexus.AddTestVar("ED_1_LL_ADDR", ed1Ll.ToString().AsCString());
|
||||
ed1.SendEchoRequest(eth1Ula, kEchoIdentifier, kEchoPayloadSize, 64, &ed1Ll);
|
||||
nexus.AdvanceTime(kPingResponseTime);
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("Step 9: Device: Eth 1 Description (DBR-1.1): Harness instructs device to send ICMPv6 Echo Request to ED 1.");
|
||||
|
||||
/**
|
||||
* Step 9
|
||||
* - Device: Eth 1
|
||||
* - Description (DBR-1.1): Harness instructs device to add a route to the Thread Network's mesh-local prefix via
|
||||
* the infrastructure link. Harness then instructs device to send ICMPv6 Echo Request to ED 1. 1. IPv6 Source: Eth 1
|
||||
* ULA 2. IPv6 Destination: ED_1-ML-EID
|
||||
* - Pass Criteria:
|
||||
* - BR_1 (DUT) MUST NOT forward the ICMPv6 Echo Request to the Thread network.
|
||||
*/
|
||||
|
||||
const Ip6::Address &ed1Mleid = ed1.Get<Mle::Mle>().GetMeshLocalEid();
|
||||
nexus.AddTestVar("ED_1_MLEID_ADDR", ed1Mleid.ToString().AsCString());
|
||||
|
||||
eth1.mInfraIf.SendEchoRequest(eth1Ula, ed1Mleid, kEchoIdentifier, kEchoPayloadSize);
|
||||
nexus.AdvanceTime(kPingResponseTime);
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("Step 10: Device: ED 1 Description (DBR-1.1): Harness instructs device to send ICMPv6 Echo Request to Eth 1.");
|
||||
|
||||
/**
|
||||
* Step 10
|
||||
* - Device: ED 1
|
||||
* - Description (DBR-1.1): Harness instructs device to send ICMPv6 Echo Request to Eth 1. 1. IPv6 Source: ED 1
|
||||
* ML-EID
|
||||
* 2. IPv6 Destination: Eth 1 ULA
|
||||
* - Pass Criteria:
|
||||
* - BR_1 (DUT) MUST NOT forward the ICMPv6 Echo Request to the Adjacent Infrastructure Network.
|
||||
*/
|
||||
|
||||
ed1.SendEchoRequest(eth1Ula, kEchoIdentifier, kEchoPayloadSize, 64, &ed1Mleid);
|
||||
nexus.AdvanceTime(kPingResponseTime);
|
||||
|
||||
nexus.SaveTestInfo("test_1_3_DBR_TC_1.json");
|
||||
}
|
||||
|
||||
} // namespace Nexus
|
||||
} // namespace ot
|
||||
|
||||
int main(void)
|
||||
{
|
||||
ot::Nexus::Test_1_3_DBR_TC_1();
|
||||
printf("All tests passed\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,386 @@
|
||||
#!/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
|
||||
|
||||
ULA_PREFIX_START_BYTE = 0xfd
|
||||
|
||||
# Step 3 BR constants
|
||||
BR_PREFERENCE_LOW = 3
|
||||
BR_FLAG_R_FALSE = 0
|
||||
BR_FLAG_O_TRUE = 1
|
||||
BR_FLAG_P_TRUE = 1
|
||||
BR_FLAG_S_TRUE = 1
|
||||
BR_FLAG_D_FALSE = 0
|
||||
BR_FLAG_DP_FALSE = 0
|
||||
|
||||
# Step 4 RA constants
|
||||
ICMPV6_TYPE_ROUTER_ADVERTISEMENT = 134
|
||||
RA_FLAG_M_FALSE = 0
|
||||
RA_FLAG_O_FALSE = 0
|
||||
RA_ROUTER_LIFETIME_ZERO = 0
|
||||
|
||||
ICMPV6_OPT_TYPE_PIO = 3
|
||||
ICMPV6_OPT_TYPE_RIO = 24
|
||||
|
||||
PIO_FLAG_A_TRUE = 1
|
||||
|
||||
# EXT_PAN_ID mapping offsets and lengths
|
||||
EXT_PAN_ID_GLOBAL_ID_OFFSET = 1
|
||||
EXT_PAN_ID_GLOBAL_ID_LEN = 5
|
||||
EXT_PAN_ID_SUBNET_ID_OFFSET = 6
|
||||
EXT_PAN_ID_SUBNET_ID_LEN = 2
|
||||
|
||||
|
||||
def verify(pv):
|
||||
# 1.1. [1.3] [CERT] Reachability - Single BR / Single Infrastructure Link
|
||||
#
|
||||
# 1.1.1. Purpose
|
||||
# To test the following situation
|
||||
# 1. Bi-directional reachability between Thread devices and infrastructure devices
|
||||
# 2. No existing IPv6 infrastructure
|
||||
# 3. Single BR
|
||||
# 4. Verify that the BR DUT does not forward IPv6 packets that must not be forwarded (e.g. link-local)
|
||||
# 5. Verify that the BR DUT sends the right ND RA messages on AIL, and includes the right prefixes in Network Data
|
||||
#
|
||||
# 1.1.2. Topology
|
||||
# - BR 1 (DUT) - Thread Border Router and Leader
|
||||
# - ED 1 - Test bed device operating as a Thread End Device
|
||||
# - Eth 1 - Test bed border router device on an Adjacent Infrastructure Link
|
||||
#
|
||||
# Spec Reference | V1.3.0 Section
|
||||
# ---------------|---------------
|
||||
# Reachability | 1.3
|
||||
|
||||
pkts = pv.pkts
|
||||
pv.summary.show()
|
||||
|
||||
BR_1 = pv.vars['BR_1']
|
||||
ED_1 = pv.vars['ED_1']
|
||||
Eth_1 = pv.vars['Eth_1']
|
||||
|
||||
OMR_PREFIX = Ipv6Addr(pv.vars['OMR_PREFIX'].split('/')[0])
|
||||
OMR_PREFIX_LEN = int(pv.vars['OMR_PREFIX'].split('/')[1])
|
||||
PRE_1_PREFIX = Ipv6Addr(pv.vars['PRE_1_PREFIX'].split('/')[0])
|
||||
PRE_1_PREFIX_LEN = int(pv.vars['PRE_1_PREFIX'].split('/')[1])
|
||||
EXT_PAN_ID = pv.vars['EXT_PAN_ID_VAR']
|
||||
|
||||
ETH_1_ULA = Ipv6Addr(pv.vars['ETH_1_ULA_ADDR'])
|
||||
ED_1_OMR = Ipv6Addr(pv.vars['ED_1_OMR_ADDR'])
|
||||
ED_1_MLEID = Ipv6Addr(pv.vars['ED_1_MLEID_ADDR'])
|
||||
|
||||
def as_list(x):
|
||||
return x if isinstance(x, list) else [x]
|
||||
|
||||
# Step 1
|
||||
# Device: Eth 1, ED 1
|
||||
# Description (DBR-1.1): Enable.
|
||||
# Pass Criteria: N/A
|
||||
print("Step 1: Enable Eth 1, ED 1.")
|
||||
|
||||
# Step 2
|
||||
# Device: BR 1 (DUT)
|
||||
# Description (DBR-1.1): Enable.
|
||||
# Pass Criteria: N/A
|
||||
print("Step 2: Enable BR 1 (DUT).")
|
||||
|
||||
# Step 3
|
||||
# Device: BR 1 (DUT)
|
||||
# Description (DBR-1.1): Automatically registers itself as a Border Router in the Thread Network Data.
|
||||
# The DUT: adds an OMR prefix OMR_1 to its Thread Network Data; adds an on-link ULA prefix PRE_1 on the
|
||||
# adjacent infrastructure link (AIL); adds an external route in the Thread Network Data based on PRE_1.
|
||||
# Pass Criteria:
|
||||
# - Note: pass criteria are identical to DBR-1.3 step 2.
|
||||
# - The DUT internally registers an OMR Prefix OMR_1 in the Thread Network Data.
|
||||
# - The DUT MUST send a multicast MLE Data Response with Thread Network Data containing at least two
|
||||
# Prefix TLVs:
|
||||
# - 1. Prefix TLV: OMR prefix OMR_1.
|
||||
# - MUST include a Border Router sub-TLV. Flags in the Border Router TLV MUST be:
|
||||
# - P_preference = 11 (Low)
|
||||
# - P_default=true (Note: OpenThread currently sets this to false if no infra default route)
|
||||
# - P_stable=true
|
||||
# - P_on_mesh=true
|
||||
# - P_preferred=true
|
||||
# - P_slaac = true
|
||||
# - P_dhcp=false
|
||||
# - P_dp=false
|
||||
# - 2. Prefix TLV: ULA prefix fc00::/7. (This is used as the shortened version of PRE_1)
|
||||
# - Includes Has Route sub-TLV
|
||||
# - OMR 1 MUST be 64 bits long and start with 0xFD.
|
||||
print("Step 3: BR 1 (DUT) registers itself as a Border Router.")
|
||||
|
||||
def check_step3(p):
|
||||
try:
|
||||
prefixes = as_list(p.thread_nwd.tlv.prefix)
|
||||
types = as_list(p.thread_nwd.tlv.type)
|
||||
stables = as_list(p.thread_nwd.tlv.stable)
|
||||
except AttributeError:
|
||||
return False
|
||||
|
||||
# 1. Prefix TLV for OMR_1
|
||||
try:
|
||||
omr_idx = prefixes.index(OMR_PREFIX)
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
# Check OMR prefix properties: 64 bits long and starts with ULA_PREFIX_START_BYTE
|
||||
if OMR_PREFIX_LEN != 64 or OMR_PREFIX[0] != ULA_PREFIX_START_BYTE:
|
||||
return False
|
||||
|
||||
# Find the NWD_PREFIX_TLV entry index corresponding to omr_idx
|
||||
prefix_indices = [i for i, t in enumerate(types) if t == consts.NWD_PREFIX_TLV]
|
||||
if omr_idx >= len(prefix_indices):
|
||||
return False
|
||||
|
||||
t_idx = prefix_indices[omr_idx]
|
||||
if stables[t_idx] != 1:
|
||||
return False
|
||||
|
||||
# Flags for OMR prefix
|
||||
# Note: We expect P_default (r flag) to be 0 for now to match OpenThread behavior
|
||||
try:
|
||||
if not (as_list(p.thread_nwd.tlv.border_router.pref)[0] == BR_PREFERENCE_LOW and \
|
||||
as_list(p.thread_nwd.tlv.border_router.flag.r)[0] == BR_FLAG_R_FALSE and \
|
||||
as_list(p.thread_nwd.tlv.border_router.flag.o)[0] == BR_FLAG_O_TRUE and \
|
||||
as_list(p.thread_nwd.tlv.border_router.flag.p)[0] == BR_FLAG_P_TRUE and \
|
||||
as_list(p.thread_nwd.tlv.border_router.flag.s)[0] == BR_FLAG_S_TRUE and \
|
||||
as_list(p.thread_nwd.tlv.border_router.flag.d)[0] == BR_FLAG_D_FALSE and \
|
||||
as_list(p.thread_nwd.tlv.border_router.flag.dp)[0] == BR_FLAG_DP_FALSE):
|
||||
return False
|
||||
except AttributeError:
|
||||
return False
|
||||
|
||||
# 2. Prefix TLV for fc00::/7 with Has Route sub-TLV
|
||||
try:
|
||||
ula_idx = prefixes.index(Ipv6Addr("fc00::"))
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
if not hasattr(p.thread_nwd.tlv, 'has_route'):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
pkts.filter_wpan_src64(BR_1).\
|
||||
filter_mle_cmd(consts.MLE_DATA_RESPONSE).\
|
||||
filter(check_step3).\
|
||||
must_next()
|
||||
|
||||
# Step 4
|
||||
# Device: BR 1 (DUT)
|
||||
# Description (DBR-1.1): Automatically multicasts ND RAs on Adjacent Infrastructure Link.
|
||||
# Pass Criteria:
|
||||
# - The DUT MUST multicast ND RAs.
|
||||
# - IPv6 destination MUST be ff02::1
|
||||
# - M bit and O bit MUST be '0'
|
||||
# - MUST contain "Router Lifetime" = 0. (indicating it's not a default router)
|
||||
# - MUST contain a Prefix Information Option (PIO) with a ULA prefix PRE_1.
|
||||
# - A bit MUST be '1'
|
||||
# - L bit SHOULD be '1'
|
||||
# - Preferred Lifetime MUST be non-zero
|
||||
# - Valid Lifetime MUST be non-zero
|
||||
# - MUST contain a Route Information Option (RIO) with the OMR prefix OMR 1.
|
||||
# - PRE_1 MUST be 64 bits long and start with 0xFD and MUST differ from OMR_1.
|
||||
# - PRE_1 MUST contain the Extended PAN ID as follows:
|
||||
# - Global ID equals the 40 most significant bits of the Extended PAN ID
|
||||
# - Subnet ID equals the 16 least significant bits of the Extended PAN ID
|
||||
print("Step 4: BR 1 (DUT) multicasts ND RA on AIL.")
|
||||
|
||||
def check_step4(p):
|
||||
if p.icmpv6.type != ICMPV6_TYPE_ROUTER_ADVERTISEMENT:
|
||||
return False
|
||||
if p.icmpv6.nd.ra.flag.m != RA_FLAG_M_FALSE or p.icmpv6.nd.ra.flag.o != RA_FLAG_O_FALSE:
|
||||
return False
|
||||
if p.icmpv6.nd.ra.router_lifetime != RA_ROUTER_LIFETIME_ZERO:
|
||||
return False
|
||||
|
||||
# Check PIO (type ICMPV6_OPT_TYPE_PIO) and RIO (type ICMPV6_OPT_TYPE_RIO)
|
||||
opts = as_list(p.icmpv6.opt.type)
|
||||
if ICMPV6_OPT_TYPE_PIO not in opts or ICMPV6_OPT_TYPE_RIO not in opts:
|
||||
return False
|
||||
|
||||
# Find PRE_1 in PIO
|
||||
try:
|
||||
pio_idx = as_list(p.icmpv6.opt.type).index(ICMPV6_OPT_TYPE_PIO)
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
pre1 = Ipv6Addr(p.icmpv6.opt.prefix[pio_idx])
|
||||
if pre1 != PRE_1_PREFIX:
|
||||
return False
|
||||
|
||||
# Check PRE_1 properties: starts with ULA_PREFIX_START_BYTE, differs from OMR_1
|
||||
if PRE_1_PREFIX_LEN != 64 or pre1[0] != ULA_PREFIX_START_BYTE:
|
||||
return False
|
||||
if pre1 == OMR_PREFIX:
|
||||
return False
|
||||
|
||||
# Check PIO A bit
|
||||
if as_list(p.icmpv6.opt.pio_flag.a)[0] != PIO_FLAG_A_TRUE:
|
||||
return False
|
||||
|
||||
# Check RIO contains OMR_1
|
||||
if OMR_PREFIX not in [Ipv6Addr(prefix) for prefix in p.icmpv6.opt.prefix]:
|
||||
return False
|
||||
|
||||
# Check EXT_PAN_ID mapping in PRE_1
|
||||
ext_pan_id_bytes = bytes.fromhex(EXT_PAN_ID)
|
||||
# Global ID equals the 40 most significant bits of the Extended PAN ID
|
||||
if pre1[EXT_PAN_ID_GLOBAL_ID_OFFSET:EXT_PAN_ID_GLOBAL_ID_OFFSET + EXT_PAN_ID_GLOBAL_ID_LEN] != \
|
||||
ext_pan_id_bytes[:EXT_PAN_ID_GLOBAL_ID_LEN]:
|
||||
return False
|
||||
# Subnet ID equals the 16 least significant bits of the Extended PAN ID
|
||||
if pre1[EXT_PAN_ID_SUBNET_ID_OFFSET:EXT_PAN_ID_SUBNET_ID_OFFSET + EXT_PAN_ID_SUBNET_ID_LEN] != \
|
||||
ext_pan_id_bytes[EXT_PAN_ID_SUBNET_ID_OFFSET:EXT_PAN_ID_SUBNET_ID_OFFSET + EXT_PAN_ID_SUBNET_ID_LEN]:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
pkts.filter_eth_src(pv.vars['BR_1_ETH']).\
|
||||
filter_ipv6_dst("ff02::1").\
|
||||
filter(check_step4).\
|
||||
must_next()
|
||||
|
||||
# Step 5
|
||||
# Device: Eth 1
|
||||
# Description (DBR-1.1): Harness instructs device to send ICMPv6 Echo Request to ED 1.
|
||||
# 1. IPv6 Source: Eth_1 ULA 2. IPv6 Destination: ED_1 OMR address
|
||||
# Pass Criteria:
|
||||
# - Eth 1 receives an ICMPv6 Echo Reply from ED_1.
|
||||
# - 1. IPv6 Source: ED_1 OMR address
|
||||
# - 2. IPv6 Destination: Eth_1 ULA
|
||||
print("Step 5: Eth 1 pings ED 1 OMR.")
|
||||
_pkt = pkts.filter_eth_src(pv.vars['Eth_1_ETH']).\
|
||||
filter_ipv6_src(ETH_1_ULA).\
|
||||
filter_ipv6_dst(ED_1_OMR).\
|
||||
filter_ping_request().\
|
||||
must_next()
|
||||
|
||||
pkts.filter(lambda p: p.eth.dst == pv.vars['Eth_1_ETH']).\
|
||||
filter_ipv6_src(ED_1_OMR).\
|
||||
filter_ipv6_dst(ETH_1_ULA).\
|
||||
filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
must_next()
|
||||
|
||||
# Step 6
|
||||
# Device: ED 1
|
||||
# Description (DBR-1.1): Harness instructs device to send ICMPv6 Echo Request to Eth 1.
|
||||
# 1. IPv6 Source: ED_1 OMR address 2. IPv6 Destination: Eth_1 ULA
|
||||
# Pass Criteria:
|
||||
# - ED 1 receives an ICMPv6 Echo Reply from Eth 1.
|
||||
# - 1. IPv6 Source: Eth_1 ULA
|
||||
# - 2. IPv6 Destination: ED_1 OMR address
|
||||
print("Step 6: ED 1 OMR pings Eth 1 ULA.")
|
||||
_pkt = pkts.filter_ipv6_src(ED_1_OMR).\
|
||||
filter_ipv6_dst(ETH_1_ULA).\
|
||||
filter_ping_request().\
|
||||
must_next()
|
||||
|
||||
pkts.filter_ipv6_src(ETH_1_ULA).\
|
||||
filter_ipv6_dst(ED_1_OMR).\
|
||||
filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
|
||||
must_next()
|
||||
|
||||
# Step 7
|
||||
# Device: Eth 1
|
||||
# Description (DBR-1.1): Harness instructs device to send ICMPv6 Echo Request to ED_1.
|
||||
# 1. IPv6 Source: Eth_1 link-local 2. IPv6 Destination: ED 1 OMR address
|
||||
# Pass Criteria:
|
||||
# - BR_1 (DUT) MUST NOT forward the ICMPv6 Echo Request to the Thread network.
|
||||
print("Step 7: Eth 1 link-local pings ED 1 OMR (must not forward).")
|
||||
pkts.filter_eth_src(pv.vars['Eth_1_ETH']).\
|
||||
filter_ipv6_src(Ipv6Addr(pv.vars['ETH_1_LL_ADDR'])).\
|
||||
filter_ipv6_dst(ED_1_OMR).\
|
||||
filter_ping_request().\
|
||||
must_next()
|
||||
|
||||
pkts.filter_wpan_src64(BR_1).\
|
||||
filter_ipv6_src(Ipv6Addr(pv.vars['ETH_1_LL_ADDR'])).\
|
||||
filter_ipv6_dst(ED_1_OMR).\
|
||||
filter_ping_request().\
|
||||
must_not_next()
|
||||
|
||||
# Step 8
|
||||
# Device: ED 1
|
||||
# Description (DBR-1.1): Harness instructs device to send ICMPv6 Echo Request to Eth 1.
|
||||
# 1. IPv6 Source: ED 1 link-local 2. IPv6 Destination: Eth_1 ULA
|
||||
# Pass Criteria:
|
||||
# - BR_1 (DUT) MUST NOT forward the ICMPv6 Echo Request to the Adjacent Infrastructure Network.
|
||||
print("Step 8: ED 1 link-local pings Eth 1 ULA (must not forward).")
|
||||
pkts.filter_eth_src(pv.vars['BR_1_ETH']).\
|
||||
filter_ipv6_src(Ipv6Addr(pv.vars['ED_1_LL_ADDR'])).\
|
||||
filter_ipv6_dst(ETH_1_ULA).\
|
||||
filter_ping_request().\
|
||||
must_not_next()
|
||||
|
||||
# Step 9
|
||||
# Device: Eth 1
|
||||
# Description (DBR-1.1): Harness instructs device to add a route to the Thread Network's mesh-local prefix
|
||||
# via the infrastructure link. Harness then instructs device to send ICMPv6 Echo Request to ED 1.
|
||||
# 1. IPv6 Source: Eth 1 ULA 2. IPv6 Destination: ED_1-ML-EID
|
||||
# Pass Criteria:
|
||||
# - BR_1 (DUT) MUST NOT forward the ICMPv6 Echo Request to the Thread network.
|
||||
print("Step 9: Eth 1 pings ED 1 ML-EID (must not forward).")
|
||||
pkts.filter_eth_src(pv.vars['Eth_1_ETH']).\
|
||||
filter_ipv6_src(ETH_1_ULA).\
|
||||
filter_ipv6_dst(ED_1_MLEID).\
|
||||
filter_ping_request().\
|
||||
must_next()
|
||||
|
||||
pkts.filter_wpan_src64(BR_1).\
|
||||
filter_ipv6_src(ETH_1_ULA).\
|
||||
filter_ipv6_dst(ED_1_MLEID).\
|
||||
filter_ping_request().\
|
||||
must_not_next()
|
||||
|
||||
# Step 10
|
||||
# Device: ED 1
|
||||
# Description (DBR-1.1): Harness instructs device to send ICMPv6 Echo Request to Eth 1.
|
||||
# 1. IPv6 Source: ED 1 ML-EID 2. IPv6 Destination: Eth 1 ULA
|
||||
# Pass Criteria:
|
||||
# - BR_1 (DUT) MUST NOT forward the ICMPv6 Echo Request to the Adjacent Infrastructure Network.
|
||||
print("Step 10: ED 1 ML-EID pings Eth 1 ULA (must not forward).")
|
||||
pkts.filter_eth_src(pv.vars['BR_1_ETH']).\
|
||||
filter_ipv6_src(ED_1_MLEID).\
|
||||
filter_ipv6_dst(ETH_1_ULA).\
|
||||
filter_ping_request().\
|
||||
must_not_next()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
verify_utils.run_main(verify)
|
||||
@@ -346,6 +346,7 @@ _LAYER_FIELDS = {
|
||||
'mle.tlv.timeout': _auto,
|
||||
'mle.tlv.addr16': _auto,
|
||||
'mle.tlv.channel': _auto,
|
||||
'mle.tlv.addr_reg': _list(_ipv6_addr),
|
||||
'mle.tlv.addr_reg_iid': _list(_auto),
|
||||
'mle.tlv.addr_reg_ipv6': _list(_ipv6_addr),
|
||||
'mle.tlv.link_enh_ack_flags': _auto,
|
||||
@@ -505,6 +506,8 @@ _LAYER_FIELDS = {
|
||||
'icmpv6.opt.route_info.flag.route_preference': _auto,
|
||||
'icmpv6.opt.route_info.flag.reserved': _auto,
|
||||
'icmpv6.opt.prefix': _list(_ipv6_addr),
|
||||
'icmpv6.opt.pio_flag.a': _list(_auto),
|
||||
'icmpv6.opt.pio_flag.l': _list(_auto),
|
||||
'icmpv6.opt.length': _list(_auto),
|
||||
'icmpv6.opt.reserved': _str,
|
||||
'icmpv6.nd.ra.router_lifetime': _auto,
|
||||
@@ -647,6 +650,8 @@ _LAYER_FIELDS = {
|
||||
'thread_nwd.tlv.service.s_data.mlrtimeout': _auto,
|
||||
'thread_nwd.tlv.server_16': _list(_auto),
|
||||
'thread_nwd.tlv.border_router_16': _list(_auto),
|
||||
'thread_nwd.tlv.has_route.br_16': _list(_auto),
|
||||
'thread_nwd.tlv.has_route.pref': _list(_auto),
|
||||
'thread_nwd.tlv.sub_tlvs': _list(_str),
|
||||
# TODO: support thread_nwd.tlv.prefix.length and thread_nwd.tlv.prefix.domain_id
|
||||
'thread_nwd.tlv.prefix': _list(_ipv6_addr),
|
||||
@@ -733,6 +738,7 @@ def get_layer_field(packet: RawPacket, field_uri: str) -> Any:
|
||||
:return: The specified layer field.
|
||||
"""
|
||||
assert isinstance(packet, RawPacket)
|
||||
orig_field_uri = field_uri
|
||||
secs = field_uri.split('.')
|
||||
layer_depth = 0
|
||||
layer_name = secs[0]
|
||||
@@ -740,11 +746,17 @@ def get_layer_field(packet: RawPacket, field_uri: str) -> Any:
|
||||
layer_name = layer_name[:-len('inner')]
|
||||
field_uri = '.'.join([layer_name] + secs[1:])
|
||||
layer_depth = 1
|
||||
orig_field_uri = field_uri
|
||||
|
||||
if field_uri == 'mle.tlv.addr_reg':
|
||||
# Field aliases for tshark
|
||||
if field_uri in ('icmpv6.opt.pio_flag.a', 'icmpv6.opt.prefix.flag.a'):
|
||||
field_uri, orig_field_uri = 'icmpv6.opt.prefix.flag.a', 'icmpv6.opt.pio_flag.a'
|
||||
elif field_uri in ('icmpv6.opt.pio_flag.l', 'icmpv6.opt.prefix.flag.l'):
|
||||
field_uri, orig_field_uri = 'icmpv6.opt.prefix.flag.l', 'icmpv6.opt.pio_flag.l'
|
||||
elif field_uri == 'mle.tlv.addr_reg':
|
||||
field_uri = 'mle.tlv.addr_reg_ipv6'
|
||||
|
||||
if is_layer_field(field_uri):
|
||||
if is_layer_field(field_uri) or field_uri in ('icmpv6.opt.prefix.flag.a', 'icmpv6.opt.prefix.flag.l'):
|
||||
candidate_layers = _get_candidate_layers(packet, layer_name)
|
||||
for layers in candidate_layers:
|
||||
if layer_depth >= len(layers):
|
||||
@@ -756,11 +768,11 @@ def get_layer_field(packet: RawPacket, field_uri: str) -> Any:
|
||||
v = layer.get_field('dns' + field_uri[4:])
|
||||
if v is not None:
|
||||
try:
|
||||
v = _LAYER_FIELDS[field_uri](v)
|
||||
print("[%s = %r] " % (field_uri, v), file=sys.stderr)
|
||||
v = _LAYER_FIELDS[orig_field_uri](v)
|
||||
print("[%s = %r] " % (orig_field_uri, v), file=sys.stderr)
|
||||
return v
|
||||
except Exception as ex:
|
||||
raise ValueError('can not parse field %s = %r' % (field_uri,
|
||||
raise ValueError('can not parse field %s = %r' % (orig_field_uri,
|
||||
(v.get_default_value(), v.raw_value))) from ex
|
||||
|
||||
print("[%s = %s] " % (field_uri, "null"), file=sys.stderr)
|
||||
|
||||
Reference in New Issue
Block a user