From 8274fb4ec11e6439931f5ea75165a0a3bd150fbc Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Tue, 2 Dec 2025 12:43:14 -0800 Subject: [PATCH] [meshcop] introduce new public APIs for `SteeringData` (#12148) This commit introduces a set of public APIs to allow manipulation of `otSteeringData`. The new APIs are provided when the configuration `OPENTHREAD_CONFIG_MESHCOP_STEERING_DATA_API_ENABLE` is enabled. The internal `SteeringData` is also improved to enhance robustness. Methods such as `Init()`, `UpdateBloomFilter()` now return an `Error` to signal failures on invalid arguments (e.g., invalid length) instead of asserting. --- doc/ot_api_doc.h | 1 + etc/cmake/options.cmake | 1 + include/openthread/BUILD.gn | 1 + include/openthread/commissioner.h | 12 +- include/openthread/instance.h | 2 +- include/openthread/link.h | 2 +- include/openthread/steering_data.h | 186 +++++++++++++++++++ src/core/BUILD.gn | 1 + src/core/CMakeLists.txt | 1 + src/core/api/steering_data_api.cpp | 88 +++++++++ src/core/config/misc.h | 9 + src/core/meshcop/commissioner.cpp | 6 +- src/core/meshcop/meshcop.cpp | 64 +++++-- src/core/meshcop/meshcop.hpp | 46 ++++- src/core/meshcop/meshcop_tlvs.cpp | 5 +- src/core/meshcop/meshcop_tlvs.hpp | 5 +- src/core/thread/discover_scanner.cpp | 2 +- src/core/thread/mle_ftd.cpp | 4 +- src/core/thread/network_data_leader.cpp | 2 +- tests/toranj/openthread-core-toranj-config.h | 2 + tests/unit/test_meshcop.cpp | 25 ++- 21 files changed, 404 insertions(+), 61 deletions(-) create mode 100644 include/openthread/steering_data.h create mode 100644 src/core/api/steering_data_api.cpp diff --git a/doc/ot_api_doc.h b/doc/ot_api_doc.h index e09f1f165..8ca1b254e 100644 --- a/doc/ot_api_doc.h +++ b/doc/ot_api_doc.h @@ -129,6 +129,7 @@ * @defgroup api-thread-router Router/Leader * @brief This module includes functions for Thread Routers and Leaders. * @defgroup api-server Server + * @defgroup api-steering-data Steering Data * * @} * diff --git a/etc/cmake/options.cmake b/etc/cmake/options.cmake index 56a0ab11e..ec7091e43 100644 --- a/etc/cmake/options.cmake +++ b/etc/cmake/options.cmake @@ -260,6 +260,7 @@ ot_option(OT_SRP_ADV_PROXY OPENTHREAD_CONFIG_SRP_SERVER_ADVERTISING_PROXY_ENABLE ot_option(OT_SRP_CLIENT OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE "SRP client") ot_option(OT_SRP_SERVER OPENTHREAD_CONFIG_SRP_SERVER_ENABLE "SRP server") ot_option(OT_SRP_SERVER_FAST_START_MODE OPENTHREAD_CONFIG_SRP_SERVER_FAST_START_MODE_ENABLE "SRP server fast start") +ot_option(OT_STEERING_DATA OPENTHREAD_CONFIG_MESHCOP_STEERING_DATA_API_ENABLE, "MeshCoP Steering Data APIs") ot_option(OT_TCP OPENTHREAD_CONFIG_TCP_ENABLE "TCP") ot_option(OT_TIME_SYNC OPENTHREAD_CONFIG_TIME_SYNC_ENABLE "time synchronization service") ot_option(OT_TREL OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE "TREL radio link for Thread over Infrastructure feature") diff --git a/include/openthread/BUILD.gn b/include/openthread/BUILD.gn index d16aa45e0..d7ccf5215 100644 --- a/include/openthread/BUILD.gn +++ b/include/openthread/BUILD.gn @@ -124,6 +124,7 @@ source_set("openthread") { "srp_client.h", "srp_client_buffers.h", "srp_server.h", + "steering_data.h", "tasklet.h", "tcat.h", "tcp.h", diff --git a/include/openthread/commissioner.h b/include/openthread/commissioner.h index be519b928..8566d9693 100644 --- a/include/openthread/commissioner.h +++ b/include/openthread/commissioner.h @@ -42,6 +42,7 @@ #include #include #include +#include #include #ifdef __cplusplus @@ -84,17 +85,6 @@ typedef enum otCommissionerJoinerEvent #define OT_PROVISIONING_URL_MAX_SIZE 64 ///< Max size (number of chars) in Provisioning URL string (excludes null char). -#define OT_STEERING_DATA_MAX_LENGTH 16 ///< Max steering data length (bytes) - -/** - * Represents the steering data. - */ -typedef struct otSteeringData -{ - uint8_t mLength; ///< Length of steering data (bytes) - uint8_t m8[OT_STEERING_DATA_MAX_LENGTH]; ///< Byte values -} otSteeringData; - /** * Represents a Commissioning Dataset. */ diff --git a/include/openthread/instance.h b/include/openthread/instance.h index d2dbb44bf..bf8149559 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 (554) +#define OPENTHREAD_API_VERSION (555) /** * @addtogroup api-instance diff --git a/include/openthread/link.h b/include/openthread/link.h index c0a7546b0..a68e27af0 100644 --- a/include/openthread/link.h +++ b/include/openthread/link.h @@ -38,10 +38,10 @@ #include #include -#include #include #include #include +#include #include #ifdef __cplusplus diff --git a/include/openthread/steering_data.h b/include/openthread/steering_data.h new file mode 100644 index 000000000..75a0c8137 --- /dev/null +++ b/include/openthread/steering_data.h @@ -0,0 +1,186 @@ +/* + * 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 MeshCoP Steering Data APIs. + * + */ + +#ifndef OPENTHREAD_STEERING_DATA_H_ +#define OPENTHREAD_STEERING_DATA_H_ + +#include +#include + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup api-steering-data + * + * @brief + * This module includes helper functions for the MeshCoP Steering Data. + * + * @{ + * + * All the functions in this header require `OPENTHREAD_CONFIG_MESHCOP_STEERING_DATA_API_ENABLE` to be enabled. + */ + +#define OT_STEERING_DATA_MIN_LENGTH 1 ///< Min Steering Data length (bytes) + +#define OT_STEERING_DATA_MAX_LENGTH 16 ///< Max Steering Data length (bytes) + +/** + * Represents the steering data. + */ +typedef struct otSteeringData +{ + uint8_t mLength; ///< Length of Steering Data (bytes). + uint8_t m8[OT_STEERING_DATA_MAX_LENGTH]; ///< Byte values. +} otSteeringData; + +/** + * Initializes the Steering Data. + * + * @param[out] aSteeringData The Steering Data to initialize. + * @param[in] aLength The length of the Steering Data in bytes. + * + * @retval OT_ERROR_NONE Successfully initialized the Steering Data. + * @retval OT_ERROR_INVALID_ARGS The @p aLength is invalid. + */ +otError otSteeringDataInit(otSteeringData *aSteeringData, uint8_t aLength); + +/** + * Checks whether the Steering Data has a valid length. + * + * @param[in] aSteeringData The Steering Data to check. + * + * @retval TRUE If the Steering Data's length is valid. + * @retval FALSE If the Steering Data's length is not valid. + */ +bool otSteeringDataIsValid(const otSteeringData *aSteeringData); + +/** + * Sets the Steering Data to permit all joiners. + * + * @param[out] aSteeringData The Steering Data to update. + */ +void otSteeringDataSetToPermitAllJoiners(otSteeringData *aSteeringData); + +/** + * Updates the Steering Data's bloom filter with a Joiner ID. + * + * @param[out] aSteeringData The Steering Data to update. + * @param[in] aJoinerId The Joiner ID to add. + * + * @retval OT_ERROR_NONE Successfully updated the Steering Data. + * @retval OT_ERROR_INVALID_ARGS The Steering Data is not valid (incorrect length). + */ +otError otSteeringDataUpdateWithJoinerId(otSteeringData *aSteeringData, const otExtAddress *aJoinerId); + +/** + * Updates the Steering Data's bloom filter with a Joiner Discerner. + * + * @param[out] aSteeringData The Steering Data to update + * @param[in] aDiscerner The Joiner Discerner to add. + * + * @retval OT_ERROR_NONE Successfully updated the Steering Data. + * @retval OT_ERROR_INVALID_ARGS The Steering Data is not valid (incorrect length). + */ +otError otSteeringDataUpdateWithDiscerner(otSteeringData *aSteeringData, const otJoinerDiscerner *aDiscerner); + +/** + * Merges two Steering Data bloom filters. + * + * The @p aOtherSteeringData must have a length that is a divisor of the @p aSteeringData length. + * + * @param[out] aSteeringData The Steering Data to merge into. + * @param[in] aOtherSteeringData The other Steering Data to merge from. + * + * @retval OT_ERROR_NONE Successfully merged the Steering Data. + * @retval OT_ERROR_INVALID_ARGS The Steering Data lengths are not valid or they cannot be merged. + */ +otError otSteeringDataMerge(otSteeringData *aSteeringData, const otSteeringData *aOtherSteeringData); + +/** + * Checks if the Steering Data permits all joiners. + * + * @param[in] aSteeringData The Steering Data to check. + * + * @retval TRUE If the Steering Data permits all joiners. + * @retval FALSE If the Steering Data does not permit all joiners. + */ +bool otSteeringDataPermitsAllJoiners(const otSteeringData *aSteeringData); + +/** + * Checks if the Steering Data is empty. + * + * @param[in] aSteeringData The Steering Data to check. + * + * @retval TRUE If the Steering Data is empty. + * @retval FALSE If the Steering Data is not empty. + */ +bool otSteeringDataIsEmpty(const otSteeringData *aSteeringData); + +/** + * Checks if the Steering Data contains a Joiner ID. + * + * @param[in] aSteeringData The Steering Data to check. + * @param[in] aJoinerId The Joiner ID. + * + * @retval TRUE If the Steering Data contains the Joiner ID. + * @retval FALSE If the Steering Data does not contain the Joiner ID. + */ +bool otSteeringDataContainsJoinerId(const otSteeringData *aSteeringData, const otExtAddress *aJoinerId); + +/** + * Checks if the Steering Data contains a Joiner Discerner. + * + * @param[in] aSteeringData The Steering Data to check. + * @param[in] aDiscerner The Joiner Discerner. + * + * @retval TRUE If the Steering Data contains the Joiner Discerner. + * @retval FALSE If the Steering Data does not contain the Joiner Discerner. + */ +bool otSteeringDataContainsDiscerner(const otSteeringData *aSteeringData, const otJoinerDiscerner *aDiscerner); + +/** + * @} + */ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // OPENTHREAD_STEERING_DATA_H_ diff --git a/src/core/BUILD.gn b/src/core/BUILD.gn index 422f47550..9bed5e494 100644 --- a/src/core/BUILD.gn +++ b/src/core/BUILD.gn @@ -214,6 +214,7 @@ openthread_core_files = [ "api/srp_client_api.cpp", "api/srp_client_buffers_api.cpp", "api/srp_server_api.cpp", + "api/steering_data_api.cpp", "api/tasklet_api.cpp", "api/tcp_api.cpp", "api/tcp_ext_api.cpp", diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 049b1f245..6679264ae 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -84,6 +84,7 @@ set(COMMON_SOURCES api/srp_client_api.cpp api/srp_client_buffers_api.cpp api/srp_server_api.cpp + api/steering_data_api.cpp api/tasklet_api.cpp api/tcp_api.cpp api/tcp_ext_api.cpp diff --git a/src/core/api/steering_data_api.cpp b/src/core/api/steering_data_api.cpp new file mode 100644 index 000000000..64b5c7c41 --- /dev/null +++ b/src/core/api/steering_data_api.cpp @@ -0,0 +1,88 @@ +/* + * 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 implements the OpenThread MeshCoP helper API. + */ + +#include "openthread-core-config.h" + +#include + +#include "meshcop/meshcop.hpp" + +using namespace ot; + +#if OPENTHREAD_CONFIG_MESHCOP_STEERING_DATA_API_ENABLE + +otError otSteeringDataInit(otSteeringData *aSteeringData, uint8_t aLength) +{ + return AsCoreType(aSteeringData).Init(aLength); +} + +bool otSteeringDataIsValid(const otSteeringData *aSteeringData) { return AsCoreType(aSteeringData).IsValid(); } + +void otSteeringDataSetToPermitAllJoiners(otSteeringData *aSteeringData) +{ + AsCoreType(aSteeringData).SetToPermitAllJoiners(); +} + +otError otSteeringDataUpdateWithJoinerId(otSteeringData *aSteeringData, const otExtAddress *aJoinerId) +{ + return AsCoreType(aSteeringData).UpdateBloomFilter(AsCoreType(aJoinerId)); +} + +otError otSteeringDataUpdateWithDiscerner(otSteeringData *aSteeringData, const otJoinerDiscerner *aDiscerner) +{ + return AsCoreType(aSteeringData).UpdateBloomFilter(AsCoreType(aDiscerner)); +} + +otError otSteeringDataMerge(otSteeringData *aSteeringData, const otSteeringData *aOtherSteeringData) +{ + return AsCoreType(aSteeringData).MergeBloomFilterWith(AsCoreType(aOtherSteeringData)); +} + +bool otSteeringDataPermitsAllJoiners(const otSteeringData *aSteeringData) +{ + return AsCoreType(aSteeringData).PermitsAllJoiners(); +} + +bool otSteeringDataIsEmpty(const otSteeringData *aSteeringData) { return AsCoreType(aSteeringData).IsEmpty(); } + +bool otSteeringDataContainsJoinerId(const otSteeringData *aSteeringData, const otExtAddress *aJoinerId) +{ + return AsCoreType(aSteeringData).Contains(AsCoreType(aJoinerId)); +} + +bool otSteeringDataContainsDiscerner(const otSteeringData *aSteeringData, const otJoinerDiscerner *aDiscerner) +{ + return AsCoreType(aSteeringData).Contains(AsCoreType(aDiscerner)); +} + +#endif // OPENTHREAD_CONFIG_MESHCOP_STEERING_DATA_API_ENABLE diff --git a/src/core/config/misc.h b/src/core/config/misc.h index bcfed58c8..101eafa09 100644 --- a/src/core/config/misc.h +++ b/src/core/config/misc.h @@ -310,6 +310,15 @@ #endif #endif +/** + * @def OPENTHREAD_CONFIG_MESHCOP_STEERING_DATA_API_ENABLE + * + * Define as 1 to enable the MeshCoP Steering Data public APIs (in `openthread/steering_data.h`). + */ +#ifndef OPENTHREAD_CONFIG_MESHCOP_STEERING_DATA_API_ENABLE +#define OPENTHREAD_CONFIG_MESHCOP_STEERING_DATA_API_ENABLE 0 +#endif + /** * @def OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE * diff --git a/src/core/meshcop/commissioner.cpp b/src/core/meshcop/commissioner.cpp index ce8f50498..f9f3100c7 100644 --- a/src/core/meshcop/commissioner.cpp +++ b/src/core/meshcop/commissioner.cpp @@ -346,7 +346,7 @@ void Commissioner::ComputeBloomFilter(SteeringData &aSteeringData) const { Mac::ExtAddress joinerId; - aSteeringData.Init(); + IgnoreError(aSteeringData.Init(SteeringData::kMaxLength)); for (const Joiner &joiner : mJoiners) { @@ -357,11 +357,11 @@ void Commissioner::ComputeBloomFilter(SteeringData &aSteeringData) const case Joiner::kTypeEui64: ComputeJoinerId(joiner.mSharedId.mEui64, joinerId); - aSteeringData.UpdateBloomFilter(joinerId); + IgnoreError(aSteeringData.UpdateBloomFilter(joinerId)); break; case Joiner::kTypeDiscerner: - aSteeringData.UpdateBloomFilter(joiner.mSharedId.mDiscerner); + IgnoreError(aSteeringData.UpdateBloomFilter(joiner.mSharedId.mDiscerner)); break; case Joiner::kTypeAny: diff --git a/src/core/meshcop/meshcop.cpp b/src/core/meshcop/meshcop.cpp index 945ca021e..a82bbc77a 100644 --- a/src/core/meshcop/meshcop.cpp +++ b/src/core/meshcop/meshcop.cpp @@ -191,49 +191,73 @@ JoinerDiscerner::InfoString JoinerDiscerner::ToString(void) const //--------------------------------------------------------------------------------------------------------------------- // SteeringData -void SteeringData::Init(uint8_t aLength) +Error SteeringData::Init(uint8_t aLength) { - OT_ASSERT(aLength <= kMaxLength); + Error error = kErrorNone; + + VerifyOrExit(IsValueInRange(aLength, kMinLength, kMaxLength), error = kErrorInvalidArgs); + mLength = aLength; ClearAllBytes(m8); + +exit: + return error; +} + +Error SteeringData::Init(uint8_t aLength, const uint8_t *aData) +{ + Error error; + + SuccessOrExit(error = Init(aLength)); + memcpy(m8, aData, mLength); + +exit: + return error; } void SteeringData::SetToPermitAllJoiners(void) { - Init(1); + IgnoreError(Init(1)); m8[0] = kPermitAll; } -void SteeringData::UpdateBloomFilter(const Mac::ExtAddress &aJoinerId) +Error SteeringData::UpdateBloomFilter(const Mac::ExtAddress &aJoinerId) { HashBitIndexes indexes; CalculateHashBitIndexes(aJoinerId, indexes); - UpdateBloomFilter(indexes); + + return UpdateBloomFilter(indexes); } -void SteeringData::UpdateBloomFilter(const JoinerDiscerner &aDiscerner) +Error SteeringData::UpdateBloomFilter(const JoinerDiscerner &aDiscerner) { HashBitIndexes indexes; CalculateHashBitIndexes(aDiscerner, indexes); - UpdateBloomFilter(indexes); + + return UpdateBloomFilter(indexes); } -void SteeringData::UpdateBloomFilter(const HashBitIndexes &aIndexes) +Error SteeringData::UpdateBloomFilter(const HashBitIndexes &aIndexes) { - OT_ASSERT(IsLengthValid()); + Error error = kErrorNone; + + VerifyOrExit(IsValid(), error = kErrorInvalidArgs); SetBit(aIndexes.mIndex[0] % GetNumBits()); SetBit(aIndexes.mIndex[1] % GetNumBits()); + +exit: + return error; } Error SteeringData::MergeBloomFilterWith(const SteeringData &aOther) { Error error = kErrorNone; - VerifyOrExit(IsLengthValid(), error = kErrorInvalidArgs); - VerifyOrExit(aOther.IsLengthValid(), error = kErrorInvalidArgs); + VerifyOrExit(IsValid(), error = kErrorInvalidArgs); + VerifyOrExit(aOther.IsValid(), error = kErrorInvalidArgs); VerifyOrExit(GetLength() % aOther.GetLength() == 0, error = kErrorInvalidArgs); @@ -266,7 +290,13 @@ bool SteeringData::Contains(const JoinerDiscerner &aDiscerner) const bool SteeringData::Contains(const HashBitIndexes &aIndexes) const { - return (mLength > 0) && GetBit(aIndexes.mIndex[0] % GetNumBits()) && GetBit(aIndexes.mIndex[1] % GetNumBits()); + bool contains = false; + + VerifyOrExit(IsValid()); + contains = GetBit(aIndexes.mIndex[0] % GetNumBits()) && GetBit(aIndexes.mIndex[1] % GetNumBits()); + +exit: + return contains; } void SteeringData::CalculateHashBitIndexes(const Mac::ExtAddress &aJoinerId, HashBitIndexes &aIndexes) @@ -287,17 +317,21 @@ void SteeringData::CalculateHashBitIndexes(const JoinerDiscerner &aDiscerner, Ha bool SteeringData::DoesAllMatch(uint8_t aMatch) const { - bool matches = true; + bool matches = false; + + VerifyOrExit(IsValid()); for (uint8_t i = 0; i < mLength; i++) { if (m8[i] != aMatch) { - matches = false; - break; + ExitNow(); } } + matches = true; + +exit: return matches; } diff --git a/src/core/meshcop/meshcop.hpp b/src/core/meshcop/meshcop.hpp index 5b6b34b2a..fffc8f3d5 100644 --- a/src/core/meshcop/meshcop.hpp +++ b/src/core/meshcop/meshcop.hpp @@ -39,10 +39,12 @@ #include #include #include +#include #include "coap/coap.hpp" #include "common/as_core_type.hpp" #include "common/clearable.hpp" +#include "common/code_utils.hpp" #include "common/equatable.hpp" #include "common/log.hpp" #include "common/message.hpp" @@ -230,7 +232,7 @@ private: class SteeringData : public otSteeringData { public: - static constexpr uint8_t kMinLength = 1; ///< Minimum Steering Data length (in bytes). + static constexpr uint8_t kMinLength = OT_STEERING_DATA_MIN_LENGTH; ///< Minimum Steering Data length (in bytes). static constexpr uint8_t kMaxLength = OT_STEERING_DATA_MAX_LENGTH; ///< Maximum Steering Data length (in bytes). static constexpr uint16_t kInfoStringSize = 45; ///< Size of `InfoString` to use with `ToString()`. @@ -255,16 +257,37 @@ public: /** * Initializes the Steering Data and clears the bloom filter. * - * @param[in] aLength The Steering Data length (in bytes) - MUST be smaller than or equal to `kMaxLength`. + * @param[in] aLength The Steering Data length (in bytes). + * + * @retval kErrorSuccess Successfully initialized the Steering Data. + * @retval kErrorInvalidArgs @p aLength is not valid. */ - void Init(uint8_t aLength = kMaxLength); + Error Init(uint8_t aLength); + + /** + * Initializes the Steering Data. + * + * @param[in] aLength The Steering Data length (in bytes). + * @param[in] aData A pointer to a buffer containing the data bytes. + * + * @retval kErrorSuccess Successfully initialized the Steering Data. + * @retval kErrorInvalidArgs @p aLength is not valid. + */ + Error Init(uint8_t aLength, const uint8_t *aData); + + /** + * Checks whether the Steering Data has a valid length. + * + * @returns TRUE if the Steering Data's length is valid (within min to max range), FALSE otherwise. + */ + bool IsValid(void) const { return IsValueInRange(mLength, kMinLength, kMaxLength); } /** * Clears the bloom filter (all bits are cleared and no Joiner Id is accepted).. * * The Steering Data length (bloom filter length) is set to one byte with all bits cleared. */ - void Clear(void) { Init(1); } + void Clear(void) { IgnoreError(Init(1)); } /** * Sets the bloom filter to permit all Joiner IDs. @@ -298,15 +321,21 @@ public: * Updates the bloom filter adding the given Joiner ID. * * @param[in] aJoinerId The Joiner ID to add to bloom filter. + * + * @retval kErrorNone Successfully updated the bloom filter. + * @retval kErrorInvalidArgs The Steering Data's length is invalid. */ - void UpdateBloomFilter(const Mac::ExtAddress &aJoinerId); + Error UpdateBloomFilter(const Mac::ExtAddress &aJoinerId); /** * Updates the bloom filter adding a given Joiner Discerner. * * @param[in] aDiscerner The Joiner Discerner to add to bloom filter. + * + * @retval kErrorNone Successfully updated the bloom filter. + * @retval kErrorInvalidArgs The Steering Data's length is invalid. */ - void UpdateBloomFilter(const JoinerDiscerner &aDiscerner); + Error UpdateBloomFilter(const JoinerDiscerner &aDiscerner); /** * Merges the bloom filter by combining it with another steering data filter. @@ -393,7 +422,6 @@ public: private: static constexpr uint8_t kPermitAll = 0xff; - bool IsLengthValid(void) const { return IsValueInRange(mLength, kMinLength, kMaxLength); } uint8_t GetNumBits(void) const { return (mLength * kBitsPerByte); } uint8_t BitIndex(uint8_t aBit) const { return (mLength - 1 - (aBit / kBitsPerByte)); } @@ -403,8 +431,8 @@ private: void SetBit(uint8_t aBit) { m8[BitIndex(aBit)] |= BitFlag(aBit); } void ClearBit(uint8_t aBit) { m8[BitIndex(aBit)] &= ~BitFlag(aBit); } - bool DoesAllMatch(uint8_t aMatch) const; - void UpdateBloomFilter(const HashBitIndexes &aIndexes); + bool DoesAllMatch(uint8_t aMatch) const; + Error UpdateBloomFilter(const HashBitIndexes &aIndexes); }; /** diff --git a/src/core/meshcop/meshcop_tlvs.cpp b/src/core/meshcop/meshcop_tlvs.cpp index 03ebef398..9b207f0e3 100644 --- a/src/core/meshcop/meshcop_tlvs.cpp +++ b/src/core/meshcop/meshcop_tlvs.cpp @@ -60,10 +60,9 @@ void NetworkNameTlv::SetNetworkName(const NameData &aNameData) bool NetworkNameTlv::IsValid(void) const { return IsValidUtf8String(mNetworkName, GetLength()); } -void SteeringDataTlv::CopyTo(SteeringData &aSteeringData) const +Error SteeringDataTlv::CopyTo(SteeringData &aSteeringData) const { - aSteeringData.Init(GetSteeringDataLength()); - memcpy(aSteeringData.GetData(), mSteeringData, GetSteeringDataLength()); + return aSteeringData.Init(GetSteeringDataLength(), mSteeringData); } bool SecurityPolicyTlv::IsValid(void) const diff --git a/src/core/meshcop/meshcop_tlvs.hpp b/src/core/meshcop/meshcop_tlvs.hpp index 06e2f1a7b..4e762ebe9 100644 --- a/src/core/meshcop/meshcop_tlvs.hpp +++ b/src/core/meshcop/meshcop_tlvs.hpp @@ -364,8 +364,11 @@ public: * Copies the Steering Data from the TLV into a given `SteeringData` variable. * * @param[out] aSteeringData A reference to a `SteeringData` to copy into. + * + * @retval kErrorNone Successfully copied the steering data into @p aSteeringData. + * @retval kErrorInvalidArgs The Steering Data TLV length is invalid. */ - void CopyTo(SteeringData &aSteeringData) const; + Error CopyTo(SteeringData &aSteeringData) const; private: uint8_t mSteeringData[OT_STEERING_DATA_MAX_LENGTH]; diff --git a/src/core/thread/discover_scanner.cpp b/src/core/thread/discover_scanner.cpp index df9cbc4b3..63af6b152 100644 --- a/src/core/thread/discover_scanner.cpp +++ b/src/core/thread/discover_scanner.cpp @@ -371,7 +371,7 @@ void DiscoverScanner::HandleDiscoveryResponse(Mle::RxInfo &aRxInfo) const OffsetRange valueOffsetRange = tlvInfo.mValueOffsetRange; valueOffsetRange.ShrinkLength(MeshCoP::SteeringData::kMaxLength); - steeringData.Init(static_cast(valueOffsetRange.GetLength())); + IgnoreError(steeringData.Init(static_cast(valueOffsetRange.GetLength()))); aRxInfo.mMessage.ReadBytes(valueOffsetRange, steeringData.GetData()); if (mEnableFiltering) diff --git a/src/core/thread/mle_ftd.cpp b/src/core/thread/mle_ftd.cpp index a8f3f73ae..49be27f46 100644 --- a/src/core/thread/mle_ftd.cpp +++ b/src/core/thread/mle_ftd.cpp @@ -2696,9 +2696,9 @@ void Mle::SetSteeringData(const Mac::ExtAddress *aExtAddress) { Mac::ExtAddress joinerId; - mSteeringData.Init(); + IgnoreError(mSteeringData.Init(MeshCoP::SteeringData::kMaxLength)); MeshCoP::ComputeJoinerId(*aExtAddress, joinerId); - mSteeringData.UpdateBloomFilter(joinerId); + IgnoreError(mSteeringData.UpdateBloomFilter(joinerId)); } } #endif // OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE diff --git a/src/core/thread/network_data_leader.cpp b/src/core/thread/network_data_leader.cpp index ab5a60eef..edd167d92 100644 --- a/src/core/thread/network_data_leader.cpp +++ b/src/core/thread/network_data_leader.cpp @@ -635,7 +635,7 @@ Error Leader::FindSteeringData(MeshCoP::SteeringData &aSteeringData) const const MeshCoP::SteeringDataTlv *steeringDataTlv = FindInCommissioningData(); VerifyOrExit(steeringDataTlv != nullptr, error = kErrorNotFound); - steeringDataTlv->CopyTo(aSteeringData); + error = steeringDataTlv->CopyTo(aSteeringData); exit: return error; diff --git a/tests/toranj/openthread-core-toranj-config.h b/tests/toranj/openthread-core-toranj-config.h index 0a8a74210..be419b82a 100644 --- a/tests/toranj/openthread-core-toranj-config.h +++ b/tests/toranj/openthread-core-toranj-config.h @@ -76,6 +76,8 @@ #define OPENTHREAD_CONFIG_COMMISSIONER_MAX_JOINER_ENTRIES 4 +#define OPENTHREAD_CONFIG_MESHCOP_STEERING_DATA_API_ENABLE 1 + #define OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE 1 #define OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE 1 diff --git a/tests/unit/test_meshcop.cpp b/tests/unit/test_meshcop.cpp index fb52e298e..3c104fae7 100644 --- a/tests/unit/test_meshcop.cpp +++ b/tests/unit/test_meshcop.cpp @@ -31,6 +31,7 @@ #include #include "test_util.hpp" +#include "common/clearable.hpp" #include "meshcop/meshcop.hpp" #include "meshcop/timestamp.hpp" @@ -75,7 +76,7 @@ void TestSteeringData(void) { printf("\n--------------------------------------------"); - steeringData.Init(len); + SuccessOrQuit(steeringData.Init(len)); VerifyOrQuit(steeringData.GetLength() == len); VerifyOrQuit(steeringData.IsEmpty()); @@ -84,14 +85,14 @@ void TestSteeringData(void) VerifyOrQuit(!steeringData.Contains(joinerId2)); VerifyOrQuit(!steeringData.Contains(indexes)); - steeringData.UpdateBloomFilter(joinerId1); + SuccessOrQuit(steeringData.UpdateBloomFilter(joinerId1)); printf("\nAfter UpdateBloomFilter(joinerId1): %s", steeringData.ToString().AsCString()); VerifyOrQuit(steeringData.GetLength() == len); VerifyOrQuit(!steeringData.IsEmpty()); VerifyOrQuit(!steeringData.PermitsAllJoiners()); VerifyOrQuit(steeringData.Contains(joinerId1)); - steeringData.UpdateBloomFilter(joinerId2); + SuccessOrQuit(steeringData.UpdateBloomFilter(joinerId2)); printf("\nAfter UpdateBloomFilter(joinerId2): %s", steeringData.ToString().AsCString()); VerifyOrQuit(steeringData.GetLength() == len); VerifyOrQuit(!steeringData.IsEmpty()); @@ -101,14 +102,12 @@ void TestSteeringData(void) VerifyOrQuit(steeringData.Contains(indexes)); } - steeringData.Init(0); + VerifyOrQuit(steeringData.Init(0) == kErrorInvalidArgs); + VerifyOrQuit(steeringData.Init(MeshCoP::SteeringData::kMaxLength + 1) == kErrorInvalidArgs); + ClearAllBytes(steeringData); VerifyOrQuit(steeringData.GetLength() == 0); - VerifyOrQuit(steeringData.IsEmpty()); - VerifyOrQuit(!steeringData.PermitsAllJoiners()); - VerifyOrQuit(!steeringData.Contains(joinerId1)); - VerifyOrQuit(!steeringData.Contains(joinerId2)); - VerifyOrQuit(!steeringData.Contains(indexes)); + VerifyOrQuit(steeringData.UpdateBloomFilter(joinerId1) == kErrorInvalidArgs); printf("TestSteeringData() passed\n"); } @@ -161,8 +160,8 @@ void TestSteeringDataBloomFilterMerge(void) printf("\n--------------------------------------------"); printf("\nLen:%u OtherLen:%u", length, otherLength); - steeringData.Init(length); - otherSteeringData.Init(otherLength); + SuccessOrQuit(steeringData.Init(length)); + SuccessOrQuit(otherSteeringData.Init(otherLength)); VerifyOrQuit(steeringData.GetLength() == length); VerifyOrQuit(otherSteeringData.GetLength() == otherLength); @@ -184,13 +183,13 @@ void TestSteeringDataBloomFilterMerge(void) for (Mac::ExtAddress &id : joinerIds) { - steeringData.UpdateBloomFilter(id); + SuccessOrQuit(steeringData.UpdateBloomFilter(id)); VerifyOrQuit(steeringData.Contains(id)); } for (Mac::ExtAddress &id : otherJoinerIds) { - otherSteeringData.UpdateBloomFilter(id); + SuccessOrQuit(otherSteeringData.UpdateBloomFilter(id)); VerifyOrQuit(otherSteeringData.Contains(id)); }