1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 FxPkgGeneral.cpp 8 9 Abstract: 10 11 This module implements the wmi package for the driver frameworks. 12 13 Author: 14 15 16 17 18 Environment: 19 20 Both kernel and user mode 21 22 Revision History: 23 24 --*/ 25 26 #if ((FX_CORE_MODE)==(FX_CORE_USER_MODE)) 27 #define FX_IS_USER_MODE (TRUE) 28 #define FX_IS_KERNEL_MODE (FALSE) 29 #elif ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) 30 #define FX_IS_USER_MODE (FALSE) 31 #define FX_IS_KERNEL_MODE (TRUE) 32 #endif 33 34 extern "C" { 35 #include "mx.h" 36 } 37 #include "fxmin.hpp" 38 39 extern "C" { 40 // #include "FxPkgGeneral.tmh" 41 } 42 43 44 FxPkgGeneral::FxPkgGeneral( 45 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 46 __in CfxDevice *Device 47 ) : 48 FxPackage(FxDriverGlobals, Device, FX_TYPE_PACKAGE_GENERAL) 49 { 50 // 51 // The count is biased to one and not zero for control device objects. When 52 // a control devobj is deleted, we will decrement this bias out so that we 53 // know when the last handle has been closed and it is now safe to free the 54 // FxDevice. 55 // 56 m_OpenHandleCount = 1; 57 58 // 59 // List of file object info. 60 // 61 InitializeListHead(&m_FileObjectInfoHeadList); 62 63 m_Flags = 0; 64 m_ExecutionLevel = WdfExecutionLevelInheritFromParent; 65 m_SynchronizationScope = WdfSynchronizationScopeInheritFromParent; 66 m_CallbackLockPtr = NULL; 67 m_CallbackLockObjectPtr = NULL; 68 m_DriverCreatedQueue = NULL; 69 m_DefaultQueueForCreates = NULL; 70 } 71 72 FxPkgGeneral::~FxPkgGeneral() 73 { 74 PLIST_ENTRY next; 75 76 ASSERT(m_OpenHandleCount <= 1); 77 78 // 79 // Delete the file object info list if present. 80 // 81 while (!IsListEmpty(&m_FileObjectInfoHeadList)) { 82 next = RemoveHeadList(&m_FileObjectInfoHeadList); 83 FxFileObjectInfo* info; 84 info = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry); 85 InitializeListHead(next); 86 delete info; 87 } 88 } 89 90 _Must_inspect_result_ 91 NTSTATUS 92 FxPkgGeneral::Initialize( 93 __in PWDFDEVICE_INIT DeviceInit 94 ) 95 /*++ 96 97 Routine Description: 98 Initiliazes how the driver will handle fileobjects and their associated 99 event callbacks (create, close, cleanup). 100 101 Assumes that FileObjectAttributes has been validated by the caller. 102 103 Arguments: 104 DeviceInit - Chain of device_init and cx_device_init with file object config. 105 106 Return Value: 107 STATUS_SUCCESS or other NTSTATUS values. 108 109 --*/ 110 { 111 NTSTATUS status; 112 PLIST_ENTRY next; 113 FxFileObjectInfo* fileObjInfo; 114 PFX_DRIVER_GLOBALS fxDriverGlobals; 115 116 fxDriverGlobals = GetDriverGlobals(); 117 118 // 119 // Init file object info. 120 // 121 if (DeviceInit->FileObject.Set) { 122 fileObjInfo = new(fxDriverGlobals) FxFileObjectInfo(); 123 if (fileObjInfo == NULL) { 124 status = STATUS_INSUFFICIENT_RESOURCES; 125 DoTraceLevelMessage(fxDriverGlobals, 126 TRACE_LEVEL_ERROR, TRACINGDEVICE, 127 "Couldn't create object FileObjectInfo, " 128 "%!STATUS!", status); 129 goto Done; 130 } 131 132 fileObjInfo->ClassExtension = FALSE; 133 fileObjInfo->FileObjectClass = DeviceInit->FileObject.Class; 134 fileObjInfo->Attributes = DeviceInit->FileObject.Attributes; 135 136 fileObjInfo->AutoForwardCleanupClose = 137 DeviceInit->FileObject.AutoForwardCleanupClose; 138 139 fileObjInfo->EvtFileCreate.Method = 140 DeviceInit->FileObject.Callbacks.EvtDeviceFileCreate; 141 142 fileObjInfo->EvtFileCleanup.Method = 143 DeviceInit->FileObject.Callbacks.EvtFileCleanup; 144 145 fileObjInfo->EvtFileClose.Method = 146 DeviceInit->FileObject.Callbacks.EvtFileClose; 147 148 InsertTailList(&m_FileObjectInfoHeadList, &fileObjInfo->ListEntry); 149 150 m_Flags |= FX_PKG_GENERAL_FLAG_CLIENT_INFO; 151 152 if (fileObjInfo->EvtFileCreate.Method != NULL) { 153 m_Flags |= FX_PKG_GENERAL_FLAG_CLIENT_CREATE; 154 } 155 } 156 157 // 158 // Build file object info chain for any class extension. 159 // 160 for (next = DeviceInit->CxDeviceInitListHead.Flink; 161 next != &DeviceInit->CxDeviceInitListHead; 162 next = next->Flink) { 163 164 PWDFCXDEVICE_INIT cxInit; 165 166 cxInit = CONTAINING_RECORD(next, WDFCXDEVICE_INIT, ListEntry); 167 168 if (cxInit->FileObject.Set == FALSE) { 169 continue; 170 } 171 172 fileObjInfo = new(fxDriverGlobals) FxFileObjectInfo(); 173 if (fileObjInfo == NULL) { 174 status = STATUS_INSUFFICIENT_RESOURCES; 175 DoTraceLevelMessage(fxDriverGlobals, 176 TRACE_LEVEL_ERROR, TRACINGDEVICE, 177 "Couldn't create object FileObjectInfo, " 178 "%!STATUS!", status); 179 goto Done; 180 } 181 182 fileObjInfo->ClassExtension = TRUE; 183 fileObjInfo->FileObjectClass = cxInit->FileObject.Class; 184 fileObjInfo->Attributes = cxInit->FileObject.Attributes; 185 186 fileObjInfo->AutoForwardCleanupClose = 187 cxInit->FileObject.AutoForwardCleanupClose; 188 189 fileObjInfo->EvtCxFileCreate.Method = 190 cxInit->FileObject.Callbacks.EvtCxDeviceFileCreate; 191 192 fileObjInfo->EvtFileCleanup.Method = 193 cxInit->FileObject.Callbacks.EvtFileCleanup; 194 195 fileObjInfo->EvtFileClose.Method = 196 cxInit->FileObject.Callbacks.EvtFileClose; 197 198 fileObjInfo->CxDeviceInfo = cxInit->CxDeviceInfo; 199 200 InsertTailList(&m_FileObjectInfoHeadList, &fileObjInfo->ListEntry); 201 202 m_Flags |= FX_PKG_GENERAL_FLAG_CX_INFO; 203 204 if (fileObjInfo->EvtCxFileCreate.Method != NULL) { 205 m_Flags |= FX_PKG_GENERAL_FLAG_CX_CREATE; 206 } 207 } 208 209 // 210 // Nothing to do if list if empty. 211 // 212 if (IsListEmpty(&m_FileObjectInfoHeadList)) { 213 status = STATUS_SUCCESS; 214 goto Done; 215 } 216 217 // 218 // We will enable this once the unlocking model is figured out. 219 // It's not okay to sent request downstack with the presentation lock held. 220 // 221 status = ConfigureConstraints(&m_FileObjectInfoHeadList); 222 if(!NT_SUCCESS(status)) { 223 goto Done; 224 } 225 226 // 227 // Configure file object class. 228 // 229 status = ConfigureFileObjectClass(&m_FileObjectInfoHeadList); 230 if (!NT_SUCCESS(status)) { 231 goto Done; 232 } 233 234 status = STATUS_SUCCESS; 235 236 Done: 237 return status; 238 } 239 240 _Must_inspect_result_ 241 NTSTATUS 242 FxPkgGeneral::ConfigureConstraints( 243 __in PLIST_ENTRY FileObjInfoList 244 ) 245 /*++ 246 247 Routine Description: 248 249 Configure the callback synchronization according to the configuration supplied by the 250 client and class extension device driver. 251 It is a requirement for this driver chain (CXs and client driver) to use the same settings. 252 253 Arguments: 254 FileObjInfoList - List of FxFileObjectInfo structs. 255 256 Returns: 257 NTSTATUS 258 259 --*/ 260 { 261 WDF_EXECUTION_LEVEL execLevel, parentExecLevel; 262 WDF_SYNCHRONIZATION_SCOPE synchScope, parentSynchScope; 263 BOOLEAN automaticLockingRequired; 264 PLIST_ENTRY next; 265 FxFileObjectInfo *fileObjInfo; 266 NTSTATUS status; 267 PFX_DRIVER_GLOBALS fxDriverGlobals; 268 269 automaticLockingRequired = FALSE; 270 fxDriverGlobals = GetDriverGlobals(); 271 272 ASSERT(!IsListEmpty(FileObjInfoList)); 273 274 // 275 // Get parent values. 276 // 277 m_Device->GetConstraints(&parentExecLevel, &parentSynchScope); 278 279 // 280 // Default constraints settings when driver uses WDF_NO_OBJECT_ATTRIBUTES: 281 // 282 // v1.9 and below: 283 // WdfExecutionLevelDispatch and WdfSynchronizationScopeNone 284 // 285 // v1.11 and above: 286 // WdfExecutionLevelPassive and WdfSynchronizationScopeNone 287 // 288 // In v1.9 and below if driver used WDF_NO_OBJECT_ATTRIBUTES for 289 // the file object's attributes, the synchronization scope and execution 290 // level were left uninitialized (i.e., zero), which means that WDF 291 // defaulted to WdfSynchronizationScopeInvalid and WdfExecutionLevelInvalid, 292 // WDF interpreted these values as no_passive and no_synchronization. 293 // 294 // This default execution level is used when disposing the device's 295 // general package object and file object object. 296 // Independently of these settings WDF guarantees that Create, 297 // Cleanup and Close callbacks are always called at passive level. 298 // 299 m_ExecutionLevel = fxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11) ? 300 WdfExecutionLevelPassive : 301 WdfExecutionLevelDispatch; 302 303 m_SynchronizationScope = WdfSynchronizationScopeNone; 304 305 // 306 // Make sure file object info chain follow these constrains: 307 // Cx's synch scope: none 308 // 309 for (next = FileObjInfoList->Blink; 310 next != FileObjInfoList; 311 next = next->Blink) { 312 313 fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry); 314 315 // 316 // Size is zero if driver didn't specify any attributes. 317 // 318 if (0 == fileObjInfo->Attributes.Size) { 319 continue; 320 } 321 322 // 323 // Execution level checks. 324 // 325 execLevel = fileObjInfo->Attributes.ExecutionLevel; 326 if (WdfExecutionLevelInheritFromParent == execLevel) { 327 execLevel = parentExecLevel; 328 } 329 330 // 331 // Passive level wins over DPC level. 332 // 333 if (WdfExecutionLevelPassive == execLevel) { 334 m_ExecutionLevel = WdfExecutionLevelPassive; 335 } 336 337 // 338 // Synchronization scope checks. 339 // 340 synchScope = fileObjInfo->Attributes.SynchronizationScope; 341 if (WdfSynchronizationScopeInheritFromParent == synchScope) { 342 synchScope = parentSynchScope; 343 } 344 345 // 346 // Make sure the Cx's synch scope is none. 347 // 348 if (fileObjInfo->ClassExtension) { 349 if (synchScope != WdfSynchronizationScopeNone) { 350 status = STATUS_INVALID_DEVICE_REQUEST; 351 DoTraceLevelMessage( 352 fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 353 "Driver 0x%p - Device 0x%p - synchronization scope: " 354 "%!WDF_SYNCHRONIZATION_SCOPE! should be" 355 "WdfSynchronizationScopeNone, %!STATUS!", 356 m_Device->GetCxDriver(fileObjInfo->CxDeviceInfo)->GetHandle(), 357 m_Device->GetHandle(), 358 synchScope, 359 status 360 ); 361 362 FxVerifierDbgBreakPoint(fxDriverGlobals); 363 goto Done; 364 } 365 } 366 else { 367 // 368 // Always use client's synch scope for file object. 369 // 370 m_SynchronizationScope = synchScope; 371 } 372 } 373 374 if(m_SynchronizationScope == WdfSynchronizationScopeQueue) { 375 status = STATUS_INVALID_DEVICE_REQUEST; 376 DoTraceLevelMessage( 377 fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 378 "WdfSynchronizationScopeQueue is not allowed on " 379 "FileObject, %!STATUS!", 380 status); 381 goto Done; 382 } 383 384 if (m_ExecutionLevel == WdfExecutionLevelPassive) { 385 386 // 387 // Mark FxObject as passive level to ensure that Dispose and Destroy 388 // callbacks are passive to the driver 389 // 390 MarkPassiveCallbacks(ObjectDoNotLock); 391 // 392 // We aren't going to use a workitem to defer the invocation of fileevents 393 // to passive-level if the caller is at DISPATCH_LEVEL because we wouldn't 394 // be able to guarantee the caller's context for fileevents. It's up to the 395 // driver writer to ensure that the layer above doesn't send create requests 396 // at dispatch-level. 397 // 398 } 399 400 if(m_SynchronizationScope == WdfSynchronizationScopeNone) { 401 status = STATUS_SUCCESS; 402 goto Done; 403 } 404 405 if(m_SynchronizationScope == WdfSynchronizationScopeDevice) { 406 // 407 // Since FileEvents can be invoked only at passive-level, we check the 408 // parent executionlevel to see if it's set to passive. If not, we return an error 409 // because we can't use the presentation lock of the device. 410 // 411 if(parentExecLevel != WdfExecutionLevelPassive) { 412 status = STATUS_INVALID_DEVICE_REQUEST; 413 DoTraceLevelMessage( 414 fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 415 "WdfSynchronizationScopeDevice or " 416 "WdfSynchronizationScopeInheritFromParent " 417 "allowed only if the parent WDFDEVICE 0x%p, " 418 "ExecutionLevel is passive, %!STATUS!", 419 m_Device->GetHandle(), status); 420 goto Done; 421 } 422 423 m_CallbackLockPtr = m_Device->GetCallbackLockPtr(&m_CallbackLockObjectPtr); 424 automaticLockingRequired = TRUE; 425 } 426 427 // 428 // Set lock constraint in client's callbacks object only. 429 // 430 if (automaticLockingRequired) { 431 if (!IsListEmpty(FileObjInfoList)) { 432 fileObjInfo = CONTAINING_RECORD(FileObjInfoList->Flink, 433 FxFileObjectInfo, 434 ListEntry); 435 436 if (FALSE == fileObjInfo->ClassExtension) { 437 fileObjInfo->EvtFileCreate.SetCallbackLockPtr(m_CallbackLockPtr); 438 fileObjInfo->EvtFileCleanup.SetCallbackLockPtr(m_CallbackLockPtr); 439 fileObjInfo->EvtFileClose.SetCallbackLockPtr(m_CallbackLockPtr); 440 } 441 } 442 } 443 444 status = STATUS_SUCCESS; 445 446 Done: 447 return status; 448 } 449 450 _Must_inspect_result_ 451 NTSTATUS 452 FxPkgGeneral::ConfigureFileObjectClass( 453 __in PLIST_ENTRY FileObjInfoList 454 ) 455 /*++ 456 457 Routine Description: 458 459 Configure the file object class for this device. 460 461 These are the possible class settings: 462 463 WdfFileObjectNotRequired 464 WdfFileObjectWdfCanUseFsContext* 465 WdfFileObjectWdfCanUseFsContext2*, 466 WdfFileObjectWdfCannotUseFsContexts* 467 468 * these can also be combined with WdfFileObjectCanBeOptional flag. 469 470 Logic: 471 472 - default: not_required. 473 - if cx/driver selects not_required, skip it. 474 - if cx/driver selects !not_required, than 475 . if everyone agrees on the setting, use that setting. 476 . else use cannot_use_fs_contexts. 477 478 Arguments: 479 FileObjInfoList - List of FxFileObjectInfo structs. 480 481 Returns: 482 NTSTATUS 483 484 --*/ 485 { 486 PLIST_ENTRY next; 487 FxFileObjectInfo* fileObjInfo; 488 NTSTATUS status; 489 PFX_DRIVER_GLOBALS fxDriverGlobals; 490 WDF_FILEOBJECT_CLASS fileObjClass; 491 FxCxDeviceInfo* previousCxInfo; 492 493 fxDriverGlobals = GetDriverGlobals(); 494 fileObjClass = WdfFileObjectNotRequired; 495 previousCxInfo = NULL; 496 497 ASSERT(!IsListEmpty(FileObjInfoList)); 498 499 // 500 // Compute the execution level and synchronization scope for all the chain. 501 // 502 for (next = FileObjInfoList->Blink; 503 next != FileObjInfoList; 504 next = next->Blink) { 505 506 fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry); 507 508 // 509 // If not required, skip it. 510 // 511 if (WdfFileObjectNotRequired == fileObjInfo->FileObjectClass) { 512 continue; 513 } 514 515 // 516 // If the same, skip it. 517 // 518 if (fileObjClass == fileObjInfo->FileObjectClass) { 519 continue; 520 } 521 522 // 523 // If not set yet, use new value. 524 // 525 if (WdfFileObjectNotRequired == fileObjClass) { 526 fileObjClass = fileObjInfo->FileObjectClass; 527 previousCxInfo = fileObjInfo->CxDeviceInfo; 528 continue; 529 } 530 531 // 532 // Make sure optional flag is compatible. 533 // 534 if (FxIsFileObjectOptional(fileObjClass) != 535 FxIsFileObjectOptional(fileObjInfo->FileObjectClass)) { 536 537 status = STATUS_INVALID_DEVICE_REQUEST; 538 DoTraceLevelMessage( 539 fxDriverGlobals, 540 TRACE_LEVEL_ERROR, TRACINGDEVICE, 541 "Device 0x%p - " 542 "Driver 0x%p - WdfFileObjectCanBeOptional (%d) is not " 543 "compatible with wdf extension " 544 "Driver 0x%p - WdfFileObjectCanBeOptional (%d), %!STATUS!", 545 m_Device->GetHandle(), 546 m_Device->GetCxDriver(fileObjInfo->CxDeviceInfo)->GetHandle(), 547 FxIsFileObjectOptional(fileObjInfo->FileObjectClass) ? 1:0, 548 previousCxInfo->Driver->GetHandle(), 549 FxIsFileObjectOptional(fileObjClass) ? 1:0, 550 status 551 ); 552 553 FxVerifierDbgBreakPoint(fxDriverGlobals); 554 goto Done; 555 } 556 557 // 558 // Drivers do not agree on the location, set cannot use fx contexts. 559 // 560 fileObjClass = WdfFileObjectWdfCannotUseFsContexts; 561 if (FxIsFileObjectOptional(fileObjInfo->FileObjectClass)) { 562 fileObjClass = (WDF_FILEOBJECT_CLASS) 563 ((ULONG)fileObjClass | WdfFileObjectCanBeOptional); 564 } 565 566 DoTraceLevelMessage( 567 fxDriverGlobals, 568 TRACE_LEVEL_INFORMATION, TRACINGDEVICE, 569 "Converting file object class for Driver 0x%p - Device 0x%p, " 570 "from 0x%x to 0x%x", 571 m_Device->GetCxDriver(fileObjInfo->CxDeviceInfo)->GetHandle(), 572 m_Device->GetHandle(), 573 fileObjInfo->FileObjectClass, 574 fileObjClass 575 ); 576 } 577 578 // 579 // Set the file object support level on the FxDevice 580 // 581 m_Device->SetFileObjectClass(fileObjClass); 582 583 status = STATUS_SUCCESS; 584 585 Done: 586 return status; 587 } 588 589 _Must_inspect_result_ 590 NTSTATUS 591 FxPkgGeneral::PostCreateDeviceInitialize( 592 __in PWDFDEVICE_INIT Init 593 ) 594 /*++ 595 596 Routine Description: 597 Optionally registers a shutdown and last chance shutdown notification on 598 behalf of the device. 599 600 Arguments: 601 Init - Initialization structure which will indicate if registration is required 602 603 Return Value: 604 NTSTATUS 605 606 --*/ 607 { 608 MdDeviceObject pDevice; 609 NTSTATUS status; 610 WDF_IO_QUEUE_CONFIG queueConfig; 611 WDF_OBJECT_ATTRIBUTES attributes; 612 PFX_DRIVER_GLOBALS pFxDriverGlobals; 613 614 pFxDriverGlobals = GetDriverGlobals(); 615 status = STATUS_SUCCESS; 616 617 618 619 620 #if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) 621 if (Init->Control.Flags != 0) { 622 pDevice = m_Device->GetDeviceObject(); 623 624 if (Init->Control.Flags & WdfDeviceShutdown) { 625 status = IoRegisterShutdownNotification(pDevice); 626 } 627 628 if (NT_SUCCESS(status) && 629 (Init->Control.Flags & WdfDeviceLastChanceShutdown)) { 630 status = IoRegisterLastChanceShutdownNotification(pDevice); 631 632 } 633 634 if (NT_SUCCESS(status)) { 635 // 636 // IoDeleteDevice will automatically unregister the shutdown 637 // notifications if the device is deleted before the machine is 638 // shutdown, so we don't need to track registration beyond this point. 639 // 640 m_EvtDeviceShutdown.m_Method = Init->Control.ShutdownNotification; 641 } 642 else { 643 // 644 // This unregisters both the normal and last chance notifications 645 // 646 IoUnregisterShutdownNotification(pDevice); 647 } 648 } 649 #else 650 UNREFERENCED_PARAMETER(Init); 651 UNREFERENCED_PARAMETER(pDevice); 652 #endif 653 654 if (NT_SUCCESS(status) && (m_Flags & FX_PKG_GENERAL_FLAG_CREATE)) { 655 // 656 // Create an internal queue to track create requests presented to the driver. 657 // This special queue is used so that we can invoke the events in the context 658 // of the caller. 659 // 660 WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchManual); 661 662 // 663 // non power managed queue because we don't anticipate drivers touching 664 // hardware in the fileevent callbacks. If they do, then they should make sure 665 // to power up the device. 666 // 667 queueConfig.PowerManaged = WdfFalse; 668 669 // 670 // Queue inherits the sync & exec level of fileobject. 671 // 672 WDF_OBJECT_ATTRIBUTES_INIT(&attributes); 673 attributes.ExecutionLevel = m_ExecutionLevel; 674 attributes.SynchronizationScope = m_SynchronizationScope; 675 676 status = m_Device->m_PkgIo->CreateQueue(&queueConfig, 677 &attributes, 678 NULL, 679 &m_DefaultQueueForCreates); 680 681 if (!NT_SUCCESS(status)) { 682 DoTraceLevelMessage( 683 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 684 "Unable to create an internal queue for creates for WDFDEVICE " 685 "0x%p, %!STATUS!", m_Device->GetHandle(), status); 686 return status; 687 } 688 } 689 690 return status; 691 } 692 693 _Must_inspect_result_ 694 NTSTATUS 695 FxPkgGeneral::ConfigureForwarding( 696 __in FxIoQueue* TargetQueue 697 ) 698 /*++ 699 700 Routine Description: 701 702 Used to register driver specified for dispatching create requests. 703 704 Arguments: 705 706 Return Value: 707 708 NTSTATUS 709 710 --*/ 711 { 712 NTSTATUS status; 713 PFX_DRIVER_GLOBALS pFxDriverGlobals; 714 KIRQL irql; 715 716 status = STATUS_SUCCESS; 717 pFxDriverGlobals = GetDriverGlobals(); 718 719 if(TargetQueue->IsIoEventHandlerRegistered(WdfRequestTypeCreate) == FALSE){ 720 status = STATUS_INVALID_DEVICE_REQUEST; 721 DoTraceLevelMessage( 722 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 723 "Must have EvtIoDefault registered to receive " 724 "WdfRequestTypeCreate requests for WDFQUEUE 0x%p, " 725 "%!STATUS!", TargetQueue->GetObjectHandle(), status); 726 FxVerifierDbgBreakPoint(pFxDriverGlobals); 727 return status; 728 } 729 730 Lock(&irql); 731 732 if (m_DriverCreatedQueue) { 733 status = STATUS_INVALID_PARAMETER; 734 735 DoTraceLevelMessage( 736 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 737 "Another WDFQUEUE 0x%p is already configured for auto dispatching " 738 "create request, %!STATUS!", 739 m_DriverCreatedQueue->GetObjectHandle(), status); 740 741 FxVerifierDbgBreakPoint(pFxDriverGlobals); 742 } 743 else { 744 m_DriverCreatedQueue = TargetQueue; 745 } 746 747 Unlock(irql); 748 749 return status; 750 } 751 752 _Must_inspect_result_ 753 NTSTATUS 754 FxPkgGeneral::Dispatch( 755 __inout MdIrp Irp 756 ) 757 /*++ 758 759 Routine Description: 760 761 Dispatch routine for handling create, cleanup, close, and shutdown requests. 762 763 Arguments: 764 765 766 Return Value: 767 768 NTSTATUS 769 770 --*/ 771 { 772 NTSTATUS status; 773 PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); 774 FxIrp fxIrp(Irp); 775 776 FX_TRACK_DRIVER(pFxDriverGlobals); 777 778 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, 779 "WDFDEVICE 0x%p !devobj 0x%p %!IRPMJ! IRP 0x%p", 780 m_Device->GetHandle(), m_Device->GetDeviceObject(), 781 fxIrp.GetMajorFunction(), Irp); 782 783 switch (fxIrp.GetMajorFunction()) { 784 case IRP_MJ_CREATE: 785 status = OnCreate(&fxIrp); 786 break; 787 788 case IRP_MJ_CLOSE: 789 status = OnClose(&fxIrp); 790 break; 791 792 case IRP_MJ_CLEANUP: 793 status = OnCleanup(&fxIrp); 794 break; 795 796 case IRP_MJ_SHUTDOWN: 797 status = OnShutdown(&fxIrp); 798 break; 799 800 default: 801 ASSERT(FALSE); 802 status = STATUS_NOT_SUPPORTED; 803 fxIrp.SetStatus(status); 804 fxIrp.CompleteRequest(IO_NO_INCREMENT); 805 break; 806 } 807 808 return status; 809 } 810 811 _Must_inspect_result_ 812 NTSTATUS 813 FxPkgGeneral::OnCreate( 814 __inout FxIrp* FxIrp 815 ) 816 /*++ 817 818 Routine Description: 819 820 1) Allow only one handle to be open for exclusive device. 821 2) Create a WDFFILEOBJECT to represent the WDM fileobject. This 822 fileobject is created only if the driver registers for EvtFile events and 823 doesn't specify WdfFileObjectNotRequired. If the file-events are not 824 registered, the default FileobjectClass is WdfFileObjectNotRequired - set 825 during DeviceInit. 826 3) If the EvtFileCreate event is *not* set or any driver queue is not configured, 827 then complete or forward the request to the lower 828 driver depending on AutoForwardCleanupClose. AutoForwardCleanupClose 829 is set to TRUE by default for filter drivers. 830 4) Create a FxRequest. 831 5) First try to dispatch it to a driver specified queue. 832 6) If there is no driver specified queue, then check to see if the driver has 833 registered EvtDeviceFileCreate event. 834 7) If EvtFileCreate is set then dispatch the request to to an internal 835 manual queue, retrieve the request by fileobject and present the request to 836 the driver in the EvtFileCreate event. This allow the driver to forward the request 837 to another queue to mark the request cancelable and complete it later. 838 839 Arguments: 840 841 Return Value: 842 843 NTSTATUS 844 845 --*/ 846 { 847 NTSTATUS status; 848 FxFileObject* pFxFO ; 849 WDFFILEOBJECT hwdfFO; 850 FxRequest * pRequest; 851 PFX_DRIVER_GLOBALS pFxDriverGlobals; 852 MdFileObject fileObject; 853 LONG count; 854 BOOLEAN inCriticalRegion; 855 BOOLEAN inDefaultQueue; 856 FxFileObjectInfo* fileObjInfo; 857 WDF_OBJECT_ATTRIBUTES attributes; 858 PLIST_ENTRY next; 859 860 pFxFO = NULL; 861 hwdfFO = NULL; 862 pRequest = NULL; 863 inCriticalRegion = FALSE; 864 inDefaultQueue = FALSE; 865 pFxDriverGlobals = GetDriverGlobals(); 866 fileObject = FxIrp->GetFileObject(); 867 fileObjInfo = NULL; 868 869 // 870 // Check for exclusivity. 871 // 872 count = InterlockedIncrement(&m_OpenHandleCount); 873 874 // 875 // The count is biased by one to help track when to delete the control 876 // device, so we need to check for 2, not 1. 877 // 878 if (m_Device->IsExclusive() && count > 2) { 879 DoTraceLevelMessage( 880 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 881 "Exclusive WDFDEVICE 0x%p, only one open handle is allowed", 882 m_Device->GetHandle()); 883 status = STATUS_ACCESS_DENIED; 884 goto Error; 885 } 886 887 // ------------------------------------------------------------------------ 888 // 889 // Create WDFFILEOBJECT. By default we allocate the root driver's file obj 890 // context; then we attach the other file obj contexts. 891 // 892 893 // 894 // Init the file obj's attributes. Use default if not present (legacy behavior). 895 // 896 WDF_OBJECT_ATTRIBUTES_INIT(&attributes); 897 if (!IsListEmpty(&m_FileObjectInfoHeadList)) { 898 // 899 // file obj info is set, use the top most driver's info, i.e., cx if present. 900 // 901 fileObjInfo = CONTAINING_RECORD(m_FileObjectInfoHeadList.Blink, 902 FxFileObjectInfo, 903 ListEntry); 904 905 // 906 // Use this layer's attributes if present. 907 // Size is zero if driver didn't specify file object's attributes. 908 // 909 if (0 != fileObjInfo->Attributes.Size) { 910 ASSERT(fileObjInfo->Attributes.Size == sizeof(WDF_OBJECT_ATTRIBUTES)); 911 attributes = fileObjInfo->Attributes; 912 } 913 914 // 915 // Use computed constraint settings. 916 // 917 attributes.ExecutionLevel = m_ExecutionLevel; 918 attributes.SynchronizationScope = m_SynchronizationScope; 919 } 920 921 // 922 // Create the file object. 923 // 924 status = FxFileObject::_CreateFileObject( 925 m_Device, 926 FxIrp->GetIrp(), 927 m_Device->GetFileObjectClass(), 928 &attributes, 929 fileObject, 930 &pFxFO 931 ); 932 933 if (!NT_SUCCESS(status) ) { 934 DoTraceLevelMessage( 935 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 936 "Could not create WDFFILEOBJECT for WDFDEVICE 0x%p, failing " 937 "IRP_MJ_CREATE %!STATUS!", m_Device->GetHandle(), status); 938 goto Error; 939 } 940 941 if (pFxFO != NULL) { 942 hwdfFO = pFxFO->GetHandle(); 943 944 // 945 // If any, attach the file obj's contexts of the other drivers in this chain. 946 // 947 for (next = m_FileObjectInfoHeadList.Blink->Blink; // skip one. 948 next != &m_FileObjectInfoHeadList; 949 next = next->Blink) { 950 951 fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry); 952 953 attributes = fileObjInfo->Attributes; 954 955 // 956 // Size is zero if driver didn't specify file object's attributes. 957 // 958 if (0 == attributes.Size) { 959 continue; 960 } 961 962 // 963 // Don't need these settings for extra contexts. 964 // 965 attributes.ExecutionLevel = WdfExecutionLevelInheritFromParent; 966 attributes.SynchronizationScope = WdfSynchronizationScopeInheritFromParent; 967 attributes.ParentObject = NULL; 968 969 status = FxObjectAllocateContext(pFxFO, 970 &attributes, 971 TRUE, 972 NULL); 973 if(!NT_SUCCESS(status)) { 974 DoTraceLevelMessage( 975 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 976 "Couldn't allocate file object context 0x%p for " 977 "device 0x%p - driver 0x%p, %!STATUS!", 978 &fileObjInfo->Attributes, 979 m_Device->GetHandle(), 980 m_Device->GetCxDriver(fileObjInfo->CxDeviceInfo)->GetHandle(), 981 status 982 ); 983 984 goto Error; 985 } 986 } 987 } 988 989 // ------------------------------------------------------------------------ 990 // 991 // If there is no driver configured queue or m_EvtFileCreate is not registered, 992 // complete the request with status-success. The reason for making this 993 // check after creating the fileobject is to allow WdfRequestGetFileObject even 994 // if the driver hasn't registered any file-event callbacks. 995 // 996 if (m_DriverCreatedQueue == NULL && 997 (m_Flags & FX_PKG_GENERAL_FLAG_CREATE) == 0) { 998 999 // 1000 // Check to see if the driver has opted to autoforward cleanup and close. 1001 // If so, we should forward create requests also. Else, we should 1002 // complete the request with STATUS_SUCCESS. Note, if the driver is 1003 // a filter driver, the default value of m_AutoForwardCleanupClose is TRUE. 1004 // 1005 // 1006 if (m_Device->m_AutoForwardCleanupClose) { 1007 status = ForwardCreateRequest(FxIrp, _CreateCompletionRoutine, this); 1008 // 1009 // _CreateCompletionRoutine will do the cleanup when the request is 1010 // completed with error status by the lower driver. 1011 // 1012 } 1013 else { 1014 status = STATUS_SUCCESS; 1015 FxIrp->SetStatus(status); 1016 FxIrp->SetInformation(0); 1017 FxIrp->CompleteRequest(IO_NO_INCREMENT); 1018 } 1019 1020 goto RequestIsGone; 1021 } 1022 1023 // ------------------------------------------------------------------------ 1024 // 1025 // Create a FxRequest for this IRP. By default we allocate the top most driver's request 1026 // context; then we attach the other request contexts. 1027 // 1028 1029 // 1030 // Init the request's attributes. 1031 // 1032 if (!IsListEmpty(&m_FileObjectInfoHeadList)) { 1033 // 1034 // file obj info is set, use the top most driver's info, i.e., cx if present. 1035 // 1036 fileObjInfo = CONTAINING_RECORD(m_FileObjectInfoHeadList.Blink, 1037 FxFileObjectInfo, 1038 ListEntry); 1039 if (fileObjInfo->ClassExtension) { 1040 attributes = fileObjInfo->CxDeviceInfo->RequestAttributes; 1041 } 1042 else { 1043 attributes = *m_Device->GetRequestAttributes(); 1044 } 1045 } 1046 else { 1047 attributes = *m_Device->GetRequestAttributes(); 1048 } 1049 1050 if (m_Device->IsCxInIoPath()) { 1051 // 1052 // Apply cx's constrains for create requests: 1053 // 1054 attributes.ExecutionLevel = WdfExecutionLevelDispatch; 1055 attributes.SynchronizationScope = WdfSynchronizationScopeNone; 1056 attributes.ParentObject = NULL; 1057 } 1058 1059 // 1060 // Create the request. 1061 // 1062 status = FxRequest::_CreateForPackage(m_Device, 1063 &attributes, 1064 FxIrp->GetIrp(), 1065 &pRequest); 1066 if(!NT_SUCCESS(status)) { 1067 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 1068 "Could not create request for WDFDEVICE 0x%p, %!STATUS!", 1069 m_Device->GetHandle(), status); 1070 goto Error; 1071 } 1072 1073 // 1074 // If any, attach the request's contexts of the other drivers in this chain. 1075 // 1076 for (next = m_FileObjectInfoHeadList.Blink->Blink; // skip one. 1077 next != &m_FileObjectInfoHeadList; 1078 next = next->Blink) { 1079 1080 fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry); 1081 1082 if (fileObjInfo->ClassExtension) { 1083 attributes = fileObjInfo->CxDeviceInfo->RequestAttributes; 1084 } 1085 else { 1086 attributes = *m_Device->GetRequestAttributes(); 1087 } 1088 1089 // 1090 // Size is zero if driver didn't specify request's attributes. 1091 // 1092 if (0 == attributes.Size) { 1093 continue; 1094 } 1095 1096 // 1097 // Don't need these settings for extra contexts. 1098 // 1099 attributes.ExecutionLevel = WdfExecutionLevelInheritFromParent; 1100 attributes.SynchronizationScope = WdfSynchronizationScopeInheritFromParent; 1101 attributes.ParentObject = NULL; 1102 1103 status = FxObjectAllocateContext( 1104 pRequest, 1105 &attributes, 1106 TRUE, 1107 NULL); 1108 1109 if(!NT_SUCCESS(status)) { 1110 DoTraceLevelMessage( 1111 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 1112 "Couldn't allocate request context for " 1113 "device 0x%p - driver 0x%p, %!STATUS!", 1114 m_Device->GetHandle(), 1115 m_Device->GetCxDriver(fileObjInfo->CxDeviceInfo)->GetHandle(), 1116 status 1117 ); 1118 1119 goto Error; 1120 } 1121 } 1122 1123 // 1124 // Disable thread suspension beyond this point by entering critical region. 1125 // 1126 if (Mx::MxGetCurrentIrql() <= APC_LEVEL) 1127 { 1128 Mx::MxEnterCriticalRegion(); 1129 inCriticalRegion = TRUE; 1130 } 1131 1132 // ------------------------------------------------------------------------ 1133 // 1134 // Queue request in default queue before invoking cx or client's create callbacks. 1135 // 1136 if ((m_Flags & FX_PKG_GENERAL_FLAG_CX_CREATE) || 1137 m_DriverCreatedQueue == NULL) { 1138 1139 FxRequest* outputRequest; 1140 1141 ASSERT(m_Flags & FX_PKG_GENERAL_FLAG_CREATE); 1142 1143 // 1144 // Make sure we are calling FileEvents at the right IRQL level. 1145 // 1146 if (m_ExecutionLevel == WdfExecutionLevelPassive && 1147 Mx::MxGetCurrentIrql() >= DISPATCH_LEVEL) { 1148 1149 status = STATUS_INVALID_DEVICE_REQUEST; 1150 DoTraceLevelMessage( 1151 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 1152 "WDFDEVICE 0x%p cannot handle create request at or above " 1153 "dispatch-level, fail the Irp: 0x%p, %!STATUS!", 1154 m_Device->GetObjectHandle(), FxIrp->GetIrp(), status); 1155 1156 goto Error; 1157 } 1158 1159 // 1160 // Now queue and immediately retrieve the request by FileObject. 1161 // QueueRequest will return an error if the queue is not accepting request 1162 // or the request is already cancelled. Either way, the request is completed by 1163 // the FxIoQueue. 1164 // 1165 status = m_DefaultQueueForCreates->QueueRequest(pRequest); 1166 if (!NT_SUCCESS(status)) { 1167 DoTraceLevelMessage( 1168 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 1169 "Couldn't forward request to the WDFQUEUE 0x%p, %!STATUS!", 1170 m_DefaultQueueForCreates->GetObjectHandle(), status); 1171 goto RequestIsGone; 1172 } 1173 1174 status = m_DefaultQueueForCreates->GetRequest(fileObject, 1175 NULL, 1176 &outputRequest); 1177 if (!NT_SUCCESS(status)) { 1178 // 1179 // Oops, request got cancelled and completed by another thread. 1180 // 1181 ASSERT(status == STATUS_NO_MORE_ENTRIES); 1182 status = STATUS_PENDING; // IRP was already marked pending. 1183 goto RequestIsGone; 1184 } 1185 1186 ASSERT(outputRequest == pRequest); 1187 1188 inDefaultQueue = TRUE; 1189 } 1190 1191 // ------------------------------------------------------------------------ 1192 // 1193 // Invoke Cx's create callbacks. Here we add the cx's file obj and request contexts. 1194 // 1195 if (m_Flags & FX_PKG_GENERAL_FLAG_CX_CREATE) { 1196 1197 // 1198 // Loop through all cx's file obj info. 1199 // 1200 for (next = m_FileObjectInfoHeadList.Blink; 1201 next != &m_FileObjectInfoHeadList; 1202 next = next->Blink) { 1203 1204 // 1205 // Get ready to invoke next layer cx's create. 1206 // 1207 fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry); 1208 1209 // 1210 // Do not invoke the client driver's create callback (if any). For compatibility 1211 // we need to check first the driver 'create' queue. 1212 // 1213 if (FALSE == fileObjInfo->ClassExtension) { 1214 break; 1215 } 1216 1217 ASSERT(fileObjInfo->EvtFileCreate.Method == NULL); 1218 ASSERT(fileObjInfo->EvtCxFileCreate.Method != NULL); 1219 1220 // 1221 // Keep track where we stopped (end, not inclusive node). 1222 // Note that we cannot do this after the Invoke b/c File Object 1223 // may be gone by the time callback returns. 1224 // 1225 if (pFxFO) { 1226 pFxFO->SetPkgCleanupCloseContext(next->Blink); 1227 } 1228 1229 // 1230 // Invoke knows how to handle NULL callbacks. 1231 // 1232 if (fileObjInfo->EvtCxFileCreate.Invoke( 1233 m_Device->GetHandle(), 1234 (WDFREQUEST)pRequest->GetObjectHandle(), 1235 hwdfFO)) { 1236 // 1237 // Callback claimed the request. 1238 // 1239 status = STATUS_PENDING; // IRP was already marked pending. 1240 goto RequestIsGone; 1241 } 1242 } 1243 } 1244 1245 //------------------------------------------------------------------------- 1246 // 1247 // First check for driver configured queue. If there is one, dispatch the request 1248 // to that queue. 1249 // 1250 if (m_DriverCreatedQueue != NULL) { 1251 if (inDefaultQueue) { 1252 ASSERT(m_Flags & FX_PKG_GENERAL_FLAG_CX_INFO); 1253 1254 status = m_DefaultQueueForCreates->ForwardRequest( 1255 m_DriverCreatedQueue, 1256 pRequest); 1257 1258 if(!NT_SUCCESS(status)) { 1259 DoTraceLevelMessage( 1260 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 1261 "Couldn't forward request to the WDFQUEUE 0x%p, %!STATUS!", 1262 m_DriverCreatedQueue->GetObjectHandle(), status); 1263 1264 pRequest->Complete(status); 1265 } 1266 1267 status = STATUS_PENDING; // IRP was already marked pending. 1268 goto RequestIsGone; 1269 } 1270 else { 1271 ASSERT(pRequest->GetRefCnt() == 1); 1272 // 1273 // QueueRequest will return an error if the queue is not accepting request 1274 // or the request is already cancelled. Either way, the request is completed by 1275 // the FxIoQueue. 1276 // 1277 status = m_DriverCreatedQueue->QueueRequest(pRequest); 1278 if(!NT_SUCCESS(status)) { 1279 DoTraceLevelMessage( 1280 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 1281 "Couldn't forward request to the WDFQUEUE 0x%p, %!STATUS!", 1282 m_DriverCreatedQueue->GetObjectHandle(), status); 1283 } 1284 1285 goto RequestIsGone; 1286 } 1287 } 1288 1289 //------------------------------------------------------------------------- 1290 // 1291 // At this point invoke the client driver callback if present. 1292 // 1293 if (m_Flags & FX_PKG_GENERAL_FLAG_CLIENT_CREATE) { 1294 ASSERT(m_Flags & FX_PKG_GENERAL_FLAG_CLIENT_INFO); 1295 ASSERT(TRUE == inDefaultQueue); 1296 ASSERT(fileObjInfo->EvtFileCreate.Method != NULL); 1297 ASSERT(fileObjInfo->EvtCxFileCreate.Method == NULL); 1298 1299 // 1300 // Invoke the client driver create requests. 1301 // 1302 fileObjInfo->EvtFileCreate.Invoke( 1303 m_Device->GetHandle(), 1304 (WDFREQUEST)pRequest->GetObjectHandle(), 1305 hwdfFO); 1306 // 1307 // QueueRequest has already marked the request pending. 1308 // 1309 status = STATUS_PENDING; 1310 goto RequestIsGone; 1311 } 1312 1313 // 1314 // We should be here only if CX's create returned 'continue' but client didn't have 1315 // a create callback. 1316 // 1317 ASSERT(m_Flags & FX_PKG_GENERAL_FLAG_CX_INFO); 1318 1319 // 1320 // Check to see if the driver has opted to autoforward cleanup and close. 1321 // If so, we should forward create requests to lower drivers. Else, we should 1322 // complete the request with STATUS_SUCCESS. Note, if the driver is 1323 // a filter driver, the default value of m_AutoForwardCleanupClose is TRUE. 1324 // 1325 if (m_Device->m_AutoForwardCleanupClose) { 1326 (void)ForwardCreateRequest(FxIrp, _CreateCompletionRoutine2, pRequest); 1327 // 1328 // _CreateCompletionRoutine2 will complete the WDF request. 1329 // 1330 } 1331 else { 1332 pRequest->Complete(STATUS_SUCCESS); 1333 } 1334 1335 // 1336 // Done processing this request. 1337 // 1338 status = STATUS_PENDING; // IRP was already marked pending. 1339 goto RequestIsGone; 1340 1341 Error: 1342 if (pRequest != NULL) { 1343 pRequest->DeleteFromFailedCreate(); 1344 pRequest = NULL; 1345 } 1346 1347 ASSERT(!NT_SUCCESS(status)); 1348 1349 if (pFxFO != NULL) { 1350 pFxFO->DeleteFileObjectFromFailedCreate(); 1351 pFxFO = NULL; 1352 } 1353 1354 // 1355 // NOTE: after this call, this object may have been deleted! 1356 // 1357 DecrementOpenHandleCount(); 1358 1359 FxIrp->SetStatus(status); 1360 FxIrp->SetInformation(0); 1361 FxIrp->CompleteRequest(IO_NO_INCREMENT); 1362 1363 // fallthrough 1364 1365 RequestIsGone: 1366 1367 // 1368 // We have lost the ownership of the request. We have either successfully 1369 // presented the request to the driver or the queue function we called to 1370 // present the request returned error but completed the FxRequest on its own. 1371 // Either way we don't need to worry about cleaning up the resources 1372 // (fileobject, handle-count, etc) because the FxRequest:Completion routine 1373 // will call FxPkgGeneral::CreateCompleted to post process IRP upon completion. 1374 // 1375 if (inCriticalRegion) { 1376 Mx::MxLeaveCriticalRegion(); 1377 } 1378 1379 return status; 1380 } 1381 1382 _Must_inspect_result_ 1383 NTSTATUS 1384 FxPkgGeneral::ForwardCreateRequest( 1385 __in FxIrp* Irp, 1386 __in MdCompletionRoutine CompletionRoutine, 1387 __in PVOID Context 1388 ) 1389 { 1390 NTSTATUS status; 1391 1392 Irp->CopyCurrentIrpStackLocationToNext(); 1393 Irp->SetCompletionRoutineEx(m_Device->GetDeviceObject(), 1394 CompletionRoutine, 1395 Context); 1396 status = Irp->CallDriver(m_Device->GetAttachedDevice()); 1397 1398 return status; 1399 } 1400 1401 VOID 1402 FxPkgGeneral::CreateCompleted( 1403 __in FxIrp *Irp 1404 ) 1405 /*++ 1406 1407 Routine Description: 1408 1409 This method is called when the WDFREQUEST for Irp 1410 is completed either by the driver or framework. 1411 1412 Here, we check the completion status of the IRP and if 1413 it's not success, we destroy the fileobject and decrement 1414 the openhandle count on the device. 1415 1416 Arguments: 1417 1418 Return Value: 1419 1420 VOID 1421 1422 --*/ 1423 { 1424 NTSTATUS status = Irp->GetStatus(); 1425 1426 // 1427 // If the create is completed with error status, 1428 // we destroy the WDFFILEOBJECT since the IoMgr will destroy 1429 // the PFILE_OBJECT if the IRP_MJ_CREATE fails and wouldn't send 1430 // Cleanup or Close IRP. 1431 // 1432 if (!NT_SUCCESS(status)) { 1433 1434 // Now destroy the WDFFILEOBJECT 1435 FxFileObject::_DestroyFileObject( 1436 m_Device, 1437 m_Device->GetFileObjectClass(), 1438 Irp->GetFileObject() 1439 ); 1440 1441 DecrementOpenHandleCount(); 1442 } 1443 } 1444 1445 _Must_inspect_result_ 1446 NTSTATUS 1447 STDCALL 1448 FxPkgGeneral::_CreateCompletionRoutine( 1449 __in MdDeviceObject DeviceObject, 1450 __in MdIrp OriginalIrp, 1451 __in_opt PVOID Context 1452 ) 1453 /*++ 1454 1455 Routine Description: 1456 1457 This completion routine is set only when the IRP is forwarded 1458 directly by the framework to the lower driver. Framework forwards 1459 the IRP request if: 1460 1) The driver happens to be a filter and hasn't registered any 1461 callbacks to handle create request. 1462 2) The driver is not a filter but has explicitly requested the 1463 framework to autoforward create/cleanup/close requests down. 1464 1465 We need to intercept the create in the completion path to find 1466 out whether the lower driver has succeeded or failed the request. 1467 If the request is failed, we should inform the package so that 1468 it can cleanup the state because I/O manager wouldn't send 1469 cleanup & close requests if the create is failed. 1470 1471 Arguments: 1472 1473 Return Value: 1474 1475 NTSTATUS 1476 1477 --*/ 1478 { 1479 FxPkgGeneral* pFxPkgGeneral; 1480 FxIrp irp(OriginalIrp); 1481 1482 UNREFERENCED_PARAMETER(DeviceObject); 1483 1484 pFxPkgGeneral = (FxPkgGeneral*) Context; 1485 1486 ASSERT(pFxPkgGeneral != NULL); 1487 1488 // 1489 // Let the package know that create is completed 1490 // so that it can cleanup the state. 1491 // 1492 pFxPkgGeneral->CreateCompleted(&irp); 1493 1494 // 1495 // Let the irp continue on its way. 1496 // 1497 irp.PropagatePendingReturned(); 1498 1499 return irp.GetStatus(); 1500 } 1501 1502 _Must_inspect_result_ 1503 NTSTATUS 1504 STDCALL 1505 FxPkgGeneral::_CreateCompletionRoutine2( 1506 __in MdDeviceObject DeviceObject, 1507 __in MdIrp OriginalIrp, 1508 __in_opt PVOID Context 1509 ) 1510 /*++ 1511 1512 Routine Description: 1513 1514 Routine Description: 1515 1516 This completion routine is set only when the create request is forwarded by the 1517 framework to the lower driver. Framework forwards the create request using this 1518 completion routine if: 1519 1520 1) Class extension's create callback is set by did not claim the request. 1521 2) Client driver did not register for a create callback or a create queue. 1522 1523 Arguments: 1524 1525 Return Value: 1526 1527 STATUS_MORE_PROCESSING_REQUIRED 1528 1529 --*/ 1530 { 1531 FxRequest* request; 1532 FxIrp irp(OriginalIrp); 1533 1534 UNREFERENCED_PARAMETER(DeviceObject); 1535 1536 request = (FxRequest*) Context; 1537 1538 ASSERT(request != NULL); 1539 1540 irp.PropagatePendingReturned(); 1541 1542 request->Complete(irp.GetStatus()); 1543 1544 return STATUS_MORE_PROCESSING_REQUIRED; 1545 } 1546 1547 _Must_inspect_result_ 1548 NTSTATUS 1549 FxPkgGeneral::OnCleanup( 1550 __inout FxIrp* FxIrp 1551 ) 1552 /*++ 1553 1554 Routine Description: 1555 1556 Called in response to IRP_MJ_CLEANUP. This means an handle to 1557 the device is closed. After invoking the driver registered callback 1558 event, flush all the queues to cancel requests that belong to the 1559 file handle being closed. There is however a possibility for 1560 new requests to come in with the same fileobject. 1561 1562 1563 1564 1565 1566 Arguments: 1567 1568 Return Value: 1569 1570 NTSTATUS 1571 1572 --*/ 1573 { 1574 NTSTATUS status; 1575 FxFileObject* pFxFO = NULL; 1576 WDFFILEOBJECT hwdfFO = NULL; 1577 PLIST_ENTRY next; 1578 FxFileObjectInfo* fileObjInfo; 1579 MxFileObject fileObject; 1580 1581 1582 1583 1584 1585 1586 // 1587 // Check to see if the fileobject represents a stream fileobject 1588 // created using IoCreateStreamFileObjectLite. 1589 // 1590 fileObject.SetFileObject(FxIrp->GetFileObject()); 1591 if (FxIrp->GetFileObject() && 1592 (fileObject.GetFlags() & FO_STREAM_FILE)){ 1593 status = STATUS_SUCCESS; 1594 goto Passthru; 1595 } 1596 1597 status = FxFileObject::_GetFileObjectFromWdm( 1598 m_Device, 1599 m_Device->GetFileObjectClass(), 1600 FxIrp->GetFileObject(), 1601 &pFxFO 1602 ); 1603 1604 ASSERT(status == STATUS_SUCCESS); 1605 1606 if (pFxFO != NULL && NT_SUCCESS(status)) { 1607 hwdfFO = pFxFO->GetHandle(); 1608 } 1609 1610 // 1611 // Invoke cleanup callbacks. 1612 // 1613 if (NULL == pFxFO) { 1614 // 1615 // Invoke cleanup callbacks of next layer (cx or client driver) based on the 1616 // autoforward setting of previous layer. (top to bottom). 1617 // AutoforwardCleanupClose set to FALSE with a not null create callback 1618 // means that create request was never forwarded to lower layer. 1619 // 1620 for (next = m_FileObjectInfoHeadList.Blink; 1621 next != &m_FileObjectInfoHeadList; 1622 next = next->Blink) { 1623 1624 fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry); 1625 1626 if (WdfFalse == fileObjInfo->AutoForwardCleanupClose && 1627 fileObjInfo->EvtCxFileCreate.Method != NULL) { 1628 next = next->Blink; // one before the real start entry. 1629 break; 1630 } 1631 } 1632 } 1633 else { 1634 // 1635 // 'OnCreate' sets this package context. 1636 // 1637 next = (PLIST_ENTRY) pFxFO->GetPkgCleanupCloseContext(); 1638 if (NULL == next) { 1639 next = &m_FileObjectInfoHeadList; 1640 } 1641 } 1642 1643 // 1644 // Invoke cleanup callbacks only if this layer (cx or client driver) had the 1645 // opprtunity to see the create request. 1646 // 1647 for (next = next->Flink; 1648 next != &m_FileObjectInfoHeadList; 1649 next = next->Flink) { 1650 1651 fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry); 1652 fileObjInfo->EvtFileCleanup.Invoke(hwdfFO); 1653 } 1654 1655 // 1656 // hwdfFO could be NULL depending on the FileObjectClass 1657 // 1658 1659 // 1660 // Scan all the I/O queues associated with this device 1661 // and cancel the requests that matches with the handle 1662 // being closed. We will be able to cancel only requests that 1663 // are waiting to be dispatched. If the requests are already 1664 // presented to the driver then it's the responsibility of the 1665 // driver to complete them when the cleanup callback is invoked. 1666 // 1667 if(FxIrp->GetFileObject() != NULL ) { 1668 FxPkgIo* pPkgIo; 1669 1670 pPkgIo = (FxPkgIo*)m_Device->m_PkgIo; 1671 pPkgIo->FlushAllQueuesByFileObject(FxIrp->GetFileObject()); 1672 } 1673 1674 Passthru: 1675 if (m_Device->m_AutoForwardCleanupClose) { 1676 FxIrp->SkipCurrentIrpStackLocation(); 1677 status = FxIrp->CallDriver(m_Device->GetAttachedDevice()); 1678 } else { 1679 FxIrp->SetStatus(status); 1680 FxIrp->SetInformation(0); 1681 FxIrp->CompleteRequest(IO_NO_INCREMENT); 1682 } 1683 1684 return status; 1685 1686 } 1687 1688 _Must_inspect_result_ 1689 NTSTATUS 1690 FxPkgGeneral::OnClose( 1691 __inout FxIrp* FxIrp 1692 ) 1693 /*++ 1694 1695 Routine Description: 1696 1697 Called in response to IRP_MJ_CLOSE. Invoke EvtFileClose event 1698 if registered and destroy the WDFFILEOBJECT. 1699 1700 Arguments: 1701 1702 Return Value: 1703 1704 NTSTATUS 1705 1706 --*/ 1707 { 1708 NTSTATUS status; 1709 FxFileObject* pFxFO = NULL; 1710 WDFFILEOBJECT hwdfFO = NULL; 1711 BOOLEAN isStreamFileObject = FALSE; 1712 BOOLEAN acquiredRemLock = FALSE; 1713 PLIST_ENTRY next; 1714 FxFileObjectInfo* fileObjInfo; 1715 MxFileObject fileObject; 1716 MdIrp irp; 1717 1718 // 1719 // FxIrp.CompleteRequest NULLs the m_Irp so store m_Irp separately 1720 // for use in ReleaseRemoveLock. 1721 // 1722 irp = FxIrp->GetIrp(); 1723 1724 // 1725 // Check to see if the fileobject represents a stream fileobject 1726 // created using IoCreateStreamFileObjectLite. If so, this is a 1727 // is spurious close sent by the I/O manager when it invalidates 1728 // the volumes (IopInvalidateVolumesForDevice). 1729 // 1730 fileObject.SetFileObject(FxIrp->GetFileObject()); 1731 if (FxIrp->GetFileObject() && 1732 (fileObject.GetFlags() & FO_STREAM_FILE)){ 1733 isStreamFileObject = TRUE; 1734 status = STATUS_SUCCESS; 1735 goto Passthru; 1736 } 1737 1738 status = FxFileObject::_GetFileObjectFromWdm( 1739 m_Device, 1740 m_Device->GetFileObjectClass(), 1741 FxIrp->GetFileObject(), 1742 &pFxFO 1743 ); 1744 1745 ASSERT(status == STATUS_SUCCESS); 1746 1747 if (pFxFO != NULL && NT_SUCCESS(status)) { 1748 hwdfFO = pFxFO->GetHandle(); 1749 } 1750 1751 // 1752 // Invoke close callbacks. 1753 // 1754 if (NULL == pFxFO) { 1755 // 1756 // Invoke close callbacks of next layer (cx or client driver) based on the autoforward 1757 // setting of previous layer. (top to bottom). 1758 // AutoforwardCleanupClose set to FALSE with a not null create callback 1759 // means that create request was never forwarded to lower layer. 1760 // 1761 for (next = m_FileObjectInfoHeadList.Blink; 1762 next != &m_FileObjectInfoHeadList; 1763 next = next->Blink) { 1764 1765 fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry); 1766 1767 if (WdfFalse == fileObjInfo->AutoForwardCleanupClose && 1768 fileObjInfo->EvtCxFileCreate.Method != NULL) { 1769 next = next->Blink; // one before the real start entry. 1770 break; 1771 } 1772 } 1773 } 1774 else { 1775 // 1776 // 'OnCreate' sets this package context. 1777 // 1778 next = (PLIST_ENTRY) pFxFO->GetPkgCleanupCloseContext(); 1779 if (NULL == next) { 1780 next = &m_FileObjectInfoHeadList; 1781 } 1782 } 1783 1784 // 1785 // Invoke close callbacks only if this layer (cx or client driver) had the opprtunity 1786 // to see the create request. 1787 // 1788 for (next = next->Flink; 1789 next != &m_FileObjectInfoHeadList; 1790 next = next->Flink) { 1791 1792 fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry); 1793 fileObjInfo->EvtFileClose.Invoke(hwdfFO); 1794 } 1795 1796 // 1797 // Destroy the WDFFILEOBJECT. This will result in 1798 // fileobject EvtCleanup and EvtDestroy event. 1799 // 1800 FxFileObject::_DestroyFileObject( 1801 m_Device, 1802 m_Device->GetFileObjectClass(), 1803 FxIrp->GetFileObject() 1804 ); 1805 1806 Passthru: 1807 1808 if (m_Device->m_AutoForwardCleanupClose) { 1809 FxIrp->SkipCurrentIrpStackLocation(); 1810 status = FxIrp->CallDriver(m_Device->GetAttachedDevice()); 1811 } else { 1812 // 1813 // We're about to complete the request, but we need to decrement the 1814 // open handle count after we complete the request. However, completing 1815 // the request immediately opens the gate for the remove IRP to arrive 1816 // and run down the device. Hence we'll acquire the remove lock in order 1817 // to ensure that the device is not removed before we've decremented the 1818 // open handle count. 1819 // 1820 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) 1821 acquiredRemLock = AcquireRemoveLockForClose(FxIrp); 1822 #endif 1823 FxIrp->SetStatus(status); 1824 FxIrp->SetInformation(0); 1825 FxIrp->CompleteRequest(IO_NO_INCREMENT); 1826 } 1827 1828 if (isStreamFileObject == FALSE) { 1829 // 1830 // Note that after this call returns, this object may have been deleted! 1831 1832 1833 1834 1835 1836 1837 1838 1839 DecrementOpenHandleCount(); 1840 } 1841 1842 if (acquiredRemLock) { 1843 Mx::MxReleaseRemoveLock(m_Device->GetRemoveLock(), 1844 irp); 1845 } 1846 1847 return status; 1848 1849 } 1850 1851 BOOLEAN 1852 FxPkgGeneral::AcquireRemoveLockForClose( 1853 __in FxIrp* FxIrp 1854 ) 1855 /*++ 1856 1857 Routine Description: 1858 1859 For PNP devices, this routine acquires the remove lock when handling the 1860 close IRP. 1861 1862 Arguments: 1863 Irp - Pointer to the close IRP 1864 1865 Return Value: 1866 1867 A BOOLEAN value that indicates whether or not the function actually acquired 1868 the remove lock 1869 1870 --*/ 1871 { 1872 NTSTATUS status; 1873 BOOLEAN lockAcquired; 1874 FxWdmDeviceExtension * wdmExtension = FxDevice::_GetFxWdmExtension( 1875 m_Device->GetDeviceObject()); 1876 1877 // 1878 // Initialization 1879 // 1880 lockAcquired = FALSE; 1881 1882 // 1883 // We attempt to acquire the remove lock only for PNP device objects 1884 // 1885 if (m_Device->IsPnp() == FALSE) { 1886 goto Done; 1887 } 1888 1889 // 1890 // If driver has opted in for remove lock for I/O operations we have 1891 // already acquired remove lock for Close so no need to do it again. 1892 // 1893 if (wdmExtension->RemoveLockOptionFlags & 1894 WDF_REMOVE_LOCK_OPTION_ACQUIRE_FOR_IO) { 1895 goto Done; 1896 } 1897 1898 status = Mx::MxAcquireRemoveLock( 1899 m_Device->GetRemoveLock(), 1900 FxIrp->GetIrp()); 1901 if (NT_SUCCESS(status)) { 1902 // 1903 // Successfully acquired the remove lock 1904 // 1905 lockAcquired = TRUE; 1906 } else { 1907 // 1908 // This is likely to have failed because we got the remove IRP and 1909 // called IoReleaseRemoveLockAndWait on another thread. This would 1910 // happen if there's a bug in the driver above us in the stack that 1911 // caused it to forward us the remove IRP before we completed the close 1912 // IRP. 1913 // 1914 // There's not much we can do now, since we're already racing against 1915 // the remove IRP. 1916 // 1917 PFX_DRIVER_GLOBALS pFxDriverGlobals; 1918 1919 pFxDriverGlobals = GetDriverGlobals(); 1920 1921 DoTraceLevelMessage( 1922 pFxDriverGlobals, 1923 TRACE_LEVEL_ERROR, 1924 TRACINGIO, 1925 "Unable to acquire remove lock while handling the close IRP" 1926 " 0x%p, %!STATUS!", 1927 FxIrp->GetIrp(), status); 1928 1929 if (pFxDriverGlobals->IsVerificationEnabled(1,9, OkForDownLevel)) { 1930 FxVerifierDbgBreakPoint(pFxDriverGlobals); 1931 } 1932 } 1933 1934 Done: 1935 return lockAcquired; 1936 } 1937 1938 1939 _Must_inspect_result_ 1940 NTSTATUS 1941 FxPkgGeneral::OnShutdown( 1942 __inout FxIrp* FxIrp 1943 ) 1944 /*++ 1945 1946 Routine Description: 1947 1948 Called in response to IRP_MJ_SHUTDOWN. 1949 1950 Arguments: 1951 1952 Return Value: 1953 1954 NTSTATUS 1955 1956 --*/ 1957 { 1958 NTSTATUS status; 1959 1960 m_EvtDeviceShutdown.Invoke(m_Device->GetHandle()); 1961 1962 if(m_Device->IsFilter()) { 1963 FxIrp->SkipCurrentIrpStackLocation(); 1964 status = FxIrp->CallDriver(m_Device->GetAttachedDevice()); 1965 } 1966 else { 1967 status = STATUS_SUCCESS; 1968 FxIrp->SetStatus(status); 1969 FxIrp->SetInformation(0); 1970 FxIrp->CompleteRequest(IO_NO_INCREMENT); 1971 } 1972 1973 return status; 1974 1975 } 1976 1977 VOID 1978 FxPkgGeneral::DecrementOpenHandleCount( 1979 VOID 1980 ) 1981 { 1982 if (InterlockedDecrement(&m_OpenHandleCount) == 0 && m_Device->IsLegacy()) { 1983 m_Device->ControlDeviceDelete(); 1984 } 1985 } 1986 1987 BOOLEAN 1988 FxPkgGeneral::CanDestroyControlDevice( 1989 VOID 1990 ) 1991 { 1992 // 1993 // Remove the bias of one that we use to track if a control device should be 1994 // deleted. 1995 // 1996 if (InterlockedDecrement(&m_OpenHandleCount) == 0) { 1997 return TRUE; 1998 } 1999 else { 2000 return FALSE; 2001 } 2002 2003 } 2004 2005 VOID 2006 FxPkgGeneral::GetConstraintsHelper( 2007 __out_opt WDF_EXECUTION_LEVEL* ExecutionLevel, 2008 __out_opt WDF_SYNCHRONIZATION_SCOPE* SynchronizationScope 2009 ) 2010 /*++ 2011 2012 Routine Description: 2013 This routine is the helper routine and is used by FxFileObject to get the 2014 ExecutionLevel and SynchronizationScope. 2015 2016 Arguments: 2017 2018 Return Value: 2019 VOID 2020 2021 --*/ 2022 2023 { 2024 if (ExecutionLevel != NULL) { 2025 *ExecutionLevel = m_ExecutionLevel; 2026 } 2027 2028 if (SynchronizationScope != NULL) { 2029 *SynchronizationScope = m_SynchronizationScope; 2030 } 2031 } 2032 2033 FxCallbackLock* 2034 FxPkgGeneral::GetCallbackLockPtrHelper( 2035 __deref_out_opt FxObject** LockObject 2036 ) 2037 /*++ 2038 2039 Routine Description: 2040 This routine is the helper routine and is used by FxFileObject to get the 2041 LockObject. 2042 2043 2044 Arguments: 2045 2046 Return Value: 2047 FxCallbackLock * 2048 2049 --*/ 2050 2051 { 2052 if (LockObject != NULL) { 2053 *LockObject = m_CallbackLockObjectPtr; 2054 } 2055 2056 return m_CallbackLockPtr; 2057 } 2058 2059 2060