Creating an URB in filter driver

Hi all,

I have written a lower filter driver(based on toaster filter) to bthusb and I am able to intercept the urb’s in the IoInternalDeviceControl.

My idea is to use sideband method to communicate with the filter driver from application and on certain IoControlCode, I need to create and send a URB to the lower layer.

Is this possible and if yes, how do I go about achieving this?

Mentioned below are the functions that I plan to call in IoDeviceControl routine.

  1. WdfIoTargetCreate
  2. WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME
  3. WdfIoTargetOpen
  4. WDF_REQUEST_SEND_OPTIONS_INIT
  5. WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT
  6. UsbBuildGetDescriptorRequest
  7. WDF_MEMORY_DESCRIPTOR_INIT_BUFFER
  8. WdfIoTargetSendInternalIoctlOthersSynchronously

Is the above sequence right?

BR,
Dhaval

Steps 4-7 are fine, you don’t need to open an iotarget, there is a built in Io target for the stack below you via WdfDeviceGetIoTarget

d

Bent from my phone


From: xxxxx@gmail.commailto:xxxxx
Sent: ?1/?30/?2015 5:29 AM
To: Windows System Software Devs Interest Listmailto:xxxxx
Subject: [ntdev] Creating an URB in filter driver

Hi all,

I have written a lower filter driver(based on toaster filter) to bthusb and I am able to intercept the urb’s in the IoInternalDeviceControl.

My idea is to use sideband method to communicate with the filter driver from application and on certain IoControlCode, I need to create and send a URB to the lower layer.

Is this possible and if yes, how do I go about achieving this?

Mentioned below are the functions that I plan to call in IoDeviceControl routine.

1. WdfIoTargetCreate
2. WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME
3. WdfIoTargetOpen
4. WDF_REQUEST_SEND_OPTIONS_INIT
5. WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT
6. UsbBuildGetDescriptorRequest
6. WDF_MEMORY_DESCRIPTOR_INIT_BUFFER
7. WdfIoTargetSendInternalIoctlOthersSynchronously

Is the above sequence right?

BR,
Dhaval


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer</mailto:xxxxx></mailto:xxxxx>

Hi Doron,

Thanks for the reply and clarification.

I tried using WdfDeviceGetIoTarget() as you mentioned, but I get a BSOD while using this function.
On Dump analysis I found that the WdfDeviceGetIoTarget always returns a NULL pointer.

In the code mentioned below mTarget is always NULL.

