1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 FxQueryInterfaceAPI.cpp 8 9 Abstract: 10 11 This module implements the device interface object. 12 13 Author: 14 15 16 17 18 Environment: 19 20 Kernel mode only 21 22 Revision History: 23 24 --*/ 25 #include "fxsupportpch.hpp" 26 27 extern "C" { 28 // #include "FxQueryInterfaceAPI.tmh" 29 } 30 31 // 32 // Extern "C" the entire file 33 // 34 extern "C" { 35 _Must_inspect_result_ 36 __drv_maxIRQL(PASSIVE_LEVEL) 37 NTSTATUS 38 STDCALL 39 WDFEXPORT(WdfDeviceAddQueryInterface)( 40 __in 41 PWDF_DRIVER_GLOBALS DriverGlobals, 42 __in 43 WDFDEVICE Device, 44 __in 45 PWDF_QUERY_INTERFACE_CONFIG InterfaceConfig 46 ) 47 { 48 PFX_DRIVER_GLOBALS pFxDriverGlobals; 49 FxQueryInterface *pQueryInterface; 50 FxDevice *pDevice; 51 PINTERFACE pInterface; 52 NTSTATUS status; 53 54 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 55 Device, 56 FX_TYPE_DEVICE, 57 (PVOID*) &pDevice, 58 &pFxDriverGlobals ); 59 60 pQueryInterface = NULL; 61 62 FxPointerNotNull(pFxDriverGlobals, Device); 63 FxPointerNotNull(pFxDriverGlobals, InterfaceConfig); 64 FxPointerNotNull(pFxDriverGlobals, InterfaceConfig->InterfaceType); 65 66 status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); 67 if (!NT_SUCCESS(status)) { 68 return status; 69 } 70 71 pInterface = InterfaceConfig->Interface; 72 73 if (InterfaceConfig->Size != sizeof(WDF_QUERY_INTERFACE_CONFIG)) { 74 status = STATUS_INFO_LENGTH_MISMATCH; 75 76 DoTraceLevelMessage( 77 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, 78 "WDFDEVICE %p, WDF_QUERY_INTERFACE_CONFIG Size %d, expected %d, " 79 "%!STATUS!", Device, InterfaceConfig->Size, 80 sizeof(WDF_QUERY_INTERFACE_CONFIG), status); 81 82 goto Done; 83 } 84 85 // 86 // A pass through interface is only associated with PDOs 87 // 88 if (InterfaceConfig->SendQueryToParentStack && pDevice->IsPdo() == FALSE) { 89 status = STATUS_INVALID_PARAMETER; 90 91 DoTraceLevelMessage( 92 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, 93 "SendQueryToParentStack TRUE, but WDFDEVICE %p not a PDO, %!STATUS!", 94 Device, status); 95 96 goto Done; 97 } 98 99 // 100 // The only time we can have a NULL Interface is if the interface is 101 // passthrough or it is an import interface (since on import interfaces 102 // the callback must do the copying). 103 // 104 if (pInterface == NULL) { 105 if (InterfaceConfig->SendQueryToParentStack || InterfaceConfig->ImportInterface) { 106 // 107 // A NULL interface is valid for this config 108 // 109 DO_NOTHING(); 110 } 111 else { 112 status = STATUS_INVALID_PARAMETER; 113 114 DoTraceLevelMessage( 115 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, 116 "WDFDEVICE %p, SendQueryToParentStack is FALSE and " 117 "InterfaceConfig->ImportInterface is FALSE, %!STATUS!", 118 Device, status); 119 120 goto Done; 121 } 122 } 123 124 // 125 // If it is an import interface, we need a callback so that the driver can 126 // modify the interface being returned. 127 // 128 if (InterfaceConfig->ImportInterface && 129 InterfaceConfig->EvtDeviceProcessQueryInterfaceRequest == NULL) { 130 status = STATUS_INVALID_PARAMETER; 131 132 DoTraceLevelMessage( 133 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, 134 "WDFDEVICE %p, ImportInterface is TRUE and " 135 "EvtDeviceProcessQueryInterfaceRequest is NULL, %!STATUS!", 136 Device, status); 137 138 goto Done; 139 } 140 141 if (pInterface != NULL) { 142 // 143 // Make sure we are exposing the minimum size 144 // 145 if (pInterface->Size < sizeof(INTERFACE)) { 146 status = STATUS_INVALID_PARAMETER; 147 148 DoTraceLevelMessage( 149 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, 150 "WDFDEVICE %p, Interface size %d < sizeof(INTERFACE) (%d), " 151 "%!STATUS!", Device, pInterface->Size, sizeof(INTERFACE), status); 152 153 goto Done; 154 } 155 } 156 157 // 158 // Since the QI irp is only allowed to be sent at passive level and 159 // the list of FxQueryInterface's is locked by a lock which does not 160 // raise IRQL, we can allocate the structure out paged pool. 161 // 162 pQueryInterface = new (pFxDriverGlobals, PagedPool) 163 FxQueryInterface(pDevice, InterfaceConfig); 164 165 if (pQueryInterface == NULL) { 166 status = STATUS_INSUFFICIENT_RESOURCES; 167 168 DoTraceLevelMessage( 169 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, 170 "WDFDEVICE %p, object creation failed, %!STATUS!", Device, status); 171 172 goto Done; 173 } 174 175 if (pInterface != NULL) { 176 // 177 // Try to allocate memory for the interface. 178 // 179 pQueryInterface->m_Interface = (PINTERFACE) 180 FxPoolAllocate(pFxDriverGlobals, PagedPool, pInterface->Size); 181 182 if (pQueryInterface->m_Interface == NULL) { 183 status = STATUS_INSUFFICIENT_RESOURCES; 184 185 DoTraceLevelMessage( 186 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, 187 "WDFDEVICE %p, interface allocation failed, %!STATUS!", 188 Device, status); 189 190 goto Done; 191 } 192 193 RtlCopyMemory(pQueryInterface->m_Interface, 194 pInterface, 195 pInterface->Size); 196 197 if (pInterface->InterfaceReference == NULL) { 198 pQueryInterface->m_Interface->InterfaceReference = 199 FxDevice::_InterfaceReferenceNoOp; 200 } 201 if (pInterface->InterfaceDereference == NULL) { 202 pQueryInterface->m_Interface->InterfaceDereference = 203 FxDevice::_InterfaceDereferenceNoOp; 204 } 205 } 206 207 status = STATUS_SUCCESS; 208 209 pDevice->m_PkgPnp->AddQueryInterface(pQueryInterface, TRUE); 210 211 Done: 212 // 213 // Delete the query interface structure if there is an error. 214 // 215 if (!NT_SUCCESS(status) && pQueryInterface != NULL) { 216 delete pQueryInterface; 217 pQueryInterface = NULL; 218 } 219 220 return status; 221 } 222 223 } // extern "C" 224