📄 plugplay.c
字号:
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/io/plugplay.c
* PURPOSE: Plug-and-play interface routines
*
* PROGRAMMERS: Eric Kohl <eric.kohl@t-online.de>
*/
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>
#if defined (ALLOC_PRAGMA)
#pragma alloc_text(INIT, IopInitPlugPlayEvents)
#endif
typedef struct _PNP_EVENT_ENTRY
{
LIST_ENTRY ListEntry;
PLUGPLAY_EVENT_BLOCK Event;
} PNP_EVENT_ENTRY, *PPNP_EVENT_ENTRY;
/* GLOBALS *******************************************************************/
static LIST_ENTRY IopPnpEventQueueHead;
static KEVENT IopPnpNotifyEvent;
/* FUNCTIONS *****************************************************************/
NTSTATUS INIT_FUNCTION
IopInitPlugPlayEvents(VOID)
{
InitializeListHead(&IopPnpEventQueueHead);
KeInitializeEvent(&IopPnpNotifyEvent,
SynchronizationEvent,
FALSE);
return STATUS_SUCCESS;
}
NTSTATUS
IopQueueTargetDeviceEvent(const GUID *Guid,
PUNICODE_STRING DeviceIds)
{
PPNP_EVENT_ENTRY EventEntry;
ULONG TotalSize;
TotalSize =
FIELD_OFFSET(PLUGPLAY_EVENT_BLOCK, TargetDevice.DeviceIds) +
DeviceIds->MaximumLength;
EventEntry = ExAllocatePool(NonPagedPool,
TotalSize + FIELD_OFFSET(PNP_EVENT_ENTRY, Event));
if (EventEntry == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
memcpy(&EventEntry->Event.EventGuid,
Guid,
sizeof(GUID));
EventEntry->Event.EventCategory = TargetDeviceChangeEvent;
EventEntry->Event.TotalSize = TotalSize;
memcpy(&EventEntry->Event.TargetDevice.DeviceIds,
DeviceIds->Buffer,
DeviceIds->MaximumLength);
InsertHeadList(&IopPnpEventQueueHead,
&EventEntry->ListEntry);
KeSetEvent(&IopPnpNotifyEvent,
0,
FALSE);
return STATUS_SUCCESS;
}
/*
* Remove the current PnP event from the tail of the event queue
* and signal IopPnpNotifyEvent if there is yet another event in the queue.
*/
static NTSTATUS
IopRemovePlugPlayEvent(VOID)
{
/* Remove a pnp event entry from the tail of the queue */
if (!IsListEmpty(&IopPnpEventQueueHead))
{
ExFreePool(RemoveTailList(&IopPnpEventQueueHead));
}
/* Signal the next pnp event in the queue */
if (!IsListEmpty(&IopPnpEventQueueHead))
{
KeSetEvent(&IopPnpNotifyEvent,
0,
FALSE);
}
return STATUS_SUCCESS;
}
/*
* Plug and Play event structure used by NtGetPlugPlayEvent.
*
* EventGuid
* Can be one of the following values:
* GUID_HWPROFILE_QUERY_CHANGE
* GUID_HWPROFILE_CHANGE_CANCELLED
* GUID_HWPROFILE_CHANGE_COMPLETE
* GUID_TARGET_DEVICE_QUERY_REMOVE
* GUID_TARGET_DEVICE_REMOVE_CANCELLED
* GUID_TARGET_DEVICE_REMOVE_COMPLETE
* GUID_PNP_CUSTOM_NOTIFICATION
* GUID_PNP_POWER_NOTIFICATION
* GUID_DEVICE_* (see above)
*
* EventCategory
* Type of the event that happened.
*
* Result
* ?
*
* Flags
* ?
*
* TotalSize
* Size of the event block including the device IDs and other
* per category specific fields.
*/
/*
* NtGetPlugPlayEvent
*
* Returns one Plug & Play event from a global queue.
*
* Parameters
* Reserved1
* Reserved2
* Always set to zero.
*
* Buffer
* The buffer that will be filled with the event information on
* successful return from the function.
*
* BufferSize
* Size of the buffer pointed by the Buffer parameter. If the
* buffer size is not large enough to hold the whole event
* information, error STATUS_BUFFER_TOO_SMALL is returned and
* the buffer remains untouched.
*
* Return Values
* STATUS_PRIVILEGE_NOT_HELD
* STATUS_BUFFER_TOO_SMALL
* STATUS_SUCCESS
*
* Remarks
* This function isn't multi-thread safe!
*
* @implemented
*/
NTSTATUS STDCALL
NtGetPlugPlayEvent(IN ULONG Reserved1,
IN ULONG Reserved2,
OUT PPLUGPLAY_EVENT_BLOCK Buffer,
IN ULONG BufferSize)
{
PPNP_EVENT_ENTRY Entry;
NTSTATUS Status;
DPRINT("NtGetPlugPlayEvent() called\n");
/* Function can only be called from user-mode */
if (KeGetPreviousMode() == KernelMode)
{
DPRINT1("NtGetPlugPlayEvent cannot be called from kernel mode!\n");
return STATUS_ACCESS_DENIED;
}
/* Check for Tcb privilege */
if (!SeSinglePrivilegeCheck(SeTcbPrivilege,
UserMode))
{
DPRINT1("NtGetPlugPlayEvent: Caller does not hold the SeTcbPrivilege privilege!\n");
return STATUS_PRIVILEGE_NOT_HELD;
}
/* Wait for a PnP event */
DPRINT("Waiting for pnp notification event\n");
Status = KeWaitForSingleObject(&IopPnpNotifyEvent,
UserRequest,
KernelMode,
FALSE,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("KeWaitForSingleObject() failed (Status %lx)\n", Status);
return Status;
}
/* Get entry from the tail of the queue */
Entry = CONTAINING_RECORD(IopPnpEventQueueHead.Blink,
PNP_EVENT_ENTRY,
ListEntry);
/* Check the buffer size */
if (BufferSize < Entry->Event.TotalSize)
{
DPRINT1("Buffer is too small for the pnp-event\n");
return STATUS_BUFFER_TOO_SMALL;
}
/* Copy event data to the user buffer */
memcpy(Buffer,
&Entry->Event,
Entry->Event.TotalSize);
DPRINT("NtGetPlugPlayEvent() done\n");
return STATUS_SUCCESS;
}
static PDEVICE_OBJECT
IopTraverseDeviceNode(PDEVICE_NODE Node, PUNICODE_STRING DeviceInstance)
{
PDEVICE_OBJECT DeviceObject;
PDEVICE_NODE ChildNode;
if (RtlEqualUnicodeString(&Node->InstancePath,
DeviceInstance, TRUE))
{
ObReferenceObject(Node->PhysicalDeviceObject);
return Node->PhysicalDeviceObject;
}
/* Traversal of all children nodes */
for (ChildNode = Node->Child;
ChildNode != NULL;
ChildNode = ChildNode->NextSibling)
{
DeviceObject = IopTraverseDeviceNode(ChildNode, DeviceInstance);
if (DeviceObject != NULL)
{
return DeviceObject;
}
}
return NULL;
}
static PDEVICE_OBJECT
IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance)
{
#if 0
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName, ValueName;
LPWSTR KeyNameBuffer;
HANDLE InstanceKeyHandle;
HANDLE ControlKeyHandle;
NTSTATUS Status;
PKEY_VALUE_PARTIAL_INFORMATION ValueInformation;
ULONG ValueInformationLength;
PDEVICE_OBJECT DeviceObject = NULL;
DPRINT("IopGetDeviceObjectFromDeviceInstance(%wZ) called\n", DeviceInstance);
KeyNameBuffer = ExAllocatePool(PagedPool,
(49 * sizeof(WCHAR)) + DeviceInstance->Length);
if (KeyNameBuffer == NULL)
{
DPRINT1("Failed to allocate key name buffer!\n");
return NULL;
}
wcscpy(KeyNameBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
wcscat(KeyNameBuffer, DeviceInstance->Buffer);
RtlInitUnicodeString(&KeyName,
KeyNameBuffer);
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = ZwOpenKey(&InstanceKeyHandle,
KEY_READ,
&ObjectAttributes);
ExFreePool(KeyNameBuffer);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to open the instance key (Status %lx)\n", Status);
return NULL;
}
/* Open the 'Control' subkey */
RtlInitUnicodeString(&KeyName,
L"Control");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
InstanceKeyHandle,
NULL);
Status = ZwOpenKey(&ControlKeyHandle,
KEY_READ,
&ObjectAttributes);
ZwClose(InstanceKeyHandle);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to open the 'Control' key (Status %lx)\n", Status);
return NULL;
}
/* Query the 'DeviceReference' value */
RtlInitUnicodeString(&ValueName,
L"DeviceReference");
ValueInformationLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,
Data[0]) + sizeof(ULONG);
ValueInformation = ExAllocatePool(PagedPool, ValueInformationLength);
if (ValueInformation == NULL)
{
DPRINT1("Failed to allocate the name information buffer!\n");
ZwClose(ControlKeyHandle);
return NULL;
}
Status = ZwQueryValueKey(ControlKeyHandle,
&ValueName,
KeyValuePartialInformation,
ValueInformation,
ValueInformationLength,
&ValueInformationLength);
ZwClose(ControlKeyHandle);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to query the 'DeviceReference' value (Status %lx)\n", Status);
return NULL;
}
/* Check the device object */
RtlCopyMemory(&DeviceObject,
ValueInformation->Data,
sizeof(PDEVICE_OBJECT));
DPRINT("DeviceObject: %p\n", DeviceObject);
if (DeviceObject->Type != IO_TYPE_DEVICE ||
DeviceObject->DeviceObjectExtension == NULL ||
DeviceObject->DeviceObjectExtension->DeviceNode == NULL ||
!RtlEqualUnicodeString(&DeviceObject->DeviceObjectExtension->DeviceNode->InstancePath,
DeviceInstance, TRUE))
{
DPRINT1("Invalid object type!\n");
return NULL;
}
DPRINT("Instance path: %wZ\n", &DeviceObject->DeviceObjectExtension->DeviceNode->InstancePath);
ObReferenceObject(DeviceObject);
DPRINT("IopGetDeviceObjectFromDeviceInstance() done\n");
return DeviceObject;
#endif
if (IopRootDeviceNode == NULL)
return NULL;
if (DeviceInstance == NULL ||
DeviceInstance->Length == 0
)
{
if (IopRootDeviceNode->PhysicalDeviceObject)
{
ObReferenceObject(IopRootDeviceNode->PhysicalDeviceObject);
return IopRootDeviceNode->PhysicalDeviceObject;
}
else
return NULL;
}
return IopTraverseDeviceNode(IopRootDeviceNode, DeviceInstance);
}
static NTSTATUS
IopCaptureUnicodeString(PUNICODE_STRING DstName, PUNICODE_STRING SrcName)
{
NTSTATUS Status = STATUS_SUCCESS;
UNICODE_STRING Name;
Name.Buffer = NULL;
_SEH_TRY
{
Name.Length = SrcName->Length;
Name.MaximumLength = SrcName->MaximumLength;
if (Name.Length > Name.MaximumLength)
{
Status = STATUS_INVALID_PARAMETER;
_SEH_LEAVE;
}
if (Name.MaximumLength)
{
ProbeForRead(SrcName->Buffer,
Name.MaximumLength,
sizeof(WCHAR));
Name.Buffer = ExAllocatePool(NonPagedPool, Name.MaximumLength);
if (Name.Buffer == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
_SEH_LEAVE;
}
memcpy(Name.Buffer, SrcName->Buffer, Name.MaximumLength);
}
*DstName = Name;
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if (!NT_SUCCESS(Status) && Name.Buffer)
{
ExFreePool(Name.Buffer);
}
return Status;
}
static NTSTATUS
IopGetDeviceProperty(PPLUGPLAY_CONTROL_PROPERTY_DATA PropertyData)
{
PDEVICE_OBJECT DeviceObject = NULL;
NTSTATUS Status = STATUS_SUCCESS;
UNICODE_STRING DeviceInstance;
ULONG BufferSize;
ULONG Property = 0;
PVOID Buffer;
DPRINT("IopGetDeviceProperty() called\n");
DPRINT("Device name: %wZ\n", &PropertyData->DeviceInstance);
Status = IopCaptureUnicodeString(&DeviceInstance, &PropertyData->DeviceInstance);
if (!NT_SUCCESS(Status))
{
return Status;
}
_SEH_TRY
{
Property = PropertyData->Property;
BufferSize = PropertyData->BufferSize;
ProbeForWrite(PropertyData->Buffer,
BufferSize,
sizeof(UCHAR));
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if (!NT_SUCCESS(Status))
{
ExFreePool(DeviceInstance.Buffer);
return Status;
}
/* Get the device object */
DeviceObject = IopGetDeviceObjectFromDeviceInstance(&PropertyData->DeviceInstance);
ExFreePool(DeviceInstance.Buffer);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -