Filtering around mouhid with kmdf

Hi,

I’m trying to rewrite a driver originally written using WDM with the new framework.

The driver is basically a mouse filter driver and was originally loaded in place of mouhid generating ioreads toward the lower part of the stack and feeding the userspace using the connect data callback. In order to populate correctly the ioreads it waits for the first useful create and uses the fileobject on all the subsequent reads that it sends down.

In order to replicate this behavior in wdf, I set a EvtFileCreate, forward synchronously the create and then go through a procedure that ends up with creating a remote iotarget that is initialized with the fileobject.
Then right before starting the reads, I open the iotarget.
(btw, should I call wdfcomplete in the evtfilecreate if I forward it synchronously?)

Now, the reads go through no problem and I get reports as expected but when I use the callback (correctly set, I checked) to post the mouse input, nothing happens. As a matter of fact it seems that some part of the stack is actually stuck somewhere.

I found out that the offending part is the WdfIoTArgetOpen. If I remove that, everything initializes correctly and the callback works (of course with fake data since I don’t have access to th e reports anymore).

I tried pretty much ev erything I could think of, moving the driver around in the stack, creating the iotarget from a completion of the create (instead of being synch) but nothing really helps and I get stuck always in different ways but the bottom line is that I cannot get the reports and at the same time a working upper stack.

What could I have done wrong? Does this suggest anything to anyone?

Thank you in advance,
Marco

You need to complete the create WDFREQUEST in all cases, so yes, even if you fwd’ed it synchronously, you still need to complete it. How are you initializing the open params for the io target in this case?

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@gmail.com
Sent: Thursday, March 10, 2011 4:23 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] Filtering around mouhid with kmdf

Hi,

I’m trying to rewrite a driver originally written using WDM with the new framework.

The driver is basically a mouse filter driver and was originally loaded in place of mouhid generating ioreads toward the lower part of the stack and feeding the userspace using the connect data callback. In order to populate correctly the ioreads it waits for the first useful create and uses the fileobject on all the subsequent reads that it sends down.

In order to replicate this behavior in wdf, I set a EvtFileCreate, forward synchronously the create and then go through a procedure that ends up with creating a remote iotarget that is initialized with the fileobject.
Then right before starting the reads, I open the iotarget.
(btw, should I call wdfcomplete in the evtfilecreate if I forward it synchronously?)

Now, the reads go through no problem and I get reports as expected but when I use the callback (correctly set, I checked) to post the mouse input, nothing happens. As a matter of fact it seems that some part of the stack is actually stuck somewhere.

I found out that the offending part is the WdfIoTArgetOpen. If I remove that, everything initializes correctly and the callback works (of course with fake data since I don’t have access to th e reports anymore).

I tried pretty much ev erything I could think of, moving the driver around in the stack, creating the iotarget from a completion of the create (instead of being synch) but nothing really helps and I get stuck always in different ways but the bottom line is that I cannot get the reports and at the same time a working upper stack.

What could I have done wrong? Does this suggest anything to anyone?

Thank you in advance,
Marco


NTDEV is sponsored by OSR

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,

thank you for your help.

I attached a snippet of the EvtFileCreate code. Actually besides a couple of sanity checks at the beginning is pretty much all of it.
If I run this code and I install the driver in place of mouhid (so no upperfilter/lowfilter key and only needs=mouclass.services in the inf file) I get reports just fine and I do get initialized the connectdata but posting stuff through it doesn’t do anything. My driver creates also a raw pdo in the add device and I never see it enumerated (usually windows would detect it as a device and I never get to that point). So it seems that something is stuck but is not clear what.

If I don’t call WdfIoTargetOpen, the enumeration succeeds but of course no chance to get reports from the device.

If I install the driver as upperfilter of mouhid, reads don’t go through (I guess mouhid refuses them) but I can initialize what you see as nextDevice with

nextDevice = WdfIoTargetWdmGetTargetPhysicalDevice(WdfDeviceGetIoTarget(Device));

so that I target the PDO directly and then again I get the reports but the upper section of the stack is stuck again. Interestingly, if I install the hook in the connectdata so that I get the processed report, I can see the hook being called and I get my reports too but still no way to move the cursor on the screen.

If I install the driver as lowerfilter I have no access to connectdata at all. On top of it, for reasons that I don’t seem to understand, the reads that I see seem to have their buffer in a place that WdfRequestRetrieveOutputBuffer cannot decode.

Under many circumstances, when WdfIoTargetOpen is used I can see ExtFileCreate being called several times (like 20 times).

In any case the driver is initialized as filter.

I hope you see what’s wrong with it because I’m really stumped.

Thanks!
Marco.

---- snippet from EvtFileCreate
WdfRequestGetParameters(Request, &requestParameters);
if(requestParameters.Parameters.Create.SecurityContext->DesiredAccess & FILE_READ_DATA)
{
WDFIOTARGET ioTarget;
DEVICE_OBJECT *nextDevice;
WDF_IO_TARGET_OPEN_PARAMS ioTargetOpenParams;

WDF_REQUEST_SEND_OPTIONS_INIT(&requestSendOptions, WDF_REQUEST_SEND_OPTION_SYNCHRONOUS);
WdfRequestFormatRequestUsingCurrentType(Request);
WdfRequestSend(Request, WdfDeviceGetIoTarget(Device), &requestSendOptions);

if(filterExt->ReadIoTarget == NULL)
{
filterExt->ReadIoTarget = WdfDeviceGetIoTarget(Device);

// Create and open a new remote ioTarget based on the same FILE_OBJECT
if(!NT_SUCCESS(WdfIoTargetCreate(Device, WDF_NO_OBJECT_ATTRIBUTES, &ioTarget)))
{
DebugPrint((“IoTargetCreate failed.\n”));
}

nextDevice = WdfDeviceWdmGetAttachedDevice(Device);
WDF_IO_TARGET_OPEN_PARAMS_INIT_EXISTING_DEVICE(&ioTargetOpenParams, nextDevice);
filterExt->FileObject = IoGetCurrentIrpStackLocation(WdfRequestWdmGetIrp(Request))->FileObject;
ioTargetOpenParams.TargetFileObject = filterExt->FileObject;

DebugPrint((“FileCreate (fo = %x)\n”, filterExt->FileObject));

if(!NT_SUCCESS(WdfIoTargetOpen(ioTarget, &ioTargetOpenParams)))
{
DebugPrint((“IoTargetOpen failed.\n”));
}

filterExt->ReadIoTarget = ioTarget;

if(!NT_SUCCESS(StartHidReader(Device, filterExt->ReportMaxSize)))
{
DebugPrint((“StartHidReader failed.\n”));
}
}
}
else
{
// we really never get here
DebugPrint((“Not a simple FILE_READ_DATA open\n”));

WDF_REQUEST_SEND_OPTIONS_INIT(&requestSendOptions, WDF_REQUEST_SEND_OPTION_SYNCHRONOUS);
WdfRequestFormatRequestUsingCurrentType(Request);
WdfRequestSend(Request, WdfDeviceGetIoTarget(Device), &requestSendOptions);
}

// Complete everything
{
WDF_REQUEST_COMPLETION_PARAMS params;

WdfRequestGetCompletionParams(Request, &params);

WdfRequestComplete(Request, params.IoStatus.Status);
}

— snippet from EvtInternalIoCtl
case IOCTL_INTERNAL_MOUSE_CONNECT:

if (filterExt->UpperConnectData.ClassService != NULL)
{
status = STATUS_SHARING_VIOLATION;
break;
}

status = WdfRequestRetrieveInputBuffer(Request, sizeof(CONNECT_DATA), &connectData, &length);
if(!NT_SUCCESS(status)){
DebugPrint((“WdfRequestRetrieveInputBuffer failed %x\n”, status));
break;
}

