1 /*
2  *  Copyright (c) 2024, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <string.h>
32 
33 #include "platform/nexus_core.hpp"
34 #include "platform/nexus_node.hpp"
35 
36 namespace ot {
37 namespace Nexus {
38 
39 typedef MeshCoP::Dtls Dtls;
40 
41 static constexpr uint16_t kMaxNodes    = 3;
42 static constexpr uint16_t kUdpPort     = 1234;
43 static constexpr uint16_t kMessageSize = 100;
44 static constexpr uint16_t kMaxAttempts = 3;
45 
46 static const uint8_t kPsk[] = {0x10, 0x20, 0x03, 0x15, 0x10, 0x00, 0x60, 0x16};
47 
48 static Dtls::Session::ConnectEvent  sDtlsEvent[kMaxNodes];
49 static Array<uint8_t, kMessageSize> sDtlsLastReceive[kMaxNodes];
50 static bool                         sDtlsAutoClosed[kMaxNodes];
51 static uint32_t                     sHeapSessionsAllocated = 0;
52 
ConnectEventToString(Dtls::Session::ConnectEvent aEvent)53 const char *ConnectEventToString(Dtls::Session::ConnectEvent aEvent)
54 {
55     const char *str = "";
56 
57     switch (aEvent)
58     {
59     case Dtls::Session::kConnected:
60         str = "kConnected";
61         break;
62     case Dtls::Session::kDisconnectedPeerClosed:
63         str = "kDisconnectedPeerClosed";
64         break;
65     case Dtls::Session::kDisconnectedLocalClosed:
66         str = "kDisconnectedLocalClosed";
67         break;
68     case Dtls::Session::kDisconnectedMaxAttempts:
69         str = "kDisconnectedMaxAttempts";
70         break;
71     case Dtls::Session::kDisconnectedError:
72         str = "kDisconnectedError";
73         break;
74     }
75 
76     return str;
77 }
78 
HandleReceive(void * aContext,uint8_t * aBuf,uint16_t aLength)79 void HandleReceive(void *aContext, uint8_t *aBuf, uint16_t aLength)
80 {
81     Node *node = static_cast<Node *>(aContext);
82 
83     VerifyOrQuit(node != nullptr);
84     VerifyOrQuit(node->GetId() < kMaxNodes);
85 
86     Log("   node%u: HandleReceive(aLength:%u)", node->GetId(), aLength);
87 
88     sDtlsLastReceive[node->GetId()].Clear();
89 
90     for (; aLength > 0; aLength--, aBuf++)
91     {
92         SuccessOrQuit(sDtlsLastReceive[node->GetId()].PushBack(*aBuf));
93     }
94 }
95 
HandleConnectEvent(Dtls::Session::ConnectEvent aEvent,void * aContext)96 void HandleConnectEvent(Dtls::Session::ConnectEvent aEvent, void *aContext)
97 {
98     Node *node = static_cast<Node *>(aContext);
99 
100     VerifyOrQuit(node != nullptr);
101     VerifyOrQuit(node->GetId() < kMaxNodes);
102     sDtlsEvent[node->GetId()] = aEvent;
103 
104     Log("   node%u: HandleConnectEvent(%s)", node->GetId(), ConnectEventToString(aEvent));
105 }
106 
HandleAutoClose(void * aContext)107 void HandleAutoClose(void *aContext)
108 {
109     Node *node = static_cast<Node *>(aContext);
110 
111     VerifyOrQuit(node != nullptr);
112     VerifyOrQuit(node->GetId() < kMaxNodes);
113     sDtlsAutoClosed[node->GetId()] = true;
114 
115     Log("   node%u: HandleAutoClose()", node->GetId());
116 }
117 
PrepareMessage(Node & aNode)118 OwnedPtr<Message> PrepareMessage(Node &aNode)
119 {
120     Message *message = aNode.Get<MessagePool>().Allocate(Message::kTypeOther);
121     uint16_t length;
122 
123     VerifyOrQuit(message != nullptr);
124 
125     length = Random::NonCrypto::GetUint16InRange(1, kMessageSize);
126 
127     for (uint16_t i = 0; i < length; i++)
128     {
129         SuccessOrQuit(message->Append(Random::NonCrypto::GetUint8()));
130     }
131 
132     return OwnedPtr<Message>(message);
133 }
134 
135 class DtlsTransportAndSingleSession : public InstanceLocator, public Dtls::Transport, public Dtls::Session
136 {
137     // A DTLS transport and single session
138 public:
DtlsTransportAndSingleSession(Node & aNode)139     explicit DtlsTransportAndSingleSession(Node &aNode)
140         : InstanceLocator(aNode.GetInstance())
141         , Dtls::Transport(aNode.GetInstance(), kWithLinkSecurity)
142         , Dtls::Session(static_cast<Dtls::Transport &>(*this))
143         , mNode(aNode)
144     {
145         SetAcceptCallback(HandleAccept, this);
146 
147         VerifyOrQuit(!IsSessionInUse());
148     }
149 
150 private:
HandleAccept(void * aContext,const Ip6::MessageInfo & aMessageInfo)151     static MeshCoP::SecureSession *HandleAccept(void *aContext, const Ip6::MessageInfo &aMessageInfo)
152     {
153         return static_cast<DtlsTransportAndSingleSession *>(aContext)->HandleAccept();
154     }
155 
HandleAccept(void)156     Dtls::Session *HandleAccept(void)
157     {
158         Dtls::Session *session = IsSessionInUse() ? nullptr : static_cast<Dtls::Session *>(this);
159 
160         Log("   node%u: HandleAccept(), %s", mNode.GetId(), (session != nullptr) ? "accepted" : "rejected");
161         return session;
162     }
163 
164     Node &mNode;
165 };
166 
167 class DtlsTransportAndHeapSession : public InstanceLocator, public Dtls::Transport
168 {
169     // A DTLS session with heap allocated sessions.
170 
171 public:
DtlsTransportAndHeapSession(Node & aNode)172     explicit DtlsTransportAndHeapSession(Node &aNode)
173         : InstanceLocator(aNode.GetInstance())
174         , Dtls::Transport(aNode.GetInstance(), kWithLinkSecurity)
175         , mNode(aNode)
176     {
177         SetAcceptCallback(HandleAccept, this);
178         SetRemoveSessionCallback(HandleRemoveSession, this);
179     }
180 
181 private:
182     class HeapDtlsSession : public Dtls::Session, public Heap::Allocatable<HeapDtlsSession>
183     {
184         friend Heap::Allocatable<HeapDtlsSession>;
185 
186     private:
HeapDtlsSession(Dtls::Transport & aTransport)187         HeapDtlsSession(Dtls::Transport &aTransport)
188             : Dtls::Session(aTransport)
189         {
190             sHeapSessionsAllocated++;
191         }
192     };
193 
HandleAccept(void * aContext,const Ip6::MessageInfo & aMessageInfo)194     static MeshCoP::SecureSession *HandleAccept(void *aContext, const Ip6::MessageInfo &aMessageInfo)
195     {
196         DtlsTransportAndHeapSession *transport;
197         HeapDtlsSession             *session;
198 
199         VerifyOrQuit(aContext != nullptr);
200         transport = static_cast<DtlsTransportAndHeapSession *>(aContext);
201 
202         Log("   node%u: HandleAccept()", transport->mNode.GetId());
203 
204         session = HeapDtlsSession::Allocate(*transport);
205         VerifyOrQuit(session != nullptr);
206 
207         session->SetReceiveCallback(&ot::Nexus::HandleReceive, &transport->mNode);
208         session->SetConnectCallback(&ot::Nexus::HandleConnectEvent, &transport->mNode);
209 
210         return session;
211     }
212 
HandleRemoveSession(void * aContext,MeshCoP::SecureSession & aSesssion)213     static void HandleRemoveSession(void *aContext, MeshCoP::SecureSession &aSesssion)
214     {
215         DtlsTransportAndHeapSession *transport;
216 
217         VerifyOrQuit(aContext != nullptr);
218         transport = static_cast<DtlsTransportAndHeapSession *>(aContext);
219 
220         Log("   node%u: HandleRemoveSession()", transport->mNode.GetId());
221 
222         VerifyOrQuit(sHeapSessionsAllocated > 0);
223 
224         static_cast<HeapDtlsSession &>(aSesssion).Free();
225         sHeapSessionsAllocated--;
226     }
227 
228 private:
229     Node &mNode;
230 };
231 
TestDtlsSingleSession(void)232 void TestDtlsSingleSession(void)
233 {
234     Core  nexus;
235     Node &node0 = nexus.CreateNode();
236     Node &node1 = nexus.CreateNode();
237     Node &node2 = nexus.CreateNode();
238 
239     Log("------------------------------------------------------------------------------------------------------");
240     Log("TestDtlsSingleSession");
241 
242     nexus.AdvanceTime(0);
243 
244     // Form the topology: node0 leader, with node1 & node2 as its FTD children
245 
246     node0.Form();
247     nexus.AdvanceTime(50 * Time::kOneSecondInMsec);
248     VerifyOrQuit(node0.Get<Mle::Mle>().IsLeader());
249 
250     SuccessOrQuit(node1.Get<Mle::MleRouter>().SetRouterEligible(false));
251     node1.Join(node0);
252     nexus.AdvanceTime(20 * Time::kOneSecondInMsec);
253     VerifyOrQuit(node1.Get<Mle::Mle>().IsChild());
254 
255     SuccessOrQuit(node2.Get<Mle::MleRouter>().SetRouterEligible(false));
256     node2.Join(node0);
257     nexus.AdvanceTime(20 * Time::kOneSecondInMsec);
258     VerifyOrQuit(node2.Get<Mle::Mle>().IsChild());
259 
260     {
261         DtlsTransportAndSingleSession dtls0(node0);
262         DtlsTransportAndSingleSession dtls1(node1);
263         DtlsTransportAndSingleSession dtls2(node2);
264         Ip6::SockAddr                 sockAddr;
265 
266         // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
267         Log("Start DTLS (server) on node0 bound to port %u", kUdpPort);
268 
269         SuccessOrQuit(dtls0.SetPsk(kPsk, sizeof(kPsk)));
270         dtls0.SetReceiveCallback(HandleReceive, &node0);
271         dtls0.SetConnectCallback(HandleConnectEvent, &node0);
272         SuccessOrQuit(dtls0.Open());
273         SuccessOrQuit(dtls0.Bind(kUdpPort));
274 
275         nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
276 
277         VerifyOrQuit(dtls0.GetUdpPort() == kUdpPort);
278         VerifyOrQuit(!dtls0.IsConnectionActive());
279 
280         sockAddr.SetAddress(node0.Get<Mle::Mle>().GetMeshLocalRloc());
281         sockAddr.SetPort(kUdpPort);
282 
283         // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
284         Log("Try to establish a DTLS connection from node 1 using a wrong PSK multiple times");
285 
286         SuccessOrQuit(dtls1.SetPsk(kPsk, sizeof(kPsk) - 1));
287         dtls1.SetReceiveCallback(HandleReceive, &node1);
288         dtls1.SetConnectCallback(HandleConnectEvent, &node1);
289         SuccessOrQuit(dtls1.Open());
290 
291         for (uint16_t iter = 0; iter <= kMaxAttempts + 1; iter++)
292         {
293             memset(sDtlsEvent, Dtls::Session::kConnected, sizeof(sDtlsEvent));
294 
295             SuccessOrQuit(dtls1.Connect(sockAddr));
296             nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
297 
298             VerifyOrQuit(!dtls0.IsConnected());
299             VerifyOrQuit(!dtls1.IsConnected());
300 
301             VerifyOrQuit(sDtlsEvent[node0.GetId()] == Dtls::Session::kDisconnectedError);
302             VerifyOrQuit(sDtlsEvent[node1.GetId()] == Dtls::Session::kDisconnectedError);
303         }
304 
305         // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
306         Log("Establish a DTLS connection from node1 with node0 using the correct PSK");
307 
308         dtls1.Close();
309 
310         SuccessOrQuit(dtls1.SetPsk(kPsk, sizeof(kPsk)));
311         dtls1.SetReceiveCallback(HandleReceive, &node1);
312         dtls1.SetConnectCallback(HandleConnectEvent, &node1);
313         SuccessOrQuit(dtls1.Open());
314         SuccessOrQuit(dtls1.Connect(sockAddr));
315 
316         nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
317 
318         VerifyOrQuit(dtls0.IsConnected());
319         VerifyOrQuit(dtls1.IsConnected());
320 
321         VerifyOrQuit(sDtlsEvent[node0.GetId()] == Dtls::Session::kConnected);
322         VerifyOrQuit(sDtlsEvent[node1.GetId()] == Dtls::Session::kConnected);
323 
324         // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
325         Log("Send message (random data and length) over DTLS session from node0 to node1");
326 
327         for (uint16_t iter = 0; iter < 20; iter++)
328         {
329             OwnedPtr<Message> msg(PrepareMessage(node0));
330 
331             SuccessOrQuit(dtls0.Send(*msg->Clone()));
332             nexus.AdvanceTime(100);
333 
334             VerifyOrQuit(sDtlsLastReceive[node1.GetId()].GetLength() == msg->GetLength());
335             VerifyOrQuit(msg->CompareBytes(0, sDtlsLastReceive[node1.GetId()].GetArrayBuffer(), msg->GetLength()));
336         }
337 
338         // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
339         Log("Now send from node1 to node0");
340 
341         for (uint16_t iter = 0; iter < 20; iter++)
342         {
343             OwnedPtr<Message> msg(PrepareMessage(node1));
344 
345             SuccessOrQuit(dtls1.Send(*msg->Clone()));
346             nexus.AdvanceTime(100);
347 
348             VerifyOrQuit(sDtlsLastReceive[node0.GetId()].GetLength() == msg->GetLength());
349             VerifyOrQuit(msg->CompareBytes(0, sDtlsLastReceive[node0.GetId()].GetArrayBuffer(), msg->GetLength()));
350         }
351 
352         // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
353         Log("Disconnect from node1 - validate the disconnect events (local/peer)");
354 
355         dtls1.Disconnect();
356 
357         nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
358 
359         VerifyOrQuit(!dtls0.IsConnected());
360         VerifyOrQuit(!dtls1.IsConnected());
361 
362         VerifyOrQuit(sDtlsEvent[node0.GetId()] == Dtls::Session::kDisconnectedPeerClosed);
363         VerifyOrQuit(sDtlsEvent[node1.GetId()] == Dtls::Session::kDisconnectedLocalClosed);
364 
365         // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
366         Log("Establish a DTLS connection again");
367 
368         SuccessOrQuit(dtls1.Connect(sockAddr));
369 
370         nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
371 
372         VerifyOrQuit(dtls0.IsConnected());
373         VerifyOrQuit(dtls1.IsConnected());
374 
375         VerifyOrQuit(sDtlsEvent[node0.GetId()] == Dtls::Session::kConnected);
376         VerifyOrQuit(sDtlsEvent[node1.GetId()] == Dtls::Session::kConnected);
377 
378         // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
379         Log("Try to connect from node2 - validate that it fails to connect since already connected");
380 
381         SuccessOrQuit(dtls2.SetPsk(kPsk, sizeof(kPsk)));
382         dtls2.SetReceiveCallback(HandleReceive, &node2);
383         dtls2.SetReceiveCallback(HandleReceive, &node2);
384         SuccessOrQuit(dtls2.Open());
385         SuccessOrQuit(dtls2.Connect(sockAddr));
386 
387         nexus.AdvanceTime(20 * Time::kOneSecondInMsec);
388 
389         VerifyOrQuit(dtls0.IsConnected());
390         VerifyOrQuit(dtls1.IsConnected());
391         VerifyOrQuit(!dtls2.IsConnected());
392 
393         // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
394         Log("Disconnect from node0 - validate the disconnect events");
395 
396         dtls0.Disconnect();
397 
398         nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
399 
400         VerifyOrQuit(!dtls0.IsConnected());
401         VerifyOrQuit(!dtls1.IsConnected());
402         VerifyOrQuit(!dtls2.IsConnected());
403 
404         VerifyOrQuit(sDtlsEvent[node0.GetId()] == Dtls::Session::kDisconnectedLocalClosed);
405         VerifyOrQuit(sDtlsEvent[node1.GetId()] == Dtls::Session::kDisconnectedPeerClosed);
406 
407         // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
408 
409         dtls0.Close();
410         dtls1.Close();
411         dtls2.Close();
412 
413         // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
414 
415         Log("Start DTLS (server) on node0 bound to port %u with auto-close max attempt %u", kUdpPort, kMaxAttempts);
416 
417         memset(sDtlsAutoClosed, false, sizeof(sDtlsAutoClosed));
418 
419         SuccessOrQuit(dtls0.SetMaxConnectionAttempts(kMaxAttempts, HandleAutoClose, &node0));
420         SuccessOrQuit(dtls0.SetPsk(kPsk, sizeof(kPsk)));
421         dtls0.SetReceiveCallback(HandleReceive, &node0);
422         dtls0.SetConnectCallback(HandleConnectEvent, &node0);
423         SuccessOrQuit(dtls0.Open());
424         SuccessOrQuit(dtls0.Bind(kUdpPort));
425 
426         nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
427 
428         VerifyOrQuit(dtls0.GetUdpPort() == kUdpPort);
429         VerifyOrQuit(!dtls0.IsConnectionActive());
430 
431         // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
432         Log("Using wrong PSK try to establish DTLS connection with node0 %u times", kMaxAttempts - 1);
433 
434         SuccessOrQuit(dtls1.SetPsk(kPsk, sizeof(kPsk) - 1));
435         dtls1.SetReceiveCallback(HandleReceive, &node1);
436         dtls1.SetConnectCallback(HandleConnectEvent, &node1);
437         SuccessOrQuit(dtls1.Open());
438 
439         for (uint16_t iter = 0; iter < kMaxAttempts - 1; iter++)
440         {
441             memset(sDtlsEvent, Dtls::Session::kConnected, sizeof(sDtlsEvent));
442 
443             SuccessOrQuit(dtls1.Connect(sockAddr));
444             nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
445 
446             VerifyOrQuit(!dtls0.IsConnected());
447             VerifyOrQuit(!dtls1.IsConnected());
448 
449             VerifyOrQuit(sDtlsEvent[node0.GetId()] == Dtls::Session::kDisconnectedError);
450             VerifyOrQuit(sDtlsEvent[node1.GetId()] == Dtls::Session::kDisconnectedError);
451         }
452 
453         // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
454         Log("Using wrong PSK try one last time, validate the auto-close behavior");
455 
456         memset(sDtlsEvent, Dtls::Session::kConnected, sizeof(sDtlsEvent));
457 
458         SuccessOrQuit(dtls1.Connect(sockAddr));
459         nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
460 
461         VerifyOrQuit(sDtlsEvent[node0.GetId()] == Dtls::Session::kDisconnectedError);
462         VerifyOrQuit(sDtlsEvent[node1.GetId()] == Dtls::Session::kDisconnectedError);
463 
464         VerifyOrQuit(sDtlsAutoClosed[node0.GetId()]);
465 
466         // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
467 
468         dtls0.Close();
469         dtls1.Close();
470         dtls2.Close();
471     }
472 }
473 
TestDtlsMultiSession(void)474 void TestDtlsMultiSession(void)
475 {
476     Core  nexus;
477     Node &node0 = nexus.CreateNode();
478     Node &node1 = nexus.CreateNode();
479     Node &node2 = nexus.CreateNode();
480 
481     Log("------------------------------------------------------------------------------------------------------");
482     Log("TestDtlsMultiSession");
483 
484     nexus.AdvanceTime(0);
485 
486     // Form the topology: node0 leader, with node1 & node2 as its FTD children
487 
488     node0.Form();
489     nexus.AdvanceTime(50 * Time::kOneSecondInMsec);
490     VerifyOrQuit(node0.Get<Mle::Mle>().IsLeader());
491 
492     SuccessOrQuit(node1.Get<Mle::MleRouter>().SetRouterEligible(false));
493     node1.Join(node0);
494     nexus.AdvanceTime(20 * Time::kOneSecondInMsec);
495     VerifyOrQuit(node1.Get<Mle::Mle>().IsChild());
496 
497     SuccessOrQuit(node2.Get<Mle::MleRouter>().SetRouterEligible(false));
498     node2.Join(node0);
499     nexus.AdvanceTime(20 * Time::kOneSecondInMsec);
500     VerifyOrQuit(node2.Get<Mle::Mle>().IsChild());
501 
502     {
503         DtlsTransportAndHeapSession   dtls0(node0);
504         DtlsTransportAndSingleSession dtls1(node1);
505         DtlsTransportAndSingleSession dtls2(node2);
506         Ip6::SockAddr                 sockAddr;
507         uint16_t                      numSessions;
508 
509         // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
510         Log("Start DTLS (server) on node0 bound to port %u", kUdpPort);
511 
512         SuccessOrQuit(dtls0.SetPsk(kPsk, sizeof(kPsk)));
513         SuccessOrQuit(dtls0.Open());
514         SuccessOrQuit(dtls0.Bind(kUdpPort));
515 
516         nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
517 
518         VerifyOrQuit(dtls0.GetUdpPort() == kUdpPort);
519 
520         sockAddr.SetAddress(node0.Get<Mle::Mle>().GetMeshLocalRloc());
521         sockAddr.SetPort(kUdpPort);
522 
523         // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
524         Log("Establish a DTLS connection with node 0 from node1");
525 
526         memset(sDtlsEvent, Dtls::Session::kDisconnectedError, sizeof(sDtlsEvent));
527 
528         SuccessOrQuit(dtls1.SetPsk(kPsk, sizeof(kPsk)));
529         dtls1.SetReceiveCallback(HandleReceive, &node1);
530         dtls1.SetConnectCallback(HandleConnectEvent, &node1);
531         SuccessOrQuit(dtls1.Open());
532         SuccessOrQuit(dtls1.Connect(sockAddr));
533 
534         nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
535 
536         VerifyOrQuit(dtls1.IsConnected());
537 
538         VerifyOrQuit(sDtlsEvent[node0.GetId()] == Dtls::Session::kConnected);
539         VerifyOrQuit(sDtlsEvent[node1.GetId()] == Dtls::Session::kConnected);
540 
541         numSessions = 0;
542 
543         for (MeshCoP::SecureSession &session : dtls0.GetSessions())
544         {
545             VerifyOrQuit(session.IsConnected());
546             numSessions++;
547         }
548 
549         VerifyOrQuit(numSessions == 1);
550         VerifyOrQuit(sHeapSessionsAllocated == 1);
551 
552         // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
553         Log("Establish a second DTLS connection with node0 from node2");
554 
555         memset(sDtlsEvent, Dtls::Session::kDisconnectedError, sizeof(sDtlsEvent));
556 
557         SuccessOrQuit(dtls2.SetPsk(kPsk, sizeof(kPsk)));
558         dtls2.SetReceiveCallback(HandleReceive, &node2);
559         dtls2.SetConnectCallback(HandleConnectEvent, &node2);
560         SuccessOrQuit(dtls2.Open());
561         SuccessOrQuit(dtls2.Connect(sockAddr));
562 
563         nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
564 
565         VerifyOrQuit(dtls2.IsConnected());
566 
567         VerifyOrQuit(sDtlsEvent[node0.GetId()] == Dtls::Session::kConnected);
568         VerifyOrQuit(sDtlsEvent[node2.GetId()] == Dtls::Session::kConnected);
569 
570         numSessions = 0;
571 
572         for (MeshCoP::SecureSession &session : dtls0.GetSessions())
573         {
574             VerifyOrQuit(session.IsConnected());
575             numSessions++;
576         }
577 
578         VerifyOrQuit(numSessions == 2);
579         VerifyOrQuit(sHeapSessionsAllocated == 2);
580 
581         // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
582         Log("Disconnect from node1 - validate the disconnect events");
583 
584         dtls1.Disconnect();
585 
586         nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
587 
588         VerifyOrQuit(!dtls1.IsConnected());
589 
590         VerifyOrQuit(sDtlsEvent[node0.GetId()] == Dtls::Session::kDisconnectedPeerClosed);
591         VerifyOrQuit(sDtlsEvent[node1.GetId()] == Dtls::Session::kDisconnectedLocalClosed);
592 
593         numSessions = 0;
594 
595         for (MeshCoP::SecureSession &session : dtls0.GetSessions())
596         {
597             VerifyOrQuit(session.IsConnected());
598             numSessions++;
599         }
600 
601         VerifyOrQuit(numSessions == 1);
602         VerifyOrQuit(sHeapSessionsAllocated == 1);
603 
604         // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
605         Log("Disconnect session with node2 from node0 (server) - validate the disconnect events");
606 
607         memset(sDtlsEvent, Dtls::Session::kConnected, sizeof(sDtlsEvent));
608 
609         dtls0.GetSessions().GetHead()->Disconnect();
610 
611         nexus.AdvanceTime(3 * Time::kOneSecondInMsec);
612 
613         VerifyOrQuit(!dtls2.IsConnected());
614 
615         VerifyOrQuit(sDtlsEvent[node0.GetId()] == Dtls::Session::kDisconnectedLocalClosed);
616         VerifyOrQuit(sDtlsEvent[node2.GetId()] == Dtls::Session::kDisconnectedPeerClosed);
617 
618         VerifyOrQuit(dtls0.GetSessions().IsEmpty());
619         VerifyOrQuit(sHeapSessionsAllocated == 0);
620 
621         // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
622         Log("Establish two DTLS connections from node1 and node2 at the same time");
623 
624         memset(sDtlsEvent, Dtls::Session::kDisconnectedError, sizeof(sDtlsEvent));
625 
626         SuccessOrQuit(dtls1.Connect(sockAddr));
627         SuccessOrQuit(dtls2.Connect(sockAddr));
628 
629         nexus.AdvanceTime(1 * Time::kOneSecondInMsec);
630 
631         VerifyOrQuit(dtls1.IsConnected());
632         VerifyOrQuit(dtls2.IsConnected());
633 
634         VerifyOrQuit(sDtlsEvent[node0.GetId()] == Dtls::Session::kConnected);
635         VerifyOrQuit(sDtlsEvent[node1.GetId()] == Dtls::Session::kConnected);
636         VerifyOrQuit(sDtlsEvent[node2.GetId()] == Dtls::Session::kConnected);
637 
638         numSessions = 0;
639 
640         for (MeshCoP::SecureSession &session : dtls0.GetSessions())
641         {
642             VerifyOrQuit(session.IsConnected());
643             numSessions++;
644         }
645 
646         VerifyOrQuit(numSessions == 2);
647         VerifyOrQuit(sHeapSessionsAllocated == 2);
648     }
649 }
650 
651 } // namespace Nexus
652 } // namespace ot
653 
main(void)654 int main(void)
655 {
656     ot::Nexus::TestDtlsSingleSession();
657     ot::Nexus::TestDtlsMultiSession();
658     printf("All tests passed\n");
659     return 0;
660 }
661