Merge the following revisions from kernel-fun branch:
[reactos.git] / reactos / ntoskrnl / wmi / wmidrv.c
index 46b2ca3..5fef374 100644 (file)
@@ -33,11 +33,35 @@ typedef struct _WMIP_RESULT
 {
     HANDLE Handle;
     ULONG Unknown04;
-    ULONG Unknown08;
-    ULONG Unknown0C;
+    TRACEHANDLE TraceHandle;
     BOOLEAN Unknown10;
 } WMIP_RESULT, *PWMIP_RESULT;
 
+typedef struct _WMI_UNREGISTER_GUID
+{
+    GUID Guid;
+    ULONG Unknown10;
+    ULONG Unknown14;
+    ULONG Unknown18;
+    ULONG Unknown1C;
+} WMI_UNREGISTER_GUID, *PWMI_UNREGISTER_GUID;
+
+typedef struct _WMI_GUID_OBJECT_ENTRY
+{
+    HANDLE Handle;
+    ULONG Unknown04;
+} WMI_GUID_OBJECT_ENTRY, *PWMI_GUID_OBJECT_ENTRY;
+
+typedef struct _WMI_NOTIFICATION
+{
+    ULONG NumberOfGuidObjects;
+    ULONG Unknown04;
+    ULONG Unknown08;
+    ULONG Unknown0C;
+    ULONG Unknown10;
+    ULONG Unknown14;
+    WMI_GUID_OBJECT_ENTRY GuidObjects[0];
+} WMI_NOTIFICATION, *PWMI_NOTIFICATION;
 
 PDEVICE_OBJECT WmipServiceDeviceObject;
 PDEVICE_OBJECT WmipAdminDeviceObject;
@@ -86,6 +110,59 @@ WmiTraceUserMessage(
     return STATUS_SUCCESS;
 }
 