filterExt->UpperConnectData = *connectData;

DebugPrint((“ConnectData ClassDeviceObject %x, ClassService %x\n”,
filterExt->UpperConnectData.ClassDeviceObject,
filterExt->UpperConnectData.ClassService));

connectData->ClassDeviceObject = WdfDeviceWdmGetDeviceObject(hDevice);
connectData->ClassService = MouseActivityCallback; // just a logging function. Only assigned when driver is upperfilter.

break;

Do you handle the close on the read file object and tear down the io target? Does WdfIoTargetOpen succeed? Opening an io target the way you are should succeed without sending any io down the stack. If your PDO is not getting created, you are somehow blocking a state changing pnp irp from completing. When you are in that state, I would run !stacks 0 2 mouclass (and with mouhid) to see if there are any stuck stacks with those drivers in them,

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@gmail.com
Sent: Thursday, March 10, 2011 11:31 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Filtering around mouhid with kmdf

Hi Doron,

thank you for your help.

I attached a snippet of the EvtFileCreate code. Actually besides a couple of sanity checks at the beginning is pretty much all of it.
If I run this code and I install the driver in place of mouhid (so no upperfilter/lowfilter key and only needs=mouclass.services in the inf file) I get reports just fine and I do get initialized the connectdata but posting stuff through it doesn’t do anything. My driver creates also a raw pdo in the add device and I never see it enumerated (usually windows would detect it as a device and I never get to that point). So it seems that something is stuck but is not clear what.

If I don’t call WdfIoTargetOpen, the enumeration succeeds but of course no chance to get reports from the device.

If I install the driver as upperfilter of mouhid, reads don’t go through (I guess mouhid refuses them) but I can initialize what you see as nextDevice with

nextDevice = WdfIoTargetWdmGetTargetPhysicalDevice(WdfDeviceGetIoTarget(Device));

so that I target the PDO directly and then again I get the reports but the upper section of the stack is stuck again. Interestingly, if I install the hook in the connectdata so that I get the processed report, I can see the hook being called and I get my reports too but still no way to move the cursor on the screen.

If I install the driver as lowerfilter I have no access to connectdata at all. On top of it, for reasons that I don’t seem to understand, the reads that I see seem to have their buffer in a place that WdfRequestRetrieveOutputBuffer cannot decode.

Under many circumstances, when WdfIoTargetOpen is used I can see ExtFileCreate being called several times (like 20 times).

In any case the driver is initialized as filter.

I hope you see what’s wrong with it because I’m really stumped.

Thanks!
Marco.

---- snippet from EvtFileCreate
WdfRequestGetParameters(Request, &requestParameters);
if(requestParameters.Parameters.Create.SecurityContext->DesiredAccess & FILE_READ_DATA)
{
WDFIOTARGET ioTarget;
DEVICE_OBJECT *nextDevice;
WDF_IO_TARGET_OPEN_PARAMS ioTargetOpenParams;

WDF_REQUEST_SEND_OPTIONS_INIT(&requestSendOptions, WDF_REQUEST_SEND_OPTION_SYNCHRONOUS);
WdfRequestFormatRequestUsingCurrentType(Request);
WdfRequestSend(Request, WdfDeviceGetIoTarget(Device), &requestSendOptions);

if(filterExt->ReadIoTarget == NULL)
{
filterExt->ReadIoTarget = WdfDeviceGetIoTarget(Device);

// Create and open a new remote ioTarget based on the same FILE_OBJECT
if(!NT_SUCCESS(WdfIoTargetCreate(Device, WDF_NO_OBJECT_ATTRIBUTES, &ioTarget)))
{
DebugPrint((“IoTargetCreate failed.\n”));
}

nextDevice = WdfDeviceWdmGetAttachedDevice(Device);
WDF_IO_TARGET_OPEN_PARAMS_INIT_EXISTING_DEVICE(&ioTargetOpenParams, nextDevice);
filterExt->FileObject = IoGetCurrentIrpStackLocation(WdfRequestWdmGetIrp(Request))->FileObject;
ioTargetOpenParams.TargetFileObject = filterExt->FileObject;

DebugPrint((“FileCreate (fo = %x)\n”, filterExt->FileObject));

if(!NT_SUCCESS(WdfIoTargetOpen(ioTarget, &ioTargetOpenParams)))
{
DebugPrint((“IoTargetOpen failed.\n”));
}

filterExt->ReadIoTarget = ioTarget;

if(!NT_SUCCESS(StartHidReader(Device, filterExt->ReportMaxSize)))
{
DebugPrint((“StartHidReader failed.\n”));
}
}
}
else
{
// we really never get here
DebugPrint((“Not a simple FILE_READ_DATA open\n”));

WDF_REQUEST_SEND_OPTIONS_INIT(&requestSendOptions, WDF_REQUEST_SEND_OPTION_SYNCHRONOUS);
WdfRequestFormatRequestUsingCurrentType(Request);
WdfRequestSend(Request, WdfDeviceGetIoTarget(Device), &requestSendOptions);
}

