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 FxPkgGeneral::_CreateCompletionRoutine( 1448 __in MdDeviceObject DeviceObject, 1449 __in MdIrp OriginalIrp, 1450 __in_opt PVOID Context 1451 ) 1452 /*++ 1453 1454 Routine Description: 1455 1456 This completion routine is set only when the IRP is forwarded 1457 directly by the framework to the lower driver. Framework forwards 1458 the IRP request if: 1459 1) The driver happens to be a filter and hasn't registered any 1460 callbacks to handle create request. 1461 2) The driver is not a filter but has explicitly requested the 1462 framework to autoforward create/cleanup/close requests down. 1463 1464 We need to intercept the create in the completion path to find 1465 out whether the lower driver has succeeded or failed the request. 1466 If the request is failed, we should inform the package so that 1467 it can cleanup the state because I/O manager wouldn't send 1468 cleanup & close requests if the create is failed. 1469 1470 Arguments: 1471 1472 Return Value: 1473 1474 NTSTATUS 1475 1476 --*/ 1477 { 1478 FxPkgGeneral* pFxPkgGeneral; 1479 FxIrp irp(OriginalIrp); 1480 1481 UNREFERENCED_PARAMETER(DeviceObject); 1482 1483 pFxPkgGeneral = (FxPkgGeneral*) Context; 1484 1485 ASSERT(pFxPkgGeneral != NULL); 1486 1487 // 1488 // Let the package know that create is completed 1489 // so that it can cleanup the state. 1490 // 1491 pFxPkgGeneral->CreateCompleted(&irp); 1492 1493 // 1494 // Let the irp continue on its way. 1495 // 1496 irp.PropagatePendingReturned(); 1497 1498 return irp.GetStatus(); 1499 } 1500 1501 _Must_inspect_result_ 1502 NTSTATUS 1503 FxPkgGeneral::_CreateCompletionRoutine2( 1504 __in MdDeviceObject DeviceObject, 1505 __in MdIrp OriginalIrp, 1506 __in_opt PVOID Context 1507 ) 1508 /*++ 1509 1510 Routine Description: 1511 1512 Routine Description: 1513 1514 This completion routine is set only when the create request is forwarded by the 1515 framework to the lower driver. Framework forwards the create request using this 1516 completion routine if: 1517 1518 1) Class extension's create callback is set by did not claim the request. 1519 2) Client driver did not register for a create callback or a create queue. 1520 1521 Arguments: 1522 1523 Return Value: 1524 1525 STATUS_MORE_PROCESSING_REQUIRED 1526 1527 --*/ 1528 { 1529 FxRequest* request; 1530 FxIrp irp(OriginalIrp); 1531 1532 UNREFERENCED_PARAMETER(DeviceObject); 1533 1534 request = (FxRequest*) Context; 1535 1536 ASSERT(request != NULL); 1537 1538 irp.PropagatePendingReturned(); 1539 1540 request->Complete(irp.GetStatus()); 1541 1542 return STATUS_MORE_PROCESSING_REQUIRED; 1543 } 1544 1545 _Must_inspect_result_ 1546 NTSTATUS 1547 FxPkgGeneral::OnCleanup( 1548 __inout FxIrp* FxIrp 1549 ) 1550 /*++ 1551 1552 Routine Description: 1553 1554 Called in response to IRP_MJ_CLEANUP. This means an handle to 1555 the device is closed. After invoking the driver registered callback 1556 event, flush all the queues to cancel requests that belong to the 1557 file handle being closed. There is however a possibility for 1558 new requests to come in with the same fileobject. 1559 1560 1561 1562 1563 1564 Arguments: 1565 1566 Return Value: 1567 1568 NTSTATUS 1569 1570 --*/ 1571 { 1572 NTSTATUS status; 1573 FxFileObject* pFxFO = NULL; 1574 WDFFILEOBJECT hwdfFO = NULL; 1575 PLIST_ENTRY next; 1576 FxFileObjectInfo* fileObjInfo; 1577 MxFileObject fileObject; 1578 1579 1580 1581 1582 1583 1584 // 1585 // Check to see if the fileobject represents a stream fileobject 1586 // created using IoCreateStreamFileObjectLite. 1587 // 1588 fileObject.SetFileObject(FxIrp->GetFileObject()); 1589 if (FxIrp->GetFileObject() && 1590 (fileObject.GetFlags() & FO_STREAM_FILE)){ 1591 status = STATUS_SUCCESS; 1592 goto Passthru; 1593 } 1594 1595 status = FxFileObject::_GetFileObjectFromWdm( 1596 m_Device, 1597 m_Device->GetFileObjectClass(), 1598 FxIrp->GetFileObject(), 1599 &pFxFO 1600 ); 1601 1602 ASSERT(status == STATUS_SUCCESS); 1603 1604 if (pFxFO != NULL && NT_SUCCESS(status)) { 1605 hwdfFO = pFxFO->GetHandle(); 1606 } 1607 1608 // 1609 // Invoke cleanup callbacks. 1610 // 1611 if (NULL == pFxFO) { 1612 // 1613 // Invoke cleanup callbacks of next layer (cx or client driver) based on the 1614 // autoforward setting of previous layer. (top to bottom). 1615 // AutoforwardCleanupClose set to FALSE with a not null create callback 1616 // means that create request was never forwarded to lower layer. 1617 // 1618 for (next = m_FileObjectInfoHeadList.Blink; 1619 next != &m_FileObjectInfoHeadList; 1620 next = next->Blink) { 1621 1622 fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry); 1623 1624 if (WdfFalse == fileObjInfo->AutoForwardCleanupClose && 1625 fileObjInfo->EvtCxFileCreate.Method != NULL) { 1626 next = next->Blink; // one before the real start entry. 1627 break; 1628 } 1629 } 1630 } 1631 else { 1632 // 1633 // 'OnCreate' sets this package context. 1634 // 1635 next = (PLIST_ENTRY) pFxFO->GetPkgCleanupCloseContext(); 1636 if (NULL == next) { 1637 next = &m_FileObjectInfoHeadList; 1638 } 1639 } 1640 1641 // 1642 // Invoke cleanup callbacks only if this layer (cx or client driver) had the 1643 // opprtunity to see the create request. 1644 // 1645 for (next = next->Flink; 1646 next != &m_FileObjectInfoHeadList; 1647 next = next->Flink) { 1648 1649 fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry); 1650 fileObjInfo->EvtFileCleanup.Invoke(hwdfFO); 1651 } 1652 1653 // 1654 // hwdfFO could be NULL depending on the FileObjectClass 1655 // 1656 1657 // 1658 // Scan all the I/O queues associated with this device 1659 // and cancel the requests that matches with the handle 1660 // being closed. We will be able to cancel only requests that 1661 // are waiting to be dispatched. If the requests are already 1662 // presented to the driver then it's the responsibility of the 1663 // driver to complete them when the cleanup callback is invoked. 1664 // 1665 if(FxIrp->GetFileObject() != NULL ) { 1666 FxPkgIo* pPkgIo; 1667 1668 pPkgIo = (FxPkgIo*)m_Device->m_PkgIo; 1669 pPkgIo->FlushAllQueuesByFileObject(FxIrp->GetFileObject()); 1670 } 1671 1672 Passthru: 1673 if (m_Device->m_AutoForwardCleanupClose) { 1674 FxIrp->SkipCurrentIrpStackLocation(); 1675 status = FxIrp->CallDriver(m_Device->GetAttachedDevice()); 1676 } else { 1677 FxIrp->SetStatus(status); 1678 FxIrp->SetInformation(0); 1679 FxIrp->CompleteRequest(IO_NO_INCREMENT); 1680 } 1681 1682 return status; 1683 1684 } 1685 1686 _Must_inspect_result_ 1687 NTSTATUS 1688 FxPkgGeneral::OnClose( 1689 __inout FxIrp* FxIrp 1690 ) 1691 /*++ 1692 1693 Routine Description: 1694 1695 Called in response to IRP_MJ_CLOSE. Invoke EvtFileClose event 1696 if registered and destroy the WDFFILEOBJECT. 1697 1698 Arguments: 1699 1700 Return Value: 1701 1702 NTSTATUS 1703 1704 --*/ 1705 { 1706 NTSTATUS status; 1707 FxFileObject* pFxFO = NULL; 1708 WDFFILEOBJECT hwdfFO = NULL; 1709 BOOLEAN isStreamFileObject = FALSE; 1710 BOOLEAN acquiredRemLock = FALSE; 1711 PLIST_ENTRY next; 1712 FxFileObjectInfo* fileObjInfo; 1713 MxFileObject fileObject; 1714 MdIrp irp; 1715 1716 // 1717 // FxIrp.CompleteRequest NULLs the m_Irp so store m_Irp separately 1718 // for use in ReleaseRemoveLock. 1719 // 1720 irp = FxIrp->GetIrp(); 1721 1722 // 1723 // Check to see if the fileobject represents a stream fileobject 1724 // created using IoCreateStreamFileObjectLite. If so, this is a 1725 // is spurious close sent by the I/O manager when it invalidates 1726 // the volumes (IopInvalidateVolumesForDevice). 1727 // 1728 fileObject.SetFileObject(FxIrp->GetFileObject()); 1729 if (FxIrp->GetFileObject() && 1730 (fileObject.GetFlags() & FO_STREAM_FILE)){ 1731 isStreamFileObject = TRUE; 1732 status = STATUS_SUCCESS; 1733 goto Passthru; 1734 } 1735 1736 status = FxFileObject::_GetFileObjectFromWdm( 1737 m_Device, 1738 m_Device->GetFileObjectClass(), 1739 FxIrp->GetFileObject(), 1740 &pFxFO 1741 ); 1742 1743 ASSERT(status == STATUS_SUCCESS); 1744 1745 if (pFxFO != NULL && NT_SUCCESS(status)) { 1746 hwdfFO = pFxFO->GetHandle(); 1747 } 1748 1749 // 1750 // Invoke close callbacks. 1751 // 1752 if (NULL == pFxFO) { 1753 // 1754 // Invoke close callbacks of next layer (cx or client driver) based on the autoforward 1755 // setting of previous layer. (top to bottom). 1756 // AutoforwardCleanupClose set to FALSE with a not null create callback 1757 // means that create request was never forwarded to lower layer. 1758 // 1759 for (next = m_FileObjectInfoHeadList.Blink; 1760 next != &m_FileObjectInfoHeadList; 1761 next = next->Blink) { 1762 1763 fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry); 1764 1765 if (WdfFalse == fileObjInfo->AutoForwardCleanupClose && 1766 fileObjInfo->EvtCxFileCreate.Method != NULL) { 1767 next = next->Blink; // one before the real start entry. 1768 break; 1769 } 1770 } 1771 } 1772 else { 1773 // 1774 // 'OnCreate' sets this package context. 1775 // 1776 next = (PLIST_ENTRY) pFxFO->GetPkgCleanupCloseContext(); 1777 if (NULL == next) { 1778 next = &m_FileObjectInfoHeadList; 1779 } 1780 } 1781 1782 // 1783 // Invoke close callbacks only if this layer (cx or client driver) had the opprtunity 1784 // to see the create request. 1785 // 1786 for (next = next->Flink; 1787 next != &m_FileObjectInfoHeadList; 1788 next = next->Flink) { 1789 1790 fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry); 1791 fileObjInfo->EvtFileClose.Invoke(hwdfFO); 1792 } 1793 1794 // 1795 // Destroy the WDFFILEOBJECT. This will result in 1796 // fileobject EvtCleanup and EvtDestroy event. 1797 // 1798 FxFileObject::_DestroyFileObject( 1799 m_Device, 1800 m_Device->GetFileObjectClass(), 1801 FxIrp->GetFileObject() 1802 ); 1803 1804 Passthru: 1805 1806 if (m_Device->m_AutoForwardCleanupClose) { 1807 FxIrp->SkipCurrentIrpStackLocation(); 1808 status = FxIrp->CallDriver(m_Device->GetAttachedDevice()); 1809 } else { 1810 // 1811 // We're about to complete the request, but we need to decrement the 1812 // open handle count after we complete the request. However, completing 1813 // the request immediately opens the gate for the remove IRP to arrive 1814 // and run down the device. Hence we'll acquire the remove lock in order 1815 // to ensure that the device is not removed before we've decremented the 1816 // open handle count. 1817 // 1818 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) 1819 acquiredRemLock = AcquireRemoveLockForClose(FxIrp); 1820 #endif 1821 FxIrp->SetStatus(status); 1822 FxIrp->SetInformation(0); 1823 FxIrp->CompleteRequest(IO_NO_INCREMENT); 1824 } 1825 1826 if (isStreamFileObject == FALSE) { 1827 // 1828 // Note that after this call returns, this object may have been deleted! 1829 1830 1831 1832 1833 1834 1835 1836 1837 DecrementOpenHandleCount(); 1838 } 1839 1840 if (acquiredRemLock) { 1841 Mx::MxReleaseRemoveLock(m_Device->GetRemoveLock(), 1842 irp); 1843 } 1844 1845 return status; 1846 1847 } 1848 1849 BOOLEAN 1850 FxPkgGeneral::AcquireRemoveLockForClose( 1851 __in FxIrp* FxIrp 1852 ) 1853 /*++ 1854 1855 Routine Description: 1856 1857 For PNP devices, this routine acquires the remove lock when handling the 1858 close IRP. 1859 1860 Arguments: 1861 Irp - Pointer to the close IRP 1862 1863 Return Value: 1864 1865 A BOOLEAN value that indicates whether or not the function actually acquired 1866 the remove lock 1867 1868 --*/ 1869 { 1870 NTSTATUS status; 1871 BOOLEAN lockAcquired; 1872 FxWdmDeviceExtension * wdmExtension = FxDevice::_GetFxWdmExtension( 1873 m_Device->GetDeviceObject()); 1874 1875 // 1876 // Initialization 1877 // 1878 lockAcquired = FALSE; 1879 1880 // 1881 // We attempt to acquire the remove lock only for PNP device objects 1882 // 1883 if (m_Device->IsPnp() == FALSE) { 1884 goto Done; 1885 } 1886 1887 // 1888 // If driver has opted in for remove lock for I/O operations we have 1889 // already acquired remove lock for Close so no need to do it again. 1890 // 1891 if (wdmExtension->RemoveLockOptionFlags & 1892 WDF_REMOVE_LOCK_OPTION_ACQUIRE_FOR_IO) { 1893 goto Done; 1894 } 1895 1896 status = Mx::MxAcquireRemoveLock( 1897 m_Device->GetRemoveLock(), 1898 FxIrp->GetIrp()); 1899 if (NT_SUCCESS(status)) { 1900 // 1901 // Successfully acquired the remove lock 1902 // 1903 lockAcquired = TRUE; 1904 } else { 1905 // 1906 // This is likely to have failed because we got the remove IRP and 1907 // called IoReleaseRemoveLockAndWait on another thread. This would 1908 // happen if there's a bug in the driver above us in the stack that 1909 // caused it to forward us the remove IRP before we completed the close 1910 // IRP. 1911 // 1912 // There's not much we can do now, since we're already racing against 1913 // the remove IRP. 1914 // 1915 PFX_DRIVER_GLOBALS pFxDriverGlobals; 1916 1917 pFxDriverGlobals = GetDriverGlobals(); 1918 1919 DoTraceLevelMessage( 1920 pFxDriverGlobals, 1921 TRACE_LEVEL_ERROR, 1922 TRACINGIO, 1923 "Unable to acquire remove lock while handling the close IRP" 1924 " 0x%p, %!STATUS!", 1925 FxIrp->GetIrp(), status); 1926 1927 if (pFxDriverGlobals->IsVerificationEnabled(1,9, OkForDownLevel)) { 1928 FxVerifierDbgBreakPoint(pFxDriverGlobals); 1929 } 1930 } 1931 1932 Done: 1933 return lockAcquired; 1934 } 1935 1936 1937 _Must_inspect_result_ 1938 NTSTATUS 1939 FxPkgGeneral::OnShutdown( 1940 __inout FxIrp* FxIrp 1941 ) 1942 /*++ 1943 1944 Routine Description: 1945 1946 Called in response to IRP_MJ_SHUTDOWN. 1947 1948 Arguments: 1949 1950 Return Value: 1951 1952 NTSTATUS 1953 1954 --*/ 1955 { 1956 NTSTATUS status; 1957 1958 m_EvtDeviceShutdown.Invoke(m_Device->GetHandle()); 1959 1960 if(m_Device->IsFilter()) { 1961 FxIrp->SkipCurrentIrpStackLocation(); 1962 status = FxIrp->CallDriver(m_Device->GetAttachedDevice()); 1963 } 1964 else { 1965 status = STATUS_SUCCESS; 1966 FxIrp->SetStatus(status); 1967 FxIrp->SetInformation(0); 1968 FxIrp->CompleteRequest(IO_NO_INCREMENT); 1969 } 1970 1971 return status; 1972 1973 } 1974 1975 VOID 1976 FxPkgGeneral::DecrementOpenHandleCount( 1977 VOID 1978 ) 1979 { 1980 if (InterlockedDecrement(&m_OpenHandleCount) == 0 && m_Device->IsLegacy()) { 1981 m_Device->ControlDeviceDelete(); 1982 } 1983 } 1984 1985 BOOLEAN 1986 FxPkgGeneral::CanDestroyControlDevice( 1987 VOID 1988 ) 1989 { 1990 // 1991 // Remove the bias of one that we use to track if a control device should be 1992 // deleted. 1993 // 1994 if (InterlockedDecrement(&m_OpenHandleCount) == 0) { 1995 return TRUE; 1996 } 1997 else { 1998 return FALSE; 1999 } 2000 2001 } 2002 2003 VOID 2004 FxPkgGeneral::GetConstraintsHelper( 2005 __out_opt WDF_EXECUTION_LEVEL* ExecutionLevel, 2006 __out_opt WDF_SYNCHRONIZATION_SCOPE* SynchronizationScope 2007 ) 2008 /*++ 2009 2010 Routine Description: 2011 This routine is the helper routine and is used by FxFileObject to get the 2012 ExecutionLevel and SynchronizationScope. 2013 2014 Arguments: 2015 2016 Return Value: 2017 VOID 2018 2019 --*/ 2020 2021 { 2022 if (ExecutionLevel != NULL) { 2023 *ExecutionLevel = m_ExecutionLevel; 2024 } 2025 2026 if (SynchronizationScope != NULL) { 2027 *SynchronizationScope = m_SynchronizationScope; 2028 } 2029 } 2030 2031 FxCallbackLock* 2032 FxPkgGeneral::GetCallbackLockPtrHelper( 2033 __deref_out_opt FxObject** LockObject 2034 ) 2035 /*++ 2036 2037 Routine Description: 2038 This routine is the helper routine and is used by FxFileObject to get the 2039 LockObject. 2040 2041 2042 Arguments: 2043 2044 Return Value: 2045 FxCallbackLock * 2046 2047 --*/ 2048 2049 { 2050 if (LockObject != NULL) { 2051 *LockObject = m_CallbackLockObjectPtr; 2052 } 2053 2054 return m_CallbackLockPtr; 2055 } 2056 2057 2058