https://git.reactos.org/?p=reactos.git;a=commitdiff;h=dd2ff41dfcf0834118227…
commit dd2ff41dfcf08341182273309205666a1a82c31a
Author: Victor Perevertkin <victor.perevertkin(a)reactos.org>
AuthorDate: Mon Nov 18 20:54:03 2019 +0300
Commit: Victor Perevertkin <victor(a)perevertkin.ru>
CommitDate: Tue Apr 7 05:32:40 2020 +0300
[IPHLPAPI] Make icmp functions use IOCTL_ICMP_ECHO_REQUEST from tcpip.sys
This adds missing features like using events and APCs within IcmpSendEcho2
functions and others.
CORE-10742 CORE-14411
Co-authored-by: Tim Crawford <crawfxrd(a)gmail.com>
---
dll/win32/iphlpapi/icmp.c | 1423 +++++++++++---------------------------
dll/win32/iphlpapi/iphlpapi.spec | 4 +-
sdk/include/psdk/ipexport.h | 51 +-
sdk/include/psdk/tcpioctl.h | 3 +
4 files changed, 464 insertions(+), 1017 deletions(-)
diff --git a/dll/win32/iphlpapi/icmp.c b/dll/win32/iphlpapi/icmp.c
index dec33c13ca9..b32aeca8876 100644
--- a/dll/win32/iphlpapi/icmp.c
+++ b/dll/win32/iphlpapi/icmp.c
@@ -1,1129 +1,552 @@
/*
- * 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: LGPL-2.1-or-later (
https://spdx.org/licenses/LGPL-2.1-or-later)
+ * PURPOSE: ICMP functions
+ * COPYRIGHT: 2016 Tim Crawford (crawfxrd(a)gmail.com)
+ * 2019 Victor Perevertkin (victor.perevertkin(a)reactos.org)
*/
-/* 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.
- */
-
-#ifdef __REACTOS__
#include "iphlpapi_private.h"
-#else // ! __REACTOS__
-#include "config.h"
-#include "wine/port.h"
-
-#include <sys/types.h>
-#ifdef HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
-#ifdef HAVE_NETDB_H
-# include <netdb.h>
-#endif
-#ifdef HAVE_NETINET_IN_SYSTM_H
-# include <netinet/in_systm.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-# include <netinet/in.h>
-#endif
-
-#ifdef HAVE_SYS_TIME_H
-# include <sys/time.h>
-#endif
-#include <stdarg.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-#ifdef HAVE_ARPA_INET_H
-# include <arpa/inet.h>
-#endif
-#ifdef HAVE_SYS_POLL_H
-# include <sys/poll.h>
-#endif
-#ifdef HAVE_SYS_WAIT_H
-# include <sys/wait.h>
-#endif
-
-#define USE_WS_PREFIX
-
-#include "windef.h"
-#include "winbase.h"
-#include "winerror.h"
-#include "winternl.h"
-#include "ipexport.h"
-#include "icmpapi.h"
-#include "wine/debug.h"
-#endif // ! __REACTOS__
-
-/* 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 u_int16_t WORD
-#define u_int32_t DWORD
-
-/* 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"
+WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
-WINE_DEFAULT_DEBUG_CHANNEL(icmp);
-WINE_DECLARE_DEBUG_CHANNEL(winediag);
-
+HANDLE
+WINAPI
+Icmp6CreateFile(void)
+{
+ HANDLE IcmpFile;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ IO_STATUS_BLOCK IoStatusBlock;
+ UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\Ip6");
+ NTSTATUS Status;
+
+ 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;
+ }
-typedef struct {
- int sid;
- IP_OPTION_INFORMATION default_opts;
-} icmp_t;
+ return IcmpFile;
+}
-#define IP_OPTS_UNKNOWN 0
-#define IP_OPTS_DEFAULT 1
-#define IP_OPTS_CUSTOM 2
+DWORD
+WINAPI
+Icmp6ParseReplies(
+ _In_ LPVOID ReplyBuffer,
+ _In_ DWORD ReplySize)
+{
+ PICMPV6_ECHO_REPLY pEcho;
-/* The sequence number is unique process wide, so that all threads
- * have a distinct sequence number.
- */
-static LONG icmp_sequence=0;
+ if (ReplyBuffer == NULL || ReplySize == 0)
+ return 0;
-static int in_cksum(u_short *addr, int len)
-{
- int nleft=len;
- u_short *w = addr;
- int sum = 0;
- u_short answer = 0;
-
- while (nleft > 1) {
- sum += *w++;
- nleft -= 2;
- }
+ pEcho = (PICMPV6_ECHO_REPLY)ReplyBuffer;
- if (nleft == 1) {
- *(u_char *)(&answer) = *(u_char *)w;
- sum += answer;
+ // XXX: MSDN also says IP_TTL_EXPIRED_TRANSIT.
+ if (pEcho->Status == IP_SUCCESS)
+ {
+ return 1;
}
- sum = (sum >> 16) + (sum & 0xffff);
- sum += (sum >> 16);
- answer = ~sum;
- return(answer);
+ SetLastError(pEcho->Status);
+ return 0;
}
-
-
-/*
- * Exported Routines.
- */
-
-/***********************************************************************
- * Icmp6CreateFile (IPHLPAPI.@)
- */
-HANDLE WINAPI Icmp6CreateFile(VOID)
+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)
{
- icmp_t* icp;
-#ifdef __REACTOS__
- int sid;
- WSADATA wsaData;
+ HANDLE hEvent;
+ PIO_STATUS_BLOCK IoStatusBlock;
+ PVOID InputBuffer;
+ ULONG InputBufferLength;
+ //ULONG OutputBufferLength;
+ PICMPV6_ECHO_REQUEST Request;
+ NTSTATUS Status;
+
+ InputBufferLength = sizeof(ICMPV6_ECHO_REQUEST) + RequestSize;
- if (WSAStartup(MAKEWORD(2, 2), &wsaData) != ERROR_SUCCESS)
+ if (ReplySize < sizeof(ICMPV6_ECHO_REPLY) + sizeof(IO_STATUS_BLOCK))
{
- ERR_(winediag)("Failed to use ICMPV6 (network ping), this requires special
permissions.\n");
- return INVALID_HANDLE_VALUE;
+ SetLastError(IP_BUF_TOO_SMALL);
+ return 0;
}
- sid=socket(AF_INET6,SOCK_RAW,IPPROTO_ICMPV6);
-#else
+ // IO_STATUS_BLOCK will be stored inside ReplyBuffer (in the end)
+ // that's because the function may return before device request ends
+ IoStatusBlock = (PIO_STATUS_BLOCK)((PUCHAR)ReplyBuffer + ReplySize -
sizeof(IO_STATUS_BLOCK));
+ ReplySize -= sizeof(IO_STATUS_BLOCK);
- int sid=socket(AF_INET6,SOCK_RAW,IPPROTO_ICMPV6);
- if (sid < 0)
+ InputBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, InputBufferLength);
+ if (InputBuffer == NULL)
{
- /* Mac OS X supports non-privileged ICMP via SOCK_DGRAM type. */
- sid=socket(AF_INET6,SOCK_DGRAM,IPPROTO_ICMPV6);
- }
-#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;
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return 0;
}
- icp=HeapAlloc(GetProcessHeap(), 0, sizeof(*icp));
- if (icp==NULL) {
-#ifdef __REACTOS__
- closesocket(sid);
- WSACleanup();
-#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;
-}
+ Request = (PICMPV6_ECHO_REQUEST)InputBuffer;
+ 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;
-/***********************************************************************
- * Icmp6SendEcho2 (IPHLPAPI.@)
- */
-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
- )
-{
- 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;
-}
+ 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;
+ // XXX: What is this and why is it sometimes 0x72?
+ Request->Unknown1 = 0x72;
-/***********************************************************************
- * IcmpCreateFile (IPHLPAPI.@)
- */
-HANDLE WINAPI IcmpCreateFile(VOID)
-{
-#ifndef __REACTOS__
- static int once;
-#endif
- icmp_t* icp;
-#ifdef __REACTOS__
- int sid;
- WSADATA wsaData;
-
- if (WSAStartup(MAKEWORD(2, 2), &wsaData) != ERROR_SUCCESS)
+ Request->Timeout = Timeout;
+ Request->Ttl = RequestOptions->Ttl;
+ Request->Flags = RequestOptions->Flags;
+
+ if (RequestSize > 0)
{
- ERR_(winediag)("Failed to use ICMPV6 (network ping), this requires special
permissions.\n");
- return INVALID_HANDLE_VALUE;
+ CopyMemory((PBYTE)InputBuffer + sizeof(ICMPV6_ECHO_REQUEST), RequestData,
RequestSize);
}
- sid=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
- if (sid < 0) {
- ERR_(winediag)("Failed to use ICMP (network ping), this requires special
permissions.\n");
- SetLastError(ERROR_ACCESS_DENIED);
- return INVALID_HANDLE_VALUE;
+
+ if (Event == NULL && ApcRoutine == NULL)
+ {
+ hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
+ }
+ else
+ {
+ hEvent = Event;
+ }
+
+ 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)
+ {
+ SetLastError(RtlNtStatusToDosError(Status));
+ HeapFree(GetProcessHeap(), 0, InputBuffer);
+ return 0;
}
-#else
- int sid=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
- if (sid < 0)
+ if (Status == STATUS_PENDING)
{
- /* Mac OS X supports non-privileged ICMP via SOCK_DGRAM type. */
- sid=socket(AF_INET,SOCK_DGRAM,IPPROTO_ICMP);
+ Status = NtWaitForSingleObject(hEvent, FALSE, NULL);
+
+ if (NT_SUCCESS(Status))
+ {
+ Status = IoStatusBlock->Status;
+ }
}
- 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");
+
+ CloseHandle(hEvent);
+ HeapFree(GetProcessHeap(), 0, InputBuffer);
+
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastError(RtlNtStatusToDosError(Status));
+ return 0;
}
-#endif
-
- icp=HeapAlloc(GetProcessHeap(), 0, sizeof(*icp));
- if (icp==NULL) {
-#ifdef __REACTOS__
- closesocket(sid);
- WSACleanup();
-#else
- if (sid >= 0) close(sid);
-#endif
- SetLastError(IP_NO_RESOURCES);
- return INVALID_HANDLE_VALUE;
+
+ Status = ((PICMPV6_ECHO_REPLY)ReplyBuffer)->Status;
+ if (Status != IP_SUCCESS)
+ {
+ SetLastError(Status);
+ return 0;
}
- icp->sid=sid;
- icp->default_opts.OptionsSize=IP_OPTS_UNKNOWN;
- return (HANDLE)icp;
-}
+ return 1;
+}
-/***********************************************************************
- * IcmpCloseHandle (IPHLPAPI.@)
- */
-BOOL WINAPI IcmpCloseHandle(HANDLE IcmpHandle)
+BOOL
+WINAPI
+IcmpCloseHandle(
+ _In_ HANDLE IcmpHandle)
{
- icmp_t* icp=(icmp_t*)IcmpHandle;
-#ifdef __REACTOS__
- // REACTOS: Added a check for NULL handle, CORE-10707
- if (IcmpHandle==INVALID_HANDLE_VALUE || IcmpHandle==NULL) {
-#else
- if (IcmpHandle==INVALID_HANDLE_VALUE) {
-#endif
- /* FIXME: in fact win98 seems to ignore the handle value !!! */
- SetLastError(ERROR_INVALID_HANDLE);
+ NTSTATUS Status;
+
+ Status = NtClose(IcmpHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastError(RtlNtStatusToDosError(Status));
return FALSE;
}
-#ifdef __REACTOS__
- shutdown(icp->sid,2);
-#else
- if (icp->sid >= 0) close(icp->sid);
-#endif
- HeapFree(GetProcessHeap (), 0, icp);
-#ifdef __REACTOS__
- WSACleanup();
-#endif
return TRUE;
}
-#ifndef __REACTOS__
-static DWORD system_icmp(
- IPAddr DestinationAddress,
- LPVOID RequestData,
- WORD RequestSize,
- PIP_OPTION_INFORMATION RequestOptions,
- LPVOID ReplyBuffer,
- DWORD ReplySize,
- DWORD Timeout
- )
+HANDLE
+WINAPI
+IcmpCreateFile(void)
{
-#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];
-
- /* 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;
-
- if (RequestOptions)
+ HANDLE IcmpFile;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ IO_STATUS_BLOCK IoStatusBlock;
+ UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\Ip");
+ NTSTATUS Status;
+
+ 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))
{
- #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
+ SetLastError(RtlNtStatusToDosError(Status));
+ return INVALID_HANDLE_VALUE;
}
- addr.s_addr = DestinationAddress;
- if (!(ptr = inet_ntoa(addr)))
- {
- SetLastError(ERROR_INVALID_PARAMETER);
+ return IcmpFile;
+}
+
+DWORD
+WINAPI
+IcmpParseReplies(
+ _In_ LPVOID ReplyBuffer,
+ _In_ DWORD ReplySize)
+{
+ PICMP_ECHO_REPLY pEcho;
+ DWORD nReplies;
+
+ if (ReplyBuffer == NULL || ReplySize == 0)
return 0;
- }
- strcpy(ntoa_buffer, ptr);
- argv[argc++] = ntoa_buffer;
- argv[argc] = NULL;
- /* Dump commandline for debugging purposes */
- TRACE("Ping commandline: ");
- for (i = 0; i < argc; i++)
- {
- TRACE("%s ", debugstr_a(argv[i]));
- }
- TRACE("\n");
-
- /* Prefill the reply struct with fallback values */
- memset(reply, 0, sizeof(*reply));
- reply->Address = DestinationAddress;
- reply->RoundTripTime = 40;
- reply->Options.Ttl = 120;
-
- /* Create communication pipes */
-#ifdef HAVE_PIPE2
- if (pipe2(pipe_out, O_CLOEXEC) < 0)
-#endif
+ // TODO: Handle ReplyBuffer having more than 1 ICMP_ECHO_REPLY.
+
+ pEcho = (PICMP_ECHO_REPLY)ReplyBuffer;
+
+ if (pEcho->Reserved == 0)
{
- if (pipe(pipe_out) < 0)
- {
- SetLastError(ERROR_OUTOFMEMORY);
- return 0;
- }
- fcntl(pipe_out[0], F_SETFD, FD_CLOEXEC);
- fcntl(pipe_out[1], F_SETFD, FD_CLOEXEC);
+ SetLastError(pEcho->Status);
}
- /* Fork child process */
- pid = fork();
- if (pid == -1)
+ nReplies = pEcho->Reserved;
+ pEcho->Reserved = 0;
+
+ return nReplies;
+}
+
+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)
+{
+ HANDLE hEvent;
+ PIO_STATUS_BLOCK IoStatusBlock;
+ PVOID InputBuffer;
+ PICMP_ECHO_REQUEST Request;
+ DWORD nReplies;
+ NTSTATUS Status;
+
+ if (ReplySize < sizeof(ICMP_ECHO_REPLY) + sizeof(IO_STATUS_BLOCK))
{
- close(pipe_out[0]);
- close(pipe_out[1]);
- SetLastError(ERROR_OUTOFMEMORY);
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
- /* Child process */
- if (pid == 0)
+ if (ReplySize < RequestSize + sizeof(ICMP_ECHO_REPLY))
{
- static char lang_env[] = "LANG=C";
+ SetLastError(IP_GENERAL_FAILURE);
+ return 0;
+ }
- dup2(pipe_out[1], 1);
- close(pipe_out[0]);
- close(pipe_out[1]);
- close(0);
- close(2);
+ // IO_STATUS_BLOCK will be stored inside ReplyBuffer (in the end)
+ // that's because the function may return before device request ends
+ IoStatusBlock = (PIO_STATUS_BLOCK)((PUCHAR)ReplyBuffer + ReplySize -
sizeof(IO_STATUS_BLOCK));
+ ReplySize -= sizeof(IO_STATUS_BLOCK);
- putenv(lang_env);
- execvp(argv[0], (char **)argv);
- _exit(1);
+ InputBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ReplySize);
+ if (InputBuffer == NULL)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return 0;
}
- close(pipe_out[1]);
+ Request = (PICMP_ECHO_REQUEST)InputBuffer;
+ Request->Address = DestinationAddress;
+ Request->Timeout = Timeout;
+ Request->OptionsOffset = sizeof(ICMP_ECHO_REQUEST);
+ Request->DataOffset = sizeof(ICMP_ECHO_REQUEST);
- /* Wait for child and read output */
- pos = 0;
- do
+ if (RequestOptions != NULL)
{
- if (pos >= sizeof(buf) - 1)
- {
- ERR("line too long, dropping buffer\n");
- pos = 0;
- }
+ Request->HasOptions = TRUE;
+ Request->Ttl = RequestOptions->Ttl;
+ Request->Tos = RequestOptions->Tos;
+ Request->Flags = RequestOptions->Flags;
- /* read next block */
- do
+ if (RequestOptions->OptionsSize > 0)
{
- 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;
- }
+ Request->OptionsSize = RequestOptions->OptionsSize;
+ Request->DataOffset += Request->OptionsSize;
- pos += res;
- while (pos)
- {
- eol = memchr(buf, '\n', pos);
- if (!eol) break;
- *eol = 0;
-
- TRACE("Received line: %s\n", debugstr_a(buf));
-
- /* 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));
- }
- }
-
- /* 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);
- }
- }
-
- /* 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);
- }
- }
-
- memmove(buf, eol + 1, pos - (eol + 1 - buf));
- pos -= (eol + 1 - buf);
+ CopyMemory(
+ (PUCHAR)InputBuffer + sizeof(ICMP_ECHO_REQUEST),
+ RequestOptions->OptionsData,
+ Request->OptionsSize);
}
}
- while (res > 0);
- close(pipe_out[0]);
- /* reap the child process */
- do
+ if (RequestSize > 0)
{
- wpid = waitpid(pid, &status, 0);
+ Request->DataSize = RequestSize;
+ CopyMemory((PUCHAR)InputBuffer + Request->DataOffset, RequestData,
RequestSize);
}
- while (wpid < 0 && errno == EINTR);
- /* fill out remaining struct fields */
- if (wpid >= 0 && WIFEXITED(status) && WEXITSTATUS(status) == 0)
+ if (Event == NULL && ApcRoutine == NULL)
{
- 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;
+ hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
}
-
- SetLastError(IP_REQ_TIMED_OUT);
- return 0;
-#else
- ERR("no fork support on this platform\n");
- SetLastError(ERROR_NOT_SUPPORTED);
- return 0;
-#endif
-}
-#else // __REACTOS__
-BOOL
-GetIPv4ByIndex(
- _In_ DWORD Index,
- _Out_ IPAddr * Address
-)
-{
- PMIB_IPADDRTABLE pIpAddrTable;
- ULONG dwSize = 0;
- BOOL result = FALSE;
-
- if (GetIpAddrTable(NULL, &dwSize, FALSE) != ERROR_INSUFFICIENT_BUFFER)
+ else
+ {
+ hEvent = Event;
+ }
+
+ 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)
{
- return result;
+ SetLastError(RtlNtStatusToDosError(Status));
+ HeapFree(GetProcessHeap(), 0, InputBuffer);
+ return 0;
}
- pIpAddrTable = HeapAlloc(GetProcessHeap(), 0, dwSize);
- if (GetIpAddrTable(pIpAddrTable, &dwSize, FALSE) == NO_ERROR)
+ // Otherwise handle it like IcmpSendEcho.
+ if (Status == STATUS_PENDING)
{
- INT i;
+ Status = NtWaitForSingleObject(hEvent, FALSE, NULL);
- for (i = 0; i < (*pIpAddrTable).dwNumEntries; i++)
+ if (NT_SUCCESS(Status))
{
- if ((*pIpAddrTable).table[i].dwIndex == Index)
- {
- *Address = (IPAddr)(*pIpAddrTable).table[i].dwAddr;
- result = TRUE;
- break;
- }
+ Status = IoStatusBlock->Status;
}
}
- HeapFree(GetProcessHeap(), 0, pIpAddrTable);
- return result;
-}
-#endif // __REACTOS__
-/***********************************************************************
- * IcmpSendEcho (IPHLPAPI.@)
- */
-DWORD WINAPI IcmpSendEcho(
- HANDLE IcmpHandle,
- IPAddr DestinationAddress,
- LPVOID RequestData,
- WORD RequestSize,
- PIP_OPTION_INFORMATION RequestOptions,
- LPVOID ReplyBuffer,
- DWORD ReplySize,
- DWORD Timeout
- )
-{
- icmp_t* icp=(icmp_t*)IcmpHandle;
- unsigned char* reqbuf;
- int reqsize;
-
- 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);
- return 0;
- }
+ CloseHandle(hEvent);
+ HeapFree(GetProcessHeap(), 0, InputBuffer);
-#ifdef __REACTOS__
- if (ReplySize<sizeof(ICMP_ECHO_REPLY)) {
- SetLastError(ERROR_INVALID_PARAMETER);
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastError(RtlNtStatusToDosError(Status));
return 0;
}
- if (ReplySize-RequestSize<sizeof(ICMP_ECHO_REPLY)) {
- SetLastError(IP_GENERAL_FAILURE);
- return 0;
+ Status = ((PICMP_ECHO_REPLY)ReplyBuffer)->Status;
+ if (Status != IP_SUCCESS)
+ {
+ SetLastError(Status);
}
- if (!ReplyBuffer) {
- SetLastError(ERROR_INVALID_PARAMETER);
- return 0;
- }
+ nReplies = ((PICMP_ECHO_REPLY)ReplyBuffer)->Reserved;
+ ((PICMP_ECHO_REPLY)ReplyBuffer)->Reserved = 0;
- if (Timeout == 0 || Timeout == -1) {
+ return nReplies;
+}
+
+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 (Timeout == 0 || Timeout == (DWORD)-1)
+ {
SetLastError(ERROR_INVALID_PARAMETER);
-#else
- if (ReplySize<sizeof(ICMP_ECHO_REPLY)+ICMP_MINLEN) {
- SetLastError(IP_BUF_TOO_SMALL);
-#endif
return 0;
}
- /* check the request size against SO_MAX_MSG_SIZE using getsockopt */
- if (!DestinationAddress) {
- SetLastError(ERROR_INVALID_NETNAME);
+ if (ReplySize < sizeof(ICMP_ECHO_REPLY))
+ {
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
-#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
-
- /* Prepare the request */
-#ifdef __REACTOS__
- id = GetCurrentProcessId() & 0xFFFF;
-#else
- id=getpid() & 0xFFFF;
-#endif
- seq=InterlockedIncrement(&icmp_sequence) & 0xFFFF;
-
-#ifdef __REACTOS__
- reqsize=ICMP_MINLEN;
- if (RequestData && RequestSize > 0)
- reqsize += RequestSize;
-#else
- reqsize=ICMP_MINLEN+RequestSize;
-#endif
- reqbuf=HeapAlloc(GetProcessHeap(), 0, reqsize);
- if (reqbuf==NULL) {
- SetLastError(ERROR_OUTOFMEMORY);
+ if (ReplySize < RequestSize + sizeof(ICMP_ECHO_REPLY))
+ {
+ SetLastError(IP_GENERAL_FAILURE);
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;
-#ifdef __REACTOS__
- if (RequestData && RequestSize > 0)
- memcpy(reqbuf+ICMP_MINLEN, RequestData, RequestSize);
-#else
- memcpy(reqbuf+ICMP_MINLEN, RequestData, RequestSize);
-#endif
- icmp_header->icmp_cksum=cksum=in_cksum((u_short*)reqbuf,reqsize);
-
- addr.sin_family=AF_INET;
- addr.sin_addr.s_addr=DestinationAddress;
- addr.sin_port=0;
-
- 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
*/
- }
+ InputBufferLength = sizeof(ICMP_ECHO_REQUEST) + RequestSize;
+ if (RequestOptions != NULL)
+ InputBufferLength += RequestOptions->OptionsSize;
- 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 */
+ if (InputBufferLength < ReplySize)
+ InputBufferLength = ReplySize;
- icp->default_opts.OptionsSize=IP_OPTS_CUSTOM;
- } else if (icp->default_opts.OptionsSize==IP_OPTS_CUSTOM) {
- int val;
+ InputBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, InputBufferLength);
+ if (InputBuffer == NULL)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ 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 */
+ Request = (PICMP_ECHO_REQUEST)InputBuffer;
+ Request->Address = DestinationAddress;
+ Request->Timeout = Timeout;
+ Request->OptionsOffset = sizeof(ICMP_ECHO_REQUEST);
+ Request->DataOffset = sizeof(ICMP_ECHO_REQUEST);
- icp->default_opts.OptionsSize=IP_OPTS_DEFAULT;
- }
+ if (RequestOptions != NULL)
+ {
+ Request->HasOptions = TRUE;
+ Request->Ttl = RequestOptions->Ttl;
+ Request->Tos = RequestOptions->Tos;
+ Request->Flags = RequestOptions->Flags;
- /* 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;
-#ifdef __REACTOS__
- endbuf=((char *) ReplyBuffer)+ReplySize;
- maxlen=sizeof(struct ip)+ICMP_MINLEN+RequestSize;
-#else
- ip_header=(struct ip *) ((char *) ReplyBuffer+sizeof(ICMP_ECHO_REPLY));
- endbuf=(char *) ReplyBuffer+ReplySize;
- maxlen=ReplySize-sizeof(ICMP_ECHO_REPLY);
-#endif
-
- /* 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
-
- send_time = GetTickCount();
-#ifdef __REACTOS__
- res=sendto(icp->sid, (const char*)reqbuf, reqsize, 0, (struct sockaddr*)&addr,
sizeof(addr));
-#else
- res=sendto(icp->sid, reqbuf, reqsize, 0, (struct sockaddr*)&addr,
sizeof(addr));
-#endif
- HeapFree(GetProcessHeap (), 0, reqbuf);
- if (res<0) {
-#ifdef __REACTOS__
- DWORD dwBestIfIndex;
- IPAddr IP4Addr;
-
- ZeroMemory(&ier->Address, sizeof(ier->Address));
-
- if (GetBestInterface(addr.sin_addr.s_addr, &dwBestIfIndex) == NO_ERROR
&&
- GetIPv4ByIndex(dwBestIfIndex, &IP4Addr))
+ if (RequestOptions->OptionsSize > 0)
{
- memcpy(&ier->Address, &IP4Addr, sizeof(IP4Addr));
- }
+ Request->OptionsSize = RequestOptions->OptionsSize;
+ Request->DataOffset += Request->OptionsSize;
- if (WSAGetLastError()==WSAEMSGSIZE)
- ier->Status = IP_PACKET_TOO_BIG;
- else {
- switch (WSAGetLastError()) {
- case WSAENETUNREACH:
- ier->Status = IP_DEST_NET_UNREACHABLE;
- break;
- case WSAEHOSTUNREACH:
- ier->Status = IP_DEST_HOST_UNREACHABLE;
- break;
- default:
- TRACE("unknown error: errno=%d\n",WSAGetLastError());
- ier->Status = IP_GENERAL_FAILURE;
- ZeroMemory(&ier->Address, sizeof(ier->Address));
- }
- }
- return 1;
-#else
- if (errno==EMSGSIZE)
- SetLastError(IP_PACKET_TOO_BIG);
- else {
- switch (errno) {
- case ENETUNREACH:
- SetLastError(IP_DEST_NET_UNREACHABLE);
- break;
- case EHOSTUNREACH:
- SetLastError(IP_DEST_HOST_UNREACHABLE);
- break;
- default:
- TRACE("unknown error: errno=%d\n",errno);
- SetLastError(IP_GENERAL_FAILURE);
- }
+ CopyMemory(
+ (PUCHAR)InputBuffer + sizeof(ICMP_ECHO_REQUEST),
+ RequestOptions->OptionsData,
+ Request->OptionsSize);
}
- return 0;
-#endif
}
- /* Get the reply */
-#ifdef __REACTOS__
- ip_header=HeapAlloc(GetProcessHeap(), 0, maxlen);
-#endif
- 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();
-#ifdef __REACTOS__
- res=recvfrom(icp->sid, (char*)ip_header, maxlen, 0, (struct
sockaddr*)&addr,(int*)&addrlen);
-#else
- res=recvfrom(icp->sid, (char*)ip_header, maxlen, 0, (struct
sockaddr*)&addr,&addrlen);
-#endif
- TRACE("received %d bytes from %s\n",res, inet_ntoa(addr.sin_addr));
- ier->Status=IP_REQ_TIMED_OUT;
-#ifdef __REACTOS__
- if (res < 0)
- break;
-#endif
-
- /* 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));
-
- /* 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;
- }
- }
- }
- }
-
- 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;
- FD_ZERO(&fdr);
- FD_SET(icp->sid, &fdr);
-#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;
- }
-
- /* Prepare for the next packet */
- ier++;
-#ifndef __REACTOS__
- ip_header=(struct ip*)(((char*)ip_header)+sizeof(ICMP_ECHO_REPLY));
- maxlen=endbuf-(char*)ip_header;
-#endif
-
- /* 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
- }
-#ifdef __REACTOS__
- FD_ZERO(&fdr);
- FD_SET(icp->sid,&fdr);
-#endif
- }
-#ifdef __REACTOS__
- HeapFree(GetProcessHeap(), 0, ip_header);
-#endif
- res=ier-(ICMP_ECHO_REPLY*)ReplyBuffer;
- if (res==0)
-#ifdef __REACTOS__
+ if (RequestSize > 0)
{
- ier->Status = IP_REQ_TIMED_OUT;
-#endif
- SetLastError(IP_REQ_TIMED_OUT);
-#ifdef __REACTOS__
+ Request->DataSize = RequestSize;
+ CopyMemory((PUCHAR)InputBuffer + Request->DataOffset, RequestData,
RequestSize);
}
-#endif
- 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)
- {
- FIXME("unsupported for events\n");
- return 0;
- }
- 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;
-/*
- * 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.
- *
- */
+ return nReplies;
+}
diff --git a/dll/win32/iphlpapi/iphlpapi.spec b/dll/win32/iphlpapi/iphlpapi.spec
index 6d186f35152..3151b5f40db 100644
--- a/dll/win32/iphlpapi/iphlpapi.spec
+++ b/dll/win32/iphlpapi/iphlpapi.spec
@@ -80,11 +80,11 @@
@ stub GetUdpTableFromStack
@ stdcall GetUniDirectionalAdapterInfo( ptr ptr )
@ stdcall Icmp6CreateFile()
-@ stdcall -stub Icmp6ParseReplies(ptr long)
+@ 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
diff --git a/sdk/include/psdk/ipexport.h b/sdk/include/psdk/ipexport.h
index 98cd3a9b82f..82c89a1531d 100644
--- a/sdk/include/psdk/ipexport.h
+++ b/sdk/include/psdk/ipexport.h
@@ -28,14 +28,14 @@ typedef ULONG IPAddr;
typedef ULONG IPMask;
typedef ULONG IP_STATUS;
-struct ip_option_information
+typedef struct ip_option_information
{
unsigned char Ttl;
unsigned char Tos;
unsigned char Flags;
unsigned char OptionsSize;
unsigned char* OptionsData;
-};
+} IP_OPTION_INFORMATION, *PIP_OPTION_INFORMATION;
#if defined(_WIN64)
@@ -64,20 +64,31 @@ struct ip_option_information32
#define MAX_OPT_SIZE 40
-struct icmp_echo_reply
+typedef struct icmp_echo_request
{
- IPAddr Address;
- ULONG Status;
- ULONG RoundTripTime;
- unsigned short DataSize;
- unsigned short Reserved;
- void* Data;
- struct ip_option_information Options;
-};
-
-typedef struct ip_option_information IP_OPTION_INFORMATION, *PIP_OPTION_INFORMATION;
-
-typedef struct icmp_echo_reply ICMP_ECHO_REPLY, *PICMP_ECHO_REPLY;
+ IPAddr Address;
+ UINT32 Timeout;
+ UINT16 DataOffset;
+ UINT16 DataSize;
+ UINT8 HasOptions;
+ UINT8 Ttl;
+ UINT8 Tos;
+ UINT8 Flags;
+ UINT16 OptionsOffset;
+ UINT8 OptionsSize;
+ UINT8 Padding;
+} ICMP_ECHO_REQUEST, *PICMP_ECHO_REQUEST;
+
+typedef struct icmp_echo_reply
+{
+ IPAddr Address;
+ UINT32 Status;
+ UINT32 RoundTripTime;
+ UINT16 DataSize;
+ UINT16 Reserved;
+ PVOID Data;
+ IP_OPTION_INFORMATION Options;
+} ICMP_ECHO_REPLY, *PICMP_ECHO_REPLY;
#ifdef _WIN64
struct icmp_echo_reply32
@@ -164,6 +175,16 @@ typedef struct _IPV6_ADDRESS_EX {
} IPV6_ADDRESS_EX, *PIPV6_ADDRESS_EX;
#include <poppack.h>
+typedef struct _ICMPV6_ECHO_REQUEST
+{
+ IPV6_ADDRESS_EX DestinationAddress;
+ IPV6_ADDRESS_EX SourceAddress;
+ UINT32 Timeout;
+ UINT16 Unknown1;
+ UINT16 Ttl; // XXX: These seem unnecessarily large.
+ UINT32 Flags; // Is something else in the struct?
+} ICMPV6_ECHO_REQUEST, *PICMPV6_ECHO_REQUEST;
+
typedef struct icmpv6_echo_reply_lh {
IPV6_ADDRESS_EX Address;
ULONG Status;
diff --git a/sdk/include/psdk/tcpioctl.h b/sdk/include/psdk/tcpioctl.h
index af7389155ca..cb9744bd508 100644
--- a/sdk/include/psdk/tcpioctl.h
+++ b/sdk/include/psdk/tcpioctl.h
@@ -46,6 +46,9 @@
#define IOCTL_DELETE_IP_ADDRESS \
_TCP_CTL_CODE(16, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+#define IOCTL_ICMP_ECHO_REQUEST \
+ _TCP_CTL_CODE(0, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
#define IF_MIB_STATS_ID 1
#define IP_MIB_STATS_ID 1
#define IP_MIB_ARPTABLE_ENTRY_ID 0x101