// Complete everything
{
WDF_REQUEST_COMPLETION_PARAMS params;

WdfRequestGetCompletionParams(Request, &params);

WdfRequestComplete(Request, params.IoStatus.Status);
}

— snippet from EvtInternalIoCtl
case IOCTL_INTERNAL_MOUSE_CONNECT:

if (filterExt->UpperConnectData.ClassService != NULL)
{
status = STATUS_SHARING_VIOLATION;
break;
}

status = WdfRequestRetrieveInputBuffer(Request, sizeof(CONNECT_DATA), &connectData, &length);
if(!NT_SUCCESS(status)){
DebugPrint((“WdfRequestRetrieveInputBuffer failed %x\n”, status));
break;
}

filterExt->UpperConnectData = *connectData;

DebugPrint((“ConnectData ClassDeviceObject %x, ClassService %x\n”,
filterExt->UpperConnectData.ClassDeviceObject,
filterExt->UpperConnectData.ClassService));

connectData->ClassDeviceObject = WdfDeviceWdmGetDeviceObject(hDevice);
connectData->ClassService = MouseActivityCallback; // just a logging function. Only assigned when driver is upperfilter.

break;


NTDEV is sponsored by OSR

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,

yes, the IoTargetOpen succeeds (I would see it logged otherwise) and as a matter of fact the following reads succeed too.
I do handle the EvtFileClose like this:

PFILE_OBJECT fileObj = WdfFileObjectWdmGetFileObject(FileObject);
if(fileObj == filterExt->FileObject)
{
DebugPrint((“Deleting IoTarget\n”));
if(filterExt->ReadIoTarget) WdfObjectDelete(filterExt->ReadIoTarget);
filterExt->ReadIoTarget = NULL;
filterExt->FileObject = NULL;
}

I’m going to run !stacks as you said and gather more info.

BTW, what should be the nicest way of placing the driver? Upperfilter of mouhid (thus sending reads directly to the PDO) or in place of it?

Thank you for your help,
Marco.

Quick update:
after a few tests moving stuff around I reverted back to original design (which is the one that I described above) and I found out that the raw pdo does get enumerated. The message in the notification area was too fast and I missed it a couple of times.

In that condition, !stacks doesn’t show anything stuck, if I move the mouse I get reports and if I install a callback in the connectdata structure, that does get called with some data. Calling the mouclass callback doesn’t accomplish anything, neither from my callback nor from the completion of my ioreads.

I tried to exclude the wdfiotargetopen and let all the filtering go through connectdata callbacks. That causes BSOD in hidclass DequeueInterruptReport. Apparently, the trigger of the problem is the synchronous forward in the filecreate event. If I transform that into a forward+completion routine, everything seems to work. Then if I try to use wdfiotargetopen again, I get stuck in the same exact way with the connectdata callback not generating any input in the system.

It really feels like having the sheets too short…

Marco.