https://git.reactos.org/?p=reactos.git;a=commitdiff;h=740a859e922e1a91a8822…
commit 740a859e922e1a91a88226b53acfd48f57c1767b
Author: Victor Perevertkin <victor.perevertkin(a)reactos.org>
AuthorDate: Mon Nov 18 20:55:10 2019 +0300
Commit: Victor Perevertkin <victor(a)perevertkin.ru>
CommitDate: Tue Apr 7 05:32:40 2020 +0300
[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(-)
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 <pshpack1.h>
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 <poppack.h>
/* 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 <tilists.h>
#include <lock.h>
#include <interface.h>
+#include <fileobjs.h>
#include <chew/chew.h>
#include <pseh/pseh2.h>
+#include <psdk/ipexport.h>
#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(a)reactos.org)
+ */
+
+#include "precomp.h"
+#include <checksum.h>
+
+
+#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(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 );
+ TI_DbgPrint(DEBUG_ICMP, ("Sending ICMP datagram (0x%x)\n", AddrFile));
- 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;
-
- TI_DbgPrint(DEBUG_ICMP, ("Called.\n"));
-
- ICMPHeader = (PICMP_HEADER)IPPacket->Data;
-
- 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));
+ PICMP_HEADER ICMPHeader = (PICMP_HEADER)IPPacket->Data;
+ UINT32 DataSize = IPPacket->TotalSize - IPPacket->HeaderSize;
- TI_DbgPrint(DEBUG_ICMP, ("Code (%d).\n", ICMPHeader->Code));
+ 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));
- 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 too short packets */
+ if (DataSize < sizeof(ICMP_HEADER))
+ {
+ TI_DbgPrint(DEBUG_ICMP, ("Packet doesn't fit ICMP header.
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;
+ /* Discard packets with bad checksum */
+ if (!IPv4CorrectChecksum(IPPacket->Data, DataSize))
+ {
+ TI_DbgPrint(DEBUG_ICMP, ("Bad ICMP checksum. Packet discarded\n"));
+ return;
}
-}
-
-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);
+ RawIpReceive(Interface, IPPacket);
- /* 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);
+ if (ICMPHeader->Type == ICMP_TYPE_ECHO_REQUEST)
+ {
+ ICMPReply(Interface, IPPacket, ICMP_TYPE_ECHO_REPLY, 0);
}
}
-
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));