[PATCH v5 1/2] nsiproxy: Fill the reply with exact ICMP_ECHO_REPLY in the output buffer.

Gabriel Ivăncescu gabrielopcode at gmail.com
Mon Oct 25 11:26:47 CDT 2021


Because iphlpapi has no opportunity to convert the reply in async mode.

Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---
 dlls/iphlpapi/iphlpapi_main.c        |  44 +-----
 dlls/nsiproxy.sys/device.c           |  36 ++++-
 dlls/nsiproxy.sys/icmp_echo.c        | 203 ++++++++++++++++++---------
 dlls/nsiproxy.sys/nsiproxy_private.h |  39 +++++
 include/wine/nsi.h                   |  21 +--
 5 files changed, 212 insertions(+), 131 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 90a7a3d..4ace66d 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,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 +230,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 +334,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;
 
@@ -353,8 +363,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 +384,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/icmp_echo.c b/dlls/nsiproxy.sys/icmp_echo.c
index 955fdfd..1e106c6 100644
--- a/dlls/nsiproxy.sys/icmp_echo.c
+++ b/dlls/nsiproxy.sys/icmp_echo.c
@@ -93,6 +93,20 @@ struct icmp_hdr
     } un;
 };
 
+struct icmp_reply_ctx
+{
+    SOCKADDR_INET addr;
+    ULONG status;
+    ULONG round_trip_time;
+    LONG data_size;
+    BYTE ttl;
+    BYTE tos;
+    BYTE flags;
+    BYTE options_size;
+    void *options_data;
+    void *data;
+};
+
 struct family_ops;
 struct icmp_data
 {
@@ -232,20 +246,22 @@ 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
 
-static BOOL ipv4_parse_ip_hdr( struct msghdr *msg, int recvd,
-                               int *ip_hdr_len, struct nsiproxy_icmp_echo_reply *reply, void **opts )
+static BOOL ipv4_parse_ip_hdr( struct msghdr *msg, int recvd, int *ip_hdr_len,
+                               struct icmp_reply_ctx *ctx )
 {
     struct ip_hdr *ip_hdr;
 
@@ -254,27 +270,27 @@ static BOOL ipv4_parse_ip_hdr( struct msghdr *msg, int recvd,
     if (ip_hdr->v_hl >> 4 != 4 || ip_hdr->protocol != IPPROTO_ICMP) return FALSE;
     *ip_hdr_len = (ip_hdr->v_hl & 0xf) << 2;
     if (*ip_hdr_len < sizeof(*ip_hdr)) return FALSE;
-    *opts = ip_hdr + 1;
-    reply->opts.ttl = ip_hdr->ttl;
-    reply->opts.tos = ip_hdr->tos;
-    reply->opts.flags = ip_hdr->frag_off >> 13;
-    reply->opts.options_size = *ip_hdr_len - sizeof(*ip_hdr);
+    ctx->options_data = ip_hdr + 1;
+    ctx->ttl = ip_hdr->ttl;
+    ctx->tos = ip_hdr->tos;
+    ctx->flags = ip_hdr->frag_off >> 13;
+    ctx->options_size = *ip_hdr_len - sizeof(*ip_hdr);
 
     return TRUE;
 }
 
 #ifdef __linux__
-static BOOL ipv4_linux_ping_parse_ip_hdr( struct msghdr *msg, int recvd,
-                                          int *ip_hdr_len, struct nsiproxy_icmp_echo_reply *reply, void **opts )
+static BOOL ipv4_linux_ping_parse_ip_hdr( struct msghdr *msg, int recvd, int *ip_hdr_len,
+                                          struct icmp_reply_ctx *ctx )
 {
     struct cmsghdr *cmsg;
 
     *ip_hdr_len = 0;
-    *opts = NULL;
-    reply->opts.ttl = 0;
-    reply->opts.tos = 0;
-    reply->opts.flags = 0;
-    reply->opts.options_size = 0; /* FIXME from IP_OPTIONS but will require checking for space in the reply */
+    ctx->options_data = NULL;
+    ctx->ttl = 0;
+    ctx->tos = 0;
+    ctx->flags = 0;
+    ctx->options_size = 0; /* FIXME from IP_OPTIONS but will require checking for space in the reply */
 
     for (cmsg = CMSG_FIRSTHDR( msg ); cmsg; cmsg = CMSG_NXTHDR( msg, cmsg ))
     {
@@ -282,10 +298,10 @@ static BOOL ipv4_linux_ping_parse_ip_hdr( struct msghdr *msg, int recvd,
         switch (cmsg->cmsg_type)
         {
         case IP_TTL:
-            reply->opts.ttl = *(BYTE *)CMSG_DATA( cmsg );
+            ctx->ttl = *(BYTE *)CMSG_DATA( cmsg );
             break;
         case IP_TOS:
-            reply->opts.tos = *(BYTE *)CMSG_DATA( cmsg );
+            ctx->tos = *(BYTE *)CMSG_DATA( cmsg );
             break;
         }
     }
@@ -294,7 +310,7 @@ static BOOL ipv4_linux_ping_parse_ip_hdr( struct msghdr *msg, int recvd,
 #endif
 
 static int ipv4_parse_icmp_hdr_( struct icmp_data *data, struct icmp_hdr *icmp, int icmp_size,
-                                 struct nsiproxy_icmp_echo_reply *reply, int ping_socket )
+                                 struct icmp_reply_ctx *ctx, int ping_socket )
 {
     static const IP_STATUS unreach_codes[] =
     {
@@ -326,7 +342,7 @@ static int ipv4_parse_icmp_hdr_( struct icmp_data *data, struct icmp_hdr *icmp,
         if ((!ping_socket && icmp->un.echo.id != data->id) ||
             icmp->un.echo.sequence != data->seq) return -1;
 
-        reply->status = IP_SUCCESS;
+        ctx->status = IP_SUCCESS;
         return icmp_size - sizeof(*icmp);
 
     case ICMP4_DST_UNREACH:
@@ -369,24 +385,90 @@ static int ipv4_parse_icmp_hdr_( struct icmp_data *data, struct icmp_hdr *icmp,
         (!ping_socket && orig_icmp_hdr->un.echo.id != data->id) ||
         orig_icmp_hdr->un.echo.sequence != data->seq) return -1;
 
-    reply->status = status;
+    ctx->status = status;
     return 0;
 }
 
-static int ipv4_parse_icmp_hdr( struct icmp_data *data, struct icmp_hdr *icmp, int icmp_size,
-                                struct nsiproxy_icmp_echo_reply *reply )
+static int ipv4_parse_icmp_hdr( struct icmp_data *data, struct icmp_hdr *icmp,
+                                int icmp_size, struct icmp_reply_ctx *ctx)
 {
-    return ipv4_parse_icmp_hdr_( data, icmp, icmp_size, reply, 0 );
+    return ipv4_parse_icmp_hdr_( data, icmp, icmp_size, ctx, 0 );
 }
 
 #ifdef __linux__
-static int ipv4_linux_ping_parse_icmp_hdr( struct icmp_data *data, struct icmp_hdr *icmp, int icmp_size,
-                                           struct nsiproxy_icmp_echo_reply *reply )
+static int ipv4_linux_ping_parse_icmp_hdr( struct icmp_data *data, struct icmp_hdr *icmp,
+                                           int icmp_size, struct icmp_reply_ctx *ctx )
 {
-    return ipv4_parse_icmp_hdr_( data, icmp, icmp_size, reply, 1 );
+    return ipv4_parse_icmp_hdr_( data, icmp, icmp_size, ctx, 1 );
 }
 #endif
 
+static NTSTATUS ipv4_set_reply_ip_status( struct icmp_listen_params *params, IP_STATUS ip_status )
+{
+    if (params->bits == 32)
+    {
+        struct icmp_echo_reply_32 *reply = params->reply;
+        memset( reply, 0, sizeof(*reply) );
+        reply->status = ip_status;
+        params->reply_len = sizeof(*reply);
+    }
+    else
+    {
+        struct icmp_echo_reply_64 *reply = params->reply;
+        memset( reply, 0, sizeof(*reply) );
+        reply->status = ip_status;
+        params->reply_len = sizeof(*reply);
+    }
+    return STATUS_SUCCESS;
+}
+
+static void ipv4_fill_reply( struct icmp_listen_params *params, struct icmp_reply_ctx *ctx)
+{
+    void *options_data;
+    ULONG data_offset;
+    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)
+        memset( (char *)options_data + ctx->options_size, 0, 4 - (ctx->options_size & 3) );
+
+    memcpy( (char *)params->reply + data_offset, ctx->data, ctx->data_size );
+    params->reply_len = data_offset + ctx->data_size;
+}
+
 struct family_ops
 {
     int family;
@@ -394,11 +476,11 @@ struct family_ops
     void (*init_icmp_hdr)( struct icmp_data *data, struct icmp_hdr *icmp_hdr );
     unsigned short (*chksum)( BYTE *data, unsigned int count );
     void (*set_socket_opts)( struct icmp_data *data, struct icmp_send_echo_params *params );
-    int (*reply_buffer_len)( int reply_len );
-    BOOL (*parse_ip_hdr)( struct msghdr *msg, int recvd,
-                          int *ip_hdr_len, struct nsiproxy_icmp_echo_reply *reply, void **opts );
-    int (*parse_icmp_hdr)( struct icmp_data *data, struct icmp_hdr *icmp, int icmp_len,
-                           struct nsiproxy_icmp_echo_reply *reply );
+    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 );
+    NTSTATUS (*set_reply_ip_status)( struct icmp_listen_params *params, IP_STATUS ip_status );
+    void (*fill_reply)( struct icmp_listen_params *params, struct icmp_reply_ctx *ctx );
 };
 
 static const struct family_ops ipv4 =
@@ -411,6 +493,8 @@ static const struct family_ops ipv4 =
     ipv4_reply_buffer_len,
     ipv4_parse_ip_hdr,
     ipv4_parse_icmp_hdr,
+    ipv4_set_reply_ip_status,
+    ipv4_fill_reply,
 };
 
 #ifdef __linux__
@@ -425,6 +509,8 @@ static const struct family_ops ipv4_linux_ping =
     ipv4_linux_ping_reply_buffer_len,
     ipv4_linux_ping_parse_ip_hdr,
     ipv4_linux_ping_parse_icmp_hdr,
+    ipv4_set_reply_ip_status,
+    ipv4_fill_reply,
 };
 #endif
 
@@ -584,16 +670,6 @@ NTSTATUS icmp_send_echo( void *args )
     return params->handle ? STATUS_PENDING : STATUS_NO_MEMORY;
 }
 
-static NTSTATUS set_reply_ip_status( struct icmp_listen_params *params, IP_STATUS ip_status )
-{
-    struct nsiproxy_icmp_echo_reply *reply = params->reply;
-
-    memset( reply, 0, sizeof(*reply) );
-    reply->status = ip_status;
-    params->reply_len = sizeof(*reply);
-    return STATUS_SUCCESS;
-}
-
 static int get_timeout( LARGE_INTEGER start, DWORD timeout )
 {
     LARGE_INTEGER now, end;
@@ -615,19 +691,18 @@ static ULONG get_rtt( LARGE_INTEGER start )
 
 static NTSTATUS recv_msg( struct icmp_data *data, struct icmp_listen_params *params )
 {
-    struct nsiproxy_icmp_echo_reply *reply = (struct nsiproxy_icmp_echo_reply *)params->reply;
     struct sockaddr_storage addr;
+    struct icmp_reply_ctx ctx;
     struct iovec iov[1];
     BYTE cmsg_buf[1024];
     struct msghdr msg = { .msg_name = &addr, .msg_namelen = sizeof(addr),
                           .msg_iov = iov, .msg_iovlen = ARRAY_SIZE(iov),
                           .msg_control = cmsg_buf, .msg_controllen = sizeof(cmsg_buf) };
-    int ip_hdr_len, recvd, reply_buf_len, data_size;
+    int ip_hdr_len, recvd, reply_buf_len;
     char *reply_buf;
-    void *opts;
     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;
 
@@ -638,31 +713,23 @@ static NTSTATUS recv_msg( struct icmp_data *data, struct icmp_listen_params *par
     TRACE( "recvmsg() rets %d errno %d addr_len %d iovlen %d msg_flags %x\n",
            recvd, errno, msg.msg_namelen, (int)iov[0].iov_len, msg.msg_flags );
 
-    if (!data->ops->parse_ip_hdr( &msg, recvd, &ip_hdr_len, reply, &opts )) goto skip;
+    if (!data->ops->parse_ip_hdr( &msg, recvd, &ip_hdr_len, &ctx )) goto skip;
     if (recvd < ip_hdr_len + sizeof(*icmp_hdr)) goto skip;
 
     icmp_hdr = (struct icmp_hdr *)(reply_buf + ip_hdr_len);
-    if ((data_size = data->ops->parse_icmp_hdr( data, icmp_hdr, recvd - ip_hdr_len, reply )) < 0) goto skip;
-    reply->data_size = data_size;
-    if (reply->data_size && msg.msg_flags & MSG_TRUNC)
+    if ((ctx.data_size = data->ops->parse_icmp_hdr( data, icmp_hdr, recvd - ip_hdr_len, &ctx )) < 0) goto skip;
+    if (ctx.data_size && msg.msg_flags & MSG_TRUNC)
     {
         free( reply_buf );
-        return set_reply_ip_status( params, IP_GENERAL_FAILURE );
+        return data->ops->set_reply_ip_status( params, IP_GENERAL_FAILURE );
     }
 
-    sockaddr_to_SOCKADDR_INET( (struct sockaddr *)&addr, &reply->addr );
-    reply->round_trip_time = get_rtt( data->send_time );
-    reply->num_of_pkts = 1;
-    reply->opts.options_offset = sizeof(*reply);
-    reply->data_offset = sizeof(*reply) + ((reply->opts.options_size + 3) & ~3);
-    if (reply->opts.options_size)
-        memcpy( (char *)reply + reply->opts.options_offset, opts, reply->opts.options_size );
-    if (reply->opts.options_size & 3)
-        memset( (char *)reply + reply->opts.options_offset + reply->opts.options_size, 0, 4 - (reply->opts.options_size & 3) );
-    if (reply->data_size)
-        memcpy( (char *)reply + reply->data_offset, icmp_hdr + 1, reply->data_size );
-
-    params->reply_len = reply->data_offset + reply->data_size;
+    sockaddr_to_SOCKADDR_INET( (struct sockaddr *)&addr, &ctx.addr );
+    ctx.round_trip_time = get_rtt( data->send_time );
+    ctx.data = icmp_hdr + 1;
+
+    data->ops->fill_reply( params, &ctx );
+
     free( reply_buf );
     return STATUS_SUCCESS;
 
@@ -703,10 +770,10 @@ NTSTATUS icmp_listen( void *args )
     if (!ret) /* timeout */
     {
         TRACE( "timeout\n" );
-        return set_reply_ip_status( params, IP_REQ_TIMED_OUT );
+        return data->ops->set_reply_ip_status( params, IP_REQ_TIMED_OUT );
     }
     /* ret < 0 */
-    return set_reply_ip_status( params, errno_to_ip_status( errno ) );
+    return data->ops->set_reply_ip_status( params, errno_to_ip_status( errno ) );
 }
 
 NTSTATUS icmp_cancel_listen( void *args )
diff --git a/dlls/nsiproxy.sys/nsiproxy_private.h b/dlls/nsiproxy.sys/nsiproxy_private.h
index 91dd393..c0b8ca0 100644
--- a/dlls/nsiproxy.sys/nsiproxy_private.h
+++ b/dlls/nsiproxy.sys/nsiproxy_private.h
@@ -21,7 +21,9 @@ struct icmp_listen_params
 {
     HANDLE handle;
     void *reply;
+    ULONGLONG user_reply_ptr;
     unsigned int reply_len;
+    unsigned int bits;
     int timeout;
 };
 
@@ -34,3 +36,40 @@ struct icmp_send_echo_params
     HANDLE handle;
     ULONG ip_status;
 };
+
+/* 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
-- 
2.31.1




More information about the wine-devel mailing list