diff --git a/include/openthread/dataset.h b/include/openthread/dataset.h index 8ef415936..09461dce9 100644 --- a/include/openthread/dataset.h +++ b/include/openthread/dataset.h @@ -75,10 +75,12 @@ typedef struct otMasterKey otMasterKey; /** * This structure represents a Network Name. * + * The `otNetworkName` is a null terminated C string (i.e., `m8` char array MUST end with null char `\0`). + * */ typedef struct otNetworkName { - char m8[OT_NETWORK_NAME_MAX_SIZE + 1]; ///< Byte values + char m8[OT_NETWORK_NAME_MAX_SIZE + 1]; ///< Byte values. The `+ 1` is for null char. } otNetworkName; #define OT_EXT_PAN_ID_SIZE 8 ///< Size of a Thread PAN ID (bytes) @@ -515,6 +517,21 @@ otError otDatasetGeneratePskc(const char * aPassPhrase, const otExtendedPanId *aExtPanId, otPskc * aPskc); +/** + * This function sets an `otNetworkName` instance from a given null terminated C string. + * + * This function also validates that the given @p aNameString follows UTF-8 encoding and its length is not longer than + * `OT_NETWORK_NAME_MAX_SIZE`. + * + * @param[out] aNetworkName A pointer to the `otNetworkName` to set. + * @param[in] aNameString A name C string. + * + * @retval OT_ERROR_NONE Successfully set @p aNetworkName from @p aNameString. + * @retval OT_ERROR_INVALID_ARGS @p aNameStrng is invalid (too long or does not follow UTF-8 encoding). + * + */ +otError otNetworkNameFromString(otNetworkName *aNetworkName, const char *aNameString); + /** * @} * diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 41aecda67..46e74a76f 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 (121) +#define OPENTHREAD_API_VERSION (122) /** * @addtogroup api-instance diff --git a/src/cli/cli_dataset.cpp b/src/cli/cli_dataset.cpp index 4431c128b..d9e88c5cd 100644 --- a/src/cli/cli_dataset.cpp +++ b/src/cli/cli_dataset.cpp @@ -41,7 +41,6 @@ #include #include "cli/cli.hpp" -#include "common/string.hpp" namespace ot { namespace Cli { @@ -100,7 +99,7 @@ otError Dataset::Print(otOperationalDataset &aDataset) if (aDataset.mComponents.mIsNetworkNamePresent) { mInterpreter.OutputFormat("Network Name: "); - mInterpreter.OutputLine("%.*s", static_cast(sizeof(aDataset.mNetworkName)), aDataset.mNetworkName.m8); + mInterpreter.OutputLine("%s", aDataset.mNetworkName.m8); } if (aDataset.mComponents.mIsPanIdPresent) @@ -441,19 +440,12 @@ otError Dataset::ProcessNetworkName(uint8_t aArgsLength, Arg aArgs[]) { if (sDataset.mComponents.mIsNetworkNamePresent) { - mInterpreter.OutputLine("%.*s", static_cast(sizeof(sDataset.mNetworkName)), - sDataset.mNetworkName.m8); + mInterpreter.OutputLine("%s", sDataset.mNetworkName.m8); } } else { - uint16_t length; - - VerifyOrExit((length = aArgs[0].GetLength()) <= OT_NETWORK_NAME_MAX_SIZE, error = OT_ERROR_INVALID_ARGS); - VerifyOrExit(IsValidUtf8String(aArgs[0].GetCString()), error = OT_ERROR_INVALID_ARGS); - - memset(&sDataset.mNetworkName, 0, sizeof(sDataset.mNetworkName)); - memcpy(sDataset.mNetworkName.m8, aArgs[0].GetCString(), length); + SuccessOrExit(error = otNetworkNameFromString(&sDataset.mNetworkName, aArgs[0].GetCString())); sDataset.mComponents.mIsNetworkNamePresent = true; } @@ -536,14 +528,9 @@ otError Dataset::ProcessMgmtSetCommand(uint8_t aArgsLength, Arg aArgs[]) } else if (aArgs[index] == "networkname") { - uint16_t length; - VerifyOrExit(++index < aArgsLength, error = OT_ERROR_INVALID_ARGS); dataset.mComponents.mIsNetworkNamePresent = true; - VerifyOrExit((length = aArgs[index].GetLength()) <= OT_NETWORK_NAME_MAX_SIZE, - error = OT_ERROR_INVALID_ARGS); - memset(&dataset.mNetworkName, 0, sizeof(sDataset.mNetworkName)); - memcpy(dataset.mNetworkName.m8, aArgs[index].GetCString(), length); + SuccessOrExit(error = otNetworkNameFromString(&dataset.mNetworkName, aArgs[index].GetCString())); } else if (aArgs[index] == "extpanid") { @@ -809,9 +796,9 @@ void Dataset::OutputSecurityPolicy(const otSecurityPolicy &aSecurityPolicy) } } -Error Dataset::ParseSecurityPolicy(otSecurityPolicy &aSecurityPolicy, uint8_t aArgsLength, Arg aArgs[]) +otError Dataset::ParseSecurityPolicy(otSecurityPolicy &aSecurityPolicy, uint8_t aArgsLength, Arg aArgs[]) { - Error error; + otError error; otSecurityPolicy policy; memset(&policy, 0, sizeof(policy)); @@ -865,10 +852,11 @@ Error Dataset::ParseSecurityPolicy(otSecurityPolicy &aSecurityPolicy, uint8_t aA } exit: - if (error == kErrorNone) + if (error == OT_ERROR_NONE) { aSecurityPolicy = policy; } + return error; } diff --git a/src/cli/cli_dataset.hpp b/src/cli/cli_dataset.hpp index e51856775..368ddd330 100644 --- a/src/cli/cli_dataset.hpp +++ b/src/cli/cli_dataset.hpp @@ -108,8 +108,8 @@ private: void HandleDatasetUpdater(otError aError); #endif - void OutputSecurityPolicy(const otSecurityPolicy &aSecurityPolicy); - Error ParseSecurityPolicy(otSecurityPolicy &aSecurityPolicy, uint8_t aArgsLength, Arg aArgs[]); + void OutputSecurityPolicy(const otSecurityPolicy &aSecurityPolicy); + otError ParseSecurityPolicy(otSecurityPolicy &aSecurityPolicy, uint8_t aArgsLength, Arg aArgs[]); static constexpr Command sCommands[] = { {"active", &Dataset::ProcessActive}, diff --git a/src/core/api/dataset_api.cpp b/src/core/api/dataset_api.cpp index e9ab9aaf7..30247f890 100644 --- a/src/core/api/dataset_api.cpp +++ b/src/core/api/dataset_api.cpp @@ -177,3 +177,10 @@ otError otDatasetGeneratePskc(const char * aPassPhrase, *static_cast(aExtPanId), *static_cast(aPskc)); } #endif // OPENTHREAD_FTD + +otError otNetworkNameFromString(otNetworkName *aNetworkName, const char *aNameString) +{ + otError error = static_cast(aNetworkName)->Set(aNameString); + + return (error == OT_ERROR_ALREADY) ? OT_ERROR_NONE : error; +} diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp index e84edfcb0..394175485 100644 --- a/src/core/mac/mac.cpp +++ b/src/core/mac/mac.cpp @@ -475,75 +475,47 @@ void Mac::SetSupportedChannelMask(const ChannelMask &aMask) Error Mac::SetNetworkName(const char *aNameString) { - // When setting Network Name from a string, we treat it as `NameData` - // with `kMaxSize + 1` chars. `NetworkName::Set(data)` will look - // for null char in the data (within its given size) to calculate - // the name's length and ensure that the name fits in `kMaxSize` - // chars. The `+ 1` ensures that a `aNameString` with length - // longer than `kMaxSize` is correctly rejected (returning error - // `kErrorInvalidArgs`). - - Error error; - NameData data(aNameString, NetworkName::kMaxSize + 1); - - VerifyOrExit(IsValidUtf8String(aNameString), error = kErrorInvalidArgs); - - error = SetNetworkName(data); - -exit: - return error; + return SignalNetworkNameChange(mNetworkName.Set(aNameString)); } Error Mac::SetNetworkName(const NameData &aNameData) { - Error error = mNetworkName.Set(aNameData); + return SignalNetworkNameChange(mNetworkName.Set(aNameData)); +} - if (error == kErrorAlready) +Error Mac::SignalNetworkNameChange(Error aError) +{ + switch (aError) { + case kErrorNone: + Get().Signal(kEventThreadNetworkNameChanged); + break; + + case kErrorAlready: Get().SignalIfFirst(kEventThreadNetworkNameChanged); - error = kErrorNone; - ExitNow(); + aError = kErrorNone; + break; + + default: + break; } - SuccessOrExit(error); - Get().Signal(kEventThreadNetworkNameChanged); - -exit: - return error; + return aError; } #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) Error Mac::SetDomainName(const char *aNameString) { - // When setting Domain Name from a string, we treat it as `NameData` - // with `kMaxSize + 1` chars. `DomainName::Set(data)` will look - // for null char in the data (within its given size) to calculate - // the name's length and ensure that the name fits in `kMaxSize` - // chars. The `+ 1` ensures that a `aNameString` with length - // longer than `kMaxSize` is correctly rejected (returning error - // `kErrorInvalidArgs`). + Error error = mDomainName.Set(aNameString); - Error error; - NameData data(aNameString, DomainName::kMaxSize + 1); - - VerifyOrExit(IsValidUtf8String(aNameString), error = kErrorInvalidArgs); - - error = SetDomainName(data); - -exit: - return error; + return (error == kErrorAlready) ? kErrorNone : error; } Error Mac::SetDomainName(const NameData &aNameData) { Error error = mDomainName.Set(aNameData); - if (error == kErrorAlready) - { - error = kErrorNone; - } - - return error; + return (error == kErrorAlready) ? kErrorNone : error; } #endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) diff --git a/src/core/mac/mac.hpp b/src/core/mac/mac.hpp index 78a69d179..00eedfa70 100644 --- a/src/core/mac/mac.hpp +++ b/src/core/mac/mac.hpp @@ -807,6 +807,7 @@ private: Error ConvertBeaconToActiveScanResult(const RxFrame *aBeaconFrame, ActiveScanResult &aResult); void PerformEnergyScan(void); void ReportEnergyScanResult(int8_t aRssi); + Error SignalNetworkNameChange(Error aError); void LogFrameRxFailure(const RxFrame *aFrame, Error aError) const; void LogFrameTxFailure(const TxFrame &aFrame, Error aError, uint8_t aRetryCount, bool aWillRetx) const; diff --git a/src/core/mac/mac_types.cpp b/src/core/mac/mac_types.cpp index 99dfbbd99..8e70ad356 100644 --- a/src/core/mac/mac_types.cpp +++ b/src/core/mac/mac_types.cpp @@ -142,6 +142,27 @@ NameData NetworkName::GetAsData(void) const return NameData(m8, len); } +Error NetworkName::Set(const char *aNameString) +{ + // When setting `NetworkName` from a string, we treat it as `NameData` + // with `kMaxSize + 1` chars. `NetworkName::Set(data)` will look + // for null char in the data (within its given size) to calculate + // the name's length and ensure that the name fits in `kMaxSize` + // chars. The `+ 1` ensures that a `aNameString` with length + // longer than `kMaxSize` is correctly rejected (returning error + // `kErrorInvalidArgs`). + + Error error; + NameData data(aNameString, kMaxSize + 1); + + VerifyOrExit(IsValidUtf8String(aNameString), error = kErrorInvalidArgs); + + error = Set(data); + +exit: + return error; +} + Error NetworkName::Set(const NameData &aNameData) { Error error = kErrorNone; @@ -168,32 +189,6 @@ bool NetworkName::operator==(const NetworkName &aOther) const (memcmp(data.GetBuffer(), otherData.GetBuffer(), data.GetLength()) == 0); } -#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) -NameData DomainName::GetAsData(void) const -{ - uint8_t len = static_cast(StringLength(m8, kMaxSize + 1)); - - return NameData(m8, len); -} - -Error DomainName::Set(const NameData &aNameData) -{ - Error error = kErrorNone; - uint8_t newLen = static_cast(StringLength(aNameData.GetBuffer(), aNameData.GetLength())); - - VerifyOrExit(newLen <= kMaxSize, error = kErrorInvalidArgs); - - // Ensure the new name does not match the current one. - VerifyOrExit(memcmp(m8, aNameData.GetBuffer(), newLen) || (m8[newLen] != '\0'), error = kErrorAlready); - - memcpy(m8, aNameData.GetBuffer(), newLen); - m8[newLen] = '\0'; - -exit: - return error; -} -#endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) - #if OPENTHREAD_CONFIG_MULTI_RADIO const RadioType RadioTypes::kAllRadioTypes[kNumRadioTypes] = { diff --git a/src/core/mac/mac_types.hpp b/src/core/mac/mac_types.hpp index 8dac5e0be..a001d4f6d 100644 --- a/src/core/mac/mac_types.hpp +++ b/src/core/mac/mac_types.hpp @@ -559,6 +559,21 @@ public: */ NameData GetAsData(void) const; + /** + * This method sets the IEEE 802.15.4 Network Name from a given null terminated C string. + * + * This method also validates that the given @p aNameString follows UTF-8 encoding and can fit in `kMaxSize` + * chars. + * + * @param[in] aNameString A name C string. + * + * @retval kErrorNone Successfully set the IEEE 802.15.4 Network Name. + * @retval kErrorAlready The name is already set to the same string. + * @retval kErrorInvalidArgs Given name is invalid (too long or does not follow UTF-8 encoding). + * + */ + Error Set(const char *aNameString); + /** * This method sets the IEEE 802.15.4 Network Name. * @@ -585,55 +600,11 @@ public: #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) /** - * This structure represents a Thread Domain Name. + * This type represents a Thread Domain Name. * */ -class DomainName -{ -public: - enum - { - kMaxSize = 16, // Maximum number of chars in Domain Name (excludes null char). - }; - - /** - * This constructor initializes the Thread Domain Name as an empty string. - * - */ - DomainName(void) { m8[0] = '\0'; } - - /** - * This method gets the Thread Domain Name as a null terminated C string. - * - * @returns The Domain Name as a null terminated C string array. - * - */ - const char *GetAsCString(void) const { return m8; } - - /** - * This method gets the Thread Domain Name as NameData. - * - * @returns The Domain Name as NameData. - * - */ - NameData GetAsData(void) const; - - /** - * This method sets the Thread Domain Name. - * - * @param[in] aNameData A reference to name data. - * - * @retval kErrorNone Successfully set the Thread Domain Name. - * @retval kErrorAlready The name is already set to the same string. - * @retval kErrorInvalidArgs Given name is too long. - * - */ - Error Set(const NameData &aNameData); - -private: - char m8[kMaxSize + 1]; ///< Byte values. -}; -#endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) +typedef NetworkName DomainName; +#endif #if OPENTHREAD_CONFIG_MULTI_RADIO