From 6f0993065ef422030c3e89c1b407185a65d9751c Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Fri, 10 Oct 2025 12:59:33 -0700 Subject: [PATCH] [border-agent] introduce `TxtData` class (#12005) This commit introduces a new `MeshCoP::BorderAgent::TxtData` class to encapsulate the logic for preparing the Border Agent's MeshCoP service TXT data. The TXT data generation logic is moved from the `BorderAgent::Manager` into the new `TxtData` class. This refactoring improves modularity and maintainability and prepares for the future addition of a MeshCoP TXT data parser. --- src/core/BUILD.gn | 2 + src/core/CMakeLists.txt | 1 + src/core/api/border_agent_api.cpp | 2 +- src/core/instance/instance.cpp | 1 + src/core/instance/instance.hpp | 3 + src/core/meshcop/border_agent.cpp | 134 +------------- src/core/meshcop/border_agent.hpp | 60 ------ src/core/meshcop/border_agent_txt_data.cpp | 204 +++++++++++++++++++++ src/core/meshcop/border_agent_txt_data.hpp | 158 ++++++++++++++++ tests/nexus/test_border_agent.cpp | 7 +- 10 files changed, 376 insertions(+), 196 deletions(-) create mode 100644 src/core/meshcop/border_agent_txt_data.cpp create mode 100644 src/core/meshcop/border_agent_txt_data.hpp diff --git a/src/core/BUILD.gn b/src/core/BUILD.gn index d8f08f00e..b613d51c0 100644 --- a/src/core/BUILD.gn +++ b/src/core/BUILD.gn @@ -528,6 +528,8 @@ openthread_core_files = [ "meshcop/border_agent.hpp", "meshcop/border_agent_tracker.cpp", "meshcop/border_agent_tracker.hpp", + "meshcop/border_agent_txt_data.cpp", + "meshcop/border_agent_txt_data.hpp", "meshcop/commissioner.cpp", "meshcop/commissioner.hpp", "meshcop/dataset.cpp", diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 590fb2e44..19910ad69 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -159,6 +159,7 @@ set(COMMON_SOURCES meshcop/announce_begin_client.cpp meshcop/border_agent.cpp meshcop/border_agent_tracker.cpp + meshcop/border_agent_txt_data.cpp meshcop/commissioner.cpp meshcop/dataset.cpp meshcop/dataset_manager.cpp diff --git a/src/core/api/border_agent_api.cpp b/src/core/api/border_agent_api.cpp index 36fc45f35..814c352ef 100644 --- a/src/core/api/border_agent_api.cpp +++ b/src/core/api/border_agent_api.cpp @@ -111,7 +111,7 @@ void otBorderAgentSetMeshCoPServiceChangedCallback(otInstance otError otBorderAgentGetMeshCoPServiceTxtData(otInstance *aInstance, otBorderAgentMeshCoPServiceTxtData *aTxtData) { - return AsCoreType(aInstance).Get().PrepareServiceTxtData(*aTxtData); + return AsCoreType(aInstance).Get().Prepare(*aTxtData); } const otBorderAgentCounters *otBorderAgentGetCounters(otInstance *aInstance) diff --git a/src/core/instance/instance.cpp b/src/core/instance/instance.cpp index ebd359490..aee032fbf 100644 --- a/src/core/instance/instance.cpp +++ b/src/core/instance/instance.cpp @@ -173,6 +173,7 @@ Instance::Instance(void) #endif #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE , mBorderAgentManager(*this) + , mBorderAgentTxtData(*this) #endif #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE && OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE , mBorderAgentEphemeralKeyManager(*this) diff --git a/src/core/instance/instance.hpp b/src/core/instance/instance.hpp index c829f6ec7..ea2ce9070 100644 --- a/src/core/instance/instance.hpp +++ b/src/core/instance/instance.hpp @@ -87,6 +87,7 @@ #include "mac/wakeup_tx_scheduler.hpp" #include "meshcop/border_agent.hpp" #include "meshcop/border_agent_tracker.hpp" +#include "meshcop/border_agent_txt_data.hpp" #include "meshcop/commissioner.hpp" #include "meshcop/dataset_manager.hpp" #include "meshcop/dataset_updater.hpp" @@ -590,6 +591,7 @@ private: #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE MeshCoP::BorderAgent::Manager mBorderAgentManager; + MeshCoP::BorderAgent::TxtData mBorderAgentTxtData; #endif #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE && OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE @@ -1034,6 +1036,7 @@ template <> inline MeshCoP::DatasetUpdater &Instance::Get(void) { return mDatase #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE template <> inline MeshCoP::BorderAgent::Manager &Instance::Get(void) { return mBorderAgentManager; } +template <> inline MeshCoP::BorderAgent::TxtData &Instance::Get(void) { return mBorderAgentTxtData; } #endif #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE && OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE diff --git a/src/core/meshcop/border_agent.cpp b/src/core/meshcop/border_agent.cpp index eebd7d67f..0e8d04af5 100644 --- a/src/core/meshcop/border_agent.cpp +++ b/src/core/meshcop/border_agent.cpp @@ -36,6 +36,7 @@ #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE #include "instance/instance.hpp" +#include "meshcop/border_agent_txt_data.hpp" namespace ot { namespace MeshCoP { @@ -46,7 +47,6 @@ RegisterLogModule("BorderAgent"); //---------------------------------------------------------------------------------------------------------------------- // `Manager` -const char Manager::kTxtDataRecordVersion[] = "1"; #if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE const char Manager::kServiceType[] = "_meshcop._udp"; const char Manager::kDefaultBaseServiceName[] = OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_BASE_NAME; @@ -476,7 +476,7 @@ void Manager::RegisterService(void) txtDataBuffer = reinterpret_cast(Heap::CAlloc(txtDataBufferSize, sizeof(uint8_t))); OT_ASSERT(txtDataBuffer != nullptr); - SuccessOrAssert(PrepareServiceTxtData(txtDataBuffer, txtDataBufferSize, txtDataLength)); + SuccessOrAssert(Get().Prepare(txtDataBuffer, txtDataBufferSize, txtDataLength)); if (mVendorTxtData.GetLength() != 0) { @@ -518,136 +518,6 @@ exit: #endif // OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE -Error Manager::PrepareServiceTxtData(ServiceTxtData &aTxtData) -{ - return PrepareServiceTxtData(aTxtData.mData, sizeof(aTxtData.mData), aTxtData.mLength); -} - -Error Manager::PrepareServiceTxtData(uint8_t *aBuffer, uint16_t aBufferSize, uint16_t &aLength) -{ - Error error = kErrorNone; - Dns::TxtDataEncoder encoder(aBuffer, aBufferSize); - MeshCoP::Dataset::Info datasetInfo; - -#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE - { - Id id; - - GetId(id); - SuccessOrExit(error = encoder.AppendEntry("id", id)); - } -#endif - SuccessOrExit(error = encoder.AppendStringEntry("rv", kTxtDataRecordVersion)); - SuccessOrExit(error = encoder.AppendBigEndianUintEntry("sb", DetermineStateBitmap())); - SuccessOrExit(error = encoder.AppendStringEntry("tv", kThreadVersionString)); - SuccessOrExit(error = encoder.AppendEntry("xa", Get().GetExtAddress())); - - if (Get().IsComplete() && - (Get().Read(datasetInfo) == kErrorNone)) - { - if (datasetInfo.IsPresent()) - { - SuccessOrExit(error = encoder.AppendEntry("xp", datasetInfo.Get())); - } - - if (datasetInfo.IsPresent()) - { - SuccessOrExit(error = encoder.AppendNameEntry("nn", datasetInfo.Get().GetAsData())); - } - } - - if (Get().IsAttached()) - { - SuccessOrExit(error = encoder.AppendBigEndianUintEntry("pt", Get().GetLeaderData().GetPartitionId())); - - if (Get().GetTimestamp().IsValid()) - { - SuccessOrExit(error = encoder.AppendEntry("at", Get().GetTimestamp())); - } - } - -#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE - if (Get().IsAttached() && Get().IsEnabled()) - { - BackboneRouter::Config bbrConfig; - - Get().GetConfig(bbrConfig); - SuccessOrExit(error = encoder.AppendEntry("sq", bbrConfig.mSequenceNumber)); - SuccessOrExit(error = encoder.AppendBigEndianUintEntry("bb", BackboneRouter::kBackboneUdpPort)); - } - - SuccessOrExit(error = - encoder.AppendNameEntry("dn", Get().GetDomainName().GetAsData())); -#endif - -#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE - { - Ip6::Prefix prefix; - BorderRouter::RoutePreference preference; - - if (Get().GetFavoredOmrPrefix(prefix, preference) == kErrorNone && - prefix.GetLength() > 0) - { - uint8_t omrData[Ip6::NetworkPrefix::kSize + 1]; - - omrData[0] = prefix.GetLength(); - memcpy(omrData + 1, prefix.GetBytes(), prefix.GetBytesSize()); - - SuccessOrExit(error = encoder.AppendEntry("omr", omrData)); - } - } -#endif - - aLength = encoder.GetLength(); - -exit: - return error; -} - -uint32_t Manager::DetermineStateBitmap(void) const -{ - uint32_t bitmap = 0; - - bitmap |= (IsRunning() ? StateBitmap::kConnectionModePskc : StateBitmap::kConnectionModeDisabled); - bitmap |= StateBitmap::kAvailabilityHigh; - - switch (Get().GetRole()) - { - case Mle::DeviceRole::kRoleDisabled: - bitmap |= (StateBitmap::kThreadIfStatusNotInitialized | StateBitmap::kThreadRoleDisabledOrDetached); - break; - case Mle::DeviceRole::kRoleDetached: - bitmap |= (StateBitmap::kThreadIfStatusInitialized | StateBitmap::kThreadRoleDisabledOrDetached); - break; - case Mle::DeviceRole::kRoleChild: - bitmap |= (StateBitmap::kThreadIfStatusActive | StateBitmap::kThreadRoleChild); - break; - case Mle::DeviceRole::kRoleRouter: - bitmap |= (StateBitmap::kThreadIfStatusActive | StateBitmap::kThreadRoleRouter); - break; - case Mle::DeviceRole::kRoleLeader: - bitmap |= (StateBitmap::kThreadIfStatusActive | StateBitmap::kThreadRoleLeader); - break; - } - -#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE - if (Get().IsAttached()) - { - bitmap |= (Get().IsEnabled() ? StateBitmap::kFlagBbrIsActive : 0); - bitmap |= (Get().IsPrimary() ? StateBitmap::kFlagBbrIsPrimary : 0); - } -#endif - -#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE - if (Get().GetState() != EphemeralKeyManager::kStateDisabled) - { - bitmap |= StateBitmap::kFlagEpskcSupported; - } -#endif - - return bitmap; -} - //---------------------------------------------------------------------------------------------------------------------- // Manager::SessionIterator diff --git a/src/core/meshcop/border_agent.hpp b/src/core/meshcop/border_agent.hpp index dc1b27bb8..d554ae968 100644 --- a/src/core/meshcop/border_agent.hpp +++ b/src/core/meshcop/border_agent.hpp @@ -120,7 +120,6 @@ public: typedef otBorderAgentCounters Counters; ///< Border Agent Counters. typedef otBorderAgentSessionInfo SessionInfo; ///< A session info. typedef otBorderAgentMeshCoPServiceChangedCallback ServiceChangedCallback; ///< Service changed callback. - typedef otBorderAgentMeshCoPServiceTxtData ServiceTxtData; ///< Service TXT data. /** * Represents an iterator for secure sessions. @@ -239,16 +238,6 @@ public: */ void SetServiceChangedCallback(ServiceChangedCallback aCallback, void *aContext); - /** - * Prepares the MeshCoP service TXT data. - * - * @param[out] aTxtData A reference to a MeshCoP Service TXT data struct to get the data. - * - * @retval kErrorNone If successfully retrieved the Border Agent MeshCoP Service TXT data. - * @retval kErrorNoBufs If the buffer in @p aTxtData doesn't have enough size. - */ - Error PrepareServiceTxtData(ServiceTxtData &aTxtData); - #if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE /** * Sets the base name to construct the service instance name used when advertising the mDNS `_meshcop._udp` service @@ -368,51 +357,6 @@ private: uint64_t mAllocationTime; }; - struct StateBitmap - { - // --- State Bitmap ConnectionMode --- - static constexpr uint8_t kOffsetConnectionMode = 0; - static constexpr uint32_t kMaskConnectionMode = 7 << kOffsetConnectionMode; - static constexpr uint32_t kConnectionModeDisabled = 0 << kOffsetConnectionMode; - static constexpr uint32_t kConnectionModePskc = 1 << kOffsetConnectionMode; - static constexpr uint32_t kConnectionModePskd = 2 << kOffsetConnectionMode; - static constexpr uint32_t kConnectionModeVendor = 3 << kOffsetConnectionMode; - static constexpr uint32_t kConnectionModeX509 = 4 << kOffsetConnectionMode; - - // --- State Bitmap ThreadIfStatus --- - static constexpr uint8_t kOffsetThreadIfStatus = 3; - static constexpr uint32_t kMaskThreadIfStatus = 3 << kOffsetThreadIfStatus; - static constexpr uint32_t kThreadIfStatusNotInitialized = 0 << kOffsetThreadIfStatus; - static constexpr uint32_t kThreadIfStatusInitialized = 1 << kOffsetThreadIfStatus; - static constexpr uint32_t kThreadIfStatusActive = 2 << kOffsetThreadIfStatus; - - // --- State Bitmap Availability --- - static constexpr uint8_t kOffsetAvailability = 5; - static constexpr uint32_t kMaskAvailability = 3 << kOffsetAvailability; - static constexpr uint32_t kAvailabilityInfrequent = 0 << kOffsetAvailability; - static constexpr uint32_t kAvailabilityHigh = 1 << kOffsetAvailability; - - // --- State Bitmap BbrIsActive --- - static constexpr uint8_t kOffsetBbrIsActive = 7; - static constexpr uint32_t kFlagBbrIsActive = 1 << kOffsetBbrIsActive; - - // --- State Bitmap BbrIsPrimary --- - static constexpr uint8_t kOffsetBbrIsPrimary = 8; - static constexpr uint32_t kFlagBbrIsPrimary = 1 << kOffsetBbrIsPrimary; - - // --- State Bitmap ThreadRole --- - static constexpr uint8_t kOffsetThreadRole = 9; - static constexpr uint32_t kMaskThreadRole = 3 << kOffsetThreadRole; - static constexpr uint32_t kThreadRoleDisabledOrDetached = 0 << kOffsetThreadRole; - static constexpr uint32_t kThreadRoleChild = 1 << kOffsetThreadRole; - static constexpr uint32_t kThreadRoleRouter = 2 << kOffsetThreadRole; - static constexpr uint32_t kThreadRoleLeader = 3 << kOffsetThreadRole; - - // --- State Bitmap EpskcSupported --- - static constexpr uint8_t kOffsetEpskcSupported = 11; - static constexpr uint32_t kFlagEpskcSupported = 1 << kOffsetEpskcSupported; - }; - void UpdateState(void); void Start(void); void Stop(void); @@ -432,9 +376,6 @@ private: static Coap::Message::Code CoapCodeFromError(Error aError); - Error PrepareServiceTxtData(uint8_t *aBuffer, uint16_t aBufferSize, uint16_t &aLength); - uint32_t DetermineStateBitmap(void) const; - void PostServiceTask(void); void HandleServiceTask(void); #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE @@ -453,7 +394,6 @@ private: using ServiceTask = TaskletIn; - static const char kTxtDataRecordVersion[]; #if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE static const char kServiceType[]; static const char kDefaultBaseServiceName[]; diff --git a/src/core/meshcop/border_agent_txt_data.cpp b/src/core/meshcop/border_agent_txt_data.cpp new file mode 100644 index 000000000..47fb355c8 --- /dev/null +++ b/src/core/meshcop/border_agent_txt_data.cpp @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2025, 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. + */ + +/** + * @file + * This file implements generation of Border Agent TXT data. + */ + +#include "border_agent_txt_data.hpp" + +#include "instance/instance.hpp" + +namespace ot { +namespace MeshCoP { +namespace BorderAgent { + +#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE + +const char TxtData::kRecordVersion[] = "1"; + +const char TxtData::Key::kRecordVersion[] = "rv"; +const char TxtData::Key::kAgentId[] = "id"; +const char TxtData::Key::kThreadVersion[] = "tv"; +const char TxtData::Key::kStateBitmap[] = "sb"; +const char TxtData::Key::kNetworkName[] = "nn"; +const char TxtData::Key::kExtendedPanId[] = "xp"; +const char TxtData::Key::kActiveTimestamp[] = "at"; +const char TxtData::Key::kPartitionId[] = "pt"; +const char TxtData::Key::kDomainName[] = "dn"; +const char TxtData::Key::kBbrSeqNum[] = "sq"; +const char TxtData::Key::kBbrPort[] = "bb"; +const char TxtData::Key::kOmrPrefix[] = "omr"; +const char TxtData::Key::kExtAddress[] = "xa"; + +TxtData::TxtData(Instance &aInstance) + : InstanceLocator(aInstance) +{ +} + +Error TxtData::Prepare(uint8_t *aBuffer, uint16_t aBufferSize, uint16_t &aLength) +{ + Error error = kErrorNone; + Dns::TxtDataEncoder encoder(aBuffer, aBufferSize); + MeshCoP::Dataset::Info datasetInfo; + + VerifyOrExit(aBuffer != nullptr, error = kErrorNoBufs); + +#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE + { + Id id; + + Get().GetId(id); + SuccessOrExit(error = encoder.AppendEntry(Key::kAgentId, id)); + } +#endif + SuccessOrExit(error = encoder.AppendStringEntry(Key::kRecordVersion, kRecordVersion)); + SuccessOrExit(error = encoder.AppendBigEndianUintEntry(Key::kStateBitmap, StateBitmap::Determine(GetInstance()))); + SuccessOrExit(error = encoder.AppendStringEntry(Key::kThreadVersion, kThreadVersionString)); + SuccessOrExit(error = encoder.AppendEntry(Key::kExtAddress, Get().GetExtAddress())); + + if (Get().IsComplete() && + (Get().Read(datasetInfo) == kErrorNone)) + { + if (datasetInfo.IsPresent()) + { + SuccessOrExit(error = encoder.AppendEntry(Key::kExtendedPanId, datasetInfo.Get())); + } + + if (datasetInfo.IsPresent()) + { + SuccessOrExit(error = encoder.AppendNameEntry(Key::kNetworkName, + datasetInfo.Get().GetAsData())); + } + } + + if (Get().IsAttached()) + { + SuccessOrExit(error = encoder.AppendBigEndianUintEntry(Key::kPartitionId, + Get().GetLeaderData().GetPartitionId())); + + if (Get().GetTimestamp().IsValid()) + { + SuccessOrExit(error = encoder.AppendEntry(Key::kActiveTimestamp, + Get().GetTimestamp())); + } + } + +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + if (Get().IsAttached() && Get().IsEnabled()) + { + BackboneRouter::Config bbrConfig; + + Get().GetConfig(bbrConfig); + SuccessOrExit(error = encoder.AppendEntry(Key::kBbrSeqNum, bbrConfig.mSequenceNumber)); + SuccessOrExit(error = encoder.AppendBigEndianUintEntry(Key::kBbrPort, BackboneRouter::kBackboneUdpPort)); + } + + SuccessOrExit(error = encoder.AppendNameEntry(Key::kDomainName, + Get().GetDomainName().GetAsData())); +#endif + +#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE + { + Ip6::Prefix prefix; + BorderRouter::RoutePreference preference; + + if (Get().GetFavoredOmrPrefix(prefix, preference) == kErrorNone && + prefix.GetLength() > 0) + { + uint8_t omrData[Ip6::NetworkPrefix::kSize + 1]; + + omrData[0] = prefix.GetLength(); + memcpy(omrData + 1, prefix.GetBytes(), prefix.GetBytesSize()); + + SuccessOrExit(error = encoder.AppendEntry(Key::kOmrPrefix, omrData)); + } + } +#endif + + aLength = encoder.GetLength(); + +exit: + return error; +} + +Error TxtData::Prepare(ServiceTxtData &aTxtData) +{ + return Prepare(aTxtData.mData, sizeof(aTxtData.mData), aTxtData.mLength); +} + +uint32_t TxtData::StateBitmap::Determine(Instance &aInstance) +{ + uint32_t bitmap = 0; + + bitmap |= (aInstance.Get().IsRunning() ? kConnectionModePskc : kConnectionModeDisabled); + bitmap |= kAvailabilityHigh; + + switch (aInstance.Get().GetRole()) + { + case Mle::DeviceRole::kRoleDisabled: + bitmap |= (kThreadIfStatusNotInitialized | kThreadRoleDisabledOrDetached); + break; + case Mle::DeviceRole::kRoleDetached: + bitmap |= (kThreadIfStatusInitialized | kThreadRoleDisabledOrDetached); + break; + case Mle::DeviceRole::kRoleChild: + bitmap |= (kThreadIfStatusActive | kThreadRoleChild); + break; + case Mle::DeviceRole::kRoleRouter: + bitmap |= (kThreadIfStatusActive | kThreadRoleRouter); + break; + case Mle::DeviceRole::kRoleLeader: + bitmap |= (kThreadIfStatusActive | kThreadRoleLeader); + break; + } + +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + if (aInstance.Get().IsAttached()) + { + bitmap |= (aInstance.Get().IsEnabled() ? kFlagBbrIsActive : 0); + bitmap |= (aInstance.Get().IsPrimary() ? kFlagBbrIsPrimary : 0); + } +#endif + +#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE + if (aInstance.Get().GetState() != EphemeralKeyManager::kStateDisabled) + { + bitmap |= kFlagEpskcSupported; + } +#endif + + return bitmap; +} + +#endif // OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE + +} // namespace BorderAgent +} // namespace MeshCoP +} // namespace ot diff --git a/src/core/meshcop/border_agent_txt_data.hpp b/src/core/meshcop/border_agent_txt_data.hpp new file mode 100644 index 000000000..af767704a --- /dev/null +++ b/src/core/meshcop/border_agent_txt_data.hpp @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2025, 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. + */ + +/** + * @file + * This file includes definitions for Border Agent MeshCoP service TXT data. + */ + +#ifndef BORDER_AGENT_TXT_DATA_HPP_ +#define BORDER_AGENT_TXT_DATA_HPP_ + +#include "openthread-core-config.h" + +#include + +#include "common/error.hpp" +#include "common/locator.hpp" + +namespace ot { +namespace MeshCoP { +namespace BorderAgent { + +#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE + +class TxtData : public InstanceLocator +{ +public: + typedef otBorderAgentMeshCoPServiceTxtData ServiceTxtData; ///< Service TXT Data. + + /** + * Initializes the `TxtData` object. + * + * @param[in] aInstance A reference to the OpenThread instance. + */ + TxtData(Instance &aInstance); + + /** + * Prepares the MeshCoP service TXT data. + * + * @param[out] aBuffer A pointer to a buffer to store the TXT data. + * @param[in] aBufferSize The size of @p aBuffer. + * @param[out] aLength On exit, the length of the prepared TXT data. + * + * @retval kErrorNone Successfully prepared the TXT data. + * @retval kErrorNoBufs The @p aBufferSize is too small. + */ + Error Prepare(uint8_t *aBuffer, uint16_t aBufferSize, uint16_t &aLength); + + /** + * Prepares the MeshCoP service TXT data. + * + * @param[out] aTxtData A reference to a MeshCoP Service TXT data struct to get the data. + * + * @retval kErrorNone Successfully prepared the TXT data. + * @retval kErrorNoBufs The buffer in @p aTxtData is too small. + */ + Error Prepare(ServiceTxtData &aTxtData); + +private: + static const char kRecordVersion[]; + + struct Key + { + static const char kRecordVersion[]; + static const char kAgentId[]; + static const char kThreadVersion[]; + static const char kStateBitmap[]; + static const char kNetworkName[]; + static const char kExtendedPanId[]; + static const char kActiveTimestamp[]; + static const char kPartitionId[]; + static const char kDomainName[]; + static const char kBbrSeqNum[]; + static const char kBbrPort[]; + static const char kOmrPrefix[]; + static const char kExtAddress[]; + }; + + struct StateBitmap + { + static uint32_t Determine(Instance &aInstance); + + // --- State Bitmap ConnectionMode --- + static constexpr uint8_t kOffsetConnectionMode = 0; + static constexpr uint32_t kMaskConnectionMode = 7 << kOffsetConnectionMode; + static constexpr uint32_t kConnectionModeDisabled = 0 << kOffsetConnectionMode; + static constexpr uint32_t kConnectionModePskc = 1 << kOffsetConnectionMode; + static constexpr uint32_t kConnectionModePskd = 2 << kOffsetConnectionMode; + static constexpr uint32_t kConnectionModeVendor = 3 << kOffsetConnectionMode; + static constexpr uint32_t kConnectionModeX509 = 4 << kOffsetConnectionMode; + + // --- State Bitmap ThreadIfStatus --- + static constexpr uint8_t kOffsetThreadIfStatus = 3; + static constexpr uint32_t kMaskThreadIfStatus = 3 << kOffsetThreadIfStatus; + static constexpr uint32_t kThreadIfStatusNotInitialized = 0 << kOffsetThreadIfStatus; + static constexpr uint32_t kThreadIfStatusInitialized = 1 << kOffsetThreadIfStatus; + static constexpr uint32_t kThreadIfStatusActive = 2 << kOffsetThreadIfStatus; + + // --- State Bitmap Availability --- + static constexpr uint8_t kOffsetAvailability = 5; + static constexpr uint32_t kMaskAvailability = 3 << kOffsetAvailability; + static constexpr uint32_t kAvailabilityInfrequent = 0 << kOffsetAvailability; + static constexpr uint32_t kAvailabilityHigh = 1 << kOffsetAvailability; + + // --- State Bitmap BbrIsActive --- + static constexpr uint8_t kOffsetBbrIsActive = 7; + static constexpr uint32_t kFlagBbrIsActive = 1 << kOffsetBbrIsActive; + + // --- State Bitmap BbrIsPrimary --- + static constexpr uint8_t kOffsetBbrIsPrimary = 8; + static constexpr uint32_t kFlagBbrIsPrimary = 1 << kOffsetBbrIsPrimary; + + // --- State Bitmap ThreadRole --- + static constexpr uint8_t kOffsetThreadRole = 9; + static constexpr uint32_t kMaskThreadRole = 3 << kOffsetThreadRole; + static constexpr uint32_t kThreadRoleDisabledOrDetached = 0 << kOffsetThreadRole; + static constexpr uint32_t kThreadRoleChild = 1 << kOffsetThreadRole; + static constexpr uint32_t kThreadRoleRouter = 2 << kOffsetThreadRole; + static constexpr uint32_t kThreadRoleLeader = 3 << kOffsetThreadRole; + + // --- State Bitmap EpskcSupported --- + static constexpr uint8_t kOffsetEpskcSupported = 11; + static constexpr uint32_t kFlagEpskcSupported = 1 << kOffsetEpskcSupported; + }; +}; + +#endif // OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE + +} // namespace BorderAgent +} // namespace MeshCoP +} // namespace ot + +#endif // BORDER_AGENT_TXT_DATA_HPP_ diff --git a/tests/nexus/test_border_agent.cpp b/tests/nexus/test_border_agent.cpp index 2e8dfda7f..bf4bacdab 100644 --- a/tests/nexus/test_border_agent.cpp +++ b/tests/nexus/test_border_agent.cpp @@ -38,6 +38,7 @@ namespace Nexus { using ActiveDatasetManager = MeshCoP::ActiveDatasetManager; using Manager = MeshCoP::BorderAgent::Manager; +using BaTxtData = MeshCoP::BorderAgent::TxtData; using EphemeralKeyManager = MeshCoP::BorderAgent::EphemeralKeyManager; using EpskcEvent = HistoryTracker::EpskcEvent; using Iterator = HistoryTracker::Iterator; @@ -1323,10 +1324,10 @@ void HandleServiceChanged(void *aContext) // Callback used in `TestBorderAgentTx void ReadAndValidateMeshCoPTxtData(Node &aNode) { - Manager::ServiceTxtData serviceTxtData; - TxtData txtData; + BaTxtData::ServiceTxtData serviceTxtData; + TxtData txtData; - SuccessOrQuit(aNode.Get().PrepareServiceTxtData(serviceTxtData)); + SuccessOrQuit(aNode.Get().Prepare(serviceTxtData)); txtData.Init(serviceTxtData.mData, serviceTxtData.mLength); ValidateMeshCoPTxtData(txtData, aNode);