/* * * Copyright (c) 2020-2021 Project CHIP Authors * Copyright (c) 2019 Google LLC * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * This file defines common preprocessor defintions, constants, * functions, and globals for unit and functional tests for the * Inet layer. * */ #include "TestInetLayerCommon.hpp" #include #include #include #include #include #include #include #include "TestInetCommon.h" using namespace ::chip; using namespace ::chip::Inet; using namespace ::chip::System; // Type Definitions struct ICMPEchoHeader { uint8_t mType; uint8_t mCode; uint16_t mChecksum; uint16_t mID; uint16_t mSequenceNumber; } __attribute__((packed)); typedef struct ICMPEchoHeader ICMPv4EchoHeader; typedef struct ICMPEchoHeader ICMPv6EchoHeader; // Global Variables static const uint8_t kICMPv4_EchoRequest = 8; static const uint8_t kICMPv4_EchoReply = 0; static const uint8_t kICMPv6_EchoRequest = 128; static const uint8_t kICMPv6_EchoReply = 129; // clang-format off const uint8_t gICMPv4Types[kICMPv4_FilterTypes] = { kICMPv4_EchoRequest, kICMPv4_EchoReply }; const uint8_t gICMPv6Types[kICMPv6_FilterTypes] = { kICMPv6_EchoRequest, kICMPv6_EchoReply }; // clang-format on bool gSendIntervalExpired = true; uint32_t gSendIntervalMs = 1000; const char * gInterfaceName = nullptr; InterfaceId gInterfaceId = InterfaceId::Null(); uint16_t gSendSize = 59; uint32_t gOptFlags = 0; namespace Common { bool IsReceiver() { return ((gOptFlags & kOptFlagListen) == kOptFlagListen); } bool IsSender() { return (!IsReceiver()); } bool IsTesting(const TestStatus & aTestStatus) { bool lStatus; lStatus = (!aTestStatus.mFailed && !aTestStatus.mSucceeded); return (lStatus); } bool WasSuccessful(const TestStatus & aTestStatus) { bool lStatus = false; if (aTestStatus.mFailed) lStatus = false; else if (aTestStatus.mSucceeded) lStatus = true; return (lStatus); } static void FillDataBufferPattern(uint8_t * aBuffer, size_t aLength, size_t aPatternStartOffset, uint8_t aFirstValue) { for (size_t i = aPatternStartOffset; i < aLength; i++) { const uint8_t lValue = static_cast(aFirstValue & 0xFF); aBuffer[i] = lValue; aFirstValue++; } } static bool CheckDataBufferPattern(const uint8_t * aBuffer, size_t aLength, size_t aPatternStartOffset, size_t aFirstValue) { for (size_t i = aPatternStartOffset; i < aLength; i++) { const uint8_t lValue = aBuffer[i]; if (lValue != static_cast(aFirstValue)) { printf("Bad data value at offset %u (0x%04x): " "expected 0x%02x, found 0x%02x\n", static_cast(i), static_cast(i), static_cast(aFirstValue), lValue); DumpMemory(aBuffer + aPatternStartOffset, static_cast(aLength - aPatternStartOffset), "0x", 16); return false; } aFirstValue++; } return true; } static PacketBufferHandle MakeDataBuffer(size_t aDesiredLength, size_t aPatternStartOffset, uint8_t aFirstValue) { VerifyOrReturnError(aPatternStartOffset <= aDesiredLength, PacketBufferHandle()); PacketBufferHandle lBuffer = PacketBufferHandle::New(aDesiredLength); VerifyOrReturnError(!lBuffer.IsNull(), lBuffer); aDesiredLength = std::min(lBuffer->MaxDataLength(), aDesiredLength); FillDataBufferPattern(lBuffer->Start(), aDesiredLength, aPatternStartOffset, aFirstValue); lBuffer->SetDataLength(aDesiredLength); return lBuffer; } static PacketBufferHandle MakeDataBuffer(size_t aDesiredLength, size_t aPatternStartOffset) { constexpr uint8_t lFirstValue = 0; return MakeDataBuffer(aDesiredLength, aPatternStartOffset, lFirstValue); } template static PacketBufferHandle MakeICMPDataBuffer(size_t aDesiredUserLength, uint16_t aHeaderLength, size_t aPatternStartOffset, uint8_t aType) { static uint16_t lSequenceNumber = 0; PacketBufferHandle lBuffer; // To ensure there is enough room for the user data and the ICMP // header, include both the user data size and the ICMP header length. lBuffer = MakeDataBuffer(aDesiredUserLength + aHeaderLength, aPatternStartOffset); if (!lBuffer.IsNull()) { tType * lHeader = reinterpret_cast(lBuffer->Start()); lHeader->mType = aType; lHeader->mCode = 0; lHeader->mChecksum = 0; lHeader->mID = static_cast(rand() & UINT16_MAX); lHeader->mSequenceNumber = nlByteOrderSwap16HostToBig(lSequenceNumber++); } return (lBuffer); } PacketBufferHandle MakeICMPv4DataBuffer(size_t aDesiredUserLength) { constexpr uint16_t lICMPHeaderLength = sizeof(ICMPv4EchoHeader); constexpr uint16_t lPatternStartOffset = lICMPHeaderLength; const uint8_t lType = gICMPv4Types[kICMP_EchoRequestIndex]; return MakeICMPDataBuffer(aDesiredUserLength, lICMPHeaderLength, lPatternStartOffset, lType); } PacketBufferHandle MakeICMPv6DataBuffer(size_t aDesiredUserLength) { constexpr uint16_t lICMPHeaderLength = sizeof(ICMPv6EchoHeader); constexpr uint16_t lPatternStartOffset = lICMPHeaderLength; const uint8_t lType = gICMPv6Types[kICMP_EchoRequestIndex]; return MakeICMPDataBuffer(aDesiredUserLength, lICMPHeaderLength, lPatternStartOffset, lType); } PacketBufferHandle MakeDataBuffer(size_t aDesiredLength, uint8_t aFirstValue) { constexpr size_t lPatternStartOffset = 0; return MakeDataBuffer(aDesiredLength, lPatternStartOffset, aFirstValue); } PacketBufferHandle MakeDataBuffer(size_t aDesiredLength) { constexpr size_t lPatternStartOffset = 0; return MakeDataBuffer(aDesiredLength, lPatternStartOffset); } static bool HandleDataReceived(const PacketBufferHandle & aBuffer, TransferStats & aStats, bool aStatsByPacket, bool aCheckBuffer, size_t aPatternStartOffset, size_t aFirstValue) { size_t lTotalDataLength = 0; // Walk through each buffer in the packet chain, checking the // buffer for the expected pattern, if requested. for (PacketBufferHandle lBuffer = aBuffer.Retain(); !lBuffer.IsNull(); lBuffer.Advance()) { const size_t lDataLength = lBuffer->DataLength(); const uint8_t * const p = lBuffer->Start(); if (aCheckBuffer && !CheckDataBufferPattern(p, lDataLength, aPatternStartOffset, aFirstValue)) { return false; } lTotalDataLength = lTotalDataLength + lDataLength; aFirstValue = aFirstValue + lDataLength; } // If we are accumulating stats by packet rather than by size, // then increment by one (1) rather than the total buffer length. VerifyOrReturnError(CanCastTo(lTotalDataLength), false); aStats.mReceive.mActual += ((aStatsByPacket) ? 1 : static_cast(lTotalDataLength)); return true; } static bool HandleICMPDataReceived(PacketBufferHandle aBuffer, uint16_t aHeaderLength, TransferStats & aStats, bool aStatsByPacket, bool aCheckBuffer) { const uint16_t lPatternStartOffset = 0; bool lStatus; aBuffer->ConsumeHead(aHeaderLength); lStatus = HandleDataReceived(aBuffer, aStats, aStatsByPacket, aCheckBuffer, lPatternStartOffset); return (lStatus); } bool HandleICMPv4DataReceived(PacketBufferHandle && aBuffer, TransferStats & aStats, bool aStatsByPacket, bool aCheckBuffer) { const uint16_t lICMPHeaderLength = sizeof(ICMPv4EchoHeader); bool lStatus; lStatus = HandleICMPDataReceived(std::move(aBuffer), lICMPHeaderLength, aStats, aStatsByPacket, aCheckBuffer); return (lStatus); } bool HandleICMPv6DataReceived(PacketBufferHandle && aBuffer, TransferStats & aStats, bool aStatsByPacket, bool aCheckBuffer) { const uint16_t lICMPHeaderLength = sizeof(ICMPv6EchoHeader); bool lStatus; lStatus = HandleICMPDataReceived(std::move(aBuffer), lICMPHeaderLength, aStats, aStatsByPacket, aCheckBuffer); return (lStatus); } bool HandleDataReceived(const PacketBufferHandle & aBuffer, TransferStats & aStats, bool aStatsByPacket, bool aCheckBuffer, uint8_t aFirstValue) { const uint16_t lPatternStartOffset = 0; bool lStatus; lStatus = HandleDataReceived(aBuffer, aStats, aStatsByPacket, aCheckBuffer, lPatternStartOffset, aFirstValue); return (lStatus); } bool HandleDataReceived(const PacketBufferHandle & aBuffer, TransferStats & aStats, bool aStatsByPacket, bool aCheckBuffer) { const uint8_t lFirstValue = 0; const uint16_t lPatternStartOffset = 0; bool lStatus; lStatus = HandleDataReceived(aBuffer, aStats, aStatsByPacket, aCheckBuffer, lPatternStartOffset, lFirstValue); return (lStatus); } bool HandleUDPDataReceived(const PacketBufferHandle & aBuffer, TransferStats & aStats, bool aStatsByPacket, bool aCheckBuffer) { bool lStatus; lStatus = HandleDataReceived(aBuffer, aStats, aStatsByPacket, aCheckBuffer); return (lStatus); } bool HandleTCPDataReceived(const PacketBufferHandle & aBuffer, TransferStats & aStats, bool aStatsByPacket, bool aCheckBuffer) { bool lStatus; lStatus = HandleDataReceived(aBuffer, aStats, aStatsByPacket, aCheckBuffer); return (lStatus); } // Timer Callback Handler void HandleSendTimerComplete(System::Layer * aSystemLayer, void * aAppState) { gSendIntervalExpired = true; DriveSend(); } // Raw Endpoint Callback Handlers void HandleRawMessageReceived(const UDPEndPoint * aEndPoint, const PacketBufferHandle & aBuffer, const IPPacketInfo * aPacketInfo) { char lSourceAddressBuffer[INET6_ADDRSTRLEN]; char lDestinationAddressBuffer[INET6_ADDRSTRLEN]; aPacketInfo->SrcAddress.ToString(lSourceAddressBuffer); aPacketInfo->DestAddress.ToString(lDestinationAddressBuffer); printf("Raw message received from %s to %s (%u bytes)\n", lSourceAddressBuffer, lDestinationAddressBuffer, static_cast(aBuffer->DataLength())); } void HandleRawReceiveError(const UDPEndPoint * aEndPoint, const CHIP_ERROR & aError, const IPPacketInfo * aPacketInfo) { char lAddressBuffer[INET6_ADDRSTRLEN]; if (aPacketInfo != nullptr) { aPacketInfo->SrcAddress.ToString(lAddressBuffer); } else { strcpy(lAddressBuffer, "(unknown)"); } printf("IP receive error from %s %s\n", lAddressBuffer, ErrorStr(aError)); } // UDP Endpoint Callback Handlers void HandleUDPMessageReceived(const UDPEndPoint * aEndPoint, const PacketBufferHandle & aBuffer, const IPPacketInfo * aPacketInfo) { char lSourceAddressBuffer[INET6_ADDRSTRLEN]; char lDestinationAddressBuffer[INET6_ADDRSTRLEN]; aPacketInfo->SrcAddress.ToString(lSourceAddressBuffer); aPacketInfo->DestAddress.ToString(lDestinationAddressBuffer); printf("UDP packet received from %s:%u to %s:%u (%u bytes)\n", lSourceAddressBuffer, aPacketInfo->SrcPort, lDestinationAddressBuffer, aPacketInfo->DestPort, static_cast(aBuffer->DataLength())); } void HandleUDPReceiveError(const UDPEndPoint * aEndPoint, const CHIP_ERROR & aError, const IPPacketInfo * aPacketInfo) { char lAddressBuffer[INET6_ADDRSTRLEN]; uint16_t lSourcePort; if (aPacketInfo != nullptr) { aPacketInfo->SrcAddress.ToString(lAddressBuffer); lSourcePort = aPacketInfo->SrcPort; } else { strcpy(lAddressBuffer, "(unknown)"); lSourcePort = 0; } printf("UDP receive error from %s:%u: %s\n", lAddressBuffer, lSourcePort, ErrorStr(aError)); } } // namespace Common