2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/wmidrv.c
5 * PURPOSE: I/O Windows Management Instrumentation (WMI) Support
6 * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org)
9 /* INCLUDES *****************************************************************/
19 // FIXME: these should go to a shared header
20 typedef struct _WMIP_REGISTER_GUIDS
22 POBJECT_ATTRIBUTES ObjectAttributes
;
30 } WMIP_REGISTER_GUIDS
, *PWMIP_REGISTER_GUIDS
;
32 typedef struct _WMIP_RESULT
36 TRACEHANDLE TraceHandle
;
38 } WMIP_RESULT
, *PWMIP_RESULT
;
40 typedef struct _WMI_UNREGISTER_GUID
47 } WMI_UNREGISTER_GUID
, *PWMI_UNREGISTER_GUID
;
49 typedef struct _WMI_GUID_OBJECT_ENTRY
53 } WMI_GUID_OBJECT_ENTRY
, *PWMI_GUID_OBJECT_ENTRY
;
55 typedef struct _WMI_NOTIFICATION
57 ULONG NumberOfGuidObjects
;
63 WMI_GUID_OBJECT_ENTRY GuidObjects
[0];
64 } WMI_NOTIFICATION
, *PWMI_NOTIFICATION
;
66 PDEVICE_OBJECT WmipServiceDeviceObject
;
67 PDEVICE_OBJECT WmipAdminDeviceObject
;
68 FAST_IO_DISPATCH WmipFastIoDispatch
;
71 /* FUNCTIONS *****************************************************************/
73 DRIVER_DISPATCH WmipOpenCloseCleanup
;
74 DRIVER_DISPATCH WmipIoControl
;
75 DRIVER_DISPATCH WmipSystemControl
;
76 DRIVER_DISPATCH WmipShutdown
;
81 _In_ PDEVICE_OBJECT DeviceObject
,
86 /* No work to do, just return success */
87 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
88 Irp
->IoStatus
.Information
= 0;
89 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
90 return STATUS_SUCCESS
;
97 KPROCESSOR_MODE PreviousMode
)
99 UNIMPLEMENTED_DBGBREAK();
100 return STATUS_SUCCESS
;
107 ULONG InputBufferLength
)
109 UNIMPLEMENTED_DBGBREAK();
110 return STATUS_SUCCESS
;
115 WmipCaptureGuidObjectAttributes(
116 _In_ POBJECT_ATTRIBUTES GuidObjectAttributes
,
117 _Out_ POBJECT_ATTRIBUTES CapuredObjectAttributes
,
118 _Out_ PUNICODE_STRING CapturedObjectName
,
119 _Out_ PWSTR ObjectNameBuffer
,
120 _In_ KPROCESSOR_MODE AccessMode
)
122 NT_ASSERT(AccessMode
!= KernelMode
);
126 /* Probe and copy the object attributes structure */
127 ProbeForRead(GuidObjectAttributes
,
128 sizeof(OBJECT_ATTRIBUTES
),
130 *CapuredObjectAttributes
= *GuidObjectAttributes
;
132 /* Probe and copy the object name UNICODE_STRING */
133 ProbeForRead(CapuredObjectAttributes
->ObjectName
,
134 sizeof(UNICODE_STRING
),
136 *CapturedObjectName
= *CapuredObjectAttributes
->ObjectName
;
138 /* Check if the object name has the expected length */
139 if (CapturedObjectName
->Length
!= 45 * sizeof(WCHAR
))
141 return STATUS_INVALID_PARAMETER
;
144 /* Probe and copy the object name buffer */
145 ProbeForRead(CapturedObjectName
->Buffer
,
146 CapturedObjectName
->Length
,
148 RtlCopyMemory(ObjectNameBuffer
,
149 CapturedObjectName
->Buffer
,
150 CapturedObjectName
->Length
);
153 CapturedObjectName
->Buffer
= ObjectNameBuffer
;
154 GuidObjectAttributes
->ObjectName
= CapturedObjectName
;
156 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
158 DPRINT1("Got exception!\n");
159 return _SEH2_GetExceptionCode();
163 return STATUS_SUCCESS
;
169 _In_ PDEVICE_OBJECT DeviceObject
,
171 _In_ ULONG InputLength
,
172 _Inout_ PULONG OutputLength
)
174 PWMIP_REGISTER_GUIDS RegisterGuids
= (PWMIP_REGISTER_GUIDS
)Buffer
;
175 PWMIP_RESULT Result
= (PWMIP_RESULT
)Buffer
;
176 OBJECT_ATTRIBUTES LocalObjectAttributes
;
177 UNICODE_STRING LocalObjectName
;
178 WCHAR LocalObjectNameBuffer
[45 + 1];
179 KPROCESSOR_MODE PreviousMode
;
180 HANDLE GuidObjectHandle
;
184 /* Make sure the input buffer is large enough */
185 if ((InputLength
< sizeof(WMIP_REGISTER_GUIDS
)) ||
186 (RegisterGuids
->RegInfo
.BufferSize
>
187 (InputLength
- FIELD_OFFSET(WMIP_REGISTER_GUIDS
, RegInfo
))))
189 return STATUS_UNSUCCESSFUL
;
192 /* Make sure we have a resonable GUID count */
193 if ((RegisterGuids
->RegInfo
.GuidCount
== 0) ||
194 (RegisterGuids
->RegInfo
.GuidCount
> 0x10000))
196 return STATUS_UNSUCCESSFUL
;
199 /* Capture object attributes */
200 PreviousMode
= ExGetPreviousMode();
201 Status
= WmipCaptureGuidObjectAttributes(RegisterGuids
->ObjectAttributes
,
202 &LocalObjectAttributes
,
204 LocalObjectNameBuffer
,
206 if (!NT_SUCCESS(Status
))
208 DPRINT1("WmipCaptureGuidObjectAttributes failed: 0x%lx\n", Status
);
212 /* Open a new GUID object */
213 Status
= WmipOpenGuidObject(&LocalObjectAttributes
,
218 if (!NT_SUCCESS(Status
))
220 DPRINT1("WmipOpenGuidObject failed: 0x%lx\n", Status
);
224 /* Dereference the GUID object */
225 ObDereferenceObject(GuidObject
);
227 /* Return the handle (user mode will close it) */
228 Result
->Handle
= GuidObjectHandle
;
229 Result
->TraceHandle
= 0;
232 return STATUS_SUCCESS
;
240 _In_ ULONG InputLength
,
241 _Inout_ PULONG OutputLength
)
243 /* For now we have nothing to do */
244 return STATUS_SUCCESS
;
249 WmipClearIrpObjectList(
252 PWMIP_IRP_CONTEXT IrpContext
;
253 PLIST_ENTRY ListEntry
;
254 PWMIP_GUID_OBJECT GuidObject
;
256 /* Get the IRP context */
257 IrpContext
= (PWMIP_IRP_CONTEXT
)Irp
->Tail
.Overlay
.DriverContext
;
259 /* Loop all GUID objects attached to this IRP */
260 for (ListEntry
= IrpContext
->GuidObjectListHead
.Flink
;
261 ListEntry
!= &IrpContext
->GuidObjectListHead
;
262 ListEntry
= ListEntry
->Flink
)
264 /* Get the GUID object */
265 GuidObject
= CONTAINING_RECORD(ListEntry
, WMIP_GUID_OBJECT
, IrpLink
);
267 /* Make sure the IRP matches and clear it */
268 ASSERT(GuidObject
->Irp
== Irp
);
269 GuidObject
->Irp
= NULL
;
271 /* Remove the entry */
272 RemoveEntryList(ListEntry
);
278 WmipNotificationIrpCancel(
279 _In_ PDEVICE_OBJECT DeviceObject
,
283 WmipClearIrpObjectList(Irp
);
285 /* Release the cancel spin lock */
286 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
288 /* Set the status to cancelled and complete the IRP */
289 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
290 Irp
->IoStatus
.Information
= 0;
291 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
296 WmipInitializeIrpContext(
297 PWMIP_IRP_CONTEXT IrpContext
)
299 /* Initialize the list head for GUID objects */
300 InitializeListHead(&IrpContext
->GuidObjectListHead
);
305 WmipReceiveNotifications(
308 _In_ ULONG InputLength
,
309 _Inout_ PULONG OutputLength
)
311 PWMI_NOTIFICATION Notification
;
312 PWMIP_IRP_CONTEXT IrpContext
;
316 if ((InputLength
< sizeof(WMI_NOTIFICATION
)) || (*OutputLength
< 0x38))
318 return STATUS_INVALID_DEVICE_REQUEST
;
321 /// FIXME: For now we don't do any actual work, but simply pretend we are
322 /// waiting for notifications. We won't ever deliver any though.
323 Notification
= (PWMI_NOTIFICATION
)Buffer
;
324 DBG_UNREFERENCED_LOCAL_VARIABLE(Notification
);
327 // reference the object
328 // on failure, fail the whole request
331 // update the irp (synchronization!)
332 // if we had one before complete the old irp with an error
334 /* Get the IRP context and initialize it */
335 IrpContext
= (PWMIP_IRP_CONTEXT
)Irp
->Tail
.Overlay
.DriverContext
;
336 WmipInitializeIrpContext(IrpContext
);
339 // insert the objects into the IRP list
341 /* Set our cancel routine for cleanup */
342 IoSetCancelRoutine(Irp
, WmipNotificationIrpCancel
);
344 /* Check if the IRP is already being cancelled */
345 if (Irp
->Cancel
&& IoSetCancelRoutine(Irp
, NULL
))
347 Status
= STATUS_CANCELLED
;
351 /* Mark the IRP as pending */
352 IoMarkIrpPending(Irp
);
353 Status
= STATUS_PENDING
;
359 typedef struct _WMI_OPEN_GUID_FOR_EVENTS
361 POBJECT_ATTRIBUTES ObjectAttributes
;
362 ACCESS_MASK DesiredAccess
;
365 } WMI_OPEN_GUID_FOR_EVENTS
, *PWMI_OPEN_GUID_FOR_EVENTS
;
367 typedef struct _WMIP_RESULT2
373 } WMIP_RESULT2
, *PWMIP_RESULT2
;
377 WmipOpenGuidForEvents(
382 PWMI_OPEN_GUID_FOR_EVENTS OpenGuidForEvents
= Buffer
;
383 PWMIP_RESULT2 Result
= (PWMIP_RESULT2
)Buffer
;
384 OBJECT_ATTRIBUTES LocalObjectAttributes
;
385 UNICODE_STRING LocalObjectName
;
386 WCHAR LocalObjectNameBuffer
[45 + 1];
387 KPROCESSOR_MODE PreviousMode
;
388 HANDLE GuidObjectHandle
;
392 if ((InputLength
!= sizeof(WMI_OPEN_GUID_FOR_EVENTS
)) ||
393 (*OutputLength
!= sizeof(WMIP_RESULT2
)))
395 return STATUS_UNSUCCESSFUL
;
398 /* Capture object attributes */
399 PreviousMode
= ExGetPreviousMode();
400 Status
= WmipCaptureGuidObjectAttributes(OpenGuidForEvents
->ObjectAttributes
,
401 &LocalObjectAttributes
,
403 LocalObjectNameBuffer
,
405 if (!NT_SUCCESS(Status
))
407 DPRINT1("ProbeAndCaptureGuidObjectAttributes failed: 0x%lx\n", Status
);
411 /* Open a new GUID object */
412 Status
= WmipOpenGuidObject(&LocalObjectAttributes
,
413 OpenGuidForEvents
->DesiredAccess
,
417 if (!NT_SUCCESS(Status
))
419 DPRINT1("WmipOpenGuidObject failed: 0x%lx\n", Status
);
423 Result
->Handle
= GuidObjectHandle
;
425 ObDereferenceObject(GuidObject
);
427 return STATUS_SUCCESS
;
433 _In_ PDEVICE_OBJECT DeviceObject
,
436 PIO_STACK_LOCATION IoStackLocation
;
439 ULONG InputLength
, OutputLength
;
443 /* Get the current stack location */
444 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
446 /* Get the io control parameters */
447 IoControlCode
= IoStackLocation
->Parameters
.DeviceIoControl
.IoControlCode
;
448 Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
449 InputLength
= IoStackLocation
->Parameters
.DeviceIoControl
.InputBufferLength
;
450 OutputLength
= IoStackLocation
->Parameters
.DeviceIoControl
.OutputBufferLength
;
452 switch (IoControlCode
)
455 case IOCTL_WMI_REGISTER_GUIDS
:
457 Status
= WmipRegisterGuids(DeviceObject
,
464 case IOCTL_WMI_UNREGISTER_GUIDS
:
466 Status
= WmipUnregisterGuids(Buffer
,
472 case IOCTL_WMI_RECEIVE_NOTIFICATIONS
:
474 Status
= WmipReceiveNotifications(Irp
,
483 DPRINT1("IOCTL 0x228168 is unimplemented, ignoring\n");
484 Status
= STATUS_SUCCESS
;
488 case IOCTL_WMI_OPEN_GUID_FOR_EVENTS
:
490 Status
= WmipOpenGuidForEvents(Buffer
, InputLength
, &OutputLength
);
495 DPRINT1("Unsupported yet IOCTL: 0x%lx\n", IoControlCode
);
496 Status
= STATUS_INVALID_DEVICE_REQUEST
;
501 if (Status
== STATUS_PENDING
)
504 Irp
->IoStatus
.Status
= Status
;
505 Irp
->IoStatus
.Information
= NT_SUCCESS(Status
) ? OutputLength
: 0;
507 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
514 _Inout_ PDEVICE_OBJECT DeviceObject
,
517 UNIMPLEMENTED_DBGBREAK();
518 return STATUS_NOT_IMPLEMENTED
;
524 _Inout_ PDEVICE_OBJECT DeviceObject
,
527 UNIMPLEMENTED_DBGBREAK();
528 return STATUS_NOT_IMPLEMENTED
;
531 _Function_class_(FAST_IO_DEVICE_CONTROL
)
535 WmipFastIoDeviceControl(
536 _In_ PFILE_OBJECT FileObject
,
538 _In_opt_ PVOID InputBuffer
,
539 _In_ ULONG InputBufferLength
,
540 _Out_opt_ PVOID OutputBuffer
,
541 _In_ ULONG OutputBufferLength
,
542 _In_ ULONG IoControlCode
,
543 _Out_ PIO_STATUS_BLOCK IoStatus
,
544 _In_ PDEVICE_OBJECT DeviceObject
)
548 if (IoControlCode
== IOCTL_WMI_TRACE_EVENT
)
550 if (InputBufferLength
< 0x30)
552 DPRINT1("Buffer too small\n");
556 IoStatus
->Status
= WmiTraceEvent(InputBuffer
, ExGetPreviousMode());
559 else if (IoControlCode
== IOCTL_WMI_TRACE_USER_MESSAGE
)
561 if (InputBufferLength
< 0x30)
563 DPRINT1("Buffer too small\n");
567 IoStatus
->Status
= WmiTraceUserMessage(InputBuffer
, InputBufferLength
);
571 DPRINT1("Invalid io control code for fast dispatch: 0x%lx\n", IoControlCode
);
577 WmipDockUndockEventCallback(
578 _In_ PVOID NotificationStructure
,
579 _Inout_opt_ PVOID Context
)
581 UNIMPLEMENTED_DBGBREAK();
582 return STATUS_NOT_IMPLEMENTED
;
585 _Function_class_(DRIVER_INITIALIZE
)
590 _In_ PDRIVER_OBJECT DriverObject
,
591 _In_ PUNICODE_STRING RegistryPath
)
593 static UNICODE_STRING ServiceDeviceName
= RTL_CONSTANT_STRING(L
"\\Device\\WMIDataDevice");
594 static UNICODE_STRING ServiceDosDeviceName
= RTL_CONSTANT_STRING(L
"\\DosDevices\\WMIDataDevice");
595 static UNICODE_STRING AdminDeviceName
= RTL_CONSTANT_STRING(L
"\\Device\\WMIAdminDevice");
596 static UNICODE_STRING AdminDosDeviceName
= RTL_CONSTANT_STRING(L
"\\DosDevices\\WMIAdminDevice");
600 /* Create the service device object */
601 Status
= IoCreateDevice(DriverObject
,
605 FILE_DEVICE_SECURE_OPEN
,
607 &WmipServiceDeviceObject
);
608 if (!NT_SUCCESS(Status
))
610 DPRINT1("Failed to create service device: 0x%lx\n", Status
);
614 /* Create a symbolic link for the service device */
615 Status
= IoCreateSymbolicLink(&ServiceDosDeviceName
, &ServiceDeviceName
);
616 if (!NT_SUCCESS(Status
))
618 DPRINT1("IoCreateSymbolicLink() failed: 0x%lx\n", Status
);
619 IoDeleteDevice(WmipServiceDeviceObject
);
623 /* Create the admin device object */
624 Status
= IoCreateDevice(DriverObject
,
628 FILE_DEVICE_SECURE_OPEN
,
630 &WmipAdminDeviceObject
);
631 if (!NT_SUCCESS(Status
))
633 DPRINT1("Failed to create admin device: 0x%lx\n", Status
);
634 IoDeleteDevice(WmipServiceDeviceObject
);
635 IoDeleteSymbolicLink(&ServiceDosDeviceName
);
639 /* Create a symbolic link for the admin device */
640 Status
= IoCreateSymbolicLink(&AdminDosDeviceName
, &AdminDeviceName
);
641 if (!NT_SUCCESS(Status
))
643 DPRINT1("IoCreateSymbolicLink() failed: 0x%lx\n", Status
);
644 IoDeleteSymbolicLink(&ServiceDosDeviceName
);
645 IoDeleteDevice(WmipServiceDeviceObject
);
646 IoDeleteDevice(WmipAdminDeviceObject
);
650 /* Initialize dispatch routines */
651 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = WmipOpenCloseCleanup
;
652 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = WmipOpenCloseCleanup
;
653 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = WmipIoControl
;
654 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = WmipOpenCloseCleanup
;
655 DriverObject
->MajorFunction
[IRP_MJ_SYSTEM_CONTROL
] = WmipSystemControl
;
656 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = WmipShutdown
;
658 /* Initialize fast dispatch */
659 RtlZeroMemory(&WmipFastIoDispatch
, sizeof(WmipFastIoDispatch
));
660 WmipFastIoDispatch
.SizeOfFastIoDispatch
= sizeof(WmipFastIoDispatch
);
661 WmipFastIoDispatch
.FastIoDeviceControl
= WmipFastIoDeviceControl
;
662 DriverObject
->FastIoDispatch
= &WmipFastIoDispatch
;
664 /* Register the WMI service device */
665 IoWMIRegistrationControl(WmipServiceDeviceObject
, WMIREG_ACTION_REGISTER
);
667 /* Register a shutdown notification */
668 IoRegisterShutdownNotification(WmipServiceDeviceObject
);
670 /* Initialization is done */
671 WmipServiceDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
672 WmipAdminDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
674 return STATUS_SUCCESS
;