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@gmail.com) + * 2019 Victor Perevertkin (victor.perevertkin@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 -#ifdef HAVE_SYS_SOCKET_H -# include -#endif -#ifdef HAVE_NETDB_H -# include -#endif -#ifdef HAVE_NETINET_IN_SYSTM_H -# include -#endif -#ifdef HAVE_NETINET_IN_H -# include -#endif +WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi); -#ifdef HAVE_SYS_TIME_H -# include -#endif -#include -#include -#include -#include -#include -#ifdef HAVE_UNISTD_H -# include -#endif -#ifdef HAVE_ARPA_INET_H -# include -#endif -#ifdef HAVE_SYS_POLL_H -# include -#endif -#ifdef HAVE_SYS_WAIT_H -# include -#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(icmp); -WINE_DECLARE_DEBUG_CHANNEL(winediag); - - -typedef struct { - int sid; - IP_OPTION_INFORMATION default_opts; -} icmp_t; - -#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; - -static int in_cksum(u_short *addr, int len) +HANDLE +WINAPI +Icmp6CreateFile(void) { - int nleft=len; - u_short *w = addr; - int sum = 0; - u_short answer = 0; + HANDLE IcmpFile; + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock; + UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\Ip6"); + NTSTATUS Status; - while (nleft > 1) { - sum += *w++; - nleft -= 2; + 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; } - if (nleft == 1) { - *(u_char *)(&answer) = *(u_char *)w; - sum += answer; - } - - sum = (sum >> 16) + (sum & 0xffff); - sum += (sum >> 16); - answer = ~sum; - return(answer); + return IcmpFile; } - - -/* - * Exported Routines. - */ - -/*********************************************************************** - * Icmp6CreateFile (IPHLPAPI.@) - */ -HANDLE WINAPI Icmp6CreateFile(VOID) +DWORD +WINAPI +Icmp6ParseReplies( + _In_ LPVOID ReplyBuffer, + _In_ DWORD ReplySize) { - icmp_t* icp; -#ifdef __REACTOS__ - int sid; - WSADATA wsaData; + PICMPV6_ECHO_REPLY pEcho; - if (WSAStartup(MAKEWORD(2, 2), &wsaData) != ERROR_SUCCESS) - { - ERR_(winediag)("Failed to use ICMPV6 (network ping), this requires special permissions.\n"); - return INVALID_HANDLE_VALUE; - } - - sid=socket(AF_INET6,SOCK_RAW,IPPROTO_ICMPV6); -#else - - int sid=socket(AF_INET6,SOCK_RAW,IPPROTO_ICMPV6); - if (sid < 0) - { - /* 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; - } - - 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; -} - - -/*********************************************************************** - * 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; -} - - -/*********************************************************************** - * 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) - { - ERR_(winediag)("Failed to use ICMPV6 (network ping), this requires special permissions.\n"); - return INVALID_HANDLE_VALUE; - } - 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; - } -#else - - int sid=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP); - if (sid < 0) - { - /* Mac OS X supports non-privileged ICMP via SOCK_DGRAM type. */ - sid=socket(AF_INET,SOCK_DGRAM,IPPROTO_ICMP); - } - 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); - WSACleanup(); -#else - if (sid >= 0) close(sid); -#endif - SetLastError(IP_NO_RESOURCES); - return INVALID_HANDLE_VALUE; - } - icp->sid=sid; - icp->default_opts.OptionsSize=IP_OPTS_UNKNOWN; - return (HANDLE)icp; -} - - -/*********************************************************************** - * IcmpCloseHandle (IPHLPAPI.@) - */ -BOOL WINAPI IcmpCloseHandle(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); - 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 - ) -{ -#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) - { - #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 - } - - addr.s_addr = DestinationAddress; - if (!(ptr = inet_ntoa(addr))) - { - SetLastError(ERROR_INVALID_PARAMETER); + 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++) + pEcho = (PICMPV6_ECHO_REPLY)ReplyBuffer; + + // XXX: MSDN also says IP_TTL_EXPIRED_TRANSIT. + if (pEcho->Status == IP_SUCCESS) { - 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 - { - 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); - } - - /* Fork child process */ - pid = fork(); - if (pid == -1) - { - close(pipe_out[0]); - close(pipe_out[1]); - SetLastError(ERROR_OUTOFMEMORY); - return 0; - } - - /* Child process */ - if (pid == 0) - { - static char lang_env[] = "LANG=C"; - - dup2(pipe_out[1], 1); - close(pipe_out[0]); - close(pipe_out[1]); - close(0); - close(2); - - putenv(lang_env); - execvp(argv[0], (char **)argv); - _exit(1); - } - - close(pipe_out[1]); - - /* Wait for child and read output */ - pos = 0; - do - { - if (pos >= sizeof(buf) - 1) - { - ERR("line too long, dropping buffer\n"); - pos = 0; - } - - /* 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; - } - - 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); - } - } - while (res > 0); - close(pipe_out[0]); - - /* reap the child process */ - do - { - wpid = waitpid(pid, &status, 0); - } - while (wpid < 0 && errno == EINTR); - - /* fill out remaining struct fields */ - if (wpid >= 0 && WIFEXITED(status) && WEXITSTATUS(status) == 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(IP_REQ_TIMED_OUT); + SetLastError(pEcho->Status); 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 -) + +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) { - PMIB_IPADDRTABLE pIpAddrTable; - ULONG dwSize = 0; - BOOL result = FALSE; + HANDLE hEvent; + PIO_STATUS_BLOCK IoStatusBlock; + PVOID InputBuffer; + ULONG InputBufferLength; + //ULONG OutputBufferLength; + PICMPV6_ECHO_REQUEST Request; + NTSTATUS Status; - if (GetIpAddrTable(NULL, &dwSize, FALSE) != ERROR_INSUFFICIENT_BUFFER) + InputBufferLength = sizeof(ICMPV6_ECHO_REQUEST) + RequestSize; + + if (ReplySize < sizeof(ICMPV6_ECHO_REPLY) + sizeof(IO_STATUS_BLOCK)) { - return result; + SetLastError(IP_BUF_TOO_SMALL); + return 0; } - pIpAddrTable = HeapAlloc(GetProcessHeap(), 0, dwSize); - if (GetIpAddrTable(pIpAddrTable, &dwSize, FALSE) == NO_ERROR) + // 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); + + InputBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, InputBufferLength); + if (InputBuffer == NULL) { - INT i; + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return 0; + } - for (i = 0; i < (*pIpAddrTable).dwNumEntries; i++) + 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; + + 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; + + Request->Timeout = Timeout; + Request->Ttl = RequestOptions->Ttl; + Request->Flags = RequestOptions->Flags; + + if (RequestSize > 0) + { + CopyMemory((PBYTE)InputBuffer + sizeof(ICMPV6_ECHO_REQUEST), RequestData, RequestSize); + } + + 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; + } + + if (Status == STATUS_PENDING) + { + Status = NtWaitForSingleObject(hEvent, FALSE, NULL); + + 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; + + CloseHandle(hEvent); + HeapFree(GetProcessHeap(), 0, InputBuffer); + + if (!NT_SUCCESS(Status)) + { + SetLastError(RtlNtStatusToDosError(Status)); + return 0; + } + + Status = ((PICMPV6_ECHO_REPLY)ReplyBuffer)->Status; + if (Status != IP_SUCCESS) + { + SetLastError(Status); + return 0; + } + + return 1; } -#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 - ) +BOOL +WINAPI +IcmpCloseHandle( + _In_ HANDLE IcmpHandle) { - icmp_t* icp=(icmp_t*)IcmpHandle; - unsigned char* reqbuf; - int reqsize; + 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; + Status = NtClose(IcmpHandle); + if (!NT_SUCCESS(Status)) + { + SetLastError(RtlNtStatusToDosError(Status)); + return FALSE; + } - if (IcmpHandle==INVALID_HANDLE_VALUE) { - /* FIXME: in fact win98 seems to ignore the handle value !!! */ - SetLastError(ERROR_INVALID_HANDLE); + return TRUE; +} + +HANDLE +WINAPI +IcmpCreateFile(void) +{ + 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)) + { + SetLastError(RtlNtStatusToDosError(Status)); + return INVALID_HANDLE_VALUE; + } + + return IcmpFile; +} + +DWORD +WINAPI +IcmpParseReplies( + _In_ LPVOID ReplyBuffer, + _In_ DWORD ReplySize) +{ + PICMP_ECHO_REPLY pEcho; + DWORD nReplies; + + if (ReplyBuffer == NULL || ReplySize == 0) + return 0; + + // TODO: Handle ReplyBuffer having more than 1 ICMP_ECHO_REPLY. + + pEcho = (PICMP_ECHO_REPLY)ReplyBuffer; + + if (pEcho->Reserved == 0) + { + SetLastError(pEcho->Status); + } + + 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)) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); return 0; } -#ifdef __REACTOS__ - if (ReplySizeAddress = DestinationAddress; + Request->Timeout = Timeout; + Request->OptionsOffset = sizeof(ICMP_ECHO_REQUEST); + Request->DataOffset = sizeof(ICMP_ECHO_REQUEST); - if (!DestinationAddress) { - SetLastError(ERROR_INVALID_NETNAME); - return 0; - } + if (RequestOptions != NULL) + { + Request->HasOptions = TRUE; + Request->Ttl = RequestOptions->Ttl; + Request->Tos = RequestOptions->Tos; + Request->Flags = RequestOptions->Flags; -#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); - 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 */ - } - - 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 */ - - icp->default_opts.OptionsSize=IP_OPTS_CUSTOM; - } else if (icp->default_opts.OptionsSize==IP_OPTS_CUSTOM) { - int val; - - /* 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; - } - - /* 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;isid, (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)); - } + CopyMemory( + (PUCHAR)InputBuffer + sizeof(ICMP_ECHO_REQUEST), + RequestOptions->OptionsData, + Request->OptionsSize); } - 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); - } - } - 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; + + 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, + 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; + } + + // Otherwise handle it like IcmpSendEcho. + if (Status == STATUS_PENDING) + { + Status = NtWaitForSingleObject(hEvent, FALSE, NULL); + + if (NT_SUCCESS(Status)) + { + Status = IoStatusBlock->Status; + } + } + + CloseHandle(hEvent); + HeapFree(GetProcessHeap(), 0, InputBuffer); + + if (!NT_SUCCESS(Status)) + { + SetLastError(RtlNtStatusToDosError(Status)); + return 0; + } + + Status = ((PICMP_ECHO_REPLY)ReplyBuffer)->Status; + if (Status != IP_SUCCESS) + { + SetLastError(Status); + } + + nReplies = ((PICMP_ECHO_REPLY)ReplyBuffer)->Reserved; + ((PICMP_ECHO_REPLY)ReplyBuffer)->Reserved = 0; + + return nReplies; } -/*********************************************************************** - * 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 - ) +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) { - 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); + HANDLE hEvent; + IO_STATUS_BLOCK IoStatusBlock; + PVOID InputBuffer; + ULONG InputBufferLength; + PICMP_ECHO_REQUEST Request; + DWORD nReplies; + NTSTATUS Status; - if (Event) + if (Timeout == 0 || Timeout == (DWORD)-1) { - FIXME("unsupported for events\n"); + SetLastError(ERROR_INVALID_PARAMETER); return 0; } - if (ApcRoutine) + + if (ReplySize < sizeof(ICMP_ECHO_REPLY)) { - FIXME("unsupported for APCs\n"); + SetLastError(ERROR_INSUFFICIENT_BUFFER); return 0; } - return IcmpSendEcho(IcmpHandle, DestinationAddress, RequestData, - RequestSize, RequestOptions, ReplyBuffer, ReplySize, Timeout); + + if (ReplySize < RequestSize + sizeof(ICMP_ECHO_REPLY)) + { + SetLastError(IP_GENERAL_FAILURE); + return 0; + } + + InputBufferLength = sizeof(ICMP_ECHO_REQUEST) + RequestSize; + if (RequestOptions != NULL) + InputBufferLength += RequestOptions->OptionsSize; + + if (InputBufferLength < ReplySize) + InputBufferLength = ReplySize; + + InputBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, InputBufferLength); + if (InputBuffer == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + 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( + (PUCHAR)InputBuffer + sizeof(ICMP_ECHO_REQUEST), + RequestOptions->OptionsData, + Request->OptionsSize); + } + } + + if (RequestSize > 0) + { + Request->DataSize = RequestSize; + CopyMemory((PUCHAR)InputBuffer + Request->DataOffset, RequestData, RequestSize); + } + + hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); + if (hEvent == NULL) + { + HeapFree(GetProcessHeap(), 0, InputBuffer); + return 0; + } + + Status = NtDeviceIoControlFile( + IcmpHandle, + hEvent, + NULL, + NULL, + &IoStatusBlock, + IOCTL_ICMP_ECHO_REQUEST, + InputBuffer, + InputBufferLength, + ReplyBuffer, + ReplySize); + + if (Status == STATUS_PENDING) + { + Status = NtWaitForSingleObject(hEvent, FALSE, NULL); + + if (NT_SUCCESS(Status)) + { + Status = IoStatusBlock.Status; + } + } + + CloseHandle(hEvent); + HeapFree(GetProcessHeap(), 0, InputBuffer); + + if (!NT_SUCCESS(Status)) + { + SetLastError(RtlNtStatusToDosError(Status)); + return 0; + } + + Status = ((PICMP_ECHO_REPLY)ReplyBuffer)->Status; + if (Status != IP_SUCCESS) + { + SetLastError(Status); + } + + nReplies = ((PICMP_ECHO_REPLY)ReplyBuffer)->Reserved; + ((PICMP_ECHO_REPLY)ReplyBuffer)->Reserved = 0; + + return nReplies; } - -/*********************************************************************** - * 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); - - if (Event) - { - FIXME("unsupported for events\n"); - return 0; - } - if (ApcRoutine) - { - FIXME("unsupported for APCs\n"); - return 0; - } - if (SourceAddress) - { - FIXME("unsupported for source addresses\n"); - return 0; - } - - return IcmpSendEcho(IcmpHandle, DestinationAddress, RequestData, - RequestSize, RequestOptions, ReplyBuffer, ReplySize, Timeout); -} - -/* - * 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. - * - */ 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; -}; + 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 ip_option_information IP_OPTION_INFORMATION, *PIP_OPTION_INFORMATION; - -typedef struct icmp_echo_reply ICMP_ECHO_REPLY, *PICMP_ECHO_REPLY; +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 +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