2025-04-27 07:49:33 -04:00

763 lines
27 KiB
C

/*--
Copyright (c) 1998, 1999 Microsoft Corporation
Module Name:
urb.c
Abstract:
Environment:
Kernel mode only.
Notes:
--*/
#include "usbverfy.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text (PAGE, UsbVerify_CheckReplacedUrbs)
#endif
#define COMPUTE_SIZE ((USHORT) 0xFFFF)
USHORT FunctionToUrbLength[] =
{
/* URB_FUNCTION_SELECT_CONFIGURATION 0x0000 */ COMPUTE_SIZE, // sizeof(struct _URB_SELECT_CONFIGURATION),
/* URB_FUNCTION_SELECT_INTERFACE 0x0001 */ COMPUTE_SIZE, // sizeof(struct _URB_SELECT_INTERFACE),
/* URB_FUNCTION_ABORT_PIPE 0x0002 */ sizeof(struct _URB_PIPE_REQUEST),
/* URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL 0x0003 */ sizeof(struct _URB_FRAME_LENGTH_CONTROL),
/* URB_FUNCTION_RELEASE_FRAME_LENGTH_CONTROL 0x0004 */ sizeof(struct _URB_FRAME_LENGTH_CONTROL),
/* URB_FUNCTION_GET_FRAME_LENGTH 0x0005 */ sizeof(struct _URB_GET_FRAME_LENGTH),
/* URB_FUNCTION_SET_FRAME_LENGTH 0x0006 */ sizeof(struct _URB_SET_FRAME_LENGTH),
/* URB_FUNCTION_GET_CURRENT_FRAME_NUMBER 0x0007 */ sizeof(struct _URB_GET_CURRENT_FRAME_NUMBER),
/* URB_FUNCTION_CONTROL_TRANSFER 0x0008 */ sizeof(struct _URB_CONTROL_TRANSFER),
/* URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER 0x0009 */ sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
/* URB_FUNCTION_ISOCH_TRANSFER 0x000A */ COMPUTE_SIZE, // sizeof(struct _URB_ISOCH_TRANSFER),
/* URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE 0x000B */ sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST ),
/* URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE 0x000C */ sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST ),
/* URB_FUNCTION_SET_FEATURE_TO_DEVICE 0x000D */ sizeof(struct _URB_CONTROL_FEATURE_REQUEST ),
/* URB_FUNCTION_SET_FEATURE_TO_INTERFACE 0x000E */ sizeof(struct _URB_CONTROL_FEATURE_REQUEST ),
/* URB_FUNCTION_SET_FEATURE_TO_ENDPOINT 0x000F */ sizeof(struct _URB_CONTROL_FEATURE_REQUEST ),
/* URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE 0x0010 */ sizeof(struct _URB_CONTROL_FEATURE_REQUEST ),
/* URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE 0x0011 */ sizeof(struct _URB_CONTROL_FEATURE_REQUEST ),
/* URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT 0x0012 */ sizeof(struct _URB_CONTROL_FEATURE_REQUEST ),
/* URB_FUNCTION_GET_STATUS_FROM_DEVICE 0x0013 */ sizeof(struct _URB_CONTROL_GET_STATUS_REQUEST ),
/* URB_FUNCTION_GET_STATUS_FROM_INTERFACE 0x0014 */ sizeof(struct _URB_CONTROL_GET_STATUS_REQUEST ),
/* URB_FUNCTION_GET_STATUS_FROM_ENDPOINT 0x0015 */ sizeof(struct _URB_CONTROL_GET_STATUS_REQUEST ),
/* URB_FUNCTION_RESERVED0 0x0016 */ 0x0,
/* URB_FUNCTION_VENDOR_DEVICE 0x0017 */ sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST ),
/* URB_FUNCTION_VENDOR_INTERFACE 0x0018 */ sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST ),
/* URB_FUNCTION_VENDOR_ENDPOINT 0x0019 */ sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST ),
/* URB_FUNCTION_CLASS_DEVICE 0x001A */ sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST ),
/* URB_FUNCTION_CLASS_INTERFACE 0x001B */ sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST ),
/* URB_FUNCTION_CLASS_ENDPOINT 0x001C */ sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST ),
/* URB_FUNCTION_RESERVED 0x001D */ 0x0,
/* URB_FUNCTION_RESET_PIPE 0x001E */ sizeof(struct _URB_PIPE_REQUEST ),
/* URB_FUNCTION_CLASS_OTHER 0x001F */ sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST ),
/* URB_FUNCTION_VENDOR_OTHER 0x0020 */ sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST ),
/* URB_FUNCTION_GET_STATUS_FROM_OTHER 0x0021 */ sizeof(struct _URB_CONTROL_GET_STATUS_REQUEST ),
/* URB_FUNCTION_CLEAR_FEATURE_TO_OTHER 0x0022 */ sizeof(struct _URB_CONTROL_FEATURE_REQUEST ),
/* URB_FUNCTION_SET_FEATURE_TO_OTHER 0x0023 */ sizeof(struct _URB_CONTROL_FEATURE_REQUEST ),
/* URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT 0x0024 */ sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST ),
/* URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT 0x0025 */ sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST ),
/* URB_FUNCTION_GET_CONFIGURATION 0x0026 */ sizeof(struct _URB_CONTROL_GET_CONFIGURATION_REQUEST ),
/* URB_FUNCTION_GET_INTERFACE 0x0027 */ sizeof(struct _URB_CONTROL_GET_INTERFACE_REQUEST ),
/* URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE 0x0028 */ sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST ),
/* URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE 0x0029 */ sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST ),
};
#define FUNCTION_TO_URB_LENGTH_MAX (sizeof(FunctionToUrbLength) / sizeof(USHORT))
USHORT
UsbVerify_DetermineInterfaceSize(
PUSB_VERIFY_DEVICE_EXTENSION DeviceExtension,
PURB Urb,
PUSBD_INTERFACE_INFORMATION Interface
)
{
USHORT minimumLength;
//
// This assert is an iffy one. It is possible that a device can
// set a zero BW interface which could be either an alternate setting
// that contains 1 EP with a MaxPacketSize of 0 or an 0 EP interface.
// Right now we'll leave this in and just choke on most streaming
// devices that rachet down on shutting off.
//
// NOTE: This assert needs to be revisited for further determination
// of its validity. At a minimum, the above behavior should
// be documented somewhere.
//
UsbVerify_ASSERT(Interface->NumberOfPipes > 0,
DeviceExtension->Self,
NULL,
Urb);
//
// Calculate the minimum required length of the interface field. This must
// equal the sizeof interface plus any room for the pipe information.
// We subtract the sizeof(USBD_PIPE_INFORMATION) from the interface
// size since an interface doesn't have to have any pipes but
// sizeof(USBD_INTERFACE_INFORMATION) returns the size of one pipe.
//
minimumLength = sizeof(USBD_INTERFACE_INFORMATION) -
sizeof(USBD_PIPE_INFORMATION) +
Interface -> NumberOfPipes * sizeof(USBD_PIPE_INFORMATION);
if (Interface->Length)
{
//
// Check that the reported interface length is at least the size
// of the minimum length.
//
// NOTE: Need to find a better way to report the mimimum length
// to the user. This is the same problem as with
// verifying the overall URB length.
//
// NOTE: Should this be an == instead of >= to perform tighter
// restrictions. Doing so would help verify that the
// length field is accurate and not just some bogus
// number that happened to be bigger than minimum length.
// Are there reasons a client may legally specify a larger
// size?
//
UsbVerify_ASSERT(Interface->Length >= minimumLength,
DeviceExtension->Self,
NULL,
Urb);
return Interface->Length;
}
else {
//
// Size of the Interface field
//
return (minimumLength);
}
}
USHORT
UsbVerify_DetermineUrbLength(
PUSB_VERIFY_DEVICE_EXTENSION DeviceExtension,
PURB Urb
)
{
USHORT length, function;
function = Urb->UrbHeader.Function;
if (function < FUNCTION_TO_URB_LENGTH_MAX) {
length = FunctionToUrbLength[function];
if (length != 0 && length != COMPUTE_SIZE) {
return length;
}
}
else {
UsbVerify_Print(DeviceExtension, PRINT_ALWAYS,
("Uknnown function 0x%x with length of 0!\n",
(ULONG) function));
return (USHORT) 0x0;
}
//
// Check to see if the user is allowed to send this URB
//
if (length == 0) {
UsbVerify_Assert("Client driver is not allowed to send this urb!",
DeviceExtension->Self, NULL, Urb, NULL);
return 0;
}
//
// length == COMPUTE_SIZE. This means we need to do some math to figure
// out the size that is required
//
switch (function) {
case URB_FUNCTION_SELECT_CONFIGURATION:
//
// The UrbSelectConfiguration size should be at least equal to
// sizeof(UrbSelectConfiguration). This would be true only when
// the configuration is being deselected (ConfigurationDescriptor ==
// NULL). Otherwise, calculate the variable length portion that is
// the interface information. Since, sizeof(UrbSelectConfiguration)
// contains the size of the Interface field, subtract that off because
// the value returned by UsbVerify_DeterminteInterfaceSize contains
// the size of the Interface field as well as the memory hanging
// on after it.
//
length = (USHORT) (sizeof(Urb->UrbSelectConfiguration));
if (NULL != Urb->UrbSelectConfiguration.ConfigurationDescriptor)
{
length -= sizeof(Urb->UrbSelectConfiguration.Interface);
length += UsbVerify_DetermineInterfaceSize(DeviceExtension,
Urb,
&Urb->UrbSelectConfiguration.Interface);
}
UsbVerify_Print(DeviceExtension, PRINT_URB_INFO,
("select config computed size = 0x%x bytes\n", (ULONG) length));
break;
case URB_FUNCTION_SELECT_INTERFACE:
//
// The sizeof UrbSelectInterface contains the size of the Interface
// field. We want to get subtract that off because the value returned by
// UsbVerify_DeterminteInterfaceSize contains the size of the Interface
// field as well as the memory hanging on after it
//
length = (USHORT)
(sizeof(Urb->UrbSelectInterface) -
sizeof(Urb->UrbSelectInterface.Interface)) +
UsbVerify_DetermineInterfaceSize(DeviceExtension,
Urb,
&Urb->UrbSelectInterface.Interface);
UsbVerify_Print(DeviceExtension, PRINT_URB_INFO,
("select interface computed size = 0x%x bytes\n", (ULONG) length));
break;
case URB_FUNCTION_ISOCH_TRANSFER:
UsbVerify_ASSERT(Urb->UrbIsochronousTransfer.NumberOfPackets > 0,
DeviceExtension->Self,
NULL,
Urb);
length = sizeof(Urb->UrbIsochronousTransfer) +
(sizeof(Urb->UrbIsochronousTransfer.IsoPacket[0]) *
(Urb->UrbIsochronousTransfer.NumberOfPackets - 1));
UsbVerify_Print(DeviceExtension, PRINT_URB_INFO,
("isoch transfer computed size = 0x%x bytes\n", (ULONG) length));
break;
default:
UsbVerify_Print(DeviceExtension, PRINT_URB_ERROR,
("need to add a case for funciton 0x%x\n", (ULONG) function));
DbgBreakPoint();
length = 0;
}
return length;
}
VOID
UsbVerify_PreProcessUrb(
PUSB_VERIFY_DEVICE_EXTENSION DeviceExtension,
PIRP Irp,
PURB *OriginalUrb
)
{
PURB urb, newUrb = NULL;
USHORT expectedUrbLength;
urb = URB_FROM_IRP(Irp);
*OriginalUrb = NULL;
//
// All URBs must definitely be sent only after START_DEVICE has been sent
// down and up the stack. Most USB clients do not handle SURPRISE_REMOVE,
// they will continue to send requests in that state.
//
UsbVerify_ASSERT((DeviceExtension->VerifyState == Started) ||
(DeviceExtension->VerifyState == SurpriseRemoved),
DeviceExtension->Self,
Irp,
urb);
UsbVerify_ASSERT(DeviceExtension->PowerState == PowerDeviceD0,
DeviceExtension->Self,
Irp,
urb);
if (UsbVerify_CheckVerifyFlags(DeviceExtension, VERIFY_TEST_MEMORY)) {
//
// NOTE implement this
//
// MmProbeForWrite () ?
// ExQueryPoolBlockSize () ?
// any Mm function to verify the pool?
}
//
// Check the length that the calling driver passed in to the urb
// function. We should be able to determine the expected length in
// all cases and the length field should match that length.
//
expectedUrbLength = UsbVerify_DetermineUrbLength(DeviceExtension, urb);
UsbVerify_Print(DeviceExtension, PRINT_URB_INFO,
("expected urb length = 0x%x bytes\n", expectedUrbLength));
UsbVerify_ASSERT(urb->UrbHeader.Length == expectedUrbLength,
DeviceExtension->Self,
Irp,
urb);
if (UsbVerify_CheckVerifyFlags(DeviceExtension, VERIFY_REPLACE_URBS)) {
if (0 == expectedUrbLength)
{
goto LowMemory;
}
//
// Can't use AllocStruct because the urb size can be easily be bigger
// then sizeof(URB)
//
newUrb = (PURB) ExAllocatePool (NonPagedPool, expectedUrbLength);
if (newUrb != NULL) {
//
// Copy the contents into the new urb and then fill the original with
// USB_VERIFY_FULL. We will copy back the contents when we are done
// in the completion routine.
//
RtlCopyMemory(newUrb, urb, expectedUrbLength);
newUrb -> UrbHeader.Length = expectedUrbLength;
RtlFillMemory(urb, expectedUrbLength, USB_VERIFY_FILL);
//
// Replace the caller supplied URB with ours
//
URB_FROM_IRP(Irp) = newUrb;
*OriginalUrb = urb;
UsbVerify_Print(DeviceExtension, PRINT_URB_INFO,
("Replacing urb\n"
"\t Original URB 0x%x\n"
"\t Verify URB 0x%x\n"
"\t in IRP 0x%x on device 0x%x\n",
urb, newUrb, Irp, DeviceExtension->Self));
}
else {
LowMemory:
//
// No memory! Behave as if the replace urb flag is not set
//
InterlockedIncrement(&DeviceExtension->ReplaceUrbsLowMemoryCount);
}
}
if (UsbVerify_CheckVerifyFlags(DeviceExtension, VERIFY_TRACK_URBS)) {
PUSB_VERIFY_TRACK_URB verify;
PLIST_ENTRY entry;
KIRQL irql;
//
// Make sure the client is reusing the same URB in two different IRPs.
// According to JD, some driver writers actually try to do this!
//
UsbVerify_LockUrbList(DeviceExtension, irql);
for (entry = DeviceExtension->UrbList.Flink;
entry != &DeviceExtension->UrbList;
/* increment handled before we free the struct */ ) {
verify = CONTAINING_RECORD(entry, USB_VERIFY_TRACK_URB, Link);
//
// Any previous client sent URBs will be in verify->Urb (we are NOT
// replacing URBs( or in verify->OriginalUrb (we ARE replacing URBs)
//
UsbVerify_ASSERT(verify->Urb != urb && verify->OriginalUrb != urb,
DeviceExtension->Self,
Irp,
urb);
entry = entry->Flink;
}
UsbVerify_UnlockUrbList(DeviceExtension, irql);
verify = AllocStruct(NonPagedPool, USB_VERIFY_TRACK_URB, 1);
if (verify) {
RtlZeroMemory(verify, sizeof(*verify));
verify->Irp = Irp;
if (newUrb) {
verify->Urb = newUrb;
verify->OriginalUrb = urb;
}
else {
verify->Urb = urb;
verify->OriginalUrb = NULL;
}
KeQueryTickCount(&verify->ArrivalTime);
UsbVerify_LockUrbList(DeviceExtension, irql);
InsertTailList(&DeviceExtension->UrbList, &verify->Link);
UsbVerify_UnlockUrbList(DeviceExtension, irql);
}
else {
InterlockedIncrement(&DeviceExtension->UrbListLowMemoryCount);
}
}
InterlockedIncrement(&DeviceExtension->UrbListCount);
}
VOID
UsbVerify_PostProcessUrb(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PURB OldUrb
)
{
PUSB_VERIFY_DEVICE_EXTENSION devExt;
PURB urb;
ULONG urbListCount;
devExt = GetExtension(DeviceObject);
//
// This urb may be an urb we sent in place of OldUrb, if OldUrb != NULL
//
urb = URB_FROM_IRP(Irp);
//
// We always keep (at least) a count of pending urbs
//
urbListCount = InterlockedDecrement(&devExt->UrbListCount);
UsbVerify_ASSERT(urbListCount >= 0, devExt->Self, Irp, urb);
if (UsbVerify_CheckVerifyFlags(devExt, VERIFY_TRACK_URBS)) {
PUSB_VERIFY_TRACK_URB verify;
PLIST_ENTRY entry;
KIRQL irql;
BOOLEAN found = FALSE;
UsbVerify_LockUrbList(devExt, irql);
for (entry = devExt->UrbList.Flink;
entry != &devExt->UrbList;
entry = entry->Flink) {
verify = CONTAINING_RECORD(entry, USB_VERIFY_TRACK_URB, Link);
if (verify->Irp == Irp) {
UsbVerify_ASSERT(urb == verify->Urb, devExt->Self, Irp, urb);
RemoveEntryList(&verify->Link);
found = TRUE;
break;
}
}
UsbVerify_UnlockUrbList(devExt, irql);
if (found) {
ExFreePool(verify);
}
else {
ULONG urbListLowMemoryCount;
//
// We go through the troule of assigning the return value to a local
// variable so it will be easier to inspect this value in the debugger
// if we need to view this value
//
urbListLowMemoryCount =
InterlockedDecrement(&devExt->UrbListLowMemoryCount);
UsbVerify_ASSERT(urbListLowMemoryCount >= 0, devExt->Self, Irp, urb);
}
}
if (UsbVerify_CheckVerifyFlags(devExt, VERIFY_REPLACE_URBS)) {
if (ARGUMENT_PRESENT(OldUrb)) {
PUCHAR buffer, bufferEnd;
buffer = (PUCHAR) OldUrb;
bufferEnd = buffer + urb->UrbHeader.Length;
//
// Make sure the caller hasn't scribbled on the URB.
//
// NTOE: is there a way for us to mark the memory as READ ONLY?
//
for ( ; buffer < bufferEnd; buffer++) {
UsbVerify_ASSERT(*buffer == USB_VERIFY_FILL,
devExt->Self,
Irp,
OldUrb);
}
UsbVerify_Print(devExt, PRINT_URB_INFO,
("returning original URB\n"
"\t Original URB 0x%x\n"
"\t Verify URB 0x%x\n"
"\t in IRP 0x%x on device 0x%x\n",
OldUrb, urb, Irp, devExt->Self));
//
// Copy the contents from our replacement URB into the caller's URB
// NOTE: the length field in the urb that we use in this copy
// is the calculated expected urb length. There may
// be problems if the client was expecting more data in the
// original urb or had not allocated enough space to hold
// everything.
//
RtlCopyMemory(OldUrb, urb, urb->UrbHeader.Length);
//
// We are done with our replacement URB. Free it and set up urb to
// point to valid pool.
//
ExFreePool(urb);
urb = OldUrb;
//
// This is necessary because we are more often than not going to play
// with this urb after this function call. The current URB in the IRP
// has just been freed, so we need to put the old and valid one back
//
URB_FROM_IRP(Irp) = OldUrb;
}
else {
ULONG replaceUrbsLowMemoryCount;
//
// We go through the troule of assigning the return value to a local
// variable so it will be easier to inspect this value in the debugger
// if we need to view this value
//
replaceUrbsLowMemoryCount =
InterlockedDecrement(&devExt->ReplaceUrbsLowMemoryCount);
UsbVerify_ASSERT(replaceUrbsLowMemoryCount >= 0,
devExt->Self, Irp, urb);
}
}
if (UsbVerify_CheckVerifyFlags(devExt, VERIFY_TEST_MEMORY)) {
//
// NOTE: implement this
//
// MmProbeForWrite () ?
// ExQueryPoolBlockSize () ?
// any Mm function to verify the pool?
}
//
// NOTE: should we check anything else on the way back up? Pipes for instance?
//
}
VOID
UsbVerify_FreePendingUrbsList(
PUSB_VERIFY_DEVICE_EXTENSION DeviceExtension
)
{
PUSB_VERIFY_TRACK_URB verify;
PLIST_ENTRY entry;
ULONG urbListCount,
urbListLowMemoryCount;
KIRQL irql;
//
// We go through the trouble of assigning the return value to a local
// variable so it will be easier to inspect this value in the debugger
// if we need to view this value
//
//
// NOTE: Looks like alot of clients don't cancel any of their pending requests
// until after they have the remove device. Perhaps this should be
// guarded by a VerifyFlags (instead of the #if 0) ?
//
urbListCount = InterlockedCompareExchange(&DeviceExtension->UrbListCount,
0,
0);
UsbVerify_ASSERT(urbListCount == 0,
DeviceExtension->Self,
NULL,
NULL);
urbListLowMemoryCount =
InterlockedCompareExchange(&DeviceExtension->UrbListLowMemoryCount,
0,
0);
UsbVerify_ASSERT(urbListLowMemoryCount == 0,
DeviceExtension->Self,
NULL,
NULL);
if (UsbVerify_CheckVerifyFlags(DeviceExtension, VERIFY_TRACK_URBS)) {
UsbVerify_LockUrbList(DeviceExtension, irql);
for (entry = DeviceExtension->UrbList.Flink;
entry != &DeviceExtension->UrbList;
/* increment handled before we free the struct */ ) {
verify = CONTAINING_RECORD(entry, USB_VERIFY_TRACK_URB, Link);
UsbVerify_ASSERT(verify->Urb != NULL && verify->Irp != NULL,
// "pended URB after remove device",
DeviceExtension->Self,
verify->Irp,
verify->Urb);
UsbVerify_LogError(IDS_STALE_URB,
DeviceExtension,
verify->Irp,
verify->Urb);
entry = entry->Flink;
RemoveEntryList(&verify->Link);
ExFreePool(verify);
}
UsbVerify_UnlockUrbList(DeviceExtension, irql);
}
}
VOID
UsbVerify_CheckReplacedUrbs(
PUSB_VERIFY_DEVICE_EXTENSION DeviceExtension
)
{
ULONG replaceUrbsLowMemoryCount;
PAGED_CODE();
//
// We go through the troule of assigning the return value to a local
// variable so it will be easier to inspect this value in the debugger
// if we need to view this value
//
replaceUrbsLowMemoryCount
= InterlockedCompareExchange(&DeviceExtension->ReplaceUrbsLowMemoryCount,
0,
0);
UsbVerify_ASSERT(replaceUrbsLowMemoryCount == 0,
DeviceExtension->Self,
NULL,
NULL);
}
NTSTATUS
UsbVerify_UrbComplete(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
Sanity check an URB on the way back up
--*/
{
PUSB_VERIFY_DEVICE_EXTENSION devExt = GetExtension(DeviceObject);
UsbVerify_PostVerifyUrb(DeviceObject, Irp);
UsbVerify_PostProcessUrb(DeviceObject, Irp, (PURB) Context);
//
// We are done with the irp, return the status code in the irp so the irp
// will progress up the stack
//
UsbVerify_Print(devExt, PRINT_URB_NOISE,
("UrbComplete, returning 0x%x\n", Irp->IoStatus.Status));
if (Irp->PendingReturned) {
IoMarkIrpPending(Irp);
}
//
// the IO completion code looks for STATUS_MORE_PROCESSING_REQUIRED, so any
// other value will do (don't waste valuable cycles dereffing
// Irp->IoStatus.Status)
//
return STATUS_SUCCESS;
}
NTSTATUS
UsbVerify_SendUrbSynchronously(
PUSB_VERIFY_DEVICE_EXTENSION DeviceExtension,
PIRP Irp,
PURB OldUrb
)
{
KEVENT event;
NTSTATUS status;
IoCopyCurrentIrpStackLocationToNext(Irp);
KeInitializeEvent(&event,
SynchronizationEvent,
FALSE
);
//
// Don't use UsbVerify_UrbComplete because its context must be an PURB, not
// a PKEVENT
//
IoSetCompletionRoutine(Irp,
(PIO_COMPLETION_ROUTINE) UsbVerify_Complete,
&event,
TRUE,
TRUE,
TRUE); // No need for Cancel
status = IoCallDriver(DeviceExtension->TopOfStack, 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;
}
UsbVerify_PostProcessUrb(DeviceExtension->Self, Irp, OldUrb);
return status;
}