diff --git a/include/openthread/border_agent.h b/include/openthread/border_agent.h index 6411142cd..94287b5cb 100644 --- a/include/openthread/border_agent.h +++ b/include/openthread/border_agent.h @@ -180,11 +180,37 @@ otError otBorderAgentGetId(otInstance *aInstance, otBorderAgentId *aId); */ otError otBorderAgentSetId(otInstance *aInstance, const otBorderAgentId *aId); +/** + * Indicates whether the Border Agent Ephemeral Key feature is enabled. + * + * The Ephemeral Key feature can only be used when it's enabled. This information will be displayed in a bitmap in the + * txt records of the meshcop service published by this Border Router. + * + * The default value is `OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_FEATURE_ENABLED_BY_DEFAULT`. + * + * @param[in] aInstance The OpenThread instance. + */ +bool otBorderAgentIsEphemeralKeyFeatureEnabled(otInstance *aInstance); + +/** + * Enables/disables the Border Agent Ephemeral Key feature. + * + * If an ephemeral key is already active and then this method is called to disable the feature, the in-use ephemeral + * key will be cleared. + * + * @param[in] aInstance The OpenThread instance. + * @param[in] aEnabled Whether to enable the BA Ephemeral Key feature. + */ +void otBorderAgentSetEphemeralKeyFeatureEnabled(otInstance *aInstance, bool aEnabled); + /** * Sets the ephemeral key for a given timeout duration. * * Requires `OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE`. * + * The API SHOULD only be called when the Ephemeral Key feature is enabled (which can be set by + * `otBorderAgentSetEphemeralKeyFeatureEnabled`) or configured as enabled by default. + * * The ephemeral key can be set when the Border Agent is already running and is not currently connected to any external * commissioner (i.e., it is in `OT_BORDER_AGENT_STATE_STARTED` state). Otherwise `OT_ERROR_INVALID_STATE` is returned. * To terminate active commissioner sessions, use the `otBorderAgentDisconnect()` API. @@ -213,8 +239,8 @@ otError otBorderAgentSetId(otInstance *aInstance, const otBorderAgentId *aId); * @retval OT_ERROR_NONE Successfully set the ephemeral key. * @retval OT_ERROR_INVALID_STATE Border Agent is not running or it is connected to an external commissioner. * @retval OT_ERROR_INVALID_ARGS The given @p aKeyString is not valid (too short or too long). + * @retval OT_ERROR_NOT_CAPABLE The Ephemeral Key feature is not enabled. * @retval OT_ERROR_FAILED Failed to set the key (e.g., could not bind to UDP port). - */ otError otBorderAgentSetEphemeralKey(otInstance *aInstance, const char *aKeyString, diff --git a/include/openthread/instance.h b/include/openthread/instance.h index e90dbd17d..ed1a4ec8c 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -52,7 +52,7 @@ extern "C" { * * @note This number versions both OpenThread platform and user APIs. */ -#define OPENTHREAD_API_VERSION (470) +#define OPENTHREAD_API_VERSION (471) /** * @addtogroup api-instance diff --git a/src/cli/README.md b/src/cli/README.md index a463e2b05..9eaa4974f 100644 --- a/src/cli/README.md +++ b/src/cli/README.md @@ -478,6 +478,34 @@ Disables callback from Border Agent for ephemeral key state changes. Done ``` +### ba ephemeralkey feature + +Displays if the Ephemeral Key feature is enabled. Note that this indicates whether the ephemeral key feature is ready to use, instead of whether an ephemeral key is active. + +```bash +> ba ephemeralkey feature +Enabled +Done +``` + +### ba ephemeralkey feature enable + +Enables the Ephemeral Key feature. + +```bash +> ba ephemeralkey feature enable +Done +``` + +### ba ephemeralkey feature disable + +Disables the Ephemeral Key feature. + +```bash +> ba ephemeralkey feature disable +Done +``` + ### ba counters Get the border agent counter values. diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 72beeb13e..e410ba549 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -623,6 +623,27 @@ template <> otError Interpreter::Process(Arg aArgs[]) otBorderAgentSetEphemeralKeyCallback(GetInstancePtr(), nullptr, nullptr); } } + /** + * @cli ba ephemeralkey feature (enable, disable) + * @code + * ba ephemeralkey feature + * Enabled + * Done + * @endcode + * @code + * ba ephemeralkey feature enable + * Done + * @endcode + * @cparam ba ephemeralkey feature [@ca{enable|disable}] + * @par api_copy + * #otBorderAgentIsEphemeralKeyFeatureEnabled + * #otBorderAgentSetEphemeralKeyFeatureEnabled + */ + else if (aArgs[1] == "feature") + { + error = ProcessEnableDisable(aArgs + 2, otBorderAgentIsEphemeralKeyFeatureEnabled, + otBorderAgentSetEphemeralKeyFeatureEnabled); + } else { error = OT_ERROR_INVALID_ARGS; diff --git a/src/core/api/border_agent_api.cpp b/src/core/api/border_agent_api.cpp index 908f1ab8a..3f0c1e6f2 100644 --- a/src/core/api/border_agent_api.cpp +++ b/src/core/api/border_agent_api.cpp @@ -81,6 +81,16 @@ uint16_t otBorderAgentGetUdpPort(otInstance *aInstance) #if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE +bool otBorderAgentIsEphemeralKeyFeatureEnabled(otInstance *aInstance) +{ + return AsCoreType(aInstance).Get().IsEphemeralKeyFeatureEnabled(); +} + +void otBorderAgentSetEphemeralKeyFeatureEnabled(otInstance *aInstance, bool aEnabled) +{ + AsCoreType(aInstance).Get().SetEphemeralKeyFeatureEnabled(aEnabled); +} + otError otBorderAgentSetEphemeralKey(otInstance *aInstance, const char *aKeyString, uint32_t aTimeout, diff --git a/src/core/config/border_agent.h b/src/core/config/border_agent.h index 0a653ecb6..19cb458e0 100644 --- a/src/core/config/border_agent.h +++ b/src/core/config/border_agent.h @@ -79,6 +79,16 @@ #define OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_4) #endif +/** + * @def OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_FEATURE_ENABLED_BY_DEFAULT + * + * Whether or not the ephemeral key feature is enabled by default at run-time. + */ +#ifndef OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_FEATURE_ENABLED_BY_DEFAULT +#define OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_FEATURE_ENABLED_BY_DEFAULT \ + (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_4) +#endif + /** * @} */ diff --git a/src/core/meshcop/border_agent.cpp b/src/core/meshcop/border_agent.cpp index 75fcd2861..90b5aaec0 100644 --- a/src/core/meshcop/border_agent.cpp +++ b/src/core/meshcop/border_agent.cpp @@ -54,6 +54,7 @@ BorderAgent::BorderAgent(Instance &aInstance) , mIdInitialized(false) #endif #if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE + , mIsEphemeralKeyFeatureEnabled(OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_FEATURE_ENABLED_BY_DEFAULT) , mUsingEphemeralKey(false) , mDidConnectWithEphemeralKey(false) , mOldUdpPort(0) @@ -382,6 +383,7 @@ Error BorderAgent::SetEphemeralKey(const char *aKeyString, uint32_t aTimeout, ui Error error = kErrorNone; uint16_t length = StringLength(aKeyString, kMaxEphemeralKeyLength + 1); + VerifyOrExit(mIsEphemeralKeyFeatureEnabled, error = kErrorNotCapable); VerifyOrExit(mState == kStateStarted, error = kErrorInvalidState); VerifyOrExit((length >= kMinEphemeralKeyLength) && (length <= kMaxEphemeralKeyLength), error = kErrorInvalidArgs); @@ -496,6 +498,27 @@ void BorderAgent::HandleDtlsTransportClosed(void) RestartAfterRemovingEphemeralKey(); } +void BorderAgent::SetEphemeralKeyFeatureEnabled(bool aEnabled) +{ + VerifyOrExit(mIsEphemeralKeyFeatureEnabled != aEnabled); + mIsEphemeralKeyFeatureEnabled = aEnabled; + + if (!mIsEphemeralKeyFeatureEnabled) + { + // If there is an active session connected with ephemeral key, we disconnect + // the session. + if (mUsingEphemeralKey) + { + Disconnect(); + } + ClearEphemeralKey(); + } + + // TODO: Update MeshCoP service after new module is added. + +exit: + return; +} #endif // OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/core/meshcop/border_agent.hpp b/src/core/meshcop/border_agent.hpp index c50886883..7da89c352 100644 --- a/src/core/meshcop/border_agent.hpp +++ b/src/core/meshcop/border_agent.hpp @@ -228,6 +228,21 @@ public: mEphemeralKeyCallback.Set(aCallback, aContext); } + /** + * Enables/disables the Border Agent Ephemeral Key feature. + * + * The Ephemeral Key feature can only be used when it's enabled. If an ephemeral key is already active and then + * this method is called to disable the feature, the in-use ephemeral key will be cleared. + * + * @param[in] aIsEnabled Whether to enable the BA Ephemeral Key feature. + */ + void SetEphemeralKeyFeatureEnabled(bool aEnabled); + + /** + * Indicates whether the Border Agent Ephemeral Key feature state is enabled. + */ + bool IsEphemeralKeyFeatureEnabled(void) { return mIsEphemeralKeyFeatureEnabled; } + #endif // OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE /** @@ -349,6 +364,7 @@ private: bool mIdInitialized; #endif #if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE + bool mIsEphemeralKeyFeatureEnabled : 1; bool mUsingEphemeralKey : 1; bool mDidConnectWithEphemeralKey : 1; uint16_t mOldUdpPort; diff --git a/tests/nexus/test_border_agent.cpp b/tests/nexus/test_border_agent.cpp index 37fcec6a8..b8c50ff24 100644 --- a/tests/nexus/test_border_agent.cpp +++ b/tests/nexus/test_border_agent.cpp @@ -211,6 +211,17 @@ void TestBorderAgentEphemeralKey(void) node1.Get().SetPanId(node0.Get().GetPanId()); node1.Get().Up(); + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Log("Check Border Agent ephemeral key feature enabled"); + + node0.Get().SetEphemeralKeyFeatureEnabled(false); + VerifyOrQuit(!node0.Get().IsEphemeralKeyFeatureEnabled()); + VerifyOrQuit(node0.Get().SetEphemeralKey(kEphemeralKey, /* aTimeout */ 0, kUdpPort) == + kErrorNotCapable); + + node0.Get().SetEphemeralKeyFeatureEnabled(true); + VerifyOrQuit(node0.Get().IsEphemeralKeyFeatureEnabled()); + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Check Border Agent ephemeral key initial state"); diff --git a/tests/toranj/cli/cli.py b/tests/toranj/cli/cli.py index cb2a4ce65..0d1a636cd 100644 --- a/tests/toranj/cli/cli.py +++ b/tests/toranj/cli/cli.py @@ -525,6 +525,12 @@ class Node(object): def ba_get_port(self): return self._cli_single_output('ba port') + def ba_is_ephemeral_key_feature_enabled(self): + return self._cli_single_output('ba ephemeralkey feature') + + def ba_set_ephemeral_key_feature_enabled(self, enable): + self._cli_no_output('ba ephemeralkey feature', 'enable' if enable else 'disable') + def ba_is_ephemeral_key_active(self): return self._cli_single_output('ba ephemeralkey') diff --git a/tests/toranj/cli/test-028-border-agent-ephemeral-key.py b/tests/toranj/cli/test-028-border-agent-ephemeral-key.py index 9c8ca5f8a..d173fd74e 100755 --- a/tests/toranj/cli/test-028-border-agent-ephemeral-key.py +++ b/tests/toranj/cli/test-028-border-agent-ephemeral-key.py @@ -55,6 +55,11 @@ leader.form('ba-ephemeral') verify(leader.get_state() == 'leader') +leader.ba_set_ephemeral_key_feature_enabled(False) +verify(leader.ba_is_ephemeral_key_feature_enabled() == 'Disabled') +leader.ba_set_ephemeral_key_feature_enabled(True) +verify(leader.ba_is_ephemeral_key_feature_enabled() == 'Enabled') + verify(leader.ba_is_ephemeral_key_active() == 'inactive') port = int(leader.ba_get_port())