diff --git a/etc/cmake/options.cmake b/etc/cmake/options.cmake index 7853d6679..8e11a53ec 100644 --- a/etc/cmake/options.cmake +++ b/etc/cmake/options.cmake @@ -85,6 +85,7 @@ ot_option(OT_BACKBONE_ROUTER OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE "backbone ot_option(OT_BACKBONE_ROUTER_DUA_NDPROXYING OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE "BBR DUA ND Proxy") ot_option(OT_BACKBONE_ROUTER_MULTICAST_ROUTING OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE "BBR MR") ot_option(OT_BORDER_AGENT OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE "border agent") +ot_option(OT_BORDER_AGENT_ID OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE "create and save border agent ID") ot_option(OT_BORDER_ROUTER OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE "border router") ot_option(OT_BORDER_ROUTING OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE "border routing") ot_option(OT_BORDER_ROUTING_COUNTERS OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE "border routing counters") diff --git a/etc/gn/openthread.gni b/etc/gn/openthread.gni index 9bf75fb0f..9bbb543d2 100644 --- a/etc/gn/openthread.gni +++ b/etc/gn/openthread.gni @@ -84,6 +84,9 @@ if (openthread_enable_core_config_args) { # Enable border agent support openthread_config_border_agent_enable = false + # Enable border agent ID + openthread_config_border_agent_id_enable = false + # Enable border router support openthread_config_border_router_enable = false diff --git a/include/openthread/border_agent.h b/include/openthread/border_agent.h index 83babfa14..e412f6d8e 100644 --- a/include/openthread/border_agent.h +++ b/include/openthread/border_agent.h @@ -51,6 +51,12 @@ extern "C" { * */ +/** + * The length of Border Agent/Router ID in bytes. + * + */ +#define OT_BORDER_AGENT_ID_LENGTH (16) + /** * This enumeration defines the Border Agent state. * @@ -82,6 +88,24 @@ otBorderAgentState otBorderAgentGetState(otInstance *aInstance); */ uint16_t otBorderAgentGetUdpPort(otInstance *aInstance); +/** + * Gets the randomly generated Border Agent ID. + * + * The ID is saved in persistent storage and survives reboots. The typical use case of the ID is to + * be published in the MeshCoP mDNS service as the `id` TXT value for the client to identify this + * Border Router/Agent device. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[out] aId A pointer to buffer to receive the ID. + * @param[inout] aLength Specifies the length of `aId` when used as input and receives the length + * actual ID data copied to `aId` when used as output. + * + * @retval OT_ERROR_INVALID_ARGS If value of `aLength` if smaller than `OT_BORDER_AGENT_ID_LENGTH`. + * @retval OT_ERROR_NONE If successfully retrieved the Border Agent ID. + * + */ +otError otBorderAgentGetId(otInstance *aInstance, uint8_t *aId, uint16_t *aLength); + /** * @} * diff --git a/include/openthread/instance.h b/include/openthread/instance.h index ec252aa40..755dc3be2 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (317) +#define OPENTHREAD_API_VERSION (318) /** * @addtogroup api-instance diff --git a/include/openthread/platform/settings.h b/include/openthread/platform/settings.h index 0b2f03576..a9ca05de4 100644 --- a/include/openthread/platform/settings.h +++ b/include/openthread/platform/settings.h @@ -73,6 +73,7 @@ enum OT_SETTINGS_KEY_SRP_SERVER_INFO = 0x000d, ///< The SRP server info (UDP port). OT_SETTINGS_KEY_BR_ULA_PREFIX = 0x000f, ///< BR ULA prefix. OT_SETTINGS_KEY_BR_ON_LINK_PREFIXES = 0x0010, ///< BR local on-link prefixes. + OT_SETTINGS_KEY_BORDER_AGENT_ID = 0x0011, ///< Unique Border Agent/Router ID. // Deprecated and reserved key values: // diff --git a/src/core/api/border_agent_api.cpp b/src/core/api/border_agent_api.cpp index a6ccea1a9..70f39baef 100644 --- a/src/core/api/border_agent_api.cpp +++ b/src/core/api/border_agent_api.cpp @@ -42,6 +42,13 @@ using namespace ot; +#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE +otError otBorderAgentGetId(otInstance *aInstance, uint8_t *aId, uint16_t *aLength) +{ + return AsCoreType(aInstance).Get().GetId(aId, *aLength); +} +#endif + otBorderAgentState otBorderAgentGetState(otInstance *aInstance) { return MapEnum(AsCoreType(aInstance).Get().GetState()); diff --git a/src/core/common/settings.cpp b/src/core/common/settings.cpp index d1a072a91..18f17d887 100644 --- a/src/core/common/settings.cpp +++ b/src/core/common/settings.cpp @@ -106,6 +106,28 @@ void SettingsBase::SrpServerInfo::Log(Action aAction) const } #endif +#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE +Error SettingsBase::BorderAgentId::SetId(const uint8_t *aId, uint16_t aLength) +{ + Error error = kErrorNone; + + VerifyOrExit(aLength == sizeof(mId), error = kErrorInvalidArgs); + memcpy(mId, aId, aLength); + +exit: + return error; +} + +void SettingsBase::BorderAgentId::Log(Action aAction) const +{ + char buffer[sizeof(BorderAgentId) * 2 + 1]; + StringWriter sw(buffer, sizeof(buffer)); + + sw.AppendHexBytes(GetId(), sizeof(BorderAgentId)); + LogInfo("%s BorderAgentId {id:%s}", ActionToString(aAction), buffer); +} +#endif // OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE + #endif // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) @@ -157,7 +179,8 @@ const char *SettingsBase::KeyToString(Key aKey) "SrpServerInfo", // (13) kKeySrpServerInfo "", // (14) Removed (previously NAT64 prefix) "BrUlaPrefix", // (15) kKeyBrUlaPrefix - "BrOnLinkPrefixes" // (16) kKeyBrOnLinkPrefixes + "BrOnLinkPrefixes", // (16) kKeyBrOnLinkPrefixes + "BorderAgentId" // (17) kKeyBorderAgentId }; static_assert(1 == kKeyActiveDataset, "kKeyActiveDataset value is incorrect"); @@ -172,8 +195,9 @@ const char *SettingsBase::KeyToString(Key aKey) static_assert(13 == kKeySrpServerInfo, "kKeySrpServerInfo value is incorrect"); static_assert(15 == kKeyBrUlaPrefix, "kKeyBrUlaPrefix value is incorrect"); static_assert(16 == kKeyBrOnLinkPrefixes, "kKeyBrOnLinkPrefixes is incorrect"); + static_assert(17 == kKeyBorderAgentId, "kKeyBorderAgentId is incorrect"); - static_assert(kLastKey == kKeyBrOnLinkPrefixes, "kLastKey is not valid"); + static_assert(kLastKey == kKeyBorderAgentId, "kLastKey is not valid"); OT_ASSERT(aKey <= kLastKey); @@ -518,6 +542,12 @@ void Settings::Log(Action aAction, Error aError, Key aKey, const void *aValue) break; #endif +#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE + case kKeyBorderAgentId: + reinterpret_cast(aValue)->Log(aAction); + break; +#endif + default: // For any other keys, we do not want to include the value // in the log, so even if it is given we set `aValue` to diff --git a/src/core/common/settings.hpp b/src/core/common/settings.hpp index 10e14876f..7b7362613 100644 --- a/src/core/common/settings.hpp +++ b/src/core/common/settings.hpp @@ -47,6 +47,7 @@ #include "common/settings_driver.hpp" #include "crypto/ecdsa.hpp" #include "mac/mac_types.hpp" +#include "meshcop/border_agent.hpp" #include "meshcop/dataset.hpp" #include "net/ip6_address.hpp" #include "thread/version.hpp" @@ -120,9 +121,10 @@ public: kKeySrpServerInfo = OT_SETTINGS_KEY_SRP_SERVER_INFO, kKeyBrUlaPrefix = OT_SETTINGS_KEY_BR_ULA_PREFIX, kKeyBrOnLinkPrefixes = OT_SETTINGS_KEY_BR_ON_LINK_PREFIXES, + kKeyBorderAgentId = OT_SETTINGS_KEY_BORDER_AGENT_ID, }; - static constexpr Key kLastKey = kKeyBrOnLinkPrefixes; ///< The last (numerically) enumerator value in `Key`. + static constexpr Key kLastKey = kKeyBorderAgentId; ///< The last (numerically) enumerator value in `Key`. static_assert(static_cast(kLastKey) < static_cast(OT_SETTINGS_KEY_VENDOR_RESERVED_MIN), "Core settings keys overlap with vendor reserved keys"); @@ -765,6 +767,58 @@ public: } OT_TOOL_PACKED_END; #endif // OPENTHREAD_CONFIG_SRP_SERVER_ENABLE && OPENTHREAD_CONFIG_SRP_SERVER_PORT_SWITCH_ENABLE +#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE + /** + * This structure represents the Border Agent ID. + * + */ + OT_TOOL_PACKED_BEGIN + class BorderAgentId : private Clearable + { + friend class Settings; + friend class Clearable; + + public: + static constexpr Key kKey = kKeyBorderAgentId; ///< The associated key. + + /** + * This method initializes the `BorderAgentId` object. + * + */ + void Init(void) { Clear(); } + + /** + * This method returns the Border Agent ID. + * + * @returns The Border Agent ID. + * + */ + const uint8_t *GetId(void) const { return mId; } + + /** + * This method returns the Border Agent ID. + * + * @returns The Border Agent ID. + * + */ + uint8_t *GetId(void) { return mId; } + + /** + * This method sets the Border Agent ID. + * + * @retval kErrorInvalidArgs If `aLength` doesn't equal to `OT_BORDER_AGENT_ID_LENGTH`. + * @retval kErrorNone If success. + * + */ + Error SetId(const uint8_t *aId, uint16_t aLength); + + private: + void Log(Action aAction) const; + + uint8_t mId[MeshCoP::BorderAgent::kIdLength]; + } OT_TOOL_PACKED_END; +#endif // OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE + protected: explicit SettingsBase(Instance &aInstance) : InstanceLocator(aInstance) diff --git a/src/core/config/border_agent.h b/src/core/config/border_agent.h index 39d7fe7f8..7e0abc19b 100644 --- a/src/core/config/border_agent.h +++ b/src/core/config/border_agent.h @@ -55,4 +55,14 @@ #define OPENTHREAD_CONFIG_BORDER_AGENT_UDP_PORT 0 #endif +/** + * @def OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE + * + * Define ro 1 to enable Border Agent ID support. + * + */ +#ifndef OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE +#define OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE 0 +#endif + #endif // CONFIG_BORDER_AGENT_H_ diff --git a/src/core/meshcop/border_agent.cpp b/src/core/meshcop/border_agent.cpp index dc066484a..fb3a061d4 100644 --- a/src/core/meshcop/border_agent.cpp +++ b/src/core/meshcop/border_agent.cpp @@ -225,10 +225,41 @@ BorderAgent::BorderAgent(Instance &aInstance) , mTimer(aInstance) , mState(kStateStopped) , mUdpProxyPort(0) +#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE + , mIdInitialized(false) +#endif { mCommissionerAloc.InitAsThreadOriginRealmLocalScope(); } +#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE +Error BorderAgent::GetId(uint8_t *aId, uint16_t &aLength) +{ + Error error = kErrorNone; + + static_assert(sizeof(mId) == kIdLength, "Invalid Border Agent ID size"); + + VerifyOrExit(aLength >= sizeof(mId), error = kErrorInvalidArgs); + VerifyOrExit(!mIdInitialized, error = kErrorNone); + + if (Get().Read(mId) != kErrorNone) + { + Random::NonCrypto::FillBuffer(mId.GetId(), sizeof(mId)); + SuccessOrExit(error = Get().Save(mId)); + } + + mIdInitialized = true; + +exit: + if (error == kErrorNone) + { + memcpy(aId, mId.GetId(), sizeof(mId)); + aLength = static_cast(sizeof(mId)); + } + return error; +} +#endif // OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE + void BorderAgent::HandleNotifierEvents(Events aEvents) { VerifyOrExit(aEvents.ContainsAny(kEventThreadRoleChanged | kEventCommissionerStateChanged)); diff --git a/src/core/meshcop/border_agent.hpp b/src/core/meshcop/border_agent.hpp index 2b33d54fa..26025c986 100644 --- a/src/core/meshcop/border_agent.hpp +++ b/src/core/meshcop/border_agent.hpp @@ -59,6 +59,10 @@ class BorderAgent : public InstanceLocator, private NonCopyable friend class Tmf::SecureAgent; public: +#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE + static constexpr uint8_t kIdLength = OT_BORDER_AGENT_ID_LENGTH; +#endif + /** * This enumeration defines the Border Agent state. * @@ -78,6 +82,25 @@ public: */ explicit BorderAgent(Instance &aInstance); +#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE + /** + * Gets the randomly generated Border Agent ID. + * + * The ID is saved in persistent storage and survives reboots. The typical use case of the ID is to + * be published in the MeshCoP mDNS service as the `id` TXT value for the client to identify this + * Border Router/Agent device. + * + * @param[out] aId A pointer to buffer to receive the ID. + * @param[inout] aLength Specifies the length of `aId` when used as input and receives the length + * actual ID data copied to `aId` when used as output. + * + * @retval OT_ERROR_INVALID_ARGS If value of `aLength` if smaller than `OT_BORDER_AGENT_ID_LENGTH`. + * @retval OT_ERROR_NONE If successfully retrieved the Border Agent ID. + * + */ + Error GetId(uint8_t *aId, uint16_t &aLength); +#endif + /** * This method gets the UDP port of this service. * @@ -178,6 +201,10 @@ private: TimeoutTimer mTimer; State mState; uint16_t mUdpProxyPort; +#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE + Settings::BorderAgentId mId; + bool mIdInitialized; +#endif }; DeclareTmfHandler(BorderAgent, kUriRelayRx);