From ad1cfb749e5b07db25d583cc4a57ae36832bc279 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Tue, 21 Oct 2025 18:40:18 -0700 Subject: [PATCH] [border-agent] introduce Border Agent TXT Data Parser (#12009) This commit introduces a new feature to parse the MeshCoP service TXT data from a Border Agent. The new API `otBorderAgentTxtDataParse()` allows parsing the raw TXT data into a structured `otBorderAgentTxtDataInfo` object. This can be used by applications to inspect the capabilities and status of a discovered Border Agent. Config `OPENTHREAD_CONFIG_BORDER_AGENT_TXT_DATA_PARSER_ENABLE` controls this new feature. The existing test for the Border Agent is updated to validate the new parser and its output. --- doc/ot_api_doc.h | 177 ++++++++--------- etc/cmake/options.cmake | 1 + include/openthread/BUILD.gn | 1 + include/openthread/border_agent_txt_data.h | 183 ++++++++++++++++++ include/openthread/instance.h | 2 +- src/core/BUILD.gn | 1 + src/core/CMakeLists.txt | 1 + src/core/api/border_agent_txt_data_api.cpp | 51 +++++ src/core/config/border_agent.h | 9 + src/core/meshcop/border_agent_txt_data.cpp | 192 ++++++++++++++++++- src/core/meshcop/border_agent_txt_data.hpp | 185 ++++++++++++++---- tests/nexus/openthread-core-nexus-config.h | 1 + tests/nexus/test_border_agent.cpp | 69 ++++++- tests/toranj/openthread-core-toranj-config.h | 2 + 14 files changed, 729 insertions(+), 146 deletions(-) create mode 100644 include/openthread/border_agent_txt_data.h create mode 100644 src/core/api/border_agent_txt_data_api.cpp diff --git a/doc/ot_api_doc.h b/doc/ot_api_doc.h index 8d134db3f..68cfc6c5d 100644 --- a/doc/ot_api_doc.h +++ b/doc/ot_api_doc.h @@ -33,142 +33,143 @@ */ /** - * @defgroup api API + * @defgroup api API * @brief * This module includes the application programming interface to the OpenThread stack. * * @{ * - * @defgroup api-error Error + * @defgroup api-error Error * - * @defgroup api-execution Execution + * @defgroup api-execution Execution * * @{ * - * @defgroup api-instance Instance - * @defgroup api-tasklets Tasklets + * @defgroup api-instance Instance + * @defgroup api-tasklets Tasklets * * @} * - * @defgroup api-net IPv6 Networking + * @defgroup api-net IPv6 Networking * @{ * - * @defgroup api-ble-secure BLE Secure - * @defgroup api-dns DNS - * @defgroup api-dnssd-server DNS-SD Server - * @defgroup api-icmp6 ICMPv6 - * @defgroup api-ip6 IPv6 - * @defgroup api-mdns Multicast DNS - * @defgroup api-nat64 NAT64 - * @defgroup api-srp SRP - * @defgroup api-ping-sender Ping Sender + * @defgroup api-ble-secure BLE Secure + * @defgroup api-dns DNS + * @defgroup api-dnssd-server DNS-SD Server + * @defgroup api-icmp6 ICMPv6 + * @defgroup api-ip6 IPv6 + * @defgroup api-mdns Multicast DNS + * @defgroup api-nat64 NAT64 + * @defgroup api-srp SRP + * @defgroup api-ping-sender Ping Sender * - * @defgroup api-tcp-group TCP + * @defgroup api-tcp-group TCP * * @{ * - * @defgroup api-tcp TCP - * @defgroup api-tcp-ext TCP Abstractions + * @defgroup api-tcp TCP + * @defgroup api-tcp-ext TCP Abstractions * * @} * - * @defgroup api-udp-group UDP + * @defgroup api-udp-group UDP * * @{ * - * @defgroup api-udp UDP - * @defgroup api-udp-forward UDP Forward + * @defgroup api-udp UDP + * @defgroup api-udp-forward UDP Forward * * @} * * @} * - * @defgroup api-link Link + * @defgroup api-link Link * * @{ * - * @defgroup api-link-link Link - * @defgroup api-link-metrics Link Metrics - * @defgroup api-link-raw Raw Link + * @defgroup api-link-link Link + * @defgroup api-link-metrics Link Metrics + * @defgroup api-link-raw Raw Link * * @} * - * @defgroup api-message Message + * @defgroup api-message Message * - * @defgroup api-multi-radio Multi Radio Link - * @defgroup api-trel TREL - Thread Stack + * @defgroup api-multi-radio Multi Radio Link + * @defgroup api-trel TREL - Thread Stack * - * @defgroup api-thread Thread + * @defgroup api-thread Thread * * @{ * - * @defgroup api-backbone-router Backbone Router - * @defgroup api-border-agent Border Agent - * @defgroup api-border-agent-tracker Border Agent Tracker - * @defgroup api-border-router Border Router - * @defgroup api-border-routing Border Routing Manager - * @defgroup api-commissioner Commissioner - * @defgroup api-thread-general General + * @defgroup api-backbone-router Backbone Router + * @defgroup api-border-agent Border Agent + * @defgroup api-border-agent-tracker Border Agent Tracker + * @defgroup api-border-agent-txt-data Border Agent TXT Data Parser + * @defgroup api-border-router Border Router + * @defgroup api-border-routing Border Routing Manager + * @defgroup api-commissioner Commissioner + * @defgroup api-thread-general General * @brief This module includes functions for all Thread roles. - * @defgroup api-joiner Joiner - * @defgroup api-operational-dataset Operational Dataset + * @defgroup api-joiner Joiner + * @defgroup api-operational-dataset Operational Dataset * @brief Includes functions for the Operational Dataset API. - * @defgroup api-thread-router Router/Leader + * @defgroup api-thread-router Router/Leader * @brief This module includes functions for Thread Routers and Leaders. - * @defgroup api-server Server + * @defgroup api-server Server * * @} * - * @defgroup api-addons Add-Ons + * @defgroup api-addons Add-Ons * * @{ * - * @defgroup api-channel-manager Channel Manager - * @defgroup api-channel-monitor Channel Monitoring - * @defgroup api-child-supervision Child Supervision - * @defgroup api-coap-group CoAP + * @defgroup api-channel-manager Channel Manager + * @defgroup api-channel-monitor Channel Monitoring + * @defgroup api-child-supervision Child Supervision + * @defgroup api-coap-group CoAP * * @{ * - * @defgroup api-coap CoAP - * @defgroup api-coap-secure CoAP Secure + * @defgroup api-coap CoAP + * @defgroup api-coap-secure CoAP Secure * * @} * - * @defgroup api-cli Command Line Interface - * @defgroup api-crypto Crypto - Thread Stack - * @defgroup api-factory-diagnostics Factory Diagnostics - Thread Stack - * @defgroup api-heap Heap - * @defgroup api-history-tracker History Tracker - * @defgroup api-jam-detection Jam Detection - * @defgroup api-logging Logging - Thread Stack - * @defgroup api-mesh-diag Mesh Diagnostics - * @defgroup api-ncp Network Co-Processor - * @defgroup api-network-time Network Time Synchronization - * @defgroup api-radio Radio Statistics - * @defgroup api-random-group Random Number Generator + * @defgroup api-cli Command Line Interface + * @defgroup api-crypto Crypto - Thread Stack + * @defgroup api-factory-diagnostics Factory Diagnostics - Thread Stack + * @defgroup api-heap Heap + * @defgroup api-history-tracker History Tracker + * @defgroup api-jam-detection Jam Detection + * @defgroup api-logging Logging - Thread Stack + * @defgroup api-mesh-diag Mesh Diagnostics + * @defgroup api-ncp Network Co-Processor + * @defgroup api-network-time Network Time Synchronization + * @defgroup api-radio Radio Statistics + * @defgroup api-random-group Random Number Generator * * @{ * - * @defgroup api-random-crypto RNG Cryptographic - * @defgroup api-random-non-crypto RNG Non-cryptographic + * @defgroup api-random-crypto RNG Cryptographic + * @defgroup api-random-non-crypto RNG Non-cryptographic * * @} * - * @defgroup api-sntp SNTP - * @defgroup api-verhoeff-checksum Verhoeff Checksum + * @defgroup api-sntp SNTP + * @defgroup api-verhoeff-checksum Verhoeff Checksum * * @} * - * @defgroup api-provisional Provisional + * @defgroup api-provisional Provisional * @brief * This module includes the OpenThread provisional APIs. These APIs are not stable and users should use them with * caution. * * @{ * - * @defgroup api-provisional-link Link - * @defgroup api-provisional-p2p Peer-to-Peer + * @defgroup api-provisional-link Link + * @defgroup api-provisional-p2p Peer-to-Peer * * @} * @@ -176,33 +177,33 @@ */ /** - * @defgroup platform Platform Abstraction + * @defgroup platform Platform Abstraction * @brief * This module includes the platform abstraction used by the OpenThread stack. * * @{ * - * @defgroup plat-alarm Alarm - * @defgroup plat-ble BLE - * @defgroup plat-crypto Crypto - Platform - * @defgroup plat-dns DNS - Platform - * @defgroup plat-dns-sd DNS-SD (mDNS) - * @defgroup plat-entropy Entropy - * @defgroup plat-factory-diagnostics Factory Diagnostics - Platform - * @defgroup plat-infra-if Infrastructure Interface - * @defgroup plat-logging Logging - Platform - * @defgroup plat-memory Memory - * @defgroup plat-messagepool Message Pool - * @defgroup plat-misc Miscellaneous - * @defgroup plat-mdns Multicast DNS - * @defgroup plat-multipan Multipan - * @defgroup plat-otns Network Simulator - * @defgroup plat-radio Radio - * @defgroup plat-settings Settings - * @defgroup plat-spi-slave SPI Slave - * @defgroup plat-time Time Service - * @defgroup plat-toolchain Toolchain - * @defgroup plat-trel TREL - Platform + * @defgroup plat-alarm Alarm + * @defgroup plat-ble BLE + * @defgroup plat-crypto Crypto - Platform + * @defgroup plat-dns DNS - Platform + * @defgroup plat-dns-sd DNS-SD (mDNS) + * @defgroup plat-entropy Entropy + * @defgroup plat-factory-diagnostics Factory Diagnostics - Platform + * @defgroup plat-infra-if Infrastructure Interface + * @defgroup plat-logging Logging - Platform + * @defgroup plat-memory Memory + * @defgroup plat-messagepool Message Pool + * @defgroup plat-misc Miscellaneous + * @defgroup plat-mdns Multicast DNS + * @defgroup plat-multipan Multipan + * @defgroup plat-otns Network Simulator + * @defgroup plat-radio Radio + * @defgroup plat-settings Settings + * @defgroup plat-spi-slave SPI Slave + * @defgroup plat-time Time Service + * @defgroup plat-toolchain Toolchain + * @defgroup plat-trel TREL - Platform * * @} */ diff --git a/etc/cmake/options.cmake b/etc/cmake/options.cmake index 0658a1698..bcc7d30ad 100644 --- a/etc/cmake/options.cmake +++ b/etc/cmake/options.cmake @@ -178,6 +178,7 @@ ot_option(OT_BORDER_AGENT_EPSKC OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENA ot_option(OT_BORDER_AGENT_ID OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE "create and save border agent ID") ot_option(OT_BORDER_AGENT_MESHCOP_SERVICE OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE "border agent meshcop service") ot_option(OT_BORDER_AGENT_TRACKER OPENTHREAD_CONFIG_BORDER_AGENT_TRACKER_ENABLE "border agent tracker") +ot_option(OT_BORDER_AGENT_TXT_DATA_PARSER OPENTHREAD_CONFIG_BORDER_AGENT_TXT_DATA_PARSER_ENABLE "border agent TXT data parser") 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_DHCP6_PD OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE "dhcpv6 pd support in border routing") diff --git a/include/openthread/BUILD.gn b/include/openthread/BUILD.gn index e8c96acce..fb79c13b3 100644 --- a/include/openthread/BUILD.gn +++ b/include/openthread/BUILD.gn @@ -44,6 +44,7 @@ source_set("openthread") { "ble_secure.h", "border_agent.h", "border_agent_tracker.h", + "border_agent_txt_data.h", "border_router.h", "border_routing.h", "channel_manager.h", diff --git a/include/openthread/border_agent_txt_data.h b/include/openthread/border_agent_txt_data.h new file mode 100644 index 000000000..a0766c4ca --- /dev/null +++ b/include/openthread/border_agent_txt_data.h @@ -0,0 +1,183 @@ +/* + * 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 + * @brief + * This file defines the OpenThread Border Agent TXT data parsing APIs. + */ + +#ifndef OPENTHREAD_BORDER_AGENT_TXT_DATA_H_ +#define OPENTHREAD_BORDER_AGENT_TXT_DATA_H_ + +#include +#include + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup api-border-agent-txt-data + * + * @brief + * This module includes APIs for parsing the MeshCoP service TXT data of a Border Agent. + * + * @{ + */ + +#define OT_BORDER_AGENT_RECORD_VERSION_SIZE (8) ///< Max size of Record Version string in `otBorderAgentTxtDataInfo`. +#define OT_BORDER_AGENT_THREAD_VERSION_SIZE (16) ///< Max size of Thread Version string in `otBorderAgentTxtDataInfo`. +#define OT_BORDER_AGENT_VENDOR_NAME_SIZE (32) ///< Max size of Vendor Name string in `otBorderAgentTxtDataInfo`. +#define OT_BORDER_AGENT_MODEL_NAME_SIZE (32) ///< Max size of Model Name string in `otBorderAgentTxtDataInfo`. + +/** + * Represents the Connection Mode in a Border Agent State Bitmap. + */ +typedef enum otBorderAgentConnMode +{ + OT_BORDER_AGENT_CONN_MODE_DISABLED = 0, ///< DTLS connection not allowed. + OT_BORDER_AGENT_CONN_MODE_PSKC = 1, ///< DTLS connection with PSKc. + OT_BORDER_AGENT_CONN_MODE_PSKD = 2, ///< DTLS connection with PSKd. + OT_BORDER_AGENT_CONN_MODE_VENDOR = 3, ///< DTLS with vendor defined credential. + OT_BORDER_AGENT_CONN_MODE_X509 = 4, ///< DTLS with X.509 certificate. +} otBorderAgentConnMode; + +/** + * Represents the Thread Interface Status in a Border Agent State Bitmap. + */ +typedef enum otBorderAgentThreadIfState +{ + OT_BORDER_AGENT_THREAD_IF_NOT_INITIALIZED = 0, ///< Thread interface is not initialized. + OT_BORDER_AGENT_THREAD_IF_INITIALIZED = 1, ///< Thread interface is initialized but is not yet active. + OT_BORDER_AGENT_THREAD_IF_ACTIVE = 2, ///< Thread interface is initialized and active. +} otBorderAgentThreadIfState; + +/** + * Represents the Availability Status in a Border Agent State Bitmap. + */ +typedef enum otBorderAgentAvailability +{ + OT_BORDER_AGENT_AVAILABILITY_INFREQUENT = 0, ///< Infrequent availability. + OT_BORDER_AGENT_AVAILABILITY_HIGH = 1, ///< High availability. +} otBorderAgentAvailability; + +/** + * Represents the Thread Role in a Border Agent State Bitmap. + */ +typedef enum otBorderAgentThreadRole +{ + OT_BORDER_AGENT_THREAD_ROLE_DISABLED_OR_DETACHED = 0, ///< Detached or disabled. + OT_BORDER_AGENT_THREAD_ROLE_CHILD = 1, ///< End device (child). + OT_BORDER_AGENT_THREAD_ROLE_ROUTER = 2, ///< Router. + OT_BORDER_AGENT_THREAD_ROLE_LEADER = 3, ///< Leader. +} otBorderAgentThreadRole; + +/** + * Represents Border Agent State Bitmap information. + */ +typedef struct otBorderAgentStateBitmap +{ + otBorderAgentConnMode mConnMode; ///< Connection Mode. + otBorderAgentThreadIfState mThreadIfState; ///< Thread Interface Status. + otBorderAgentAvailability mAvailability; ///< Availability + otBorderAgentThreadRole mThreadRole; ///< Thread Role. + bool mBbrIsActive; ///< Backbone Router function is active. + bool mBbrIsPrimary; ///< Device is the Primary Backbone Router. + bool mEpskcSupported; ///< ePSKc Mode is supported. +} otBorderAgentStateBitmap; + +/** + * Represents parsed Border Agent TXT data. + * + * The boolean flags indicate whether a specific field is present in the parsed TXT data. + */ +typedef struct otBorderAgentTxtDataInfo +{ + bool mHasRecordVersion : 1; ///< Indicates whether Record Version is present. + bool mHasAgentId : 1; ///< Indicates whether Agent ID is present. + bool mHasThreadVersion : 1; ///< Indicates whether Thread Version is present. + bool mHasStateBitmap : 1; ///< Indicates whether State Bitmap is present. + bool mHasNetworkName : 1; ///< Indicates whether Network Name is present. + bool mHasExtendedPanId : 1; ///< Indicates whether Extended PAN ID is present. + bool mHasActiveTimestamp : 1; ///< Indicates whether Active Timestamp is present. + bool mHasPartitionId : 1; ///< Indicates whether Partition ID is present. + bool mHasDomainName : 1; ///< Indicates whether Domain Name is present. + bool mHasBbrSeqNum : 1; ///< Indicates whether BBR Sequence Number is present. + bool mHasBbrPort : 1; ///< Indicates whether BBR Port is present. + bool mHasOmrPrefix : 1; ///< Indicates whether OMR Prefix is present. + bool mHasExtAddress : 1; ///< Indicates whether Extended Address is present. + bool mHasVendorName : 1; ///< Indicates whether Vendor Name is present. + bool mHasModelName : 1; ///< Indicates whether Model Name is present. + char mRecordVersion[OT_BORDER_AGENT_RECORD_VERSION_SIZE]; ///< Record Version string. + otBorderAgentId mAgentId; ///< Agent ID. + char mThreadVersion[OT_BORDER_AGENT_THREAD_VERSION_SIZE]; ///< Thread Version string. + otBorderAgentStateBitmap mStateBitmap; ///< State Bitmap. + otNetworkName mNetworkName; ///< Network Name. + otExtendedPanId mExtendedPanId; ///< Extended PAN ID. + otTimestamp mActiveTimestamp; ///< Active Timestamp. + uint32_t mPartitionId; ///< Partition ID. + otNetworkName mDomainName; ///< Domain Name. + uint8_t mBbrSeqNum; ///< BBR Sequence Number. + uint16_t mBbrPort; ///< BBR Port. + otIp6Prefix mOmrPrefix; ///< OMR Prefix. + otExtAddress mExtAddress; ///< Extended Address. + char mVendorName[OT_BORDER_AGENT_VENDOR_NAME_SIZE]; ///< Vendor Name string. + char mModelName[OT_BORDER_AGENT_MODEL_NAME_SIZE]; ///< Model Name string. +} otBorderAgentTxtDataInfo; + +/** + * Parses a Border Agent's MeshCoP service TXT data. + * + * Requires `OPENTHREAD_CONFIG_BORDER_AGENT_TXT_DATA_PARSER_ENABLE`. + * + * @param[in] aTxtData A pointer to the buffer containing the TXT data. + * @param[in] aTxtDataLength The length of the TXT data in bytes. + * @param[out] aInfo A pointer to a structure to output the parsed information. + * + * @retval OT_ERROR_NONE Successfully parsed the TXT data. + * @retval OT_ERROR_PARSE Failed to parse the TXT data. + */ +otError otBorderAgentTxtDataParse(const uint8_t *aTxtData, uint16_t aTxtDataLength, otBorderAgentTxtDataInfo *aInfo); + +/** + * @} + * + */ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // OPENTHREAD_BORDER_AGENT_TXT_DATA_H_ diff --git a/include/openthread/instance.h b/include/openthread/instance.h index a89d1b324..684909dcd 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -52,7 +52,7 @@ extern "C" { * * @note This number versions both OpenThread platform and user APIs. */ -#define OPENTHREAD_API_VERSION (542) +#define OPENTHREAD_API_VERSION (543) /** * @addtogroup api-instance diff --git a/src/core/BUILD.gn b/src/core/BUILD.gn index b613d51c0..66f8bf02b 100644 --- a/src/core/BUILD.gn +++ b/src/core/BUILD.gn @@ -310,6 +310,7 @@ openthread_core_files = [ "api/ble_secure_api.cpp", "api/border_agent_api.cpp", "api/border_agent_tracker_api.cpp", + "api/border_agent_txt_data_api.cpp", "api/border_router_api.cpp", "api/border_routing_api.cpp", "api/channel_manager_api.cpp", diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 19910ad69..6b083a60f 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -36,6 +36,7 @@ set(COMMON_SOURCES api/ble_secure_api.cpp api/border_agent_api.cpp api/border_agent_tracker_api.cpp + api/border_agent_txt_data_api.cpp api/border_router_api.cpp api/border_routing_api.cpp api/channel_manager_api.cpp diff --git a/src/core/api/border_agent_txt_data_api.cpp b/src/core/api/border_agent_txt_data_api.cpp new file mode 100644 index 000000000..1e1392773 --- /dev/null +++ b/src/core/api/border_agent_txt_data_api.cpp @@ -0,0 +1,51 @@ +/* + * 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 the OpenThread Border Agent TXT data parsing APIs. + */ + +#include "openthread-core-config.h" + +#if OPENTHREAD_CONFIG_BORDER_AGENT_TXT_DATA_PARSER_ENABLE + +#include + +#include "instance/instance.hpp" + +using namespace ot; + +otError otBorderAgentTxtDataParse(const uint8_t *aTxtData, uint16_t aTxtDataLength, otBorderAgentTxtDataInfo *aInfo) +{ + AssertPointerIsNotNull(aTxtData); + + return AsCoreType(aInfo).ParseFrom(aTxtData, aTxtDataLength); +} + +#endif // OPENTHREAD_CONFIG_BORDER_AGENT_TXT_DATA_PARSER_ENABLE diff --git a/src/core/config/border_agent.h b/src/core/config/border_agent.h index 556837156..e5532a191 100644 --- a/src/core/config/border_agent.h +++ b/src/core/config/border_agent.h @@ -134,6 +134,15 @@ #define OPENTHREAD_CONFIG_BORDER_AGENT_TRACKER_ENABLE 0 #endif +/** + * @def OPENTHREAD_CONFIG_BORDER_AGENT_TXT_DATA_PARSER_ENABLE + * + * Define to 1 to enable the Border Agent TXT Data Parser feature. + */ +#ifndef OPENTHREAD_CONFIG_BORDER_AGENT_TXT_DATA_PARSER_ENABLE +#define OPENTHREAD_CONFIG_BORDER_AGENT_TXT_DATA_PARSER_ENABLE 0 +#endif + /** * @} */ diff --git a/src/core/meshcop/border_agent_txt_data.cpp b/src/core/meshcop/border_agent_txt_data.cpp index 47fb355c8..8a9047bff 100644 --- a/src/core/meshcop/border_agent_txt_data.cpp +++ b/src/core/meshcop/border_agent_txt_data.cpp @@ -33,13 +33,14 @@ #include "border_agent_txt_data.hpp" +#include "common/string.hpp" #include "instance/instance.hpp" namespace ot { namespace MeshCoP { namespace BorderAgent { -#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE +#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE || OPENTHREAD_CONFIG_BORDER_AGENT_TXT_DATA_PARSER_ENABLE const char TxtData::kRecordVersion[] = "1"; @@ -56,12 +57,18 @@ const char TxtData::Key::kBbrSeqNum[] = "sq"; const char TxtData::Key::kBbrPort[] = "bb"; const char TxtData::Key::kOmrPrefix[] = "omr"; const char TxtData::Key::kExtAddress[] = "xa"; +#if OPENTHREAD_CONFIG_BORDER_AGENT_TXT_DATA_PARSER_ENABLE +const char TxtData::Key::kVendorName[] = "vn"; +const char TxtData::Key::kModelName[] = "mn"; +#endif TxtData::TxtData(Instance &aInstance) : InstanceLocator(aInstance) { } +#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE + Error TxtData::Prepare(uint8_t *aBuffer, uint16_t aBufferSize, uint16_t &aLength) { Error error = kErrorNone; @@ -157,25 +164,25 @@ uint32_t TxtData::StateBitmap::Determine(Instance &aInstance) { uint32_t bitmap = 0; - bitmap |= (aInstance.Get().IsRunning() ? kConnectionModePskc : kConnectionModeDisabled); - bitmap |= kAvailabilityHigh; + bitmap |= ((aInstance.Get().IsRunning() ? kConnModePskc : kConnModeDisabled) << kOffsetConnMode); + bitmap |= (kAvailabilityHigh << kOffsetAvailability); switch (aInstance.Get().GetRole()) { case Mle::DeviceRole::kRoleDisabled: - bitmap |= (kThreadIfStatusNotInitialized | kThreadRoleDisabledOrDetached); + bitmap |= (kThreadIfNotInit << kOffsetIfState) | (kRoleDisabledDetached << kOffsetRole); break; case Mle::DeviceRole::kRoleDetached: - bitmap |= (kThreadIfStatusInitialized | kThreadRoleDisabledOrDetached); + bitmap |= (kThreadIfInit << kOffsetIfState) | (kRoleDisabledDetached << kOffsetRole); break; case Mle::DeviceRole::kRoleChild: - bitmap |= (kThreadIfStatusActive | kThreadRoleChild); + bitmap |= (kThreadIfActive << kOffsetIfState) | (kRoleChild << kOffsetRole); break; case Mle::DeviceRole::kRoleRouter: - bitmap |= (kThreadIfStatusActive | kThreadRoleRouter); + bitmap |= (kThreadIfActive << kOffsetIfState) | (kRoleRouter << kOffsetRole); break; case Mle::DeviceRole::kRoleLeader: - bitmap |= (kThreadIfStatusActive | kThreadRoleLeader); + bitmap |= (kThreadIfActive << kOffsetIfState) | (kRoleLeader << kOffsetRole); break; } @@ -199,6 +206,175 @@ uint32_t TxtData::StateBitmap::Determine(Instance &aInstance) #endif // OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE +#if OPENTHREAD_CONFIG_BORDER_AGENT_TXT_DATA_PARSER_ENABLE + +Error TxtData::Info::ParseFrom(const uint8_t *aTxtData, uint16_t aTxtDataLength) +{ + Error error; + Dns::TxtEntry entry; + Dns::TxtEntry::Iterator iterator; + + Clear(); + + iterator.Init(aTxtData, aTxtDataLength); + + while ((error = iterator.GetNextEntry(entry)) == kErrorNone) + { + ProcessTxtEntry(entry); + } + + if (error == kErrorNotFound) + { + error = kErrorNone; + } + + return error; +} + +void TxtData::Info::ProcessTxtEntry(const Dns::TxtEntry &aEntry) +{ + if (aEntry.mKey == nullptr) + { + // If the TXT data happens to have entries with key longer + // than `kMaxIterKeyLength`, `mKey` would be `nullptr` and full + // entry would be placed in `mValue`. We skip over such + // entries. + } + else if (StringMatch(aEntry.mKey, Key::kRecordVersion)) + { + ReadStringValue(aEntry, mRecordVersion); + mHasRecordVersion = true; + } + else if (StringMatch(aEntry.mKey, Key::kAgentId)) + { + mHasAgentId = ReadValue(aEntry, mAgentId); + } + else if (StringMatch(aEntry.mKey, Key::kThreadVersion)) + { + ReadStringValue(aEntry, mThreadVersion); + mHasThreadVersion = true; + } + else if (StringMatch(aEntry.mKey, Key::kStateBitmap)) + { + uint32_t bitmap; + + if (ReadBigEndianUintValue(aEntry, bitmap)) + { + StateBitmap::Parse(bitmap, mStateBitmap); + mHasStateBitmap = true; + } + } + else if (StringMatch(aEntry.mKey, Key::kNetworkName)) + { + ReadStringValue(aEntry, mNetworkName.m8); + mHasNetworkName = true; + } + else if (StringMatch(aEntry.mKey, Key::kExtendedPanId)) + { + mHasExtendedPanId = ReadValue(aEntry, mExtendedPanId); + } + else if (StringMatch(aEntry.mKey, Key::kActiveTimestamp)) + { + Timestamp timestamp; + + if (ReadValue(aEntry, timestamp)) + { + timestamp.ConvertTo(mActiveTimestamp); + mHasActiveTimestamp = true; + } + } + else if (StringMatch(aEntry.mKey, Key::kPartitionId)) + { + mHasPartitionId = ReadBigEndianUintValue(aEntry, mPartitionId); + } + else if (StringMatch(aEntry.mKey, Key::kDomainName)) + { + ReadStringValue(aEntry, mDomainName.m8); + mHasDomainName = true; + } + else if (StringMatch(aEntry.mKey, Key::kBbrSeqNum)) + { + mHasBbrSeqNum = ReadBigEndianUintValue(aEntry, mBbrSeqNum); + } + else if (StringMatch(aEntry.mKey, Key::kBbrPort)) + { + mHasBbrPort = ReadBigEndianUintValue(aEntry, mBbrPort); + } + else if (StringMatch(aEntry.mKey, Key::kOmrPrefix)) + { + mHasOmrPrefix = ReadOmrPrefix(aEntry, AsCoreType(&mOmrPrefix)); + } + else if (StringMatch(aEntry.mKey, Key::kExtAddress)) + { + mHasExtAddress = ReadValue(aEntry, mExtAddress); + } + else if (StringMatch(aEntry.mKey, Key::kVendorName)) + { + ReadStringValue(aEntry, mVendorName); + mHasVendorName = true; + } + else if (StringMatch(aEntry.mKey, Key::kModelName)) + { + ReadStringValue(aEntry, mModelName); + mHasModelName = true; + } +} + +bool TxtData::Info::ReadValue(const Dns::TxtEntry &aEntry, void *aBuffer, uint16_t aSize) +{ + bool didRead = false; + + VerifyOrExit(aEntry.mValueLength >= aSize); + memcpy(aBuffer, aEntry.mValue, aSize); + didRead = true; + +exit: + return didRead; +} + +void TxtData::Info::ReadStringValue(const Dns::TxtEntry &aEntry, char *aString, uint16_t aStringSize) +{ + uint16_t copyLength = Min(aStringSize - 1, aEntry.mValueLength); + + memcpy(aString, aEntry.mValue, copyLength); + aString[copyLength] = kNullChar; +} + +bool TxtData::Info::ReadOmrPrefix(const Dns::TxtEntry &aEntry, Ip6::Prefix &aPrefix) +{ + bool didRead = false; + uint8_t length; + + VerifyOrExit(aEntry.mValueLength >= sizeof(uint8_t)); + length = aEntry.mValue[0]; + + VerifyOrExit(length <= Ip6::Prefix::kMaxLength); + VerifyOrExit(aEntry.mValueLength >= sizeof(uint8_t) + Ip6::Prefix::SizeForLength(length)); + + aPrefix.Set(&aEntry.mValue[1], length); + didRead = true; + +exit: + return didRead; +} + +void TxtData::StateBitmap::Parse(uint32_t aBitmap, Info &aInfo) +{ + ClearAllBytes(aInfo); + + aInfo.mConnMode = static_cast((aBitmap & kMaskConnMode) >> kOffsetConnMode); + aInfo.mThreadIfState = static_cast((aBitmap & kMaskIfState) >> kOffsetIfState); + aInfo.mAvailability = static_cast((aBitmap & kMaskAvailability) >> kOffsetAvailability); + aInfo.mThreadRole = static_cast((aBitmap & kMaskRole) >> kOffsetRole); + aInfo.mBbrIsActive = aBitmap & kFlagBbrIsActive; + aInfo.mBbrIsPrimary = aBitmap & kFlagBbrIsPrimary; + aInfo.mEpskcSupported = aBitmap & kFlagEpskcSupported; +} + +#endif // OPENTHREAD_CONFIG_BORDER_AGENT_TXT_DATA_PARSER_ENABLE + +#endif // OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE || OPENTHREAD_CONFIG_BORDER_AGENT_TXT_DATA_PARSER_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 index af767704a..76e63303f 100644 --- a/src/core/meshcop/border_agent_txt_data.hpp +++ b/src/core/meshcop/border_agent_txt_data.hpp @@ -37,20 +37,48 @@ #include "openthread-core-config.h" #include +#include +#include "common/as_core_type.hpp" +#include "common/clearable.hpp" +#include "common/encoding.hpp" #include "common/error.hpp" #include "common/locator.hpp" +#include "common/type_traits.hpp" +#include "net/dns_types.hpp" +#include "net/ip6_address.hpp" namespace ot { namespace MeshCoP { namespace BorderAgent { -#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE +#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE || OPENTHREAD_CONFIG_BORDER_AGENT_TXT_DATA_PARSER_ENABLE class TxtData : public InstanceLocator { public: - typedef otBorderAgentMeshCoPServiceTxtData ServiceTxtData; ///< Service TXT Data. + typedef otBorderAgentConnMode ConnMode; ///< Connection Mode in a Border Agent State Bitmap. + typedef otBorderAgentThreadIfState IfState; ///< Thread Interface State in a Border Agent State Bitmap. + typedef otBorderAgentAvailability Availability; ///< Availability Status in a Border Agent State Bitmap. + typedef otBorderAgentThreadRole Role; ///< Thread Role in a Border Agent State Bitmap. + + static constexpr ConnMode kConnModeDisabled = OT_BORDER_AGENT_CONN_MODE_DISABLED; ///< Not allowed. + static constexpr ConnMode kConnModePskc = OT_BORDER_AGENT_CONN_MODE_PSKC; ///< DTLS with PSKc. + static constexpr ConnMode kConnModePskd = OT_BORDER_AGENT_CONN_MODE_PSKD; ///< DTLS with PSKd. + static constexpr ConnMode kConnModeVendor = OT_BORDER_AGENT_CONN_MODE_VENDOR; ///< Vendor defined. + static constexpr ConnMode kConnModeX509 = OT_BORDER_AGENT_CONN_MODE_X509; ///< DTLS X.509 cert. + + static constexpr IfState kThreadIfNotInit = OT_BORDER_AGENT_THREAD_IF_NOT_INITIALIZED; ///< Not init. + static constexpr IfState kThreadIfInit = OT_BORDER_AGENT_THREAD_IF_INITIALIZED; ///< Init but not active. + static constexpr IfState kThreadIfActive = OT_BORDER_AGENT_THREAD_IF_ACTIVE; ///< Init and active. + + static constexpr Availability kAvailabilityInfreq = OT_BORDER_AGENT_AVAILABILITY_INFREQUENT; ///< Infrequent. + static constexpr Availability kAvailabilityHigh = OT_BORDER_AGENT_AVAILABILITY_HIGH; ///< High. + + static constexpr Role kRoleDisabledDetached = OT_BORDER_AGENT_THREAD_ROLE_DISABLED_OR_DETACHED; ///< Detach. + static constexpr Role kRoleChild = OT_BORDER_AGENT_THREAD_ROLE_CHILD; ///< Child. + static constexpr Role kRoleRouter = OT_BORDER_AGENT_THREAD_ROLE_ROUTER; ///< Router. + static constexpr Role kRoleLeader = OT_BORDER_AGENT_THREAD_ROLE_LEADER; ///< Leader. /** * Initializes the `TxtData` object. @@ -59,6 +87,68 @@ public: */ TxtData(Instance &aInstance); +#if OPENTHREAD_CONFIG_BORDER_AGENT_TXT_DATA_PARSER_ENABLE + + /** + * Represents information parsed from a Border Agent TXT Data. + */ + class Info : public otBorderAgentTxtDataInfo, public Clearable + { + public: + /** + * Parses a Border Agent's MeshCoP service TXT data. + * + * @param[in] aTxtData A pointer to the buffer containing the TXT data. + * @param[in] aTxtDataLength The length of the TXT data in bytes. + * + * @retval kErrorNone Successfully parsed the TXT data. + * @retval kErrorParse Failed to parse the TXT data. + */ + Error ParseFrom(const uint8_t *aTxtData, uint16_t aTxtDataLength); + + private: + void ProcessTxtEntry(const Dns::TxtEntry &aEntry); + + static bool ReadValue(const Dns::TxtEntry &aEntry, void *aBuffer, uint16_t aSize); + static void ReadStringValue(const Dns::TxtEntry &aEntry, char *aString, uint16_t aStringSize); + static bool ReadOmrPrefix(const Dns::TxtEntry &aEntry, Ip6::Prefix &aPrefix); + + template bool ReadValue(const Dns::TxtEntry &aEntry, ObjectType &aObject) + { + static_assert(!TypeTraits::IsPointer::kValue, "ObjectType must not be a pointer"); + + return ReadValue(aEntry, &aObject, sizeof(aObject)); + } + + template + static void ReadStringValue(const Dns::TxtEntry &aEntry, char (&aString)[kStringSize]) + { + ReadStringValue(aEntry, aString, kStringSize); + } + + template + static bool ReadBigEndianUintValue(const Dns::TxtEntry &aEntry, UintType &aUintValue) + { + static_assert(TypeTraits::IsUint::kValue, "UintType must be a 8, 16, 32, or 64 bit uint"); + + bool didRead = false; + + if (aEntry.mValueLength >= sizeof(UintType)) + { + aUintValue = BigEndian::Read(aEntry.mValue); + didRead = true; + } + + return didRead; + } + }; + +#endif // OPENTHREAD_CONFIG_BORDER_AGENT_TXT_DATA_PARSER_ENABLE + +#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE + + typedef otBorderAgentMeshCoPServiceTxtData ServiceTxtData; ///< Service TXT Data. + /** * Prepares the MeshCoP service TXT data. * @@ -81,6 +171,8 @@ public: */ Error Prepare(ServiceTxtData &aTxtData); +#endif // OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE + private: static const char kRecordVersion[]; @@ -99,60 +191,69 @@ private: static const char kBbrPort[]; static const char kOmrPrefix[]; static const char kExtAddress[]; +#if OPENTHREAD_CONFIG_BORDER_AGENT_TXT_DATA_PARSER_ENABLE + static const char kVendorName[]; + static const char kModelName[]; +#endif }; struct StateBitmap { - static uint32_t Determine(Instance &aInstance); + static constexpr uint8_t kOffsetConnMode = 0; + static constexpr uint8_t kOffsetIfState = 3; + static constexpr uint8_t kOffsetAvailability = 5; + static constexpr uint8_t kOffsetBbrIsActive = 7; + static constexpr uint8_t kOffsetBbrIsPrimary = 8; + static constexpr uint8_t kOffsetRole = 9; + static constexpr uint8_t kOffsetEpskcSupported = 11; - // --- 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 kMaskConnMode = 7 << kOffsetConnMode; + static constexpr uint32_t kMaskIfState = 3 << kOffsetIfState; + static constexpr uint32_t kMaskAvailability = 3 << kOffsetAvailability; + static constexpr uint32_t kFlagBbrIsActive = 1 << kOffsetBbrIsActive; static constexpr uint32_t kFlagBbrIsPrimary = 1 << kOffsetBbrIsPrimary; + static constexpr uint32_t kMaskRole = 3 << kOffsetRole; + static constexpr uint32_t kFlagEpskcSupported = 1 << kOffsetEpskcSupported; - // --- 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; + static_assert(kConnModeDisabled == 0, "kConnModeDisabled is incorrect"); + static_assert(kConnModePskc == 1, "kConnModePskc is incorrect"); + static_assert(kConnModePskd == 2, "kConnModePskd is incorrect"); + static_assert(kConnModeVendor == 3, "kConnModeVendor is incorrect"); + static_assert(kConnModeX509 == 4, "kConnModeX509 is incorrect"); - // --- State Bitmap EpskcSupported --- - static constexpr uint8_t kOffsetEpskcSupported = 11; - static constexpr uint32_t kFlagEpskcSupported = 1 << kOffsetEpskcSupported; + static_assert(kThreadIfNotInit == 0, "kThreadIfNotInit is incorrect"); + static_assert(kThreadIfInit == 1, "kThreadIfInit is incorrect"); + static_assert(kThreadIfActive == 2, "kThreadIfActive is incorrect"); + + static_assert(kAvailabilityInfreq == 0, "kAvailabilityInfreq is incorrect"); + static_assert(kAvailabilityHigh == 1, "kAvailabilityHigh is incorrect"); + + static_assert(kRoleDisabledDetached == 0, "kRoleDisabledDetached is incorrect"); + static_assert(kRoleChild == 1, "kRoleChild is incorrect"); + static_assert(kRoleRouter == 2, "kRoleRouter is incorrect"); + static_assert(kRoleLeader == 3, "kRoleLeader is incorrect"); + +#if OPENTHREAD_CONFIG_BORDER_AGENT_TXT_DATA_PARSER_ENABLE + typedef otBorderAgentStateBitmap Info; + + static void Parse(uint32_t aBitmap, Info &aInfo); +#endif + +#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE + static uint32_t Determine(Instance &aInstance); +#endif }; }; -#endif // OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE +#endif // OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE || OPENTHREAD_CONFIG_BORDER_AGENT_TXT_DATA_PARSER_ENABLE } // namespace BorderAgent } // namespace MeshCoP + +#if OPENTHREAD_CONFIG_BORDER_AGENT_TXT_DATA_PARSER_ENABLE +DefineCoreType(otBorderAgentTxtDataInfo, MeshCoP::BorderAgent::TxtData::Info); +#endif + } // namespace ot #endif // BORDER_AGENT_TXT_DATA_HPP_ diff --git a/tests/nexus/openthread-core-nexus-config.h b/tests/nexus/openthread-core-nexus-config.h index fd0d98506..75a8682f9 100644 --- a/tests/nexus/openthread-core-nexus-config.h +++ b/tests/nexus/openthread-core-nexus-config.h @@ -47,6 +47,7 @@ #define OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE 1 #define OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE 1 #define OPENTHREAD_CONFIG_BORDER_AGENT_TRACKER_ENABLE 1 +#define OPENTHREAD_CONFIG_BORDER_AGENT_TXT_DATA_PARSER_ENABLE 1 #define OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE 1 #define OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE 1 #define OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_CLIENT_ENABLE 0 diff --git a/tests/nexus/test_border_agent.cpp b/tests/nexus/test_border_agent.cpp index bf4bacdab..5b02f2f8d 100644 --- a/tests/nexus/test_border_agent.cpp +++ b/tests/nexus/test_border_agent.cpp @@ -1242,61 +1242,114 @@ void ValidateMeshCoPTxtData(TxtData &aTxtData, Node &aNode) static constexpr uint32_t kFlagEpskcSupported = 1 << 11; MeshCoP::BorderAgent::Id id; + BaTxtData::Info info; + const Mac::ExtAddress &extAddress = aNode.Get().GetExtAddress(); uint32_t stateBitmap; uint32_t threadIfStatus; uint32_t threadRole; + bool baIsRunning; aTxtData.ValidateFormat(); aTxtData.LogAllTxtEntries(); + SuccessOrQuit(info.ParseFrom(aTxtData.mData, aTxtData.mLength)); + aNode.Get().GetId(id); aTxtData.ValidateKey("id", id); + VerifyOrQuit(info.mHasAgentId); + VerifyOrQuit(id == AsCoreType(&info.mAgentId)); + aTxtData.ValidateKey("rv", "1"); + VerifyOrQuit(info.mHasRecordVersion); + VerifyOrQuit(StringMatch(info.mRecordVersion, "1")); + aTxtData.ValidateKey("tv", kThreadVersionString); - aTxtData.ValidateKey("xa", aNode.Get().GetExtAddress()); + VerifyOrQuit(info.mHasThreadVersion); + VerifyOrQuit(StringMatch(info.mThreadVersion, kThreadVersionString)); + + aTxtData.ValidateKey("xa", extAddress); + VerifyOrQuit(info.mHasExtAddress); + VerifyOrQuit(AsCoreType(&info.mExtAddress) == extAddress); if (aNode.Get().IsComplete()) { - aTxtData.ValidateKey("nn", aNode.Get().GetNetworkName().GetAsCString()); - aTxtData.ValidateKey("xp", aNode.Get().GetExtPanId()); + const char *networkName = aNode.Get().GetNetworkName().GetAsCString(); + const MeshCoP::ExtendedPanId &extPanId = aNode.Get().GetExtPanId(); + + aTxtData.ValidateKey("nn", networkName); + VerifyOrQuit(info.mHasNetworkName); + VerifyOrQuit(StringMatch(info.mNetworkName.m8, networkName)); + + aTxtData.ValidateKey("xp", extPanId); + VerifyOrQuit(info.mHasExtendedPanId); + VerifyOrQuit(AsCoreType(&info.mExtendedPanId) == extPanId); } if (aNode.Get().IsAttached()) { - aTxtData.ValidateKey("pt", BigEndian::HostSwap32(aNode.Get().GetLeaderData().GetPartitionId())); - aTxtData.ValidateKey("at", aNode.Get().GetTimestamp()); + uint32_t partitionId = aNode.Get().GetLeaderData().GetPartitionId(); + const MeshCoP::Timestamp ×tamp = aNode.Get().GetTimestamp(); + MeshCoP::Timestamp::Info timestampInfo; + + aTxtData.ValidateKey("pt", BigEndian::HostSwap32(partitionId)); + VerifyOrQuit(info.mHasPartitionId); + VerifyOrQuit(info.mPartitionId == partitionId); + + aTxtData.ValidateKey("at", timestamp); + timestamp.ConvertTo(timestampInfo); + VerifyOrQuit(info.mHasActiveTimestamp); + VerifyOrQuit(info.mActiveTimestamp.mSeconds == timestampInfo.mSeconds); + VerifyOrQuit(info.mActiveTimestamp.mTicks == timestampInfo.mTicks); + VerifyOrQuit(info.mActiveTimestamp.mAuthoritative == timestampInfo.mAuthoritative); } else { VerifyOrQuit(!aTxtData.ContainsKey("pt")); + VerifyOrQuit(!info.mHasPartitionId); + VerifyOrQuit(!aTxtData.ContainsKey("at")); + VerifyOrQuit(!info.mHasActiveTimestamp); } stateBitmap = aTxtData.ReadUint32Key("sb"); + VerifyOrQuit(info.mHasStateBitmap); + + baIsRunning = aNode.Get().IsRunning(); + VerifyOrQuit((stateBitmap & kMaskConnectionMode) == (baIsRunning ? kConnectionModePskc : kConnectionModeDisabled)); + VerifyOrQuit(info.mStateBitmap.mConnMode == + (baIsRunning ? BaTxtData::kConnModePskc : BaTxtData::kConnModeDisabled)); - VerifyOrQuit((stateBitmap & kMaskConnectionMode) == aNode.Get().IsRunning() ? kConnectionModePskc - : kConnectionModeDisabled); switch (aNode.Get().GetRole()) { case Mle::DeviceRole::kRoleDisabled: threadIfStatus = kThreadIfStatusNotInitialized; threadRole = kThreadRoleDisabledOrDetached; + VerifyOrQuit(info.mStateBitmap.mThreadIfState == BaTxtData::kThreadIfNotInit); + VerifyOrQuit(info.mStateBitmap.mThreadRole == BaTxtData::kRoleDisabledDetached); break; case Mle::DeviceRole::kRoleDetached: threadIfStatus = kThreadIfStatusInitialized; threadRole = kThreadRoleDisabledOrDetached; + VerifyOrQuit(info.mStateBitmap.mThreadIfState == BaTxtData::kThreadIfInit); + VerifyOrQuit(info.mStateBitmap.mThreadRole == BaTxtData::kRoleDisabledDetached); break; case Mle::DeviceRole::kRoleChild: threadIfStatus = kThreadIfStatusActive; threadRole = kThreadRoleChild; + VerifyOrQuit(info.mStateBitmap.mThreadIfState == BaTxtData::kThreadIfActive); + VerifyOrQuit(info.mStateBitmap.mThreadRole == BaTxtData::kRoleChild); break; case Mle::DeviceRole::kRoleRouter: threadIfStatus = kThreadIfStatusActive; threadRole = kThreadRoleRouter; + VerifyOrQuit(info.mStateBitmap.mThreadIfState == BaTxtData::kThreadIfActive); + VerifyOrQuit(info.mStateBitmap.mThreadRole == BaTxtData::kRoleRouter); break; case Mle::DeviceRole::kRoleLeader: threadIfStatus = kThreadIfStatusActive; threadRole = kThreadRoleLeader; + VerifyOrQuit(info.mStateBitmap.mThreadIfState == BaTxtData::kThreadIfActive); + VerifyOrQuit(info.mStateBitmap.mThreadRole == BaTxtData::kRoleLeader); break; } @@ -1306,10 +1359,12 @@ void ValidateMeshCoPTxtData(TxtData &aTxtData, Node &aNode) if (aNode.Get().GetState() != EphemeralKeyManager::kStateDisabled) { VerifyOrQuit(stateBitmap & kFlagEpskcSupported); + VerifyOrQuit(info.mStateBitmap.mEpskcSupported); } else { VerifyOrQuit(!(stateBitmap & kFlagEpskcSupported)); + VerifyOrQuit(!info.mStateBitmap.mEpskcSupported); } } diff --git a/tests/toranj/openthread-core-toranj-config.h b/tests/toranj/openthread-core-toranj-config.h index 99ad01a6b..0a8a74210 100644 --- a/tests/toranj/openthread-core-toranj-config.h +++ b/tests/toranj/openthread-core-toranj-config.h @@ -84,6 +84,8 @@ #define OPENTHREAD_CONFIG_BORDER_AGENT_TRACKER_ENABLE 1 +#define OPENTHREAD_CONFIG_BORDER_AGENT_TXT_DATA_PARSER_ENABLE 1 + #define OPENTHREAD_CONFIG_DIAG_ENABLE 1 #define OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE 1