blob: efade0586acb4c6726af41c8edfd3b3780e9fe7d [file] [log] [blame]
/*
* Copyright (c) 2016, 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 CLI interpreter.
*/
#include "cli_dataset.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <openthread/dataset.h>
#include <openthread/dataset_ftd.h>
#include <openthread/dataset_updater.h>
#include "cli/cli.hpp"
namespace ot {
namespace Cli {
otOperationalDataset Dataset::sDataset;
otError Dataset::Print(otOperationalDataset &aDataset)
{
if (aDataset.mComponents.mIsPendingTimestampPresent)
{
OutputLine("Pending Timestamp: %lu", aDataset.mPendingTimestamp);
}
if (aDataset.mComponents.mIsActiveTimestampPresent)
{
OutputLine("Active Timestamp: %lu", aDataset.mActiveTimestamp);
}
if (aDataset.mComponents.mIsChannelPresent)
{
OutputLine("Channel: %d", aDataset.mChannel);
}
if (aDataset.mComponents.mIsChannelMaskPresent)
{
OutputLine("Channel Mask: 0x%08x", aDataset.mChannelMask);
}
if (aDataset.mComponents.mIsDelayPresent)
{
OutputLine("Delay: %d", aDataset.mDelay);
}
if (aDataset.mComponents.mIsExtendedPanIdPresent)
{
OutputFormat("Ext PAN ID: ");
OutputBytesLine(aDataset.mExtendedPanId.m8);
}
if (aDataset.mComponents.mIsMeshLocalPrefixPresent)
{
OutputFormat("Mesh Local Prefix: ");
OutputIp6PrefixLine(aDataset.mMeshLocalPrefix);
}
if (aDataset.mComponents.mIsNetworkKeyPresent)
{
OutputFormat("Network Key: ");
OutputBytesLine(aDataset.mNetworkKey.m8);
}
if (aDataset.mComponents.mIsNetworkNamePresent)
{
OutputFormat("Network Name: ");
OutputLine("%s", aDataset.mNetworkName.m8);
}
if (aDataset.mComponents.mIsPanIdPresent)
{
OutputLine("PAN ID: 0x%04x", aDataset.mPanId);
}
if (aDataset.mComponents.mIsPskcPresent)
{
OutputFormat("PSKc: ");
OutputBytesLine(aDataset.mPskc.m8);
}
if (aDataset.mComponents.mIsSecurityPolicyPresent)
{
OutputFormat("Security Policy: ");
OutputSecurityPolicy(aDataset.mSecurityPolicy);
}
return OT_ERROR_NONE;
}
template <> otError Dataset::Process<Cmd("init")>(Arg aArgs[])
{
otError error = OT_ERROR_INVALID_ARGS;
if (aArgs[0] == "active")
{
error = otDatasetGetActive(GetInstancePtr(), &sDataset);
}
else if (aArgs[0] == "pending")
{
error = otDatasetGetPending(GetInstancePtr(), &sDataset);
}
#if OPENTHREAD_FTD
else if (aArgs[0] == "new")
{
error = otDatasetCreateNewNetwork(GetInstancePtr(), &sDataset);
}
#endif
else if (aArgs[0] == "tlvs")
{
otOperationalDatasetTlvs datasetTlvs;
uint16_t size = sizeof(datasetTlvs.mTlvs);
SuccessOrExit(error = aArgs[1].ParseAsHexString(size, datasetTlvs.mTlvs));
datasetTlvs.mLength = static_cast<uint8_t>(size);
SuccessOrExit(error = otDatasetParseTlvs(&datasetTlvs, &sDataset));
}
exit:
return error;
}
template <> otError Dataset::Process<Cmd("active")>(Arg aArgs[])
{
otError error = OT_ERROR_INVALID_ARGS;
if (aArgs[0].IsEmpty())
{
otOperationalDataset dataset;
SuccessOrExit(error = otDatasetGetActive(GetInstancePtr(), &dataset));
error = Print(dataset);
}
else if (aArgs[0] == "-x")
{
otOperationalDatasetTlvs dataset;
SuccessOrExit(error = otDatasetGetActiveTlvs(GetInstancePtr(), &dataset));
OutputBytesLine(dataset.mTlvs, dataset.mLength);
}
exit:
return error;
}
template <> otError Dataset::Process<Cmd("pending")>(Arg aArgs[])
{
otError error = OT_ERROR_INVALID_ARGS;
if (aArgs[0].IsEmpty())
{
otOperationalDataset dataset;
SuccessOrExit(error = otDatasetGetPending(GetInstancePtr(), &dataset));
error = Print(dataset);
}
else if (aArgs[0] == "-x")
{
otOperationalDatasetTlvs dataset;
SuccessOrExit(error = otDatasetGetPendingTlvs(GetInstancePtr(), &dataset));
OutputBytesLine(dataset.mTlvs, dataset.mLength);
}
exit:
return error;
}
template <> otError Dataset::Process<Cmd("activetimestamp")>(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
if (aArgs[0].IsEmpty())
{
if (sDataset.mComponents.mIsActiveTimestampPresent)
{
OutputLine("%lu", sDataset.mActiveTimestamp);
}
}
else
{
SuccessOrExit(error = aArgs[0].ParseAsUint64(sDataset.mActiveTimestamp));
sDataset.mComponents.mIsActiveTimestampPresent = true;
}
exit:
return error;
}
template <> otError Dataset::Process<Cmd("channel")>(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
if (aArgs[0].IsEmpty())
{
if (sDataset.mComponents.mIsChannelPresent)
{
OutputLine("%d", sDataset.mChannel);
}
}
else
{
SuccessOrExit(error = aArgs[0].ParseAsUint16(sDataset.mChannel));
sDataset.mComponents.mIsChannelPresent = true;
}
exit:
return error;
}
template <> otError Dataset::Process<Cmd("channelmask")>(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
if (aArgs[0].IsEmpty())
{
if (sDataset.mComponents.mIsChannelMaskPresent)
{
OutputLine("0x%08x", sDataset.mChannelMask);
}
}
else
{
SuccessOrExit(error = aArgs[0].ParseAsUint32(sDataset.mChannelMask));
sDataset.mComponents.mIsChannelMaskPresent = true;
}
exit:
return error;
}
template <> otError Dataset::Process<Cmd("clear")>(Arg aArgs[])
{
OT_UNUSED_VARIABLE(aArgs);
memset(&sDataset, 0, sizeof(sDataset));
return OT_ERROR_NONE;
}
template <> otError Dataset::Process<Cmd("commit")>(Arg aArgs[])
{
otError error = OT_ERROR_INVALID_ARGS;
if (aArgs[0] == "active")
{
error = otDatasetSetActive(GetInstancePtr(), &sDataset);
}
else if (aArgs[0] == "pending")
{
error = otDatasetSetPending(GetInstancePtr(), &sDataset);
}
return error;
}
template <> otError Dataset::Process<Cmd("delay")>(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
if (aArgs[0].IsEmpty())
{
if (sDataset.mComponents.mIsDelayPresent)
{
OutputLine("%d", sDataset.mDelay);
}
}
else
{
SuccessOrExit(error = aArgs[0].ParseAsUint32(sDataset.mDelay));
sDataset.mComponents.mIsDelayPresent = true;
}
exit:
return error;
}
template <> otError Dataset::Process<Cmd("extpanid")>(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
if (aArgs[0].IsEmpty())
{
if (sDataset.mComponents.mIsExtendedPanIdPresent)
{
OutputBytesLine(sDataset.mExtendedPanId.m8);
}
}
else
{
SuccessOrExit(error = aArgs[0].ParseAsHexString(sDataset.mExtendedPanId.m8));
sDataset.mComponents.mIsExtendedPanIdPresent = true;
}
exit:
return error;
}
template <> otError Dataset::Process<Cmd("meshlocalprefix")>(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
if (aArgs[0].IsEmpty())
{
if (sDataset.mComponents.mIsMeshLocalPrefixPresent)
{
OutputFormat("Mesh Local Prefix: ");
OutputIp6PrefixLine(sDataset.mMeshLocalPrefix);
}
}
else
{
otIp6Address prefix;
SuccessOrExit(error = aArgs[0].ParseAsIp6Address(prefix));
memcpy(sDataset.mMeshLocalPrefix.m8, prefix.mFields.m8, sizeof(sDataset.mMeshLocalPrefix.m8));
sDataset.mComponents.mIsMeshLocalPrefixPresent = true;
}
exit:
return error;
}
template <> otError Dataset::Process<Cmd("networkkey")>(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
if (aArgs[0].IsEmpty())
{
if (sDataset.mComponents.mIsNetworkKeyPresent)
{
OutputBytesLine(sDataset.mNetworkKey.m8);
}
}
else
{
SuccessOrExit(error = aArgs[0].ParseAsHexString(sDataset.mNetworkKey.m8));
sDataset.mComponents.mIsNetworkKeyPresent = true;
}
exit:
return error;
}
template <> otError Dataset::Process<Cmd("networkname")>(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
if (aArgs[0].IsEmpty())
{
if (sDataset.mComponents.mIsNetworkNamePresent)
{
OutputLine("%s", sDataset.mNetworkName.m8);
}
}
else
{
SuccessOrExit(error = otNetworkNameFromString(&sDataset.mNetworkName, aArgs[0].GetCString()));
sDataset.mComponents.mIsNetworkNamePresent = true;
}
exit:
return error;
}
template <> otError Dataset::Process<Cmd("panid")>(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
if (aArgs[0].IsEmpty())
{
if (sDataset.mComponents.mIsPanIdPresent)
{
OutputLine("0x%04x", sDataset.mPanId);
}
}
else
{
SuccessOrExit(error = aArgs[0].ParseAsUint16(sDataset.mPanId));
sDataset.mComponents.mIsPanIdPresent = true;
}
exit:
return error;
}
template <> otError Dataset::Process<Cmd("pendingtimestamp")>(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
if (aArgs[0].IsEmpty())
{
if (sDataset.mComponents.mIsPendingTimestampPresent)
{
OutputLine("%lu", sDataset.mPendingTimestamp);
}
}
else
{
SuccessOrExit(error = aArgs[0].ParseAsUint64(sDataset.mPendingTimestamp));
sDataset.mComponents.mIsPendingTimestampPresent = true;
}
exit:
return error;
}
template <> otError Dataset::Process<Cmd("mgmtsetcommand")>(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
otOperationalDataset dataset;
uint8_t tlvs[128];
uint8_t tlvsLength = 0;
memset(&dataset, 0, sizeof(dataset));
for (Arg *arg = &aArgs[1]; !arg->IsEmpty(); arg++)
{
if (*arg == "activetimestamp")
{
arg++;
dataset.mComponents.mIsActiveTimestampPresent = true;
SuccessOrExit(error = arg->ParseAsUint64(dataset.mActiveTimestamp));
}
else if (*arg == "pendingtimestamp")
{
arg++;
dataset.mComponents.mIsPendingTimestampPresent = true;
SuccessOrExit(error = arg->ParseAsUint64(dataset.mPendingTimestamp));
}
else if (*arg == "networkkey")
{
arg++;
dataset.mComponents.mIsNetworkKeyPresent = true;
SuccessOrExit(error = arg->ParseAsHexString(dataset.mNetworkKey.m8));
}
else if (*arg == "networkname")
{
arg++;
dataset.mComponents.mIsNetworkNamePresent = true;
VerifyOrExit(!arg->IsEmpty(), error = OT_ERROR_INVALID_ARGS);
SuccessOrExit(error = otNetworkNameFromString(&dataset.mNetworkName, arg->GetCString()));
}
else if (*arg == "extpanid")
{
arg++;
dataset.mComponents.mIsExtendedPanIdPresent = true;
SuccessOrExit(error = arg->ParseAsHexString(dataset.mExtendedPanId.m8));
}
else if (*arg == "localprefix")
{
otIp6Address prefix;
arg++;
dataset.mComponents.mIsMeshLocalPrefixPresent = true;
SuccessOrExit(error = arg->ParseAsIp6Address(prefix));
memcpy(dataset.mMeshLocalPrefix.m8, prefix.mFields.m8, sizeof(dataset.mMeshLocalPrefix.m8));
}
else if (*arg == "delaytimer")
{
arg++;
dataset.mComponents.mIsDelayPresent = true;
SuccessOrExit(error = arg->ParseAsUint32(dataset.mDelay));
}
else if (*arg == "panid")
{
arg++;
dataset.mComponents.mIsPanIdPresent = true;
SuccessOrExit(error = arg->ParseAsUint16(dataset.mPanId));
}
else if (*arg == "channel")
{
arg++;
dataset.mComponents.mIsChannelPresent = true;
SuccessOrExit(error = arg->ParseAsUint16(dataset.mChannel));
}
else if (*arg == "channelmask")
{
arg++;
dataset.mComponents.mIsChannelMaskPresent = true;
SuccessOrExit(error = arg->ParseAsUint32(dataset.mChannelMask));
}
else if (*arg == "securitypolicy")
{
arg++;
SuccessOrExit(error = ParseSecurityPolicy(dataset.mSecurityPolicy, arg));
dataset.mComponents.mIsSecurityPolicyPresent = true;
}
else if (*arg == "-x")
{
uint16_t length;
arg++;
length = sizeof(tlvs);
SuccessOrExit(error = arg->ParseAsHexString(length, tlvs));
tlvsLength = static_cast<uint8_t>(length);
}
else
{
ExitNow(error = OT_ERROR_INVALID_ARGS);
}
}
if (aArgs[0] == "active")
{
error = otDatasetSendMgmtActiveSet(GetInstancePtr(), &dataset, tlvs, tlvsLength, /* aCallback */ nullptr,
/* aContext */ nullptr);
}
else if (aArgs[0] == "pending")
{
error = otDatasetSendMgmtPendingSet(GetInstancePtr(), &dataset, tlvs, tlvsLength, /* aCallback */ nullptr,
/* aContext */ nullptr);
}
else
{
error = OT_ERROR_INVALID_ARGS;
}
exit:
return error;
}
template <> otError Dataset::Process<Cmd("mgmtgetcommand")>(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
otOperationalDatasetComponents datasetComponents;
uint8_t tlvs[32];
uint8_t tlvsLength = 0;
bool destAddrSpecified = false;
otIp6Address address;
memset(&datasetComponents, 0, sizeof(datasetComponents));
for (Arg *arg = &aArgs[1]; !arg->IsEmpty(); arg++)
{
if (*arg == "activetimestamp")
{
datasetComponents.mIsActiveTimestampPresent = true;
}
else if (*arg == "pendingtimestamp")
{
datasetComponents.mIsPendingTimestampPresent = true;
}
else if (*arg == "networkkey")
{
datasetComponents.mIsNetworkKeyPresent = true;
}
else if (*arg == "networkname")
{
datasetComponents.mIsNetworkNamePresent = true;
}
else if (*arg == "extpanid")
{
datasetComponents.mIsExtendedPanIdPresent = true;
}
else if (*arg == "localprefix")
{
datasetComponents.mIsMeshLocalPrefixPresent = true;
}
else if (*arg == "delaytimer")
{
datasetComponents.mIsDelayPresent = true;
}
else if (*arg == "panid")
{
datasetComponents.mIsPanIdPresent = true;
}
else if (*arg == "channel")
{
datasetComponents.mIsChannelPresent = true;
}
else if (*arg == "securitypolicy")
{
datasetComponents.mIsSecurityPolicyPresent = true;
}
else if (*arg == "-x")
{
uint16_t length;
arg++;
length = sizeof(tlvs);
SuccessOrExit(error = arg->ParseAsHexString(length, tlvs));
tlvsLength = static_cast<uint8_t>(length);
}
else if (*arg == "address")
{
arg++;
SuccessOrExit(error = arg->ParseAsIp6Address(address));
destAddrSpecified = true;
}
else
{
ExitNow(error = OT_ERROR_INVALID_ARGS);
}
}
if (aArgs[0] == "active")
{
error = otDatasetSendMgmtActiveGet(GetInstancePtr(), &datasetComponents, tlvs, tlvsLength,
destAddrSpecified ? &address : nullptr);
}
else if (aArgs[0] == "pending")
{
error = otDatasetSendMgmtPendingGet(GetInstancePtr(), &datasetComponents, tlvs, tlvsLength,
destAddrSpecified ? &address : nullptr);
}
else
{
error = OT_ERROR_INVALID_ARGS;
}
exit:
return error;
}
template <> otError Dataset::Process<Cmd("pskc")>(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
if (aArgs[0].IsEmpty())
{
// sDataset holds the key as a literal string, we don't
// need to export it from PSA ITS.
if (sDataset.mComponents.mIsPskcPresent)
{
OutputBytesLine(sDataset.mPskc.m8);
}
}
else
{
#if OPENTHREAD_FTD
if (aArgs[0] == "-p")
{
VerifyOrExit(!aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
SuccessOrExit(
error = otDatasetGeneratePskc(
aArgs[1].GetCString(),
(sDataset.mComponents.mIsNetworkNamePresent
? &sDataset.mNetworkName
: reinterpret_cast<const otNetworkName *>(otThreadGetNetworkName(GetInstancePtr()))),
(sDataset.mComponents.mIsExtendedPanIdPresent ? &sDataset.mExtendedPanId
: otThreadGetExtendedPanId(GetInstancePtr())),
&sDataset.mPskc));
}
else
#endif
{
SuccessOrExit(error = aArgs[0].ParseAsHexString(sDataset.mPskc.m8));
}
sDataset.mComponents.mIsPskcPresent = true;
}
exit:
return error;
}
void Dataset::OutputSecurityPolicy(const otSecurityPolicy &aSecurityPolicy)
{
OutputFormat("%d ", aSecurityPolicy.mRotationTime);
if (aSecurityPolicy.mObtainNetworkKeyEnabled)
{
OutputFormat("o");
}
if (aSecurityPolicy.mNativeCommissioningEnabled)
{
OutputFormat("n");
}
if (aSecurityPolicy.mRoutersEnabled)
{
OutputFormat("r");
}
if (aSecurityPolicy.mExternalCommissioningEnabled)
{
OutputFormat("c");
}
if (aSecurityPolicy.mCommercialCommissioningEnabled)
{
OutputFormat("C");
}
if (aSecurityPolicy.mAutonomousEnrollmentEnabled)
{
OutputFormat("e");
}
if (aSecurityPolicy.mNetworkKeyProvisioningEnabled)
{
OutputFormat("p");
}
if (aSecurityPolicy.mNonCcmRoutersEnabled)
{
OutputFormat("R");
}
OutputLine("");
}
otError Dataset::ParseSecurityPolicy(otSecurityPolicy &aSecurityPolicy, Arg *&aArgs)
{
otError error;
otSecurityPolicy policy;
memset(&policy, 0, sizeof(policy));
SuccessOrExit(error = aArgs->ParseAsUint16(policy.mRotationTime));
aArgs++;
VerifyOrExit(!aArgs->IsEmpty());
for (const char *flag = aArgs->GetCString(); *flag != '\0'; flag++)
{
switch (*flag)
{
case 'o':
policy.mObtainNetworkKeyEnabled = true;
break;
case 'n':
policy.mNativeCommissioningEnabled = true;
break;
case 'r':
policy.mRoutersEnabled = true;
break;
case 'c':
policy.mExternalCommissioningEnabled = true;
break;
case 'C':
policy.mCommercialCommissioningEnabled = true;
break;
case 'e':
policy.mAutonomousEnrollmentEnabled = true;
break;
case 'p':
policy.mNetworkKeyProvisioningEnabled = true;
break;
case 'R':
policy.mNonCcmRoutersEnabled = true;
break;
default:
ExitNow(error = OT_ERROR_INVALID_ARGS);
}
}
aArgs++;
exit:
if (error == OT_ERROR_NONE)
{
aSecurityPolicy = policy;
}
return error;
}
template <> otError Dataset::Process<Cmd("securitypolicy")>(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
if (aArgs[0].IsEmpty())
{
if (sDataset.mComponents.mIsSecurityPolicyPresent)
{
OutputSecurityPolicy(sDataset.mSecurityPolicy);
}
}
else
{
Arg *arg = &aArgs[0];
SuccessOrExit(error = ParseSecurityPolicy(sDataset.mSecurityPolicy, arg));
sDataset.mComponents.mIsSecurityPolicyPresent = true;
}
exit:
return error;
}
template <> otError Dataset::Process<Cmd("set")>(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
MeshCoP::Dataset::Type datasetType;
if (aArgs[0] == "active")
{
datasetType = MeshCoP::Dataset::Type::kActive;
}
else if (aArgs[0] == "pending")
{
datasetType = MeshCoP::Dataset::Type::kPending;
}
else
{
ExitNow(error = OT_ERROR_INVALID_ARGS);
}
{
MeshCoP::Dataset dataset;
MeshCoP::Dataset::Info datasetInfo;
uint16_t tlvsLength = MeshCoP::Dataset::kMaxSize;
SuccessOrExit(error = aArgs[1].ParseAsHexString(tlvsLength, dataset.GetBytes()));
dataset.SetSize(tlvsLength);
VerifyOrExit(dataset.IsValid(), error = OT_ERROR_INVALID_ARGS);
dataset.ConvertTo(datasetInfo);
switch (datasetType)
{
case MeshCoP::Dataset::Type::kActive:
SuccessOrExit(error = otDatasetSetActive(GetInstancePtr(), &datasetInfo));
break;
case MeshCoP::Dataset::Type::kPending:
SuccessOrExit(error = otDatasetSetPending(GetInstancePtr(), &datasetInfo));
break;
}
}
exit:
return error;
}
#if OPENTHREAD_CONFIG_DATASET_UPDATER_ENABLE && OPENTHREAD_FTD
template <> otError Dataset::Process<Cmd("updater")>(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
if (aArgs[0].IsEmpty())
{
OutputEnabledDisabledStatus(otDatasetUpdaterIsUpdateOngoing(GetInstancePtr()));
}
else if (aArgs[0] == "start")
{
error = otDatasetUpdaterRequestUpdate(GetInstancePtr(), &sDataset, &Dataset::HandleDatasetUpdater, this);
}
else if (aArgs[0] == "cancel")
{
otDatasetUpdaterCancelUpdate(GetInstancePtr());
}
else
{
error = OT_ERROR_INVALID_ARGS;
}
return error;
}
void Dataset::HandleDatasetUpdater(otError aError, void *aContext)
{
static_cast<Dataset *>(aContext)->HandleDatasetUpdater(aError);
}
void Dataset::HandleDatasetUpdater(otError aError)
{
OutputLine("Dataset update complete: %s", otThreadErrorToString(aError));
}
#endif // OPENTHREAD_CONFIG_DATASET_UPDATER_ENABLE && OPENTHREAD_FTD
otError Dataset::Process(Arg aArgs[])
{
#define CmdEntry(aCommandString) \
{ \
aCommandString, &Dataset::Process<Cmd(aCommandString)> \
}
static constexpr Command kCommands[] = {
CmdEntry("active"),
CmdEntry("activetimestamp"),
CmdEntry("channel"),
CmdEntry("channelmask"),
CmdEntry("clear"),
CmdEntry("commit"),
CmdEntry("delay"),
CmdEntry("extpanid"),
CmdEntry("init"),
CmdEntry("meshlocalprefix"),
CmdEntry("mgmtgetcommand"),
CmdEntry("mgmtsetcommand"),
CmdEntry("networkkey"),
CmdEntry("networkname"),
CmdEntry("panid"),
CmdEntry("pending"),
CmdEntry("pendingtimestamp"),
CmdEntry("pskc"),
CmdEntry("securitypolicy"),
CmdEntry("set"),
#if OPENTHREAD_CONFIG_DATASET_UPDATER_ENABLE && OPENTHREAD_FTD
CmdEntry("updater"),
#endif
};
#undef CmdEntry
static_assert(BinarySearch::IsSorted(kCommands), "kCommands is not sorted");
otError error = OT_ERROR_INVALID_COMMAND;
const Command *command;
if (aArgs[0].IsEmpty())
{
ExitNow(error = Print(sDataset));
}
if (aArgs[0] == "help")
{
OutputCommandTable(kCommands);
ExitNow(error = OT_ERROR_NONE);
}
command = BinarySearch::Find(aArgs[0].GetCString(), kCommands);
VerifyOrExit(command != nullptr);
error = (this->*command->mHandler)(aArgs + 1);
exit:
return error;
}
} // namespace Cli
} // namespace ot