[epskc] add API for ePSKc telemetry (#10608)

Adds API to get border agent counters which include counters for
ePSKc, PSKc and coap messages.
This commit is contained in:
Yang Sun
2024-08-21 23:02:44 -07:00
committed by GitHub
parent e90792da0b
commit 24e930654e
24 changed files with 452 additions and 86 deletions
+32
View File
@@ -110,6 +110,38 @@ typedef enum otBorderAgentState
OT_BORDER_AGENT_STATE_ACTIVE = 2, ///< Border agent is connected with external commissioner.
} otBorderAgentState;
typedef struct otBorderAgentCounters
{
uint32_t mEpskcActivations; ///< The number of ePSKc activations
uint32_t mEpskcDeactivationClears; ///< The number of ePSKc deactivations via API
uint32_t mEpskcDeactivationTimeouts; ///< The number of ePSKc deactivations due to timeout
uint32_t mEpskcDeactivationMaxAttempts; ///< The number of ePSKc deactivations due to reached max attempts
uint32_t mEpskcDeactivationDisconnects; ///< The number of ePSKc deactivations due to commissioner disconnected
uint32_t mEpskcInvalidBaStateErrors; ///< The number of invalid border agent state errors at ePSKc activation
uint32_t mEpskcInvalidArgsErrors; ///< The number of invalid args errors at ePSKc activation
uint32_t mEpskcStartSecureSessionErrors; ///< The number of start secure session errors at ePSKc activation
uint32_t mEpskcSecureSessionSuccesses; ///< The number of established secure sessions with ePSKc
uint32_t mEpskcSecureSessionFailures; ///< The number of failed secure sessions with ePSKc
uint32_t mEpskcCommissionerPetitions; ///< The number of successful commissioner petitions with ePSKc
uint32_t mPskcSecureSessionSuccesses; ///< The number of established secure sessions with PSKc
uint32_t mPskcSecureSessionFailures; ///< The number of failed secure sessions with PSKc
uint32_t mPskcCommissionerPetitions; ///< The number of successful commissioner petitions with PSKc
uint32_t mMgmtActiveGets; ///< The number of MGMT_ACTIVE_GET.req sent over secure sessions
uint32_t mMgmtPendingGets; ///< The number of MGMT_PENDING_GET.req sent over secure sessions
} otBorderAgentCounters;
/**
* Gets the counters of the Thread Border Agent.
*
* @param[in] aInstance A pointer to an OpenThread instance.
*
* @returns A pointer to the Border Agent counters.
*
*/
const otBorderAgentCounters *otBorderAgentGetCounters(otInstance *aInstance);
/**
* Gets the #otBorderAgentState of the Thread Border Agent role.
*
+21 -8
View File
@@ -67,14 +67,27 @@ extern "C" {
#define OT_DEFAULT_COAP_SECURE_PORT 5684 ///< Default CoAP Secure port, as specified in RFC 7252
/**
* CoAP secure connection event types.
*
*/
typedef enum otCoapSecureConnectEvent
{
OT_COAP_SECURE_CONNECTED = 0, ///< Connection established
OT_COAP_SECURE_DISCONNECTED_PEER_CLOSED, ///< Disconnected by peer
OT_COAP_SECURE_DISCONNECTED_LOCAL_CLOSED, ///< Disconnected locally
OT_COAP_SECURE_DISCONNECTED_MAX_ATTEMPTS, ///< Disconnected due to reaching the max connection attempts
OT_COAP_SECURE_DISCONNECTED_ERROR, ///< Disconnected due to an error
} otCoapSecureConnectEvent;
/**
* Pointer is called when the DTLS connection state changes.
*
* @param[in] aConnected true, if a connection was established, false otherwise.
* @param[in] aEvent The connection event.
* @param[in] aContext A pointer to arbitrary context information.
*
*/
typedef void (*otHandleCoapSecureClientConnect)(bool aConnected, void *aContext);
typedef void (*otHandleCoapSecureClientConnect)(otCoapSecureConnectEvent aEvent, void *aContext);
/**
* Callback function pointer to notify when the CoAP secure agent is automatically stopped due to reaching the maximum
@@ -368,17 +381,17 @@ void otCoapSecureRemoveBlockWiseResource(otInstance *aInstance, otCoapBlockwiseR
void otCoapSecureSetDefaultHandler(otInstance *aInstance, otCoapRequestHandler aHandler, void *aContext);
/**
* Sets the connected callback to indicate, when
* a Client connect to the CoAP Secure server.
* Sets the connect event callback to indicate when
* a Client connection to the CoAP Secure server has changed.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aHandler A pointer to a function that will be called once DTLS connection is established.
* @param[in] aHandler A pointer to a function that will be called once DTLS connection has changed.
* @param[in] aContext A pointer to arbitrary context information. May be NULL if not used.
*
*/
void otCoapSecureSetClientConnectedCallback(otInstance *aInstance,
otHandleCoapSecureClientConnect aHandler,
void *aContext);
void otCoapSecureSetClientConnectEventCallback(otInstance *aInstance,
otHandleCoapSecureClientConnect aHandler,
void *aContext);
/**
* Sends a CoAP response block-wise from the CoAP Secure server.
+1 -1
View File
@@ -53,7 +53,7 @@ extern "C" {
* @note This number versions both OpenThread platform and user APIs.
*
*/
#define OPENTHREAD_API_VERSION (435)
#define OPENTHREAD_API_VERSION (436)
/**
* @addtogroup api-instance
+27
View File
@@ -453,6 +453,33 @@ Disables callback from Border Agent for ephemeral key state changes.
Done
```
### ba counters
Get the border agent counter values.
Note that it requires `OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE` to output the ePSKc counters.
```bash
> ba counters
epskcActivation: 2
epskcApiDeactivation: 1
epskcTimeoutDeactivation: 1
epskcMaxAttemptDeactivation: 0
epskcDisconnectDeactivation: 0
epskcInvalidBaStateError: 1
epskcInvalidArgsError: 1
epskcStartSecureSessionError: 0
epskcSecureSessionSuccess: 0
epskcSecureSessionFailure: 0
epskcCommissionerPetition: 0
pskcSecureSessionSuccess: 0
pskcSecureSessionFailure: 0
pskcCommissionerPetition: 0
mgmtActiveGet: 0
mgmtPendingGet: 0
Done
```
### bufferinfo
Show the current message buffer information.
+52
View File
@@ -541,6 +541,36 @@ template <> otError Interpreter::Process<Cmd("ba")>(Arg aArgs[])
}
}
#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);
@@ -550,6 +580,28 @@ exit:
return error;
}
void Interpreter::OutputBorderAgentCounters(const otBorderAgentCounters &aCounters)
{
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
OutputLine("epskcActivation: %lu ", ToUlong(aCounters.mEpskcActivations));
OutputLine("epskcApiDeactivation: %lu ", ToUlong(aCounters.mEpskcDeactivationClears));
OutputLine("epskcTimeoutDeactivation: %lu ", ToUlong(aCounters.mEpskcDeactivationTimeouts));
OutputLine("epskcMaxAttemptDeactivation: %lu ", ToUlong(aCounters.mEpskcDeactivationMaxAttempts));
OutputLine("epskcDisconnectDeactivation: %lu ", ToUlong(aCounters.mEpskcDeactivationDisconnects));
OutputLine("epskcInvalidBaStateError: %lu ", ToUlong(aCounters.mEpskcInvalidBaStateErrors));
OutputLine("epskcInvalidArgsError: %lu ", ToUlong(aCounters.mEpskcInvalidArgsErrors));
OutputLine("epskcStartSecureSessionError: %lu ", ToUlong(aCounters.mEpskcStartSecureSessionErrors));
OutputLine("epskcSecureSessionSuccess: %lu ", ToUlong(aCounters.mEpskcSecureSessionSuccesses));
OutputLine("epskcSecureSessionFailure: %lu ", ToUlong(aCounters.mEpskcSecureSessionFailures));
OutputLine("epskcCommissionerPetition: %lu ", ToUlong(aCounters.mEpskcCommissionerPetitions));
#endif
OutputLine("pskcSecureSessionSuccess: %lu ", ToUlong(aCounters.mPskcSecureSessionSuccesses));
OutputLine("pskcSecureSessionFailure: %lu ", ToUlong(aCounters.mPskcSecureSessionFailures));
OutputLine("pskcCommissionerPetition: %lu ", ToUlong(aCounters.mPskcCommissionerPetitions));
OutputLine("mgmtActiveGet: %lu ", ToUlong(aCounters.mMgmtActiveGets));
OutputLine("mgmtPendingGet: %lu", ToUlong(aCounters.mMgmtPendingGets));
}
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
void Interpreter::HandleBorderAgentEphemeralKeyStateChange(void *aContext)
{
+5 -1
View File
@@ -40,6 +40,7 @@
#include <stdarg.h>
#include <openthread/border_agent.h>
#include <openthread/cli.h>
#include <openthread/dataset.h>
#include <openthread/dns_client.h>
@@ -314,9 +315,12 @@ private:
void HandleSntpResponse(uint64_t aTime, otError aResult);
#endif
#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE && OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
#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);
+7 -7
View File
@@ -210,7 +210,7 @@ exit:
* Starts the CoAP Secure service. @moreinfo{@coaps}.
* @sa otCoapSecureStart
* @sa otCoapSecureSetSslAuthMode
* @sa otCoapSecureSetClientConnectedCallback
* @sa otCoapSecureSetClientConnectEventCallback
*/
template <> otError CoapSecure::Process<Cmd("start")>(Arg aArgs[])
{
@@ -235,7 +235,7 @@ template <> otError CoapSecure::Process<Cmd("start")>(Arg aArgs[])
}
otCoapSecureSetSslAuthMode(GetInstancePtr(), verifyPeerCert);
otCoapSecureSetClientConnectedCallback(GetInstancePtr(), &CoapSecure::HandleConnected, this);
otCoapSecureSetClientConnectEventCallback(GetInstancePtr(), &CoapSecure::HandleConnectEvent, this);
#if CLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER
otCoapSecureSetDefaultHandler(GetInstancePtr(), &CoapSecure::DefaultHandler, this);
@@ -629,7 +629,7 @@ template <> otError CoapSecure::Process<Cmd("connect")>(Arg aArgs[])
SuccessOrExit(error = aArgs[1].ParseAsUint16(sockaddr.mPort));
}
SuccessOrExit(error = otCoapSecureConnect(GetInstancePtr(), &sockaddr, &CoapSecure::HandleConnected, this));
SuccessOrExit(error = otCoapSecureConnect(GetInstancePtr(), &sockaddr, &CoapSecure::HandleConnectEvent, this));
exit:
return error;
@@ -783,14 +783,14 @@ void CoapSecure::Stop(void)
otCoapSecureStop(GetInstancePtr());
}
void CoapSecure::HandleConnected(bool aConnected, void *aContext)
void CoapSecure::HandleConnectEvent(otCoapSecureConnectEvent aEvent, void *aContext)
{
static_cast<CoapSecure *>(aContext)->HandleConnected(aConnected);
static_cast<CoapSecure *>(aContext)->HandleConnectEvent(aEvent);
}
void CoapSecure::HandleConnected(bool aConnected)
void CoapSecure::HandleConnectEvent(otCoapSecureConnectEvent aEvent)
{
if (aConnected)
if (aEvent == OT_COAP_SECURE_CONNECTED)
{
OutputLine("coaps connected");
}
+2 -2
View File
@@ -137,8 +137,8 @@ private:
void DefaultHandler(otMessage *aMessage, const otMessageInfo *aMessageInfo);
#endif // CLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER
static void HandleConnected(bool aConnected, void *aContext);
void HandleConnected(bool aConnected);
static void HandleConnectEvent(otCoapSecureConnectEvent aEvent, void *aContext);
void HandleConnectEvent(otCoapSecureConnectEvent aEvent);
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
otCoapBlockwiseResource mResource;
+5
View File
@@ -110,4 +110,9 @@ void otBorderAgentSetEphemeralKeyCallback(otInstance *aIns
#endif // OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
const otBorderAgentCounters *otBorderAgentGetCounters(otInstance *aInstance)
{
return AsCoreType(aInstance).Get<MeshCoP::BorderAgent>().GetCounters();
}
#endif // OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
+4 -4
View File
@@ -178,11 +178,11 @@ void otCoapSecureRemoveResource(otInstance *aInstance, otCoapResource *aResource
AsCoreType(aInstance).GetApplicationCoapSecure().RemoveResource(AsCoreType(aResource));
}
void otCoapSecureSetClientConnectedCallback(otInstance *aInstance,
otHandleCoapSecureClientConnect aHandler,
void *aContext)
void otCoapSecureSetClientConnectEventCallback(otInstance *aInstance,
otHandleCoapSecureClientConnect aHandler,
void *aContext)
{
AsCoreType(aInstance).GetApplicationCoapSecure().SetConnectedCallback(aHandler, aContext);
AsCoreType(aInstance).GetApplicationCoapSecure().SetConnectEventCallback(aHandler, aContext);
}
void otCoapSecureSetDefaultHandler(otInstance *aInstance, otCoapRequestHandler aHandler, void *aContext)
+10 -7
View File
@@ -85,8 +85,8 @@ Error CoapSecure::Open(uint16_t aMaxAttempts, AutoStopCallback aCallback, void *
SuccessOrExit(mDtls.SetMaxConnectionAttempts(aMaxAttempts, HandleDtlsAutoClose, this));
mAutoStopCallback.Set(aCallback, aContext);
mConnectedCallback.Clear();
SuccessOrExit(mDtls.Open(HandleDtlsReceive, HandleDtlsConnected, this));
mConnectEventCallback.Clear();
SuccessOrExit(mDtls.Open(HandleDtlsReceive, HandleDtlsConnectEvent, this));
error = kErrorNone;
@@ -102,9 +102,9 @@ void CoapSecure::Stop(void)
ClearRequestsAndResponses();
}
Error CoapSecure::Connect(const Ip6::SockAddr &aSockAddr, ConnectedCallback aCallback, void *aContext)
Error CoapSecure::Connect(const Ip6::SockAddr &aSockAddr, ConnectEventCallback aCallback, void *aContext)
{
mConnectedCallback.Set(aCallback, aContext);
mConnectEventCallback.Set(aCallback, aContext);
return mDtls.Connect(aSockAddr);
}
@@ -178,12 +178,15 @@ Error CoapSecure::Send(ot::Message &aMessage, const Ip6::MessageInfo &aMessageIn
return kErrorNone;
}
void CoapSecure::HandleDtlsConnected(void *aContext, bool aConnected)
void CoapSecure::HandleDtlsConnectEvent(MeshCoP::SecureTransport::ConnectEvent aEvent, void *aContext)
{
return static_cast<CoapSecure *>(aContext)->HandleDtlsConnected(aConnected);
return static_cast<CoapSecure *>(aContext)->HandleDtlsConnectEvent(aEvent);
}
void CoapSecure::HandleDtlsConnected(bool aConnected) { mConnectedCallback.InvokeIfSet(aConnected); }
void CoapSecure::HandleDtlsConnectEvent(MeshCoP::SecureTransport::ConnectEvent aEvent)
{
mConnectEventCallback.InvokeIfSet(aEvent);
}
void CoapSecure::HandleDtlsAutoClose(void *aContext)
{
+12 -15
View File
@@ -53,13 +53,10 @@ class CoapSecure : public CoapBase
{
public:
/**
* Pointer is called once DTLS connection is established.
*
* @param[in] aConnected TRUE if a connection was established, FALSE otherwise.
* @param[in] aContext A pointer to arbitrary context information.
* Function pointer which is called reporting a connection event (when connection established or disconnected)
*
*/
typedef void (*ConnectedCallback)(bool aConnected, void *aContext);
typedef otHandleCoapSecureClientConnect ConnectEventCallback;
/**
* Callback to notify when the agent is automatically stopped due to reaching the maximum number of connection
@@ -122,9 +119,9 @@ public:
* @param[in] aContext A pointer to arbitrary context information.
*
*/
void SetConnectedCallback(ConnectedCallback aCallback, void *aContext)
void SetConnectEventCallback(ConnectEventCallback aCallback, void *aContext)
{
mConnectedCallback.Set(aCallback, aContext);
mConnectEventCallback.Set(aCallback, aContext);
}
/**
@@ -143,7 +140,7 @@ public:
* @retval kErrorNone Successfully started DTLS connection.
*
*/
Error Connect(const Ip6::SockAddr &aSockAddr, ConnectedCallback aCallback, void *aContext);
Error Connect(const Ip6::SockAddr &aSockAddr, ConnectEventCallback aCallback, void *aContext);
/**
* Indicates whether or not the DTLS session is active.
@@ -421,8 +418,8 @@ private:
}
Error Send(ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
static void HandleDtlsConnected(void *aContext, bool aConnected);
void HandleDtlsConnected(bool aConnected);
static void HandleDtlsConnectEvent(MeshCoP::SecureTransport::ConnectEvent aEvent, void *aContext);
void HandleDtlsConnectEvent(MeshCoP::SecureTransport::ConnectEvent aEvent);
static void HandleDtlsAutoClose(void *aContext);
void HandleDtlsAutoClose(void);
@@ -433,11 +430,11 @@ private:
static void HandleTransmit(Tasklet &aTasklet);
void HandleTransmit(void);
MeshCoP::SecureTransport mDtls;
Callback<ConnectedCallback> mConnectedCallback;
Callback<AutoStopCallback> mAutoStopCallback;
ot::MessageQueue mTransmitQueue;
TaskletContext mTransmitTask;
MeshCoP::SecureTransport mDtls;
Callback<ConnectEventCallback> mConnectEventCallback;
Callback<AutoStopCallback> mAutoStopCallback;
ot::MessageQueue mTransmitQueue;
TaskletContext mTransmitTask;
};
} // namespace Coap
+66 -5
View File
@@ -205,6 +205,17 @@ void BorderAgent::HandleCoapResponse(const ForwardContext &aForwardContext,
IgnoreError(Get<Ip6::Udp>().AddReceiver(mUdpReceiver));
mState = kStateAccepted;
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
if (mUsingEphemeralKey)
{
mCounters.mEpskcCommissionerPetitions++;
}
else
#endif
{
mCounters.mPskcCommissionerPetitions++;
}
LogInfo("Commissioner accepted - SessionId:%u ALOC:%s", sessionId,
mCommissionerAloc.GetAddress().ToString().AsCString());
}
@@ -252,6 +263,7 @@ BorderAgent::BorderAgent(Instance &aInstance)
#endif
{
mCommissionerAloc.InitAsThreadOriginMeshLocal();
ClearAllBytes(mCounters);
}
#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
@@ -468,6 +480,7 @@ void BorderAgent::HandleTmf<kUriCommissionerSet>(Coap::Message &aMessage, const
template <> void BorderAgent::HandleTmf<kUriActiveGet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
HandleTmfDatasetGet(aMessage, aMessageInfo, Dataset::kActive);
mCounters.mMgmtActiveGets++;
}
template <> void BorderAgent::HandleTmf<kUriActiveSet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
@@ -478,6 +491,7 @@ template <> void BorderAgent::HandleTmf<kUriActiveSet>(Coap::Message &aMessage,
template <> void BorderAgent::HandleTmf<kUriPendingGet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
HandleTmfDatasetGet(aMessage, aMessageInfo, Dataset::kPending);
mCounters.mMgmtPendingGets++;
}
template <> void BorderAgent::HandleTmf<kUriPendingSet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
@@ -635,18 +649,28 @@ exit:
FreeMessageOnError(response, error);
}
void BorderAgent::HandleConnected(bool aConnected, void *aContext)
void BorderAgent::HandleConnected(SecureTransport::ConnectEvent aEvent, void *aContext)
{
static_cast<BorderAgent *>(aContext)->HandleConnected(aConnected);
static_cast<BorderAgent *>(aContext)->HandleConnected(aEvent);
}
void BorderAgent::HandleConnected(bool aConnected)
void BorderAgent::HandleConnected(SecureTransport::ConnectEvent aEvent)
{
if (aConnected)
if (aEvent == SecureTransport::kConnected)
{
LogInfo("SecureSession connected");
mState = kStateConnected;
mTimer.Start(kKeepAliveTimeout);
#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
if (mUsingEphemeralKey)
{
mCounters.mEpskcSecureSessionSuccesses++;
}
else
#endif
{
mCounters.mPskcSecureSessionSuccesses++;
}
}
else
{
@@ -658,12 +682,24 @@ void BorderAgent::HandleConnected(bool aConnected)
if (mUsingEphemeralKey)
{
RestartAfterRemovingEphemeralKey();
if (aEvent == SecureTransport::kDisconnectedError)
{
mCounters.mEpskcSecureSessionFailures++;
}
if (aEvent == SecureTransport::kDisconnectedPeerClosed)
{
mCounters.mEpskcDeactivationDisconnects++;
}
}
else
#endif
{
mState = kStateStarted;
mUdpProxyPort = 0;
if (aEvent == SecureTransport::kDisconnectedError)
{
mCounters.mPskcSecureSessionFailures++;
}
}
}
}
@@ -702,7 +738,7 @@ Error BorderAgent::Start(uint16_t aUdpPort, const uint8_t *aPsk, uint8_t aPskLen
SuccessOrExit(error = Get<Tmf::SecureAgent>().SetPsk(aPsk, aPskLength));
Get<Tmf::SecureAgent>().SetConnectedCallback(HandleConnected, this);
Get<Tmf::SecureAgent>().SetConnectEventCallback(HandleConnected, this);
mState = kStateStarted;
mUdpProxyPort = 0;
@@ -776,6 +812,7 @@ Error BorderAgent::SetEphemeralKey(const char *aKeyString, uint32_t aTimeout, ui
{
mUsingEphemeralKey = false;
IgnoreError(Start(mOldUdpPort));
mCounters.mEpskcStartSecureSessionErrors++;
ExitNow();
}
@@ -789,10 +826,23 @@ Error BorderAgent::SetEphemeralKey(const char *aKeyString, uint32_t aTimeout, ui
aTimeout = Min(aTimeout, kMaxEphemeralKeyTimeout);
mEphemeralKeyTimer.Start(aTimeout);
mCounters.mEpskcActivations++;
LogInfo("Allow ephemeral key for %lu msec on port %u", ToUlong(aTimeout), GetUdpPort());
exit:
switch (error)
{
case kErrorInvalidState:
mCounters.mEpskcInvalidBaStateErrors++;
break;
case kErrorInvalidArgs:
mCounters.mEpskcInvalidArgsErrors++;
break;
default:
break;
}
return error;
}
@@ -801,6 +851,16 @@ void BorderAgent::ClearEphemeralKey(void)
VerifyOrExit(mUsingEphemeralKey);
LogInfo("Clearing ephemeral key");
if (mEphemeralKeyTimer.IsRunning())
{
mCounters.mEpskcDeactivationClears++;
}
else
{
mCounters.mEpskcDeactivationTimeouts++;
}
mEphemeralKeyTimer.Stop();
switch (mState)
@@ -847,6 +907,7 @@ void BorderAgent::HandleSecureAgentStopped(void)
{
LogInfo("Reached max allowed connection attempts with ephemeral key");
RestartAfterRemovingEphemeralKey();
mCounters.mEpskcDeactivationMaxAttempts++;
}
#endif // OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
+11 -2
View File
@@ -238,6 +238,14 @@ public:
#endif // OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE
/**
* Gets the set of border agent counters.
*
* @returns The border agent counters.
*
*/
const otBorderAgentCounters *GetCounters(void) { return &mCounters; }
/**
* Returns the UDP Proxy port to which the commissioner is currently
* bound.
@@ -285,8 +293,8 @@ private:
void SendErrorMessage(const ForwardContext &aForwardContext, Error aError);
void SendErrorMessage(const Coap::Message &aRequest, bool aSeparate, Error aError);
static void HandleConnected(bool aConnected, void *aContext);
void HandleConnected(bool aConnected);
static void HandleConnected(SecureTransport::ConnectEvent aEvent, void *aContext);
void HandleConnected(SecureTransport::ConnectEvent aEvent);
template <Uri kUri> void HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
@@ -333,6 +341,7 @@ private:
EphemeralKeyTask mEphemeralKeyTask;
Callback<EphemeralKeyCallback> mEphemeralKeyCallback;
#endif
otBorderAgentCounters mCounters;
};
DeclareTmfHandler(BorderAgent, kUriRelayRx);
+7 -6
View File
@@ -127,19 +127,20 @@ exit:
return;
}
void Commissioner::HandleSecureAgentConnected(bool aConnected, void *aContext)
void Commissioner::HandleSecureAgentConnectEvent(SecureTransport::ConnectEvent aEvent, void *aContext)
{
static_cast<Commissioner *>(aContext)->HandleSecureAgentConnected(aConnected);
static_cast<Commissioner *>(aContext)->HandleSecureAgentConnectEvent(aEvent);
}
void Commissioner::HandleSecureAgentConnected(bool aConnected)
void Commissioner::HandleSecureAgentConnectEvent(SecureTransport::ConnectEvent aEvent)
{
if (!aConnected)
bool isConnected = (aEvent == SecureTransport::kConnected);
if (!isConnected)
{
mJoinerSessionTimer.Stop();
}
SignalJoinerEvent(aConnected ? kJoinerEventConnected : kJoinerEventEnd, mActiveJoiner);
SignalJoinerEvent(isConnected ? kJoinerEventConnected : kJoinerEventEnd, mActiveJoiner);
}
Commissioner::Joiner *Commissioner::GetUnusedJoinerEntry(void)
@@ -287,7 +288,7 @@ Error Commissioner::Start(StateCallback aStateCallback, JoinerCallback aJoinerCa
#endif
SuccessOrExit(error = Get<Tmf::SecureAgent>().Start(SendRelayTransmit, this));
Get<Tmf::SecureAgent>().SetConnectedCallback(&Commissioner::HandleSecureAgentConnected, this);
Get<Tmf::SecureAgent>().SetConnectEventCallback(&Commissioner::HandleSecureAgentConnectEvent, this);
mStateCallback.Set(aStateCallback, aCallbackContext);
mJoinerCallback.Set(aJoinerCallback, aCallbackContext);
+2 -2
View File
@@ -440,8 +440,8 @@ private:
Error aResult);
void HandleLeaderKeepAliveResponse(Coap::Message *aMessage, const Ip6::MessageInfo *aMessageInfo, Error aResult);
static void HandleSecureAgentConnected(bool aConnected, void *aContext);
void HandleSecureAgentConnected(bool aConnected);
static void HandleSecureAgentConnectEvent(SecureTransport::ConnectEvent aEvent, void *aContext);
void HandleSecureAgentConnectEvent(SecureTransport::ConnectEvent aEvent);
template <Uri kUri> void HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
+4 -4
View File
@@ -382,16 +382,16 @@ exit:
return error;
}
void Joiner::HandleSecureCoapClientConnect(bool aConnected, void *aContext)
void Joiner::HandleSecureCoapClientConnect(SecureTransport::ConnectEvent aEvent, void *aContext)
{
static_cast<Joiner *>(aContext)->HandleSecureCoapClientConnect(aConnected);
static_cast<Joiner *>(aContext)->HandleSecureCoapClientConnect(aEvent);
}
void Joiner::HandleSecureCoapClientConnect(bool aConnected)
void Joiner::HandleSecureCoapClientConnect(SecureTransport::ConnectEvent aEvent)
{
VerifyOrExit(mState == kStateConnect);
if (aConnected)
if (aEvent == SecureTransport::kConnected)
{
SetState(kStateConnected);
SendJoinerFinalize();
+2 -2
View File
@@ -199,8 +199,8 @@ private:
static void HandleDiscoverResult(Mle::DiscoverScanner::ScanResult *aResult, void *aContext);
void HandleDiscoverResult(Mle::DiscoverScanner::ScanResult *aResult);
static void HandleSecureCoapClientConnect(bool aConnected, void *aContext);
void HandleSecureCoapClientConnect(bool aConnected);
static void HandleSecureCoapClientConnect(SecureTransport::ConnectEvent aEvent, void *aContext);
void HandleSecureCoapClientConnect(SecureTransport::ConnectEvent aEvent);
static void HandleJoinerFinalizeResponse(void *aContext,
otMessage *aMessage,
+8 -3
View File
@@ -1043,15 +1043,15 @@ void SecureTransport::HandleTimer(void)
if ((mMaxConnectionAttempts > 0) && (mRemainingConnectionAttempts == 0))
{
Close();
mConnectedCallback.InvokeIfSet(false);
mConnectEvent = kDisconnectedMaxAttempts;
mAutoCloseCallback.InvokeIfSet();
}
else
{
SetState(kStateOpen);
mTimer.Stop();
mConnectedCallback.InvokeIfSet(false);
}
mConnectedCallback.InvokeIfSet(mConnectEvent);
}
}
@@ -1070,7 +1070,8 @@ void SecureTransport::Process(void)
if (mSsl.MBEDTLS_PRIVATE(state) == MBEDTLS_SSL_HANDSHAKE_OVER)
{
SetState(kStateConnected);
mConnectedCallback.InvokeIfSet(true);
mConnectEvent = kConnected;
mConnectedCallback.InvokeIfSet(mConnectEvent);
}
}
else
@@ -1092,6 +1093,7 @@ void SecureTransport::Process(void)
{
case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
mbedtls_ssl_close_notify(&mSsl);
mConnectEvent = kDisconnectedPeerClosed;
ExitNow(shouldDisconnect = true);
OT_UNREACHABLE_CODE(break);
@@ -1100,6 +1102,7 @@ void SecureTransport::Process(void)
case MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE:
mbedtls_ssl_close_notify(&mSsl);
mConnectEvent = kDisconnectedError;
ExitNow(shouldDisconnect = true);
OT_UNREACHABLE_CODE(break);
@@ -1108,6 +1111,7 @@ void SecureTransport::Process(void)
{
mbedtls_ssl_send_alert_message(&mSsl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_BAD_RECORD_MAC);
mConnectEvent = kDisconnectedError;
ExitNow(shouldDisconnect = true);
}
@@ -1118,6 +1122,7 @@ void SecureTransport::Process(void)
{
mbedtls_ssl_send_alert_message(&mSsl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE);
mConnectEvent = kDisconnectedError;
ExitNow(shouldDisconnect = true);
}
+18 -9
View File
@@ -69,6 +69,8 @@
#endif
#endif
#include <openthread/coap_secure.h>
#include "common/callback.hpp"
#include "common/locator.hpp"
#include "common/log.hpp"
@@ -87,8 +89,22 @@ namespace MeshCoP {
class SecureTransport : public InstanceLocator
{
public:
typedef otCoapSecureConnectEvent ConnectEvent; ///< A connect event.
static constexpr ConnectEvent kConnected = OT_COAP_SECURE_CONNECTED;
static constexpr ConnectEvent kDisconnectedPeerClosed = OT_COAP_SECURE_DISCONNECTED_PEER_CLOSED;
static constexpr ConnectEvent kDisconnectedLocalClosed = OT_COAP_SECURE_DISCONNECTED_LOCAL_CLOSED;
static constexpr ConnectEvent kDisconnectedMaxAttempts = OT_COAP_SECURE_DISCONNECTED_MAX_ATTEMPTS;
static constexpr ConnectEvent kDisconnectedError = OT_COAP_SECURE_DISCONNECTED_ERROR;
static constexpr uint8_t kPskMaxLength = 32; ///< Maximum PSK length.
/**
* Function pointer which is called reporting a connection event (when connection established or disconnected)
*
*/
typedef otHandleCoapSecureClientConnect ConnectedHandler;
/**
* Initializes the SecureTransport object.
*
@@ -99,15 +115,6 @@ public:
*/
explicit SecureTransport(Instance &aInstance, bool aLayerTwoSecurity, bool aDatagramTransport = true);
/**
* Pointer is called when a connection is established or torn down.
*
* @param[in] aContext A pointer to application-specific context.
* @param[in] aConnected TRUE if a connection was established, FALSE otherwise.
*
*/
typedef void (*ConnectedHandler)(void *aContext, bool aConnected);
/**
* Pointer is called when data is received from the session.
*
@@ -670,6 +677,8 @@ private:
Message::SubType mMessageSubType;
Message::SubType mMessageDefaultSubType;
ConnectEvent mConnectEvent;
};
} // namespace MeshCoP
+6 -6
View File
@@ -83,7 +83,7 @@ Error BleSecure::Start(ConnectCallback aConnectHandler, ReceiveCallback aReceive
SuccessOrExit(error = otPlatBleGapAdvSetData(&GetInstance(), advertisementData, advertisementLen));
SuccessOrExit(error = otPlatBleGapAdvStart(&GetInstance(), OT_BLE_ADV_INTERVAL_DEFAULT));
SuccessOrExit(error = mTls.Open(&BleSecure::HandleTlsReceive, &BleSecure::HandleTlsConnected, this));
SuccessOrExit(error = mTls.Open(&BleSecure::HandleTlsReceive, &BleSecure::HandleTlsConnectEvent, this));
SuccessOrExit(error = mTls.Bind(HandleTransport, this));
exit:
@@ -321,14 +321,14 @@ Error BleSecure::HandleBleMtuUpdate(uint16_t aMtu)
return error;
}
void BleSecure::HandleTlsConnected(void *aContext, bool aConnected)
void BleSecure::HandleTlsConnectEvent(MeshCoP::SecureTransport::ConnectEvent aEvent, void *aContext)
{
return static_cast<BleSecure *>(aContext)->HandleTlsConnected(aConnected);
return static_cast<BleSecure *>(aContext)->HandleTlsConnectEvent(aEvent);
}
void BleSecure::HandleTlsConnected(bool aConnected)
void BleSecure::HandleTlsConnectEvent(MeshCoP::SecureTransport::ConnectEvent aEvent)
{
if (aConnected)
if (aEvent == MeshCoP::SecureTransport::kConnected)
{
if (mReceivedMessage == nullptr)
{
@@ -358,7 +358,7 @@ void BleSecure::HandleTlsConnected(bool aConnected)
}
}
mConnectCallback.InvokeIfSet(&GetInstance(), aConnected, true);
mConnectCallback.InvokeIfSet(&GetInstance(), aEvent == MeshCoP::SecureTransport::kConnected, true);
exit:
return;
+2 -2
View File
@@ -464,8 +464,8 @@ private:
static constexpr uint8_t kPacketBufferSize = OT_BLE_ATT_MTU_MAX - kGattOverhead;
static constexpr uint16_t kTxBleHandle = 0; // Characteristics Handle for TX (not used)
static void HandleTlsConnected(void *aContext, bool aConnected);
void HandleTlsConnected(bool aConnected);
static void HandleTlsConnectEvent(MeshCoP::SecureTransport::ConnectEvent aEvent, void *aContext);
void HandleTlsConnectEvent(MeshCoP::SecureTransport::ConnectEvent aEvent);
static void HandleTlsReceive(void *aContext, uint8_t *aBuf, uint16_t aLength);
void HandleTlsReceive(uint8_t *aBuf, uint16_t aLength);
@@ -0,0 +1,123 @@
#!/usr/bin/env python3
#
# Copyright (c) 2024, 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.
#
import logging
import unittest
import config
import thread_cert
# Test description:
# This test verifies the counters of ephemeral key activations/deactivations.
#
# Topology:
# --------------
# |
# BR1
#
BR1 = 1
class EphemeralKeyCountersTest(thread_cert.TestCase):
USE_MESSAGE_FACTORY = False
TOPOLOGY = {
BR1: {
'name': 'BR_1',
'is_otbr': True,
'version': '1.4',
'network_name': 'ot-br1',
},
}
def test(self):
br1 = self.nodes[BR1]
counters = br1.get_border_agent_counters()
self.assertEqual(counters['epskcActivation'], 0)
self.assertEqual(counters['epskcApiDeactivation'], 0)
self.assertEqual(counters['epskcTimeoutDeactivation'], 0)
self.assertEqual(counters['epskcMaxAttemptDeactivation'], 0)
self.assertEqual(counters['epskcDisconnectDeactivation'], 0)
self.assertEqual(counters['epskcInvalidBaStateError'], 0)
self.assertEqual(counters['epskcInvalidArgsError'], 0)
self.assertEqual(counters['epskcStartSecureSessionError'], 0)
self.assertEqual(counters['epskcSecureSessionSuccess'], 0)
self.assertEqual(counters['epskcSecureSessionFailure'], 0)
self.assertEqual(counters['epskcCommissionerPetition'], 0)
self.assertEqual(counters['pskcSecureSessionSuccess'], 0)
self.assertEqual(counters['pskcSecureSessionFailure'], 0)
self.assertEqual(counters['pskcCommissionerPetition'], 0)
self.assertEqual(counters['mgmtActiveGet'], 0)
self.assertEqual(counters['mgmtPendingGet'], 0)
# activate epskc before border agent is up returns an error
br1.set_epskc('123456789')
counters = br1.get_border_agent_counters()
self.assertEqual(counters['epskcActivation'], 0)
self.assertEqual(counters['epskcInvalidBaStateError'], 1)
br1.set_active_dataset(updateExisting=True, network_name='ot-br1')
br1.start()
self.simulator.go(config.BORDER_ROUTER_STARTUP_DELAY)
self.assertEqual('leader', br1.get_state())
# activate epskc and let it timeout
br1.set_epskc('123456789', 10)
self.simulator.go(1)
counters = br1.get_border_agent_counters()
self.assertEqual(counters['epskcActivation'], 1)
self.assertEqual(counters['epskcApiDeactivation'], 0)
self.assertEqual(counters['epskcTimeoutDeactivation'], 1)
# activate epskc and clear it
br1.set_epskc('123456789', 10000)
self.simulator.go(1)
br1.clear_epskc()
counters = br1.get_border_agent_counters()
self.assertEqual(counters['epskcActivation'], 2)
self.assertEqual(counters['epskcApiDeactivation'], 1)
self.assertEqual(counters['epskcTimeoutDeactivation'], 1)
# set epskc with invalid passcode
br1.set_epskc('123')
self.simulator.go(1)
counters = br1.get_border_agent_counters()
self.assertEqual(counters['epskcActivation'], 2)
self.assertEqual(counters['epskcApiDeactivation'], 1)
self.assertEqual(counters['epskcTimeoutDeactivation'], 1)
self.assertEqual(counters['epskcInvalidArgsError'], 1)
if __name__ == '__main__':
unittest.main()
+25
View File
@@ -1451,6 +1451,31 @@ class NodeImpl:
self.send_command(cmd)
self._expect_done()
def set_epskc(self, keystring: str, timeout=120000, port=0):
cmd = 'ba ephemeralkey set ' + keystring + ' ' + str(timeout) + ' ' + str(port)
self.send_command(cmd)
self._expect(r"(Done|Error .*)")
def clear_epskc(self):
cmd = 'ba ephemeralkey clear'
self.send_command(cmd)
self._expect_done()
def get_border_agent_counters(self):
cmd = 'ba counters'
self.send_command(cmd)
result = self._expect_command_output()
counters = {}
for line in result:
m = re.match(r'(\w+)\: (\d+)', line)
if m:
counter_name = m.group(1)
counter_value = m.group(2)
counters[counter_name] = int(counter_value)
return counters
def _encode_txt_entry(self, entry):
"""Encodes the TXT entry to the DNS-SD TXT record format as a HEX string.