From aec6b5d79593d7a97a2296f1c7fca465fbcdc6ad Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Fri, 3 Apr 2026 23:16:37 -0700 Subject: [PATCH] [border-router] introduce `LinkLayerAddress` in `InfraIf` (#12819) This commit introduces the `LinkLayerAddress` class as a nested type within `InfraIf`. The new class inherits from the `otPlatInfraIfLinkLayerAddress` and provides utility methods to simplify address manipulation and logging. Specifically, the following capabilities are added: - `ConvertToIid()` converts the link-layer address into an IPv6 `InterfaceIdentifier`. - `ToString()` formats the address into a human-readable string. - Getters like `GetLength()` and `GetBytes()` for accessing the underlying address data. The `nexus` platform tests are updated to leverage the newly added `LinkLayerAddress` methods, simplifying the handling of MAC addresses and the derivation of IPv6 interface identifiers. --- src/core/border_router/infra_if.cpp | 65 +++++++++++++++++++++++++ src/core/border_router/infra_if.hpp | 57 ++++++++++++++++++++-- tests/nexus/platform/nexus_core.cpp | 10 +--- tests/nexus/platform/nexus_infra_if.cpp | 24 ++------- tests/nexus/platform/nexus_infra_if.hpp | 2 +- tests/nexus/platform/nexus_pcap.cpp | 19 ++++---- tests/nexus/platform/nexus_pcap.hpp | 14 +++--- tests/nexus/test_1_3_DBR_TC_6.cpp | 9 +--- 8 files changed, 145 insertions(+), 55 deletions(-) diff --git a/src/core/border_router/infra_if.cpp b/src/core/border_router/infra_if.cpp index ae7d71735..6b35daf4f 100644 --- a/src/core/border_router/infra_if.cpp +++ b/src/core/border_router/infra_if.cpp @@ -236,6 +236,71 @@ InfraIf::InfoString InfraIf::ToString(void) const return string; } +//--------------------------------------------------------------------------------------------------------------------- +// InfraIf::LinkLayerAddress + +Error InfraIf::LinkLayerAddress::ConvertToIid(Ip6::InterfaceIdentifier &aIid) const +{ + Error error = kErrorNone; + Mac::ExtAddress extAddress; + + switch (mLength) + { + case 5: + // EUI-40 - [AA BB] + [FF FF FE] + [CC DD EE] + extAddress.m8[0] = mAddress[0]; + extAddress.m8[1] = mAddress[1]; + extAddress.m8[2] = 0xff; + extAddress.m8[3] = 0xff; + extAddress.m8[4] = 0xfe; + extAddress.m8[5] = mAddress[2]; + extAddress.m8[6] = mAddress[3]; + extAddress.m8[7] = mAddress[4]; + break; + + case 6: + // EUI-48 - [AA BB CC] + [FF FE] + [DD EE FF] + extAddress.m8[0] = mAddress[0]; + extAddress.m8[1] = mAddress[1]; + extAddress.m8[2] = mAddress[2]; + extAddress.m8[3] = 0xff; + extAddress.m8[4] = 0xfe; + extAddress.m8[5] = mAddress[3]; + extAddress.m8[6] = mAddress[4]; + extAddress.m8[7] = mAddress[5]; + break; + + case 8: + extAddress.Set(mAddress); + break; + + default: + ExitNow(error = kErrorNotCapable); + } + + aIid.SetFromExtAddress(extAddress); + +exit: + return error; +} + +InfraIf::LinkLayerAddress::InfoString InfraIf::LinkLayerAddress::ToString(void) const +{ + InfoString string; + + for (uint8_t i = 0; i < GetLength(); i++) + { + if (i > 0) + { + string.Append(":"); + } + + string.Append("%02x", mAddress[i]); + } + + return string; +} + //--------------------------------------------------------------------------------------------------------------------- extern "C" void otPlatInfraIfRecvIcmp6Nd(otInstance *aInstance, diff --git a/src/core/border_router/infra_if.hpp b/src/core/border_router/infra_if.hpp index 0b4dd715b..6bebd1cfc 100644 --- a/src/core/border_router/infra_if.hpp +++ b/src/core/border_router/infra_if.hpp @@ -40,6 +40,7 @@ #include +#include "common/as_core_type.hpp" #include "common/data.hpp" #include "common/error.hpp" #include "common/locator.hpp" @@ -87,9 +88,56 @@ class InfraIf : public InstanceLocator public: static constexpr uint16_t kInfoStringSize = 20; ///< Max chars for the info string (`ToString()`). - typedef String InfoString; ///< String type returned from `ToString()`. - typedef Data Icmp6Packet; ///< An IMCPv6 packet (data containing the IP payload) - typedef otPlatInfraIfLinkLayerAddress LinkLayerAddress; ///< A link-layer address + typedef String InfoString; ///< String type returned from `ToString()`. + typedef Data Icmp6Packet; ///< An IMCPv6 packet (data containing the IP payload) + + /** + * Represents a link-layer address. + */ + class LinkLayerAddress : public otPlatInfraIfLinkLayerAddress, public Clearable + { + public: + static constexpr uint8_t kMaxLength = OT_PLAT_INFRA_IF_MAX_LINK_LAYER_ADDR_LENGTH; ///< Max length + + static constexpr uint16_t kInfoStringSize = 50; ///< `InfoString` size + + typedef String InfoString; //< String type returned from `ToString()`. + + /** + * Gets the link-layer address's length (number of bytes). + * + * @return The link-layer address's length (in bytes). + */ + uint8_t GetLength(void) const { return mLength; } + + /** + * Gets the address bytes (as a pointer to a byte array). + * + * @returns A pointer to a byte array containing the link layer address + */ + const uint8_t *GetBytes(void) const { return mAddress; }; + + /** + * Converts the link-layer address to an IPv6 Interface Identifier (IID). + * + * Currently supports link-layer addresses of length 5 (40-bit), 6 (48-bit), and 8 (64-bit) bytes. + * + * @param[out] aIid A reference to an `InterfaceIdentifier` to output the converted IID. + * + * @retval kErrorNone Successfully converted to an IID and updated @p aIid. + * @retval kErrorNotCapable The link-layer address length is not supported for conversion. + */ + Error ConvertToIid(Ip6::InterfaceIdentifier &aIid) const; + + /** + * Converts the link-layer address to a human-readable string. + * + * The address is represented as a sequence of hex digits (lower case) separated by `:`, e.g., `01:ab:7c:d2:38`. + * + * @returns The string representation of the link-layer address. + */ + InfoString ToString(void) const; + }; /** * Initializes the `InfraIf`. @@ -238,6 +286,9 @@ private: }; } // namespace BorderRouter + +DefineCoreType(otPlatInfraIfLinkLayerAddress, BorderRouter::InfraIf::LinkLayerAddress); + } // namespace ot #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE diff --git a/tests/nexus/platform/nexus_core.cpp b/tests/nexus/platform/nexus_core.cpp index 91c9668fa..1ad88e1b5 100644 --- a/tests/nexus/platform/nexus_core.cpp +++ b/tests/nexus/platform/nexus_core.cpp @@ -195,14 +195,8 @@ void Core::SaveTestInfo(const char *aFilename, Node *aLeaderNode) InfraIf::LinkLayerAddress mac; node.mInfraIf.GetLinkLayerAddress(mac); - fprintf(file, " \"%u\": \"", node.GetInstance().GetId()); - - for (uint8_t i = 0; i < mac.mLength; i++) - { - fprintf(file, "%02x%s", mac.mAddress[i], (i + 1 == mac.mLength) ? "" : ":"); - } - - fprintf(file, "\"%s\n", (&node == tail) ? "" : ","); + fprintf(file, " \"%u\": \"%s\"%s\n", node.GetInstance().GetId(), mac.ToString().AsCString(), + (&node == tail) ? "" : ","); } fprintf(file, " },\n"); diff --git a/tests/nexus/platform/nexus_infra_if.cpp b/tests/nexus/platform/nexus_infra_if.cpp index e6f660740..0656b6e70 100644 --- a/tests/nexus/platform/nexus_infra_if.cpp +++ b/tests/nexus/platform/nexus_infra_if.cpp @@ -54,15 +54,7 @@ void InfraIf::Init(Node &aNode) mNodeId = aNode.GetId(); GetLinkLayerAddress(mac); - - iid.mFields.m8[0] = mac.mAddress[0] ^ 0x02; - iid.mFields.m8[1] = mac.mAddress[1]; - iid.mFields.m8[2] = mac.mAddress[2]; - iid.mFields.m8[3] = 0xff; - iid.mFields.m8[4] = 0xfe; - iid.mFields.m8[5] = mac.mAddress[3]; - iid.mFields.m8[6] = mac.mAddress[4]; - iid.mFields.m8[7] = mac.mAddress[5]; + SuccessOrQuit(mac.ConvertToIid(iid)); address.SetToLinkLocalAddress(iid); @@ -270,15 +262,7 @@ void InfraIf::HandlePrefixInfoOption(const Ip6::Nd::PrefixInfoOption &aPio) address = AsCoreType(&prefix.mPrefix); GetLinkLayerAddress(mac); - - address.mFields.m8[8] = mac.mAddress[0] ^ 0x02; - address.mFields.m8[9] = mac.mAddress[1]; - address.mFields.m8[10] = mac.mAddress[2]; - address.mFields.m8[11] = 0xff; - address.mFields.m8[12] = 0xfe; - address.mFields.m8[13] = mac.mAddress[3]; - address.mFields.m8[14] = mac.mAddress[4]; - address.mFields.m8[15] = mac.mAddress[5]; + SuccessOrQuit(mac.ConvertToIid(address.GetIid())); if (aPio.GetValidLifetime() == 0) { @@ -586,7 +570,7 @@ void InfraIf::GetLinkLayerAddress(LinkLayerAddress &aLinkLayerAddress) const ClearAllBytes(aLinkLayerAddress); aLinkLayerAddress.mLength = 6; aLinkLayerAddress.mAddress[0] = 0x02; - aLinkLayerAddress.mAddress[5] = static_cast(mNodeId); + BigEndian::WriteUint32(mNodeId, &aLinkLayerAddress.mAddress[2]); } Node &InfraIf::GetNode(void) @@ -637,7 +621,7 @@ otError otPlatGetInfraIfLinkLayerAddress(otInstance *aInstanc { OT_UNUSED_VARIABLE(aInfraIfIndex); - AsNode(aInstance).mInfraIf.GetLinkLayerAddress(*aLinkLayerAddress); + AsNode(aInstance).mInfraIf.GetLinkLayerAddress(AsCoreType(aLinkLayerAddress)); return OT_ERROR_NONE; } diff --git a/tests/nexus/platform/nexus_infra_if.hpp b/tests/nexus/platform/nexus_infra_if.hpp index 2ca103d1a..a05ce9185 100644 --- a/tests/nexus/platform/nexus_infra_if.hpp +++ b/tests/nexus/platform/nexus_infra_if.hpp @@ -39,7 +39,7 @@ class Node; class InfraIf { public: - typedef otPlatInfraIfLinkLayerAddress LinkLayerAddress; + using LinkLayerAddress = BorderRouter::InfraIf::LinkLayerAddress; explicit InfraIf(Instance &aInstance); diff --git a/tests/nexus/platform/nexus_pcap.cpp b/tests/nexus/platform/nexus_pcap.cpp index 871c8b892..fbdab6ff6 100644 --- a/tests/nexus/platform/nexus_pcap.cpp +++ b/tests/nexus/platform/nexus_pcap.cpp @@ -202,11 +202,11 @@ exit: return; } -void Pcap::WritePacket(const otPlatInfraIfLinkLayerAddress &aSrcAddr, - const otPlatInfraIfLinkLayerAddress &aDstAddr, - const uint8_t *aBuffer, - uint16_t aLength, - uint64_t aTimeUs) +void Pcap::WritePacket(const InfraIf::LinkLayerAddress &aSrcAddr, + const InfraIf::LinkLayerAddress &aDstAddr, + const uint8_t *aBuffer, + uint16_t aLength, + uint64_t aTimeUs) { Epb epb; @@ -227,10 +227,11 @@ void Pcap::WritePacket(const otPlatInfraIfLinkLayerAddress &aSrcAddr, VerifyOrExit(mFile != nullptr); ClearAllBytes(ethHeader); - VerifyOrQuit(aDstAddr.mLength >= sizeof(ethHeader.mDst), "Destination MAC address length is less than expected"); - memcpy(ethHeader.mDst, aDstAddr.mAddress, sizeof(ethHeader.mDst)); - VerifyOrQuit(aSrcAddr.mLength >= sizeof(ethHeader.mSrc), "Source MAC address length is less than expected"); - memcpy(ethHeader.mSrc, aSrcAddr.mAddress, sizeof(ethHeader.mSrc)); + VerifyOrQuit(aDstAddr.GetLength() >= sizeof(ethHeader.mDst), + "Destination MAC address length is less than expected"); + memcpy(ethHeader.mDst, aDstAddr.GetBytes(), sizeof(ethHeader.mDst)); + VerifyOrQuit(aSrcAddr.GetLength() >= sizeof(ethHeader.mSrc), "Source MAC address length is less than expected"); + memcpy(ethHeader.mSrc, aSrcAddr.GetBytes(), sizeof(ethHeader.mSrc)); ethHeader.mType = BigEndian::HostSwap16(kEtherTypeIPv6); packetLen = sizeof(ethHeader) + aLength; diff --git a/tests/nexus/platform/nexus_pcap.hpp b/tests/nexus/platform/nexus_pcap.hpp index 8ee6b8f83..9f4e20159 100644 --- a/tests/nexus/platform/nexus_pcap.hpp +++ b/tests/nexus/platform/nexus_pcap.hpp @@ -32,8 +32,8 @@ #include #include -#include -#include +#include "nexus_infra_if.hpp" +#include "nexus_radio.hpp" namespace ot { namespace Nexus { @@ -73,11 +73,11 @@ public: * @param[in] aLength The packet length. * @param[in] aTimeUs The timestamp in microseconds. */ - void WritePacket(const otPlatInfraIfLinkLayerAddress &aSrcAddr, - const otPlatInfraIfLinkLayerAddress &aDstAddr, - const uint8_t *aBuffer, - uint16_t aLength, - uint64_t aTimeUs); + void WritePacket(const InfraIf::LinkLayerAddress &aSrcAddr, + const InfraIf::LinkLayerAddress &aDstAddr, + const uint8_t *aBuffer, + uint16_t aLength, + uint64_t aTimeUs); private: static constexpr uint32_t kPcapngShbType = 0x0a0d0d0a; diff --git a/tests/nexus/test_1_3_DBR_TC_6.cpp b/tests/nexus/test_1_3_DBR_TC_6.cpp index 8564ad110..d98abe084 100644 --- a/tests/nexus/test_1_3_DBR_TC_6.cpp +++ b/tests/nexus/test_1_3_DBR_TC_6.cpp @@ -252,18 +252,13 @@ void Test_1_3_DBR_TC_6(void) nexus.AdvanceTime(kPingResponseTime); { - char macStr[18]; InfraIf::LinkLayerAddress addr; br1.mInfraIf.GetLinkLayerAddress(addr); - snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x", addr.mAddress[0], addr.mAddress[1], - addr.mAddress[2], addr.mAddress[3], addr.mAddress[4], addr.mAddress[5]); - nexus.AddTestVar("BR1_ETH", macStr); + nexus.AddTestVar("BR1_ETH", addr.ToString().AsCString()); eth1.mInfraIf.GetLinkLayerAddress(addr); - snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x", addr.mAddress[0], addr.mAddress[1], - addr.mAddress[2], addr.mAddress[3], addr.mAddress[4], addr.mAddress[5]); - nexus.AddTestVar("ETH1_ETH", macStr); + nexus.AddTestVar("ETH1_ETH", addr.ToString().AsCString()); } nexus.AddTestVar("BR1", br1.Get().GetExtAddress().ToString().AsCString());