Index: dll/win32/iphlpapi/icmp.c
===================================================================
--- dll/win32/iphlpapi/icmp.c	(revision 70522)
+++ dll/win32/iphlpapi/icmp.c	(working copy)
@@ -1,918 +1,608 @@
 /*
- * ICMP
- *
- * Francois Gouget, 1999, based on the work of
- *   RW Hall, 1999, based on public domain code PING.C by Mike Muus (1983)
- *   and later works (c) 1989 Regents of Univ. of California - see copyright
- *   notice at end of source-code.
- * Copyright 2015 Sebastian Lackner
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ * PROJECT:         ReactOS IP Helper API
+ * LICENSE:         LGPLv2.1+ - See COPYING.LIB in the top level directory
+ * FILE:            dll/win32/iphlpapi/icmp.c
+ * PURPOSE:         ICMP functions
+ * PROGRAMMERS:     Tim Crawford <crawfxrd@gmail.com>
  */
 
-/* Future work:
- * - Systems like FreeBSD don't seem to support the IP_TTL option and maybe others.
- *   But using IP_HDRINCL and building the IP header by hand might work.
- * - Not all IP options are supported.
- * - Are ICMP handles real handles, i.e. inheritable and all? There might be some
- *   more work to do here, including server side stuff with synchronization.
- * - This API should probably be thread safe. Is it really?
- * - Using the winsock functions has not been tested.
- */
+/*
+#define WIN32_NO_STATUS
+#define _INC_WINDOWS
+#define COM_NO_WINDOWS_H
 
-#include "iphlpapi_private.h"
+#include <windef.h>
+#include <winbase.h>
 
-/* Set up endianness macros for the ip and ip_icmp BSD headers */
-#ifndef BIG_ENDIAN
-#define BIG_ENDIAN       4321
-#endif
-#ifndef LITTLE_ENDIAN
-#define LITTLE_ENDIAN    1234
-#endif
-#ifndef BYTE_ORDER
-#ifdef WORDS_BIGENDIAN
-#define BYTE_ORDER       BIG_ENDIAN
-#else
-#define BYTE_ORDER       LITTLE_ENDIAN
-#endif
-#endif /* BYTE_ORDER */
+#define NTOS_MODE_USER
+#include <ndk/iofuncs.h>
+#include <ndk/obfuncs.h>
+#include <ndk/rtlfuncs.h>
 
-#define u_int16_t  WORD
-#define u_int32_t  DWORD
+#include <ws2tcpip.h>
+#include <iphlpapi.h>
 
-/* These are BSD headers. We use these here because they are needed on
- * libc5 Linux systems. On other platforms they are usually simply more
- * complete than the native stuff, and cause less portability problems
- * so we use them anyway.
- */
-#include "ip.h"
-#include "ip_icmp.h"
+#include <debug.h>
+*/
 
+#include "iphlpapi_private.h"
 
-WINE_DEFAULT_DEBUG_CHANNEL(icmp);
-WINE_DECLARE_DEBUG_CHANNEL(winediag);
+WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
 
 
-typedef struct {
-    int sid;
-    IP_OPTION_INFORMATION default_opts;
-} icmp_t;
+// XXX: Only reference I've found says ICMP uses 0x120000.
+#define IOCTL_ICMP_ECHO_REQUEST \
+    CTL_CODE(FILE_DEVICE_NETWORK, 0, METHOD_BUFFERED, FILE_ANY_ACCESS)
 
-#define IP_OPTS_UNKNOWN     0
-#define IP_OPTS_DEFAULT     1
-#define IP_OPTS_CUSTOM      2
 
-/* The sequence number is unique process wide, so that all threads
- * have a distinct sequence number.
- */
-static LONG icmp_sequence=0;
+typedef struct _ICMP_ECHO_REQUEST
+{
+    IPAddr Address;
+    ULONG  Timeout;
+    USHORT DataOffset;
+    USHORT DataSize;
+    UCHAR  HasOptions;
+    UCHAR  Ttl;
+    UCHAR  Tos;
+    UCHAR  Flags;
+    USHORT OptionsOffset;
+    USHORT OptionsSize;
+} ICMP_ECHO_REQUEST, *PICMP_ECHO_REQUEST;
 
-static int in_cksum(u_short *addr, int len)
+typedef struct _ICMPV6_ECHO_REQUEST
 {
-    int nleft=len;
-    u_short *w = addr;
-    int sum = 0;
-    u_short answer = 0;
+    IPV6_ADDRESS_EX DestinationAddress;
+    IPV6_ADDRESS_EX SourceAddress;
+    ULONG           Timeout;
+    USHORT          Unknown1;
+    USHORT          Ttl;            // XXX: These seem unnecessarily large.
+    ULONG           Flags;          //      Is something else in the struct?
+} ICMPV6_ECHO_REQUEST, *PICMPV6_ECHO_REQUEST;
 
