Because iphlpapi has no opportunity to convert the reply in async mode.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/iphlpapi/iphlpapi_main.c | 44 ++----------- dlls/nsiproxy.sys/device.c | 12 +++- dlls/nsiproxy.sys/icmp_echo.c | 93 ++++++++++++++++++---------- dlls/nsiproxy.sys/nsiproxy_private.h | 42 ++++++++++++- include/wine/nsi.h | 21 +------ 5 files changed, 120 insertions(+), 92 deletions(-)
diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c index d9a85be..8a31241 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->user_reply_ptr = (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 dd08282..9e0a1d1 100644 --- a/dlls/nsiproxy.sys/device.c +++ b/dlls/nsiproxy.sys/device.c @@ -211,6 +211,13 @@ static void WINAPI icmp_echo_cancel( DEVICE_OBJECT *device, IRP *irp ) LeaveCriticalSection( &nsiproxy_cs ); }
+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 +229,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) @@ -326,8 +333,10 @@ static DWORD WINAPI listen_thread_proc( void *arg )
TRACE( "\n" );
+ params.user_reply_ptr = in->user_reply_ptr; params.handle = irp_get_icmp_handle( irp ); params.timeout = in->timeout; + params.bits = in->bits; params.reply = irp->AssociatedIrp.SystemBuffer; params.reply_len = irpsp->Parameters.DeviceIoControl.OutputBufferLength;
@@ -360,6 +369,7 @@ static void handle_queued_send_echo( IRP *irp ) params.request = in->data + ((in->opt_size + 3) & ~3); params.request_size = in->req_size; params.reply = irp->AssociatedIrp.SystemBuffer; + params.bits = in->bits; params.ttl = in->ttl; params.tos = in->tos; params.dst = &in->dst; diff --git a/dlls/nsiproxy.sys/icmp_echo.c b/dlls/nsiproxy.sys/icmp_echo.c index 4807569..07d76f0 100644 --- a/dlls/nsiproxy.sys/icmp_echo.c +++ b/dlls/nsiproxy.sys/icmp_echo.c @@ -224,12 +224,22 @@ static unsigned short null_chksum( BYTE *data, unsigned int count ) } #endif
-static int ipv4_set_reply_ip_status( IP_STATUS ip_status, void *out ) +static int ipv4_set_reply_ip_status( IP_STATUS ip_status, unsigned int bits, void *out ) { - struct nsiproxy_icmp_echo_reply *reply = out; - memset( reply, 0, sizeof(*reply) ); - reply->status = ip_status; - return sizeof(*reply); + if (bits == 32) + { + struct icmp_echo_reply_32 *reply = out; + memset( reply, 0, sizeof(*reply) ); + reply->status = ip_status; + return sizeof(*reply); + } + else + { + struct icmp_echo_reply_64 *reply = out; + memset( reply, 0, sizeof(*reply) ); + reply->status = ip_status; + return sizeof(*reply); + } }
static void ipv4_set_socket_opts( struct icmp_data *data, struct icmp_send_echo_params *params ) @@ -254,15 +264,17 @@ static void ipv4_linux_ping_set_socket_opts( struct icmp_data *data, struct icmp } #endif
-static int ipv4_reply_buffer_len( int reply_len ) +static int ipv4_reply_buffer_len( struct icmp_listen_params *params ) { - return sizeof(struct ip_hdr) + sizeof(struct icmp_hdr) + reply_len - sizeof(struct nsiproxy_icmp_echo_reply); + int struct_len = (params->bits == 32) ? sizeof(struct icmp_echo_reply_32) : sizeof(struct icmp_echo_reply_64); + return sizeof(struct ip_hdr) + sizeof(struct icmp_hdr) + params->reply_len - struct_len; }
#ifdef __linux__ -static int ipv4_linux_ping_reply_buffer_len( int reply_len ) +static int ipv4_linux_ping_reply_buffer_len( struct icmp_listen_params *params ) { - return sizeof(struct icmp_hdr) + reply_len - sizeof(struct nsiproxy_icmp_echo_reply); + int struct_len = (params->bits == 32) ? sizeof(struct icmp_echo_reply_32) : sizeof(struct icmp_echo_reply_64); + return sizeof(struct icmp_hdr) + params->reply_len - struct_len; } #endif
@@ -411,23 +423,42 @@ static int ipv4_linux_ping_parse_icmp_hdr( struct icmp_data *data, struct icmp_h
static void ipv4_fill_reply( struct icmp_listen_params *params, struct icmp_reply_ctx *ctx) { - struct nsiproxy_icmp_echo_reply *reply = params->reply; void *options_data; ULONG data_offset; - - data_offset = sizeof(*reply) + ((ctx->options_size + 3) & ~3); - reply->addr = ctx->addr; - reply->status = ctx->status; - reply->round_trip_time = ctx->round_trip_time; - reply->data_size = ctx->data_size; - reply->num_of_pkts = 1; - reply->data_offset = data_offset; - reply->opts.ttl = ctx->ttl; - reply->opts.tos = ctx->tos; - reply->opts.flags = ctx->flags; - reply->opts.options_size = ctx->options_size; - reply->opts.options_offset = sizeof(*reply); - options_data = reply + 1; + if (params->bits == 32) + { + struct icmp_echo_reply_32 *reply = params->reply; + data_offset = sizeof(*reply) + ((ctx->options_size + 3) & ~3); + reply->addr = ctx->addr.Ipv4.sin_addr.WS_s_addr; + reply->status = ctx->status; + reply->round_trip_time = ctx->round_trip_time; + reply->data_size = ctx->data_size; + reply->num_of_pkts = 1; + reply->data_ptr = params->user_reply_ptr + data_offset; + reply->opts.ttl = ctx->ttl; + reply->opts.tos = ctx->tos; + reply->opts.flags = ctx->flags; + reply->opts.options_size = ctx->options_size; + reply->opts.options_ptr = params->user_reply_ptr + sizeof(*reply); + options_data = reply + 1; + } + else + { + struct icmp_echo_reply_64 *reply = params->reply; + data_offset = sizeof(*reply) + ((ctx->options_size + 3) & ~3); + reply->addr = ctx->addr.Ipv4.sin_addr.WS_s_addr; + reply->status = ctx->status; + reply->round_trip_time = ctx->round_trip_time; + reply->data_size = ctx->data_size; + reply->num_of_pkts = 1; + reply->data_ptr = params->user_reply_ptr + data_offset; + reply->opts.ttl = ctx->ttl; + reply->opts.tos = ctx->tos; + reply->opts.flags = ctx->flags; + reply->opts.options_size = ctx->options_size; + reply->opts.options_ptr = params->user_reply_ptr + sizeof(*reply); + options_data = reply + 1; + }
memcpy( options_data, ctx->options_data, ctx->options_size ); if (ctx->options_size & 3) @@ -443,9 +474,9 @@ struct family_ops int icmp_protocol; void (*init_icmp_hdr)( struct icmp_data *data, struct icmp_hdr *icmp_hdr ); unsigned short (*chksum)( BYTE *data, unsigned int count ); - int (*set_reply_ip_status)( IP_STATUS ip_status, void *out ); + int (*set_reply_ip_status)( IP_STATUS ip_status, unsigned int bits, void *out ); void (*set_socket_opts)( struct icmp_data *data, struct icmp_send_echo_params *params ); - int (*reply_buffer_len)( int reply_len ); + int (*reply_buffer_len)( struct icmp_listen_params *params ); BOOL (*parse_ip_hdr)( struct msghdr *msg, int recvd, int *ip_hdr_len, struct icmp_reply_ctx *ctx ); int (*parse_icmp_hdr)( struct icmp_data *data, struct icmp_hdr *icmp, int icmp_len, struct icmp_reply_ctx *ctx ); void (*fill_reply)( struct icmp_listen_params *params, struct icmp_reply_ctx *ctx ); @@ -629,7 +660,7 @@ NTSTATUS icmp_send_echo( void *args ) { TRACE( "sendto() rets %d errno %d\n", ret, errno ); icmp_data_free( data ); - params->reply_len = data->ops->set_reply_ip_status( errno_to_ip_status( errno ), params->reply ); + params->reply_len = data->ops->set_reply_ip_status( errno_to_ip_status( errno ), params->bits, params->reply ); return STATUS_SUCCESS; }
@@ -670,7 +701,7 @@ static NTSTATUS recv_msg( struct icmp_data *data, struct icmp_listen_params *par char *reply_buf; struct icmp_hdr *icmp_hdr;
- reply_buf_len = data->ops->reply_buffer_len( params->reply_len ); + reply_buf_len = data->ops->reply_buffer_len( params ); reply_buf = malloc( reply_buf_len ); if (!reply_buf) return STATUS_NO_MEMORY;
@@ -689,7 +720,7 @@ static NTSTATUS recv_msg( struct icmp_data *data, struct icmp_listen_params *par if (ctx.data_size && msg.msg_flags & MSG_TRUNC) { free( reply_buf ); - params->reply_len = data->ops->set_reply_ip_status( IP_GENERAL_FAILURE, params->reply ); + params->reply_len = data->ops->set_reply_ip_status( IP_GENERAL_FAILURE, params->bits, params->reply ); return STATUS_SUCCESS; }
@@ -739,11 +770,11 @@ NTSTATUS icmp_listen( void *args ) if (!ret) /* timeout */ { TRACE( "timeout\n" ); - params->reply_len = data->ops->set_reply_ip_status( IP_REQ_TIMED_OUT, params->reply ); + params->reply_len = data->ops->set_reply_ip_status( IP_REQ_TIMED_OUT, params->bits, params->reply ); return STATUS_SUCCESS; } /* ret < 0 */ - params->reply_len = data->ops->set_reply_ip_status( errno_to_ip_status( errno ), params->reply ); + params->reply_len = data->ops->set_reply_ip_status( errno_to_ip_status( errno ), params->bits, params->reply ); return STATUS_SUCCESS; }
diff --git a/dlls/nsiproxy.sys/nsiproxy_private.h b/dlls/nsiproxy.sys/nsiproxy_private.h index 8a9f2dd..bdea1c6 100644 --- a/dlls/nsiproxy.sys/nsiproxy_private.h +++ b/dlls/nsiproxy.sys/nsiproxy_private.h @@ -21,7 +21,8 @@ struct icmp_listen_params { HANDLE handle; void *reply; - unsigned int reply_len; + ULONGLONG user_reply_ptr; + unsigned int bits, reply_len; int timeout; };
@@ -30,6 +31,43 @@ struct icmp_send_echo_params SOCKADDR_INET *dst; void *request, *reply; DWORD request_size, reply_len; - BYTE ttl, tos; + BYTE bits, ttl, tos; HANDLE handle; }; + +/* output for IOCTL_NSIPROXY_WINE_ICMP_ECHO - cf. ICMP_ECHO_REPLY */ +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..8c3488d 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 user_reply_ptr; + 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