Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / inet / tests / TestInetLayer.cpp
1 /*
2  *
3  *    Copyright (c) 2020 Project CHIP Authors
4  *    Copyright (c) 2019 Google LLC.
5  *    Copyright (c) 2013-2017 Nest Labs, Inc.
6  *    All rights reserved.
7  *
8  *    Licensed under the Apache License, Version 2.0 (the "License");
9  *    you may not use this file except in compliance with the License.
10  *    You may obtain a copy of the License at
11  *
12  *        http://www.apache.org/licenses/LICENSE-2.0
13  *
14  *    Unless required by applicable law or agreed to in writing, software
15  *    distributed under the License is distributed on an "AS IS" BASIS,
16  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  *    See the License for the specific language governing permissions and
18  *    limitations under the License.
19  */
20
21 /**
22  *    @file
23  *      This file implements a process to effect a functional test for
24  *      the InetLayer Internet Protocol stack abstraction interfaces.
25  *
26  */
27
28 #ifndef __STDC_LIMIT_MACROS
29 #define __STDC_LIMIT_MACROS
30 #endif
31
32 #include <signal.h>
33 #include <stdint.h>
34 #include <string.h>
35 #include <type_traits>
36 #include <unistd.h>
37
38 #include <CHIPVersion.h>
39
40 #include <inet/InetArgParser.h>
41 #include <support/CodeUtils.h>
42
43 #include <system/SystemTimer.h>
44
45 #include "TestInetCommon.h"
46 #include "TestInetCommonOptions.h"
47 #include "TestInetLayerCommon.hpp"
48 #include "TestSetupFaultInjection.h"
49 #include "TestSetupSignalling.h"
50
51 using namespace chip;
52 using namespace chip::Inet;
53 using namespace chip::ArgParser;
54 using namespace chip::System;
55
56 /* Preprocessor Macros */
57
58 #define kToolName "TestInetLayer"
59
60 #define kToolOptTCPIP 't'
61
62 #define kToolOptExpectedRxSize (kToolOptBase + 0)
63 #define kToolOptExpectedTxSize (kToolOptBase + 1)
64
65 /* Type Definitions */
66
67 enum OptFlags
68 {
69     kOptFlagExpectedRxSize = 0x00010000,
70     kOptFlagExpectedTxSize = 0x00020000,
71
72     kOptFlagUseTCPIP = 0x00040000
73 };
74
75 struct TestState
76 {
77     TransferStats mStats;
78     TestStatus mStatus;
79 };
80
81 /* Function Declarations */
82
83 static void HandleSignal(int aSignal);
84 static bool HandleOption(const char * aProgram, OptionSet * aOptions, int aIdentifier, const char * aName, const char * aValue);
85 static bool HandleNonOptionArgs(const char * aProgram, int argc, char * argv[]);
86
87 static void StartTest();
88 static void CleanupTest();
89
90 /* Global Variables */
91
92 static const uint32_t kExpectedRxSizeDefault = 1523;
93 static const uint32_t kExpectedTxSizeDefault = kExpectedRxSizeDefault;
94
95 static const uint32_t kOptFlagsDefault = (kOptFlagUseIPv6 | kOptFlagUseUDPIP);
96
97 static RawEndPoint * sRawIPEndPoint       = nullptr;
98 static TCPEndPoint * sTCPIPEndPoint       = nullptr; // Used for connect/send/receive
99 static TCPEndPoint * sTCPIPListenEndPoint = nullptr; // Used for accept/listen
100 static UDPEndPoint * sUDPIPEndPoint       = nullptr;
101
102 static const uint16_t kTCPPort = kUDPPort;
103 // clang-format off
104 static TestState         sTestState             =
105 {
106     { { 0, 0 }, { 0, 0 } },
107     { false, false }
108 };
109 // clang-format on
110
111 static IPAddress sDestinationAddress   = IPAddress::Any;
112 static const char * sDestinationString = nullptr;
113
114 // clang-format off
115 static OptionDef         sToolOptionDefs[] =
116 {
117     { "interface",                 kArgumentRequired,  kToolOptInterface              },
118     { "expected-rx-size",          kArgumentRequired,  kToolOptExpectedRxSize         },
119     { "expected-tx-size",          kArgumentRequired,  kToolOptExpectedTxSize         },
120     { "interval",                  kArgumentRequired,  kToolOptInterval               },
121 #if INET_CONFIG_ENABLE_IPV4
122     { "ipv4",                      kNoArgument,        kToolOptIPv4Only               },
123 #endif // INET_CONFIG_ENABLE_IPV4
124     { "ipv6",                      kNoArgument,        kToolOptIPv6Only               },
125     { "listen",                    kNoArgument,        kToolOptListen                 },
126     { "raw",                       kNoArgument,        kToolOptRawIP                  },
127     { "send-size",                 kArgumentRequired,  kToolOptSendSize               },
128     { "tcp",                       kNoArgument,        kToolOptTCPIP                  },
129     { "udp",                       kNoArgument,        kToolOptUDPIP                  },
130     { }
131 };
132
133 static const char *      sToolOptionHelp =
134     "  -I, --interface <interface>\n"
135     "       The network interface to bind to and from which to send and receive all packets.\n"
136     "\n"
137     "  --expected-rx-size <size>\n"
138     "       Expect to receive size bytes of user data (default 1523).\n"
139     "\n"
140     "  --expected-tx-size <size>\n"
141     "       Expect to send size bytes of user data (default 1523).\n"
142     "\n"
143     "  -i, --interval <interval>\n"
144     "       Wait interval milliseconds between sending each packet (default: 1000 ms).\n"
145     "\n"
146     "  -l, --listen\n"
147     "       Act as a server (i.e., listen) for packets rather than send them.\n"
148     "\n"
149 #if INET_CONFIG_ENABLE_IPV4
150     "  -4, --ipv4\n"
151     "       Use IPv4 only.\n"
152     "\n"
153 #endif // INET_CONFIG_ENABLE_IPV4
154     "  -6, --ipv6\n"
155     "       Use IPv6 only (default).\n"
156     "\n"
157     "  -s, --send-size <size>\n"
158     "       Send size bytes of user data (default: 59 bytes)\n"
159     "\n"
160     "  -r, --raw\n"
161     "       Use raw IP (default).\n"
162     "\n"
163     "  -t, --tcp\n"
164     "       Use TCP over IP.\n"
165     "\n"
166     "  -u, --udp\n"
167     "       Use UDP over IP (default).\n"
168     "\n";
169
170 static OptionSet         sToolOptions =
171 {
172     HandleOption,
173     sToolOptionDefs,
174     "GENERAL OPTIONS",
175     sToolOptionHelp
176 };
177
178 static HelpOptions       sHelpOptions(
179     kToolName,
180     "Usage: " kToolName " [ <options> ] <dest-node-addr>\n"
181     "       " kToolName " [ <options> ] --listen\n",
182     CHIP_VERSION_STRING "\n" CHIP_TOOL_COPYRIGHT
183 );
184
185 static OptionSet *       sToolOptionSets[] =
186 {
187     &sToolOptions,
188     &gNetworkOptions,
189     &gFaultInjectionOptions,
190     &sHelpOptions,
191     nullptr
192 };
193 // clang-format on
194
195 static void CheckSucceededOrFailed(TestState & aTestState, bool & aOutSucceeded, bool & aOutFailed)
196 {
197     const TransferStats & lStats = aTestState.mStats;
198
199 #if DEBUG
200     printf("%u/%u sent, %u/%u received\n", lStats.mTransmit.mActual, lStats.mTransmit.mExpected, lStats.mReceive.mActual,
201            lStats.mReceive.mExpected);
202 #endif
203
204     if (((lStats.mTransmit.mExpected > 0) && (lStats.mTransmit.mActual > lStats.mTransmit.mExpected)) ||
205         ((lStats.mReceive.mExpected > 0) && (lStats.mReceive.mActual > lStats.mReceive.mExpected)))
206     {
207         aOutFailed = true;
208     }
209     else if (((lStats.mTransmit.mExpected > 0) && (lStats.mTransmit.mActual < lStats.mTransmit.mExpected)) ||
210              ((lStats.mReceive.mExpected > 0) && (lStats.mReceive.mActual < lStats.mReceive.mExpected)))
211     {
212         aOutSucceeded = false;
213     }
214
215     if (aOutSucceeded || aOutFailed)
216     {
217         if (aOutSucceeded)
218             aTestState.mStatus.mSucceeded = true;
219
220         if (aOutFailed)
221             SetStatusFailed(aTestState.mStatus);
222     }
223 }
224
225 static void HandleSignal(int aSignal)
226 {
227     switch (aSignal)
228     {
229
230     case SIGUSR1:
231         SetStatusFailed(sTestState.mStatus);
232         break;
233     }
234 }
235
236 int main(int argc, char * argv[])
237 {
238     bool lSuccessful = true;
239     INET_ERROR lStatus;
240
241     InitTestInetCommon();
242
243     SetupFaultInjectionContext(argc, argv);
244
245     SetSignalHandler(HandleSignal);
246
247     if (argc == 1)
248     {
249         sHelpOptions.PrintBriefUsage(stderr);
250         lSuccessful = false;
251         goto exit;
252     }
253
254     if (!ParseArgsFromEnvVar(kToolName, TOOL_OPTIONS_ENV_VAR_NAME, sToolOptionSets, nullptr, true) ||
255         !ParseArgs(kToolName, argc, argv, sToolOptionSets, HandleNonOptionArgs))
256     {
257         lSuccessful = false;
258         goto exit;
259     }
260
261     InitSystemLayer();
262
263     InitNetwork();
264
265     // At this point, we should have valid network interfaces,
266     // including LwIP TUN/TAP shim interfaces. Validate the
267     // -I/--interface argument, if present.
268
269     if (gInterfaceName != nullptr)
270     {
271         lStatus = InterfaceNameToId(gInterfaceName, gInterfaceId);
272         if (lStatus != INET_NO_ERROR)
273         {
274             PrintArgError("%s: unknown network interface %s\n", kToolName, gInterfaceName);
275             lSuccessful = false;
276             goto shutdown;
277         }
278     }
279
280     StartTest();
281
282     while (Common::IsTesting(sTestState.mStatus))
283     {
284         struct timeval sleepTime;
285         bool lSucceeded = true;
286         bool lFailed    = false;
287
288         sleepTime.tv_sec  = 0;
289         sleepTime.tv_usec = 10000;
290
291         ServiceNetwork(sleepTime);
292
293         CheckSucceededOrFailed(sTestState, lSucceeded, lFailed);
294
295 #if DEBUG
296         // clang-format off
297         printf("%s %s number of expected bytes\n",
298                ((lSucceeded) ? "successfully" :
299                 ((lFailed) ? "failed to" :
300                  "has not yet")),
301                ((lSucceeded) ? (Common::IsReceiver() ? "received" : "sent") :
302                 ((lFailed) ? (Common::IsReceiver() ? "receive" : "send") :
303                  Common::IsReceiver() ? "received" : "sent"))
304                );
305         // clang-format on
306 #endif
307     }
308
309     CleanupTest();
310
311 shutdown:
312     ShutdownNetwork();
313     ShutdownSystemLayer();
314
315     lSuccessful = Common::WasSuccessful(sTestState.mStatus);
316
317 exit:
318     return (lSuccessful ? EXIT_SUCCESS : EXIT_FAILURE);
319 }
320
321 static bool HandleOption(const char * aProgram, OptionSet * aOptions, int aIdentifier, const char * aName, const char * aValue)
322 {
323     bool retval = true;
324
325     switch (aIdentifier)
326     {
327
328     case kToolOptInterval:
329         if (!ParseInt(aValue, gSendIntervalMs))
330         {
331             PrintArgError("%s: invalid value specified for send interval: %s\n", aProgram, aValue);
332             retval = false;
333         }
334         break;
335
336     case kToolOptListen:
337         gOptFlags |= kOptFlagListen;
338         break;
339
340     case kToolOptExpectedRxSize:
341         if (!ParseInt(aValue, sTestState.mStats.mReceive.mExpected) || sTestState.mStats.mReceive.mExpected > UINT32_MAX)
342         {
343             PrintArgError("%s: Invalid value specified for max receive: %s\n", aProgram, aValue);
344             retval = false;
345         }
346         gOptFlags |= kOptFlagExpectedRxSize;
347         break;
348
349     case kToolOptExpectedTxSize:
350         if (!ParseInt(aValue, sTestState.mStats.mTransmit.mExpected) || sTestState.mStats.mTransmit.mExpected > UINT32_MAX)
351         {
352             PrintArgError("%s: Invalid value specified for max send: %s\n", aProgram, aValue);
353             retval = false;
354         }
355         gOptFlags |= kOptFlagExpectedTxSize;
356         break;
357
358 #if INET_CONFIG_ENABLE_IPV4
359     case kToolOptIPv4Only:
360         if (gOptFlags & kOptFlagUseIPv6)
361         {
362             PrintArgError("%s: the use of --ipv4 is exclusive with --ipv6. Please select only one of the two options.\n", aProgram);
363             retval = false;
364         }
365         gOptFlags |= kOptFlagUseIPv4;
366         break;
367 #endif // INET_CONFIG_ENABLE_IPV4
368
369     case kToolOptIPv6Only:
370         if (gOptFlags & kOptFlagUseIPv4)
371         {
372             PrintArgError("%s: the use of --ipv6 is exclusive with --ipv4. Please select only one of the two options.\n", aProgram);
373             retval = false;
374         }
375         gOptFlags |= kOptFlagUseIPv6;
376         break;
377
378     case kToolOptInterface:
379
380         // NOTE: When using LwIP on a hosted OS, the interface will
381         // not actually be available until AFTER InitNetwork,
382         // consequently, we cannot do any meaningful validation
383         // here. Simply save the value off and we will validate it
384         // later.
385
386         gInterfaceName = aValue;
387         break;
388
389     case kToolOptRawIP:
390         if (gOptFlags & kOptFlagUseUDPIP)
391         {
392             PrintArgError("%s: the use of --raw is exclusive with --udp. Please select only one of the two options.\n", aProgram);
393             retval = false;
394         }
395         else if (gOptFlags & kOptFlagUseTCPIP)
396         {
397             PrintArgError("%s: the use of --raw is exclusive with --tcp. Please select only one of the two options.\n", aProgram);
398             retval = false;
399         }
400         gOptFlags |= kOptFlagUseRawIP;
401         break;
402
403     case kToolOptTCPIP:
404         if (gOptFlags & kOptFlagUseRawIP)
405         {
406             PrintArgError("%s: the use of --tcp is exclusive with --raw. Please select only one of the two options.\n", aProgram);
407             retval = false;
408         }
409         else if (gOptFlags & kOptFlagUseUDPIP)
410         {
411             PrintArgError("%s: the use of --tcp is exclusive with --udp. Please select only one of the two options.\n", aProgram);
412             retval = false;
413         }
414         gOptFlags |= kOptFlagUseTCPIP;
415         break;
416
417     case kToolOptSendSize:
418         if (!ParseInt(aValue, gSendSize))
419         {
420             PrintArgError("%s: invalid value specified for send size: %s\n", aProgram, aValue);
421             return false;
422         }
423         break;
424
425     case kToolOptUDPIP:
426         if (gOptFlags & kOptFlagUseRawIP)
427         {
428             PrintArgError("%s: the use of --udp is exclusive with --raw. Please select only one of the two options.\n", aProgram);
429             retval = false;
430         }
431         else if (gOptFlags & kOptFlagUseTCPIP)
432         {
433             PrintArgError("%s: the use of --udp is exclusive with --tcp. Please select only one of the two options.\n", aProgram);
434             retval = false;
435         }
436         gOptFlags |= kOptFlagUseUDPIP;
437         break;
438
439     default:
440         PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", aProgram, aName);
441         retval = false;
442         break;
443     }
444
445     return (retval);
446 }
447
448 bool HandleNonOptionArgs(const char * aProgram, int argc, char * argv[])
449 {
450     bool retval = true;
451
452     if (Common::IsSender())
453     {
454         if (argc == 0)
455         {
456             PrintArgError("%s: Please specify a destination address.\n", aProgram);
457             retval = false;
458             goto exit;
459         }
460
461         retval = IPAddress::FromString(argv[0], sDestinationAddress);
462         VerifyOrExit(retval == true, PrintArgError("%s: Please specify a valid destination address: %s\n", aProgram, argv[0]));
463
464         sDestinationString = argv[0];
465
466         argc--;
467         argv++;
468     }
469
470     if (argc > 0)
471     {
472         PrintArgError("%s: unexpected argument: %s\n", aProgram, argv[0]);
473         retval = false;
474         goto exit;
475     }
476
477     // If no IP version or transport flags were specified, use the defaults.
478
479     if (!(gOptFlags & (kOptFlagUseIPv4 | kOptFlagUseIPv6 | kOptFlagUseRawIP | kOptFlagUseTCPIP | kOptFlagUseUDPIP)))
480     {
481         gOptFlags |= kOptFlagsDefault;
482     }
483
484     // If no expected send or receive lengths were specified, use the defaults.
485
486     if (!(gOptFlags & kOptFlagExpectedRxSize))
487     {
488         sTestState.mStats.mReceive.mExpected = kExpectedRxSizeDefault;
489     }
490
491     if (!(gOptFlags & kOptFlagExpectedTxSize))
492     {
493         sTestState.mStats.mTransmit.mExpected = kExpectedTxSizeDefault;
494     }
495
496 exit:
497     return (retval);
498 }
499
500 static void PrintReceivedStats(const TransferStats & aStats)
501 {
502     printf("%u/%u received\n", aStats.mReceive.mActual, aStats.mReceive.mExpected);
503 }
504
505 static bool HandleDataReceived(const PacketBufferHandle & aBuffer, bool aCheckBuffer, uint8_t aFirstValue)
506 {
507     const bool lStatsByPacket = true;
508     bool lStatus              = true;
509
510     lStatus = Common::HandleDataReceived(aBuffer, sTestState.mStats, !lStatsByPacket, aCheckBuffer, aFirstValue);
511     VerifyOrExit(lStatus == true, );
512
513     PrintReceivedStats(sTestState.mStats);
514
515 exit:
516     return (lStatus);
517 }
518
519 static bool HandleDataReceived(const PacketBufferHandle & aBuffer, bool aCheckBuffer)
520 {
521     const uint8_t lFirstValue = 0;
522     bool lStatus              = true;
523
524     lStatus = HandleDataReceived(aBuffer, aCheckBuffer, lFirstValue);
525     VerifyOrExit(lStatus == true, );
526
527 exit:
528     return (lStatus);
529 }
530
531 // TCP Endpoint Callbacks
532
533 void HandleTCPConnectionComplete(TCPEndPoint * aEndPoint, INET_ERROR aError)
534 {
535     INET_ERROR lStatus;
536
537     if (aError == INET_NO_ERROR)
538     {
539         IPAddress lPeerAddress;
540         uint16_t lPeerPort;
541         char lPeerAddressBuffer[INET6_ADDRSTRLEN];
542
543         lStatus = aEndPoint->GetPeerInfo(&lPeerAddress, &lPeerPort);
544         INET_FAIL_ERROR(lStatus, "TCPEndPoint::GetPeerInfo failed");
545
546         lPeerAddress.ToString(lPeerAddressBuffer);
547
548         printf("TCP connection established to %s:%u\n", lPeerAddressBuffer, lPeerPort);
549
550         if (sTCPIPEndPoint->PendingReceiveLength() == 0)
551             sTCPIPEndPoint->SetReceivedDataForTesting(nullptr);
552
553         sTCPIPEndPoint->DisableReceive();
554         sTCPIPEndPoint->EnableKeepAlive(10, 100);
555         sTCPIPEndPoint->DisableKeepAlive();
556         sTCPIPEndPoint->EnableReceive();
557
558         DriveSend();
559     }
560     else
561     {
562         printf("TCP connection FAILED: %s\n", ErrorStr(aError));
563
564         aEndPoint->Free();
565         aEndPoint = nullptr;
566
567         gSendIntervalExpired = false;
568         gSystemLayer.CancelTimer(Common::HandleSendTimerComplete, nullptr);
569         gSystemLayer.StartTimer(gSendIntervalMs, Common::HandleSendTimerComplete, nullptr);
570
571         SetStatusFailed(sTestState.mStatus);
572     }
573 }
574
575 static void HandleTCPConnectionClosed(TCPEndPoint * aEndPoint, INET_ERROR aError)
576 {
577     if (aError == INET_NO_ERROR)
578     {
579         printf("TCP connection closed\n");
580     }
581     else
582     {
583         printf("TCP connection closed with error: %s\n", ErrorStr(aError));
584
585         SetStatusFailed(sTestState.mStatus);
586     }
587
588     aEndPoint->Free();
589
590     if (aEndPoint == sTCPIPEndPoint)
591     {
592         sTCPIPEndPoint = nullptr;
593     }
594 }
595
596 static void HandleTCPDataSent(TCPEndPoint * aEndPoint, uint16_t len) {}
597
598 static INET_ERROR HandleTCPDataReceived(TCPEndPoint * aEndPoint, PacketBufferHandle aBuffer)
599 {
600     const uint32_t lFirstValueReceived = sTestState.mStats.mReceive.mActual;
601     const uint8_t lFirstValue          = uint8_t(lFirstValueReceived);
602     const bool lCheckBuffer            = true;
603     IPAddress lPeerAddress;
604     uint16_t lPeerPort;
605     char lPeerAddressBuffer[INET6_ADDRSTRLEN];
606     bool lCheckPassed;
607     INET_ERROR lStatus = INET_NO_ERROR;
608
609     // Check that we did not lose information in our narrowing cast.
610     VerifyOrExit(lFirstValue == lFirstValueReceived, lStatus = INET_ERROR_UNEXPECTED_EVENT);
611
612     VerifyOrExit(aEndPoint != nullptr, lStatus = INET_ERROR_BAD_ARGS);
613     VerifyOrExit(!aBuffer.IsNull(), lStatus = INET_ERROR_BAD_ARGS);
614
615     if (aEndPoint->State != TCPEndPoint::kState_Connected)
616     {
617         lStatus = aEndPoint->SetReceivedDataForTesting(std::move(aBuffer));
618         INET_FAIL_ERROR(lStatus, "TCPEndPoint::PutBackReceivedData failed");
619         goto exit;
620     }
621
622     lStatus = aEndPoint->GetPeerInfo(&lPeerAddress, &lPeerPort);
623     INET_FAIL_ERROR(lStatus, "TCPEndPoint::GetPeerInfo failed");
624
625     lPeerAddress.ToString(lPeerAddressBuffer);
626
627     printf("TCP message received from %s:%u (%zu bytes)\n", lPeerAddressBuffer, lPeerPort,
628            static_cast<size_t>(aBuffer->DataLength()));
629
630     lCheckPassed = HandleDataReceived(aBuffer, lCheckBuffer, lFirstValue);
631     VerifyOrExit(lCheckPassed == true, lStatus = INET_ERROR_UNEXPECTED_EVENT);
632
633     lStatus = aEndPoint->AckReceive(aBuffer->TotalLength());
634     INET_FAIL_ERROR(lStatus, "TCPEndPoint::AckReceive failed");
635
636 exit:
637     if (lStatus != INET_NO_ERROR)
638     {
639         SetStatusFailed(sTestState.mStatus);
640     }
641     return lStatus;
642 }
643
644 static void HandleTCPAcceptError(TCPEndPoint * aEndPoint, INET_ERROR aError)
645 {
646     printf("TCP accept error: %s\n", ErrorStr(aError));
647
648     SetStatusFailed(sTestState.mStatus);
649 }
650
651 static void HandleTCPConnectionReceived(TCPEndPoint * aListenEndPoint, TCPEndPoint * aConnectEndPoint,
652                                         const IPAddress & aPeerAddress, uint16_t aPeerPort)
653 {
654     char lPeerAddressBuffer[INET6_ADDRSTRLEN];
655
656     aPeerAddress.ToString(lPeerAddressBuffer);
657
658     printf("TCP connection accepted from %s:%u\n", lPeerAddressBuffer, aPeerPort);
659
660     aConnectEndPoint->OnConnectComplete  = HandleTCPConnectionComplete;
661     aConnectEndPoint->OnConnectionClosed = HandleTCPConnectionClosed;
662     aConnectEndPoint->OnDataSent         = HandleTCPDataSent;
663     aConnectEndPoint->OnDataReceived     = HandleTCPDataReceived;
664
665     sTCPIPEndPoint = aConnectEndPoint;
666 }
667
668 // Raw Endpoint Callbacks
669
670 static void HandleRawMessageReceived(IPEndPointBasis * aEndPoint, PacketBufferHandle aBuffer, const IPPacketInfo * aPacketInfo)
671 {
672     const bool lCheckBuffer   = true;
673     const bool lStatsByPacket = true;
674     IPAddressType lAddressType;
675     bool lStatus;
676
677     VerifyOrExit(aEndPoint != nullptr, lStatus = false);
678     VerifyOrExit(!aBuffer.IsNull(), lStatus = false);
679     VerifyOrExit(aPacketInfo != nullptr, lStatus = false);
680
681     Common::HandleRawMessageReceived(aEndPoint, aBuffer, aPacketInfo);
682
683     lAddressType = aPacketInfo->DestAddress.Type();
684
685     if (lAddressType == kIPAddressType_IPv4)
686     {
687         const uint16_t kIPv4HeaderSize = 20;
688
689         aBuffer->ConsumeHead(kIPv4HeaderSize);
690
691         lStatus = Common::HandleICMPv4DataReceived(std::move(aBuffer), sTestState.mStats, !lStatsByPacket, lCheckBuffer);
692     }
693     else if (lAddressType == kIPAddressType_IPv6)
694     {
695         lStatus = Common::HandleICMPv6DataReceived(std::move(aBuffer), sTestState.mStats, !lStatsByPacket, lCheckBuffer);
696     }
697     else
698     {
699         lStatus = false;
700     }
701
702     if (lStatus)
703     {
704         PrintReceivedStats(sTestState.mStats);
705     }
706
707 exit:
708     if (!lStatus)
709     {
710         SetStatusFailed(sTestState.mStatus);
711     }
712 }
713
714 static void HandleRawReceiveError(IPEndPointBasis * aEndPoint, INET_ERROR aError, const IPPacketInfo * aPacketInfo)
715 {
716     Common::HandleRawReceiveError(aEndPoint, aError, aPacketInfo);
717
718     SetStatusFailed(sTestState.mStatus);
719 }
720
721 // UDP Endpoint Callbacks
722
723 static void HandleUDPMessageReceived(IPEndPointBasis * aEndPoint, PacketBufferHandle aBuffer, const IPPacketInfo * aPacketInfo)
724 {
725     const bool lCheckBuffer = true;
726     bool lStatus;
727
728     VerifyOrExit(aEndPoint != nullptr, lStatus = false);
729     VerifyOrExit(!aBuffer.IsNull(), lStatus = false);
730     VerifyOrExit(aPacketInfo != nullptr, lStatus = false);
731
732     Common::HandleUDPMessageReceived(aEndPoint, aBuffer, aPacketInfo);
733
734     lStatus = HandleDataReceived(aBuffer, lCheckBuffer);
735
736 exit:
737     if (!lStatus)
738     {
739         SetStatusFailed(sTestState.mStatus);
740     }
741 }
742
743 static void HandleUDPReceiveError(IPEndPointBasis * aEndPoint, INET_ERROR aError, const IPPacketInfo * aPacketInfo)
744 {
745     Common::HandleUDPReceiveError(aEndPoint, aError, aPacketInfo);
746
747     SetStatusFailed(sTestState.mStatus);
748 }
749
750 static bool IsTransportReadyForSend()
751 {
752     bool lStatus = false;
753
754     if ((gOptFlags & (kOptFlagUseRawIP)) == (kOptFlagUseRawIP))
755     {
756         lStatus = (sRawIPEndPoint != nullptr);
757     }
758     else if ((gOptFlags & kOptFlagUseUDPIP) == kOptFlagUseUDPIP)
759     {
760         lStatus = (sUDPIPEndPoint != nullptr);
761     }
762     else if ((gOptFlags & kOptFlagUseTCPIP) == kOptFlagUseTCPIP)
763     {
764         if (sTCPIPEndPoint != nullptr)
765         {
766             if (sTCPIPEndPoint->PendingSendLength() == 0)
767             {
768                 switch (sTCPIPEndPoint->State)
769                 {
770                 case TCPEndPoint::kState_Connected:
771                 case TCPEndPoint::kState_ReceiveShutdown:
772                     lStatus = true;
773                     break;
774
775                 default:
776                     break;
777                 }
778             }
779         }
780     }
781
782     return (lStatus);
783 }
784
785 static INET_ERROR PrepareTransportForSend()
786 {
787     INET_ERROR lStatus = INET_NO_ERROR;
788
789     if (gOptFlags & kOptFlagUseTCPIP)
790     {
791         if (sTCPIPEndPoint == nullptr)
792         {
793             lStatus = gInet.NewTCPEndPoint(&sTCPIPEndPoint);
794             INET_FAIL_ERROR(lStatus, "InetLayer::NewTCPEndPoint failed");
795
796             sTCPIPEndPoint->OnConnectComplete  = HandleTCPConnectionComplete;
797             sTCPIPEndPoint->OnConnectionClosed = HandleTCPConnectionClosed;
798             sTCPIPEndPoint->OnDataSent         = HandleTCPDataSent;
799             sTCPIPEndPoint->OnDataReceived     = HandleTCPDataReceived;
800
801             lStatus = sTCPIPEndPoint->Connect(sDestinationAddress, kTCPPort, gInterfaceId);
802             INET_FAIL_ERROR(lStatus, "TCPEndPoint::Connect failed");
803         }
804     }
805
806     return (lStatus);
807 }
808
809 static INET_ERROR DriveSendForDestination(const IPAddress & aAddress, uint16_t aSize)
810 {
811     PacketBufferHandle lBuffer;
812     INET_ERROR lStatus = INET_NO_ERROR;
813
814     if ((gOptFlags & (kOptFlagUseRawIP)) == (kOptFlagUseRawIP))
815     {
816         // For ICMP (v4 or v6), we'll send n aSize or smaller
817         // datagrams (with overhead for the ICMP header), each
818         // patterned from zero to aSize - 1, following the ICMP
819         // header.
820
821         if ((gOptFlags & kOptFlagUseIPv6) == (kOptFlagUseIPv6))
822         {
823             lBuffer = Common::MakeICMPv6DataBuffer(aSize);
824             VerifyOrExit(!lBuffer.IsNull(), lStatus = INET_ERROR_NO_MEMORY);
825         }
826 #if INET_CONFIG_ENABLE_IPV4
827         else if ((gOptFlags & kOptFlagUseIPv4) == (kOptFlagUseIPv4))
828         {
829             lBuffer = Common::MakeICMPv4DataBuffer(aSize);
830             VerifyOrExit(!lBuffer.IsNull(), lStatus = INET_ERROR_NO_MEMORY);
831         }
832 #endif // INET_CONFIG_ENABLE_IPV4
833
834         lStatus = sRawIPEndPoint->SendTo(aAddress, std::move(lBuffer));
835         SuccessOrExit(lStatus);
836     }
837     else
838     {
839         if ((gOptFlags & kOptFlagUseUDPIP) == kOptFlagUseUDPIP)
840         {
841             const uint8_t lFirstValue = 0;
842
843             // For UDP, we'll send n aSize or smaller datagrams, each
844             // patterned from zero to aSize - 1.
845
846             lBuffer = Common::MakeDataBuffer(aSize, lFirstValue);
847             VerifyOrExit(!lBuffer.IsNull(), lStatus = INET_ERROR_NO_MEMORY);
848
849             lStatus = sUDPIPEndPoint->SendTo(aAddress, kUDPPort, std::move(lBuffer));
850             SuccessOrExit(lStatus);
851         }
852         else if ((gOptFlags & kOptFlagUseTCPIP) == kOptFlagUseTCPIP)
853         {
854             const uint32_t lFirstValue = sTestState.mStats.mTransmit.mActual;
855             VerifyOrExit(lFirstValue < 256u, lStatus = INET_ERROR_UNEXPECTED_EVENT);
856
857             // For TCP, we'll send one byte stream of
858             // sTestState.mStats.mTransmit.mExpected in n aSize or
859             // smaller transactions, patterned from zero to
860             // sTestState.mStats.mTransmit.mExpected - 1.
861
862             lBuffer = Common::MakeDataBuffer(aSize, uint8_t(lFirstValue));
863             VerifyOrExit(!lBuffer.IsNull(), lStatus = INET_ERROR_NO_MEMORY);
864
865             lStatus = sTCPIPEndPoint->Send(std::move(lBuffer));
866             SuccessOrExit(lStatus);
867         }
868     }
869
870 exit:
871     return (lStatus);
872 }
873
874 void DriveSend()
875 {
876     INET_ERROR lStatus = INET_NO_ERROR;
877
878     if (!Common::IsSender())
879         goto exit;
880
881     if (!gSendIntervalExpired)
882         goto exit;
883
884     if (!IsTransportReadyForSend())
885     {
886         lStatus = PrepareTransportForSend();
887         SuccessOrExit(lStatus);
888     }
889     else
890     {
891         gSendIntervalExpired = false;
892         gSystemLayer.StartTimer(gSendIntervalMs, Common::HandleSendTimerComplete, nullptr);
893
894         if (sTestState.mStats.mTransmit.mActual < sTestState.mStats.mTransmit.mExpected)
895         {
896             const uint32_t lRemaining = (sTestState.mStats.mTransmit.mExpected - sTestState.mStats.mTransmit.mActual);
897             const uint32_t lSendSize  = chip::min(lRemaining, static_cast<uint32_t>(gSendSize));
898
899             // gSendSize is uint16_t, so this cast is safe: the value has to be
900             // in the uint16_t range.
901             static_assert(std::is_same<decltype(gSendSize), uint16_t>::value, "Unexpected type for gSendSize");
902             lStatus = DriveSendForDestination(sDestinationAddress, uint16_t(lSendSize));
903             SuccessOrExit(lStatus);
904
905             sTestState.mStats.mTransmit.mActual += lSendSize;
906
907             printf("%u/%u transmitted to %s\n", sTestState.mStats.mTransmit.mActual, sTestState.mStats.mTransmit.mExpected,
908                    sDestinationString);
909         }
910     }
911
912 exit:
913     if (lStatus != INET_NO_ERROR)
914     {
915         SetStatusFailed(sTestState.mStatus);
916     }
917 }
918
919 static void StartTest()
920 {
921     IPAddressType lIPAddressType = kIPAddressType_IPv6;
922     IPProtocol lIPProtocol       = kIPProtocol_ICMPv6;
923     IPVersion lIPVersion         = kIPVersion_6;
924     IPAddress lAddress           = chip::Inet::IPAddress::Any;
925     INET_ERROR lStatus;
926
927     if (!gNetworkOptions.LocalIPv6Addr.empty())
928         lAddress = gNetworkOptions.LocalIPv6Addr[0];
929
930 #if INET_CONFIG_ENABLE_IPV4
931     if (gOptFlags & kOptFlagUseIPv4)
932     {
933         lIPAddressType = kIPAddressType_IPv4;
934         lIPProtocol    = kIPProtocol_ICMPv4;
935         lIPVersion     = kIPVersion_4;
936         if (!gNetworkOptions.LocalIPv6Addr.empty())
937             lAddress = gNetworkOptions.LocalIPv4Addr[0];
938         else
939             lAddress = chip::Inet::IPAddress::Any;
940     }
941 #endif // INET_CONFIG_ENABLE_IPV4
942
943     // clang-format off
944     printf("Using %sIP%s, device interface: %s (w/%c LwIP)\n",
945            ((gOptFlags & kOptFlagUseRawIP) ? "" : ((gOptFlags & kOptFlagUseTCPIP) ? "TCP/" : "UDP/")),
946            ((gOptFlags & kOptFlagUseIPv4) ? "v4" : "v6"),
947            ((gInterfaceName) ? gInterfaceName : "<none>"),
948            (CHIP_SYSTEM_CONFIG_USE_LWIP ? '\0' : 'o'));
949     // clang-format on
950
951     // Allocate the endpoints for sending or receiving.
952
953     if (gOptFlags & kOptFlagUseRawIP)
954     {
955         lStatus = gInet.NewRawEndPoint(lIPVersion, lIPProtocol, &sRawIPEndPoint);
956         INET_FAIL_ERROR(lStatus, "InetLayer::NewRawEndPoint failed");
957
958         sRawIPEndPoint->OnMessageReceived = HandleRawMessageReceived;
959         sRawIPEndPoint->OnReceiveError    = HandleRawReceiveError;
960
961         if (IsInterfaceIdPresent(gInterfaceId))
962         {
963             lStatus = sRawIPEndPoint->BindInterface(lIPAddressType, gInterfaceId);
964             INET_FAIL_ERROR(lStatus, "RawEndPoint::BindInterface failed");
965         }
966     }
967     else if (gOptFlags & kOptFlagUseUDPIP)
968     {
969         lStatus = gInet.NewUDPEndPoint(&sUDPIPEndPoint);
970         INET_FAIL_ERROR(lStatus, "InetLayer::NewUDPEndPoint failed");
971
972         sUDPIPEndPoint->OnMessageReceived = HandleUDPMessageReceived;
973         sUDPIPEndPoint->OnReceiveError    = HandleUDPReceiveError;
974
975         if (IsInterfaceIdPresent(gInterfaceId))
976         {
977             lStatus = sUDPIPEndPoint->BindInterface(lIPAddressType, gInterfaceId);
978             INET_FAIL_ERROR(lStatus, "UDPEndPoint::BindInterface failed");
979         }
980     }
981
982     if (Common::IsReceiver())
983     {
984         if (gOptFlags & kOptFlagUseRawIP)
985         {
986             lStatus = sRawIPEndPoint->Bind(lIPAddressType, lAddress);
987             INET_FAIL_ERROR(lStatus, "RawEndPoint::Bind failed");
988
989             if (gOptFlags & kOptFlagUseIPv6)
990             {
991                 lStatus = sRawIPEndPoint->SetICMPFilter(kICMPv6_FilterTypes, gICMPv6Types);
992                 INET_FAIL_ERROR(lStatus, "RawEndPoint::SetICMPFilter failed");
993             }
994
995             lStatus = sRawIPEndPoint->Listen();
996             INET_FAIL_ERROR(lStatus, "RawEndPoint::Listen failed");
997         }
998         else if (gOptFlags & kOptFlagUseUDPIP)
999         {
1000             lStatus = sUDPIPEndPoint->Bind(lIPAddressType, IPAddress::Any, kUDPPort);
1001             INET_FAIL_ERROR(lStatus, "UDPEndPoint::Bind failed");
1002
1003             lStatus = sUDPIPEndPoint->Listen();
1004             INET_FAIL_ERROR(lStatus, "UDPEndPoint::Listen failed");
1005         }
1006         else if (gOptFlags & kOptFlagUseTCPIP)
1007         {
1008             const uint16_t lConnectionBacklogMax = 1;
1009             const bool lReuseAddress             = true;
1010
1011             lStatus = gInet.NewTCPEndPoint(&sTCPIPListenEndPoint);
1012             INET_FAIL_ERROR(lStatus, "InetLayer::NewTCPEndPoint failed");
1013
1014             sTCPIPListenEndPoint->OnConnectionReceived = HandleTCPConnectionReceived;
1015             sTCPIPListenEndPoint->OnAcceptError        = HandleTCPAcceptError;
1016
1017             lStatus = sTCPIPListenEndPoint->Bind(lIPAddressType, IPAddress::Any, kTCPPort, lReuseAddress);
1018             INET_FAIL_ERROR(lStatus, "TCPEndPoint::Bind failed");
1019
1020             lStatus = sTCPIPListenEndPoint->Listen(lConnectionBacklogMax);
1021             INET_FAIL_ERROR(lStatus, "TCPEndPoint::Listen failed");
1022         }
1023     }
1024
1025     if (Common::IsReceiver())
1026         printf("Listening...\n");
1027     else
1028         DriveSend();
1029 }
1030
1031 static void CleanupTest()
1032 {
1033     INET_ERROR lStatus;
1034
1035     gSendIntervalExpired = false;
1036     gSystemLayer.CancelTimer(Common::HandleSendTimerComplete, nullptr);
1037
1038     // Release the resources associated with the allocated end points.
1039
1040     if (sRawIPEndPoint != nullptr)
1041     {
1042         sRawIPEndPoint->Free();
1043     }
1044
1045     if (sTCPIPEndPoint != nullptr)
1046     {
1047         lStatus = sTCPIPEndPoint->Close();
1048         INET_FAIL_ERROR(lStatus, "TCPEndPoint::Close failed");
1049
1050         sTCPIPEndPoint->Free();
1051     }
1052
1053     if (sTCPIPListenEndPoint != nullptr)
1054     {
1055         sTCPIPListenEndPoint->Shutdown();
1056         sTCPIPListenEndPoint->Free();
1057     }
1058
1059     if (sUDPIPEndPoint != nullptr)
1060     {
1061         sUDPIPEndPoint->Free();
1062     }
1063 }