[cli] move border agent commands to a separate module (#12214)

This change moves the CLI implementation for the Border Agent from
the main `cli.cpp` into a new dedicated `Ba` class within
`cli_ba.cpp` and `cli_ba.hpp`.

The new `Ba` module is integrated into the main `Interpreter` class,
following the same pattern used by other CLI modules such as `Bbr`
and `Br`. This improves code organization and modularity, making the
CLI codebase easier to navigate and maintain.

The functionality of the `ba` commands remains unchanged.
This commit is contained in:
Abtin Keshavarzian
2025-12-17 10:27:21 -08:00
committed by GitHub
parent 7c9de986c7
commit 20585616d2
6 changed files with 654 additions and 388 deletions
+2
View File
@@ -30,6 +30,8 @@ import("../../etc/gn/openthread.gni")
openthread_cli_sources = [
"cli.cpp",
"cli.hpp",
"cli_ba.cpp",
"cli_ba.hpp",
"cli_bbr.cpp",
"cli_bbr.hpp",
"cli_br.cpp",
+1
View File
@@ -33,6 +33,7 @@ set(COMMON_INCLUDES
set(COMMON_SOURCES
cli.cpp
cli_ba.cpp
cli_bbr.cpp
cli_br.cpp
cli_coap.cpp
+4 -380
View File
@@ -95,6 +95,9 @@ Interpreter::Interpreter(Instance *aInstance, otCliOutputCallback aCallback, voi
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE && OPENTHREAD_CONFIG_MULTICAST_DNS_PUBLIC_API_ENABLE
, mMdns(aInstance, *this)
#endif
#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
, mBa(aInstance, *this)
#endif
#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
, mBbr(aInstance, *this)
#endif
@@ -442,387 +445,8 @@ template <> otError Interpreter::Process<Cmd("history")>(Arg aArgs[]) { return m
#endif
#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
template <> otError Interpreter::Process<Cmd("ba")>(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
/**
* @cli ba (enable, disable)
* @code
* ba enable
* Done
* @endcode
* @code
* ba disable
* Done
* @endcode
* @cparam ba @ca{enable|disable}
* @par api_copy
* #otBorderAgentSetEnabled
*/
if (ProcessEnableDisable(aArgs, otBorderAgentSetEnabled) == OT_ERROR_NONE)
{
}
/**
* @cli ba port
* @code
* ba port
* 49153
* Done
* @endcode
* @par api_copy
* #otBorderAgentGetUdpPort
*/
else if (aArgs[0] == "port")
{
OutputLine("%u", otBorderAgentGetUdpPort(GetInstancePtr()));
}
/**
* @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
*/
else if (aArgs[0] == "state")
{
if (!otBorderAgentIsEnabled(GetInstancePtr()))
{
OutputLine("Disabled");
}
else
{
OutputLine("%s", otBorderAgentIsActive(GetInstancePtr()) ? "Active" : "Inactive");
}
}
#if OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
/**
* @cli ba servicebasename
* @code
* ba servicebasename OpenThreadBorderAgent
* Done
* @endcode
* @par api_copy
* #otBorderAgentSetMeshCoPServiceBaseName
*/
else if (aArgs[0] == "servicebasename")
{
VerifyOrExit(!aArgs[1].IsEmpty() && aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
error = otBorderAgentSetMeshCoPServiceBaseName(GetInstancePtr(), aArgs[1].GetCString());
}
template <> otError Interpreter::Process<Cmd("ba")>(Arg aArgs[]) { return mBa.Process(aArgs); }
#endif
/**
* @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).
*/
else if (aArgs[0] == "sessions")
{
otBorderAgentSessionIterator iterator;
otBorderAgentSessionInfo info;
char sockAddrString[OT_IP6_SOCK_ADDR_STRING_SIZE];
Uint64StringBuffer lifetimeString;
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, info.mIsConnected ? "yes" : "no",
info.mIsCommissioner ? "yes" : "no", Uint64ToString(info.mLifetime, lifetimeString));
}
}
#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
*/
else if (aArgs[0] == "id")
{
otBorderAgentId id;
if (aArgs[1].IsEmpty())
{
SuccessOrExit(error = otBorderAgentGetId(GetInstancePtr(), &id));
OutputBytesLine(id.mId);
}
else
{
uint16_t idLength = sizeof(id);
SuccessOrExit(error = aArgs[1].ParseAsHexString(idLength, id.mId));
VerifyOrExit(idLength == sizeof(id), error = OT_ERROR_INVALID_ARGS);
error = otBorderAgentSetId(GetInstancePtr(), &id);
}
}
#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
*/
else if (aArgs[0] == "evictcommissioner")
{
VerifyOrExit(aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
error = otBorderAgentEvictActiveCommissioner(GetInstancePtr());
}
#endif
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
else if (aArgs[0] == "ephemeralkey")
{
bool enable;
/**
* @cli ba ephemeralkey
* @code
* ba ephemeralkey
* Stopped
* Done
* @endcode
* @par api_copy
* #otBorderAgentEphemeralKeyGetState
*/
if (aArgs[1].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 + 1, otBorderAgentEphemeralKeySetEnabled) == OT_ERROR_NONE)
{
}
/**
* @cli ba ephemeralkey start <keystring> [timeout-in-msec] [port]
* @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[1] == "start")
{
uint32_t timeout = 0;
uint16_t port = 0;
VerifyOrExit(!aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
if (!aArgs[3].IsEmpty())
{
SuccessOrExit(error = aArgs[3].ParseAsUint32(timeout));
}
if (!aArgs[4].IsEmpty())
{
SuccessOrExit(error = aArgs[4].ParseAsUint16(port));
}
error = otBorderAgentEphemeralKeyStart(GetInstancePtr(), aArgs[2].GetCString(), timeout, port);
}
/**
* @cli ba ephemeralkey stop
* @code
* ba ephemeralkey stop
* Done
* @endcode
* @par api_copy
* #otBorderAgentEphemeralKeyStop
*/
else if (aArgs[1] == "stop")
{
otBorderAgentEphemeralKeyStop(GetInstancePtr());
}
/**
* @cli ba ephemeralkey port
* @code
* ba ephemeralkey port
* 49153
* Done
* @endcode
* @par api_copy
* #otBorderAgentEphemeralKeyGetUdpPort
*/
else if (aArgs[1] == "port")
{
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[1] == "callback")
{
SuccessOrExit(error = ParseEnableOrDisable(aArgs[2], enable));
if (enable)
{
otBorderAgentEphemeralKeySetCallback(GetInstancePtr(), HandleBorderAgentEphemeralKeyStateChange, this);
}
else
{
otBorderAgentEphemeralKeySetCallback(GetInstancePtr(), nullptr, nullptr);
}
}
else
{
error = OT_ERROR_INVALID_ARGS;
}
}
#endif // OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
/**
* @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
*/
else if (aArgs[0] == "counters")
{
OutputBorderAgentCounters(*otBorderAgentGetCounters(GetInstancePtr()));
}
else
{
ExitNow(error = OT_ERROR_INVALID_COMMAND);
}
exit:
return error;
}
void Interpreter::OutputBorderAgentCounters(const otBorderAgentCounters &aCounters)
{
struct BaCounterName
{
const uint32_t otBorderAgentCounters::*mValuePtr;
const char *mName;
};
static const BaCounterName kBaCounterNames[] = {
#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 BaCounterName &counter : kBaCounterNames)
{
OutputLine("%s: %lu", counter.mName, ToUlong(aCounters.*counter.mValuePtr));
}
}
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
void Interpreter::HandleBorderAgentEphemeralKeyStateChange(void *aContext)
{
reinterpret_cast<Interpreter *>(aContext)->HandleBorderAgentEphemeralKeyStateChange();
}
void Interpreter::HandleBorderAgentEphemeralKeyStateChange(void)
{
otBorderAgentEphemeralKeyState state = otBorderAgentEphemeralKeyGetState(GetInstancePtr());
OutputLine("BorderAgentEphemeralKey callback - state:%s", otBorderAgentEphemeralKeyStateToString(state));
}
#endif
#endif // OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
#if OPENTHREAD_CONFIG_BORDER_AGENT_TRACKER_ENABLE
+6 -8
View File
@@ -56,6 +56,7 @@
#include <openthread/thread_ftd.h>
#include <openthread/udp.h>
#include "cli/cli_ba.hpp"
#include "cli/cli_bbr.hpp"
#include "cli/cli_br.hpp"
#include "cli/cli_coap.hpp"
@@ -106,6 +107,7 @@ extern "C" void otCliOutputFormat(const char *aFmt, ...);
class Interpreter : public OutputImplementer, public Utils
{
#if OPENTHREAD_FTD || OPENTHREAD_MTD
friend class Ba;
friend class Br;
friend class Bbr;
friend class Commissioner;
@@ -292,14 +294,6 @@ private:
void HandleSntpResponse(uint64_t aTime, otError aResult);
#endif
#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
void OutputBorderAgentCounters(const otBorderAgentCounters &aCounters);
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
static void HandleBorderAgentEphemeralKeyStateChange(void *aContext);
void HandleBorderAgentEphemeralKeyStateChange(void);
#endif
#endif
static void HandleDetachGracefullyResult(void *aContext);
void HandleDetachGracefullyResult(void);
@@ -373,6 +367,10 @@ private:
Mdns mMdns;
#endif
#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
Ba mBa;
#endif
#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
Bbr mBbr;
#endif
+545
View File
@@ -0,0 +1,545 @@
/*
* 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 api_copy
* #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 api_copy
* #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, info.mIsConnected ? "yes" : "no",
info.mIsCommissioner ? "yes" : "no", 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 <keystring> [timeout-in-msec] [port]
* @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);
}
}
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
otError Ba::Process(Arg aArgs[])
{
#define CmdEntry(aCommandString) {aCommandString, &Ba::Process<Cmd(aCommandString)>}
static constexpr Command kCommands[] = {
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
+96
View File
@@ -0,0 +1,96 @@
/*
* 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 contains definitions for CLI to Border Agent.
*/
#ifndef CLI_BA_HPP_
#define CLI_BA_HPP_
#include "openthread-core-config.h"
#include <openthread/border_agent.h>
#include "cli/cli_config.h"
#include "cli/cli_utils.hpp"
#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
namespace ot {
namespace Cli {
/**
* Implements the Border Agent CLI interpreter.
*/
class Ba : private Utils
{
public:
/**
* Constructor
*
* @param[in] aInstance The OpenThread Instance.
* @param[in] aOutputImplementer An `OutputImplementer`.
*/
Ba(otInstance *aInstance, OutputImplementer &aOutputImplementer)
: Utils(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<Ba>;
template <CommandId kCommandId> otError Process(Arg aArgs[]);
void OutputBorderAgentCounters(const otBorderAgentCounters &aCounters);
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
static void HandleBorderAgentEphemeralKeyStateChange(void *aContext);
void HandleBorderAgentEphemeralKeyStateChange(void);
#endif
};
} // namespace Cli
} // namespace ot
#endif // OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
#endif // CLI_BA_HPP_