| /* |
| * Copyright (c) 2025, 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 Border Agent. |
| */ |
| |
| #include "cli_ba.hpp" |
| |
| #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE |
| |
| #include <string.h> |
| |
| #include "cli/cli.hpp" |
| |
| namespace ot { |
| namespace Cli { |
| |
| /** |
| * @cli ba enable |
| * @code |
| * ba enable |
| * Done |
| * @endcode |
| * @par |
| * Enables the Border Agent service on the device. |
| * @par |
| * By default, the Border Agent service is enabled. The `ba enable` and `ba disable` commands allow users to explicitly |
| * control its state. This can be useful in scenarios such as: |
| * - The user wishes to delay the start of the Border Agent service (and its mDNS advertisement of the `_meshcop._udp` |
| * service on the infrastructure link). This allows time to prepare or determine vendor-specific TXT data entries for |
| * inclusion. |
| * - Unit tests or test scripts might disable the Border Agent service to prevent it from interfering with specific |
| * test steps. For example, tests validating mDNS or DNS-SD functionality may disable the Border Agent to prevent its |
| * registration of the MeshCoP service. |
| * @sa otBorderAgentSetEnabled |
| */ |
| template <> otError Ba::Process<Cmd("enable")>(Arg aArgs[]) |
| { |
| otError error = OT_ERROR_NONE; |
| |
| VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
| otBorderAgentSetEnabled(GetInstancePtr(), true); |
| |
| exit: |
| return error; |
| } |
| |
| /** |
| * @cli ba disable |
| * @code |
| * ba disable |
| * Done |
| * @endcode |
| * @par |
| * Disables the Border Agent service on the device. |
| * @csa{ba enable} |
| * @sa otBorderAgentSetEnabled |
| */ |
| template <> otError Ba::Process<Cmd("disable")>(Arg aArgs[]) |
| { |
| otError error = OT_ERROR_NONE; |
| |
| VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
| otBorderAgentSetEnabled(GetInstancePtr(), false); |
| |
| exit: |
| return error; |
| } |
| |
| /** |
| * @cli ba port |
| * @code |
| * ba port |
| * 49153 |
| * Done |
| * @endcode |
| * @par api_copy |
| * #otBorderAgentGetUdpPort |
| */ |
| template <> otError Ba::Process<Cmd("port")>(Arg aArgs[]) |
| { |
| otError error = OT_ERROR_NONE; |
| |
| VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
| OutputLine("%u", otBorderAgentGetUdpPort(GetInstancePtr())); |
| |
| exit: |
| return error; |
| } |
| |
| /** |
| * @cli ba state |
| * @code |
| * ba state |
| * Active |
| * Done |
| * @endcode |
| * @par |
| * Prints the current state of the Border Agent service. Possible states are: |
| * - `Disabled`: Border Agent service is disabled. |
| * - `Inactive`: Border Agent service is enabled but not yet active. |
| * - `Active`: Border Agent service is enabled and active. External commissioner can connect and establish secure |
| * DTLS sessions with the Border Agent using PSKc |
| * @sa #otBorderAgentIsActive |
| */ |
| template <> otError Ba::Process<Cmd("state")>(Arg aArgs[]) |
| { |
| otError error = OT_ERROR_NONE; |
| |
| VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
| |
| if (!otBorderAgentIsEnabled(GetInstancePtr())) |
| { |
| OutputLine("Disabled"); |
| } |
| else |
| { |
| OutputLine("%s", otBorderAgentIsActive(GetInstancePtr()) ? "Active" : "Inactive"); |
| } |
| |
| exit: |
| return error; |
| } |
| |
| /** |
| * @cli ba sessions |
| * @code |
| * ba sessions |
| * [fe80:0:0:0:cc79:2a29:d311:1aea]:9202 connected:yes commissioner:no lifetime:1860 |
| * Done |
| * @endcode |
| * @par |
| * Prints the list of Border Agent's sessions. Information per session: |
| * * Peer socket address (IPv6 address and port). |
| * * Whether or not the session is connected. |
| * * Whether or not the session is accepted as full commissioner. |
| * * Session lifetime in milliseconds (calculated from the time the session was first established). |
| */ |
| template <> otError Ba::Process<Cmd("sessions")>(Arg aArgs[]) |
| { |
| otError error = OT_ERROR_NONE; |
| otBorderAgentSessionIterator iterator; |
| otBorderAgentSessionInfo info; |
| char sockAddrString[OT_IP6_SOCK_ADDR_STRING_SIZE]; |
| Uint64StringBuffer lifetimeString; |
| |
| VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
| |
| otBorderAgentInitSessionIterator(GetInstancePtr(), &iterator); |
| |
| while (otBorderAgentGetNextSessionInfo(&iterator, &info) == OT_ERROR_NONE) |
| { |
| otIp6SockAddrToString(&info.mPeerSockAddr, sockAddrString, sizeof(sockAddrString)); |
| |
| OutputLine("%s connected:%s commissioner:%s lifetime:%s", sockAddrString, ToYesNo(info.mIsConnected), |
| ToYesNo(info.mIsCommissioner), Uint64ToString(info.mLifetime, lifetimeString)); |
| } |
| exit: |
| return error; |
| } |
| |
| /** |
| * @cli ba counters |
| * @code |
| * ba counters |
| * epskcActivation: 0 |
| * epskcApiDeactivation: 0 |
| * epskcTimeoutDeactivation: 0 |
| * epskcMaxAttemptDeactivation: 0 |
| * epskcDisconnectDeactivation: 0 |
| * epskcInvalidBaStateError: 0 |
| * epskcInvalidArgsError: 0 |
| * epskcStartSecureSessionError: 0 |
| * epskcSecureSessionSuccess: 0 |
| * epskcSecureSessionFailure: 0 |
| * epskcCommissionerPetition: 0 |
| * pskcSecureSessionSuccess: 0 |
| * pskcSecureSessionFailure: 0 |
| * pskcCommissionerPetition: 0 |
| * mgmtActiveGet: 0 |
| * mgmtPendingGet: 0 |
| * Done |
| * @endcode |
| * @par |
| * Gets the border agent counters. |
| * @sa otBorderAgentGetCounters |
| */ |
| template <> otError Ba::Process<Cmd("counters")>(Arg aArgs[]) |
| { |
| otError error = OT_ERROR_NONE; |
| |
| VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
| OutputBorderAgentCounters(*otBorderAgentGetCounters(GetInstancePtr())); |
| |
| exit: |
| return error; |
| } |
| |
| void Ba::OutputBorderAgentCounters(const otBorderAgentCounters &aCounters) |
| { |
| struct CounterName |
| { |
| const uint32_t otBorderAgentCounters::*mValuePtr; |
| const char *mName; |
| }; |
| |
| static const CounterName kCounterNames[] = { |
| #if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE |
| {&otBorderAgentCounters::mEpskcActivations, "epskcActivation"}, |
| {&otBorderAgentCounters::mEpskcDeactivationClears, "epskcApiDeactivation"}, |
| {&otBorderAgentCounters::mEpskcDeactivationTimeouts, "epskcTimeoutDeactivation"}, |
| {&otBorderAgentCounters::mEpskcDeactivationMaxAttempts, "epskcMaxAttemptDeactivation"}, |
| {&otBorderAgentCounters::mEpskcDeactivationDisconnects, "epskcDisconnectDeactivation"}, |
| {&otBorderAgentCounters::mEpskcInvalidBaStateErrors, "epskcInvalidBaStateError"}, |
| {&otBorderAgentCounters::mEpskcInvalidArgsErrors, "epskcInvalidArgsError"}, |
| {&otBorderAgentCounters::mEpskcStartSecureSessionErrors, "epskcStartSecureSessionError"}, |
| {&otBorderAgentCounters::mEpskcSecureSessionSuccesses, "epskcSecureSessionSuccess"}, |
| {&otBorderAgentCounters::mEpskcSecureSessionFailures, "epskcSecureSessionFailure"}, |
| {&otBorderAgentCounters::mEpskcCommissionerPetitions, "epskcCommissionerPetition"}, |
| #endif |
| {&otBorderAgentCounters::mPskcSecureSessionSuccesses, "pskcSecureSessionSuccess"}, |
| {&otBorderAgentCounters::mPskcSecureSessionFailures, "pskcSecureSessionFailure"}, |
| {&otBorderAgentCounters::mPskcCommissionerPetitions, "pskcCommissionerPetition"}, |
| {&otBorderAgentCounters::mMgmtActiveGets, "mgmtActiveGet"}, |
| {&otBorderAgentCounters::mMgmtPendingGets, "mgmtPendingGet"}, |
| }; |
| |
| for (const CounterName &counter : kCounterNames) |
| { |
| OutputLine("%s: %lu", counter.mName, ToUlong(aCounters.*counter.mValuePtr)); |
| } |
| } |
| |
| #if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE |
| /** |
| * @cli ba servicebasename |
| * @code |
| * ba servicebasename OpenThreadBorderAgent |
| * Done |
| * @endcode |
| * @par api_copy |
| * #otBorderAgentSetMeshCoPServiceBaseName |
| */ |
| template <> otError Ba::Process<Cmd("servicebasename")>(Arg aArgs[]) |
| { |
| otError error = OT_ERROR_NONE; |
| |
| VerifyOrExit(!aArgs[0].IsEmpty() && aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
| error = otBorderAgentSetMeshCoPServiceBaseName(GetInstancePtr(), aArgs[0].GetCString()); |
| |
| exit: |
| return error; |
| } |
| #endif |
| |
| #if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE |
| /** |
| * @cli ba id (get,set) |
| * @code |
| * ba id |
| * cb6da1e0c0448aaec39fa90f3d58f45c |
| * Done |
| * @endcode |
| * @code |
| * ba id 00112233445566778899aabbccddeeff |
| * Done |
| * @endcode |
| * @cparam ba id [@ca{border-agent-id}] |
| * Use the optional `border-agent-id` argument to set the Border Agent ID. |
| * @par |
| * Gets or sets the 16 bytes Border Router ID which can uniquely identifies the device among multiple BRs. |
| * @sa otBorderAgentGetId |
| * @sa otBorderAgentSetId |
| */ |
| template <> otError Ba::Process<Cmd("id")>(Arg aArgs[]) |
| { |
| otError error = OT_ERROR_NONE; |
| otBorderAgentId id; |
| |
| if (aArgs[0].IsEmpty()) |
| { |
| SuccessOrExit(error = otBorderAgentGetId(GetInstancePtr(), &id)); |
| OutputBytesLine(id.mId); |
| } |
| else |
| { |
| uint16_t idLength = sizeof(id); |
| |
| SuccessOrExit(error = aArgs[0].ParseAsHexString(idLength, id.mId)); |
| VerifyOrExit(idLength == sizeof(id), error = OT_ERROR_INVALID_ARGS); |
| VerifyOrExit(aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
| |
| error = otBorderAgentSetId(GetInstancePtr(), &id); |
| } |
| |
| exit: |
| return error; |
| } |
| #endif // OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE |
| |
| #if OPENTHREAD_CONFIG_BORDER_AGENT_COMMISSIONER_EVICTION_API_ENABLE |
| /** |
| * @cli ba evictcommissioner |
| * @code |
| * ba evictcommissioner |
| * Done |
| * @endcode |
| * @par api_copy |
| * #otBorderAgentEvictActiveCommissioner |
| */ |
| template <> otError Ba::Process<Cmd("evictcommissioner")>(Arg aArgs[]) |
| { |
| otError error = OT_ERROR_NONE; |
| |
| VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
| error = otBorderAgentEvictActiveCommissioner(GetInstancePtr()); |
| |
| exit: |
| return error; |
| } |
| #endif |
| |
| #if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE |
| |
| template <> otError Ba::Process<Cmd("ephemeralkey")>(Arg aArgs[]) |
| { |
| otError error = OT_ERROR_NONE; |
| bool enable; |
| |
| /** |
| * @cli ba ephemeralkey |
| * @code |
| * ba ephemeralkey |
| * Stopped |
| * Done |
| * @endcode |
| * @par api_copy |
| * #otBorderAgentEphemeralKeyGetState |
| */ |
| if (aArgs[0].IsEmpty()) |
| { |
| otBorderAgentEphemeralKeyState state = otBorderAgentEphemeralKeyGetState(GetInstancePtr()); |
| |
| OutputLine("%s", otBorderAgentEphemeralKeyStateToString(state)); |
| } |
| /** |
| * @cli ba ephemeralkey (enable, disable) |
| * @code |
| * ba ephemeralkey enable |
| * Done |
| * @endcode |
| * @code |
| * ba ephemeralkey |
| * Enabled |
| * Done |
| * @endcode |
| * @cparam ba ephemeralkey @ca{enable|disable} |
| * @par api_copy |
| * #otBorderAgentEphemeralKeySetEnabled |
| */ |
| else if (ProcessEnableDisable(aArgs, otBorderAgentEphemeralKeySetEnabled) == OT_ERROR_NONE) |
| { |
| } |
| /** |
| * @cli ba ephemeralkey start |
| * @code |
| * ba ephemeralkey start Z10X20g3J15w1000P60m16 5000 1234 |
| * Done |
| * @endcode |
| * @cparam ba ephemeralkey start @ca{keystring} [@ca{timeout-in-msec}] [@ca{port}] |
| * @par api_copy |
| * #otBorderAgentEphemeralKeyStart |
| */ |
| else if (aArgs[0] == "start") |
| { |
| uint32_t timeout = 0; |
| uint16_t port = 0; |
| |
| VerifyOrExit(!aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
| |
| if (!aArgs[2].IsEmpty()) |
| { |
| SuccessOrExit(error = aArgs[2].ParseAsUint32(timeout)); |
| } |
| |
| if (!aArgs[3].IsEmpty()) |
| { |
| SuccessOrExit(error = aArgs[3].ParseAsUint16(port)); |
| |
| VerifyOrExit(aArgs[4].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
| } |
| |
| error = otBorderAgentEphemeralKeyStart(GetInstancePtr(), aArgs[1].GetCString(), timeout, port); |
| } |
| /** |
| * @cli ba ephemeralkey stop |
| * @code |
| * ba ephemeralkey stop |
| * Done |
| * @endcode |
| * @par api_copy |
| * #otBorderAgentEphemeralKeyStop |
| */ |
| else if (aArgs[0] == "stop") |
| { |
| VerifyOrExit(aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
| |
| otBorderAgentEphemeralKeyStop(GetInstancePtr()); |
| } |
| /** |
| * @cli ba ephemeralkey port |
| * @code |
| * ba ephemeralkey port |
| * 49153 |
| * Done |
| * @endcode |
| * @par api_copy |
| * #otBorderAgentEphemeralKeyGetUdpPort |
| */ |
| else if (aArgs[0] == "port") |
| { |
| VerifyOrExit(aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
| |
| OutputLine("%u", otBorderAgentEphemeralKeyGetUdpPort(GetInstancePtr())); |
| } |
| /** |
| * @cli ba ephemeralkey callback (enable, disable) |
| * @code |
| * ba ephemeralkey callback enable |
| * Done |
| * @endcode |
| * @code |
| * ba ephemeralkey start W10X10 5000 49155 |
| * Done |
| * BorderAgentEphemeralKey callback - state:Started |
| * BorderAgentEphemeralKey callback - state:Connected |
| * @endcode |
| * @cparam ba ephemeralkey callback @ca{enable|disable} |
| * @par api_copy |
| * #otBorderAgentEphemeralKeySetCallback |
| */ |
| else if (aArgs[0] == "callback") |
| { |
| SuccessOrExit(error = ParseEnableOrDisable(aArgs[1], enable)); |
| |
| VerifyOrExit(aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
| |
| if (enable) |
| { |
| otBorderAgentEphemeralKeySetCallback(GetInstancePtr(), HandleBorderAgentEphemeralKeyStateChange, this); |
| } |
| else |
| { |
| otBorderAgentEphemeralKeySetCallback(GetInstancePtr(), nullptr, nullptr); |
| } |
| } |
| #if OPENTHREAD_CONFIG_VERHOEFF_CHECKSUM_ENABLE |
| /** |
| * @cli ba ephemeralkey generate-tap |
| * @code |
| * ba ephemeralkey generate-tap |
| * 989710128 |
| * Done |
| * @endcode |
| * @par |
| * Generates a cryptographically secure random Thread Administration One-Time Passcode (TAP) string. |
| * @par |
| * Requires `OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE` and `OPENTHREAD_CONFIG_VERHOEFF_CHECKSUM_ENABLE`. |
| * @par |
| * The TAP is a string of 9 characters, generated as a sequence of eight cryptographically secure random |
| * numeric digits [`0`-`9`] followed by a single check digit determined using the Verhoeff algorithm. |
| * @par |
| * Note that this command simply generates and outputs a TAP. It does not start ephemeral key use with this TAP on |
| * the Border Agent. |
| * @sa otBorderAgentEphemeralKeyGenerateTap |
| */ |
| else if (aArgs[0] == "generate-tap") |
| { |
| otBorderAgentEphemeralKeyTap tap; |
| |
| VerifyOrExit(aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
| |
| SuccessOrExit(error = otBorderAgentEphemeralKeyGenerateTap(&tap)); |
| OutputLine("%s", tap.mTap); |
| } |
| /** |
| * @cli ba ephemeralkey validate-tap |
| * @code |
| * ba ephemeralkey validate-tap 989710128 |
| * validated |
| * Done |
| * @endcode |
| * @cparam ba ephemeralkey validate-tap @ca{tapstring} |
| * @par |
| * Validates a given Thread Administration One-Time Passcode (TAP) string. |
| * @par |
| * Requires `OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE` and `OPENTHREAD_CONFIG_VERHOEFF_CHECKSUM_ENABLE`. |
| * @par |
| * Validates that the TAP string has the proper length, contains digit characters [`0`-`9`], and validates the |
| * Verhoeff checksum. |
| * @sa otBorderAgentEphemeralKeyValidateTap |
| */ |
| else if (aArgs[0] == "validate-tap") |
| { |
| otBorderAgentEphemeralKeyTap tap; |
| |
| ClearAllBytes(tap); |
| |
| VerifyOrExit(!aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
| VerifyOrExit(aArgs[1].GetLength() <= OT_BORDER_AGENT_EPHEMERAL_KEY_TAP_STRING_LENGTH, |
| error = OT_ERROR_INVALID_ARGS); |
| memcpy(tap.mTap, aArgs[1].GetCString(), aArgs[1].GetLength()); |
| SuccessOrExit(error = otBorderAgentEphemeralKeyValidateTap(&tap)); |
| OutputLine("validated"); |
| } |
| #endif // OPENTHREAD_CONFIG_VERHOEFF_CHECKSUM_ENABLE |
| else |
| { |
| error = OT_ERROR_INVALID_ARGS; |
| } |
| |
| exit: |
| return error; |
| } |
| |
| void Ba::HandleBorderAgentEphemeralKeyStateChange(void *aContext) |
| { |
| reinterpret_cast<Ba *>(aContext)->HandleBorderAgentEphemeralKeyStateChange(); |
| } |
| |
| void Ba::HandleBorderAgentEphemeralKeyStateChange(void) |
| { |
| otBorderAgentEphemeralKeyState state = otBorderAgentEphemeralKeyGetState(GetInstancePtr()); |
| |
| OutputLine("BorderAgentEphemeralKey callback - state:%s", otBorderAgentEphemeralKeyStateToString(state)); |
| } |
| |
| #endif // OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE |
| |
| #if OPENTHREAD_CONFIG_BORDER_AGENT_ADMITTER_ENABLE |
| |
| template <> otError Ba::Process<Cmd("admitter")>(Arg aArgs[]) |
| { |
| otError error = OT_ERROR_NONE; |
| |
| /** |
| * @cli ba admitter |
| * @code |
| * ba admitter |
| * Disabled |
| * Done |
| * @endcode |
| * @par api_copy |
| * #otBorderAdmitterIsEnabled |
| */ |
| if (aArgs[0].IsEmpty()) |
| { |
| OutputEnabledDisabledStatus(otBorderAdmitterIsEnabled(GetInstancePtr())); |
| } |
| /** |
| * @cli ba admitter (enable, disable) |
| * @code |
| * ba admitter enable |
| * Done |
| * @endcode |
| * @code |
| * ba admitter |
| * Enabled |
| * Done |
| * @endcode |
| * @cparam ba admitter @ca{enable|disable} |
| * @par api_copy |
| * #otBorderAdmitterSetEnabled |
| */ |
| else if (ProcessEnableDisable(aArgs, otBorderAdmitterSetEnabled) == OT_ERROR_NONE) |
| { |
| } |
| /** |
| * @cli ba admitter state |
| * @code |
| * ba admitter state |
| * enabled: yes |
| * is-prime: yes |
| * is-active-commissioner: yes |
| * is-petition-rejected: no |
| * Done |
| * @endcode |
| * @par |
| * Outputs the state of Border Agent Admitter. |
| * @sa otBorderAdmitterIsEnabled |
| * @sa otBorderAdmitterIsPrimeAdmitter |
| * @sa otBorderAdmitterIsActiveCommissioner |
| * @sa otBorderAdmitterIsPetitionRejected |
| */ |
| else if (aArgs[0] == "state") |
| { |
| bool enabled = otBorderAdmitterIsEnabled(GetInstancePtr()); |
| |
| VerifyOrExit(aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
| |
| OutputLine("enabled: %s", ToYesNo(enabled)); |
| VerifyOrExit(enabled); |
| OutputLine("is-prime: %s", ToYesNo(otBorderAdmitterIsPrimeAdmitter(GetInstancePtr()))); |
| OutputLine("is-active-commissioner: %s", ToYesNo(otBorderAdmitterIsActiveCommissioner(GetInstancePtr()))); |
| OutputLine("is-petition-rejected: %s", ToYesNo(otBorderAdmitterIsPetitionRejected(GetInstancePtr()))); |
| } |
| /** |
| * @cli ba admitter joinerudpport (get,set) |
| * @code |
| * ba admitter joinerudpport |
| * 1000 |
| * Done |
| * @endcode |
| * @code |
| * ba admitter joinerudpport 1001 |
| * Done |
| * @endcode |
| * @cparam ba admitter joinerudpport [@ca{port}] |
| * @par |
| * Gets or sets the Border Agent Admitter Joiner UDP port. |
| * @sa otBorderAdmitterGetJoinerUdpPort |
| * @sa otBorderAdmitterSetJoinerUdpPort |
| */ |
| else if (aArgs[0] == "joinerudpport") |
| { |
| error = ProcessGetSet(aArgs + 1, otBorderAdmitterGetJoinerUdpPort, otBorderAdmitterSetJoinerUdpPort); |
| } |
| |
| /** |
| * @cli ba admitter enrollers |
| * @code |
| * ba admitter enrollers |
| * Enroller - id: phone01275ABC |
| * steering-data: [0042008000000000] |
| * mode: 0xc0 |
| * msec-since-registered: 10478 |
| * Joiner - iid: a5d2e4f0c8b1937e |
| * msec-since-accepted: 3299 |
| * msec-till-expiration: 418852 |
| * Done |
| * @endcode |
| * @par |
| * Outputs the list of enrollers and accepted joiners per enroller. |
| * @sa otBorderAdmitterGetNextEnrollerInfo |
| * @sa otBorderAdmitterGetNextJoinerInfo |
| */ |
| else if (aArgs[0] == "enrollers") |
| { |
| otBorderAdmitterIterator iter; |
| otBorderAdmitterEnrollerInfo enrollerInfo; |
| otBorderAdmitterJoinerInfo joinerInfo; |
| Uint64StringBuffer u64String; |
| |
| VerifyOrExit(aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS); |
| |
| otBorderAdmitterInitIterator(GetInstancePtr(), &iter); |
| |
| while (otBorderAdmitterGetNextEnrollerInfo(&iter, &enrollerInfo) == OT_ERROR_NONE) |
| { |
| OutputLine("Enroller - id: %s", enrollerInfo.mId); |
| OutputFormat(kIndentSize, "steering-data: ["); |
| OutputBytes(enrollerInfo.mSteeringData.m8, enrollerInfo.mSteeringData.mLength); |
| OutputLine("]"); |
| OutputLine(kIndentSize, "mode: 0x%02x", enrollerInfo.mMode); |
| OutputLine(kIndentSize, "msec-since-registered: %s", |
| Uint64ToString(enrollerInfo.mRegisterDuration, u64String)); |
| |
| while (otBorderAdmitterGetNextJoinerInfo(&iter, &joinerInfo) == OT_ERROR_NONE) |
| { |
| OutputFormat(kIndentSize, "Joiner - iid: "); |
| OutputBytesLine(joinerInfo.mIid.mFields.m8, OT_IP6_IID_SIZE); |
| |
| OutputLine(kIndentSize * 2, "msec-since-accepted: %s", |
| Uint64ToString(joinerInfo.mMsecSinceAccept, u64String)); |
| OutputLine(kIndentSize * 2, "msec-till-expiration: %lu", ToUlong(joinerInfo.mMsecTillExpiration)); |
| } |
| } |
| } |
| else |
| { |
| error = OT_ERROR_INVALID_ARGS; |
| } |
| |
| exit: |
| return error; |
| } |
| |
| #endif // OPENTHREAD_CONFIG_BORDER_AGENT_ADMITTER_ENABLE |
| |
| otError Ba::Process(Arg aArgs[]) |
| { |
| #define CmdEntry(aCommandString) {aCommandString, &Ba::Process<Cmd(aCommandString)>} |
| |
| static constexpr Command kCommands[] = { |
| #if OPENTHREAD_CONFIG_BORDER_AGENT_ADMITTER_ENABLE |
| CmdEntry("admitter"), |
| #endif |
| CmdEntry("counters"), |
| CmdEntry("disable"), |
| CmdEntry("enable"), |
| #if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE |
| CmdEntry("ephemeralkey"), |
| #endif |
| #if OPENTHREAD_CONFIG_BORDER_AGENT_COMMISSIONER_EVICTION_API_ENABLE |
| CmdEntry("evictcommissioner"), |
| #endif |
| #if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE |
| CmdEntry("id"), |
| #endif |
| CmdEntry("port"), |
| #if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE |
| CmdEntry("servicebasename"), |
| #endif |
| CmdEntry("sessions"), |
| CmdEntry("state"), |
| }; |
| |
| #undef CmdEntry |
| |
| static_assert(BinarySearch::IsSorted(kCommands), "kCommands is not sorted"); |
| |
| otError error = OT_ERROR_INVALID_COMMAND; |
| const Command *command; |
| |
| 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 |
| |
| #endif // OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE |