544 lines
15 KiB
C
544 lines
15 KiB
C
/*--
|
|
Copyright (c) 1998, 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
pnp.c
|
|
|
|
Abstract:
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Notes:
|
|
|
|
|
|
--*/
|
|
|
|
#include "usbverfy.h"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text (PAGE, UsbVerify_AddDevice)
|
|
#pragma alloc_text (PAGE, UsbVerify_InitializeFromRegistry)
|
|
#pragma alloc_text (PAGE, UsbVerify_OpenServiceParameters)
|
|
#pragma alloc_text (PAGE, UsbVerify_PnP)
|
|
#pragma alloc_text (PAGE, UsbVerify_QueryKey)
|
|
#pragma alloc_text (PAGE, UsbVerify_StartDevice)
|
|
#endif
|
|
|
|
// {F16328AF-4480-4b18-B028-51301BEB166D}
|
|
const GUID GUID_USB_VERIFY =
|
|
{ 0xf16328afL, 0x4480, 0x4b18, { 0xb0, 0x28, 0x51, 0x30, 0x1b, 0xeb, 0x16, 0x6d } };
|
|
|
|
NTSTATUS
|
|
UsbVerify_QueryKey (
|
|
IN HANDLE Handle,
|
|
IN PWCHAR ValueNameString,
|
|
OUT PVOID Data,
|
|
IN ULONG DataLength
|
|
)
|
|
{
|
|
PKEY_VALUE_FULL_INFORMATION fullInfo;
|
|
NTSTATUS status;
|
|
UNICODE_STRING valueName;
|
|
ULONG length;
|
|
|
|
PAGED_CODE();
|
|
|
|
RtlInitUnicodeString(&valueName, ValueNameString);
|
|
|
|
length = sizeof (KEY_VALUE_FULL_INFORMATION)
|
|
+ valueName.MaximumLength + DataLength;
|
|
|
|
fullInfo = ExAllocatePool (PagedPool, length);
|
|
|
|
if (fullInfo) {
|
|
status = ZwQueryValueKey(Handle,
|
|
&valueName,
|
|
KeyValueFullInformation,
|
|
fullInfo,
|
|
length,
|
|
&length);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
// ASSERT(DataLength == fullInfo->DataLength);
|
|
RtlCopyMemory(Data,
|
|
((PUCHAR) fullInfo) + fullInfo->DataOffset,
|
|
fullInfo->DataLength);
|
|
}
|
|
|
|
ExFreePool(fullInfo);
|
|
}
|
|
else {
|
|
status = STATUS_NO_MEMORY;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
HANDLE
|
|
UsbVerify_OpenServiceParameters(
|
|
PUSB_VERIFY_DEVICE_EXTENSION DeviceExtension
|
|
)
|
|
{
|
|
OBJECT_ATTRIBUTES oa;
|
|
UNICODE_STRING parameters;
|
|
HANDLE hService, hParameters = NULL;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
InitializeObjectAttributes(
|
|
&oa,
|
|
UsbVerify_GetRegistryPath(DeviceExtension->Self->DriverObject),
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
(PSECURITY_DESCRIPTOR) NULL);
|
|
|
|
//
|
|
// Try to create/open the service key. The key should always exist
|
|
// for Win2k but may or may not need to be created if this is Win9x.
|
|
// However, for simplicity's sake, ZwCreateKey() will be used on
|
|
// both OSs as it acts like open if the key is already created.
|
|
//
|
|
// Previous code was:
|
|
//
|
|
// status = ZwOpenKey(&hService, KEY_ALL_ACCESS, &oa);
|
|
//
|
|
|
|
status = ZwCreateKey (&hService,
|
|
KEY_ALL_ACCESS,
|
|
&oa,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
NULL);
|
|
|
|
if (NT_SUCCESS (status))
|
|
{
|
|
RtlInitUnicodeString(¶meters, L"Parameters");
|
|
InitializeObjectAttributes (&oa,
|
|
¶meters,
|
|
OBJ_CASE_INSENSITIVE,
|
|
hService,
|
|
(PSECURITY_DESCRIPTOR) NULL);
|
|
|
|
ZwOpenKey (&hParameters, KEY_ALL_ACCESS, &oa);
|
|
ZwClose(hService);
|
|
}
|
|
else
|
|
{
|
|
DbgPrint("ZwCreateKey failed with status 0x%08x\n", status);
|
|
}
|
|
|
|
return hParameters;
|
|
}
|
|
|
|
VOID
|
|
UsbVerify_InitializeFromRegistry(
|
|
PUSB_VERIFY_DEVICE_EXTENSION DeviceExtension,
|
|
HANDLE Handle
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
UsbVerify_QueryKey(Handle,
|
|
USB_VERIFY_FLAGS_SZ,
|
|
&DeviceExtension->VerifyFlags,
|
|
sizeof(DeviceExtension->VerifyFlags));
|
|
|
|
UsbVerify_QueryKey(Handle,
|
|
USB_LOG_FLAGS_SZ,
|
|
&DeviceExtension->LogFlags,
|
|
sizeof(DeviceExtension->LogFlags));
|
|
|
|
UsbVerify_QueryKey(Handle,
|
|
USB_VERIFY_LOGSIZE_SZ,
|
|
&DeviceExtension->LogSize,
|
|
sizeof(DeviceExtension->LogSize));
|
|
|
|
UsbVerify_QueryKey(Handle,
|
|
USB_PRINT_FLAGS_SZ,
|
|
&DeviceExtension->PrintFlags,
|
|
sizeof(DeviceExtension->PrintFlags));
|
|
|
|
UsbVerify_QueryKey(Handle,
|
|
USB_WARNINGS_AS_ERRORS_SZ,
|
|
&DeviceExtension->TreatWarningsAsErrors,
|
|
sizeof(DeviceExtension->TreatWarningsAsErrors));
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
UsbVerify_AddDevice(
|
|
IN PDRIVER_OBJECT Driver,
|
|
IN PDEVICE_OBJECT PDO
|
|
)
|
|
{
|
|
PUSB_VERIFY_DEVICE_EXTENSION devExt;
|
|
PDEVICE_OBJECT device;
|
|
HANDLE hKey, hParameters;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
|
|
status = IoCreateDevice(Driver,
|
|
sizeof(USB_VERIFY_DEVICE_EXTENSION),
|
|
NULL,
|
|
FILE_DEVICE_NULL,
|
|
0,
|
|
FALSE,
|
|
&device
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
return (status);
|
|
}
|
|
|
|
RtlZeroMemory(device->DeviceExtension, sizeof(USB_VERIFY_DEVICE_EXTENSION));
|
|
|
|
devExt = GetExtension(device);
|
|
devExt->TopOfStack = IoAttachDeviceToDeviceStack(device, PDO);
|
|
|
|
ASSERT(devExt->TopOfStack);
|
|
|
|
devExt->Self = device;
|
|
devExt->PDO = PDO;
|
|
devExt->PowerState = PowerDeviceD0;
|
|
|
|
devExt->VerifyState = Uninitialized;
|
|
|
|
UsbVerify_InitializeInterfaceListLock(devExt);
|
|
devExt->InterfaceList = NULL;
|
|
devExt->InterfaceListCount = -1;
|
|
devExt->InterfaceListSize = -1;
|
|
|
|
UsbVerify_InitializeUrbListLock(devExt);
|
|
UsbVerify_InitializeUrbList(devExt);
|
|
|
|
UsbVerify_InitLog(devExt);
|
|
|
|
//
|
|
// Preinitialize in case the values are missing from the reg
|
|
//
|
|
devExt->VerifyFlags = VERIFY_FLAGS_DEFAULT;
|
|
devExt->LogFlags = LOG_FLAGS_DEFAULT;
|
|
devExt->LogSize = LOG_SIZE_DEFAULT;
|
|
devExt->PrintFlags = PRINT_FLAGS_DEFAULT;
|
|
|
|
devExt->TreatWarningsAsErrors = FALSE;
|
|
|
|
//
|
|
// Read values from the sevices\parameters key first.
|
|
// Then read from the devnode.
|
|
//
|
|
// The devnode values will override the global values
|
|
//
|
|
|
|
hParameters = UsbVerify_OpenServiceParameters(devExt);
|
|
|
|
if (hParameters != NULL) {
|
|
UsbVerify_InitializeFromRegistry(devExt, hParameters);
|
|
ZwClose(hParameters);
|
|
}
|
|
|
|
status = IoOpenDeviceRegistryKey(devExt->PDO,
|
|
PLUGPLAY_REGKEY_DEVICE,
|
|
STANDARD_RIGHTS_READ,
|
|
&hKey);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
UsbVerify_InitializeFromRegistry(devExt, hKey);
|
|
ZwClose(hKey);
|
|
|
|
}
|
|
|
|
device->Flags |= (DO_BUFFERED_IO | DO_POWER_PAGABLE);
|
|
device->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
#ifdef DO_INTERFACE
|
|
status = IoRegisterDeviceInterface(PDO,
|
|
(LPGUID)&GUID_USB_VERIFY,
|
|
NULL,
|
|
&devExt->SymbolicLinkName);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
IoDeleteDevice(device);
|
|
}
|
|
#endif
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
NTSTATUS temp;
|
|
WCHAR dd[512];
|
|
ULONG len;
|
|
UNICODE_STRING uniDD;
|
|
ANSI_STRING ansiDD;
|
|
|
|
temp = IoGetDeviceProperty(devExt -> PDO,
|
|
DevicePropertyDeviceDescription,
|
|
sizeof(dd),
|
|
dd,
|
|
&len);
|
|
|
|
if (NT_SUCCESS(temp))
|
|
{
|
|
RtlInitUnicodeString(&uniDD, dd);
|
|
|
|
temp = RtlUnicodeStringToAnsiString(&ansiDD, &uniDD, TRUE);
|
|
|
|
if (NT_SUCCESS(temp))
|
|
{
|
|
DbgPrint("Usbverifier loaded on %s\n", ansiDD.Buffer);
|
|
RtlFreeAnsiString(&ansiDD);
|
|
}
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
UsbVerify_SendIrpSynchronously(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp
|
|
)
|
|
{
|
|
KEVENT event;
|
|
NTSTATUS status;
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|
KeInitializeEvent(&event,
|
|
SynchronizationEvent,
|
|
FALSE
|
|
);
|
|
|
|
IoSetCompletionRoutine(Irp,
|
|
(PIO_COMPLETION_ROUTINE) UsbVerify_Complete,
|
|
&event,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE); // No need for Cancel
|
|
|
|
status = IoCallDriver(DeviceObject, Irp);
|
|
|
|
if (STATUS_PENDING == status) {
|
|
KeWaitForSingleObject(
|
|
&event,
|
|
Executive, // Waiting for reason of a driver
|
|
KernelMode, // Waiting in kernel mode
|
|
FALSE, // No allert
|
|
NULL); // No timeout
|
|
|
|
status = Irp->IoStatus.Status;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
#define UsbVerify_LogPnpEvent(devExt, irp) \
|
|
if ((devExt)->LogFlags & LOG_PNP) { \
|
|
USB_VERIFY_LOG_ENTRY logEntry; \
|
|
RtlZeroMemory(&logEntry, sizeof(logEntry)); \
|
|
logEntry.Type = LOG_PNP; \
|
|
logEntry.u.PnpEvent.MinorFunction = IoGetCurrentIrpStackLocation((irp))->MinorFunction; \
|
|
UsbVerify_Log(devExt, &logEntry); \
|
|
}
|
|
|
|
NTSTATUS
|
|
UsbVerify_PnP(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the dispatch routine for plug and play irps
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the device object.
|
|
|
|
Irp - Pointer to the request packet.
|
|
|
|
Return Value:
|
|
|
|
Status is returned.
|
|
|
|
--*/
|
|
{
|
|
PUSB_VERIFY_DEVICE_EXTENSION devExt;
|
|
PIO_STACK_LOCATION stack;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
|
|
devExt = GetExtension(DeviceObject);
|
|
stack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
switch (stack->MinorFunction) {
|
|
case IRP_MN_START_DEVICE:
|
|
|
|
//
|
|
// The device is starting.
|
|
//
|
|
// We cannot touch the device (send it any non pnp irps) until a
|
|
// start device has been passed down to the lower drivers.
|
|
//
|
|
|
|
status = UsbVerify_SendIrpSynchronously(devExt->TopOfStack, Irp);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
|
|
//
|
|
// As we are successfully now back from our start device
|
|
// we can do work.
|
|
//
|
|
|
|
UsbVerify_LogPnpEvent(devExt, Irp);
|
|
UsbVerify_StartDevice(devExt);
|
|
}
|
|
|
|
//
|
|
// We must now complete the IRP, since we stopped it in the
|
|
// completion routine with MORE_PROCESSING_REQUIRED.
|
|
//
|
|
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
break;
|
|
|
|
case IRP_MN_SURPRISE_REMOVAL:
|
|
//
|
|
// Same as a remove device, but don't call IoDetach or IoDeleteDevice
|
|
//
|
|
devExt->VerifyState = SurpriseRemoved;
|
|
UsbVerify_LogPnpEvent(devExt, Irp);
|
|
|
|
// Remove code here
|
|
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
status = IoCallDriver(devExt->TopOfStack, Irp);
|
|
break;
|
|
|
|
case IRP_MN_REMOVE_DEVICE:
|
|
|
|
devExt->VerifyState = Removed;
|
|
UsbVerify_LogPnpEvent(devExt, Irp);
|
|
|
|
UsbVerify_ASSERT(devExt->HasFrameLengthControl == FALSE,
|
|
devExt->Self,
|
|
Irp,
|
|
NULL);
|
|
|
|
//
|
|
// NOTE: it is unclear where we should check for any URBs that are still
|
|
// pending. I am concerned that many USB clients will leave
|
|
// URBs pended and will let USBD clean up the URBs upon removal.
|
|
// I am not sure if this is by design or not.
|
|
//
|
|
// If we don't check before the remove is sent, we definitely/
|
|
// need to check afterwards
|
|
//
|
|
|
|
// UsbVerify_CheckPendingUrbs(devExt);
|
|
|
|
status = UsbVerify_SendIrpSynchronously(devExt->TopOfStack, Irp);
|
|
|
|
UsbVerify_RemoveDevice(devExt);
|
|
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
break;
|
|
|
|
//
|
|
// We just want to log these events
|
|
//
|
|
case IRP_MN_QUERY_REMOVE_DEVICE:
|
|
case IRP_MN_QUERY_STOP_DEVICE:
|
|
case IRP_MN_CANCEL_REMOVE_DEVICE:
|
|
case IRP_MN_CANCEL_STOP_DEVICE:
|
|
case IRP_MN_STOP_DEVICE:
|
|
UsbVerify_LogPnpEvent(devExt, Irp);
|
|
|
|
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
|
|
case IRP_MN_QUERY_DEVICE_RELATIONS:
|
|
case IRP_MN_QUERY_INTERFACE:
|
|
case IRP_MN_QUERY_CAPABILITIES:
|
|
case IRP_MN_QUERY_DEVICE_TEXT:
|
|
case IRP_MN_QUERY_RESOURCES:
|
|
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
|
|
case IRP_MN_READ_CONFIG:
|
|
case IRP_MN_WRITE_CONFIG:
|
|
case IRP_MN_EJECT:
|
|
case IRP_MN_SET_LOCK:
|
|
case IRP_MN_QUERY_ID:
|
|
case IRP_MN_QUERY_PNP_DEVICE_STATE:
|
|
default:
|
|
//
|
|
// Here the filter driver might modify the behavior of these IRPS
|
|
// Please see PlugPlay documentation for use of these IRPs.
|
|
//
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
status = IoCallDriver(devExt->TopOfStack, Irp);
|
|
break;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
VOID
|
|
UsbVerify_StartDevice(
|
|
PUSB_VERIFY_DEVICE_EXTENSION DeviceExtension
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
DeviceExtension->VerifyState = Started;
|
|
|
|
if (!DeviceExtension->Initialized) {
|
|
#ifdef DO_INTERFACE
|
|
IoSetDeviceInterfaceState(&DeviceExtension->SymbolicLinkName, TRUE);
|
|
#endif
|
|
DeviceExtension->Initialized = TRUE;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
UsbVerify_RemoveDevice(
|
|
PUSB_VERIFY_DEVICE_EXTENSION DeviceExtension
|
|
)
|
|
{
|
|
KIRQL irql;
|
|
|
|
#ifdef DO_INTERFACE
|
|
IoSetDeviceInterfaceState(&DeviceExtension->SymbolicLinkName, FALSE);
|
|
RtlFreeUnicodeString(&DeviceExtension->SymbolicLinkName);
|
|
#endif
|
|
|
|
UsbVerify_FreePendingUrbsList(DeviceExtension);
|
|
|
|
UsbVerify_CheckReplacedUrbs(DeviceExtension);
|
|
|
|
UsbVerify_LockInterfaceList(DeviceExtension, irql);
|
|
UsbVerify_ClearInterfaceList(DeviceExtension, RemoveDeviceRemoved);
|
|
UsbVerify_UnlockInterfaceList(DeviceExtension, irql);
|
|
|
|
UsbVerify_DestroyLog(DeviceExtension);
|
|
|
|
//
|
|
// Clean up all allocated memory
|
|
//
|
|
|
|
IoDetachDevice(DeviceExtension->TopOfStack);
|
|
IoDeleteDevice(DeviceExtension->Self);
|
|
}
|