From 15a789267d06d1ea55f88c33c6d0e78290ca0ab0 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Wed, 12 Feb 2025 11:04:13 -0800 Subject: [PATCH] [border-agent] support multiple parallel sessions (#11212) This commit updates the `BorderAgent` implementation to support multiple parallel sessions using PSKc. It adds new public OT APIs to iterate over all sessions, along with related CLI commands. The nexus `test_border_agent` is updated to cover multi-session behavior and the new session iteration APIs. --- include/openthread/border_agent.h | 60 ++++- include/openthread/instance.h | 2 +- src/cli/README.md | 15 ++ src/cli/cli.cpp | 31 +++ src/core/api/border_agent_api.cpp | 14 +- src/core/meshcop/border_agent.cpp | 118 +++++---- src/core/meshcop/border_agent.hpp | 97 ++++--- src/core/meshcop/secure_transport.hpp | 2 +- tests/nexus/test_border_agent.cpp | 349 ++++++++++++++++++++------ 9 files changed, 527 insertions(+), 161 deletions(-) diff --git a/include/openthread/border_agent.h b/include/openthread/border_agent.h index a9300cd3fdc..eada91debea 100644 --- a/include/openthread/border_agent.h +++ b/include/openthread/border_agent.h @@ -36,6 +36,7 @@ #define OPENTHREAD_BORDER_AGENT_H_ #include +#include #ifdef __cplusplus extern "C" { @@ -89,13 +90,32 @@ typedef struct otBorderAgentCounters } otBorderAgentCounters; /** - * Gets the counters of the Thread Border Agent. + * Represents information about a Border Agent session. * - * @param[in] aInstance A pointer to an OpenThread instance. + * This structure is populated by `otBorderAgentGetNextSessionInfo()` during iteration over the list of sessions using + * an `otBorderAgentSessionIterator`. * - * @returns A pointer to the Border Agent counters. + * To ensure consistent `mLifetime` calculations, the iterator's initialization time is stored within the iterator, + * and each session's `mLifetime` is calculated relative to this time. */ -const otBorderAgentCounters *otBorderAgentGetCounters(otInstance *aInstance); +typedef struct otBorderAgentSessionInfo +{ + otSockAddr mPeerSockAddr; ///< Socket address (IPv6 address and port number) of session peer. + bool mIsConnected; ///< Indicates whether the session is connected. + bool mIsCommissioner; ///< Indicates whether the session is accepted as full commissioner. + uint64_t mLifetime; ///< Milliseconds since the session was first established. +} otBorderAgentSessionInfo; + +/** + * Represents an iterator for Border Agent sessions. + * + * The caller MUST NOT access or update the fields in this struct. It is intended for OpenThread internal use only. + */ +typedef struct otBorderAgentSessionIterator +{ + void *mPtr; + uint64_t mData; +} otBorderAgentSessionIterator; /** * Indicates whether or not the Border Agent service is active and running. @@ -161,6 +181,38 @@ otError otBorderAgentGetId(otInstance *aInstance, otBorderAgentId *aId); */ otError otBorderAgentSetId(otInstance *aInstance, const otBorderAgentId *aId); +/** + * Initializes a session iterator. + * + * An iterator MUST be initialized before being used in `otBorderAgentGetNextSessionInfo()`. A previously initialized + * iterator can be re-initialized to start from the beginning of the session list. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aIterator The iterator to initialize. + */ +void otBorderAgentInitSessionIterator(otInstance *aInstance, otBorderAgentSessionIterator *aIterator); + +/** + * Retrieves the next Border Agent session information. + * + * @param[in] aIterator The iterator to use. + * @param[out] aSessionInfo A pointer to an `otBorderAgentSessionInfo` to populate. + * + * @retval OT_ERROR_NONE Successfully retrieved the next session info. + * @retval OT_ERROR_NOT_FOUND No more sessions are available. The end of the list has been reached. + */ +otError otBorderAgentGetNextSessionInfo(otBorderAgentSessionIterator *aIterator, + otBorderAgentSessionInfo *aSessionInfo); + +/** + * 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); + /*-------------------------------------------------------------------------------------------------------------------- * Border Agent Ephemeral Key feature */ diff --git a/include/openthread/instance.h b/include/openthread/instance.h index abe5496ea4e..e2cc51602ed 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 (475) +#define OPENTHREAD_API_VERSION (476) /** * @addtogroup api-instance diff --git a/src/cli/README.md b/src/cli/README.md index 64b9802f4d1..a80c1859059 100644 --- a/src/cli/README.md +++ b/src/cli/README.md @@ -387,6 +387,21 @@ Active Done ``` +### ba sessions + +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). + +```bash +ba sessions +[fe80:0:0:0:cc79:2a29:d311:1aea]:9202 connected:yes commissioner:no lifetime:1860 +Done +``` + ### ba ephemeralkey Print the Border Agent's Ephemeral Key Manager state. diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index a2f8e9cce09..2d48fac3fd6 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -475,6 +475,37 @@ template <> otError Interpreter::Process(Arg aArgs[]) { OutputLine("%s", otBorderAgentIsActive(GetInstancePtr()) ? "Active" : "Inactive"); } + /** + * @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) diff --git a/src/core/api/border_agent_api.cpp b/src/core/api/border_agent_api.cpp index f93346018e2..d0da6b5366a 100644 --- a/src/core/api/border_agent_api.cpp +++ b/src/core/api/border_agent_api.cpp @@ -56,7 +56,7 @@ otError otBorderAgentSetId(otInstance *aInstance, const otBorderAgentId *aId) bool otBorderAgentIsActive(otInstance *aInstance) { - return AsCoreType(aInstance).Get().IsActive(); + return AsCoreType(aInstance).Get().IsRunning(); } uint16_t otBorderAgentGetUdpPort(otInstance *aInstance) @@ -64,6 +64,18 @@ uint16_t otBorderAgentGetUdpPort(otInstance *aInstance) return AsCoreType(aInstance).Get().GetUdpPort(); } +void otBorderAgentInitSessionIterator(otInstance *aInstance, otBorderAgentSessionIterator *aIterator) +{ + AsCoreType(aIterator).Init(AsCoreType(aInstance)); +} + +otError otBorderAgentGetNextSessionInfo(otBorderAgentSessionIterator *aIterator, otBorderAgentSessionInfo *aSessionInfo) +{ + AssertPointerIsNotNull(aSessionInfo); + + return AsCoreType(aIterator).GetNextSessionInfo(*aSessionInfo); +} + const otBorderAgentCounters *otBorderAgentGetCounters(otInstance *aInstance) { return &AsCoreType(aInstance).Get().GetCounters(); diff --git a/src/core/meshcop/border_agent.cpp b/src/core/meshcop/border_agent.cpp index 0257fd1fa4a..ca3add05078 100644 --- a/src/core/meshcop/border_agent.cpp +++ b/src/core/meshcop/border_agent.cpp @@ -47,9 +47,8 @@ RegisterLogModule("BorderAgent"); BorderAgent::BorderAgent(Instance &aInstance) : InstanceLocator(aInstance) - , mState(kStateStopped) + , mIsRunning(false) , mDtlsTransport(aInstance, kNoLinkSecurity) - , mCoapDtlsSession(nullptr) #if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE , mIdInitialized(false) #endif @@ -97,48 +96,43 @@ Error BorderAgent::SetId(const Id &aId) } #endif // OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE -Error BorderAgent::Start(uint16_t aUdpPort) -{ - Error error; - Pskc pskc; - - Get().GetPskc(pskc); - error = Start(aUdpPort, pskc.m8, Pskc::kSize); - pskc.Clear(); - - return error; -} - -Error BorderAgent::Start(uint16_t aUdpPort, const uint8_t *aPsk, uint8_t aPskLength) +void BorderAgent::Start(void) { Error error = kErrorNone; + Pskc pskc; - VerifyOrExit(mState == kStateStopped); + VerifyOrExit(!mIsRunning); mDtlsTransport.SetAcceptCallback(BorderAgent::HandleAcceptSession, this); mDtlsTransport.SetRemoveSessionCallback(BorderAgent::HandleRemoveSession, this); SuccessOrExit(error = mDtlsTransport.Open()); - SuccessOrExit(error = mDtlsTransport.Bind(aUdpPort)); + SuccessOrExit(error = mDtlsTransport.Bind(kUdpPort)); - SuccessOrExit(error = mDtlsTransport.SetPsk(aPsk, aPskLength)); + Get().GetPskc(pskc); + SuccessOrExit(error = mDtlsTransport.SetPsk(pskc.m8, Pskc::kSize)); + pskc.Clear(); - mState = kStateStarted; + mIsRunning = true; LogInfo("Border Agent start listening on port %u", GetUdpPort()); exit: + if (!mIsRunning) + { + mDtlsTransport.Close(); + } + LogWarnOnError(error, "start agent"); - return error; } void BorderAgent::Stop(void) { - VerifyOrExit(mState != kStateStopped); + VerifyOrExit(mIsRunning); mDtlsTransport.Close(); + mIsRunning = false; - mState = kStateStopped; LogInfo("Border Agent stopped"); exit: @@ -165,7 +159,7 @@ void BorderAgent::HandleNotifierEvents(Events aEvents) { Pskc pskc; - VerifyOrExit(mState != kStateStopped); + VerifyOrExit(mIsRunning); Get().GetPskc(pskc); @@ -188,17 +182,7 @@ SecureSession *BorderAgent::HandleAcceptSession(void *aContext, const Ip6::Messa BorderAgent::CoapDtlsSession *BorderAgent::HandleAcceptSession(void) { - CoapDtlsSession *session = nullptr; - - VerifyOrExit(mCoapDtlsSession == nullptr); - - session = CoapDtlsSession::Allocate(GetInstance(), mDtlsTransport); - VerifyOrExit(session != nullptr); - - mCoapDtlsSession = session; - -exit: - return session; + return CoapDtlsSession::Allocate(GetInstance(), mDtlsTransport); } void BorderAgent::HandleRemoveSession(void *aContext, SecureSession &aSession) @@ -212,7 +196,6 @@ void BorderAgent::HandleRemoveSession(SecureSession &aSession) coapSession.Cleanup(); coapSession.Free(); - mCoapDtlsSession = nullptr; } void BorderAgent::HandleSessionConnected(CoapDtlsSession &aSession) @@ -227,7 +210,6 @@ void BorderAgent::HandleSessionConnected(CoapDtlsSession &aSession) else #endif { - mState = kStateConnected; mCounters.mPskcSecureSessionSuccesses++; } } @@ -244,8 +226,6 @@ void BorderAgent::HandleSessionDisconnected(CoapDtlsSession &aSession, CoapDtlsS else #endif { - mState = kStateStarted; - if (aEvent == CoapDtlsSession::kDisconnectedError) { mCounters.mPskcSecureSessionFailures++; @@ -265,11 +245,28 @@ void BorderAgent::HandleCommissionerPetitionAccepted(CoapDtlsSession &aSession) else #endif { - mState = kStateAccepted; mCounters.mPskcCommissionerPetitions++; } } +BorderAgent::CoapDtlsSession *BorderAgent::FindActiveCommissionerSession(void) +{ + CoapDtlsSession *commissionerSession = nullptr; + + for (SecureSession &session : mDtlsTransport.GetSessions()) + { + CoapDtlsSession &coapSession = static_cast(session); + + if (coapSession.IsActiveCommissioner()) + { + commissionerSession = &coapSession; + break; + } + } + + return commissionerSession; +} + Coap::Message::Code BorderAgent::CoapCodeFromError(Error aError) { Coap::Message::Code code; @@ -298,25 +295,55 @@ template <> void BorderAgent::HandleTmf(Coap::Message &aMessage, co OT_UNUSED_VARIABLE(aMessageInfo); - Coap::Message *message = nullptr; - Error error = kErrorNone; + Coap::Message *message = nullptr; + Error error = kErrorNone; + CoapDtlsSession *session; - VerifyOrExit(mState != kStateStopped); + VerifyOrExit(mIsRunning); VerifyOrExit(aMessage.IsNonConfirmablePostRequest(), error = kErrorDrop); - VerifyOrExit(mCoapDtlsSession != nullptr); + session = FindActiveCommissionerSession(); + VerifyOrExit(session != nullptr); - message = mCoapDtlsSession->NewPriorityNonConfirmablePostMessage(kUriRelayRx); + message = session->NewPriorityNonConfirmablePostMessage(kUriRelayRx); VerifyOrExit(message != nullptr, error = kErrorNoBufs); - SuccessOrExit(error = mCoapDtlsSession->ForwardToCommissioner(*message, aMessage)); + SuccessOrExit(error = session->ForwardToCommissioner(*message, aMessage)); LogInfo("Sent to commissioner on RelayRx (c/rx)"); exit: FreeMessageOnError(message, error); } +//---------------------------------------------------------------------------------------------------------------------- +// BorderAgent::SessionIterator + +void BorderAgent::SessionIterator::Init(Instance &aInstance) +{ + SetSession(static_cast(aInstance.Get().mDtlsTransport.GetSessions().GetHead())); + SetInitTime(aInstance.Get().GetUptime()); +} + +Error BorderAgent::SessionIterator::GetNextSessionInfo(SessionInfo &aSessionInfo) +{ + Error error = kErrorNone; + CoapDtlsSession *session = GetSession(); + + VerifyOrExit(session != nullptr, error = kErrorNotFound); + + SetSession(static_cast(session->GetNext())); + + aSessionInfo.mPeerSockAddr.mAddress = session->GetMessageInfo().GetPeerAddr(); + aSessionInfo.mPeerSockAddr.mPort = session->GetMessageInfo().GetPeerPort(); + aSessionInfo.mIsConnected = session->IsConnected(); + aSessionInfo.mIsCommissioner = session->IsActiveCommissioner(); + aSessionInfo.mLifetime = GetInitTime() - session->GetAllocationTime(); + +exit: + return error; +} + //---------------------------------------------------------------------------------------------------------------------- // BorderAgent::EphemeralKeyManager @@ -614,6 +641,7 @@ BorderAgent::CoapDtlsSession::CoapDtlsSession(Instance &aInstance, Dtls::Transpo , mIsActiveCommissioner(false) , mTimer(aInstance, HandleTimer, this) , mUdpReceiver(HandleUdpReceive, this) + , mAllocationTime(aInstance.Get().GetUptime()) { mCommissionerAloc.InitAsThreadOriginMeshLocal(); diff --git a/src/core/meshcop/border_agent.hpp b/src/core/meshcop/border_agent.hpp index 241658a9ba6..357b7a5251c 100644 --- a/src/core/meshcop/border_agent.hpp +++ b/src/core/meshcop/border_agent.hpp @@ -50,6 +50,7 @@ #include "common/tasklet.hpp" #include "meshcop/dataset.hpp" #include "meshcop/secure_transport.hpp" +#include "net/socket.hpp" #include "net/udp6.hpp" #include "thread/tmf.hpp" #include "thread/uri_paths.hpp" @@ -62,6 +63,10 @@ namespace MeshCoP { #error "Border Agent feature requires `OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE`" #endif +#if !OPENTHREAD_CONFIG_UPTIME_ENABLE +#error "Border Agent feature requires `OPENTHREAD_CONFIG_UPTIME_ENABLE`" +#endif + class BorderAgent : public InstanceLocator, private NonCopyable { friend class ot::Notifier; @@ -70,16 +75,38 @@ class BorderAgent : public InstanceLocator, private NonCopyable class CoapDtlsSession; public: - typedef otBorderAgentId Id; ///< Border Agent ID. - typedef otBorderAgentCounters Counters; ///< Border Agent Counters. + typedef otBorderAgentId Id; ///< Border Agent ID. + typedef otBorderAgentCounters Counters; ///< Border Agent Counters. + typedef otBorderAgentSessionInfo SessionInfo; ///< A session info. - enum State : uint8_t + /** + * Represents an iterator for secure sessions. + */ + class SessionIterator : public otBorderAgentSessionIterator { - kStateDisabled = OT_BORDER_AGENT_STATE_DISABLED, ///< Ephemeral key feature is disabled. - kStateStopped = OT_BORDER_AGENT_STATE_STOPPED, ///< Enabled, but the ephemeral key is not set and started. - kStateStarted = OT_BORDER_AGENT_STATE_STARTED, ///< Ephemeral key is set and listening to accept connection - kStateConnected = OT_BORDER_AGENT_STATE_CONNECTED, ///< Session connected with candidate, not full commissioner - kStateAccepted = OT_BORDER_AGENT_STATE_ACCEPTED, ///< Session connected and accepted as full commissioner. + public: + /** + * Initializes the `SessionIterator`. + * + * @param[in] aInstance The OpenThread instance. + */ + void Init(Instance &aInstance); + + /** + * Retrieves the next session information. + * + * @param[out] aSessionInfo A `SessionInfo` to populate. + * + * @retval kErrorNone Successfully retrieved the next session. @p aSessionInfo is updated. + * @retval kErrorNotFound No more sessions are available. The end of the list has been reached. + */ + Error GetNextSessionInfo(SessionInfo &aSessionInfo); + + private: + CoapDtlsSession *GetSession(void) const { return static_cast(mPtr); } + void SetSession(CoapDtlsSession *aSession) { mPtr = aSession; } + uint64_t GetInitTime(void) const { return mData; } + void SetInitTime(uint64_t aInitTime) { mData = aInitTime; } }; /** @@ -127,19 +154,12 @@ class BorderAgent : public InstanceLocator, private NonCopyable uint16_t GetUdpPort(void) const; /** - * Gets the state of the Border Agent service. + * Indicates whether the Border Agent service is running. * - * @returns The state of the Border Agent service. + * @retval TRUE Border Agent service is running. + * @retval FALSE Border Agent service is not running. */ - State GetState(void) const { return mState; } - - /** - * Indicates whether the Border Agent service is active. - * - * @retval TRUE Border Agent service is active. - * @retval FALSE Border Agent service is not active. - */ - bool IsActive(void) const { return (mState != kStateDisabled) && (mState != kStateStopped); } + bool IsRunning(void) const { return mIsRunning; } #if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE /** @@ -157,6 +177,18 @@ class BorderAgent : public InstanceLocator, private NonCopyable typedef otBorderAgentEphemeralKeyCallback CallbackHandler; ///< Callback function pointer. + /** + * Represents the state of the `EphemeralKeyManager`. + */ + enum State : uint8_t + { + kStateDisabled = OT_BORDER_AGENT_STATE_DISABLED, ///< Ephemeral key feature is disabled. + kStateStopped = OT_BORDER_AGENT_STATE_STOPPED, ///< Enabled, but the key is not set and started. + kStateStarted = OT_BORDER_AGENT_STATE_STARTED, ///< Key is set and listening to accept connection. + kStateConnected = OT_BORDER_AGENT_STATE_CONNECTED, ///< Session connected, not full commissioner. + kStateAccepted = OT_BORDER_AGENT_STATE_ACCEPTED, ///< Session connected and accepted as full commissioner. + }; + /** * Enables/disables Ephemeral Key Manager. * @@ -308,8 +340,10 @@ class BorderAgent : public InstanceLocator, private NonCopyable friend Heap::Allocatable; public: - Error ForwardToCommissioner(Coap::Message &aForwardMessage, const Message &aMessage); - void Cleanup(void); + Error ForwardToCommissioner(Coap::Message &aForwardMessage, const Message &aMessage); + void Cleanup(void); + bool IsActiveCommissioner(void) const { return mIsActiveCommissioner; } + uint64_t GetAllocationTime(void) const { return mAllocationTime; } private: class ForwardContext : public ot::LinkedListEntry, @@ -366,13 +400,12 @@ class BorderAgent : public InstanceLocator, private NonCopyable TimerMilliContext mTimer; Ip6::Udp::Receiver mUdpReceiver; Ip6::Netif::UnicastAddress mCommissionerAloc; + uint64_t mAllocationTime; }; - void Start(void) { IgnoreError(Start(kUdpPort)); } - Error Start(uint16_t aUdpPort); - Error Start(uint16_t aUdpPort, const uint8_t *aPsk, uint8_t aPskLength); - void Stop(void); - void HandleNotifierEvents(Events aEvents); + void Start(void); + void Stop(void); + void HandleNotifierEvents(Events aEvents); template void HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); @@ -380,6 +413,7 @@ class BorderAgent : public InstanceLocator, private NonCopyable CoapDtlsSession *HandleAcceptSession(void); static void HandleRemoveSession(void *aContext, SecureSession &aSession); void HandleRemoveSession(SecureSession &aSession); + CoapDtlsSession *FindActiveCommissionerSession(void); void HandleSessionConnected(CoapDtlsSession &aSession); void HandleSessionDisconnected(CoapDtlsSession &aSession, CoapDtlsSession::ConnectEvent aEvent); @@ -387,9 +421,8 @@ class BorderAgent : public InstanceLocator, private NonCopyable static Coap::Message::Code CoapCodeFromError(Error aError); - State mState; - Dtls::Transport mDtlsTransport; - CoapDtlsSession *mCoapDtlsSession; + bool mIsRunning; + Dtls::Transport mDtlsTransport; #if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE Id mId; bool mIdInitialized; @@ -405,7 +438,11 @@ DeclareTmfHandler(BorderAgent, kUriRelayRx); } // namespace MeshCoP DefineCoreType(otBorderAgentId, MeshCoP::BorderAgent::Id); -DefineMapEnum(otBorderAgentEphemeralKeyState, MeshCoP::BorderAgent::State); +DefineCoreType(otBorderAgentSessionIterator, MeshCoP::BorderAgent::SessionIterator); + +#if OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE +DefineMapEnum(otBorderAgentEphemeralKeyState, MeshCoP::BorderAgent::EphemeralKeyManager::State); +#endif } // namespace ot diff --git a/src/core/meshcop/secure_transport.hpp b/src/core/meshcop/secure_transport.hpp index cc71403b723..63eb40444a3 100644 --- a/src/core/meshcop/secure_transport.hpp +++ b/src/core/meshcop/secure_transport.hpp @@ -100,7 +100,7 @@ class Tls; /** * Represents a secure session. */ -class SecureSession : private LinkedListEntry, private NonCopyable +class SecureSession : public LinkedListEntry, private NonCopyable { friend class LinkedListEntry; friend class LinkedList; diff --git a/tests/nexus/test_border_agent.cpp b/tests/nexus/test_border_agent.cpp index f4d1b6824d4..2081ef7f579 100644 --- a/tests/nexus/test_border_agent.cpp +++ b/tests/nexus/test_border_agent.cpp @@ -36,16 +36,21 @@ namespace ot { namespace Nexus { -using BorderAgent = MeshCoP::BorderAgent; +using BorderAgent = MeshCoP::BorderAgent; +using EphemeralKeyManager = ot::MeshCoP::BorderAgent::EphemeralKeyManager; void TestBorderAgent(void) { - Core nexus; - Node &node0 = nexus.CreateNode(); - Node &node1 = nexus.CreateNode(); - Ip6::SockAddr sockAddr; - Pskc pskc; - Coap::Message *message; + Core nexus; + Node &node0 = nexus.CreateNode(); + Node &node1 = nexus.CreateNode(); + Node &node2 = nexus.CreateNode(); + Node &node3 = nexus.CreateNode(); + Ip6::SockAddr sockAddr; + Pskc pskc; + Coap::Message *message; + BorderAgent::SessionIterator iter; + BorderAgent::SessionInfo sessionInfo; Log("------------------------------------------------------------------------------------------------------"); Log("TestBorderAgent"); @@ -54,7 +59,7 @@ void TestBorderAgent(void) // Form the topology: // - node0 leader acting as Border Agent, - // - node1 staying disconnected (acting as candidate) + // - node1-3 stay disconnected (acting as candidate) node0.Form(); nexus.AdvanceTime(50 * Time::kOneSecondInMsec); @@ -64,10 +69,18 @@ void TestBorderAgent(void) node1.Get().SetPanId(node0.Get().GetPanId()); node1.Get().Up(); + SuccessOrQuit(node2.Get().SetPanChannel(node0.Get().GetPanChannel())); + node2.Get().SetPanId(node0.Get().GetPanId()); + node2.Get().Up(); + + SuccessOrQuit(node3.Get().SetPanChannel(node0.Get().GetPanChannel())); + node3.Get().SetPanId(node0.Get().GetPanId()); + node3.Get().Up(); + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Check Border Agent initial state"); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateStarted); + VerifyOrQuit(node0.Get().IsRunning()); SuccessOrQuit(node0.Get().AddUnsecurePort(node0.Get().GetUdpPort())); @@ -87,9 +100,15 @@ void TestBorderAgent(void) VerifyOrQuit(node1.Get().IsConnected()); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateConnected); VerifyOrQuit(node0.Get().GetCounters().mPskcSecureSessionSuccesses == 1); + iter.Init(node0.GetInstance()); + SuccessOrQuit(iter.GetNextSessionInfo(sessionInfo)); + VerifyOrQuit(sessionInfo.mIsConnected); + VerifyOrQuit(!sessionInfo.mIsCommissioner); + VerifyOrQuit(node1.Get().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress))); + VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound); + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Disconnect from candidate side"); @@ -98,7 +117,10 @@ void TestBorderAgent(void) nexus.AdvanceTime(3 * Time::kOneSecondInMsec); VerifyOrQuit(!node1.Get().IsConnected()); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateStarted); + VerifyOrQuit(node0.Get().IsRunning()); + + iter.Init(node0.GetInstance()); + VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Establish a secure connection again"); @@ -110,9 +132,15 @@ void TestBorderAgent(void) VerifyOrQuit(node1.Get().IsConnected()); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateConnected); VerifyOrQuit(node0.Get().GetCounters().mPskcSecureSessionSuccesses == 2); + iter.Init(node0.GetInstance()); + SuccessOrQuit(iter.GetNextSessionInfo(sessionInfo)); + VerifyOrQuit(sessionInfo.mIsConnected); + VerifyOrQuit(!sessionInfo.mIsCommissioner); + VerifyOrQuit(node1.Get().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress))); + VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound); + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Send `Commissioner Petition` TMF command to become full commissioner"); @@ -123,19 +151,29 @@ void TestBorderAgent(void) nexus.AdvanceTime(1 * Time::kOneSecondInMsec); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateAccepted); - VerifyOrQuit(node0.Get().GetCounters().mPskcSecureSessionSuccesses == 2); VerifyOrQuit(node0.Get().GetCounters().mPskcCommissionerPetitions == 1); + iter.Init(node0.GetInstance()); + SuccessOrQuit(iter.GetNextSessionInfo(sessionInfo)); + VerifyOrQuit(sessionInfo.mIsConnected); + VerifyOrQuit(sessionInfo.mIsCommissioner); + VerifyOrQuit(node1.Get().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress))); + VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound); + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Send `Commissioner Keep Alive` and check timeout behavior"); nexus.AdvanceTime(30 * Time::kOneSecondInMsec); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateAccepted); VerifyOrQuit(node1.Get().IsConnected()); + iter.Init(node0.GetInstance()); + SuccessOrQuit(iter.GetNextSessionInfo(sessionInfo)); + VerifyOrQuit(sessionInfo.mIsConnected); + VerifyOrQuit(sessionInfo.mIsCommissioner); + VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound); + message = node1.Get().NewPriorityConfirmablePostMessage(kUriCommissionerKeepAlive); VerifyOrQuit(message != nullptr); SuccessOrQuit(Tlv::Append(*message, MeshCoP::StateTlv::kAccept)); @@ -146,16 +184,18 @@ void TestBorderAgent(void) nexus.AdvanceTime(49 * Time::kOneSecondInMsec); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateAccepted); VerifyOrQuit(node1.Get().IsConnected()); Log(" Wait for additional 5 seconds (ensuring TIMEOUT_LEAD_PET and session disconnect guard time expires)"); nexus.AdvanceTime(5 * Time::kOneSecondInMsec); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateStarted); + VerifyOrQuit(node0.Get().IsRunning()); VerifyOrQuit(!node1.Get().IsConnected()); + iter.Init(node0.GetInstance()); + VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound); + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Establish a secure session again and petition to become commissioner"); @@ -163,7 +203,6 @@ void TestBorderAgent(void) nexus.AdvanceTime(1 * Time::kOneSecondInMsec); VerifyOrQuit(node1.Get().IsConnected()); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateConnected); message = node1.Get().NewPriorityConfirmablePostMessage(kUriCommissionerPetition); VerifyOrQuit(message != nullptr); @@ -172,12 +211,145 @@ void TestBorderAgent(void) nexus.AdvanceTime(1 * Time::kOneSecondInMsec); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateAccepted); - VerifyOrQuit(node0.Get().GetCounters().mPskcSecureSessionSuccesses == 3); VerifyOrQuit(node0.Get().GetCounters().mPskcCommissionerPetitions == 2); + + iter.Init(node0.GetInstance()); + SuccessOrQuit(iter.GetNextSessionInfo(sessionInfo)); + VerifyOrQuit(sessionInfo.mIsConnected); + VerifyOrQuit(sessionInfo.mIsCommissioner); + VerifyOrQuit(node1.Get().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress))); + VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound); + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Log("Establish two more secure sessions while the first session is still active"); + + SuccessOrQuit(node2.Get().SetPsk(pskc.m8, Pskc::kSize)); + SuccessOrQuit(node2.Get().Open()); + SuccessOrQuit(node2.Get().Connect(sockAddr)); + + SuccessOrQuit(node3.Get().SetPsk(pskc.m8, Pskc::kSize)); + SuccessOrQuit(node3.Get().Open()); + SuccessOrQuit(node3.Get().Connect(sockAddr)); + + nexus.AdvanceTime(1 * Time::kOneSecondInMsec); + + VerifyOrQuit(node1.Get().IsConnected()); + VerifyOrQuit(node2.Get().IsConnected()); + VerifyOrQuit(node3.Get().IsConnected()); + + VerifyOrQuit(node0.Get().GetCounters().mPskcSecureSessionSuccesses == 5); + VerifyOrQuit(node0.Get().GetCounters().mPskcCommissionerPetitions == 2); + + iter.Init(node0.GetInstance()); + + for (uint8_t numSessions = 0; numSessions < 3; numSessions++) + { + SuccessOrQuit(iter.GetNextSessionInfo(sessionInfo)); + VerifyOrQuit(sessionInfo.mIsConnected); + + if (node1.Get().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress))) + { + VerifyOrQuit(sessionInfo.mIsCommissioner); + } + else + { + VerifyOrQuit(node2.Get().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress)) || + node3.Get().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress))); + VerifyOrQuit(!sessionInfo.mIsCommissioner); + } + } + + VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound); + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Log("Disconnect from candidate side on node 1"); + + node1.Get().Close(); + + nexus.AdvanceTime(3 * Time::kOneSecondInMsec); + + VerifyOrQuit(!node1.Get().IsConnected()); + VerifyOrQuit(node0.Get().IsRunning()); + + VerifyOrQuit(node2.Get().IsConnected()); + VerifyOrQuit(node3.Get().IsConnected()); + + iter.Init(node0.GetInstance()); + + for (uint8_t numSessions = 0; numSessions < 2; numSessions++) + { + SuccessOrQuit(iter.GetNextSessionInfo(sessionInfo)); + VerifyOrQuit(sessionInfo.mIsConnected); + VerifyOrQuit(!sessionInfo.mIsCommissioner); + VerifyOrQuit(node2.Get().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress)) || + node3.Get().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress))); + } + + VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound); + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Log("Connect again from node 1 after 25 seconds"); + + nexus.AdvanceTime(25 * Time::kOneSecondInMsec); + + SuccessOrQuit(node1.Get().Open()); + SuccessOrQuit(node1.Get().Connect(sockAddr)); + + nexus.AdvanceTime(1 * Time::kOneSecondInMsec); + + VerifyOrQuit(node1.Get().IsConnected()); + VerifyOrQuit(node2.Get().IsConnected()); + VerifyOrQuit(node3.Get().IsConnected()); + + iter.Init(node0.GetInstance()); + + for (uint8_t numSessions = 0; numSessions < 3; numSessions++) + { + SuccessOrQuit(iter.GetNextSessionInfo(sessionInfo)); + VerifyOrQuit(sessionInfo.mIsConnected); + VerifyOrQuit(!sessionInfo.mIsCommissioner); + VerifyOrQuit(node1.Get().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress)) || + node2.Get().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress)) || + node3.Get().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress))); + } + + VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound); + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Log("Wait for the first two sessions to timeout, check that only the recent node1 session is connected"); + + nexus.AdvanceTime(28 * Time::kOneSecondInMsec); + + VerifyOrQuit(node1.Get().IsConnected()); + VerifyOrQuit(!node2.Get().IsConnected()); + VerifyOrQuit(!node3.Get().IsConnected()); + + iter.Init(node0.GetInstance()); + + SuccessOrQuit(iter.GetNextSessionInfo(sessionInfo)); + VerifyOrQuit(sessionInfo.mIsConnected); + VerifyOrQuit(!sessionInfo.mIsCommissioner); + VerifyOrQuit(node1.Get().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress))); + + VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound); + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Log("Wait for the node1 session to also timeout, validate that its disconnected"); + + nexus.AdvanceTime(25 * Time::kOneSecondInMsec); + + VerifyOrQuit(!node1.Get().IsConnected()); + VerifyOrQuit(!node2.Get().IsConnected()); + VerifyOrQuit(!node3.Get().IsConnected()); + + iter.Init(node0.GetInstance()); + + VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound); } +//---------------------------------------------------------------------------------------------------------------------- + static bool sEphemeralKeyCallbackCalled = false; void HandleEphemeralKeyChange(void *aContext) @@ -188,7 +360,7 @@ void HandleEphemeralKeyChange(void *aContext) node = reinterpret_cast(aContext); Log(" EphemeralKeyCallback() state:%s", - BorderAgent::EphemeralKeyManager::StateToString(node->Get().GetState())); + EphemeralKeyManager::StateToString(node->Get().GetState())); sEphemeralKeyCallbackCalled = true; } @@ -201,13 +373,15 @@ void TestBorderAgentEphemeralKey(void) static constexpr uint16_t kEphemeralKeySize = sizeof(kEphemeralKey) - 1; static constexpr uint16_t kUdpPort = 49155; - Core nexus; - Node &node0 = nexus.CreateNode(); - Node &node1 = nexus.CreateNode(); - Node &node2 = nexus.CreateNode(); - Ip6::SockAddr sockAddr; - Ip6::SockAddr baSockAddr; - Pskc pskc; + Core nexus; + Node &node0 = nexus.CreateNode(); + Node &node1 = nexus.CreateNode(); + Node &node2 = nexus.CreateNode(); + Ip6::SockAddr sockAddr; + Ip6::SockAddr baSockAddr; + Pskc pskc; + BorderAgent::SessionIterator iter; + BorderAgent::SessionInfo sessionInfo; Log("------------------------------------------------------------------------------------------------------"); Log("TestBorderAgentEphemeralKey"); @@ -245,15 +419,15 @@ void TestBorderAgentEphemeralKey(void) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Check Border Agent ephemeral key feature enabled"); - node0.Get().SetEnabled(false); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateDisabled); - VerifyOrQuit(node0.Get().Start(kEphemeralKey, /* aTimeout */ 0, - kUdpPort) == kErrorInvalidState); + node0.Get().SetEnabled(false); + VerifyOrQuit(node0.Get().GetState() == EphemeralKeyManager::kStateDisabled); + VerifyOrQuit(node0.Get().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort) == + kErrorInvalidState); VerifyOrQuit(node0.Get().GetCounters().mEpskcInvalidBaStateErrors == 1); - node0.Get().SetEnabled(true); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateStopped); + node0.Get().SetEnabled(true); + VerifyOrQuit(node0.Get().GetState() == EphemeralKeyManager::kStateStopped); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Check Border Agent ephemeral key initial state"); @@ -264,12 +438,12 @@ void TestBorderAgentEphemeralKey(void) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Set and start ephemeral key on Border Agent"); - node0.Get().SetCallback(HandleEphemeralKeyChange, &node0); + node0.Get().SetCallback(HandleEphemeralKeyChange, &node0); - SuccessOrQuit(node0.Get().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort)); + SuccessOrQuit(node0.Get().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort)); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateStarted); - VerifyOrQuit(node0.Get().GetUdpPort() == kUdpPort); + VerifyOrQuit(node0.Get().GetState() == EphemeralKeyManager::kStateStarted); + VerifyOrQuit(node0.Get().GetUdpPort() == kUdpPort); VerifyOrQuit(node0.Get().GetCounters().mEpskcActivations == 1); SuccessOrQuit(node0.Get().AddUnsecurePort(kUdpPort)); @@ -293,7 +467,7 @@ void TestBorderAgentEphemeralKey(void) nexus.AdvanceTime(1 * Time::kOneSecondInMsec); VerifyOrQuit(node1.Get().IsConnected()); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateConnected); + VerifyOrQuit(node0.Get().GetState() == EphemeralKeyManager::kStateConnected); VerifyOrQuit(node0.Get().GetCounters().mEpskcActivations == 1); VerifyOrQuit(node0.Get().GetCounters().mEpskcSecureSessionSuccesses == 1); @@ -310,7 +484,7 @@ void TestBorderAgentEphemeralKey(void) nexus.AdvanceTime(3 * Time::kOneSecondInMsec); VerifyOrQuit(!node1.Get().IsConnected()); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateStopped); + VerifyOrQuit(node0.Get().GetState() == EphemeralKeyManager::kStateStopped); VerifyOrQuit(sEphemeralKeyCallbackCalled); VerifyOrQuit(node0.Get().GetCounters().mEpskcActivations == 1); @@ -322,11 +496,10 @@ void TestBorderAgentEphemeralKey(void) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Start using ephemeral key again with short timeout (20 seconds) and establish a connection"); - SuccessOrQuit( - node0.Get().Start(kEphemeralKey, 20 * Time::kOneSecondInMsec, kUdpPort)); + SuccessOrQuit(node0.Get().Start(kEphemeralKey, 20 * Time::kOneSecondInMsec, kUdpPort)); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateStarted); - VerifyOrQuit(node0.Get().GetUdpPort() == kUdpPort); + VerifyOrQuit(node0.Get().GetState() == EphemeralKeyManager::kStateStarted); + VerifyOrQuit(node0.Get().GetUdpPort() == kUdpPort); SuccessOrQuit(node1.Get().Open()); SuccessOrQuit(node1.Get().Connect(sockAddr)); @@ -334,7 +507,7 @@ void TestBorderAgentEphemeralKey(void) nexus.AdvanceTime(2 * Time::kOneSecondInMsec); VerifyOrQuit(node1.Get().IsConnected()); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateConnected); + VerifyOrQuit(node0.Get().GetState() == EphemeralKeyManager::kStateConnected); VerifyOrQuit(node0.Get().GetCounters().mEpskcActivations == 2); VerifyOrQuit(node0.Get().GetCounters().mEpskcSecureSessionSuccesses == 2); @@ -346,7 +519,7 @@ void TestBorderAgentEphemeralKey(void) nexus.AdvanceTime(25 * Time::kOneSecondInMsec); VerifyOrQuit(!node1.Get().IsConnected()); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateStopped); + VerifyOrQuit(node0.Get().GetState() == EphemeralKeyManager::kStateStopped); VerifyOrQuit(sEphemeralKeyCallbackCalled); VerifyOrQuit(node0.Get().GetCounters().mEpskcActivations == 2); @@ -357,16 +530,16 @@ void TestBorderAgentEphemeralKey(void) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Start using ephemeral key without any candidate connecting, check timeout"); - SuccessOrQuit(node0.Get().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort)); + SuccessOrQuit(node0.Get().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort)); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateStarted); - VerifyOrQuit(node0.Get().GetUdpPort() == kUdpPort); + VerifyOrQuit(node0.Get().GetState() == EphemeralKeyManager::kStateStarted); + VerifyOrQuit(node0.Get().GetUdpPort() == kUdpPort); Log(" Wait more than 120 seconds (default ephemeral key timeout)"); sEphemeralKeyCallbackCalled = false; nexus.AdvanceTime(122 * Time::kOneSecondInMsec); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateStopped); + VerifyOrQuit(node0.Get().GetState() == EphemeralKeyManager::kStateStopped); VerifyOrQuit(sEphemeralKeyCallbackCalled); VerifyOrQuit(node0.Get().GetCounters().mEpskcActivations == 3); @@ -377,10 +550,10 @@ void TestBorderAgentEphemeralKey(void) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Check that ephemeral key use is stopped after max failed connection attempts"); - SuccessOrQuit(node0.Get().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort)); + SuccessOrQuit(node0.Get().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort)); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateStarted); - VerifyOrQuit(node0.Get().GetUdpPort() == kUdpPort); + VerifyOrQuit(node0.Get().GetState() == EphemeralKeyManager::kStateStarted); + VerifyOrQuit(node0.Get().GetUdpPort() == kUdpPort); SuccessOrQuit( node1.Get().SetPsk(reinterpret_cast(kEphemeralKey), kEphemeralKeySize - 2)); @@ -394,7 +567,7 @@ void TestBorderAgentEphemeralKey(void) nexus.AdvanceTime(3 * Time::kOneSecondInMsec); VerifyOrQuit(!node1.Get().IsConnected()); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateStarted); + VerifyOrQuit(node0.Get().GetState() == EphemeralKeyManager::kStateStarted); } Log(" Attempt 10 (final attempt) to connect with the wrong key, check that ephemeral key use is stopped"); @@ -404,7 +577,7 @@ void TestBorderAgentEphemeralKey(void) nexus.AdvanceTime(3 * Time::kOneSecondInMsec); VerifyOrQuit(!node1.Get().IsConnected()); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateStopped); + VerifyOrQuit(node0.Get().GetState() == EphemeralKeyManager::kStateStopped); VerifyOrQuit(sEphemeralKeyCallbackCalled); VerifyOrQuit(node0.Get().GetCounters().mEpskcActivations == 4); @@ -418,10 +591,10 @@ void TestBorderAgentEphemeralKey(void) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Validate that disabling ephemeral key will stop and disconnect an active session"); - SuccessOrQuit(node0.Get().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort)); + SuccessOrQuit(node0.Get().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort)); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateStarted); - VerifyOrQuit(node0.Get().GetUdpPort() == kUdpPort); + VerifyOrQuit(node0.Get().GetState() == EphemeralKeyManager::kStateStarted); + VerifyOrQuit(node0.Get().GetUdpPort() == kUdpPort); SuccessOrQuit( node1.Get().SetPsk(reinterpret_cast(kEphemeralKey), kEphemeralKeySize)); @@ -432,18 +605,18 @@ void TestBorderAgentEphemeralKey(void) nexus.AdvanceTime(1 * Time::kOneSecondInMsec); VerifyOrQuit(node1.Get().IsConnected()); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateConnected); + VerifyOrQuit(node0.Get().GetState() == EphemeralKeyManager::kStateConnected); VerifyOrQuit(sEphemeralKeyCallbackCalled); nexus.AdvanceTime(1 * Time::kOneSecondInMsec); sEphemeralKeyCallbackCalled = false; - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateConnected); - node0.Get().SetEnabled(false); + VerifyOrQuit(node0.Get().GetState() == EphemeralKeyManager::kStateConnected); + node0.Get().SetEnabled(false); nexus.AdvanceTime(0); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateDisabled); + VerifyOrQuit(node0.Get().GetState() == EphemeralKeyManager::kStateDisabled); VerifyOrQuit(sEphemeralKeyCallbackCalled); nexus.AdvanceTime(3 * Time::kOneSecondInMsec); @@ -459,16 +632,16 @@ void TestBorderAgentEphemeralKey(void) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Check ephemeral key can be used along with PSKc"); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateStarted); + VerifyOrQuit(node0.Get().IsRunning()); SuccessOrQuit(node0.Get().AddUnsecurePort(node0.Get().GetUdpPort())); - node0.Get().SetEnabled(true); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateStopped); + node0.Get().SetEnabled(true); + VerifyOrQuit(node0.Get().GetState() == EphemeralKeyManager::kStateStopped); - SuccessOrQuit(node0.Get().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort)); + SuccessOrQuit(node0.Get().Start(kEphemeralKey, /* aTimeout */ 0, kUdpPort)); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateStarted); - VerifyOrQuit(node0.Get().GetUdpPort() == kUdpPort); + VerifyOrQuit(node0.Get().GetState() == EphemeralKeyManager::kStateStarted); + VerifyOrQuit(node0.Get().GetUdpPort() == kUdpPort); Log(" Establish a secure session using PSKc (from node2)"); @@ -483,7 +656,13 @@ void TestBorderAgentEphemeralKey(void) nexus.AdvanceTime(1 * Time::kOneSecondInMsec); VerifyOrQuit(node2.Get().IsConnected()); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateConnected); + + iter.Init(node0.GetInstance()); + SuccessOrQuit(iter.GetNextSessionInfo(sessionInfo)); + VerifyOrQuit(sessionInfo.mIsConnected); + VerifyOrQuit(!sessionInfo.mIsCommissioner); + VerifyOrQuit(node2.Get().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress))); + VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound); Log(" Establish a secure session using ephemeral key (from node1)"); @@ -497,18 +676,18 @@ void TestBorderAgentEphemeralKey(void) nexus.AdvanceTime(1 * Time::kOneSecondInMsec); VerifyOrQuit(node1.Get().IsConnected()); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateConnected); + VerifyOrQuit(node0.Get().GetState() == EphemeralKeyManager::kStateConnected); VerifyOrQuit(sEphemeralKeyCallbackCalled); Log(" Stop the secure session using ephemeral key"); - node0.Get().Stop(); + node0.Get().Stop(); sEphemeralKeyCallbackCalled = false; nexus.AdvanceTime(0); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateStopped); + VerifyOrQuit(node0.Get().GetState() == EphemeralKeyManager::kStateStopped); VerifyOrQuit(sEphemeralKeyCallbackCalled); VerifyOrQuit(node0.Get().GetCounters().mEpskcActivations == 6); @@ -521,27 +700,39 @@ void TestBorderAgentEphemeralKey(void) Log(" Check the BA session using PSKc is still connected"); VerifyOrQuit(node2.Get().IsConnected()); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateConnected); + + iter.Init(node0.GetInstance()); + SuccessOrQuit(iter.GetNextSessionInfo(sessionInfo)); + VerifyOrQuit(sessionInfo.mIsConnected); + VerifyOrQuit(!sessionInfo.mIsCommissioner); + VerifyOrQuit(node2.Get().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress))); + VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound); nexus.AdvanceTime(3 * Time::kOneSecondInMsec); VerifyOrQuit(!node1.Get().IsConnected()); VerifyOrQuit(node2.Get().IsConnected()); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateStopped); - VerifyOrQuit(node0.Get().GetState() == BorderAgent::kStateConnected); + VerifyOrQuit(node0.Get().GetState() == EphemeralKeyManager::kStateStopped); + + iter.Init(node0.GetInstance()); + SuccessOrQuit(iter.GetNextSessionInfo(sessionInfo)); + VerifyOrQuit(sessionInfo.mIsConnected); + VerifyOrQuit(!sessionInfo.mIsCommissioner); + VerifyOrQuit(node2.Get().HasUnicastAddress(AsCoreType(&sessionInfo.mPeerSockAddr.mAddress))); + VerifyOrQuit(iter.GetNextSessionInfo(sessionInfo) == kErrorNotFound); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Check proper error is returned with invalid ephemeral key (too short or long)"); - VerifyOrQuit(node0.Get().Start(kTooShortEphemeralKey, /* aTimeout */ 0, - kUdpPort) == kErrorInvalidArgs); + VerifyOrQuit(node0.Get().Start(kTooShortEphemeralKey, /* aTimeout */ 0, kUdpPort) == + kErrorInvalidArgs); VerifyOrQuit(node0.Get().GetCounters().mEpskcActivations == 6); VerifyOrQuit(node0.Get().GetCounters().mEpskcInvalidArgsErrors == 1); - VerifyOrQuit(node0.Get().Start(kTooLongEphemeralKey, /* aTimeout */ 0, - kUdpPort) == kErrorInvalidArgs); + VerifyOrQuit(node0.Get().Start(kTooLongEphemeralKey, /* aTimeout */ 0, kUdpPort) == + kErrorInvalidArgs); VerifyOrQuit(node0.Get().GetCounters().mEpskcActivations == 6); VerifyOrQuit(node0.Get().GetCounters().mEpskcInvalidArgsErrors == 2); }