1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 FxIoTargetRemoteKm.cpp 8 9 Abstract: 10 11 Author: 12 13 Environment: 14 15 kernel mode only 16 17 Revision History: 18 19 --*/ 20 21 #include "../../fxtargetsshared.hpp" 22 23 extern "C" { 24 // #include "FxIoTargetRemoteKm.tmh" 25 } 26 27 #include <initguid.h> 28 #include "wdmguid.h" 29 30 _Must_inspect_result_ 31 NTSTATUS 32 STDCALL 33 FxIoTargetRemote::_PlugPlayNotification( 34 __in PVOID NotificationStructure, 35 __inout_opt PVOID Context 36 ) 37 { 38 PFX_DRIVER_GLOBALS pFxDriverGlobals; 39 PTARGET_DEVICE_REMOVAL_NOTIFICATION pNotification; 40 FxIoTargetRemote* pThis; 41 NTSTATUS status; 42 43 ASSERT(Mx::MxGetCurrentIrql() < DISPATCH_LEVEL); 44 pNotification = (PTARGET_DEVICE_REMOVAL_NOTIFICATION) NotificationStructure; 45 pThis = (FxIoTargetRemote*) Context; 46 47 // 48 // In one of these callbacks, the driver may decide to delete the target. 49 // If that is the case, we need to be able to return and deref the object until 50 // we are done. 51 // 52 pThis->ADDREF((PVOID)_PlugPlayNotification); 53 54 pFxDriverGlobals = pThis->GetDriverGlobals(); 55 56 status = STATUS_SUCCESS; 57 58 if (FxIsEqualGuid(&pNotification->Event, &GUID_TARGET_DEVICE_QUERY_REMOVE)) { 59 60 DoTraceLevelMessage( 61 pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 62 "WDFIOTARGET %p: query remove notification", pThis->GetObjectHandle()); 63 64 // 65 // Device is gracefully being removed. PnP is asking us to close down 66 // the target. If there is a driver callback, there is *no* default 67 // behavior. This is because we don't know what the callback is going 68 // to do. For instance, the driver could reopen the target to a 69 // different device in a multi-path scenario. 70 // 71 if (pThis->m_EvtQueryRemove.m_Method != NULL) { 72 status = pThis->m_EvtQueryRemove.Invoke(pThis->GetHandle()); 73 } 74 else { 75 DoTraceLevelMessage( 76 pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 77 "WDFIOTARGET %p: query remove, default action (close for QR)", 78 pThis->GetObjectHandle()); 79 80 // 81 // No callback, close it down conditionally. 82 // 83 pThis->Close(FxIoTargetRemoteCloseReasonQueryRemove); 84 } 85 } 86 else if (FxIsEqualGuid(&pNotification->Event, &GUID_TARGET_DEVICE_REMOVE_COMPLETE)) { 87 88 DoTraceLevelMessage( 89 pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 90 "WDFIOTARGET %p: remove complete notification", pThis->GetObjectHandle()); 91 92 // 93 // The device was surprise removed, close it for good if the driver has 94 // no override. 95 // 96 if (pThis->m_EvtRemoveComplete.m_Method != NULL) { 97 pThis->m_EvtRemoveComplete.Invoke(pThis->GetHandle()); 98 } 99 else { 100 DoTraceLevelMessage( 101 pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 102 "WDFIOTARGET %p: remove complete, default action (close)", 103 pThis->GetObjectHandle()); 104 105 // 106 // The device is now gone for good. Close down the target for good. 107 // 108 pThis->Close(FxIoTargetRemoteCloseReasonPlainClose); 109 } 110 } 111 else if (FxIsEqualGuid(&pNotification->Event, &GUID_TARGET_DEVICE_REMOVE_CANCELLED)) { 112 113 DoTraceLevelMessage( 114 pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 115 "WDFIOTARGET %p: remove canceled notification", pThis->GetObjectHandle()); 116 117 if (pThis->m_EvtRemoveCanceled.m_Method != NULL) { 118 pThis->m_EvtRemoveCanceled.Invoke(pThis->GetHandle()); 119 } 120 else { 121 WDF_IO_TARGET_OPEN_PARAMS params; 122 123 DoTraceLevelMessage( 124 pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 125 "WDFIOTARGET %p: remove canceled, default action (reopen)", 126 pThis->GetObjectHandle()); 127 128 WDF_IO_TARGET_OPEN_PARAMS_INIT_REOPEN(¶ms); 129 130 // 131 // Attempt to reopen the target with stored settings 132 // 133 status = pThis->Open(¶ms); 134 } 135 } 136 137 pThis->RELEASE((PVOID)_PlugPlayNotification); 138 139 return status; 140 } 141 142 NTSTATUS 143 FxIoTargetRemote::RegisterForPnpNotification( 144 ) 145 { 146 NTSTATUS status; 147 148 // 149 // Register for PNP notifications on the handle we just opened. 150 // This will notify us of pnp state changes on the handle. 151 // 152 status = IoRegisterPlugPlayNotification( 153 EventCategoryTargetDeviceChange, 154 0, 155 m_TargetFileObject, 156 m_Driver->GetDriverObject(), 157 _PlugPlayNotification, 158 this, 159 &m_TargetNotifyHandle); 160 161 return status; 162 } 163 164 VOID 165 FxIoTargetRemote::UnregisterForPnpNotification( 166 _In_ MdTargetNotifyHandle Handle 167 ) 168 { 169 if (Handle != NULL) { 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 if (FxLibraryGlobals.IoUnregisterPlugPlayNotificationEx != NULL) { 194 FxLibraryGlobals.IoUnregisterPlugPlayNotificationEx(Handle); 195 } 196 else { 197 IoUnregisterPlugPlayNotification(Handle); 198 } 199 } 200 } 201 202 NTSTATUS 203 FxIoTargetRemote::OpenTargetHandle( 204 _In_ PWDF_IO_TARGET_OPEN_PARAMS OpenParams, 205 _Inout_ FxIoTargetRemoveOpenParams* pParams 206 ) 207 { 208 OBJECT_ATTRIBUTES oa; 209 IO_STATUS_BLOCK ioStatus; 210 NTSTATUS status; 211 212 InitializeObjectAttributes(&oa, 213 &pParams->TargetDeviceName, 214 OBJ_KERNEL_HANDLE, 215 NULL, 216 NULL); 217 218 status = ZwCreateFile(&m_TargetHandle, 219 pParams->DesiredAccess, 220 &oa, 221 &ioStatus, 222 pParams->AllocationSizePointer, 223 pParams->FileAttributes, 224 pParams->ShareAccess, 225 pParams->CreateDisposition, 226 pParams->CreateOptions, 227 pParams->EaBuffer, 228 pParams->EaBufferLength); 229 230 OpenParams->FileInformation = (ULONG)ioStatus.Information; 231 232 if (NT_SUCCESS(status)) { 233 DoTraceLevelMessage( 234 GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGIOTARGET, 235 "ZwCreateFile for WDFIOTARGET %p returned status %!STATUS!, info 0x%x", 236 GetObjectHandle(), status, (ULONG) ioStatus.Information); 237 238 // 239 // The open operation was successful. Dereference the file handle and 240 // obtain a pointer to the device object for the handle. 241 // 242 status = ObReferenceObjectByHandle( 243 m_TargetHandle, 244 pParams->DesiredAccess, 245 *IoFileObjectType, 246 KernelMode, 247 (PVOID*) &m_TargetFileObject, 248 NULL); 249 250 if (NT_SUCCESS(status)) { 251 m_TargetDevice = IoGetRelatedDeviceObject(m_TargetFileObject); 252 253 if (m_TargetDevice == NULL) { 254 DoTraceLevelMessage( 255 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 256 "WDFIOTARGET %p, could not convert filobj %p to devobj", 257 GetObjectHandle(), m_TargetFileObject); 258 259 status = STATUS_NO_SUCH_DEVICE; 260 } 261 } 262 else { 263 DoTraceLevelMessage( 264 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 265 "WDFIOTARGET %p, could not convert handle %p to fileobject, " 266 "status %!STATUS!", 267 GetObjectHandle(), m_TargetHandle, status); 268 } 269 } 270 else { 271 DoTraceLevelMessage( 272 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 273 "ZwCreateFile for WDFIOTARGET %p returned status %!STATUS!, info 0x%x", 274 GetObjectHandle(), status, (ULONG) ioStatus.Information); 275 } 276 277 return status; 278 } 279 280 NTSTATUS 281 FxIoTargetRemote::GetTargetDeviceRelations( 282 _Inout_ BOOLEAN* Close 283 ) 284 { 285 PDEVICE_OBJECT pTopOfStack; 286 FxAutoIrp irp(NULL); 287 PIRP pIrp; 288 NTSTATUS status; 289 290 pTopOfStack = IoGetAttachedDeviceReference(m_TargetDevice); 291 292 pIrp = IoAllocateIrp(pTopOfStack->StackSize, FALSE); 293 294 if (pIrp != NULL) { 295 PIO_STACK_LOCATION stack; 296 297 irp.SetIrp(pIrp); 298 299 stack = irp.GetNextIrpStackLocation(); 300 stack->MajorFunction = IRP_MJ_PNP; 301 stack->MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS; 302 stack->Parameters.QueryDeviceRelations.Type = TargetDeviceRelation; 303 304 // 305 // Initialize the status to error in case the bus driver decides not 306 // to set it correctly. 307 // 308 irp.SetStatus(STATUS_NOT_SUPPORTED); 309 310 status = irp.SendIrpSynchronously(pTopOfStack); 311 312 if (NT_SUCCESS(status)) { 313 PDEVICE_RELATIONS pRelations; 314 315 pRelations = (PDEVICE_RELATIONS) irp.GetInformation(); 316 317 ASSERT(pRelations != NULL); 318 319 // 320 // m_TargetPdo was referenced by the bus driver, it will be 321 // dereferenced when the target is closed. 322 // 323 m_TargetPdo = pRelations->Objects[0]; 324 325 // 326 // We, as the caller, are responsible for freeing the relations 327 // that the bus driver allocated. 328 // 329 ExFreePool(pRelations); 330 } 331 else { 332 // 333 // Could not retrieve the PDO pointer, error handled later 334 // 335 DO_NOTHING(); 336 } 337 } 338 else { 339 // 340 // Could not even allocate an irp, failure. 341 // 342 status = STATUS_INSUFFICIENT_RESOURCES; 343 DoTraceLevelMessage( 344 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, 345 "Unable to allocate memory for IRP WDFIOTARGET %p, %!STATUS!", 346 GetObjectHandle(), status); 347 } 348 349 // 350 // Only fail the open if we cannot allocate an irp or if the lower 351 // driver could not allocate a relations. 352 // 353 if (status == STATUS_INSUFFICIENT_RESOURCES) { 354 *Close = TRUE; 355 } 356 else { 357 status = STATUS_SUCCESS; 358 } 359 360 // 361 // Remove the reference taken by IoGetAttachedDeviceReference 362 // 363 ObDereferenceObject(pTopOfStack); 364 365 return status; 366 } 367 368