From 740a859e922e1a91a88226b53acfd48f57c1767b Mon Sep 17 00:00:00 2001 From: Victor Perevertkin Date: Mon, 18 Nov 2019 20:55:10 +0300 Subject: [PATCH] [TCPIP] Implement IOCTL_ICMP_ECHO_REQUEST in tcpip.sys Also clean up ICMP handling code in sdk/lib/drivers/ip CORE-10760 --- drivers/network/tcpip/CMakeLists.txt | 1 + drivers/network/tcpip/include/icmp.h | 22 +- drivers/network/tcpip/include/precomp.h | 2 + drivers/network/tcpip/include/rawip.h | 10 + drivers/network/tcpip/tcpip/icmp.c | 431 +++++++++++++++++++++ drivers/network/tcpip/tcpip/main.c | 9 +- media/doc/README.WINE | 1 - sdk/lib/drivers/ip/network/icmp.c | 268 ++----------- sdk/lib/drivers/ip/transport/rawip/rawip.c | 2 +- 9 files changed, 505 insertions(+), 241 deletions(-) create mode 100644 drivers/network/tcpip/tcpip/icmp.c diff --git a/drivers/network/tcpip/CMakeLists.txt b/drivers/network/tcpip/CMakeLists.txt index 0dd5a5271e0..53b2c571cff 100644 --- a/drivers/network/tcpip/CMakeLists.txt +++ b/drivers/network/tcpip/CMakeLists.txt @@ -17,6 +17,7 @@ list(APPEND SOURCE tcpip/cinfo.c tcpip/dispatch.c tcpip/fileobjs.c + tcpip/icmp.c tcpip/iinfo.c tcpip/info.c tcpip/lock.c diff --git a/drivers/network/tcpip/include/icmp.h b/drivers/network/tcpip/include/icmp.h index e0902e02737..eb0f9b3faed 100644 --- a/drivers/network/tcpip/include/icmp.h +++ b/drivers/network/tcpip/include/icmp.h @@ -7,12 +7,15 @@ #pragma once +#include typedef struct ICMP_HEADER { - UCHAR Type; /* ICMP message type */ - UCHAR Code; /* ICMP message code */ - USHORT Checksum; /* ICMP message checksum */ - ULONG Unused; /* ICMP unused */ + UINT8 Type; /* ICMP message type */ + UINT8 Code; /* ICMP message code */ + UINT16 Checksum; /* ICMP message checksum */ + UINT16 Identifier; /* ICMP Echo message identifier */ + UINT16 Seq; /* ICMP Echo message sequence num */ } ICMP_HEADER, *PICMP_HEADER; +#include /* ICMP message types */ #define ICMP_TYPE_ECHO_REPLY 0 /* Echo reply */ @@ -48,6 +51,12 @@ typedef struct ICMP_HEADER { /* ICMP codes for ICMP_TYPE_PARAMETER */ #define ICMP_CODE_TP_POINTER 1 /* Pointer indicates the error */ +NTSTATUS +DispEchoRequest( + PDEVICE_OBJECT DeviceObject, + PIRP Irp, + PIO_STACK_LOCATION IrpSp); + NTSTATUS ICMPSendDatagram( PADDRESS_FILE AddrFile, PTDI_CONNECTION_INFORMATION ConnInfo, @@ -63,11 +72,6 @@ VOID ICMPReceive( PIP_INTERFACE Interface, PIP_PACKET IPPacket); -VOID ICMPTransmit( - PIP_PACKET IPPacket, - PIP_TRANSMIT_COMPLETE Complete, - PVOID Context); - VOID ICMPReply( PIP_INTERFACE Interface, PIP_PACKET IPPacket, diff --git a/drivers/network/tcpip/include/precomp.h b/drivers/network/tcpip/include/precomp.h index a96c4a51c3e..3055bc57bd3 100644 --- a/drivers/network/tcpip/include/precomp.h +++ b/drivers/network/tcpip/include/precomp.h @@ -15,7 +15,9 @@ #include #include #include +#include #include #include +#include #endif /* _TCPIP_PCH_ */ diff --git a/drivers/network/tcpip/include/rawip.h b/drivers/network/tcpip/include/rawip.h index 821fdb4f868..7a5feba27f8 100644 --- a/drivers/network/tcpip/include/rawip.h +++ b/drivers/network/tcpip/include/rawip.h @@ -36,4 +36,14 @@ NTSTATUS AddGenericHeaderIPv4( UINT ExtraLength, PVOID *NextHeader ); +NTSTATUS BuildRawIpPacket( + PADDRESS_FILE AddrFile, + PIP_PACKET Packet, + PIP_ADDRESS RemoteAddress, + USHORT RemotePort, + PIP_ADDRESS LocalAddress, + USHORT LocalPort, + PCHAR DataBuffer, + UINT DataLen); + /* EOF */ diff --git a/drivers/network/tcpip/tcpip/icmp.c b/drivers/network/tcpip/tcpip/icmp.c new file mode 100644 index 00000000000..7603e2551a5 --- /dev/null +++ b/drivers/network/tcpip/tcpip/icmp.c @@ -0,0 +1,431 @@ +/* + * PROJECT: ReactOS TCP/IP protocol driver + * LICENCE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: ICMP functions implementation + * COPYRIGHT: 2019 Victor Perevertkin (victor.perevertkin@reactos.org) + */ + +#include "precomp.h" +#include + + +#define UINT16_MAX (65535U) + +typedef struct _ICMP_PACKET_CONTEXT +{ + TDI_REQUEST TdiRequest; + KDPC TimeoutDpc; + KEVENT InitializationFinishedEvent; + KEVENT DatagramProcessedEvent; + LARGE_INTEGER TimerResolution; + INT64 StartTicks; + PIRP Irp; + PUCHAR CurrentReply; + UINT32 RemainingSize; + LONG nReplies; + PIO_WORKITEM FinishWorker; + KTIMER TimeoutTimer; +} ICMP_PACKET_CONTEXT, *PICMP_PACKET_CONTEXT; + +static volatile INT16 IcmpSequence = 0; + +static +UINT32 +GetReplyStatus(PICMP_HEADER IcmpHeader) +{ + switch (IcmpHeader->Type) + { + case ICMP_TYPE_ECHO_REPLY: + return IP_SUCCESS; + case ICMP_TYPE_DEST_UNREACH: + switch (IcmpHeader->Code) + { + case ICMP_CODE_DU_NET_UNREACH: + return IP_DEST_NET_UNREACHABLE; + case ICMP_CODE_DU_HOST_UNREACH: + return IP_DEST_HOST_UNREACHABLE; + case ICMP_CODE_DU_PROTOCOL_UNREACH: + return IP_DEST_PROT_UNREACHABLE; + case ICMP_CODE_DU_PORT_UNREACH: + return IP_DEST_PORT_UNREACHABLE; + case ICMP_CODE_DU_FRAG_DF_SET: + return IP_DEST_NET_UNREACHABLE; + case ICMP_CODE_DU_SOURCE_ROUTE_FAILED: + return IP_BAD_ROUTE; + default: + return IP_DEST_NET_UNREACHABLE; + } + case ICMP_TYPE_SOURCE_QUENCH: + return IP_SOURCE_QUENCH; + case ICMP_TYPE_TIME_EXCEEDED: + if (IcmpHeader->Code == ICMP_CODE_TE_REASSEMBLY) + return IP_TTL_EXPIRED_REASSEM; + else + return IP_TTL_EXPIRED_TRANSIT; + case ICMP_TYPE_PARAMETER: + return IP_PARAM_PROBLEM; + default: + return IP_REQ_TIMED_OUT; + } +} + +static +VOID +ClearReceiveHandler( + _In_ PADDRESS_FILE AddrFile) +{ + KIRQL OldIrql; + + LockObject(AddrFile, &OldIrql); + AddrFile->RegisteredReceiveDatagramHandler = FALSE; + UnlockObject(AddrFile, OldIrql); +} + +IO_WORKITEM_ROUTINE EndRequestHandler; + +VOID +NTAPI +EndRequestHandler( + PDEVICE_OBJECT DeviceObject, + PVOID _Context) +{ + PICMP_PACKET_CONTEXT Context = (PICMP_PACKET_CONTEXT)_Context; + PIO_STACK_LOCATION CurrentStack; + PIRP Irp; + UINT32 nReplies; + KIRQL OldIrql; + + KeWaitForSingleObject(&Context->DatagramProcessedEvent, Executive, KernelMode, FALSE, NULL); + + TI_DbgPrint(DEBUG_ICMP, ("Finishing request Context: %p\n", Context)); + + Irp = Context->Irp; + CurrentStack = IoGetCurrentIrpStackLocation(Irp); + + if (Context->nReplies > 0) + { + ((PICMP_ECHO_REPLY)Irp->AssociatedIrp.SystemBuffer)->Reserved = Context->nReplies; + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = CurrentStack->Parameters.DeviceIoControl.OutputBufferLength; + } + else + { + PICMP_ECHO_REPLY ReplyBuffer = (PICMP_ECHO_REPLY)Irp->AssociatedIrp.SystemBuffer; + RtlZeroMemory(ReplyBuffer, sizeof(*ReplyBuffer)); + ReplyBuffer->Status = IP_REQ_TIMED_OUT; + + Irp->IoStatus.Status = STATUS_TIMEOUT; + Irp->IoStatus.Information = sizeof(*ReplyBuffer); + } + + // for debugging + nReplies = ((PICMP_ECHO_REPLY)Irp->AssociatedIrp.SystemBuffer)->Reserved; + + // taken from dispatch.c:IRPFinish + IoAcquireCancelSpinLock(&OldIrql); + IoSetCancelRoutine(Irp, NULL); + IoReleaseCancelSpinLock(OldIrql); + IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); + + { + NTSTATUS _Status = FileCloseAddress(&Context->TdiRequest); + ASSERT(NT_SUCCESS(_Status)); + } + + IoFreeWorkItem(Context->FinishWorker); + ExFreePoolWithTag(Context, OUT_DATA_TAG); + + TI_DbgPrint(DEBUG_ICMP, ("Leaving, nReplies: %u\n", nReplies)); +} + +NTSTATUS +NTAPI +ReceiveDatagram( + _In_opt_ PVOID TdiEventContext, + _In_ LONG SourceAddressLength, + _In_reads_bytes_(SourceAddressLength) PVOID SourceAddress, + _In_ LONG OptionsLength, + _In_reads_bytes_opt_(OptionsLength) PVOID Options, + _In_ ULONG ReceiveDatagramFlags, + _In_ ULONG BytesIndicated, + _In_ ULONG BytesAvailable, + _Out_ ULONG *OutBytesTaken, + _In_ PVOID Tsdu, + _Out_opt_ PIRP *IoRequestPacket) +{ + PICMP_PACKET_CONTEXT Context = TdiEventContext; + PIPv4_HEADER IpHeader = Tsdu; + UINT16 IpHeaderSize = sizeof(IPv4_HEADER) + OptionsLength; + PICMP_HEADER IcmpHeader = (PICMP_HEADER)((PUCHAR)Tsdu + IpHeaderSize); + + PVOID DataBuffer = (PUCHAR)Tsdu + IpHeaderSize + sizeof(ICMP_HEADER); + INT32 DataSize = min(BytesAvailable, UINT16_MAX) - IpHeaderSize - sizeof(ICMP_HEADER); + + INT64 CurrentTime; + UINT32 RoundTripTime; + PICMP_ECHO_REPLY CurrentReply; + PUCHAR CurrentUserBuffer; + + // do not handle echo requests + if (DataSize >= 0 && IcmpHeader->Type == ICMP_TYPE_ECHO_REQUEST) + { + return STATUS_SUCCESS; + } + + KeWaitForSingleObject(&Context->InitializationFinishedEvent, Executive, KernelMode, FALSE, NULL); + KeClearEvent(&Context->DatagramProcessedEvent); + + ASSERT(SourceAddressLength == sizeof(IPAddr)); + TI_DbgPrint(DEBUG_ICMP, ("Received datagram Context: 0x%p\n", TdiEventContext)); + + CurrentTime = KeQueryPerformanceCounter(NULL).QuadPart; + RoundTripTime = (CurrentTime - Context->StartTicks) * 1000 / Context->TimerResolution.QuadPart; + CurrentReply = (PICMP_ECHO_REPLY)Context->CurrentReply; + + if (Context->RemainingSize >= sizeof(ICMP_ECHO_REPLY) && DataSize >= 0) + { + TI_DbgPrint(DEBUG_ICMP, ("RemainingSize: %u, RoundTripTime: %u\n", Context->RemainingSize, RoundTripTime)); + + memcpy(&CurrentReply->Address, SourceAddress, sizeof(CurrentReply->Address)); + CurrentReply->Status = GetReplyStatus(IcmpHeader); + CurrentReply->RoundTripTime = RoundTripTime; + CurrentReply->Reserved = 0; + CurrentReply->Data = NULL; + CurrentReply->DataSize = 0; + CurrentReply->Options.Ttl = IpHeader->Ttl; + CurrentReply->Options.Tos = IpHeader->Tos; + CurrentReply->Options.Flags = IpHeader->FlagsFragOfs >> 13; + CurrentReply->Options.OptionsData = NULL; + CurrentReply->Options.OptionsSize = 0; + + Context->RemainingSize -= sizeof(ICMP_ECHO_REPLY); + Context->CurrentReply += sizeof(ICMP_ECHO_REPLY); + } + + CurrentUserBuffer = (PUCHAR)Context->Irp->UserBuffer + (Context->CurrentReply - (PUCHAR)Context->Irp->AssociatedIrp.SystemBuffer); + + if (DataSize > 0 && Context->RemainingSize > 0) + { + UINT32 _DataSize = min(Context->RemainingSize, DataSize); + + memcpy(Context->CurrentReply + Context->RemainingSize - _DataSize, DataBuffer, _DataSize); + CurrentReply->Data = CurrentUserBuffer + Context->RemainingSize - _DataSize; + CurrentReply->DataSize = _DataSize; + + Context->RemainingSize -= _DataSize; + // Context->ReplyBuffer += _DataSize; + } + else + { + TI_DbgPrint(DEBUG_ICMP, ("RemainingSize: %u, DataSize: %d\n", Context->RemainingSize, DataSize)); + } + + if (OptionsLength > 0 && Context->RemainingSize > 0) + { + UINT32 _OptSize = min(Context->RemainingSize, OptionsLength); + + memcpy(Context->CurrentReply + Context->RemainingSize + _OptSize, Options, _OptSize); + CurrentReply->Options.OptionsData = CurrentUserBuffer + Context->RemainingSize + _OptSize; + CurrentReply->Options.OptionsSize = _OptSize; + + Context->RemainingSize -= _OptSize; + // Context->ReplyBuffer += _OptSize; + } + else + { + TI_DbgPrint(DEBUG_ICMP, ("RemainingSize: %u, OptSize: %d\n", Context->RemainingSize, OptionsLength)); + } + + Context->nReplies++; + + if (Context->RemainingSize < sizeof(ICMP_ECHO_REPLY)) + { + TI_DbgPrint(DEBUG_ICMP, ("The space is over: %u\n", Context->RemainingSize)); + + // if the timer was inserted, that means DPC has not been queued yet + if (KeCancelTimer(&Context->TimeoutTimer)) + { + PADDRESS_FILE AddrFile = (PADDRESS_FILE)Context->TdiRequest.Handle.AddressHandle; + ClearReceiveHandler(AddrFile); + + IoQueueWorkItem(Context->FinishWorker, &EndRequestHandler, DelayedWorkQueue, Context); + } + } + + KeSetEvent(&Context->DatagramProcessedEvent, IO_NO_INCREMENT, FALSE); + return STATUS_SUCCESS; +} + +KDEFERRED_ROUTINE TimeoutHandler; + +VOID +NTAPI +TimeoutHandler( + _In_ PKDPC Dpc, + _In_opt_ PVOID _Context, + _In_opt_ PVOID SystemArgument1, + _In_opt_ PVOID SystemArgument2) +{ + PICMP_PACKET_CONTEXT Context = (PICMP_PACKET_CONTEXT)_Context; + PADDRESS_FILE AddrFile = (PADDRESS_FILE)Context->TdiRequest.Handle.AddressHandle; + ClearReceiveHandler(AddrFile); + + IoQueueWorkItem(Context->FinishWorker, &EndRequestHandler, DelayedWorkQueue, _Context); +} + +NTSTATUS +DispEchoRequest( + _In_ PDEVICE_OBJECT DeviceObject, + _In_ PIRP Irp, + _In_ PIO_STACK_LOCATION IrpSp) +{ + PICMP_ECHO_REQUEST Request = Irp->AssociatedIrp.SystemBuffer; + UINT32 OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength; + UINT32 InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength; + NTSTATUS Status; + TDI_CONNECTION_INFORMATION ConnectionInfo; + TA_IP_ADDRESS RemoteAddressTa, LocalAddressTa; + PADDRESS_FILE AddrFile; + ULONG DataUsed; + PUCHAR Buffer; + UINT16 RequestSize; + PICMP_PACKET_CONTEXT SendContext; + KIRQL OldIrql; + LARGE_INTEGER RequestTimeout; + UINT8 SavedTtl; + + TI_DbgPrint(DEBUG_ICMP, ("About to send datagram, OutputBufferLength: %u, SystemBuffer: %p\n", OutputBufferLength, Irp->AssociatedIrp.SystemBuffer)); + + // check buffers + if (OutputBufferLength < sizeof(ICMP_ECHO_REPLY) || InputBufferLength < sizeof(ICMP_ECHO_REQUEST)) + { + return STATUS_INVALID_PARAMETER; + } + + // check request parameters + if ((Request->DataSize > UINT16_MAX - sizeof(ICMP_HEADER) - sizeof(IPv4_HEADER)) || + ((UINT32)Request->DataOffset + Request->DataSize > InputBufferLength) || + ((UINT32)Request->OptionsOffset + Request->OptionsSize > InputBufferLength)) + { + return STATUS_INVALID_PARAMETER; + } + + SendContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(*SendContext), OUT_DATA_TAG); + if (!SendContext) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(&SendContext->TdiRequest, sizeof(SendContext->TdiRequest)); + SendContext->TdiRequest.RequestContext = Irp; + + // setting up everything needed for sending the packet + + RtlZeroMemory(&RemoteAddressTa, sizeof(RemoteAddressTa)); + RtlZeroMemory(&LocalAddressTa, sizeof(LocalAddressTa)); + RtlZeroMemory(&ConnectionInfo, sizeof(ConnectionInfo)); + + RemoteAddressTa.TAAddressCount = 1; + RemoteAddressTa.Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP; + RemoteAddressTa.Address[0].AddressType = TDI_ADDRESS_TYPE_IP; + RemoteAddressTa.Address[0].Address[0].in_addr = Request->Address; + + LocalAddressTa.TAAddressCount = 1; + LocalAddressTa.Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP; + LocalAddressTa.Address[0].AddressType = TDI_ADDRESS_TYPE_IP; + LocalAddressTa.Address[0].Address[0].in_addr = 0; + + Status = FileOpenAddress(&SendContext->TdiRequest, &LocalAddressTa, IPPROTO_ICMP, FALSE, NULL); + + if (!NT_SUCCESS(Status)) + { + TI_DbgPrint(DEBUG_ICMP, ("Failed to open address file status: 0x%x\n", Status)); + + ExFreePoolWithTag(SendContext, OUT_DATA_TAG); + + return Status; + } + + AddrFile = (PADDRESS_FILE)SendContext->TdiRequest.Handle.AddressHandle; + + // setting up the context + + KeQueryPerformanceCounter(&SendContext->TimerResolution); + SendContext->Irp = Irp; + SendContext->CurrentReply = Irp->AssociatedIrp.SystemBuffer; + SendContext->RemainingSize = OutputBufferLength; + SendContext->nReplies = 0; + SendContext->FinishWorker = IoAllocateWorkItem(DeviceObject); + KeInitializeEvent(&SendContext->InitializationFinishedEvent, NotificationEvent, FALSE); + KeInitializeEvent(&SendContext->DatagramProcessedEvent, NotificationEvent, TRUE); + + KeInitializeDpc(&SendContext->TimeoutDpc, &TimeoutHandler, SendContext); + KeInitializeTimerEx(&SendContext->TimeoutTimer, SynchronizationTimer); + + RequestTimeout.QuadPart = (-1LL) * 10 * 1000 * Request->Timeout; + + ConnectionInfo.RemoteAddress = &RemoteAddressTa; + ConnectionInfo.RemoteAddressLength = sizeof(RemoteAddressTa); + + RequestSize = sizeof(ICMP_HEADER) + Request->DataSize; + + // making up the request packet + Buffer = ExAllocatePoolWithTag(NonPagedPool, RequestSize, OUT_DATA_TAG); + + if (!Buffer) + { + ExFreePoolWithTag(SendContext, OUT_DATA_TAG); + + return STATUS_INSUFFICIENT_RESOURCES; + } + + ((PICMP_HEADER)Buffer)->Type = ICMP_TYPE_ECHO_REQUEST; + ((PICMP_HEADER)Buffer)->Code = ICMP_TYPE_ECHO_REPLY; + ((PICMP_HEADER)Buffer)->Checksum = 0; + ((PICMP_HEADER)Buffer)->Identifier = (UINT_PTR)PsGetCurrentProcessId() & UINT16_MAX; + ((PICMP_HEADER)Buffer)->Seq = InterlockedIncrement16(&IcmpSequence); + memcpy(Buffer + sizeof(ICMP_HEADER), (PUCHAR)Request + Request->DataOffset, Request->DataSize); + ((PICMP_HEADER)Buffer)->Checksum = IPv4Checksum(Buffer, RequestSize, 0); + SavedTtl = Request->Ttl; + + RtlZeroMemory(Irp->AssociatedIrp.SystemBuffer, OutputBufferLength); + + LockObject(AddrFile, &OldIrql); + + AddrFile->TTL = SavedTtl; + AddrFile->ReceiveDatagramHandlerContext = SendContext; + AddrFile->ReceiveDatagramHandler = ReceiveDatagram; + AddrFile->RegisteredReceiveDatagramHandler = TRUE; + + UnlockObject(AddrFile, OldIrql); + + Status = AddrFile->Send(AddrFile, &ConnectionInfo, (PCHAR)Buffer, RequestSize, &DataUsed); + + // From this point we may receive a reply packet. + // But we are not ready for it thus InitializationFinishedEvent is needed (see below) + + SendContext->StartTicks = KeQueryPerformanceCounter(NULL).QuadPart; + + ExFreePoolWithTag(Buffer, OUT_DATA_TAG); + + if (!NT_SUCCESS(Status)) + { + NTSTATUS _Status; + + ClearReceiveHandler(AddrFile); + _Status = FileCloseAddress(&SendContext->TdiRequest); + ASSERT(NT_SUCCESS(_Status)); + + IoFreeWorkItem(SendContext->FinishWorker); + ExFreePoolWithTag(SendContext, OUT_DATA_TAG); + + TI_DbgPrint(DEBUG_ICMP, ("Failed to send a datagram: 0x%x\n", Status)); + return Status; + } + + IoMarkIrpPending(Irp); + KeSetTimer(&SendContext->TimeoutTimer, RequestTimeout, &SendContext->TimeoutDpc); + KeSetEvent(&SendContext->InitializationFinishedEvent, IO_NO_INCREMENT, FALSE); + + return STATUS_PENDING; +} diff --git a/drivers/network/tcpip/tcpip/main.c b/drivers/network/tcpip/tcpip/main.c index 919d0260221..b99a66f1092 100644 --- a/drivers/network/tcpip/tcpip/main.c +++ b/drivers/network/tcpip/tcpip/main.c @@ -475,12 +475,12 @@ TiDispatchInternal( /** * @brief Dispatch routine for IRP_MJ_DEVICE_CONTROL requests - * + * * @param[in] DeviceObject * Pointer to a device object for this driver * @param[in] Irp * Pointer to a I/O request packet - * + * * @return * Status of the operation */ @@ -538,6 +538,11 @@ TiDispatch( Status = DispTdiQueryIpHwAddress(DeviceObject, Irp, IrpSp); break; + case IOCTL_ICMP_ECHO_REQUEST: + TI_DbgPrint(MIN_TRACE, ("ICMP_ECHO_REQUEST\n")); + Status = DispEchoRequest(DeviceObject, Irp, IrpSp); + break; + default: TI_DbgPrint(MIN_TRACE, ("Unknown IOCTL 0x%X\n", IrpSp->Parameters.DeviceIoControl.IoControlCode)); diff --git a/media/doc/README.WINE b/media/doc/README.WINE index 5a0a9cb1a15..947ac3b1d97 100644 --- a/media/doc/README.WINE +++ b/media/doc/README.WINE @@ -270,7 +270,6 @@ gdi32 - dll/win32/gdi32/objects/linedda.c # Synced at 20090410 iphlpapi - - dll/win32/iphlpapi/icmp.c # Synced to WineStaging-1.7.55 modules/rostests/winetests/iphlpapi # Synced to WineStaging-1.9.11 kernel32 - diff --git a/sdk/lib/drivers/ip/network/icmp.c b/sdk/lib/drivers/ip/network/icmp.c index b95ecaa2edf..509f994b31f 100644 --- a/sdk/lib/drivers/ip/network/icmp.c +++ b/sdk/lib/drivers/ip/network/icmp.c @@ -26,95 +26,6 @@ NTSTATUS ICMPShutdown() return STATUS_SUCCESS; } -BOOLEAN PrepareICMPPacket( - PADDRESS_FILE AddrFile, - PIP_INTERFACE Interface, - PIP_PACKET IPPacket, - PIP_ADDRESS Destination, - PCHAR Data, - UINT DataSize) -/* - * FUNCTION: Prepares an ICMP packet - * ARGUMENTS: - * NTE = Pointer to net table entry to use - * Destination = Pointer to destination address - * DataSize = Size of dataarea - * RETURNS: - * Pointer to IP packet, NULL if there is not enough free resources - */ -{ - PNDIS_PACKET NdisPacket; - NDIS_STATUS NdisStatus; - PIPv4_HEADER IPHeader; - ULONG Size; - - TI_DbgPrint(DEBUG_ICMP, ("Called. DataSize (%d).\n", DataSize)); - - IPInitializePacket(IPPacket, IP_ADDRESS_V4); - - /* No special flags */ - IPPacket->Flags = 0; - - Size = sizeof(IPv4_HEADER) + DataSize; - - /* Allocate NDIS packet */ - NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL, Size ); - - if( !NT_SUCCESS(NdisStatus) ) return FALSE; - - IPPacket->NdisPacket = NdisPacket; - IPPacket->MappedHeader = TRUE; - - GetDataPtr( IPPacket->NdisPacket, 0, - (PCHAR *)&IPPacket->Header, &IPPacket->TotalSize ); - ASSERT(IPPacket->TotalSize == Size); - - TI_DbgPrint(DEBUG_ICMP, ("Size (%d). Data at (0x%X).\n", Size, Data)); - TI_DbgPrint(DEBUG_ICMP, ("NdisPacket at (0x%X).\n", NdisPacket)); - - IPPacket->HeaderSize = sizeof(IPv4_HEADER); - IPPacket->Data = ((PCHAR)IPPacket->Header) + IPPacket->HeaderSize; - - TI_DbgPrint(DEBUG_ICMP, ("Copying Address: %x -> %x\n", - &IPPacket->DstAddr, Destination)); - - RtlCopyMemory(&IPPacket->DstAddr, Destination, sizeof(IP_ADDRESS)); - RtlCopyMemory(IPPacket->Data, Data, DataSize); - - /* Build IPv4 header. FIXME: IPv4 only */ - - IPHeader = (PIPv4_HEADER)IPPacket->Header; - - /* Version = 4, Length = 5 DWORDs */ - IPHeader->VerIHL = 0x45; - /* Normal Type-of-Service */ - IPHeader->Tos = 0; - /* Length of data and header */ - IPHeader->TotalLength = WH2N((USHORT)DataSize + sizeof(IPv4_HEADER)); - /* Identification */ - IPHeader->Id = (USHORT)Random(); - /* One fragment at offset 0 */ - IPHeader->FlagsFragOfs = 0; - /* Set TTL */ - if (AddrFile) - IPHeader->Ttl = AddrFile->TTL; - else - IPHeader->Ttl = 128; - /* Internet Control Message Protocol */ - IPHeader->Protocol = IPPROTO_ICMP; - /* Checksum is 0 (for later calculation of this) */ - IPHeader->Checksum = 0; - /* Source address */ - IPHeader->SrcAddr = Interface->Unicast.Address.IPv4Address; - /* Destination address */ - IPHeader->DstAddr = Destination->Address.IPv4Address; - - - TI_DbgPrint(MID_TRACE,("Leaving\n")); - - return TRUE; -} - NTSTATUS ICMPSendDatagram( PADDRESS_FILE AddrFile, PTDI_CONNECTION_INFORMATION ConnInfo, @@ -132,79 +43,10 @@ NTSTATUS ICMPSendDatagram( * Status of operation */ { - IP_PACKET Packet; - PTA_IP_ADDRESS RemoteAddressTa = (PTA_IP_ADDRESS)ConnInfo->RemoteAddress; - IP_ADDRESS RemoteAddress, LocalAddress; - NTSTATUS Status; - PNEIGHBOR_CACHE_ENTRY NCE; - KIRQL OldIrql; + TI_DbgPrint(DEBUG_ICMP, ("Sending ICMP datagram (0x%x)\n", AddrFile)); - TI_DbgPrint(MID_TRACE,("Sending Datagram(%x %x %x %d)\n", - AddrFile, ConnInfo, BufferData, DataSize)); - TI_DbgPrint(MID_TRACE,("RemoteAddressTa: %x\n", RemoteAddressTa)); - - switch( RemoteAddressTa->Address[0].AddressType ) { - case TDI_ADDRESS_TYPE_IP: - RemoteAddress.Type = IP_ADDRESS_V4; - RemoteAddress.Address.IPv4Address = - RemoteAddressTa->Address[0].Address[0].in_addr; - break; - - default: - return STATUS_UNSUCCESSFUL; - } - - TI_DbgPrint(MID_TRACE,("About to get route to destination\n")); - - LockObject(AddrFile, &OldIrql); - - LocalAddress = AddrFile->Address; - if (AddrIsUnspecified(&LocalAddress)) - { - /* If the local address is unspecified (0), - * then use the unicast address of the - * interface we're sending over - */ - if(!(NCE = RouteGetRouteToDestination( &RemoteAddress ))) - { - UnlockObject(AddrFile, OldIrql); - return STATUS_NETWORK_UNREACHABLE; - } - - LocalAddress = NCE->Interface->Unicast; - } - else - { - if(!(NCE = NBLocateNeighbor( &LocalAddress, NULL ))) - { - UnlockObject(AddrFile, OldIrql); - return STATUS_INVALID_PARAMETER; - } - } - - Status = PrepareICMPPacket( AddrFile, - NCE->Interface, - &Packet, - &RemoteAddress, - BufferData, - DataSize ); - - UnlockObject(AddrFile, OldIrql); - - if( !NT_SUCCESS(Status) ) - return Status; - - TI_DbgPrint(MID_TRACE,("About to send datagram\n")); - - Status = IPSendDatagram(&Packet, NCE); - if (!NT_SUCCESS(Status)) - return Status; - - *DataUsed = DataSize; - - TI_DbgPrint(MID_TRACE,("Leaving\n")); - - return STATUS_SUCCESS; + /* just forward the call to RawIP handler */ + return RawIPSendDatagram(AddrFile, ConnInfo, BufferData, DataSize, DataUsed); } @@ -218,81 +60,34 @@ VOID ICMPReceive( * IPPacket = Pointer to an IP packet that was received */ { - PICMP_HEADER ICMPHeader; + PICMP_HEADER ICMPHeader = (PICMP_HEADER)IPPacket->Data; + UINT32 DataSize = IPPacket->TotalSize - IPPacket->HeaderSize; - TI_DbgPrint(DEBUG_ICMP, ("Called.\n")); + TI_DbgPrint(DEBUG_ICMP, ("ICMPReceive: Size (%d) HeaderSize (%d) Type (%d) Code (%d) Checksum (0x%x)\n", + IPPacket->TotalSize, IPPacket->HeaderSize, ICMPHeader->Type, ICMPHeader->Code, ICMPHeader->Checksum)); - ICMPHeader = (PICMP_HEADER)IPPacket->Data; + /* Discard too short packets */ + if (DataSize < sizeof(ICMP_HEADER)) + { + TI_DbgPrint(DEBUG_ICMP, ("Packet doesn't fit ICMP header. Discarded\n")); + return; + } - TI_DbgPrint(DEBUG_ICMP, ("Size (%d).\n", IPPacket->TotalSize)); - - TI_DbgPrint(DEBUG_ICMP, ("HeaderSize (%d).\n", IPPacket->HeaderSize)); - - TI_DbgPrint(DEBUG_ICMP, ("Type (%d).\n", ICMPHeader->Type)); - - TI_DbgPrint(DEBUG_ICMP, ("Code (%d).\n", ICMPHeader->Code)); - - TI_DbgPrint(DEBUG_ICMP, ("Checksum (0x%X).\n", ICMPHeader->Checksum)); - - /* Checksum ICMP header and data */ - if (!IPv4CorrectChecksum(IPPacket->Data, IPPacket->TotalSize - IPPacket->HeaderSize)) { - TI_DbgPrint(DEBUG_ICMP, ("Bad ICMP checksum.\n")); - /* Discard packet */ + /* Discard packets with bad checksum */ + if (!IPv4CorrectChecksum(IPPacket->Data, DataSize)) + { + TI_DbgPrint(DEBUG_ICMP, ("Bad ICMP checksum. Packet discarded\n")); return; } RawIpReceive(Interface, IPPacket); - switch (ICMPHeader->Type) { - case ICMP_TYPE_ECHO_REQUEST: - ICMPReply( Interface, IPPacket, ICMP_TYPE_ECHO_REPLY, 0 ); - break; - - case ICMP_TYPE_ECHO_REPLY: - break; - - default: - TI_DbgPrint(DEBUG_ICMP, - ("Discarded ICMP datagram of unknown type %d.\n", - ICMPHeader->Type)); - /* Discard packet */ - break; + if (ICMPHeader->Type == ICMP_TYPE_ECHO_REQUEST) + { + ICMPReply(Interface, IPPacket, ICMP_TYPE_ECHO_REPLY, 0); } } - -VOID ICMPTransmit( - PIP_PACKET IPPacket, - PIP_TRANSMIT_COMPLETE Complete, - PVOID Context) -/* - * FUNCTION: Transmits an ICMP packet - * ARGUMENTS: - * NTE = Pointer to net table entry to use (NULL if don't care) - * IPPacket = Pointer to IP packet to transmit - */ -{ - PNEIGHBOR_CACHE_ENTRY NCE; - - TI_DbgPrint(DEBUG_ICMP, ("Called.\n")); - - /* Calculate checksum of ICMP header and data */ - ((PICMP_HEADER)IPPacket->Data)->Checksum = (USHORT) - IPv4Checksum(IPPacket->Data, IPPacket->TotalSize - IPPacket->HeaderSize, 0); - - /* Get a route to the destination address */ - if ((NCE = RouteGetRouteToDestination(&IPPacket->DstAddr))) { - /* Send the packet */ - IPSendDatagram(IPPacket, NCE); - } else { - /* No route to destination (or no free resources) */ - TI_DbgPrint(DEBUG_ICMP, ("No route to destination address 0x%X.\n", - IPPacket->DstAddr.Address.IPv4Address)); - IPPacket->Free(IPPacket); - } -} - - VOID ICMPReply( PIP_INTERFACE Interface, PIP_PACKET IPPacket, @@ -314,19 +109,36 @@ VOID ICMPReply( { UINT DataSize; IP_PACKET NewPacket; + ADDRESS_FILE FakeAddrFile; + PNEIGHBOR_CACHE_ENTRY NCE; TI_DbgPrint(DEBUG_ICMP, ("Called. Type (%d) Code (%d).\n", Type, Code)); DataSize = IPPacket->TotalSize - IPPacket->HeaderSize; - if( !PrepareICMPPacket(NULL, Interface, &NewPacket, &IPPacket->SrcAddr, - IPPacket->Data, DataSize) ) return; + /* First check if we have a route to sender */ + NCE = RouteGetRouteToDestination(&IPPacket->SrcAddr); + if (!NCE) + { + return; + } + + /* This is the only data needed to generate a packet */ + FakeAddrFile.Protocol = IPPROTO_ICMP; + FakeAddrFile.TTL = 128; + + if (!NT_SUCCESS(BuildRawIpPacket( + &FakeAddrFile, &NewPacket, &IPPacket->SrcAddr, 0, &Interface->Unicast, 0, IPPacket->Data, DataSize))) + { + return; + } ((PICMP_HEADER)NewPacket.Data)->Type = Type; ((PICMP_HEADER)NewPacket.Data)->Code = Code; ((PICMP_HEADER)NewPacket.Data)->Checksum = 0; + ((PICMP_HEADER)NewPacket.Data)->Checksum = (USHORT)IPv4Checksum(NewPacket.Data, DataSize, 0); - ICMPTransmit(&NewPacket, NULL, NULL); + IPSendDatagram(&NewPacket, NCE); } /* EOF */ diff --git a/sdk/lib/drivers/ip/transport/rawip/rawip.c b/sdk/lib/drivers/ip/transport/rawip/rawip.c index 180f545db39..7e7fb22436a 100644 --- a/sdk/lib/drivers/ip/transport/rawip/rawip.c +++ b/sdk/lib/drivers/ip/transport/rawip/rawip.c @@ -46,7 +46,7 @@ NTSTATUS AddGenericHeaderIPv4( &IPPacket->TotalSize ); IPPacket->MappedHeader = TRUE; - IPPacket->HeaderSize = 20; + IPPacket->HeaderSize = sizeof(IPv4_HEADER); TI_DbgPrint(MAX_TRACE, ("Allocated %d bytes for headers at 0x%X.\n", BufferSize, IPPacket->Header));