/*++ 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 #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) KeAcquireInStackQueuedSpinLock(&parentContext->ChildListLock, &handle); RemoveEntryList(&extension->ListEntry); KeReleaseInStackQueuedSpinLock(&handle); #pragma warning(default: 28150) 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) 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); #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)