VOID
FilterEvtIoDeviceControl(
IN WDFQUEUE Queue,
IN WDFREQUEST Request,
IN size_t OutputBufferLength,
IN size_t InputBufferLength,
IN ULONG IoControlCode
)
{
PFILTER_EXTENSION filterExt;
NTSTATUS status = STATUS_SUCCESS;
WDFDEVICE device;
WDFIOTARGET mTarget;

UNREFERENCED_PARAMETER(OutputBufferLength);
UNREFERENCED_PARAMETER(InputBufferLength);

KdPrint((“Entered FilterEvtIoDeviceControl\n”));

device = WdfIoQueueGetDevice(Queue);
mTarget = WdfDeviceGetIoTarget(WdfIoQueueGetDevice(Queue));

KdPrint(DBGLVL_DEFAULT, (" Entered FilterEvtIoDeviceControl %p - mTarget %p - device\r\n", mTarget, device));

filterExt = FilterGetData(device);

Is my call sequence right?

BR,
Dhaval

Is your WDFDEVICE a PDO or a filter? Filters should get a built in io target, PDOs do not. See https://msdn.microsoft.com/en-us/library/windows/hardware/ff543227(v=vs.85).aspx . What does !wdfkd.wdflogdump (your driver name) say when get NULL back?

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@gmail.com
Sent: Tuesday, February 03, 2015 12:04 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Creating an URB in filter driver

Hi Doron,

Thanks for the reply and clarification.

I tried using WdfDeviceGetIoTarget() as you mentioned, but I get a BSOD while using this function.
On Dump analysis I found that the WdfDeviceGetIoTarget always returns a NULL pointer.

In the code mentioned below mTarget is always NULL.

VOID
FilterEvtIoDeviceControl(
IN WDFQUEUE Queue,
IN WDFREQUEST Request,
IN size_t OutputBufferLength,
IN size_t InputBufferLength,
IN ULONG IoControlCode
)
{
PFILTER_EXTENSION filterExt;
NTSTATUS status = STATUS_SUCCESS;
WDFDEVICE device;
WDFIOTARGET mTarget;

UNREFERENCED_PARAMETER(OutputBufferLength);
UNREFERENCED_PARAMETER(InputBufferLength);

KdPrint((“Entered FilterEvtIoDeviceControl\n”));

device = WdfIoQueueGetDevice(Queue);
mTarget = WdfDeviceGetIoTarget(WdfIoQueueGetDevice(Queue));

KdPrint(DBGLVL_DEFAULT, (" Entered FilterEvtIoDeviceControl %p - mTarget %p - device\r\n", mTarget, device));

filterExt = FilterGetData(device);

Is my call sequence right?

BR,
Dhaval


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Hi Doron,

My WDFDEVICE is a filter.

I have added following code in filter device add.

status = FilterCreateControlDevice(device);

my FilterCreateControlDevice method contains the following code

Use_decl_annotations
NTSTATUS
FilterCreateControlDevice(
WDFDEVICE Device
)
{
PWDFDEVICE_INIT pInit = NULL;
WDFDEVICE controlDevice = NULL;
WDF_OBJECT_ATTRIBUTES controlAttributes;
WDF_IO_QUEUE_CONFIG ioQueueConfig;
BOOLEAN bCreate = FALSE;
NTSTATUS status;
WDFQUEUE queue;
DECLARE_CONST_UNICODE_STRING(ntDeviceName, NTDEVICE_NAME_STRING);
DECLARE_CONST_UNICODE_STRING(symbolicLinkName, SYMBOLIC_NAME_STRING);

PAGED_CODE();

//
// First find out whether any ControlDevice has been created. If the
// collection has more than one device then we know somebody has already
// created or in the process of creating the device.
//
WdfWaitLockAcquire(FilterDeviceCollectionLock, NULL);

if (WdfCollectionGetCount(FilterDeviceCollection) == 1) {
bCreate = TRUE;
}

WdfWaitLockRelease(FilterDeviceCollectionLock);

if (!bCreate) {
//
// Control device is already created. So return success.
//
return STATUS_SUCCESS;
}

KdPrint((“Creating Control Device\n”));

//
//
// In order to create a control device, we first need to allocate a
// WDFDEVICE_INIT structure and set all properties.
//
pInit = WdfControlDeviceInitAllocate(
WdfDeviceGetDriver(Device),
&SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RW_RES_R
//&SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RWX_RES_RWX
);

if (pInit == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto Error;
}

//
// Set exclusive to false so that more than one app can talk to the
// control device simultaneously.
//
WdfDeviceInitSetExclusive(pInit, FALSE);

status = WdfDeviceInitAssignName(pInit, &ntDeviceName);

if (!NT_SUCCESS(status)) {
goto Error;
}

//
// Specify the size of device context
//
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&controlAttributes,
CONTROL_DEVICE_EXTENSION);

status = WdfDeviceCreate(&pInit,
&controlAttributes,
&controlDevice);
if (!NT_SUCCESS(status)) {
goto Error;
}

//
// Create a symbolic link for the control object so that usermode can open
// the device.
//

status = WdfDeviceCreateSymbolicLink(controlDevice,
&symbolicLinkName);

if (!NT_SUCCESS(status)) {
goto Error;
}

//
// Configure the default queue associated with the control device object
// to be Serial so that request passed to EvtIoDeviceControl are serialized.
//

WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig,
WdfIoQueueDispatchSequential);

ioQueueConfig.EvtIoDeviceControl = FilterEvtIoDeviceControl;

//
// Framework by default creates non-power managed queues for
// filter drivers.
//
status = WdfIoQueueCreate(controlDevice,
&ioQueueConfig,
WDF_NO_OBJECT_ATTRIBUTES,
&queue // pointer to default queue
);
if (!NT_SUCCESS(status)) {
goto Error;
}

//
// Control devices must notify WDF when they are done initializing. I/O is
// rejected until this call is made.
//
WdfControlFinishInitializing(controlDevice);

ControlDevice = controlDevice;

return STATUS_SUCCESS;

Error:

if (pInit != NULL) {
WdfDeviceInitFree(pInit);
}

if (controlDevice != NULL) {
//
// Release the reference on the newly created object, since
// we couldn’t initialize it.
//
WdfObjectDelete(controlDevice);
controlDevice = NULL;
}

return status;
}

