A framework for KMDF-based upper filter drivers to behave as bus filters. You don't need to write WDM drivers any more!
Friday, June 17, 2016
May I Make a Feature Request?
Yes, please fill this form. Please note that not every feature request will be accepted.
How Do I Get the WDM Device Object of a Bus Filter?
BFF provides the following routine for this purpose:
where BffDevice is the WDF general object handle to the bus filter device object.
PDEVICE_OBJECT BffDeviceWdmGetDeviceObject(WDFOBJECT BffDevice);
where BffDevice is the WDF general object handle to the bus filter device object.
Thursday, June 16, 2016
BffDeviceWdmGetPhysicalDevice
Description
Retrieve the PDO from the device stack of the specified WDF object.
Declaration
PDEVICE_OBJECT BffDeviceWdmGetPhysicalDevice(WDFOBJECT BffDevice);
Parameter
BffDevice | The WDF object as a bus filter device object. |
Return value
The PDO for success; NULL otherwise.
BffDeviceWdmGetAttachedDevice
Description
Retrieve the next lower WDM device object in the device stack of the specified WDF object.
Declaration
PDEVICE_OBJECT BffDeviceWdmGetAttachedDevice(WDFOBJECT BffDevice);
Parameter
BffDevice | The WDF object as a bus filter device object. |
Return value
The next lower WDM device object for success; NULL otherwise.
BffDeviceWdmGetDeviceObject
Description
Retrieve the WDM bus filter device object that is associated with the specified WDF object.
Declaration
PDEVICE_OBJECT BffDeviceWdmGetDeviceObject(WDFOBJECT BffDevice);
Parameter
BffDevice | The WDF object as a bus filter device object. |
Return value
The WDM bus filter device object for success; NULL otherwise.
BffPreprocessQueryBusRelations
Description
The callback function for an upper filter driver to preprocess IRP_MN_QUERY_DEVICE_RELATIONS/BusRelations before KMDF. This routine can be passed as EvtDeviceWdmIrpPreprocess into WdfDeviceInitAssignWdmIrpPreprocessCallback for IRP_MJ_PNP/IRP_MN_QUERY_DEVICE_RELATIONS, or be invoked in an upper filter driver's EvtDeviceWdmIrpPreprocess callback function. In the latter case, the upper filter driver must return the value that this routine returns.
Declaration
NTSTATUS BffPreprocessQueryBusRelations(WDFDEVICE Device, PIRP Irp);
Parameters
Device | The WDF device object representing an upper filter device object. |
Irp | The IRP_MN_QUERY_DEVICE_RELATIONS I/O request packet. |
Return value
The value that WdfDeviceWdmDispatchPreprocessedIrp returns.
BffAllocateContext
Description
Allocate context space for an upper filter device object on behalf of Bus Filter Framework. This routine is typically called in the EvtDriverDeviceAdd callback function.
Declaration
NTSTATUS BffAllocateContext(WDFDEVICE Device);
Parameters
Device | The WDF device object representing an upper filter device object. |
Return value
The value that WdfObjectAllocateContext returns.
BffInitialize
Description
Initialize Bus Filter Framework with the initialization data. This routine must be invoked in DriverEntry after a call to WdfDriverCreate.
Declaration
NTSTATUS BffInitialize(PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath, PBFF_INITIALIZATION_DATA InitData);
Parameters
DriverObject | The same as DriverEntry's first parameter. |
RegistryPath | The same as DriverEntry's second parameter. |
InitData | The initialization data previously prepared by a call to BffSetInitializationData. |
Return value
One of the following values:
- Zero or any positive value for success;
- STATUS_NOT_SUPPORTED if the driver has not called WdfDriverCreate;
- STATUS_INVALID_PARAMEER if an invalid parameter is specified; or
- Any other negative value for failure.
BffSetInitializationData
Description
Prepare the initialization data for BFF. Obviously, this routine must be called before BffInitialize. After this call, InitData->PnPMinorFunction[IRP_MN_*] will be NULL-initialized. You may selectively re-initialize InitData->PnPMinorFunction[IRP_MN_*] with your own handlers before calling BffInitialize.
Declaration
VOID BffSetInitializationData(PBFF_INITIALIZATION_DATA InitData,
DEVICE_TYPE Type, ULONG Characteristics,
PBFF_DEVICE_ADD DeviceAdd, PBFF_DEVICE_REMOVE DeviceRemove);
Parameters
InitData | The pointer to the initialization data, typically declared as a local variable. |
Type | The device type for creation of a bus filter device object. |
Characteristics | The device characteristics for creation of a bus filter device object. |
DeviceAdd | The callback function for creation of a bus filter device object. |
DeviceRemove | The callback function for removal of a bus filter device object. |
Return value
None.
BFF_INITIALIZATION_DATA / PBFF_INITIALIZATION_DATA
Desciprtion
Data structure for initialization of Bus Filter Framework. Typically, you declare a local variable of this type, and call BffSetInitializationData to initialize it. Then, you selectively re-initialize PnPMinorFunction[IRP_MN_*] with your own handlers before calling BffInitialize.
Declaration
typedef struct _BFF_INITIALIZATION_DATA {
ULONG Size;
BFF_DEVICE_CONFIG DeviceConfig;
PBFF_DISPATCH_PNP PnPMinorFunction[IRP_MN_DEVICE_ENUMERATED+1];
} BFF_INITIALIZATION_DATA, *PBFF_INITIALIZATION_DATA;
Members
Size | Must be the size of this data structure. (Mandatory) |
DeviceConfig | Configuration data for a bus filter device object. |
PnPMinorFunction | The array of function pointers to PnP minor function handlers. |
BFF_DISPATCH_PNP / PBFF_DISPATCH_PNP
Description
Callback function for processing a PnP IRP. It must either complete that IRP or, optionally register an IoCompletion routine, and pass that IRP to the next lower driver before returning to BFF. See also BFF_INITIALIZATION_DATA / PBFF_INITIALIZATION_DATA.
Example#1: NTSTATUS callback1(WDFOBJECT BffDevice, PIRP Irp) { ... IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } Example#2: NTSTATUS callback2(WDFOBJECT BffDevice, PIRP Irp) { ... IoSkipCurrentIrpStackLocation(Irp); status = IoCallDriver(BffDeviceWdmGetAttachedDevice(BffDevice), Irp); ... return status; } Example#3: NTSTATUS callback3(WDFOBJECT BffDevice, PIRP Irp) { ... IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine(Irp, IoCompletion, BffDevice, ...); status = IoCallDriver(BffDeviceWdmGetAttachedDevice(BffDevice), Irp); ... return status; }
Declarations
typedef NTSTATUS BFF_DISPATCH_PNP(WDFOBJECT BffDevice, PIRP Irp); typedef BFF_DISPATCH_PNP *PBFF_DISPATCH_PNP;
Parameters
BffDevice | The WDF object as a bus filter device object. |
Irp | The PnP I/O request packet. |
Return value
Zero or any positive value for success, otherwise for failure.
BFF_DEVICE_CONFIG / PBFF_DEVICE_CONFIG
Description
Data structure for configuration of a bus filter device object. See also BFF_INITIALIZATION_DATA / PBFF_INITIALIZATION_DATA.
Declaration
typedef struct _BFF_DEVICE_CONFIG { DEVICE_TYPE DeviceType; ULONG DeviceCharacteristics; PBFF_DEVICE_ADD DeviceAdd; PBFF_DEVICE_REMOVE DeviceRemove; } BFF_DEVICE_CONFIG, *PBFF_DEVICE_CONFIG;
Members
DeviceType | Same as DeviceType parameter of IoCreateDevice. (Mandatory) |
DeviceCharacteristics | Same as DeviceCharacteristics parameter of IoCreateDevice. (Mandatory) |
DeviceAdd | Callback function for creation of a bus filter device object. (Optional) |
DeviceRemove | Callback function for removal of a bus filter device object. (Optional) |
BFF_DEVICE_ADD / PBFF_DEVICE_ADD
Description
Callback function for creation of a bus filter device object. Before this call, a WDF object, BffDevice, and its underlying WDM device object had been created, and the latter in particular was then attached to the next lower device object. See also BFF_DEVICE_CONFIG / PBFF_DEVICE_CONFIG.
Declarations
typedef NTSTATUS BFF_DEVICE_ADD(WDFDEVICE Device, WDFOBJECT BffDevice);
typedef BFF_DEVICE_ADD *PBFF_DEVICE_ADD;
Parameters
Device | The parent WDF device object, i.e., the upper filter device object. |
BffDevice | The WDF object as a bus filter device object. |
Return value
Zero or any positive value for success, otherwise for failure.
BFF_DEVICE_REMOVE / PBFF_DEVICE_REMOVE
Description
Callback function for removal of a bus filter device object. After this call, the WDF object, BffDevice, will be deleted, and its underlying WDM device object will be detached, and then deleted as well. See also BFF_DEVICE_CONFIG / PBFF_DEVICE_CONFIG.
Declarations
typedef VOID BFF_DEVICE_REMOVE(WDFDEVICE Device, WDFOBJECT BffDevice);
typedef BFF_DEVICE_REMOVE *PBFF_DEVICE_REMOVE;
Parameters
Device | The parent WDF device object, i.e., the upper filter device object. |
BffDevice | The WDF object as a bus filter device object. |
Return value
Zero or any positive value for success, otherwise for failure.
Tuesday, June 7, 2016
What Is the Targeted Windows Version?
A BFF-based driver should be compatible with Windows 7 or higher, x86 or x64.
Sunday, June 5, 2016
Is There a Sample Driver?
The sample driver, which demonstrates presence of a bus filter by adding a new compatible ID, "BffDevice", to the compatible IDs list, must be installed on Windows 7 or higher, x86. You may get it over here.
How Do I Get the Next Lower WDM Device Object in the Device Stack?
BFF provides the following routine for this purpose:
where BffDevice is the WDF general object handle to the bus filter device object.
PDEVICE_OBJECT BffDeviceWdmGetAttachedDevice(WDFOBJECT BffDevice);
where BffDevice is the WDF general object handle to the bus filter device object.
How Do I Get the WDM PDO of a Bus Filter?
BFF provides the following routine for this purpose:
where BffDevice is the WDF general object handle to the bus filter device object.
PDEVICE_OBJECT BffDeviceWdmGetPhysicalDevice(WDFOBJECT BffDevice);
where BffDevice is the WDF general object handle to the bus filter device object.
What Should I Do in a PnP Minor Function Handler?
A PnP minor function handler, when invoked, will receive two parameters:
- One is the WDF general object handle to the bus filter device object.
- The other is the PnP IRP itself.
Similar to a callback function registered with WdfDeviceInitAssignWdmIrpPreprocessCallback, the handler, before returning to BFF, must do one of the following actions:
- Complete the PnP IRP if appropriate.
- Optionally register an WDM IoCompletion routine and pass the PnP IRP down to the next lower driver.
If the latter is the case, the handler will end like:
NTSTATUS PnPMinorFunctionHandler(WDFOBJECT BffDevice, PIRP Irp) { ... ... ... return IoCallDriver(BffDeviceWdmGetAttachedDevice(BffDevice), Irp); }
How Do I Clean up/Destroy My Own Device-Specific Data?
You have two options:
- You provide the callback function, DeviceRemove, for removal of a bus filter device object at initialization of BFF. DeviceRemove, when invoked, will receive the WDF general object handle to the bus filter device object which is being removed. Therefore, you may release any resource therein.
- You provide EvtCleanupCallback or EvtDestroyCallback for your own context space in your DeviceAdd callback function, just like the destruction of any ordinary WDF object.
Where Do I Store My Own Device-Specific Data?
At initialization of BFF, if you provide the callback function, DeviceAdd, for creation of bus filter device objects, DeviceAdd, when invoked, will receive two WDF object handles:
- One is a WDF device object handle which is associated with the parent device object, i.e., the upper filter device object.
- The other is a WDF general object handle which is associated with a newly created bus filter device object.
Is There Any Other Restriction on Usage of BFF?
Yes, the following names of context types are reserved:
- BFF_PARENT_CONTEXT
- The name of the context type for upper filter device objects.
- BFF_DEVICE_CONTEXT
- The name of the context type for bus filter device objects.
You must not name any context type as any of them, since BFF is a static library, i.e., it's in the very same driver context as the upper filter driver; otherwise, the driver would behave unpredictably.
What Is Bus Filter Framework?
Bus Filter Framework, or BFF for short, is a static library that integrates with a KMDF-based upper filter driver into a bus filter driver.
The KMDF-based upper filter driver to be integrated provides for initialization of BFF necessary parameters for creation of bus filter device objects, optional handlers for PnP minor functions it wants to filter, and optional callback functions for creation and removal of bus filter device objects. With these handlers and callback functions, the upper filter driver may be transformed into a bus filter driver.
After initialization, BFF requires the upper filter driver to register a callback function with KMDF to preprocess IRP_MN_QUERY_DEVICE_RELATIONS, specifically for BusRelations. The callback function to be registered can be provided either by BFF or by the upper filter driver. In the latter case, that callback function must eventually call the one provided by BFF.
Additionally, BFF requires the upper filter driver to allocate context space for upper filter device objects on behalf of BFF. With that context space, BFF may manage creation and removal of bus filter device objects.
In summary, BFF is a framework for KMDF-based upper filter drivers to behave as bus filters. You don't need to write WDM drivers any more!
The KMDF-based upper filter driver to be integrated provides for initialization of BFF necessary parameters for creation of bus filter device objects, optional handlers for PnP minor functions it wants to filter, and optional callback functions for creation and removal of bus filter device objects. With these handlers and callback functions, the upper filter driver may be transformed into a bus filter driver.
After initialization, BFF requires the upper filter driver to register a callback function with KMDF to preprocess IRP_MN_QUERY_DEVICE_RELATIONS, specifically for BusRelations. The callback function to be registered can be provided either by BFF or by the upper filter driver. In the latter case, that callback function must eventually call the one provided by BFF.
Additionally, BFF requires the upper filter driver to allocate context space for upper filter device objects on behalf of BFF. With that context space, BFF may manage creation and removal of bus filter device objects.
In summary, BFF is a framework for KMDF-based upper filter drivers to behave as bus filters. You don't need to write WDM drivers any more!
Saturday, June 4, 2016
What Can a BFF-Based Driver Do? And What Cannot?
The design of BFF focuses on processing PnP IRPs; a BFF-based driver may register its own handlers for all minor functions of PnP, except for IRP_MN_REMOVE_DEVICE; non-PnP IRPs or PnP IRPs without registered handlers are simply passed down to the next lower driver, typically the bus driver. Therefore, a BFF-based driver may entirely replace a lower filter driver, if only PnP IRPs are concerned; otherwise, a lower filter driver is still required.
Although no handler can be registered for IRP_MN_REMOVE_DEVICE, a callback function, DeviceRemove, may be specified during BFF initialization, and it will be invoked during the processing of IRP_MN_REMOVE_DEVICE.
Although no handler can be registered for IRP_MN_REMOVE_DEVICE, a callback function, DeviceRemove, may be specified during BFF initialization, and it will be invoked during the processing of IRP_MN_REMOVE_DEVICE.
Why Do I Need a Bus Filter?
After a new PnP device is enumerated by a bus function driver and identified by PnP Manager, PnP Manager will send the following PnP IRPs to the device stack of that device:
- IRP_MN_QUERY_ID
- BusQueryDeviceID
- BusQueryInstanceID
- BusQueryHardwareIDs
- BusQueryCompatibleIDs
- BusQueryContainerID (for Windows 7+)
- IRP_MN_QUERY_CAPABILITIES
- IRP_MN_QUERY_DEVICE_TEXT
- DeviceTextDescription
- DeviceTextLocationInformation
- IRP_MN_QUERY_BUS_INFORMATION
- IRP_MN_QUERY_RESOURCES
- IRP_MN_QUERY_RESOURCE_REQUIREMENTS
Note that, at this moment, the device stack has only one PDO, and optionally one or more bus filter DOs. And don't forget that the function driver and filter drivers, if any, are selected and loaded by PnP Manager, according to a matched hardware ID or compatible ID. Therefore, if you want to influence PnP Manager's decision on which function and any optional filter drivers get selected and loaded, you must modify hardware IDs or compatible IDs generated by the bus function driver. In other words, you have two options:
- You either write your own bus function driver, or
- You write a bus filter driver.
Obviously, the second one is easier.
Wednesday, June 1, 2016
Why Bus Filter Framework?
Writing a KMDF driver is much more easier than writing a WDM one. Once you start to do it in the KMDF way, you will never ever want to go back to WDM!
In spite of so many advantages, KMDF has a drawback: It does not support bus filters, officially. The only way to create bus filters was to do it in a WDM manner.
Ever since KMDF was born, people have been asking the question: How can I write a bus filter driver with KMDF? Yet, the answer was disappointing...until now! I present you Bus Filter Framework, or BFF for short! With BFF, you can create bus filters with your beloved KMDF! Say good-bye to WDM from now on!
In spite of so many advantages, KMDF has a drawback: It does not support bus filters, officially. The only way to create bus filters was to do it in a WDM manner.
Ever since KMDF was born, people have been asking the question: How can I write a bus filter driver with KMDF? Yet, the answer was disappointing...until now! I present you Bus Filter Framework, or BFF for short! With BFF, you can create bus filters with your beloved KMDF! Say good-bye to WDM from now on!
Creating a Bus Filter Driver Is As Easy As 1-2-3
How to make a KMDF-based upper filter driver behave as a bus filter?
Easy! Just follow three steps:
Easy! Just follow three steps:
- Initialize Bus Filter Framework in DriverEntry, after a call to WdfDriverCreate.
- Call WdfDeviceInitAssignWdmIrpPreprocessCallback in your EvtDriverDeviceAdd callback function, to register a Bus Filter Framework handler for IRP_MJ_PNP/IRP_MN_QUERY_DEVICE_RELATIONS/BusRelations.
- Allocate context space for an upper filter device object on behalf of Bus Filter Framework in your EvtDriverDeviceAdd callback function, after a call to WdfDeviceCreate.
That's it!
Subscribe to:
Posts (Atom)