+static
+NTSTATUS
+WmipCaptureGuidObjectAttributes(
+    _In_ POBJECT_ATTRIBUTES GuidObjectAttributes,
+    _Out_ POBJECT_ATTRIBUTES CapuredObjectAttributes,
+    _Out_ PUNICODE_STRING CapturedObjectName,
+    _Out_ PWSTR ObjectNameBuffer,
+    _In_ KPROCESSOR_MODE AccessMode)
+{
+    NT_ASSERT(AccessMode != KernelMode);
+
+    _SEH2_TRY
+    {
+        /* Probe and copy the object attributes structure */
+        ProbeForRead(GuidObjectAttributes,
+                     sizeof(OBJECT_ATTRIBUTES),
+                     sizeof(PVOID));
+        *CapuredObjectAttributes = *GuidObjectAttributes;
+
+        /* Probe and copy the object name UNICODE_STRING */
+        ProbeForRead(CapuredObjectAttributes->ObjectName,
+                     sizeof(UNICODE_STRING),
+                     sizeof(PVOID));
+        *CapturedObjectName = *CapuredObjectAttributes->ObjectName;
+
+        /* Check if the object name has the expected length */
+        if (CapturedObjectName->Length != 45 * sizeof(WCHAR))
+        {
+            return STATUS_INVALID_PARAMETER;
+        }
+
+        /* Probe and copy the object name buffer */
+        ProbeForRead(CapturedObjectName->Buffer,
+                     CapturedObjectName->Length,
+                     sizeof(WCHAR));
+        RtlCopyMemory(ObjectNameBuffer,
+                      CapturedObjectName->Buffer,
+                      CapturedObjectName->Length);
+
+        /* Fix pointers */
+        CapturedObjectName->Buffer = ObjectNameBuffer;
+        GuidObjectAttributes->ObjectName = CapturedObjectName;
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        DPRINT1("Got exception!\n");
+        return _SEH2_GetExceptionCode();
+    }
+    _SEH2_END;
+
+    return STATUS_SUCCESS;
+}
+
 static
 NTSTATUS
 WmipRegisterGuids(
@@ -106,7 +183,7 @@ WmipRegisterGuids(
 
     /* Make sure the input buffer is large enough */
     if ((InputLength < sizeof(WMIP_REGISTER_GUIDS)) ||
-        (RegisterGuids->RegInfo.BufferSize > 
+        (RegisterGuids->RegInfo.BufferSize >
          (InputLength - FIELD_OFFSET(WMIP_REGISTER_GUIDS, RegInfo))))
     {
         return STATUS_UNSUCCESSFUL;
@@ -119,61 +196,233 @@ WmipRegisterGuids(
         return STATUS_UNSUCCESSFUL;
     }
 
-    _SEH2_TRY
+    /* Capture object attributes */
+    PreviousMode = ExGetPreviousMode();
+    Status = WmipCaptureGuidObjectAttributes(RegisterGuids->ObjectAttributes,
+                                             &LocalObjectAttributes,
+                                             &LocalObjectName,
+                                             LocalObjectNameBuffer,
+                                             PreviousMode);
+    if (!NT_SUCCESS(Status))
     {
-        /* Probe and copy the object attributes structure */
-        ProbeForRead(RegisterGuids->ObjectAttributes,
-                     sizeof(OBJECT_ATTRIBUTES),
-                     sizeof(PVOID));
-        LocalObjectAttributes = *RegisterGuids->ObjectAttributes;
+        DPRINT1("WmipCaptureGuidObjectAttributes failed: 0x%lx\n", Status);
+        return Status;
+    }
 
-        /* Probe and copy the object name UNICODE_STRING */
-        ProbeForRead(LocalObjectAttributes.ObjectName,
-                     sizeof(UNICODE_STRING),
-                     sizeof(PVOID));
-        LocalObjectName = *LocalObjectAttributes.ObjectName;
+    /* Open a new GUID object */
+    Status = WmipOpenGuidObject(&LocalObjectAttributes,
+                                SPECIFIC_RIGHTS_ALL,
+                                PreviousMode,
+                                &GuidObjectHandle,
+                                &GuidObject);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("WmipOpenGuidObject failed: 0x%lx\n", Status);
+        return Status;
+    }
 
-        /* Check if the object name has the expected length */
-        if (LocalObjectName.Length != 45 * sizeof(WCHAR))
-        {
-            return STATUS_INVALID_PARAMETER;
-        }
+    /* Dereference the GUID object */
+    ObDereferenceObject(GuidObject);
 
-        /* Probe and copy the object name buffer */
-        ProbeForRead(LocalObjectName.Buffer, LocalObjectName.Length, sizeof(WCHAR));
-        RtlCopyMemory(LocalObjectNameBuffer,
-                      LocalObjectName.Buffer,
-                      LocalObjectName.Length);
+    /* Return the handle (user mode will close it) */
+    Result->Handle = GuidObjectHandle;
+    Result->TraceHandle = 0;
+    *OutputLength = 24;
 
-        /* Fix pointers */
-        LocalObjectName.Buffer = LocalObjectNameBuffer;
-        LocalObjectAttributes.ObjectName = &LocalObjectName;
+    return STATUS_SUCCESS;
+}
+
+
+static
+NTSTATUS
+WmipUnregisterGuids(
+    _In_ PVOID Buffer,
+    _In_ ULONG InputLength,
+    _Inout_ PULONG OutputLength)
+{
+    /* For now we have nothing to do */
+    return STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+WmipClearIrpObjectList(
+    _In_ PIRP Irp)
+{
+    PWMIP_IRP_CONTEXT IrpContext;
+    PLIST_ENTRY ListEntry;
+    PWMIP_GUID_OBJECT GuidObject;
+
+    /* Get the IRP context */
+    IrpContext = (PWMIP_IRP_CONTEXT)Irp->Tail.Overlay.DriverContext;
+
+    /* Loop all GUID objects attached to this IRP */
+    for (ListEntry = IrpContext->GuidObjectListHead.Flink;
+         ListEntry != &IrpContext->GuidObjectListHead;
+         ListEntry = ListEntry->Flink)
+    {
+        /* Get the GUID object */
+        GuidObject = CONTAINING_RECORD(ListEntry, WMIP_GUID_OBJECT, IrpLink);
+
+        /* Make sure the IRP matches and clear it */
+        ASSERT(GuidObject->Irp == Irp);
+        GuidObject->Irp = NULL;
+
+        /* Remove the entry */
+        RemoveEntryList(ListEntry);
     }
-    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+}
+
+VOID
+NTAPI
+WmipNotificationIrpCancel(
+    _In_ PDEVICE_OBJECT DeviceObject,
+    _Inout_ PIRP Irp)
+{
+    /* Clear the list */
+    WmipClearIrpObjectList(Irp);
+
+    /* Release the cancel spin lock */
+    IoReleaseCancelSpinLock(Irp->CancelIrql);
+
+    /* Set the status to cancelled and complete the IRP */
+    Irp->IoStatus.Status = STATUS_CANCELLED;
+    Irp->IoStatus.Information = 0;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+}
+
+static
+VOID
+WmipInitializeIrpContext(
+    PWMIP_IRP_CONTEXT IrpContext)
+{
+    /* Initialize the list head for GUID objects */
+    InitializeListHead(&IrpContext->GuidObjectListHead);
+}
+
+static
+NTSTATUS
+WmipReceiveNotifications(
+    _Inout_ PIRP Irp,
+    _In_ PVOID Buffer,
+    _In_ ULONG InputLength,
+    _Inout_ PULONG OutputLength)
+{
+    PWMI_NOTIFICATION Notification;
+    PWMIP_IRP_CONTEXT IrpContext;
+    NTSTATUS Status;
+
+    //__debugbreak();
+    if ((InputLength < sizeof(WMI_NOTIFICATION)) || (*OutputLength < 0x38))
     {
-        DPRINT1("Got exception!\n");
-        return _SEH2_GetExceptionCode();
+        return STATUS_INVALID_DEVICE_REQUEST;
     }
-    _SEH2_END;
 
-    /* Open a new GUID object */
+    /// FIXME: For now we don't do any actual work, but simply pretend we are
+    /// waiting for notifications. We won't ever deliver any though.
+    Notification = (PWMI_NOTIFICATION)Buffer;
+    DBG_UNREFERENCED_LOCAL_VARIABLE(Notification);
+
+    // loop all objects
+        // reference the object
+            // on failure, fail the whole request
+
+    // loop all objects
+        // update the irp (synchronization!)
+            // if we had one before complete the old irp with an error
+
+    /* Get the IRP context and initialize it */
+    IrpContext = (PWMIP_IRP_CONTEXT)Irp->Tail.Overlay.DriverContext;
+    WmipInitializeIrpContext(IrpContext);
+
+    // loop all objects
+        // insert the objects into the IRP list
+
+    /* Set our cancel routine for cleanup */
+    IoSetCancelRoutine(Irp, WmipNotificationIrpCancel);
+
+    /* Check if the IRP is already being cancelled */
+    if (Irp->Cancel && IoSetCancelRoutine(Irp, NULL))
+    {
+        Status = STATUS_CANCELLED;
+    }
+    else
+    {
+        /* Mark the IRP as pending */
+        IoMarkIrpPending(Irp);
+        Status = STATUS_PENDING;
+    }
+
+    return Status;
+}
+
+typedef struct _WMI_OPEN_GUID_FOR_EVENTS
+{
+    POBJECT_ATTRIBUTES ObjectAttributes;
+    ACCESS_MASK DesiredAccess;
+    ULONG Unknown08;
+    ULONG Unknown0C;
+} WMI_OPEN_GUID_FOR_EVENTS, *PWMI_OPEN_GUID_FOR_EVENTS;
+
+typedef struct _WMIP_RESULT2
+{
+    ULONG Unknown00;
+    ULONG Unknown04;
+    HANDLE Handle;
+    ULONG Unknown0C;
+} WMIP_RESULT2, *PWMIP_RESULT2;
+
+static
+NTSTATUS
+WmipOpenGuidForEvents(
+    PVOID Buffer,
+    ULONG InputLength,
+    PULONG OutputLength)
+{
+    PWMI_OPEN_GUID_FOR_EVENTS OpenGuidForEvents = Buffer;
+    PWMIP_RESULT2 Result = (PWMIP_RESULT2)Buffer;
+    OBJECT_ATTRIBUTES LocalObjectAttributes;
+    UNICODE_STRING LocalObjectName;
+    WCHAR LocalObjectNameBuffer[45 + 1];
+    KPROCESSOR_MODE PreviousMode;
+    HANDLE GuidObjectHandle;
+    PVOID GuidObject;
+    NTSTATUS Status;
+
+    if ((InputLength != sizeof(WMI_OPEN_GUID_FOR_EVENTS)) ||
+        (*OutputLength != sizeof(WMIP_RESULT2)))
+    {
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    /* Capture object attributes */
     PreviousMode = ExGetPreviousMode();
+    Status = WmipCaptureGuidObjectAttributes(OpenGuidForEvents->ObjectAttributes,
+                                             &LocalObjectAttributes,
+                                             &LocalObjectName,
+                                             LocalObjectNameBuffer,
+                                             PreviousMode);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("ProbeAndCaptureGuidObjectAttributes failed: 0x%lx\n", Status);
+        return Status;
+    }
+
+    /* Open a new GUID object */
     Status = WmipOpenGuidObject(&LocalObjectAttributes,
-                                SPECIFIC_RIGHTS_ALL,
+                                OpenGuidForEvents->DesiredAccess,
                                 PreviousMode,
                                 &GuidObjectHandle,
                                 &GuidObject);
     if (!NT_SUCCESS(Status))
     {
+        DPRINT1("WmipOpenGuidObject failed: 0x%lx\n", Status);
         return Status;
     }
 
-    /* Derefernce the GUID object */
-    ObDereferenceObject(GuidObject);
-
-    /* Return the handle */
     Result->Handle = GuidObjectHandle;
-    *OutputLength = 24;
+
+    ObDereferenceObject(GuidObject);
 
     return STATUS_SUCCESS;
 }
@@ -212,6 +461,36 @@ WmipIoControl(
             break;
         }
 
+        case IOCTL_WMI_UNREGISTER_GUIDS:
+        {
+            Status = WmipUnregisterGuids(Buffer,
+                                         InputLength,
+                                         &OutputLength);
+            break;
+        }
+
+        case IOCTL_WMI_RECEIVE_NOTIFICATIONS:
+        {
+            Status = WmipReceiveNotifications(Irp,
+                                              Buffer,
+                                              InputLength,
+                                              &OutputLength);
+            break;
+        }
+
+        case 0x228168:
+        {
+            DPRINT1("IOCTL 0x228168 is unimplemented, ignoring\n");
+            Status = STATUS_SUCCESS;
+            break;
+        }
+
+        case IOCTL_WMI_OPEN_GUID_FOR_EVENTS:
+        {
+            Status = WmipOpenGuidForEvents(Buffer, InputLength, &OutputLength);
+            break;
+        }
+
         default:
             DPRINT1("Unsupported yet IOCTL: 0x%lx\n", IoControlCode);
             Status = STATUS_INVALID_DEVICE_REQUEST;