Is this the right way to create the control device ?

BR,
Dhaval

Control devices don’t have a built in Io target. You need to keep a reference to the filter wdfdevice in the control device’s context and use the filter wdfdevice to send the urb.

d

Bent from my phone


From: xxxxx@gmail.commailto:xxxxx
Sent: ?2/?3/?2015 7:15 AM
To: Windows System Software Devs Interest Listmailto:xxxxx
Subject: RE:[ntdev] Creating an URB in filter driver

Hi Doron,

My WDFDEVICE is a filter.

I have added following code in filter device add.

status = FilterCreateControlDevice(device);

my FilterCreateControlDevice method contains the following code

Use_decl_annotations
NTSTATUS
FilterCreateControlDevice(
WDFDEVICE Device
)
{
PWDFDEVICE_INIT pInit = NULL;
WDFDEVICE controlDevice = NULL;
WDF_OBJECT_ATTRIBUTES controlAttributes;
WDF_IO_QUEUE_CONFIG ioQueueConfig;
BOOLEAN bCreate = FALSE;
NTSTATUS status;
WDFQUEUE queue;
DECLARE_CONST_UNICODE_STRING(ntDeviceName, NTDEVICE_NAME_STRING);
DECLARE_CONST_UNICODE_STRING(symbolicLinkName, SYMBOLIC_NAME_STRING);

PAGED_CODE();

//
// First find out whether any ControlDevice has been created. If the
// collection has more than one device then we know somebody has already
// created or in the process of creating the device.
//
WdfWaitLockAcquire(FilterDeviceCollectionLock, NULL);

if (WdfCollectionGetCount(FilterDeviceCollection) == 1) {
bCreate = TRUE;
}

WdfWaitLockRelease(FilterDeviceCollectionLock);

if (!bCreate) {
//
// Control device is already created. So return success.
//
return STATUS_SUCCESS;
}

KdPrint((“Creating Control Device\n”));

//
//
// In order to create a control device, we first need to allocate a
// WDFDEVICE_INIT structure and set all properties.
//
pInit = WdfControlDeviceInitAllocate(
WdfDeviceGetDriver(Device),
&SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RW_RES_R
//&SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RWX_RES_RWX
);

if (pInit == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto Error;
}

//
// Set exclusive to false so that more than one app can talk to the
// control device simultaneously.
//
WdfDeviceInitSetExclusive(pInit, FALSE);

status = WdfDeviceInitAssignName(pInit, &ntDeviceName);

if (!NT_SUCCESS(status)) {
goto Error;
}

//
// Specify the size of device context
//
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&controlAttributes,
CONTROL_DEVICE_EXTENSION);

status = WdfDeviceCreate(&pInit,
&controlAttributes,
&controlDevice);
if (!NT_SUCCESS(status)) {
goto Error;
}

//
// Create a symbolic link for the control object so that usermode can open
// the device.
//

status = WdfDeviceCreateSymbolicLink(controlDevice,
&symbolicLinkName);

if (!NT_SUCCESS(status)) {
goto Error;
}

//
// Configure the default queue associated with the control device object
// to be Serial so that request passed to EvtIoDeviceControl are serialized.
//

WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig,
WdfIoQueueDispatchSequential);

ioQueueConfig.EvtIoDeviceControl = FilterEvtIoDeviceControl;

//
// Framework by default creates non-power managed queues for
// filter drivers.
//
status = WdfIoQueueCreate(controlDevice,
&ioQueueConfig,
WDF_NO_OBJECT_ATTRIBUTES,
&queue // pointer to default queue
);
if (!NT_SUCCESS(status)) {
goto Error;
}

//
// Control devices must notify WDF when they are done initializing. I/O is
// rejected until this call is made.
//
WdfControlFinishInitializing(controlDevice);

ControlDevice = controlDevice;

return STATUS_SUCCESS;

Error:

if (pInit != NULL) {
WdfDeviceInitFree(pInit);
}

