Writing Filter Drivers

< BACK  NEXT >
[oR]

A filter driver is a special type of intermediate driver. Filter drivers perform their work surreptitiously. They sit on top of some other driver and intercept requests directed at the lower driver's Device objects. Users of the lower driver are completely unaware that their requests are being preprocessed or intercepted by the filter driver. Some examples of the use of filter drivers include the following:

  • Filters allow modification of some aspect of an existing driver's behavior without rewriting the entire driver. SCSI filter drivers work this way.

  • Filters make it easier to hide the limitations of lower-level device drivers. For example, a filter could split large transfers into smaller pieces before passing them on to a driver with transfer size limits.

  • Filters allow the addition of new features like compression or encryption to a device without modifying the underlying device driver or the programs that use the device.

  • Filters allow the addition or removal of expensive behavior (like performance monitoring) a driver may not perform at all times. The disk performance monitoring tools in Windows 2000 work this way.

The remainder of this section explains how to write filter drivers. Bear in mind that driver-allocated IRPs and I/O Completion routines work the same in a filter driver as they do in a regular layered driver.

How Filter Drivers Work

The main distinction between filter drivers and other layered drivers is in the Device objects they create. Whereas a layered driver exposes Device objects with their own unique names, filter drivers' Device objects have no names at all. Filter drivers work by attaching one of these nameless Device objects to a Device object created by some lower-level driver. Figure 15.2 illustrates this relationship.

Figure 15.2. Filter driver operation.
graphics/15fig02.gif

In the diagram, FLTDRIVER has attached a filter Device object to FD0, one of FDODRIVER's Device objects. Any IRPs sent to FD0 are automatically rerouted to the Dispatch routines in FLTDRIVER. It works as follows:

  1. The AddDevice routine in the filter driver creates an invisible Device object and attaches it to a named Device object belonging to a driver beneath it.

  2. A client of the lower-level driver opens a connection to FD0. This is typically done using the Win32 CreateFile method to obtain a handle, or a kernel-mode client can use IoGetDeviceObjectPointer. Regardless, the I/O Manager actually opens a connection between the client and the filter driver's invisible Device object.

  3. When the client sends an I/O request to FD0, the I/O Manager sends it to the filter driver's unnamed Device object instead. The I/O Manager uses the MajorFunction table of the filter's Driver object to select an appropriate Dispatch routine.

  4. The Dispatch routines in the filter driver either process the IRP on their own and complete immediately, or they send the IRP down to FD0 with IoCallDriver. If the filter driver needs to regain control of the IRP when a lower-level driver completes it, the filter can associate an I/O Completion routine with the IRP.

Filters can also be layered above other filters. Attaching a new filter to an already filtered Device object results in the new filter simply getting layered on top of the highest existing filter. Essentially, any number of filter layers can exist for a single Device object.

Initialization and Cleanup in Filter Drivers

Like every other kernel-mode driver, a filter driver must have a main entry point called DriverEntry. Like other WDM drivers, it must export an AddDevice, RemoveDevice, and Unload routine. The following sections describe what these routines must do.

AddDevice routine

The initialization sequence in a filter driver for the PnP request to add a device is straightforward.

  1. The filter calls IoCreateDevice to create a filter Device object for this target device. The filter Device object has no internal name, nor does it have a symbolic link name.

  2. It calls IoAttachDeviceToDeviceStack (as usual) to stack itself on top of the lower driver and obtain a pointer to the target Device object.

  3. It stores the address of the target device object in the Device Extension of the filter Device object. Other parts of the filter driver use this pointer to call the target driver.

  4. Next, AddDevice copies the DeviceType and Characteristics fields from the target Device object to the filter Device object. It also copies the DO_DIRECT_IO, DO_BUFFERED_IO, DO_POWER_INRUSH, and DO_POWER_PAGABLE bits from the target Device object's Flags field. This guarantees that the filter looks the same and has the same buffering strategy as the target driver.

RemoveDevice Routine

A filter driver's RemoveDevice routine must disconnect the filter and target Device objects. It does this by calling IoDetachDevice and passing a pointer to the target Device object. Once the filter Device object has been detached, the RemoveDevice routine calls IoDeleteDevice to delete the unnamed object.

Making the Attachment Transparent

Once a filter has attached itself to the target driver, any I/O requests sent to the target must pass through the Dispatch routines of the filter driver first. If the MajorFunction table of the filter Driver object does not support the same set of IRP_MJ_XXX codes as the target driver, clients of the target may experience problems when the filter is attached. Specifically, some types of requests that work without the filter are rejected as illegal operations when the filter is in place.

To avoid this inconsistency, the filter driver's MajorFunction table must contain a Dispatch routine for every IRP_MJ_XXX function supported by the target driver. Even if the filter is not interested in modifying a particular MajorFunction code, it still must supply the Dispatch routine that simply passes the IRP on to the target driver.

The most straightforward way for the filter driver to avoid the inconsistency problem is to provide a pass-through Dispatch routine for every slot within the MajorFunction table of the filter Driver object. For each MajorFunction entry that the filter wishes to override, a non-pass-through function is provided. The sample driver in the next section demonstrates this technique.

< BACK  NEXT >


The Windows 2000 Device Driver Book(c) A Guide for Programmers
The Windows 2000 Device Driver Book: A Guide for Programmers (2nd Edition)
ISBN: 0130204315
EAN: 2147483647
Year: 2000
Pages: 156

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net