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:
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


BffDeviceThe 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


BffDeviceThe 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


BffDeviceThe 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


DeviceThe WDF device object representing an upper filter device object.
IrpThe 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


DeviceThe 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


DriverObjectThe same as DriverEntry's first parameter.
RegistryPathThe same as DriverEntry's second parameter.
InitDataThe initialization data previously prepared by a call to BffSetInitializationData.

Return value


One of the following values:
  1. Zero or any positive value for success;
  2. STATUS_NOT_SUPPORTED if the driver has not called WdfDriverCreate;
  3. STATUS_INVALID_PARAMEER if an invalid parameter is specified; or
  4. 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


InitDataThe pointer to the initialization data, typically declared as a local variable.
TypeThe device type for creation of a bus filter device object.
CharacteristicsThe device characteristics for creation of a bus filter device object.
DeviceAddThe callback function for creation of a bus filter device object.
DeviceRemoveThe 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


SizeMust be the size of this data structure. (Mandatory)
DeviceConfigConfiguration data for a bus filter device object.
PnPMinorFunctionThe 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


BffDeviceThe WDF object as a bus filter device object.
IrpThe 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


DeviceTypeSame as DeviceType parameter of IoCreateDevice. (Mandatory)
DeviceCharacteristicsSame as DeviceCharacteristics parameter of IoCreateDevice. (Mandatory)
DeviceAddCallback function for creation of a bus filter device object. (Optional)
DeviceRemoveCallback 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


DeviceThe parent WDF device object, i.e., the upper filter device object.
BffDeviceThe 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


DeviceThe parent WDF device object, i.e., the upper filter device object.
BffDeviceThe 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:
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:
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:
  1. One is the WDF general object handle to the bus filter device object.
  2. 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:
  1. Complete the PnP IRP if appropriate.
  2. 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:
  1. 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.
  2. 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:
  1. One is a WDF device object handle which is associated with the parent device object, i.e., the upper filter device object.
  2. The other is a WDF general object handle which is associated with a newly created bus filter device object.
Therefore, you may call WdfObjectAllocateContext to allocate your own context space and store your own private data therein.

Is There Any Other Restriction on Usage of BFF?

Yes, the following names of context types are reserved:
  1. BFF_PARENT_CONTEXT
    • The name of the context type for upper filter device objects.
  2. 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!

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.

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:
  1. IRP_MN_QUERY_ID
    • BusQueryDeviceID
    • BusQueryInstanceID
    • BusQueryHardwareIDs
    • BusQueryCompatibleIDs
    • BusQueryContainerID (for Windows 7+)
  2. IRP_MN_QUERY_CAPABILITIES
  3. IRP_MN_QUERY_DEVICE_TEXT
    • DeviceTextDescription
    • DeviceTextLocationInformation
  4. IRP_MN_QUERY_BUS_INFORMATION
  5. IRP_MN_QUERY_RESOURCES
  6. 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:
  1. You either write your own bus function driver, or
  2. 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!

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:
  1. Initialize Bus Filter Framework in DriverEntry, after a call to WdfDriverCreate.
  2. Call WdfDeviceInitAssignWdmIrpPreprocessCallback in your EvtDriverDeviceAdd callback function, to register a Bus Filter Framework handler for IRP_MJ_PNP/IRP_MN_QUERY_DEVICE_RELATIONS/BusRelations.
  3. 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!