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