3 * Copyright (c) 2020 Project CHIP Authors
4 * Copyright (c) 2019 Google LLC.
5 * Copyright (c) 2013-2017 Nest Labs, Inc.
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 * This file implements a process to effect a functional test for
24 * the InetLayer Internet Protocol stack abstraction interfaces.
28 #ifndef __STDC_LIMIT_MACROS
29 #define __STDC_LIMIT_MACROS
35 #include <type_traits>
38 #include <CHIPVersion.h>
40 #include <inet/InetArgParser.h>
41 #include <support/CodeUtils.h>
43 #include <system/SystemTimer.h>
45 #include "TestInetCommon.h"
46 #include "TestInetCommonOptions.h"
47 #include "TestInetLayerCommon.hpp"
48 #include "TestSetupFaultInjection.h"
49 #include "TestSetupSignalling.h"
52 using namespace chip::Inet;
53 using namespace chip::ArgParser;
54 using namespace chip::System;
56 /* Preprocessor Macros */
58 #define kToolName "TestInetLayer"
60 #define kToolOptTCPIP 't'
62 #define kToolOptExpectedRxSize (kToolOptBase + 0)
63 #define kToolOptExpectedTxSize (kToolOptBase + 1)
65 /* Type Definitions */
69 kOptFlagExpectedRxSize = 0x00010000,
70 kOptFlagExpectedTxSize = 0x00020000,
72 kOptFlagUseTCPIP = 0x00040000
81 /* Function Declarations */
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[]);
87 static void StartTest();
88 static void CleanupTest();
90 /* Global Variables */
92 static const uint32_t kExpectedRxSizeDefault = 1523;
93 static const uint32_t kExpectedTxSizeDefault = kExpectedRxSizeDefault;
95 static const uint32_t kOptFlagsDefault = (kOptFlagUseIPv6 | kOptFlagUseUDPIP);
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;
102 static const uint16_t kTCPPort = kUDPPort;
104 static TestState sTestState =
106 { { 0, 0 }, { 0, 0 } },
111 static IPAddress sDestinationAddress = IPAddress::Any;
112 static const char * sDestinationString = nullptr;
115 static OptionDef sToolOptionDefs[] =
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 },
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"
137 " --expected-rx-size <size>\n"
138 " Expect to receive size bytes of user data (default 1523).\n"
140 " --expected-tx-size <size>\n"
141 " Expect to send size bytes of user data (default 1523).\n"
143 " -i, --interval <interval>\n"
144 " Wait interval milliseconds between sending each packet (default: 1000 ms).\n"
147 " Act as a server (i.e., listen) for packets rather than send them.\n"
149 #if INET_CONFIG_ENABLE_IPV4
153 #endif // INET_CONFIG_ENABLE_IPV4
155 " Use IPv6 only (default).\n"
157 " -s, --send-size <size>\n"
158 " Send size bytes of user data (default: 59 bytes)\n"
161 " Use raw IP (default).\n"
164 " Use TCP over IP.\n"
167 " Use UDP over IP (default).\n"
170 static OptionSet sToolOptions =
178 static HelpOptions sHelpOptions(
180 "Usage: " kToolName " [ <options> ] <dest-node-addr>\n"
181 " " kToolName " [ <options> ] --listen\n",
182 CHIP_VERSION_STRING "\n" CHIP_TOOL_COPYRIGHT
185 static OptionSet * sToolOptionSets[] =
189 &gFaultInjectionOptions,
195 static void CheckSucceededOrFailed(TestState & aTestState, bool & aOutSucceeded, bool & aOutFailed)
197 const TransferStats & lStats = aTestState.mStats;
200 printf("%u/%u sent, %u/%u received\n", lStats.mTransmit.mActual, lStats.mTransmit.mExpected, lStats.mReceive.mActual,
201 lStats.mReceive.mExpected);
204 if (((lStats.mTransmit.mExpected > 0) && (lStats.mTransmit.mActual > lStats.mTransmit.mExpected)) ||
205 ((lStats.mReceive.mExpected > 0) && (lStats.mReceive.mActual > lStats.mReceive.mExpected)))
209 else if (((lStats.mTransmit.mExpected > 0) && (lStats.mTransmit.mActual < lStats.mTransmit.mExpected)) ||
210 ((lStats.mReceive.mExpected > 0) && (lStats.mReceive.mActual < lStats.mReceive.mExpected)))
212 aOutSucceeded = false;
215 if (aOutSucceeded || aOutFailed)
218 aTestState.mStatus.mSucceeded = true;
221 SetStatusFailed(aTestState.mStatus);
225 static void HandleSignal(int aSignal)
231 SetStatusFailed(sTestState.mStatus);
236 int main(int argc, char * argv[])
238 bool lSuccessful = true;
241 InitTestInetCommon();
243 SetupFaultInjectionContext(argc, argv);
245 SetSignalHandler(HandleSignal);
249 sHelpOptions.PrintBriefUsage(stderr);
254 if (!ParseArgsFromEnvVar(kToolName, TOOL_OPTIONS_ENV_VAR_NAME, sToolOptionSets, nullptr, true) ||
255 !ParseArgs(kToolName, argc, argv, sToolOptionSets, HandleNonOptionArgs))
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.
269 if (gInterfaceName != nullptr)
271 lStatus = InterfaceNameToId(gInterfaceName, gInterfaceId);
272 if (lStatus != INET_NO_ERROR)
274 PrintArgError("%s: unknown network interface %s\n", kToolName, gInterfaceName);
282 while (Common::IsTesting(sTestState.mStatus))
284 struct timeval sleepTime;
285 bool lSucceeded = true;
286 bool lFailed = false;
288 sleepTime.tv_sec = 0;
289 sleepTime.tv_usec = 10000;
291 ServiceNetwork(sleepTime);
293 CheckSucceededOrFailed(sTestState, lSucceeded, lFailed);
297 printf("%s %s number of expected bytes\n",
298 ((lSucceeded) ? "successfully" :
299 ((lFailed) ? "failed to" :
301 ((lSucceeded) ? (Common::IsReceiver() ? "received" : "sent") :
302 ((lFailed) ? (Common::IsReceiver() ? "receive" : "send") :
303 Common::IsReceiver() ? "received" : "sent"))
313 ShutdownSystemLayer();
315 lSuccessful = Common::WasSuccessful(sTestState.mStatus);
318 return (lSuccessful ? EXIT_SUCCESS : EXIT_FAILURE);
321 static bool HandleOption(const char * aProgram, OptionSet * aOptions, int aIdentifier, const char * aName, const char * aValue)
328 case kToolOptInterval:
329 if (!ParseInt(aValue, gSendIntervalMs))
331 PrintArgError("%s: invalid value specified for send interval: %s\n", aProgram, aValue);
337 gOptFlags |= kOptFlagListen;
340 case kToolOptExpectedRxSize:
341 if (!ParseInt(aValue, sTestState.mStats.mReceive.mExpected) || sTestState.mStats.mReceive.mExpected > UINT32_MAX)
343 PrintArgError("%s: Invalid value specified for max receive: %s\n", aProgram, aValue);
346 gOptFlags |= kOptFlagExpectedRxSize;
349 case kToolOptExpectedTxSize:
350 if (!ParseInt(aValue, sTestState.mStats.mTransmit.mExpected) || sTestState.mStats.mTransmit.mExpected > UINT32_MAX)
352 PrintArgError("%s: Invalid value specified for max send: %s\n", aProgram, aValue);
355 gOptFlags |= kOptFlagExpectedTxSize;
358 #if INET_CONFIG_ENABLE_IPV4
359 case kToolOptIPv4Only:
360 if (gOptFlags & kOptFlagUseIPv6)
362 PrintArgError("%s: the use of --ipv4 is exclusive with --ipv6. Please select only one of the two options.\n", aProgram);
365 gOptFlags |= kOptFlagUseIPv4;
367 #endif // INET_CONFIG_ENABLE_IPV4
369 case kToolOptIPv6Only:
370 if (gOptFlags & kOptFlagUseIPv4)
372 PrintArgError("%s: the use of --ipv6 is exclusive with --ipv4. Please select only one of the two options.\n", aProgram);
375 gOptFlags |= kOptFlagUseIPv6;
378 case kToolOptInterface:
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
386 gInterfaceName = aValue;
390 if (gOptFlags & kOptFlagUseUDPIP)
392 PrintArgError("%s: the use of --raw is exclusive with --udp. Please select only one of the two options.\n", aProgram);
395 else if (gOptFlags & kOptFlagUseTCPIP)
397 PrintArgError("%s: the use of --raw is exclusive with --tcp. Please select only one of the two options.\n", aProgram);
400 gOptFlags |= kOptFlagUseRawIP;
404 if (gOptFlags & kOptFlagUseRawIP)
406 PrintArgError("%s: the use of --tcp is exclusive with --raw. Please select only one of the two options.\n", aProgram);
409 else if (gOptFlags & kOptFlagUseUDPIP)
411 PrintArgError("%s: the use of --tcp is exclusive with --udp. Please select only one of the two options.\n", aProgram);
414 gOptFlags |= kOptFlagUseTCPIP;
417 case kToolOptSendSize:
418 if (!ParseInt(aValue, gSendSize))
420 PrintArgError("%s: invalid value specified for send size: %s\n", aProgram, aValue);
426 if (gOptFlags & kOptFlagUseRawIP)
428 PrintArgError("%s: the use of --udp is exclusive with --raw. Please select only one of the two options.\n", aProgram);
431 else if (gOptFlags & kOptFlagUseTCPIP)
433 PrintArgError("%s: the use of --udp is exclusive with --tcp. Please select only one of the two options.\n", aProgram);
436 gOptFlags |= kOptFlagUseUDPIP;
440 PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", aProgram, aName);
448 bool HandleNonOptionArgs(const char * aProgram, int argc, char * argv[])
452 if (Common::IsSender())
456 PrintArgError("%s: Please specify a destination address.\n", aProgram);
461 retval = IPAddress::FromString(argv[0], sDestinationAddress);
462 VerifyOrExit(retval == true, PrintArgError("%s: Please specify a valid destination address: %s\n", aProgram, argv[0]));
464 sDestinationString = argv[0];
472 PrintArgError("%s: unexpected argument: %s\n", aProgram, argv[0]);
477 // If no IP version or transport flags were specified, use the defaults.
479 if (!(gOptFlags & (kOptFlagUseIPv4 | kOptFlagUseIPv6 | kOptFlagUseRawIP | kOptFlagUseTCPIP | kOptFlagUseUDPIP)))
481 gOptFlags |= kOptFlagsDefault;
484 // If no expected send or receive lengths were specified, use the defaults.
486 if (!(gOptFlags & kOptFlagExpectedRxSize))
488 sTestState.mStats.mReceive.mExpected = kExpectedRxSizeDefault;
491 if (!(gOptFlags & kOptFlagExpectedTxSize))
493 sTestState.mStats.mTransmit.mExpected = kExpectedTxSizeDefault;
500 static void PrintReceivedStats(const TransferStats & aStats)
502 printf("%u/%u received\n", aStats.mReceive.mActual, aStats.mReceive.mExpected);
505 static bool HandleDataReceived(const PacketBufferHandle & aBuffer, bool aCheckBuffer, uint8_t aFirstValue)
507 const bool lStatsByPacket = true;
510 lStatus = Common::HandleDataReceived(aBuffer, sTestState.mStats, !lStatsByPacket, aCheckBuffer, aFirstValue);
511 VerifyOrExit(lStatus == true, );
513 PrintReceivedStats(sTestState.mStats);
519 static bool HandleDataReceived(const PacketBufferHandle & aBuffer, bool aCheckBuffer)
521 const uint8_t lFirstValue = 0;
524 lStatus = HandleDataReceived(aBuffer, aCheckBuffer, lFirstValue);
525 VerifyOrExit(lStatus == true, );
531 // TCP Endpoint Callbacks
533 void HandleTCPConnectionComplete(TCPEndPoint * aEndPoint, INET_ERROR aError)
537 if (aError == INET_NO_ERROR)
539 IPAddress lPeerAddress;
541 char lPeerAddressBuffer[INET6_ADDRSTRLEN];
543 lStatus = aEndPoint->GetPeerInfo(&lPeerAddress, &lPeerPort);
544 INET_FAIL_ERROR(lStatus, "TCPEndPoint::GetPeerInfo failed");
546 lPeerAddress.ToString(lPeerAddressBuffer);
548 printf("TCP connection established to %s:%u\n", lPeerAddressBuffer, lPeerPort);
550 if (sTCPIPEndPoint->PendingReceiveLength() == 0)
551 sTCPIPEndPoint->SetReceivedDataForTesting(nullptr);
553 sTCPIPEndPoint->DisableReceive();
554 sTCPIPEndPoint->EnableKeepAlive(10, 100);
555 sTCPIPEndPoint->DisableKeepAlive();
556 sTCPIPEndPoint->EnableReceive();
562 printf("TCP connection FAILED: %s\n", ErrorStr(aError));
567 gSendIntervalExpired = false;
568 gSystemLayer.CancelTimer(Common::HandleSendTimerComplete, nullptr);
569 gSystemLayer.StartTimer(gSendIntervalMs, Common::HandleSendTimerComplete, nullptr);
571 SetStatusFailed(sTestState.mStatus);
575 static void HandleTCPConnectionClosed(TCPEndPoint * aEndPoint, INET_ERROR aError)
577 if (aError == INET_NO_ERROR)
579 printf("TCP connection closed\n");
583 printf("TCP connection closed with error: %s\n", ErrorStr(aError));
585 SetStatusFailed(sTestState.mStatus);
590 if (aEndPoint == sTCPIPEndPoint)
592 sTCPIPEndPoint = nullptr;
596 static void HandleTCPDataSent(TCPEndPoint * aEndPoint, uint16_t len) {}
598 static INET_ERROR HandleTCPDataReceived(TCPEndPoint * aEndPoint, PacketBufferHandle aBuffer)
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;
605 char lPeerAddressBuffer[INET6_ADDRSTRLEN];
607 INET_ERROR lStatus = INET_NO_ERROR;
609 // Check that we did not lose information in our narrowing cast.
610 VerifyOrExit(lFirstValue == lFirstValueReceived, lStatus = INET_ERROR_UNEXPECTED_EVENT);
612 VerifyOrExit(aEndPoint != nullptr, lStatus = INET_ERROR_BAD_ARGS);
613 VerifyOrExit(!aBuffer.IsNull(), lStatus = INET_ERROR_BAD_ARGS);
615 if (aEndPoint->State != TCPEndPoint::kState_Connected)
617 lStatus = aEndPoint->SetReceivedDataForTesting(std::move(aBuffer));
618 INET_FAIL_ERROR(lStatus, "TCPEndPoint::PutBackReceivedData failed");
622 lStatus = aEndPoint->GetPeerInfo(&lPeerAddress, &lPeerPort);
623 INET_FAIL_ERROR(lStatus, "TCPEndPoint::GetPeerInfo failed");
625 lPeerAddress.ToString(lPeerAddressBuffer);
627 printf("TCP message received from %s:%u (%zu bytes)\n", lPeerAddressBuffer, lPeerPort,
628 static_cast<size_t>(aBuffer->DataLength()));
630 lCheckPassed = HandleDataReceived(aBuffer, lCheckBuffer, lFirstValue);
631 VerifyOrExit(lCheckPassed == true, lStatus = INET_ERROR_UNEXPECTED_EVENT);
633 lStatus = aEndPoint->AckReceive(aBuffer->TotalLength());
634 INET_FAIL_ERROR(lStatus, "TCPEndPoint::AckReceive failed");
637 if (lStatus != INET_NO_ERROR)
639 SetStatusFailed(sTestState.mStatus);
644 static void HandleTCPAcceptError(TCPEndPoint * aEndPoint, INET_ERROR aError)
646 printf("TCP accept error: %s\n", ErrorStr(aError));
648 SetStatusFailed(sTestState.mStatus);
651 static void HandleTCPConnectionReceived(TCPEndPoint * aListenEndPoint, TCPEndPoint * aConnectEndPoint,
652 const IPAddress & aPeerAddress, uint16_t aPeerPort)
654 char lPeerAddressBuffer[INET6_ADDRSTRLEN];
656 aPeerAddress.ToString(lPeerAddressBuffer);
658 printf("TCP connection accepted from %s:%u\n", lPeerAddressBuffer, aPeerPort);
660 aConnectEndPoint->OnConnectComplete = HandleTCPConnectionComplete;
661 aConnectEndPoint->OnConnectionClosed = HandleTCPConnectionClosed;
662 aConnectEndPoint->OnDataSent = HandleTCPDataSent;
663 aConnectEndPoint->OnDataReceived = HandleTCPDataReceived;
665 sTCPIPEndPoint = aConnectEndPoint;
668 // Raw Endpoint Callbacks
670 static void HandleRawMessageReceived(IPEndPointBasis * aEndPoint, PacketBufferHandle aBuffer, const IPPacketInfo * aPacketInfo)
672 const bool lCheckBuffer = true;
673 const bool lStatsByPacket = true;
674 IPAddressType lAddressType;
677 VerifyOrExit(aEndPoint != nullptr, lStatus = false);
678 VerifyOrExit(!aBuffer.IsNull(), lStatus = false);
679 VerifyOrExit(aPacketInfo != nullptr, lStatus = false);
681 Common::HandleRawMessageReceived(aEndPoint, aBuffer, aPacketInfo);
683 lAddressType = aPacketInfo->DestAddress.Type();
685 if (lAddressType == kIPAddressType_IPv4)
687 const uint16_t kIPv4HeaderSize = 20;
689 aBuffer->ConsumeHead(kIPv4HeaderSize);
691 lStatus = Common::HandleICMPv4DataReceived(std::move(aBuffer), sTestState.mStats, !lStatsByPacket, lCheckBuffer);
693 else if (lAddressType == kIPAddressType_IPv6)
695 lStatus = Common::HandleICMPv6DataReceived(std::move(aBuffer), sTestState.mStats, !lStatsByPacket, lCheckBuffer);
704 PrintReceivedStats(sTestState.mStats);
710 SetStatusFailed(sTestState.mStatus);
714 static void HandleRawReceiveError(IPEndPointBasis * aEndPoint, INET_ERROR aError, const IPPacketInfo * aPacketInfo)
716 Common::HandleRawReceiveError(aEndPoint, aError, aPacketInfo);
718 SetStatusFailed(sTestState.mStatus);
721 // UDP Endpoint Callbacks
723 static void HandleUDPMessageReceived(IPEndPointBasis * aEndPoint, PacketBufferHandle aBuffer, const IPPacketInfo * aPacketInfo)
725 const bool lCheckBuffer = true;
728 VerifyOrExit(aEndPoint != nullptr, lStatus = false);
729 VerifyOrExit(!aBuffer.IsNull(), lStatus = false);
730 VerifyOrExit(aPacketInfo != nullptr, lStatus = false);
732 Common::HandleUDPMessageReceived(aEndPoint, aBuffer, aPacketInfo);
734 lStatus = HandleDataReceived(aBuffer, lCheckBuffer);
739 SetStatusFailed(sTestState.mStatus);
743 static void HandleUDPReceiveError(IPEndPointBasis * aEndPoint, INET_ERROR aError, const IPPacketInfo * aPacketInfo)
745 Common::HandleUDPReceiveError(aEndPoint, aError, aPacketInfo);
747 SetStatusFailed(sTestState.mStatus);
750 static bool IsTransportReadyForSend()
752 bool lStatus = false;
754 if ((gOptFlags & (kOptFlagUseRawIP)) == (kOptFlagUseRawIP))
756 lStatus = (sRawIPEndPoint != nullptr);
758 else if ((gOptFlags & kOptFlagUseUDPIP) == kOptFlagUseUDPIP)
760 lStatus = (sUDPIPEndPoint != nullptr);
762 else if ((gOptFlags & kOptFlagUseTCPIP) == kOptFlagUseTCPIP)
764 if (sTCPIPEndPoint != nullptr)
766 if (sTCPIPEndPoint->PendingSendLength() == 0)
768 switch (sTCPIPEndPoint->State)
770 case TCPEndPoint::kState_Connected:
771 case TCPEndPoint::kState_ReceiveShutdown:
785 static INET_ERROR PrepareTransportForSend()
787 INET_ERROR lStatus = INET_NO_ERROR;
789 if (gOptFlags & kOptFlagUseTCPIP)
791 if (sTCPIPEndPoint == nullptr)
793 lStatus = gInet.NewTCPEndPoint(&sTCPIPEndPoint);
794 INET_FAIL_ERROR(lStatus, "InetLayer::NewTCPEndPoint failed");
796 sTCPIPEndPoint->OnConnectComplete = HandleTCPConnectionComplete;
797 sTCPIPEndPoint->OnConnectionClosed = HandleTCPConnectionClosed;
798 sTCPIPEndPoint->OnDataSent = HandleTCPDataSent;
799 sTCPIPEndPoint->OnDataReceived = HandleTCPDataReceived;
801 lStatus = sTCPIPEndPoint->Connect(sDestinationAddress, kTCPPort, gInterfaceId);
802 INET_FAIL_ERROR(lStatus, "TCPEndPoint::Connect failed");
809 static INET_ERROR DriveSendForDestination(const IPAddress & aAddress, uint16_t aSize)
811 PacketBufferHandle lBuffer;
812 INET_ERROR lStatus = INET_NO_ERROR;
814 if ((gOptFlags & (kOptFlagUseRawIP)) == (kOptFlagUseRawIP))
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
821 if ((gOptFlags & kOptFlagUseIPv6) == (kOptFlagUseIPv6))
823 lBuffer = Common::MakeICMPv6DataBuffer(aSize);
824 VerifyOrExit(!lBuffer.IsNull(), lStatus = INET_ERROR_NO_MEMORY);
826 #if INET_CONFIG_ENABLE_IPV4
827 else if ((gOptFlags & kOptFlagUseIPv4) == (kOptFlagUseIPv4))
829 lBuffer = Common::MakeICMPv4DataBuffer(aSize);
830 VerifyOrExit(!lBuffer.IsNull(), lStatus = INET_ERROR_NO_MEMORY);
832 #endif // INET_CONFIG_ENABLE_IPV4
834 lStatus = sRawIPEndPoint->SendTo(aAddress, std::move(lBuffer));
835 SuccessOrExit(lStatus);
839 if ((gOptFlags & kOptFlagUseUDPIP) == kOptFlagUseUDPIP)
841 const uint8_t lFirstValue = 0;
843 // For UDP, we'll send n aSize or smaller datagrams, each
844 // patterned from zero to aSize - 1.
846 lBuffer = Common::MakeDataBuffer(aSize, lFirstValue);
847 VerifyOrExit(!lBuffer.IsNull(), lStatus = INET_ERROR_NO_MEMORY);
849 lStatus = sUDPIPEndPoint->SendTo(aAddress, kUDPPort, std::move(lBuffer));
850 SuccessOrExit(lStatus);
852 else if ((gOptFlags & kOptFlagUseTCPIP) == kOptFlagUseTCPIP)
854 const uint32_t lFirstValue = sTestState.mStats.mTransmit.mActual;
855 VerifyOrExit(lFirstValue < 256u, lStatus = INET_ERROR_UNEXPECTED_EVENT);
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.
862 lBuffer = Common::MakeDataBuffer(aSize, uint8_t(lFirstValue));
863 VerifyOrExit(!lBuffer.IsNull(), lStatus = INET_ERROR_NO_MEMORY);
865 lStatus = sTCPIPEndPoint->Send(std::move(lBuffer));
866 SuccessOrExit(lStatus);
876 INET_ERROR lStatus = INET_NO_ERROR;
878 if (!Common::IsSender())
881 if (!gSendIntervalExpired)
884 if (!IsTransportReadyForSend())
886 lStatus = PrepareTransportForSend();
887 SuccessOrExit(lStatus);
891 gSendIntervalExpired = false;
892 gSystemLayer.StartTimer(gSendIntervalMs, Common::HandleSendTimerComplete, nullptr);
894 if (sTestState.mStats.mTransmit.mActual < sTestState.mStats.mTransmit.mExpected)
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));
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);
905 sTestState.mStats.mTransmit.mActual += lSendSize;
907 printf("%u/%u transmitted to %s\n", sTestState.mStats.mTransmit.mActual, sTestState.mStats.mTransmit.mExpected,
913 if (lStatus != INET_NO_ERROR)
915 SetStatusFailed(sTestState.mStatus);
919 static void StartTest()
921 IPAddressType lIPAddressType = kIPAddressType_IPv6;
922 IPProtocol lIPProtocol = kIPProtocol_ICMPv6;
923 IPVersion lIPVersion = kIPVersion_6;
924 IPAddress lAddress = chip::Inet::IPAddress::Any;
927 if (!gNetworkOptions.LocalIPv6Addr.empty())
928 lAddress = gNetworkOptions.LocalIPv6Addr[0];
930 #if INET_CONFIG_ENABLE_IPV4
931 if (gOptFlags & kOptFlagUseIPv4)
933 lIPAddressType = kIPAddressType_IPv4;
934 lIPProtocol = kIPProtocol_ICMPv4;
935 lIPVersion = kIPVersion_4;
936 if (!gNetworkOptions.LocalIPv6Addr.empty())
937 lAddress = gNetworkOptions.LocalIPv4Addr[0];
939 lAddress = chip::Inet::IPAddress::Any;
941 #endif // INET_CONFIG_ENABLE_IPV4
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'));
951 // Allocate the endpoints for sending or receiving.
953 if (gOptFlags & kOptFlagUseRawIP)
955 lStatus = gInet.NewRawEndPoint(lIPVersion, lIPProtocol, &sRawIPEndPoint);
956 INET_FAIL_ERROR(lStatus, "InetLayer::NewRawEndPoint failed");
958 sRawIPEndPoint->OnMessageReceived = HandleRawMessageReceived;
959 sRawIPEndPoint->OnReceiveError = HandleRawReceiveError;
961 if (IsInterfaceIdPresent(gInterfaceId))
963 lStatus = sRawIPEndPoint->BindInterface(lIPAddressType, gInterfaceId);
964 INET_FAIL_ERROR(lStatus, "RawEndPoint::BindInterface failed");
967 else if (gOptFlags & kOptFlagUseUDPIP)
969 lStatus = gInet.NewUDPEndPoint(&sUDPIPEndPoint);
970 INET_FAIL_ERROR(lStatus, "InetLayer::NewUDPEndPoint failed");
972 sUDPIPEndPoint->OnMessageReceived = HandleUDPMessageReceived;
973 sUDPIPEndPoint->OnReceiveError = HandleUDPReceiveError;
975 if (IsInterfaceIdPresent(gInterfaceId))
977 lStatus = sUDPIPEndPoint->BindInterface(lIPAddressType, gInterfaceId);
978 INET_FAIL_ERROR(lStatus, "UDPEndPoint::BindInterface failed");
982 if (Common::IsReceiver())
984 if (gOptFlags & kOptFlagUseRawIP)
986 lStatus = sRawIPEndPoint->Bind(lIPAddressType, lAddress);
987 INET_FAIL_ERROR(lStatus, "RawEndPoint::Bind failed");
989 if (gOptFlags & kOptFlagUseIPv6)
991 lStatus = sRawIPEndPoint->SetICMPFilter(kICMPv6_FilterTypes, gICMPv6Types);
992 INET_FAIL_ERROR(lStatus, "RawEndPoint::SetICMPFilter failed");
995 lStatus = sRawIPEndPoint->Listen();
996 INET_FAIL_ERROR(lStatus, "RawEndPoint::Listen failed");
998 else if (gOptFlags & kOptFlagUseUDPIP)
1000 lStatus = sUDPIPEndPoint->Bind(lIPAddressType, IPAddress::Any, kUDPPort);
1001 INET_FAIL_ERROR(lStatus, "UDPEndPoint::Bind failed");
1003 lStatus = sUDPIPEndPoint->Listen();
1004 INET_FAIL_ERROR(lStatus, "UDPEndPoint::Listen failed");
1006 else if (gOptFlags & kOptFlagUseTCPIP)
1008 const uint16_t lConnectionBacklogMax = 1;
1009 const bool lReuseAddress = true;
1011 lStatus = gInet.NewTCPEndPoint(&sTCPIPListenEndPoint);
1012 INET_FAIL_ERROR(lStatus, "InetLayer::NewTCPEndPoint failed");
1014 sTCPIPListenEndPoint->OnConnectionReceived = HandleTCPConnectionReceived;
1015 sTCPIPListenEndPoint->OnAcceptError = HandleTCPAcceptError;
1017 lStatus = sTCPIPListenEndPoint->Bind(lIPAddressType, IPAddress::Any, kTCPPort, lReuseAddress);
1018 INET_FAIL_ERROR(lStatus, "TCPEndPoint::Bind failed");
1020 lStatus = sTCPIPListenEndPoint->Listen(lConnectionBacklogMax);
1021 INET_FAIL_ERROR(lStatus, "TCPEndPoint::Listen failed");
1025 if (Common::IsReceiver())
1026 printf("Listening...\n");
1031 static void CleanupTest()
1035 gSendIntervalExpired = false;
1036 gSystemLayer.CancelTimer(Common::HandleSendTimerComplete, nullptr);
1038 // Release the resources associated with the allocated end points.
1040 if (sRawIPEndPoint != nullptr)
1042 sRawIPEndPoint->Free();
1045 if (sTCPIPEndPoint != nullptr)
1047 lStatus = sTCPIPEndPoint->Close();
1048 INET_FAIL_ERROR(lStatus, "TCPEndPoint::Close failed");
1050 sTCPIPEndPoint->Free();
1053 if (sTCPIPListenEndPoint != nullptr)
1055 sTCPIPListenEndPoint->Shutdown();
1056 sTCPIPListenEndPoint->Free();
1059 if (sUDPIPEndPoint != nullptr)
1061 sUDPIPEndPoint->Free();