blob: 0f86b24415ed01fac3c49dc351b03f896da6296e [file] [log] [blame]
/*
* Copyright (c) 2023, 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 for Backbone Router.
*/
#include "cli_bbr.hpp"
#include "cli/cli.hpp"
#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
namespace ot {
namespace Cli {
void Bbr::OutputConfig(const otBackboneRouterConfig &aConfig)
{
OutputLine("seqno: %u", aConfig.mSequenceNumber);
OutputLine("delay: %u secs", aConfig.mReregistrationDelay);
OutputLine("timeout: %lu secs", ToUlong(aConfig.mMlrTimeout));
}
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE
template <> otError Bbr::Process<Cmd("mlr")>(Arg aArgs[])
{
otError error = OT_ERROR_INVALID_COMMAND;
/**
* @cli bbr mgmt mlr listener
* @code
* bbr mgmt mlr listener
* ff04:0:0:0:0:0:0:abcd 3534000
* ff04:0:0:0:0:0:0:eeee 3537610
* Done
* @endcode
* @par
* Returns the Multicast Listeners with the #otBackboneRouterMulticastListenerInfo
* `mTimeout` in seconds.
* @par
* Available when `OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE` and
* `OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE` are enabled.
* @sa otBackboneRouterMulticastListenerGetNext
*/
if (aArgs[0] == "listener")
{
if (aArgs[1].IsEmpty())
{
otBackboneRouterMulticastListenerIterator iter = OT_BACKBONE_ROUTER_MULTICAST_LISTENER_ITERATOR_INIT;
otBackboneRouterMulticastListenerInfo listenerInfo;
while (otBackboneRouterMulticastListenerGetNext(GetInstancePtr(), &iter, &listenerInfo) == OT_ERROR_NONE)
{
OutputIp6Address(listenerInfo.mAddress);
OutputLine(" %lu", ToUlong(listenerInfo.mTimeout));
}
ExitNow(error = OT_ERROR_NONE);
}
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
/**
* @cli bbr mgmt mlr listener clear
* @code
* bbr mgmt mlr listener clear
* Done
* @endcode
* @par api_copy
* #otBackboneRouterMulticastListenerClear
*/
if (aArgs[1] == "clear")
{
otBackboneRouterMulticastListenerClear(GetInstancePtr());
error = OT_ERROR_NONE;
}
/**
* @cli bbr mgmt mlr listener add
* @code
* bbr mgmt mlr listener add ff04::1
* Done
* @endcode
* @code
* bbr mgmt mlr listener add ff04::2 300
* Done
* @endcode
* @cparam bbr mgmt mlr listener add @ca{ipaddress} [@ca{timeout-seconds}]
* @par api_copy
* #otBackboneRouterMulticastListenerAdd
*/
else if (aArgs[1] == "add")
{
otIp6Address address;
uint32_t timeout = 0;
SuccessOrExit(error = aArgs[2].ParseAsIp6Address(address));
if (!aArgs[3].IsEmpty())
{
SuccessOrExit(error = aArgs[3].ParseAsUint32(timeout));
}
error = otBackboneRouterMulticastListenerAdd(GetInstancePtr(), &address, timeout);
}
}
/**
* @cli bbr mgmt mlr response
* @code
* bbr mgmt mlr response 2
* Done
* @endcode
* @cparam bbr mgmt mlr response @ca{status-code}
* For `status-code`, use:
* * 0: ST_MLR_SUCCESS
* * 2: ST_MLR_INVALID
* * 3: ST_MLR_NO_PERSISTENT
* * 4: ST_MLR_NO_RESOURCES
* * 5: ST_MLR_BBR_NOT_PRIMARY
* * 6: ST_MLR_GENERAL_FAILURE
* @par api_copy
* #otBackboneRouterConfigNextMulticastListenerRegistrationResponse
*/
else if (aArgs[0] == "response")
{
uint8_t status;
SuccessOrExit(error = aArgs[1].ParseAsUint8(status));
otBackboneRouterConfigNextMulticastListenerRegistrationResponse(GetInstancePtr(), status);
error = OT_ERROR_NONE;
#endif // OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
}
exit:
return error;
}
#endif // #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE
template <> otError Bbr::Process<Cmd("mgmt")>(Arg aArgs[])
{
otError error = OT_ERROR_INVALID_COMMAND;
if (aArgs[0].IsEmpty())
{
ExitNow(error = OT_ERROR_INVALID_COMMAND);
}
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
/**
* @cli bbr mgmt dua
* @code
* bbr mgmt dua 1 2f7c235e5025a2fd
* Done
* @endcode
* @code
* bbr mgmt dua 160
* Done
* @endcode
* @cparam bbr mgmt dua @ca{status|coap-code} [@ca{meshLocalIid}]
* For `status` or `coap-code`, use:
* * 0: ST_DUA_SUCCESS
* * 1: ST_DUA_REREGISTER
* * 2: ST_DUA_INVALID
* * 3: ST_DUA_DUPLICATE
* * 4: ST_DUA_NO_RESOURCES
* * 5: ST_DUA_BBR_NOT_PRIMARY
* * 6: ST_DUA_GENERAL_FAILURE
* * 160: COAP code 5.00
* @par
* With the `meshLocalIid` included, this command configures the response status
* for the next DUA registration. Without `meshLocalIid`, respond to the next
* DUA.req with the specified `status` or `coap-code`.
* @par
* Available when `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is enabled.
* @sa otBackboneRouterConfigNextDuaRegistrationResponse
*/
if (aArgs[0] == "dua")
{
uint8_t status;
otIp6InterfaceIdentifier *mlIid = nullptr;
otIp6InterfaceIdentifier iid;
SuccessOrExit(error = aArgs[1].ParseAsUint8(status));
if (!aArgs[2].IsEmpty())
{
SuccessOrExit(error = aArgs[2].ParseAsHexString(iid.mFields.m8));
mlIid = &iid;
VerifyOrExit(aArgs[3].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
}
otBackboneRouterConfigNextDuaRegistrationResponse(GetInstancePtr(), mlIid, status);
ExitNow();
}
#endif // OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE
if (aArgs[0] == "mlr")
{
error = Process<Cmd("mlr")>(aArgs + 1);
ExitNow();
}
#endif
exit:
return error;
}
/**
* @cli bbr enable
* @code
* bbr enable
* Done
* @endcode
* @par api_copy
* #otBackboneRouterSetEnabled
*/
template <> otError Bbr::Process<Cmd("enable")>(Arg aArgs[])
{
OT_UNUSED_VARIABLE(aArgs);
otBackboneRouterSetEnabled(GetInstancePtr(), true);
return OT_ERROR_NONE;
}
/**
* @cli bbr disable
* @code
* bbr disable
* Done
* @endcode
* @par api_copy
* #otBackboneRouterSetEnabled
*/
template <> otError Bbr::Process<Cmd("disable")>(Arg aArgs[])
{
OT_UNUSED_VARIABLE(aArgs);
otBackboneRouterSetEnabled(GetInstancePtr(), false);
return OT_ERROR_NONE;
}
/**
* @cli bbr jitter (get,set)
* @code
* bbr jitter
* 20
* Done
* @endcode
* @code
* bbr jitter 10
* Done
* @endcode
* @cparam bbr jitter [@ca{jitter}]
* @par
* Gets or sets jitter (in seconds) for Backbone Router registration.
* @par
* Available when `OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE` is enabled.
* @sa otBackboneRouterGetRegistrationJitter
* @sa otBackboneRouterSetRegistrationJitter
*/
template <> otError Bbr::Process<Cmd("jitter")>(Arg aArgs[])
{
return ProcessGetSet(aArgs, otBackboneRouterGetRegistrationJitter, otBackboneRouterSetRegistrationJitter);
}
/**
* @cli bbr register
* @code
* bbr register
* Done
* @endcode
* @par api_copy
* #otBackboneRouterRegister
*/
template <> otError Bbr::Process<Cmd("register")>(Arg aArgs[])
{
OT_UNUSED_VARIABLE(aArgs);
return otBackboneRouterRegister(GetInstancePtr());
}
/**
* @cli bbr state
* @code
* bbr state
* Disabled
* Done
* @endcode
* @code
* bbr state
* Primary
* Done
* @endcode
* @code
* bbr state
* Secondary
* Done
* @endcode
* @par
* Available when `OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE` is enabled.
* @par api_copy
* #otBackboneRouterGetState
*/
template <> otError Bbr::Process<Cmd("state")>(Arg aArgs[])
{
static const char *const kStateStrings[] = {
"Disabled", // (0) OT_BACKBONE_ROUTER_STATE_DISABLED
"Secondary", // (1) OT_BACKBONE_ROUTER_STATE_SECONDARY
"Primary", // (2) OT_BACKBONE_ROUTER_STATE_PRIMARY
};
static_assert(0 == OT_BACKBONE_ROUTER_STATE_DISABLED, "OT_BACKBONE_ROUTER_STATE_DISABLED value is incorrect");
static_assert(1 == OT_BACKBONE_ROUTER_STATE_SECONDARY, "OT_BACKBONE_ROUTER_STATE_SECONDARY value is incorrect");
static_assert(2 == OT_BACKBONE_ROUTER_STATE_PRIMARY, "OT_BACKBONE_ROUTER_STATE_PRIMARY value is incorrect");
OT_UNUSED_VARIABLE(aArgs);
OutputLine("%s", Stringify(otBackboneRouterGetState(GetInstancePtr()), kStateStrings));
return OT_ERROR_NONE;
}
/**
* @cli bbr config
* @code
* bbr config
* seqno: 10
* delay: 120 secs
* timeout: 300 secs
* Done
* @endcode
* @par api_copy
* #otBackboneRouterGetConfig
*/
template <> otError Bbr::Process<Cmd("config")>(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
otBackboneRouterConfig config;
otBackboneRouterGetConfig(GetInstancePtr(), &config);
if (aArgs[0].IsEmpty())
{
OutputConfig(config);
}
else
{
// Set local Backbone Router configuration.
/**
* @cli bbr config (set)
* @code
* bbr config seqno 20 delay 30
* Done
* @endcode
* @cparam bbr config [seqno @ca{seqno}] [delay @ca{delay}] [timeout @ca{timeout}]
* @par
* `bbr register` should be issued explicitly to register Backbone Router service to Leader
* for Secondary Backbone Router.
* @par api_copy
* #otBackboneRouterSetConfig
*/
for (Arg *arg = &aArgs[0]; !arg->IsEmpty(); arg++)
{
if (*arg == "seqno")
{
arg++;
SuccessOrExit(error = arg->ParseAsUint8(config.mSequenceNumber));
}
else if (*arg == "delay")
{
arg++;
SuccessOrExit(error = arg->ParseAsUint16(config.mReregistrationDelay));
}
else if (*arg == "timeout")
{
arg++;
SuccessOrExit(error = arg->ParseAsUint32(config.mMlrTimeout));
}
else
{
ExitNow(error = OT_ERROR_INVALID_ARGS);
}
}
error = otBackboneRouterSetConfig(GetInstancePtr(), &config);
}
exit:
return error;
}
#endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
otError Bbr::Process(Arg aArgs[])
{
#define CmdEntry(aCommandString) {aCommandString, &Bbr::Process<Cmd(aCommandString)>}
otError error = OT_ERROR_INVALID_COMMAND;
/**
* @cli bbr
* @code
* bbr
* BBR Primary:
* server16: 0xE400
* seqno: 10
* delay: 120 secs
* timeout: 300 secs
* Done
* @endcode
* @code
* bbr
* BBR Primary: None
* Done
* @endcode
* @par
* Returns the current Primary Backbone Router information for the Thread device.
*/
if (aArgs[0].IsEmpty())
{
otBackboneRouterConfig config;
OutputFormat("BBR Primary:");
if (otBackboneRouterGetPrimary(GetInstancePtr(), &config) == OT_ERROR_NONE)
{
OutputNewLine();
OutputLine("server16: 0x%04X", config.mServer16);
OutputConfig(config);
}
else
{
OutputLine(" None");
}
error = OT_ERROR_NONE;
ExitNow();
}
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
{
static constexpr Command kCommands[] = {
CmdEntry("config"), CmdEntry("disable"), CmdEntry("enable"), CmdEntry("jitter"),
CmdEntry("mgmt"), CmdEntry("register"), CmdEntry("state"),
};
#undef CmdEntry
static_assert(BinarySearch::IsSorted(kCommands), "kCommands is not sorted");
const Command *command;
command = BinarySearch::Find(aArgs[0].GetCString(), kCommands);
VerifyOrExit(command != nullptr);
error = (this->*command->mHandler)(aArgs + 1);
}
#endif // #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
exit:
return error;
}
} // namespace Cli
} // namespace ot
#endif // #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)