From 41d6fc861c1f9a04a0cfb181b746fe42b059484b Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Mon, 5 Jun 2023 12:32:25 -0700 Subject: [PATCH] [cli] add CLI Backbone Router (`Bbr`) sub-module (#9128) This commit adds `Bbr` CLI sub-module that implements all "bbr" sub-commands. --- src/cli/BUILD.gn | 2 + src/cli/CMakeLists.txt | 1 + src/cli/Makefile.am | 2 + src/cli/cli.cpp | 402 +-------------------------------- src/cli/cli.hpp | 6 + src/cli/cli_bbr.cpp | 499 +++++++++++++++++++++++++++++++++++++++++ src/cli/cli_bbr.hpp | 98 ++++++++ 7 files changed, 612 insertions(+), 398 deletions(-) create mode 100644 src/cli/cli_bbr.cpp create mode 100644 src/cli/cli_bbr.hpp diff --git a/src/cli/BUILD.gn b/src/cli/BUILD.gn index db116c58f..fb68e8c86 100644 --- a/src/cli/BUILD.gn +++ b/src/cli/BUILD.gn @@ -30,6 +30,8 @@ import("../../etc/gn/openthread.gni") openthread_cli_sources = [ "cli.cpp", "cli.hpp", + "cli_bbr.cpp", + "cli_bbr.hpp", "cli_br.cpp", "cli_br.hpp", "cli_coap.cpp", diff --git a/src/cli/CMakeLists.txt b/src/cli/CMakeLists.txt index a94d3e0f6..c203c2667 100644 --- a/src/cli/CMakeLists.txt +++ b/src/cli/CMakeLists.txt @@ -33,6 +33,7 @@ set(COMMON_INCLUDES set(COMMON_SOURCES cli.cpp + cli_bbr.cpp cli_br.cpp cli_coap.cpp cli_coap_secure.cpp diff --git a/src/cli/Makefile.am b/src/cli/Makefile.am index f17f54427..4f8f9fb29 100644 --- a/src/cli/Makefile.am +++ b/src/cli/Makefile.am @@ -153,6 +153,7 @@ libopenthread_cli_radio_a_CPPFLAGS = \ SOURCES_COMMON = \ cli.cpp \ + cli_bbr.cpp \ cli_br.cpp \ cli_coap.cpp \ cli_coap_secure.cpp \ @@ -185,6 +186,7 @@ libopenthread_cli_radio_a_SOURCES = \ noinst_HEADERS = \ cli.hpp \ + cli_bbr.hpp \ cli_br.hpp \ cli_coap.hpp \ cli_coap_secure.hpp \ diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 4fd237aa1..d848e7f80 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -115,6 +115,9 @@ Interpreter::Interpreter(Instance *aInstance, otCliOutputCallback aCallback, voi #if OPENTHREAD_CLI_DNS_ENABLE , mDns(aInstance, *this) #endif +#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) + , mBbr(aInstance, *this) +#endif #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE , mBr(aInstance, *this) #endif @@ -902,405 +905,8 @@ void Interpreter::OutputNat64Counters(const otNat64Counters &aCounters) #endif // OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE || OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) -template <> otError Interpreter::Process(Arg aArgs[]) -{ - otError error = OT_ERROR_INVALID_COMMAND; - otBackboneRouterConfig config; - /** - * @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()) - { - if (otBackboneRouterGetPrimary(GetInstancePtr(), &config) == OT_ERROR_NONE) - { - OutputLine("BBR Primary:"); - OutputLine("server16: 0x%04X", config.mServer16); - OutputLine("seqno: %u", config.mSequenceNumber); - OutputLine("delay: %u secs", config.mReregistrationDelay); - OutputLine("timeout: %lu secs", ToUlong(config.mMlrTimeout)); - } - else - { - OutputLine("BBR Primary: None"); - } - - error = OT_ERROR_NONE; - } -#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE - else - { - if (aArgs[0] == "mgmt") - { - if (aArgs[1].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 - */ - else if (aArgs[1] == "dua") - { - uint8_t status; - otIp6InterfaceIdentifier *mlIid = nullptr; - otIp6InterfaceIdentifier iid; - - SuccessOrExit(error = aArgs[2].ParseAsUint8(status)); - - if (!aArgs[3].IsEmpty()) - { - SuccessOrExit(error = aArgs[3].ParseAsHexString(iid.mFields.m8)); - mlIid = &iid; - VerifyOrExit(aArgs[4].IsEmpty(), error = OT_ERROR_INVALID_ARGS); - } - - otBackboneRouterConfigNextDuaRegistrationResponse(GetInstancePtr(), mlIid, status); - ExitNow(); - } -#endif -#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE - else if (aArgs[1] == "mlr") - { - error = ProcessBackboneRouterMgmtMlr(aArgs + 2); - ExitNow(); - } -#endif - } - SuccessOrExit(error = ProcessBackboneRouterLocal(aArgs)); - } - -exit: -#endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE - return error; -} - -#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE - -#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE -otError Interpreter::ProcessBackboneRouterMgmtMlr(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()) - { - PrintMulticastListenersTable(); - 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)); - VerifyOrExit(aArgs[4].IsEmpty(), error = OT_ERROR_INVALID_ARGS); - } - - 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") - { - error = ProcessSet(aArgs + 1, otBackboneRouterConfigNextMulticastListenerRegistrationResponse); -#endif - } - -exit: - return error; -} - -void Interpreter::PrintMulticastListenersTable(void) -{ - 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)); - } -} - -#endif // OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE - -otError Interpreter::ProcessBackboneRouterLocal(Arg aArgs[]) -{ - otError error = OT_ERROR_NONE; - otBackboneRouterConfig config; - bool enable; - - /** - * @cli bbr (enable,disable) - * @code - * bbr enable - * Done - * @endcode - * @code - * bbr disable - * Done - * @endcode - * @par api_copy - * #otBackboneRouterSetEnabled - */ - if (ParseEnableOrDisable(aArgs[0], enable) == OT_ERROR_NONE) - { - otBackboneRouterSetEnabled(GetInstancePtr(), enable); - } - /** - * @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 - */ - else if (aArgs[0] == "jitter") - { - error = ProcessGetSet(aArgs + 1, otBackboneRouterGetRegistrationJitter, otBackboneRouterSetRegistrationJitter); - } - /** - * @cli bbr register - * @code - * bbr register - * Done - * @endcode - * @par api_copy - * #otBackboneRouterRegister - */ - else if (aArgs[0] == "register") - { - SuccessOrExit(error = 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 - */ - else if (aArgs[0] == "state") - { - 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"); - - OutputLine("%s", Stringify(otBackboneRouterGetState(GetInstancePtr()), kStateStrings)); - } - /** - * @cli bbr config - * @code - * bbr config - * seqno: 10 - * delay: 120 secs - * timeout: 300 secs - * Done - * @endcode - * @par api_copy - * #otBackboneRouterGetConfig - */ - else if (aArgs[0] == "config") - { - otBackboneRouterGetConfig(GetInstancePtr(), &config); - - if (aArgs[1].IsEmpty()) - { - OutputLine("seqno: %u", config.mSequenceNumber); - OutputLine("delay: %u secs", config.mReregistrationDelay); - OutputLine("timeout: %lu secs", ToUlong(config.mMlrTimeout)); - } - 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[1]; !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); - } - } - - SuccessOrExit(error = otBackboneRouterSetConfig(GetInstancePtr(), &config)); - } - } - else - { - error = OT_ERROR_INVALID_COMMAND; - } - -exit: - return error; -} -#endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE +template <> otError Interpreter::Process(Arg aArgs[]) { return mBbr.Process(aArgs); } /** * @cli domainname diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp index 169080819..2a19e9463 100644 --- a/src/cli/cli.hpp +++ b/src/cli/cli.hpp @@ -58,6 +58,7 @@ #include #include +#include "cli/cli_bbr.hpp" #include "cli/cli_br.hpp" #include "cli/cli_commissioner.hpp" #include "cli/cli_dataset.hpp" @@ -108,6 +109,7 @@ class Interpreter : public OutputImplementer, public Output { #if OPENTHREAD_FTD || OPENTHREAD_MTD friend class Br; + friend class Bbr; friend class Commissioner; friend class Dns; friend class Joiner; @@ -549,6 +551,10 @@ private: Dns mDns; #endif +#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) + Bbr mBbr; +#endif + #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE Br mBr; #endif diff --git a/src/cli/cli_bbr.cpp b/src/cli/cli_bbr.cpp new file mode 100644 index 000000000..d37d3dfcc --- /dev/null +++ b/src/cli/cli_bbr.cpp @@ -0,0 +1,499 @@ +/* + * 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(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(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(aArgs + 1); + ExitNow(); + } +#endif + +exit: + return error; +} + +/** + * @cli bbr enable + * @code + * bbr enable + * Done + * @endcode + * @par api_copy + * #otBackboneRouterSetEnabled + */ +template <> otError Bbr::Process(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(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(Arg aArgs[]) +{ + return Interpreter::GetInterpreter().ProcessGetSet(aArgs, otBackboneRouterGetRegistrationJitter, + otBackboneRouterSetRegistrationJitter); +} + +/** + * @cli bbr register + * @code + * bbr register + * Done + * @endcode + * @par api_copy + * #otBackboneRouterRegister + */ +template <> otError Bbr::Process(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(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(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} + + 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) diff --git a/src/cli/cli_bbr.hpp b/src/cli/cli_bbr.hpp new file mode 100644 index 000000000..40ed979f6 --- /dev/null +++ b/src/cli/cli_bbr.hpp @@ -0,0 +1,98 @@ +/* + * 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 contains definitions for CLI to backbone router. + */ + +#ifndef CLI_BBR_HPP_ +#define CLI_BBR_HPP_ + +#include "openthread-core-config.h" + +#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) + +#include +#include + +#include "cli/cli_config.h" +#include "cli/cli_output.hpp" + +namespace ot { +namespace Cli { + +/** + * Implements the BBR CLI interpreter. + * + */ +class Bbr : private Output +{ +public: + typedef Utils::CmdLineParser::Arg Arg; + + /** + * Constructor. + * + * @param[in] aInstance The OpenThread Instance. + * @param[in] aOutputImplementer An `OutputImplementer`. + * + */ + Bbr(otInstance *aInstance, OutputImplementer &aOutputImplementer) + : Output(aInstance, aOutputImplementer) + { + } + + /** + * Processes a CLI sub-command. + * + * @param[in] aArgs An array of command line arguments. + * + * @retval OT_ERROR_NONE Successfully executed the CLI command. + * @retval OT_ERROR_PENDING The CLI command was successfully started but final result is pending. + * @retval OT_ERROR_INVALID_COMMAND Invalid or unknown CLI command. + * @retval OT_ERROR_INVALID_ARGS Invalid arguments. + * @retval ... Error during execution of the CLI command. + * + */ + otError Process(Arg aArgs[]); + +private: + using Command = CommandEntry; + + template otError Process(Arg aArgs[]); + + void OutputConfig(const otBackboneRouterConfig &aConfig); +}; + +} // namespace Cli +} // namespace ot + +#endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) + +#endif // CLI_BBR_HPP_