if (controlDevice != NULL) {
//
// Release the reference on the newly created object, since
// we couldn’t initialize it.
//
WdfObjectDelete(controlDevice);
controlDevice = NULL;
}

return status;
}

Is this the right way to create the control device ?

BR,
Dhaval


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer</mailto:xxxxx></mailto:xxxxx>

xxxxx@gmail.com wrote:

Thanks for the reply and clarification.

I tried using WdfDeviceGetIoTarget() as you mentioned, but I get a BSOD while using this function.
On Dump analysis I found that the WdfDeviceGetIoTarget always returns a NULL pointer.

In the code mentioned below mTarget is always NULL.

Lower filter to what? How did you install your filter? Many of the
“toaster” samples create fake devices that do not have lower edges. If
you expect to send URBs, then you had darn well better be in a USB
device stack.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

xxxxx@gmail.com wrote:

My WDFDEVICE is a filter.

No, it’s not.

Your driver is handling two WDFDEVICEs. One of them is a filter in the
USB stack (assuming you installed it on a USB device). The other is a
non-PnP device that stands alone, without being attached to any other
devices at all. Because of that, it has no automatic lower device to
receive requests.

So, all that means is that you need to save the in-stack WDFDEVICE
somewhere in the context space for your control device. When you get a
request on your control device, you just send your requests to the other
device’s I/O target.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Thanks Tim & Doron,

I was able to get WDFDEVICE by storing in control device context and I am also able to get target by using WdfDeviceGetIoTarget().

@Tim
This is a lower filter to BthUSB as mentioned in my initial query.

Dear Doron &Tim,

I tried to build vendor urb and send it to lower layer using WdfIoTargetSendInternalIoctlOthersSynchronously.

But I always get return status of WdfIoTargetSendInternalIoctlOthersSynchronously as
0xc0000001 (STATUS_UNSUCCESSFUL)

Mentioned Below is the code that I am using to build the urb and sending the same to lower layer.

WDF_REQUEST_SEND_OPTIONS syncReqOptions;
USHORT UrbSize = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
pUrb = (PURB)ExAllocatePool(NonPagedPool, UrbSize);

if (pUrb == NULL) {
WdfRequestComplete(Request, status);
return;
}

WDF_REQUEST_SEND_OPTIONS_INIT(
&syncReqOptions,
0
);

WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(
&syncReqOptions,
DEFAULT_CONTROL_TRANSFER_TIMEOUT
);

UsbBuildVendorRequest(
pUrb,
URB_FUNCTION_CLASS_DEVICE,
(USHORT)sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
USBD_TRANSFER_DIRECTION_OUT,
0,
0,
0,
0,
TransferBuffer,
NULL,
TransferBufferLength,
NULL
);

WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(
&urbRequest,
(PVOID)pUrb,
sizeof(URB));

status = WdfIoTargetSendInternalIoctlOthersSynchronously(
mTarget, // VALID target device got from WdfDeviceGetIoTarget()
NULL,
IOCTL_INTERNAL_USB_SUBMIT_URB,
&urbRequest, // URB
NULL,
NULL,
&syncReqOptions,
(PULONG_PTR)&bytesReturned);

if (!NT_SUCCESS(status)) {
KdPrint(" WdfIoTargetSendInternalIoctlOthersSynchronously failed!!! lasterror 0x%0x \r\n", status));
}

Is my call sequence right ?

BR,
Dhaval

On Feb 4, 2015, at 9:00 PM, xxxxx@gmail.com wrote:

I tried to build vendor urb and send it to lower layer using WdfIoTargetSendInternalIoctlOthersSynchronously.

But I always get return status of WdfIoTargetSendInternalIoctlOthersSynchronously as
0xc0000001 (STATUS_UNSUCCESSFUL)

UsbBuildVendorRequest(
pUrb,
URB_FUNCTION_CLASS_DEVICE,
(USHORT)sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
USBD_TRANSFER_DIRECTION_OUT,
0,
0,
0,
0,
TransferBuffer,
NULL,
TransferBufferLength,
NULL
);

If you want to send a vendor request, then you certainly don’t want URB_FUNCTION_CLASS_DEVICE. That can only be used to send requests that are specified in the USB class spec. You probably want URB_FUNCTION_VENDOR_DEVICE.

But do you really want to send Request=0? Where are you getting the information about which requests to send?

Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.