From eaa2779047c3bf781874954e82c716239460c5f7 Mon Sep 17 00:00:00 2001 From: Kangping Date: Sat, 6 May 2023 01:48:57 +0800 Subject: [PATCH] [settings] define new Settings key for Border Router ID (#8971) This commit adds new Border Agent functionality that generates and saves 16 bytes ID in settings. The ID can be published in the MeshCoP mDNS service and used by the client to identify a Border Router device. A new `otBorderAgentGetId()` API is defined and the ID is generated the first time this API is called. --- etc/cmake/options.cmake | 1 + etc/gn/openthread.gni | 3 ++ include/openthread/border_agent.h | 24 +++++++++++ include/openthread/instance.h | 2 +- include/openthread/platform/settings.h | 1 + src/core/api/border_agent_api.cpp | 7 ++++ src/core/common/settings.cpp | 34 +++++++++++++++- src/core/common/settings.hpp | 56 +++++++++++++++++++++++++- src/core/config/border_agent.h | 10 +++++ src/core/meshcop/border_agent.cpp | 31 ++++++++++++++ src/core/meshcop/border_agent.hpp | 27 +++++++++++++ 11 files changed, 192 insertions(+), 4 deletions(-) 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);