diff --git a/src/core/config/border_agent.h b/src/core/config/border_agent.h index 2341a2c05..1294657e2 100644 --- a/src/core/config/border_agent.h +++ b/src/core/config/border_agent.h @@ -76,7 +76,8 @@ * Define to 1 to enable ephemeral key mechanism and its APIs in Border Agent. */ #ifndef OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE -#define OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_4) +#define OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE \ + (OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE && (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_4)) #endif /** diff --git a/src/lib/spinel/spinel.c b/src/lib/spinel/spinel.c index 8c4f5f4e2..0b1af9cc7 100644 --- a/src/lib/spinel/spinel.c +++ b/src/lib/spinel/spinel.c @@ -1420,6 +1420,10 @@ const char *spinel_prop_key_to_cstr(spinel_prop_key_t prop_key) {SPINEL_PROP_DNSSD_SERVICE, "DNSSD_SERVICE"}, {SPINEL_PROP_DNSSD_KEY_RECORD, "DNSSD_KEY_RECORD"}, {SPINEL_PROP_BORDER_AGENT_MESHCOP_SERVICE_STATE, "BORDER_AGENT_MESHCOP_SERVICE_STATE"}, + {SPINEL_PROP_BORDER_AGENT_EPHEMERAL_KEY_STATE, "SPINEL_PROP_BORDER_AGENT_EPHEMERAL_KEY_STATE"}, + {SPINEL_PROP_BORDER_AGENT_EPHEMERAL_KEY_ENABLE, "SPINEL_PROP_BORDER_AGENT_EPHEMERAL_KEY_ENABLE"}, + {SPINEL_PROP_BORDER_AGENT_EPHEMERAL_KEY_ACTIVATE, "SPINEL_PROP_BORDER_AGENT_EPHEMERAL_KEY_ACTIVATE"}, + {SPINEL_PROP_BORDER_AGENT_EPHEMERAL_KEY_DEACTIVATE, "SPINEL_PROP_BORDER_AGENT_EPHEMERAL_KEY_DEACTIVATE"}, {SPINEL_PROP_BACKBONE_ROUTER_STATE, "BACKBONE_ROUTER_STATE"}, {SPINEL_PROP_BACKBONE_ROUTER_ENABLE, "BACKBONE_ROUTER_ENABLE"}, {SPINEL_PROP_BACKBONE_ROUTER_MULTICAST_LISTENER, "BACKBONE_ROUTER_MULTICAST_LISTENER"}, diff --git a/src/lib/spinel/spinel.h b/src/lib/spinel/spinel.h index c2fc71432..72e06bbdc 100644 --- a/src/lib/spinel/spinel.h +++ b/src/lib/spinel/spinel.h @@ -4911,6 +4911,43 @@ enum */ SPINEL_PROP_BORDER_AGENT_MESHCOP_SERVICE_STATE = SPINEL_PROP_BORDER_AGENT__BEGIN + 1, + /// Border Agent Ephemeral Key State. + /** + * Format: `C` - Get and Unsolicited notifications. + * + * `C`: The Ephemeral Key state. The value corresponds to `otBorderAgentEphemeralKeyState`. + */ + SPINEL_PROP_BORDER_AGENT_EPHEMERAL_KEY_STATE = SPINEL_PROP_BORDER_AGENT__BEGIN + 2, + + /// Enablement/Disablement of the Ephemeral Key feature. + /** + * Format: `b` - Write-Only + * + * `b`: true to enable the Ephemeral Key feature and false to disable the feature. + * + * Note that enabling the Ephemeral Key feature doesn't mean activating Ephemeral Key mode. If the feature + * is enabled, the corresponding bit in state bitmap in the meshcop service will be set. + */ + SPINEL_PROP_BORDER_AGENT_EPHEMERAL_KEY_ENABLE = SPINEL_PROP_BORDER_AGENT__BEGIN + 3, + + /// Activation of the Ephemeral Key mode. + /** + * Format: `ULS` - Write-Only + * + * `U`: The ephemeral key to use. + * `L`: The timeout duration, in milliseconds, to use the ephemeral key. + * `S`: The UDP port for the MeshCop-e service. An ephemeral port will be used if this is 0. + */ + SPINEL_PROP_BORDER_AGENT_EPHEMERAL_KEY_ACTIVATE = SPINEL_PROP_BORDER_AGENT__BEGIN + 4, + + /// Deactivation of the Ephemeral Key mode. + /** + * Format: `b` - Write-Only + * + * `b`: true to retain the current session if existed. false to force the disconnection for existing session. + */ + SPINEL_PROP_BORDER_AGENT_EPHEMERAL_KEY_DEACTIVATE = SPINEL_PROP_BORDER_AGENT__BEGIN + 5, + SPINEL_PROP_BORDER_AGENT__END = 0x970, SPINEL_PROP_BACKBONE_ROUTER__BEGIN = 0x970, diff --git a/src/ncp/changed_props_set.cpp b/src/ncp/changed_props_set.cpp index 124d7d35f..3bd30e970 100644 --- a/src/ncp/changed_props_set.cpp +++ b/src/ncp/changed_props_set.cpp @@ -93,8 +93,13 @@ const ChangedPropsSet::Entry ChangedPropsSet::mSupportedProps[] = { #endif {SPINEL_PROP_PARENT_RESPONSE_INFO, SPINEL_STATUS_OK, true}, {SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS, SPINEL_STATUS_OK, false}, -#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE +#if OPENTHREAD_FTD +#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE {SPINEL_PROP_BORDER_AGENT_MESHCOP_SERVICE_STATE, SPINEL_STATUS_OK, false}, +#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE + {SPINEL_PROP_BORDER_AGENT_EPHEMERAL_KEY_STATE, SPINEL_STATUS_OK, false}, +#endif +#endif #endif {SPINEL_PROP_BACKBONE_ROUTER_STATE, SPINEL_STATUS_OK, false}, }; diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index 9fda9aaa5..798b057d0 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -375,6 +375,9 @@ NcpBase::NcpBase(Instance *aInstance) #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE otBorderAgentSetMeshCoPServiceChangedCallback(mInstance, HandleBorderAgentMeshCoPServiceChanged, this); #endif +#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE + otBorderAgentEphemeralKeySetCallback(mInstance, HandleBorderAgentEphemeralKeyStateChanged, this); +#endif #endif // OPENTHREAD_FTD #if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE otSrpClientSetCallback(mInstance, HandleSrpClientCallback, this); diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp index 0a9158a36..f6eae6387 100644 --- a/src/ncp/ncp_base.hpp +++ b/src/ncp/ncp_base.hpp @@ -886,6 +886,11 @@ protected: const otIp6Address *aAddress); #endif +#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE && OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE + static void HandleBorderAgentEphemeralKeyStateChanged(void *aContext); + void HandleBorderAgentEphemeralKeyStateChanged(void); +#endif + #endif // OPENTHREAD_FTD #if OPENTHREAD_CONFIG_DIAG_ENABLE diff --git a/src/ncp/ncp_base_dispatcher.cpp b/src/ncp/ncp_base_dispatcher.cpp index 64fe0dacd..d653a15eb 100644 --- a/src/ncp/ncp_base_dispatcher.cpp +++ b/src/ncp/ncp_base_dispatcher.cpp @@ -226,6 +226,9 @@ NcpBase::PropertyHandler NcpBase::FindGetPropertyHandler(spinel_prop_key_t aKey) #endif #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_BORDER_AGENT_MESHCOP_SERVICE_STATE), +#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE + OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_BORDER_AGENT_EPHEMERAL_KEY_STATE), +#endif #endif #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_BACKBONE_ROUTER_STATE), @@ -543,6 +546,11 @@ NcpBase::PropertyHandler NcpBase::FindSetPropertyHandler(spinel_prop_key_t aKey) OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_DNSSD_STATE), OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_DNSSD_REQUEST_RESULT), #endif +#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE && OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE + OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_BORDER_AGENT_EPHEMERAL_KEY_ENABLE), + OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_BORDER_AGENT_EPHEMERAL_KEY_ACTIVATE), + OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_BORDER_AGENT_EPHEMERAL_KEY_DEACTIVATE), +#endif #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_BACKBONE_ROUTER_ENABLE), #endif diff --git a/src/ncp/ncp_base_ftd.cpp b/src/ncp/ncp_base_ftd.cpp index 9996ebdfb..84298a181 100644 --- a/src/ncp/ncp_base_ftd.cpp +++ b/src/ncp/ncp_base_ftd.cpp @@ -36,6 +36,9 @@ #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE #include #endif +#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE +#include +#endif #if OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE #include #endif @@ -205,6 +208,19 @@ void NcpBase::HandleBorderAgentMeshCoPServiceChanged(void) #endif // OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE +#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE +void NcpBase::HandleBorderAgentEphemeralKeyStateChanged(void *aContext) +{ + static_cast(aContext)->HandleBorderAgentEphemeralKeyStateChanged(); +} + +void NcpBase::HandleBorderAgentEphemeralKeyStateChanged(void) +{ + mChangedPropsSet.AddProperty(SPINEL_PROP_BORDER_AGENT_EPHEMERAL_KEY_STATE); + mUpdateChangedPropsTask.Post(); +} +#endif + // ---------------------------------------------------------------------------- // MARK: Individual Property Handlers // ---------------------------------------------------------------------------- @@ -416,6 +432,70 @@ exit: } #endif // OPENTHREAD_CONFIG_DUA_ENABLE +#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE + +template <> otError NcpBase::HandlePropertySet(void) +{ + bool enabled; + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = mDecoder.ReadBool(enabled)); + otBorderAgentEphemeralKeySetEnabled(mInstance, enabled); + +exit: + return error; +} + +template <> otError NcpBase::HandlePropertySet(void) +{ + otError error = OT_ERROR_NONE; + const char *epskc; + uint32_t durationMilli; + uint16_t port; + + SuccessOrExit(error = mDecoder.ReadUtf8(epskc)); + SuccessOrExit(error = mDecoder.ReadUint32(durationMilli)); + SuccessOrExit(error = mDecoder.ReadUint16(port)); + + VerifyOrExit(otBorderAgentEphemeralKeyGetState(mInstance) != OT_BORDER_AGENT_STATE_DISABLED, + error = OT_ERROR_NOT_CAPABLE); + error = otBorderAgentEphemeralKeyStart(mInstance, epskc, durationMilli, port); + +exit: + return error; +} + +template <> otError NcpBase::HandlePropertySet(void) +{ + otError error = OT_ERROR_NONE; + + bool retainActiveSession; + + SuccessOrExit(error = mDecoder.ReadBool(retainActiveSession)); + + switch (otBorderAgentEphemeralKeyGetState(mInstance)) + { + case OT_BORDER_AGENT_STATE_STARTED: + break; + case OT_BORDER_AGENT_STATE_CONNECTED: + case OT_BORDER_AGENT_STATE_ACCEPTED: + VerifyOrExit(!retainActiveSession); + break; + case OT_BORDER_AGENT_STATE_DISABLED: + error = OT_ERROR_NOT_CAPABLE; + // Fall through + case OT_BORDER_AGENT_STATE_STOPPED: + ExitNow(); + } + + otBorderAgentEphemeralKeyStop(mInstance); + +exit: + return error; +} + +#endif // OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE + #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE template <> otError NcpBase::HandlePropertyGet(void) { @@ -1664,6 +1744,15 @@ exit: return error; } +#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE + +template <> otError NcpBase::HandlePropertyGet(void) +{ + return mEncoder.WriteUint8(static_cast(otBorderAgentEphemeralKeyGetState(mInstance))); +} + +#endif + #endif // OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 3f1996c53..3dfa921ec 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -270,6 +270,7 @@ ot_unit_ncp_test(cli) ot_unit_ncp_test(dnssd) ot_unit_ncp_test(infra_if) ot_unit_ncp_test(srp_server) +ot_unit_ncp_test(ephemeral_key) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/unit/test_ncp_ephemeral_key.cpp b/tests/unit/test_ncp_ephemeral_key.cpp new file mode 100644 index 000000000..13f2a6aad --- /dev/null +++ b/tests/unit/test_ncp_ephemeral_key.cpp @@ -0,0 +1,181 @@ +/* + * 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. + */ + +#include + +#include + +#include "test_platform.h" +#include "test_util.h" +#include "common/code_utils.hpp" +#include "lib/spinel/spinel_buffer.hpp" +#include "lib/spinel/spinel_encoder.hpp" +#include "ncp/ncp_base.hpp" + +#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE + +namespace ot { + +constexpr uint16_t kMaxSpinelBufferSize = 2048; + +static otError GenerateEphemeralKeySetEnabledFrame(bool aEnable, uint8_t *aBuf, uint16_t &aLen) +{ + otError error = OT_ERROR_NONE; + uint8_t buf[kMaxSpinelBufferSize]; + Spinel::Buffer ncpBuffer(buf, kMaxSpinelBufferSize); + Spinel::Encoder encoder(ncpBuffer); + + uint8_t header = SPINEL_HEADER_FLAG | 0 /* Iid */ | 1 /* Tid */; + SuccessOrExit( + error = encoder.BeginFrame(header, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_BORDER_AGENT_EPHEMERAL_KEY_ENABLE)); + SuccessOrExit(error = encoder.WriteBool(aEnable)); + SuccessOrExit(error = encoder.EndFrame()); + + SuccessOrExit(ncpBuffer.OutFrameBegin()); + aLen = ncpBuffer.OutFrameGetLength(); + VerifyOrExit(ncpBuffer.OutFrameRead(aLen, aBuf) == aLen, error = OT_ERROR_FAILED); + +exit: + return error; +} + +static otError GenerateEphemeralKeyStartFrame(const char *aEpskc, + uint32_t aTimeout, + uint16_t aPort, + uint8_t *aBuf, + uint16_t &aLen) +{ + otError error = OT_ERROR_NONE; + uint8_t buf[kMaxSpinelBufferSize]; + Spinel::Buffer ncpBuffer(buf, kMaxSpinelBufferSize); + Spinel::Encoder encoder(ncpBuffer); + + uint8_t header = SPINEL_HEADER_FLAG | 0 /* Iid */ | 1 /* Tid */; + SuccessOrExit( + error = encoder.BeginFrame(header, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_BORDER_AGENT_EPHEMERAL_KEY_ACTIVATE)); + SuccessOrExit(error = encoder.WriteUtf8(aEpskc)); + SuccessOrExit(error = encoder.WriteUint32(aTimeout)); + SuccessOrExit(error = encoder.WriteUint16(aPort)); + SuccessOrExit(error = encoder.EndFrame()); + + SuccessOrExit(ncpBuffer.OutFrameBegin()); + aLen = ncpBuffer.OutFrameGetLength(); + VerifyOrExit(ncpBuffer.OutFrameRead(aLen, aBuf) == aLen, error = OT_ERROR_FAILED); + +exit: + return error; +} + +static otError GenerateEphemeralKeyStopFrame(uint8_t *aBuf, uint16_t &aLen) +{ + otError error = OT_ERROR_NONE; + uint8_t buf[kMaxSpinelBufferSize]; + Spinel::Buffer ncpBuffer(buf, kMaxSpinelBufferSize); + Spinel::Encoder encoder(ncpBuffer); + + uint8_t header = SPINEL_HEADER_FLAG | 0 /* Iid */ | 1 /* Tid */; + SuccessOrExit(error = encoder.BeginFrame(header, SPINEL_CMD_PROP_VALUE_SET, + SPINEL_PROP_BORDER_AGENT_EPHEMERAL_KEY_DEACTIVATE)); + SuccessOrExit(error = encoder.WriteBool(false)); // Not retain active session. Doesn't matter here. + SuccessOrExit(error = encoder.EndFrame()); + + SuccessOrExit(ncpBuffer.OutFrameBegin()); + aLen = ncpBuffer.OutFrameGetLength(); + VerifyOrExit(ncpBuffer.OutFrameRead(aLen, aBuf) == aLen, error = OT_ERROR_FAILED); + +exit: + return error; +} + +void TestEphemeralKeySetEnabled(void) +{ + Instance *instance = static_cast(testInitInstance()); + Ncp::NcpBase ncpBase(instance); + + uint8_t recvBuf[kMaxSpinelBufferSize]; + uint16_t recvLen; + + // Set Ephemeral Key feature to enabled. + SuccessOrQuit(GenerateEphemeralKeySetEnabledFrame(true, recvBuf, recvLen)); + ncpBase.HandleReceive(recvBuf, recvLen); + + // The state should be 'Stopped' after enabling it. + VerifyOrQuit(otBorderAgentEphemeralKeyGetState(instance) == OT_BORDER_AGENT_STATE_STOPPED); + + // Set Ephemeral Key feature to disabled. + SuccessOrQuit(GenerateEphemeralKeySetEnabledFrame(false, recvBuf, recvLen)); + ncpBase.HandleReceive(recvBuf, recvLen); + + // The state should be 'Disabled' after disabling it. + VerifyOrQuit(otBorderAgentEphemeralKeyGetState(instance) == OT_BORDER_AGENT_STATE_DISABLED); + + // Set Ephemeral Key feature to enabled again. + SuccessOrQuit(GenerateEphemeralKeySetEnabledFrame(true, recvBuf, recvLen)); + ncpBase.HandleReceive(recvBuf, recvLen); + + // The state should be 'Stopped' after enabling it. + VerifyOrQuit(otBorderAgentEphemeralKeyGetState(instance) == OT_BORDER_AGENT_STATE_STOPPED); +} + +void TestEphemeralKeyStartAndStop(void) +{ + Instance *instance = static_cast(testInitInstance()); + Ncp::NcpBase ncpBase(instance); + + uint8_t recvBuf[kMaxSpinelBufferSize]; + uint16_t recvLen; + + // Set Ephemeral Key feature to enabled. + SuccessOrQuit(GenerateEphemeralKeySetEnabledFrame(true, recvBuf, recvLen)); + ncpBase.HandleReceive(recvBuf, recvLen); + VerifyOrQuit(otBorderAgentEphemeralKeyGetState(instance) == OT_BORDER_AGENT_STATE_STOPPED); + + // Activate the Ephemeral Key mode. + SuccessOrQuit(GenerateEphemeralKeyStartFrame("123456789", 300000, 12345, recvBuf, recvLen)); + ncpBase.HandleReceive(recvBuf, recvLen); + VerifyOrQuit(otBorderAgentEphemeralKeyGetState(instance) == OT_BORDER_AGENT_STATE_STARTED); + + // Deactivate the Ephemeral Key mode. + SuccessOrQuit(GenerateEphemeralKeyStopFrame(recvBuf, recvLen)); + ncpBase.HandleReceive(recvBuf, recvLen); + VerifyOrQuit(otBorderAgentEphemeralKeyGetState(instance) == OT_BORDER_AGENT_STATE_STOPPED); +} + +} // namespace ot + +#endif // OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE + +int main(void) +{ +#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE + ot::TestEphemeralKeySetEnabled(); + ot::TestEphemeralKeyStartAndStop(); +#endif + printf("All tests passed\n"); + return 0; +}