mirror of
https://github.com/espressif/openthread.git
synced 2026-08-03 01:17:46 +00:00
[mac] new public API to validate and set otNetworkName (#6703)
This commit adds a new public API `otNetworkNameFromString()` to set an `otNetworkName` instance from a given null terminated C string. The new API will also validate that the given name string follows UTF-8 encoding and its length is not longer than max network name size. This commit also simplifies the UTF-8 validation of `NetworkName` by moving the check from `Mac::SetNetworkName()` to a newly added method in `Mac::NetworkName` to set it from a C string. It also defines `DomainName` as a `typedef` of `NetworkName` which helps simplify its use and remove repeated code. Finally, it updates the `Cli::Dataset` to use the new public API for validating `otNetworkName`.
This commit is contained in:
@@ -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);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
|
||||
@@ -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
|
||||
|
||||
+8
-20
@@ -41,7 +41,6 @@
|
||||
#include <openthread/dataset_updater.h>
|
||||
|
||||
#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<uint16_t>(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<uint16_t>(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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -177,3 +177,10 @@ otError otDatasetGeneratePskc(const char * aPassPhrase,
|
||||
*static_cast<const Mac::ExtendedPanId *>(aExtPanId), *static_cast<Pskc *>(aPskc));
|
||||
}
|
||||
#endif // OPENTHREAD_FTD
|
||||
|
||||
otError otNetworkNameFromString(otNetworkName *aNetworkName, const char *aNameString)
|
||||
{
|
||||
otError error = static_cast<Mac::NetworkName *>(aNetworkName)->Set(aNameString);
|
||||
|
||||
return (error == OT_ERROR_ALREADY) ? OT_ERROR_NONE : error;
|
||||
}
|
||||
|
||||
+20
-48
@@ -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<Notifier>().Signal(kEventThreadNetworkNameChanged);
|
||||
break;
|
||||
|
||||
case kErrorAlready:
|
||||
Get<Notifier>().SignalIfFirst(kEventThreadNetworkNameChanged);
|
||||
error = kErrorNone;
|
||||
ExitNow();
|
||||
aError = kErrorNone;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
SuccessOrExit(error);
|
||||
Get<Notifier>().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)
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
+21
-26
@@ -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<uint8_t>(StringLength(m8, kMaxSize + 1));
|
||||
|
||||
return NameData(m8, len);
|
||||
}
|
||||
|
||||
Error DomainName::Set(const NameData &aNameData)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
uint8_t newLen = static_cast<uint8_t>(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] = {
|
||||
|
||||
+18
-47
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user