Because iphlpapi has no opportunity to convert the buffer in async mode.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
Handles architecture differences and family (can be easily extended to support IPv6's struct).
dlls/iphlpapi/iphlpapi_main.c | 44 ++---------- dlls/nsiproxy.sys/device.c | 103 ++++++++++++++++++++++++--- dlls/nsiproxy.sys/nsiproxy_private.h | 55 ++++++++++++++ include/wine/nsi.h | 21 +----- 4 files changed, 155 insertions(+), 68 deletions(-)
diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c index d9a85be..a024224 100644 --- a/dlls/iphlpapi/iphlpapi_main.c +++ b/dlls/iphlpapi/iphlpapi_main.c @@ -4579,33 +4579,6 @@ 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.@) */ @@ -4636,9 +4609,8 @@ 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; - DWORD opt_size, in_size, ret = 0, out_size; + DWORD opt_size, in_size, ret = 0; struct nsiproxy_icmp_echo *in; - struct nsiproxy_icmp_echo_reply *out; HANDLE request_event; IO_STATUS_BLOCK iosb; NTSTATUS status; @@ -4658,17 +4630,15 @@ DWORD WINAPI IcmpSendEcho2Ex( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc_r 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) + if (!in) { - heap_free( out ); - heap_free( in ); SetLastError( IP_NO_RESOURCES ); return 0; }
+ in->addr = (ULONG_PTR)reply; + in->bits = sizeof(void*) * 8; in->src.Ipv4.sin_family = AF_INET; in->src.Ipv4.sin_addr.s_addr = src; in->dst.Ipv4.sin_family = AF_INET; @@ -4689,19 +4659,15 @@ DWORD WINAPI IcmpSendEcho2Ex( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc_r
status = NtDeviceIoControlFile( data->nsi_device, request_event, NULL, NULL, &iosb, IOCTL_NSIPROXY_WINE_ICMP_ECHO, in, in_size, - out, out_size ); + reply, reply_size );
if (status == STATUS_PENDING && !WaitForSingleObject( request_event, INFINITE )) status = iosb.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 ) ); diff --git a/dlls/nsiproxy.sys/device.c b/dlls/nsiproxy.sys/device.c index 90a7a3d..e310805 100644 --- a/dlls/nsiproxy.sys/device.c +++ b/dlls/nsiproxy.sys/device.c @@ -31,6 +31,7 @@ #include "netiodef.h" #include "wine/nsi.h" #include "wine/debug.h" +#include "wine/heap.h" #include "wine/unixlib.h"
#include "nsiproxy_private.h" @@ -211,6 +212,57 @@ static void WINAPI icmp_echo_cancel( DEVICE_OBJECT *device, IRP *irp ) LeaveCriticalSection( &nsiproxy_cs ); }
+static void icmp_echo_reply_fixup( void *out, struct nsiproxy_icmp_echo_reply *reply, ULONGLONG addr, ULONG family, ULONG bits ) +{ + void *data = out; + if (family == AF_INET) + { + void *options_data; + if (bits == 32) + { + struct icmp_echo_reply_32 *dst = out; + dst->addr = reply->addr.Ipv4.sin_addr.s_addr; + dst->status = reply->status; + dst->round_trip_time = reply->round_trip_time; + dst->data_size = reply->data_size; + dst->num_of_pkts = reply->num_of_pkts; + dst->data_ptr = addr + sizeof(*dst) + ((reply->opts.options_size + 3) & ~3); + dst->opts.ttl = reply->opts.ttl; + dst->opts.tos = reply->opts.tos; + dst->opts.flags = reply->opts.flags; + dst->opts.options_size = reply->opts.options_size; + dst->opts.options_ptr = addr + sizeof(*dst); + options_data = dst + 1; + } + else + { + struct icmp_echo_reply_64 *dst = out; + dst->addr = reply->addr.Ipv4.sin_addr.s_addr; + dst->status = reply->status; + dst->round_trip_time = reply->round_trip_time; + dst->data_size = reply->data_size; + dst->num_of_pkts = reply->num_of_pkts; + dst->data_ptr = addr + sizeof(*dst) + ((reply->opts.options_size + 3) & ~3); + dst->opts.ttl = reply->opts.ttl; + dst->opts.tos = reply->opts.tos; + dst->opts.flags = reply->opts.flags; + dst->opts.options_size = reply->opts.options_size; + dst->opts.options_ptr = addr + sizeof(*dst); + options_data = dst + 1; + } + memcpy( options_data, (BYTE *)reply + reply->opts.options_offset, reply->opts.options_size ); + data = (BYTE *)options_data + ((reply->opts.options_size + 3) & ~3); + } + memcpy( data, (BYTE *)reply + reply->data_offset, reply->data_size ); +} + +static int icmp_echo_reply_struct_len( ULONG family, ULONG bits ) +{ + if (family == AF_INET) + return (bits == 32) ? sizeof(struct icmp_echo_reply_32) : sizeof(struct icmp_echo_reply_64); + return 0; +} + static NTSTATUS nsiproxy_icmp_echo( IRP *irp ) { IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); @@ -222,7 +274,7 @@ static NTSTATUS nsiproxy_icmp_echo( IRP *irp )
if (in_len < offsetof(struct nsiproxy_icmp_echo, data[0]) || in_len < offsetof(struct nsiproxy_icmp_echo, data[((in->opt_size + 3) & ~3) + in->req_size]) || - out_len < sizeof(struct nsiproxy_icmp_echo_reply)) + out_len < icmp_echo_reply_struct_len( in->dst.si_family, in->bits )) return STATUS_INVALID_PARAMETER;
switch (in->dst.si_family) @@ -320,19 +372,34 @@ static DWORD WINAPI listen_thread_proc( void *arg ) { IRP *irp = arg; IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); + unsigned int reply_len = irpsp->Parameters.DeviceIoControl.OutputBufferLength; struct nsiproxy_icmp_echo *in = irp->AssociatedIrp.SystemBuffer; struct icmp_listen_params params; + ULONG family = in->dst.si_family; + ULONGLONG addr = in->addr; + ULONG bits = in->bits; + ULONG struct_len; NTSTATUS status;
TRACE( "\n" );
+ struct_len = icmp_echo_reply_struct_len( family, bits ); params.handle = irp_get_icmp_handle( irp ); params.timeout = in->timeout; - params.reply = irp->AssociatedIrp.SystemBuffer; - params.reply_len = irpsp->Parameters.DeviceIoControl.OutputBufferLength; + params.reply_len = reply_len - struct_len + sizeof(struct nsiproxy_icmp_echo_reply); + params.reply = heap_alloc( params.reply_len );
- status = nsiproxy_call( icmp_listen, ¶ms ); - TRACE( "icmp_listen rets %08x\n", status ); + if (params.reply) + { + void *reply = irp->AssociatedIrp.SystemBuffer; + status = nsiproxy_call( icmp_listen, ¶ms ); + TRACE( "icmp_listen rets %08x\n", status ); + + icmp_echo_reply_fixup( reply, params.reply, addr, family, bits ); + heap_free( params.reply ); + reply_len = params.reply_len - sizeof(struct nsiproxy_icmp_echo_reply) + struct_len; + } + else status = STATUS_NO_MEMORY;
EnterCriticalSection( &nsiproxy_cs );
@@ -340,7 +407,7 @@ static DWORD WINAPI listen_thread_proc( void *arg )
irp->IoStatus.Status = status; if (status == STATUS_SUCCESS) - irp->IoStatus.Information = params.reply_len; + irp->IoStatus.Information = reply_len; else irp->IoStatus.Information = 0; IoCompleteRequest( irp, IO_NO_INCREMENT ); @@ -353,8 +420,10 @@ static DWORD WINAPI listen_thread_proc( void *arg ) static void handle_queued_send_echo( IRP *irp ) { struct nsiproxy_icmp_echo *in = (struct nsiproxy_icmp_echo *)irp->AssociatedIrp.SystemBuffer; - struct nsiproxy_icmp_echo_reply *reply = (struct nsiproxy_icmp_echo_reply *)irp->AssociatedIrp.SystemBuffer; + void *out = irp->AssociatedIrp.SystemBuffer; struct icmp_send_echo_params params; + ULONG family = in->dst.si_family; + ULONG bits = in->bits; NTSTATUS status;
TRACE( "\n" ); @@ -372,9 +441,23 @@ static void handle_queued_send_echo( IRP *irp ) irp->IoStatus.Status = status; if (status == STATUS_SUCCESS) { - memset( reply, 0, sizeof(*reply) ); - reply->status = params.ip_status; - irp->IoStatus.Information = sizeof(*reply); + if (family == AF_INET) + { + if (bits == 32) + { + struct icmp_echo_reply_32 *reply = out; + memset( reply, 0, sizeof(*reply) ); + reply->status = params.ip_status; + irp->IoStatus.Information = sizeof(*reply); + } + else + { + struct icmp_echo_reply_64 *reply = out; + memset( reply, 0, sizeof(*reply) ); + reply->status = params.ip_status; + irp->IoStatus.Information = sizeof(*reply); + } + } } IoCompleteRequest( irp, IO_NO_INCREMENT ); } diff --git a/dlls/nsiproxy.sys/nsiproxy_private.h b/dlls/nsiproxy.sys/nsiproxy_private.h index 91dd393..0694757 100644 --- a/dlls/nsiproxy.sys/nsiproxy_private.h +++ b/dlls/nsiproxy.sys/nsiproxy_private.h @@ -34,3 +34,58 @@ struct icmp_send_echo_params HANDLE handle; ULONG ip_status; }; + +/* output for IOCTL_NSIPROXY_WINE_ICMP_ECHO - cf. ICMP_ECHO_REPLY */ +struct nsiproxy_icmp_echo_reply +{ + SOCKADDR_INET addr; + ULONG status; + ULONG round_trip_time; + USHORT data_size; + USHORT num_of_pkts; + DWORD data_offset; + struct + { + BYTE ttl; + BYTE tos; + BYTE flags; + BYTE options_size; + DWORD options_offset; + } opts; +}; + +struct icmp_echo_reply_32 +{ + ULONG addr; + ULONG status; + ULONG round_trip_time; + USHORT data_size; + USHORT num_of_pkts; + ULONG data_ptr; + struct + { + BYTE ttl; + BYTE tos; + BYTE flags; + BYTE options_size; + ULONG options_ptr; + } opts; +}; + +struct icmp_echo_reply_64 +{ + ULONG addr; + ULONG status; + ULONG round_trip_time; + USHORT data_size; + USHORT num_of_pkts; + ULONGLONG data_ptr; + struct + { + BYTE ttl; + BYTE tos; + BYTE flags; + BYTE options_size; + ULONGLONG options_ptr; + } opts; +}; diff --git a/include/wine/nsi.h b/include/wine/nsi.h index 9664b53..4e60ff6 100644 --- a/include/wine/nsi.h +++ b/include/wine/nsi.h @@ -426,6 +426,8 @@ struct nsiproxy_icmp_echo { SOCKADDR_INET src; SOCKADDR_INET dst; + ULONGLONG addr; /* user-mode reply buffer address */ + BYTE bits; BYTE ttl; BYTE tos; BYTE flags; @@ -435,25 +437,6 @@ struct nsiproxy_icmp_echo BYTE data[1]; /* ((opt_size + 3) & ~3) + req_size */ };
-/* output for IOCTL_NSIPROXY_WINE_ICMP_ECHO - cf. ICMP_ECHO_REPLY */ -struct nsiproxy_icmp_echo_reply -{ - SOCKADDR_INET addr; - ULONG status; - ULONG round_trip_time; - USHORT data_size; - USHORT num_of_pkts; - DWORD data_offset; - struct - { - BYTE ttl; - BYTE tos; - BYTE flags; - BYTE options_size; - DWORD options_offset; - } opts; -}; - /* Undocumented Nsi api */
#define NSI_PARAM_TYPE_RW 0