nsiproxy: Introduce IOCTL_NSIPROXY_WINE_ICMP_ECHO.

With this patch the irp is simply marked as pending and transferred to
the request thread which completes the irp with STATUS_NOT_SUPPORTED.

Signed-off-by: Huw Davies <huw@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Huw Davies 2021-10-04 12:23:20 +01:00 committed by Alexandre Julliard
parent 7ed25b6c16
commit f59a64144b
2 changed files with 137 additions and 0 deletions

View File

@ -36,6 +36,18 @@
WINE_DEFAULT_DEBUG_CHANNEL(nsi);
static unixlib_handle_t nsiproxy_handle;
static HANDLE request_event;
#define DECLARE_CRITICAL_SECTION(cs) \
static CRITICAL_SECTION cs; \
static CRITICAL_SECTION_DEBUG cs##_debug = \
{ 0, 0, &cs, { &cs##_debug.ProcessLocksList, &cs##_debug.ProcessLocksList }, \
0, 0, { (DWORD_PTR)(__FILE__ ": " # cs) }}; \
static CRITICAL_SECTION cs = { &cs##_debug, -1, 0, 0, 0, 0 };
DECLARE_CRITICAL_SECTION( nsiproxy_cs );
#define LIST_ENTRY_INIT( list ) { .Flink = &(list), .Blink = &(list) }
static LIST_ENTRY request_queue = LIST_ENTRY_INIT( request_queue );
static NTSTATUS nsiproxy_call( unsigned int code, void *args )
{
@ -162,6 +174,59 @@ static NTSTATUS nsiproxy_get_parameter( IRP *irp )
return status;
}
static void WINAPI icmp_echo_cancel( DEVICE_OBJECT *device, IRP *irp )
{
TRACE( "device %p, irp %p.\n", device, irp );
IoReleaseCancelSpinLock( irp->CancelIrql );
/* FIXME: at the moment just let the request thread bail */
return;
}
static NTSTATUS nsiproxy_icmp_echo( IRP *irp )
{
IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
struct nsiproxy_icmp_echo *in = (struct nsiproxy_icmp_echo *)irp->AssociatedIrp.SystemBuffer;
DWORD in_len = irpsp->Parameters.DeviceIoControl.InputBufferLength;
DWORD out_len = irpsp->Parameters.DeviceIoControl.OutputBufferLength;
TRACE( "\n" );
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))
return STATUS_INVALID_PARAMETER;
switch (in->dst.si_family)
{
case AF_INET:
if (in->dst.Ipv4.sin_addr.s_addr == INADDR_ANY) return STATUS_INVALID_ADDRESS_WILDCARD;
break;
default:
return STATUS_INVALID_PARAMETER;
}
EnterCriticalSection( &nsiproxy_cs );
IoSetCancelRoutine( irp, icmp_echo_cancel );
if (irp->Cancel && !IoSetCancelRoutine( irp, NULL ))
{
/* IRP was canceled before we set cancel routine */
InitializeListHead( &irp->Tail.Overlay.ListEntry );
LeaveCriticalSection( &nsiproxy_cs );
return STATUS_CANCELLED;
}
InsertTailList( &request_queue, &irp->Tail.Overlay.ListEntry );
IoMarkIrpPending( irp );
LeaveCriticalSection( &nsiproxy_cs );
SetEvent( request_event );
return STATUS_PENDING;
}
static NTSTATUS WINAPI nsi_ioctl( DEVICE_OBJECT *device, IRP *irp )
{
IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
@ -186,6 +251,10 @@ static NTSTATUS WINAPI nsi_ioctl( DEVICE_OBJECT *device, IRP *irp )
status = nsiproxy_get_parameter( irp );
break;
case IOCTL_NSIPROXY_WINE_ICMP_ECHO:
status = nsiproxy_icmp_echo( irp );
break;
default:
FIXME( "ioctl %x not supported\n", irpsp->Parameters.DeviceIoControl.IoControlCode );
status = STATUS_NOT_SUPPORTED;
@ -220,10 +289,40 @@ static int add_device( DRIVER_OBJECT *driver )
return 1;
}
static DWORD WINAPI request_thread_proc( void *arg )
{
LIST_ENTRY *entry;
while (WaitForSingleObject( request_event, INFINITE ) == WAIT_OBJECT_0)
{
TRACE( "request_event triggered\n" );
EnterCriticalSection( &nsiproxy_cs );
while ((entry = RemoveHeadList( &request_queue )) != &request_queue )
{
IRP *irp = CONTAINING_RECORD( entry, IRP, Tail.Overlay.ListEntry );
if (irp->Cancel)
{
irp->IoStatus.Status = STATUS_CANCELLED;
TRACE( "already cancelled\n" );
IoCompleteRequest( irp, IO_NO_INCREMENT );
continue;
}
/* FIXME */
irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
IoCompleteRequest( irp, IO_NO_INCREMENT );
}
LeaveCriticalSection( &nsiproxy_cs );
}
return 0;
}
NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path )
{
HMODULE instance;
NTSTATUS status;
HANDLE thread;
TRACE( "(%p, %s)\n", driver, debugstr_w( path->Buffer ) );
@ -236,5 +335,9 @@ NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path )
add_device( driver );
request_event = CreateEventW( NULL, FALSE, FALSE, NULL );
thread = CreateThread( NULL, 0, request_thread_proc, NULL, 0, NULL );
CloseHandle( thread );
return STATUS_SUCCESS;
}

View File

@ -380,6 +380,7 @@ struct nsi_udp_endpoint_static
#define IOCTL_NSIPROXY_WINE_ENUMERATE_ALL CTL_CODE(FILE_DEVICE_NETWORK, 0x400, METHOD_BUFFERED, 0)
#define IOCTL_NSIPROXY_WINE_GET_ALL_PARAMETERS CTL_CODE(FILE_DEVICE_NETWORK, 0x401, METHOD_BUFFERED, 0)
#define IOCTL_NSIPROXY_WINE_GET_PARAMETER CTL_CODE(FILE_DEVICE_NETWORK, 0x402, METHOD_BUFFERED, 0)
#define IOCTL_NSIPROXY_WINE_ICMP_ECHO CTL_CODE(FILE_DEVICE_NETWORK, 0x403, METHOD_BUFFERED, 0)
/* input for IOCTL_NSIPROXY_WINE_ENUMERATE_ALL */
struct nsiproxy_enumerate_all
@ -420,6 +421,39 @@ struct nsiproxy_get_parameter
BYTE key[1]; /* key_size */
};
/* input for IOCTL_NSIPROXY_WINE_ICMP_ECHO */
struct nsiproxy_icmp_echo
{
SOCKADDR_INET src;
SOCKADDR_INET dst;
BYTE ttl;
BYTE tos;
BYTE flags;
DWORD opt_size;
DWORD req_size;
DWORD timeout;
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