1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 FxIoTargetAPI.cpp 8 9 Abstract: 10 11 This module implements the IO Target APIs 12 13 Author: 14 15 Environment: 16 17 kernel mode only 18 19 Revision History: 20 21 --*/ 22 23 #include "../fxtargetsshared.hpp" 24 25 extern "C" { 26 // #include "FxIoTargetAPI.tmh" 27 } 28 29 // 30 // Extern the entire file 31 // 32 extern "C" { 33 34 _Must_inspect_result_ 35 __drv_maxIRQL(DISPATCH_LEVEL) 36 NTSTATUS 37 STDCALL 38 WDFEXPORT(WdfIoTargetStart)( 39 __in 40 PWDF_DRIVER_GLOBALS DriverGlobals, 41 __in 42 WDFIOTARGET IoTarget 43 ) 44 /*++ 45 46 Routine Description: 47 Changes the target's state to started. In the started state, the target 48 can send I/O. 49 50 Arguments: 51 IoTarget - the target whose state will change 52 53 Return Value: 54 NTSTATUS 55 56 --*/ 57 { 58 DDI_ENTRY(); 59 60 FxIoTarget* pTarget; 61 62 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), 63 IoTarget, 64 FX_TYPE_IO_TARGET, 65 (PVOID*) &pTarget); 66 67 return pTarget->Start(); 68 } 69 70 __drv_when(Action == 3, __drv_maxIRQL(DISPATCH_LEVEL)) 71 __drv_when(Action == 0 || Action == 1 || Action == 2, __drv_maxIRQL(PASSIVE_LEVEL)) 72 VOID 73 STDCALL 74 WDFEXPORT(WdfIoTargetStop)( 75 __in 76 PWDF_DRIVER_GLOBALS DriverGlobals, 77 __in 78 WDFIOTARGET IoTarget, 79 __in 80 __drv_strictTypeMatch(__drv_typeConst) 81 WDF_IO_TARGET_SENT_IO_ACTION Action 82 ) 83 /*++ 84 85 Routine Description: 86 This function puts the target into the stopped state. Depending on the value 87 of Action, this function may not return until sent I/O has been canceled and/or 88 completed. 89 90 Arguments: 91 IoTarget - the target whose state is being changed 92 93 Action - what to do with the I/O that is pending in the target already 94 95 Return Value: 96 None 97 98 --*/ 99 { 100 DDI_ENTRY(); 101 102 PFX_DRIVER_GLOBALS pFxDriverGlobals; 103 FxIoTarget* pTarget; 104 NTSTATUS status; 105 106 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 107 IoTarget, 108 FX_TYPE_IO_TARGET, 109 (PVOID*) &pTarget, 110 &pFxDriverGlobals); 111 112 if (Action == WdfIoTargetSentIoUndefined || 113 Action > WdfIoTargetLeaveSentIoPending) { 114 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 115 "Action %d undefined or out of range", Action); 116 return; 117 } 118 119 if (Action == WdfIoTargetCancelSentIo || 120 Action == WdfIoTargetWaitForSentIoToComplete) { 121 status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); 122 if (!NT_SUCCESS(status)) { 123 return; 124 } 125 } 126 127 pTarget->Stop(Action); 128 } 129 130 __drv_when(Action == 2, __drv_maxIRQL(DISPATCH_LEVEL)) 131 __drv_when(Action == 0 || Action == 1, __drv_maxIRQL(PASSIVE_LEVEL)) 132 VOID 133 STDCALL 134 WDFEXPORT(WdfIoTargetPurge)( 135 __in 136 PWDF_DRIVER_GLOBALS DriverGlobals, 137 __in 138 WDFIOTARGET IoTarget, 139 __in 140 __drv_strictTypeMatch(__drv_typeConst) 141 WDF_IO_TARGET_PURGE_IO_ACTION Action 142 ) 143 /*++ 144 145 Routine Description: 146 This function puts the target into the purged state. Depending on the value 147 of Action, this function may not return until pending and sent I/O has been 148 canceled and completed. 149 150 Arguments: 151 IoTarget - the target whose state is being changed 152 153 Action - purge action: wait or not for I/O to complete after doing the purge. 154 155 Return Value: 156 None 157 158 --*/ 159 { 160 DDI_ENTRY(); 161 162 PFX_DRIVER_GLOBALS pFxDriverGlobals; 163 FxIoTarget* pTarget; 164 NTSTATUS status; 165 166 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 167 IoTarget, 168 FX_TYPE_IO_TARGET, 169 (PVOID*) &pTarget, 170 &pFxDriverGlobals); 171 172 if (Action == WdfIoTargetPurgeIoUndefined || 173 Action > WdfIoTargetPurgeIo) { 174 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 175 "Action %d undefined or out of range", Action); 176 return; 177 } 178 179 if (Action == WdfIoTargetPurgeIoAndWait) { 180 status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); 181 if (!NT_SUCCESS(status)) { 182 return; 183 } 184 } 185 186 pTarget->Purge(Action); 187 } 188 189 __drv_maxIRQL(DISPATCH_LEVEL) 190 WDF_IO_TARGET_STATE 191 STDCALL 192 WDFEXPORT(WdfIoTargetGetState)( 193 __in 194 PWDF_DRIVER_GLOBALS DriverGlobals, 195 __in 196 WDFIOTARGET IoTarget 197 ) 198 /*++ 199 200 Routine Description: 201 Returns the current state of the target 202 203 Arguments: 204 IoTarget - target whose state is being returned 205 206 Return Value: 207 current target state 208 209 --*/ 210 { 211 DDI_ENTRY(); 212 213 FxIoTarget* pTarget; 214 215 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), 216 IoTarget, 217 FX_TYPE_IO_TARGET, 218 (PVOID*) &pTarget); 219 220 return pTarget->GetState(); 221 } 222 223 _Must_inspect_result_ 224 NTSTATUS 225 FxIoTargetValidateOpenParams( 226 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 227 __in PWDF_IO_TARGET_OPEN_PARAMS OpenParams 228 ) 229 /*++ 230 231 Routine Description: 232 Validates the target open parameters structure. 233 234 Arguments: 235 FxDriverGlobals - driver globals 236 237 OpenParams - the structure to validate 238 239 Return Value: 240 NTSTATUS 241 242 --*/ 243 244 { 245 NTSTATUS status; 246 247 // 248 // Check specific fields based on Type 249 // 250 switch (OpenParams->Type) { 251 case WdfIoTargetOpenUseExistingDevice: 252 if (OpenParams->TargetDeviceObject == NULL) { 253 status = STATUS_INVALID_PARAMETER; 254 DoTraceLevelMessage( 255 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 256 "Expected non NULL TargetDeviceObject in OpenParams, %!STATUS!", 257 status); 258 return status; 259 } 260 261 // 262 // This type is supported only in KMDF. 263 // 264 if (FxDriverGlobals->IsUserModeDriver) { 265 status = STATUS_INVALID_PARAMETER; 266 DoTraceLevelMessage( 267 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 268 "The open type WdfIoTargetOpenUseExistingDevice is not " 269 "supported in UMDF drivers. It is supported in KMDF " 270 "drivers only, %!STATUS!", 271 status); 272 return status; 273 } 274 275 if (OpenParams->TargetFileObject == NULL && 276 (OpenParams->EvtIoTargetQueryRemove != NULL || 277 OpenParams->EvtIoTargetRemoveCanceled != NULL || 278 OpenParams->EvtIoTargetRemoveComplete != NULL)) { 279 status = STATUS_INVALID_PARAMETER; 280 281 DoTraceLevelMessage( 282 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 283 "OpenParams %p TargetFileObject is NULL but a state callback " 284 "(query remove %p, remove canceled %p, remove complete %p)" 285 " was specified, %!STATUS!", 286 OpenParams, OpenParams->EvtIoTargetQueryRemove, 287 OpenParams->EvtIoTargetRemoveCanceled, 288 OpenParams->EvtIoTargetRemoveComplete, status); 289 290 return status; 291 } 292 break; 293 294 case WdfIoTargetOpenByName: 295 if (OpenParams->TargetDeviceName.Buffer == NULL || 296 OpenParams->TargetDeviceName.Length == 0 || 297 OpenParams->TargetDeviceName.MaximumLength == 0) { 298 status = STATUS_INVALID_PARAMETER; 299 DoTraceLevelMessage( 300 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 301 "Expected valid OpenParams TargetDeviceName string, %!STATUS!", 302 status); 303 return status; 304 } 305 break; 306 307 case WdfIoTargetOpenLocalTargetByFile: 308 // 309 // This type is supported only in UMDF. 310 // 311 if (FxDriverGlobals->IsUserModeDriver == FALSE) { 312 status = STATUS_INVALID_PARAMETER; 313 DoTraceLevelMessage( 314 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 315 "The open type WdfIoTargetOpenLocalTargetByFile is not " 316 "supported in KMDF drivers. It is supported in UMDF " 317 "drivers only, %!STATUS!", 318 status); 319 return status; 320 } 321 322 if ((OpenParams->EvtIoTargetQueryRemove != NULL || 323 OpenParams->EvtIoTargetRemoveCanceled != NULL || 324 OpenParams->EvtIoTargetRemoveComplete != NULL)) { 325 status = STATUS_INVALID_PARAMETER; 326 327 DoTraceLevelMessage( 328 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 329 "The open type is WdfIoTargetOpenLocalTargetByFile but a state" 330 " callback (query remove %p, remove canceled %p, remove" 331 " complete %p) was specified, %!STATUS!", 332 OpenParams->EvtIoTargetQueryRemove, 333 OpenParams->EvtIoTargetRemoveCanceled, 334 OpenParams->EvtIoTargetRemoveComplete, status); 335 336 return status; 337 } 338 339 if (OpenParams->FileName.Buffer != NULL || 340 OpenParams->FileName.Length != 0 || 341 OpenParams->FileName.MaximumLength != 0) { 342 status = FxValidateUnicodeString(FxDriverGlobals, 343 &OpenParams->FileName); 344 if (!NT_SUCCESS(status)) { 345 return status; 346 } 347 } 348 349 350 break; 351 352 case WdfIoTargetOpenReopen: 353 break; 354 355 default: 356 status = STATUS_INVALID_PARAMETER; 357 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 358 "OpenParams Type (%d) incorrect, %!STATUS!", 359 OpenParams->Type, status); 360 361 return status; 362 } 363 364 return STATUS_SUCCESS; 365 } 366 367 368 _Must_inspect_result_ 369 __drv_maxIRQL(PASSIVE_LEVEL) 370 NTSTATUS 371 STDCALL 372 WDFEXPORT(WdfIoTargetCreate)( 373 __in 374 PWDF_DRIVER_GLOBALS DriverGlobals, 375 __in 376 WDFDEVICE Device, 377 __in_opt 378 PWDF_OBJECT_ATTRIBUTES IoTargetAttributes, 379 __out 380 WDFIOTARGET* IoTarget 381 ) 382 /*++ 383 384 Routine Description: 385 Creates a WDFIOTARGET which can be opened upon success. 386 387 Arguments: 388 Device - the device which will own the target. The target will be parented 389 by the owning device 390 391 IoTargetAttributes - optional attributes to apply to the target 392 393 IoTarget - pointer which will receive the created target handle 394 395 Return Value: 396 NTSTATUS 397 398 --*/ 399 { 400 DDI_ENTRY(); 401 402 PFX_DRIVER_GLOBALS pFxDriverGlobals; 403 FxIoTargetRemote* pTarget; 404 FxDeviceBase* pDevice; 405 NTSTATUS status; 406 407 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 408 Device, 409 FX_TYPE_DEVICE_BASE, 410 (PWDFOBJECT) &pDevice, 411 &pFxDriverGlobals); 412 413 FxPointerNotNull(pFxDriverGlobals, IoTarget); 414 415 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 416 "WDFDEVICE 0x%p", Device); 417 418 status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); 419 if (!NT_SUCCESS(status)) { 420 return status; 421 } 422 423 // 424 // Since the target is auto parented to the Device, we don't allow the client 425 // to specify a parent. 426 // 427 status = FxValidateObjectAttributes(pFxDriverGlobals, IoTargetAttributes); 428 if (!NT_SUCCESS(status)) { 429 return status; 430 } 431 432 status = FxIoTargetRemote::_Create( 433 pFxDriverGlobals, IoTargetAttributes, pDevice, &pTarget); 434 435 if (NT_SUCCESS(status)) { 436 *IoTarget = pTarget->GetHandle(); 437 } 438 439 return status; 440 } 441 442 _Must_inspect_result_ 443 __drv_maxIRQL(PASSIVE_LEVEL) 444 NTSTATUS 445 STDCALL 446 WDFEXPORT(WdfIoTargetOpen)( 447 __in 448 PWDF_DRIVER_GLOBALS DriverGlobals, 449 __in 450 WDFIOTARGET IoTarget, 451 __in 452 PWDF_IO_TARGET_OPEN_PARAMS OpenParams 453 ) 454 /*++ 455 456 Routine Description: 457 Opens a target. The target must be in the closed state for an open to 458 succeed. Open is either wrapping an existing PDEVICE_OBJECT + PFILE_OBJECT 459 that the client provides or opening a PDEVICE_OBJECT by name. 460 461 Arguments: 462 IoTarget - Target to be opened 463 464 OpenParams - structure which describes how to open the target 465 466 Return Value: 467 NTSTATUS 468 469 --*/ 470 { 471 // 472 // UMDF only, noop for KMDF. 473 // It's ok to be impersonated here, because it can be required in order for 474 // the CreateFile() call to succeed. 475 // 476 DDI_ENTRY_IMPERSONATION_OK(); 477 478 PFX_DRIVER_GLOBALS pFxDriverGlobals; 479 FxIoTargetRemote* pTarget; 480 NTSTATUS status; 481 ULONG expectedConfigSize; 482 WDF_IO_TARGET_OPEN_PARAMS openParams; 483 484 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 485 IoTarget, 486 FX_TYPE_IO_TARGET_REMOTE, 487 (PVOID*) &pTarget, 488 &pFxDriverGlobals); 489 490 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 491 "enter WDFIOTARGET 0x%p", IoTarget); 492 493 FxPointerNotNull(pFxDriverGlobals, OpenParams); 494 495 status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); 496 if (!NT_SUCCESS(status)) { 497 return status; 498 } 499 500 expectedConfigSize = pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,13) ? 501 sizeof(WDF_IO_TARGET_OPEN_PARAMS) : 502 sizeof(WDF_IO_TARGET_OPEN_PARAMS_V1_11); 503 504 // 505 // Check Size 506 // 507 if (OpenParams->Size != sizeof(WDF_IO_TARGET_OPEN_PARAMS) && 508 OpenParams->Size != sizeof(WDF_IO_TARGET_OPEN_PARAMS_V1_11)) { 509 status = STATUS_INFO_LENGTH_MISMATCH; 510 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 511 "OpenParams size (%d) incorrect, expected %d, %!STATUS!", 512 OpenParams->Size, expectedConfigSize, status); 513 return status; 514 } 515 516 // 517 // Normalize WDF_IO_TARGET_OPEN_PARAMS structure. 518 // 519 if (OpenParams->Size < sizeof(WDF_IO_TARGET_OPEN_PARAMS)) { 520 RtlZeroMemory(&openParams, sizeof(WDF_IO_TARGET_OPEN_PARAMS)); 521 522 // 523 // Copy over existing fields and readjust the struct size. 524 // 525 RtlCopyMemory(&openParams, OpenParams, OpenParams->Size); 526 openParams.Size = sizeof(openParams); 527 528 // 529 // Use new open params structure from now on. 530 // 531 OpenParams = &openParams; 532 } 533 534 status = FxIoTargetValidateOpenParams(pFxDriverGlobals, OpenParams); 535 if (!NT_SUCCESS(status)) { 536 // 537 // FxIoTargetValidateCreateParams traces the error 538 // 539 return status; 540 } 541 542 status = pTarget->Open(OpenParams); 543 544 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 545 "exit WDFIOTARGET 0x%p, %!STATUS!", IoTarget, status); 546 547 return status; 548 } 549 550 __drv_maxIRQL(PASSIVE_LEVEL) 551 VOID 552 STDCALL 553 WDFEXPORT(WdfIoTargetCloseForQueryRemove)( 554 __in 555 PWDF_DRIVER_GLOBALS DriverGlobals, 556 __in 557 WDFIOTARGET IoTarget 558 ) 559 /*++ 560 561 Routine Description: 562 Closes a target in response to a query remove notification callback. This 563 will pend all i/o sent after the call returns. 564 565 Arguments: 566 IoTarget - Target to be closed 567 568 Return Value: 569 None 570 571 --*/ 572 { 573 DDI_ENTRY(); 574 575 PFX_DRIVER_GLOBALS pFxDriverGlobals; 576 FxIoTargetRemote* pTarget; 577 NTSTATUS status; 578 579 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 580 IoTarget, 581 FX_TYPE_IO_TARGET_REMOTE, 582 (PVOID*) &pTarget, 583 &pFxDriverGlobals); 584 585 pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); 586 587 DoTraceLevelMessage( 588 pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 589 "enter WDFIOTARGET 0x%p", IoTarget); 590 591 status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); 592 if (!NT_SUCCESS(status)) { 593 return; 594 } 595 596 pTarget->Close(FxIoTargetRemoteCloseReasonQueryRemove); 597 } 598 599 __drv_maxIRQL(PASSIVE_LEVEL) 600 VOID 601 STDCALL 602 WDFEXPORT(WdfIoTargetClose)( 603 __in 604 PWDF_DRIVER_GLOBALS DriverGlobals, 605 __in 606 WDFIOTARGET IoTarget 607 ) 608 /*++ 609 610 Routine Description: 611 Closes the target for good. The target can be in either a query removed or 612 opened state. 613 614 Arguments: 615 IoTarget - target to close 616 617 Return Value: 618 None 619 620 --*/ 621 { 622 DDI_ENTRY(); 623 624 PFX_DRIVER_GLOBALS pFxDriverGlobals; 625 FxIoTargetRemote* pTarget; 626 NTSTATUS status; 627 628 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 629 IoTarget, 630 FX_TYPE_IO_TARGET_REMOTE, 631 (PVOID*) &pTarget, 632 &pFxDriverGlobals); 633 634 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 635 "enter WDFIOTARGET 0x%p", IoTarget); 636 637 status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); 638 if (!NT_SUCCESS(status)) { 639 return; 640 } 641 642 pTarget->Close(FxIoTargetRemoteCloseReasonPlainClose); 643 } 644 645 __drv_maxIRQL(DISPATCH_LEVEL) 646 WDFDEVICE 647 STDCALL 648 WDFEXPORT(WdfIoTargetGetDevice)( 649 __in 650 PWDF_DRIVER_GLOBALS DriverGlobals, 651 __in 652 WDFIOTARGET IoTarget 653 ) 654 /*++ 655 656 Routine Description: 657 Returns the owning WDFDEVICE for the WDFIOTARGET, this is not necessarily 658 the PDEVICE_OBJECT of the target itself. 659 660 Arguments: 661 IoTarget - the target being retrieved 662 663 Return Value: 664 a valid WDFDEVICE handle , NULL if there are any problems 665 666 --*/ 667 668 { 669 DDI_ENTRY(); 670 671 PFX_DRIVER_GLOBALS pFxDriverGlobals; 672 FxIoTarget* pTarget; 673 WDFDEVICE device; 674 675 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 676 IoTarget, 677 FX_TYPE_IO_TARGET, 678 (PVOID*) &pTarget, 679 &pFxDriverGlobals); 680 681 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 682 "enter WDFIOTARGET 0x%p", IoTarget); 683 684 device = pTarget->GetDeviceHandle(); 685 686 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 687 "exit WDFIOTARGET 0x%p, WDFDEVICE 0x%p", IoTarget, device); 688 689 return device; 690 } 691 692 static 693 _Must_inspect_result_ 694 NTSTATUS 695 FxIoTargetSendIo( 696 __in 697 PFX_DRIVER_GLOBALS FxDriverGlobals, 698 __in 699 WDFIOTARGET IoTarget, 700 __inout_opt 701 WDFREQUEST Request, 702 __in 703 UCHAR MajorCode, 704 __inout_opt 705 PWDF_MEMORY_DESCRIPTOR IoBuffer, 706 __in_opt 707 PLONGLONG DeviceOffset, 708 __in_opt 709 PWDF_REQUEST_SEND_OPTIONS RequestOptions, 710 __out_opt 711 PULONG_PTR BytesReturned 712 ) 713 /*++ 714 715 Routine Description: 716 This routine sends a read or write synchronously to the target. If Request 717 is not NULL, the PIRP it contains will be used to send the IO. 718 719 Arguments: 720 IoTarget - target to where the IO is going to be sent 721 722 Request - optional. If specified, the PIRP it contains will be used 723 to send the I/O 724 725 MajorCode - read or write major code 726 727 IoBuffer - Buffer which will be used in the I/O. The buffer can be a PMDL, 728 buffer, or WDFMEMORY 729 730 DeviceOffset - offset into the target (and not the memory) in which the I/O 731 will start 732 733 RequestOptions - optional. If specified, the timeout value is used to cancel 734 the sent i/o if the timeout is exceeded 735 736 BytesReturned - upon success, the number of bytes transferred in the I/O 737 request 738 739 Return Value: 740 NTSTATUS 741 742 --*/ 743 744 { 745 FxIoTarget* pTarget; 746 FxRequestBuffer ioBuf; 747 NTSTATUS status; 748 749 FxObjectHandleGetPtrAndGlobals(FxDriverGlobals, 750 IoTarget, 751 FX_TYPE_IO_TARGET, 752 (PVOID*) &pTarget, 753 &FxDriverGlobals); 754 755 // 756 // Minimize the points of failure by using the stack instead of allocating 757 // out of pool. For UMDF, request initialization can fail so we still need 758 // to call initialize for FxSyncRequest. Initialization always succeeds for 759 // KM. 760 // 761 FxIoContext context; 762 FxSyncRequest request(FxDriverGlobals, &context, Request); 763 764 status = request.Initialize(); 765 if (!NT_SUCCESS(status)) { 766 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 767 "Failed to initialize FxSyncRequest for WDFIOTARGET " 768 "0x%p", IoTarget); 769 return status; 770 } 771 772 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 773 "enter: WDFIOTARGET 0x%p, WDFREQUEST 0x%p, MJ code 0x%x", 774 IoTarget, Request, MajorCode); 775 776 // 777 // Since we are synchronously waiting, we must be at passive level 778 // 779 status = FxVerifierCheckIrqlLevel(FxDriverGlobals, PASSIVE_LEVEL); 780 if (!NT_SUCCESS(status)) { 781 return status; 782 } 783 784 status = FxValidateRequestOptions(FxDriverGlobals, RequestOptions); 785 if (!NT_SUCCESS(status)) { 786 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 787 "invalid options, %!STATUS!", status); 788 return status; 789 } 790 791 if (IoBuffer != NULL) { 792 // 793 // This transcribes the client union into a local structure which we 794 // can change w/out altering the client's buffer. 795 // 796 status = ioBuf.ValidateMemoryDescriptor(FxDriverGlobals, IoBuffer); 797 if (!NT_SUCCESS(status)) { 798 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 799 "invalid input buffer descriptor 0x%p, %!STATUS!", 800 IoBuffer, status); 801 return status; 802 } 803 } 804 805 // 806 // Format the next stack location in the PIRP 807 // 808 status = pTarget->FormatIoRequest( 809 request.m_TrueRequest, MajorCode, &ioBuf, DeviceOffset, NULL); 810 811 if (NT_SUCCESS(status)) { 812 // 813 // And send it 814 // 815 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 816 "WDFIOTARGET 0x%p, WDFREQUEST 0x%p being submitted", 817 IoTarget, request.m_TrueRequest->GetTraceObjectHandle()); 818 819 status = pTarget->SubmitSync(request.m_TrueRequest, RequestOptions); 820 821 if (BytesReturned != NULL) { 822 *BytesReturned = request.m_TrueRequest->GetSubmitFxIrp()->GetInformation(); 823 824 } 825 } 826 else { 827 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 828 "could not format MJ 0x%x request, %!STATUS!", 829 MajorCode, status); 830 } 831 832 return status; 833 } 834 835 static 836 _Must_inspect_result_ 837 NTSTATUS 838 FxIoTargetFormatIo( 839 __in 840 PFX_DRIVER_GLOBALS FxDriverGlobals, 841 __in 842 WDFIOTARGET IoTarget, 843 __inout 844 WDFREQUEST Request, 845 __in 846 UCHAR MajorCode, 847 __inout_opt 848 WDFMEMORY IoBuffer, 849 __in_opt 850 PWDFMEMORY_OFFSET IoBufferOffsets, 851 __in_opt 852 PLONGLONG DeviceOffset 853 ) 854 /*++ 855 856 Routine Description: 857 Formats a Request for a read or write. The request can later be sent to the 858 target using WdfRequestSend. Upon success, this will take a reference on the 859 Iobuffer handle if it is not NULL. This reference will be released when 860 one of the following occurs: 861 1) the request is completed through WdfRequestComplete 862 2) the request is reused through WdfRequestReuse 863 3) the request is reformatted through any target format DDI 864 865 Arguments: 866 IoTarget - the request that the read or write will later be sent to 867 868 Request - the request that will be formatted 869 870 MajorCode - read or write major code 871 872 IoBuffer - optional reference counted memory handle 873 874 IoBufferOffset - optional offset into the IoBuffer. This can specify the 875 starting offset and/or length of the transfer 876 877 DeviceOffset - offset into the target in which the i/o will start 878 879 Return Value: 880 NTSTATUS 881 882 --*/ 883 { 884 FxIoTarget *pTarget; 885 FxRequest *pRequest; 886 IFxMemory* pIoMemory; 887 FxRequestBuffer ioBuf; 888 NTSTATUS status; 889 890 FxObjectHandleGetPtrAndGlobals(FxDriverGlobals, 891 IoTarget, 892 FX_TYPE_IO_TARGET, 893 (PVOID*) &pTarget, 894 &FxDriverGlobals); 895 896 DoTraceLevelMessage(FxDriverGlobals, 897 TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 898 "enter: WDFIOTARGET 0x%p, WDFREQUEST 0x%p, MJ code 0x%x, WDFMEMORY 0x%p", 899 IoTarget, Request, MajorCode, IoBuffer); 900 901 FxObjectHandleGetPtr(FxDriverGlobals, 902 Request, 903 FX_TYPE_REQUEST, 904 (PVOID*) &pRequest); 905 906 if (IoBuffer != NULL) { 907 FxObjectHandleGetPtr(FxDriverGlobals, 908 IoBuffer, 909 IFX_TYPE_MEMORY, 910 (PVOID*) &pIoMemory); 911 912 status = pIoMemory->ValidateMemoryOffsets(IoBufferOffsets); 913 if (!NT_SUCCESS(status)) { 914 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 915 "invalid memory offsets, %!STATUS!", 916 status); 917 return status; 918 } 919 920 // 921 // This transcribes the client union into a local structure which we 922 // can change w/out altering the client's buffer. 923 // 924 ioBuf.SetMemory(pIoMemory, IoBufferOffsets); 925 } 926 else { 927 pIoMemory = NULL; 928 } 929 930 // 931 // Format the next stack locaiton in the PIRP 932 // 933 status = pTarget->FormatIoRequest( 934 pRequest, MajorCode, &ioBuf, DeviceOffset, NULL); 935 936 if (NT_SUCCESS(status)) { 937 if (MajorCode == IRP_MJ_WRITE) { 938 pRequest->GetContext()->FormatWriteParams(pIoMemory, IoBufferOffsets); 939 } 940 else if (MajorCode == IRP_MJ_READ) { 941 pRequest->GetContext()->FormatReadParams(pIoMemory, IoBufferOffsets); 942 } 943 } 944 945 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 946 "exit WDFIOTARGET 0x%p, WDFREQUEST 0x%p, %!STATUS!", 947 IoTarget, Request, status); 948 949 return status; 950 } 951 952 _Must_inspect_result_ 953 __drv_maxIRQL(PASSIVE_LEVEL) 954 NTSTATUS 955 STDCALL 956 WDFEXPORT(WdfIoTargetSendReadSynchronously)( 957 __in 958 PWDF_DRIVER_GLOBALS DriverGlobals, 959 __in 960 WDFIOTARGET IoTarget, 961 __in_opt 962 WDFREQUEST Request, 963 __in_opt 964 PWDF_MEMORY_DESCRIPTOR OutputBuffer, 965 __in_opt 966 PLONGLONG DeviceOffset, 967 __in_opt 968 PWDF_REQUEST_SEND_OPTIONS RequestOptions, 969 __out_opt 970 PULONG_PTR BytesRead 971 ) 972 { 973 DDI_ENTRY(); 974 975 return FxIoTargetSendIo(GetFxDriverGlobals(DriverGlobals), 976 IoTarget, 977 Request, 978 IRP_MJ_READ, 979 OutputBuffer, 980 DeviceOffset, 981 RequestOptions, 982 BytesRead); 983 } 984 985 _Must_inspect_result_ 986 __drv_maxIRQL(DISPATCH_LEVEL) 987 NTSTATUS 988 STDCALL 989 WDFEXPORT(WdfIoTargetFormatRequestForRead)( 990 __in 991 PWDF_DRIVER_GLOBALS DriverGlobals, 992 __in 993 WDFIOTARGET IoTarget, 994 __in 995 WDFREQUEST Request, 996 __in_opt 997 WDFMEMORY OutputBuffer, 998 __in_opt 999 PWDFMEMORY_OFFSET OutputBufferOffsets, 1000 __in_opt 1001 PLONGLONG DeviceOffset 1002 ) 1003 { 1004 DDI_ENTRY(); 1005 1006 return FxIoTargetFormatIo(GetFxDriverGlobals(DriverGlobals), 1007 IoTarget, 1008 Request, 1009 IRP_MJ_READ, 1010 OutputBuffer, 1011 OutputBufferOffsets, 1012 DeviceOffset); 1013 } 1014 1015 1016 _Must_inspect_result_ 1017 __drv_maxIRQL(PASSIVE_LEVEL) 1018 NTSTATUS 1019 STDCALL 1020 WDFEXPORT(WdfIoTargetSendWriteSynchronously)( 1021 __in 1022 PWDF_DRIVER_GLOBALS DriverGlobals, 1023 __in 1024 WDFIOTARGET IoTarget, 1025 __in_opt 1026 WDFREQUEST Request, 1027 __in_opt 1028 PWDF_MEMORY_DESCRIPTOR InputBuffer, 1029 __in_opt 1030 PLONGLONG DeviceOffset, 1031 __in_opt 1032 PWDF_REQUEST_SEND_OPTIONS RequestOptions, 1033 __out_opt 1034 PULONG_PTR BytesWritten 1035 ) 1036 { 1037 DDI_ENTRY(); 1038 1039 return FxIoTargetSendIo(GetFxDriverGlobals(DriverGlobals), 1040 IoTarget, 1041 Request, 1042 IRP_MJ_WRITE, 1043 InputBuffer, 1044 DeviceOffset, 1045 RequestOptions, 1046 BytesWritten); 1047 } 1048 1049 _Must_inspect_result_ 1050 __drv_maxIRQL(DISPATCH_LEVEL) 1051 NTSTATUS 1052 STDCALL 1053 WDFEXPORT(WdfIoTargetFormatRequestForWrite)( 1054 __in 1055 PWDF_DRIVER_GLOBALS DriverGlobals, 1056 __in 1057 WDFIOTARGET IoTarget, 1058 __in 1059 WDFREQUEST Request, 1060 __in_opt 1061 WDFMEMORY InputBuffer, 1062 __in_opt 1063 PWDFMEMORY_OFFSET InputBufferOffsets, 1064 __in_opt 1065 PLONGLONG DeviceOffset 1066 ) 1067 { 1068 DDI_ENTRY(); 1069 1070 return FxIoTargetFormatIo(GetFxDriverGlobals(DriverGlobals), 1071 IoTarget, 1072 Request, 1073 IRP_MJ_WRITE, 1074 InputBuffer, 1075 InputBufferOffsets, 1076 DeviceOffset); 1077 } 1078 1079 _Must_inspect_result_ 1080 NTSTATUS 1081 FxIoTargetSendIoctl( 1082 __in 1083 PFX_DRIVER_GLOBALS FxDriverGlobals, 1084 __in 1085 WDFIOTARGET IoTarget, 1086 __in_opt 1087 WDFREQUEST Request, 1088 __in 1089 ULONG Ioctl, 1090 __in 1091 BOOLEAN Internal, 1092 __in_opt 1093 PWDF_MEMORY_DESCRIPTOR InputBuffer, 1094 __in_opt 1095 PWDF_MEMORY_DESCRIPTOR OutputBuffer, 1096 __in_opt 1097 PWDF_REQUEST_SEND_OPTIONS RequestOptions, 1098 __out_opt 1099 PULONG_PTR BytesReturned 1100 ) 1101 /*++ 1102 1103 Routine Description: 1104 Sends an external or internal IOCTL to the target. If the optional request 1105 is specified, this function will use it's PIRP to send the request to the 1106 target. Both buffers are optional. 1107 1108 Arguments: 1109 IoTarget - the target to which the IOCTL is being sent 1110 1111 IOCTL - the device io control value 1112 1113 Internal - if TRUE, an internal IOCTL, if FALSE, a normal IOCTL 1114 1115 InputBuffer - optional. Can be one of the following: PMDL, PVOID, or WDFMEMORY 1116 1117 OutputBuffer - optional. Can be one of the following: PMDL, PVOID, or WDFMEMORY 1118 1119 RequestOptions - optional. Specifies a timeout to be used if the sent IO 1120 does not return within the time specified. 1121 1122 BytesReturned - number of bytes transfered 1123 1124 Return Value: 1125 NTSTATUS 1126 1127 --*/ 1128 { 1129 FxIoTarget* pTarget; 1130 FxRequestBuffer inputBuf, outputBuf; 1131 NTSTATUS status; 1132 1133 FxObjectHandleGetPtrAndGlobals(FxDriverGlobals, 1134 IoTarget, 1135 FX_TYPE_IO_TARGET, 1136 (PVOID*) &pTarget, 1137 &FxDriverGlobals); 1138 1139 // 1140 // Minimize the points of failure by using the stack instead of allocating 1141 // out of pool. For UMDF, request initialization can fail so we still need 1142 // to call initialize for FxSyncRequest. Initialization always succeeds for 1143 // KM. 1144 // 1145 FxIoContext context; 1146 FxSyncRequest request(FxDriverGlobals, &context, Request); 1147 1148 status = request.Initialize(); 1149 if (!NT_SUCCESS(status)) { 1150 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1151 "Failed to initialize FxSyncRequest for WDFIOTARGET " 1152 "0x%p", IoTarget); 1153 return status; 1154 } 1155 1156 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 1157 "enter: WDFIOTARGET 0x%p, WDFREQUEST 0x%p, IOCTL 0x%x, " 1158 "internal %d", IoTarget, Request, Ioctl, Internal); 1159 1160 // 1161 // Since we are synchronously waiting, we must be at passive 1162 // 1163 status = FxVerifierCheckIrqlLevel(FxDriverGlobals, PASSIVE_LEVEL); 1164 if (!NT_SUCCESS(status)) { 1165 return status; 1166 } 1167 1168 status = FxValidateRequestOptions(FxDriverGlobals, RequestOptions); 1169 if (!NT_SUCCESS(status)) { 1170 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1171 "invalid options, %!STATUS!", status); 1172 return status; 1173 } 1174 1175 if (InputBuffer != NULL) { 1176 // 1177 // This transcribes the client union into a local structure which we 1178 // can change w/out altering the client's buffer. 1179 // 1180 status = inputBuf.ValidateMemoryDescriptor(FxDriverGlobals, InputBuffer); 1181 if (!NT_SUCCESS(status)) { 1182 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1183 "invalid input buffer descriptor 0x%p, %!STATUS!", 1184 InputBuffer, status); 1185 return status; 1186 } 1187 } 1188 1189 if (OutputBuffer != NULL) { 1190 // 1191 // This transcribes the client union into a local structure which we 1192 // can change w/out altering the client's buffer. 1193 // 1194 status = outputBuf.ValidateMemoryDescriptor(FxDriverGlobals, OutputBuffer); 1195 if (!NT_SUCCESS(status)) { 1196 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1197 "invalid output buffer descriptor 0x%p, %!STATUS!", 1198 OutputBuffer, status); 1199 return status; 1200 } 1201 } 1202 1203 // 1204 // Format the next stack location 1205 // 1206 status = pTarget->FormatIoctlRequest( 1207 request.m_TrueRequest, Ioctl, Internal, &inputBuf, &outputBuf, NULL); 1208 1209 if (NT_SUCCESS(status)) { 1210 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 1211 "WDFIOTARGET 0x%p, WDFREQUEST 0x%p being submitted", 1212 IoTarget, 1213 request.m_TrueRequest->GetTraceObjectHandle()); 1214 1215 status = pTarget->SubmitSync(request.m_TrueRequest, RequestOptions); 1216 1217 if (BytesReturned != NULL) { 1218 *BytesReturned = request.m_TrueRequest->GetSubmitFxIrp()->GetInformation(); 1219 } 1220 } 1221 else { 1222 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1223 "could not format IOCTL 0x%x request, %!STATUS!", 1224 Ioctl, status); 1225 } 1226 1227 return status; 1228 } 1229 1230 static 1231 _Must_inspect_result_ 1232 NTSTATUS 1233 FxIoTargetFormatIoctl( 1234 __in 1235 PFX_DRIVER_GLOBALS FxDriverGlobals, 1236 __in 1237 WDFIOTARGET IoTarget, 1238 __in 1239 WDFREQUEST Request, 1240 __in 1241 ULONG Ioctl, 1242 __in 1243 BOOLEAN Internal, 1244 __in_opt 1245 WDFMEMORY InputBuffer, 1246 __in_opt 1247 PWDFMEMORY_OFFSET InputBufferOffsets, 1248 __in_opt 1249 WDFMEMORY OutputBuffer, 1250 __in_opt 1251 PWDFMEMORY_OFFSET OutputBufferOffsets 1252 ) 1253 /*++ 1254 1255 Routine Description: 1256 Formats a request as an IOCTL to be sent to the specified target. Upon 1257 success, this will take a reference on each of the WDFMEMORY handles that 1258 are passed in. This reference will be released when one of the following 1259 occurs: 1260 1) the request is completed through WdfRequestComplete 1261 2) the request is reused through WdfRequestReuse 1262 3) the request is reformatted through any target format DDI 1263 1264 Arguments: 1265 IoTarget - the target to which the IOCTL will be formatted for 1266 1267 Request - the request which will be formatted 1268 1269 IOCTL - the device IO control itself to be used 1270 1271 Internal - if TRUE, an internal IOCTL, if FALSE, a normal IOCTL 1272 1273 InputBuffer - optional. If specified, a reference counted memory handle to 1274 be placed in the next stack location. 1275 1276 InputBufferOffsets - optional. If specified, it can override the starting 1277 offset of the buffer and the length of the buffer used 1278 1279 OutputBuffer - optional. If specified, a reference counted memory handle to 1280 be placed in the next stack location. 1281 1282 OutputBufferOffsets - optional. If specified, it can override the starting 1283 offset of the buffer and the length of the buffer used 1284 1285 Return Value: 1286 NTSTATUS 1287 1288 --*/ 1289 { 1290 FxIoTarget *pTarget; 1291 FxRequest *pRequest; 1292 IFxMemory *pInputMemory, *pOutputMemory; 1293 FxRequestBuffer inputBuf, outputBuf; 1294 NTSTATUS status; 1295 1296 FxObjectHandleGetPtrAndGlobals(FxDriverGlobals, 1297 IoTarget, 1298 FX_TYPE_IO_TARGET, 1299 (PVOID*) &pTarget, 1300 &FxDriverGlobals); 1301 1302 DoTraceLevelMessage( 1303 FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 1304 "enter: WDFIOTARGET 0x%p, WDFREQUEST 0x%p, IOCTL 0x%x, internal %d, input " 1305 "WDFMEMORY 0x%p, output WDFMEMORY 0x%p", 1306 IoTarget, Request, Ioctl, Internal, InputBuffer, OutputBuffer); 1307 1308 FxObjectHandleGetPtr(FxDriverGlobals, 1309 Request, 1310 FX_TYPE_REQUEST, 1311 (PVOID*) &pRequest); 1312 1313 if (InputBuffer != NULL) { 1314 FxObjectHandleGetPtr(FxDriverGlobals, 1315 InputBuffer, 1316 IFX_TYPE_MEMORY, 1317 (PVOID*) &pInputMemory); 1318 1319 status = pInputMemory->ValidateMemoryOffsets(InputBufferOffsets); 1320 if (!NT_SUCCESS(status)) { 1321 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1322 "Invalid input memory offsets, %!STATUS!", 1323 status); 1324 return status; 1325 } 1326 1327 // 1328 // This transcribes the client union into a local structure which we 1329 // can change w/out altering the client's buffer. 1330 // 1331 inputBuf.SetMemory(pInputMemory, InputBufferOffsets); 1332 } 1333 1334 if (OutputBuffer != NULL) { 1335 FxObjectHandleGetPtr(FxDriverGlobals, 1336 OutputBuffer, 1337 IFX_TYPE_MEMORY, 1338 (PVOID*) &pOutputMemory); 1339 1340 status = pOutputMemory->ValidateMemoryOffsets(OutputBufferOffsets); 1341 if (!NT_SUCCESS(status)) { 1342 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1343 "Invalid output memory offsets, %!STATUS!", 1344 status); 1345 return status; 1346 } 1347 1348 // 1349 // This transcribes the client union into a local structure which we 1350 // can change w/out altering the client's buffer. 1351 // 1352 outputBuf.SetMemory(pOutputMemory, OutputBufferOffsets); 1353 } 1354 1355 // 1356 // format the next stack location 1357 // 1358 status = pTarget->FormatIoctlRequest( 1359 pRequest, Ioctl, Internal, &inputBuf, &outputBuf, NULL); 1360 1361 if (NT_SUCCESS(status)) { 1362 FxRequestContext* pContext; 1363 1364 // 1365 // Upon a successful format, a FxRequestContext will have been 1366 // associated with the FxRequest 1367 // 1368 pContext = pRequest->GetContext(); 1369 1370 pContext->m_CompletionParams.Parameters.Ioctl.IoControlCode = Ioctl; 1371 1372 if (Internal) { 1373 pContext->m_CompletionParams.Type = WdfRequestTypeDeviceControlInternal; 1374 } 1375 else { 1376 pContext->m_CompletionParams.Type = WdfRequestTypeDeviceControl; 1377 } 1378 1379 pContext->m_CompletionParams.Parameters.Ioctl.Input.Buffer = InputBuffer; 1380 if (InputBufferOffsets != NULL) { 1381 pContext->m_CompletionParams.Parameters.Ioctl.Input.Offset = 1382 InputBufferOffsets->BufferOffset; 1383 } 1384 1385 pContext->m_CompletionParams.Parameters.Ioctl.Output.Buffer = OutputBuffer; 1386 if (OutputBufferOffsets != NULL) { 1387 pContext->m_CompletionParams.Parameters.Ioctl.Output.Offset = 1388 OutputBufferOffsets->BufferOffset; 1389 } 1390 } 1391 1392 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 1393 "Exit WDFIOTARGET 0x%p, WDFREQUEST 0x%p, %!STATUS!", 1394 IoTarget, Request, status); 1395 1396 return status; 1397 } 1398 1399 _Must_inspect_result_ 1400 __drv_maxIRQL(PASSIVE_LEVEL) 1401 NTSTATUS 1402 STDCALL 1403 WDFEXPORT(WdfIoTargetSendIoctlSynchronously)( 1404 __in 1405 PWDF_DRIVER_GLOBALS DriverGlobals, 1406 __in 1407 WDFIOTARGET IoTarget, 1408 __in_opt 1409 WDFREQUEST Request, 1410 __in 1411 ULONG Ioctl, 1412 __in_opt 1413 PWDF_MEMORY_DESCRIPTOR InputBuffer, 1414 __in_opt 1415 PWDF_MEMORY_DESCRIPTOR OutputBuffer, 1416 __in_opt 1417 PWDF_REQUEST_SEND_OPTIONS RequestOptions, 1418 __out_opt 1419 PULONG_PTR BytesReturned 1420 ) 1421 { 1422 DDI_ENTRY(); 1423 1424 return FxIoTargetSendIoctl( 1425 GetFxDriverGlobals(DriverGlobals), 1426 IoTarget, 1427 Request, 1428 Ioctl, 1429 FALSE, 1430 InputBuffer, 1431 OutputBuffer, 1432 RequestOptions, 1433 BytesReturned 1434 ); 1435 } 1436 1437 _Must_inspect_result_ 1438 __drv_maxIRQL(DISPATCH_LEVEL) 1439 NTSTATUS 1440 STDCALL 1441 WDFEXPORT(WdfIoTargetFormatRequestForIoctl)( 1442 __in 1443 PWDF_DRIVER_GLOBALS DriverGlobals, 1444 __in 1445 WDFIOTARGET IoTarget, 1446 __in 1447 WDFREQUEST Request, 1448 __in 1449 ULONG Ioctl, 1450 __in_opt 1451 WDFMEMORY InputBuffer, 1452 __in_opt 1453 PWDFMEMORY_OFFSET InputBufferOffsets, 1454 __in_opt 1455 WDFMEMORY OutputBuffer, 1456 __in_opt 1457 PWDFMEMORY_OFFSET OutputBufferOffsets 1458 ) 1459 { 1460 DDI_ENTRY(); 1461 1462 return FxIoTargetFormatIoctl(GetFxDriverGlobals(DriverGlobals), 1463 IoTarget, 1464 Request, 1465 Ioctl, 1466 FALSE, 1467 InputBuffer, 1468 InputBufferOffsets, 1469 OutputBuffer, 1470 OutputBufferOffsets); 1471 } 1472 1473 _Must_inspect_result_ 1474 __drv_maxIRQL(PASSIVE_LEVEL) 1475 NTSTATUS 1476 STDCALL 1477 WDFEXPORT(WdfIoTargetSendInternalIoctlSynchronously)( 1478 __in 1479 PWDF_DRIVER_GLOBALS DriverGlobals, 1480 __in 1481 WDFIOTARGET IoTarget, 1482 __in_opt 1483 WDFREQUEST Request, 1484 __in 1485 ULONG Ioctl, 1486 __in_opt 1487 PWDF_MEMORY_DESCRIPTOR InputBuffer, 1488 __in_opt 1489 PWDF_MEMORY_DESCRIPTOR OutputBuffer, 1490 __in_opt 1491 PWDF_REQUEST_SEND_OPTIONS RequestOptions, 1492 __out_opt 1493 PULONG_PTR BytesReturned 1494 ) 1495 { 1496 DDI_ENTRY(); 1497 1498 return FxIoTargetSendIoctl( 1499 GetFxDriverGlobals(DriverGlobals), 1500 IoTarget, 1501 Request, 1502 Ioctl, 1503 TRUE, 1504 InputBuffer, 1505 OutputBuffer, 1506 RequestOptions, 1507 BytesReturned 1508 ); 1509 } 1510 1511 _Must_inspect_result_ 1512 __drv_maxIRQL(DISPATCH_LEVEL) 1513 NTSTATUS 1514 STDCALL 1515 WDFEXPORT(WdfIoTargetFormatRequestForInternalIoctl)( 1516 __in 1517 PWDF_DRIVER_GLOBALS DriverGlobals, 1518 __in 1519 WDFIOTARGET IoTarget, 1520 __in 1521 WDFREQUEST Request, 1522 __in 1523 ULONG Ioctl, 1524 __in_opt 1525 WDFMEMORY InputBuffer, 1526 __in_opt 1527 PWDFMEMORY_OFFSET InputBufferOffsets, 1528 __in_opt 1529 WDFMEMORY OutputBuffer, 1530 __in_opt 1531 PWDFMEMORY_OFFSET OutputBufferOffsets 1532 ) 1533 { 1534 DDI_ENTRY(); 1535 1536 return FxIoTargetFormatIoctl(GetFxDriverGlobals(DriverGlobals), 1537 IoTarget, 1538 Request, 1539 Ioctl, 1540 TRUE, 1541 InputBuffer, 1542 InputBufferOffsets, 1543 OutputBuffer, 1544 OutputBufferOffsets); 1545 } 1546 1547 _Must_inspect_result_ 1548 __drv_maxIRQL(PASSIVE_LEVEL) 1549 NTSTATUS 1550 STDCALL 1551 WDFEXPORT(WdfIoTargetSendInternalIoctlOthersSynchronously)( 1552 __in 1553 PWDF_DRIVER_GLOBALS DriverGlobals, 1554 __in 1555 WDFIOTARGET IoTarget, 1556 __in_opt 1557 WDFREQUEST Request, 1558 __in 1559 ULONG Ioctl, 1560 __in_opt 1561 PWDF_MEMORY_DESCRIPTOR OtherArg1, 1562 __in_opt 1563 PWDF_MEMORY_DESCRIPTOR OtherArg2, 1564 __in_opt 1565 PWDF_MEMORY_DESCRIPTOR OtherArg4, 1566 __in_opt 1567 PWDF_REQUEST_SEND_OPTIONS RequestOptions, 1568 __out_opt 1569 PULONG_PTR BytesReturned 1570 ) 1571 /*++ 1572 1573 Routine Description: 1574 Sends an internal IOCTL to the target synchronously. Since all 3 buffers can 1575 be used, we cannot overload WdfIoTargetSendInternalIoctlSynchronously since 1576 it can only take 2 buffers. 1577 1578 Arguments: 1579 IoTarget - the target to which the request will be sent 1580 1581 Request - optional. If specified, the request's PIRP will be used to send 1582 the i/o to the target. 1583 1584 Ioctl - internal ioctl value to send 1585 1586 OtherArg1 1587 OtherArg2 1588 OtherArg4 - arguments to use in the stack locations's Others field. There 1589 is no OtherArg3 because 3 is where the IOCTL value is written. 1590 All buffers are optional. 1591 1592 RequestOptions - optional. If specified, the timeout indicated will be used 1593 if the request exceeds the timeout. 1594 1595 BytesReturned - the number of bytes returned by the target 1596 1597 Return Value: 1598 NTSTATUS 1599 1600 --*/ 1601 { 1602 DDI_ENTRY(); 1603 1604 PFX_DRIVER_GLOBALS pFxDriverGlobals; 1605 FxIoTarget* pTarget; 1606 FxRequestBuffer args[FX_REQUEST_NUM_OTHER_PARAMS]; 1607 NTSTATUS status; 1608 1609 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 1610 IoTarget, 1611 FX_TYPE_IO_TARGET, 1612 (PVOID*) &pTarget, 1613 &pFxDriverGlobals); 1614 1615 // 1616 // Minimize the points of failure by using the stack instead of allocating 1617 // out of pool. For UMDF, request initialization can fail so we still need 1618 // to call initialize for FxSyncRequest. Initialization always succeeds for 1619 // KM. 1620 // 1621 FxInternalIoctlOthersContext context; 1622 FxSyncRequest request(pFxDriverGlobals, &context, Request); 1623 1624 status = request.Initialize(); 1625 if (!NT_SUCCESS(status)) { 1626 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1627 "Failed to initialize FxSyncRequest for WDFIOTARGET " 1628 "0x%p", IoTarget); 1629 return status; 1630 } 1631 1632 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 1633 "enter: WDFIOTARGET 0x%p, WDFREQUEST 0x%p, IOCTL 0x%x, Args %p %p %p", 1634 IoTarget, Request, Ioctl, OtherArg1, OtherArg2, OtherArg4); 1635 1636 // 1637 // Since we are waiting synchronously, we must be at pasisve 1638 // 1639 status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); 1640 if (!NT_SUCCESS(status)) { 1641 return status; 1642 } 1643 1644 status = FxValidateRequestOptions(pFxDriverGlobals, RequestOptions); 1645 if (!NT_SUCCESS(status)) { 1646 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1647 "Invalid options, %!STATUS!", status); 1648 return status; 1649 } 1650 1651 ULONG i; 1652 1653 i = 0; 1654 if (OtherArg1 != NULL) { 1655 // 1656 // This transcribes the client union into a local structure which we 1657 // can change w/out altering the client's buffer. 1658 // 1659 status = args[i].ValidateMemoryDescriptor(pFxDriverGlobals, OtherArg1); 1660 if (!NT_SUCCESS(status)) { 1661 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1662 "invalid OtherArg1 buffer descriptor 0x%p, %!STATUS!", 1663 OtherArg1, status); 1664 return status; 1665 } 1666 } 1667 1668 i++; 1669 if (OtherArg2 != NULL) { 1670 // 1671 // This transcribes the client union into a local structure which we 1672 // can change w/out altering the client's buffer. 1673 // 1674 status = args[i].ValidateMemoryDescriptor(pFxDriverGlobals, OtherArg2); 1675 if (!NT_SUCCESS(status)) { 1676 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1677 "invalid OtherArg2 buffer descriptor 0x%p, %!STATUS!", 1678 OtherArg2, status); 1679 return status; 1680 } 1681 } 1682 1683 i++; 1684 if (OtherArg4 != NULL) { 1685 // 1686 // This transcribes the client union into a local structure which we 1687 // can change w/out altering the client's buffer. 1688 // 1689 status = args[i].ValidateMemoryDescriptor(pFxDriverGlobals, OtherArg4); 1690 if (!NT_SUCCESS(status)) { 1691 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1692 "invalid OtherArg4 buffer descriptor 0x%p, %!STATUS!", 1693 OtherArg4, status); 1694 return status; 1695 } 1696 } 1697 1698 // 1699 // Format the next stack location 1700 // 1701 status = pTarget->FormatInternalIoctlOthersRequest(request.m_TrueRequest, 1702 Ioctl, 1703 args); 1704 1705 if (NT_SUCCESS(status)) { 1706 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 1707 "WDFIOTARGET 0x%p, WDFREQUEST 0x%p being submitted", 1708 IoTarget, 1709 request.m_TrueRequest->GetTraceObjectHandle()); 1710 1711 status = pTarget->SubmitSync(request.m_TrueRequest, RequestOptions); 1712 1713 if (BytesReturned != NULL) { 1714 *BytesReturned = request.m_TrueRequest->GetSubmitFxIrp()->GetInformation(); 1715 } 1716 } 1717 else { 1718 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1719 "Could not format IOCTL 0x%x request, %!STATUS!", 1720 Ioctl, status); 1721 } 1722 1723 return status; 1724 } 1725 1726 _Must_inspect_result_ 1727 __drv_maxIRQL(DISPATCH_LEVEL) 1728 NTSTATUS 1729 STDCALL 1730 WDFEXPORT(WdfIoTargetFormatRequestForInternalIoctlOthers)( 1731 __in 1732 PWDF_DRIVER_GLOBALS DriverGlobals, 1733 __in 1734 WDFIOTARGET IoTarget, 1735 __in 1736 WDFREQUEST Request, 1737 __in 1738 ULONG Ioctl, 1739 __in_opt 1740 WDFMEMORY OtherArg1, 1741 __in_opt 1742 PWDFMEMORY_OFFSET OtherArg1Offsets, 1743 __in_opt 1744 WDFMEMORY OtherArg2, 1745 __in_opt 1746 PWDFMEMORY_OFFSET OtherArg2Offsets, 1747 __in_opt 1748 WDFMEMORY OtherArg4, 1749 __in_opt 1750 PWDFMEMORY_OFFSET OtherArg4Offsets 1751 ) 1752 /*++ 1753 1754 Routine Description: 1755 Formats an internal IOCTL so that it can sent to the target. Since all 3 1756 buffers can be used, we cannot overload 1757 WdfIoTargetFormatRequestForInternalIoctlOthers since it can only take 2 buffers. 1758 1759 Upon success, this will take a reference on each of the WDFMEMORY handles that 1760 are passed in. This reference will be released when one of the following 1761 occurs: 1762 1) the request is completed through WdfRequestComplete 1763 2) the request is reused through WdfRequestReuse 1764 3) the request is reformatted through any target format DDI 1765 1766 Arguments: 1767 IoTarget - the target to which the request will be sent 1768 1769 Request - the request to be formatted 1770 1771 Ioctl - internal ioctl value to send 1772 1773 OtherArg1 1774 OtherArg2 1775 OtherArg4 - arguments to use in the stack locations's Others field. There 1776 is no OtherArg3 because 3 is where the IOCTL value is written. 1777 All buffers are optional 1778 1779 OterhArgXOffsets - offset into each buffer which can override the starting 1780 offset of the buffer. Length does not matter since 1781 there is no way of generically describing the length of 1782 each of the 3 buffers in the PIRP 1783 1784 Return Value: 1785 NTSTATUS 1786 1787 --*/ 1788 { 1789 DDI_ENTRY(); 1790 1791 PFX_DRIVER_GLOBALS pFxDriverGlobals; 1792 FxIoTarget *pTarget; 1793 FxRequest *pRequest; 1794 IFxMemory *pMemory[FX_REQUEST_NUM_OTHER_PARAMS]; 1795 FxRequestBuffer args[FX_REQUEST_NUM_OTHER_PARAMS]; 1796 WDFMEMORY memoryHandles[FX_REQUEST_NUM_OTHER_PARAMS]; 1797 PWDFMEMORY_OFFSET offsets[FX_REQUEST_NUM_OTHER_PARAMS]; 1798 NTSTATUS status; 1799 ULONG i; 1800 FxInternalIoctlParams InternalIoctlParams; 1801 1802 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 1803 IoTarget, 1804 FX_TYPE_IO_TARGET, 1805 (PVOID*) &pTarget, 1806 &pFxDriverGlobals); 1807 1808 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 1809 "Enter: WDFIOTARGET 0x%p, WDFREQUEST 0x%p, IOCTL 0x%x, " 1810 "WDFMEMORY 1 0x%p, 2 0x%p, 3 0x%p", 1811 IoTarget, Request, Ioctl, OtherArg1, OtherArg2, 1812 OtherArg4); 1813 1814 FxObjectHandleGetPtr(pFxDriverGlobals, 1815 Request, 1816 FX_TYPE_REQUEST, 1817 (PVOID*) &pRequest); 1818 1819 i = 0; 1820 InternalIoctlParams.Argument1 = memoryHandles[i] = OtherArg1; 1821 offsets[i] = OtherArg1Offsets; 1822 1823 InternalIoctlParams.Argument2 = memoryHandles[++i] = OtherArg2; 1824 offsets[i] = OtherArg2Offsets; 1825 1826 InternalIoctlParams.Argument4 = memoryHandles[++i] = OtherArg4; 1827 offsets[i] = OtherArg4Offsets; 1828 1829 for (i = 0; i < FX_REQUEST_NUM_OTHER_PARAMS; i++) { 1830 if (memoryHandles[i] != NULL) { 1831 1832 FxObjectHandleGetPtr(pFxDriverGlobals, 1833 memoryHandles[i], 1834 IFX_TYPE_MEMORY, 1835 (PVOID*) &pMemory[i]); 1836 1837 status = pMemory[i]->ValidateMemoryOffsets(offsets[i]); 1838 if (!NT_SUCCESS(status)) { 1839 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, 1840 "Invalid OtherArg%d memory offsets, %!STATUS!", 1841 i+1, status); 1842 return status; 1843 } 1844 1845 // 1846 // This transcribes the client union into a local structure which we 1847 // can change w/out altering the client's buffer. 1848 // 1849 args[i].SetMemory(pMemory[i], offsets[i]); 1850 } 1851 } 1852 1853 status = pTarget->FormatInternalIoctlOthersRequest(pRequest, Ioctl, args); 1854 if (NT_SUCCESS(status)) { 1855 pRequest->GetContext()->FormatOtherParams(&InternalIoctlParams); 1856 } 1857 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 1858 "Exit: WDFIOTARGET %p, WDFREQUEST %p, IOCTL 0x%x, " 1859 "Arg Handles %p %p %p, status %!STATUS!", 1860 IoTarget, Request, Ioctl, OtherArg1, OtherArg2, 1861 OtherArg4, status); 1862 1863 return status; 1864 } 1865 1866 _Must_inspect_result_ 1867 _IRQL_requires_max_(DISPATCH_LEVEL) 1868 NTSTATUS 1869 STDCALL 1870 WDFEXPORT(WdfIoTargetSelfAssignDefaultIoQueue)( 1871 _In_ 1872 PWDF_DRIVER_GLOBALS DriverGlobals, 1873 _In_ 1874 WDFIOTARGET IoTarget, 1875 _In_ 1876 WDFQUEUE Queue 1877 ) 1878 1879 /*++ 1880 1881 Routine Description: 1882 1883 Assigns a default queue for the Self IO Target. 1884 1885 By default the IO sent to the Self IO Target is dispatched ot the 1886 client's default / top level queue. 1887 1888 This routine assigns a default queue for the Intenral I/O target. 1889 If a client calls this API, all the I/O directed to the Self IO target 1890 is dispatched to the queue specified. 1891 1892 Arguments: 1893 1894 IoTarget - Handle to the Self Io Target. 1895 1896 Queue - Handle to a queue that is being assigned as the default queue for 1897 the Self io target. 1898 1899 Returns: 1900 1901 NTSTATUS 1902 1903 --*/ 1904 1905 { 1906 DDI_ENTRY(); 1907 1908 PFX_DRIVER_GLOBALS pGlobals; 1909 NTSTATUS status; 1910 FxIoTargetSelf* pTargetSelf; 1911 FxDevice* pDevice; 1912 FxIoQueue* pFxIoQueue; 1913 1914 pDevice = NULL; 1915 pFxIoQueue = NULL; 1916 1917 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 1918 IoTarget, 1919 FX_TYPE_IO_TARGET_SELF, 1920 (PVOID *) &pTargetSelf, 1921 &pGlobals); 1922 1923 pDevice = pTargetSelf->GetDevice(); 1924 1925 // 1926 // Validate the Queue handle 1927 // 1928 FxObjectHandleGetPtr(pGlobals, 1929 Queue, 1930 FX_TYPE_QUEUE, 1931 (PVOID*)&pFxIoQueue); 1932 1933 if (pDevice != pFxIoQueue->GetDevice()) { 1934 status = STATUS_INVALID_DEVICE_REQUEST; 1935 1936 DoTraceLevelMessage( 1937 pGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 1938 "Input WDFQUEUE 0x%p belongs to WDFDEVICE 0x%p, but " 1939 "Self Io Target 0x%p corresponds to the WDFDEVICE 0x%p, %!STATUS!", 1940 Queue, pFxIoQueue->GetDevice()->GetHandle(), IoTarget, 1941 pDevice->GetHandle(), status); 1942 1943 return status; 1944 } 1945 1946 if (pDevice->IsLegacy()) { 1947 // 1948 // This is a controldevice. Make sure the create is called after the device 1949 // is initialized and ready to accept I/O. 1950 // 1951 MxDeviceObject deviceObject(pDevice->GetDeviceObject()); 1952 if ((deviceObject.GetFlags() & DO_DEVICE_INITIALIZING) == 0x0) { 1953 1954 status = STATUS_INVALID_DEVICE_STATE; 1955 DoTraceLevelMessage( 1956 pGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 1957 "Queue cannot be configured for automatic dispatching" 1958 " after WdfControlDeviceFinishInitializing" 1959 "is called on the WDFDEVICE %p is called %!STATUS!", 1960 pDevice->GetHandle(), 1961 status); 1962 return status; 1963 } 1964 } 1965 else { 1966 // 1967 // This is either FDO or PDO. Make sure it's not started yet. 1968 // 1969 if (pDevice->GetDevicePnpState() != WdfDevStatePnpInit) { 1970 status = STATUS_INVALID_DEVICE_STATE; 1971 DoTraceLevelMessage( 1972 pGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, 1973 "Queue cannot be configured for automatic dispatching" 1974 "after the WDFDEVICE %p is started, %!STATUS!", 1975 pDevice->GetHandle(), status); 1976 return status; 1977 } 1978 } 1979 1980 pTargetSelf->SetDispatchQueue(pFxIoQueue); 1981 1982 return STATUS_SUCCESS; 1983 } 1984 1985 __drv_maxIRQL(DISPATCH_LEVEL) 1986 HANDLE 1987 STDCALL 1988 WDFEXPORT(WdfIoTargetWdmGetTargetFileHandle)( 1989 __in 1990 PWDF_DRIVER_GLOBALS DriverGlobals, 1991 __in 1992 WDFIOTARGET IoTarget 1993 ) 1994 /*++ 1995 1996 Routine Description: 1997 Returns the file handle that the target represents. For KMDF, the handle is a kernel 1998 handle, so it is not tied to any process context. For UMDF it is a Win32 handle opened 1999 in the host process context. Not all targets have a file handle associated with them, 2000 so NULL is a valid return value that does not indicate error. 2001 2002 Arguments: 2003 IoTarget - target whose file handle is being returned 2004 2005 Return Value: 2006 A valid kernel/win32 handle or NULL 2007 2008 --*/ 2009 { 2010 PFX_DRIVER_GLOBALS pFxDriverGlobals; 2011 FxIoTargetRemote* pTarget; 2012 PVOID handle; 2013 2014 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 2015 IoTarget, 2016 FX_TYPE_IO_TARGET_REMOTE, 2017 (PVOID*) &pTarget, 2018 &pFxDriverGlobals); 2019 2020 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 2021 "enter WDFIOTARGET 0x%p", IoTarget); 2022 2023 handle = pTarget->GetTargetHandle(); 2024 2025 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, 2026 "exit WDFIOTARGET 0x%p, WDM file handle 0x%p", 2027 IoTarget, handle); 2028 2029 return handle; 2030 } 2031 2032 2033 } // extern "C" 2034