Why is my IRP being cancelled?

Continuing my quest to enumerate the path between the HCD and my usb device,
I’m stuck at the last step in the process.

I am using the device serial number to determine whether the device attached
to the port
I’m currently enumerating is actually the device for my device object.

When I detect a usb device, I create an Irp to send a
IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION to request the serial number
of the device attached to the port on the hub being enumerated.

If my device is connected to a port on an external hub, everything goes
great
and I am able to get the serial number string descriptor.

However, if my device is connected directly to a port on the root hub for an
HCD, IoCallDriver returns STATUS_CANCELLED.

Any idea why my irp would be cancelled in this case?

Here’s the relevant code I use to build the Irp:

// Build the string descriptor request

ULONG ulBytesRequested = sizeof(USB_DESCRIPTOR_REQUEST)

  • sizeof(USB_STRING_DESCRIPTOR)
  • MAXIMUM_USB_STRING_LENGTH;

PUSB_DESCRIPTOR_REQUEST pstStringDescRequest = (PUSB_DESCRIPTOR_REQUEST)
ExAllocatePool ( NonPagedPool, ulBytesRequested );

RtlZeroMemory ( pstStringDescRequest, ulBytesRequested );

pstStringDescRequest->ConnectionIndex = ulConnectionIndex_;
pstStringDescRequest->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE
<< 8)
| iSerialNumberIndex_;
pstStringDescRequest->SetupPacket.wIndex = usLanguageId_;
pstStringDescRequest->SetupPacket.wLength = (USHORT)
MAXIMUM_USB_STRING_LENGTH;

// Build the IRP

KeInitializeEvent ( &event, NotificationEvent, FALSE );

Irp = IoBuildDeviceIoControlRequest

IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, // ioctl
pHubFdo_, // target device object
pstStringDescRequest, ulBytesRequested, // input buffer and
length
pstStringDescRequest, ulBytesRequested, // output buffer and
length
FALSE, // not an internal
device control
&event, // event to signal
completion
&iostatus ); // completion status

// Send it and wait for a response

NTSTATUS status = IoCallDriver ( pHubFdo_, Irp );
if ( status == STATUS_PENDING )
{
KeWaitForSingleObject ( &event, Executive, KernelMode, FALSE, NULL );
status = iostatus.Status;
}