mirror of
https://github.com/espressif/openthread.git
synced 2026-08-10 20:57:47 +00:00
[cmd-parser] adding helper 'ParseAs{Type}' function (#5607)
This commit adds new helper functions under `Utils::CmdLineParser` to
parse a given ASCII string as different simple types, namely signed or
unsigned integers of different bit lengths (`uint8/16/32/64`, and
`int8/16/32`). The new functions validate that the parsed value fits
within the supported range of the expected int type. This commit also
adds different flavors of `ParseAsHexString()` to parse a hex string
into sequence of bytes (with fixed/known size or unknown size allowing
or disallowing truncation). It also moves the parse related methods
(like `ParseAsIp6Prefix`) from CLI modules in `CmdLineParser`.
The CLI modules are then updated to use the new `ParseAs{Type}`
functions simplifying the code and adding extra checks when parsing
the CLI input.
Finally, this commit adds a unit test `test_cmd_line_parser` verifying
the behavior of new `ParseAs{Type}()` functions.
This commit is contained in:
+55
-99
@@ -40,6 +40,14 @@
|
||||
#include <openthread/dataset_ftd.h>
|
||||
|
||||
#include "cli/cli.hpp"
|
||||
#include "utils/parse_cmdline.hpp"
|
||||
|
||||
using ot::Utils::CmdLineParser::ParseAsHexString;
|
||||
using ot::Utils::CmdLineParser::ParseAsIp6Address;
|
||||
using ot::Utils::CmdLineParser::ParseAsUint16;
|
||||
using ot::Utils::CmdLineParser::ParseAsUint32;
|
||||
using ot::Utils::CmdLineParser::ParseAsUint64;
|
||||
using ot::Utils::CmdLineParser::ParseAsUint8;
|
||||
|
||||
namespace ot {
|
||||
namespace Cli {
|
||||
@@ -284,10 +292,7 @@ otError Dataset::ProcessActiveTimestamp(uint8_t aArgsLength, char *aArgs[])
|
||||
}
|
||||
else
|
||||
{
|
||||
long value;
|
||||
|
||||
SuccessOrExit(error = Interpreter::ParseLong(aArgs[0], value));
|
||||
sDataset.mActiveTimestamp = static_cast<uint64_t>(value);
|
||||
SuccessOrExit(error = ParseAsUint64(aArgs[0], sDataset.mActiveTimestamp));
|
||||
sDataset.mComponents.mIsActiveTimestampPresent = true;
|
||||
}
|
||||
|
||||
@@ -308,10 +313,7 @@ otError Dataset::ProcessChannel(uint8_t aArgsLength, char *aArgs[])
|
||||
}
|
||||
else
|
||||
{
|
||||
long value;
|
||||
|
||||
SuccessOrExit(error = Interpreter::ParseLong(aArgs[0], value));
|
||||
sDataset.mChannel = static_cast<uint16_t>(value);
|
||||
SuccessOrExit(error = ParseAsUint16(aArgs[0], sDataset.mChannel));
|
||||
sDataset.mComponents.mIsChannelPresent = true;
|
||||
}
|
||||
|
||||
@@ -332,10 +334,7 @@ otError Dataset::ProcessChannelMask(uint8_t aArgsLength, char *aArgs[])
|
||||
}
|
||||
else
|
||||
{
|
||||
long value;
|
||||
|
||||
SuccessOrExit(error = Interpreter::ParseLong(aArgs[0], value));
|
||||
sDataset.mChannelMask = static_cast<uint32_t>(value);
|
||||
SuccessOrExit(error = ParseAsUint32(aArgs[0], sDataset.mChannelMask));
|
||||
sDataset.mComponents.mIsChannelMaskPresent = true;
|
||||
}
|
||||
|
||||
@@ -388,10 +387,7 @@ otError Dataset::ProcessDelay(uint8_t aArgsLength, char *aArgs[])
|
||||
}
|
||||
else
|
||||
{
|
||||
long value;
|
||||
|
||||
SuccessOrExit(error = Interpreter::ParseLong(aArgs[0], value));
|
||||
sDataset.mDelay = static_cast<uint32_t>(value);
|
||||
SuccessOrExit(error = ParseAsUint32(aArgs[0], sDataset.mDelay));
|
||||
sDataset.mComponents.mIsDelayPresent = true;
|
||||
}
|
||||
|
||||
@@ -413,12 +409,7 @@ otError Dataset::ProcessExtPanId(uint8_t aArgsLength, char *aArgs[])
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t extPanId[OT_EXT_PAN_ID_SIZE];
|
||||
|
||||
VerifyOrExit(Interpreter::Hex2Bin(aArgs[0], extPanId, sizeof(extPanId)) == sizeof(extPanId),
|
||||
error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
memcpy(sDataset.mExtendedPanId.m8, extPanId, sizeof(sDataset.mExtendedPanId));
|
||||
SuccessOrExit(error = ParseAsHexString(aArgs[0], sDataset.mExtendedPanId.m8));
|
||||
sDataset.mComponents.mIsExtendedPanIdPresent = true;
|
||||
}
|
||||
|
||||
@@ -440,12 +431,7 @@ otError Dataset::ProcessMasterKey(uint8_t aArgsLength, char *aArgs[])
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t key[OT_MASTER_KEY_SIZE];
|
||||
|
||||
VerifyOrExit((Interpreter::Hex2Bin(aArgs[0], key, sizeof(key))) == OT_MASTER_KEY_SIZE,
|
||||
error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
memcpy(sDataset.mMasterKey.m8, key, sizeof(sDataset.mMasterKey));
|
||||
SuccessOrExit(error = ParseAsHexString(aArgs[0], sDataset.mMasterKey.m8));
|
||||
sDataset.mComponents.mIsMasterKeyPresent = true;
|
||||
}
|
||||
|
||||
@@ -473,7 +459,7 @@ otError Dataset::ProcessMeshLocalPrefix(uint8_t aArgsLength, char *aArgs[])
|
||||
{
|
||||
otIp6Address prefix;
|
||||
|
||||
SuccessOrExit(error = otIp6AddressFromString(aArgs[0], &prefix));
|
||||
SuccessOrExit(error = ParseAsIp6Address(aArgs[0], prefix));
|
||||
|
||||
memcpy(sDataset.mMeshLocalPrefix.m8, prefix.mFields.m8, sizeof(sDataset.mMeshLocalPrefix.m8));
|
||||
sDataset.mComponents.mIsMeshLocalPrefixPresent = true;
|
||||
@@ -523,10 +509,7 @@ otError Dataset::ProcessPanId(uint8_t aArgsLength, char *aArgs[])
|
||||
}
|
||||
else
|
||||
{
|
||||
long value;
|
||||
|
||||
SuccessOrExit(error = Interpreter::ParseLong(aArgs[0], value));
|
||||
sDataset.mPanId = static_cast<otPanId>(value);
|
||||
SuccessOrExit(error = ParseAsUint16(aArgs[0], sDataset.mPanId));
|
||||
sDataset.mComponents.mIsPanIdPresent = true;
|
||||
}
|
||||
|
||||
@@ -547,10 +530,7 @@ otError Dataset::ProcessPendingTimestamp(uint8_t aArgsLength, char *aArgs[])
|
||||
}
|
||||
else
|
||||
{
|
||||
long value;
|
||||
|
||||
SuccessOrExit(error = Interpreter::ParseLong(aArgs[0], value));
|
||||
sDataset.mPendingTimestamp = static_cast<uint64_t>(value);
|
||||
SuccessOrExit(error = ParseAsUint64(aArgs[0], sDataset.mPendingTimestamp));
|
||||
sDataset.mComponents.mIsPendingTimestampPresent = true;
|
||||
}
|
||||
|
||||
@@ -563,9 +543,7 @@ otError Dataset::ProcessMgmtSetCommand(uint8_t aArgsLength, char *aArgs[])
|
||||
otError error = OT_ERROR_NONE;
|
||||
otOperationalDataset dataset;
|
||||
uint8_t tlvs[128];
|
||||
long value;
|
||||
int length = 0;
|
||||
otIp6Address prefix;
|
||||
uint8_t tlvsLength = 0;
|
||||
|
||||
VerifyOrExit(aArgsLength > 0, error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
@@ -577,85 +555,77 @@ otError Dataset::ProcessMgmtSetCommand(uint8_t aArgsLength, char *aArgs[])
|
||||
{
|
||||
VerifyOrExit(++index < aArgsLength, error = OT_ERROR_INVALID_ARGS);
|
||||
dataset.mComponents.mIsActiveTimestampPresent = true;
|
||||
SuccessOrExit(error = Interpreter::ParseLong(aArgs[index], value));
|
||||
dataset.mActiveTimestamp = static_cast<uint64_t>(value);
|
||||
SuccessOrExit(error = ParseAsUint64(aArgs[index], dataset.mActiveTimestamp));
|
||||
}
|
||||
else if (strcmp(aArgs[index], "pendingtimestamp") == 0)
|
||||
{
|
||||
VerifyOrExit(++index < aArgsLength, error = OT_ERROR_INVALID_ARGS);
|
||||
dataset.mComponents.mIsPendingTimestampPresent = true;
|
||||
SuccessOrExit(error = Interpreter::ParseLong(aArgs[index], value));
|
||||
dataset.mPendingTimestamp = static_cast<uint64_t>(value);
|
||||
SuccessOrExit(error = ParseAsUint64(aArgs[index], dataset.mPendingTimestamp));
|
||||
}
|
||||
else if (strcmp(aArgs[index], "masterkey") == 0)
|
||||
{
|
||||
VerifyOrExit(++index < aArgsLength, error = OT_ERROR_INVALID_ARGS);
|
||||
dataset.mComponents.mIsMasterKeyPresent = true;
|
||||
VerifyOrExit((length = Interpreter::Hex2Bin(aArgs[index], dataset.mMasterKey.m8,
|
||||
sizeof(dataset.mMasterKey.m8))) == OT_MASTER_KEY_SIZE,
|
||||
error = OT_ERROR_INVALID_ARGS);
|
||||
length = 0;
|
||||
SuccessOrExit(error = ParseAsHexString(aArgs[index], dataset.mMasterKey.m8));
|
||||
}
|
||||
else if (strcmp(aArgs[index], "networkname") == 0)
|
||||
{
|
||||
size_t length;
|
||||
|
||||
VerifyOrExit(++index < aArgsLength, error = OT_ERROR_INVALID_ARGS);
|
||||
dataset.mComponents.mIsNetworkNamePresent = true;
|
||||
VerifyOrExit((length = static_cast<int>(strlen(aArgs[index]))) <= OT_NETWORK_NAME_MAX_SIZE,
|
||||
error = OT_ERROR_INVALID_ARGS);
|
||||
VerifyOrExit((length = strlen(aArgs[index])) <= OT_NETWORK_NAME_MAX_SIZE, error = OT_ERROR_INVALID_ARGS);
|
||||
memset(&dataset.mNetworkName, 0, sizeof(sDataset.mNetworkName));
|
||||
memcpy(dataset.mNetworkName.m8, aArgs[index], static_cast<size_t>(length));
|
||||
length = 0;
|
||||
memcpy(dataset.mNetworkName.m8, aArgs[index], length);
|
||||
}
|
||||
else if (strcmp(aArgs[index], "extpanid") == 0)
|
||||
{
|
||||
VerifyOrExit(++index < aArgsLength, error = OT_ERROR_INVALID_ARGS);
|
||||
dataset.mComponents.mIsExtendedPanIdPresent = true;
|
||||
VerifyOrExit(Interpreter::Hex2Bin(aArgs[index], dataset.mExtendedPanId.m8,
|
||||
sizeof(dataset.mExtendedPanId.m8)) == sizeof(dataset.mExtendedPanId.m8),
|
||||
error = OT_ERROR_INVALID_ARGS);
|
||||
SuccessOrExit(error = ParseAsHexString(aArgs[index], dataset.mExtendedPanId.m8));
|
||||
}
|
||||
else if (strcmp(aArgs[index], "localprefix") == 0)
|
||||
{
|
||||
otIp6Address prefix;
|
||||
|
||||
VerifyOrExit(++index < aArgsLength, error = OT_ERROR_INVALID_ARGS);
|
||||
dataset.mComponents.mIsMeshLocalPrefixPresent = true;
|
||||
SuccessOrExit(error = otIp6AddressFromString(aArgs[index], &prefix));
|
||||
SuccessOrExit(error = ParseAsIp6Address(aArgs[index], prefix));
|
||||
memcpy(dataset.mMeshLocalPrefix.m8, prefix.mFields.m8, sizeof(dataset.mMeshLocalPrefix.m8));
|
||||
}
|
||||
else if (strcmp(aArgs[index], "delaytimer") == 0)
|
||||
{
|
||||
VerifyOrExit(++index < aArgsLength, error = OT_ERROR_INVALID_ARGS);
|
||||
dataset.mComponents.mIsDelayPresent = true;
|
||||
SuccessOrExit(error = Interpreter::ParseLong(aArgs[index], value));
|
||||
dataset.mDelay = static_cast<uint32_t>(value);
|
||||
SuccessOrExit(error = ParseAsUint32(aArgs[index], dataset.mDelay));
|
||||
}
|
||||
else if (strcmp(aArgs[index], "panid") == 0)
|
||||
{
|
||||
VerifyOrExit(++index < aArgsLength, error = OT_ERROR_INVALID_ARGS);
|
||||
dataset.mComponents.mIsPanIdPresent = true;
|
||||
SuccessOrExit(error = Interpreter::ParseLong(aArgs[index], value));
|
||||
dataset.mPanId = static_cast<otPanId>(value);
|
||||
SuccessOrExit(error = ParseAsUint16(aArgs[index], dataset.mPanId));
|
||||
}
|
||||
else if (strcmp(aArgs[index], "channel") == 0)
|
||||
{
|
||||
VerifyOrExit(++index < aArgsLength, error = OT_ERROR_INVALID_ARGS);
|
||||
dataset.mComponents.mIsChannelPresent = true;
|
||||
SuccessOrExit(error = Interpreter::ParseLong(aArgs[index], value));
|
||||
dataset.mChannel = static_cast<uint16_t>(value);
|
||||
SuccessOrExit(error = ParseAsUint16(aArgs[index], dataset.mChannel));
|
||||
}
|
||||
else if (strcmp(aArgs[index], "channelmask") == 0)
|
||||
{
|
||||
VerifyOrExit(++index < aArgsLength, error = OT_ERROR_INVALID_ARGS);
|
||||
dataset.mComponents.mIsChannelMaskPresent = true;
|
||||
SuccessOrExit(error = Interpreter::ParseLong(aArgs[index], value));
|
||||
dataset.mChannelMask = static_cast<uint32_t>(value);
|
||||
SuccessOrExit(error = ParseAsUint32(aArgs[index], dataset.mChannelMask));
|
||||
}
|
||||
else if (strcmp(aArgs[index], "-x") == 0)
|
||||
{
|
||||
uint16_t length;
|
||||
|
||||
VerifyOrExit(++index < aArgsLength, error = OT_ERROR_INVALID_ARGS);
|
||||
length = static_cast<int>((strlen(aArgs[index]) + 1) / 2);
|
||||
VerifyOrExit(static_cast<size_t>(length) <= sizeof(tlvs), error = OT_ERROR_NO_BUFS);
|
||||
VerifyOrExit(Interpreter::Hex2Bin(aArgs[index], tlvs, static_cast<uint16_t>(length)) == length,
|
||||
error = OT_ERROR_INVALID_ARGS);
|
||||
length = sizeof(tlvs);
|
||||
SuccessOrExit(error = ParseAsHexString(aArgs[index], length, tlvs));
|
||||
tlvsLength = static_cast<uint8_t>(length);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -665,13 +635,11 @@ otError Dataset::ProcessMgmtSetCommand(uint8_t aArgsLength, char *aArgs[])
|
||||
|
||||
if (strcmp(aArgs[0], "active") == 0)
|
||||
{
|
||||
SuccessOrExit(
|
||||
error = otDatasetSendMgmtActiveSet(mInterpreter.mInstance, &dataset, tlvs, static_cast<uint8_t>(length)));
|
||||
SuccessOrExit(error = otDatasetSendMgmtActiveSet(mInterpreter.mInstance, &dataset, tlvs, tlvsLength));
|
||||
}
|
||||
else if (strcmp(aArgs[0], "pending") == 0)
|
||||
{
|
||||
SuccessOrExit(
|
||||
error = otDatasetSendMgmtPendingSet(mInterpreter.mInstance, &dataset, tlvs, static_cast<uint8_t>(length)));
|
||||
SuccessOrExit(error = otDatasetSendMgmtPendingSet(mInterpreter.mInstance, &dataset, tlvs, tlvsLength));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -687,8 +655,7 @@ otError Dataset::ProcessMgmtGetCommand(uint8_t aArgsLength, char *aArgs[])
|
||||
otError error = OT_ERROR_NONE;
|
||||
otOperationalDatasetComponents datasetComponents;
|
||||
uint8_t tlvs[32];
|
||||
long value;
|
||||
int length = 0;
|
||||
uint8_t tlvsLength = 0;
|
||||
bool destAddrSpecified = false;
|
||||
otIp6Address address;
|
||||
|
||||
@@ -698,8 +665,6 @@ otError Dataset::ProcessMgmtGetCommand(uint8_t aArgsLength, char *aArgs[])
|
||||
|
||||
for (uint8_t index = 1; index < aArgsLength; index++)
|
||||
{
|
||||
VerifyOrExit(static_cast<size_t>(length) < sizeof(tlvs), error = OT_ERROR_NO_BUFS);
|
||||
|
||||
if (strcmp(aArgs[index], "activetimestamp") == 0)
|
||||
{
|
||||
datasetComponents.mIsActiveTimestampPresent = true;
|
||||
@@ -738,18 +703,17 @@ otError Dataset::ProcessMgmtGetCommand(uint8_t aArgsLength, char *aArgs[])
|
||||
}
|
||||
else if (strcmp(aArgs[index], "-x") == 0)
|
||||
{
|
||||
uint16_t length;
|
||||
|
||||
VerifyOrExit(++index < aArgsLength, error = OT_ERROR_INVALID_ARGS);
|
||||
value = static_cast<long>(strlen(aArgs[index]) + 1) / 2;
|
||||
VerifyOrExit(static_cast<size_t>(value) <= (sizeof(tlvs) - static_cast<size_t>(length)),
|
||||
error = OT_ERROR_NO_BUFS);
|
||||
VerifyOrExit(Interpreter::Hex2Bin(aArgs[index], tlvs + length, static_cast<uint16_t>(value)) == value,
|
||||
error = OT_ERROR_INVALID_ARGS);
|
||||
length += value;
|
||||
length = sizeof(tlvs);
|
||||
SuccessOrExit(error = ParseAsHexString(aArgs[index], length, tlvs));
|
||||
tlvsLength = static_cast<uint8_t>(length);
|
||||
}
|
||||
else if (strcmp(aArgs[index], "address") == 0)
|
||||
{
|
||||
VerifyOrExit(++index < aArgsLength, error = OT_ERROR_INVALID_ARGS);
|
||||
SuccessOrExit(error = otIp6AddressFromString(aArgs[index], &address));
|
||||
SuccessOrExit(error = ParseAsIp6Address(aArgs[index], address));
|
||||
destAddrSpecified = true;
|
||||
}
|
||||
else
|
||||
@@ -760,14 +724,12 @@ otError Dataset::ProcessMgmtGetCommand(uint8_t aArgsLength, char *aArgs[])
|
||||
|
||||
if (strcmp(aArgs[0], "active") == 0)
|
||||
{
|
||||
SuccessOrExit(error = otDatasetSendMgmtActiveGet(mInterpreter.mInstance, &datasetComponents, tlvs,
|
||||
static_cast<uint8_t>(length),
|
||||
SuccessOrExit(error = otDatasetSendMgmtActiveGet(mInterpreter.mInstance, &datasetComponents, tlvs, tlvsLength,
|
||||
destAddrSpecified ? &address : nullptr));
|
||||
}
|
||||
else if (strcmp(aArgs[0], "pending") == 0)
|
||||
{
|
||||
SuccessOrExit(error = otDatasetSendMgmtPendingGet(mInterpreter.mInstance, &datasetComponents, tlvs,
|
||||
static_cast<uint8_t>(length),
|
||||
SuccessOrExit(error = otDatasetSendMgmtPendingGet(mInterpreter.mInstance, &datasetComponents, tlvs, tlvsLength,
|
||||
destAddrSpecified ? &address : nullptr));
|
||||
}
|
||||
else
|
||||
@@ -793,9 +755,7 @@ otError Dataset::ProcessPskc(uint8_t aArgsLength, char *aArgs[])
|
||||
}
|
||||
else if (aArgsLength == 1)
|
||||
{
|
||||
VerifyOrExit(Interpreter::Hex2Bin(aArgs[0], sDataset.mPskc.m8, sizeof(sDataset.mPskc)) ==
|
||||
sizeof(sDataset.mPskc),
|
||||
error = OT_ERROR_INVALID_ARGS);
|
||||
SuccessOrExit(error = ParseAsHexString(aArgs[0], sDataset.mPskc.m8));
|
||||
}
|
||||
#if OPENTHREAD_FTD
|
||||
else if (aArgsLength == 2 && !strcmp(aArgs[0], "-p"))
|
||||
@@ -862,11 +822,8 @@ otError Dataset::ProcessSecurityPolicy(uint8_t aArgsLength, char *aArgs[])
|
||||
}
|
||||
else
|
||||
{
|
||||
long value;
|
||||
|
||||
SuccessOrExit(error = Interpreter::ParseLong(aArgs[0], value));
|
||||
sDataset.mSecurityPolicy.mRotationTime = static_cast<uint16_t>(value);
|
||||
sDataset.mSecurityPolicy.mFlags = 0;
|
||||
SuccessOrExit(error = ParseAsUint16(aArgs[0], sDataset.mSecurityPolicy.mRotationTime));
|
||||
sDataset.mSecurityPolicy.mFlags = 0;
|
||||
|
||||
if (aArgsLength > 1)
|
||||
{
|
||||
@@ -911,13 +868,12 @@ otError Dataset::ProcessSet(uint8_t aArgsLength, char *aArgs[])
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
otOperationalDatasetTlvs dataset;
|
||||
int tlvsLength;
|
||||
uint16_t tlvsLength;
|
||||
|
||||
VerifyOrExit(aArgsLength == 2, error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
tlvsLength = Interpreter::Hex2Bin(aArgs[1], dataset.mTlvs, sizeof(dataset.mTlvs));
|
||||
VerifyOrExit((0 <= tlvsLength) && (static_cast<size_t>(tlvsLength) <= sizeof(dataset.mTlvs)),
|
||||
error = OT_ERROR_INVALID_ARGS);
|
||||
tlvsLength = sizeof(dataset.mTlvs);
|
||||
SuccessOrExit(error = ParseAsHexString(aArgs[1], tlvsLength, dataset.mTlvs));
|
||||
dataset.mLength = static_cast<uint8_t>(tlvsLength);
|
||||
|
||||
if (strcmp(aArgs[0], "active") == 0)
|
||||
|
||||
Reference in New Issue
Block a user