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:
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 WorkThe 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.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:
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 DriversLike 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 routineThe initialization sequence in a filter driver for the PnP request to add a device is straightforward.
RemoveDevice RoutineA 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 TransparentOnce 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.
|