1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 FxWmiIrpHandler.cpp 8 9 Abstract: 10 11 This module implements the wmi irp handler for the driver frameworks. 12 13 Author: 14 15 16 17 Environment: 18 19 Kernel mode only 20 21 Revision History: 22 23 --*/ 24 25 #include "fxwmipch.hpp" 26 27 extern "C" { 28 // #include "FxWmiIrpHandler.tmh" 29 } 30 31 #ifndef WppDebug 32 #define WppDebug(a, b) 33 #endif 34 35 const FxWmiMinorEntry FxWmiIrpHandler::m_WmiDispatchTable[] = 36 { 37 // IRP_MN_QUERY_ALL_DATA 38 { _QueryAllData, FALSE }, 39 40 // IRP_MN_QUERY_SINGLE_INSTANCE 41 { _QuerySingleInstance, TRUE }, 42 43 // IRP_MN_CHANGE_SINGLE_INSTANCE 44 { _ChangeSingleInstance, TRUE }, 45 46 // IRP_MN_CHANGE_SINGLE_ITEM 47 { _ChangeSingleItem, TRUE }, 48 49 // IRP_MN_ENABLE_EVENTS 50 { _EnableDisableEventsAndCollection, FALSE }, 51 52 // IRP_MN_DISABLE_EVENTS 53 { _EnableDisableEventsAndCollection, FALSE }, 54 55 // IRP_MN_ENABLE_COLLECTION 56 { _EnableDisableEventsAndCollection, FALSE }, 57 58 // IRP_MN_DISABLE_COLLECTION 59 { _EnableDisableEventsAndCollection, FALSE }, 60 61 // IRP_MN_REGINFO 62 { _RegInfo, FALSE }, 63 64 // IRP_MN_EXECUTE_METHOD 65 { _ExecuteMethod, TRUE }, 66 67 // 0xA is reseverved 68 { NULL, FALSE }, 69 70 // IRP_MN_REGINFO_EX 71 { _RegInfo, FALSE }, 72 }; 73 74 VOID 75 FxWmiIrpHandler::CheckAssumptions( 76 VOID 77 ) 78 { 79 WDFCASSERT(sizeof(m_WmiDispatchTable)/sizeof(m_WmiDispatchTable[0]) == 80 IRP_MN_REGINFO_EX + 1); 81 } 82 83 FxWmiIrpHandler::FxWmiIrpHandler( 84 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 85 __in FxDevice *Device, 86 __in WDFTYPE Type 87 ) : 88 FxPackage(FxDriverGlobals, Device, Type), 89 m_NumProviders(0), m_RegisteredState(WmiUnregistered), 90 m_WorkItem(NULL), m_WorkItemEvent(NULL), m_WorkItemQueued(FALSE), 91 m_UpdateCount(1) // bias m_UpdateCount to 1, Deregister routine will 92 // decrement this. 93 { 94 InitializeListHead(&m_ProvidersListHead); 95 } 96 97 FxWmiIrpHandler::~FxWmiIrpHandler() 98 { 99 // 100 // If the device could not get past AddDevice or failed the initial start 101 // device, we will be unregistered. Otherwise we should be cleaned up. 102 // 103 ASSERT(m_RegisteredState != WmiRegistered); 104 105 ASSERT(IsListEmpty(&m_ProvidersListHead)); 106 107 if (m_WorkItem != NULL) { 108 IoFreeWorkItem(m_WorkItem); 109 } 110 } 111 112 _Must_inspect_result_ 113 NTSTATUS 114 FxWmiIrpHandler::PostCreateDeviceInitialize( 115 VOID 116 ) 117 { 118 m_WorkItem = IoAllocateWorkItem(GetDevice()->GetDeviceObject()); 119 if (m_WorkItem == NULL) { 120 return STATUS_INSUFFICIENT_RESOURCES; 121 } 122 123 return STATUS_SUCCESS; 124 } 125 126 _Must_inspect_result_ 127 NTSTATUS 128 FxWmiIrpHandler::Register( 129 VOID 130 ) 131 { 132 NTSTATUS status; 133 KIRQL irql; 134 135 // 136 // We rely on the PnP state machine to manage our state transitions properly 137 // so that we don't have to do any state checking here. 138 // 139 Lock(&irql); 140 ASSERT(m_RegisteredState == WmiUnregistered || 141 m_RegisteredState == WmiDeregistered); 142 m_RegisteredState = WmiRegistered; 143 Unlock(irql); 144 145 status = IoWMIRegistrationControl(GetDevice()->GetDeviceObject(), 146 WMIREG_ACTION_REGISTER); 147 148 if (!NT_SUCCESS(status)) { 149 DoTraceLevelMessage( 150 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 151 "could not register WMI with OS, %!STATUS!", status); 152 153 Lock(&irql); 154 m_RegisteredState = WmiUnregistered; 155 Unlock(irql); 156 } 157 158 return status; 159 } 160 161 VOID 162 FxWmiIrpHandler::Deregister( 163 VOID 164 ) 165 { 166 FxCREvent event; 167 KIRQL irql; 168 BOOLEAN call; 169 170 call = FALSE; 171 172 Lock(&irql); 173 if (m_RegisteredState == WmiRegistered) { 174 m_RegisteredState = WmiDeregistered; 175 176 if (m_WorkItemQueued) { 177 178 179 180 181 182 m_WorkItemEvent = (PKEVENT)event.GetEvent(); 183 } 184 185 call = TRUE; 186 } 187 Unlock(irql); 188 189 if (m_WorkItemEvent != NULL) { 190 event.EnterCRAndWaitAndLeave(); 191 } 192 193 if (call) { 194 NTSTATUS status; 195 196 // 197 // Per WMI rules, there should not be any call to update WMI 198 // registration after we have deregistered because that can lead to 199 // deadlock in Pnp, so before we go ahead to deregister, let's ensure 200 // that. This will wait for any pending updates to happen. 201 // 202 DecrementUpdateCountAndWait(); 203 204 status = IoWMIRegistrationControl(GetDevice()->GetDeviceObject(), 205 WMIREG_ACTION_DEREGISTER); 206 207 if (!NT_SUCCESS(status)) { 208 DoTraceLevelMessage( 209 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 210 "failure deregistering WMI with OS, %!STATUS!", status); 211 } 212 } 213 } 214 215 VOID 216 FxWmiIrpHandler::Cleanup( 217 VOID 218 ) 219 { 220 KIRQL irql; 221 222 Lock(&irql); 223 m_RegisteredState = WmiCleanedUp; 224 Unlock(irql); 225 } 226 227 VOID 228 FxWmiIrpHandler::ResetStateForPdoRestart( 229 VOID 230 ) 231 { 232 KIRQL irql; 233 234 Lock(&irql); 235 236 // 237 // We can reach this state in 2 ways: 238 // 1. PDO went through Init->Started->Removed->Started transition 239 // 2. PDO went through Init-><SomeFailedState>->Started state (e.g. 240 // Init->Ejected->EjectFailed->Started) transition. 241 // 242 // So, WMI registration state would either be Deregistered due to #1 243 // or, Unregistered due to #2. Also, update count would be 0 in case of #1 244 // and 1 in case of #2. 245 // 246 ASSERT(m_RegisteredState == WmiUnregistered || 247 m_RegisteredState == WmiDeregistered); 248 ASSERT(m_UpdateCount == 0 || m_UpdateCount == 1); 249 250 // 251 // Update count is biased to 1 when created so do the same here. 252 // 253 m_UpdateCount = 1; 254 m_UpdateEvent.Initialize(); 255 Unlock(irql); 256 } 257 258 _Must_inspect_result_ 259 NTSTATUS 260 FxWmiIrpHandler::AddProviderLocked( 261 __in FxWmiProvider* Provider, 262 __in KIRQL OldIrql, 263 __out_opt PBOOLEAN Update 264 ) 265 { 266 BOOLEAN update; 267 268 update = FALSE; 269 270 switch (m_RegisteredState) { 271 case WmiRegistered: 272 if (Provider->m_Flags & WdfWmiProviderTracing) { 273 update = TRUE; 274 } 275 case WmiUnregistered: 276 break; 277 278 case WmiDeregistered: 279 return STATUS_INVALID_DEVICE_STATE; 280 } 281 282 // 283 // Didn't find it in the list, add it 284 // 285 m_NumProviders++; 286 InsertTailList(&m_ProvidersListHead, &Provider->m_ListEntry); 287 288 if (update) { 289 update = DeferUpdateLocked(OldIrql); 290 291 if (Update != NULL) { 292 *Update = update; 293 } 294 } 295 296 return STATUS_SUCCESS; 297 } 298 299 BOOLEAN 300 FxWmiIrpHandler::DeferUpdateLocked( 301 __in KIRQL OldIrql 302 ) 303 { 304 BOOLEAN checkQueue; 305 306 checkQueue = FALSE; 307 308 // 309 // Check to see if the caller is going to return to something > PASSIVE_LEVEL. 310 // If so, then always defer to the workitem. 311 // 312 if (OldIrql > PASSIVE_LEVEL) { 313 checkQueue = TRUE; 314 } 315 else { 316 // 317 // At passive level and updates are allowed, indicate to the caller to 318 // update. The caller will do registration update outside of lock but 319 // update count needs to be incremented under lock, so this is done here. 320 // 321 IncrementUpdateCount(); 322 return TRUE; 323 } 324 325 if (checkQueue && m_WorkItemQueued == FALSE) { 326 // 327 // we are going to queue a workitem which will do registration update, 328 // so increment the update count. Note that one work item may correspond 329 // to multiple requests to update (since if the workitem is already 330 // queued, it's not queued again). 331 // 332 IncrementUpdateCount(); 333 334 m_WorkItemQueued = TRUE; 335 IoQueueWorkItem(m_WorkItem, 336 _UpdateGuids, 337 DelayedWorkQueue, 338 this); 339 } 340 341 return FALSE; 342 } 343 344 VOID 345 FxWmiIrpHandler::_UpdateGuids( 346 __in PDEVICE_OBJECT DeviceObject, 347 __in PVOID Context 348 ) 349 { 350 FxWmiIrpHandler* pThis; 351 KIRQL irql; 352 353 UNREFERENCED_PARAMETER(DeviceObject); 354 355 pThis = (FxWmiIrpHandler*)Context; 356 357 pThis->UpdateGuids(); 358 359 pThis->Lock(&irql); 360 pThis->m_WorkItemQueued = FALSE; 361 362 if (pThis->m_WorkItemEvent != NULL) { 363 KeSetEvent(pThis->m_WorkItemEvent, FALSE, IO_NO_INCREMENT); 364 } 365 pThis->Unlock(irql); 366 } 367 368 VOID 369 FxWmiIrpHandler::UpdateGuids( 370 VOID 371 ) 372 { 373 NTSTATUS status; 374 375 status = IoWMIRegistrationControl(GetDevice()->GetDeviceObject(), 376 WMIREG_ACTION_UPDATE_GUIDS); 377 378 if (!NT_SUCCESS(status)) { 379 DoTraceLevelMessage( 380 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIO, 381 "IoWMIRegistrationControl DevObj %p, for UpdateGuids failed, %!STATUS!", 382 GetDevice()->GetDeviceObject(), status); 383 384 // 385 // Just drop the error 386 // 387 } 388 389 // 390 // The caller incremented the update count when it decided to do the update. 391 // Decrement the count now that we have completed registration update. 392 // 393 DecrementUpdateCount(); 394 } 395 396 _Must_inspect_result_ 397 NTSTATUS 398 FxWmiIrpHandler::AddProvider( 399 __in FxWmiProvider* Provider, 400 __out_opt PBOOLEAN Update 401 ) 402 { 403 NTSTATUS status; 404 KIRQL irql; 405 406 Lock(&irql); 407 408 if (IsListEmpty(&Provider->m_ListEntry) == FALSE || 409 FindProviderLocked(Provider->GetGUID()) != NULL) { 410 status = STATUS_OBJECT_NAME_EXISTS; 411 } 412 else { 413 status = AddProviderLocked(Provider, irql, Update); 414 } 415 Unlock(irql); 416 417 return status; 418 } 419 420 _Must_inspect_result_ 421 NTSTATUS 422 FxWmiIrpHandler::AddPowerPolicyProviderAndInstance( 423 __in PWDF_WMI_PROVIDER_CONFIG ProviderConfig, 424 __in FxWmiInstanceInternalCallbacks* InstanceCallbacks, 425 __inout FxWmiInstanceInternal** Instance 426 ) 427 { 428 FxWmiProvider* pProvider; 429 FxWmiInstanceInternal* pInstance; 430 NTSTATUS status; 431 KIRQL irql; 432 BOOLEAN providerAllocated, providerAdded, update; 433 434 providerAllocated = FALSE; 435 providerAdded = FALSE; 436 update = FALSE; 437 438 pInstance = NULL; 439 440 status = STATUS_SUCCESS; 441 442 Lock(&irql); 443 444 pProvider = FindProviderLocked(&ProviderConfig->Guid); 445 446 if (pProvider == NULL) { 447 pProvider = new (GetDriverGlobals(), WDF_NO_OBJECT_ATTRIBUTES) 448 FxWmiProvider(GetDriverGlobals(), ProviderConfig, GetDevice()); 449 450 if (pProvider == NULL) { 451 status = STATUS_INSUFFICIENT_RESOURCES; 452 goto Done; 453 } 454 455 providerAllocated = TRUE; 456 457 status = AddProviderLocked(pProvider, irql); 458 if (!NT_SUCCESS(status)) { 459 goto Done; 460 } 461 462 providerAdded = TRUE; 463 464 status = pProvider->AssignParentObject(GetDevice()); 465 if (!NT_SUCCESS(status)) { 466 goto Done; 467 } 468 } 469 else if (pProvider->m_NumInstances > 0 && 470 (FxIsEqualGuid(pProvider->GetGUID(), &GUID_POWER_DEVICE_ENABLE) || 471 FxIsEqualGuid(pProvider->GetGUID(), &GUID_POWER_DEVICE_WAKE_ENABLE))) { 472 473 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIO, 474 "WMI Guid already registered by client driver"); 475 status = STATUS_WMI_GUID_DISCONNECTED; 476 } 477 478 if (NT_SUCCESS(status)) { 479 pInstance = new (GetDriverGlobals(), WDF_NO_OBJECT_ATTRIBUTES) 480 FxWmiInstanceInternal(GetDriverGlobals(), InstanceCallbacks, pProvider); 481 482 if (pInstance != NULL) { 483 status = pInstance->AssignParentObject(pProvider); 484 } 485 else { 486 status = STATUS_INSUFFICIENT_RESOURCES; 487 } 488 489 if (NT_SUCCESS(status) && 490 InterlockedCompareExchangePointer((PVOID*) Instance, 491 pInstance, 492 NULL) != NULL) { 493 // 494 // Some other thread got here first and created an instance, just 495 // bail out. the caller will handle this specific return value 496 // gracefully. 497 // 498 status = STATUS_OBJECT_NAME_COLLISION; 499 } 500 else { 501 // 502 // We are the first one to set the value, good for us. 503 // 504 DO_NOTHING(); 505 } 506 } 507 508 // 509 // Add the instance only if we are successful to this point 510 // 511 if (NT_SUCCESS(status)) { 512 // 513 // Passing FALSE indicates that this instance cannot be in the list 514 // when added. 515 // 516 status = pProvider->AddInstanceLocked( 517 pInstance, 518 FALSE, 519 &update, 520 FxWmiProvider::AddInstanceToHead 521 ); 522 } 523 524 Done: 525 if (NT_SUCCESS(status)) { 526 if (update) { 527 update = DeferUpdateLocked(irql); 528 } 529 } 530 else if (providerAdded) { 531 RemoveProviderLocked(pProvider); 532 } 533 534 Unlock(irql); 535 536 if (NT_SUCCESS(status)) { 537 if (update) { 538 UpdateGuids(); 539 } 540 } 541 else { 542 if (pInstance != NULL) { 543 pInstance->DeleteObject(); 544 } 545 546 if (providerAllocated) { 547 pProvider->DeleteObject(); 548 } 549 } 550 551 return status; 552 } 553 554 VOID 555 FxWmiIrpHandler::RemoveProvider( 556 __in FxWmiProvider* Provider 557 ) 558 { 559 KIRQL irql; 560 561 // 562 // No need to update via IoWMIRegistrationControl because this is only 563 // called in the error path of creating a provider. 564 // 565 Lock(&irql); 566 RemoveProviderLocked(Provider); 567 Unlock(irql); 568 } 569 570 VOID 571 FxWmiIrpHandler::RemoveProviderLocked( 572 __in FxWmiProvider* Provider 573 ) 574 { 575 m_NumProviders--; 576 RemoveEntryList(&Provider->m_ListEntry); 577 InitializeListHead(&Provider->m_ListEntry); 578 } 579 580 _Must_inspect_result_ 581 FxWmiProvider* 582 FxWmiIrpHandler::FindProviderLocked( 583 __in LPGUID Guid 584 ) 585 { 586 FxWmiProvider* pFound; 587 PLIST_ENTRY ple; 588 589 pFound = NULL; 590 591 for (ple = m_ProvidersListHead.Flink; 592 ple != &m_ProvidersListHead; 593 ple = ple->Flink) { 594 595 FxWmiProvider* pProvider; 596 597 pProvider = CONTAINING_RECORD(ple, FxWmiProvider, m_ListEntry); 598 599 if (RtlCompareMemory(&pProvider->m_Guid, 600 Guid, 601 sizeof(GUID)) == sizeof(GUID)) { 602 pFound = pProvider; 603 break; 604 } 605 } 606 607 return pFound; 608 } 609 610 _Must_inspect_result_ 611 FxWmiProvider* 612 FxWmiIrpHandler::FindProviderReferenced( 613 __in LPGUID Guid, 614 __in PVOID Tag 615 ) 616 { 617 FxWmiProvider* pProvider; 618 KIRQL irql; 619 620 Lock(&irql); 621 pProvider = FindProviderLocked(Guid); 622 if (pProvider != NULL) { 623 pProvider->ADDREF(Tag); 624 } 625 Unlock(irql); 626 627 return pProvider; 628 } 629 630 _Must_inspect_result_ 631 NTSTATUS 632 FxWmiIrpHandler::Dispatch( 633 __in PIRP Irp 634 ) 635 { 636 PFX_DRIVER_GLOBALS pFxDriverGlobals; 637 FxWmiProvider* pProvider; 638 FxWmiInstance* pInstance; 639 PIO_STACK_LOCATION stack; 640 PDEVICE_OBJECT pAttached; 641 NTSTATUS status; 642 PVOID pTag; 643 ULONG instanceIndex; 644 KIRQL irql; 645 BOOLEAN handled, completeNow; 646 UCHAR minor; 647 648 pFxDriverGlobals = GetDriverGlobals(); 649 650 FX_TRACK_DRIVER(pFxDriverGlobals); 651 652 stack = IoGetCurrentIrpStackLocation(Irp); 653 minor = stack->MinorFunction; 654 pTag = UlongToPtr(minor); 655 status = Irp->IoStatus.Status; 656 657 pProvider = NULL; 658 pInstance = NULL; 659 660 handled = FALSE; 661 completeNow = FALSE; 662 663 DoTraceLevelMessage( 664 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO, 665 "WDFDEVICE 0x%p !devobj 0x%p IRP_MJ_SYSTEM_CONTROL, %!sysctrl! IRP 0x%p", 666 m_Device->GetHandle(), m_Device->GetDeviceObject(), minor, Irp); 667 668 // 669 // Verify the minor code is within range, there is hole in the table at 0xA. 670 // This check works around the hole in the table. 671 // 672 if (minor > IRP_MN_EXECUTE_METHOD && minor != IRP_MN_REGINFO_EX) { 673 goto Done; 674 } 675 676 // 677 // If the irp is not targetted at this device, send it down the stack 678 // 679 if (stack->Parameters.WMI.ProviderId != (UINT_PTR) m_Device->GetDeviceObject()) { 680 goto Done; 681 } 682 683 if (minor == IRP_MN_REGINFO || minor == IRP_MN_REGINFO_EX) { 684 status = STATUS_SUCCESS; 685 } 686 else { 687 Lock(&irql); 688 689 pProvider = FindProviderLocked((LPGUID)stack->Parameters.WMI.DataPath); 690 691 if (pProvider != NULL) { 692 status = STATUS_SUCCESS; 693 } 694 else { 695 // 696 // check for WMI tracing (no pProvider) 697 // 698 status = STATUS_WMI_GUID_NOT_FOUND; 699 } 700 701 if (NT_SUCCESS(status) && m_WmiDispatchTable[minor].CheckInstance) { 702 PWNODE_SINGLE_INSTANCE pSingle; 703 704 pSingle = (PWNODE_SINGLE_INSTANCE) stack->Parameters.WMI.Buffer; 705 706 instanceIndex = pSingle->InstanceIndex; 707 708 // 709 // Also possible bits set in Flags related to instance names 710 // WNODE_FLAG_PDO_INSTANCE_NAMES 711 // 712 if (pSingle->WnodeHeader.Flags & WNODE_FLAG_STATIC_INSTANCE_NAMES) { 713 // 714 // Try to get the instance 715 // 716 pInstance = pProvider->GetInstanceReferencedLocked( 717 instanceIndex, pTag); 718 719 if (pInstance == NULL) { 720 status = STATUS_WMI_INSTANCE_NOT_FOUND; 721 } 722 } 723 else { 724 725 726 727 728 729 730 status = STATUS_WMI_INSTANCE_NOT_FOUND; 731 } 732 } 733 734 if (NT_SUCCESS(status)) { 735 pProvider->ADDREF(pTag); 736 } 737 else { 738 // 739 // NULL out the provider so we don't deref it later. We could not 740 // use if (pProvider != NULL && NT_SUCCESS(status) in the Done: block 741 // because we could have success here, but the dispatch function 742 // returns error. 743 // 744 pProvider = NULL; 745 } 746 747 Unlock(irql); 748 749 if (!NT_SUCCESS(status)) { 750 Irp->IoStatus.Status = status; 751 completeNow = TRUE; 752 } 753 } 754 755 if (NT_SUCCESS(status) && m_WmiDispatchTable[minor].Handler != NULL) { 756 status = m_WmiDispatchTable[minor].Handler(this, 757 Irp, 758 pProvider, 759 pInstance); 760 handled = TRUE; 761 } 762 763 Done: 764 if (pInstance != NULL) { 765 pInstance->RELEASE(pTag); 766 pInstance = NULL; 767 } 768 769 if (pProvider != NULL) { 770 pProvider->RELEASE(pTag); 771 pProvider = NULL; 772 } 773 774 if (handled == FALSE) { 775 pAttached = m_Device->GetAttachedDevice(); 776 if (completeNow || pAttached == NULL) { 777 // 778 // Sent to a PDO, error in the FDO handling, or controller devobj 779 // style devobj, complete it here 780 // 781 status = Irp->IoStatus.Status; 782 IoCompleteRequest(Irp, IO_NO_INCREMENT); 783 } 784 else { 785 // 786 // Request sent to PNP device object that is not a PDO, send down 787 // the stack 788 // 789 IoSkipCurrentIrpStackLocation(Irp); 790 status = IoCallDriver(pAttached, Irp); 791 } 792 } 793 794 // 795 // Only release the remove lock *after* we have removed the thread entry 796 // from the list because the list lifetime is tied to the FxDevice lifetime 797 // and the remlock controls the lifetime of FxDevice. 798 // 799 // Since we never pend the wmi request, we can release the remove lock in 800 // this Dispatch routine. If we ever pended the IRPs, this would have to 801 // have some more logic involved. 802 // 803 IoReleaseRemoveLock( 804 &FxDevice::_GetFxWdmExtension(m_Device->GetDeviceObject())->IoRemoveLock, 805 Irp 806 ); 807 808 return status; 809 } 810 811 _Must_inspect_result_ 812 NTSTATUS 813 FxWmiIrpHandler::_QueryAllData( 814 __in FxWmiIrpHandler* This, 815 __in PIRP Irp, 816 __in FxWmiProvider* Provider, 817 __in_opt FxWmiInstance* Instance 818 ) 819 /*++ 820 821 Routine Description: 822 Handles querying all instances for data. In the case where there is not 823 enough space in the buffer, we query each instance for the required amount 824 of buffer space and report that. 825 826 Arguments: 827 This - device instance 828 829 Irp - WMI request for query all data 830 831 Providre - the provider being queried 832 833 Instance - ignored, NULL 834 835 Return Value: 836 STATUS_BUFFER_TOO_SMALL in case the buffer is not large enough 837 STATUS_SUCCESS on a successful query 838 or other values depending on the client driver 839 840 --*/ 841 { 842 POFFSETINSTANCEDATAANDLENGTH pOffsets; 843 PWNODE_ALL_DATA pNodeData; 844 PIO_STACK_LOCATION stack; 845 PUCHAR pData; 846 NTSTATUS status, addStatus; 847 ULONG instanceCount, dataBlockOffset, lengthArraySize, i, sizeRemaining, 848 lastAdjustment, bufferUsed, tempOffset; 849 KIRQL irql; 850 BOOLEAN tooSmall; 851 852 UNREFERENCED_PARAMETER(Instance); 853 854 status = STATUS_SUCCESS; 855 856 stack = IoGetCurrentIrpStackLocation(Irp); 857 pNodeData = (PWNODE_ALL_DATA) stack->Parameters.WMI.Buffer; 858 859 lastAdjustment = 0; 860 pData = NULL; 861 dataBlockOffset = 0; 862 863 // 864 // This either the amount of buffer used on successful queries or the 865 // amount of buffer required if the buffer is not big enough. 866 // 867 bufferUsed = 0; 868 869 tooSmall = FALSE; 870 871 if (stack->Parameters.WMI.BufferSize < sizeof(WNODE_ALL_DATA)) { 872 status = STATUS_UNSUCCESSFUL; 873 goto Done; 874 } 875 876 877 878 879 880 881 882 // 883 // All of the provider's access is guarded by the irp handler's lock 884 // 885 This->Lock(&irql); 886 instanceCount = Provider->m_NumInstances; 887 This->Unlock(irql); 888 889 890 891 892 893 894 895 896 897 898 899 if (instanceCount == 0) { 900 status = STATUS_WMI_INSTANCE_NOT_FOUND; 901 DoTraceLevelMessage( 902 This->GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 903 "Failing QueryAllData since no instances found for " 904 "WDFWMIPROVIDER %p, %!STATUS!", 905 Provider->GetHandle(), status); 906 bufferUsed = 0; 907 goto Done; 908 } 909 910 DoTraceLevelMessage( 911 This->GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 912 "WDFWMIPROVIDER %p QueryAllData, num instances %d", 913 Provider->GetHandle(), instanceCount); 914 915 pNodeData->InstanceCount = instanceCount; 916 917 918 919 920 921 922 pNodeData->WnodeHeader.Flags &= ~WNODE_FLAG_FIXED_INSTANCE_SIZE; 923 924 // 925 // Since value of instanceCount is not limited, do overflow-safe addition 926 // and multiplication 927 // 928 // lengthArraySize = instanceCount * sizeof(OFFSETINSTANCEDATAANDLENGTH); 929 status = RtlULongMult(instanceCount, 930 sizeof(OFFSETINSTANCEDATAANDLENGTH), 931 &lengthArraySize); 932 933 if (NT_SUCCESS(status)) { 934 // dataBlockOffset = 935 // FIELD_OFFSET(WNODE_ALL_DATA, OffsetInstanceDataAndLength) + lengthArraySize; 936 status = RtlULongAdd( 937 FIELD_OFFSET(WNODE_ALL_DATA, OffsetInstanceDataAndLength), 938 lengthArraySize, 939 &tempOffset); 940 941 if (NT_SUCCESS(status)) { 942 dataBlockOffset = (ULONG) WDF_ALIGN_SIZE_UP( 943 tempOffset, MEMORY_ALLOCATION_ALIGNMENT); 944 945 if (dataBlockOffset < tempOffset) { 946 status = STATUS_INTEGER_OVERFLOW; 947 } 948 } 949 } 950 951 if (!NT_SUCCESS(status)) { 952 DoTraceLevelMessage( 953 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 954 "Failing QueryAllData since integer overflow occured using" 955 " provider instance count %d for WDFWMIPROVIDER %p, %!STATUS!", 956 instanceCount, Provider->GetHandle(), status); 957 bufferUsed = 0; 958 goto Done; 959 } 960 961 pNodeData->DataBlockOffset = dataBlockOffset; 962 963 if (dataBlockOffset <= stack->Parameters.WMI.BufferSize) { 964 pOffsets = &pNodeData->OffsetInstanceDataAndLength[0]; 965 sizeRemaining = stack->Parameters.WMI.BufferSize - dataBlockOffset; 966 pData = (PUCHAR) WDF_PTR_ADD_OFFSET(pNodeData, dataBlockOffset); 967 } 968 else { 969 // 970 // There is not enough room in the WNODE to complete the query, but 971 // we still want to query all the instances to see how big a buffer the 972 // caller should resend. 973 // 974 pOffsets = NULL; 975 pData = NULL; 976 sizeRemaining = 0; 977 978 // 979 // We are in the too small case 980 // 981 tooSmall = TRUE; 982 status = STATUS_BUFFER_TOO_SMALL; 983 } 984 985 if (instanceCount > 0 && Provider->GetMinInstanceBufferSize() != 0) { 986 ULONG size, minSizeAdjusted; 987 988 size = 0; 989 990 minSizeAdjusted = (ULONG) WDF_ALIGN_SIZE_UP( 991 Provider->GetMinInstanceBufferSize(), 992 MEMORY_ALLOCATION_ALIGNMENT 993 ); 994 995 // 996 // Quick size check to make sure there is enough buffer for all of the 997 // instances. We round up all but the last instance's minimum size so 998 // that we can make sure we have enough room for an aligned bufer for 999 // each instance. 1000 // 1001 // All but the last instance are using the adjusted size. In the end, 1002 // we will have: 1003 // 1004 // size = minSizeAdjusted * (instanceCount-1) + 1005 // Provider->GetMinInstanceBufferSize(); 1006 // 1007 // NOTE: we do not care about instances which do not support query 1008 // data. We don't care b/c by computing the total size of all 1009 // instances we compute the maximum sized buffer needed, and if 1010 // a few instances do no support query data, then the buffer 1011 // will just be too large, never too small. 1012 // 1013 status = RtlULongMult(minSizeAdjusted, instanceCount - 1, &size); 1014 if (!NT_SUCCESS(status)) { 1015 goto Done; 1016 } 1017 1018 status = RtlULongAdd(size, Provider->GetMinInstanceBufferSize(), &size); 1019 if (!NT_SUCCESS(status)) { 1020 goto Done; 1021 } 1022 1023 // 1024 // Since the client indicated that that each block as a minimum instance 1025 // size (which in reality is the fixed size, variable sized instnaces 1026 // should report a minimum instance size of zero), we can compute the 1027 // required buffer size w/out querying each instance for the required 1028 // size. 1029 // 1030 if (sizeRemaining < size) { 1031 // 1032 // bufferUsed in the buffer too small case indicates how many bytes 1033 // we want the caller to allocate. 1034 // 1035 bufferUsed = size; 1036 status = STATUS_BUFFER_TOO_SMALL; 1037 goto Done; 1038 } 1039 } 1040 1041 for (i = 0; i < instanceCount; i++) { 1042 FxWmiInstance* pInstance; 1043 1044 // 1045 // In the case where we have a minimum instance size, we should have 1046 // verified correctly above to have enough buffer. 1047 // 1048 ASSERT(sizeRemaining >= Provider->GetMinInstanceBufferSize()); 1049 1050 pInstance = Provider->GetInstanceReferenced(i, Irp); 1051 1052 if (pInstance == NULL) { 1053 break; 1054 } 1055 1056 if (pInstance->IsQueryInstanceSupported()) { 1057 ULONG tmpSize; 1058 1059 tmpSize = 0; 1060 1061 status = pInstance->QueryInstance(sizeRemaining, pData, &tmpSize); 1062 1063 if (NT_SUCCESS(status) || status == STATUS_BUFFER_TOO_SMALL) { 1064 ULONG adjustedSize; 1065 1066 // 1067 // We calculate the size in both cases. In the NT_SUCCESS case, 1068 // it is the amount of buffer used. In the too small case, it is 1069 // the amount of buffer required for a subsequent query. 1070 // 1071 adjustedSize = (ULONG) WDF_ALIGN_SIZE_UP( 1072 tmpSize, MEMORY_ALLOCATION_ALIGNMENT 1073 ); 1074 1075 if (adjustedSize < tmpSize) { 1076 // 1077 // Overflow, adjustedSize will be >= tmpSize in the normal 1078 // case. 1079 // 1080 status = STATUS_INTEGER_OVERFLOW; 1081 DoTraceLevelMessage( 1082 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 1083 "WDFWMIINSTNACE %p queried, returned a buffer size of %d," 1084 "but it could not be rounded up, %!STATUS!", 1085 pInstance->GetHandle(), tmpSize, status); 1086 goto QueryError; 1087 } 1088 1089 // 1090 // Keep track of how much we adjusted up the size on the last 1091 // instance so that when compute the total buffer used, we 1092 // do not include the final size adjustment. 1093 // 1094 lastAdjustment = adjustedSize - tmpSize; 1095 1096 // 1097 // We only write the offset and data if we have not yet 1098 // encountered an instance where the buffer size was too small. 1099 // 1100 if (NT_SUCCESS(status) && tooSmall == FALSE) { 1101 // 1102 // dataBlockOffset is where we are currently at in the buffer 1103 // 1104 pOffsets[i].LengthInstanceData = tmpSize; 1105 pOffsets[i].OffsetInstanceData = dataBlockOffset; 1106 1107 pData += adjustedSize; 1108 } 1109 else { 1110 tooSmall = TRUE; 1111 } 1112 1113 // 1114 // Compute how much buffer we have left and our offset into it. 1115 // 1116 if (adjustedSize <= sizeRemaining) { 1117 sizeRemaining -= adjustedSize; 1118 1119 // 1120 // dataBlockOffset += adjustedSize; 1121 // 1122 addStatus = RtlULongAdd(dataBlockOffset, 1123 adjustedSize, 1124 &dataBlockOffset); 1125 } 1126 else { 1127 // 1128 // dataBlockOffset += sizeRemaining; 1129 // 1130 addStatus = RtlULongAdd(dataBlockOffset, 1131 sizeRemaining, 1132 &dataBlockOffset); 1133 sizeRemaining = 0; 1134 } 1135 1136 if (!NT_SUCCESS(addStatus)) { 1137 status = addStatus; 1138 DoTraceLevelMessage( 1139 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 1140 "WDFWMIPROVIDER %p, arithmetic overflow in computing " 1141 "block offset, %!STATUS!", Provider->GetHandle(), 1142 status); 1143 goto QueryError; 1144 } 1145 1146 // 1147 // Compute how much buffer space we have used or require the 1148 // caller to provide. This is just the count of bytes for the 1149 // data queried, it does not yet include the array size required 1150 // to report offset & lengths. 1151 // 1152 // bufferUsed += adjustedSize; 1153 // 1154 addStatus = RtlULongAdd(bufferUsed, adjustedSize, &bufferUsed); 1155 1156 if (!NT_SUCCESS(addStatus)) { 1157 status = addStatus; 1158 DoTraceLevelMessage( 1159 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 1160 "WDFWMIPROVIDER %p, arithmetic overflow in computing " 1161 "buffer consumed(%d+%d), %!STATUS!", 1162 Provider->GetHandle(), bufferUsed, adjustedSize, status); 1163 goto QueryError; 1164 } 1165 } 1166 } 1167 else if (pOffsets != NULL) { 1168 // 1169 // Indicate no buffer and the current offset. If there any 1170 // other instances after this one, they will share the same 1171 // offset. 1172 // 1173 pOffsets[i].LengthInstanceData = 0; 1174 pOffsets[i].OffsetInstanceData = dataBlockOffset; 1175 } 1176 1177 QueryError: 1178 pInstance->RELEASE(Irp); 1179 1180 // 1181 // We continue on STATUS_BUFFER_TOO_SMALL so that we can ask each 1182 // instance the amount of buffer it needs. 1183 // 1184 if (!NT_SUCCESS(status) && status != STATUS_BUFFER_TOO_SMALL) { 1185 break; 1186 } 1187 } 1188 1189 // 1190 // We can have STATUS_BUFFER_TOO_SMALL if the last instance could not fit 1191 // its data into the buffer or have success if the last instance could write 1192 // its data, but a previous instance could not. 1193 // 1194 if (status == STATUS_BUFFER_TOO_SMALL || (NT_SUCCESS(status) && tooSmall)) { 1195 // 1196 // Since we align up the size of each block to MEMORY_ALLOCATION_ALIGNMENT, 1197 // the total buffer size is possibly adjusted up too high. Subtract the 1198 // last adjustment made for alignment when computing the instance size 1199 // so that our total size is not rounded up. 1200 // 1201 // CompleteWmiQueryAllDataRequest will take care of adding enough space 1202 // to the requested size to account for the array of instance offsets 1203 // and lengths. 1204 // 1205 bufferUsed -=lastAdjustment; 1206 1207 status = STATUS_BUFFER_TOO_SMALL; 1208 1209 DoTraceLevelMessage( 1210 This->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, 1211 "WDFWMIPROVIDER %p QueryAllData returning %!STATUS!, requesting " 1212 "buffer size of 0x%x", Provider->GetHandle(), status, bufferUsed); 1213 } 1214 else if (NT_SUCCESS(status)) { 1215 // 1216 // Compute the total amount of buffer used. dataBlockOffset is the 1217 // offset of the next instance, which is one past the end, so just 1218 // compute the distance from the start. 1219 // 1220 // Since align up the size of each block to MEMORY_ALLOCATION_ALIGNMENT, 1221 // the total buffer size is possibly adjusted up too high. Subtract the 1222 // last adjustment made for alignment when computing the instance size 1223 // so that our total size is not rounded up. 1224 // 1225 ASSERT(dataBlockOffset >= pNodeData->DataBlockOffset); 1226 ASSERT(dataBlockOffset - pNodeData->DataBlockOffset >= lastAdjustment); 1227 bufferUsed = dataBlockOffset - pNodeData->DataBlockOffset - lastAdjustment; 1228 } 1229 else { 1230 DoTraceLevelMessage( 1231 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 1232 "WDFWMIPROVIDER %p QueryAllData returning %!STATUS!", 1233 Provider->GetHandle(), status); 1234 1235 bufferUsed = 0; 1236 } 1237 1238 DoTraceLevelMessage( 1239 This->GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 1240 "WDFWMIPROVIDER %p QueryAllData returning %!STATUS!, buffer used 0x%x", 1241 Provider->GetHandle(), status, bufferUsed); 1242 1243 Done: 1244 status = This->CompleteWmiRequest(Irp, status, bufferUsed); 1245 1246 return status; 1247 } 1248 1249 _Must_inspect_result_ 1250 NTSTATUS 1251 FxWmiIrpHandler::_QuerySingleInstance( 1252 __in FxWmiIrpHandler* This, 1253 __in PIRP Irp, 1254 __in FxWmiProvider* Provider, 1255 __in FxWmiInstance* Instance 1256 ) 1257 { 1258 PWNODE_SINGLE_INSTANCE pSingle; 1259 PIO_STACK_LOCATION stack; 1260 NTSTATUS status; 1261 ULONG size, bufferSize; 1262 1263 size = 0; 1264 1265 stack = IoGetCurrentIrpStackLocation(Irp); 1266 pSingle = (PWNODE_SINGLE_INSTANCE) stack->Parameters.WMI.Buffer; 1267 bufferSize = stack->Parameters.WMI.BufferSize - pSingle->DataBlockOffset; 1268 1269 if (Instance->IsQueryInstanceSupported() == FALSE) { 1270 status = STATUS_INVALID_DEVICE_REQUEST; 1271 } 1272 else if (bufferSize < Provider->GetMinInstanceBufferSize()) { 1273 size = Provider->GetMinInstanceBufferSize(); 1274 status = STATUS_BUFFER_TOO_SMALL; 1275 } 1276 else { 1277 status = STATUS_SUCCESS; 1278 } 1279 1280 if (NT_SUCCESS(status)) { 1281 status = Instance->QueryInstance( 1282 bufferSize, 1283 WDF_PTR_ADD_OFFSET(pSingle, pSingle->DataBlockOffset), 1284 &size 1285 ); 1286 1287 pSingle->SizeDataBlock = size; 1288 } 1289 1290 status = This->CompleteWmiRequest(Irp, status, size); 1291 1292 return status; 1293 } 1294 1295 _Must_inspect_result_ 1296 NTSTATUS 1297 FxWmiIrpHandler::_ChangeSingleInstance( 1298 __in FxWmiIrpHandler* This, 1299 __in PIRP Irp, 1300 __in FxWmiProvider* Provider, 1301 __in FxWmiInstance* Instance 1302 ) 1303 { 1304 PWNODE_SINGLE_INSTANCE pSingle; 1305 PIO_STACK_LOCATION stack; 1306 NTSTATUS status; 1307 ULONG size; 1308 1309 size = 0; 1310 1311 stack = IoGetCurrentIrpStackLocation(Irp); 1312 pSingle = (PWNODE_SINGLE_INSTANCE) stack->Parameters.WMI.Buffer; 1313 1314 if (Instance->IsSetInstanceSupported() == FALSE) { 1315 status = STATUS_WMI_READ_ONLY; 1316 } 1317 else if (pSingle->SizeDataBlock < Provider->m_MinInstanceBufferSize) { 1318 size = Provider->m_MinInstanceBufferSize; 1319 status = STATUS_BUFFER_TOO_SMALL; 1320 } 1321 else { 1322 status = STATUS_SUCCESS; 1323 } 1324 1325 if (NT_SUCCESS(status)) { 1326 size = pSingle->SizeDataBlock; 1327 1328 status = Instance->SetInstance( 1329 pSingle->SizeDataBlock, 1330 size == 0 ? 1331 NULL : WDF_PTR_ADD_OFFSET(pSingle, pSingle->DataBlockOffset) 1332 ); 1333 1334 ASSERT(status != STATUS_PENDING); 1335 if (status == STATUS_PENDING) { 1336 status = STATUS_UNSUCCESSFUL; 1337 size = 0; 1338 } 1339 } 1340 1341 status = This->CompleteWmiRequest(Irp, status, size); 1342 1343 return status; 1344 } 1345 1346 _Must_inspect_result_ 1347 NTSTATUS 1348 FxWmiIrpHandler::_ChangeSingleItem( 1349 __in FxWmiIrpHandler* This, 1350 __in PIRP Irp, 1351 __in FxWmiProvider* Provider, 1352 __in FxWmiInstance* Instance 1353 ) 1354 { 1355 PWNODE_SINGLE_ITEM pSingle; 1356 NTSTATUS status; 1357 ULONG size; 1358 1359 UNREFERENCED_PARAMETER(Provider); 1360 1361 size = 0; 1362 1363 pSingle = (PWNODE_SINGLE_ITEM) IoGetCurrentIrpStackLocation(Irp)-> 1364 Parameters.WMI.Buffer; 1365 1366 if (Instance->IsSetItemSupported() == FALSE) { 1367 status = STATUS_WMI_READ_ONLY; 1368 } 1369 else { 1370 status = STATUS_SUCCESS; 1371 } 1372 1373 if (NT_SUCCESS(status)) { 1374 status = Instance->SetItem( 1375 pSingle->ItemId, 1376 pSingle->SizeDataItem, 1377 pSingle->SizeDataItem == 0 ? 1378 NULL : WDF_PTR_ADD_OFFSET(pSingle, pSingle->DataBlockOffset) 1379 ); 1380 1381 ASSERT(status != STATUS_PENDING); 1382 if (status == STATUS_PENDING) { 1383 status = STATUS_UNSUCCESSFUL; 1384 size = 0; 1385 } 1386 } 1387 1388 status = This->CompleteWmiRequest(Irp, status, size); 1389 1390 return status; 1391 } 1392 1393 _Must_inspect_result_ 1394 NTSTATUS 1395 FxWmiIrpHandler::_EnableDisableEventsAndCollection( 1396 __in FxWmiIrpHandler* This, 1397 __in PIRP Irp, 1398 __in FxWmiProvider* Provider, 1399 __in FxWmiInstance* Instance 1400 ) 1401 { 1402 NTSTATUS status; 1403 BOOLEAN enable; 1404 WDF_WMI_PROVIDER_CONTROL control; 1405 PIO_STACK_LOCATION stack; 1406 1407 UNREFERENCED_PARAMETER(This); 1408 UNREFERENCED_PARAMETER(Instance); 1409 1410 Irp->IoStatus.Information = 0; 1411 1412 stack = IoGetCurrentIrpStackLocation(Irp); 1413 1414 if (stack->Parameters.WMI.BufferSize < sizeof(WNODE_HEADER)) { 1415 status = STATUS_INVALID_PARAMETER; 1416 goto Done; 1417 } 1418 1419 switch (stack->MinorFunction) { 1420 case IRP_MN_ENABLE_EVENTS: 1421 enable = TRUE; 1422 control = WdfWmiEventControl; 1423 break; 1424 1425 case IRP_MN_DISABLE_EVENTS: 1426 enable = FALSE; 1427 control = WdfWmiEventControl; 1428 break; 1429 1430 case IRP_MN_ENABLE_COLLECTION: 1431 enable = TRUE; 1432 control = WdfWmiInstanceControl; 1433 break; 1434 1435 case IRP_MN_DISABLE_COLLECTION: 1436 enable = FALSE; 1437 control = WdfWmiInstanceControl; 1438 break; 1439 1440 default: 1441 status = Irp->IoStatus.Status; 1442 goto Done; 1443 } 1444 1445 if (control == WdfWmiEventControl) { 1446 Provider->m_EventControlEnabled = enable; 1447 1448 // 1449 // Capture the tracing information before making the callback 1450 // 1451 if (Provider->m_Flags & WdfWmiProviderTracing) { 1452 Provider->SetTracingHandle( 1453 ((PWNODE_HEADER) stack->Parameters.WMI.Buffer)->HistoricalContext 1454 ); 1455 } 1456 } 1457 else { 1458 Provider->m_DataBlockControlEnabled = enable; 1459 } 1460 1461 if (Provider->IsFunctionControlSupported()) { 1462 status = Provider->FunctionControl(control, enable); 1463 } 1464 else { 1465 status = STATUS_SUCCESS; 1466 } 1467 1468 ASSERT(status != STATUS_PENDING); 1469 if (status == STATUS_PENDING) { 1470 status = STATUS_UNSUCCESSFUL; 1471 } 1472 1473 // 1474 // Undo the previous capture on error 1475 // 1476 if (!NT_SUCCESS(status)) { 1477 if (control == WdfWmiEventControl) { 1478 Provider->m_EventControlEnabled = FALSE; 1479 1480 if (Provider->m_Flags & WdfWmiProviderTracing) { 1481 Provider->SetTracingHandle(NULL); 1482 } 1483 } 1484 else { 1485 Provider->m_DataBlockControlEnabled = FALSE; 1486 } 1487 1488 } 1489 1490 Done: 1491 Irp->IoStatus.Status = status; 1492 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1493 1494 return status; 1495 } 1496 1497 _Must_inspect_result_ 1498 NTSTATUS 1499 FxWmiIrpHandler::_ExecuteMethod( 1500 __in FxWmiIrpHandler* This, 1501 __in PIRP Irp, 1502 __in FxWmiProvider* Provider, 1503 __in FxWmiInstance* Instance 1504 ) 1505 { 1506 PWNODE_METHOD_ITEM pMethod; 1507 PIO_STACK_LOCATION stack; 1508 NTSTATUS status; 1509 ULONG size, inBufferSize, outBufferSize; 1510 1511 UNREFERENCED_PARAMETER(This); 1512 UNREFERENCED_PARAMETER(Provider); 1513 1514 size = 0; 1515 1516 stack = IoGetCurrentIrpStackLocation(Irp); 1517 pMethod = (PWNODE_METHOD_ITEM) stack->Parameters.WMI.Buffer; 1518 inBufferSize = pMethod->SizeDataBlock; 1519 outBufferSize = stack->Parameters.WMI.BufferSize - pMethod->DataBlockOffset; 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 if (Instance->IsExecuteMethodSupported() == FALSE) { 1532 // 1533 // WmiLib returns this value when there is no execute method function 1534 // pointer specified to it. 1535 // 1536 status = STATUS_INVALID_DEVICE_REQUEST; 1537 } 1538 else { 1539 status = STATUS_SUCCESS; 1540 } 1541 1542 if (NT_SUCCESS(status)) { 1543 status = Instance->ExecuteMethod( 1544 pMethod->MethodId, 1545 inBufferSize, 1546 outBufferSize, 1547 (inBufferSize == 0 && outBufferSize == 0) ? 1548 NULL : WDF_PTR_ADD_OFFSET(pMethod, pMethod->DataBlockOffset), 1549 &size 1550 ); 1551 1552 ASSERT(status != STATUS_PENDING); 1553 if (status == STATUS_PENDING) { 1554 status = STATUS_UNSUCCESSFUL; 1555 size = 0; 1556 } 1557 } 1558 1559 status = This->CompleteWmiRequest(Irp, status, size); 1560 1561 return status; 1562 } 1563 1564 _Must_inspect_result_ 1565 NTSTATUS 1566 FxWmiIrpHandler::_RegInfo( 1567 __in FxWmiIrpHandler* This, 1568 __in PIRP Irp, 1569 __in_opt FxWmiProvider* Provider, 1570 __in_opt FxWmiInstance* Instance 1571 ) 1572 { 1573 PIO_STACK_LOCATION stack; 1574 PUNICODE_STRING pRegPath; 1575 PWMIREGINFO pWmiRegInfo; 1576 PUCHAR pBuffer; 1577 PUNICODE_STRING pMofString; 1578 FxDevice* pDevice; 1579 NTSTATUS status; 1580 ULONG registryPathOffset, mofResourceOffset, bufferNeeded, information, 1581 bufferSize; 1582 KIRQL irql; 1583 1584 UNREFERENCED_PARAMETER(Provider); 1585 UNREFERENCED_PARAMETER(Instance); 1586 1587 information = 0; 1588 1589 stack = IoGetCurrentIrpStackLocation(Irp); 1590 pBuffer = (PUCHAR) stack->Parameters.WMI.Buffer; 1591 bufferSize = stack->Parameters.WMI.BufferSize; 1592 1593 pDevice = This->m_Device; 1594 1595 This->Lock(&irql); 1596 1597 mofResourceOffset = sizeof(WMIREGINFO) + 1598 This->m_NumProviders * sizeof(WMIREGGUIDW); 1599 1600 pMofString = NULL; 1601 1602 if (pDevice->m_MofResourceName.Buffer != NULL) { 1603 pMofString = &pDevice->m_MofResourceName; 1604 } 1605 else { 1606 // 1607 // Start with the parent and iterate up until we hit a device without 1608 // a parent. 1609 // 1610 pDevice = pDevice->m_ParentDevice; 1611 1612 while (pDevice != NULL) { 1613 if (pDevice->m_MofResourceName.Buffer != NULL) { 1614 pMofString = &pDevice->m_MofResourceName; 1615 break; 1616 } 1617 1618 // 1619 // Advance to the next ancestor 1620 // 1621 pDevice = pDevice->m_ParentDevice; 1622 } 1623 1624 // 1625 // Restore pDevice back to this device 1626 // 1627 pDevice = This->m_Device; 1628 } 1629 1630 pRegPath = pDevice->GetDriver()->GetRegistryPathUnicodeString(); 1631 1632 // 1633 // if there is a mof string, add its length. We always need to at least 1634 // add the USHORT to indicate a string of size 0. 1635 // 1636 registryPathOffset = mofResourceOffset + sizeof(USHORT); 1637 if (pMofString != NULL) { 1638 registryPathOffset += pMofString->Length; 1639 } 1640 1641 // 1642 // eventually bufferNeeded = registryPathOffset + pRegPath->Length + 1643 // sizeof(USHORT) 1644 // 1645 status = RtlULongAdd(registryPathOffset, pRegPath->Length, &bufferNeeded); 1646 if (!NT_SUCCESS(status)) { 1647 goto Done; 1648 } 1649 1650 status = RtlULongAdd(bufferNeeded, sizeof(USHORT), &bufferNeeded); 1651 if (!NT_SUCCESS(status)) { 1652 goto Done; 1653 } 1654 1655 if (bufferNeeded <= bufferSize) { 1656 PLIST_ENTRY ple; 1657 ULONG i; 1658 BOOLEAN addref; 1659 1660 information = bufferNeeded; 1661 1662 pWmiRegInfo = (PWMIREGINFO) pBuffer; 1663 pWmiRegInfo->BufferSize = bufferNeeded; 1664 pWmiRegInfo->NextWmiRegInfo = 0; 1665 pWmiRegInfo->MofResourceName = mofResourceOffset; 1666 pWmiRegInfo->RegistryPath = registryPathOffset; 1667 pWmiRegInfo->GuidCount = This->m_NumProviders; 1668 1669 addref = IoGetCurrentIrpStackLocation(Irp)->MinorFunction == IRP_MN_REGINFO_EX 1670 ? TRUE : FALSE; 1671 1672 for (ple = This->m_ProvidersListHead.Flink, i = 0; 1673 i < This->m_NumProviders; 1674 ple = ple->Flink, i++) { 1675 1676 PWMIREGGUIDW pWmiRegGuid; 1677 PDEVICE_OBJECT pdo; 1678 FxWmiProvider* pProvider; 1679 1680 pProvider = CONTAINING_RECORD(ple, FxWmiProvider, m_ListEntry); 1681 1682 pWmiRegGuid = &pWmiRegInfo->WmiRegGuid[i]; 1683 1684 RtlCopyMemory(&pWmiRegGuid->Guid, 1685 &pProvider->m_Guid, 1686 sizeof(GUID)); 1687 1688 pWmiRegGuid->InstanceCount = pProvider->m_NumInstances; 1689 1690 pWmiRegGuid->Flags = pProvider->GetRegistrationFlagsLocked(); 1691 1692 pdo = pDevice->GetPhysicalDevice(); 1693 pWmiRegGuid->Pdo = (ULONG_PTR) pdo; 1694 1695 if (addref) { 1696 ObReferenceObject(pdo); 1697 } 1698 } 1699 } 1700 else { 1701 *((PULONG) pBuffer) = bufferNeeded; 1702 information = sizeof(ULONG); 1703 } 1704 1705 This->Unlock(irql); 1706 1707 // 1708 // Must copy the strings outside of any lock since they are in paged pool 1709 // 1710 if (bufferNeeded <= bufferSize) { 1711 PUSHORT pLength; 1712 1713 pLength = WDF_PTR_ADD_OFFSET_TYPE(pBuffer, mofResourceOffset, PUSHORT); 1714 1715 if (pMofString != NULL) { 1716 *pLength = pMofString->Length; 1717 1718 RtlCopyMemory(pLength + 1, 1719 pMofString->Buffer, 1720 pMofString->Length); 1721 } 1722 else { 1723 *pLength = 0; 1724 } 1725 1726 pLength = WDF_PTR_ADD_OFFSET_TYPE(pBuffer, registryPathOffset, PUSHORT); 1727 1728 *pLength = pRegPath->Length; 1729 RtlCopyMemory(pLength + 1, 1730 pRegPath->Buffer, 1731 pRegPath->Length); 1732 } 1733 1734 status = STATUS_SUCCESS; 1735 1736 Done: 1737 if (!NT_SUCCESS(status)) { 1738 This->Unlock(irql); 1739 } 1740 1741 Irp->IoStatus.Status = status; 1742 Irp->IoStatus.Information = information; 1743 1744 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1745 1746 return status; 1747 } 1748 1749 VOID 1750 FxWmiIrpHandler::CompleteWmiQueryAllDataRequest( 1751 __in PIRP Irp, 1752 __in NTSTATUS Status, 1753 __in ULONG BufferUsed 1754 ) 1755 { 1756 PWNODE_ALL_DATA pNodeAllData; 1757 ULONG bufferNeeded, information; 1758 PIO_STACK_LOCATION stack; 1759 1760 stack = IoGetCurrentIrpStackLocation(Irp); 1761 1762 pNodeAllData = (PWNODE_ALL_DATA) stack->Parameters.WMI.Buffer; 1763 bufferNeeded = pNodeAllData->DataBlockOffset + BufferUsed; 1764 1765 if (NT_SUCCESS(Status) && bufferNeeded > stack->Parameters.WMI.BufferSize) { 1766 Status = STATUS_BUFFER_TOO_SMALL; 1767 } 1768 1769 if (NT_SUCCESS(Status)) { 1770 KeQuerySystemTime(&pNodeAllData->WnodeHeader.TimeStamp); 1771 1772 pNodeAllData->WnodeHeader.BufferSize = bufferNeeded; 1773 information = bufferNeeded; 1774 } 1775 else if (Status == STATUS_BUFFER_TOO_SMALL) { 1776 PWNODE_TOO_SMALL pNodeTooSmall; 1777 1778 pNodeTooSmall = (PWNODE_TOO_SMALL) stack->Parameters.WMI.Buffer; 1779 1780 pNodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL); 1781 pNodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL; 1782 pNodeTooSmall->SizeNeeded = bufferNeeded; 1783 1784 information = sizeof(WNODE_TOO_SMALL); 1785 Status = STATUS_SUCCESS; 1786 } 1787 else { 1788 information = 0; 1789 } 1790 1791 Irp->IoStatus.Information = information; 1792 Irp->IoStatus.Status = Status; 1793 } 1794 1795 VOID 1796 FxWmiIrpHandler::CompleteWmiQuerySingleInstanceRequest( 1797 __in PIRP Irp, 1798 __in NTSTATUS Status, 1799 __in ULONG BufferUsed 1800 ) 1801 { 1802 PWNODE_SINGLE_INSTANCE pNodeSingle; 1803 ULONG bufferNeeded, information; 1804 1805 pNodeSingle = (PWNODE_SINGLE_INSTANCE) 1806 IoGetCurrentIrpStackLocation(Irp)->Parameters.WMI.Buffer; 1807 1808 bufferNeeded = pNodeSingle->DataBlockOffset + BufferUsed; 1809 1810 if (NT_SUCCESS(Status)) { 1811 pNodeSingle->WnodeHeader.BufferSize = bufferNeeded; 1812 KeQuerySystemTime(&pNodeSingle->WnodeHeader.TimeStamp); 1813 1814 ASSERT(pNodeSingle->SizeDataBlock <= BufferUsed); 1815 information = bufferNeeded; 1816 } 1817 else if (Status == STATUS_BUFFER_TOO_SMALL) { 1818 PWNODE_TOO_SMALL pNodeTooSmall; 1819 1820 pNodeTooSmall = (PWNODE_TOO_SMALL) pNodeSingle; 1821 1822 pNodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL); 1823 pNodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL; 1824 pNodeTooSmall->SizeNeeded = bufferNeeded; 1825 1826 information = sizeof(WNODE_TOO_SMALL); 1827 Status = STATUS_SUCCESS; 1828 } 1829 else { 1830 information = 0; 1831 } 1832 1833 Irp->IoStatus.Information = information; 1834 Irp->IoStatus.Status = Status; 1835 } 1836 1837 VOID 1838 FxWmiIrpHandler::CompleteWmiExecuteMethodRequest( 1839 __in PIRP Irp, 1840 __in NTSTATUS Status, 1841 __in ULONG BufferUsed 1842 ) 1843 { 1844 PWNODE_METHOD_ITEM pNodeMethod; 1845 ULONG bufferNeeded, information; 1846 1847 pNodeMethod = (PWNODE_METHOD_ITEM) 1848 IoGetCurrentIrpStackLocation(Irp)->Parameters.WMI.Buffer; 1849 1850 bufferNeeded = pNodeMethod->DataBlockOffset + BufferUsed; 1851 1852 if (NT_SUCCESS(Status)) { 1853 pNodeMethod->WnodeHeader.BufferSize = bufferNeeded; 1854 pNodeMethod->SizeDataBlock = BufferUsed; 1855 KeQuerySystemTime(&pNodeMethod->WnodeHeader.TimeStamp); 1856 1857 information = bufferNeeded; 1858 } 1859 else if (Status == STATUS_BUFFER_TOO_SMALL) { 1860 PWNODE_TOO_SMALL pNodeTooSmall; 1861 1862 pNodeTooSmall = (PWNODE_TOO_SMALL) pNodeMethod; 1863 1864 pNodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL); 1865 pNodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL; 1866 pNodeTooSmall->SizeNeeded = bufferNeeded; 1867 1868 information = sizeof(WNODE_TOO_SMALL); 1869 Status = STATUS_SUCCESS; 1870 } 1871 else { 1872 information = 0; 1873 } 1874 1875 Irp->IoStatus.Information = information; 1876 Irp->IoStatus.Status = Status; 1877 } 1878 1879 _Must_inspect_result_ 1880 NTSTATUS 1881 FxWmiIrpHandler::CompleteWmiRequest( 1882 __in PIRP Irp, 1883 __in NTSTATUS Status, 1884 __in ULONG BufferUsed 1885 ) 1886 /*++ 1887 1888 Routine Description: 1889 This routine will do the work of completing a WMI irp. Depending upon the 1890 the WMI request this routine will fixup the returned WNODE appropriately. 1891 1892 This may be called at DPC level 1893 1894 Arguments: 1895 1896 Irp - Supplies the Irp making the request. 1897 1898 Status has the return status code for the IRP 1899 1900 BufferUsed has the number of bytes needed by the device to return the 1901 data requested in any query. In the case that the buffer passed to 1902 the device is too small this has the number of bytes needed for the 1903 return data. If the buffer passed is large enough then this has the 1904 number of bytes actually used by the device. 1905 1906 Return Value: 1907 1908 status 1909 1910 --*/ 1911 { 1912 switch (IoGetCurrentIrpStackLocation(Irp)->MinorFunction) { 1913 case IRP_MN_QUERY_ALL_DATA: 1914 CompleteWmiQueryAllDataRequest(Irp, Status, BufferUsed); 1915 break; 1916 1917 case IRP_MN_QUERY_SINGLE_INSTANCE: 1918 CompleteWmiQuerySingleInstanceRequest(Irp, Status, BufferUsed); 1919 break; 1920 1921 case IRP_MN_EXECUTE_METHOD: 1922 CompleteWmiExecuteMethodRequest(Irp, Status, BufferUsed); 1923 break; 1924 1925 case IRP_MN_CHANGE_SINGLE_INSTANCE: 1926 case IRP_MN_CHANGE_SINGLE_ITEM: 1927 // 1928 // Lot's of drivers return STATUS_BUFFER_TOO_SMALL for an invalid buffer 1929 // size. WMI expects STATUS_WMI_SET_FAILURE in this case. Change the 1930 // Status to the expected value. No way to return any size in 1931 // Information, the buffer is input only. 1932 // 1933 if (Status == STATUS_BUFFER_TOO_SMALL) { 1934 DoTraceLevelMessage( 1935 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, 1936 "Converting %!STATUS! to %!STATUS!", 1937 Status, STATUS_WMI_SET_FAILURE); 1938 Status = STATUS_WMI_SET_FAILURE; 1939 } 1940 // || || Fall through || || 1941 // \/ \/ \/ \/ 1942 1943 default: 1944 // 1945 // All other requests don't return any data 1946 // 1947 Irp->IoStatus.Status = Status; 1948 Irp->IoStatus.Information = 0; 1949 break; 1950 } 1951 1952 // 1953 // One of the complete functions may have morphed the status value 1954 // 1955 Status = Irp->IoStatus.Status; 1956 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1957 1958 return Status; 1959 } 1960 1961