1
0
mirror of https://github.com/wine-mirror/wine synced 2024-07-08 03:45:57 +00:00

nsi: Forward request to nsiproxy from NsiRequestChangeNotification().

This commit is contained in:
Paul Gofman 2023-07-25 19:26:18 -06:00 committed by Alexandre Julliard
parent dbe9f348d4
commit a72f91f5f5
4 changed files with 108 additions and 16 deletions

View File

@ -31,6 +31,7 @@
WINE_DEFAULT_DEBUG_CHANNEL(nsi);
static HANDLE nsi_device = INVALID_HANDLE_VALUE;
static HANDLE nsi_device_async = INVALID_HANDLE_VALUE;
BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, void *reserved)
{
@ -41,23 +42,26 @@ BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, void *reserved)
break;
case DLL_PROCESS_DETACH:
if (nsi_device != INVALID_HANDLE_VALUE) CloseHandle( nsi_device );
if (nsi_device_async != INVALID_HANDLE_VALUE) CloseHandle( nsi_device_async );
break;
}
return TRUE;
}
static inline HANDLE get_nsi_device( void )
static inline HANDLE get_nsi_device( BOOL async )
{
HANDLE *cached_device = async ? &nsi_device_async : &nsi_device;
HANDLE device;
if (nsi_device == INVALID_HANDLE_VALUE)
if (*cached_device == INVALID_HANDLE_VALUE)
{
device = CreateFileW( L"\\\\.\\Nsi", 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
device = CreateFileW( L"\\\\.\\Nsi", 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
async ? FILE_FLAG_OVERLAPPED : 0, NULL );
if (device != INVALID_HANDLE_VALUE
&& InterlockedCompareExchangePointer( &nsi_device, device, INVALID_HANDLE_VALUE ) != INVALID_HANDLE_VALUE)
&& InterlockedCompareExchangePointer( cached_device, device, INVALID_HANDLE_VALUE ) != INVALID_HANDLE_VALUE)
CloseHandle( device );
}
return nsi_device;
return *cached_device;
}
DWORD WINAPI NsiAllocateAndGetTable( DWORD unk, const NPI_MODULEID *module, DWORD table, void **key_data, DWORD key_size,
@ -155,7 +159,7 @@ DWORD WINAPI NsiEnumerateObjectsAllParameters( DWORD unk, DWORD unk2, const NPI_
DWORD WINAPI NsiEnumerateObjectsAllParametersEx( struct nsi_enumerate_all_ex *params )
{
DWORD out_size, received, err = ERROR_SUCCESS;
HANDLE device = get_nsi_device();
HANDLE device = get_nsi_device( FALSE );
struct nsiproxy_enumerate_all in;
BYTE *out, *ptr;
@ -235,7 +239,7 @@ DWORD WINAPI NsiGetAllParameters( DWORD unk, const NPI_MODULEID *module, DWORD t
DWORD WINAPI NsiGetAllParametersEx( struct nsi_get_all_parameters_ex *params )
{
HANDLE device = get_nsi_device();
HANDLE device = get_nsi_device( FALSE );
struct nsiproxy_get_all_parameters *in;
ULONG in_size = FIELD_OFFSET( struct nsiproxy_get_all_parameters, key[params->key_size] ), received;
ULONG out_size = params->rw_size + params->dynamic_size + params->static_size;
@ -304,7 +308,7 @@ DWORD WINAPI NsiGetParameter( DWORD unk, const NPI_MODULEID *module, DWORD table
DWORD WINAPI NsiGetParameterEx( struct nsi_get_parameter_ex *params )
{
HANDLE device = get_nsi_device();
HANDLE device = get_nsi_device( FALSE );
struct nsiproxy_get_parameter *in;
ULONG in_size = FIELD_OFFSET( struct nsiproxy_get_parameter, key[params->key_size] ), received;
DWORD err = ERROR_SUCCESS;
@ -345,7 +349,40 @@ DWORD WINAPI NsiRequestChangeNotification( DWORD unk, const NPI_MODULEID *module
DWORD WINAPI NsiRequestChangeNotificationEx( struct nsi_request_change_notification_ex *params )
{
FIXME( "%p stub.\n", params );
HANDLE device = get_nsi_device( TRUE );
struct nsiproxy_request_notification *in;
ULONG in_size = sizeof(struct nsiproxy_get_parameter), received;
OVERLAPPED overlapped, *ovr;
DWORD err = ERROR_SUCCESS;
DWORD len;
return ERROR_NOT_SUPPORTED;
TRACE( "%p.\n", params );
if (params->unk) FIXME( "unknown parameter %#lx.\n", params->unk );
if (device == INVALID_HANDLE_VALUE) return GetLastError();
in = malloc( in_size );
if (!in) return ERROR_OUTOFMEMORY;
in->module = *params->module;
in->table = params->table;
if (!(ovr = params->ovr))
{
overlapped.hEvent = CreateEventW( NULL, FALSE, FALSE, NULL );
ovr = &overlapped;
}
if (!DeviceIoControl( device, IOCTL_NSIPROXY_WINE_CHANGE_NOTIFICATION, in, in_size, NULL, 0, &received, ovr ))
err = GetLastError();
if (ovr == &overlapped)
{
if (err == ERROR_IO_PENDING)
err = GetOverlappedResult( device, ovr, &len, TRUE ) ? 0 : GetLastError();
CloseHandle( overlapped.hEvent );
}
else if (params->handle && ovr && err == ERROR_IO_PENDING)
*params->handle = device;
free( in );
return err;
}

View File

@ -1039,7 +1039,7 @@ void test_change_notifications(void)
handle = (HANDLE)0xdeadbeef;
ret = NsiRequestChangeNotification( 0, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, &ovr, &handle );
todo_wine ok( ret == ERROR_IO_PENDING, "got %lu.\n", ret );
ok( ret == ERROR_IO_PENDING, "got %lu.\n", ret );
memset( &params, 0, sizeof(params) );
handle2 = (HANDLE)0xdeadbeef;
@ -1049,11 +1049,11 @@ void test_change_notifications(void)
params.ovr = &ovr2;
params.handle = &handle2;
ret = NsiRequestChangeNotificationEx( &params );
todo_wine ok( ret == ERROR_IO_PENDING, "got %lu.\n", ret );
ok( ret == ERROR_IO_PENDING, "got %lu.\n", ret );
ok( handle2 == handle, "got %p, %p.\n", handle, handle2 );
bret = GetOverlappedResult( handle, &ovr, &bytes, FALSE );
todo_wine ok( !bret && GetLastError() == ERROR_IO_INCOMPLETE, "got bret %d, err %lu.\n", bret, GetLastError() );
ok( !bret && GetLastError() == ERROR_IO_INCOMPLETE, "got bret %d, err %lu.\n", bret, GetLastError() );
ret = NsiCancelChangeNotification( NULL );
todo_wine ok( ret == ERROR_NOT_FOUND, "got %lu.\n", ret );
@ -1063,12 +1063,13 @@ void test_change_notifications(void)
bytes = 0xdeadbeef;
bret = GetOverlappedResult( handle, &ovr, &bytes, FALSE );
todo_wine ok( !bret && GetLastError() == ERROR_OPERATION_ABORTED, "got bret %d, err %lu.\n", bret, GetLastError() );
todo_wine ok( ovr.Internal == (ULONG)STATUS_CANCELLED, "got %Ix.\n", ovr.Internal );
ok( !bytes, "got %lu.\n", bytes );
todo_wine ok( !bytes, "got %lu.\n", bytes );
bret = GetOverlappedResult( handle2, &ovr2, &bytes, FALSE );
todo_wine ok( !bret && GetLastError() == ERROR_IO_INCOMPLETE, "got bret %d, err %lu.\n", bret, GetLastError() );
ok( !bret && GetLastError() == ERROR_IO_INCOMPLETE, "got bret %d, err %lu.\n", bret, GetLastError() );
ret = NsiCancelChangeNotification( &ovr2 );
todo_wine ok( !ret, "got %lu.\n", ret );
bret = GetOverlappedResult( handle, &ovr, &bytes, FALSE );
@ -1078,7 +1079,7 @@ void test_change_notifications(void)
todo_wine ok( ret == ERROR_INVALID_PARAMETER, "got %lu.\n", ret );
ret = NsiRequestChangeNotification( 0, &NPI_MS_IPV4_MODULEID, NSI_IP_FORWARD_TABLE, &ovr, &handle );
todo_wine ok( ret == ERROR_IO_PENDING, "got %lu.\n", ret );
ok( ret == ERROR_IO_PENDING, "got %lu.\n", ret );
ret = NsiCancelChangeNotification( &ovr );
todo_wine ok( !ret, "got %lu.\n", ret );
bret = GetOverlappedResult( handle, &ovr, &bytes, FALSE );

View File

@ -49,6 +49,7 @@ 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 LIST_ENTRY notification_queue = LIST_ENTRY_INIT( notification_queue );
static NTSTATUS nsiproxy_call( unsigned int code, void *args )
{
@ -261,6 +262,47 @@ static NTSTATUS nsiproxy_icmp_echo( IRP *irp )
return STATUS_PENDING;
}
static void WINAPI change_notification_cancel( DEVICE_OBJECT *device, IRP *irp )
{
TRACE( "device %p, irp %p.\n", device, irp );
IoReleaseCancelSpinLock( irp->CancelIrql );
EnterCriticalSection( &nsiproxy_cs );
RemoveEntryList( &irp->Tail.Overlay.ListEntry );
LeaveCriticalSection( &nsiproxy_cs );
irp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest( irp, IO_NO_INCREMENT );
}
static NTSTATUS nsiproxy_change_notification( IRP *irp )
{
IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
struct nsiproxy_request_notification *in = (struct nsiproxy_request_notification *)irp->AssociatedIrp.SystemBuffer;
DWORD in_len = irpsp->Parameters.DeviceIoControl.InputBufferLength;
FIXME( "\n" );
if (in_len < sizeof(*in)) return STATUS_INVALID_PARAMETER;
/* FIXME: validate module and table. */
EnterCriticalSection( &nsiproxy_cs );
IoSetCancelRoutine( irp, change_notification_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( &notification_queue, &irp->Tail.Overlay.ListEntry );
IoMarkIrpPending( irp );
LeaveCriticalSection( &nsiproxy_cs );
return STATUS_PENDING;
}
static NTSTATUS WINAPI nsi_ioctl( DEVICE_OBJECT *device, IRP *irp )
{
IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
@ -289,6 +331,10 @@ static NTSTATUS WINAPI nsi_ioctl( DEVICE_OBJECT *device, IRP *irp )
status = nsiproxy_icmp_echo( irp );
break;
case IOCTL_NSIPROXY_WINE_CHANGE_NOTIFICATION:
status = nsiproxy_change_notification( irp );
break;
default:
FIXME( "ioctl %lx not supported\n", irpsp->Parameters.DeviceIoControl.IoControlCode );
status = STATUS_NOT_SUPPORTED;

View File

@ -380,6 +380,7 @@ struct nsi_udp_endpoint_static
#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)
#define IOCTL_NSIPROXY_WINE_CHANGE_NOTIFICATION CTL_CODE(FILE_DEVICE_NETWORK, 0x404, METHOD_BUFFERED, 0)
/* input for IOCTL_NSIPROXY_WINE_ENUMERATE_ALL */
struct nsiproxy_enumerate_all
@ -436,6 +437,13 @@ struct nsiproxy_icmp_echo
BYTE data[1]; /* ((opt_size + 3) & ~3) + req_size */
};
/* input for IOCTL_NSIPROXY_WINE_CHANGE_NOTIFICATION */
struct nsiproxy_request_notification
{
NPI_MODULEID module;
UINT table;
};
/* Undocumented Nsi api */
#define NSI_PARAM_TYPE_RW 0