d3d11: Remove null dxgi object checks.
[wine.git] / dlls / nsiproxy.sys / device.c
blobd3845829a85a66ffdae7ef9ca9b04cf6581474da
1 /*
2 * nsiproxy.sys
4 * Copyright 2021 Huw Davies
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #include "ntstatus.h"
24 #define WIN32_NO_STATUS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winternl.h"
28 #include "winioctl.h"
29 #include "ddk/wdm.h"
30 #include "ifdef.h"
31 #include "netiodef.h"
32 #include "wine/nsi.h"
33 #include "wine/debug.h"
34 #include "wine/unixlib.h"
36 #include "nsiproxy_private.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(nsi);
40 static unixlib_handle_t nsiproxy_handle;
41 static HANDLE request_event;
43 #define DECLARE_CRITICAL_SECTION(cs) \
44 static CRITICAL_SECTION cs; \
45 static CRITICAL_SECTION_DEBUG cs##_debug = \
46 { 0, 0, &cs, { &cs##_debug.ProcessLocksList, &cs##_debug.ProcessLocksList }, \
47 0, 0, { (DWORD_PTR)(__FILE__ ": " # cs) }}; \
48 static CRITICAL_SECTION cs = { &cs##_debug, -1, 0, 0, 0, 0 };
49 DECLARE_CRITICAL_SECTION( nsiproxy_cs );
51 #define LIST_ENTRY_INIT( list ) { .Flink = &(list), .Blink = &(list) }
52 static LIST_ENTRY request_queue = LIST_ENTRY_INIT( request_queue );
54 static NTSTATUS nsiproxy_call( unsigned int code, void *args )
56 return __wine_unix_call( nsiproxy_handle, code, args );
59 enum unix_calls
61 icmp_cancel_listen,
62 icmp_close,
63 icmp_listen,
64 icmp_send_echo,
65 nsi_enumerate_all_ex,
66 nsi_get_all_parameters_ex,
67 nsi_get_parameter_ex,
70 static NTSTATUS nsiproxy_enumerate_all( IRP *irp )
72 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
73 struct nsiproxy_enumerate_all *in = (struct nsiproxy_enumerate_all *)irp->AssociatedIrp.SystemBuffer;
74 DWORD in_len = irpsp->Parameters.DeviceIoControl.InputBufferLength;
75 void *out = irp->AssociatedIrp.SystemBuffer;
76 DWORD out_len = irpsp->Parameters.DeviceIoControl.OutputBufferLength;
77 struct nsi_enumerate_all_ex enum_all;
78 NTSTATUS status;
80 if (in_len != sizeof(*in)) return STATUS_INVALID_PARAMETER;
82 if (out_len < sizeof(UINT) + (in->key_size + in->rw_size + in->dynamic_size + in->static_size) * in->count)
83 return STATUS_INVALID_PARAMETER;
85 enum_all.unknown[0] = 0;
86 enum_all.unknown[1] = 0;
87 enum_all.first_arg = in->first_arg;
88 enum_all.second_arg = in->second_arg;
89 enum_all.module = &in->module;
90 enum_all.table = in->table;
91 enum_all.key_data = (BYTE *)out + sizeof(UINT);
92 enum_all.key_size = in->key_size;
93 enum_all.rw_data = (BYTE *)enum_all.key_data + in->key_size * in->count;
94 enum_all.rw_size = in->rw_size;
95 enum_all.dynamic_data = (BYTE *)enum_all.rw_data + in->rw_size * in->count;
96 enum_all.dynamic_size = in->dynamic_size;
97 enum_all.static_data = (BYTE *)enum_all.dynamic_data + in->dynamic_size * in->count;
98 enum_all.static_size = in->static_size;
99 enum_all.count = in->count;
101 status = nsiproxy_call( nsi_enumerate_all_ex, &enum_all );
102 if (status == STATUS_SUCCESS || status == STATUS_BUFFER_OVERFLOW)
104 irp->IoStatus.Information = out_len;
105 *(UINT *)out = enum_all.count;
107 else irp->IoStatus.Information = 0;
109 return status;
112 static NTSTATUS nsiproxy_get_all_parameters( IRP *irp )
114 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
115 struct nsiproxy_get_all_parameters *in = (struct nsiproxy_get_all_parameters *)irp->AssociatedIrp.SystemBuffer;
116 DWORD in_len = irpsp->Parameters.DeviceIoControl.InputBufferLength;
117 BYTE *out = irp->AssociatedIrp.SystemBuffer;
118 DWORD out_len = irpsp->Parameters.DeviceIoControl.OutputBufferLength;
119 struct nsi_get_all_parameters_ex get_all;
120 NTSTATUS status;
122 if (in_len < offsetof(struct nsiproxy_get_all_parameters, key[0]) ||
123 in_len < offsetof(struct nsiproxy_get_all_parameters, key[in->key_size]))
124 return STATUS_INVALID_PARAMETER;
126 if (out_len < in->rw_size + in->dynamic_size + in->static_size)
127 return STATUS_INVALID_PARAMETER;
129 get_all.unknown[0] = 0;
130 get_all.unknown[1] = 0;
131 get_all.first_arg = in->first_arg;
132 get_all.unknown2 = 0;
133 get_all.module = &in->module;
134 get_all.table = in->table;
135 get_all.key = in->key;
136 get_all.key_size = in->key_size;
137 get_all.rw_data = out;
138 get_all.rw_size = in->rw_size;
139 get_all.dynamic_data = out + in->rw_size;
140 get_all.dynamic_size = in->dynamic_size;
141 get_all.static_data = out + in->rw_size + in->dynamic_size;
142 get_all.static_size = in->static_size;
144 status = nsiproxy_call( nsi_get_all_parameters_ex, &get_all );
145 irp->IoStatus.Information = (status == STATUS_SUCCESS) ? out_len : 0;
147 return status;
150 static NTSTATUS nsiproxy_get_parameter( IRP *irp )
152 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
153 struct nsiproxy_get_parameter *in = (struct nsiproxy_get_parameter *)irp->AssociatedIrp.SystemBuffer;
154 DWORD in_len = irpsp->Parameters.DeviceIoControl.InputBufferLength;
155 void *out = irp->AssociatedIrp.SystemBuffer;
156 DWORD out_len = irpsp->Parameters.DeviceIoControl.OutputBufferLength;
157 struct nsi_get_parameter_ex get_param;
158 NTSTATUS status;
160 if (in_len < offsetof(struct nsiproxy_get_parameter, key[0]) ||
161 in_len < offsetof(struct nsiproxy_get_parameter, key[in->key_size]))
162 return STATUS_INVALID_PARAMETER;
164 get_param.unknown[0] = 0;
165 get_param.unknown[1] = 0;
166 get_param.first_arg = in->first_arg;
167 get_param.unknown2 = 0;
168 get_param.module = &in->module;
169 get_param.table = in->table;
170 get_param.key = in->key;
171 get_param.key_size = in->key_size;
172 get_param.param_type = in->param_type;
173 get_param.data = out;
174 get_param.data_size = out_len;
175 get_param.data_offset = in->data_offset;
177 status = nsiproxy_call( nsi_get_parameter_ex, &get_param );
178 irp->IoStatus.Information = (status == STATUS_SUCCESS) ? out_len : 0;
180 return status;
183 static inline HANDLE irp_get_icmp_handle( IRP *irp )
185 return irp->Tail.Overlay.DriverContext[0];
188 static inline HANDLE irp_set_icmp_handle( IRP *irp, HANDLE handle )
190 return InterlockedExchangePointer( irp->Tail.Overlay.DriverContext, handle );
193 static void WINAPI icmp_echo_cancel( DEVICE_OBJECT *device, IRP *irp )
195 HANDLE handle;
197 TRACE( "device %p, irp %p.\n", device, irp );
199 IoReleaseCancelSpinLock( irp->CancelIrql );
201 EnterCriticalSection( &nsiproxy_cs );
203 /* If the handle is not set, either the irp is still
204 in the request queue, in which case the request thread will
205 cancel it, or the irp has already finished. If the handle
206 does exist then notify the listen thread. In all cases the irp
207 will be completed elsewhere. */
208 handle = irp_get_icmp_handle( irp );
209 if (handle) nsiproxy_call( icmp_cancel_listen, handle );
211 LeaveCriticalSection( &nsiproxy_cs );
214 static int icmp_echo_reply_struct_len( ULONG family, ULONG bits )
216 if (family == AF_INET)
217 return (bits == 32) ? sizeof(struct icmp_echo_reply_32) : sizeof(struct icmp_echo_reply_64);
218 return 0;
221 static NTSTATUS nsiproxy_icmp_echo( IRP *irp )
223 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
224 struct nsiproxy_icmp_echo *in = (struct nsiproxy_icmp_echo *)irp->AssociatedIrp.SystemBuffer;
225 DWORD in_len = irpsp->Parameters.DeviceIoControl.InputBufferLength;
226 DWORD out_len = irpsp->Parameters.DeviceIoControl.OutputBufferLength;
228 TRACE( "\n" );
230 if (in_len < offsetof(struct nsiproxy_icmp_echo, data[0]) ||
231 in_len < offsetof(struct nsiproxy_icmp_echo, data[((in->opt_size + 3) & ~3) + in->req_size]) ||
232 out_len < icmp_echo_reply_struct_len( in->dst.si_family, in->bits ))
233 return STATUS_INVALID_PARAMETER;
235 switch (in->dst.si_family)
237 case AF_INET:
238 if (in->dst.Ipv4.sin_addr.s_addr == INADDR_ANY) return STATUS_INVALID_ADDRESS_WILDCARD;
239 break;
240 default:
241 return STATUS_INVALID_PARAMETER;
244 EnterCriticalSection( &nsiproxy_cs );
246 IoSetCancelRoutine( irp, icmp_echo_cancel );
247 if (irp->Cancel && !IoSetCancelRoutine( irp, NULL ))
249 /* IRP was canceled before we set cancel routine */
250 InitializeListHead( &irp->Tail.Overlay.ListEntry );
251 LeaveCriticalSection( &nsiproxy_cs );
252 return STATUS_CANCELLED;
255 InsertTailList( &request_queue, &irp->Tail.Overlay.ListEntry );
256 IoMarkIrpPending( irp );
258 LeaveCriticalSection( &nsiproxy_cs );
259 SetEvent( request_event );
261 return STATUS_PENDING;
264 static NTSTATUS WINAPI nsi_ioctl( DEVICE_OBJECT *device, IRP *irp )
266 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
267 NTSTATUS status;
269 TRACE( "ioctl %lx insize %lu outsize %lu\n",
270 irpsp->Parameters.DeviceIoControl.IoControlCode,
271 irpsp->Parameters.DeviceIoControl.InputBufferLength,
272 irpsp->Parameters.DeviceIoControl.OutputBufferLength );
274 switch (irpsp->Parameters.DeviceIoControl.IoControlCode)
276 case IOCTL_NSIPROXY_WINE_ENUMERATE_ALL:
277 status = nsiproxy_enumerate_all( irp );
278 break;
280 case IOCTL_NSIPROXY_WINE_GET_ALL_PARAMETERS:
281 status = nsiproxy_get_all_parameters( irp );
282 break;
284 case IOCTL_NSIPROXY_WINE_GET_PARAMETER:
285 status = nsiproxy_get_parameter( irp );
286 break;
288 case IOCTL_NSIPROXY_WINE_ICMP_ECHO:
289 status = nsiproxy_icmp_echo( irp );
290 break;
292 default:
293 FIXME( "ioctl %lx not supported\n", irpsp->Parameters.DeviceIoControl.IoControlCode );
294 status = STATUS_NOT_SUPPORTED;
295 break;
298 if (status != STATUS_PENDING)
300 irp->IoStatus.Status = status;
301 IoCompleteRequest( irp, IO_NO_INCREMENT );
303 return status;
306 static int add_device( DRIVER_OBJECT *driver )
308 UNICODE_STRING name, link;
309 DEVICE_OBJECT *device;
310 NTSTATUS status;
312 RtlInitUnicodeString( &name, L"\\Device\\Nsi" );
313 RtlInitUnicodeString( &link, L"\\??\\Nsi" );
315 if (!(status = IoCreateDevice( driver, 0, &name, FILE_DEVICE_NETWORK, FILE_DEVICE_SECURE_OPEN, FALSE, &device )))
316 status = IoCreateSymbolicLink( &link, &name );
317 if (status)
319 FIXME( "failed to create device error %lx\n", status );
320 return 0;
323 return 1;
326 static DWORD WINAPI listen_thread_proc( void *arg )
328 IRP *irp = arg;
329 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
330 struct nsiproxy_icmp_echo *in = irp->AssociatedIrp.SystemBuffer;
331 struct icmp_listen_params params;
332 NTSTATUS status;
334 TRACE( "\n" );
336 params.user_reply_ptr = in->user_reply_ptr;
337 params.handle = irp_get_icmp_handle( irp );
338 params.timeout = in->timeout;
339 params.bits = in->bits;
340 params.reply = irp->AssociatedIrp.SystemBuffer;
341 params.reply_len = irpsp->Parameters.DeviceIoControl.OutputBufferLength;
343 status = nsiproxy_call( icmp_listen, &params );
344 TRACE( "icmp_listen rets %08lx\n", status );
346 EnterCriticalSection( &nsiproxy_cs );
348 nsiproxy_call( icmp_close, irp_set_icmp_handle( irp, NULL ) );
350 irp->IoStatus.Status = status;
351 if (status == STATUS_SUCCESS)
352 irp->IoStatus.Information = params.reply_len;
353 else
354 irp->IoStatus.Information = 0;
355 IoCompleteRequest( irp, IO_NO_INCREMENT );
357 LeaveCriticalSection( &nsiproxy_cs );
359 return 0;
362 static void handle_queued_send_echo( IRP *irp )
364 struct nsiproxy_icmp_echo *in = (struct nsiproxy_icmp_echo *)irp->AssociatedIrp.SystemBuffer;
365 struct icmp_send_echo_params params;
366 NTSTATUS status;
368 TRACE( "\n" );
369 params.request = in->data + ((in->opt_size + 3) & ~3);
370 params.request_size = in->req_size;
371 params.reply = irp->AssociatedIrp.SystemBuffer;
372 params.bits = in->bits;
373 params.ttl = in->ttl;
374 params.tos = in->tos;
375 params.dst = &in->dst;
377 status = nsiproxy_call( icmp_send_echo, &params );
378 TRACE( "icmp_send_echo rets %08lx\n", status );
380 if (status != STATUS_PENDING)
382 irp->IoStatus.Status = status;
383 if (status == STATUS_SUCCESS)
384 irp->IoStatus.Information = params.reply_len;
385 IoCompleteRequest( irp, IO_NO_INCREMENT );
387 else
389 irp_set_icmp_handle( irp, params.handle );
390 RtlQueueWorkItem( listen_thread_proc, irp, WT_EXECUTELONGFUNCTION );
394 static DWORD WINAPI request_thread_proc( void *arg )
396 LIST_ENTRY *entry;
398 while (WaitForSingleObject( request_event, INFINITE ) == WAIT_OBJECT_0)
400 TRACE( "request_event triggered\n" );
401 EnterCriticalSection( &nsiproxy_cs );
402 while ((entry = RemoveHeadList( &request_queue )) != &request_queue )
404 IRP *irp = CONTAINING_RECORD( entry, IRP, Tail.Overlay.ListEntry );
406 if (irp->Cancel)
408 irp->IoStatus.Status = STATUS_CANCELLED;
409 TRACE( "already cancelled\n" );
410 IoCompleteRequest( irp, IO_NO_INCREMENT );
411 continue;
414 handle_queued_send_echo( irp );
416 LeaveCriticalSection( &nsiproxy_cs );
418 return 0;
421 NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path )
423 HMODULE instance;
424 NTSTATUS status;
425 HANDLE thread;
427 TRACE( "(%p, %s)\n", driver, debugstr_w( path->Buffer ) );
429 RtlPcToFileHeader( &DriverEntry, (void *)&instance );
430 status = NtQueryVirtualMemory( GetCurrentProcess(), instance, MemoryWineUnixFuncs,
431 &nsiproxy_handle, sizeof(nsiproxy_handle), NULL );
432 if (status) return status;
434 driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = nsi_ioctl;
436 add_device( driver );
438 request_event = CreateEventW( NULL, FALSE, FALSE, NULL );
439 thread = CreateThread( NULL, 0, request_thread_proc, NULL, 0, NULL );
440 CloseHandle( thread );
442 return STATUS_SUCCESS;