-    while (nleft > 1) {
-        sum += *w++;
-        nleft -= 2;
-    }
+/**
+ * Icmp6CreateFile
+ * @implemented
+ */
+HANDLE
+WINAPI
+Icmp6CreateFile(void)
+{
+    HANDLE IcmpFile;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    IO_STATUS_BLOCK IoStatusBlock;
+    UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\Ip6");
+    NTSTATUS Status;
 
-    if (nleft == 1) {
-        *(u_char *)(&answer) = *(u_char *)w;
-        sum += answer;
+    InitializeObjectAttributes(
+        &ObjectAttributes,
+        &DeviceName,
+        OBJ_CASE_INSENSITIVE,
+        NULL,
+        NULL);
+
+    Status = NtCreateFile(
+        &IcmpFile,
+        GENERIC_EXECUTE,
+        &ObjectAttributes,
+        &IoStatusBlock,
+        NULL,
+        FILE_ATTRIBUTE_NORMAL,
+        FILE_SHARE_READ | FILE_SHARE_WRITE,
+        FILE_OPEN_IF,
+        0,
+        NULL,
+        0);
+
+    if (!NT_SUCCESS(Status))
+    {
+        SetLastError(RtlNtStatusToDosError(Status));
+        return INVALID_HANDLE_VALUE;
     }
 
-    sum = (sum >> 16) + (sum & 0xffff);
-    sum  += (sum >> 16);
-    answer = ~sum;
-    return(answer);
+    return IcmpFile;
 }
 
+/**
+ * Icmp6ParseReplies
+ * @implemented
+ */
+DWORD
+WINAPI
+Icmp6ParseReplies(
+    _In_ LPVOID ReplyBuffer,
+    _In_ DWORD  ReplySize)
+{
+    PICMPV6_ECHO_REPLY pEcho;
 
+    if (ReplyBuffer == NULL || ReplySize == 0)
+        return 0;
 
-/*
- * Exported Routines.
- */
+    pEcho = (PICMPV6_ECHO_REPLY)ReplyBuffer;
 
-/***********************************************************************
- *		Icmp6CreateFile (IPHLPAPI.@)
- */
-HANDLE WINAPI Icmp6CreateFile(VOID)
-{
-    icmp_t* icp;
-
-    int sid=socket(AF_INET6,SOCK_RAW,IPPROTO_ICMPV6);
-#ifndef __REACTOS__
-    if (sid < 0)
+    // XXX: MSDN also says IP_TTL_EXPIRED_TRANSIT.
+    if (pEcho->Status == IP_SUCCESS)
     {
-        /* Mac OS X supports non-privileged ICMP via SOCK_DGRAM type. */
-        sid=socket(AF_INET6,SOCK_DGRAM,IPPROTO_ICMPV6);
+        return 1;
     }
-#endif
-    if (sid < 0) {
-        ERR_(winediag)("Failed to use ICMPV6 (network ping), this requires special permissions.\n");
-        SetLastError(ERROR_ACCESS_DENIED);
-        return INVALID_HANDLE_VALUE;
-    }
 
-    icp=HeapAlloc(GetProcessHeap(), 0, sizeof(*icp));
-    if (icp==NULL) {
-#ifdef __REACTOS__
-        closesocket(sid);
-#else
-        close(sid);
-#endif
-        SetLastError(IP_NO_RESOURCES);
-        return INVALID_HANDLE_VALUE;
-    }
-    icp->sid=sid;
-    icp->default_opts.OptionsSize=IP_OPTS_UNKNOWN;
-    return (HANDLE)icp;
+    SetLastError(pEcho->Status);
+    return 0;
 }
 
-
-/***********************************************************************
- *		Icmp6SendEcho2 (IPHLPAPI.@)
+/**
+ * Icmp6SendEcho2
+ * @implemented
  */
-DWORD WINAPI Icmp6SendEcho2(
-    HANDLE                   IcmpHandle,
-    HANDLE                   Event,
-    PIO_APC_ROUTINE          ApcRoutine,
-    PVOID                    ApcContext,
-    struct sockaddr_in6*     SourceAddress,
-    struct sockaddr_in6*     DestinationAddress,
-    LPVOID                   RequestData,
-    WORD                     RequestSize,
-    PIP_OPTION_INFORMATION   RequestOptions,
-    LPVOID                   ReplyBuffer,
-    DWORD                    ReplySize,
-    DWORD                    Timeout
-    )
+DWORD
+WINAPI
+Icmp6SendEcho2(
+    _In_     HANDLE                 IcmpHandle,
+    _In_opt_ HANDLE                 Event,
+    _In_opt_ PIO_APC_ROUTINE        ApcRoutine,
+    _In_opt_ PVOID                  ApcContext,
+    _In_     struct sockaddr_in6    *SourceAddress,
+    _In_     struct sockaddr_in6    *DestinationAddress,
+    _In_     LPVOID                 RequestData,
+    _In_     WORD                   RequestSize,
+    _In_     PIP_OPTION_INFORMATION RequestOptions,
+    _Out_    LPVOID                 ReplyBuffer,
+    _In_     DWORD                  ReplySize,
+    _In_     DWORD                  Timeout)
 {
-    FIXME("(%p, %p, %p, %p, %p, %p, %p, %d, %p, %p, %d, %d): stub\n", IcmpHandle, Event,
-            ApcRoutine, ApcContext, SourceAddress, DestinationAddress, RequestData,
-            RequestSize, RequestOptions, ReplyBuffer, ReplySize, Timeout);
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return 0;
-}
+    HANDLE hEvent;
+    IO_STATUS_BLOCK IoStatusBlock;
+    PVOID InputBuffer;
+    ULONG InputBufferLength;
+    //ULONG OutputBufferLength;
+    PICMPV6_ECHO_REQUEST Request;
+    NTSTATUS Status;
 
+    InputBufferLength = sizeof(ICMPV6_ECHO_REQUEST) + RequestSize;
 
-/***********************************************************************
- *		IcmpCreateFile (IPHLPAPI.@)
- */
-HANDLE WINAPI IcmpCreateFile(VOID)
-{
-#ifndef __REACTOS__
-    static int once;
-#endif
-    icmp_t* icp;
-
-    int sid=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
-#ifdef __REACTOS__
-    if (sid < 0) {
-        ERR_(winediag)("Failed to use ICMP (network ping), this requires special permissions.\n");
-        SetLastError(ERROR_ACCESS_DENIED);
-        return INVALID_HANDLE_VALUE;
-    }
-#else
-    if (sid < 0)
+    // XXX: What is the extra 8 bytes it needs?
+    if (ReplySize < sizeof(ICMPV6_ECHO_REPLY) + 8)
     {
-        /* Mac OS X supports non-privileged ICMP via SOCK_DGRAM type. */
-        sid=socket(AF_INET,SOCK_DGRAM,IPPROTO_ICMP);
+        SetLastError(ERROR_INSUFFICIENT_BUFFER);
+        return 0;
     }
-    if (sid < 0 && !once++) {
-        FIXME_(winediag)("Failed to use ICMP (network ping), this requires special permissions.\n");
-        FIXME_(winediag)("Falling back to system 'ping' command as a workaround.\n");
-    }
-#endif
 
-    icp=HeapAlloc(GetProcessHeap(), 0, sizeof(*icp));
-    if (icp==NULL) {
-#ifdef __REACTOS__
-        closesocket(sid);
-#else
-        if (sid >= 0) close(sid);
-#endif
-        SetLastError(IP_NO_RESOURCES);
-        return INVALID_HANDLE_VALUE;
+    InputBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, InputBufferLength);
+    if (InputBuffer == NULL)
+    {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        return 0;
     }
-    icp->sid=sid;
-    icp->default_opts.OptionsSize=IP_OPTS_UNKNOWN;
-    return (HANDLE)icp;
-}
 
+    Request = (PICMPV6_ECHO_REQUEST)InputBuffer;
 
-/***********************************************************************
- *		IcmpCloseHandle (IPHLPAPI.@)
- */
-BOOL WINAPI IcmpCloseHandle(HANDLE  IcmpHandle)
-{
-    icmp_t* icp=(icmp_t*)IcmpHandle;
-    if (IcmpHandle==INVALID_HANDLE_VALUE) {
-        /* FIXME: in fact win98 seems to ignore the handle value !!! */
-        SetLastError(ERROR_INVALID_HANDLE);
-        return FALSE;
-    }
+    Request->DestinationAddress.sin6_port = DestinationAddress->sin6_port;
+    Request->DestinationAddress.sin6_flowinfo = DestinationAddress->sin6_flowinfo;
+    CopyMemory(&(Request->DestinationAddress.sin6_addr), &(DestinationAddress->sin6_addr), sizeof(Request->DestinationAddress.sin6_addr));
+    Request->DestinationAddress.sin6_scope_id = DestinationAddress->sin6_scope_id;
 
-#ifdef __REACTOS__
-    shutdown(icp->sid,2);
-#else
-    if (icp->sid >= 0) close(icp->sid);
-#endif
-    HeapFree(GetProcessHeap (), 0, icp);
-    return TRUE;
-}
+    Request->SourceAddress.sin6_port = SourceAddress->sin6_port;
+    Request->SourceAddress.sin6_flowinfo = SourceAddress->sin6_flowinfo;
+    CopyMemory(&(Request->SourceAddress.sin6_addr), &(SourceAddress->sin6_addr), sizeof(Request->SourceAddress.sin6_addr));
+    Request->SourceAddress.sin6_scope_id = SourceAddress->sin6_scope_id;
 
-#ifndef __REACTOS__
-static DWORD system_icmp(
-    IPAddr                   DestinationAddress,
-    LPVOID                   RequestData,
-    WORD                     RequestSize,
-    PIP_OPTION_INFORMATION   RequestOptions,
-    LPVOID                   ReplyBuffer,
-    DWORD                    ReplySize,
-    DWORD                    Timeout
-    )
-{
-#ifdef HAVE_FORK
-    ICMP_ECHO_REPLY *reply = ReplyBuffer;
-    char ntoa_buffer[16]; /* 4*3 digits + 3 '.' + 1 '\0' */
-    char size_buffer[6];  /* 5 digits + '\0' */
-    char tos_buffer[4];   /* 3 digits + '\0' */
-    char ttl_buffer[4];   /* 3 digits + '\0' */
-    char time_buffer[11]; /* 10 digits + '\0' */
-    int i, pos, res, status, argc;
-    const char *argv[20];
-    struct in_addr addr;
-    int pipe_out[2];
-    pid_t pid, wpid;
-    char *ptr, *eol;
-    char buf[127];
+    // XXX: What is this and why is it sometimes 0x72?
+    Request->Unknown1 = 0x72;
 
-    /* Assemble the ping commandline */
-    argc = 0;
-    argv[argc++] = "ping";
-    argv[argc++] = "-c";    /* only send a single ping */
-    argv[argc++] = "1";
-    argv[argc++] = "-n";    /* numeric output only */
-    argv[argc++] = "-s";    /* request size */
-    sprintf(size_buffer, "%u", (RequestSize >= 16) ? RequestSize : 16);
-    argv[argc++] = size_buffer;
-    argv[argc++] = "-W";    /* timeout */
-#ifdef __linux__
-    /* The linux 'ping' utlity expects a time in seconds */
-    Timeout = (Timeout + 999) / 1000;
-#endif
-    sprintf(time_buffer, "%u", Timeout);
-    argv[argc++] = time_buffer;
+    Request->Timeout = Timeout;
+    Request->Ttl = RequestOptions->Ttl;
+    Request->Flags = RequestOptions->Flags;
 
-    if (RequestOptions)
+    if (RequestSize > 0)
     {
-    #ifdef __linux__
-        argv[argc++] = "-Q";    /* tos option */
-    #else
-        argv[argc++] = "-z";    /* tos option */
-    #endif
-        sprintf(tos_buffer, "%u", RequestOptions->Tos);
-        argv[argc++] = tos_buffer;
-    #ifdef __linux__
-        /* TTL can only be specified for multicast addresses on FreeBSD/MacOS */
-        argv[argc++] = "-t";    /* ttl option */
-        sprintf(ttl_buffer, "%u", RequestOptions->Ttl);
-        argv[argc++] = ttl_buffer;
-    #endif
+        CopyMemory((PBYTE)InputBuffer + sizeof(ICMPV6_ECHO_REQUEST), RequestData, RequestSize);
     }
 
-    addr.s_addr = DestinationAddress;
-    if (!(ptr = inet_ntoa(addr)))
+    if (Event == NULL && ApcRoutine == NULL)
     {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return 0;
+        hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
     }
-    strcpy(ntoa_buffer, ptr);
-    argv[argc++] = ntoa_buffer;
-    argv[argc] = NULL;
+    else
+    {
+        hEvent = Event;
+    }
 
-    /* Dump commandline for debugging purposes */
-    TRACE("Ping commandline: ");
-    for (i = 0; i < argc; i++)
+    Status = NtDeviceIoControlFile(
+        IcmpHandle,
+        hEvent,
+        ApcRoutine,
+        ApcContext,
+        &IoStatusBlock,
+        IOCTL_ICMP_ECHO_REQUEST,
+        InputBuffer,
+        InputBufferLength,
+        ReplyBuffer,
+        ReplySize);         // TODO: Determine how Windows calculates OutputBufferLength.
+
+    if (Event != NULL || ApcRoutine != NULL)
     {
-        TRACE("%s ", debugstr_a(argv[i]));
+        SetLastError(RtlNtStatusToDosError(Status));
+        HeapFree(GetProcessHeap(), 0, InputBuffer);
+        return 0;
     }
-    TRACE("\n");
 
-    /* Prefill the reply struct with fallback values */
-    memset(reply, 0, sizeof(*reply));
-    reply->Address       = DestinationAddress;
-    reply->RoundTripTime = 40;
-    reply->Options.Ttl   = 120;
+    if (Status == STATUS_PENDING)
+    {
+        Status = NtWaitForSingleObject(hEvent, FALSE, NULL);
 
-    /* Create communication pipes */
-#ifdef HAVE_PIPE2
-    if (pipe2(pipe_out, O_CLOEXEC) < 0)
-#endif
-    {
-        if (pipe(pipe_out) < 0)
+        if (NT_SUCCESS(Status))
         {
-            SetLastError(ERROR_OUTOFMEMORY);
-            return 0;
+            Status = IoStatusBlock.Status;
         }
-        fcntl(pipe_out[0], F_SETFD, FD_CLOEXEC);
-        fcntl(pipe_out[1], F_SETFD, FD_CLOEXEC);
     }
 
-    /* Fork child process */
-    pid = fork();
-    if (pid == -1)
+    CloseHandle(hEvent);
+    HeapFree(GetProcessHeap(), 0, InputBuffer);
+
+    if (!NT_SUCCESS(Status))
     {
-        close(pipe_out[0]);
-        close(pipe_out[1]);
-        SetLastError(ERROR_OUTOFMEMORY);
+        SetLastError(RtlNtStatusToDosError(Status));
         return 0;
     }
 
-    /* Child process */
-    if (pid == 0)
+    Status = ((PICMPV6_ECHO_REPLY)ReplyBuffer)->Status;
+    if (Status != IP_SUCCESS)
     {
-        static char lang_env[] = "LANG=C";
+        SetLastError(Status);
+        return 0;
+    }
 
-        dup2(pipe_out[1], 1);
-        close(pipe_out[0]);
-        close(pipe_out[1]);
-        close(0);
-        close(2);
+    return 1;
+}
 
-        putenv(lang_env);
-        execvp(argv[0], (char **)argv);
-        _exit(1);
+/**
+ * IcmpCloseHandle
+ * @implemented
+ */
+BOOL
+WINAPI
+IcmpCloseHandle(
+    _In_ HANDLE IcmpHandle)
+{
+    NTSTATUS Status;
+
+    Status = NtClose(IcmpHandle);
+    if (!NT_SUCCESS(Status))
+    {
+        SetLastError(RtlNtStatusToDosError(Status));
+        return FALSE;
     }
 
-    close(pipe_out[1]);
+    return TRUE;
+}
 
-    /* Wait for child and read output */
-    pos = 0;
-    do
-    {
-        if (pos >= sizeof(buf) - 1)
-        {
-            ERR("line too long, dropping buffer\n");
-            pos = 0;
-        }
+/**
+ * IcmpCreateFile
+ * @implemented
+ */
+HANDLE
+WINAPI
+IcmpCreateFile(void)
+{
+    HANDLE IcmpFile;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    IO_STATUS_BLOCK IoStatusBlock;
+    UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\Ip");
+    NTSTATUS Status;
 
-        /* read next block */
-        do
-        {
-            res = read(pipe_out[0], &buf[pos], (sizeof(buf) - 1) - pos);
-        }
-        while (res < 0 && errno == EINTR);
-        if (res < 0)
-        {
-            ERR("read failed: %s\n", strerror(errno));
-            break;
-        }
+    InitializeObjectAttributes(
+        &ObjectAttributes,
+        &DeviceName,
+        OBJ_CASE_INSENSITIVE,
+        NULL,
+        NULL);
 
-        pos += res;
-        while (pos)
-        {
-            eol = memchr(buf, '\n', pos);
-            if (!eol) break;
-            *eol = 0;
+    Status = NtCreateFile(
+        &IcmpFile,
+        GENERIC_EXECUTE,
+        &ObjectAttributes,
+        &IoStatusBlock,
+        NULL,
+        FILE_ATTRIBUTE_NORMAL,
+        FILE_SHARE_READ | FILE_SHARE_WRITE,
+        FILE_OPEN_IF,
+        0,
+        NULL,
+        0);
 
-            TRACE("Received line: %s\n", debugstr_a(buf));
+    if (!NT_SUCCESS(Status))
+    {
+        SetLastError(RtlNtStatusToDosError(Status));
+        return INVALID_HANDLE_VALUE;
+    }
 
-            /* Interpret address */
-            if ((ptr = strstr(buf, "from ")))
-            {
-                int a, b, c, d;
-                if (sscanf(ptr + 5, "%u.%u.%u.%u", &a, &b, &c, &d) >= 4)
-                {
-                    reply->Address = a | (b << 8) | (c << 16) | (d << 24);
-                    addr.s_addr = reply->Address;
-                    TRACE("Got address %s\n", inet_ntoa(addr));
-                }
-            }
+    return IcmpFile;
+}
 
-            /* Interpret ttl */
-            if ((ptr = strstr(buf, "ttl=")))
-            {
-                int val;
-                if (sscanf(ptr + 4, "%u", &val) >= 1)
-                {
-                    reply->Options.Ttl = val;
-                    TRACE("Got ttl %u\n", val);
-                }
-            }
+/**
+ * IcmpParseReplies
+ * @implemented
+ */
+DWORD
+WINAPI
+IcmpParseReplies(
+    _In_ LPVOID ReplyBuffer,
+    _In_ DWORD  ReplySize)
+{
+    PICMP_ECHO_REPLY pEcho;
+    DWORD nReplies;
 
-            /* Interpret time */
-            if ((ptr = strstr(buf, "time=")))
-            {
-                float val;
-                if (sscanf(ptr + 5, "%f", &val) >= 1)
-                {
-                    reply->RoundTripTime = (unsigned int)(val + 0.5);
-                    TRACE("Got rtt = %u\n", reply->RoundTripTime);
-                }
-            }
+    if (ReplyBuffer == NULL || ReplySize == 0)
+        return 0;
 
-            memmove(buf, eol + 1, pos - (eol + 1 - buf));
-            pos -= (eol + 1 - buf);
-        }
-    }
-    while (res > 0);
-    close(pipe_out[0]);
+    // TODO: Handle ReplyBuffer having more than 1 ICMP_ECHO_REPLY.
 
-    /* reap the child process */
-    do
-    {
-        wpid = waitpid(pid, &status, 0);
-    }
-    while (wpid < 0 && errno == EINTR);
+    pEcho = (PICMP_ECHO_REPLY)ReplyBuffer;
 
-    /* fill out remaining struct fields */
-    if (wpid >= 0 && WIFEXITED(status) && WEXITSTATUS(status) == 0)
+    if (pEcho->Reserved == 0)
     {
-        if (ReplySize < RequestSize + sizeof(*reply))
-        {
-            reply->Status   = IP_BUF_TOO_SMALL;
-            reply->DataSize = 0;
-            reply->Data     = NULL;
-        }
-        else
-        {
-            reply->Status   = 0;
-            reply->DataSize = RequestSize;
-            reply->Data     = (char *)reply + sizeof(*reply);
-            memcpy(reply->Data, RequestData, RequestSize);
-        }
-        return 1;
+        SetLastError(pEcho->Status);
     }
 
-    SetLastError(IP_REQ_TIMED_OUT);
-    return 0;
-#else
-    ERR("no fork support on this platform\n");
-    SetLastError(ERROR_NOT_SUPPORTED);
-    return 0;
-#endif
+    nReplies = pEcho->Reserved;
+    pEcho->Reserved = 0;
+
+    return nReplies;
 }
-#endif
 
-/***********************************************************************
- *		IcmpSendEcho (IPHLPAPI.@)
+/**
+ * IcmpSendEcho2
+ * @implemented
  */
-DWORD WINAPI IcmpSendEcho(
-    HANDLE                   IcmpHandle,
-    IPAddr                   DestinationAddress,
-    LPVOID                   RequestData,
-    WORD                     RequestSize,
-    PIP_OPTION_INFORMATION   RequestOptions,
-    LPVOID                   ReplyBuffer,
-    DWORD                    ReplySize,
-    DWORD                    Timeout
-    )
+DWORD
+WINAPI
+IcmpSendEcho2(
+    _In_     HANDLE                 IcmpHandle,
+    _In_opt_ HANDLE                 Event,
+    _In_opt_ PIO_APC_ROUTINE        ApcRoutine,
+    _In_opt_ PVOID                  ApcContext,
+    _In_     IPAddr                 DestinationAddress,
+    _In_     LPVOID                 RequestData,
+    _In_     WORD                   RequestSize,
+    _In_opt_ PIP_OPTION_INFORMATION RequestOptions,
+    _Out_    LPVOID                 ReplyBuffer,
+    _In_     DWORD                  ReplySize,
+    _In_     DWORD                  Timeout)
 {
-    icmp_t* icp=(icmp_t*)IcmpHandle;
-    unsigned char* reqbuf;
-    int reqsize;
+    HANDLE hEvent;
+    IO_STATUS_BLOCK IoStatusBlock;
+    PVOID InputBuffer;
+    PICMP_ECHO_REQUEST Request;
+    DWORD nReplies;
+    NTSTATUS Status;
 
-    struct icmp_echo_reply* ier;
-    struct ip* ip_header;
-    struct icmp* icmp_header;
-    char* endbuf;
-    int ip_header_len;
-    int maxlen;
-#ifdef __REACTOS__
-    fd_set fdr;
-    struct timeval timeout;
-#else
-    struct pollfd fdr;
-#endif
-    DWORD send_time,recv_time;
-    struct sockaddr_in addr;
-    socklen_t addrlen;
-    unsigned short id,seq,cksum;
-    int res;
-
-    if (IcmpHandle==INVALID_HANDLE_VALUE) {
-        /* FIXME: in fact win98 seems to ignore the handle value !!! */
-        SetLastError(ERROR_INVALID_HANDLE);
+    // XXX: What is the extra 8 bytes it needs?
+    if (ReplySize < sizeof(ICMP_ECHO_REPLY) + 8)
+    {
+        SetLastError(ERROR_INSUFFICIENT_BUFFER);
         return 0;
     }
 
-    if (ReplySize<sizeof(ICMP_ECHO_REPLY)+ICMP_MINLEN) {
-        SetLastError(IP_BUF_TOO_SMALL);
+    InputBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ReplySize);
+    if (InputBuffer == NULL)
+    {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
         return 0;
     }
-    /* check the request size against SO_MAX_MSG_SIZE using getsockopt */
 
-    if (!DestinationAddress) {
-        SetLastError(ERROR_INVALID_NETNAME);
-        return 0;
+    Request = (PICMP_ECHO_REQUEST)InputBuffer;
+    Request->Address = DestinationAddress;
+    Request->Timeout = Timeout;
+    Request->OptionsOffset = sizeof(ICMP_ECHO_REQUEST);
+    Request->DataOffset = sizeof(ICMP_ECHO_REQUEST);
+
+    if (RequestOptions != NULL)
+    {
+        Request->HasOptions = TRUE;
+        Request->Ttl = RequestOptions->Ttl;
+        Request->Tos = RequestOptions->Tos;
+        Request->Flags = RequestOptions->Flags;
+
+        if (RequestOptions->OptionsSize > 0)
+        {
+            Request->OptionsSize = RequestOptions->OptionsSize;
+            Request->DataOffset += Request->OptionsSize;
+
+            CopyMemory(
+                (PBYTE)InputBuffer + sizeof(ICMP_ECHO_REQUEST),
+                RequestOptions->OptionsData,
+                Request->OptionsSize);
+        }
     }
 
-#ifndef __REACTOS__
-    if (icp->sid < 0) {
-        WARN("using system ping command since SOCK_RAW was not supported.\n");
-        return system_icmp(DestinationAddress, RequestData, RequestSize,
-                           RequestOptions, ReplyBuffer, ReplySize, Timeout);
-#endif
+    if (RequestSize > 0)
+    {
+        Request->DataSize = RequestSize;
+        CopyMemory((PBYTE)InputBuffer + Request->DataOffset, RequestData, RequestSize);
+    }
 
-    /* Prepare the request */
-#ifdef __REACTOS__
-    id = GetCurrentProcessId() & 0xFFFF;
-#else
-    id=getpid() & 0xFFFF;
-#endif
-    seq=InterlockedIncrement(&icmp_sequence) & 0xFFFF;
+    if (Event == NULL && ApcRoutine == NULL)
+    {
+        hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
+    }
+    else
+    {
+        hEvent = Event;
+    }
 
-    reqsize=ICMP_MINLEN+RequestSize;
-    reqbuf=HeapAlloc(GetProcessHeap(), 0, reqsize);
-    if (reqbuf==NULL) {
-        SetLastError(ERROR_OUTOFMEMORY);
+    Status = NtDeviceIoControlFile(
+        IcmpHandle,
+        hEvent,
+        ApcRoutine,
+        ApcContext,
+        &IoStatusBlock,
+        IOCTL_ICMP_ECHO_REQUEST,
+        InputBuffer,
+        ReplySize,
+        ReplyBuffer,
+        ReplySize);         // TODO: Determine how Windows calculates OutputBufferLength.
+
+    // If called asynchronously, return for the caller to handle.
+    if (Event != NULL || ApcRoutine != NULL)
+    {
+        SetLastError(RtlNtStatusToDosError(Status));
+        HeapFree(GetProcessHeap(), 0, InputBuffer);
         return 0;
     }
 
-    icmp_header=(struct icmp*)reqbuf;
-    icmp_header->icmp_type=ICMP_ECHO;
-    icmp_header->icmp_code=0;
-    icmp_header->icmp_cksum=0;
-    icmp_header->icmp_id=id;
-    icmp_header->icmp_seq=seq;
-    memcpy(reqbuf+ICMP_MINLEN, RequestData, RequestSize);
-    icmp_header->icmp_cksum=cksum=in_cksum((u_short*)reqbuf,reqsize);
+    // Otherwise handle it like IcmpSendEcho.
 
-    addr.sin_family=AF_INET;
-    addr.sin_addr.s_addr=DestinationAddress;
-    addr.sin_port=0;
+    if (Status == STATUS_PENDING)
+    {
+        Status = NtWaitForSingleObject(hEvent, FALSE, NULL);
 
-    if (RequestOptions!=NULL) {
-        int val;
-        if (icp->default_opts.OptionsSize==IP_OPTS_UNKNOWN) {
-            socklen_t len;
-            /* Before we mess with the options, get the default values */
-            len=sizeof(val);
-            getsockopt(icp->sid,IPPROTO_IP,IP_TTL,(char *)&val,&len);
-            icp->default_opts.Ttl=val;
-
-            len=sizeof(val);
-            getsockopt(icp->sid,IPPROTO_IP,IP_TOS,(char *)&val,&len);
-            icp->default_opts.Tos=val;
-            /* FIXME: missing: handling of IP 'flags', and all the other options */
+        if (NT_SUCCESS(Status))
+        {
+            Status = IoStatusBlock.Status;
         }
+    }
 
-        val=RequestOptions->Ttl;
-        setsockopt(icp->sid,IPPROTO_IP,IP_TTL,(char *)&val,sizeof(val));
-        val=RequestOptions->Tos;
-        setsockopt(icp->sid,IPPROTO_IP,IP_TOS,(char *)&val,sizeof(val));
-        /* FIXME:  missing: handling of IP 'flags', and all the other options */
+    CloseHandle(hEvent);
+    HeapFree(GetProcessHeap(), 0, InputBuffer);
 
-        icp->default_opts.OptionsSize=IP_OPTS_CUSTOM;
-    } else if (icp->default_opts.OptionsSize==IP_OPTS_CUSTOM) {
-        int val;
+    if (!NT_SUCCESS(Status))
+    {
+        SetLastError(RtlNtStatusToDosError(Status));
+        return 0;
+    }
 
-        /* Restore the default options */
-        val=icp->default_opts.Ttl;
-        setsockopt(icp->sid,IPPROTO_IP,IP_TTL,(char *)&val,sizeof(val));
-        val=icp->default_opts.Tos;
-        setsockopt(icp->sid,IPPROTO_IP,IP_TOS,(char *)&val,sizeof(val));
-        /* FIXME: missing: handling of IP 'flags', and all the other options */
-
-        icp->default_opts.OptionsSize=IP_OPTS_DEFAULT;
+    Status = ((PICMP_ECHO_REPLY)ReplyBuffer)->Status;
+    if (Status != IP_SUCCESS)
+    {
+        SetLastError(Status);
     }
 
-    /* Get ready for receiving the reply
-     * Do it before we send the request to minimize the risk of introducing delays
-     */
-#ifdef __REACTOS__
-    FD_ZERO(&fdr);
-    FD_SET(icp->sid,&fdr);
-    timeout.tv_sec=Timeout/1000;
-    timeout.tv_usec=(Timeout % 1000)*1000;
-#else
-    fdr.fd = icp->sid;
-    fdr.events = POLLIN;
-#endif
-    addrlen=sizeof(addr);
-    ier=ReplyBuffer;
-    ip_header=(struct ip *) ((char *) ReplyBuffer+sizeof(ICMP_ECHO_REPLY));
-    endbuf=(char *) ReplyBuffer+ReplySize;
-    maxlen=ReplySize-sizeof(ICMP_ECHO_REPLY);
+    nReplies = ((PICMP_ECHO_REPLY)ReplyBuffer)->Reserved;
+    ((PICMP_ECHO_REPLY)ReplyBuffer)->Reserved = 0;
 
-    /* Send the packet */
-    TRACE("Sending %d bytes (RequestSize=%d) to %s\n", reqsize, RequestSize, inet_ntoa(addr.sin_addr));
-#if 0
-    if (TRACE_ON(icmp)){
-        unsigned char* buf=(unsigned char*)reqbuf;
-        int i;
-        printf("Output buffer:\n");
-        for (i=0;i<reqsize;i++)
-            printf("%2x,", buf[i]);
-        printf("\n");
-    }
-#endif
+    return nReplies;
+}
 
-    send_time = GetTickCount();
-    res=sendto(icp->sid, (const char*)reqbuf, reqsize, 0, (struct sockaddr*)&addr, sizeof(addr));
-    HeapFree(GetProcessHeap (), 0, reqbuf);
-    if (res<0) {
-        if (WSAGetLastError()==WSAEMSGSIZE)
-            SetLastError(IP_PACKET_TOO_BIG);
-        else {
-            switch (WSAGetLastError()) {
-            case WSAENETUNREACH:
-                SetLastError(IP_DEST_NET_UNREACHABLE);
-                break;
-            case WSAEHOSTUNREACH:
-                SetLastError(IP_DEST_HOST_UNREACHABLE);
-                break;
-            default:
-                TRACE("unknown error: errno=%d\n",WSAGetLastError());
-                SetLastError(IP_GENERAL_FAILURE);
-            }
-        }
+/**
+ * IcmpSendEcho
+ * @implemented
+ */
+DWORD
+WINAPI
+IcmpSendEcho(
+    _In_     HANDLE                 IcmpHandle,
+    _In_     IPAddr                 DestinationAddress,
+    _In_     LPVOID                 RequestData,
+    _In_     WORD                   RequestSize,
+    _In_opt_ PIP_OPTION_INFORMATION RequestOptions,
+    _Out_    LPVOID                 ReplyBuffer,
+    _In_     DWORD                  ReplySize,
+    _In_     DWORD                  Timeout)
+{
+    HANDLE hEvent;
+    IO_STATUS_BLOCK IoStatusBlock;
+    PVOID InputBuffer;
+    ULONG InputBufferLength;
+    PICMP_ECHO_REQUEST Request;
+    DWORD nReplies;
+    NTSTATUS Status;
+
+    if (ReplySize < sizeof(ICMP_ECHO_REPLY))
+    {
+        SetLastError(ERROR_INSUFFICIENT_BUFFER);
         return 0;
     }
 
-    /* Get the reply */
-    ip_header_len=0; /* because gcc was complaining */
-#ifdef __REACTOS__
-    while ((res=select(icp->sid+1,&fdr,NULL,NULL,&timeout))>0) {
-#else
-    while (poll(&fdr,1,Timeout)>0) {
-#endif
-        recv_time = GetTickCount();
-        res=recvfrom(icp->sid, (char*)ip_header, maxlen, 0, (struct sockaddr*)&addr,(int*)&addrlen);
-        TRACE("received %d bytes from %s\n",res, inet_ntoa(addr.sin_addr));
-        ier->Status=IP_REQ_TIMED_OUT;
+    InputBufferLength = sizeof(ICMP_ECHO_REQUEST) + RequestSize;
+    if (RequestOptions != NULL)
+        InputBufferLength += RequestOptions->OptionsSize;
 
-        /* Check whether we should ignore this packet */
-        if ((ip_header->ip_p==IPPROTO_ICMP) && (res>=sizeof(struct ip)+ICMP_MINLEN)) {
-            ip_header_len=ip_header->ip_hl << 2;
-            icmp_header=(struct icmp*)(((char*)ip_header)+ip_header_len);
-            TRACE("received an ICMP packet of type,code=%d,%d\n",icmp_header->icmp_type,icmp_header->icmp_code);
-            if (icmp_header->icmp_type==ICMP_ECHOREPLY) {
-                if ((icmp_header->icmp_id==id) && (icmp_header->icmp_seq==seq))
-                    ier->Status=IP_SUCCESS;
-            } else {
-                switch (icmp_header->icmp_type) {
-                case ICMP_UNREACH:
-                    switch (icmp_header->icmp_code) {
-                    case ICMP_UNREACH_HOST:
-#ifdef ICMP_UNREACH_HOST_UNKNOWN
-                    case ICMP_UNREACH_HOST_UNKNOWN:
-#endif
-#ifdef ICMP_UNREACH_ISOLATED
-                    case ICMP_UNREACH_ISOLATED:
-#endif
-#ifdef ICMP_UNREACH_HOST_PROHIB
-		    case ICMP_UNREACH_HOST_PROHIB:
-#endif
-#ifdef ICMP_UNREACH_TOSHOST
-                    case ICMP_UNREACH_TOSHOST:
-#endif
-                        ier->Status=IP_DEST_HOST_UNREACHABLE;
-                        break;
-                    case ICMP_UNREACH_PORT:
-                        ier->Status=IP_DEST_PORT_UNREACHABLE;
-                        break;
-                    case ICMP_UNREACH_PROTOCOL:
-                        ier->Status=IP_DEST_PROT_UNREACHABLE;
-                        break;
-                    case ICMP_UNREACH_SRCFAIL:
-                        ier->Status=IP_BAD_ROUTE;
-                        break;
-                    default:
-                        ier->Status=IP_DEST_NET_UNREACHABLE;
-                    }
-                    break;
-                case ICMP_TIMXCEED:
-                    if (icmp_header->icmp_code==ICMP_TIMXCEED_REASS)
-                        ier->Status=IP_TTL_EXPIRED_REASSEM;
-                    else
-                        ier->Status=IP_TTL_EXPIRED_TRANSIT;
-                    break;
-                case ICMP_PARAMPROB:
-                    ier->Status=IP_PARAM_PROBLEM;
-                    break;
-                case ICMP_SOURCEQUENCH:
-                    ier->Status=IP_SOURCE_QUENCH;
-                    break;
-                }
-                if (ier->Status!=IP_REQ_TIMED_OUT) {
-                    struct ip* rep_ip_header;
-                    struct icmp* rep_icmp_header;
-                    /* The ICMP header size of all the packets we accept is the same */
-                    rep_ip_header=(struct ip*)(((char*)icmp_header)+ICMP_MINLEN);
-                    rep_icmp_header=(struct icmp*)(((char*)rep_ip_header)+(rep_ip_header->ip_hl << 2));
+    if (InputBufferLength < ReplySize)
+        InputBufferLength = ReplySize;
 
-		    /* Make sure that this is really a reply to our packet */
-                    if (ip_header_len+ICMP_MINLEN+(rep_ip_header->ip_hl << 2)+ICMP_MINLEN>ip_header->ip_len) {
-			ier->Status=IP_REQ_TIMED_OUT;
-                    } else if ((rep_icmp_header->icmp_type!=ICMP_ECHO) ||
-                        (rep_icmp_header->icmp_code!=0) ||
-                        (rep_icmp_header->icmp_id!=id) ||
-                        /* windows doesn't check this checksum, else tracert */
-                        /* behind a Linux 2.2 masquerading firewall would fail*/
-                        /* (rep_icmp_header->icmp_cksum!=cksum) || */
-                        (rep_icmp_header->icmp_seq!=seq)) {
-                        /* This was not a reply to one of our packets after all */
-                        TRACE("skipping type,code=%d,%d id,seq=%d,%d cksum=%d\n",
-                            rep_icmp_header->icmp_type,rep_icmp_header->icmp_code,
-                            rep_icmp_header->icmp_id,rep_icmp_header->icmp_seq,
-                            rep_icmp_header->icmp_cksum);
-                        TRACE("expected type,code=8,0 id,seq=%d,%d cksum=%d\n",
-                            id,seq,
-                            cksum);
-			ier->Status=IP_REQ_TIMED_OUT;
-		    }
-                }
-	    }
-	}
+    InputBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, InputBufferLength);
+    if (InputBuffer == NULL)
+    {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        return 0;
+    }
 
-        if (ier->Status==IP_REQ_TIMED_OUT) {
-            /* This packet was not for us.
-             * Decrease the timeout so that we don't enter an endless loop even
-             * if we get flooded with ICMP packets that are not for us.
-             */
-#ifdef __REACTOS__
-            int t = Timeout - (recv_time - send_time);
-            if (t < 0) t = 0;
-            timeout.tv_sec = t / 1000;
-            timeout.tv_usec = (t % 1000) * 1000;
-#else
-            DWORD t = (recv_time - send_time);
-            if (Timeout > t) Timeout -= t;
-            else             Timeout = 0;
-#endif
-            continue;
-        } else {
-            /* This is a reply to our packet */
-            memcpy(&ier->Address,&ip_header->ip_src,sizeof(IPAddr));
-            /* Status is already set */
-            ier->RoundTripTime= recv_time - send_time;
-            ier->DataSize=res-ip_header_len-ICMP_MINLEN;
-            ier->Reserved=0;
-            ier->Data=endbuf-ier->DataSize;
-            memmove(ier->Data,((char*)ip_header)+ip_header_len+ICMP_MINLEN,ier->DataSize);
-            ier->Options.Ttl=ip_header->ip_ttl;
-            ier->Options.Tos=ip_header->ip_tos;
-            ier->Options.Flags=ip_header->ip_off >> 13;
-            ier->Options.OptionsSize=ip_header_len-sizeof(struct ip);
-            if (ier->Options.OptionsSize!=0) {
-                ier->Options.OptionsData=(unsigned char *) ier->Data-ier->Options.OptionsSize;
-                /* FIXME: We are supposed to rearrange the option's 'source route' data */
-                memmove(ier->Options.OptionsData,((char*)ip_header)+ip_header_len,ier->Options.OptionsSize);
-                endbuf=(char*)ier->Options.OptionsData;
-            } else {
-                ier->Options.OptionsData=NULL;
-                endbuf=ier->Data;
-            }
+    Request = (PICMP_ECHO_REQUEST)InputBuffer;
+    Request->Address = DestinationAddress;
+    Request->Timeout = Timeout;
+    Request->OptionsOffset = sizeof(ICMP_ECHO_REQUEST);
+    Request->DataOffset = sizeof(ICMP_ECHO_REQUEST);
 
-            /* Prepare for the next packet */
-            ier++;
-            ip_header=(struct ip*)(((char*)ip_header)+sizeof(ICMP_ECHO_REPLY));
-            maxlen=endbuf-(char*)ip_header;
+    if (RequestOptions != NULL)
+    {
+        Request->HasOptions = TRUE;
+        Request->Ttl = RequestOptions->Ttl;
+        Request->Tos = RequestOptions->Tos;
+        Request->Flags = RequestOptions->Flags;
 
-            /* Check out whether there is more but don't wait this time */
-#ifdef __REACTOS__
-            timeout.tv_sec=0;
-            timeout.tv_usec=0;
-#else
-            Timeout=0;
-#endif
+        if (RequestOptions->OptionsSize > 0)
+        {
+            Request->OptionsSize = RequestOptions->OptionsSize;
+            Request->DataOffset += Request->OptionsSize;
+
+            CopyMemory(
+                (PBYTE)InputBuffer + sizeof(ICMP_ECHO_REQUEST),
+                RequestOptions->OptionsData,
+                Request->OptionsSize);
         }
-#ifdef __REACTOS__
-        FD_ZERO(&fdr);
-        FD_SET(icp->sid,&fdr);
-#endif
     }
-    res=ier-(ICMP_ECHO_REPLY*)ReplyBuffer;
-    if (res==0)
-        SetLastError(IP_REQ_TIMED_OUT);
-    TRACE("received %d replies\n",res);
-    return res;
-}
 
-/***********************************************************************
- *		IcmpSendEcho2 (IPHLPAPI.@)
- */
-DWORD WINAPI IcmpSendEcho2(
-    HANDLE                   IcmpHandle,
-    HANDLE                   Event,
-    PIO_APC_ROUTINE          ApcRoutine,
-    PVOID                    ApcContext,
-    IPAddr                   DestinationAddress,
-    LPVOID                   RequestData,
-    WORD                     RequestSize,
-    PIP_OPTION_INFORMATION   RequestOptions,
-    LPVOID                   ReplyBuffer,
-    DWORD                    ReplySize,
-    DWORD                    Timeout
-    )
-{
-    TRACE("(%p, %p, %p, %p, %08x, %p, %d, %p, %p, %d, %d): stub\n", IcmpHandle,
-            Event, ApcRoutine, ApcContext, DestinationAddress, RequestData,
-            RequestSize, RequestOptions, ReplyBuffer, ReplySize, Timeout);
-
-    if (Event)
+    if (RequestSize > 0)
     {
-        FIXME("unsupported for events\n");
-        return 0;
+        Request->DataSize = RequestSize;
+        CopyMemory((PBYTE)InputBuffer + Request->DataOffset, RequestData, RequestSize);
     }
-    if (ApcRoutine)
+
+    hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
+    if (hEvent == NULL)
     {
-        FIXME("unsupported for APCs\n");
+        HeapFree(GetProcessHeap(), 0, InputBuffer);
         return 0;
     }
-    return IcmpSendEcho(IcmpHandle, DestinationAddress, RequestData,
-            RequestSize, RequestOptions, ReplyBuffer, ReplySize, Timeout);
-}
 
-/***********************************************************************
- *		IcmpSendEcho2Ex (IPHLPAPI.@)
- */
-DWORD WINAPI IcmpSendEcho2Ex(
-    HANDLE                   IcmpHandle,
-    HANDLE                   Event,
-    PIO_APC_ROUTINE          ApcRoutine,
-    PVOID                    ApcContext,
-    IPAddr                   SourceAddress,
-    IPAddr                   DestinationAddress,
-    LPVOID                   RequestData,
-    WORD                     RequestSize,
-    PIP_OPTION_INFORMATION   RequestOptions,
-    LPVOID                   ReplyBuffer,
-    DWORD                    ReplySize,
-    DWORD                    Timeout
-    )
-{
-    TRACE("(%p, %p, %p, %p, %08x, %08x, %p, %d, %p, %p, %d, %d): stub\n", IcmpHandle,
-            Event, ApcRoutine, ApcContext, SourceAddress, DestinationAddress, RequestData,
-            RequestSize, RequestOptions, ReplyBuffer, ReplySize, Timeout);
+    Status = NtDeviceIoControlFile(
+        IcmpHandle,
+        hEvent,
+        NULL,
+        NULL,
+        &IoStatusBlock,
+        IOCTL_ICMP_ECHO_REQUEST,
+        InputBuffer,
+        InputBufferLength,
+        ReplyBuffer,
+        ReplySize);
 
-    if (Event)
+    if (Status == STATUS_PENDING)
     {
-        FIXME("unsupported for events\n");
-        return 0;
+        Status = NtWaitForSingleObject(hEvent, FALSE, NULL);
+
+        if (NT_SUCCESS(Status))
+        {
+            Status = IoStatusBlock.Status;
+        }
     }
-    if (ApcRoutine)
+
+    CloseHandle(hEvent);
+    HeapFree(GetProcessHeap(), 0, InputBuffer);
+
+    if (!NT_SUCCESS(Status))
     {
-        FIXME("unsupported for APCs\n");
+        SetLastError(RtlNtStatusToDosError(Status));
         return 0;
     }
-    if (SourceAddress)
+
+    Status = ((PICMP_ECHO_REPLY)ReplyBuffer)->Status;
+    if (Status != IP_SUCCESS)
     {
-        FIXME("unsupported for source addresses\n");
-        return 0;
+        SetLastError(Status);
     }
 
-    return IcmpSendEcho(IcmpHandle, DestinationAddress, RequestData,
-            RequestSize, RequestOptions, ReplyBuffer, ReplySize, Timeout);
+    nReplies = ((PICMP_ECHO_REPLY)ReplyBuffer)->Reserved;
+    ((PICMP_ECHO_REPLY)ReplyBuffer)->Reserved = 0;
+
+    return nReplies;
 }
-
-/*
- * Copyright (c) 1989 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Mike Muuss.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- */
Index: dll/win32/iphlpapi/iphlpapi.spec
===================================================================
--- dll/win32/iphlpapi/iphlpapi.spec	(revision 70522)
+++ dll/win32/iphlpapi/iphlpapi.spec	(working copy)
@@ -80,11 +80,11 @@
 @ stub GetUdpTableFromStack
 @ stdcall GetUniDirectionalAdapterInfo( ptr ptr )
 @ stdcall Icmp6CreateFile()
-@ stub Icmp6ParseReplies
+@ stdcall Icmp6ParseReplies(ptr long)
 @ stdcall Icmp6SendEcho2(ptr ptr ptr ptr ptr ptr ptr long ptr ptr long long)
 @ stdcall IcmpCloseHandle(ptr)
 @ stdcall IcmpCreateFile()
-@ stdcall -stub IcmpParseReplies(ptr long)
+@ stdcall IcmpParseReplies(ptr long)
 @ stdcall IcmpSendEcho2(ptr ptr ptr ptr long ptr long ptr ptr long long)
 @ stdcall IcmpSendEcho(ptr long ptr long ptr ptr long long)
 @ stub InternalCreateIpForwardEntry
Index: dll/win32/iphlpapi/iphlpapi_main.c
===================================================================
--- dll/win32/iphlpapi/iphlpapi_main.c	(revision 70522)
+++ dll/win32/iphlpapi/iphlpapi_main.c	(working copy)
@@ -35,17 +35,13 @@
 
 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
 {
-  WSADATA wsaData;
-
   switch (fdwReason) {
     case DLL_PROCESS_ATTACH:
       DisableThreadLibraryCalls( hinstDLL );
       interfaceMapInit();
-      WSAStartup(MAKEWORD(2, 2), &wsaData);
       break;
 
     case DLL_PROCESS_DETACH:
-      WSACleanup();
       interfaceMapFree();
       break;
   }
Index: media/doc/README.WINE
===================================================================
--- media/doc/README.WINE	(revision 70522)
+++ media/doc/README.WINE	(working copy)
@@ -267,7 +267,7 @@
   reactos/dll/win32/gdi32/objects/linedda.c     # Synced at 20090410
 
 iphlpapi -
-  reactos/dll/win32/iphlpapi/icmp.c # Partially synced to WineStaging-1.7.55
+  reactos/dll/win32/iphlpapi/icmp.c # Forked
 
 kernel32 -
   reactos/dll/win32/kernel32/wine/actctx.c               # Partly synced with Wine 1.7.55
