3 * Copyright (c) 2020 Project CHIP Authors
4 * Copyright (c) 2018-2019 Google LLC
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
22 * This file implements a process to effect a functional test for
23 * the InetLayer Internet Protocol stack abstraction interfaces
24 * for handling IP (v4 or v6) multicast on either bare IP (i.e.,
25 * "raw") or UDP endpoints.
29 #ifndef __STDC_LIMIT_MACROS
30 #define __STDC_LIMIT_MACROS
38 #include <nlbyteorder.hpp>
40 #include <CHIPVersion.h>
42 #include <inet/IPAddress.h>
43 #include <inet/InetArgParser.h>
44 #include <support/CHIPArgParser.hpp>
45 #include <system/SystemTimer.h>
47 #include "TestInetCommon.h"
48 #include "TestInetCommonOptions.h"
49 #include "TestInetLayerCommon.hpp"
50 #include "TestSetupFaultInjection.h"
51 #include "TestSetupSignalling.h"
54 using namespace chip::ArgParser;
55 using namespace chip::Inet;
56 using namespace chip::System;
58 /* Preprocessor Macros */
60 #define kToolName "TestInetLayerMulticast"
62 #define kToolOptNoLoopback 'L'
63 #define kToolOptGroup 'g'
65 #define kToolOptExpectedGroupRxPackets (kToolOptBase + 0)
66 #define kToolOptExpectedGroupTxPackets (kToolOptBase + 1)
68 /* Type Definitions */
72 kOptFlagNoLoopback = 0x00010000
79 IPAddress mMulticastAddress;
82 template <size_t tCapacity>
86 const size_t mCapacity = tCapacity;
87 GroupAddress mAddresses[tCapacity];
90 template <size_t tCapacity>
93 GroupAddresses<tCapacity> & mGroupAddresses;
97 /* Function Declarations */
99 static void HandleSignal(int aSignal);
100 static bool HandleOption(const char * aProgram, OptionSet * aOptions, int aIdentifier, const char * aName, const char * aValue);
101 static bool HandleNonOptionArgs(const char * aProgram, int argc, char * argv[]);
102 static bool ParseGroupOpt(const char * aProgram, const char * aValue, bool aIPv6, uint32_t & aOutLastGroupIndex);
103 static bool ParseAndUpdateExpectedGroupPackets(const char * aProgram, const char * aValue, uint32_t aGroup,
104 const char * aDescription, uint32_t & aOutExpected);
106 static void StartTest();
107 static void CleanupTest();
109 /* Global Variables */
112 static const uint32_t kOptFlagsDefault = (kOptFlagUseIPv6 | kOptFlagUseRawIP);
114 static RawEndPoint * sRawIPEndPoint = nullptr;
115 static UDPEndPoint * sUDPIPEndPoint = nullptr;
117 static GroupAddresses<4> sGroupAddresses;
119 static TestState<4> sTestState =
125 static uint32_t sLastGroupIndex = 0;
127 static OptionDef sToolOptionDefs[] =
129 { "interface", kArgumentRequired, kToolOptInterface },
130 { "group", kArgumentRequired, kToolOptGroup },
131 { "group-expected-rx-packets", kArgumentRequired, kToolOptExpectedGroupRxPackets },
132 { "group-expected-tx-packets", kArgumentRequired, kToolOptExpectedGroupTxPackets },
133 { "interval", kArgumentRequired, kToolOptInterval },
134 #if INET_CONFIG_ENABLE_IPV4
135 { "ipv4", kNoArgument, kToolOptIPv4Only },
136 #endif // INET_CONFIG_ENABLE_IPV4
137 { "ipv6", kNoArgument, kToolOptIPv6Only },
138 { "listen", kNoArgument, kToolOptListen },
139 { "no-loopback", kNoArgument, kToolOptNoLoopback },
140 { "raw", kNoArgument, kToolOptRawIP },
141 { "send-size", kArgumentRequired, kToolOptSendSize },
142 { "udp", kNoArgument, kToolOptUDPIP },
146 static const char * sToolOptionHelp =
147 " -I, --interface <interface>\n"
148 " The network interface to bind to and from which to send and receive all packets.\n"
150 " -L, --no-loopback\n"
151 " Suppress the loopback of multicast packets.\n"
153 " -g, --group <group>\n"
154 " Multicast group number to join.\n"
156 " --group-expected-rx-packets <packets>\n"
157 " Expect to receive this number of packets for the previously-specified multicast group.\n"
159 " --group-expected-tx-packets <packets>\n"
160 " Expect to send this number of packets for the previously-specified multicast group.\n"
162 " -i, --interval <interval>\n"
163 " Wait interval milliseconds between sending each packet (default: 1000 ms).\n"
166 " Act as a server (i.e., listen) for packets rather than send them.\n"
168 #if INET_CONFIG_ENABLE_IPV4
172 #endif // INET_CONFIG_ENABLE_IPV4
174 " Use IPv6 only (default).\n"
176 " -s, --send-size <size>\n"
177 " Send size bytes of user data (default: 59 bytes)\n"
180 " Use raw IP (default).\n"
183 " Use UDP over IP.\n"
186 static OptionSet sToolOptions =
194 static HelpOptions sHelpOptions(
196 "Usage: " kToolName " [ <options> ] [ -g <group> [ ... ] -I <interface> ]\n",
197 CHIP_VERSION_STRING "\n" CHIP_TOOL_COPYRIGHT
200 static OptionSet * sToolOptionSets[] =
204 &gFaultInjectionOptions,
210 static void CheckSucceededOrFailed(const GroupAddress & aAddress, bool & aOutSucceeded, bool & aOutFailed)
212 const TransferStats & lStats = aAddress.mStats;
215 printf("Group %u: %u/%u sent, %u/%u received\n", aAddress.mGroup, lStats.mTransmit.mActual, lStats.mTransmit.mExpected,
216 lStats.mReceive.mActual, lStats.mReceive.mExpected);
219 if (((lStats.mTransmit.mExpected > 0) && (lStats.mTransmit.mActual > lStats.mTransmit.mExpected)) ||
220 ((lStats.mReceive.mExpected > 0) && (lStats.mReceive.mActual > lStats.mReceive.mExpected)))
224 else if (((lStats.mTransmit.mExpected > 0) && (lStats.mTransmit.mActual < lStats.mTransmit.mExpected)) ||
225 ((lStats.mReceive.mExpected > 0) && (lStats.mReceive.mActual < lStats.mReceive.mExpected)))
227 aOutSucceeded = false;
231 template <size_t tCapacity>
232 static void CheckSucceededOrFailed(TestState<tCapacity> & aTestState, bool & aOutSucceeded, bool & aOutFailed)
234 for (size_t i = 0; i < aTestState.mGroupAddresses.mSize; i++)
236 const GroupAddress & lGroup = aTestState.mGroupAddresses.mAddresses[i];
238 CheckSucceededOrFailed(lGroup, aOutSucceeded, aOutFailed);
241 if (aOutSucceeded || aOutFailed)
244 aTestState.mStatus.mSucceeded = true;
247 SetStatusFailed(aTestState.mStatus);
251 static void HandleSignal(int aSignal)
257 SetStatusFailed(sTestState.mStatus);
262 namespace TestInetLayerMulticast {
263 int main(int argc, char * argv[])
265 bool lSuccessful = true;
268 InitTestInetCommon();
270 SetupFaultInjectionContext(argc, argv);
272 SetSignalHandler(HandleSignal);
276 sHelpOptions.PrintBriefUsage(stderr);
281 if (!ParseArgsFromEnvVar(kToolName, TOOL_OPTIONS_ENV_VAR_NAME, sToolOptionSets, nullptr, true) ||
282 !ParseArgs(kToolName, argc, argv, sToolOptionSets, HandleNonOptionArgs))
292 // At this point, we should have valid network interfaces,
293 // including LwIP TUN/TAP shim interfaces. Validate the
294 // -I/--interface argument, if present.
296 if (gInterfaceName != nullptr)
298 lStatus = InterfaceNameToId(gInterfaceName, gInterfaceId);
299 if (lStatus != INET_NO_ERROR)
301 PrintArgError("%s: unknown network interface %s\n", kToolName, gInterfaceName);
307 // If any multicast groups have been specified, ensure that a
308 // network interface identifier has been specified and is valid.
310 if ((sGroupAddresses.mSize > 0) && !IsInterfaceIdPresent(gInterfaceId))
312 PrintArgError("%s: a network interface is required when specifying one or more multicast groups\n", kToolName);
319 while (Common::IsTesting(sTestState.mStatus))
321 struct timeval sleepTime;
322 bool lSucceeded = true;
323 bool lFailed = false;
325 sleepTime.tv_sec = 0;
326 sleepTime.tv_usec = 10000;
328 ServiceNetwork(sleepTime);
330 CheckSucceededOrFailed(sTestState, lSucceeded, lFailed);
333 printf("%s %s number of expected packets\n", ((lSucceeded) ? "successfully" : ((lFailed) ? "failed to" : "has not yet")),
335 ? (Common::IsReceiver() ? "received" : "sent")
336 : ((lFailed) ? (Common::IsReceiver() ? "receive" : "send") : Common::IsReceiver() ? "received" : "sent")));
344 ShutdownSystemLayer();
346 lSuccessful = Common::WasSuccessful(sTestState.mStatus);
349 return (lSuccessful ? EXIT_SUCCESS : EXIT_FAILURE);
351 } // namespace TestInetLayerMulticast
353 static bool HandleOption(const char * aProgram, OptionSet * aOptions, int aIdentifier, const char * aName, const char * aValue)
360 case kToolOptInterval:
361 if (!ParseInt(aValue, gSendIntervalMs))
363 PrintArgError("%s: invalid value specified for send interval: %s\n", aProgram, aValue);
369 gOptFlags |= kOptFlagListen;
372 case kToolOptNoLoopback:
373 gOptFlags |= kOptFlagNoLoopback;
377 if (!ParseGroupOpt(aProgram, aValue, gOptFlags & kOptFlagUseIPv6, sLastGroupIndex))
383 case kToolOptExpectedGroupRxPackets: {
384 GroupAddress & lGroupAddress = sGroupAddresses.mAddresses[sLastGroupIndex];
386 if (!ParseAndUpdateExpectedGroupPackets(aProgram, aValue, lGroupAddress.mGroup, "received",
387 lGroupAddress.mStats.mReceive.mExpected))
394 case kToolOptExpectedGroupTxPackets: {
395 GroupAddress & lGroupAddress = sGroupAddresses.mAddresses[sLastGroupIndex];
397 if (!ParseAndUpdateExpectedGroupPackets(aProgram, aValue, lGroupAddress.mGroup, "sent",
398 lGroupAddress.mStats.mTransmit.mExpected))
405 #if INET_CONFIG_ENABLE_IPV4
406 case kToolOptIPv4Only:
407 if (gOptFlags & kOptFlagUseIPv6)
409 PrintArgError("%s: the use of --ipv4 is exclusive with --ipv6. Please select only one of the two options.\n", aProgram);
412 gOptFlags |= kOptFlagUseIPv4;
414 #endif // INET_CONFIG_ENABLE_IPV4
416 case kToolOptIPv6Only:
417 if (gOptFlags & kOptFlagUseIPv4)
419 PrintArgError("%s: the use of --ipv6 is exclusive with --ipv4. Please select only one of the two options.\n", aProgram);
422 gOptFlags |= kOptFlagUseIPv6;
425 case kToolOptInterface:
427 // NOTE: When using LwIP on a hosted OS, the interface will
428 // not actually be available until AFTER InitNetwork,
429 // consequently, we cannot do any meaningful validation
430 // here. Simply save the value off and we will validate it
433 gInterfaceName = aValue;
437 if (gOptFlags & kOptFlagUseUDPIP)
439 PrintArgError("%s: the use of --raw is exclusive with --udp. Please select only one of the two options.\n", aProgram);
442 gOptFlags |= kOptFlagUseRawIP;
445 case kToolOptSendSize:
446 if (!ParseInt(aValue, gSendSize))
448 PrintArgError("%s: invalid value specified for send size: %s\n", aProgram, aValue);
454 if (gOptFlags & kOptFlagUseRawIP)
456 PrintArgError("%s: the use of --udp is exclusive with --raw. Please select only one of the two options.\n", aProgram);
459 gOptFlags |= kOptFlagUseUDPIP;
463 PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", aProgram, aName);
471 bool HandleNonOptionArgs(const char * aProgram, int argc, char * argv[])
475 if ((gOptFlags & (kOptFlagListen | kOptFlagNoLoopback)) == (kOptFlagListen | kOptFlagNoLoopback))
477 PrintArgError("%s: the listen option is exclusive with the loopback suppression option. Please select one or the other.\n",
483 // If there were any additional, non-parsed arguments, it's an error.
487 PrintArgError("%s: unexpected argument: %s\n", aProgram, argv[0]);
492 // If no IP version or transport flags were specified, use the defaults.
494 if (!(gOptFlags & (kOptFlagUseIPv4 | kOptFlagUseIPv6 | kOptFlagUseRawIP | kOptFlagUseUDPIP)))
496 gOptFlags |= kOptFlagsDefault;
503 // Create an IPv4 administratively-scoped multicast address
505 static IPAddress MakeIPv4Multicast(uint32_t aGroupIdentifier)
509 lAddress.Addr[0] = 0;
510 lAddress.Addr[1] = 0;
511 lAddress.Addr[2] = nlByteOrderSwap32HostToBig(0xFFFF);
512 lAddress.Addr[3] = nlByteOrderSwap32HostToBig((239 << 24) | (aGroupIdentifier & 0xFFFFFF));
517 // Create an IPv6 site-scoped multicast address
519 static IPAddress MakeIPv6Multicast(uint32_t aGroupIdentifier)
521 const uint8_t lFlags = kIPv6MulticastFlag_Transient;
523 return (IPAddress::MakeIPv6Multicast(lFlags, kIPv6MulticastScope_Site, aGroupIdentifier));
526 static void SetGroup(GroupAddress & aGroupAddress, uint32_t aGroupIdentifier, uint32_t aExpectedRx, uint32_t aExpectedTx)
528 aGroupAddress.mGroup = aGroupIdentifier;
529 aGroupAddress.mStats.mReceive.mExpected = aExpectedRx;
530 aGroupAddress.mStats.mReceive.mActual = 0;
531 aGroupAddress.mStats.mTransmit.mExpected = aExpectedTx;
532 aGroupAddress.mStats.mTransmit.mActual = 0;
535 static bool ParseGroupOpt(const char * aProgram, const char * aValue, bool aIPv6, uint32_t & aOutLastGroupIndex)
537 uint32_t lGroupIdentifier;
540 if (sGroupAddresses.mSize == sGroupAddresses.mCapacity)
542 PrintArgError("%s: the maximum number of allowed groups (%zu) have been specified\n", aProgram, sGroupAddresses.mCapacity);
547 if (!ParseInt(aValue, lGroupIdentifier))
549 PrintArgError("%s: unrecognized group %s\n", aProgram, aValue);
554 aOutLastGroupIndex = sGroupAddresses.mSize++;
556 SetGroup(sGroupAddresses.mAddresses[aOutLastGroupIndex], lGroupIdentifier, lGroupIdentifier, lGroupIdentifier);
562 static bool ParseAndUpdateExpectedGroupPackets(const char * aProgram, const char * aValue, uint32_t aGroup,
563 const char * aDescription, uint32_t & aOutExpected)
565 uint32_t lExpectedGroupPackets;
568 if (!ParseInt(aValue, lExpectedGroupPackets))
570 PrintArgError("%s: invalid value specified for expected group %u %s packets: %s\n", aProgram, aGroup, aDescription, aValue);
575 aOutExpected = lExpectedGroupPackets;
581 static GroupAddress * FindGroupAddress(const IPAddress & aSourceAddress)
583 GroupAddress * lResult = nullptr;
585 for (size_t i = 0; i < sGroupAddresses.mSize; i++)
587 GroupAddress & lGroupAddress = sGroupAddresses.mAddresses[i];
589 if (lGroupAddress.mMulticastAddress == aSourceAddress)
591 lResult = &lGroupAddress;
599 static void PrintReceivedStats(const GroupAddress & aGroupAddress)
601 printf("%u/%u received for multicast group %u\n", aGroupAddress.mStats.mReceive.mActual,
602 aGroupAddress.mStats.mReceive.mExpected, aGroupAddress.mGroup);
605 static bool HandleDataReceived(const PacketBufferHandle & aBuffer, GroupAddress & aGroupAddress, bool aCheckBuffer)
607 const bool lStatsByPacket = true;
610 lStatus = Common::HandleDataReceived(aBuffer, aGroupAddress.mStats, lStatsByPacket, aCheckBuffer);
611 VerifyOrExit(lStatus == true, );
613 PrintReceivedStats(aGroupAddress);
619 static bool HandleDataReceived(const PacketBufferHandle & aBuffer, const IPPacketInfo & aPacketInfo, bool aCheckBuffer)
622 GroupAddress * lGroupAddress;
624 lGroupAddress = FindGroupAddress(aPacketInfo.DestAddress);
626 if (lGroupAddress != nullptr)
628 lStatus = HandleDataReceived(aBuffer, *lGroupAddress, aCheckBuffer);
629 VerifyOrExit(lStatus == true, );
636 // Raw Endpoint Callbacks
638 static void HandleRawMessageReceived(IPEndPointBasis * aEndPoint, PacketBufferHandle aBuffer, const IPPacketInfo * aPacketInfo)
640 const bool lCheckBuffer = true;
641 const bool lStatsByPacket = true;
642 IPAddressType lAddressType;
644 GroupAddress * lGroupAddress;
646 VerifyOrExit(aEndPoint != nullptr, lStatus = false);
647 VerifyOrExit(!aBuffer.IsNull(), lStatus = false);
648 VerifyOrExit(aPacketInfo != nullptr, lStatus = false);
650 Common::HandleRawMessageReceived(aEndPoint, aBuffer, aPacketInfo);
652 lGroupAddress = FindGroupAddress(aPacketInfo->DestAddress);
654 if (lGroupAddress != nullptr)
656 lAddressType = aPacketInfo->DestAddress.Type();
658 if (lAddressType == kIPAddressType_IPv4)
660 const uint16_t kIPv4HeaderSize = 20;
662 aBuffer->ConsumeHead(kIPv4HeaderSize);
664 lStatus = Common::HandleICMPv4DataReceived(std::move(aBuffer), lGroupAddress->mStats, lStatsByPacket, lCheckBuffer);
666 else if (lAddressType == kIPAddressType_IPv6)
668 lStatus = Common::HandleICMPv6DataReceived(std::move(aBuffer), lGroupAddress->mStats, lStatsByPacket, lCheckBuffer);
677 PrintReceivedStats(*lGroupAddress);
684 SetStatusFailed(sTestState.mStatus);
688 static void HandleRawReceiveError(IPEndPointBasis * aEndPoint, INET_ERROR aError, const IPPacketInfo * aPacketInfo)
690 Common::HandleRawReceiveError(aEndPoint, aError, aPacketInfo);
692 SetStatusFailed(sTestState.mStatus);
695 // UDP Endpoint Callbacks
697 static void HandleUDPMessageReceived(IPEndPointBasis * aEndPoint, PacketBufferHandle aBuffer, const IPPacketInfo * aPacketInfo)
699 const bool lCheckBuffer = true;
702 VerifyOrExit(aEndPoint != nullptr, lStatus = false);
703 VerifyOrExit(!aBuffer.IsNull(), lStatus = false);
704 VerifyOrExit(aPacketInfo != nullptr, lStatus = false);
706 Common::HandleUDPMessageReceived(aEndPoint, aBuffer, aPacketInfo);
708 lStatus = HandleDataReceived(std::move(aBuffer), *aPacketInfo, lCheckBuffer);
713 SetStatusFailed(sTestState.mStatus);
717 static void HandleUDPReceiveError(IPEndPointBasis * aEndPoint, INET_ERROR aError, const IPPacketInfo * aPacketInfo)
719 Common::HandleUDPReceiveError(aEndPoint, aError, aPacketInfo);
721 SetStatusFailed(sTestState.mStatus);
724 static bool IsTransportReadyForSend()
726 bool lStatus = false;
728 if ((gOptFlags & (kOptFlagUseRawIP)) == (kOptFlagUseRawIP))
730 lStatus = (sRawIPEndPoint != nullptr);
732 else if ((gOptFlags & kOptFlagUseUDPIP) == kOptFlagUseUDPIP)
734 lStatus = (sUDPIPEndPoint != nullptr);
740 static INET_ERROR PrepareTransportForSend()
742 INET_ERROR lStatus = INET_NO_ERROR;
747 static INET_ERROR DriveSendForDestination(const IPAddress & aAddress, uint16_t aSize)
749 PacketBufferHandle lBuffer;
750 INET_ERROR lStatus = INET_NO_ERROR;
752 if ((gOptFlags & (kOptFlagUseRawIP)) == (kOptFlagUseRawIP))
754 // For ICMP (v4 or v6), we'll send n aSize or smaller
755 // datagrams (with overhead for the ICMP header), each
756 // patterned from zero to aSize - 1, following the ICMP
759 if ((gOptFlags & kOptFlagUseIPv6) == (kOptFlagUseIPv6))
761 lBuffer = Common::MakeICMPv6DataBuffer(aSize);
762 VerifyOrExit(!lBuffer.IsNull(), lStatus = INET_ERROR_NO_MEMORY);
764 #if INET_CONFIG_ENABLE_IPV4
765 else if ((gOptFlags & kOptFlagUseIPv4) == (kOptFlagUseIPv4))
767 lBuffer = Common::MakeICMPv4DataBuffer(aSize);
768 VerifyOrExit(!lBuffer.IsNull(), lStatus = INET_ERROR_NO_MEMORY);
770 #endif // INET_CONFIG_ENABLE_IPV4
772 lStatus = sRawIPEndPoint->SendTo(aAddress, std::move(lBuffer));
773 SuccessOrExit(lStatus);
777 if ((gOptFlags & kOptFlagUseUDPIP) == kOptFlagUseUDPIP)
779 const uint8_t lFirstValue = 0;
781 // For UDP, we'll send n aSize or smaller datagrams, each
782 // patterned from zero to aSize - 1.
784 lBuffer = Common::MakeDataBuffer(aSize, lFirstValue);
785 VerifyOrExit(!lBuffer.IsNull(), lStatus = INET_ERROR_NO_MEMORY);
787 lStatus = sUDPIPEndPoint->SendTo(aAddress, kUDPPort, std::move(lBuffer));
788 SuccessOrExit(lStatus);
796 static INET_ERROR DriveSendForGroup(GroupAddress & aGroupAddress)
798 INET_ERROR lStatus = INET_NO_ERROR;
800 if (aGroupAddress.mStats.mTransmit.mActual < aGroupAddress.mStats.mTransmit.mExpected)
802 lStatus = DriveSendForDestination(aGroupAddress.mMulticastAddress, gSendSize);
803 SuccessOrExit(lStatus);
805 aGroupAddress.mStats.mTransmit.mActual++;
807 printf("%u/%u transmitted for multicast group %u\n", aGroupAddress.mStats.mTransmit.mActual,
808 aGroupAddress.mStats.mTransmit.mExpected, aGroupAddress.mGroup);
815 template <size_t tCapacity>
816 static INET_ERROR DriveSendForGroups(GroupAddresses<tCapacity> & aGroupAddresses)
818 INET_ERROR lStatus = INET_NO_ERROR;
820 // Iterate over each multicast group for which this node is a
821 // member and send a packet.
823 for (size_t i = 0; i < aGroupAddresses.mSize; i++)
825 GroupAddress & lGroupAddress = aGroupAddresses.mAddresses[i];
827 lStatus = DriveSendForGroup(lGroupAddress);
828 SuccessOrExit(lStatus);
837 INET_ERROR lStatus = INET_NO_ERROR;
839 if (!Common::IsSender())
842 if (!gSendIntervalExpired)
845 if (!IsTransportReadyForSend())
847 lStatus = PrepareTransportForSend();
848 SuccessOrExit(lStatus);
852 gSendIntervalExpired = false;
853 gSystemLayer.StartTimer(gSendIntervalMs, Common::HandleSendTimerComplete, nullptr);
855 lStatus = DriveSendForGroups(sGroupAddresses);
856 SuccessOrExit(lStatus);
860 if (lStatus != INET_NO_ERROR)
862 SetStatusFailed(sTestState.mStatus);
866 static void StartTest()
868 IPAddressType lIPAddressType = kIPAddressType_IPv6;
869 IPProtocol lIPProtocol = kIPProtocol_ICMPv6;
870 IPVersion lIPVersion = kIPVersion_6;
871 IPAddress lAddress = IPAddress::Any;
872 IPEndPointBasis * lEndPoint = nullptr;
873 const bool lUseLoopback = ((gOptFlags & kOptFlagNoLoopback) == 0);
876 #if INET_CONFIG_ENABLE_IPV4
877 if (gOptFlags & kOptFlagUseIPv4)
879 lIPAddressType = kIPAddressType_IPv4;
880 lIPProtocol = kIPProtocol_ICMPv4;
881 lIPVersion = kIPVersion_4;
883 #endif // INET_CONFIG_ENABLE_IPV4
886 printf("Using %sIP%s, device interface: %s (w/%c LwIP)\n",
887 ((gOptFlags & kOptFlagUseRawIP) ? "" : "UDP/"),
888 ((gOptFlags & kOptFlagUseIPv4) ? "v4" : "v6"),
889 ((gInterfaceName) ? gInterfaceName : "<none>"),
890 (CHIP_SYSTEM_CONFIG_USE_LWIP ? '\0' : 'o'));
893 // Allocate the endpoints for sending or receiving.
895 if (gOptFlags & kOptFlagUseRawIP)
897 lStatus = gInet.NewRawEndPoint(lIPVersion, lIPProtocol, &sRawIPEndPoint);
898 INET_FAIL_ERROR(lStatus, "InetLayer::NewRawEndPoint failed");
900 sRawIPEndPoint->OnMessageReceived = HandleRawMessageReceived;
901 sRawIPEndPoint->OnReceiveError = HandleRawReceiveError;
903 lStatus = sRawIPEndPoint->Bind(lIPAddressType, lAddress);
904 INET_FAIL_ERROR(lStatus, "RawEndPoint::Bind failed");
906 if (gOptFlags & kOptFlagUseIPv6)
908 lStatus = sRawIPEndPoint->SetICMPFilter(kICMPv6_FilterTypes, gICMPv6Types);
909 INET_FAIL_ERROR(lStatus, "RawEndPoint::SetICMPFilter (IPv6) failed");
912 if (IsInterfaceIdPresent(gInterfaceId))
914 lStatus = sRawIPEndPoint->BindInterface(lIPAddressType, gInterfaceId);
915 INET_FAIL_ERROR(lStatus, "RawEndPoint::BindInterface failed");
918 lStatus = sRawIPEndPoint->Listen();
919 INET_FAIL_ERROR(lStatus, "RawEndPoint::Listen failed");
921 lEndPoint = sRawIPEndPoint;
923 else if (gOptFlags & kOptFlagUseUDPIP)
925 lStatus = gInet.NewUDPEndPoint(&sUDPIPEndPoint);
926 INET_FAIL_ERROR(lStatus, "InetLayer::NewUDPEndPoint failed");
928 sUDPIPEndPoint->OnMessageReceived = HandleUDPMessageReceived;
929 sUDPIPEndPoint->OnReceiveError = HandleUDPReceiveError;
931 lStatus = sUDPIPEndPoint->Bind(lIPAddressType, lAddress, kUDPPort);
932 INET_FAIL_ERROR(lStatus, "UDPEndPoint::Bind failed");
934 if (IsInterfaceIdPresent(gInterfaceId))
936 lStatus = sUDPIPEndPoint->BindInterface(lIPAddressType, gInterfaceId);
937 INET_FAIL_ERROR(lStatus, "UDPEndPoint::BindInterface failed");
940 lStatus = sUDPIPEndPoint->Listen();
941 INET_FAIL_ERROR(lStatus, "UDPEndPoint::Listen failed");
943 lEndPoint = sUDPIPEndPoint;
946 // If loopback suppression has been requested, attempt to disable
947 // it; otherwise, attempt to enable it.
949 lStatus = lEndPoint->SetMulticastLoopback(lIPVersion, lUseLoopback);
950 INET_FAIL_ERROR(lStatus, "SetMulticastLoopback failed");
952 // Configure and join the multicast groups
954 for (size_t i = 0; i < sGroupAddresses.mSize; i++)
956 char lAddressBuffer[INET6_ADDRSTRLEN];
957 GroupAddress & lGroupAddress = sGroupAddresses.mAddresses[i];
958 IPAddress & lMulticastAddress = lGroupAddress.mMulticastAddress;
960 if ((lEndPoint != nullptr) && IsInterfaceIdPresent(gInterfaceId))
962 if (gOptFlags & kOptFlagUseIPv4)
964 lMulticastAddress = MakeIPv4Multicast(lGroupAddress.mGroup);
968 lMulticastAddress = MakeIPv6Multicast(lGroupAddress.mGroup);
971 lMulticastAddress.ToString(lAddressBuffer, sizeof(lAddressBuffer));
973 printf("Will join multicast group %s\n", lAddressBuffer);
975 lStatus = lEndPoint->JoinMulticastGroup(gInterfaceId, lMulticastAddress);
976 INET_FAIL_ERROR(lStatus, "Could not join multicast group");
980 if (Common::IsReceiver())
981 printf("Listening...\n");
986 static void CleanupTest()
988 IPEndPointBasis * lEndPoint = nullptr;
991 gSendIntervalExpired = false;
992 gSystemLayer.CancelTimer(Common::HandleSendTimerComplete, nullptr);
994 // Leave the multicast groups
996 if (gOptFlags & kOptFlagUseRawIP)
998 lEndPoint = sRawIPEndPoint;
1000 else if (gOptFlags & kOptFlagUseUDPIP)
1002 lEndPoint = sUDPIPEndPoint;
1005 for (size_t i = 0; i < sGroupAddresses.mSize; i++)
1007 char lAddressBuffer[INET6_ADDRSTRLEN];
1008 GroupAddress & lGroupAddress = sGroupAddresses.mAddresses[i];
1009 IPAddress & lMulticastAddress = lGroupAddress.mMulticastAddress;
1011 if ((lEndPoint != nullptr) && IsInterfaceIdPresent(gInterfaceId))
1013 lMulticastAddress.ToString(lAddressBuffer, sizeof(lAddressBuffer));
1015 printf("Will leave multicast group %s\n", lAddressBuffer);
1017 lStatus = lEndPoint->LeaveMulticastGroup(gInterfaceId, lMulticastAddress);
1018 INET_FAIL_ERROR(lStatus, "Could not leave multicast group");
1022 // Release the resources associated with the allocated end points.
1024 if (sRawIPEndPoint != nullptr)
1026 sRawIPEndPoint->Free();
1029 if (sUDPIPEndPoint != nullptr)
1031 sUDPIPEndPoint->Free();