blob: 7aa0dd5ed0e22ab66f409486d222d71655b35501 [file] [log] [blame]
/*
* Copyright (c) 2020, 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 CLI commands for Network Data.
*/
#include "cli_network_data.hpp"
#include <openthread/border_router.h>
#include <openthread/netdata_publisher.h>
#include <openthread/server.h>
#include "cli/cli.hpp"
#include "common/encoding.hpp"
namespace ot {
namespace Cli {
NetworkData::NetworkData(otInstance *aInstance, OutputImplementer &aOutputImplementer)
: Utils(aInstance, aOutputImplementer)
{
#if OPENTHREAD_CONFIG_BORDER_ROUTER_SIGNAL_NETWORK_DATA_FULL
mFullCallbackWasCalled = false;
otBorderRouterSetNetDataFullCallback(aInstance, HandleNetdataFull, this);
#endif
}
void NetworkData::PrefixFlagsToString(const otBorderRouterConfig &aConfig, FlagsString &aString)
{
char *flagsPtr = &aString[0];
if (aConfig.mPreferred)
{
*flagsPtr++ = 'p';
}
if (aConfig.mSlaac)
{
*flagsPtr++ = 'a';
}
if (aConfig.mDhcp)
{
*flagsPtr++ = 'd';
}
if (aConfig.mConfigure)
{
*flagsPtr++ = 'c';
}
if (aConfig.mDefaultRoute)
{
*flagsPtr++ = 'r';
}
if (aConfig.mOnMesh)
{
*flagsPtr++ = 'o';
}
if (aConfig.mStable)
{
*flagsPtr++ = 's';
}
if (aConfig.mNdDns)
{
*flagsPtr++ = 'n';
}
if (aConfig.mDp)
{
*flagsPtr++ = 'D';
}
*flagsPtr = '\0';
}
void NetworkData::OutputPrefix(const otBorderRouterConfig &aConfig)
{
FlagsString flagsString;
OutputIp6Prefix(aConfig.mPrefix);
PrefixFlagsToString(aConfig, flagsString);
if (flagsString[0] != '\0')
{
OutputFormat(" %s", flagsString);
}
OutputLine(" %s %04x", Interpreter::PreferenceToString(aConfig.mPreference), aConfig.mRloc16);
}
void NetworkData::RouteFlagsToString(const otExternalRouteConfig &aConfig, FlagsString &aString)
{
char *flagsPtr = &aString[0];
if (aConfig.mStable)
{
*flagsPtr++ = 's';
}
if (aConfig.mNat64)
{
*flagsPtr++ = 'n';
}
if (aConfig.mAdvPio)
{
*flagsPtr++ = 'a';
}
*flagsPtr = '\0';
}
void NetworkData::OutputRoute(const otExternalRouteConfig &aConfig)
{
FlagsString flagsString;
OutputIp6Prefix(aConfig.mPrefix);
RouteFlagsToString(aConfig, flagsString);
if (flagsString[0] != '\0')
{
OutputFormat(" %s", flagsString);
}
OutputLine(" %s %04x", Interpreter::PreferenceToString(aConfig.mPreference), aConfig.mRloc16);
}
void NetworkData::OutputService(const otServiceConfig &aConfig)
{
OutputFormat("%lu ", ToUlong(aConfig.mEnterpriseNumber));
OutputBytes(aConfig.mServiceData, aConfig.mServiceDataLength);
OutputFormat(" ");
OutputBytes(aConfig.mServerConfig.mServerData, aConfig.mServerConfig.mServerDataLength);
if (aConfig.mServerConfig.mStable)
{
OutputFormat(" s");
}
OutputLine(" %04x", aConfig.mServerConfig.mRloc16);
}
/**
* @cli netdata length
* @code
* netdata length
* 23
* Done
* @endcode
* @par api_copy
* #otNetDataGetLength
*/
template <> otError NetworkData::Process<Cmd("length")>(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
OutputLine("%u", otNetDataGetLength(GetInstancePtr()));
exit:
return error;
}
template <> otError NetworkData::Process<Cmd("maxlength")>(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
/**
* @cli netdata maxlength
* @code
* netdata maxlength
* 40
* Done
* @endcode
* @par api_copy
* #otNetDataGetMaxLength
*/
if (aArgs[0].IsEmpty())
{
OutputLine("%u", otNetDataGetMaxLength(GetInstancePtr()));
}
/**
* @cli netdata maxlength reset
* @code
* netdata maxlength reset
* Done
* @endcode
* @par api_copy
* #otNetDataResetMaxLength
*/
else if (aArgs[0] == "reset")
{
otNetDataResetMaxLength(GetInstancePtr());
}
else
{
error = OT_ERROR_INVALID_ARGS;
}
return error;
}
#if OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
template <> otError NetworkData::Process<Cmd("publish")>(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
#if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
if (aArgs[0] == "dnssrp")
{
/**
* @cli netdata publish dnssrp anycast
* @code
* netdata publish dnssrp anycast 1
* Done
* @endcode
* @cparam netdata publish dnssrp anycast @ca{seq-num}
* @par
* Publishes a DNS/SRP Service Anycast Address with a sequence number. Any current
* DNS/SRP Service entry being published from a previous `publish dnssrp{anycast|unicast}`
* command is removed and replaced with the new arguments.
* @par
* `OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE` must be enabled.
* @csa{netdata publish dnssrp unicast (addr,port)}
* @csa{netdata publish dnssrp unicast (mle)}
* @sa otNetDataPublishDnsSrpServiceAnycast
* @endcli
*/
if (aArgs[1] == "anycast")
{
uint8_t sequenceNumber;
SuccessOrExit(error = aArgs[2].ParseAsUint8(sequenceNumber));
otNetDataPublishDnsSrpServiceAnycast(GetInstancePtr(), sequenceNumber);
ExitNow();
}
if (aArgs[1] == "unicast")
{
otIp6Address address;
uint16_t port;
/**
* @cli netdata publish dnssrp unicast (mle)
* @code
* netdata publish dnssrp unicast 50152
* Done
* @endcode
* @cparam netdata publish dnssrp unicast @ca{port}
* @par
* Publishes the device's Mesh-Local EID with a port number. MLE and port information is
* included in the Server TLV data. To use a different Unicast address, use the
* `netdata publish dnssrp unicast (addr,port)` command.
* @par
* Any current DNS/SRP Service entry being published from a previous
* `publish dnssrp{anycast|unicast}` command is removed and replaced with the new arguments.
* @par
* `OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE` must be enabled.
* @csa{netdata publish dnssrp unicast (addr,port)}
* @csa{netdata publish dnssrp anycast}
* @sa otNetDataPublishDnsSrpServiceUnicastMeshLocalEid
*/
if (aArgs[3].IsEmpty())
{
SuccessOrExit(error = aArgs[2].ParseAsUint16(port));
otNetDataPublishDnsSrpServiceUnicastMeshLocalEid(GetInstancePtr(), port);
ExitNow();
}
/**
* @cli netdata publish dnssrp unicast (addr,port)
* @code
* netdata publish dnssrp unicast fd00::1234 51525
* Done
* @endcode
* @cparam netdata publish dnssrp unicast @ca{address} @ca{port}
* @par
* Publishes a DNS/SRP Service Unicast Address with an address and port number. The address
* and port information is included in Service TLV data. Any current DNS/SRP Service entry being
* published from a previous `publish dnssrp{anycast|unicast}` command is removed and replaced
* with the new arguments.
* @par
* `OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE` must be enabled.
* @csa{netdata publish dnssrp unicast (mle)}
* @csa{netdata publish dnssrp anycast}
* @sa otNetDataPublishDnsSrpServiceUnicast
*/
SuccessOrExit(error = aArgs[2].ParseAsIp6Address(address));
SuccessOrExit(error = aArgs[3].ParseAsUint16(port));
otNetDataPublishDnsSrpServiceUnicast(GetInstancePtr(), &address, port);
ExitNow();
}
}
#endif // OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
/**
* @cli netdata publish prefix
* @code
* netdata publish prefix fd00:1234:5678::/64 paos med
* Done
* @endcode
* @cparam netdata publish prefix @ca{prefix} [@ca{padcrosnD}] [@ca{high}|@ca{med}|@ca{low}]
* OT CLI uses mapped arguments to configure #otBorderRouterConfig values. @moreinfo{the @overview}.
* @par
* Publish an on-mesh prefix entry. @moreinfo{@netdata}.
* @sa otNetDataPublishOnMeshPrefix
*/
if (aArgs[0] == "prefix")
{
otBorderRouterConfig config;
SuccessOrExit(error = Interpreter::ParsePrefix(aArgs + 1, config));
error = otNetDataPublishOnMeshPrefix(GetInstancePtr(), &config);
ExitNow();
}
/**
* @cli netdata publish route
* @code
* netdata publish route fd00:1234:5678::/64 s high
* Done
* @endcode
* @cparam publish route @ca{prefix} [@ca{sn}] [@ca{high}|@ca{med}|@ca{low}]
* OT CLI uses mapped arguments to configure #otExternalRouteConfig values. @moreinfo{the @overview}.
* @par
* Publish an external route entry. @moreinfo{@netdata}.
* @sa otNetDataPublishExternalRoute
*/
if (aArgs[0] == "route")
{
otExternalRouteConfig config;
SuccessOrExit(error = Interpreter::ParseRoute(aArgs + 1, config));
error = otNetDataPublishExternalRoute(GetInstancePtr(), &config);
ExitNow();
}
/**
* @cli netdata publish replace
* @code
* netdata publish replace ::/0 fd00:1234:5678::/64 s high
* Done
* @endcode
* @cparam netdata publish replace @ca{oldprefix} @ca{prefix} [@ca{sn}] [@ca{high}|@ca{med}|@ca{low}]
* OT CLI uses mapped arguments to configure #otExternalRouteConfig values. @moreinfo{the @overview}.
* @par
* Replaces a previously published external route entry. @moreinfo{@netdata}.
* @sa otNetDataReplacePublishedExternalRoute
*/
if (aArgs[0] == "replace")
{
otIp6Prefix prefix;
otExternalRouteConfig config;
SuccessOrExit(error = aArgs[1].ParseAsIp6Prefix(prefix));
SuccessOrExit(error = Interpreter::ParseRoute(aArgs + 2, config));
error = otNetDataReplacePublishedExternalRoute(GetInstancePtr(), &prefix, &config);
ExitNow();
}
#endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
error = OT_ERROR_INVALID_ARGS;
exit:
return error;
}
template <> otError NetworkData::Process<Cmd("unpublish")>(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
/**
* @cli netdata unpublish dnssrp
* @code
* netdata unpublish dnssrp
* Done
* @endcode
* @par api_copy
* #otNetDataUnpublishDnsSrpService
*/
#if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
if (aArgs[0] == "dnssrp")
{
otNetDataUnpublishDnsSrpService(GetInstancePtr());
ExitNow();
}
#endif
/**
* @cli netdata unpublish (prefix)
* @code
* netdata unpublish fd00:1234:5678::/64
* Done
* @endcode
* @cparam netdata unpublish @ca{prefix}
* @par api_copy
* #otNetDataUnpublishPrefix
* @par
* @moreinfo{@netdata}.
*/
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
{
otIp6Prefix prefix;
if (aArgs[0].ParseAsIp6Prefix(prefix) == OT_ERROR_NONE)
{
error = otNetDataUnpublishPrefix(GetInstancePtr(), &prefix);
ExitNow();
}
}
#endif
error = OT_ERROR_INVALID_ARGS;
exit:
return error;
}
#endif // OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
/**
* @cli netdata register
* @code
* netdata register
* Done
* @endcode
* @par
* Register configured prefixes, routes, and services with the Leader.
* @par
* OT CLI checks for `OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE`. If OTBR is enabled, it
* registers local Network Data with the Leader. Otherwise, it calls the CLI function `otServerRegister`.
* @moreinfo{@netdata}.
* @csa{prefix add}
* @sa otBorderRouterRegister
* @sa otServerAddService
*/
template <> otError NetworkData::Process<Cmd("register")>(Arg aArgs[])
{
OT_UNUSED_VARIABLE(aArgs);
otError error = OT_ERROR_NONE;
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
SuccessOrExit(error = otBorderRouterRegister(GetInstancePtr()));
#else
SuccessOrExit(error = otServerRegister(GetInstancePtr()));
#endif
exit:
return error;
}
#endif
template <> otError NetworkData::Process<Cmd("steeringdata")>(Arg aArgs[])
{
otError error;
otExtAddress addr;
otJoinerDiscerner discerner;
VerifyOrExit(aArgs[0] == "check", error = OT_ERROR_INVALID_ARGS);
error = Interpreter::ParseJoinerDiscerner(aArgs[1], discerner);
if (error == OT_ERROR_NOT_FOUND)
{
discerner.mLength = 0;
error = aArgs[1].ParseAsHexString(addr.m8);
}
SuccessOrExit(error);
/**
* @cli netdata steeringdata check (discerner)
* @code
* netdata steeringdata check 0xabc/12
* Done
* @endcode
* @code
* netdata steeringdata check 0xdef/12
* Error 23: NotFound
* @endcode
* @cparam netdata steeringdata check @ca{discerner}
* * `discerner`: The %Joiner discerner in format `{number}/{length}`.
* @par api_copy
* #otNetDataSteeringDataCheckJoinerWithDiscerner
* @csa{joiner discerner}
*/
if (discerner.mLength)
{
error = otNetDataSteeringDataCheckJoinerWithDiscerner(GetInstancePtr(), &discerner);
}
/**
* @cli netdata steeringdata check (eui64)
* @code
* netdata steeringdata check d45e64fa83f81cf7
* Done
* @endcode
* @cparam netdata steeringdata check @ca{eui64}
* * `eui64`: The IEEE EUI-64 of the %Joiner.
* @par api_copy
* #otNetDataSteeringDataCheckJoiner
* @csa{eui64}
*/
else
{
error = otNetDataSteeringDataCheckJoiner(GetInstancePtr(), &addr);
}
exit:
return error;
}
otError NetworkData::GetNextPrefix(otNetworkDataIterator *aIterator, otBorderRouterConfig *aConfig, bool aLocal)
{
otError error;
if (aLocal)
{
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
error = otBorderRouterGetNextOnMeshPrefix(GetInstancePtr(), aIterator, aConfig);
#else
error = OT_ERROR_NOT_FOUND;
#endif
}
else
{
error = otNetDataGetNextOnMeshPrefix(GetInstancePtr(), aIterator, aConfig);
}
return error;
}
void NetworkData::OutputNetworkData(bool aLocal, uint16_t aRloc16)
{
otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT;
otBorderRouterConfig prefix;
otExternalRouteConfig route;
otServiceConfig service;
otLowpanContextInfo context;
otCommissioningDataset dataset;
OutputLine("Prefixes:");
while (GetNextPrefix(&iterator, &prefix, aLocal) == OT_ERROR_NONE)
{
if ((aRloc16 == kAnyRloc16) || (aRloc16 == prefix.mRloc16))
{
OutputPrefix(prefix);
}
}
OutputLine("Routes:");
iterator = OT_NETWORK_DATA_ITERATOR_INIT;
while (GetNextRoute(&iterator, &route, aLocal) == OT_ERROR_NONE)
{
if ((aRloc16 == kAnyRloc16) || (aRloc16 == route.mRloc16))
{
OutputRoute(route);
}
}
OutputLine("Services:");
iterator = OT_NETWORK_DATA_ITERATOR_INIT;
while (GetNextService(&iterator, &service, aLocal) == OT_ERROR_NONE)
{
if ((aRloc16 == kAnyRloc16) || (aRloc16 == service.mServerConfig.mRloc16))
{
OutputService(service);
}
}
VerifyOrExit(!aLocal);
VerifyOrExit(aRloc16 == kAnyRloc16);
OutputLine("Contexts:");
iterator = OT_NETWORK_DATA_ITERATOR_INIT;
while (otNetDataGetNextLowpanContextInfo(GetInstancePtr(), &iterator, &context) == OT_ERROR_NONE)
{
OutputIp6Prefix(context.mPrefix);
OutputLine(" %u %c", context.mContextId, context.mCompressFlag ? 'c' : '-');
}
otNetDataGetCommissioningDataset(GetInstancePtr(), &dataset);
OutputLine("Commissioning:");
dataset.mIsSessionIdSet ? OutputFormat("%u ", dataset.mSessionId) : OutputFormat("- ");
dataset.mIsLocatorSet ? OutputFormat("%04x ", dataset.mLocator) : OutputFormat("- ");
dataset.mIsJoinerUdpPortSet ? OutputFormat("%u ", dataset.mJoinerUdpPort) : OutputFormat("- ");
dataset.mIsSteeringDataSet ? OutputBytes(dataset.mSteeringData.m8, dataset.mSteeringData.mLength)
: OutputFormat("-");
if (dataset.mHasExtraTlv)
{
OutputFormat(" e");
}
OutputNewLine();
exit:
return;
}
otError NetworkData::GetNextRoute(otNetworkDataIterator *aIterator, otExternalRouteConfig *aConfig, bool aLocal)
{
otError error;
if (aLocal)
{
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
error = otBorderRouterGetNextRoute(GetInstancePtr(), aIterator, aConfig);
#else
error = OT_ERROR_NOT_FOUND;
#endif
}
else
{
error = otNetDataGetNextRoute(GetInstancePtr(), aIterator, aConfig);
}
return error;
}
otError NetworkData::GetNextService(otNetworkDataIterator *aIterator, otServiceConfig *aConfig, bool aLocal)
{
otError error;
if (aLocal)
{
#if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
error = otServerGetNextService(GetInstancePtr(), aIterator, aConfig);
#else
error = OT_ERROR_NOT_FOUND;
#endif
}
else
{
error = otNetDataGetNextService(GetInstancePtr(), aIterator, aConfig);
}
return error;
}
otError NetworkData::OutputBinary(bool aLocal)
{
otError error;
uint8_t data[255];
uint8_t len = sizeof(data);
if (aLocal)
{
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
error = otBorderRouterGetNetData(GetInstancePtr(), false, data, &len);
#else
error = OT_ERROR_NOT_IMPLEMENTED;
#endif
}
else
{
error = otNetDataGet(GetInstancePtr(), false, data, &len);
}
SuccessOrExit(error);
OutputBytesLine(data, static_cast<uint8_t>(len));
exit:
return error;
}
/**
* @cli netdata show
* @code
* netdata show
* Prefixes:
* fd00:dead:beef:cafe::/64 paros med dc00
* Routes:
* fd49:7770:7fc5:0::/64 s med 4000
* Services:
* 44970 5d c000 s 4000
* 44970 01 9a04b000000e10 s 4000
* Contexts:
* fd00:dead:beef:cafe::/64 1 c
* Commissioning:
* 1248 dc00 9988 00000000000120000000000000000000 e
* Done
* @endcode
* @code
* netdata show -x
* 08040b02174703140040fd00deadbeefcafe0504dc00330007021140
* Done
* @endcode
* @code
* netdata show 0xdc00
* Prefixes:
* fd00:dead:beef:cafe::/64 paros med dc00
* Routes:
* Services:
* Done
* @cparam netdata show [@ca{-x}|@ca{rloc16}]
* * The optional `-x` argument gets Network Data as hex-encoded TLVs.
* * The optional `rloc16` argument gets all prefix/route/service entries associated with a given RLOC16.
* @par
* `netdata show` from OT CLI gets full Network Data received from the Leader. This command uses several
* API functions to combine prefixes, routes, and services, including #otNetDataGetNextOnMeshPrefix,
* #otNetDataGetNextRoute, #otNetDataGetNextService and #otNetDataGetNextLowpanContextInfo.
* @par
* On-mesh prefixes are listed under `Prefixes` header:
* * The on-mesh prefix
* * Flags
* * p: Preferred flag
* * a: Stateless IPv6 Address Autoconfiguration flag
* * d: DHCPv6 IPv6 Address Configuration flag
* * c: DHCPv6 Other Configuration flag
* * r: Default Route flag
* * o: On Mesh flag
* * s: Stable flag
* * n: Nd Dns flag
* * D: Domain Prefix flag (only available for Thread 1.2).
* * Preference `high`, `med`, or `low`
* * RLOC16 of device which added the on-mesh prefix
* @par
* External Routes are listed under `Routes` header:
* * The route prefix
* * Flags
* * s: Stable flag
* * n: NAT64 flag
* * Preference `high`, `med`, or `low`
* * RLOC16 of device which added the route prefix
* @par
* Service entries are listed under `Services` header:
* * Enterprise number
* * Service data (as hex bytes)
* * Server data (as hex bytes)
* * Flags
* * s: Stable flag
* * RLOC16 of devices which added the service entry
* @par
* 6LoWPAN Context IDs are listed under `Contexts` header:
* * The prefix
* * Context ID
* * Compress flag (`c` if marked or `-` otherwise).
* @par
* Commissioning Dataset information is printed under `Commissioning` header:
* * Session ID if present in Dataset or `-` otherwise
* * Border Agent RLOC16 (in hex) if present in Dataset or `-` otherwise
* * Joiner UDP port number if present in Dataset or `-` otherwise
* * Steering Data (as hex bytes) if present in Dataset or `-` otherwise
* * Flags:
* * e: If Dataset contains any extra unknown TLV
* @par
* @moreinfo{@netdata}.
* @csa{br omrprefix}
* @csa{br onlinkprefix}
* @sa otBorderRouterGetNetData
*/
template <> otError NetworkData::Process<Cmd("show")>(Arg aArgs[])
{
otError error = OT_ERROR_INVALID_ARGS;
uint16_t rloc16 = kAnyRloc16;
bool local = false;
bool binary = false;
for (uint8_t i = 0; !aArgs[i].IsEmpty(); i++)
{
/**
* @cli netdata show local
* @code
* netdata show local
* Prefixes:
* fd00:dead:beef:cafe::/64 paros med dc00
* Routes:
* Services:
* Done
* @endcode
* @code
* netdata show local -x
* 08040b02174703140040fd00deadbeefcafe0504dc00330007021140
* Done
* @endcode
* @cparam netdata show local [@ca{-x}]
* * The optional `-x` argument gets local Network Data as hex-encoded TLVs.
* @par
* Print local Network Data to sync with the Leader.
* @csa{netdata show}
*/
if (aArgs[i] == "local")
{
local = true;
}
else if (aArgs[i] == "-x")
{
binary = true;
}
else
{
SuccessOrExit(error = aArgs[i].ParseAsUint16(rloc16));
}
}
if (local || binary)
{
VerifyOrExit(rloc16 == kAnyRloc16, error = OT_ERROR_INVALID_ARGS);
}
if (binary)
{
error = OutputBinary(local);
}
else
{
OutputNetworkData(local, rloc16);
error = OT_ERROR_NONE;
}
exit:
return error;
}
#if OPENTHREAD_CONFIG_BORDER_ROUTER_SIGNAL_NETWORK_DATA_FULL
template <> otError NetworkData::Process<Cmd("full")>(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
/**
* @cli netdata full
* @code
* netdata full
* no
* Done
* @endcode
* @par
* Print "yes" or "no" indicating whether or not the "net data full" callback has been invoked since start of
* Thread operation or since the last time `netdata full reset` was used to reset the flag.
* This command requires `OPENTHREAD_CONFIG_BORDER_ROUTER_SIGNAL_NETWORK_DATA_FULL`.
* The "net data full" callback is invoked whenever:
* - The device is acting as a leader and receives a Network Data registration from a Border Router (BR) that it
* cannot add to Network Data (running out of space).
* - The device is acting as a BR and new entries cannot be added to its local Network Data.
* - The device is acting as a BR and tries to register its local Network Data entries with the leader, but
* determines that its local entries will not fit.
* @sa otBorderRouterSetNetDataFullCallback
*/
if (aArgs[0].IsEmpty())
{
OutputLine(mFullCallbackWasCalled ? "yes" : "no");
}
/**
* @cli netdata full reset
* @code
* netdata full reset
* Done
* @endcode
* @par
* Reset the flag tracking whether "net data full" callback was invoked.
*/
else if (aArgs[0] == "reset")
{
VerifyOrExit(aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
mFullCallbackWasCalled = false;
}
else
{
error = OT_ERROR_INVALID_ARGS;
}
exit:
return error;
}
#endif // OPENTHREAD_CONFIG_BORDER_ROUTER_SIGNAL_NETWORK_DATA_FULL
otError NetworkData::Process(Arg aArgs[])
{
#define CmdEntry(aCommandString) \
{ \
aCommandString, &NetworkData::Process<Cmd(aCommandString)> \
}
static constexpr Command kCommands[] = {
#if OPENTHREAD_CONFIG_BORDER_ROUTER_SIGNAL_NETWORK_DATA_FULL
CmdEntry("full"),
#endif
CmdEntry("length"),
CmdEntry("maxlength"),
#if OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
CmdEntry("publish"),
#endif
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
CmdEntry("register"),
#endif
CmdEntry("show"),
CmdEntry("steeringdata"),
#if OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
CmdEntry("unpublish"),
#endif
};
#undef CmdEntry
static_assert(BinarySearch::IsSorted(kCommands), "kCommands is not sorted");
otError error = OT_ERROR_INVALID_COMMAND;
const Command *command;
/**
* @cli netdata help
* @code
* netdata help
* length
* maxlength
* publish
* register
* show
* steeringdata
* unpublish
* Done
* @endcode
* @par
* Gets a list of `netdata` CLI commands.
* @sa @netdata
*/
if (aArgs[0].IsEmpty() || (aArgs[0] == "help"))
{
OutputCommandTable(kCommands);
ExitNow(error = aArgs[0].IsEmpty() ? 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