| /* |
| * 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. |
| */ |
| |
| #include <stdarg.h> |
| #include <stdio.h> |
| #include <string.h> |
| |
| #include "platform/nexus_core.hpp" |
| #include "platform/nexus_node.hpp" |
| |
| namespace ot { |
| namespace Nexus { |
| |
| typedef MeshCoP::Dtls Dtls; |
| |
| static constexpr uint16_t kMaxNodes = 3; |
| static constexpr uint16_t kUdpPort = 1234; |
| static constexpr uint16_t kMessageSize = 100; |
| static constexpr uint16_t kMaxAttempts = 3; |
| |
| static const uint8_t kPsk[] = {0x10, 0x20, 0x03, 0x15, 0x10, 0x00, 0x60, 0x16}; |
| |
| static Dtls::Session::ConnectEvent sDtlsEvent[kMaxNodes]; |
| static Array<uint8_t, kMessageSize> sDtlsLastReceive[kMaxNodes]; |
| static bool sDtlsAutoClosed[kMaxNodes]; |
| static uint32_t sHeapSessionsAllocated = 0; |
| |
| const char *ConnectEventToString(Dtls::Session::ConnectEvent aEvent) |
| { |
| const char *str = ""; |
| |
| switch (aEvent) |
| { |
| case Dtls::Session::kConnected: |
| str = "kConnected"; |
| break; |
| case Dtls::Session::kDisconnectedPeerClosed: |
| str = "kDisconnectedPeerClosed"; |
| break; |
| case Dtls::Session::kDisconnectedLocalClosed: |
| str = "kDisconnectedLocalClosed"; |
| break; |
| case Dtls::Session::kDisconnectedMaxAttempts: |
| str = "kDisconnectedMaxAttempts"; |
| break; |
| case Dtls::Session::kDisconnectedError: |
| str = "kDisconnectedError"; |
| break; |
| case Dtls::Session::kDisconnectedTimeout: |
| str = "kDisconnectedTimeout"; |
| break; |
| } |
| |
| return str; |
| } |
| |
| void HandleReceive(void *aContext, uint8_t *aBuf, uint16_t aLength) |
| { |
| Node *node = static_cast<Node *>(aContext); |
| |
| VerifyOrQuit(node != nullptr); |
| VerifyOrQuit(node->GetId() < kMaxNodes); |
| |
| Log(" node%u: HandleReceive(aLength:%u)", node->GetId(), aLength); |
| |
| sDtlsLastReceive[node->GetId()].Clear(); |
| |
| for (; aLength > 0; aLength--, aBuf++) |
| { |
| SuccessOrQuit(sDtlsLastReceive[node->GetId()].PushBack(*aBuf)); |
| } |
| } |
| |
| void HandleConnectEvent(Dtls::Session::ConnectEvent aEvent, void *aContext) |
| { |
| Node *node = static_cast<Node *>(aContext); |
| |
| VerifyOrQuit(node != nullptr); |
| VerifyOrQuit(node->GetId() < kMaxNodes); |
| sDtlsEvent[node->GetId()] = aEvent; |
| |
| Log(" node%u: HandleConnectEvent(%s)", node->GetId(), ConnectEventToString(aEvent)); |
| } |
| |
| void HandleAutoClose(void *aContext) |
| { |
| Node *node = static_cast<Node *>(aContext); |
| |
| VerifyOrQuit(node != nullptr); |
| VerifyOrQuit(node->GetId() < kMaxNodes); |
| sDtlsAutoClosed[node->GetId()] = true; |
| |
| Log(" node%u: HandleAutoClose()", node->GetId()); |
| } |
| |
| OwnedPtr<Message> PrepareMessage(Node &aNode) |
| { |
| Message *message = aNode.Get<MessagePool>().Allocate(Message::kTypeOther); |
| uint16_t length; |
| |
| VerifyOrQuit(message != nullptr); |
| |
| length = Random::NonCrypto::GetUint16InRange(1, kMessageSize); |
| |
| for (uint16_t i = 0; i < length; i++) |
| { |
| SuccessOrQuit(message->Append(Random::NonCrypto::GetUint8())); |
| } |
| |
| return OwnedPtr<Message>(message); |
| } |
| |
| class DtlsTransportAndSingleSession : public InstanceLocator, public Dtls::Transport, public Dtls::Session |
| { |
| // A DTLS transport and single session |
| public: |
| explicit DtlsTransportAndSingleSession(Node &aNode) |
| : InstanceLocator(aNode.GetInstance()) |
| , Dtls::Transport(aNode.GetInstance(), kWithLinkSecurity) |
| , Dtls::Session(static_cast<Dtls::Transport &>(*this)) |
| , mNode(aNode) |
| { |
| SetAcceptCallback(HandleAccept, this); |
| |
| VerifyOrQuit(!IsSessionInUse()); |
| } |
| |
| private: |
| static MeshCoP::SecureSession *HandleAccept(void *aContext, const Ip6::MessageInfo &aMessageInfo) |
| { |
| OT_UNUSED_VARIABLE(aMessageInfo); |
| |
| return static_cast<DtlsTransportAndSingleSession *>(aContext)->HandleAccept(); |
| } |
| |
| Dtls::Session *HandleAccept(void) |
| { |
| Dtls::Session *session = IsSessionInUse() ? nullptr : static_cast<Dtls::Session *>(this); |
| |
| Log(" node%u: HandleAccept(), %s", mNode.GetId(), (session != nullptr) ? "accepted" : "rejected"); |
| return session; |
| } |
| |
| Node &mNode; |
| }; |
| |
| class DtlsTransportAndHeapSession : public InstanceLocator, public Dtls::Transport |
| { |
| // A DTLS session with heap allocated sessions. |
| |
| public: |
| explicit DtlsTransportAndHeapSession(Node &aNode) |
| : InstanceLocator(aNode.GetInstance()) |
| , Dtls::Transport(aNode.GetInstance(), kWithLinkSecurity) |
| , mNode(aNode) |
| { |
| SetAcceptCallback(HandleAccept, this); |
| SetRemoveSessionCallback(HandleRemoveSession, this); |
| } |
| |
| private: |
| class HeapDtlsSession : public Dtls::Session, public Heap::Allocatable<HeapDtlsSession> |
| { |
| friend Heap::Allocatable<HeapDtlsSession>; |
| |
| private: |
| HeapDtlsSession(Dtls::Transport &aTransport) |
| : Dtls::Session(aTransport) |
| { |
| sHeapSessionsAllocated++; |
| } |
| }; |
| |
| static MeshCoP::SecureSession *HandleAccept(void *aContext, const Ip6::MessageInfo &aMessageInfo) |
| { |
| OT_UNUSED_VARIABLE(aMessageInfo); |
| |
| DtlsTransportAndHeapSession *transport; |
| HeapDtlsSession *session; |
| |
| VerifyOrQuit(aContext != nullptr); |
| transport = static_cast<DtlsTransportAndHeapSession *>(aContext); |
| |
| Log(" node%u: HandleAccept()", transport->mNode.GetId()); |
| |
| session = HeapDtlsSession::Allocate(*transport); |
| VerifyOrQuit(session != nullptr); |
| |
| session->SetReceiveCallback(&ot::Nexus::HandleReceive, &transport->mNode); |
| session->SetConnectCallback(&ot::Nexus::HandleConnectEvent, &transport->mNode); |
| |
| return session; |
| } |
| |
| static void HandleRemoveSession(void *aContext, MeshCoP::SecureSession &aSesssion) |
| { |
| DtlsTransportAndHeapSession *transport; |
| |
| VerifyOrQuit(aContext != nullptr); |
| transport = static_cast<DtlsTransportAndHeapSession *>(aContext); |
| |
| Log(" node%u: HandleRemoveSession()", transport->mNode.GetId()); |
| |
| VerifyOrQuit(sHeapSessionsAllocated > 0); |
| |
| static_cast<HeapDtlsSession &>(aSesssion).Free(); |
| sHeapSessionsAllocated--; |
| } |
| |
| private: |
| Node &mNode; |
| }; |
| |
| void TestDtlsSingleSession(void) |
| { |
| Core nexus; |
| Node &node0 = nexus.CreateNode(); |
| Node &node1 = nexus.CreateNode(); |
| Node &node2 = nexus.CreateNode(); |
| |
| Log("------------------------------------------------------------------------------------------------------"); |
| Log("TestDtlsSingleSession"); |
| |
| nexus.AdvanceTime(0); |
| |
| // Form the topology: node0 leader, with node1 & node2 as its FTD children |
| |
| node0.Form(); |
| nexus.AdvanceTime(50 * Time::kOneSecondInMsec); |
| VerifyOrQuit(node0.Get<Mle::Mle>().IsLeader()); |
| |
| node1.Join(node0, Node::kAsFed); |
| nexus.AdvanceTime(20 * Time::kOneSecondInMsec); |
| VerifyOrQuit(node1.Get<Mle::Mle>().IsChild()); |
| |
| node2.Join(node0, Node::kAsFed); |
| nexus.AdvanceTime(20 * Time::kOneSecondInMsec); |
| VerifyOrQuit(node2.Get<Mle::Mle>().IsChild()); |
| |
| { |
| DtlsTransportAndSingleSession dtls0(node0); |
| DtlsTransportAndSingleSession dtls1(node1); |
| DtlsTransportAndSingleSession dtls2(node2); |
| Ip6::SockAddr sockAddr; |
| |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| Log("Start DTLS (server) on node0 bound to port %u", kUdpPort); |
| |
| SuccessOrQuit(dtls0.SetPsk(kPsk, sizeof(kPsk))); |
| dtls0.SetReceiveCallback(HandleReceive, &node0); |
| dtls0.SetConnectCallback(HandleConnectEvent, &node0); |
| SuccessOrQuit(dtls0.Open()); |
| SuccessOrQuit(dtls0.Bind(kUdpPort)); |
| |
| nexus.AdvanceTime(1 * Time::kOneSecondInMsec); |
| |
| VerifyOrQuit(dtls0.GetUdpPort() == kUdpPort); |
| VerifyOrQuit(!dtls0.IsConnectionActive()); |
| |
| sockAddr.SetAddress(node0.Get<Mle::Mle>().GetMeshLocalRloc()); |
| sockAddr.SetPort(kUdpPort); |
| |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| Log("Try to establish a DTLS connection from node 1 using a wrong PSK multiple times"); |
| |
| SuccessOrQuit(dtls1.SetPsk(kPsk, sizeof(kPsk) - 1)); |
| dtls1.SetReceiveCallback(HandleReceive, &node1); |
| dtls1.SetConnectCallback(HandleConnectEvent, &node1); |
| SuccessOrQuit(dtls1.Open()); |
| |
| for (uint16_t iter = 0; iter <= kMaxAttempts + 1; iter++) |
| { |
| memset(sDtlsEvent, Dtls::Session::kConnected, sizeof(sDtlsEvent)); |
| |
| SuccessOrQuit(dtls1.Connect(sockAddr)); |
| nexus.AdvanceTime(3 * Time::kOneSecondInMsec); |
| |
| VerifyOrQuit(!dtls0.IsConnected()); |
| VerifyOrQuit(!dtls1.IsConnected()); |
| |
| VerifyOrQuit(sDtlsEvent[node0.GetId()] == Dtls::Session::kDisconnectedError); |
| VerifyOrQuit(sDtlsEvent[node1.GetId()] == Dtls::Session::kDisconnectedError); |
| } |
| |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| Log("Establish a DTLS connection from node1 with node0 using the correct PSK"); |
| |
| dtls1.Close(); |
| |
| SuccessOrQuit(dtls1.SetPsk(kPsk, sizeof(kPsk))); |
| dtls1.SetReceiveCallback(HandleReceive, &node1); |
| dtls1.SetConnectCallback(HandleConnectEvent, &node1); |
| SuccessOrQuit(dtls1.Open()); |
| SuccessOrQuit(dtls1.Connect(sockAddr)); |
| |
| nexus.AdvanceTime(1 * Time::kOneSecondInMsec); |
| |
| VerifyOrQuit(dtls0.IsConnected()); |
| VerifyOrQuit(dtls1.IsConnected()); |
| |
| VerifyOrQuit(sDtlsEvent[node0.GetId()] == Dtls::Session::kConnected); |
| VerifyOrQuit(sDtlsEvent[node1.GetId()] == Dtls::Session::kConnected); |
| |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| Log("Send message (random data and length) over DTLS session from node0 to node1"); |
| |
| for (uint16_t iter = 0; iter < 20; iter++) |
| { |
| OwnedPtr<Message> msg(PrepareMessage(node0)); |
| |
| SuccessOrQuit(dtls0.Send(*msg->Clone<kNoReservedHeader>())); |
| nexus.AdvanceTime(100); |
| |
| VerifyOrQuit(sDtlsLastReceive[node1.GetId()].GetLength() == msg->GetLength()); |
| VerifyOrQuit(msg->CompareBytes(0, sDtlsLastReceive[node1.GetId()].GetArrayBuffer(), msg->GetLength())); |
| } |
| |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| Log("Now send from node1 to node0"); |
| |
| for (uint16_t iter = 0; iter < 20; iter++) |
| { |
| OwnedPtr<Message> msg(PrepareMessage(node1)); |
| |
| SuccessOrQuit(dtls1.Send(*msg->Clone<kNoReservedHeader>())); |
| nexus.AdvanceTime(100); |
| |
| VerifyOrQuit(sDtlsLastReceive[node0.GetId()].GetLength() == msg->GetLength()); |
| VerifyOrQuit(msg->CompareBytes(0, sDtlsLastReceive[node0.GetId()].GetArrayBuffer(), msg->GetLength())); |
| } |
| |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| Log("Disconnect from node1 - validate the disconnect events (local/peer)"); |
| |
| dtls1.Disconnect(); |
| |
| nexus.AdvanceTime(3 * Time::kOneSecondInMsec); |
| |
| VerifyOrQuit(!dtls0.IsConnected()); |
| VerifyOrQuit(!dtls1.IsConnected()); |
| |
| VerifyOrQuit(sDtlsEvent[node0.GetId()] == Dtls::Session::kDisconnectedPeerClosed); |
| VerifyOrQuit(sDtlsEvent[node1.GetId()] == Dtls::Session::kDisconnectedLocalClosed); |
| |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| Log("Establish a DTLS connection again"); |
| |
| SuccessOrQuit(dtls1.Connect(sockAddr)); |
| |
| nexus.AdvanceTime(1 * Time::kOneSecondInMsec); |
| |
| VerifyOrQuit(dtls0.IsConnected()); |
| VerifyOrQuit(dtls1.IsConnected()); |
| |
| VerifyOrQuit(sDtlsEvent[node0.GetId()] == Dtls::Session::kConnected); |
| VerifyOrQuit(sDtlsEvent[node1.GetId()] == Dtls::Session::kConnected); |
| |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| Log("Try to connect from node2 - validate that it fails to connect since already connected"); |
| |
| SuccessOrQuit(dtls2.SetPsk(kPsk, sizeof(kPsk))); |
| dtls2.SetReceiveCallback(HandleReceive, &node2); |
| dtls2.SetReceiveCallback(HandleReceive, &node2); |
| SuccessOrQuit(dtls2.Open()); |
| SuccessOrQuit(dtls2.Connect(sockAddr)); |
| |
| nexus.AdvanceTime(20 * Time::kOneSecondInMsec); |
| |
| VerifyOrQuit(dtls0.IsConnected()); |
| VerifyOrQuit(dtls1.IsConnected()); |
| VerifyOrQuit(!dtls2.IsConnected()); |
| |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| Log("Disconnect from node0 - validate the disconnect events"); |
| |
| dtls0.Disconnect(); |
| |
| nexus.AdvanceTime(3 * Time::kOneSecondInMsec); |
| |
| VerifyOrQuit(!dtls0.IsConnected()); |
| VerifyOrQuit(!dtls1.IsConnected()); |
| VerifyOrQuit(!dtls2.IsConnected()); |
| |
| VerifyOrQuit(sDtlsEvent[node0.GetId()] == Dtls::Session::kDisconnectedLocalClosed); |
| VerifyOrQuit(sDtlsEvent[node1.GetId()] == Dtls::Session::kDisconnectedPeerClosed); |
| |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| |
| dtls0.Close(); |
| dtls1.Close(); |
| dtls2.Close(); |
| |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| |
| Log("Start DTLS (server) on node0 bound to port %u with auto-close max attempt %u", kUdpPort, kMaxAttempts); |
| |
| memset(sDtlsAutoClosed, false, sizeof(sDtlsAutoClosed)); |
| |
| SuccessOrQuit(dtls0.SetMaxConnectionAttempts(kMaxAttempts, HandleAutoClose, &node0)); |
| SuccessOrQuit(dtls0.SetPsk(kPsk, sizeof(kPsk))); |
| dtls0.SetReceiveCallback(HandleReceive, &node0); |
| dtls0.SetConnectCallback(HandleConnectEvent, &node0); |
| SuccessOrQuit(dtls0.Open()); |
| SuccessOrQuit(dtls0.Bind(kUdpPort)); |
| |
| nexus.AdvanceTime(1 * Time::kOneSecondInMsec); |
| |
| VerifyOrQuit(dtls0.GetUdpPort() == kUdpPort); |
| VerifyOrQuit(!dtls0.IsConnectionActive()); |
| |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| Log("Using wrong PSK try to establish DTLS connection with node0 %u times", kMaxAttempts - 1); |
| |
| SuccessOrQuit(dtls1.SetPsk(kPsk, sizeof(kPsk) - 1)); |
| dtls1.SetReceiveCallback(HandleReceive, &node1); |
| dtls1.SetConnectCallback(HandleConnectEvent, &node1); |
| SuccessOrQuit(dtls1.Open()); |
| |
| for (uint16_t iter = 0; iter < kMaxAttempts - 1; iter++) |
| { |
| memset(sDtlsEvent, Dtls::Session::kConnected, sizeof(sDtlsEvent)); |
| |
| SuccessOrQuit(dtls1.Connect(sockAddr)); |
| nexus.AdvanceTime(3 * Time::kOneSecondInMsec); |
| |
| VerifyOrQuit(!dtls0.IsConnected()); |
| VerifyOrQuit(!dtls1.IsConnected()); |
| |
| VerifyOrQuit(sDtlsEvent[node0.GetId()] == Dtls::Session::kDisconnectedError); |
| VerifyOrQuit(sDtlsEvent[node1.GetId()] == Dtls::Session::kDisconnectedError); |
| } |
| |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| Log("Using wrong PSK try one last time, validate the auto-close behavior"); |
| |
| memset(sDtlsEvent, Dtls::Session::kConnected, sizeof(sDtlsEvent)); |
| |
| SuccessOrQuit(dtls1.Connect(sockAddr)); |
| nexus.AdvanceTime(3 * Time::kOneSecondInMsec); |
| |
| VerifyOrQuit(sDtlsEvent[node0.GetId()] == Dtls::Session::kDisconnectedError); |
| VerifyOrQuit(sDtlsEvent[node1.GetId()] == Dtls::Session::kDisconnectedError); |
| |
| VerifyOrQuit(sDtlsAutoClosed[node0.GetId()]); |
| |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| |
| dtls0.Close(); |
| dtls1.Close(); |
| dtls2.Close(); |
| } |
| } |
| |
| void TestDtlsMultiSession(void) |
| { |
| Core nexus; |
| Node &node0 = nexus.CreateNode(); |
| Node &node1 = nexus.CreateNode(); |
| Node &node2 = nexus.CreateNode(); |
| |
| Log("------------------------------------------------------------------------------------------------------"); |
| Log("TestDtlsMultiSession"); |
| |
| nexus.AdvanceTime(0); |
| |
| // Form the topology: node0 leader, with node1 & node2 as its FTD children |
| |
| node0.Form(); |
| nexus.AdvanceTime(50 * Time::kOneSecondInMsec); |
| VerifyOrQuit(node0.Get<Mle::Mle>().IsLeader()); |
| |
| node1.Join(node0, Node::kAsFed); |
| nexus.AdvanceTime(20 * Time::kOneSecondInMsec); |
| VerifyOrQuit(node1.Get<Mle::Mle>().IsChild()); |
| |
| node2.Join(node0, Node::kAsFed); |
| nexus.AdvanceTime(20 * Time::kOneSecondInMsec); |
| VerifyOrQuit(node2.Get<Mle::Mle>().IsChild()); |
| |
| { |
| DtlsTransportAndHeapSession dtls0(node0); |
| DtlsTransportAndSingleSession dtls1(node1); |
| DtlsTransportAndSingleSession dtls2(node2); |
| Ip6::SockAddr sockAddr; |
| uint16_t numSessions; |
| |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| Log("Start DTLS (server) on node0 bound to port %u", kUdpPort); |
| |
| SuccessOrQuit(dtls0.SetPsk(kPsk, sizeof(kPsk))); |
| SuccessOrQuit(dtls0.Open()); |
| SuccessOrQuit(dtls0.Bind(kUdpPort)); |
| |
| nexus.AdvanceTime(1 * Time::kOneSecondInMsec); |
| |
| VerifyOrQuit(dtls0.GetUdpPort() == kUdpPort); |
| |
| sockAddr.SetAddress(node0.Get<Mle::Mle>().GetMeshLocalRloc()); |
| sockAddr.SetPort(kUdpPort); |
| |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| Log("Establish a DTLS connection with node 0 from node1"); |
| |
| memset(sDtlsEvent, Dtls::Session::kDisconnectedError, sizeof(sDtlsEvent)); |
| |
| SuccessOrQuit(dtls1.SetPsk(kPsk, sizeof(kPsk))); |
| dtls1.SetReceiveCallback(HandleReceive, &node1); |
| dtls1.SetConnectCallback(HandleConnectEvent, &node1); |
| SuccessOrQuit(dtls1.Open()); |
| SuccessOrQuit(dtls1.Connect(sockAddr)); |
| |
| nexus.AdvanceTime(1 * Time::kOneSecondInMsec); |
| |
| VerifyOrQuit(dtls1.IsConnected()); |
| |
| VerifyOrQuit(sDtlsEvent[node0.GetId()] == Dtls::Session::kConnected); |
| VerifyOrQuit(sDtlsEvent[node1.GetId()] == Dtls::Session::kConnected); |
| |
| numSessions = 0; |
| |
| for (MeshCoP::SecureSession &session : dtls0.GetSessions()) |
| { |
| VerifyOrQuit(session.IsConnected()); |
| numSessions++; |
| } |
| |
| VerifyOrQuit(numSessions == 1); |
| VerifyOrQuit(sHeapSessionsAllocated == 1); |
| |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| Log("Establish a second DTLS connection with node0 from node2"); |
| |
| memset(sDtlsEvent, Dtls::Session::kDisconnectedError, sizeof(sDtlsEvent)); |
| |
| SuccessOrQuit(dtls2.SetPsk(kPsk, sizeof(kPsk))); |
| dtls2.SetReceiveCallback(HandleReceive, &node2); |
| dtls2.SetConnectCallback(HandleConnectEvent, &node2); |
| SuccessOrQuit(dtls2.Open()); |
| SuccessOrQuit(dtls2.Connect(sockAddr)); |
| |
| nexus.AdvanceTime(1 * Time::kOneSecondInMsec); |
| |
| VerifyOrQuit(dtls2.IsConnected()); |
| |
| VerifyOrQuit(sDtlsEvent[node0.GetId()] == Dtls::Session::kConnected); |
| VerifyOrQuit(sDtlsEvent[node2.GetId()] == Dtls::Session::kConnected); |
| |
| numSessions = 0; |
| |
| for (MeshCoP::SecureSession &session : dtls0.GetSessions()) |
| { |
| VerifyOrQuit(session.IsConnected()); |
| numSessions++; |
| } |
| |
| VerifyOrQuit(numSessions == 2); |
| VerifyOrQuit(sHeapSessionsAllocated == 2); |
| |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| Log("Disconnect from node1 - validate the disconnect events"); |
| |
| dtls1.Disconnect(); |
| |
| nexus.AdvanceTime(3 * Time::kOneSecondInMsec); |
| |
| VerifyOrQuit(!dtls1.IsConnected()); |
| |
| VerifyOrQuit(sDtlsEvent[node0.GetId()] == Dtls::Session::kDisconnectedPeerClosed); |
| VerifyOrQuit(sDtlsEvent[node1.GetId()] == Dtls::Session::kDisconnectedLocalClosed); |
| |
| numSessions = 0; |
| |
| for (MeshCoP::SecureSession &session : dtls0.GetSessions()) |
| { |
| VerifyOrQuit(session.IsConnected()); |
| numSessions++; |
| } |
| |
| VerifyOrQuit(numSessions == 1); |
| VerifyOrQuit(sHeapSessionsAllocated == 1); |
| |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| Log("Disconnect session with node2 from node0 (server) - validate the disconnect events"); |
| |
| memset(sDtlsEvent, Dtls::Session::kConnected, sizeof(sDtlsEvent)); |
| |
| dtls0.GetSessions().GetHead()->Disconnect(); |
| |
| nexus.AdvanceTime(3 * Time::kOneSecondInMsec); |
| |
| VerifyOrQuit(!dtls2.IsConnected()); |
| |
| VerifyOrQuit(sDtlsEvent[node0.GetId()] == Dtls::Session::kDisconnectedLocalClosed); |
| VerifyOrQuit(sDtlsEvent[node2.GetId()] == Dtls::Session::kDisconnectedPeerClosed); |
| |
| VerifyOrQuit(dtls0.GetSessions().IsEmpty()); |
| VerifyOrQuit(sHeapSessionsAllocated == 0); |
| |
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| Log("Establish two DTLS connections from node1 and node2 at the same time"); |
| |
| memset(sDtlsEvent, Dtls::Session::kDisconnectedError, sizeof(sDtlsEvent)); |
| |
| SuccessOrQuit(dtls1.Connect(sockAddr)); |
| SuccessOrQuit(dtls2.Connect(sockAddr)); |
| |
| nexus.AdvanceTime(1 * Time::kOneSecondInMsec); |
| |
| VerifyOrQuit(dtls1.IsConnected()); |
| VerifyOrQuit(dtls2.IsConnected()); |
| |
| VerifyOrQuit(sDtlsEvent[node0.GetId()] == Dtls::Session::kConnected); |
| VerifyOrQuit(sDtlsEvent[node1.GetId()] == Dtls::Session::kConnected); |
| VerifyOrQuit(sDtlsEvent[node2.GetId()] == Dtls::Session::kConnected); |
| |
| numSessions = 0; |
| |
| for (MeshCoP::SecureSession &session : dtls0.GetSessions()) |
| { |
| VerifyOrQuit(session.IsConnected()); |
| numSessions++; |
| } |
| |
| VerifyOrQuit(numSessions == 2); |
| VerifyOrQuit(sHeapSessionsAllocated == 2); |
| } |
| } |
| |
| } // namespace Nexus |
| } // namespace ot |
| |
| int main(void) |
| { |
| ot::Nexus::TestDtlsSingleSession(); |
| ot::Nexus::TestDtlsMultiSession(); |
| printf("All tests passed\n"); |
| return 0; |
| } |