1
0
DmfBusFilterExtension/src/Dmf_BusFilter.c

1214 lines
30 KiB
C

/*++
Copyright (c) Nefarius Software Solutions e.U. All rights reserved.
Licensed under the MIT license.
Module Name:
Dmf_BusFilter.c
Abstract:
Creates the supporting plumbing for a Bus Filter Driver.
Environment:
Kernel-mode Driver Framework
--*/
#include "DmfDefinitions.h"
#include "Dmf_BusFilter.h"
#include "DmfModules.Library.Trace.h"
#include <initguid.h>
#if defined(DMF_INCLUDE_TMH)
#include "Dmf_BusFilter.tmh"
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////////
// Bus Filter
///////////////////////////////////////////////////////////////////////////////////////////////////////
//
#if defined(DMF_KERNEL_MODE)
// WDM child device context
//
typedef struct _WDM_CHILD_DEVICE_EXTENSION
{
// GUID to identify WDM child device.
//
GUID Signature;
// Target Device Object
//
PDEVICE_OBJECT TargetDeviceObject;
// Physical Device Object
//
PDEVICE_OBJECT PhysicalDeviceObject;
// Parent ChildList entry
//
LIST_ENTRY ListEntry;
// Parent WDF device object
//
WDFDEVICE Parent;
// Child WDF wrapper object
//
DMFBUSCHILDDEVICE Child;
// TRUE if PDO is attached, FALSE otherwise
//
BOOLEAN IsExisting;
} WDM_CHILD_DEVICE_EXTENSION;
// Parent bus device context
//
typedef struct _PARENT_BUS_DEVICE_CONTEXT
{
//
// List of child device (relations)
//
LIST_ENTRY ChildList;
//
// Spin lock protecting child list access
//
KSPIN_LOCK ChildListLock;
} PARENT_BUS_DEVICE_CONTEXT;
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(PARENT_BUS_DEVICE_CONTEXT, DMF_BusFilter_GetParentContext)
// Bus child device context
//
typedef struct _BUS_CHILD_DEVICE_CONTEXT
{
// WDM device object
//
PDEVICE_OBJECT DeviceObject;
} BUS_CHILD_DEVICE_CONTEXT;
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(BUS_CHILD_DEVICE_CONTEXT, DMF_BusFilter_GetChildContext)
typedef
_Function_class_(EVT_DMF_BusFilter_DispatchPnp)
_IRQL_requires_same_
_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS
EVT_DMF_BusFilter_DispatchPnp(
_In_ DMFBUSCHILDDEVICE ChildDevice,
_In_ PIRP Irp
);
// Module-internal context data
//
typedef struct _DMF_CONTEXT_BusFilter
{
// Copy of the module configuration
//
DMF_BusFilter_CONFIG Configuration;
// Hooked dispatch table
//
PDRIVER_DISPATCH MajorDispatchFunctions[IRP_MJ_MAXIMUM_FUNCTION + 1];
// PNP minor functions dispatch routines
//
EVT_DMF_BusFilter_DispatchPnp* PnPMinorDispatchFunctions[IRP_MN_DEVICE_ENUMERATED + 1];
} BusFilter_Context;
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(BusFilter_Context,
BusFilterContextGet);
// {678CBB8D-019F-4D07-912A-73E2E568B148}
DEFINE_GUID(GUID_DMF_BUSFILTER_SIGNATURE,
0x678cbb8d, 0x19f, 0x4d07, 0x91, 0x2a, 0x73, 0xe2, 0xe5, 0x68, 0xb1, 0x48);
#pragma code_seg("PAGE")
_IRQL_requires_max_(PASSIVE_LEVEL)
static
void
DMF_BusFilter_Relations_RemoveDevice(
_In_ PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Processes child device removal.
Arguments:
DeviceObject - Parent device object.
Return Value:
None
--*/
{
KLOCK_QUEUE_HANDLE handle;
WDM_CHILD_DEVICE_EXTENSION* extension = (WDM_CHILD_DEVICE_EXTENSION*)DeviceObject->DeviceExtension;
PARENT_BUS_DEVICE_CONTEXT* parentContext = DMF_BusFilter_GetParentContext(extension->Parent);
const BusFilter_Context* context = BusFilterContextGet(WdfGetDriver());
const DMF_BusFilter_CONFIG* config = &context->Configuration;
FuncEntry(DMF_TRACE);
PAGED_CODE();
if (extension->IsExisting)
{
goto Exit;
}
#pragma warning(disable: 28150) // elevates to DISPATCH_LEVEL
KeAcquireInStackQueuedSpinLock(&parentContext->ChildListLock,
&handle);
RemoveEntryList(&extension->ListEntry);
KeReleaseInStackQueuedSpinLock(&handle);
#pragma warning(default: 28150) // drops to PASSIVE_LEVEL
TraceVerbose(DMF_TRACE, "%!FUNC! called at %!irql!", KeGetCurrentIrql());
if (config->EvtDeviceRemove)
{
config->EvtDeviceRemove(extension->Parent, extension->Child);
}
WdfObjectDelete(extension->Child);
IoDetachDevice(extension->TargetDeviceObject);
IoDeleteDevice(DeviceObject);
Exit:
FuncExitNoReturn(DMF_TRACE);
}
#pragma code_seg()
_IRQL_requires_max_(DISPATCH_LEVEL)
static
NTSTATUS
DMF_BusFilter_DispatchPnp(
_In_ PDEVICE_OBJECT DeviceObject,
_In_ PIRP Irp,
_In_ UCHAR MinorCode
)
/*++
Routine Description:
Handles PnP requests.
Arguments:
DeviceObject - Parent device object.
Irp - Irp with PnP request.
MinorCode - Request minor code.
Return Value:
NTSTATUS
--*/
{
const WDM_CHILD_DEVICE_EXTENSION* extension = (WDM_CHILD_DEVICE_EXTENSION*)DeviceObject->DeviceExtension;
const BusFilter_Context* context = BusFilterContextGet(WdfGetDriver());
if (MinorCode == IRP_MN_REMOVE_DEVICE)
{
// Handle child device removal
//
DMF_BusFilter_Relations_RemoveDevice(DeviceObject);
}
else if (MinorCode <= IRP_MN_DEVICE_ENUMERATED)
{
if (context->PnPMinorDispatchFunctions[MinorCode] != NULL)
{
//
// Forward to PnP minor code dispatch routines
//
return context->PnPMinorDispatchFunctions[MinorCode](extension->Child, Irp);
}
}
// Forward to lower driver
//
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(extension->TargetDeviceObject,
Irp);
}
_IRQL_requires_max_(DISPATCH_LEVEL)
static
NTSTATUS
DMF_BusFilter_DispatchHandler(
_In_ PDEVICE_OBJECT DeviceObject,
_In_ PIRP Irp
)
/*++
Routine Description:
Dispatch routine handler for all IRPs
Arguments:
DeviceObject - Parent device object.
Irp - Irp with request.
Return Value:
NTSTATUS
--*/
{
const WDM_CHILD_DEVICE_EXTENSION* extension = (WDM_CHILD_DEVICE_EXTENSION*)DeviceObject->DeviceExtension;
const PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
const BusFilter_Context* context = BusFilterContextGet(WdfGetDriver());
if (!IsEqualGUID(&extension->Signature,
&GUID_DMF_BUSFILTER_SIGNATURE))
{
return context->MajorDispatchFunctions[stack->MajorFunction](DeviceObject, Irp);
}
// Handle PNP requests
//
if (stack->MajorFunction == IRP_MJ_PNP)
{
return DMF_BusFilter_DispatchPnp(DeviceObject, Irp, stack->MinorFunction);
}
// Forward to lower driver
//
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(extension->TargetDeviceObject, Irp);
}
_IRQL_requires_max_(APC_LEVEL)
static
NTSTATUS
DMF_BusFilter_Relations_AddDevice(
_In_ WDFDEVICE Device,
_In_ PDEVICE_OBJECT PhysicalDeviceObject
)
/*++
Routine Description:
Creates proxy child device for bus PDO.
Arguments:
Device - Child device to add.
PhysicalDeviceObject - Parent device object.
Return Value:
NTSTATUS
--*/
{
NTSTATUS ntStatus = STATUS_NOT_IMPLEMENTED;
WDF_OBJECT_ATTRIBUTES attributes;
PLIST_ENTRY entry = NULL;
KLOCK_QUEUE_HANDLE handle;
WDM_CHILD_DEVICE_EXTENSION* childExtension = NULL;
PDEVICE_OBJECT filterDeviceObject = NULL;
BOOLEAN preexisting = FALSE;
DMFBUSCHILDDEVICE child = NULL;
BUS_CHILD_DEVICE_CONTEXT* childContext = NULL;
PARENT_BUS_DEVICE_CONTEXT* parentContext = DMF_BusFilter_GetParentContext(Device);
const PDEVICE_OBJECT deviceObject = WdfDeviceWdmGetDeviceObject(Device);
const BusFilter_Context* context = BusFilterContextGet(WdfGetDriver());
const DMF_BusFilter_CONFIG* config = &context->Configuration;
FuncEntry(DMF_TRACE);
if (parentContext == NULL)
{
ntStatus = STATUS_INVALID_DEVICE_STATE;
goto Exit;
}
KeAcquireInStackQueuedSpinLock(&parentContext->ChildListLock,
&handle);
// Find and update PDO status
//
for (
entry = parentContext->ChildList.Flink;
entry != &parentContext->ChildList;
entry = entry->Flink
)
{
childExtension = CONTAINING_RECORD(entry,
WDM_CHILD_DEVICE_EXTENSION,
ListEntry);
if (childExtension->PhysicalDeviceObject == PhysicalDeviceObject)
{
preexisting = TRUE;
childExtension->IsExisting = TRUE;
break;
}
}
KeReleaseInStackQueuedSpinLock(&handle);
if (preexisting)
{
ntStatus = STATUS_SUCCESS;
goto Exit;
}
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes,
BUS_CHILD_DEVICE_CONTEXT);
attributes.ParentObject = Device;
// Create piggyback framework object for WDM child device object
//
ntStatus = WdfObjectCreate(&attributes, (WDFOBJECT*)&child);
if (!NT_SUCCESS(ntStatus))
{
TraceError(DMF_TRACE, "WdfObjectCreate fails: ntStatus=%!STATUS!", ntStatus);
goto Exit;
}
// Create WDM device
//
ntStatus = IoCreateDevice(deviceObject->DriverObject,
sizeof(WDM_CHILD_DEVICE_EXTENSION),
NULL,
config->DeviceType,
FILE_DEVICE_SECURE_OPEN | config->DeviceCharacteristics,
FALSE,
&filterDeviceObject);
if (!NT_SUCCESS(ntStatus))
{
TraceError(DMF_TRACE, "IoCreateDevice fails: ntStatus=%!STATUS!", ntStatus);
goto Exit;
}
// Link WDM and WDF device together.
//
childContext = DMF_BusFilter_GetChildContext(child);
childContext->DeviceObject = filterDeviceObject;
childExtension = (WDM_CHILD_DEVICE_EXTENSION*)filterDeviceObject->DeviceExtension;
RtlZeroMemory(childExtension,
sizeof(WDM_CHILD_DEVICE_EXTENSION));
RtlCopyMemory(&childExtension->Signature,
&GUID_DMF_BUSFILTER_SIGNATURE,
sizeof(GUID));
childExtension->Parent = Device;
childExtension->Child = child;
childExtension->PhysicalDeviceObject = PhysicalDeviceObject;
childExtension->TargetDeviceObject = IoAttachDeviceToDeviceStack(filterDeviceObject,
PhysicalDeviceObject);
if (childExtension->TargetDeviceObject == NULL)
{
IoDeleteDevice(filterDeviceObject);
ntStatus = STATUS_NO_SUCH_DEVICE;
goto Exit;
}
filterDeviceObject->Flags |= childExtension->TargetDeviceObject->Flags &
(DO_BUFFERED_IO | DO_DIRECT_IO | DO_POWER_INRUSH | DO_POWER_PAGABLE);
if (config->EvtDeviceAdd)
{
ntStatus = config->EvtDeviceAdd(Device, child);
if (!NT_SUCCESS(ntStatus))
{
TraceError(DMF_TRACE, "EvtDeviceAdd fails: ntStatus=%!STATUS!", ntStatus);
IoDetachDevice(childExtension->TargetDeviceObject);
IoDeleteDevice(filterDeviceObject);
goto Exit;
}
}
KeAcquireInStackQueuedSpinLock(&parentContext->ChildListLock,
&handle);
childExtension->IsExisting = TRUE;
InsertTailList(&parentContext->ChildList,
&childExtension->ListEntry);
KeReleaseInStackQueuedSpinLock(&handle);
filterDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
ntStatus = STATUS_SUCCESS;
Exit:
if (!NT_SUCCESS(ntStatus) && child != NULL)
{
WdfObjectDelete(child);
}
FuncExit(DMF_TRACE, "status=%!STATUS!", ntStatus);
return ntStatus;
}
#pragma code_seg("PAGE")
_IRQL_requires_max_(PASSIVE_LEVEL)
static
NTSTATUS
DMF_BusFilter_QueryBusRelationsCompleted(
_In_ PDEVICE_OBJECT DeviceObject,
_In_ PIRP Irp,
_In_ WDFDEVICE Device
)
/*++
Routine Description:
Bus relations query completed routine.
Arguments:
DeviceObject - Parent device object.
Irp - Query Bus Relations IRP.
Device - Target WDFDEVICE.
Return Value:
NTSTATUS
--*/
{
NTSTATUS ntStatus = STATUS_NOT_IMPLEMENTED;
PARENT_BUS_DEVICE_CONTEXT* parentContext = DMF_BusFilter_GetParentContext(Device);
PDEVICE_RELATIONS deviceRelations = NULL;
KLOCK_QUEUE_HANDLE handle;
WDM_CHILD_DEVICE_EXTENSION* childExtension = NULL;
UNREFERENCED_PARAMETER(DeviceObject);
FuncEntry(DMF_TRACE);
PAGED_CODE();
if (Irp->PendingReturned)
{
IoMarkIrpPending(Irp);
}
if (!NT_SUCCESS(Irp->IoStatus.Status))
{
goto Exit;
}
if (parentContext == NULL)
{
goto Exit;
}
#pragma warning(disable: 28150) // elevates to DISPATCH_LEVEL
KeAcquireInStackQueuedSpinLock(&parentContext->ChildListLock,
&handle);
// Reset child states
//
for (
LIST_ENTRY* entry = parentContext->ChildList.Flink;
entry != &parentContext->ChildList;
entry = entry->Flink
)
{
childExtension = CONTAINING_RECORD(entry,
WDM_CHILD_DEVICE_EXTENSION,
ListEntry);
childExtension->IsExisting = FALSE;
}
KeReleaseInStackQueuedSpinLock(&handle); // drops to PASSIVE_LEVEL
#pragma warning(default: 28150)
deviceRelations = (PDEVICE_RELATIONS)Irp->IoStatus.Information;
if (deviceRelations == NULL)
{
goto Exit;
}
// Walk through device relations.
//
for (ULONG index = 0; index < deviceRelations->Count; index++)
{
TraceVerbose(DMF_TRACE, "%!FUNC! called at %!irql!", KeGetCurrentIrql());
ntStatus = DMF_BusFilter_Relations_AddDevice(Device,
deviceRelations->Objects[index]);
if (!NT_SUCCESS(ntStatus))
{
TraceError(DMF_TRACE, "DMF_BusFilter_Relations_AddDevice fails: ntStatus=%!STATUS!", ntStatus);
}
}
Exit:
FuncExitNoReturn(DMF_TRACE);
return STATUS_CONTINUE_COMPLETION;
}
#pragma code_seg()
_IRQL_requires_max_(DISPATCH_LEVEL)
static
NTSTATUS
DMF_BusFilter_PreprocessQueryBusRelations(
_In_ WDFDEVICE Device,
_In_ PIRP Irp
)
/*++
Routine Description:
Pre-processes IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS.
Arguments:
DeviceObject - Parent device object.
Irp - IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS request.
Return Value:
NTSTATUS
--*/
{
const PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
if (
stack->MajorFunction != IRP_MJ_PNP ||
stack->MinorFunction != IRP_MN_QUERY_DEVICE_RELATIONS ||
stack->Parameters.QueryDeviceRelations.Type != BusRelations
)
{
IoSkipCurrentIrpStackLocation(Irp);
}
else
{
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp,
(PIO_COMPLETION_ROUTINE)DMF_BusFilter_QueryBusRelationsCompleted,
Device,
TRUE,
TRUE,
TRUE);
}
return WdfDeviceWdmDispatchPreprocessedIrp(Device,
Irp);
}
#pragma code_seg("PAGE")
static
NTSTATUS
DMF_BusFilter_PnP_StartDevice(
_In_ DMFBUSCHILDDEVICE ChildDevice,
_In_ PIRP Irp
)
/*++
Routine Description:
Handles IRP_MN_START_DEVICE
Arguments:
ChildDevice - Associated child device.
Irp - IRP_MJ_PNP / IRP_MN_START_DEVICE request.
Return Value:
NTSTATUS
--*/
{
NTSTATUS ntStatus;
const BusFilter_Context* context = BusFilterContextGet(WdfGetDriver());
const DMF_BusFilter_CONFIG* config = &context->Configuration;
FuncEntry(DMF_TRACE);
PAGED_CODE();
if (!IoForwardIrpSynchronously(DMF_BusFilter_WdmAttachedDeviceGet(ChildDevice),
Irp))
{
TraceError(DMF_TRACE, "IoForwardIrpSynchronously fails: Irp=0x%p", Irp);
Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
}
else if (NT_SUCCESS(Irp->IoStatus.Status) && config->EvtDeviceStarted)
{
config->EvtDeviceStarted(ChildDevice,
Irp);
}
ntStatus = Irp->IoStatus.Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
FuncExit(DMF_TRACE, "ntStatus=%!STATUS!", ntStatus);
return ntStatus;
}
#pragma code_seg()
static
NTSTATUS
DMF_BusFilter_PnP_DeviceEnumerated(
_In_ DMFBUSCHILDDEVICE ChildDevice,
_In_ PIRP Irp
)
/*++
Routine Description:
Handles IRP_MN_DEVICE_ENUMERATED.
Arguments:
ChildDevice - Associated child device.
Irp - IRP_MJ_PNP / IRP_MN_DEVICE_ENUMERATED request.
Return Value:
NTSTATUS
--*/
{
NTSTATUS ntStatus;
const BusFilter_Context* context = BusFilterContextGet(WdfGetDriver());
const DMF_BusFilter_CONFIG* config = &context->Configuration;
FuncEntry(DMF_TRACE);
if (config->EvtDeviceEnumerated)
{
config->EvtDeviceEnumerated(ChildDevice,
Irp);
}
// Forward to the parent bus driver
//
IoSkipCurrentIrpStackLocation(Irp);
ntStatus = IoCallDriver(DMF_BusFilter_WdmAttachedDeviceGet(ChildDevice),
Irp);
FuncExit(DMF_TRACE, "ntStatus=%!STATUS!", ntStatus);
return ntStatus;
}
static
NTSTATUS
DMF_BusFilter_PnP_QueryId(
_In_ DMFBUSCHILDDEVICE ChildDevice,
_In_ PIRP Irp
)
/*++
Routine Description:
Handles IRP_MN_QUERY_ID.
Arguments:
ChildDevice - Associated child device.
Irp - IRP_MJ_PNP / IRP_MN_QUERY_ID request.
Return Value:
NTSTATUS
--*/
{
NTSTATUS ntStatus;
const BusFilter_Context* context = BusFilterContextGet(WdfGetDriver());
const DMF_BusFilter_CONFIG* config = &context->Configuration;
FuncEntry(DMF_TRACE);
// Forward immediately if client driver has no handler
//
if (config->EvtDeviceQueryId == NULL)
{
IoSkipCurrentIrpStackLocation(Irp);
ntStatus = IoCallDriver(DMF_BusFilter_WdmAttachedDeviceGet(ChildDevice),
Irp);
FuncExit(DMF_TRACE, "status=%!STATUS!", ntStatus);
return ntStatus;
}
// If client driver didn't do anything with the IRP...
//
if (!config->EvtDeviceQueryId(ChildDevice, Irp))
{
// ...forward it prior to completion
//
if (!IoForwardIrpSynchronously(DMF_BusFilter_WdmAttachedDeviceGet(ChildDevice),
Irp))
{
TraceError(DMF_TRACE, "IoForwardIrpSynchronously fails: Irp=0x%p", Irp);
Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
}
}
// Complete the Irp.
//
ntStatus = Irp->IoStatus.Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
FuncExit(DMF_TRACE, "status=%!STATUS!", ntStatus);
return ntStatus;
}
static
NTSTATUS
DMF_BusFilter_PnP_QueryInterface(
_In_ DMFBUSCHILDDEVICE ChildDevice,
_In_ PIRP Irp
)
/*++
Routine Description:
Handles IRP_MN_QUERY_INTERFACE.
Arguments:
ChildDevice - Associated child device.
Irp - IRP_MJ_PNP / IRP_MN_QUERY_INTERFACE request.
Return Value:
NTSTATUS
--*/
{
NTSTATUS ntStatus;
const BusFilter_Context* context = BusFilterContextGet(WdfGetDriver());
const DMF_BusFilter_CONFIG* config = &context->Configuration;
FuncEntry(DMF_TRACE);
// Forward immediately if client driver has no handler
//
if (config->EvtDeviceQueryInterface == NULL)
{
IoSkipCurrentIrpStackLocation(Irp);
ntStatus = IoCallDriver(DMF_BusFilter_WdmAttachedDeviceGet(ChildDevice),
Irp);
FuncExit(DMF_TRACE, "status=%!STATUS!", ntStatus);
return ntStatus;
}
// If client driver didn't do anything with the IRP...
//
if (!config->EvtDeviceQueryInterface(ChildDevice, Irp))
{
// ...forward it prior to completion
//
if (!IoForwardIrpSynchronously(DMF_BusFilter_WdmAttachedDeviceGet(ChildDevice),
Irp))
{
TraceError(DMF_TRACE, "IoForwardIrpSynchronously fails: Irp=0x%p", Irp);
Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
}
}
// Complete the Irp
//
ntStatus = Irp->IoStatus.Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
FuncExit(DMF_TRACE, "status=%!STATUS!", ntStatus);
return ntStatus;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
// BusFilter Public Calls by Client
//
#pragma warning(disable:4995)
#pragma code_seg("PAGE")
_IRQL_requires_max_(PASSIVE_LEVEL)
_Must_inspect_result_
NTSTATUS
DMF_BusFilter_Initialize(
_In_ DMF_BusFilter_CONFIG* BusFilterConfig
)
/*++
Routine Description:
Called by Client Driver to initialize DMF BusFilter operations from DriverEntry().
Arguments:
BusFilterConfig - Client Driver configuration parameters.
Return Value:
NTSTATUS
--*/
{
NTSTATUS ntStatus;
WDF_OBJECT_ATTRIBUTES attributes;
BusFilter_Context* contextBusFilter;
FuncEntry(DMF_TRACE);
PAGED_CODE();
contextBusFilter = NULL;
// Config is required
//
if (BusFilterConfig == NULL)
{
ntStatus = STATUS_INVALID_PARAMETER;
goto Exit;
}
// Driver object must be already created
//
if (!WdfGetDriver())
{
ntStatus = STATUS_NOT_SUPPORTED;
goto Exit;
}
if (!BusFilterConfig->DriverObject)
{
ntStatus = STATUS_INVALID_PARAMETER;
goto Exit;
}
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes,
BusFilter_Context);
// Attach context to driver object.
//
ntStatus = WdfObjectAllocateContext(WdfGetDriver(),
&attributes,
(void**)&contextBusFilter);
if (!NT_SUCCESS(ntStatus))
{
TraceError(DMF_TRACE, "WdfObjectAllocateContext fails: ntStatus=%!STATUS!",ntStatus);
goto Exit;
}
// Save copy of config in context to invoke callback routines later.
//
RtlCopyMemory(&contextBusFilter->Configuration,
BusFilterConfig,
sizeof(DMF_BusFilter_CONFIG));
ULONG index;
PDRIVER_DISPATCH* pDispatch;
// Store original dispatch routine pointers and overwrite with our own
//
#pragma warning(disable:28175)
for (
index = 0,
pDispatch = BusFilterConfig->DriverObject->MajorFunction;
index <= IRP_MJ_MAXIMUM_FUNCTION;
index++, pDispatch++
)
{
contextBusFilter->MajorDispatchFunctions[index] = *pDispatch;
*pDispatch = DMF_BusFilter_DispatchHandler;
}
#pragma warning(default:28175)
// PnP minor code dispatch routines
//
contextBusFilter->PnPMinorDispatchFunctions[IRP_MN_START_DEVICE] = DMF_BusFilter_PnP_StartDevice;
contextBusFilter->PnPMinorDispatchFunctions[IRP_MN_DEVICE_ENUMERATED] = DMF_BusFilter_PnP_DeviceEnumerated;
contextBusFilter->PnPMinorDispatchFunctions[IRP_MN_QUERY_ID] = DMF_BusFilter_PnP_QueryId;
contextBusFilter->PnPMinorDispatchFunctions[IRP_MN_QUERY_INTERFACE] = DMF_BusFilter_PnP_QueryInterface;
// Clear invalid characteristics (see MS docs)
//
BusFilterConfig->DeviceCharacteristics &= ~(FILE_AUTOGENERATED_DEVICE_NAME |
FILE_CHARACTERISTIC_TS_DEVICE |
FILE_CHARACTERISTIC_WEBDAV_DEVICE |
FILE_DEVICE_IS_MOUNTED |
FILE_VIRTUAL_VOLUME);
ntStatus = STATUS_SUCCESS;
Exit:
FuncExit(DMF_TRACE, "status=%!STATUS!", ntStatus);
return ntStatus;
}
#pragma code_seg()
#pragma warning(default:4995)
#pragma code_seg("PAGE")
NTSTATUS
DMF_BusFilter_DeviceAdd(
_In_ WDFDRIVER Driver,
_Inout_ PWDFDEVICE_INIT DeviceInit
)
/*++
Routine Description:
Creates bus WDF device.
Arguments:
Driver - Associated WDFDRIVER.
DeviceInit - WDF PWDFDEVICE_INIT.
Return Value:
NTSTATUS
--*/
{
NTSTATUS ntStatus = STATUS_NOT_IMPLEMENTED;
WDF_OBJECT_ATTRIBUTES attributes;
WDFDEVICE device = NULL;
UCHAR minorPnP = IRP_MN_QUERY_DEVICE_RELATIONS;
PDMFDEVICE_INIT dmfDeviceInit = NULL;
FuncEntry(DMF_TRACE);
PAGED_CODE();
const BusFilter_Context* context = BusFilterContextGet(Driver);
const DMF_BusFilter_CONFIG* config = &context->Configuration;
WdfFdoInitSetFilter(DeviceInit);
// Attach IRP preprocessor.
//
ntStatus = WdfDeviceInitAssignWdmIrpPreprocessCallback(DeviceInit,
DMF_BusFilter_PreprocessQueryBusRelations,
IRP_MJ_PNP,
&minorPnP,
1);
if (!NT_SUCCESS(ntStatus))
{
TraceError(DMF_TRACE, "WdfDeviceInitAssignWdmIrpPreprocessCallback fails: ntStatus=%!STATUS!", ntStatus);
goto Exit;
}
// Don't initialize with context here as client driver might decide
// to set their own context memory in EvtPreBusDeviceAdd
//
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
// Call pre-device-creation callback, if set.
//
if (config->EvtPreBusDeviceAdd)
{
ntStatus = config->EvtPreBusDeviceAdd(Driver,
DeviceInit,
&attributes,
&dmfDeviceInit);
if (!NT_SUCCESS(ntStatus))
{
TraceError(DMF_TRACE, "EvtPreBusDeviceAdd fails: ntStatus=%!STATUS!", ntStatus);
goto Exit;
}
}
// Client driver is using DMF modules.
//
if (dmfDeviceInit != NULL)
{
DMF_DmfFdoSetFilter(dmfDeviceInit);
}
// Create device object
//
ntStatus = WdfDeviceCreate(&DeviceInit,
&attributes,
&device);
if (!NT_SUCCESS(ntStatus))
{
TraceError(DMF_TRACE, "WdfDeviceCreate fails: ntStatus=%!STATUS!", ntStatus);
goto Exit;
}
PARENT_BUS_DEVICE_CONTEXT* parentContext = NULL;
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes,
PARENT_BUS_DEVICE_CONTEXT);
// Add bus device context.
//
ntStatus = WdfObjectAllocateContext(device,
&attributes,
(void**)&parentContext);
if (!NT_SUCCESS(ntStatus))
{
TraceError(DMF_TRACE, "WdfObjectAllocateContext fails: ntStatus=%!STATUS!", ntStatus);
goto Exit;
}
InitializeListHead(&parentContext->ChildList);
KeInitializeSpinLock(&parentContext->ChildListLock);
// Call post-device-creation callback, if set.
//
if (config->EvtPostBusDeviceAdd)
{
ntStatus = config->EvtPostBusDeviceAdd(device,
dmfDeviceInit);
if (!NT_SUCCESS(ntStatus))
{
TraceError(DMF_TRACE, "EvtPostBusDeviceAdd fails: ntStatus=%!STATUS!", ntStatus);
goto Exit;
}
}
Exit:
if (!NT_SUCCESS(ntStatus) && dmfDeviceInit != NULL)
{
DMF_DmfDeviceInitFree(&dmfDeviceInit);
}
if (!NT_SUCCESS(ntStatus) && device != NULL)
{
WdfObjectDelete(device);
}
FuncExit(DMF_TRACE, "status=%!STATUS!", ntStatus);
return ntStatus;
}
#pragma code_seg()
PDEVICE_OBJECT
DMF_BusFilter_WdmDeviceObjectGet(
_In_ DMFBUSCHILDDEVICE ChildDevice
)
/*++
Routine Description:
Returns DEVICE_OBJECT associated with a given DMFBUSCHILDDEVICE.
Arguments:
ChildDevice - The given DMFBUSCHILDDEVICE.
Return Value:
The associated DEVICE_OBJECT.
--*/
{
const BUS_CHILD_DEVICE_CONTEXT* childContext = DMF_BusFilter_GetChildContext(ChildDevice);
if (childContext)
{
return childContext->DeviceObject;
}
return NULL;
}
PDEVICE_OBJECT
DMF_BusFilter_WdmAttachedDeviceGet(
_In_ DMFBUSCHILDDEVICE ChildDevice
)
/*++
Routine Description:
Returns the attached DEVICE_OBJECT associated with a given DMFBUSCHILDDEVICE.
Arguments:
ChildDevice - The given DMFBUSCHILDDEVICE.
Return Value:
The attached DEVICE_OBJECT.
--*/
{
const BUS_CHILD_DEVICE_CONTEXT* childContext = DMF_BusFilter_GetChildContext(ChildDevice);
if (childContext)
{
const WDM_CHILD_DEVICE_EXTENSION* childExtension = (WDM_CHILD_DEVICE_EXTENSION*)childContext->DeviceObject->DeviceExtension;
if (IsEqualGUID(&childExtension->Signature,
&GUID_DMF_BUSFILTER_SIGNATURE))
{
return childExtension->TargetDeviceObject;
}
}
return NULL;
}
PDEVICE_OBJECT
DMF_BusFilter_WdmPhysicalDeviceGet(
_In_ DMFBUSCHILDDEVICE ChildDevice
)
/*++
Routine Description:
Returns the associated physical DEVICE_OBJECT associated with a given DMFBUSCHILDDEVICE.
Arguments:
ChildDevice - The given DMFBUSCHILDDEVICE.
Return Value:
The associated physical (parent) DEVICE_OBJECT.
--*/
{
const BUS_CHILD_DEVICE_CONTEXT* childContext = DMF_BusFilter_GetChildContext(ChildDevice);
if (childContext)
{
const WDM_CHILD_DEVICE_EXTENSION* childExtension = (WDM_CHILD_DEVICE_EXTENSION*)childContext->DeviceObject->DeviceExtension;
if (IsEqualGUID(&childExtension->Signature,
&GUID_DMF_BUSFILTER_SIGNATURE))
{
return childExtension->PhysicalDeviceObject;
}
}
return NULL;
}
#endif // defined(DMF_KERNEL_MODE)