Wine-devel
Threads by month
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
October 2021
- 81 participants
- 772 discussions
08 Oct '21
This results in a small change in behaviour reflected by the change to
the tests: previously IcmpCreateFile() would fail if neither a
SOCK_RAW nor a SOCK_DGRAM socket were available. With this patch, that
failure is delayed until IcmpSendEcho2Ex(). There's no evidence that
the original behaviour matches Windows; it's likely the tests were
written this way to match Wine's implementation. If there does turn
out to be an app that depends on the old behaviour, it would be
possible to send an ioctl during IcmpCreateFile() to probe for this.
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/iphlpapi/Makefile.in | 1 -
dlls/iphlpapi/icmp.c | 643 ---------------------------------
dlls/iphlpapi/ip.h | 180 ---------
dlls/iphlpapi/ip_icmp.h | 186 ----------
dlls/iphlpapi/iphlpapi_main.c | 172 +++++++++
dlls/iphlpapi/tests/iphlpapi.c | 14 +-
6 files changed, 177 insertions(+), 1019 deletions(-)
delete mode 100644 dlls/iphlpapi/icmp.c
delete mode 100644 dlls/iphlpapi/ip.h
delete mode 100644 dlls/iphlpapi/ip_icmp.h
diff --git a/dlls/iphlpapi/Makefile.in b/dlls/iphlpapi/Makefile.in
index d5f7818be5f..e413337a420 100644
--- a/dlls/iphlpapi/Makefile.in
+++ b/dlls/iphlpapi/Makefile.in
@@ -5,7 +5,6 @@ IMPORTS = advapi32 dnsapi nsi uuid
EXTRADLLFLAGS = -mcygwin
C_SRCS = \
- icmp.c \
iphlpapi_main.c
RC_SRCS = version.rc
diff --git a/dlls/iphlpapi/icmp.c b/dlls/iphlpapi/icmp.c
deleted file mode 100644
index 6441d7dd8ad..00000000000
--- a/dlls/iphlpapi/icmp.c
+++ /dev/null
@@ -1,643 +0,0 @@
-/*
- * 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.
- *
- * 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
- */
-
-/* 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.
- */
-
-#include "config.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 <errno.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
-
-#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"
-
-/* 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
-
-#define MAXIPLEN 60
-#define MAXICMPLEN 76
-
-/* 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)
-{
- int nleft=len;
- u_short *w = addr;
- int sum = 0;
- u_short answer = 0;
-
- while (nleft > 1) {
- sum += *w++;
- nleft -= 2;
- }
-
- if (nleft == 1) {
- *(u_char *)(&answer) = *(u_char *)w;
- sum += answer;
- }
-
- sum = (sum >> 16) + (sum & 0xffff);
- sum += (sum >> 16);
- answer = ~sum;
- return(answer);
-}
-
-/* Receive a reply (IPv4); this function uses, takes ownership of and will always free `buffer` */
-static DWORD icmp_get_reply(int sid, unsigned char *buffer, DWORD send_time, void *reply_buf, DWORD reply_size, DWORD timeout)
-{
- int repsize = MAXIPLEN + MAXICMPLEN + min(65535, reply_size);
- struct icmp *icmp_header = (struct icmp*)buffer;
- char *endbuf = (char*)reply_buf + reply_size;
- struct ip *ip_header = (struct ip*)buffer;
- struct icmp_echo_reply *ier = reply_buf;
- unsigned short id, seq, cksum;
- struct sockaddr_in addr;
- int ip_header_len = 0;
- socklen_t addrlen;
- struct pollfd fdr;
- DWORD recv_time;
- int res;
-
- id = icmp_header->icmp_id;
- seq = icmp_header->icmp_seq;
- cksum = icmp_header->icmp_cksum;
- fdr.fd = sid;
- fdr.events = POLLIN;
- addrlen = sizeof(addr);
-
- while (poll(&fdr,1,timeout)>0) {
- recv_time = GetTickCount();
- res=recvfrom(sid, buffer, repsize, 0, (struct sockaddr*)&addr, &addrlen);
- TRACE("received %d bytes from %s\n",res, inet_ntoa(addr.sin_addr));
- ier->Status=IP_REQ_TIMED_OUT;
-
- /* 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;
- SetLastError(NO_ERROR);
- }
- } 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.
- */
- DWORD t = (recv_time - send_time);
- if (timeout > t) timeout -= t;
- else timeout = 0;
- continue;
- } else {
- /* Check free space, should be large enough for an ICMP_ECHO_REPLY and remainning icmp data */
- if (endbuf-(char *)ier < sizeof(struct icmp_echo_reply)+(res-ip_header_len-ICMP_MINLEN)) {
- res=ier-(ICMP_ECHO_REPLY *)reply_buf;
- SetLastError(IP_GENERAL_FAILURE);
- goto done;
- }
- /* 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;
- memcpy(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 */
- memcpy(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++;
-
- /* Check out whether there is more but don't wait this time */
- timeout=0;
- }
- }
- res=ier-(ICMP_ECHO_REPLY*)reply_buf;
- if (res==0)
- SetLastError(IP_REQ_TIMED_OUT);
-done:
- if (res)
- {
- /* Move the data so there's no gap between it and the ICMP_ECHO_REPLY array */
- DWORD gap_size = endbuf - (char*)ier;
-
- if (gap_size)
- {
- memmove(ier, endbuf, ((char*)reply_buf + reply_size) - endbuf);
-
- /* Fix the pointers */
- while (ier-- != reply_buf)
- {
- ier->Data = (char*)ier->Data - gap_size;
- if (ier->Options.OptionsData)
- ier->Options.OptionsData -= gap_size;
- }
-
- /* According to MSDN, the reply buffer needs to hold space for a IO_STATUS_BLOCK,
- found at the very end of the reply. This is confirmed on Windows XP, but Vista
- and later do not store it anywhere and in fact don't even require it at all.
-
- However, in case old apps analyze this IO_STATUS_BLOCK and expect it, we mimic
- it and write it out if there's enough space available in the buffer. */
- if (gap_size >= sizeof(IO_STATUS_BLOCK))
- {
- IO_STATUS_BLOCK *io = (IO_STATUS_BLOCK*)((char*)reply_buf + reply_size - sizeof(IO_STATUS_BLOCK));
-
- io->Pointer = NULL; /* Always NULL or STATUS_SUCCESS */
- io->Information = reply_size - gap_size;
- }
- }
- }
-
- HeapFree(GetProcessHeap(), 0, buffer);
- TRACE("received %d replies\n",res);
- return res;
-}
-
-
-
-/*
- * Exported Routines.
- */
-
-/***********************************************************************
- * IcmpCreateFile (IPHLPAPI.@)
- */
-HANDLE WINAPI IcmpCreateFile(VOID)
-{
- icmp_t* icp;
-
- int sid=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
- if (sid < 0)
- {
- /* Some systems (e.g. Linux 3.0+ and Mac OS X) support
- non-privileged ICMP via SOCK_DGRAM type. */
- sid=socket(AF_INET,SOCK_DGRAM,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;
- }
-
- icp=HeapAlloc(GetProcessHeap(), 0, sizeof(*icp));
- if (icp==NULL) {
- close(sid);
- 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;
- if (IcmpHandle==INVALID_HANDLE_VALUE) {
- /* FIXME: in fact win98 seems to ignore the handle value !!! */
- SetLastError(ERROR_INVALID_HANDLE);
- return FALSE;
- }
-
- close( icp->sid );
- HeapFree(GetProcessHeap (), 0, icp);
- return TRUE;
-}
-
-
-/***********************************************************************
- * IcmpSendEcho (IPHLPAPI.@)
- */
-DWORD WINAPI IcmpSendEcho(
- HANDLE IcmpHandle,
- IPAddr DestinationAddress,
- LPVOID RequestData,
- WORD RequestSize,
- PIP_OPTION_INFORMATION RequestOptions,
- LPVOID ReplyBuffer,
- DWORD ReplySize,
- DWORD Timeout
- )
-{
- return IcmpSendEcho2Ex(IcmpHandle, NULL, NULL, NULL, 0, DestinationAddress,
- RequestData, RequestSize, RequestOptions, ReplyBuffer, ReplySize, Timeout);
-}
-
-/***********************************************************************
- * 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
- )
-{
- return IcmpSendEcho2Ex(IcmpHandle, Event, ApcRoutine, ApcContext, 0,
- 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
- )
-{
- icmp_t* icp=(icmp_t*)IcmpHandle;
- struct icmp* icmp_header;
- struct sockaddr_in addr;
- unsigned short id, seq;
- unsigned char *buffer;
- int reqsize, repsize;
- DWORD send_time;
-
- TRACE("(%p, %p, %p, %p, %08x, %08x, %p, %d, %p, %p, %d, %d)\n", IcmpHandle,
- Event, ApcRoutine, ApcContext, SourceAddress, DestinationAddress, RequestData,
- RequestSize, RequestOptions, ReplyBuffer, ReplySize, Timeout);
-
- if (IcmpHandle==INVALID_HANDLE_VALUE) {
- /* FIXME: in fact win98 seems to ignore the handle value !!! */
- SetLastError(ERROR_INVALID_PARAMETER);
- return 0;
- }
-
- if (!ReplyBuffer||!ReplySize) {
- SetLastError(ERROR_INVALID_PARAMETER);
- return 0;
- }
-
- if (ReplySize<sizeof(ICMP_ECHO_REPLY)) {
- SetLastError(IP_BUF_TOO_SMALL);
- return 0;
- }
- /* check the request size against SO_MAX_MSG_SIZE using getsockopt */
-
- if (!DestinationAddress) {
- SetLastError(ERROR_INVALID_NETNAME);
- return 0;
- }
-
- 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;
- }
-
- /* Prepare the request */
- id=getpid() & 0xFFFF;
- seq=InterlockedIncrement(&icmp_sequence) & 0xFFFF;
-
- reqsize=ICMP_MINLEN+RequestSize;
- /* max ip header + max icmp header and error data + reply size(max 65535 on Windows) */
- /* FIXME: request size of 65535 is not supported yet because max buffer size of raw socket on linux is 32767 */
- repsize = MAXIPLEN + MAXICMPLEN + min( 65535, ReplySize );
- buffer = HeapAlloc(GetProcessHeap(), 0, max( repsize, reqsize ));
- if (buffer == NULL) {
- SetLastError(ERROR_OUTOFMEMORY);
- return 0;
- }
-
- icmp_header=(struct icmp*)buffer;
- 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(buffer+ICMP_MINLEN, RequestData, RequestSize);
- icmp_header->icmp_cksum=in_cksum((u_short*)buffer,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;
- }
-
- /* 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)){
- int i;
- printf("Output buffer:\n");
- for (i=0;i<reqsize;i++)
- printf("%2x,", buffer[i]);
- printf("\n");
- }
-#endif
-
- send_time = GetTickCount();
- if (sendto(icp->sid, buffer, reqsize, 0, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
- 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);
- }
- }
- HeapFree(GetProcessHeap(), 0, buffer);
- return 0;
- }
-
- return icmp_get_reply(icp->sid, buffer, send_time, 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/dlls/iphlpapi/ip.h b/dlls/iphlpapi/ip.h
deleted file mode 100644
index 9c669d9fd88..00000000000
--- a/dlls/iphlpapi/ip.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (c) 1982, 1986, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * 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.
- *
- * @(#)ip.h 8.2 (Berkeley) 6/1/94
- * $FreeBSD: src/sys/netinet/ip.h,v 1.16 1999/08/28 00:49:19 peter Exp $
- */
-
-#ifndef _NETINET_IP_H_
-#define _NETINET_IP_H_
-
-/*
- * Definitions for internet protocol version 4.
- * Per RFC 791, September 1981.
- */
-#define IPVERSION 4
-
-/*
- * Structure of an internet header, naked of options.
- */
-struct ip {
-#ifdef _IP_VHL
- u_char ip_vhl; /* version << 4 | header length >> 2 */
-#else
-#if BYTE_ORDER == LITTLE_ENDIAN
- u_int ip_hl:4, /* header length */
- ip_v:4; /* version */
-#endif
-#if BYTE_ORDER == BIG_ENDIAN
- u_int ip_v:4, /* version */
- ip_hl:4; /* header length */
-#endif
-#endif /* not _IP_VHL */
- u_char ip_tos; /* type of service */
- u_short ip_len; /* total length */
- u_short ip_id; /* identification */
- u_short ip_off; /* fragment offset field */
-#define IP_RF 0x8000 /* reserved fragment flag */
-#define IP_DF 0x4000 /* don't fragment flag */
-#define IP_MF 0x2000 /* more fragments flag */
-#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
- u_char ip_ttl; /* time to live */
- u_char ip_p; /* protocol */
- u_short ip_sum; /* checksum */
- struct in_addr ip_src,ip_dst; /* source and dest address */
-};
-
-#ifdef _IP_VHL
-#define IP_MAKE_VHL(v, hl) ((v) << 4 | (hl))
-#define IP_VHL_HL(vhl) ((vhl) & 0x0f)
-#define IP_VHL_V(vhl) ((vhl) >> 4)
-#define IP_VHL_BORING 0x45
-#endif
-
-#define IP_MAXPACKET 65535 /* maximum packet size */
-
-/*
- * Definitions for IP type of service (ip_tos)
- */
-#define IPTOS_LOWDELAY 0x10
-#define IPTOS_THROUGHPUT 0x08
-#define IPTOS_RELIABILITY 0x04
-#define IPTOS_MINCOST 0x02
-
-/*
- * Definitions for IP precedence (also in ip_tos) (hopefully unused)
- */
-#define IPTOS_PREC_NETCONTROL 0xe0
-#define IPTOS_PREC_INTERNETCONTROL 0xc0
-#define IPTOS_PREC_CRITIC_ECP 0xa0
-#define IPTOS_PREC_FLASHOVERRIDE 0x80
-#define IPTOS_PREC_FLASH 0x60
-#define IPTOS_PREC_IMMEDIATE 0x40
-#define IPTOS_PREC_PRIORITY 0x20
-#define IPTOS_PREC_ROUTINE 0x00
-
-/*
- * Definitions for options.
- */
-#define IPOPT_COPIED(o) ((o)&0x80)
-#define IPOPT_CLASS(o) ((o)&0x60)
-#define IPOPT_NUMBER(o) ((o)&0x1f)
-
-#define IPOPT_CONTROL 0x00
-#define IPOPT_RESERVED1 0x20
-#define IPOPT_DEBMEAS 0x40
-#define IPOPT_RESERVED2 0x60
-
-#define IPOPT_EOL 0 /* end of option list */
-#define IPOPT_NOP 1 /* no operation */
-
-#define IPOPT_RR 7 /* record packet route */
-#define IPOPT_TS 68 /* timestamp */
-#define IPOPT_SECURITY 130 /* provide s,c,h,tcc */
-#define IPOPT_LSRR 131 /* loose source route */
-#define IPOPT_SATID 136 /* satnet id */
-#define IPOPT_SSRR 137 /* strict source route */
-#define IPOPT_RA 148 /* router alert */
-
-/*
- * Offsets to fields in options other than EOL and NOP.
- */
-#define IPOPT_OPTVAL 0 /* option ID */
-#define IPOPT_OLEN 1 /* option length */
-#define IPOPT_OFFSET 2 /* offset within option */
-#define IPOPT_MINOFF 4 /* min value of above */
-
-/*
- * Time stamp option structure.
- */
-struct ip_timestamp {
- u_char ipt_code; /* IPOPT_TS */
- u_char ipt_len; /* size of structure (variable) */
- u_char ipt_ptr; /* index of current entry */
-#if BYTE_ORDER == LITTLE_ENDIAN
- u_int ipt_flg:4, /* flags, see below */
- ipt_oflw:4; /* overflow counter */
-#endif
-#if BYTE_ORDER == BIG_ENDIAN
- u_int ipt_oflw:4, /* overflow counter */
- ipt_flg:4; /* flags, see below */
-#endif
- union ipt_timestamp {
- n_long ipt_time[1];
- struct ipt_ta {
- struct in_addr ipt_addr;
- n_long ipt_time;
- } ipt_ta[1];
- } ipt_timestamp;
-};
-
-/* flag bits for ipt_flg */
-#define IPOPT_TS_TSONLY 0 /* timestamps only */
-#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */
-#define IPOPT_TS_PRESPEC 3 /* specified modules only */
-
-/* bits for security (not byte swapped) */
-#define IPOPT_SECUR_UNCLASS 0x0000
-#define IPOPT_SECUR_CONFID 0xf135
-#define IPOPT_SECUR_EFTO 0x789a
-#define IPOPT_SECUR_MMMM 0xbc4d
-#define IPOPT_SECUR_RESTR 0xaf13
-#define IPOPT_SECUR_SECRET 0xd788
-#define IPOPT_SECUR_TOPSECRET 0x6bc5
-
-/*
- * Internet implementation parameters.
- */
-#define MAXTTL 255 /* maximum time to live (seconds) */
-#define IPDEFTTL 64 /* default ttl, from RFC 1340 */
-#define IPFRAGTTL 60 /* time to live for frags, slowhz */
-#define IPTTLDEC 1 /* subtracted when forwarding */
-
-#define IP_MSS 576 /* default maximum segment size */
-
-#endif
diff --git a/dlls/iphlpapi/ip_icmp.h b/dlls/iphlpapi/ip_icmp.h
deleted file mode 100644
index ce5449526d2..00000000000
--- a/dlls/iphlpapi/ip_icmp.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (c) 1982, 1986, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * 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.
- *
- * @(#)ip_icmp.h 8.1 (Berkeley) 6/10/93
- * $FreeBSD: src/sys/netinet/ip_icmp.h,v 1.13 1999/08/28 00:49:24 peter Exp $
- */
-
-#ifndef _NETINET_IP_ICMP_H_
-#define _NETINET_IP_ICMP_H_
-
-/*
- * Interface Control Message Protocol Definitions.
- * Per RFC 792, September 1981.
- */
-
-/*
- * Internal of an ICMP Router Advertisement
- */
-struct icmp_ra_addr {
- u_int32_t ira_addr;
- u_int32_t ira_preference;
-};
-
-/*
- * Structure of an icmp header.
- */
-struct icmp {
- u_char icmp_type; /* type of message, see below */
- u_char icmp_code; /* type sub code */
- u_short icmp_cksum; /* ones complement cksum of struct */
- union {
- u_char ih_pptr; /* ICMP_PARAMPROB */
- struct in_addr ih_gwaddr; /* ICMP_REDIRECT */
- struct ih_idseq {
- n_short icd_id;
- n_short icd_seq;
- } ih_idseq;
- int ih_void;
-
- /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
- struct ih_pmtu {
- n_short ipm_void;
- n_short ipm_nextmtu;
- } ih_pmtu;
-
- struct ih_rtradv {
- u_char irt_num_addrs;
- u_char irt_wpa;
- u_int16_t irt_lifetime;
- } ih_rtradv;
- } icmp_hun;
-#define icmp_pptr icmp_hun.ih_pptr
-#define icmp_gwaddr icmp_hun.ih_gwaddr
-#define icmp_id icmp_hun.ih_idseq.icd_id
-#define icmp_seq icmp_hun.ih_idseq.icd_seq
-#define icmp_void icmp_hun.ih_void
-#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void
-#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu
-#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs
-#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa
-#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime
- union {
- struct id_ts {
- n_time its_otime;
- n_time its_rtime;
- n_time its_ttime;
- } id_ts;
- struct id_ip {
- struct ip idi_ip;
- /* options and then 64 bits of data */
- } id_ip;
- struct icmp_ra_addr id_radv;
- u_int32_t id_mask;
- char id_data[1];
- } icmp_dun;
-#define icmp_otime icmp_dun.id_ts.its_otime
-#define icmp_rtime icmp_dun.id_ts.its_rtime
-#define icmp_ttime icmp_dun.id_ts.its_ttime
-#define icmp_ip icmp_dun.id_ip.idi_ip
-#define icmp_radv icmp_dun.id_radv
-#define icmp_mask icmp_dun.id_mask
-#define icmp_data icmp_dun.id_data
-};
-
-/*
- * Lower bounds on packet lengths for various types.
- * For the error advice packets must first insure that the
- * packet is large enough to contain the returned ip header.
- * Only then can we do the check to see if 64 bits of packet
- * data have been returned, since we need to check the returned
- * ip header length.
- */
-#define ICMP_MINLEN 8 /* abs minimum */
-#define ICMP_TSLEN (8 + 3 * sizeof (n_time)) /* timestamp */
-#define ICMP_MASKLEN 12 /* address mask */
-#define ICMP_ADVLENMIN (8 + sizeof (struct ip) + 8) /* min */
-#ifndef _IP_VHL
-#define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8)
- /* N.B.: must separately check that ip_hl >= 5 */
-#else
-#define ICMP_ADVLEN(p) (8 + (IP_VHL_HL((p)->icmp_ip.ip_vhl) << 2) + 8)
- /* N.B.: must separately check that header length >= 5 */
-#endif
-
-/*
- * Definition of type and code field values.
- */
-#define ICMP_ECHOREPLY 0 /* echo reply */
-#define ICMP_UNREACH 3 /* dest unreachable, codes: */
-#define ICMP_UNREACH_NET 0 /* bad net */
-#define ICMP_UNREACH_HOST 1 /* bad host */
-#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */
-#define ICMP_UNREACH_PORT 3 /* bad port */
-#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */
-#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */
-#define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */
-#define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */
-#define ICMP_UNREACH_ISOLATED 8 /* src host isolated */
-#define ICMP_UNREACH_NET_PROHIB 9 /* prohibited access */
-#define ICMP_UNREACH_HOST_PROHIB 10 /* ditto */
-#define ICMP_UNREACH_TOSNET 11 /* bad tos for net */
-#define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */
-#define ICMP_UNREACH_FILTER_PROHIB 13 /* admin prohib */
-#define ICMP_UNREACH_HOST_PRECEDENCE 14 /* host prec vio. */
-#define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 /* prec cutoff */
-#define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */
-#define ICMP_REDIRECT 5 /* shorter route, codes: */
-#define ICMP_REDIRECT_NET 0 /* for network */
-#define ICMP_REDIRECT_HOST 1 /* for host */
-#define ICMP_REDIRECT_TOSNET 2 /* for tos and net */
-#define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */
-#define ICMP_ECHO 8 /* echo service */
-#define ICMP_ROUTERADVERT 9 /* router advertisement */
-#define ICMP_ROUTERSOLICIT 10 /* router solicitation */
-#define ICMP_TIMXCEED 11 /* time exceeded, code: */
-#define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */
-#define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */
-#define ICMP_PARAMPROB 12 /* ip header bad */
-#define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */
-#define ICMP_TSTAMP 13 /* timestamp request */
-#define ICMP_TSTAMPREPLY 14 /* timestamp reply */
-#define ICMP_IREQ 15 /* information request */
-#define ICMP_IREQREPLY 16 /* information reply */
-#define ICMP_MASKREQ 17 /* address mask request */
-#define ICMP_MASKREPLY 18 /* address mask reply */
-
-#define ICMP_MAXTYPE 18
-
-#define ICMP_INFOTYPE(type) \
- ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \
- (type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \
- (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \
- (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \
- (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY)
-
-#ifdef KERNEL
-void icmp_error __P((struct mbuf *, int, int, n_long, struct ifnet *));
-void icmp_input __P((struct mbuf *, int));
-#endif
-
-#endif
diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c
index 2286c732383..6cdf7948901 100644
--- a/dlls/iphlpapi/iphlpapi_main.c
+++ b/dlls/iphlpapi/iphlpapi_main.c
@@ -37,6 +37,7 @@
#include "tcpestats.h"
#include "ip2string.h"
#include "netiodef.h"
+#include "icmpapi.h"
#include "wine/nsi.h"
#include "wine/debug.h"
@@ -4543,6 +4544,48 @@ DWORD WINAPI ParseNetworkString(const WCHAR *str, DWORD type,
return ERROR_INVALID_PARAMETER;
}
+struct icmp_handle_data
+{
+ HANDLE nsi_device;
+};
+
+/***********************************************************************
+ * IcmpCloseHandle (IPHLPAPI.@)
+ */
+BOOL WINAPI IcmpCloseHandle( HANDLE handle )
+{
+ struct icmp_handle_data *data = (struct icmp_handle_data *)handle;
+
+ CloseHandle( data->nsi_device );
+ heap_free( data );
+ return TRUE;
+}
+
+/***********************************************************************
+ * IcmpCreateFile (IPHLPAPI.@)
+ */
+HANDLE WINAPI IcmpCreateFile( void )
+{
+ struct icmp_handle_data *data = heap_alloc( sizeof(*data) );
+ static const WCHAR device_name[] = {'\\','\\','.','\\','N','s','i',0};
+
+ if (!data)
+ {
+ SetLastError( IP_NO_RESOURCES );
+ return INVALID_HANDLE_VALUE;
+ }
+
+ data->nsi_device = CreateFileW( device_name, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED, NULL );
+ if (data->nsi_device == INVALID_HANDLE_VALUE)
+ {
+ heap_free( data );
+ return INVALID_HANDLE_VALUE;
+ }
+
+ return (HANDLE)data;
+}
+
/******************************************************************
* IcmpParseReplies (IPHLPAPI.@)
*/
@@ -4556,6 +4599,135 @@ DWORD WINAPI IcmpParseReplies( void *reply, DWORD reply_size )
return num_pkts;
}
+/*************************************************************************
+ * icmpv4_echo_reply_fixup
+ *
+ * Convert struct nsiproxy_icmpv4_echo_reply into ICMP_ECHO_REPLY.
+ *
+ * This is necessary due to the different sizes of ICMP_ECHO_REPLY on
+ * 32 and 64-bits. Despite mention of ICMP_ECHO_REPLY32, 64-bit Windows
+ * actually does return a full 64-bit version.
+ */
+static void icmpv4_echo_reply_fixup( ICMP_ECHO_REPLY *dst, struct nsiproxy_icmp_echo_reply *reply )
+{
+ dst->Address = reply->addr.Ipv4.sin_addr.s_addr;
+ dst->Status = reply->status;
+ dst->RoundTripTime = reply->round_trip_time;
+ dst->DataSize = reply->data_size;
+ dst->Reserved = reply->num_of_pkts;
+ dst->Data = (BYTE *)(dst + 1) + ((reply->opts.options_size + 3) & ~3);
+ dst->Options.Ttl = reply->opts.ttl;
+ dst->Options.Tos = reply->opts.tos;
+ dst->Options.Flags = reply->opts.flags;
+ dst->Options.OptionsSize = reply->opts.options_size;
+ dst->Options.OptionsData = (BYTE *)(reply + 1);
+
+ memcpy( dst->Options.OptionsData, (BYTE *)reply + reply->opts.options_offset, reply->opts.options_size );
+ memcpy( dst->Data, (BYTE *)reply + reply->data_offset, reply->data_size );
+}
+
+/***********************************************************************
+ * IcmpSendEcho (IPHLPAPI.@)
+ */
+DWORD WINAPI IcmpSendEcho( HANDLE handle, IPAddr dst, void *request, WORD request_size,
+ IP_OPTION_INFORMATION *opts, void *reply, DWORD reply_size,
+ DWORD timeout )
+{
+ return IcmpSendEcho2Ex( handle, NULL, NULL, NULL, INADDR_ANY, dst, request, request_size,
+ opts, reply, reply_size, timeout );
+}
+
+/***********************************************************************
+ * IcmpSendEcho2 (IPHLPAPI.@)
+ */
+DWORD WINAPI IcmpSendEcho2( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc_routine, void *apc_ctxt,
+ IPAddr dst, void *request, WORD request_size, IP_OPTION_INFORMATION *opts,
+ void *reply, DWORD reply_size, DWORD timeout )
+{
+ return IcmpSendEcho2Ex( handle, event, apc_routine, apc_ctxt, INADDR_ANY, dst, request, request_size,
+ opts, reply, reply_size, timeout );
+}
+
+/***********************************************************************
+ * IcmpSendEcho2Ex (IPHLPAPI.@)
+ */
+DWORD WINAPI IcmpSendEcho2Ex( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc_routine, void *apc_ctxt,
+ IPAddr src, IPAddr dst, void *request, WORD request_size, IP_OPTION_INFORMATION *opts,
+ void *reply, DWORD reply_size, DWORD timeout )
+{
+ struct icmp_handle_data *data = (struct icmp_handle_data *)handle;
+ DWORD opt_size, in_size, ret = 0, out_size;
+ struct nsiproxy_icmp_echo *in;
+ struct nsiproxy_icmp_echo_reply *out;
+ HANDLE request_event;
+ IO_STATUS_BLOCK iosb;
+ NTSTATUS status;
+
+ if (event || apc_routine)
+ {
+ FIXME( "Async requests not yet supported\n" );
+ return 0;
+ }
+
+ if (handle == INVALID_HANDLE_VALUE || !reply)
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return 0;
+ }
+
+ opt_size = opts ? (opts->OptionsSize + 3) & ~3 : 0;
+ in_size = FIELD_OFFSET(struct nsiproxy_icmp_echo, data[opt_size + request_size]);
+ in = heap_alloc_zero( in_size );
+ out_size = reply_size - sizeof(ICMP_ECHO_REPLY) + sizeof(*out);
+ out = heap_alloc( out_size );
+
+ if (!in || !out)
+ {
+ heap_free( out );
+ heap_free( in );
+ SetLastError( IP_NO_RESOURCES );
+ return 0;
+ }
+
+ in->src.Ipv4.sin_family = AF_INET;
+ in->src.Ipv4.sin_addr.s_addr = src;
+ in->dst.Ipv4.sin_family = AF_INET;
+ in->dst.Ipv4.sin_addr.s_addr = dst;
+ if (opts)
+ {
+ in->ttl = opts->Ttl;
+ in->tos = opts->Tos;
+ in->flags = opts->Flags;
+ memcpy( in->data, opts->OptionsData, opts->OptionsSize );
+ in->opt_size = opts->OptionsSize;
+ }
+ in->req_size = request_size;
+ in->timeout = timeout;
+ memcpy( in->data + opt_size, request, request_size );
+
+ request_event = CreateEventW( NULL, 0, 0, NULL );
+
+ status = NtDeviceIoControlFile( data->nsi_device, request_event, NULL, NULL,
+ &iosb, IOCTL_NSIPROXY_WINE_ICMP_ECHO, in, in_size,
+ out, out_size );
+
+ if (status == STATUS_PENDING && !WaitForSingleObject( request_event, INFINITE ))
+ status = iosb.u.Status;
+
+ if (!status)
+ {
+ icmpv4_echo_reply_fixup( reply, out );
+ ret = IcmpParseReplies( reply, reply_size );
+ }
+
+ CloseHandle( request_event );
+ heap_free( out );
+ heap_free( in );
+
+ if (status) SetLastError( RtlNtStatusToDosError( status ) );
+ return ret;
+}
+
/***********************************************************************
* Icmp6CreateFile (IPHLPAPI.@)
*/
diff --git a/dlls/iphlpapi/tests/iphlpapi.c b/dlls/iphlpapi/tests/iphlpapi.c
index 080feb364f9..e20ada88f16 100644
--- a/dlls/iphlpapi/tests/iphlpapi.c
+++ b/dlls/iphlpapi/tests/iphlpapi.c
@@ -894,15 +894,6 @@ static void testIcmpSendEcho(void)
"expected 87, got %d\n", error);
icmp = IcmpCreateFile();
- if (icmp == INVALID_HANDLE_VALUE)
- {
- error = GetLastError();
- if (error == ERROR_ACCESS_DENIED)
- {
- skip ("ICMP is not available.\n");
- return;
- }
- }
ok (icmp != INVALID_HANDLE_VALUE, "IcmpCreateFile failed unexpectedly with error %d\n", GetLastError());
address = 0;
@@ -924,6 +915,11 @@ static void testIcmpSendEcho(void)
SetLastError(0xdeadbeef);
ret = IcmpSendEcho(icmp, address, senddata, 0, NULL, replydata, replysz, 1000);
error = GetLastError();
+ if (!ret && error == ERROR_ACCESS_DENIED)
+ {
+ skip( "ICMP is not available.\n" );
+ return;
+ }
ok (ret, "IcmpSendEcho failed unexpectedly with error %d\n", error);
SetLastError(0xdeadbeef);
--
2.25.1
2
3
[PATCH 1/3] iphlpapi: Implement asynchronous events for IcmpSendEcho2Ex.
by Gabriel Ivăncescu 08 Oct '21
by Gabriel Ivăncescu 08 Oct '21
08 Oct '21
Signed-off-by: Gabriel Ivăncescu <gabrielopcode(a)gmail.com>
---
dlls/iphlpapi/iphlpapi_main.c | 91 ++++++++++++++-
dlls/iphlpapi/tests/iphlpapi.c | 203 +++++++++++++++++++++++++++++++++
2 files changed, 288 insertions(+), 6 deletions(-)
diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c
index d9a85be..c0ea214 100644
--- a/dlls/iphlpapi/iphlpapi_main.c
+++ b/dlls/iphlpapi/iphlpapi_main.c
@@ -4530,6 +4530,16 @@ struct icmp_handle_data
HANDLE nsi_device;
};
+struct icmp_echo_async_ctx
+{
+ HANDLE event;
+ HANDLE request_event;
+ struct nsiproxy_icmp_echo *in;
+ struct nsiproxy_icmp_echo_reply *out;
+ ICMP_ECHO_REPLY *reply;
+ IO_STATUS_BLOCK iosb;
+};
+
/***********************************************************************
* IcmpCloseHandle (IPHLPAPI.@)
*/
@@ -4606,6 +4616,36 @@ static void icmpv4_echo_reply_fixup( ICMP_ECHO_REPLY *dst, struct nsiproxy_icmp_
memcpy( dst->Data, (BYTE *)reply + reply->data_offset, reply->data_size );
}
+/*************************************************************************
+ * icmpv4_echo_async
+ *
+ * Wait for the reply, convert it into ICMP_ECHO_REPLY, and signal the event.
+ */
+static DWORD WINAPI icmpv4_echo_async( VOID *parameter )
+{
+ struct icmp_echo_async_ctx *ctx = parameter;
+
+ WaitForSingleObject( ctx->request_event, INFINITE );
+ CloseHandle( ctx->request_event );
+
+ if (!ctx->iosb.Status)
+ {
+ icmpv4_echo_reply_fixup( ctx->reply, ctx->out );
+ }
+ else
+ {
+ memset( ctx->reply, 0, sizeof(ICMP_ECHO_REPLY) );
+ ctx->reply->Status = IP_GENERAL_FAILURE;
+ }
+
+ SetEvent( ctx->event );
+
+ heap_free( ctx->out );
+ heap_free( ctx->in );
+ heap_free( ctx );
+ return 0;
+}
+
/***********************************************************************
* IcmpSendEcho (IPHLPAPI.@)
*/
@@ -4636,25 +4676,43 @@ DWORD WINAPI IcmpSendEcho2Ex( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc_r
void *reply, DWORD reply_size, DWORD timeout )
{
struct icmp_handle_data *data = (struct icmp_handle_data *)handle;
+ IO_STATUS_BLOCK iosb_stack, *iosb = &iosb_stack;
+ struct icmp_echo_async_ctx *async_ctx = NULL;
DWORD opt_size, in_size, ret = 0, out_size;
struct nsiproxy_icmp_echo *in;
struct nsiproxy_icmp_echo_reply *out;
HANDLE request_event;
- IO_STATUS_BLOCK iosb;
NTSTATUS status;
- if (event || apc_routine)
+ if (apc_routine)
{
FIXME( "Async requests not yet supported\n" );
return 0;
}
- if (handle == INVALID_HANDLE_VALUE || !reply)
+ if (handle == INVALID_HANDLE_VALUE || !reply || !reply_size)
{
SetLastError( ERROR_INVALID_PARAMETER );
return 0;
}
+ if (reply_size < sizeof(ICMP_ECHO_REPLY))
+ {
+ SetLastError( IP_BUF_TOO_SMALL );
+ return 0;
+ }
+
+ if (event)
+ {
+ async_ctx = heap_alloc( sizeof(*async_ctx) );
+ if (!async_ctx)
+ {
+ SetLastError( IP_NO_RESOURCES );
+ return 0;
+ }
+ iosb = &async_ctx->iosb;
+ }
+
opt_size = opts ? (opts->OptionsSize + 3) & ~3 : 0;
in_size = FIELD_OFFSET(struct nsiproxy_icmp_echo, data[opt_size + request_size]);
in = heap_alloc_zero( in_size );
@@ -4663,6 +4721,7 @@ DWORD WINAPI IcmpSendEcho2Ex( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc_r
if (!in || !out)
{
+ heap_free( async_ctx );
heap_free( out );
heap_free( in );
SetLastError( IP_NO_RESOURCES );
@@ -4688,19 +4747,39 @@ DWORD WINAPI IcmpSendEcho2Ex( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc_r
request_event = CreateEventW( NULL, 0, 0, NULL );
status = NtDeviceIoControlFile( data->nsi_device, request_event, NULL, NULL,
- &iosb, IOCTL_NSIPROXY_WINE_ICMP_ECHO, in, in_size,
+ iosb, IOCTL_NSIPROXY_WINE_ICMP_ECHO, in, in_size,
out, out_size );
- if (status == STATUS_PENDING && !WaitForSingleObject( request_event, INFINITE ))
- status = iosb.Status;
+ if (status == STATUS_PENDING)
+ {
+ if (async_ctx)
+ {
+ async_ctx->event = event;
+ async_ctx->request_event = request_event;
+ async_ctx->in = in;
+ async_ctx->out = out;
+ async_ctx->reply = reply;
+ status = RtlQueueWorkItem( icmpv4_echo_async, async_ctx, WT_EXECUTEDEFAULT | WT_EXECUTELONGFUNCTION );
+ if (!status)
+ {
+ SetLastError( ERROR_IO_PENDING );
+ return 0;
+ }
+ /* fall back to sync, we can't have the buffers released now */
+ }
+ if (!WaitForSingleObject( request_event, INFINITE ))
+ status = iosb->Status;
+ }
if (!status)
{
icmpv4_echo_reply_fixup( reply, out );
ret = IcmpParseReplies( reply, reply_size );
+ if (event) SetEvent( event );
}
CloseHandle( request_event );
+ heap_free( async_ctx );
heap_free( out );
heap_free( in );
diff --git a/dlls/iphlpapi/tests/iphlpapi.c b/dlls/iphlpapi/tests/iphlpapi.c
index e20ada8..93a5843 100644
--- a/dlls/iphlpapi/tests/iphlpapi.c
+++ b/dlls/iphlpapi/tests/iphlpapi.c
@@ -38,6 +38,7 @@
#include "winsock2.h"
#include "windef.h"
#include "winbase.h"
+#include "winternl.h"
#include "ws2tcpip.h"
#include "windns.h"
#include "iphlpapi.h"
@@ -877,9 +878,11 @@ static void testIcmpSendEcho(void)
{
HANDLE icmp;
char senddata[32], replydata[sizeof(senddata) + sizeof(ICMP_ECHO_REPLY)];
+ char replydata2[sizeof(replydata) + sizeof(IO_STATUS_BLOCK)];
DWORD ret, error, replysz = sizeof(replydata);
IPAddr address;
ICMP_ECHO_REPLY *reply;
+ HANDLE event;
INT i;
memset(senddata, 0, sizeof(senddata));
@@ -893,6 +896,15 @@ static void testIcmpSendEcho(void)
|| broken(error == ERROR_INVALID_HANDLE) /* <= 2003 */,
"expected 87, got %d\n", error);
+ address = htonl(INADDR_LOOPBACK);
+ SetLastError(0xdeadbeef);
+ ret = IcmpSendEcho2(INVALID_HANDLE_VALUE, NULL, NULL, NULL, address, senddata, sizeof(senddata), NULL, replydata, replysz, 1000);
+ error = GetLastError();
+ ok (!ret, "IcmpSendEcho2 succeeded unexpectedly\n");
+ ok (error == ERROR_INVALID_PARAMETER
+ || broken(error == ERROR_INVALID_HANDLE) /* <= 2003 */,
+ "expected 87, got %d\n", error);
+
icmp = IcmpCreateFile();
ok (icmp != INVALID_HANDLE_VALUE, "IcmpCreateFile failed unexpectedly with error %d\n", GetLastError());
@@ -1036,6 +1048,197 @@ static void testIcmpSendEcho(void)
ok(reply->DataSize == sizeof(senddata), "Got size:%d\n", reply->DataSize);
ok(!memcmp(senddata, reply->Data, min(sizeof(senddata), reply->DataSize)), "Data mismatch\n");
+
+ /*
+ * IcmpSendEcho2
+ */
+ address = 0;
+ replysz = sizeof(replydata2);
+ memset(senddata, 0, sizeof(senddata));
+
+ SetLastError(0xdeadbeef);
+ ret = IcmpSendEcho2(icmp, NULL, NULL, NULL, address, senddata, sizeof(senddata), NULL, replydata2, replysz, 1000);
+ error = GetLastError();
+ ok(!ret, "IcmpSendEcho2 succeeded unexpectedly\n");
+ ok(error == ERROR_INVALID_NETNAME
+ || broken(error == IP_BAD_DESTINATION) /* <= 2003 */,
+ "expected 1214, got %d\n", error);
+
+ event = CreateEventW(NULL, FALSE, FALSE, NULL);
+ ok(event != NULL, "CreateEventW failed unexpectedly with error %d\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ ret = IcmpSendEcho2(icmp, event, NULL, NULL, address, senddata, sizeof(senddata), NULL, replydata2, replysz, 1000);
+ error = GetLastError();
+ ok(!ret, "IcmpSendEcho2 returned success unexpectedly\n");
+ ok(error == ERROR_INVALID_NETNAME
+ || broken(error == ERROR_IO_PENDING) /* <= 2003 */,
+ "Got last error: 0x%08x\n", error);
+ if (error == ERROR_IO_PENDING)
+ {
+ ret = WaitForSingleObjectEx(event, 2000, TRUE);
+ ok(ret == WAIT_OBJECT_0, "WaitForSingleObjectEx failed unexpectedly with %u\n", ret);
+ }
+
+ address = htonl(INADDR_LOOPBACK);
+ SetLastError(0xdeadbeef);
+ ret = IcmpSendEcho2(icmp, NULL, NULL, NULL, address, senddata, sizeof(senddata), NULL, NULL, replysz, 1000);
+ error = GetLastError();
+ ok(!ret, "IcmpSendEcho2 succeeded unexpectedly\n");
+ ok(error == ERROR_INVALID_PARAMETER
+ || broken(error == ERROR_NOACCESS) /* <= 2003 */,
+ "expected 87, got %d\n", error);
+
+ SetLastError(0xdeadbeef);
+ ret = IcmpSendEcho2(icmp, event, NULL, NULL, address, senddata, sizeof(senddata), NULL, NULL, replysz, 1000);
+ error = GetLastError();
+ ok(!ret, "IcmpSendEcho2 succeeded unexpectedly\n");
+ ok(error == ERROR_INVALID_PARAMETER
+ || broken(error == ERROR_NOACCESS) /* <= 2003 */,
+ "expected 87, got %d\n", error);
+ ok(WaitForSingleObjectEx(event, 0, TRUE) == WAIT_TIMEOUT, "Event was unexpectedly signalled.\n");
+
+ SetLastError(0xdeadbeef);
+ ret = IcmpSendEcho2(icmp, NULL, NULL, NULL, address, senddata, sizeof(senddata), NULL, replydata2, 0, 1000);
+ error = GetLastError();
+ ok(!ret, "IcmpSendEcho2 succeeded unexpectedly\n");
+ ok(error == ERROR_INVALID_PARAMETER
+ || broken(error == ERROR_INSUFFICIENT_BUFFER) /* <= 2003 */,
+ "expected 87, got %d\n", error);
+
+ SetLastError(0xdeadbeef);
+ ret = IcmpSendEcho2(icmp, event, NULL, NULL, address, senddata, sizeof(senddata), NULL, replydata2, 0, 1000);
+ error = GetLastError();
+ ok(!ret, "IcmpSendEcho2 succeeded unexpectedly\n");
+ ok(error == ERROR_INVALID_PARAMETER
+ || broken(error == ERROR_INSUFFICIENT_BUFFER) /* <= 2003 */,
+ "expected 87, got %d\n", error);
+ ok(WaitForSingleObjectEx(event, 0, TRUE) == WAIT_TIMEOUT, "Event was unexpectedly signalled.\n");
+
+ SetLastError(0xdeadbeef);
+ ret = IcmpSendEcho2(icmp, NULL, NULL, NULL, address, senddata, sizeof(senddata), NULL, NULL, 0, 1000);
+ error = GetLastError();
+ ok(!ret, "IcmpSendEcho2 succeeded unexpectedly\n");
+ ok(error == ERROR_INVALID_PARAMETER
+ || broken(error == ERROR_INSUFFICIENT_BUFFER) /* <= 2003 */,
+ "expected 87, got %d\n", error);
+
+ SetLastError(0xdeadbeef);
+ ret = IcmpSendEcho2(icmp, event, NULL, NULL, address, senddata, sizeof(senddata), NULL, NULL, 0, 1000);
+ error = GetLastError();
+ ok(!ret, "IcmpSendEcho2 succeeded unexpectedly\n");
+ ok(error == ERROR_INVALID_PARAMETER
+ || broken(error == ERROR_INSUFFICIENT_BUFFER) /* <= 2003 */,
+ "expected 87, got %d\n", error);
+ ok(WaitForSingleObjectEx(event, 0, TRUE) == WAIT_TIMEOUT, "Event was unexpectedly signalled.\n");
+
+ /* synchronous tests */
+ SetLastError(0xdeadbeef);
+ address = htonl(INADDR_LOOPBACK);
+ replysz = sizeof(ICMP_ECHO_REPLY) + sizeof(IO_STATUS_BLOCK);
+ ret = IcmpSendEcho2(icmp, NULL, NULL, NULL, address, senddata, 0, NULL, replydata2, replysz, 1000);
+ ok(ret, "IcmpSendEcho2 failed unexpectedly with error %d\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ ret = IcmpSendEcho2(icmp, NULL, NULL, NULL, address, NULL, 0, NULL, replydata2, replysz, 1000);
+ ok(ret, "IcmpSendEcho2 failed unexpectedly with error %d\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ ret = IcmpSendEcho2(icmp, NULL, NULL, NULL, address, senddata, 0, NULL, replydata2, replysz, 1000);
+ ok(ret, "IcmpSendEcho2 failed unexpectedly with error %d\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ replysz = sizeof(ICMP_ECHO_REPLY) + sizeof(IO_STATUS_BLOCK) + ICMP_MINLEN;
+ ret = IcmpSendEcho2(icmp, NULL, NULL, NULL, address, senddata, ICMP_MINLEN, NULL, replydata2, replysz, 1000);
+ ok(ret, "IcmpSendEcho2 failed unexpectedly with error %d\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ replysz = sizeof(replydata2);
+ ret = IcmpSendEcho2(icmp, NULL, NULL, NULL, address, senddata, sizeof(senddata), NULL, replydata2, replysz, 1000);
+ if (!ret)
+ {
+ error = GetLastError();
+ skip("Failed to ping with error %d, is lo interface down?\n", error);
+ }
+ else if (winetest_debug > 1)
+ {
+ reply = (ICMP_ECHO_REPLY*)replydata2;
+ trace("send addr : %s\n", ntoa(address));
+ trace("reply addr : %s\n", ntoa(reply->Address));
+ trace("reply size : %u\n", replysz);
+ trace("roundtrip : %u ms\n", reply->RoundTripTime);
+ trace("status : %u\n", reply->Status);
+ trace("recv size : %u\n", reply->DataSize);
+ trace("ttl : %u\n", reply->Options.Ttl);
+ trace("flags : 0x%x\n", reply->Options.Flags);
+ }
+
+ SetLastError(0xdeadbeef);
+ for (i = 0; i < ARRAY_SIZE(senddata); i++) senddata[i] = i & 0xff;
+ ret = IcmpSendEcho2(icmp, NULL, NULL, NULL, address, senddata, sizeof(senddata), NULL, replydata2, replysz, 1000);
+ error = GetLastError();
+ reply = (ICMP_ECHO_REPLY*)replydata2;
+ ok(ret, "IcmpSendEcho2 failed unexpectedly\n");
+ ok(error == NO_ERROR, "Expect last error: 0x%08x, got: 0x%08x\n", NO_ERROR, error);
+ ok(ntohl(reply->Address) == INADDR_LOOPBACK, "Address mismatch, expect: %s, got: %s\n", ntoa(INADDR_LOOPBACK),
+ ntoa(reply->Address));
+ ok(reply->Status == IP_SUCCESS, "Expect status: 0x%08x, got: 0x%08x\n", IP_SUCCESS, reply->Status);
+ ok(reply->DataSize == sizeof(senddata), "Got size: %d\n", reply->DataSize);
+ ok(!memcmp(senddata, reply->Data, min(sizeof(senddata), reply->DataSize)), "Data mismatch\n");
+
+ /* asynchronous tests with event */
+ SetLastError(0xdeadbeef);
+ replysz = sizeof(replydata2);
+ address = htonl(INADDR_LOOPBACK);
+ memset(senddata, 0, sizeof(senddata));
+ ret = IcmpSendEcho2(icmp, event, NULL, NULL, address, senddata, sizeof(senddata), NULL, replydata2, replysz, 1000);
+ error = GetLastError();
+ if (!ret && error != ERROR_IO_PENDING)
+ {
+ skip("Failed to ping with error %d, is lo interface down?\n", error);
+ }
+ else
+ {
+ ok(!ret, "IcmpSendEcho2 returned success unexpectedly\n");
+ ok(error == ERROR_IO_PENDING, "Expect last error: 0x%08x, got: 0x%08x\n", ERROR_IO_PENDING, error);
+ ret = WaitForSingleObjectEx(event, 2000, TRUE);
+ ok(ret == WAIT_OBJECT_0, "WaitForSingleObjectEx failed unexpectedly with %u\n", ret);
+ reply = (ICMP_ECHO_REPLY*)replydata2;
+ ok(ntohl(reply->Address) == INADDR_LOOPBACK, "Address mismatch, expect: %s, got: %s\n", ntoa(INADDR_LOOPBACK),
+ ntoa(reply->Address));
+ ok(reply->Status == IP_SUCCESS, "Expect status: 0x%08x, got: 0x%08x\n", IP_SUCCESS, reply->Status);
+ ok(reply->DataSize == sizeof(senddata), "Got size: %d\n", reply->DataSize);
+ if (winetest_debug > 1)
+ {
+ reply = (ICMP_ECHO_REPLY*)replydata2;
+ trace("send addr : %s\n", ntoa(address));
+ trace("reply addr : %s\n", ntoa(reply->Address));
+ trace("reply size : %u\n", replysz);
+ trace("roundtrip : %u ms\n", reply->RoundTripTime);
+ trace("status : %u\n", reply->Status);
+ trace("recv size : %u\n", reply->DataSize);
+ trace("ttl : %u\n", reply->Options.Ttl);
+ trace("flags : 0x%x\n", reply->Options.Flags);
+ }
+ }
+
+ SetLastError(0xdeadbeef);
+ for (i = 0; i < ARRAY_SIZE(senddata); i++) senddata[i] = i & 0xff;
+ ret = IcmpSendEcho2(icmp, event, NULL, NULL, address, senddata, sizeof(senddata), NULL, replydata2, replysz, 1000);
+ error = GetLastError();
+ ok(!ret, "IcmpSendEcho2 returned success unexpectedly\n");
+ ok(error == ERROR_IO_PENDING, "Expect last error: 0x%08x, got: 0x%08x\n", ERROR_IO_PENDING, error);
+ ret = WaitForSingleObjectEx(event, 2000, TRUE);
+ ok(ret == WAIT_OBJECT_0, "WaitForSingleObjectEx failed unexpectedly with %u\n", ret);
+ reply = (ICMP_ECHO_REPLY*)replydata2;
+ ok(ntohl(reply->Address) == INADDR_LOOPBACK, "Address mismatch, expect: %s, got: %s\n", ntoa(INADDR_LOOPBACK),
+ ntoa(reply->Address));
+ ok(reply->Status == IP_SUCCESS, "Expect status: 0x%08x, got: 0x%08x\n", IP_SUCCESS, reply->Status);
+ ok(reply->DataSize == sizeof(senddata), "Got size: %d\n", reply->DataSize);
+ /* pre-Vista, reply->Data is an offset; otherwise it's a pointer, so hardcode the offset */
+ ok(!memcmp(senddata, reply + 1, min(sizeof(senddata), reply->DataSize)), "Data mismatch\n");
+
+ CloseHandle(event);
IcmpCloseHandle(icmp);
}
--
2.31.1
1
2
clang -c -o dlls/vcruntime140_1/except_x86_64.cross.o ../wine.src/dlls/vcruntime140_1/except_x86_64.c -Idlls/vcruntime140_1 \
-I../wine.src/dlls/vcruntime140_1 -Iinclude -I../wine.src/include -I../wine.src/include/msvcrt \
-D__WINESRC__ -D_UCRT -DWINE_CROSS_PE -Wall -target x86_64-windows -fno-strict-aliasing \
-Wdeclaration-after-statement -Wempty-body -Wignored-qualifiers -Winit-self -Wno-pragma-pack \
-Wstrict-prototypes -Wtype-limits -Wvla -Wwrite-strings -Wpointer-arith -Wabsolute-value \
-Wno-format -Wnonnull -mcx16 -gdwarf-2 -gstrict-dwarf -g -O2
In file included from ../wine.src/dlls/vcruntime140_1/except_x86_64.c:25:
In file included from ../wine.src/include/wine/exception.h:25:
../wine.src/include/winternl.h:4239:82: error: unknown type name 'va_list'
NTSYSAPI NTSTATUS WINAPI RtlFormatMessage(LPCWSTR,ULONG,BOOLEAN,BOOLEAN,BOOLEAN,__ms_va_list *,LPWSTR,ULONG,ULONG*);
Signed-off-by: Dmitry Timoshkov <dmitry(a)baikal.ru>
---
dlls/vcruntime140_1/except_x86_64.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/dlls/vcruntime140_1/except_x86_64.c b/dlls/vcruntime140_1/except_x86_64.c
index 039da37d598..f50847d886d 100644
--- a/dlls/vcruntime140_1/except_x86_64.c
+++ b/dlls/vcruntime140_1/except_x86_64.c
@@ -20,6 +20,7 @@
#ifdef __x86_64__
+#include <stdarg.h>
#include <stdlib.h>
#include "wine/exception.h"
--
2.31.1
2
1
[PATCH 1/5] xinput1_3: Wait for CancelIoEx completion when disabling controllers.
by Rémi Bernon 08 Oct '21
by Rémi Bernon 08 Oct '21
08 Oct '21
Otherwise we may later write the cancelled status to invalid memory.
Also use a manual-reset event, as it should be for overlapped I/O, so
all waiters are waken up on cancel.
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
Supersedes: 216572-216573
dlls/xinput1_3/main.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/dlls/xinput1_3/main.c b/dlls/xinput1_3/main.c
index 81d11e5d38f..1f9d4881751 100644
--- a/dlls/xinput1_3/main.c
+++ b/dlls/xinput1_3/main.c
@@ -354,6 +354,7 @@ static void controller_disable(struct xinput_controller *controller)
controller->enabled = FALSE;
CancelIoEx(controller->device, &controller->hid.read_ovl);
+ WaitForSingleObject(controller->hid.read_ovl.hEvent, INFINITE);
SetEvent(update_event);
}
@@ -365,7 +366,7 @@ static BOOL controller_init(struct xinput_controller *controller, PHIDP_PREPARSE
controller->hid.caps = *caps;
if (!(controller->hid.feature_report_buf = calloc(1, controller->hid.caps.FeatureReportByteLength))) goto failed;
if (!controller_check_caps(controller, device, preparsed)) goto failed;
- if (!(event = CreateEventA(NULL, FALSE, FALSE, NULL))) goto failed;
+ if (!(event = CreateEventW(NULL, TRUE, FALSE, NULL))) goto failed;
TRACE("Found gamepad %s\n", debugstr_w(device_path));
--
2.33.0
1
4
[PATCH] winebus.sys: Fix incorrect length when parsing uevent "HID_NAME=".
by Rémi Bernon 08 Oct '21
by Rémi Bernon 08 Oct '21
08 Oct '21
From: Ivo Ivanov <logos128(a)gmail.com>
Signed-off-by: Ivo Ivanov <logos128(a)gmail.com>
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
dlls/winebus.sys/bus_udev.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c
index cc54d6490be..2ed9a031af6 100644
--- a/dlls/winebus.sys/bus_udev.c
+++ b/dlls/winebus.sys/bus_udev.c
@@ -1108,7 +1108,7 @@ static void get_device_subsystem_info(struct udev_device *dev, char const *subsy
if (sscanf(ptr, "HID_UNIQ=%256s\n", buffer) == 1)
ntdll_umbstowcs(buffer, strlen(buffer) + 1, desc->serialnumber, ARRAY_SIZE(desc->serialnumber));
}
- if (!strncmp(ptr, "HID_NAME=", 7))
+ if (!strncmp(ptr, "HID_NAME=", 9))
{
if (desc->product[0]) continue;
if (sscanf(ptr, "HID_NAME=%256s\n", buffer) == 1)
--
2.33.0
1
0
08 Oct '21
From: Ivo Ivanov <logos128(a)gmail.com>
Signed-off-by: Ivo Ivanov <logos128(a)gmail.com>
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
dlls/winebus.sys/unixlib.c | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/dlls/winebus.sys/unixlib.c b/dlls/winebus.sys/unixlib.c
index ea26094049e..f66fd78d176 100644
--- a/dlls/winebus.sys/unixlib.c
+++ b/dlls/winebus.sys/unixlib.c
@@ -329,7 +329,11 @@ BOOL bus_event_queue_device_removed(struct list *queue, struct unix_device *devi
struct bus_event *event = malloc(size);
if (!event) return FALSE;
- if (unix_device_incref(device) == 1) return FALSE; /* being destroyed */
+ if (unix_device_incref(device) == 1) /* being destroyed */
+ {
+ free(event);
+ return FALSE;
+ }
event->type = BUS_EVENT_TYPE_DEVICE_REMOVED;
event->device = device;
@@ -344,7 +348,11 @@ BOOL bus_event_queue_device_created(struct list *queue, struct unix_device *devi
struct bus_event *event = malloc(size);
if (!event) return FALSE;
- if (unix_device_incref(device) == 1) return FALSE; /* being destroyed */
+ if (unix_device_incref(device) == 1) /* being destroyed */
+ {
+ free(event);
+ return FALSE;
+ }
event->type = BUS_EVENT_TYPE_DEVICE_CREATED;
event->device = device;
@@ -360,7 +368,11 @@ BOOL bus_event_queue_input_report(struct list *queue, struct unix_device *device
struct bus_event *event = malloc(size);
if (!event) return FALSE;
- if (unix_device_incref(device) == 1) return FALSE; /* being destroyed */
+ if (unix_device_incref(device) == 1) /* being destroyed */
+ {
+ free(event);
+ return FALSE;
+ }
event->type = BUS_EVENT_TYPE_INPUT_REPORT;
event->device = device;
--
2.33.0
1
0
08 Oct '21
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
This can happen to bcrypt when builtin without gnutls.
dlls/ntdll/unix/virtual.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index 924aa78b306..6db08de6473 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -642,7 +642,7 @@ static NTSTATUS get_builtin_unix_funcs( void *module, BOOL wow, void **funcs )
{
if (builtin->module != module) continue;
*funcs = dlsym( builtin->unix_handle, ptr_name );
- status = STATUS_SUCCESS;
+ status = *funcs ? STATUS_SUCCESS : STATUS_ENTRYPOINT_NOT_FOUND;
break;
}
server_leave_uninterrupted_section( &virtual_mutex, &sigset );
--
2.23.0
1
0
The design of hidclass.sys prevents any concurrent irps, there's no
need to queue more.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51824
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
dlls/winebus.sys/main.c | 49 +++++++++++++++++++++++++----------------
1 file changed, 30 insertions(+), 19 deletions(-)
diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c
index c9e930632e2..33b2a609077 100644
--- a/dlls/winebus.sys/main.c
+++ b/dlls/winebus.sys/main.c
@@ -19,6 +19,7 @@
*/
#include <stdarg.h>
+#include <assert.h>
#include "ntstatus.h"
#define WIN32_NO_STATUS
@@ -74,7 +75,7 @@ struct device_extension
DWORD last_report_size;
BOOL last_report_read;
DWORD buffer_size;
- LIST_ENTRY irp_queue;
+ IRP *pending_read;
struct unix_device *unix_device;
};
@@ -249,17 +250,28 @@ static WCHAR *get_compatible_ids(DEVICE_OBJECT *device)
return dst;
}
+static IRP *pop_pending_read(struct device_extension *ext)
+{
+ IRP *pending;
+
+ RtlEnterCriticalSection(&ext->cs);
+ pending = ext->pending_read;
+ ext->pending_read = NULL;
+ RtlLeaveCriticalSection(&ext->cs);
+
+ return pending;
+}
+
static void remove_pending_irps(DEVICE_OBJECT *device)
{
struct device_extension *ext = device->DeviceExtension;
- LIST_ENTRY *entry;
+ IRP *pending;
- while ((entry = RemoveHeadList(&ext->irp_queue)) != &ext->irp_queue)
+ if ((pending = pop_pending_read(ext)))
{
- IRP *queued_irp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
- queued_irp->IoStatus.Status = STATUS_DELETE_PENDING;
- queued_irp->IoStatus.Information = 0;
- IoCompleteRequest(queued_irp, IO_NO_INCREMENT);
+ pending->IoStatus.Status = STATUS_DELETE_PENDING;
+ pending->IoStatus.Information = 0;
+ IoCompleteRequest(pending, IO_NO_INCREMENT);
}
}
@@ -295,7 +307,6 @@ static DEVICE_OBJECT *bus_create_hid_device(struct device_desc *desc, struct uni
ext->buffer_size = 0;
ext->unix_device = unix_device;
- InitializeListHead(&ext->irp_queue);
InitializeCriticalSection(&ext->cs);
ext->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs");
@@ -398,9 +409,10 @@ static NTSTATUS deliver_last_report(struct device_extension *ext, DWORD buffer_l
static void process_hid_report(DEVICE_OBJECT *device, BYTE *report, DWORD length)
{
- struct device_extension *ext = (struct device_extension*)device->DeviceExtension;
+ struct device_extension *ext = (struct device_extension *)device->DeviceExtension;
+ IO_STACK_LOCATION *stack;
+ ULONG buffer_len;
IRP *irp;
- LIST_ENTRY *entry;
if (!length || !report)
return;
@@ -427,15 +439,11 @@ static void process_hid_report(DEVICE_OBJECT *device, BYTE *report, DWORD length
ext->last_report_size = length;
ext->last_report_read = FALSE;
- while ((entry = RemoveHeadList(&ext->irp_queue)) != &ext->irp_queue)
+ if ((irp = pop_pending_read(ext)))
{
- IO_STACK_LOCATION *irpsp;
- TRACE_(hid_report)("Processing Request\n");
- irp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
- irpsp = IoGetCurrentIrpStackLocation(irp);
- irp->IoStatus.Status = deliver_last_report(ext,
- irpsp->Parameters.DeviceIoControl.OutputBufferLength,
- irp->UserBuffer, &irp->IoStatus.Information);
+ stack = IoGetCurrentIrpStackLocation(irp);
+ buffer_len = stack->Parameters.DeviceIoControl.OutputBufferLength;
+ irp->IoStatus.Status = deliver_last_report(ext, buffer_len, irp->UserBuffer, &irp->IoStatus.Information);
ext->last_report_read = TRUE;
IoCompleteRequest(irp, IO_NO_INCREMENT);
}
@@ -1015,7 +1023,10 @@ static NTSTATUS WINAPI hid_internal_dispatch(DEVICE_OBJECT *device, IRP *irp)
}
else
{
- InsertTailList(&ext->irp_queue, &irp->Tail.Overlay.ListEntry);
+ /* hidclass.sys should guarantee this */
+ assert(!ext->pending_read);
+ ext->pending_read = irp;
+ IoMarkIrpPending(irp);
irp->IoStatus.Status = STATUS_PENDING;
}
break;
--
2.33.0
1
3
08 Oct '21
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
With this series we should have all non-custom force feedback effect
types supported in the dinput HID joystick through PID reports, as well
as down in the SDL and UDEV lnxev devices.
Any raw device, like UDEV hidraw or IOHID may be supported too, as long
as they use the standard PID reports, although it's quite untested. They
may expect slightly different usage of the reports.
What remains after that is a effect status input report, in order to
implement force feedback status functions, and then dropping the other
backends to convert dinput(8) to PE.
dlls/winebus.sys/bus_sdl.c | 4 ++
dlls/winebus.sys/bus_udev.c | 4 ++
dlls/winebus.sys/hid.c | 107 ++++++++++++++++++++++++++++++++
dlls/winebus.sys/unix_private.h | 13 ++++
4 files changed, 128 insertions(+)
diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c
index 4eab51b5cb2..1bec3661757 100644
--- a/dlls/winebus.sys/bus_sdl.c
+++ b/dlls/winebus.sys/bus_sdl.c
@@ -549,6 +549,10 @@ static NTSTATUS sdl_device_physical_effect_update(struct unix_device *iface, BYT
effect.periodic.direction.type = SDL_HAPTIC_SPHERICAL;
effect.periodic.direction.dir[0] = params->direction[0] * 36000 / 256;
effect.periodic.direction.dir[1] = params->direction[1] * 36000 / 256;
+ effect.periodic.period = params->periodic.period;
+ effect.periodic.magnitude = params->periodic.magnitude * 128;
+ effect.periodic.offset = params->periodic.offset;
+ effect.periodic.phase = params->periodic.phase;
break;
case PID_USAGE_ET_SPRING:
diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c
index f780aac2785..e60891c2244 100644
--- a/dlls/winebus.sys/bus_udev.c
+++ b/dlls/winebus.sys/bus_udev.c
@@ -1001,6 +1001,10 @@ static NTSTATUS lnxev_device_physical_effect_update(struct unix_device *iface, B
case PID_USAGE_ET_SAWTOOTH_UP:
case PID_USAGE_ET_SAWTOOTH_DOWN:
FIXME("periodic effect semi-stub!");
+ effect.u.periodic.period = params->periodic.period;
+ effect.u.periodic.magnitude = params->periodic.magnitude * 128;
+ effect.u.periodic.offset = params->periodic.offset;
+ effect.u.periodic.phase = params->periodic.phase;
break;
case PID_USAGE_ET_SPRING:
diff --git a/dlls/winebus.sys/hid.c b/dlls/winebus.sys/hid.c
index 72d358e6ad7..10e9316eb6c 100644
--- a/dlls/winebus.sys/hid.c
+++ b/dlls/winebus.sys/hid.c
@@ -440,8 +440,85 @@ struct pid_effect_update
BYTE enable_bits;
BYTE direction[2];
};
+
+struct pid_set_periodic
+{
+ BYTE index;
+ BYTE magnitude;
+ BYTE offset;
+ BYTE phase;
+ UINT16 period;
+};
#include "poppack.h"
+static BOOL hid_descriptor_add_set_periodic(struct unix_device *iface)
+{
+ struct hid_report_descriptor *desc = &iface->hid_report_descriptor;
+ const BYTE report_id = ++desc->next_report_id[HidP_Output];
+ const BYTE template[] =
+ {
+ /* Periodic Report Definition */
+ USAGE(1, PID_USAGE_SET_PERIODIC_REPORT),
+ COLLECTION(1, Logical),
+ REPORT_ID(1, report_id),
+
+ USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX),
+ LOGICAL_MAXIMUM(1, 0x7f),
+ LOGICAL_MINIMUM(1, 0x00),
+ REPORT_SIZE(1, 8),
+ REPORT_COUNT(1, 1),
+ OUTPUT(1, Data|Var|Abs),
+
+ USAGE(1, PID_USAGE_MAGNITUDE),
+ LOGICAL_MINIMUM(1, 0),
+ LOGICAL_MAXIMUM(2, 0x00ff),
+ PHYSICAL_MINIMUM(1, 0),
+ PHYSICAL_MAXIMUM(2, 10000),
+ REPORT_SIZE(1, 8),
+ REPORT_COUNT(1, 1),
+ OUTPUT(1, Data|Var|Abs),
+
+ USAGE(1, PID_USAGE_OFFSET),
+ LOGICAL_MINIMUM(1, 0x80),
+ LOGICAL_MAXIMUM(1, 0x7f),
+ PHYSICAL_MINIMUM(2, -10000),
+ PHYSICAL_MAXIMUM(2, 10000),
+ REPORT_SIZE(1, 8),
+ REPORT_COUNT(1, 1),
+ OUTPUT(1, Data|Var|Abs),
+
+ USAGE(1, PID_USAGE_PHASE),
+ UNIT(1, 0x14), /* Eng Rot:Angular Pos */
+ UNIT_EXPONENT(1, -2),
+ LOGICAL_MINIMUM(1, 0),
+ LOGICAL_MAXIMUM(2, 0xff),
+ PHYSICAL_MINIMUM(1, 0),
+ PHYSICAL_MAXIMUM(4, 36000),
+ REPORT_SIZE(1, 8),
+ REPORT_COUNT(1, 1),
+ OUTPUT(1, Data|Var|Abs),
+
+ USAGE(1, PID_USAGE_PERIOD),
+ UNIT(2, 0x1003), /* Eng Lin:Time */
+ UNIT_EXPONENT(1, -3), /* 10^-3 */
+ LOGICAL_MINIMUM(1, 0),
+ LOGICAL_MAXIMUM(2, 0x7fff),
+ PHYSICAL_MINIMUM(1, 0),
+ PHYSICAL_MAXIMUM(2, 0x7fff),
+ REPORT_SIZE(1, 16),
+ REPORT_COUNT(1, 1),
+ OUTPUT(1, Data|Var|Abs),
+
+ PHYSICAL_MAXIMUM(1, 0),
+ UNIT_EXPONENT(1, 0),
+ UNIT(1, 0), /* None */
+ END_COLLECTION,
+ };
+
+ iface->hid_physical.set_periodic_report = report_id;
+ return hid_report_descriptor_append(desc, template, sizeof(template));
+}
+
BOOL hid_device_add_physical(struct unix_device *iface, USAGE *usages, USHORT count)
{
struct hid_report_descriptor *desc = &iface->hid_report_descriptor;
@@ -592,6 +669,7 @@ BOOL hid_device_add_physical(struct unix_device *iface, USAGE *usages, USHORT co
UNIT(1, 0), /* None */
END_COLLECTION,
};
+ BOOL periodic = FALSE;
ULONG i;
if (!hid_report_descriptor_append(desc, device_control_header, sizeof(device_control_header)))
@@ -624,6 +702,19 @@ BOOL hid_device_add_physical(struct unix_device *iface, USAGE *usages, USHORT co
if (!hid_report_descriptor_append(desc, effect_update_footer, sizeof(effect_update_footer)))
return FALSE;
+ for (i = 0; i < count; ++i)
+ {
+ if (usages[i] == PID_USAGE_ET_SINE ||
+ usages[i] == PID_USAGE_ET_SQUARE ||
+ usages[i] == PID_USAGE_ET_TRIANGLE ||
+ usages[i] == PID_USAGE_ET_SAWTOOTH_UP ||
+ usages[i] == PID_USAGE_ET_SAWTOOTH_DOWN)
+ periodic = TRUE;
+ }
+
+ if (periodic && !hid_descriptor_add_set_periodic(iface))
+ return FALSE;
+
/* HID nary collection indexes start at 1 */
memcpy(iface->hid_physical.effect_types + 1, usages, count * sizeof(*usages));
@@ -751,6 +842,22 @@ static void hid_device_set_output_report(struct unix_device *iface, HID_XFER_PAC
io->Status = iface->hid_vtbl->physical_effect_update(iface, report->index, params);
}
}
+ else if (packet->reportId == physical->set_periodic_report)
+ {
+ struct pid_set_periodic *report = (struct pid_set_periodic *)(packet->reportBuffer + 1);
+ struct effect_params *params = iface->hid_physical.effect_params + report->index;
+
+ io->Information = sizeof(*report) + 1;
+ if (packet->reportBufferLen < io->Information)
+ io->Status = STATUS_BUFFER_TOO_SMALL;
+ else
+ {
+ params->periodic.magnitude = report->magnitude;
+ params->periodic.offset = report->offset;
+ params->periodic.phase = report->phase;
+ params->periodic.period = report->period;
+ }
+ }
else
{
io->Information = 0;
diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h
index 125ee600eb6..5962de7fb10 100644
--- a/dlls/winebus.sys/unix_private.h
+++ b/dlls/winebus.sys/unix_private.h
@@ -29,6 +29,14 @@
#include "wine/list.h"
+struct effect_periodic
+{
+ BYTE magnitude;
+ BYTE offset;
+ BYTE phase;
+ UINT16 period;
+};
+
struct effect_params
{
USAGE effect_type;
@@ -41,6 +49,10 @@ struct effect_params
BOOL axis_enabled[2];
BOOL direction_enabled;
BYTE direction[2];
+ union
+ {
+ struct effect_periodic periodic;
+ };
};
struct raw_device_vtbl
@@ -112,6 +124,7 @@ struct hid_physical
BYTE device_control_report;
BYTE effect_control_report;
BYTE effect_update_report;
+ BYTE set_periodic_report;
};
struct hid_device_state
--
2.33.0
1
10
Basic files and required changes to configure(.ac) to create a stub version
of the robocopy utility
Signed-off-by: Florian Eder <others.meder(a)gmail.com>
---
v6: Identical to patch in v5
---
configure | 2 +-
configure.ac | 1 +
programs/robocopy/Makefile.in | 8 ++++++++
programs/robocopy/main.c | 29 +++++++++++++++++++++++++++++
programs/robocopy/robocopy.rc | 34 ++++++++++++++++++++++++++++++++++
5 files changed, 73 insertions(+), 1 deletion(-)
create mode 100644 programs/robocopy/Makefile.in
create mode 100644 programs/robocopy/main.c
create mode 100644 programs/robocopy/robocopy.rc
diff --git a/configure b/configure
index db592f0868d..3a8dee81bbc 100755
--- a/configure
+++ b/configure
@@ -21235,6 +21235,7 @@ wine_fn_config_makefile programs/regedit/tests enable_tests
wine_fn_config_makefile programs/regini enable_regini
wine_fn_config_makefile programs/regsvcs enable_regsvcs
wine_fn_config_makefile programs/regsvr32 enable_regsvr32
+wine_fn_config_makefile programs/robocopy enable_robocopy
wine_fn_config_makefile programs/rpcss enable_rpcss
wine_fn_config_makefile programs/rundll.exe16 enable_win16
wine_fn_config_makefile programs/rundll32 enable_rundll32
@@ -22768,4 +22769,3 @@ IFS="$ac_save_IFS"
$as_echo "
$as_me: Finished. Do '${ac_make}' to compile Wine.
" >&6
-
diff --git a/configure.ac b/configure.ac
index 0bc46a1427b..5bd54cfbba7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3959,6 +3959,7 @@ WINE_CONFIG_MAKEFILE(programs/regedit/tests)
WINE_CONFIG_MAKEFILE(programs/regini)
WINE_CONFIG_MAKEFILE(programs/regsvcs)
WINE_CONFIG_MAKEFILE(programs/regsvr32)
+WINE_CONFIG_MAKEFILE(programs/robocopy)
WINE_CONFIG_MAKEFILE(programs/rpcss)
WINE_CONFIG_MAKEFILE(programs/rundll.exe16,enable_win16)
WINE_CONFIG_MAKEFILE(programs/rundll32)
diff --git a/programs/robocopy/Makefile.in b/programs/robocopy/Makefile.in
new file mode 100644
index 00000000000..5a48be3725b
--- /dev/null
+++ b/programs/robocopy/Makefile.in
@@ -0,0 +1,8 @@
+MODULE = robocopy.exe
+
+EXTRADLLFLAGS = -mconsole -municode -mno-cygwin
+
+C_SRCS = \
+ main.c
+
+RC_SRCS = robocopy.rc
diff --git a/programs/robocopy/main.c b/programs/robocopy/main.c
new file mode 100644
index 00000000000..bbda15f573a
--- /dev/null
+++ b/programs/robocopy/main.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2021 Florian Eder
+ *
+ * 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
+ */
+
+#include "wine/debug.h"
+WINE_DEFAULT_DEBUG_CHANNEL(robocopy);
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+int __cdecl wmain(int argc, WCHAR *argv[])
+{
+ WINE_FIXME("robocopy stub");
+ return 1;
+}
diff --git a/programs/robocopy/robocopy.rc b/programs/robocopy/robocopy.rc
new file mode 100644
index 00000000000..edae5b71d86
--- /dev/null
+++ b/programs/robocopy/robocopy.rc
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2021 Florian Eder
+ *
+ * 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
+ */
+
+#include <windef.h>
+
+#pragma makedep po
+
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+
+#define WINE_FILEDESCRIPTION_STR "Wine Robocopy"
+#define WINE_FILENAME_STR "robocopy.exe"
+#define WINE_FILETYPE VFT_APP
+#define WINE_FILEVERSION 5,1,10,1027
+#define WINE_FILEVERSION_STR "5.1.10.1027"
+
+#define WINE_PRODUCTVERSION 5,1,10,1027
+#define WINE_PRODUCTVERSION_STR "XP027"
+
+#include "wine/wine_common_ver.rc"
--
2.32.0
3
19