| /* |
| * 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) |