[TCPIP] Implement IOCTL_ICMP_ECHO_REQUEST in tcpip.sys
authorVictor Perevertkin <victor.perevertkin@reactos.org>
Mon, 18 Nov 2019 17:55:10 +0000 (20:55 +0300)
committerVictor Perevertkin <victor@perevertkin.ru>
Tue, 7 Apr 2020 02:32:40 +0000 (05:32 +0300)
Also clean up ICMP handling code in sdk/lib/drivers/ip
CORE-10760

drivers/network/tcpip/CMakeLists.txt
drivers/network/tcpip/include/icmp.h
drivers/network/tcpip/include/precomp.h
drivers/network/tcpip/include/rawip.h
drivers/network/tcpip/tcpip/icmp.c [new file with mode: 0644]
drivers/network/tcpip/tcpip/main.c
media/doc/README.WINE
sdk/lib/drivers/ip/network/icmp.c
sdk/lib/drivers/ip/transport/rawip/rawip.c

index 0dd5a52..53b2c57 100644 (file)
@@ -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
index e0902e0..eb0f9b3 100644 (file)
@@ -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,
index a96c4a5..3055bc5 100644 (file)
@@ -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_ */
index 821fdb4..7a5feba 100644 (file)
@@ -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 (file)
index 0000000..7603e25
--- /dev/null
@@ -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 <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;
+}
index 919d026..b99a66f 100644 (file)
@@ -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));
index 5a0a9cb..947ac3b 100644 (file)
@@ -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 -
index b95ecaa..509f994 100644 (file)
@@ -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 */
index 180f545..7e7fb22 100644 (file)
@@ -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));