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 typedef struct _WMI_SET_MARK
70 } WMI_SET_MARK
, *PWMI_SET_MARK
;
72 PDEVICE_OBJECT WmipServiceDeviceObject
;
73 PDEVICE_OBJECT WmipAdminDeviceObject
;
74 FAST_IO_DISPATCH WmipFastIoDispatch
;
77 /* FUNCTIONS *****************************************************************/
79 DRIVER_DISPATCH WmipOpenCloseCleanup
;
80 DRIVER_DISPATCH WmipIoControl
;
81 DRIVER_DISPATCH WmipSystemControl
;
82 DRIVER_DISPATCH WmipShutdown
;
87 _In_ PDEVICE_OBJECT DeviceObject
,
92 /* No work to do, just return success */
93 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
94 Irp
->IoStatus
.Information
= 0;
95 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
96 return STATUS_SUCCESS
;
103 KPROCESSOR_MODE PreviousMode
)
105 UNIMPLEMENTED_DBGBREAK();
106 return STATUS_SUCCESS
;
113 ULONG InputBufferLength
)
115 UNIMPLEMENTED_DBGBREAK();
116 return STATUS_SUCCESS
;
121 WmipCaptureGuidObjectAttributes(
122 _In_ POBJECT_ATTRIBUTES GuidObjectAttributes
,
123 _Out_ POBJECT_ATTRIBUTES CapuredObjectAttributes
,
124 _Out_ PUNICODE_STRING CapturedObjectName
,
125 _Out_ PWSTR ObjectNameBuffer
,
126 _In_ KPROCESSOR_MODE AccessMode
)
128 ASSERT(AccessMode
!= KernelMode
);
132 /* Probe and copy the object attributes structure */
133 ProbeForRead(GuidObjectAttributes
,
134 sizeof(OBJECT_ATTRIBUTES
),
136 *CapuredObjectAttributes
= *GuidObjectAttributes
;
138 /* Probe and copy the object name UNICODE_STRING */
139 ProbeForRead(CapuredObjectAttributes
->ObjectName
,
140 sizeof(UNICODE_STRING
),
142 *CapturedObjectName
= *CapuredObjectAttributes
->ObjectName
;
144 /* Check if the object name has the expected length */
145 if (CapturedObjectName
->Length
!= 45 * sizeof(WCHAR
))
147 return STATUS_INVALID_PARAMETER
;
150 /* Probe and copy the object name buffer */
151 ProbeForRead(CapturedObjectName
->Buffer
,
152 CapturedObjectName
->Length
,
154 RtlCopyMemory(ObjectNameBuffer
,
155 CapturedObjectName
->Buffer
,
156 CapturedObjectName
->Length
);
159 CapturedObjectName
->Buffer
= ObjectNameBuffer
;
160 GuidObjectAttributes
->ObjectName
= CapturedObjectName
;
162 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
164 DPRINT1("Got exception!\n");
165 return _SEH2_GetExceptionCode();
169 return STATUS_SUCCESS
;
175 _In_ PDEVICE_OBJECT DeviceObject
,
177 _In_ ULONG InputLength
,
178 _Inout_ PULONG OutputLength
)
180 PWMIP_REGISTER_GUIDS RegisterGuids
= (PWMIP_REGISTER_GUIDS
)Buffer
;
181 PWMIP_RESULT Result
= (PWMIP_RESULT
)Buffer
;
182 OBJECT_ATTRIBUTES LocalObjectAttributes
;
183 UNICODE_STRING LocalObjectName
;
184 WCHAR LocalObjectNameBuffer
[45 + 1];
185 KPROCESSOR_MODE PreviousMode
;
186 HANDLE GuidObjectHandle
;
190 /* Make sure the input buffer is large enough */
191 if ((InputLength
< sizeof(WMIP_REGISTER_GUIDS
)) ||
192 (RegisterGuids
->RegInfo
.BufferSize
>
193 (InputLength
- FIELD_OFFSET(WMIP_REGISTER_GUIDS
, RegInfo
))))
195 return STATUS_UNSUCCESSFUL
;
198 /* Make sure we have a resonable GUID count */
199 if ((RegisterGuids
->RegInfo
.GuidCount
== 0) ||
200 (RegisterGuids
->RegInfo
.GuidCount
> 0x10000))
202 return STATUS_UNSUCCESSFUL
;
205 /* Capture object attributes */
206 PreviousMode
= ExGetPreviousMode();
207 Status
= WmipCaptureGuidObjectAttributes(RegisterGuids
->ObjectAttributes
,
208 &LocalObjectAttributes
,
210 LocalObjectNameBuffer
,
212 if (!NT_SUCCESS(Status
))
214 DPRINT1("WmipCaptureGuidObjectAttributes failed: 0x%lx\n", Status
);
218 /* Open a new GUID object */
219 Status
= WmipOpenGuidObjectByName(&LocalObjectAttributes
,
224 if (!NT_SUCCESS(Status
))
226 DPRINT1("WmipOpenGuidObjectByName failed: 0x%lx\n", Status
);
230 /* Dereference the GUID object */
231 ObDereferenceObject(GuidObject
);
233 /* Return the handle (user mode will close it) */
234 Result
->Handle
= GuidObjectHandle
;
235 Result
->TraceHandle
= 0;
238 return STATUS_SUCCESS
;
246 _In_ ULONG InputLength
,
247 _Inout_ PULONG OutputLength
)
249 /* For now we have nothing to do */
250 return STATUS_SUCCESS
;
255 WmipClearIrpObjectList(
258 PWMIP_IRP_CONTEXT IrpContext
;
259 PLIST_ENTRY ListEntry
;
260 PWMIP_GUID_OBJECT GuidObject
;
262 /* Get the IRP context */
263 IrpContext
= (PWMIP_IRP_CONTEXT
)Irp
->Tail
.Overlay
.DriverContext
;
265 /* Loop all GUID objects attached to this IRP */
266 for (ListEntry
= IrpContext
->GuidObjectListHead
.Flink
;
267 ListEntry
!= &IrpContext
->GuidObjectListHead
;
268 ListEntry
= ListEntry
->Flink
)
270 /* Get the GUID object */
271 GuidObject
= CONTAINING_RECORD(ListEntry
, WMIP_GUID_OBJECT
, IrpLink
);
273 /* Make sure the IRP matches and clear it */
274 ASSERT(GuidObject
->Irp
== Irp
);
275 GuidObject
->Irp
= NULL
;
277 /* Remove the entry */
278 RemoveEntryList(ListEntry
);
284 WmipNotificationIrpCancel(
285 _In_ PDEVICE_OBJECT DeviceObject
,
289 WmipClearIrpObjectList(Irp
);
291 /* Release the cancel spin lock */
292 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
294 /* Set the status to cancelled and complete the IRP */
295 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
296 Irp
->IoStatus
.Information
= 0;
297 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
302 WmipInitializeIrpContext(
303 PWMIP_IRP_CONTEXT IrpContext
)
305 /* Initialize the list head for GUID objects */
306 InitializeListHead(&IrpContext
->GuidObjectListHead
);
311 WmipReceiveNotifications(
314 _In_ ULONG InputLength
,
315 _Inout_ PULONG OutputLength
)
317 PWMI_NOTIFICATION Notification
;
318 PWMIP_IRP_CONTEXT IrpContext
;
322 if ((InputLength
< sizeof(WMI_NOTIFICATION
)) || (*OutputLength
< 0x38))
324 return STATUS_INVALID_DEVICE_REQUEST
;
327 /// FIXME: For now we don't do any actual work, but simply pretend we are
328 /// waiting for notifications. We won't ever deliver any though.
329 Notification
= (PWMI_NOTIFICATION
)Buffer
;
330 DBG_UNREFERENCED_LOCAL_VARIABLE(Notification
);
333 // reference the object
334 // on failure, fail the whole request
337 // update the irp (synchronization!)
338 // if we had one before complete the old irp with an error
340 /* Get the IRP context and initialize it */
341 IrpContext
= (PWMIP_IRP_CONTEXT
)Irp
->Tail
.Overlay
.DriverContext
;
342 WmipInitializeIrpContext(IrpContext
);
345 // insert the objects into the IRP list
347 /* Set our cancel routine for cleanup */
348 IoSetCancelRoutine(Irp
, WmipNotificationIrpCancel
);
350 /* Check if the IRP is already being cancelled */
351 if (Irp
->Cancel
&& IoSetCancelRoutine(Irp
, NULL
))
353 Status
= STATUS_CANCELLED
;
357 /* Mark the IRP as pending */
358 IoMarkIrpPending(Irp
);
359 Status
= STATUS_PENDING
;
365 typedef struct _WMI_OPEN_GUID_FOR_EVENTS
367 POBJECT_ATTRIBUTES ObjectAttributes
;
368 ACCESS_MASK DesiredAccess
;
371 } WMI_OPEN_GUID_FOR_EVENTS
, *PWMI_OPEN_GUID_FOR_EVENTS
;
373 typedef struct _WMIP_RESULT2
379 } WMIP_RESULT2
, *PWMIP_RESULT2
;
383 WmipOpenGuidForEvents(
388 PWMI_OPEN_GUID_FOR_EVENTS OpenGuidForEvents
= Buffer
;
389 PWMIP_RESULT2 Result
= (PWMIP_RESULT2
)Buffer
;
390 OBJECT_ATTRIBUTES LocalObjectAttributes
;
391 UNICODE_STRING LocalObjectName
;
392 WCHAR LocalObjectNameBuffer
[45 + 1];
393 KPROCESSOR_MODE PreviousMode
;
394 HANDLE GuidObjectHandle
;
398 if ((InputLength
!= sizeof(WMI_OPEN_GUID_FOR_EVENTS
)) ||
399 (*OutputLength
!= sizeof(WMIP_RESULT2
)))
401 return STATUS_UNSUCCESSFUL
;
404 /* Capture object attributes */
405 PreviousMode
= ExGetPreviousMode();
406 Status
= WmipCaptureGuidObjectAttributes(OpenGuidForEvents
->ObjectAttributes
,
407 &LocalObjectAttributes
,
409 LocalObjectNameBuffer
,
411 if (!NT_SUCCESS(Status
))
413 DPRINT1("ProbeAndCaptureGuidObjectAttributes failed: 0x%lx\n", Status
);
417 /* Open a new GUID object */
418 Status
= WmipOpenGuidObjectByName(&LocalObjectAttributes
,
419 OpenGuidForEvents
->DesiredAccess
,
423 if (!NT_SUCCESS(Status
))
425 DPRINT1("WmipOpenGuidObjectByName failed: 0x%lx\n", Status
);
429 Result
->Handle
= GuidObjectHandle
;
431 ObDereferenceObject(GuidObject
);
433 return STATUS_SUCCESS
;
439 PWMI_SET_MARK Buffer
,
442 UNIMPLEMENTED_DBGBREAK();
443 return STATUS_SUCCESS
;
449 _In_ PDEVICE_OBJECT DeviceObject
,
452 PIO_STACK_LOCATION IoStackLocation
;
455 ULONG InputLength
, OutputLength
;
459 /* Get the current stack location */
460 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
462 /* Get the io control parameters */
463 IoControlCode
= IoStackLocation
->Parameters
.DeviceIoControl
.IoControlCode
;
464 Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
465 InputLength
= IoStackLocation
->Parameters
.DeviceIoControl
.InputBufferLength
;
466 OutputLength
= IoStackLocation
->Parameters
.DeviceIoControl
.OutputBufferLength
;
468 switch (IoControlCode
)
471 case IOCTL_WMI_REGISTER_GUIDS
:
473 Status
= WmipRegisterGuids(DeviceObject
,
480 case IOCTL_WMI_UNREGISTER_GUIDS
:
482 Status
= WmipUnregisterGuids(Buffer
,
488 case IOCTL_WMI_RECEIVE_NOTIFICATIONS
:
490 Status
= WmipReceiveNotifications(Irp
,
499 DPRINT1("IOCTL 0x228168 is unimplemented, ignoring\n");
500 Status
= STATUS_SUCCESS
;
504 case IOCTL_WMI_OPEN_GUID_FOR_EVENTS
:
506 Status
= WmipOpenGuidForEvents(Buffer
, InputLength
, &OutputLength
);
510 case IOCTL_WMI_SET_MARK
:
512 if (InputLength
< FIELD_OFFSET(WMI_SET_MARK
, Mark
))
514 Status
= STATUS_UNSUCCESSFUL
;
518 Status
= WmiSetMark(Buffer
, InputLength
);
523 DPRINT1("Unsupported yet IOCTL: 0x%lx\n", IoControlCode
);
524 Status
= STATUS_INVALID_DEVICE_REQUEST
;
529 if (Status
== STATUS_PENDING
)
532 Irp
->IoStatus
.Status
= Status
;
533 Irp
->IoStatus
.Information
= NT_SUCCESS(Status
) ? OutputLength
: 0;
535 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
542 _Inout_ PDEVICE_OBJECT DeviceObject
,
545 UNIMPLEMENTED_DBGBREAK();
546 return STATUS_NOT_IMPLEMENTED
;
552 _Inout_ PDEVICE_OBJECT DeviceObject
,
556 return STATUS_NOT_IMPLEMENTED
;
559 _Function_class_(FAST_IO_DEVICE_CONTROL
)
563 WmipFastIoDeviceControl(
564 _In_ PFILE_OBJECT FileObject
,
566 _In_opt_ PVOID InputBuffer
,
567 _In_ ULONG InputBufferLength
,
568 _Out_opt_ PVOID OutputBuffer
,
569 _In_ ULONG OutputBufferLength
,
570 _In_ ULONG IoControlCode
,
571 _Out_ PIO_STATUS_BLOCK IoStatus
,
572 _In_ PDEVICE_OBJECT DeviceObject
)
576 if (IoControlCode
== IOCTL_WMI_TRACE_EVENT
)
578 if (InputBufferLength
< 0x30)
580 DPRINT1("Buffer too small\n");
584 IoStatus
->Status
= WmiTraceEvent(InputBuffer
, ExGetPreviousMode());
587 else if (IoControlCode
== IOCTL_WMI_TRACE_USER_MESSAGE
)
589 if (InputBufferLength
< 0x30)
591 DPRINT1("Buffer too small\n");
595 IoStatus
->Status
= WmiTraceUserMessage(InputBuffer
, InputBufferLength
);
599 DPRINT1("Invalid io control code for fast dispatch: 0x%lx\n", IoControlCode
);
605 WmipDockUndockEventCallback(
606 _In_ PVOID NotificationStructure
,
607 _Inout_opt_ PVOID Context
)
609 UNIMPLEMENTED_DBGBREAK();
610 return STATUS_NOT_IMPLEMENTED
;
613 _Function_class_(DRIVER_INITIALIZE
)
618 _In_ PDRIVER_OBJECT DriverObject
,
619 _In_ PUNICODE_STRING RegistryPath
)
621 static UNICODE_STRING ServiceDeviceName
= RTL_CONSTANT_STRING(L
"\\Device\\WMIDataDevice");
622 static UNICODE_STRING ServiceDosDeviceName
= RTL_CONSTANT_STRING(L
"\\DosDevices\\WMIDataDevice");
623 static UNICODE_STRING AdminDeviceName
= RTL_CONSTANT_STRING(L
"\\Device\\WMIAdminDevice");
624 static UNICODE_STRING AdminDosDeviceName
= RTL_CONSTANT_STRING(L
"\\DosDevices\\WMIAdminDevice");
628 /* Create the service device object */
629 Status
= IoCreateDevice(DriverObject
,
633 FILE_DEVICE_SECURE_OPEN
,
635 &WmipServiceDeviceObject
);
636 if (!NT_SUCCESS(Status
))
638 DPRINT1("Failed to create service device: 0x%lx\n", Status
);
642 /* Create a symbolic link for the service device */
643 Status
= IoCreateSymbolicLink(&ServiceDosDeviceName
, &ServiceDeviceName
);
644 if (!NT_SUCCESS(Status
))
646 DPRINT1("IoCreateSymbolicLink() failed: 0x%lx\n", Status
);
647 IoDeleteDevice(WmipServiceDeviceObject
);
651 /* Create the admin device object */
652 Status
= IoCreateDevice(DriverObject
,
656 FILE_DEVICE_SECURE_OPEN
,
658 &WmipAdminDeviceObject
);
659 if (!NT_SUCCESS(Status
))
661 DPRINT1("Failed to create admin device: 0x%lx\n", Status
);
662 IoDeleteDevice(WmipServiceDeviceObject
);
663 IoDeleteSymbolicLink(&ServiceDosDeviceName
);
667 /* Create a symbolic link for the admin device */
668 Status
= IoCreateSymbolicLink(&AdminDosDeviceName
, &AdminDeviceName
);
669 if (!NT_SUCCESS(Status
))
671 DPRINT1("IoCreateSymbolicLink() failed: 0x%lx\n", Status
);
672 IoDeleteSymbolicLink(&ServiceDosDeviceName
);
673 IoDeleteDevice(WmipServiceDeviceObject
);
674 IoDeleteDevice(WmipAdminDeviceObject
);
678 /* Initialize dispatch routines */
679 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = WmipOpenCloseCleanup
;
680 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = WmipOpenCloseCleanup
;
681 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = WmipIoControl
;
682 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = WmipOpenCloseCleanup
;
683 DriverObject
->MajorFunction
[IRP_MJ_SYSTEM_CONTROL
] = WmipSystemControl
;
684 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = WmipShutdown
;
686 /* Initialize fast dispatch */
687 RtlZeroMemory(&WmipFastIoDispatch
, sizeof(WmipFastIoDispatch
));
688 WmipFastIoDispatch
.SizeOfFastIoDispatch
= sizeof(WmipFastIoDispatch
);
689 WmipFastIoDispatch
.FastIoDeviceControl
= WmipFastIoDeviceControl
;
690 DriverObject
->FastIoDispatch
= &WmipFastIoDispatch
;
692 /* Register the WMI service device */
693 IoWMIRegistrationControl(WmipServiceDeviceObject
, WMIREG_ACTION_REGISTER
);
695 /* Register a shutdown notification */
696 IoRegisterShutdownNotification(WmipServiceDeviceObject
);
698 /* Initialization is done */
699 WmipServiceDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
700 WmipAdminDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
702 return STATUS_SUCCESS
;