Filter drivers have come up in conversations recently (both internal and external), so I wanted to take some time here to address some of the issues that were brought up with regards to UMDF filter drivers and how to make them.  Note: I’m not going to cover all the configuration dynamics available for UMDF filter drivers in this one post simply to avoid the risk information overload and clutter, so expect a couple of posts on this subject.

Let’s start with some basics, we’ll simply demonstrate how to configure and load a UMDF Filter as an upper filter driver to a kernel mode driver (KMDF or WDM) in the same INF-

As some of you may remember from my earlier posts, a UMDF filter driver should use the SetFilter(); property in the DeviceInitialization routine. This tells the Framework to do a couple of things for us automatically:

  1. Send I/O for which the Filter has not registered a callback for to the next logical driver in the stack.  Example: Your filter driver registers a DeviceIoctl callback method, but not read or write.  As a result your filter driver will only see IOCTLs
  2. Automatically forward file create cleanup and close so there is no need to invoke the AutoForwardCreateCleanupClose method.

That covers the really basic code required at driver / device initialization time.  Now we need to add the pertinent sections to the INF file.  As we’re going to focus on being an upper filter for this example, you need to make the following modifications to your INF (in addition to the normal UMDF specific sections);

[<mydriver>.NT.Wdf]
UmdfService = "<mydriver>", <mydriver>_Install
UmdfServiceOrder = <mydriver>

[<mydriver>_Device_AddReg]
; Load the redirector as an upperfilter on this specific device.
; 0x00010008 - FLG_ADDREG_TYPE_MULTI_SZ | FLG_ADDREG_APPEND
HKR,,"UpperFilters",0x00010008,"WUDFRd" 

So a couple of things to note here -

One is the UmdfServiceOrder directive, this is load order specific.   I’ll address a more UMDF centric stack in the next post, but for those of you who like to work ahead, this is a left to right reading list to determine stack order.

Second thing is the registry key addition section.  As WUDFRd is the kernel mode transport service for UMDF drivers, WUDFRd is the upper level filter driver to a kernel mode driver.

Now that your driver is loaded as an upper filter, what should your driver do in order to be a good citizen in the stack?  Short answer is, as little as possible.  You perform the same steps for handling PnP and Power as you would for any basic UMDF driver (one that lets the framework handle the heavy lifting for those two).  You register your I/O callback routines and build your queues just like any normal UMDF driver, the only additional requirement here is to forward I/O requests as required.

For this example, let’s just demonstrate using a fairly simple pass through driver.  How you actually implement this is up to you, but the basic requirements here are - as your driver receives the request on the queue, it needs to pas pass it on to the next driver in the stack.  So first you need to get the default I/O target (next driver in the stack).  Next, format the request using the same type and then finally, send the request.  A condensed version would be something along these lines;

    IWDFIoTarget * kmdfIoTarget = NULL;
    
    this->GetFxDevice()->GetDefaultIoTarget (&kmdfIoTarget);

    Request->FormatUsingCurrentType();

    hr = Request->Send (
        kmdfIoTarget, 
        0,  // 0 Submits Asynchronous else use WDF_REQUEST_SEND_OPTION_SYNCHRONOUS
        0);

I also have some more basic code here for you to peruse.

So now we have a basic UMDF upper filter driver on top of a kernel mode driver.

Now Playing Capitals v. Rangers