Skip to content

Commit

Permalink
[secure-transport] support multiple sessions on the same transport (o…
Browse files Browse the repository at this point in the history
…penthread#11092)

This commit updates `SecureTransport` to support multiple
`SecureSession`s on the same transport. The transport tracks a list
of sessions that it owns and manages. Two new callbacks are
introduced:

- `AcceptCallback`: Used to accept a new connection request, providing
  the `SecureSession` instance to use (passing ownership of the
  session to the transport).
- `RemoveSessionCallback`: Signals that a session is removed,
  releasing ownership of the session.

`BorderAgent`, `Tmf::SecureAgent`, and `ApplicationCoapSecure` are
updated to adopt the new model.

This commit also updates the Nexus `test_dtls`, adding
`TestDtlsMultiSession` to validate multiple session support
behavior.
  • Loading branch information
abtink authored Jan 8, 2025
1 parent 70d315a commit 2ae1ce5
Show file tree
Hide file tree
Showing 11 changed files with 671 additions and 128 deletions.
11 changes: 8 additions & 3 deletions src/core/coap/coap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,11 @@ CoapBase::CoapBase(Instance &aInstance, Sender aSender)
{
}

void CoapBase::ClearRequestsAndResponses(void)
void CoapBase::ClearAllRequestsAndResponses(void)
{
ClearRequests(nullptr); // Clear requests matching any address.
mResponsesQueue.DequeueAllResponses();
mRetransmissionTimer.Stop();
}

void CoapBase::ClearRequests(const Ip6::Address &aAddress) { ClearRequests(&aAddress); }
Expand Down Expand Up @@ -1553,7 +1554,11 @@ void ResponsesQueue::UpdateQueue(void)

void ResponsesQueue::DequeueResponse(Message &aMessage) { mQueue.DequeueAndFree(aMessage); }

void ResponsesQueue::DequeueAllResponses(void) { mQueue.DequeueAndFreeAll(); }
void ResponsesQueue::DequeueAllResponses(void)
{
mQueue.DequeueAndFreeAll();
mTimer.Stop();
}

void ResponsesQueue::HandleTimer(Timer &aTimer)
{
Expand Down Expand Up @@ -1693,7 +1698,7 @@ Error Coap::Stop(void)
VerifyOrExit(mSocket.IsBound());

SuccessOrExit(error = mSocket.Close());
ClearRequestsAndResponses();
ClearAllRequestsAndResponses();

exit:
return error;
Expand Down
4 changes: 2 additions & 2 deletions src/core/coap/coap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -358,9 +358,9 @@ class CoapBase : public InstanceLocator, private NonCopyable
typedef Error (*Interceptor)(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo, void *aContext);

/**
* Clears requests and responses used by this CoAP agent.
* Clears all requests and responses used by this CoAP agent and stops all timers.
*/
void ClearRequestsAndResponses(void);
void ClearAllRequestsAndResponses(void);

/**
* Clears requests with specified source address used by this CoAP agent.
Expand Down
25 changes: 24 additions & 1 deletion src/core/coap/coap_secure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ SecureSession::SecureSession(Instance &aInstance, Dtls::Transport &aDtlsTranspor
Dtls::Session::SetReceiveCallback(HandleDtlsReceive, this);
}

void SecureSession::Cleanup(void)
{
ClearAllRequestsAndResponses();
mTransmitQueue.DequeueAndFreeAll();
mTransmitTask.Unpost();
}

#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE

Error SecureSession::SendMessage(Message &aMessage,
Expand Down Expand Up @@ -103,7 +110,7 @@ void SecureSession::HandleDtlsConnectEvent(ConnectEvent aEvent)
if (aEvent != kConnected)
{
mTransmitQueue.DequeueAndFreeAll();
ClearRequestsAndResponses();
ClearAllRequestsAndResponses();
}

mConnectCallback.InvokeIfSet(aEvent);
Expand Down Expand Up @@ -151,6 +158,22 @@ void SecureSession::HandleTransmitTask(void)
FreeMessageOnError(message, error);
}

#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE

MeshCoP::SecureSession *ApplicationCoapSecure::HandleDtlsAccept(void *aContext, const Ip6::MessageInfo &aMessageInfo)
{
OT_UNUSED_VARIABLE(aMessageInfo);

return static_cast<ApplicationCoapSecure *>(aContext)->HandleDtlsAccept();
}

SecureSession *ApplicationCoapSecure::HandleDtlsAccept(void)
{
return IsSessionInUse() ? nullptr : static_cast<SecureSession *>(this);
}

#endif

} // namespace Coap
} // namespace ot

Expand Down
10 changes: 10 additions & 0 deletions src/core/coap/coap_secure.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ typedef MeshCoP::Dtls Dtls;
class SecureSession : public CoapBase, public Dtls::Session
{
public:
/**
* Dequeues and frees all queued messages (requests and responses) and stops all timers and tasklets.
*/
void Cleanup(void);

/**
* Sets the connection event callback.
*
Expand Down Expand Up @@ -148,8 +153,13 @@ class ApplicationCoapSecure : public Dtls::Transport, public Dtls::Transport::Ex
, Dtls::Transport::Extension(static_cast<Dtls::Transport &>(*this))
, SecureSession(aInstance, static_cast<Dtls::Transport &>(*this))
{
Dtls::Transport::SetAcceptCallback(HandleDtlsAccept, this);
Dtls::Transport::SetExtension(static_cast<Dtls::Transport::Extension &>(*this));
}

private:
static MeshCoP::SecureSession *HandleDtlsAccept(void *aContext, const Ip6::MessageInfo &aMessageInfo);
SecureSession *HandleDtlsAccept(void);
};

#endif // OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
Expand Down
74 changes: 63 additions & 11 deletions src/core/meshcop/border_agent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ BorderAgent::BorderAgent(Instance &aInstance)
, mUdpReceiver(BorderAgent::HandleUdpReceive, this)
, mTimer(aInstance)
, mDtlsTransport(aInstance, kNoLinkSecurity)
, mCoapDtlsSession(nullptr)
#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
, mIdInitialized(false)
#endif
Expand Down Expand Up @@ -129,16 +130,14 @@ Error BorderAgent::Start(uint16_t aUdpPort, const uint8_t *aPsk, uint8_t aPskLen
}
#endif

mCoapDtlsSession.Reset(CoapDtlsSession::Allocate(GetInstance(), mDtlsTransport));
VerifyOrExit(mCoapDtlsSession != nullptr, error = kErrorNoBufs);
mDtlsTransport.SetAcceptCallback(HandleAcceptSession, this);
mDtlsTransport.SetRemoveSessionCallback(HandleRemoveSession, this);

SuccessOrExit(error = mDtlsTransport.Open());
SuccessOrExit(error = mDtlsTransport.Bind(aUdpPort));

SuccessOrExit(error = mDtlsTransport.SetPsk(aPsk, aPskLength));

mCoapDtlsSession->SetConnectCallback(HandleConnected, this);

mState = kStateStarted;

LogInfo("Border Agent start listening on port %u", GetUdpPort());
Expand All @@ -163,7 +162,6 @@ void BorderAgent::Stop(void)

mTimer.Stop();
mDtlsTransport.Close();
mCoapDtlsSession.Free();

mState = kStateStopped;
LogInfo("Border Agent stopped");
Expand All @@ -175,6 +173,7 @@ void BorderAgent::Stop(void)
void BorderAgent::Disconnect(void)
{
VerifyOrExit(mState == kStateConnected || mState == kStateAccepted);
VerifyOrExit(mCoapDtlsSession != nullptr);

mCoapDtlsSession->Disconnect();

Expand Down Expand Up @@ -225,11 +224,51 @@ void BorderAgent::HandleNotifierEvents(Events aEvents)

void BorderAgent::HandleTimeout(void)
{
if (mCoapDtlsSession->IsConnected())
{
mCoapDtlsSession->Disconnect();
LogWarn("Reset secure session");
}
VerifyOrExit(mCoapDtlsSession != nullptr);
VerifyOrExit(mCoapDtlsSession->IsConnected());

mCoapDtlsSession->Disconnect();
LogWarn("Reset secure session");

exit:
return;
}

SecureSession *BorderAgent::HandleAcceptSession(void *aContext, const Ip6::MessageInfo &aMessageInfo)
{
OT_UNUSED_VARIABLE(aMessageInfo);

return static_cast<BorderAgent *>(aContext)->HandleAcceptSession();
}

BorderAgent::CoapDtlsSession *BorderAgent::HandleAcceptSession(void)
{
CoapDtlsSession *session = nullptr;

VerifyOrExit(mCoapDtlsSession == nullptr);

session = CoapDtlsSession::Allocate(GetInstance(), mDtlsTransport);
VerifyOrExit(session != nullptr);

session->SetConnectCallback(HandleConnected, this);
mCoapDtlsSession = session;

exit:
return session;
}

void BorderAgent::HandleRemoveSession(void *aContext, SecureSession &aSesssion)
{
static_cast<BorderAgent *>(aContext)->HandleRemoveSession(aSesssion);
}

void BorderAgent::HandleRemoveSession(SecureSession &aSesssion)
{
CoapDtlsSession &coapSession = static_cast<CoapDtlsSession &>(aSesssion);

coapSession.Cleanup();
coapSession.Free();
mCoapDtlsSession = nullptr;
}

void BorderAgent::HandleConnected(Dtls::Session::ConnectEvent aEvent, void *aContext)
Expand Down Expand Up @@ -315,6 +354,7 @@ Error BorderAgent::ForwardToLeader(const Coap::Message &aMessage, const Ip6::Mes
OffsetRange offsetRange;

VerifyOrExit(mState != kStateStopped);
VerifyOrExit(mCoapDtlsSession != nullptr);

switch (aUri)
{
Expand Down Expand Up @@ -389,6 +429,7 @@ void BorderAgent::HandleCoapResponse(const ForwardContext &aForwardContext,
Error error;

SuccessOrExit(error = aResult);
VerifyOrExit(mCoapDtlsSession != nullptr);
VerifyOrExit((message = mCoapDtlsSession->NewPriorityMessage()) != nullptr, error = kErrorNoBufs);

if (aForwardContext.IsPetition() && aResponse->GetCode() == Coap::kCodeChanged)
Expand Down Expand Up @@ -464,6 +505,7 @@ bool BorderAgent::HandleUdpReceive(const Message &aMessage, const Ip6::MessageIn
OffsetRange offsetRange;

VerifyOrExit(aMessageInfo.GetSockAddr() == mCommissionerAloc.GetAddress());
VerifyOrExit(mCoapDtlsSession != nullptr);

didHandle = true;

Expand Down Expand Up @@ -499,9 +541,11 @@ bool BorderAgent::HandleUdpReceive(const Message &aMessage, const Ip6::MessageIn

Error BorderAgent::ForwardToCommissioner(Coap::Message &aForwardMessage, const Message &aMessage)
{
Error error;
Error error = kErrorNone;
OffsetRange offsetRange;

VerifyOrExit(mCoapDtlsSession != nullptr);

offsetRange.InitFromMessageOffsetToEnd(aMessage);
SuccessOrExit(error = aForwardMessage.AppendBytesFromMessage(aMessage, offsetRange));

Expand All @@ -519,6 +563,8 @@ void BorderAgent::SendErrorMessage(const ForwardContext &aForwardContext, Error
Error error = kErrorNone;
Coap::Message *message = nullptr;

VerifyOrExit(mCoapDtlsSession != nullptr);

VerifyOrExit((message = mCoapDtlsSession->NewPriorityMessage()) != nullptr, error = kErrorNoBufs);
SuccessOrExit(error = aForwardContext.ToHeader(*message, CoapCodeFromError(aError)));
SuccessOrExit(error = mCoapDtlsSession->SendMessage(*message));
Expand All @@ -533,6 +579,8 @@ void BorderAgent::SendErrorMessage(const Coap::Message &aRequest, bool aSeparate
Error error = kErrorNone;
Coap::Message *message = nullptr;

VerifyOrExit(mCoapDtlsSession != nullptr);

VerifyOrExit((message = mCoapDtlsSession->NewPriorityMessage()) != nullptr, error = kErrorNoBufs);

if (aRequest.IsNonConfirmable() || aSeparate)
Expand Down Expand Up @@ -593,6 +641,8 @@ template <> void BorderAgent::HandleTmf<kUriRelayRx>(Coap::Message &aMessage, co

VerifyOrExit(aMessage.IsNonConfirmablePostRequest(), error = kErrorDrop);

VerifyOrExit(mCoapDtlsSession != nullptr);

message = mCoapDtlsSession->NewPriorityNonConfirmablePostMessage(kUriRelayRx);
VerifyOrExit(message != nullptr, error = kErrorNoBufs);

Expand Down Expand Up @@ -681,6 +731,8 @@ void BorderAgent::HandleTmfDatasetGet(Coap::Message &aMessage, const Ip6::Messag
Error error = kErrorNone;
Coap::Message *response = nullptr;

VerifyOrExit(mCoapDtlsSession != nullptr);

// When processing `MGMT_GET` request directly on Border Agent,
// the Security Policy flags (O-bit) should be ignored to allow
// the commissioner candidate to get the full Operational Dataset.
Expand Down
7 changes: 6 additions & 1 deletion src/core/meshcop/border_agent.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,11 @@ class BorderAgent : public InstanceLocator, private NonCopyable

template <Uri kUri> void HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);

static SecureSession *HandleAcceptSession(void *aContext, const Ip6::MessageInfo &aMessageInfo);
CoapDtlsSession *HandleAcceptSession(void);
static void HandleRemoveSession(void *aContext, SecureSession &aSesssion);
void HandleRemoveSession(SecureSession &aSesssion);

static void HandleConnected(Dtls::Session::ConnectEvent aEvent, void *aContext);
void HandleConnected(Dtls::Session::ConnectEvent aEvent);
static void HandleCoapResponse(void *aContext,
Expand Down Expand Up @@ -331,7 +336,7 @@ class BorderAgent : public InstanceLocator, private NonCopyable
Ip6::Netif::UnicastAddress mCommissionerAloc;
TimeoutTimer mTimer;
Dtls::Transport mDtlsTransport;
OwnedPtr<CoapDtlsSession> mCoapDtlsSession;
CoapDtlsSession *mCoapDtlsSession;
#if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
Id mId;
bool mIdInitialized;
Expand Down
Loading

0 comments on commit 2ae1ce5

Please sign in to comment.