1 /*-- 2 3 Copyright (C) Microsoft Corporation. All rights reserved. 4 5 Module Name: 6 7 ioctl.c 8 9 Abstract: 10 11 Include all funtions for processing IOCTLs 12 13 Environment: 14 15 kernel mode only 16 17 Notes: 18 19 20 Revision History: 21 22 --*/ 23 24 #include "stddef.h" 25 #include "string.h" 26 27 #include "ntddk.h" 28 #include "ntddstor.h" 29 #include "cdrom.h" 30 #include "ioctl.h" 31 #include "scratch.h" 32 #include "mmc.h" 33 34 35 #ifdef DEBUG_USE_WPP 36 #include "ioctl.tmh" 37 #endif 38 39 40 #define FirstDriveLetter 'C' 41 #define LastDriveLetter 'Z' 42 43 #if DBG 44 LPCSTR READ_DVD_STRUCTURE_FORMAT_STRINGS[DvdMaxDescriptor+1] = { 45 "Physical", 46 "Copyright", 47 "DiskKey", 48 "BCA", 49 "Manufacturer", 50 "Unknown" 51 }; 52 #endif // DBG 53 54 _IRQL_requires_max_(APC_LEVEL) 55 VOID 56 GetConfigurationDataConversionTypeAllToTypeOne( 57 _In_ FEATURE_NUMBER RequestedFeature, 58 _In_ PSCSI_REQUEST_BLOCK Srb, 59 _Out_ size_t * DataLength 60 ); 61 62 _IRQL_requires_max_(APC_LEVEL) 63 VOID 64 GetConfigurationDataSynthesize( 65 _In_reads_bytes_(InputBufferSize) PVOID InputBuffer, 66 _In_ ULONG InputBufferSize, 67 _Out_writes_bytes_(OutputBufferSize) PVOID OutputBuffer, 68 _In_ size_t OutputBufferSize, 69 _In_ FEATURE_NUMBER StartingFeature, 70 _In_ ULONG RequestType, 71 _Out_ size_t * DataLength 72 ); 73 74 _IRQL_requires_max_(APC_LEVEL) 75 PCDB 76 RequestGetScsiPassThroughCdb( 77 _In_ PIRP Irp 78 ); 79 80 #ifdef ALLOC_PRAGMA 81 82 #pragma alloc_text(PAGE, DeviceIsPlayActive) 83 #pragma alloc_text(PAGE, RequestHandleGetDvdRegion) 84 #pragma alloc_text(PAGE, RequestHandleReadTOC) 85 #pragma alloc_text(PAGE, RequestHandleReadTocEx) 86 #pragma alloc_text(PAGE, RequestHandleGetConfiguration) 87 #pragma alloc_text(PAGE, RequestHandleGetDriveGeometry) 88 #pragma alloc_text(PAGE, RequestHandleDiskVerify) 89 #pragma alloc_text(PAGE, RequestHandleCheckVerify) 90 #pragma alloc_text(PAGE, RequestHandleFakePartitionInfo) 91 #pragma alloc_text(PAGE, RequestHandleEjectionControl) 92 #pragma alloc_text(PAGE, RequestHandleEnableStreaming) 93 #pragma alloc_text(PAGE, RequestHandleSendOpcInformation) 94 #pragma alloc_text(PAGE, RequestHandleGetPerformance) 95 #pragma alloc_text(PAGE, RequestHandleMcnSyncFakeIoctl) 96 #pragma alloc_text(PAGE, RequestHandleLoadEjectMedia) 97 #pragma alloc_text(PAGE, RequestHandleReserveRelease) 98 #pragma alloc_text(PAGE, RequestHandlePersistentReserve) 99 #pragma alloc_text(PAGE, DeviceHandleRawRead) 100 #pragma alloc_text(PAGE, DeviceHandlePlayAudioMsf) 101 #pragma alloc_text(PAGE, DeviceHandleReadQChannel) 102 #pragma alloc_text(PAGE, ReadQChannel) 103 #pragma alloc_text(PAGE, DeviceHandlePauseAudio) 104 #pragma alloc_text(PAGE, DeviceHandleResumeAudio) 105 #pragma alloc_text(PAGE, DeviceHandleSeekAudioMsf) 106 #pragma alloc_text(PAGE, DeviceHandleStopAudio) 107 #pragma alloc_text(PAGE, DeviceHandleGetSetVolume) 108 #pragma alloc_text(PAGE, DeviceHandleReadDvdStructure) 109 #pragma alloc_text(PAGE, ReadDvdStructure) 110 #pragma alloc_text(PAGE, DeviceHandleDvdEndSession) 111 #pragma alloc_text(PAGE, DeviceHandleDvdStartSessionReadKey) 112 #pragma alloc_text(PAGE, DvdStartSessionReadKey) 113 #pragma alloc_text(PAGE, DeviceHandleDvdSendKey) 114 #pragma alloc_text(PAGE, DvdSendKey) 115 #pragma alloc_text(PAGE, DeviceHandleSetReadAhead) 116 #pragma alloc_text(PAGE, DeviceHandleSetSpeed) 117 #pragma alloc_text(PAGE, RequestHandleExclusiveAccessQueryLockState) 118 #pragma alloc_text(PAGE, RequestHandleExclusiveAccessLockDevice) 119 #pragma alloc_text(PAGE, RequestHandleExclusiveAccessUnlockDevice) 120 #pragma alloc_text(PAGE, RequestHandleScsiPassThrough) 121 #pragma alloc_text(PAGE, RequestGetScsiPassThroughCdb) 122 #pragma alloc_text(PAGE, GetConfigurationDataConversionTypeAllToTypeOne) 123 #pragma alloc_text(PAGE, GetConfigurationDataSynthesize) 124 125 #endif 126 127 NTSTATUS 128 RequestHandleUnknownIoctl( 129 _In_ WDFDEVICE Device, 130 _In_ WDFREQUEST Request 131 ) 132 /*++ 133 134 Routine Description: 135 136 All unknown IOCTLs will be forward to lower level driver. 137 138 Arguments: 139 140 Device - device object 141 Request - request to be handled 142 143 Return Value: 144 145 NTSTATUS 146 147 --*/ 148 { 149 NTSTATUS status = STATUS_UNSUCCESSFUL; 150 PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); 151 PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request); 152 BOOLEAN syncRequired = requestContext->SyncRequired; 153 154 ULONG sendOptionsFlags = 0; 155 BOOLEAN requestSent = FALSE; 156 157 WdfRequestFormatRequestUsingCurrentType(Request); 158 159 if (syncRequired) 160 { 161 sendOptionsFlags = WDF_REQUEST_SEND_OPTION_SYNCHRONOUS; 162 } 163 else 164 { 165 WdfRequestSetCompletionRoutine(Request, RequestDummyCompletionRoutine, NULL); 166 } 167 168 status = RequestSend(deviceExtension, 169 Request, 170 deviceExtension->IoTarget, 171 sendOptionsFlags, 172 &requestSent); 173 174 if (requestSent) 175 { 176 if (syncRequired) 177 { 178 // the request needs to be completed here. 179 RequestCompletion(deviceExtension, Request, status, WdfRequestGetInformation(Request)); 180 } 181 } 182 else 183 { 184 // failed to send the request to IoTarget 185 RequestCompletion(deviceExtension, Request, status, WdfRequestGetInformation(Request)); 186 } 187 188 return status; 189 } 190 191 _IRQL_requires_max_(APC_LEVEL) 192 BOOLEAN 193 DeviceIsPlayActive( 194 _In_ WDFDEVICE Device 195 ) 196 /*++ 197 198 Routine Description: 199 200 This routine determines if the cd is currently playing music. 201 202 Arguments: 203 204 Device - Device object. 205 206 Return Value: 207 208 BOOLEAN - TRUE if the device is playing music. 209 210 --*/ 211 { 212 NTSTATUS status = STATUS_SUCCESS; 213 PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); 214 PSUB_Q_CURRENT_POSITION currentBuffer; 215 size_t bytesRead = 0; 216 217 PAGED_CODE (); 218 219 // if we don't think it is playing audio, don't bother checking. 220 if (!deviceExtension->DeviceAdditionalData.PlayActive) 221 { 222 return FALSE; 223 } 224 225 // Allocate the required memory 226 NT_ASSERT(sizeof(SUB_Q_CURRENT_POSITION) >= sizeof(CDROM_SUB_Q_DATA_FORMAT)); 227 currentBuffer = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, 228 sizeof(SUB_Q_CURRENT_POSITION), 229 CDROM_TAG_PLAY_ACTIVE); 230 if (currentBuffer == NULL) 231 { 232 return FALSE; 233 } 234 235 // set the options in the output buffer format 236 ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Format = IOCTL_CDROM_CURRENT_POSITION; 237 ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Track = 0; 238 239 // Send SCSI command to read Q Channel information. 240 status = ReadQChannel(deviceExtension, 241 NULL, 242 currentBuffer, 243 sizeof(CDROM_SUB_Q_DATA_FORMAT), 244 currentBuffer, 245 sizeof(SUB_Q_CURRENT_POSITION), 246 &bytesRead); 247 248 if (!NT_SUCCESS(status)) 249 { 250 ExFreePool(currentBuffer); 251 return FALSE; 252 } 253 254 // update the playactive flag appropriately 255 if (currentBuffer->Header.AudioStatus == AUDIO_STATUS_IN_PROGRESS) 256 { 257 deviceExtension->DeviceAdditionalData.PlayActive = TRUE; 258 } 259 else 260 { 261 deviceExtension->DeviceAdditionalData.PlayActive = FALSE; 262 } 263 264 ExFreePool(currentBuffer); 265 266 return deviceExtension->DeviceAdditionalData.PlayActive; 267 } 268 269 NTSTATUS 270 RequestHandleGetInquiryData( 271 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 272 _In_ WDFREQUEST Request, 273 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 274 _Out_ size_t * DataLength) 275 /*++ 276 277 Routine Description: 278 279 Handler for IOCTL_CDROM_GET_INQUIRY_DATA 280 281 Arguments: 282 283 DeviceExtension - device context 284 Request - request to be handled 285 RequestParameters - request parameter 286 DataLength - transferred data length 287 288 Return Value: 289 290 NTSTATUS 291 292 --*/ 293 { 294 NTSTATUS status = STATUS_SUCCESS; 295 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); 296 297 *DataLength = 0; 298 299 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength == 0) 300 { 301 status = STATUS_BUFFER_TOO_SMALL; 302 } 303 else 304 { 305 PVOID outputBuffer = NULL; 306 307 *DataLength = min(cdData->CachedInquiryDataByteCount, 308 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength); 309 310 status = WdfRequestRetrieveOutputBuffer(Request, 311 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 312 &outputBuffer, 313 NULL); 314 315 if (NT_SUCCESS(status) && 316 (outputBuffer != NULL)) 317 { 318 // Always copy as much data as possible 319 RtlCopyMemory(outputBuffer, 320 cdData->CachedInquiryData, 321 *DataLength); 322 } 323 324 // and finally decide between two possible status values 325 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < cdData->CachedInquiryDataByteCount) 326 { 327 status = STATUS_BUFFER_OVERFLOW; 328 } 329 } 330 331 return status; 332 } 333 334 335 NTSTATUS 336 RequestHandleGetMediaTypeEx( 337 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 338 _In_ WDFREQUEST Request, 339 _Out_ size_t * DataLength 340 ) 341 /*++ 342 343 Routine Description: 344 345 Handler for IOCTL_STORAGE_GET_MEDIA_TYPES_EX 346 347 Arguments: 348 349 DeviceExtension - device context 350 Request - request to be handled 351 DataLength - transferred data length 352 353 Return Value: 354 355 NTSTATUS 356 357 --*/ 358 { 359 NTSTATUS status = STATUS_SUCCESS; 360 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); 361 362 PGET_MEDIA_TYPES mediaTypes = NULL; 363 PDEVICE_MEDIA_INFO mediaInfo = NULL; //&mediaTypes->MediaInfo[0]; 364 ULONG sizeNeeded = 0; 365 PZERO_POWER_ODD_INFO zpoddInfo = DeviceExtension->ZeroPowerODDInfo; 366 367 *DataLength = 0; 368 369 // Must run below dispatch level. 370 if (KeGetCurrentIrql() >= DISPATCH_LEVEL) 371 { 372 NT_ASSERT(FALSE); 373 return STATUS_INVALID_LEVEL; 374 } 375 376 sizeNeeded = sizeof(GET_MEDIA_TYPES); 377 378 // IsMmc is static... 379 if (cdData->Mmc.IsMmc) 380 { 381 sizeNeeded += sizeof(DEVICE_MEDIA_INFO) * 1; // return two media types 382 } 383 384 status = WdfRequestRetrieveOutputBuffer(Request, 385 sizeNeeded, 386 (PVOID*)&mediaTypes, 387 NULL); 388 389 if (NT_SUCCESS(status) && 390 (mediaTypes != NULL)) 391 { 392 mediaInfo = &mediaTypes->MediaInfo[0]; 393 394 RtlZeroMemory(mediaTypes, sizeNeeded); 395 396 // ISSUE-2000/5/11-henrygab - need to update GET_MEDIA_TYPES_EX 397 398 mediaTypes->DeviceType = cdData->DriveDeviceType; 399 400 mediaTypes->MediaInfoCount = 1; 401 mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = CD_ROM; 402 mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = 1; 403 mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_READ_ONLY; 404 mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart = DeviceExtension->DiskGeometry.Cylinders.QuadPart; 405 mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder = DeviceExtension->DiskGeometry.TracksPerCylinder; 406 mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack = DeviceExtension->DiskGeometry.SectorsPerTrack; 407 mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = DeviceExtension->DiskGeometry.BytesPerSector; 408 409 if (cdData->Mmc.IsMmc) 410 { 411 // also report a removable disk 412 mediaTypes->MediaInfoCount += 1; 413 414 mediaInfo++; 415 mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = RemovableMedia; 416 mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = 1; 417 mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_READ_WRITE; 418 mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart = DeviceExtension->DiskGeometry.Cylinders.QuadPart; 419 mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder = DeviceExtension->DiskGeometry.TracksPerCylinder; 420 mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack = DeviceExtension->DiskGeometry.SectorsPerTrack; 421 mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = DeviceExtension->DiskGeometry.BytesPerSector; 422 mediaInfo--; 423 424 } 425 426 // Status will either be success, if media is present, or no media. 427 // It would be optimal to base from density code and medium type, but not all devices 428 // have values for these fields. 429 430 // Send a TUR to determine if media is present, only if the device is not in ZPODD mode. 431 if ((!EXCLUSIVE_MODE(cdData) || 432 EXCLUSIVE_OWNER(cdData, WdfRequestGetFileObject(Request))) && 433 ((zpoddInfo == NULL) || 434 (zpoddInfo->InZeroPowerState == FALSE))) 435 { 436 SCSI_REQUEST_BLOCK srb; 437 PCDB cdb = (PCDB)srb.Cdb; 438 439 RtlZeroMemory(&srb,sizeof(SCSI_REQUEST_BLOCK)); 440 441 srb.CdbLength = 6; 442 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY; 443 444 srb.TimeOutValue = CDROM_TEST_UNIT_READY_TIMEOUT; 445 446 status = DeviceSendSrbSynchronously(DeviceExtension->Device, 447 &srb, 448 NULL, 449 0, 450 FALSE, 451 Request); 452 453 if (NT_SUCCESS(status)) 454 { 455 // set the disk's media as current if we can write to it. 456 if (cdData->Mmc.IsMmc && cdData->Mmc.WriteAllowed) 457 { 458 mediaInfo++; 459 SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, 460 MEDIA_CURRENTLY_MOUNTED); 461 mediaInfo--; 462 } 463 else 464 { 465 SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, 466 MEDIA_CURRENTLY_MOUNTED); 467 } 468 } 469 else 470 { 471 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 472 "RequestHandleGetMediaTypeEx: GET_MEDIA_TYPES status of TUR - %lx\n", status)); 473 } 474 } 475 476 // per legacy cdrom behavior, always return success 477 status = STATUS_SUCCESS; 478 } 479 480 *DataLength = sizeNeeded; 481 482 return status; 483 } 484 485 _IRQL_requires_max_(APC_LEVEL) 486 NTSTATUS 487 RequestHandleGetDvdRegion( 488 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 489 _In_ WDFREQUEST Request, 490 _Out_ size_t * DataLength 491 ) 492 /*++ 493 494 Routine Description: 495 496 Handler for IOCTL_DVD_GET_REGION 497 498 Arguments: 499 500 DeviceExtension - device context 501 Request - request to be handled 502 DataLength - transferred data length 503 504 Return Value: 505 506 NTSTATUS 507 508 --*/ 509 { 510 NTSTATUS status = STATUS_SUCCESS; 511 512 PVOID outputBuffer = NULL; 513 size_t bytesReturned = 0; 514 515 PDVD_COPY_PROTECT_KEY copyProtectKey = NULL; 516 ULONG keyLength = 0; 517 PDVD_DESCRIPTOR_HEADER dvdHeader; 518 PDVD_COPYRIGHT_DESCRIPTOR copyRightDescriptor; 519 PDVD_REGION dvdRegion = NULL; 520 PDVD_READ_STRUCTURE readStructure = NULL; 521 PDVD_RPC_KEY rpcKey; 522 523 PAGED_CODE (); 524 525 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, 526 "RequestHandleGetDvdRegion: [%p] IOCTL_DVD_GET_REGION\n", Request)); 527 528 *DataLength = 0; 529 530 // reject the request if it's not a DVD device. 531 if (DeviceExtension->DeviceAdditionalData.DriveDeviceType != FILE_DEVICE_DVD) 532 { 533 status = STATUS_INVALID_DEVICE_REQUEST; 534 } 535 536 if (NT_SUCCESS(status)) 537 { 538 status = WdfRequestRetrieveOutputBuffer(Request, 539 sizeof(DVD_REGION), 540 &outputBuffer, 541 NULL); 542 } 543 544 if (NT_SUCCESS(status)) 545 { 546 // figure out how much data buffer we need 547 keyLength = max((sizeof(DVD_DESCRIPTOR_HEADER) + sizeof(DVD_COPYRIGHT_DESCRIPTOR)), 548 sizeof(DVD_READ_STRUCTURE)); 549 keyLength = max(keyLength, 550 DVD_RPC_KEY_LENGTH); 551 552 // round the size to nearest ULONGLONG -- why? 553 // could this be to deal with device alignment issues? 554 keyLength += sizeof(ULONGLONG) - (keyLength & (sizeof(ULONGLONG) - 1)); 555 556 readStructure = ExAllocatePoolWithTag(NonPagedPoolNx, 557 keyLength, 558 DVD_TAG_READ_KEY); 559 if (readStructure == NULL) 560 { 561 status = STATUS_INSUFFICIENT_RESOURCES; 562 } 563 } 564 565 if (NT_SUCCESS(status)) 566 { 567 RtlZeroMemory (readStructure, keyLength); 568 readStructure->Format = DvdCopyrightDescriptor; 569 570 // use READ_STRUCTURE to read copyright descriptor 571 status = ReadDvdStructure(DeviceExtension, 572 Request, 573 readStructure, 574 keyLength, 575 readStructure, 576 sizeof(DVD_DESCRIPTOR_HEADER) + sizeof(DVD_COPYRIGHT_DESCRIPTOR), 577 &bytesReturned); 578 } 579 580 if (NT_SUCCESS(status)) 581 { 582 // we got the copyright descriptor, so now get the region if possible 583 dvdHeader = (PDVD_DESCRIPTOR_HEADER) readStructure; 584 copyRightDescriptor = (PDVD_COPYRIGHT_DESCRIPTOR) dvdHeader->Data; 585 586 // the original irp's systembuffer has a copy of the info that 587 // should be passed down in the request 588 dvdRegion = outputBuffer; 589 590 dvdRegion->CopySystem = copyRightDescriptor->CopyrightProtectionType; 591 dvdRegion->RegionData = copyRightDescriptor->RegionManagementInformation; 592 593 // now reuse the buffer to request the copy protection info 594 copyProtectKey = (PDVD_COPY_PROTECT_KEY) readStructure; 595 RtlZeroMemory (copyProtectKey, DVD_RPC_KEY_LENGTH); 596 copyProtectKey->KeyLength = DVD_RPC_KEY_LENGTH; 597 copyProtectKey->KeyType = DvdGetRpcKey; 598 599 // send a request for READ_KEY 600 status = DvdStartSessionReadKey(DeviceExtension, 601 IOCTL_DVD_READ_KEY, 602 Request, 603 copyProtectKey, 604 DVD_RPC_KEY_LENGTH, 605 copyProtectKey, 606 DVD_RPC_KEY_LENGTH, 607 &bytesReturned); 608 } 609 610 if (NT_SUCCESS(status)) 611 { 612 // the request succeeded. if a supported scheme is returned, 613 // then return the information to the caller 614 rpcKey = (PDVD_RPC_KEY) copyProtectKey->KeyData; 615 616 if (rpcKey->RpcScheme == 1) 617 { 618 if (rpcKey->TypeCode) 619 { 620 dvdRegion->SystemRegion = ~rpcKey->RegionMask; 621 dvdRegion->ResetCount = rpcKey->UserResetsAvailable; 622 } 623 else 624 { 625 // the drive has not been set for any region 626 dvdRegion->SystemRegion = 0; 627 dvdRegion->ResetCount = rpcKey->UserResetsAvailable; 628 } 629 630 *DataLength = sizeof(DVD_REGION); 631 } 632 else 633 { 634 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, 635 "RequestHandleGetDvdRegion => rpcKey->RpcScheme != 1\n")); 636 status = STATUS_INVALID_DEVICE_REQUEST; 637 } 638 } 639 640 // Clean up 641 if (readStructure != NULL) 642 { 643 ExFreePool(readStructure); 644 } 645 646 return status; 647 } 648 649 NTSTATUS 650 RequestValidateRawRead( 651 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 652 _In_ WDFREQUEST Request, 653 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 654 _Out_ size_t * DataLength 655 ) 656 /*++ 657 658 Routine Description: 659 660 Validate request of IOCTL_CDROM_RAW_READ 661 662 Arguments: 663 664 DeviceExtension - device context 665 Request - request to be handled 666 RequestParameters - request parameter 667 DataLength - transferred data length 668 669 Return Value: 670 671 NTSTATUS 672 673 --*/ 674 { 675 NTSTATUS status = STATUS_SUCCESS; 676 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); 677 678 PVOID inputBuffer = NULL; 679 PIRP irp = NULL; 680 PIO_STACK_LOCATION currentStack = NULL; 681 682 LARGE_INTEGER startingOffset = {0}; 683 ULONGLONG transferBytes = 0; 684 ULONGLONG endOffset; 685 ULONGLONG mdlBytes; 686 RAW_READ_INFO rawReadInfo = {0}; 687 688 *DataLength = 0; 689 690 irp = WdfRequestWdmGetIrp(Request); 691 currentStack = IoGetCurrentIrpStackLocation(irp); 692 693 status = WdfRequestRetrieveInputBuffer(Request, 694 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 695 &inputBuffer, 696 NULL); 697 698 // Check that ending sector is on disc and buffers are there and of 699 // correct size. 700 if (NT_SUCCESS(status) && 701 (RequestParameters.Parameters.DeviceIoControl.Type3InputBuffer == NULL)) 702 { 703 // This is a call from user space. This is the only time that we need to validate parameters. 704 // Validate the input and get the input buffer into Type3InputBuffer 705 // so the rest of the code will be uniform. 706 if (inputBuffer != NULL) 707 { 708 currentStack->Parameters.DeviceIoControl.Type3InputBuffer = inputBuffer; 709 RequestParameters.Parameters.DeviceIoControl.Type3InputBuffer = inputBuffer; 710 711 if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(RAW_READ_INFO)) 712 { 713 *DataLength = sizeof(RAW_READ_INFO); 714 status = STATUS_BUFFER_TOO_SMALL; 715 } 716 } 717 else 718 { 719 status = STATUS_INVALID_PARAMETER; 720 } 721 } 722 723 if (NT_SUCCESS(status)) 724 { 725 // Since this ioctl is METHOD_OUT_DIRECT, we need to copy away the input buffer before interpreting it. 726 // This prevents a malicious app from messing with the input buffer while we are interpreting it. 727 rawReadInfo = *(PRAW_READ_INFO)RequestParameters.Parameters.DeviceIoControl.Type3InputBuffer; 728 729 startingOffset.QuadPart = rawReadInfo.DiskOffset.QuadPart; 730 731 if ((rawReadInfo.TrackMode == CDDA) || 732 (rawReadInfo.TrackMode == YellowMode2) || 733 (rawReadInfo.TrackMode == XAForm2) ) 734 { 735 transferBytes = (ULONGLONG)rawReadInfo.SectorCount * RAW_SECTOR_SIZE; 736 } 737 else if (rawReadInfo.TrackMode == RawWithSubCode) 738 { 739 transferBytes = (ULONGLONG)rawReadInfo.SectorCount * CD_RAW_SECTOR_WITH_SUBCODE_SIZE; 740 } 741 else if (rawReadInfo.TrackMode == RawWithC2) 742 { 743 transferBytes = (ULONGLONG)rawReadInfo.SectorCount * CD_RAW_SECTOR_WITH_C2_SIZE; 744 } 745 else if (rawReadInfo.TrackMode == RawWithC2AndSubCode) 746 { 747 transferBytes = (ULONGLONG)rawReadInfo.SectorCount * CD_RAW_SECTOR_WITH_C2_AND_SUBCODE_SIZE; 748 } 749 else 750 { 751 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, 752 "RequestValidateRawRead: Invalid TrackMode type %x for XA read\n", 753 rawReadInfo.TrackMode 754 )); 755 } 756 757 endOffset = (ULONGLONG)rawReadInfo.SectorCount * COOKED_SECTOR_SIZE; 758 endOffset += startingOffset.QuadPart; 759 760 // check for overflows.... 761 if (rawReadInfo.SectorCount == 0) 762 { 763 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, 764 "RequestValidateRawRead: Invalid I/O parameters for XA " 765 "Read (zero sectors requested)\n")); 766 status = STATUS_INVALID_PARAMETER; 767 } 768 else if (transferBytes < (ULONGLONG)(rawReadInfo.SectorCount)) 769 { 770 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, 771 "RequestValidateRawRead: Invalid I/O parameters for XA " 772 "Read (TransferBytes Overflow)\n")); 773 status = STATUS_INVALID_PARAMETER; 774 } 775 else if (endOffset < (ULONGLONG)startingOffset.QuadPart) 776 { 777 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, 778 "RequestValidateRawRead: Invalid I/O parameters for XA " 779 "Read (EndingOffset Overflow)\n")); 780 status = STATUS_INVALID_PARAMETER; 781 } 782 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < transferBytes) 783 { 784 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, 785 "RequestValidateRawRead: Invalid I/O parameters for XA " 786 "Read (Bad buffer size)\n")); 787 status = STATUS_INVALID_PARAMETER; 788 } 789 else if (endOffset > (ULONGLONG)DeviceExtension->PartitionLength.QuadPart) 790 { 791 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, 792 "RequestValidateRawRead: Invalid I/O parameters for XA " 793 "Read (Request Out of Bounds)\n")); 794 status = STATUS_INVALID_PARAMETER; 795 } 796 } 797 798 if (NT_SUCCESS(status)) 799 { 800 // cannot validate the MdlAddress, since it is not included in any 801 // other location per the DDK and file system calls. 802 803 // validate the mdl describes at least the number of bytes 804 // requested from us. 805 mdlBytes = (ULONGLONG)MmGetMdlByteCount(irp->MdlAddress); 806 if (mdlBytes < transferBytes) 807 { 808 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, 809 "RequestValidateRawRead: Invalid MDL %s, Irp %p\n", 810 "size (5)", irp)); 811 status = STATUS_INVALID_PARAMETER; 812 } 813 } 814 815 if (NT_SUCCESS(status)) 816 { 817 // check the buffer for alignment 818 // This is important for x86 as some busses (ie ATAPI) 819 // require word-aligned buffers. 820 if ( ((ULONG_PTR)MmGetMdlVirtualAddress(irp->MdlAddress)) & 821 DeviceExtension->AdapterDescriptor->AlignmentMask ) 822 { 823 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, 824 "RequestValidateRawRead: Invalid I/O parameters for " 825 "XA Read (Buffer %p not aligned with mask %x\n", 826 RequestParameters.Parameters.DeviceIoControl.Type3InputBuffer, 827 DeviceExtension->AdapterDescriptor->AlignmentMask)); 828 status = STATUS_INVALID_PARAMETER; 829 } 830 } 831 832 if (NT_SUCCESS(status)) 833 { 834 // Validate the request is not too large for the adapter 835 BOOLEAN bufferIsPageAligned = FALSE; 836 ULONG maxLength = 0; 837 838 // if buffer is not page-aligned, then subtract one as the 839 // transfer could cross a page boundary. 840 if ((((ULONG_PTR)MmGetMdlVirtualAddress(irp->MdlAddress)) & (PAGE_SIZE-1)) == 0) 841 { 842 bufferIsPageAligned = TRUE; 843 } 844 845 if (bufferIsPageAligned) 846 { 847 maxLength = cdData->MaxPageAlignedTransferBytes; 848 } 849 else 850 { 851 maxLength = cdData->MaxUnalignedTransferBytes; 852 } 853 854 if (transferBytes > maxLength) 855 { 856 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, 857 "RequestValidateRawRead: The XA Read (type %x) would require %I64x bytes, " 858 "but the adapter can only handle %x bytes (for a%saligned buffer)\n", 859 rawReadInfo.TrackMode, 860 transferBytes, 861 maxLength, 862 (bufferIsPageAligned ? " " : "n un") 863 )); 864 status = STATUS_INVALID_PARAMETER; 865 } 866 } 867 868 if (NT_SUCCESS(status)) 869 { 870 // 871 // HACKHACK - REF #0001 872 // The retry count will be in this irp's IRP_MN function, 873 // as the new irp was freed, and we therefore cannot use 874 // this irp's next stack location for this function. 875 // This may be a good location to store this info for 876 // when we remove RAW_READ (mode switching), as we will 877 // no longer have the nextIrpStackLocation to play with 878 // when that occurs 879 // 880 currentStack->MinorFunction = MAXIMUM_RETRIES; // HACKHACK - REF #0001 881 } 882 883 return status; 884 } 885 886 NTSTATUS 887 RequestValidateReadTocEx( 888 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 889 _In_ WDFREQUEST Request, 890 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 891 _Out_ size_t * DataLength 892 ) 893 /*++ 894 895 Routine Description: 896 897 Validate request of IOCTL_CDROM_READ_TOC_EX 898 899 Arguments: 900 901 DeviceExtension - device context 902 Request - request to be handled 903 RequestParameters - request parameter 904 DataLength - transferred data length 905 906 Return Value: 907 908 NTSTATUS 909 910 --*/ 911 { 912 NTSTATUS status = STATUS_SUCCESS; 913 914 PCDROM_READ_TOC_EX inputBuffer = NULL; 915 916 *DataLength = 0; 917 918 if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < 919 sizeof(CDROM_READ_TOC_EX)) 920 { 921 status = STATUS_INFO_LENGTH_MISMATCH; 922 } 923 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < 924 MINIMUM_CDROM_READ_TOC_EX_SIZE) 925 { 926 status = STATUS_BUFFER_TOO_SMALL; 927 *DataLength = MINIMUM_CDROM_READ_TOC_EX_SIZE; 928 } 929 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > 930 ((USHORT)-1)) 931 { 932 status = STATUS_INVALID_PARAMETER; 933 } 934 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength & 935 DeviceExtension->AdapterDescriptor->AlignmentMask) 936 { 937 status = STATUS_INVALID_PARAMETER; 938 } 939 940 if (NT_SUCCESS(status)) 941 { 942 status = WdfRequestRetrieveInputBuffer(Request, 943 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 944 &inputBuffer, 945 NULL); 946 } 947 948 if (NT_SUCCESS(status)) 949 { 950 if ((inputBuffer->Reserved1 != 0) || 951 (inputBuffer->Reserved2 != 0) || 952 (inputBuffer->Reserved3 != 0)) 953 { 954 status = STATUS_INVALID_PARAMETER; 955 } 956 // NOTE: when adding new formats, ensure that first two bytes 957 // specify the amount of additional data available. 958 else if ((inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_TOC ) || 959 (inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_FULL_TOC) || 960 (inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_CDTEXT )) 961 { 962 // SessionTrack field is used 963 } 964 else if ((inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_SESSION) || 965 (inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_PMA) || 966 (inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_ATIP)) 967 { 968 // SessionTrack field is reserved 969 if (inputBuffer->SessionTrack != 0) 970 { 971 status = STATUS_INVALID_PARAMETER; 972 } 973 } 974 else 975 { 976 status = STATUS_INVALID_PARAMETER; 977 } 978 } 979 980 return status; 981 } 982 983 NTSTATUS 984 RequestValidateReadToc( 985 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 986 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 987 _Out_ size_t * DataLength 988 ) 989 /*++ 990 991 Routine Description: 992 993 Validate request of IOCTL_CDROM_READ_TOC 994 995 Arguments: 996 997 DeviceExtension - device context 998 RequestParameters - request parameter 999 DataLength - transferred data length 1000 1001 Return Value: 1002 1003 NTSTATUS 1004 1005 --*/ 1006 { 1007 NTSTATUS status = STATUS_SUCCESS; 1008 1009 *DataLength = 0; 1010 1011 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < 1012 sizeof(CDROM_TOC)) 1013 { 1014 // they didn't request the entire TOC -- use _EX version 1015 // for partial transfers and such. 1016 status = STATUS_BUFFER_TOO_SMALL; 1017 *DataLength = sizeof(CDROM_TOC); 1018 } 1019 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength & 1020 DeviceExtension->AdapterDescriptor->AlignmentMask) 1021 { 1022 status = STATUS_INVALID_PARAMETER; 1023 } 1024 1025 return status; 1026 } 1027 1028 NTSTATUS 1029 RequestValidateGetLastSession( 1030 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 1031 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 1032 _Out_ size_t * DataLength 1033 ) 1034 /*++ 1035 1036 Routine Description: 1037 1038 Validate request of IOCTL_CDROM_GET_LAST_SESSION 1039 1040 Arguments: 1041 1042 DeviceExtension - device context 1043 RequestParameters - request parameter 1044 DataLength - transferred data length 1045 1046 Return Value: 1047 1048 NTSTATUS 1049 1050 --*/ 1051 { 1052 NTSTATUS status = STATUS_SUCCESS; 1053 1054 *DataLength = 0; 1055 1056 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < 1057 sizeof(CDROM_TOC_SESSION_DATA)) 1058 { 1059 status = STATUS_BUFFER_TOO_SMALL; 1060 *DataLength = sizeof(CDROM_TOC_SESSION_DATA); 1061 } 1062 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength & 1063 DeviceExtension->AdapterDescriptor->AlignmentMask) 1064 { 1065 status = STATUS_INVALID_PARAMETER; 1066 } 1067 1068 return status; 1069 } 1070 1071 NTSTATUS 1072 RequestValidateReadQChannel( 1073 _In_ WDFREQUEST Request, 1074 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 1075 _Out_ size_t * DataLength 1076 ) 1077 /*++ 1078 1079 Routine Description: 1080 1081 Validate request of IOCTL_CDROM_READ_Q_CHANNEL 1082 1083 Arguments: 1084 1085 Request - request to be handled 1086 RequestParameters - request parameter 1087 DataLength - transferred data length 1088 1089 Return Value: 1090 1091 NTSTATUS 1092 1093 --*/ 1094 { 1095 NTSTATUS status = STATUS_SUCCESS; 1096 PCDROM_SUB_Q_DATA_FORMAT inputBuffer = NULL; 1097 ULONG transferByteCount = 0; 1098 1099 *DataLength = 0; 1100 1101 if(RequestParameters.Parameters.DeviceIoControl.InputBufferLength < 1102 sizeof(CDROM_SUB_Q_DATA_FORMAT)) 1103 { 1104 status = STATUS_INFO_LENGTH_MISMATCH; 1105 } 1106 1107 if (NT_SUCCESS(status)) 1108 { 1109 status = WdfRequestRetrieveInputBuffer(Request, 1110 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 1111 &inputBuffer, 1112 NULL); 1113 } 1114 1115 if (NT_SUCCESS(status)) 1116 { 1117 // check for all valid types of request 1118 if (inputBuffer->Format == IOCTL_CDROM_CURRENT_POSITION) 1119 { 1120 transferByteCount = sizeof(SUB_Q_CURRENT_POSITION); 1121 } 1122 else if (inputBuffer->Format == IOCTL_CDROM_MEDIA_CATALOG) 1123 { 1124 transferByteCount = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER); 1125 } 1126 else if (inputBuffer->Format == IOCTL_CDROM_TRACK_ISRC) 1127 { 1128 transferByteCount = sizeof(SUB_Q_TRACK_ISRC); 1129 } 1130 else 1131 { 1132 // Format not valid 1133 status = STATUS_INVALID_PARAMETER; 1134 } 1135 } 1136 1137 if (NT_SUCCESS(status)) 1138 { 1139 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < 1140 transferByteCount) 1141 { 1142 status = STATUS_BUFFER_TOO_SMALL; 1143 *DataLength = transferByteCount; 1144 } 1145 } 1146 1147 return status; 1148 } 1149 1150 NTSTATUS 1151 RequestValidateDvdReadStructure( 1152 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 1153 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 1154 _Out_ size_t * DataLength 1155 ) 1156 /*++ 1157 1158 Routine Description: 1159 1160 Validate request of IOCTL_DVD_READ_STRUCTURE 1161 1162 Arguments: 1163 1164 DeviceExtension - device context 1165 RequestParameters - request parameter 1166 DataLength - transferred data length 1167 1168 Return Value: 1169 1170 NTSTATUS 1171 1172 --*/ 1173 { 1174 NTSTATUS status = STATUS_SUCCESS; 1175 1176 *DataLength = 0; 1177 1178 if (NT_SUCCESS(status)) 1179 { 1180 if(RequestParameters.Parameters.DeviceIoControl.InputBufferLength < 1181 sizeof(DVD_READ_STRUCTURE)) 1182 { 1183 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, 1184 "RequestValidateDvdReadStructure - input buffer " 1185 "length too small (was %d should be %d)\n", 1186 (int)RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 1187 sizeof(DVD_READ_STRUCTURE))); 1188 status = STATUS_INVALID_PARAMETER; 1189 } 1190 else if(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < 1191 sizeof(READ_DVD_STRUCTURES_HEADER)) 1192 { 1193 1194 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, 1195 "RequestValidateDvdReadStructure - output buffer " 1196 "cannot hold header information\n")); 1197 status = STATUS_BUFFER_TOO_SMALL; 1198 *DataLength = sizeof(READ_DVD_STRUCTURES_HEADER); 1199 } 1200 else if(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > 1201 MAXUSHORT) 1202 { 1203 // key length must fit in two bytes 1204 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, 1205 "RequestValidateDvdReadStructure - output buffer " 1206 "too large\n")); 1207 status = STATUS_INVALID_PARAMETER; 1208 } 1209 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength & 1210 DeviceExtension->AdapterDescriptor->AlignmentMask) 1211 { 1212 status = STATUS_INVALID_PARAMETER; 1213 } 1214 else if (DeviceExtension->DeviceAdditionalData.DriveDeviceType != FILE_DEVICE_DVD) 1215 { 1216 // reject the request if it's not a DVD device. 1217 status = STATUS_INVALID_DEVICE_REQUEST; 1218 } 1219 } 1220 1221 return status; 1222 } 1223 1224 NTSTATUS 1225 RequestValidateDvdStartSession( 1226 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 1227 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 1228 _Out_ size_t * DataLength 1229 ) 1230 /*++ 1231 1232 Routine Description: 1233 1234 Validate request of IOCTL_DVD_START_SESSION 1235 1236 Arguments: 1237 1238 DeviceExtension - device context 1239 RequestParameters - request parameter 1240 DataLength - transferred data length 1241 1242 Return Value: 1243 1244 NTSTATUS 1245 1246 --*/ 1247 { 1248 NTSTATUS status = STATUS_SUCCESS; 1249 1250 *DataLength = 0; 1251 1252 if (NT_SUCCESS(status)) 1253 { 1254 if(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < 1255 sizeof(DVD_SESSION_ID)) 1256 { 1257 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, 1258 "RequestValidateDvdStartSession: DVD_START_SESSION - output " 1259 "buffer too small\n")); 1260 status = STATUS_BUFFER_TOO_SMALL; 1261 *DataLength = sizeof(DVD_SESSION_ID); 1262 } 1263 else if (DeviceExtension->DeviceAdditionalData.DriveDeviceType != FILE_DEVICE_DVD) 1264 { 1265 // reject the request if it's not a DVD device. 1266 status = STATUS_INVALID_DEVICE_REQUEST; 1267 } 1268 } 1269 1270 return status; 1271 } 1272 1273 NTSTATUS 1274 RequestValidateDvdSendKey( 1275 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 1276 _In_ WDFREQUEST Request, 1277 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 1278 _Out_ size_t * DataLength 1279 ) 1280 /*++ 1281 1282 Routine Description: 1283 1284 Validate request of IOCTL_DVD_SEND_KEY, IOCTL_DVD_SEND_KEY2 1285 1286 Arguments: 1287 1288 DeviceExtension - device context 1289 Request - request to be handled 1290 RequestParameters - request parameter 1291 DataLength - transferred data length 1292 1293 Return Value: 1294 1295 NTSTATUS 1296 1297 --*/ 1298 { 1299 NTSTATUS status = STATUS_SUCCESS; 1300 PDVD_COPY_PROTECT_KEY key = NULL; 1301 1302 *DataLength = 0; 1303 1304 status = WdfRequestRetrieveInputBuffer(Request, 1305 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 1306 &key, 1307 NULL); 1308 1309 if (NT_SUCCESS(status)) 1310 { 1311 if((RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(DVD_COPY_PROTECT_KEY)) || 1312 (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != key->KeyLength)) 1313 { 1314 1315 // 1316 // Key is too small to have a header or the key length doesn't 1317 // match the input buffer length. Key must be invalid 1318 // 1319 1320 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, 1321 "RequestValidateDvdSendKey: [%p] IOCTL_DVD_SEND_KEY - " 1322 "key is too small or does not match KeyLength\n", 1323 Request)); 1324 status = STATUS_INVALID_PARAMETER; 1325 } 1326 } 1327 1328 if (NT_SUCCESS(status)) 1329 { 1330 // allow only certain key type (non-destructive) to go through 1331 // IOCTL_DVD_SEND_KEY (which only requires READ access to the device) 1332 if (RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_DVD_SEND_KEY) 1333 { 1334 if ((key->KeyType != DvdChallengeKey) && 1335 (key->KeyType != DvdBusKey2) && 1336 (key->KeyType != DvdInvalidateAGID)) 1337 { 1338 status = STATUS_INVALID_PARAMETER; 1339 } 1340 } 1341 else if ((key->KeyType != DvdChallengeKey) && 1342 (key->KeyType != DvdBusKey1) && 1343 (key->KeyType != DvdBusKey2) && 1344 (key->KeyType != DvdTitleKey) && 1345 (key->KeyType != DvdAsf) && 1346 (key->KeyType != DvdSetRpcKey) && 1347 (key->KeyType != DvdGetRpcKey) && 1348 (key->KeyType != DvdDiskKey) && 1349 (key->KeyType != DvdInvalidateAGID)) 1350 { 1351 status = STATUS_INVALID_PARAMETER; 1352 } 1353 else if (DeviceExtension->DeviceAdditionalData.DriveDeviceType != FILE_DEVICE_DVD) 1354 { 1355 // reject the request if it's not a DVD device. 1356 status = STATUS_INVALID_DEVICE_REQUEST; 1357 } 1358 } 1359 1360 return status; 1361 } 1362 1363 NTSTATUS 1364 RequestValidateGetConfiguration( 1365 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 1366 _In_ WDFREQUEST Request, 1367 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 1368 _Out_ size_t * DataLength 1369 ) 1370 /*++ 1371 1372 Routine Description: 1373 1374 Validate request of IOCTL_CDROM_GET_CONFIGURATION 1375 1376 Arguments: 1377 1378 DeviceExtension - device context 1379 Request - request to be handled 1380 RequestParameters - request parameter 1381 DataLength - transferred data length 1382 1383 Return Value: 1384 1385 NTSTATUS 1386 1387 --*/ 1388 { 1389 NTSTATUS status = STATUS_SUCCESS; 1390 1391 *DataLength = 0; 1392 1393 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < 1394 sizeof(GET_CONFIGURATION_HEADER)) 1395 { 1396 status = STATUS_BUFFER_TOO_SMALL; 1397 *DataLength = sizeof(GET_CONFIGURATION_HEADER); 1398 } 1399 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > 0xffff) 1400 { 1401 // output buffer is too large 1402 status = STATUS_INVALID_BUFFER_SIZE; 1403 } 1404 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength & 1405 DeviceExtension->AdapterDescriptor->AlignmentMask) 1406 { 1407 // buffer is not proper size multiple 1408 status = STATUS_INVALID_PARAMETER; 1409 } 1410 1411 if (NT_SUCCESS(status)) 1412 { 1413 1414 #if BUILD_WOW64_ENABLED && defined(_WIN64) 1415 1416 if (WdfRequestIsFrom32BitProcess(Request)) 1417 { 1418 PGET_CONFIGURATION_IOCTL_INPUT32 inputBuffer = NULL; 1419 1420 if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < 1421 sizeof(GET_CONFIGURATION_IOCTL_INPUT32)) 1422 { 1423 status = STATUS_INFO_LENGTH_MISMATCH; 1424 } 1425 1426 // 1427 // also verify the arguments are reasonable. 1428 // 1429 if (NT_SUCCESS(status)) 1430 { 1431 status = WdfRequestRetrieveInputBuffer(Request, 1432 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 1433 &inputBuffer, 1434 NULL); 1435 } 1436 1437 if (NT_SUCCESS(status)) 1438 { 1439 if (inputBuffer->Feature > 0xffff) 1440 { 1441 status = STATUS_INVALID_PARAMETER; 1442 } 1443 else if ((inputBuffer->RequestType != SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE) && 1444 (inputBuffer->RequestType != SCSI_GET_CONFIGURATION_REQUEST_TYPE_CURRENT) && 1445 (inputBuffer->RequestType != SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL)) 1446 { 1447 status = STATUS_INVALID_PARAMETER; 1448 } 1449 else if (inputBuffer->Reserved[0] || inputBuffer->Reserved[1]) 1450 { 1451 status = STATUS_INVALID_PARAMETER; 1452 } 1453 } 1454 } 1455 else 1456 1457 #endif 1458 1459 { 1460 PGET_CONFIGURATION_IOCTL_INPUT inputBuffer = NULL; 1461 1462 if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < 1463 sizeof(GET_CONFIGURATION_IOCTL_INPUT)) 1464 { 1465 status = STATUS_INFO_LENGTH_MISMATCH; 1466 } 1467 1468 // also verify the arguments are reasonable. 1469 if (NT_SUCCESS(status)) 1470 { 1471 status = WdfRequestRetrieveInputBuffer(Request, 1472 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 1473 &inputBuffer, 1474 NULL); 1475 } 1476 1477 if (NT_SUCCESS(status)) 1478 { 1479 if (inputBuffer->Feature > 0xffff) 1480 { 1481 status = STATUS_INVALID_PARAMETER; 1482 } 1483 else if ((inputBuffer->RequestType != SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE) && 1484 (inputBuffer->RequestType != SCSI_GET_CONFIGURATION_REQUEST_TYPE_CURRENT) && 1485 (inputBuffer->RequestType != SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL)) 1486 { 1487 status = STATUS_INVALID_PARAMETER; 1488 } 1489 else if (inputBuffer->Reserved[0] || inputBuffer->Reserved[1]) 1490 { 1491 status = STATUS_INVALID_PARAMETER; 1492 } 1493 } 1494 } 1495 } 1496 1497 return status; 1498 } 1499 1500 NTSTATUS 1501 RequestValidateSetSpeed( 1502 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 1503 _In_ WDFREQUEST Request, 1504 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 1505 _Out_ size_t * DataLength 1506 ) 1507 /*++ 1508 1509 Routine Description: 1510 1511 Validate request of IOCTL_CDROM_SET_SPEED 1512 1513 Arguments: 1514 1515 DeviceExtension - device context 1516 Request - request to be handled 1517 RequestParameters - request parameter 1518 DataLength - transferred data length 1519 1520 Return Value: 1521 1522 NTSTATUS 1523 1524 --*/ 1525 { 1526 NTSTATUS status = STATUS_SUCCESS; 1527 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); 1528 PCDROM_SET_SPEED inputBuffer = NULL; 1529 ULONG requiredLength = 0; 1530 1531 *DataLength = 0; 1532 1533 if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(CDROM_SET_SPEED)) 1534 { 1535 status = STATUS_INFO_LENGTH_MISMATCH; 1536 } 1537 1538 if (NT_SUCCESS(status)) 1539 { 1540 // Get the request type using CDROM_SET_SPEED structure 1541 status = WdfRequestRetrieveInputBuffer(Request, 1542 sizeof(CDROM_SET_SPEED), 1543 &inputBuffer, 1544 NULL); 1545 1546 } 1547 1548 if (NT_SUCCESS(status)) 1549 { 1550 if (inputBuffer->RequestType > CdromSetStreaming) 1551 { 1552 // Unknown request type. 1553 status = STATUS_INVALID_PARAMETER; 1554 } 1555 else if (inputBuffer->RequestType == CdromSetSpeed) 1556 { 1557 requiredLength = sizeof(CDROM_SET_SPEED); 1558 } 1559 else 1560 { 1561 // Don't send SET STREAMING command if this is not a MMC compliant device 1562 if (cdData->Mmc.IsMmc == FALSE) 1563 { 1564 status = STATUS_INVALID_DEVICE_REQUEST; 1565 } 1566 1567 requiredLength = sizeof(CDROM_SET_STREAMING); 1568 } 1569 } 1570 1571 if (NT_SUCCESS(status)) 1572 { 1573 if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < requiredLength) 1574 { 1575 // Input buffer too small 1576 status = STATUS_INFO_LENGTH_MISMATCH; 1577 } 1578 } 1579 1580 return status; 1581 } 1582 1583 NTSTATUS 1584 RequestValidateAacsReadMediaKeyBlock( 1585 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 1586 _In_ WDFREQUEST Request, 1587 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 1588 _Out_ size_t * DataLength 1589 ) 1590 /*++ 1591 1592 Routine Description: 1593 1594 Validate request of IOCTL_AACS_READ_MEDIA_KEY_BLOCK 1595 1596 Arguments: 1597 1598 DeviceExtension - device context 1599 Request - request to be handled 1600 RequestParameters - request parameter 1601 DataLength - transferred data length 1602 1603 Return Value: 1604 1605 NTSTATUS 1606 1607 --*/ 1608 { 1609 NTSTATUS status = STATUS_SUCCESS; 1610 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); 1611 PAACS_LAYER_NUMBER layerNumber = NULL; 1612 1613 *DataLength = 0; 1614 1615 if (!cdData->Mmc.IsAACS) 1616 { 1617 status = STATUS_INVALID_DEVICE_REQUEST; 1618 } 1619 else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(AACS_LAYER_NUMBER)) 1620 { 1621 status = STATUS_INFO_LENGTH_MISMATCH; 1622 } 1623 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < 8) 1624 { 1625 // This is a variable-length structure, but we're pretty sure 1626 // it can never be less than eight bytes... 1627 *DataLength = 8; 1628 status = STATUS_BUFFER_TOO_SMALL; 1629 } 1630 1631 if (NT_SUCCESS(status)) 1632 { 1633 status = WdfRequestRetrieveInputBuffer(Request, 1634 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 1635 &layerNumber, 1636 NULL); 1637 } 1638 1639 if (NT_SUCCESS(status)) 1640 { 1641 if (*layerNumber > 255) 1642 { 1643 status = STATUS_INVALID_PARAMETER; 1644 } 1645 } 1646 1647 return status; 1648 } 1649 1650 NTSTATUS 1651 RequestValidateAacsStartSession( 1652 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 1653 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 1654 _Out_ size_t * DataLength 1655 ) 1656 /*++ 1657 1658 Routine Description: 1659 1660 Validate request of IOCTL_AACS_START_SESSION 1661 1662 Arguments: 1663 1664 DeviceExtension - device context 1665 RequestParameters - request parameter 1666 DataLength - transferred data length 1667 1668 Return Value: 1669 1670 NTSTATUS 1671 1672 --*/ 1673 { 1674 NTSTATUS status = STATUS_SUCCESS; 1675 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); 1676 1677 *DataLength = 0; 1678 1679 if (!cdData->Mmc.IsAACS) 1680 { 1681 status = STATUS_INVALID_DEVICE_REQUEST; 1682 } 1683 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(DVD_SESSION_ID)) 1684 { 1685 *DataLength = sizeof(DVD_SESSION_ID); 1686 status = STATUS_BUFFER_TOO_SMALL; 1687 } 1688 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > sizeof(DVD_SESSION_ID)) 1689 { 1690 status = STATUS_INVALID_BUFFER_SIZE; 1691 } 1692 1693 return status; 1694 } 1695 1696 NTSTATUS 1697 RequestValidateAacsSendCertificate( 1698 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 1699 _In_ WDFREQUEST Request, 1700 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 1701 _Out_ size_t * DataLength 1702 ) 1703 /*++ 1704 1705 Routine Description: 1706 1707 Validate request of IOCTL_AACS_SEND_CERTIFICATE 1708 1709 Arguments: 1710 1711 DeviceExtension - device context 1712 Request - request to be handled 1713 RequestParameters - request parameter 1714 DataLength - transferred data length 1715 1716 Return Value: 1717 1718 NTSTATUS 1719 1720 --*/ 1721 { 1722 NTSTATUS status = STATUS_SUCCESS; 1723 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); 1724 PAACS_SEND_CERTIFICATE inputBuffer = NULL; 1725 1726 *DataLength = 0; 1727 1728 if (!cdData->Mmc.IsAACS) 1729 { 1730 status = STATUS_INVALID_DEVICE_REQUEST; 1731 } 1732 else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(AACS_SEND_CERTIFICATE)) 1733 { 1734 status = STATUS_INFO_LENGTH_MISMATCH; 1735 } 1736 1737 if (NT_SUCCESS(status)) 1738 { 1739 status = WdfRequestRetrieveInputBuffer(Request, 1740 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 1741 &inputBuffer, 1742 NULL); 1743 } 1744 1745 if (NT_SUCCESS(status)) 1746 { 1747 if (inputBuffer->SessionId > MAX_COPY_PROTECT_AGID) 1748 { 1749 status = STATUS_INVALID_PARAMETER; 1750 } 1751 } 1752 1753 return status; 1754 } 1755 1756 NTSTATUS 1757 RequestValidateAacsGetCertificate( 1758 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 1759 _In_ WDFREQUEST Request, 1760 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 1761 _Out_ size_t * DataLength 1762 ) 1763 /*++ 1764 1765 Routine Description: 1766 1767 Validate request of IOCTL_AACS_GET_CERTIFICATE 1768 1769 Arguments: 1770 1771 DeviceExtension - device context 1772 Request - request to be handled 1773 RequestParameters - request parameter 1774 DataLength - transferred data length 1775 1776 Return Value: 1777 1778 NTSTATUS 1779 1780 --*/ 1781 { 1782 NTSTATUS status = STATUS_SUCCESS; 1783 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); 1784 PDVD_SESSION_ID sessionId = NULL; 1785 1786 *DataLength = 0; 1787 1788 if (!cdData->Mmc.IsAACS) 1789 { 1790 status = STATUS_INVALID_DEVICE_REQUEST; 1791 } 1792 else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(DVD_SESSION_ID)) 1793 { 1794 status = STATUS_INFO_LENGTH_MISMATCH; 1795 } 1796 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(AACS_CERTIFICATE)) 1797 { 1798 *DataLength = sizeof(AACS_CERTIFICATE); 1799 status = STATUS_BUFFER_TOO_SMALL; 1800 } 1801 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > sizeof(AACS_CERTIFICATE)) 1802 { 1803 status = STATUS_INVALID_BUFFER_SIZE; 1804 } 1805 1806 if (NT_SUCCESS(status)) 1807 { 1808 status = WdfRequestRetrieveInputBuffer(Request, 1809 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 1810 &sessionId, 1811 NULL); 1812 } 1813 1814 if (NT_SUCCESS(status)) 1815 { 1816 if (*sessionId > MAX_COPY_PROTECT_AGID) 1817 { 1818 status = STATUS_INVALID_PARAMETER; 1819 } 1820 } 1821 1822 return status; 1823 } 1824 1825 NTSTATUS 1826 RequestValidateAacsGetChallengeKey( 1827 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 1828 _In_ WDFREQUEST Request, 1829 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 1830 _Out_ size_t * DataLength 1831 ) 1832 /*++ 1833 1834 Routine Description: 1835 1836 Validate request of IOCTL_AACS_GET_CHALLENGE_KEY 1837 1838 Arguments: 1839 1840 DeviceExtension - device context 1841 Request - request to be handled 1842 RequestParameters - request parameter 1843 DataLength - transferred data length 1844 1845 Return Value: 1846 1847 NTSTATUS 1848 1849 --*/ 1850 { 1851 NTSTATUS status = STATUS_SUCCESS; 1852 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); 1853 PDVD_SESSION_ID sessionId = NULL; 1854 1855 *DataLength = 0; 1856 1857 if (!cdData->Mmc.IsAACS) 1858 { 1859 status = STATUS_INVALID_DEVICE_REQUEST; 1860 } 1861 else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(DVD_SESSION_ID)) 1862 { 1863 status = STATUS_INFO_LENGTH_MISMATCH; 1864 } 1865 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(AACS_CHALLENGE_KEY)) 1866 { 1867 *DataLength = sizeof(AACS_CHALLENGE_KEY); 1868 status = STATUS_BUFFER_TOO_SMALL; 1869 } 1870 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > sizeof(AACS_CHALLENGE_KEY)) 1871 { 1872 status = STATUS_INVALID_BUFFER_SIZE; 1873 } 1874 1875 if (NT_SUCCESS(status)) 1876 { 1877 status = WdfRequestRetrieveInputBuffer(Request, 1878 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 1879 &sessionId, 1880 NULL); 1881 } 1882 1883 if (NT_SUCCESS(status)) 1884 { 1885 if (*sessionId > MAX_COPY_PROTECT_AGID) 1886 { 1887 status = STATUS_INVALID_PARAMETER; 1888 } 1889 } 1890 1891 return status; 1892 } 1893 1894 NTSTATUS 1895 RequestValidateAacsSendChallengeKey( 1896 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 1897 _In_ WDFREQUEST Request, 1898 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 1899 _Out_ size_t * DataLength 1900 ) 1901 /*++ 1902 1903 Routine Description: 1904 1905 Validate request of IOCTL_AACS_SEND_CHALLENGE_KEY 1906 1907 Arguments: 1908 1909 DeviceExtension - device context 1910 Request - request to be handled 1911 RequestParameters - request parameter 1912 DataLength - transferred data length 1913 1914 Return Value: 1915 1916 NTSTATUS 1917 1918 --*/ 1919 { 1920 NTSTATUS status = STATUS_SUCCESS; 1921 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); 1922 PAACS_SEND_CHALLENGE_KEY inputBuffer = NULL; 1923 1924 *DataLength = 0; 1925 1926 if (!cdData->Mmc.IsAACS) 1927 { 1928 status = STATUS_INVALID_DEVICE_REQUEST; 1929 } 1930 else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(AACS_SEND_CHALLENGE_KEY)) 1931 { 1932 status = STATUS_INFO_LENGTH_MISMATCH; 1933 } 1934 1935 if (NT_SUCCESS(status)) 1936 { 1937 status = WdfRequestRetrieveInputBuffer(Request, 1938 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 1939 &inputBuffer, 1940 NULL); 1941 } 1942 1943 if (NT_SUCCESS(status)) 1944 { 1945 if (inputBuffer->SessionId > MAX_COPY_PROTECT_AGID) 1946 { 1947 status = STATUS_INVALID_PARAMETER; 1948 } 1949 } 1950 1951 return status; 1952 } 1953 1954 NTSTATUS 1955 RequestValidateAacsReadVolumeId( 1956 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 1957 _In_ WDFREQUEST Request, 1958 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 1959 _Out_ size_t * DataLength 1960 ) 1961 /*++ 1962 1963 Routine Description: 1964 1965 Validate request of IOCTL_AACS_READ_VOLUME_ID 1966 1967 Arguments: 1968 1969 DeviceExtension - device context 1970 Request - request to be handled 1971 RequestParameters - request parameter 1972 DataLength - transferred data length 1973 1974 Return Value: 1975 1976 NTSTATUS 1977 1978 --*/ 1979 { 1980 NTSTATUS status = STATUS_SUCCESS; 1981 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); 1982 PDVD_SESSION_ID sessionId = NULL; 1983 1984 *DataLength = 0; 1985 1986 if (!cdData->Mmc.IsAACS) 1987 { 1988 status = STATUS_INVALID_DEVICE_REQUEST; 1989 } 1990 else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(DVD_SESSION_ID)) 1991 { 1992 status = STATUS_INFO_LENGTH_MISMATCH; 1993 } 1994 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(AACS_VOLUME_ID)) 1995 { 1996 *DataLength = sizeof(AACS_VOLUME_ID); 1997 status = STATUS_BUFFER_TOO_SMALL; 1998 } 1999 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > sizeof(AACS_VOLUME_ID)) 2000 { 2001 status = STATUS_INVALID_BUFFER_SIZE; 2002 } 2003 2004 if (NT_SUCCESS(status)) 2005 { 2006 status = WdfRequestRetrieveInputBuffer(Request, 2007 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 2008 &sessionId, 2009 NULL); 2010 } 2011 2012 if (NT_SUCCESS(status)) 2013 { 2014 if (*sessionId > MAX_COPY_PROTECT_AGID) 2015 { 2016 status = STATUS_INVALID_PARAMETER; 2017 } 2018 } 2019 2020 return status; 2021 } 2022 2023 NTSTATUS 2024 RequestValidateAacsReadSerialNumber( 2025 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 2026 _In_ WDFREQUEST Request, 2027 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 2028 _Out_ size_t * DataLength 2029 ) 2030 /*++ 2031 2032 Routine Description: 2033 2034 Validate request of IOCTL_AACS_READ_SERIAL_NUMBER 2035 2036 Arguments: 2037 2038 DeviceExtension - device context 2039 Request - request to be handled 2040 RequestParameters - request parameter 2041 DataLength - transferred data length 2042 2043 Return Value: 2044 2045 NTSTATUS 2046 2047 --*/ 2048 { 2049 NTSTATUS status = STATUS_SUCCESS; 2050 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); 2051 PDVD_SESSION_ID sessionId = NULL; 2052 2053 *DataLength = 0; 2054 2055 if (!cdData->Mmc.IsAACS) 2056 { 2057 status = STATUS_INVALID_DEVICE_REQUEST; 2058 } 2059 else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(DVD_SESSION_ID)) 2060 { 2061 status = STATUS_INFO_LENGTH_MISMATCH; 2062 } 2063 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(AACS_SERIAL_NUMBER)) 2064 { 2065 *DataLength = sizeof(AACS_SERIAL_NUMBER); 2066 status = STATUS_BUFFER_TOO_SMALL; 2067 } 2068 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > sizeof(AACS_SERIAL_NUMBER)) 2069 { 2070 status = STATUS_INVALID_BUFFER_SIZE; 2071 } 2072 2073 if (NT_SUCCESS(status)) 2074 { 2075 status = WdfRequestRetrieveInputBuffer(Request, 2076 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 2077 &sessionId, 2078 NULL); 2079 } 2080 2081 if (NT_SUCCESS(status)) 2082 { 2083 if (*sessionId > MAX_COPY_PROTECT_AGID) 2084 { 2085 status = STATUS_INVALID_PARAMETER; 2086 } 2087 } 2088 2089 return status; 2090 } 2091 2092 NTSTATUS 2093 RequestValidateAacsReadMediaId( 2094 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 2095 _In_ WDFREQUEST Request, 2096 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 2097 _Out_ size_t * DataLength 2098 ) 2099 /*++ 2100 2101 Routine Description: 2102 2103 Validate request of IOCTL_AACS_READ_MEDIA_ID 2104 2105 Arguments: 2106 2107 DeviceExtension - device context 2108 Request - request to be handled 2109 RequestParameters - request parameter 2110 DataLength - transferred data length 2111 2112 Return Value: 2113 2114 NTSTATUS 2115 2116 --*/ 2117 { 2118 NTSTATUS status = STATUS_SUCCESS; 2119 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); 2120 PDVD_SESSION_ID sessionId = NULL; 2121 2122 *DataLength = 0; 2123 2124 if (!cdData->Mmc.IsAACS) 2125 { 2126 status = STATUS_INVALID_DEVICE_REQUEST; 2127 } 2128 else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(DVD_SESSION_ID)) 2129 { 2130 status = STATUS_INFO_LENGTH_MISMATCH; 2131 } 2132 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(AACS_MEDIA_ID)) 2133 { 2134 *DataLength = sizeof(AACS_MEDIA_ID); 2135 status = STATUS_BUFFER_TOO_SMALL; 2136 } 2137 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > sizeof(AACS_MEDIA_ID)) 2138 { 2139 status = STATUS_INVALID_BUFFER_SIZE; 2140 } 2141 2142 if (NT_SUCCESS(status)) 2143 { 2144 status = WdfRequestRetrieveInputBuffer(Request, 2145 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 2146 &sessionId, 2147 NULL); 2148 } 2149 2150 if (NT_SUCCESS(status)) 2151 { 2152 if (*sessionId > MAX_COPY_PROTECT_AGID) 2153 { 2154 status = STATUS_INVALID_PARAMETER; 2155 } 2156 } 2157 2158 return status; 2159 } 2160 2161 NTSTATUS 2162 RequestValidateAacsBindingNonce( 2163 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 2164 _In_ WDFREQUEST Request, 2165 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 2166 _Out_ size_t * DataLength 2167 ) 2168 /*++ 2169 2170 Routine Description: 2171 2172 Validate request of IOCTL_AACS_READ_BINDING_NONCE 2173 IOCTL_AACS_GENERATE_BINDING_NONCE 2174 2175 Arguments: 2176 2177 DeviceExtension - device context 2178 Request - request to be handled 2179 RequestParameters - request parameter 2180 DataLength - transferred data length 2181 2182 Return Value: 2183 2184 NTSTATUS 2185 2186 --*/ 2187 { 2188 NTSTATUS status = STATUS_SUCCESS; 2189 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); 2190 PAACS_READ_BINDING_NONCE inputBuffer = NULL; 2191 2192 *DataLength = 0; 2193 2194 if (!cdData->Mmc.IsAACS) 2195 { 2196 status = STATUS_INVALID_DEVICE_REQUEST; 2197 } 2198 else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(AACS_READ_BINDING_NONCE)) 2199 { 2200 status = STATUS_INFO_LENGTH_MISMATCH; 2201 } 2202 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(AACS_BINDING_NONCE)) 2203 { 2204 *DataLength = sizeof(AACS_BINDING_NONCE); 2205 status = STATUS_BUFFER_TOO_SMALL; 2206 } 2207 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > sizeof(AACS_BINDING_NONCE)) 2208 { 2209 status = STATUS_INVALID_BUFFER_SIZE; 2210 } 2211 2212 if (NT_SUCCESS(status)) 2213 { 2214 status = WdfRequestRetrieveInputBuffer(Request, 2215 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 2216 &inputBuffer, 2217 NULL); 2218 } 2219 2220 if (NT_SUCCESS(status)) 2221 { 2222 if (inputBuffer->SessionId > MAX_COPY_PROTECT_AGID) 2223 { 2224 status = STATUS_INVALID_PARAMETER; 2225 } 2226 else if (inputBuffer->NumberOfSectors > 255) 2227 { 2228 status = STATUS_INVALID_PARAMETER; 2229 } 2230 else if (inputBuffer->StartLba > MAXULONG) 2231 { 2232 status = STATUS_INVALID_PARAMETER; 2233 } 2234 } 2235 2236 return status; 2237 } 2238 2239 NTSTATUS 2240 RequestValidateExclusiveAccess( 2241 _In_ WDFREQUEST Request, 2242 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 2243 _Out_ size_t * DataLength 2244 ) 2245 /*++ 2246 2247 Routine Description: 2248 2249 Validate request of IOCTL_CDROM_EXCLUSIVE_ACCESS 2250 2251 Arguments: 2252 2253 Request - request to be handled 2254 RequestParameters - request parameter 2255 DataLength - transferred data length 2256 2257 Return Value: 2258 2259 NTSTATUS 2260 2261 --*/ 2262 { 2263 NTSTATUS status = STATUS_SUCCESS; 2264 PCDROM_EXCLUSIVE_ACCESS exclusiveAccess = NULL; 2265 2266 *DataLength = 0; 2267 2268 if (KeGetCurrentIrql() != PASSIVE_LEVEL) 2269 { 2270 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "RequestValidateExclusiveAccess: IOCTL must be called at passive level.\n")); 2271 status = STATUS_INVALID_DEVICE_REQUEST; 2272 } 2273 else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(CDROM_EXCLUSIVE_ACCESS)) 2274 { 2275 2276 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "RequestValidateExclusiveAccess: Input buffer too small\n")); 2277 status = STATUS_INFO_LENGTH_MISMATCH; 2278 } 2279 2280 if (NT_SUCCESS(status)) 2281 { 2282 status = WdfRequestRetrieveInputBuffer(Request, 2283 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 2284 &exclusiveAccess, 2285 NULL); 2286 } 2287 2288 if (NT_SUCCESS(status)) 2289 { 2290 switch (exclusiveAccess->RequestType) 2291 { 2292 case ExclusiveAccessQueryState: 2293 { 2294 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < 2295 sizeof(CDROM_EXCLUSIVE_LOCK_STATE)) 2296 { 2297 // 2298 // Output buffer too small. 2299 // 2300 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "RequestValidateExclusiveAccess: Output buffer too small\n")); 2301 *DataLength = sizeof(CDROM_EXCLUSIVE_LOCK_STATE); 2302 status = STATUS_BUFFER_TOO_SMALL; 2303 } 2304 break; 2305 } 2306 2307 case ExclusiveAccessLockDevice: 2308 { 2309 if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < 2310 sizeof(CDROM_EXCLUSIVE_LOCK)) 2311 { 2312 // 2313 // Input buffer too small 2314 // 2315 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "RequestValidateExclusiveAccess: Input buffer too small\n")); 2316 status = STATUS_INFO_LENGTH_MISMATCH; 2317 } 2318 break; 2319 } 2320 case ExclusiveAccessUnlockDevice: 2321 { 2322 // 2323 // Nothing to check 2324 // 2325 break; 2326 } 2327 2328 default: 2329 { 2330 // 2331 // Unknown request type. 2332 // 2333 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "RequestValidateExclusiveAccess: Invalid request type\n")); 2334 status = STATUS_INVALID_PARAMETER; 2335 } 2336 } 2337 } 2338 2339 return status; 2340 } 2341 2342 _IRQL_requires_max_(APC_LEVEL) 2343 NTSTATUS 2344 RequestHandleExclusiveAccessQueryLockState( 2345 _In_ WDFDEVICE Device, 2346 _In_ WDFREQUEST Request 2347 ) 2348 /*++ 2349 2350 Routine Description: 2351 2352 Handle request of IOCTL_CDROM_EXCLUSIVE_ACCESS with ExclusiveAccessQueryState 2353 2354 Arguments: 2355 2356 DeviceExtension - device context 2357 Request - request to be handled 2358 RequestParameters - request parameter 2359 DataLength - transferred data length 2360 2361 Return Value: 2362 2363 NTSTATUS 2364 2365 --*/ 2366 { 2367 NTSTATUS status = STATUS_SUCCESS; 2368 PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); 2369 PCDROM_DATA cdData = &deviceExtension->DeviceAdditionalData; 2370 PCDROM_EXCLUSIVE_LOCK_STATE exclusiveLockState = NULL; 2371 2372 PAGED_CODE(); 2373 2374 status = WdfRequestRetrieveOutputBuffer(Request, 2375 sizeof(CDROM_EXCLUSIVE_LOCK_STATE), 2376 &exclusiveLockState, 2377 NULL); 2378 NT_ASSERT(NT_SUCCESS(status)); 2379 2380 RtlZeroMemory(exclusiveLockState, sizeof(CDROM_EXCLUSIVE_LOCK_STATE)); 2381 2382 if (EXCLUSIVE_MODE(cdData)) 2383 { 2384 // Device is locked for exclusive use 2385 exclusiveLockState->LockState = TRUE; 2386 2387 RtlCopyMemory(&exclusiveLockState->CallerName, 2388 &cdData->CallerName, 2389 CDROM_EXCLUSIVE_CALLER_LENGTH); 2390 2391 } 2392 else 2393 { 2394 // Device is not locked 2395 exclusiveLockState->LockState = FALSE; 2396 } 2397 2398 RequestCompletion(deviceExtension, Request, status, sizeof(CDROM_EXCLUSIVE_LOCK_STATE)); 2399 2400 return status; 2401 } 2402 2403 _IRQL_requires_max_(APC_LEVEL) 2404 NTSTATUS 2405 RequestHandleExclusiveAccessLockDevice( 2406 _In_ WDFDEVICE Device, 2407 _In_ WDFREQUEST Request 2408 ) 2409 /*++ 2410 2411 Routine Description: 2412 2413 Handle request of IOCTL_CDROM_EXCLUSIVE_ACCESS with ExclusiveAccessLockDevice 2414 2415 Arguments: 2416 2417 DeviceExtension - device context 2418 Request - request to be handled 2419 RequestParameters - request parameter 2420 DataLength - transferred data length 2421 2422 Return Value: 2423 2424 NTSTATUS 2425 2426 --*/ 2427 { 2428 NTSTATUS status = STATUS_SUCCESS; 2429 PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); 2430 PCDROM_DATA cdData = &deviceExtension->DeviceAdditionalData; 2431 PCDROM_EXCLUSIVE_LOCK exclusiveLock = NULL; 2432 PIO_ERROR_LOG_PACKET logEntry; 2433 2434 WDFFILEOBJECT fileObject = NULL; 2435 ULONG idx = 0; 2436 ULONG nameLength = 0; 2437 2438 PAGED_CODE(); 2439 2440 fileObject = WdfRequestGetFileObject(Request); 2441 2442 if (fileObject == NULL) 2443 { 2444 status = STATUS_INVALID_HANDLE; 2445 2446 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, 2447 "RequestHandleExclusiveAccessLockDevice: FileObject is NULL, cannot grant exclusive access\n")); 2448 } 2449 2450 if (NT_SUCCESS(status)) 2451 { 2452 status = WdfRequestRetrieveInputBuffer(Request, 2453 sizeof(CDROM_EXCLUSIVE_LOCK), 2454 &exclusiveLock, 2455 NULL); 2456 } 2457 2458 if (NT_SUCCESS(status)) 2459 { 2460 // Validate the caller name string 2461 for (idx = 0; (idx < CDROM_EXCLUSIVE_CALLER_LENGTH) && (exclusiveLock->CallerName[idx] != '\0'); idx++) 2462 { 2463 if (!ValidChar(exclusiveLock->CallerName[idx])) 2464 { 2465 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, 2466 "RequestHandleExclusiveAccessLockDevice: Invalid characters in caller name\n")); 2467 // error out 2468 status = STATUS_INVALID_PARAMETER; 2469 break; 2470 } 2471 } 2472 } 2473 2474 if (NT_SUCCESS(status)) 2475 { 2476 if ((idx == 0) || (idx >= CDROM_EXCLUSIVE_CALLER_LENGTH)) 2477 { 2478 2479 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, 2480 "RequestHandleExclusiveAccessLockDevice: Not a valid null terminated string.\n")); 2481 //error out 2482 status = STATUS_INVALID_PARAMETER; 2483 } 2484 else 2485 { 2486 nameLength = idx+1; // Add 1 for the NULL character 2487 NT_ASSERT(nameLength <= CDROM_EXCLUSIVE_CALLER_LENGTH); 2488 } 2489 } 2490 2491 // If the file system is still mounted on this device fail the request, 2492 // unless the force lock flag is set. 2493 if (NT_SUCCESS(status)) 2494 { 2495 if ((TEST_FLAG(exclusiveLock->Access.Flags, CDROM_LOCK_IGNORE_VOLUME) == FALSE) && 2496 IsVolumeMounted(deviceExtension->DeviceObject)) 2497 { 2498 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, 2499 "RequestHandleExclusiveAccessLockDevice: Unable to lock device, file system mounted\n")); 2500 status = STATUS_INVALID_DEVICE_STATE; 2501 } 2502 } 2503 2504 // Lock the device for exclusive access if the device is not already locked 2505 if (NT_SUCCESS(status)) 2506 { 2507 if (InterlockedCompareExchangePointer((PVOID)&cdData->ExclusiveOwner, (PVOID)fileObject, NULL) == NULL) 2508 { 2509 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 2510 "RequestHandleExclusiveAccessLockDevice: Entering exclusive mode! Device locked by file object %p\n", fileObject)); 2511 2512 // Zero out the CallerName before storing it in the extension 2513 RtlZeroMemory(&cdData->CallerName, CDROM_EXCLUSIVE_CALLER_LENGTH); 2514 RtlCopyMemory(&cdData->CallerName, 2515 &exclusiveLock->CallerName, 2516 nameLength); 2517 2518 // Send Exclusive Lock notification 2519 DeviceSendNotification(deviceExtension, 2520 &GUID_IO_CDROM_EXCLUSIVE_LOCK, 2521 0, 2522 NULL); 2523 2524 // Log an informational event with the caller name 2525 logEntry = IoAllocateErrorLogEntry( 2526 deviceExtension->DeviceObject, 2527 sizeof(IO_ERROR_LOG_PACKET) + CDROM_EXCLUSIVE_CALLER_LENGTH); 2528 2529 if (logEntry != NULL) 2530 { 2531 PUCHAR dumpDataPtr = (PUCHAR) logEntry->DumpData; 2532 2533 logEntry->FinalStatus = STATUS_SUCCESS; 2534 logEntry->ErrorCode = IO_CDROM_EXCLUSIVE_LOCK; 2535 logEntry->SequenceNumber = 0; 2536 logEntry->MajorFunctionCode = IRP_MJ_DEVICE_CONTROL; 2537 logEntry->IoControlCode = IOCTL_CDROM_EXCLUSIVE_ACCESS; 2538 logEntry->RetryCount = 0; 2539 logEntry->UniqueErrorValue = 0x1; 2540 logEntry->DumpDataSize = CDROM_EXCLUSIVE_CALLER_LENGTH; 2541 2542 RtlCopyMemory(dumpDataPtr, 2543 (PUCHAR)&cdData->CallerName, 2544 CDROM_EXCLUSIVE_CALLER_LENGTH); 2545 2546 // Write the error log packet. 2547 IoWriteErrorLogEntry(logEntry); 2548 } 2549 2550 } 2551 else 2552 { 2553 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, 2554 "RequestHandleExclusiveAccessLockDevice: Unable to lock device, device already locked.\n")); 2555 2556 status = STATUS_ACCESS_DENIED; 2557 } 2558 } 2559 2560 RequestCompletion(deviceExtension, Request, status, 0); 2561 2562 return status; 2563 } 2564 2565 _IRQL_requires_max_(APC_LEVEL) 2566 NTSTATUS 2567 RequestHandleExclusiveAccessUnlockDevice( 2568 _In_ WDFDEVICE Device, 2569 _In_ WDFREQUEST Request 2570 ) 2571 /*++ 2572 2573 Routine Description: 2574 2575 Handle request of IOCTL_CDROM_EXCLUSIVE_ACCESS with ExclusiveAccessUnlockDevice 2576 2577 Arguments: 2578 2579 Device - device handle 2580 Request - request to be handled 2581 2582 Return Value: 2583 2584 NTSTATUS 2585 2586 --*/ 2587 { 2588 NTSTATUS status = STATUS_SUCCESS; 2589 PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); 2590 PCDROM_EXCLUSIVE_ACCESS exclusiveAccess = NULL; 2591 WDFFILEOBJECT fileObject = NULL; 2592 2593 PAGED_CODE(); 2594 2595 fileObject = WdfRequestGetFileObject(Request); 2596 2597 if (fileObject == NULL) 2598 { 2599 // The device can be unlocked from exclusive mode only via the file object which locked it. 2600 status = STATUS_INVALID_HANDLE; 2601 2602 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, 2603 "RequestHandleExclusiveAccessUnlockDevice: FileObject is NULL, cannot release exclusive access\n")); 2604 } 2605 2606 if (NT_SUCCESS(status)) 2607 { 2608 status = WdfRequestRetrieveInputBuffer(Request, 2609 sizeof(PCDROM_EXCLUSIVE_ACCESS), 2610 &exclusiveAccess, 2611 NULL); 2612 } 2613 2614 if (NT_SUCCESS(status)) 2615 { 2616 status = DeviceUnlockExclusive(deviceExtension, fileObject, 2617 TEST_FLAG(exclusiveAccess->Flags, CDROM_NO_MEDIA_NOTIFICATIONS)); 2618 2619 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "RequestHandleExclusiveAccessUnlockDevice: Device unlocked\n")); 2620 } 2621 2622 RequestCompletion(deviceExtension, Request, status, 0); 2623 2624 return status; 2625 } 2626 2627 NTSTATUS 2628 RequestHandleQueryPropertyRetrieveCachedData( 2629 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 2630 _In_ WDFREQUEST Request, 2631 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 2632 _Out_ size_t * DataLength 2633 ) 2634 /*++ 2635 2636 Routine Description: 2637 2638 Handle request of IOCTL_STORAGE_QUERY_PROPERTY when the required data is cached. 2639 2640 Arguments: 2641 2642 DeviceExtension - device context 2643 Request - request to be handled 2644 RequestParameters - request parameter 2645 DataLength - transferred data length 2646 2647 Return Value: 2648 2649 NTSTATUS 2650 2651 --*/ 2652 { 2653 NTSTATUS status = STATUS_SUCCESS; 2654 PSTORAGE_PROPERTY_QUERY inputBuffer = NULL; 2655 2656 *DataLength = 0; 2657 2658 status = WdfRequestRetrieveInputBuffer(Request, 2659 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 2660 &inputBuffer, 2661 NULL); 2662 2663 if (NT_SUCCESS(status)) 2664 { 2665 if (inputBuffer->PropertyId == StorageDeviceProperty) 2666 { 2667 // check output buffer length 2668 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength == 0) 2669 { 2670 // According to MSDN, an output buffer of size 0 can be used to determine if a property exists 2671 // so this must be a success case with no data transferred 2672 *DataLength = 0; 2673 status = STATUS_SUCCESS; 2674 } 2675 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_DESCRIPTOR_HEADER)) 2676 { 2677 // Buffer too small 2678 *DataLength = DeviceExtension->DeviceDescriptor->Size; 2679 status = STATUS_BUFFER_TOO_SMALL; 2680 } 2681 else 2682 { 2683 PSTORAGE_DEVICE_DESCRIPTOR outputDescriptor = NULL; 2684 CHAR* localDescriptorBuffer = (CHAR*)DeviceExtension->DeviceDescriptor; 2685 2686 status = WdfRequestRetrieveOutputBuffer(Request, 2687 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 2688 &outputDescriptor, 2689 NULL); 2690 2691 if (NT_SUCCESS(status)) 2692 { 2693 // transfer as much data out as the buffer will allow 2694 *DataLength = min(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 2695 DeviceExtension->DeviceDescriptor->Size); 2696 2697 RtlCopyMemory(outputDescriptor, 2698 DeviceExtension->DeviceDescriptor, 2699 *DataLength); 2700 2701 // walk through and update offset variables to reflect data that didn't make it into the output buffer 2702 if ((*DataLength >= RTL_SIZEOF_THROUGH_FIELD(STORAGE_DEVICE_DESCRIPTOR, VendorIdOffset)) && 2703 (DeviceExtension->DeviceDescriptor->VendorIdOffset != 0) && 2704 (DeviceExtension->DeviceDescriptor->VendorIdOffset != 0xFFFFFFFF)) 2705 { 2706 // set VendorIdOffset appropriately 2707 if (*DataLength < 2708 (DeviceExtension->DeviceDescriptor->VendorIdOffset + strlen(localDescriptorBuffer + DeviceExtension->DeviceDescriptor->VendorIdOffset))) 2709 { 2710 outputDescriptor->VendorIdOffset = 0; 2711 } 2712 } 2713 2714 if ((*DataLength >= RTL_SIZEOF_THROUGH_FIELD(STORAGE_DEVICE_DESCRIPTOR, ProductIdOffset)) && 2715 (DeviceExtension->DeviceDescriptor->ProductIdOffset != 0) && 2716 (DeviceExtension->DeviceDescriptor->ProductIdOffset != 0xFFFFFFFF)) 2717 { 2718 // set ProductIdOffset appropriately 2719 if (*DataLength < 2720 (DeviceExtension->DeviceDescriptor->ProductIdOffset + strlen(localDescriptorBuffer + DeviceExtension->DeviceDescriptor->ProductIdOffset))) 2721 { 2722 outputDescriptor->ProductIdOffset = 0; 2723 } 2724 } 2725 2726 if ((*DataLength >= RTL_SIZEOF_THROUGH_FIELD(STORAGE_DEVICE_DESCRIPTOR, ProductRevisionOffset)) && 2727 (DeviceExtension->DeviceDescriptor->ProductRevisionOffset != 0) && 2728 (DeviceExtension->DeviceDescriptor->ProductRevisionOffset != 0xFFFFFFFF)) 2729 { 2730 // set ProductRevisionOffset appropriately 2731 if (*DataLength < 2732 (DeviceExtension->DeviceDescriptor->ProductRevisionOffset + strlen(localDescriptorBuffer + DeviceExtension->DeviceDescriptor->ProductRevisionOffset))) 2733 { 2734 outputDescriptor->ProductRevisionOffset = 0; 2735 } 2736 } 2737 2738 if ((*DataLength >= RTL_SIZEOF_THROUGH_FIELD(STORAGE_DEVICE_DESCRIPTOR, SerialNumberOffset)) && 2739 (DeviceExtension->DeviceDescriptor->SerialNumberOffset != 0) && 2740 (DeviceExtension->DeviceDescriptor->SerialNumberOffset != 0xFFFFFFFF)) 2741 { 2742 // set SerialNumberOffset appropriately 2743 if (*DataLength < 2744 (DeviceExtension->DeviceDescriptor->SerialNumberOffset + strlen(localDescriptorBuffer + DeviceExtension->DeviceDescriptor->SerialNumberOffset))) 2745 { 2746 // NOTE: setting this to 0 since that is what most port drivers do 2747 // [this could cause issues with SCSI port devices whose clients expect -1 in this field] 2748 outputDescriptor->SerialNumberOffset = 0; 2749 } 2750 } 2751 status = STATUS_SUCCESS; 2752 } 2753 } 2754 } //end of StorageDeviceProperty 2755 else if (inputBuffer->PropertyId == StorageAdapterProperty) 2756 { 2757 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength == 0) 2758 { 2759 // According to MSDN, an output buffer of size 0 can be used to determine if a property exists 2760 // so this must be a success case with no data transferred 2761 *DataLength = 0; 2762 status = STATUS_SUCCESS; 2763 } 2764 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_DESCRIPTOR_HEADER)) 2765 { 2766 // Buffer too small 2767 *DataLength = DeviceExtension->AdapterDescriptor->Size; 2768 status = STATUS_BUFFER_TOO_SMALL; 2769 } 2770 else 2771 { 2772 PSTORAGE_ADAPTER_DESCRIPTOR outputDescriptor = NULL; 2773 2774 status = WdfRequestRetrieveOutputBuffer(Request, 2775 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 2776 &outputDescriptor, 2777 NULL); 2778 if (NT_SUCCESS(status)) 2779 { 2780 // copy as much data out as the buffer will allow 2781 *DataLength = min(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 2782 DeviceExtension->AdapterDescriptor->Size); 2783 2784 RtlCopyMemory(outputDescriptor, 2785 DeviceExtension->AdapterDescriptor, 2786 *DataLength); 2787 2788 // set status 2789 status = STATUS_SUCCESS; 2790 } 2791 } 2792 } 2793 } 2794 2795 return status; 2796 } 2797 2798 NTSTATUS 2799 RequestHandleQueryPropertyDeviceUniqueId( 2800 _In_ WDFDEVICE Device, 2801 _In_ WDFREQUEST Request 2802 ) 2803 /*++ 2804 2805 Routine Description: 2806 2807 Handle request of IOCTL_STORAGE_QUERY_PROPERTY with StorageDeviceUniqueIdProperty. 2808 2809 Arguments: 2810 2811 DeviceExtension - device context 2812 Request - request to be handled 2813 RequestParameters - request parameter 2814 DataLength - transferred data length 2815 2816 Return Value: 2817 2818 NTSTATUS 2819 2820 --*/ 2821 { 2822 NTSTATUS status = STATUS_SUCCESS; 2823 PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); 2824 PSTORAGE_PROPERTY_QUERY inputBuffer = NULL; 2825 PSTORAGE_DESCRIPTOR_HEADER descHeader = NULL; 2826 size_t outLength = 0; 2827 WDF_REQUEST_PARAMETERS requestParameters; 2828 2829 // Get the Request parameters 2830 WDF_REQUEST_PARAMETERS_INIT(&requestParameters); 2831 WdfRequestGetParameters(Request, &requestParameters); 2832 2833 status = WdfRequestRetrieveInputBuffer(Request, 2834 requestParameters.Parameters.DeviceIoControl.InputBufferLength, 2835 &inputBuffer, 2836 NULL); 2837 2838 if (NT_SUCCESS(status)) 2839 { 2840 BOOLEAN overflow = FALSE; 2841 BOOLEAN infoFound = FALSE; 2842 2843 // Must run at less then dispatch. 2844 if (KeGetCurrentIrql() >= DISPATCH_LEVEL) 2845 { 2846 NT_ASSERT(FALSE); 2847 outLength = 0; 2848 status = STATUS_INVALID_LEVEL; 2849 } 2850 else if (inputBuffer->QueryType == PropertyExistsQuery) 2851 { 2852 outLength = 0; 2853 status = STATUS_SUCCESS; 2854 } 2855 else if (inputBuffer->QueryType != PropertyStandardQuery) 2856 { 2857 outLength = 0; 2858 status = STATUS_NOT_SUPPORTED; 2859 } 2860 else 2861 { 2862 // Check AdditionalParameters validity. 2863 if (inputBuffer->AdditionalParameters[0] == DUID_INCLUDE_SOFTWARE_IDS) 2864 { 2865 // Do nothing 2866 } 2867 else if (inputBuffer->AdditionalParameters[0] == DUID_HARDWARE_IDS_ONLY) 2868 { 2869 // Do nothing 2870 } 2871 else 2872 { 2873 outLength = 0; 2874 status = STATUS_INVALID_PARAMETER; 2875 } 2876 2877 if (NT_SUCCESS(status) && 2878 (outLength < sizeof(STORAGE_DESCRIPTOR_HEADER))) 2879 { 2880 outLength = 0; 2881 status = STATUS_INFO_LENGTH_MISMATCH; 2882 } 2883 } 2884 2885 // From this point forward the status depends on the overflow 2886 // and infoFound flags. 2887 if (NT_SUCCESS(status)) 2888 { 2889 outLength = requestParameters.Parameters.DeviceIoControl.OutputBufferLength; 2890 status = WdfRequestRetrieveOutputBuffer(Request, 2891 requestParameters.Parameters.DeviceIoControl.OutputBufferLength, 2892 &descHeader, 2893 NULL); 2894 } 2895 2896 if (NT_SUCCESS(status)) 2897 { 2898 RtlZeroMemory(descHeader, outLength); 2899 2900 descHeader->Version = DUID_VERSION_1; 2901 descHeader->Size = sizeof(STORAGE_DEVICE_UNIQUE_IDENTIFIER); 2902 2903 // Try to build device unique id from StorageDeviceIdProperty. 2904 status = RequestDuidGetDeviceIdProperty(deviceExtension, 2905 Request, 2906 requestParameters, 2907 &outLength); 2908 2909 if (status == STATUS_BUFFER_OVERFLOW) 2910 { 2911 overflow = TRUE; 2912 } 2913 2914 if (NT_SUCCESS(status)) 2915 { 2916 infoFound = TRUE; 2917 } 2918 2919 // Try to build device unique id from StorageDeviceProperty. 2920 status = RequestDuidGetDeviceProperty(deviceExtension, 2921 Request, 2922 requestParameters, 2923 &outLength); 2924 2925 if (status == STATUS_BUFFER_OVERFLOW) 2926 { 2927 overflow = TRUE; 2928 } 2929 2930 if (NT_SUCCESS(status)) 2931 { 2932 infoFound = TRUE; 2933 } 2934 2935 // Return overflow, success, or a generic error. 2936 if (overflow) 2937 { 2938 // If output buffer is STORAGE_DESCRIPTOR_HEADER, then return 2939 // success to the user. Otherwise, send an error so the user 2940 // knows a larger buffer is required. 2941 if (outLength == sizeof(STORAGE_DESCRIPTOR_HEADER)) 2942 { 2943 status = STATUS_SUCCESS; 2944 } 2945 else 2946 { 2947 outLength = (ULONG)WdfRequestGetInformation(Request); 2948 status = STATUS_BUFFER_OVERFLOW; 2949 } 2950 2951 } 2952 else if (infoFound) 2953 { 2954 status = STATUS_SUCCESS; 2955 2956 // Exercise the compare routine. This should always succeed. 2957 NT_ASSERT(DuidExactMatch == CompareStorageDuids((PSTORAGE_DEVICE_UNIQUE_IDENTIFIER)descHeader, 2958 (PSTORAGE_DEVICE_UNIQUE_IDENTIFIER)descHeader)); 2959 2960 } 2961 else 2962 { 2963 status = STATUS_NOT_FOUND; 2964 } 2965 } 2966 } 2967 2968 RequestCompletion(deviceExtension, Request, status, outLength); 2969 2970 return status; 2971 } 2972 2973 NTSTATUS 2974 RequestHandleQueryPropertyWriteCache( 2975 _In_ WDFDEVICE Device, 2976 _In_ WDFREQUEST Request 2977 ) 2978 /*++ 2979 2980 Routine Description: 2981 2982 Handle request of IOCTL_STORAGE_QUERY_PROPERTY with StorageDeviceWriteCacheProperty. 2983 2984 Arguments: 2985 2986 DeviceExtension - device context 2987 Request - request to be handled 2988 2989 Return Value: 2990 2991 NTSTATUS 2992 2993 --*/ 2994 { 2995 NTSTATUS status = STATUS_SUCCESS; 2996 PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); 2997 PSTORAGE_PROPERTY_QUERY query = NULL; 2998 PSTORAGE_WRITE_CACHE_PROPERTY writeCache = NULL; 2999 PMODE_PARAMETER_HEADER modeData = NULL; 3000 PMODE_CACHING_PAGE pageData = NULL; 3001 size_t length = 0; 3002 ULONG information = 0; 3003 PSCSI_REQUEST_BLOCK srb = NULL; 3004 WDF_REQUEST_PARAMETERS requestParameters; 3005 3006 // Get the Request parameters 3007 WDF_REQUEST_PARAMETERS_INIT(&requestParameters); 3008 WdfRequestGetParameters(Request, &requestParameters); 3009 3010 status = WdfRequestRetrieveInputBuffer(Request, 3011 requestParameters.Parameters.DeviceIoControl.InputBufferLength, 3012 &query, 3013 NULL); 3014 3015 if (NT_SUCCESS(status)) 3016 { 3017 3018 // Must run at less then dispatch. 3019 if (KeGetCurrentIrql() >= DISPATCH_LEVEL) 3020 { 3021 NT_ASSERT(FALSE); 3022 status = STATUS_INVALID_LEVEL; 3023 } 3024 else if (query->QueryType == PropertyExistsQuery) 3025 { 3026 information = 0; 3027 status = STATUS_SUCCESS; 3028 } 3029 else if (query->QueryType != PropertyStandardQuery) 3030 { 3031 status = STATUS_NOT_SUPPORTED; 3032 } 3033 } 3034 3035 if (NT_SUCCESS(status)) 3036 { 3037 length = requestParameters.Parameters.DeviceIoControl.OutputBufferLength; 3038 3039 if (length < sizeof(STORAGE_DESCRIPTOR_HEADER)) 3040 { 3041 status = STATUS_INFO_LENGTH_MISMATCH; 3042 } 3043 } 3044 3045 if (NT_SUCCESS(status)) 3046 { 3047 status = WdfRequestRetrieveOutputBuffer(Request, 3048 requestParameters.Parameters.DeviceIoControl.OutputBufferLength, 3049 &writeCache, 3050 NULL); 3051 } 3052 3053 if (NT_SUCCESS(status)) 3054 { 3055 RtlZeroMemory(writeCache, length); 3056 3057 // Set version and required size. 3058 writeCache->Version = sizeof(STORAGE_WRITE_CACHE_PROPERTY); 3059 writeCache->Size = sizeof(STORAGE_WRITE_CACHE_PROPERTY); 3060 3061 if (length < sizeof(STORAGE_WRITE_CACHE_PROPERTY)) 3062 { 3063 // caller only wants header information, bail out. 3064 information = sizeof(STORAGE_DESCRIPTOR_HEADER); 3065 status = STATUS_SUCCESS; 3066 3067 RequestCompletion(deviceExtension, Request, status, information); 3068 return status; 3069 } 3070 } 3071 3072 if (NT_SUCCESS(status)) 3073 { 3074 srb = ExAllocatePoolWithTag(NonPagedPoolNx, 3075 sizeof(SCSI_REQUEST_BLOCK) + 3076 (sizeof(ULONG_PTR) * 2), 3077 CDROM_TAG_SRB); 3078 3079 if (srb == NULL) 3080 { 3081 status = STATUS_INSUFFICIENT_RESOURCES; 3082 } 3083 } 3084 3085 if (NT_SUCCESS(status)) 3086 { 3087 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK)); 3088 3089 // Set known values 3090 writeCache->NVCacheEnabled = FALSE; 3091 writeCache->UserDefinedPowerProtection = TEST_FLAG(deviceExtension->DeviceFlags, DEV_POWER_PROTECTED); 3092 3093 // Check for flush cache support by sending a sync cache command 3094 // to the device. 3095 3096 // Set timeout value and mark the request as not being a tagged request. 3097 srb->Length = SCSI_REQUEST_BLOCK_SIZE; 3098 srb->TimeOutValue = TimeOutValueGetCapValue(deviceExtension->TimeOutValue, 4); 3099 srb->QueueTag = SP_UNTAGGED; 3100 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; 3101 srb->SrbFlags = deviceExtension->SrbFlags; 3102 3103 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 3104 srb->CdbLength = 10; 3105 3106 srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE; 3107 3108 status = DeviceSendSrbSynchronously(Device, 3109 srb, 3110 NULL, 3111 0, 3112 TRUE, //flush drive cache 3113 Request); 3114 3115 if (NT_SUCCESS(status)) 3116 { 3117 writeCache->FlushCacheSupported = TRUE; 3118 } 3119 else 3120 { 3121 // Device does not support sync cache 3122 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 3123 "RequestHandleQueryPropertyWriteCache: Synchronize cache failed with status 0x%X\n", status)); 3124 writeCache->FlushCacheSupported = FALSE; 3125 3126 // Reset the status if there was any failure 3127 status = STATUS_SUCCESS; 3128 } 3129 3130 modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, 3131 MODE_PAGE_DATA_SIZE, 3132 CDROM_TAG_MODE_DATA); 3133 3134 if (modeData == NULL) 3135 { 3136 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, 3137 "RequestHandleQueryPropertyWriteCache: Unable to allocate mode data buffer\n")); 3138 status = STATUS_INSUFFICIENT_RESOURCES; 3139 } 3140 } 3141 3142 if (NT_SUCCESS(status)) 3143 { 3144 RtlZeroMemory(modeData, MODE_PAGE_DATA_SIZE); 3145 3146 length = DeviceRetrieveModeSenseUsingScratch(deviceExtension, 3147 (PCHAR)modeData, 3148 MODE_PAGE_DATA_SIZE, 3149 MODE_PAGE_CACHING, 3150 MODE_SENSE_CURRENT_VALUES); 3151 3152 if (length < sizeof(MODE_PARAMETER_HEADER)) 3153 { 3154 // Retry the request in case of a check condition. 3155 length = DeviceRetrieveModeSenseUsingScratch(deviceExtension, 3156 (PCHAR)modeData, 3157 MODE_PAGE_DATA_SIZE, 3158 MODE_PAGE_CACHING, 3159 MODE_SENSE_CURRENT_VALUES); 3160 3161 if (length < sizeof(MODE_PARAMETER_HEADER)) 3162 { 3163 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, "RequestHandleQueryPropertyWriteCache: Mode Sense failed\n")); 3164 status = STATUS_IO_DEVICE_ERROR; 3165 } 3166 } 3167 } 3168 3169 if (NT_SUCCESS(status)) 3170 { 3171 // If the length is greater than length indicated by the mode data reset 3172 // the data to the mode data. 3173 if (length > (ULONG) (modeData->ModeDataLength + 1)) 3174 { 3175 length = modeData->ModeDataLength + 1; 3176 } 3177 3178 // Look for caching page in the returned mode page data. 3179 pageData = ModeSenseFindSpecificPage((PCHAR)modeData, 3180 length, 3181 MODE_PAGE_CACHING, 3182 TRUE); 3183 3184 // Check if valid caching page exists. 3185 if (pageData == NULL) 3186 { 3187 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "RequestHandleQueryPropertyWriteCache: Unable to find caching mode page.\n")); 3188 3189 // Set write cache value as unknown. 3190 writeCache->WriteCacheEnabled = WriteCacheEnableUnknown; 3191 writeCache->WriteCacheType = WriteCacheTypeUnknown; 3192 } 3193 else 3194 { 3195 writeCache->WriteCacheEnabled = pageData->WriteCacheEnable 3196 ? WriteCacheEnabled 3197 : WriteCacheDisabled; 3198 3199 writeCache->WriteCacheType = pageData->WriteCacheEnable 3200 ? WriteCacheTypeWriteBack 3201 : WriteCacheTypeUnknown; 3202 } 3203 3204 // Check write through support. 3205 if (modeData->DeviceSpecificParameter & MODE_DSP_FUA_SUPPORTED) 3206 { 3207 writeCache->WriteThroughSupported = WriteThroughSupported; 3208 } 3209 else 3210 { 3211 writeCache->WriteThroughSupported = WriteThroughNotSupported; 3212 } 3213 3214 // Get the changeable caching mode page and check write cache is changeable. 3215 RtlZeroMemory(modeData, MODE_PAGE_DATA_SIZE); 3216 3217 length = DeviceRetrieveModeSenseUsingScratch(deviceExtension, 3218 (PCHAR) modeData, 3219 MODE_PAGE_DATA_SIZE, 3220 MODE_PAGE_CACHING, 3221 MODE_SENSE_CHANGEABLE_VALUES); 3222 3223 if (length < sizeof(MODE_PARAMETER_HEADER)) 3224 { 3225 // Retry the request in case of a check condition. 3226 length = DeviceRetrieveModeSenseUsingScratch(deviceExtension, 3227 (PCHAR) modeData, 3228 MODE_PAGE_DATA_SIZE, 3229 MODE_PAGE_CACHING, 3230 MODE_SENSE_CHANGEABLE_VALUES); 3231 3232 if (length < sizeof(MODE_PARAMETER_HEADER)) 3233 { 3234 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "RequestHandleQueryPropertyWriteCache: Mode Sense failed\n")); 3235 3236 // If the device fails to return changeable pages, then 3237 // set the write cache changeable value to unknown. 3238 writeCache->WriteCacheChangeable = WriteCacheChangeUnknown; 3239 information = sizeof(STORAGE_WRITE_CACHE_PROPERTY); 3240 } 3241 } 3242 } 3243 3244 if (NT_SUCCESS(status)) 3245 { 3246 // If the length is greater than length indicated by the mode data reset 3247 // the data to the mode data. 3248 if (length > (ULONG) (modeData->ModeDataLength + 1)) 3249 { 3250 length = modeData->ModeDataLength + 1; 3251 } 3252 3253 // Look for caching page in the returned mode page data. 3254 pageData = ModeSenseFindSpecificPage((PCHAR)modeData, 3255 length, 3256 MODE_PAGE_CACHING, 3257 TRUE); 3258 // Check if valid caching page exists. 3259 if (pageData == NULL) 3260 { 3261 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "RequestHandleQueryPropertyWriteCache: Unable to find caching mode page.\n")); 3262 3263 // Set write cache changeable value to unknown. 3264 writeCache->WriteCacheChangeable = WriteCacheChangeUnknown; 3265 } 3266 else 3267 { 3268 writeCache->WriteCacheChangeable = pageData->WriteCacheEnable 3269 ? WriteCacheChangeable 3270 : WriteCacheNotChangeable; 3271 } 3272 3273 information = sizeof(STORAGE_WRITE_CACHE_PROPERTY); 3274 3275 } 3276 3277 FREE_POOL(srb); 3278 FREE_POOL(modeData); 3279 3280 RequestCompletion(deviceExtension, Request, status, information); 3281 3282 return status; 3283 } 3284 3285 NTSTATUS 3286 RequestValidateDvdReadKey( 3287 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 3288 _In_ WDFREQUEST Request, 3289 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 3290 _Out_ size_t * DataLength 3291 ) 3292 /*++ 3293 3294 Routine Description: 3295 3296 Validate request of IOCTL_DVD_READ_KEY 3297 3298 Arguments: 3299 3300 DeviceExtension - device context 3301 Request - request to be handled 3302 RequestParameters - request parameter 3303 DataLength - transferred data length 3304 3305 Return Value: 3306 3307 NTSTATUS 3308 3309 --*/ 3310 { 3311 NTSTATUS status = STATUS_SUCCESS; 3312 PDVD_COPY_PROTECT_KEY keyParameters = NULL; 3313 ULONG keyLength = 0; 3314 3315 *DataLength = 0; 3316 3317 status = WdfRequestRetrieveInputBuffer(Request, 3318 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 3319 &keyParameters, 3320 NULL); 3321 3322 if (NT_SUCCESS(status)) 3323 { 3324 if(RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(DVD_COPY_PROTECT_KEY)) 3325 { 3326 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, 3327 "DvdDeviceControl: EstablishDriveKey - challenge " 3328 "key buffer too small\n")); 3329 status = STATUS_INVALID_PARAMETER; 3330 } 3331 } 3332 3333 if (NT_SUCCESS(status)) 3334 { 3335 switch(keyParameters->KeyType) 3336 { 3337 3338 case DvdChallengeKey: 3339 { 3340 C_ASSERT(sizeof(DVD_COPY_PROTECT_KEY) <= DVD_CHALLENGE_KEY_LENGTH); 3341 keyLength = DVD_CHALLENGE_KEY_LENGTH; 3342 break; 3343 } 3344 case DvdBusKey1: 3345 case DvdBusKey2: 3346 { 3347 C_ASSERT(sizeof(DVD_COPY_PROTECT_KEY) <= DVD_BUS_KEY_LENGTH); 3348 keyLength = DVD_BUS_KEY_LENGTH; 3349 break; 3350 } 3351 case DvdTitleKey: 3352 { 3353 C_ASSERT(sizeof(DVD_COPY_PROTECT_KEY) <= DVD_TITLE_KEY_LENGTH); 3354 keyLength = DVD_TITLE_KEY_LENGTH; 3355 break; 3356 } 3357 case DvdAsf: 3358 { 3359 C_ASSERT(sizeof(DVD_COPY_PROTECT_KEY) <= DVD_ASF_LENGTH); 3360 keyLength = DVD_ASF_LENGTH; 3361 break; 3362 } 3363 case DvdDiskKey: 3364 { 3365 C_ASSERT(sizeof(DVD_COPY_PROTECT_KEY) <= DVD_DISK_KEY_LENGTH); 3366 keyLength = DVD_DISK_KEY_LENGTH; 3367 break; 3368 } 3369 case DvdGetRpcKey: 3370 { 3371 C_ASSERT(sizeof(DVD_COPY_PROTECT_KEY) <= DVD_RPC_KEY_LENGTH); 3372 keyLength = DVD_RPC_KEY_LENGTH; 3373 break; 3374 } 3375 default: 3376 { 3377 keyLength = sizeof(DVD_COPY_PROTECT_KEY); 3378 break; 3379 } 3380 } 3381 3382 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < keyLength) 3383 { 3384 3385 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, 3386 "DvdDeviceControl: EstablishDriveKey - output " 3387 "buffer too small\n")); 3388 status = STATUS_BUFFER_TOO_SMALL; 3389 *DataLength = keyLength; 3390 } 3391 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength & 3392 DeviceExtension->AdapterDescriptor->AlignmentMask) 3393 { 3394 status = STATUS_INVALID_PARAMETER; 3395 } 3396 else if (DeviceExtension->DeviceAdditionalData.DriveDeviceType != FILE_DEVICE_DVD) 3397 { 3398 // reject the request if it's not a DVD device. 3399 status = STATUS_INVALID_DEVICE_REQUEST; 3400 } 3401 } 3402 3403 return status; 3404 } 3405 3406 3407 NTSTATUS 3408 RequestValidateDvdEndSession( 3409 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 3410 _In_ WDFREQUEST Request, 3411 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 3412 _Out_ size_t * DataLength 3413 ) 3414 /*++ 3415 3416 Routine Description: 3417 3418 Handle request of IOCTL_DVD_END_SESSION 3419 3420 Arguments: 3421 3422 DeviceExtension - device context 3423 Request - request to be handled 3424 RequestParameters - request parameter 3425 DataLength - transferred data length 3426 3427 Return Value: 3428 3429 NTSTATUS 3430 3431 --*/ 3432 { 3433 NTSTATUS status = STATUS_SUCCESS; 3434 PDVD_SESSION_ID sessionId = NULL; 3435 3436 UNREFERENCED_PARAMETER(DeviceExtension); 3437 3438 *DataLength = 0; 3439 3440 status = WdfRequestRetrieveInputBuffer(Request, 3441 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 3442 &sessionId, 3443 NULL); 3444 3445 if (NT_SUCCESS(status)) 3446 { 3447 if(RequestParameters.Parameters.DeviceIoControl.InputBufferLength < 3448 sizeof(DVD_SESSION_ID)) 3449 { 3450 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, 3451 "DvdDeviceControl: EndSession - input buffer too " 3452 "small\n")); 3453 status = STATUS_INVALID_PARAMETER; 3454 } 3455 } 3456 3457 return status; 3458 } 3459 3460 3461 NTSTATUS 3462 RequestValidateAacsEndSession( 3463 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 3464 _In_ WDFREQUEST Request, 3465 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 3466 _Out_ size_t * DataLength 3467 ) 3468 /*++ 3469 3470 Routine Description: 3471 3472 Validate request of IOCTL_AACS_END_SESSION 3473 3474 Arguments: 3475 3476 DeviceExtension - device context 3477 Request - request to be handled 3478 RequestParameters - request parameter 3479 DataLength - transferred data length 3480 3481 Return Value: 3482 3483 NTSTATUS 3484 3485 --*/ 3486 { 3487 NTSTATUS status = STATUS_SUCCESS; 3488 PDVD_SESSION_ID sessionId = NULL; 3489 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); 3490 3491 *DataLength = 0; 3492 3493 status = WdfRequestRetrieveInputBuffer(Request, 3494 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 3495 &sessionId, 3496 NULL); 3497 3498 if (NT_SUCCESS(status)) 3499 { 3500 if (!cdData->Mmc.IsAACS) 3501 { 3502 status = STATUS_INVALID_DEVICE_REQUEST; 3503 } 3504 else if(RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(DVD_SESSION_ID)) 3505 { 3506 status = STATUS_INVALID_PARAMETER; 3507 } 3508 } 3509 3510 return status; 3511 } 3512 3513 3514 NTSTATUS 3515 RequestValidateEnableStreaming( 3516 _In_ WDFREQUEST Request, 3517 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 3518 _Out_ size_t * DataLength 3519 ) 3520 /*++ 3521 3522 Routine Description: 3523 3524 Validates an IOCTL_CDROM_ENABLE_STREAMING request 3525 3526 Arguments: 3527 3528 Request - request to be handled 3529 RequestParameters - request parameters 3530 DataLength - transferred data length 3531 3532 Return Value: 3533 3534 NTSTATUS 3535 3536 --*/ 3537 { 3538 NTSTATUS status = STATUS_SUCCESS; 3539 3540 PCDROM_STREAMING_CONTROL inputBuffer = NULL; 3541 3542 *DataLength = 0; 3543 3544 if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < 3545 sizeof(CDROM_STREAMING_CONTROL)) 3546 { 3547 status = STATUS_INFO_LENGTH_MISMATCH; 3548 } 3549 3550 if (NT_SUCCESS(status)) 3551 { 3552 // Get the request type using CDROM_STREAMING_CONTROL structure 3553 status = WdfRequestRetrieveInputBuffer(Request, 3554 sizeof(CDROM_STREAMING_CONTROL), 3555 &inputBuffer, 3556 NULL); 3557 } 3558 3559 if (NT_SUCCESS(status)) 3560 { 3561 if (inputBuffer->RequestType != CdromStreamingDisable && 3562 inputBuffer->RequestType != CdromStreamingEnableForReadOnly && 3563 inputBuffer->RequestType != CdromStreamingEnableForWriteOnly && 3564 inputBuffer->RequestType != CdromStreamingEnableForReadWrite) 3565 { 3566 // Unknown request type 3567 status = STATUS_INVALID_PARAMETER; 3568 } 3569 } 3570 3571 return status; 3572 } 3573 3574 3575 NTSTATUS 3576 RequestValidateSendOpcInformation( 3577 _In_ WDFREQUEST Request, 3578 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 3579 _Out_ size_t * DataLength 3580 ) 3581 /*++ 3582 3583 Routine Description: 3584 3585 Validates an IOCTL_CDROM_SEND_OPC_INFORMATION request 3586 3587 Arguments: 3588 3589 Request - request to be handled 3590 RequestParameters - request parameters 3591 DataLength - transferred data length 3592 3593 Return Value: 3594 3595 NTSTATUS 3596 3597 --*/ 3598 { 3599 NTSTATUS status = STATUS_SUCCESS; 3600 3601 PCDROM_SIMPLE_OPC_INFO inputBuffer = NULL; 3602 3603 *DataLength = 0; 3604 3605 if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < 3606 sizeof(CDROM_SIMPLE_OPC_INFO)) 3607 { 3608 status = STATUS_INFO_LENGTH_MISMATCH; 3609 } 3610 3611 if (NT_SUCCESS(status)) 3612 { 3613 // Get the request type using CDROM_SIMPLE_OPC_INFO structure 3614 status = WdfRequestRetrieveInputBuffer(Request, 3615 sizeof(CDROM_SIMPLE_OPC_INFO), 3616 &inputBuffer, 3617 NULL); 3618 } 3619 3620 if (NT_SUCCESS(status)) 3621 { 3622 if (inputBuffer->RequestType != SimpleOpcInfo) 3623 { 3624 // Unknown request type 3625 status = STATUS_INVALID_PARAMETER; 3626 } 3627 } 3628 3629 return status; 3630 } 3631 3632 3633 NTSTATUS 3634 RequestValidateGetPerformance( 3635 _In_ WDFREQUEST Request, 3636 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 3637 _Out_ size_t * DataLength 3638 ) 3639 /*++ 3640 3641 Routine Description: 3642 3643 Validates an IOCTL_CDROM_GET_PERFORMANCE request 3644 3645 Arguments: 3646 3647 Request - request to be handled 3648 RequestParameters - request parameter 3649 DataLength - transferred data length 3650 3651 Return Value: 3652 3653 NTSTATUS 3654 3655 --*/ 3656 { 3657 NTSTATUS status = STATUS_SUCCESS; 3658 PCDROM_WRITE_SPEED_REQUEST writeSpeedRequest = NULL; 3659 PCDROM_PERFORMANCE_REQUEST performanceRequest = NULL; 3660 3661 *DataLength = 0; 3662 3663 // CDROM_WRITE_SPEED_REQUEST is the smallest performance request that we support. 3664 // We use it to retrieve request type and then check input length more carefully 3665 // on a per request type basis. 3666 if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < 3667 sizeof(CDROM_WRITE_SPEED_REQUEST)) 3668 { 3669 status = STATUS_INFO_LENGTH_MISMATCH; 3670 } 3671 3672 if (NT_SUCCESS(status)) 3673 { 3674 status = WdfRequestRetrieveInputBuffer(Request, 3675 sizeof(CDROM_WRITE_SPEED_REQUEST), 3676 (PVOID*)&writeSpeedRequest, 3677 NULL); 3678 } 3679 3680 if (NT_SUCCESS(status)) 3681 { 3682 if (writeSpeedRequest->RequestType == CdromPerformanceRequest) 3683 { 3684 // CDROM_PERFORMANCE_REQUEST is bigger than CDROM_WRITE_SPEED_REQUEST, 3685 // so we perform more checks and retrieve more bytes through WDF. 3686 if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < 3687 sizeof(CDROM_PERFORMANCE_REQUEST)) 3688 { 3689 status = STATUS_INFO_LENGTH_MISMATCH; 3690 } 3691 if (NT_SUCCESS(status)) 3692 { 3693 status = WdfRequestRetrieveInputBuffer(Request, 3694 sizeof(CDROM_PERFORMANCE_REQUEST), 3695 &performanceRequest, 3696 NULL); 3697 } 3698 3699 if (!NT_SUCCESS(status)) 3700 { 3701 // just pass the status code from above 3702 } 3703 // validate all enum-type fields of CDROM_PERFORMANCE_REQUEST 3704 else if (performanceRequest->PerformanceType != CdromReadPerformance && 3705 performanceRequest->PerformanceType != CdromWritePerformance) 3706 { 3707 status = STATUS_INVALID_PARAMETER; 3708 } 3709 else if (performanceRequest->Exceptions != CdromNominalPerformance && 3710 performanceRequest->Exceptions != CdromEntirePerformanceList && 3711 performanceRequest->Exceptions != CdromPerformanceExceptionsOnly) 3712 { 3713 status = STATUS_INVALID_PARAMETER; 3714 } 3715 else if (performanceRequest->Tolerance != Cdrom10Nominal20Exceptions) 3716 { 3717 status = STATUS_INVALID_PARAMETER; 3718 } 3719 } 3720 else if (writeSpeedRequest->RequestType == CdromWriteSpeedRequest) 3721 { 3722 // No additional checks here: all remaining fields are ignored 3723 // if RequestType == CdromWriteSpeedRequest. 3724 } 3725 else 3726 { 3727 status = STATUS_INVALID_PARAMETER; 3728 } 3729 } 3730 3731 // finally, check output buffer length 3732 if (NT_SUCCESS(status)) 3733 { 3734 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < 3735 sizeof(CDROM_PERFORMANCE_HEADER)) 3736 { 3737 status = STATUS_BUFFER_TOO_SMALL; 3738 *DataLength = sizeof(CDROM_PERFORMANCE_HEADER); 3739 } 3740 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > 3741 ((USHORT)-1)) 3742 { 3743 status = STATUS_INVALID_PARAMETER; 3744 } 3745 } 3746 3747 return status; 3748 } 3749 3750 3751 _IRQL_requires_max_(APC_LEVEL) 3752 PCDB 3753 RequestGetScsiPassThroughCdb( 3754 _In_ PIRP Irp 3755 ) 3756 /*++ 3757 3758 Routine Description: 3759 3760 Get the CDB structure from the SCSI pass through 3761 3762 Arguments: 3763 3764 Irp - request to be handled 3765 3766 Return Value: 3767 3768 PCDB 3769 3770 --*/ 3771 { 3772 PCDB cdb = NULL; 3773 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); 3774 ULONG inputBufferLength = 0; 3775 PVOID inputBuffer = NULL; 3776 BOOLEAN legacyPassThrough = FALSE; 3777 3778 PAGED_CODE(); 3779 3780 if (((currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH) || 3781 (currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT) || 3782 (currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_EX) || 3783 (currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT_EX)) && 3784 (Irp->AssociatedIrp.SystemBuffer != NULL)) 3785 { 3786 inputBufferLength = currentIrpStack->Parameters.DeviceIoControl.InputBufferLength; 3787 inputBuffer = Irp->AssociatedIrp.SystemBuffer; 3788 legacyPassThrough = TRUE; 3789 3790 if ((currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_EX) || 3791 (currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT_EX)) 3792 { 3793 legacyPassThrough = FALSE; 3794 } 3795 3796 // 3797 // If this is a 32 bit application running on 64 bit then thunk the 3798 // input structures to grab the cdb. 3799 // 3800 3801 #if BUILD_WOW64_ENABLED && defined(_WIN64) 3802 3803 if (IoIs32bitProcess(Irp)) 3804 { 3805 if (legacyPassThrough) 3806 { 3807 if (inputBufferLength >= sizeof(SCSI_PASS_THROUGH32)) 3808 { 3809 cdb = (PCDB)((PSCSI_PASS_THROUGH32)inputBuffer)->Cdb; 3810 } 3811 } 3812 else 3813 { 3814 if (inputBufferLength >= sizeof(SCSI_PASS_THROUGH32_EX)) 3815 { 3816 cdb = (PCDB)((PSCSI_PASS_THROUGH32_EX)inputBuffer)->Cdb; 3817 } 3818 } 3819 3820 } 3821 else 3822 3823 #endif 3824 3825 { 3826 if (legacyPassThrough) 3827 { 3828 if (inputBufferLength >= sizeof(SCSI_PASS_THROUGH)) 3829 { 3830 cdb = (PCDB)((PSCSI_PASS_THROUGH)inputBuffer)->Cdb; 3831 } 3832 } 3833 else 3834 { 3835 if (inputBufferLength >= sizeof(SCSI_PASS_THROUGH_EX)) 3836 { 3837 cdb = (PCDB)((PSCSI_PASS_THROUGH_EX)inputBuffer)->Cdb; 3838 } 3839 } 3840 } 3841 } 3842 3843 return cdb; 3844 } 3845 3846 _IRQL_requires_max_(APC_LEVEL) 3847 NTSTATUS 3848 RequestHandleScsiPassThrough( 3849 _In_ WDFDEVICE Device, 3850 _In_ WDFREQUEST Request 3851 ) 3852 /*++ 3853 3854 Routine Description: 3855 3856 Handle request of IOCTL_SCSI_PASS_THROUGH 3857 IOCTL_SCSI_PASS_THROUGH_DIRECT 3858 3859 The function sets the MinorFunction field of irpStack, 3860 and pass the request to lower level driver. 3861 3862 Arguments: 3863 3864 Device - device object 3865 Request - request to be handled 3866 3867 Return Value: 3868 3869 NTSTATUS 3870 3871 --*/ 3872 { 3873 NTSTATUS status = STATUS_UNSUCCESSFUL; 3874 PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); 3875 PIRP irp = WdfRequestWdmGetIrp(Request); 3876 PZERO_POWER_ODD_INFO zpoddInfo = deviceExtension->ZeroPowerODDInfo; 3877 PCDB cdb = NULL; 3878 BOOLEAN isSoftEject = FALSE; 3879 3880 #if DBG 3881 PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request); 3882 #endif 3883 3884 3885 PAGED_CODE(); 3886 3887 #if DBG 3888 // SPTI is always processed in sync manner. 3889 NT_ASSERT(requestContext->SyncRequired); 3890 #endif 3891 3892 if ((zpoddInfo != NULL) && 3893 (zpoddInfo->LoadingMechanism == LOADING_MECHANISM_TRAY) && 3894 (zpoddInfo->Load == 0)) // Drawer 3895 { 3896 cdb = RequestGetScsiPassThroughCdb(irp); 3897 3898 if ((cdb != NULL) && 3899 (cdb->AsByte[0] == SCSIOP_START_STOP_UNIT) && 3900 (cdb->START_STOP.LoadEject == 1) && 3901 (cdb->START_STOP.Start == 0)) 3902 { 3903 isSoftEject = TRUE; 3904 } 3905 } 3906 3907 WdfRequestFormatRequestUsingCurrentType(Request); 3908 3909 // Special for SPTI, set the MinorFunction. 3910 { 3911 PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(irp); 3912 3913 nextStack->MinorFunction = 1; 3914 } 3915 3916 3917 status = RequestSend(deviceExtension, 3918 Request, 3919 deviceExtension->IoTarget, 3920 WDF_REQUEST_SEND_OPTION_SYNCHRONOUS, 3921 NULL); 3922 3923 3924 if (!NT_SUCCESS(status) && 3925 (isSoftEject != FALSE)) 3926 { 3927 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, 3928 "RequestHandleScsiPassThrough: soft eject detected, device marked as active\n")); 3929 3930 DeviceMarkActive(deviceExtension, TRUE, FALSE); 3931 } 3932 3933 RequestCompletion(deviceExtension, Request, status, WdfRequestGetInformation(Request)); 3934 3935 return status; 3936 } 3937 3938 NTSTATUS 3939 RequestHandleMountQueryUniqueId( 3940 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 3941 _In_ WDFREQUEST Request, 3942 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 3943 _Out_ size_t * DataLength 3944 ) 3945 /*++ 3946 3947 Routine Description: 3948 3949 Handle request of IOCTL_MOUNTDEV_QUERY_UNIQUE_ID 3950 3951 Arguments: 3952 3953 DeviceExtension - device context 3954 Request - request to be handled 3955 RequestParameters - request parameter 3956 DataLength - transferred data length 3957 3958 Return Value: 3959 3960 NTSTATUS 3961 3962 --*/ 3963 { 3964 NTSTATUS status = STATUS_SUCCESS; 3965 PMOUNTDEV_UNIQUE_ID uniqueId = NULL; 3966 3967 *DataLength = 0; 3968 3969 if (!DeviceExtension->MountedDeviceInterfaceName.Buffer) 3970 { 3971 status = STATUS_INVALID_PARAMETER; 3972 } 3973 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTDEV_UNIQUE_ID)) 3974 { 3975 *DataLength = sizeof(MOUNTDEV_UNIQUE_ID); 3976 status = STATUS_BUFFER_TOO_SMALL; 3977 } 3978 3979 if (NT_SUCCESS(status)) 3980 { 3981 status = WdfRequestRetrieveOutputBuffer(Request, 3982 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 3983 &uniqueId, 3984 NULL); 3985 } 3986 3987 if (NT_SUCCESS(status)) 3988 { 3989 RtlZeroMemory(uniqueId, RequestParameters.Parameters.DeviceIoControl.OutputBufferLength); 3990 3991 uniqueId->UniqueIdLength = DeviceExtension->MountedDeviceInterfaceName.Length; 3992 3993 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < 3994 (sizeof(USHORT) + DeviceExtension->MountedDeviceInterfaceName.Length)) 3995 { 3996 *DataLength = sizeof(MOUNTDEV_UNIQUE_ID); 3997 status = STATUS_BUFFER_OVERFLOW; 3998 } 3999 } 4000 4001 if (NT_SUCCESS(status)) 4002 { 4003 RtlCopyMemory(uniqueId->UniqueId, 4004 DeviceExtension->MountedDeviceInterfaceName.Buffer, 4005 uniqueId->UniqueIdLength); 4006 4007 *DataLength = sizeof(USHORT) + uniqueId->UniqueIdLength; 4008 status = STATUS_SUCCESS; 4009 } 4010 4011 return status; 4012 } 4013 4014 NTSTATUS 4015 RequestHandleMountQueryDeviceName( 4016 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 4017 _In_ WDFREQUEST Request, 4018 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 4019 _Out_ size_t * DataLength 4020 ) 4021 /*++ 4022 4023 Routine Description: 4024 4025 Handle request of IOCTL_MOUNTDEV_QUERY_DEVICE_NAME 4026 4027 Arguments: 4028 4029 DeviceExtension - device context 4030 Request - request to be handled 4031 RequestParameters - request parameter 4032 DataLength - transferred data length 4033 4034 Return Value: 4035 4036 NTSTATUS 4037 4038 --*/ 4039 { 4040 NTSTATUS status = STATUS_SUCCESS; 4041 PMOUNTDEV_NAME name = NULL; 4042 4043 *DataLength = 0; 4044 4045 NT_ASSERT(DeviceExtension->DeviceName.Buffer); 4046 4047 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTDEV_NAME)) 4048 { 4049 status = STATUS_BUFFER_TOO_SMALL; 4050 *DataLength = sizeof(MOUNTDEV_NAME); 4051 } 4052 4053 if (NT_SUCCESS(status)) 4054 { 4055 status = WdfRequestRetrieveOutputBuffer(Request, 4056 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 4057 &name, 4058 NULL); 4059 } 4060 4061 if (NT_SUCCESS(status)) 4062 { 4063 RtlZeroMemory(name, RequestParameters.Parameters.DeviceIoControl.OutputBufferLength); 4064 name->NameLength = DeviceExtension->DeviceName.Length; 4065 4066 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < 4067 (sizeof(USHORT) + DeviceExtension->DeviceName.Length)) 4068 { 4069 status = STATUS_BUFFER_OVERFLOW; 4070 *DataLength = sizeof(MOUNTDEV_NAME); 4071 } 4072 } 4073 4074 if (NT_SUCCESS(status)) 4075 { 4076 RtlCopyMemory(name->Name, 4077 DeviceExtension->DeviceName.Buffer, 4078 name->NameLength); 4079 4080 status = STATUS_SUCCESS; 4081 *DataLength = sizeof(USHORT) + name->NameLength; 4082 } 4083 4084 return status; 4085 } 4086 4087 NTSTATUS 4088 RequestHandleMountQuerySuggestedLinkName( 4089 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 4090 _In_ WDFREQUEST Request, 4091 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 4092 _Out_ size_t * DataLength 4093 ) 4094 /*++ 4095 4096 Routine Description: 4097 4098 Handle request of IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME 4099 4100 Arguments: 4101 4102 DeviceExtension - device context 4103 Request - request to be handled 4104 RequestParameters - request parameter 4105 DataLength - transferred data length 4106 4107 Return Value: 4108 4109 NTSTATUS 4110 4111 --*/ 4112 { 4113 NTSTATUS status = STATUS_SUCCESS; 4114 4115 PMOUNTDEV_SUGGESTED_LINK_NAME suggestedName = NULL; 4116 4117 WCHAR driveLetterNameBuffer[10] = {0}; 4118 RTL_QUERY_REGISTRY_TABLE queryTable[2] = {0}; 4119 PWSTR valueName = NULL; 4120 UNICODE_STRING driveLetterName = {0}; 4121 4122 *DataLength = 0; 4123 4124 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < 4125 sizeof(MOUNTDEV_SUGGESTED_LINK_NAME)) 4126 { 4127 status = STATUS_BUFFER_TOO_SMALL; 4128 *DataLength = sizeof(MOUNTDEV_SUGGESTED_LINK_NAME); 4129 } 4130 4131 if (NT_SUCCESS(status)) 4132 { 4133 valueName = ExAllocatePoolWithTag(PagedPool, 4134 DeviceExtension->DeviceName.Length + sizeof(WCHAR), 4135 CDROM_TAG_STRINGS); 4136 if (valueName == NULL) 4137 { 4138 status = STATUS_INSUFFICIENT_RESOURCES; 4139 } 4140 } 4141 4142 if (NT_SUCCESS(status)) 4143 { 4144 RtlCopyMemory(valueName, 4145 DeviceExtension->DeviceName.Buffer, 4146 DeviceExtension->DeviceName.Length); 4147 valueName[DeviceExtension->DeviceName.Length/sizeof(WCHAR)] = 0; 4148 4149 driveLetterName.Buffer = driveLetterNameBuffer; 4150 driveLetterName.MaximumLength = sizeof(driveLetterNameBuffer); 4151 driveLetterName.Length = 0; 4152 4153 queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK; 4154 queryTable[0].Name = valueName; 4155 queryTable[0].EntryContext = &driveLetterName; 4156 queryTable[0].DefaultType = (REG_SZ << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE; 4157 4158 status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 4159 L"\\Registry\\Machine\\System\\DISK", // why hard coded? 4160 queryTable, NULL, NULL); 4161 } 4162 4163 if (NT_SUCCESS(status)) 4164 { 4165 if ((driveLetterName.Length == 4) && 4166 (driveLetterName.Buffer[0] == '%') && 4167 (driveLetterName.Buffer[1] == ':')) 4168 { 4169 driveLetterName.Buffer[0] = 0xFF; 4170 } 4171 else if ((driveLetterName.Length != 4) || 4172 (driveLetterName.Buffer[0] < FirstDriveLetter) || 4173 (driveLetterName.Buffer[0] > LastDriveLetter) || 4174 (driveLetterName.Buffer[1] != ':')) 4175 { 4176 status = STATUS_NOT_FOUND; 4177 } 4178 } 4179 4180 if (NT_SUCCESS(status)) 4181 { 4182 status = WdfRequestRetrieveOutputBuffer(Request, 4183 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 4184 &suggestedName, 4185 NULL); 4186 } 4187 4188 if (NT_SUCCESS(status)) 4189 { 4190 RtlZeroMemory(suggestedName, RequestParameters.Parameters.DeviceIoControl.OutputBufferLength); 4191 suggestedName->UseOnlyIfThereAreNoOtherLinks = TRUE; 4192 suggestedName->NameLength = 28; 4193 4194 *DataLength = FIELD_OFFSET(MOUNTDEV_SUGGESTED_LINK_NAME, Name) + 28; 4195 4196 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < *DataLength) 4197 { 4198 *DataLength = sizeof(MOUNTDEV_SUGGESTED_LINK_NAME); 4199 status = STATUS_BUFFER_OVERFLOW; 4200 } 4201 } 4202 4203 if (NT_SUCCESS(status)) 4204 { 4205 RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE, 4206 L"\\Registry\\Machine\\System\\DISK", 4207 valueName); 4208 4209 RtlCopyMemory(suggestedName->Name, L"\\DosDevices\\", 24); 4210 suggestedName->Name[12] = driveLetterName.Buffer[0]; 4211 suggestedName->Name[13] = ':'; 4212 } 4213 4214 FREE_POOL(valueName); 4215 4216 return status; 4217 } 4218 4219 _IRQL_requires_max_(APC_LEVEL) 4220 NTSTATUS 4221 RequestHandleReadTOC( 4222 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 4223 _In_ WDFREQUEST Request, 4224 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 4225 _Out_ size_t * DataLength 4226 ) 4227 /*++ 4228 4229 Routine Description: 4230 4231 Handle request of IOCTL_CDROM_READ_TOC 4232 IOCTL_CDROM_GET_LAST_SESSION 4233 4234 Arguments: 4235 4236 DeviceExtension - device context 4237 Request - request to be handled 4238 RequestParameters - request parameter 4239 DataLength - transferred data length 4240 4241 Return Value: 4242 4243 NTSTATUS 4244 4245 --*/ 4246 { 4247 NTSTATUS status = STATUS_SUCCESS; 4248 VOID* outputBuffer = NULL; 4249 4250 PAGED_CODE (); 4251 4252 *DataLength = 0; 4253 4254 if (DeviceIsPlayActive(DeviceExtension->Device)) 4255 { 4256 status = STATUS_DEVICE_BUSY; 4257 } 4258 4259 if (NT_SUCCESS(status)) 4260 { 4261 status = WdfRequestRetrieveOutputBuffer(Request, 4262 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 4263 &outputBuffer, 4264 NULL); 4265 } 4266 4267 // handle the request 4268 if (NT_SUCCESS(status)) 4269 { 4270 size_t transferSize; 4271 CDB cdb; 4272 4273 transferSize = min(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, sizeof(CDROM_TOC)); 4274 4275 RtlZeroMemory(outputBuffer, transferSize); 4276 4277 ScratchBuffer_BeginUse(DeviceExtension); 4278 4279 RtlZeroMemory(&cdb, sizeof(CDB)); 4280 // Set up the CDB 4281 if (RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_LAST_SESSION) 4282 { 4283 // Set format to return first and last session numbers. 4284 cdb.READ_TOC.Format2 = CDROM_READ_TOC_EX_FORMAT_SESSION; 4285 } 4286 else 4287 { 4288 // Use MSF addressing 4289 cdb.READ_TOC.Msf = 1; 4290 } 4291 4292 cdb.READ_TOC.OperationCode = SCSIOP_READ_TOC; 4293 cdb.READ_TOC.AllocationLength[0] = (UCHAR)(transferSize >> 8); 4294 cdb.READ_TOC.AllocationLength[1] = (UCHAR)(transferSize & 0xFF); 4295 4296 status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, (ULONG)transferSize, TRUE, &cdb, 10); 4297 4298 if (NT_SUCCESS(status)) 4299 { 4300 *DataLength = DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength; 4301 RtlCopyMemory(outputBuffer, 4302 DeviceExtension->ScratchContext.ScratchBuffer, 4303 *DataLength); 4304 } 4305 4306 ScratchBuffer_EndUse(DeviceExtension); 4307 } 4308 4309 return status; 4310 } 4311 4312 _IRQL_requires_max_(APC_LEVEL) 4313 NTSTATUS 4314 RequestHandleReadTocEx( 4315 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 4316 _In_ WDFREQUEST Request, 4317 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 4318 _Out_ size_t * DataLength 4319 ) 4320 /*++ 4321 4322 Routine Description: 4323 4324 Handle request of IOCTL_CDROM_READ_TOC_EX 4325 4326 Arguments: 4327 4328 DeviceExtension - device context 4329 Request - request to be handled 4330 RequestParameters - request parameter 4331 DataLength - transferred data length 4332 4333 Return Value: 4334 4335 NTSTATUS 4336 4337 --*/ 4338 { 4339 NTSTATUS status = STATUS_SUCCESS; 4340 PCDROM_READ_TOC_EX inputBuffer = NULL; 4341 VOID* outputBuffer = NULL; 4342 4343 PAGED_CODE (); 4344 4345 *DataLength = 0; 4346 4347 if (DeviceIsPlayActive(DeviceExtension->Device)) 4348 { 4349 status = STATUS_DEVICE_BUSY; 4350 } 4351 4352 if (NT_SUCCESS(status)) 4353 { 4354 status = WdfRequestRetrieveInputBuffer(Request, 4355 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 4356 &inputBuffer, 4357 NULL); 4358 } 4359 4360 if (NT_SUCCESS(status)) 4361 { 4362 status = WdfRequestRetrieveOutputBuffer(Request, 4363 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 4364 &outputBuffer, 4365 NULL); 4366 } 4367 4368 // handle the request 4369 if (NT_SUCCESS(status)) 4370 { 4371 size_t transferSize; 4372 CDB cdb; 4373 4374 transferSize = min(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, MAXUSHORT); 4375 ScratchBuffer_BeginUse(DeviceExtension); 4376 4377 RtlZeroMemory(&cdb, sizeof(CDB)); 4378 // Set up the CDB 4379 cdb.READ_TOC.OperationCode = SCSIOP_READ_TOC; 4380 cdb.READ_TOC.Msf = inputBuffer->Msf; 4381 cdb.READ_TOC.Format2 = inputBuffer->Format; 4382 cdb.READ_TOC.StartingTrack = inputBuffer->SessionTrack; 4383 cdb.READ_TOC.AllocationLength[0] = (UCHAR)(transferSize >> 8); 4384 cdb.READ_TOC.AllocationLength[1] = (UCHAR)(transferSize & 0xFF); 4385 4386 status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, (ULONG)transferSize, TRUE, &cdb, 10); 4387 4388 if (NT_SUCCESS(status)) 4389 { 4390 if (DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength < MINIMUM_CDROM_READ_TOC_EX_SIZE) 4391 { 4392 *DataLength = 0; 4393 status = STATUS_INVALID_DEVICE_REQUEST; 4394 } 4395 else 4396 { 4397 *DataLength = DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength; 4398 RtlCopyMemory(outputBuffer, 4399 DeviceExtension->ScratchContext.ScratchBuffer, 4400 *DataLength); 4401 } 4402 } 4403 4404 ScratchBuffer_EndUse(DeviceExtension); 4405 } 4406 4407 return status; 4408 } 4409 4410 4411 _IRQL_requires_max_(APC_LEVEL) 4412 VOID 4413 GetConfigurationDataConversionTypeAllToTypeOne( 4414 _In_ FEATURE_NUMBER RequestedFeature, 4415 _In_ PSCSI_REQUEST_BLOCK Srb, 4416 _Out_ size_t * DataLength 4417 ) 4418 /*++ 4419 4420 Routine Description: 4421 4422 Some CDROM devices do not handle the GET CONFIGURATION commands with 4423 TYPE ONE request. The command will time out causing a bus reset. 4424 To avoid this problem we set a device flag during start device if the device 4425 fails a TYPE ONE request. If this flag is set the TYPE ONE requests will be 4426 tried as TYPE ALL request and the data will be converted to TYPE ONE format 4427 in this routine. 4428 4429 Arguments: 4430 4431 RequestedFeature - device context 4432 Srb - request to be handled 4433 DataLength - transfer data length 4434 4435 Return Value: 4436 4437 NTSTATUS 4438 4439 --*/ 4440 { 4441 PFEATURE_HEADER featureHeader = NULL; 4442 FEATURE_NUMBER thisFeature; 4443 ULONG totalLength = 0; 4444 ULONG featureLength = 0; 4445 ULONG headerLength = 0; 4446 4447 PGET_CONFIGURATION_HEADER header = NULL; 4448 4449 PAGED_CODE (); 4450 4451 *DataLength = 0; 4452 4453 if (Srb->DataTransferLength < RTL_SIZEOF_THROUGH_FIELD(GET_CONFIGURATION_HEADER, DataLength)) 4454 { 4455 // do not have valid data. 4456 return; 4457 } 4458 4459 // Calculate the length of valid data available in the 4460 // capabilities buffer from the DataLength field 4461 header = (PGET_CONFIGURATION_HEADER) Srb->DataBuffer; 4462 REVERSE_BYTES(&totalLength, header->DataLength); 4463 4464 totalLength += RTL_SIZEOF_THROUGH_FIELD(GET_CONFIGURATION_HEADER, DataLength); 4465 4466 // Make sure the we have enough data in the SRB 4467 totalLength = min(totalLength, Srb->DataTransferLength); 4468 4469 // If we have received enough data from the device 4470 // check for the given feature. 4471 if (totalLength >= (sizeof(GET_CONFIGURATION_HEADER) + sizeof(FEATURE_HEADER))) 4472 { 4473 // Feature information is present. Verify the feature. 4474 featureHeader = (PFEATURE_HEADER)((PUCHAR)Srb->DataBuffer + sizeof(GET_CONFIGURATION_HEADER)); 4475 4476 thisFeature = (featureHeader->FeatureCode[0] << 8) | (featureHeader->FeatureCode[1]); 4477 4478 if (thisFeature == RequestedFeature) 4479 { 4480 // Calculate the feature length 4481 featureLength = sizeof(FEATURE_HEADER) + featureHeader->AdditionalLength; 4482 } 4483 } 4484 4485 // Calculate the total size 4486 totalLength = sizeof(GET_CONFIGURATION_HEADER) + featureLength; 4487 4488 headerLength = totalLength - 4489 RTL_SIZEOF_THROUGH_FIELD(GET_CONFIGURATION_HEADER, DataLength); 4490 4491 REVERSE_BYTES(header->DataLength, &headerLength); 4492 4493 *DataLength = totalLength; 4494 4495 return; 4496 } 4497 4498 _IRQL_requires_max_(APC_LEVEL) 4499 VOID 4500 GetConfigurationDataSynthesize( 4501 _In_reads_bytes_(InputBufferSize) PVOID InputBuffer, 4502 _In_ ULONG InputBufferSize, 4503 _Out_writes_bytes_(OutputBufferSize) PVOID OutputBuffer, 4504 _In_ size_t OutputBufferSize, 4505 _In_ FEATURE_NUMBER StartingFeature, 4506 _In_ ULONG RequestType, 4507 _Out_ size_t * DataLength 4508 ) 4509 /*++ 4510 4511 Routine Description: 4512 4513 Get Configuration is a frequently used command, and we don't want it to wake 4514 up the device in case it is in Zero Power state. Before entering Zero Power state, 4515 the complete response of the command is saved in cache, and since the response 4516 is always the same in case there is no media, we can synthesize the response 4517 based on the user request. 4518 4519 Arguments: 4520 4521 InputBuffer - buffer containing cached command response 4522 InputBufferSize - size of above buffer 4523 OutputBuffer - buffer to fill in result 4524 OutputBufferSize - size of above buffer 4525 StartingFeature - requested Starting Feature Number 4526 RequestType - requested Request Type 4527 DataLength - transfer data length 4528 4529 Return Value: 4530 4531 --*/ 4532 { 4533 PFEATURE_HEADER featureHeader = NULL; 4534 ULONG validLength = 0; 4535 ULONG featureLength = 0; 4536 ULONG headerLength = 0; 4537 PUCHAR buffer = NULL; 4538 ULONG bytesRemaining = 0; 4539 FEATURE_NUMBER featureCode = 0; 4540 BOOLEAN shouldCopy = FALSE; 4541 size_t copyLength = 0; 4542 size_t transferedLength = 0; 4543 size_t requiredLength = 0; 4544 4545 PGET_CONFIGURATION_HEADER header = NULL; 4546 4547 PAGED_CODE (); 4548 4549 if (InputBufferSize < sizeof (GET_CONFIGURATION_HEADER)) 4550 { 4551 // do not have valid data. 4552 *DataLength = 0; 4553 4554 return; 4555 } 4556 4557 // Calculate the length of valid data available in the 4558 // capabilities buffer from the DataLength field 4559 header = (PGET_CONFIGURATION_HEADER) InputBuffer; 4560 REVERSE_BYTES(&validLength, header->DataLength); 4561 4562 validLength += RTL_SIZEOF_THROUGH_FIELD(GET_CONFIGURATION_HEADER, DataLength); 4563 4564 // Make sure we have enough data 4565 validLength = min(validLength, InputBufferSize); 4566 4567 // Copy the header first 4568 copyLength = min(OutputBufferSize, sizeof (GET_CONFIGURATION_HEADER)); 4569 4570 RtlMoveMemory(OutputBuffer, 4571 InputBuffer, 4572 copyLength); 4573 4574 transferedLength = copyLength; 4575 requiredLength = sizeof (GET_CONFIGURATION_HEADER); 4576 4577 if (validLength > sizeof (GET_CONFIGURATION_HEADER)) 4578 { 4579 buffer = header->Data; 4580 bytesRemaining = validLength - sizeof (GET_CONFIGURATION_HEADER); 4581 4582 // Ignore incomplete feature descriptor 4583 while (bytesRemaining >= sizeof (FEATURE_HEADER)) 4584 { 4585 featureHeader = (PFEATURE_HEADER) buffer; 4586 shouldCopy = FALSE; 4587 4588 featureCode = (featureHeader->FeatureCode[0] << 8) | (featureHeader->FeatureCode[1]); 4589 featureLength = sizeof (FEATURE_HEADER) + featureHeader->AdditionalLength; 4590 4591 if (featureCode >= StartingFeature) 4592 { 4593 switch (RequestType) { 4594 4595 case SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL: 4596 4597 shouldCopy = TRUE; 4598 break; 4599 4600 case SCSI_GET_CONFIGURATION_REQUEST_TYPE_CURRENT: 4601 4602 if (featureHeader->Current) 4603 { 4604 shouldCopy = TRUE; 4605 } 4606 break; 4607 4608 case SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE: 4609 4610 if (featureCode == StartingFeature) 4611 { 4612 shouldCopy = TRUE; 4613 } 4614 break; 4615 4616 default: 4617 4618 break; 4619 } 4620 } 4621 4622 if (shouldCopy != FALSE) 4623 { 4624 copyLength = min(featureLength, bytesRemaining); 4625 copyLength = min(copyLength, OutputBufferSize - transferedLength); 4626 4627 RtlMoveMemory((PUCHAR) OutputBuffer + transferedLength, 4628 buffer, 4629 copyLength); 4630 4631 transferedLength += copyLength; 4632 requiredLength += featureLength; 4633 } 4634 4635 buffer += min(featureLength, bytesRemaining); 4636 bytesRemaining -= min(featureLength, bytesRemaining); 4637 } 4638 } 4639 4640 // Adjust Data Length field in header 4641 if (transferedLength >= RTL_SIZEOF_THROUGH_FIELD(GET_CONFIGURATION_HEADER, DataLength)) 4642 { 4643 headerLength = (ULONG) requiredLength - RTL_SIZEOF_THROUGH_FIELD(GET_CONFIGURATION_HEADER, DataLength); 4644 4645 header = (PGET_CONFIGURATION_HEADER) OutputBuffer; 4646 REVERSE_BYTES(header->DataLength, &headerLength); 4647 } 4648 4649 *DataLength = transferedLength; 4650 4651 return; 4652 } 4653 4654 4655 _IRQL_requires_max_(APC_LEVEL) 4656 NTSTATUS 4657 RequestHandleGetConfiguration( 4658 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 4659 _In_ WDFREQUEST Request, 4660 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 4661 _Out_ size_t * DataLength 4662 ) 4663 /*++ 4664 4665 Routine Description: 4666 4667 Handle request of IOCTL_CDROM_GET_CONFIGURATION 4668 4669 Arguments: 4670 4671 DeviceExtension - device context 4672 Request - request to be handled 4673 RequestParameters - request parameter 4674 DataLength - transferred data length 4675 4676 Return Value: 4677 4678 NTSTATUS 4679 4680 --*/ 4681 { 4682 NTSTATUS status = STATUS_SUCCESS; 4683 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); 4684 PGET_CONFIGURATION_IOCTL_INPUT inputBuffer = NULL; 4685 VOID* outputBuffer = NULL; 4686 size_t transferByteCount = 0; 4687 PZERO_POWER_ODD_INFO zpoddInfo = DeviceExtension->ZeroPowerODDInfo; 4688 BOOLEAN inZeroPowerState = FALSE; 4689 4690 PAGED_CODE (); 4691 4692 *DataLength = 0; 4693 4694 // 4695 if (!cdData->Mmc.IsMmc) 4696 { 4697 status = STATUS_INVALID_DEVICE_REQUEST; 4698 } 4699 else 4700 { 4701 status = WdfRequestRetrieveInputBuffer(Request, 4702 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 4703 &inputBuffer, 4704 NULL); 4705 } 4706 4707 if (NT_SUCCESS(status)) 4708 { 4709 status = WdfRequestRetrieveOutputBuffer(Request, 4710 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 4711 &outputBuffer, 4712 NULL); 4713 } 4714 4715 if (NT_SUCCESS(status)) 4716 { 4717 // If device is Zero Power state, there should be no media in device, thus we can synthesize the response 4718 // from our cache. Avoid waking up the device in this case. 4719 if ((zpoddInfo != NULL) && 4720 (zpoddInfo->InZeroPowerState != FALSE)) 4721 { 4722 inZeroPowerState = TRUE; 4723 } 4724 4725 if ((inZeroPowerState == FALSE) || 4726 (zpoddInfo->GetConfigurationBuffer == NULL)) 4727 { 4728 CDB cdb; 4729 4730 //The maximum number of bytes that a Drive may return 4731 //to describe its Features in one GET CONFIGURATION Command is 65,534 4732 transferByteCount = min(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, (MAXUSHORT - 1)); 4733 4734 // If this is a TYPE ONE request and if this device can't handle this 4735 // request, then we need to send TYPE ALL request to the device and 4736 // convert the data in the completion routine. If required allocate a big 4737 // buffer to get both configuration and feature header. 4738 if ((inputBuffer->RequestType == SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE) && 4739 TEST_FLAG(cdData->HackFlags, CDROM_HACK_BAD_TYPE_ONE_GET_CONFIG)) 4740 { 4741 transferByteCount = max(transferByteCount, 4742 sizeof(GET_CONFIGURATION_HEADER) + sizeof(FEATURE_HEADER)); 4743 } 4744 4745 ScratchBuffer_BeginUse(DeviceExtension); 4746 4747 RtlZeroMemory(&cdb, sizeof(CDB)); 4748 // Set up the CDB 4749 cdb.GET_CONFIGURATION.OperationCode = SCSIOP_GET_CONFIGURATION; 4750 cdb.GET_CONFIGURATION.AllocationLength[0] = (UCHAR)(transferByteCount >> 8); 4751 cdb.GET_CONFIGURATION.AllocationLength[1] = (UCHAR)(transferByteCount & 0xff); 4752 4753 cdb.GET_CONFIGURATION.StartingFeature[0] = (UCHAR)(inputBuffer->Feature >> 8); 4754 cdb.GET_CONFIGURATION.StartingFeature[1] = (UCHAR)(inputBuffer->Feature & 0xff); 4755 cdb.GET_CONFIGURATION.RequestType = (UCHAR)(inputBuffer->RequestType); 4756 4757 // If the device does not support TYPE ONE get configuration commands 4758 // then change the request type to TYPE ALL. Convert the returned data to 4759 // TYPE ONE format in the completion routine. 4760 if ((inputBuffer->RequestType == SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE) && 4761 TEST_FLAG(cdData->HackFlags, CDROM_HACK_BAD_TYPE_ONE_GET_CONFIG)) 4762 { 4763 4764 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, 4765 "DeviceHandleGetConfiguration: Changing TYPE_ONE Get Config to TYPE_ALL\n")); 4766 cdb.GET_CONFIGURATION.RequestType = SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL; 4767 } 4768 4769 status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, (ULONG)transferByteCount, TRUE, &cdb, 12); 4770 4771 if (NT_SUCCESS(status)) 4772 { 4773 if ((inputBuffer->RequestType == SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE) && 4774 TEST_FLAG(cdData->HackFlags, CDROM_HACK_BAD_TYPE_ONE_GET_CONFIG)) 4775 { 4776 4777 if (DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength < sizeof(GET_CONFIGURATION_HEADER)) 4778 { 4779 // Not enough data to calculate the data length. 4780 // So assume feature is not present 4781 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DeviceHandleGetConfiguration: No get config header!\n")); 4782 *DataLength = 0; 4783 status = STATUS_INVALID_DEVICE_REQUEST; 4784 } 4785 else 4786 { 4787 //Some CDROM devices do not handle the GET CONFIGURATION commands with 4788 //TYPE ONE request. The command will time out causing a bus reset. 4789 //To avoid this problem we set a device flag during start device if the device 4790 //fails a TYPE ONE request. If this flag is set the TYPE ONE requests will be 4791 //tried as TYPE ALL request and the data will be converted to TYPE ONE format 4792 //in this routine. 4793 GetConfigurationDataConversionTypeAllToTypeOne(inputBuffer->Feature, DeviceExtension->ScratchContext.ScratchSrb, DataLength); 4794 *DataLength = min(*DataLength, RequestParameters.Parameters.DeviceIoControl.OutputBufferLength); 4795 } 4796 } 4797 else 4798 { 4799 *DataLength = DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength; 4800 } 4801 4802 // copy data to output buffer 4803 if (NT_SUCCESS(status)) 4804 { 4805 RtlMoveMemory(outputBuffer, 4806 DeviceExtension->ScratchContext.ScratchBuffer, 4807 *DataLength); 4808 } 4809 } 4810 4811 ScratchBuffer_EndUse(DeviceExtension); 4812 } 4813 else 4814 { 4815 // We are in Zero Power state, and our cached response is available. 4816 // Synthesize the requested data. 4817 GetConfigurationDataSynthesize(zpoddInfo->GetConfigurationBuffer, 4818 zpoddInfo->GetConfigurationBufferSize, 4819 outputBuffer, 4820 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 4821 inputBuffer->Feature, 4822 inputBuffer->RequestType, 4823 DataLength 4824 ); 4825 } 4826 } 4827 4828 return status; 4829 } 4830 4831 _IRQL_requires_max_(PASSIVE_LEVEL) 4832 NTSTATUS 4833 RequestHandleGetDriveGeometry( 4834 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 4835 _In_ WDFREQUEST Request, 4836 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 4837 _Out_ size_t * DataLength 4838 ) 4839 /*++ 4840 4841 Routine Description: 4842 4843 Handle request of IOCTL_DISK_GET_LENGTH_INFO 4844 IOCTL_DISK_GET_DRIVE_GEOMETRY 4845 IOCTL_DISK_GET_DRIVE_GEOMETRY_EX 4846 IOCTL_CDROM_GET_DRIVE_GEOMETRY 4847 IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX 4848 IOCTL_STORAGE_READ_CAPACITY 4849 4850 Arguments: 4851 4852 DeviceExtension - device context 4853 Request - request to be handled 4854 RequestParameters - request parameter 4855 DataLength - transferred data length 4856 4857 Return Value: 4858 4859 NTSTATUS 4860 4861 --*/ 4862 { 4863 NTSTATUS status = STATUS_SUCCESS; 4864 VOID* outputBuffer = NULL; 4865 4866 PAGED_CODE (); 4867 4868 *DataLength = 0; 4869 4870 status = WdfRequestRetrieveOutputBuffer(Request, 4871 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 4872 &outputBuffer, 4873 NULL); 4874 4875 // Issue ReadCapacity to update device extension 4876 // with information for current media. 4877 if (NT_SUCCESS(status)) 4878 { 4879 status = MediaReadCapacity(DeviceExtension->Device); 4880 } 4881 4882 if (NT_SUCCESS(status)) 4883 { 4884 switch(RequestParameters.Parameters.DeviceIoControl.IoControlCode) 4885 { 4886 case IOCTL_DISK_GET_LENGTH_INFO: 4887 { 4888 PGET_LENGTH_INFORMATION lengthInfo = (PGET_LENGTH_INFORMATION)outputBuffer; 4889 4890 lengthInfo->Length = DeviceExtension->PartitionLength; 4891 *DataLength = sizeof(GET_LENGTH_INFORMATION); 4892 break; 4893 } 4894 case IOCTL_DISK_GET_DRIVE_GEOMETRY: 4895 case IOCTL_CDROM_GET_DRIVE_GEOMETRY: 4896 { 4897 PDISK_GEOMETRY geometry = (PDISK_GEOMETRY)outputBuffer; 4898 4899 *geometry = DeviceExtension->DiskGeometry; 4900 *DataLength = sizeof(DISK_GEOMETRY); 4901 break; 4902 } 4903 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX: 4904 case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX: 4905 { 4906 PDISK_GEOMETRY_EX geometryEx = (PDISK_GEOMETRY_EX)outputBuffer; 4907 4908 geometryEx->DiskSize = DeviceExtension->PartitionLength; 4909 geometryEx->Geometry = DeviceExtension->DiskGeometry; 4910 *DataLength = FIELD_OFFSET(DISK_GEOMETRY_EX, Data); 4911 break; 4912 } 4913 case IOCTL_STORAGE_READ_CAPACITY: 4914 { 4915 PSTORAGE_READ_CAPACITY readCapacity = (PSTORAGE_READ_CAPACITY)outputBuffer; 4916 4917 readCapacity->Version = sizeof(STORAGE_READ_CAPACITY); 4918 readCapacity->Size = sizeof(STORAGE_READ_CAPACITY); 4919 4920 readCapacity->BlockLength = DeviceExtension->DiskGeometry.BytesPerSector; 4921 if (readCapacity->BlockLength > 0) 4922 { 4923 readCapacity->NumberOfBlocks.QuadPart = DeviceExtension->PartitionLength.QuadPart/readCapacity->BlockLength; 4924 } 4925 else 4926 { 4927 readCapacity->NumberOfBlocks.QuadPart = 0; 4928 } 4929 4930 readCapacity->DiskLength = DeviceExtension->PartitionLength; 4931 4932 *DataLength = sizeof(STORAGE_READ_CAPACITY); 4933 break; 4934 } 4935 default: 4936 { 4937 NT_ASSERT(FALSE); 4938 break; 4939 } 4940 } // end of switch() 4941 } 4942 4943 return status; 4944 } 4945 4946 _IRQL_requires_max_(APC_LEVEL) 4947 NTSTATUS 4948 RequestHandleDiskVerify( 4949 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 4950 _In_ WDFREQUEST Request, 4951 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 4952 _Out_ size_t * DataLength 4953 ) 4954 /*++ 4955 4956 Routine Description: 4957 4958 Handle request of IOCTL_DISK_VERIFY 4959 4960 Arguments: 4961 4962 DeviceExtension - device context 4963 Request - request to be handled 4964 RequestParameters - request parameter 4965 DataLength - transferred data length 4966 4967 Return Value: 4968 4969 NTSTATUS 4970 4971 --*/ 4972 { 4973 NTSTATUS status = STATUS_SUCCESS; 4974 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); 4975 PVERIFY_INFORMATION verifyInfo = NULL; 4976 4977 PAGED_CODE (); 4978 4979 *DataLength = 0; 4980 4981 if (!cdData->Mmc.WriteAllowed) 4982 { 4983 status = STATUS_MEDIA_WRITE_PROTECTED; 4984 } 4985 4986 if (NT_SUCCESS(status)) 4987 { 4988 status = WdfRequestRetrieveInputBuffer(Request, 4989 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 4990 &verifyInfo, 4991 NULL); 4992 } 4993 4994 // handle the request 4995 if (NT_SUCCESS(status)) 4996 { 4997 LARGE_INTEGER byteOffset = {0}; 4998 4999 // Add disk offset to starting sector. 5000 byteOffset.QuadPart = DeviceExtension->StartingOffset.QuadPart + 5001 verifyInfo->StartingOffset.QuadPart; 5002 5003 // prevent overflow returning success but only validating small area 5004 if (((DeviceExtension->StartingOffset.QuadPart + verifyInfo->StartingOffset.QuadPart) < DeviceExtension->StartingOffset.QuadPart) || 5005 ((verifyInfo->Length >> DeviceExtension->SectorShift) > MAXUSHORT) || 5006 ((byteOffset.QuadPart >> DeviceExtension->SectorShift) > MAXULONG) ) 5007 { 5008 status = STATUS_INVALID_PARAMETER; 5009 } 5010 else 5011 { 5012 ULONG transferSize = 0; 5013 ULONG timeoutValue = 0; 5014 CDB cdb; 5015 ULONG sectorOffset; 5016 USHORT sectorCount; 5017 5018 ScratchBuffer_BeginUse(DeviceExtension); 5019 5020 // Convert byte offset to sector offset. 5021 sectorOffset = (ULONG)(byteOffset.QuadPart >> DeviceExtension->SectorShift); 5022 5023 // Convert ULONG byte count to USHORT sector count. 5024 sectorCount = (USHORT)(verifyInfo->Length >> DeviceExtension->SectorShift); 5025 5026 RtlZeroMemory(&cdb, sizeof(CDB)); 5027 // Set up the CDB 5028 cdb.CDB10.OperationCode = SCSIOP_VERIFY; 5029 5030 // Move little endian values into CDB in big endian format. 5031 cdb.CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)§orOffset)->Byte3; 5032 cdb.CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)§orOffset)->Byte2; 5033 cdb.CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)§orOffset)->Byte1; 5034 cdb.CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)§orOffset)->Byte0; 5035 5036 cdb.CDB10.TransferBlocksMsb = ((PFOUR_BYTE)§orCount)->Byte1; 5037 cdb.CDB10.TransferBlocksLsb = ((PFOUR_BYTE)§orCount)->Byte0; 5038 5039 // The verify command is used by the NT FORMAT utility and 5040 // requests are sent down for 5% of the volume size. The 5041 // request timeout value is calculated based on the number of 5042 // sectors verified. 5043 if (sectorCount != 0) 5044 { 5045 // sectorCount is a USHORT, so no overflow here... 5046 timeoutValue = TimeOutValueGetCapValue(DeviceExtension->TimeOutValue, ((sectorCount + 128) / 128)); 5047 } 5048 5049 status = ScratchBuffer_ExecuteCdbEx(DeviceExtension, Request, transferSize, FALSE, &cdb, 10, timeoutValue); 5050 5051 // nothing to do after the command finishes. 5052 ScratchBuffer_EndUse(DeviceExtension); 5053 } 5054 } 5055 5056 return status; 5057 } 5058 5059 5060 _IRQL_requires_max_(APC_LEVEL) 5061 NTSTATUS 5062 RequestHandleCheckVerify( 5063 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 5064 _In_ WDFREQUEST Request, 5065 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 5066 _Out_ size_t * DataLength 5067 ) 5068 /*++ 5069 5070 Routine Description: 5071 5072 Handle request of IOCTL_STORAGE_CHECK_VERIFY2 5073 IOCTL_STORAGE_CHECK_VERIFY 5074 5075 Arguments: 5076 5077 DeviceExtension - device context 5078 Request - request to be handled 5079 RequestParameters - request parameter 5080 DataLength - transferred data length 5081 5082 Return Value: 5083 5084 NTSTATUS 5085 5086 --*/ 5087 { 5088 NTSTATUS status = STATUS_SUCCESS; 5089 5090 PAGED_CODE (); 5091 5092 *DataLength = 0; 5093 5094 if (NT_SUCCESS(status)) 5095 { 5096 ULONG transferSize = 0; 5097 CDB cdb; 5098 5099 ScratchBuffer_BeginUse(DeviceExtension); 5100 5101 RtlZeroMemory(&cdb, sizeof(CDB)); 5102 // Set up the CDB 5103 cdb.CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY; 5104 5105 status = ScratchBuffer_ExecuteCdbEx(DeviceExtension, Request, transferSize, FALSE, &cdb, 6, CDROM_TEST_UNIT_READY_TIMEOUT); 5106 5107 if (NT_SUCCESS(status)) 5108 { 5109 if((RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_STORAGE_CHECK_VERIFY) && 5110 (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength)) 5111 { 5112 PULONG outputBuffer = NULL; 5113 status = WdfRequestRetrieveOutputBuffer(Request, 5114 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 5115 &outputBuffer, 5116 NULL); 5117 5118 if (outputBuffer != NULL) 5119 { 5120 *outputBuffer = DeviceExtension->MediaChangeCount; 5121 *DataLength = sizeof(ULONG); 5122 } 5123 } 5124 else 5125 { 5126 *DataLength = 0; 5127 } 5128 } 5129 5130 // nothing to do after the command finishes. 5131 ScratchBuffer_EndUse(DeviceExtension); 5132 } 5133 5134 return status; 5135 } 5136 5137 5138 _IRQL_requires_max_(APC_LEVEL) 5139 NTSTATUS 5140 RequestHandleFakePartitionInfo( 5141 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 5142 _In_ WDFREQUEST Request, 5143 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 5144 _Out_ size_t * DataLength 5145 ) 5146 /*++ 5147 5148 Routine Description: 5149 5150 Handle request of IOCTL_DISK_GET_DRIVE_LAYOUT 5151 IOCTL_DISK_GET_DRIVE_LAYOUT_EX 5152 IOCTL_DISK_GET_PARTITION_INFO 5153 IOCTL_DISK_GET_PARTITION_INFO_EX 5154 5155 Arguments: 5156 5157 DeviceExtension - device context 5158 Request - request to be handled 5159 RequestParameters - request parameter 5160 DataLength - transferred data length 5161 5162 Return Value: 5163 5164 NTSTATUS 5165 5166 --*/ 5167 { 5168 NTSTATUS status = STATUS_SUCCESS; 5169 VOID* outputBuffer = NULL; 5170 ULONG ioctl = RequestParameters.Parameters.DeviceIoControl.IoControlCode; 5171 5172 PAGED_CODE (); 5173 5174 *DataLength = 0; 5175 5176 if (NT_SUCCESS(status)) 5177 { 5178 if ((ioctl != IOCTL_DISK_GET_DRIVE_LAYOUT) && 5179 (ioctl != IOCTL_DISK_GET_DRIVE_LAYOUT_EX) && 5180 (ioctl != IOCTL_DISK_GET_PARTITION_INFO) && 5181 (ioctl != IOCTL_DISK_GET_PARTITION_INFO_EX)) 5182 { 5183 status = STATUS_INTERNAL_ERROR; 5184 } 5185 } 5186 5187 if (NT_SUCCESS(status)) 5188 { 5189 status = WdfRequestRetrieveOutputBuffer(Request, 5190 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 5191 &outputBuffer, 5192 NULL); 5193 } 5194 5195 // handle the request 5196 if (NT_SUCCESS(status)) 5197 { 5198 switch (ioctl) 5199 { 5200 case IOCTL_DISK_GET_DRIVE_LAYOUT: 5201 *DataLength = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry[1]); 5202 RtlZeroMemory(outputBuffer, *DataLength); 5203 break; 5204 case IOCTL_DISK_GET_DRIVE_LAYOUT_EX: 5205 *DataLength = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[1]); 5206 RtlZeroMemory(outputBuffer, *DataLength); 5207 break; 5208 case IOCTL_DISK_GET_PARTITION_INFO: 5209 *DataLength = sizeof(PARTITION_INFORMATION); 5210 RtlZeroMemory(outputBuffer, *DataLength); 5211 break; 5212 case IOCTL_DISK_GET_PARTITION_INFO_EX: 5213 *DataLength = sizeof(PARTITION_INFORMATION_EX); 5214 RtlZeroMemory(outputBuffer, *DataLength); 5215 break; 5216 default: 5217 NT_ASSERT(!"Invalid ioctl should not have reached this point\n"); 5218 break; 5219 } 5220 5221 // if we are getting the drive layout, then we need to start by 5222 // adding some of the non-partition stuff that says we have 5223 // exactly one partition available. 5224 if (ioctl == IOCTL_DISK_GET_DRIVE_LAYOUT) 5225 { 5226 PDRIVE_LAYOUT_INFORMATION layout; 5227 layout = (PDRIVE_LAYOUT_INFORMATION)outputBuffer; 5228 layout->PartitionCount = 1; 5229 layout->Signature = 1; 5230 outputBuffer = (PVOID)(layout->PartitionEntry); 5231 ioctl = IOCTL_DISK_GET_PARTITION_INFO; 5232 } 5233 else if (ioctl == IOCTL_DISK_GET_DRIVE_LAYOUT_EX) 5234 { 5235 PDRIVE_LAYOUT_INFORMATION_EX layoutEx; 5236 layoutEx = (PDRIVE_LAYOUT_INFORMATION_EX)outputBuffer; 5237 layoutEx->PartitionStyle = PARTITION_STYLE_MBR; 5238 layoutEx->PartitionCount = 1; 5239 layoutEx->Mbr.Signature = 1; 5240 outputBuffer = (PVOID)(layoutEx->PartitionEntry); 5241 ioctl = IOCTL_DISK_GET_PARTITION_INFO_EX; 5242 } 5243 5244 // NOTE: the local var 'ioctl' is now modified to either EX or 5245 // non-EX version. the local var 'systemBuffer' is now pointing 5246 // to the partition information structure. 5247 if (ioctl == IOCTL_DISK_GET_PARTITION_INFO) 5248 { 5249 PPARTITION_INFORMATION partitionInfo; 5250 partitionInfo = (PPARTITION_INFORMATION)outputBuffer; 5251 partitionInfo->RewritePartition = FALSE; 5252 partitionInfo->RecognizedPartition = TRUE; 5253 partitionInfo->PartitionType = PARTITION_FAT32; 5254 partitionInfo->BootIndicator = FALSE; 5255 partitionInfo->HiddenSectors = 0; 5256 partitionInfo->StartingOffset.QuadPart = 0; 5257 partitionInfo->PartitionLength = DeviceExtension->PartitionLength; 5258 partitionInfo->PartitionNumber = 0; 5259 } 5260 else 5261 { 5262 PPARTITION_INFORMATION_EX partitionInfo; 5263 partitionInfo = (PPARTITION_INFORMATION_EX)outputBuffer; 5264 partitionInfo->PartitionStyle = PARTITION_STYLE_MBR; 5265 partitionInfo->RewritePartition = FALSE; 5266 partitionInfo->Mbr.RecognizedPartition = TRUE; 5267 partitionInfo->Mbr.PartitionType = PARTITION_FAT32; 5268 partitionInfo->Mbr.BootIndicator = FALSE; 5269 partitionInfo->Mbr.HiddenSectors = 0; 5270 partitionInfo->StartingOffset.QuadPart = 0; 5271 partitionInfo->PartitionLength = DeviceExtension->PartitionLength; 5272 partitionInfo->PartitionNumber = 0; 5273 } 5274 } 5275 5276 return status; 5277 } 5278 5279 NTSTATUS 5280 RequestHandleGetDeviceNumber( 5281 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 5282 _In_ WDFREQUEST Request, 5283 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 5284 _Out_ size_t * DataLength 5285 ) 5286 /*++ 5287 5288 Routine Description: 5289 5290 Handle request of IOCTL_STORAGE_GET_DEVICE_NUMBER 5291 5292 Arguments: 5293 5294 DeviceExtension - device context 5295 Request - request to be handled 5296 RequestParameters - request parameter 5297 DataLength - transferred data length 5298 5299 Return Value: 5300 5301 NTSTATUS 5302 5303 --*/ 5304 { 5305 NTSTATUS status = STATUS_SUCCESS; 5306 5307 *DataLength = 0; 5308 5309 if(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength >= 5310 sizeof(STORAGE_DEVICE_NUMBER)) 5311 { 5312 PSTORAGE_DEVICE_NUMBER deviceNumber = NULL; 5313 status = WdfRequestRetrieveOutputBuffer(Request, 5314 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 5315 &deviceNumber, 5316 NULL); 5317 if (NT_SUCCESS(status)) 5318 { 5319 deviceNumber->DeviceType = DeviceExtension->DeviceObject->DeviceType; 5320 deviceNumber->DeviceNumber = DeviceExtension->DeviceNumber; 5321 deviceNumber->PartitionNumber = (ULONG)-1; // legacy reason, return (-1) for this IOCTL. 5322 5323 status = STATUS_SUCCESS; 5324 *DataLength = sizeof(STORAGE_DEVICE_NUMBER); 5325 } 5326 } 5327 else 5328 { 5329 status = STATUS_BUFFER_TOO_SMALL; 5330 *DataLength = sizeof(STORAGE_DEVICE_NUMBER); 5331 } 5332 5333 return status; 5334 } 5335 5336 NTSTATUS 5337 RequestHandleGetHotPlugInfo( 5338 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 5339 _In_ WDFREQUEST Request, 5340 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 5341 _Out_ size_t * DataLength 5342 ) 5343 /*++ 5344 5345 Routine Description: 5346 5347 Handle request of IOCTL_STORAGE_GET_HOTPLUG_INFO 5348 5349 Arguments: 5350 5351 DeviceExtension - device context 5352 Request - request to be handled 5353 RequestParameters - request parameter 5354 DataLength - transferred data length 5355 5356 Return Value: 5357 5358 NTSTATUS 5359 5360 --*/ 5361 { 5362 NTSTATUS status = STATUS_SUCCESS; 5363 5364 *DataLength = 0; 5365 5366 if(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength >= 5367 sizeof(STORAGE_HOTPLUG_INFO)) 5368 { 5369 PSTORAGE_HOTPLUG_INFO info = NULL; 5370 status = WdfRequestRetrieveOutputBuffer(Request, 5371 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 5372 &info, 5373 NULL); 5374 if (NT_SUCCESS(status)) 5375 { 5376 *info = DeviceExtension->PrivateFdoData->HotplugInfo; 5377 5378 status = STATUS_SUCCESS; 5379 *DataLength = sizeof(STORAGE_HOTPLUG_INFO); 5380 } 5381 } 5382 else 5383 { 5384 status = STATUS_BUFFER_TOO_SMALL; 5385 *DataLength = sizeof(STORAGE_HOTPLUG_INFO); 5386 } 5387 5388 return status; 5389 } 5390 5391 NTSTATUS 5392 RequestHandleSetHotPlugInfo( 5393 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 5394 _In_ WDFREQUEST Request, 5395 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 5396 _Out_ size_t * DataLength 5397 ) 5398 /*++ 5399 5400 Routine Description: 5401 5402 Handle request of IOCTL_STORAGE_SET_HOTPLUG_INFO 5403 5404 Arguments: 5405 5406 DeviceExtension - device context 5407 Request - request to be handled 5408 RequestParameters - request parameter 5409 DataLength - transferred data length 5410 5411 Return Value: 5412 5413 NTSTATUS 5414 5415 --*/ 5416 { 5417 NTSTATUS status = STATUS_SUCCESS; 5418 PSTORAGE_HOTPLUG_INFO info = NULL; 5419 5420 *DataLength = 0; 5421 5422 if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < 5423 sizeof(STORAGE_HOTPLUG_INFO)) 5424 { 5425 // Indicate unsuccessful status and no data transferred. 5426 status = STATUS_INFO_LENGTH_MISMATCH; 5427 } 5428 5429 if (NT_SUCCESS(status)) 5430 { 5431 status = WdfRequestRetrieveInputBuffer(Request, 5432 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 5433 &info, 5434 NULL); 5435 } 5436 5437 if (NT_SUCCESS(status)) 5438 { 5439 if (info->Size != DeviceExtension->PrivateFdoData->HotplugInfo.Size) 5440 { 5441 status = STATUS_INVALID_PARAMETER_1; 5442 } 5443 5444 if (info->MediaRemovable != DeviceExtension->PrivateFdoData->HotplugInfo.MediaRemovable) 5445 { 5446 status = STATUS_INVALID_PARAMETER_2; 5447 } 5448 5449 if (info->MediaHotplug != DeviceExtension->PrivateFdoData->HotplugInfo.MediaHotplug) 5450 { 5451 status = STATUS_INVALID_PARAMETER_3; 5452 } 5453 5454 if (info->WriteCacheEnableOverride != DeviceExtension->PrivateFdoData->HotplugInfo.WriteCacheEnableOverride) 5455 { 5456 status = STATUS_INVALID_PARAMETER_5; 5457 } 5458 } 5459 5460 if (NT_SUCCESS(status)) 5461 { 5462 DeviceExtension->PrivateFdoData->HotplugInfo.DeviceHotplug = info->DeviceHotplug; 5463 5464 // Store the user-defined override in the registry 5465 DeviceSetParameter(DeviceExtension, 5466 CLASSP_REG_SUBKEY_NAME, 5467 CLASSP_REG_REMOVAL_POLICY_VALUE_NAME, 5468 (info->DeviceHotplug) ? RemovalPolicyExpectSurpriseRemoval : RemovalPolicyExpectOrderlyRemoval); 5469 } 5470 5471 return status; 5472 } 5473 5474 _IRQL_requires_max_(APC_LEVEL) 5475 NTSTATUS 5476 RequestHandleEventNotification( 5477 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 5478 _In_opt_ WDFREQUEST Request, 5479 _In_opt_ PWDF_REQUEST_PARAMETERS RequestParameters, 5480 _Out_ size_t * DataLength 5481 ) 5482 /*++ 5483 5484 Routine Description: 5485 5486 This routine handles the process of IOCTL_STORAGE_EVENT_NOTIFICATION 5487 5488 Arguments: 5489 5490 DeviceExtension - device context 5491 5492 Request - request to be handled 5493 5494 RequestParameters - request parameter 5495 5496 DataLength - data transferred 5497 5498 Return Value: 5499 NTSTATUS 5500 5501 --*/ 5502 { 5503 NTSTATUS status = STATUS_SUCCESS; 5504 PMEDIA_CHANGE_DETECTION_INFO info = NULL; 5505 LONG requestInUse; 5506 PSTORAGE_EVENT_NOTIFICATION eventBuffer = NULL; 5507 5508 *DataLength = 0; 5509 5510 info = DeviceExtension->MediaChangeDetectionInfo; 5511 5512 // Since AN is ASYNCHRONOUS and can happen at any time, 5513 // make certain not to do anything before properly initialized. 5514 if ((!DeviceExtension->IsInitialized) || (info == NULL)) 5515 { 5516 status = STATUS_UNSUCCESSFUL; 5517 } 5518 5519 if (NT_SUCCESS(status) && (Request != NULL) && (RequestParameters != NULL)) { 5520 5521 // 5522 // Validate IOCTL parameters 5523 // 5524 if (RequestParameters->Parameters.DeviceIoControl.InputBufferLength < 5525 sizeof(STORAGE_EVENT_NOTIFICATION)) { 5526 status = STATUS_INFO_LENGTH_MISMATCH; 5527 } 5528 5529 // 5530 // Check for an supported event 5531 // 5532 if (NT_SUCCESS(status)) { 5533 status = WdfRequestRetrieveInputBuffer(Request, 5534 RequestParameters->Parameters.DeviceIoControl.InputBufferLength, 5535 &eventBuffer, 5536 NULL); 5537 if (NT_SUCCESS(status)) { 5538 if ((eventBuffer->Version != STORAGE_EVENT_NOTIFICATION_VERSION_V1) || 5539 (eventBuffer->Size != sizeof(STORAGE_EVENT_NOTIFICATION))) { 5540 status = STATUS_INVALID_PARAMETER; 5541 } else if ((eventBuffer->Events & 5542 (STORAGE_EVENT_MEDIA_STATUS | STORAGE_EVENT_DEVICE_STATUS | STORAGE_EVENT_DEVICE_OPERATION)) == 0) { 5543 status = STATUS_NOT_SUPPORTED; 5544 } 5545 } 5546 } 5547 5548 } 5549 5550 if (NT_SUCCESS(status)) 5551 { 5552 if (info->MediaChangeDetectionDisableCount != 0) 5553 { 5554 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_MCN, 5555 "RequestHandleEventNotification: device %p has detection disabled \n", 5556 DeviceExtension->DeviceObject)); 5557 status = STATUS_UNSUCCESSFUL; 5558 } 5559 } 5560 5561 if (NT_SUCCESS(status)) 5562 { 5563 // if the request is not in use, mark it as such. 5564 requestInUse = InterlockedCompareExchange((PLONG)&info->MediaChangeRequestInUse, 1, 0); 5565 5566 if (requestInUse != 0) 5567 { 5568 status = STATUS_UNSUCCESSFUL; 5569 } 5570 } 5571 5572 if (NT_SUCCESS(status)) 5573 { 5574 // The last MCN finished. ok to issue the new one. 5575 RequestSetupMcnSyncIrp(DeviceExtension); 5576 5577 // The irp will go into KMDF framework and a request will be created there to represent it. 5578 IoCallDriver(DeviceExtension->DeviceObject, info->MediaChangeSyncIrp); 5579 } 5580 5581 return status; 5582 } 5583 5584 5585 _IRQL_requires_max_(PASSIVE_LEVEL) 5586 NTSTATUS 5587 RequestHandleEjectionControl( 5588 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 5589 _In_ WDFREQUEST Request, 5590 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 5591 _Out_ size_t * DataLength 5592 ) 5593 /*++ 5594 5595 Routine Description: 5596 5597 Handle request of IOCTL_STORAGE_MEDIA_REMOVAL 5598 IOCTL_STORAGE_EJECTION_CONTROL 5599 5600 Arguments: 5601 5602 DeviceExtension - device context 5603 Request - request to be handled 5604 RequestParameters - request parameter 5605 DataLength - transferred data length 5606 5607 Return Value: 5608 5609 NTSTATUS 5610 5611 --*/ 5612 { 5613 NTSTATUS status = STATUS_SUCCESS; 5614 PPREVENT_MEDIA_REMOVAL mediaRemoval = NULL; 5615 5616 PAGED_CODE (); 5617 5618 *DataLength = 0; 5619 5620 if(RequestParameters.Parameters.DeviceIoControl.InputBufferLength < 5621 sizeof(PREVENT_MEDIA_REMOVAL)) 5622 { 5623 status = STATUS_INFO_LENGTH_MISMATCH; 5624 } 5625 else 5626 { 5627 status = WdfRequestRetrieveInputBuffer(Request, 5628 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 5629 &mediaRemoval, 5630 NULL); 5631 } 5632 5633 if (NT_SUCCESS(status)) 5634 { 5635 status = PerformEjectionControl(DeviceExtension, 5636 Request, 5637 ((RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_STORAGE_EJECTION_CONTROL) 5638 ? SecureMediaLock 5639 : SimpleMediaLock), 5640 mediaRemoval->PreventMediaRemoval); 5641 } 5642 5643 return status; 5644 } 5645 5646 5647 _IRQL_requires_max_(APC_LEVEL) 5648 NTSTATUS 5649 RequestHandleEnableStreaming( 5650 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 5651 _In_ WDFREQUEST Request, 5652 _Out_ size_t * DataLength 5653 ) 5654 /*++ 5655 5656 Routine Description: 5657 5658 Handles an IOCTL_CDROM_ENABLE_STREAMING request 5659 5660 Arguments: 5661 5662 DeviceExtension - device context 5663 Request - request to be handled 5664 DataLength - transferred data length 5665 5666 Notes: 5667 5668 This IOCTL is serialized because it changes read/write 5669 behavior and we want to make sure that all previous 5670 reads/writes have been completed before we change the 5671 behavior. 5672 5673 Return Value: 5674 5675 NTSTATUS 5676 5677 --*/ 5678 { 5679 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); 5680 PCDROM_PRIVATE_FDO_DATA fdoData = DeviceExtension->PrivateFdoData; 5681 5682 WDFFILEOBJECT fileObject = NULL; 5683 PFILE_OBJECT_CONTEXT fileObjectContext = NULL; 5684 5685 NTSTATUS status = STATUS_SUCCESS; 5686 PCDROM_STREAMING_CONTROL inputBuffer = NULL; 5687 5688 BOOLEAN enforceStreamingRead = FALSE; 5689 BOOLEAN enforceStreamingWrite = FALSE; 5690 BOOLEAN streamingReadSupported, streamingWriteSupported; 5691 5692 PAGED_CODE (); 5693 5694 *DataLength = 0; 5695 5696 status = WdfRequestRetrieveInputBuffer(Request, 5697 sizeof(CDROM_STREAMING_CONTROL), 5698 &inputBuffer, 5699 NULL); 5700 5701 if (NT_SUCCESS(status)) 5702 { 5703 // get file object context 5704 fileObject = WdfRequestGetFileObject(Request); 5705 if (fileObject != NULL) { 5706 fileObjectContext = FileObjectGetContext(fileObject); 5707 } 5708 NT_ASSERT(fileObjectContext != NULL); 5709 5710 if (fileObjectContext == NULL) 5711 { 5712 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, 5713 "RequestHandleEnableStreaming: cannot find file object context\n")); 5714 status = STATUS_INVALID_HANDLE; 5715 } 5716 } 5717 5718 if (NT_SUCCESS(status)) 5719 { 5720 if (inputBuffer->RequestType == CdromStreamingDisable) 5721 { 5722 enforceStreamingRead = FALSE; 5723 enforceStreamingWrite = FALSE; 5724 } 5725 else if (inputBuffer->RequestType == CdromStreamingEnableForReadOnly) 5726 { 5727 enforceStreamingRead = TRUE; 5728 enforceStreamingWrite = FALSE; 5729 } 5730 else if (inputBuffer->RequestType == CdromStreamingEnableForWriteOnly) 5731 { 5732 enforceStreamingRead = FALSE; 5733 enforceStreamingWrite = TRUE; 5734 } 5735 else if (inputBuffer->RequestType == CdromStreamingEnableForReadWrite) 5736 { 5737 enforceStreamingRead = TRUE; 5738 enforceStreamingWrite = TRUE; 5739 } 5740 5741 streamingReadSupported = cdData->Mmc.StreamingReadSupported && !TEST_FLAG(fdoData->HackFlags, FDO_HACK_NO_STREAMING); 5742 streamingWriteSupported = cdData->Mmc.StreamingWriteSupported && !TEST_FLAG(fdoData->HackFlags, FDO_HACK_NO_STREAMING); 5743 if ((enforceStreamingRead && !streamingReadSupported) || 5744 (enforceStreamingWrite && !streamingWriteSupported)) 5745 { 5746 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, 5747 "RequestHandleEnableStreaming: requested Streaming mode is not supported\n")); 5748 status = STATUS_INVALID_DEVICE_REQUEST; 5749 } 5750 else 5751 { 5752 fileObjectContext->EnforceStreamingRead = enforceStreamingRead; 5753 fileObjectContext->EnforceStreamingWrite = enforceStreamingWrite; 5754 } 5755 } 5756 5757 return status; 5758 } 5759 5760 5761 _IRQL_requires_max_(APC_LEVEL) 5762 NTSTATUS 5763 RequestHandleSendOpcInformation( 5764 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 5765 _In_ WDFREQUEST Request, 5766 _Out_ size_t * DataLength 5767 ) 5768 /*++ 5769 5770 Routine Description: 5771 5772 Handles an IOCTL_CDROM_SEND_OPC_INFORMATION request 5773 5774 Arguments: 5775 5776 DeviceExtension - device context 5777 Request - request to be handled 5778 DataLength - transferred data length 5779 5780 Return Value: 5781 5782 NTSTATUS 5783 5784 --*/ 5785 { 5786 NTSTATUS status = STATUS_SUCCESS; 5787 PCDROM_SIMPLE_OPC_INFO inputBuffer = NULL; 5788 5789 PAGED_CODE (); 5790 5791 *DataLength = 0; 5792 5793 status = WdfRequestRetrieveInputBuffer(Request, 5794 sizeof(CDROM_SIMPLE_OPC_INFO), 5795 (PVOID*)&inputBuffer, 5796 NULL); 5797 5798 if (NT_SUCCESS(status)) 5799 { 5800 CDB cdb; 5801 5802 ScratchBuffer_BeginUse(DeviceExtension); 5803 5804 RtlZeroMemory(&cdb, sizeof(CDB)); 5805 5806 // we support only the simplest version for now 5807 cdb.SEND_OPC_INFORMATION.OperationCode = SCSIOP_SEND_OPC_INFORMATION; 5808 cdb.SEND_OPC_INFORMATION.DoOpc = 1; 5809 cdb.SEND_OPC_INFORMATION.Exclude0 = (inputBuffer->Exclude0 ? 1 : 0); 5810 cdb.SEND_OPC_INFORMATION.Exclude1 = (inputBuffer->Exclude1 ? 1 : 0); 5811 5812 status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, 0, FALSE, &cdb, sizeof(cdb.SEND_OPC_INFORMATION)); 5813 5814 // nothing to do after the command finishes 5815 ScratchBuffer_EndUse(DeviceExtension); 5816 } 5817 5818 return status; 5819 } 5820 5821 5822 _IRQL_requires_max_(APC_LEVEL) 5823 NTSTATUS 5824 RequestHandleGetPerformance( 5825 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 5826 _In_ WDFREQUEST Request, 5827 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 5828 _Out_ size_t * DataLength 5829 ) 5830 /*++ 5831 5832 Routine Description: 5833 5834 Handles an IOCTL_CDROM_GET_PERFORMANCE request 5835 5836 Arguments: 5837 5838 DeviceExtension - device context 5839 Request - request to be handled 5840 RequestParameters - request parameter 5841 DataLength - transferred data length 5842 5843 Return Value: 5844 5845 NTSTATUS 5846 5847 --*/ 5848 { 5849 NTSTATUS status = STATUS_SUCCESS; 5850 PCDROM_PERFORMANCE_REQUEST inputBuffer = NULL; 5851 PVOID outputBuffer = NULL; 5852 5853 PAGED_CODE (); 5854 5855 *DataLength = 0; 5856 5857 // Retrieve pointers to input/output data. The size has been validated earlier 5858 // in RequestValidateGetPerformance, so we do not check it again. 5859 if (NT_SUCCESS(status)) 5860 { 5861 status = WdfRequestRetrieveInputBuffer(Request, 5862 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 5863 (PVOID*)&inputBuffer, 5864 NULL); 5865 } 5866 if (NT_SUCCESS(status)) 5867 { 5868 status = WdfRequestRetrieveOutputBuffer(Request, 5869 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 5870 &outputBuffer, 5871 NULL); 5872 } 5873 5874 if (NT_SUCCESS(status)) 5875 { 5876 USHORT descriptorSize = 0; 5877 USHORT descriptorCount = 0; 5878 size_t transferSize = 0; 5879 CDB cdb; 5880 5881 ScratchBuffer_BeginUse(DeviceExtension); 5882 5883 // Set up the CDB 5884 RtlZeroMemory(&cdb, sizeof(CDB)); 5885 5886 if (inputBuffer->RequestType == CdromPerformanceRequest) 5887 { 5888 cdb.GET_PERFORMANCE.Type = 0; 5889 5890 // 10b is the only defined tolerance in MMCr6 5891 cdb.GET_PERFORMANCE.Tolerance = 2; 5892 5893 switch (inputBuffer->Exceptions) { 5894 case CdromNominalPerformance: 5895 cdb.GET_PERFORMANCE.Except = 0; 5896 descriptorSize = sizeof(CDROM_NOMINAL_PERFORMANCE_DESCRIPTOR); 5897 break; 5898 case CdromEntirePerformanceList: 5899 cdb.GET_PERFORMANCE.Except = 1; 5900 descriptorSize = sizeof(CDROM_NOMINAL_PERFORMANCE_DESCRIPTOR); 5901 break; 5902 case CdromPerformanceExceptionsOnly: 5903 cdb.GET_PERFORMANCE.Except = 2; 5904 descriptorSize = sizeof(CDROM_EXCEPTION_PERFORMANCE_DESCRIPTOR); 5905 break; 5906 } 5907 5908 switch (inputBuffer->PerformanceType) { 5909 case CdromReadPerformance: 5910 cdb.GET_PERFORMANCE.Write = 0; break; 5911 case CdromWritePerformance: 5912 cdb.GET_PERFORMANCE.Write = 1; break; 5913 } 5914 5915 REVERSE_BYTES(&cdb.GET_PERFORMANCE.StartingLBA, &inputBuffer->StaringLba); 5916 } 5917 else if (inputBuffer->RequestType == CdromWriteSpeedRequest) 5918 { 5919 cdb.GET_PERFORMANCE.Type = 3; 5920 descriptorSize = sizeof(CDROM_WRITE_SPEED_DESCRIPTOR); 5921 } 5922 5923 cdb.GET_PERFORMANCE.OperationCode = SCSIOP_GET_PERFORMANCE; 5924 5925 // calculate how many descriptors can fit into the output buffer 5926 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength >= 5927 sizeof(CDROM_PERFORMANCE_HEADER) && 5928 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength <= 5929 MAXUSHORT && 5930 descriptorSize > 0) 5931 { 5932 descriptorCount = (USHORT)(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength - sizeof(CDROM_PERFORMANCE_HEADER)); 5933 descriptorCount /= descriptorSize; 5934 } 5935 else 5936 { 5937 status = STATUS_INVALID_PARAMETER; 5938 } 5939 5940 REVERSE_BYTES_SHORT(&cdb.GET_PERFORMANCE.MaximumNumberOfDescriptors, &descriptorCount); 5941 5942 // Calculate transfer size. We round it up to meet adapter requirements. 5943 // Extra bytes are discarded later, when we copy data to the output buffer. 5944 transferSize = RequestParameters.Parameters.DeviceIoControl.OutputBufferLength; 5945 transferSize += DeviceExtension->AdapterDescriptor->AlignmentMask; 5946 transferSize &= ~DeviceExtension->AdapterDescriptor->AlignmentMask; 5947 5948 if (NT_SUCCESS(status)) 5949 { 5950 status = ScratchBuffer_ExecuteCdbEx(DeviceExtension, Request, (ULONG)transferSize, TRUE, &cdb, sizeof(cdb.GET_PERFORMANCE), CDROM_GET_PERFORMANCE_TIMEOUT); 5951 } 5952 5953 if (NT_SUCCESS(status)) 5954 { 5955 if (DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength < sizeof(CDROM_PERFORMANCE_HEADER)) 5956 { 5957 *DataLength = 0; 5958 status = STATUS_INVALID_DEVICE_REQUEST; 5959 } 5960 else 5961 { 5962 *DataLength = min(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 5963 DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength); 5964 RtlCopyMemory(outputBuffer, 5965 DeviceExtension->ScratchContext.ScratchBuffer, 5966 *DataLength); 5967 } 5968 } 5969 5970 ScratchBuffer_EndUse(DeviceExtension); 5971 } 5972 5973 return status; 5974 } 5975 5976 _IRQL_requires_max_(APC_LEVEL) 5977 NTSTATUS 5978 RequestHandleMcnSyncFakeIoctl( 5979 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 5980 _Out_ size_t * DataLength 5981 ) 5982 /*++ 5983 5984 Routine Description: 5985 5986 Handles an IOCTL_MCN_SYNC_FAKE_IOCTL request 5987 5988 Arguments: 5989 5990 DeviceExtension - device context 5991 DataLength - transferred data length 5992 5993 Return Value: 5994 5995 NTSTATUS 5996 5997 --*/ 5998 { 5999 NTSTATUS status = STATUS_SUCCESS; 6000 PMEDIA_CHANGE_DETECTION_INFO info = DeviceExtension->MediaChangeDetectionInfo; 6001 BOOLEAN shouldRetry = TRUE; 6002 BOOLEAN requestSent = FALSE; 6003 6004 PAGED_CODE (); 6005 6006 *DataLength = 0; 6007 6008 // 6009 // Try to acquire the media change event. If we can't do it immediately 6010 // then bail out and assume the caller will try again later. 6011 // 6012 while (shouldRetry) 6013 { 6014 6015 status = RequestSetupMcnRequest(DeviceExtension, 6016 info->Gesn.Supported); 6017 6018 if (!NT_SUCCESS(status)) 6019 { 6020 shouldRetry = FALSE; 6021 } 6022 6023 if (NT_SUCCESS(status)) 6024 { 6025 requestSent = RequestSendMcnRequest(DeviceExtension); 6026 6027 if (requestSent) 6028 { 6029 shouldRetry = RequestPostWorkMcnRequest(DeviceExtension); 6030 } 6031 else 6032 { 6033 shouldRetry = FALSE; 6034 } 6035 } 6036 } 6037 6038 // If there were any media change notifications that were not delivered 6039 // for some reason, make an attempt to do so at this time. 6040 DeviceSendDelayedMediaChangeNotifications(DeviceExtension); 6041 6042 // Set the status and then complete the original request. 6043 // The timer handler will be able to send the next request. 6044 status = STATUS_SUCCESS; 6045 6046 return status; 6047 } 6048 6049 BOOLEAN 6050 RequestIsRealtimeStreaming( 6051 _In_ WDFREQUEST Request, 6052 _In_ BOOLEAN IsReadRequest 6053 ) 6054 /*++ 6055 6056 Routine Description: 6057 6058 Checks whether a given read/write request should 6059 be performed in Real-Time Streaming mode. 6060 6061 Arguments: 6062 6063 Request - request to be checked 6064 IsReadRequest - TRUE = read request; FALSE = write request 6065 6066 Return Value: 6067 6068 TRUE - a Real-Time Streaming operation has to be performed 6069 FALSE - a normal (non-Streaming) operation has to be performed 6070 6071 --*/ 6072 { 6073 BOOLEAN useStreaming = FALSE; 6074 6075 if (!useStreaming) { 6076 // 6077 // Check if we're required to use Streaming via I/O Stack Location flags 6078 // 6079 UCHAR currentStackLocationFlags = 0; 6080 currentStackLocationFlags = RequestGetCurrentStackLocationFlags(Request); 6081 6082 useStreaming = TEST_FLAG(currentStackLocationFlags, SL_REALTIME_STREAM); 6083 } 6084 6085 if (!useStreaming) { 6086 // 6087 // Check if we were previously requested to enforce Streaming for 6088 // the file handle through which this request was sent. 6089 // 6090 6091 WDFFILEOBJECT fileObject; 6092 PFILE_OBJECT_CONTEXT fileObjectContext; 6093 6094 fileObject = WdfRequestGetFileObject(Request); 6095 6096 if (fileObject != NULL) { 6097 fileObjectContext = FileObjectGetContext(fileObject); 6098 NT_ASSERT(fileObjectContext != NULL); 6099 6100 if (IsReadRequest && fileObjectContext->EnforceStreamingRead) 6101 { 6102 useStreaming = TRUE; 6103 } 6104 6105 if (!IsReadRequest && fileObjectContext->EnforceStreamingWrite) 6106 { 6107 useStreaming = TRUE; 6108 } 6109 } 6110 } 6111 6112 return useStreaming; 6113 } 6114 6115 6116 NTSTATUS 6117 RequestValidateReadWrite( 6118 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 6119 _In_ WDFREQUEST Request, 6120 _In_ WDF_REQUEST_PARAMETERS RequestParameters 6121 ) 6122 /*++ 6123 6124 Routine Description: 6125 6126 Validate Read/Write request 6127 6128 Arguments: 6129 6130 DeviceExtension - device context 6131 Request - request to be handled 6132 RequestParameters - request parameter 6133 6134 Return Value: 6135 6136 NTSTATUS 6137 6138 --*/ 6139 { 6140 NTSTATUS status = STATUS_SUCCESS; 6141 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); 6142 6143 BOOLEAN isValid = TRUE; 6144 LONGLONG startingOffset = 0; 6145 size_t transferByteCount = 0; 6146 PIRP irp = NULL; 6147 PIO_STACK_LOCATION currentStack = NULL; 6148 6149 irp = WdfRequestWdmGetIrp(Request); 6150 currentStack = IoGetCurrentIrpStackLocation(irp); 6151 6152 if (TEST_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME) && 6153 (currentStack->MinorFunction != CDROM_VOLUME_VERIFY_CHECKED) && 6154 !TEST_FLAG(currentStack->Flags, SL_OVERRIDE_VERIFY_VOLUME)) 6155 { 6156 // DO_VERIFY_VOLUME is set for the device object, 6157 // but this request is not itself a verify request. 6158 // So fail this request. 6159 6160 //set the status for volume verification. 6161 status = STATUS_VERIFY_REQUIRED; 6162 } 6163 6164 if (NT_SUCCESS(status)) 6165 { 6166 if (PLAY_ACTIVE(DeviceExtension)) 6167 { 6168 status = STATUS_DEVICE_BUSY; 6169 } 6170 } 6171 6172 if (NT_SUCCESS(status)) 6173 { 6174 // If the device is in exclusive mode, check whether the request is from 6175 // the handle that locked the device. 6176 if (EXCLUSIVE_MODE(cdData) && !EXCLUSIVE_OWNER(cdData, WdfRequestGetFileObject(Request))) 6177 { 6178 // This request is not from the owner. We can't let the operation go. 6179 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "RequestValidateReadWrite: Access Denied! Device in exclusive mode.\n")); 6180 6181 status = STATUS_ACCESS_DENIED; 6182 } 6183 } 6184 6185 // Validate the request alignment. 6186 if (NT_SUCCESS(status)) 6187 { 6188 if (RequestParameters.Type == WdfRequestTypeRead) 6189 { 6190 startingOffset = RequestParameters.Parameters.Read.DeviceOffset; 6191 transferByteCount = RequestParameters.Parameters.Read.Length; 6192 } 6193 else 6194 { 6195 startingOffset = RequestParameters.Parameters.Write.DeviceOffset; 6196 transferByteCount = RequestParameters.Parameters.Write.Length; 6197 } 6198 6199 if (!DeviceExtension->DiskGeometry.BytesPerSector) 6200 { 6201 DeviceExtension->DiskGeometry.BytesPerSector = 2048; 6202 } 6203 6204 if (!DeviceExtension->SectorShift) 6205 { 6206 DeviceExtension->SectorShift = 11; 6207 } 6208 6209 // Perform some basic validation up front 6210 if (TEST_FLAG(startingOffset, DeviceExtension->DiskGeometry.BytesPerSector - 1) || 6211 TEST_FLAG(transferByteCount, DeviceExtension->DiskGeometry.BytesPerSector - 1)) 6212 { 6213 status = STATUS_INVALID_DEVICE_REQUEST; 6214 } 6215 } 6216 6217 // validate the request against the current mmc schema 6218 if (NT_SUCCESS(status)) 6219 { 6220 FEATURE_NUMBER schema = cdData->Mmc.ValidationSchema; 6221 6222 // We validate read requests according to the RandomWritable schema, except in the 6223 // case of IncrementalStreamingWritable, wherein the drive is responsible for all 6224 // of the verification 6225 if (RequestParameters.Type == WdfRequestTypeRead) 6226 { 6227 if (!cdData->Mmc.WriteAllowed) 6228 { 6229 // standard legacy validation of read irps 6230 // if writing is not allowed on the media 6231 schema = FeatureRandomWritable; 6232 } 6233 else if (schema != FeatureIncrementalStreamingWritable) 6234 { 6235 // standard legacy validation of read irps 6236 // if not using streaming writes on writable media 6237 schema = FeatureRandomWritable; 6238 } 6239 } 6240 6241 // Fail write requests to read-only media 6242 if ((RequestParameters.Type == WdfRequestTypeWrite) && 6243 !(cdData->Mmc.WriteAllowed)) 6244 { 6245 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "RequestValidateReadWrite: Write request to read-only media\n")); 6246 isValid = FALSE; 6247 } 6248 6249 if (isValid) 6250 { 6251 switch (schema) 6252 { 6253 case FeatureDefectManagement: 6254 case FeatureRandomWritable: 6255 // Ensure that the request is within bounds for ROM drives. 6256 // Writer drives do not need to have bounds as outbounds request should not damage the drive. 6257 if(!cdData->Mmc.IsWriter) 6258 { 6259 if ((startingOffset >= DeviceExtension->PartitionLength.QuadPart) || 6260 startingOffset < 0) 6261 { 6262 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "RequestValidateReadWrite: Request is out of bounds\n")); 6263 isValid = FALSE; 6264 6265 } 6266 else 6267 { 6268 ULONGLONG bytesRemaining = DeviceExtension->PartitionLength.QuadPart - startingOffset; 6269 6270 if ((ULONGLONG)transferByteCount > bytesRemaining) 6271 { 6272 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "RequestValidateReadWrite: Request is out of bounds\n")); 6273 isValid = FALSE; 6274 } 6275 } 6276 } 6277 break; 6278 6279 case FeatureRigidRestrictedOverwrite: 6280 // Ensure that the number of blocks is a multiple of the blocking size 6281 if (((transferByteCount >> DeviceExtension->SectorShift) % cdData->Mmc.Blocking) != 0) 6282 { 6283 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, 6284 "RequestValidateReadWrite: Number of blocks is not a multiple of the blocking size (%x)\n", 6285 cdData->Mmc.Blocking)); 6286 6287 isValid = FALSE; 6288 } 6289 // Fall through 6290 case FeatureRestrictedOverwrite: 6291 // Ensure that the request begins on a blocking boundary 6292 if ((Int64ShrlMod32(startingOffset, DeviceExtension->SectorShift) % cdData->Mmc.Blocking) != 0) 6293 { 6294 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, 6295 "RequestValidateReadWrite: Starting block is not a multiple of the blocking size (%x)\n", 6296 cdData->Mmc.Blocking)); 6297 6298 isValid = FALSE; 6299 } 6300 break; 6301 6302 case FeatureIncrementalStreamingWritable: 6303 // Let the drive handle the verification 6304 break; 6305 6306 default: 6307 // Unknown schema. Fail the request 6308 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, 6309 "RequestValidateReadWrite: Unknown validation schema (%x)\n", 6310 schema)); 6311 6312 isValid = FALSE; 6313 break; 6314 } //end of switch (schema) 6315 } // end of if (isValid) 6316 6317 if (!isValid) 6318 { 6319 status = STATUS_INVALID_DEVICE_REQUEST; 6320 } 6321 } // end of mmc schema validation 6322 6323 // validate that the Real-Time Streaming requests meet device capabilties 6324 if (NT_SUCCESS(status)) 6325 { 6326 // We do not check for FDO_HACK_NO_STREAMING in DeviceExtension->PrivateFdoData->HackFlags here, 6327 // because we're going to hide device failures related to streaming reads/writes from the sender 6328 // of the request. FDO_HACK_NO_STREAMING is going to be taken into account later during actual 6329 // processing of the request. 6330 if (RequestIsRealtimeStreaming(Request, RequestParameters.Type == WdfRequestTypeRead)) 6331 { 6332 if (RequestParameters.Type == WdfRequestTypeRead && !cdData->Mmc.StreamingReadSupported) 6333 { 6334 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, 6335 "RequestValidateReadWrite: Streaming reads are not supported.\n")); 6336 6337 status = STATUS_INVALID_DEVICE_REQUEST; 6338 } 6339 if (RequestParameters.Type == WdfRequestTypeWrite && !cdData->Mmc.StreamingWriteSupported) 6340 { 6341 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, 6342 "RequestValidateReadWrite: Streaming writes are not supported.\n")); 6343 6344 status = STATUS_INVALID_DEVICE_REQUEST; 6345 } 6346 } 6347 } 6348 6349 return status; 6350 } 6351 6352 NTSTATUS 6353 RequestHandleReadWrite( 6354 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 6355 _In_ WDFREQUEST Request, 6356 _In_ WDF_REQUEST_PARAMETERS RequestParameters 6357 ) 6358 /*++ 6359 6360 Routine Description: 6361 6362 Handle a read/write request 6363 6364 Arguments: 6365 6366 DeviceExtension - device context 6367 Request - request to be handled 6368 RequestParameters - request parameter 6369 6370 Return Value: 6371 6372 NTSTATUS 6373 6374 --*/ 6375 { 6376 NTSTATUS status = STATUS_SUCCESS; 6377 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); 6378 6379 size_t transferByteCount = 0; 6380 PIRP irp = NULL; 6381 PIO_STACK_LOCATION currentStack = NULL; 6382 6383 PUCHAR dataBuffer; 6384 6385 6386 irp = WdfRequestWdmGetIrp(Request); 6387 currentStack = IoGetCurrentIrpStackLocation(irp); 6388 dataBuffer = MmGetMdlVirtualAddress(irp->MdlAddress); 6389 6390 if (NT_SUCCESS(status)) 6391 { 6392 if (RequestParameters.Type == WdfRequestTypeRead) 6393 { 6394 transferByteCount = RequestParameters.Parameters.Read.Length; 6395 } 6396 else 6397 { 6398 transferByteCount = RequestParameters.Parameters.Write.Length; 6399 } 6400 6401 if (transferByteCount == 0) 6402 { 6403 // Several parts of the code turn 0 into 0xffffffff, 6404 // so don't process a zero-length request any further. 6405 status = STATUS_SUCCESS; 6406 RequestCompletion(DeviceExtension, Request, status, 0); 6407 return status; 6408 } 6409 6410 // Add partition byte offset to make starting byte relative to 6411 // beginning of disk. 6412 currentStack->Parameters.Read.ByteOffset.QuadPart += (DeviceExtension->StartingOffset.QuadPart); 6413 6414 //not very necessary as the starting offset for CD/DVD device is always 0. 6415 if (RequestParameters.Type == WdfRequestTypeRead) 6416 { 6417 RequestParameters.Parameters.Read.DeviceOffset = currentStack->Parameters.Read.ByteOffset.QuadPart; 6418 } 6419 else 6420 { 6421 RequestParameters.Parameters.Write.DeviceOffset = currentStack->Parameters.Write.ByteOffset.QuadPart; 6422 } 6423 } 6424 6425 if (NT_SUCCESS(status)) 6426 { 6427 ULONG entireXferLen = currentStack->Parameters.Read.Length; 6428 ULONG maxLength = 0; 6429 ULONG packetsCount = 0; 6430 6431 PCDROM_SCRATCH_READ_WRITE_CONTEXT readWriteContext; 6432 PCDROM_REQUEST_CONTEXT requestContext; 6433 PCDROM_REQUEST_CONTEXT originalRequestContext; 6434 6435 // get the count of packets we need to send. 6436 if ((((ULONG_PTR)dataBuffer) & (PAGE_SIZE-1)) == 0) 6437 { 6438 maxLength = cdData->MaxPageAlignedTransferBytes; 6439 } 6440 else 6441 { 6442 maxLength = cdData->MaxUnalignedTransferBytes; 6443 } 6444 6445 packetsCount = entireXferLen / maxLength; 6446 6447 if (entireXferLen % maxLength != 0) 6448 { 6449 packetsCount++; 6450 } 6451 6452 originalRequestContext = RequestGetContext(Request); 6453 6454 6455 ScratchBuffer_BeginUse(DeviceExtension); 6456 6457 readWriteContext = &DeviceExtension->ScratchContext.ScratchReadWriteContext; 6458 requestContext = RequestGetContext(DeviceExtension->ScratchContext.ScratchRequest); 6459 6460 readWriteContext->PacketsCount = packetsCount; 6461 readWriteContext->EntireXferLen = entireXferLen; 6462 readWriteContext->MaxLength = maxLength; 6463 readWriteContext->StartingOffset = currentStack->Parameters.Read.ByteOffset; 6464 readWriteContext->DataBuffer = dataBuffer; 6465 readWriteContext->TransferedBytes = 0; 6466 readWriteContext->IsRead = (RequestParameters.Type == WdfRequestTypeRead); 6467 6468 requestContext->OriginalRequest = Request; 6469 requestContext->DeviceExtension = DeviceExtension; 6470 6471 // 6472 // Setup the READ/WRITE fields in the original request which is what 6473 // we use to properly synchronize cancellation logic between the 6474 // cancel callback and the timer routine. 6475 // 6476 6477 originalRequestContext->ReadWriteIsCompleted = FALSE; 6478 originalRequestContext->ReadWriteRetryInitialized = FALSE; 6479 originalRequestContext->DeviceExtension = DeviceExtension; 6480 6481 status = ScratchBuffer_PerformNextReadWrite(DeviceExtension, TRUE); 6482 6483 // We do not call ScratchBuffer_EndUse here, because we're not releasing the scratch SRB. 6484 // It will be released in the completion routine. 6485 } 6486 6487 return status; 6488 } 6489 6490 _IRQL_requires_max_(PASSIVE_LEVEL) 6491 NTSTATUS 6492 RequestHandleLoadEjectMedia( 6493 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 6494 _In_ WDFREQUEST Request, 6495 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 6496 _Out_ size_t * DataLength 6497 ) 6498 /*++ 6499 6500 Routine Description: 6501 6502 Handle request of IOCTL_STORAGE_EJECT_MEDIA 6503 IOCTL_STORAGE_LOAD_MEDIA 6504 IOCTL_STORAGE_LOAD_MEDIA2 6505 6506 Arguments: 6507 6508 DeviceExtension - device context 6509 Request - request to be handled 6510 RequestParameters - request parameter 6511 DataLength - transferred data length 6512 6513 Return Value: 6514 6515 NTSTATUS 6516 6517 --*/ 6518 { 6519 NTSTATUS status = STATUS_SUCCESS; 6520 PZERO_POWER_ODD_INFO zpoddInfo = DeviceExtension->ZeroPowerODDInfo; 6521 6522 PAGED_CODE (); 6523 6524 *DataLength = 0; 6525 6526 if (NT_SUCCESS(status)) 6527 { 6528 // Synchronize with ejection control and ejection cleanup code as 6529 // well as other eject/load requests. 6530 WdfWaitLockAcquire(DeviceExtension->EjectSynchronizationLock, NULL); 6531 6532 if(DeviceExtension->ProtectedLockCount != 0) 6533 { 6534 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, "RequestHandleLoadEjectMedia: call to eject protected locked " 6535 "device - failure\n")); 6536 status = STATUS_DEVICE_BUSY; 6537 } 6538 6539 if (NT_SUCCESS(status)) 6540 { 6541 SCSI_REQUEST_BLOCK srb; 6542 PCDB cdb = (PCDB)srb.Cdb; 6543 6544 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); 6545 6546 srb.CdbLength = 6; 6547 6548 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT; 6549 cdb->START_STOP.LoadEject = 1; 6550 6551 if(RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_STORAGE_EJECT_MEDIA) 6552 { 6553 cdb->START_STOP.Start = 0; 6554 6555 // We are sending down a soft eject, and in this case we should take an active ref 6556 // if the command succeeds. 6557 if ((zpoddInfo != NULL) && 6558 (zpoddInfo->LoadingMechanism == LOADING_MECHANISM_TRAY) && 6559 (zpoddInfo->Load == 0)) // Drawer 6560 { 6561 zpoddInfo->MonitorStartStopUnit = TRUE; 6562 } 6563 } 6564 else 6565 { 6566 cdb->START_STOP.Start = 1; 6567 } 6568 6569 status = DeviceSendSrbSynchronously(DeviceExtension->Device, 6570 &srb, 6571 NULL, 6572 0, 6573 FALSE, 6574 Request); 6575 6576 if (zpoddInfo != NULL) 6577 { 6578 zpoddInfo->MonitorStartStopUnit = FALSE; 6579 } 6580 } 6581 6582 WdfWaitLockRelease(DeviceExtension->EjectSynchronizationLock); 6583 } 6584 6585 return status; 6586 } 6587 6588 6589 _IRQL_requires_max_(PASSIVE_LEVEL) 6590 NTSTATUS 6591 RequestHandleReserveRelease( 6592 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 6593 _In_ WDFREQUEST Request, 6594 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 6595 _Out_ size_t * DataLength 6596 ) 6597 /*++ 6598 6599 Routine Description: 6600 6601 Handle request of IOCTL_STORAGE_RESERVE 6602 IOCTL_STORAGE_RELEASE 6603 6604 Arguments: 6605 6606 DeviceExtension - device context 6607 Request - request to be handled 6608 RequestParameters - request parameter 6609 DataLength - transferred data length 6610 6611 Return Value: 6612 6613 NTSTATUS 6614 6615 --*/ 6616 { 6617 NTSTATUS status = STATUS_SUCCESS; 6618 PSCSI_REQUEST_BLOCK srb = NULL; 6619 PCDB cdb = NULL; 6620 ULONG ioctlCode = 0; 6621 6622 PAGED_CODE (); 6623 6624 *DataLength = 0; 6625 6626 srb = ExAllocatePoolWithTag(NonPagedPoolNx, 6627 sizeof(SCSI_REQUEST_BLOCK) + 6628 (sizeof(ULONG_PTR) * 2), 6629 CDROM_TAG_SRB); 6630 6631 if (srb == NULL) 6632 { 6633 status = STATUS_INSUFFICIENT_RESOURCES; 6634 } 6635 6636 if (NT_SUCCESS(status)) 6637 { 6638 ioctlCode = RequestParameters.Parameters.DeviceIoControl.IoControlCode; 6639 cdb = (PCDB)srb->Cdb; 6640 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK)); 6641 6642 if (TEST_FLAG(DeviceExtension->PrivateFdoData->HackFlags, FDO_HACK_NO_RESERVE6)) 6643 { 6644 srb->CdbLength = 10; 6645 cdb->CDB10.OperationCode = (ioctlCode == IOCTL_STORAGE_RESERVE) ? SCSIOP_RESERVE_UNIT10 : SCSIOP_RELEASE_UNIT10; 6646 } 6647 else 6648 { 6649 srb->CdbLength = 6; 6650 cdb->CDB6GENERIC.OperationCode = (ioctlCode == IOCTL_STORAGE_RESERVE) ? SCSIOP_RESERVE_UNIT : SCSIOP_RELEASE_UNIT; 6651 } 6652 6653 // Set timeout value. 6654 srb->TimeOutValue = DeviceExtension->TimeOutValue; 6655 6656 // Send reserves as tagged requests. 6657 if (ioctlCode == IOCTL_STORAGE_RESERVE) 6658 { 6659 SET_FLAG(srb->SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE); 6660 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; 6661 } 6662 6663 status = DeviceSendSrbSynchronously(DeviceExtension->Device, 6664 srb, 6665 NULL, 6666 0, 6667 FALSE, 6668 Request); 6669 // no data transfer. 6670 *DataLength = 0; 6671 6672 FREE_POOL(srb); 6673 } 6674 6675 return status; 6676 } // end RequestHandleReserveRelease() 6677 6678 static // __REACTOS__ 6679 BOOLEAN 6680 ValidPersistentReserveScope( 6681 UCHAR Scope) 6682 { 6683 switch (Scope) { 6684 case RESERVATION_SCOPE_LU: 6685 case RESERVATION_SCOPE_ELEMENT: 6686 6687 return TRUE; 6688 6689 default: 6690 6691 return FALSE; 6692 } 6693 } 6694 6695 static // __REACTOS__ 6696 BOOLEAN 6697 ValidPersistentReserveType( 6698 UCHAR Type) 6699 { 6700 switch (Type) { 6701 case RESERVATION_TYPE_WRITE_EXCLUSIVE: 6702 case RESERVATION_TYPE_EXCLUSIVE: 6703 case RESERVATION_TYPE_WRITE_EXCLUSIVE_REGISTRANTS: 6704 case RESERVATION_TYPE_EXCLUSIVE_REGISTRANTS: 6705 6706 return TRUE; 6707 6708 default: 6709 6710 return FALSE; 6711 } 6712 } 6713 6714 NTSTATUS 6715 RequestValidatePersistentReserve( 6716 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 6717 _In_ WDFREQUEST Request, 6718 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 6719 _Out_ size_t * DataLength 6720 ) 6721 /*++ 6722 6723 Routine Description: 6724 6725 Validate request of IOCTL_STORAGE_PERSISTENT_RESERVE_IN 6726 IOCTL_STORAGE_PERSISTENT_RESERVE_OUT 6727 6728 Arguments: 6729 6730 DeviceExtension - device context 6731 Request - request to be handled 6732 RequestParameters - request parameter 6733 DataLength - transferred data length 6734 6735 Return Value: 6736 6737 NTSTATUS 6738 6739 --*/ 6740 { 6741 NTSTATUS status = STATUS_SUCCESS; 6742 ULONG ioctlCode = RequestParameters.Parameters.DeviceIoControl.IoControlCode; 6743 6744 PPERSISTENT_RESERVE_COMMAND reserveCommand = NULL; 6745 6746 *DataLength = 0; 6747 6748 status = WdfRequestRetrieveInputBuffer(Request, 6749 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 6750 (PVOID*)&reserveCommand, 6751 NULL); 6752 if (NT_SUCCESS(status)) 6753 { 6754 if ((RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(PERSISTENT_RESERVE_COMMAND)) || 6755 (reserveCommand->Size < sizeof(PERSISTENT_RESERVE_COMMAND))) 6756 { 6757 *DataLength = 0; 6758 status = STATUS_INFO_LENGTH_MISMATCH; 6759 } 6760 else if ((ULONG_PTR)reserveCommand & DeviceExtension->AdapterDescriptor->AlignmentMask) 6761 { 6762 // Check buffer alignment. Only an issue if another kernel mode component 6763 // (not the I/O manager) allocates the buffer. 6764 *DataLength = 0; 6765 status = STATUS_INVALID_USER_BUFFER; 6766 } 6767 } 6768 6769 if (NT_SUCCESS(status)) 6770 { 6771 if (ioctlCode == IOCTL_STORAGE_PERSISTENT_RESERVE_IN) 6772 { 6773 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < reserveCommand->PR_IN.AllocationLength) 6774 { 6775 *DataLength = 0; 6776 status = STATUS_INVALID_PARAMETER; 6777 } 6778 else 6779 { 6780 switch (reserveCommand->PR_IN.ServiceAction) 6781 { 6782 case RESERVATION_ACTION_READ_KEYS: 6783 if (reserveCommand->PR_IN.AllocationLength < sizeof(PRI_REGISTRATION_LIST)) 6784 { 6785 *DataLength = 0; 6786 status = STATUS_INVALID_PARAMETER; 6787 } 6788 break; 6789 6790 case RESERVATION_ACTION_READ_RESERVATIONS: 6791 if (reserveCommand->PR_IN.AllocationLength < sizeof(PRI_RESERVATION_LIST)) 6792 { 6793 *DataLength = 0; 6794 status = STATUS_INVALID_PARAMETER; 6795 } 6796 break; 6797 6798 default: 6799 *DataLength = 0; 6800 status = STATUS_INVALID_PARAMETER; 6801 break; 6802 } 6803 } 6804 } 6805 else // case of IOCTL_STORAGE_PERSISTENT_RESERVE_OUT 6806 { 6807 // Verify ServiceAction, Scope, and Type 6808 switch (reserveCommand->PR_OUT.ServiceAction) 6809 { 6810 case RESERVATION_ACTION_REGISTER: 6811 case RESERVATION_ACTION_REGISTER_IGNORE_EXISTING: 6812 case RESERVATION_ACTION_CLEAR: 6813 // Scope and type ignored. 6814 break; 6815 6816 case RESERVATION_ACTION_RESERVE: 6817 case RESERVATION_ACTION_RELEASE: 6818 case RESERVATION_ACTION_PREEMPT: 6819 case RESERVATION_ACTION_PREEMPT_ABORT: 6820 if (!ValidPersistentReserveScope(reserveCommand->PR_OUT.Scope) || 6821 !ValidPersistentReserveType(reserveCommand->PR_OUT.Type)) 6822 { 6823 *DataLength = 0; 6824 status = STATUS_INVALID_PARAMETER; 6825 } 6826 break; 6827 6828 default: 6829 *DataLength = 0; 6830 status = STATUS_INVALID_PARAMETER; 6831 break; 6832 } 6833 6834 // Check input buffer for PR Out. 6835 // Caller must include the PR parameter list. 6836 if (NT_SUCCESS(status)) 6837 { 6838 if ((RequestParameters.Parameters.DeviceIoControl.InputBufferLength < 6839 (sizeof(PERSISTENT_RESERVE_COMMAND) + sizeof(PRO_PARAMETER_LIST))) || 6840 (reserveCommand->Size < RequestParameters.Parameters.DeviceIoControl.InputBufferLength)) 6841 { 6842 *DataLength = 0; 6843 status = STATUS_INVALID_PARAMETER; 6844 } 6845 } 6846 } // end of validation for IOCTL_STORAGE_PERSISTENT_RESERVE_OUT 6847 } 6848 6849 return status; 6850 } // end RequestValidatePersistentReserve() 6851 6852 6853 _IRQL_requires_max_(PASSIVE_LEVEL) 6854 NTSTATUS 6855 RequestHandlePersistentReserve( 6856 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 6857 _In_ WDFREQUEST Request, 6858 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 6859 _Out_ size_t * DataLength 6860 ) 6861 /*++ 6862 6863 Routine Description: 6864 6865 Handle request of IOCTL_STORAGE_PERSISTENT_RESERVE_IN 6866 IOCTL_STORAGE_PERSISTENT_RESERVE_OUT 6867 6868 Arguments: 6869 6870 DeviceExtension - device context 6871 Request - request to be handled 6872 RequestParameters - request parameter 6873 DataLength - transferred data length 6874 6875 Return Value: 6876 6877 NTSTATUS 6878 6879 --*/ 6880 { 6881 NTSTATUS status = STATUS_SUCCESS; 6882 ULONG ioctlCode = RequestParameters.Parameters.DeviceIoControl.IoControlCode; 6883 PSCSI_REQUEST_BLOCK srb = NULL; 6884 PCDB cdb = NULL; 6885 BOOLEAN writeToDevice; 6886 6887 PPERSISTENT_RESERVE_COMMAND reserveCommand = NULL; 6888 6889 PAGED_CODE (); 6890 6891 *DataLength = 0; 6892 6893 status = WdfRequestRetrieveInputBuffer(Request, 6894 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 6895 (PVOID*)&reserveCommand, 6896 NULL); 6897 if (NT_SUCCESS(status)) 6898 { 6899 srb = ExAllocatePoolWithTag(NonPagedPoolNx, 6900 sizeof(SCSI_REQUEST_BLOCK) + 6901 (sizeof(ULONG_PTR) * 2), 6902 CDROM_TAG_SRB); 6903 6904 if (srb == NULL) 6905 { 6906 status = STATUS_INSUFFICIENT_RESOURCES; 6907 } 6908 else 6909 { 6910 cdb = (PCDB)srb->Cdb; 6911 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK)); 6912 } 6913 } 6914 6915 if (NT_SUCCESS(status)) 6916 { 6917 size_t dataBufLen = 0; 6918 6919 // Fill in the CDB. 6920 if (ioctlCode == IOCTL_STORAGE_PERSISTENT_RESERVE_IN) 6921 { 6922 cdb->PERSISTENT_RESERVE_IN.OperationCode = SCSIOP_PERSISTENT_RESERVE_IN; 6923 cdb->PERSISTENT_RESERVE_IN.ServiceAction = reserveCommand->PR_IN.ServiceAction; 6924 6925 REVERSE_BYTES_SHORT(&(cdb->PERSISTENT_RESERVE_IN.AllocationLength), 6926 &(reserveCommand->PR_IN.AllocationLength)); 6927 6928 dataBufLen = RequestParameters.Parameters.DeviceIoControl.OutputBufferLength; 6929 writeToDevice = FALSE; 6930 } 6931 else 6932 { 6933 cdb->PERSISTENT_RESERVE_OUT.OperationCode = SCSIOP_PERSISTENT_RESERVE_OUT; 6934 cdb->PERSISTENT_RESERVE_OUT.ServiceAction = reserveCommand->PR_OUT.ServiceAction; 6935 cdb->PERSISTENT_RESERVE_OUT.Scope = reserveCommand->PR_OUT.Scope; 6936 cdb->PERSISTENT_RESERVE_OUT.Type = reserveCommand->PR_OUT.Type; 6937 6938 cdb->PERSISTENT_RESERVE_OUT.ParameterListLength[1] = (UCHAR)sizeof(PRO_PARAMETER_LIST); 6939 6940 // Move the parameter list to the beginning of the data buffer (so it is aligned 6941 // correctly and that the MDL describes it correctly). 6942 RtlMoveMemory(reserveCommand, 6943 reserveCommand->PR_OUT.ParameterList, 6944 sizeof(PRO_PARAMETER_LIST)); 6945 6946 dataBufLen = sizeof(PRO_PARAMETER_LIST); 6947 writeToDevice = TRUE; 6948 } 6949 6950 srb->CdbLength = 10; 6951 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; 6952 6953 status = DeviceSendSrbSynchronously(DeviceExtension->Device, 6954 srb, 6955 reserveCommand, 6956 (ULONG) dataBufLen, 6957 writeToDevice, 6958 Request); 6959 6960 FREE_POOL(srb); 6961 } 6962 6963 return status; 6964 } 6965 6966 #if (NTDDI_VERSION >= NTDDI_WIN8) 6967 _IRQL_requires_max_(APC_LEVEL) 6968 NTSTATUS 6969 RequestHandleAreVolumesReady( 6970 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 6971 _In_ WDFREQUEST Request, 6972 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 6973 _Out_ size_t * DataLength 6974 ) 6975 /*++ 6976 6977 Routine Description: 6978 6979 Handle request of IOCTL_DISK_ARE_VOLUMES_READY 6980 6981 Arguments: 6982 6983 DeviceExtension - device context 6984 Request - request to be handled 6985 RequestParameters - request parameter 6986 DataLength - transferred data length 6987 6988 Return Value: 6989 6990 NTSTATUS 6991 6992 --*/ 6993 { 6994 BOOLEAN completeRequest = TRUE; 6995 NTSTATUS status = STATUS_SUCCESS; 6996 6997 UNREFERENCED_PARAMETER(RequestParameters); 6998 6999 *DataLength = 0; 7000 7001 if (DeviceExtension->IsVolumeOnlinePending == FALSE) 7002 { 7003 status = STATUS_SUCCESS; 7004 goto Cleanup; 7005 } 7006 7007 // 7008 // Add to the volume ready queue. No worries about request cancellation, 7009 // since KMDF will automatically handle that while request is in queue. 7010 // 7011 status = WdfRequestForwardToIoQueue(Request, 7012 DeviceExtension->ManualVolumeReadyQueue 7013 ); 7014 7015 if(!NT_SUCCESS(status)) 7016 { 7017 goto Cleanup; 7018 } 7019 7020 status = STATUS_PENDING; 7021 completeRequest = FALSE; 7022 7023 Cleanup: 7024 7025 if (completeRequest) 7026 { 7027 RequestCompletion(DeviceExtension, Request, status, 0); 7028 } 7029 7030 return status; 7031 } 7032 7033 _IRQL_requires_max_(APC_LEVEL) 7034 NTSTATUS 7035 RequestHandleVolumeOnline( 7036 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 7037 _In_ WDFREQUEST Request, 7038 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 7039 _Out_ size_t * DataLength 7040 ) 7041 /*++ 7042 7043 Routine Description: 7044 7045 Handle request of IOCTL_VOLUME_ONLINE / IOCTL_VOLUME_POST_ONLINE 7046 7047 Arguments: 7048 7049 DeviceExtension - device context 7050 Request - request to be handled 7051 RequestParameters - request parameter 7052 DataLength - transferred data length 7053 7054 Return Value: 7055 7056 NTSTATUS 7057 7058 --*/ 7059 { 7060 NTSTATUS status = STATUS_SUCCESS; 7061 WDFREQUEST request; 7062 PIRP irp = NULL; 7063 PIO_STACK_LOCATION nextStack = NULL; 7064 7065 UNREFERENCED_PARAMETER(RequestParameters); 7066 7067 *DataLength = 0; 7068 7069 DeviceExtension->IsVolumeOnlinePending = FALSE; 7070 7071 // Complete all parked volume ready requests. 7072 for (;;) 7073 { 7074 status = WdfIoQueueRetrieveNextRequest(DeviceExtension->ManualVolumeReadyQueue, 7075 &request); 7076 7077 if (!NT_SUCCESS(status)) 7078 { 7079 break; 7080 } 7081 7082 RequestCompletion(DeviceExtension, request, STATUS_SUCCESS, 0); 7083 } 7084 7085 // Change the IOCTL code to IOCTL_DISK_VOLUMES_ARE_READY, and forward the request down, 7086 // so that if the underlying port driver will also know that volume is ready. 7087 WdfRequestFormatRequestUsingCurrentType(Request); 7088 irp = WdfRequestWdmGetIrp(Request); 7089 nextStack = IoGetNextIrpStackLocation(irp); 7090 7091 irp->AssociatedIrp.SystemBuffer = &DeviceExtension->DeviceNumber; 7092 nextStack->Parameters.DeviceIoControl.OutputBufferLength = 0; 7093 nextStack->Parameters.DeviceIoControl.InputBufferLength = sizeof (DeviceExtension->DeviceNumber); 7094 nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_DISK_VOLUMES_ARE_READY; 7095 7096 // Send the request straight down (synchronously). 7097 RequestSend(DeviceExtension, 7098 Request, 7099 DeviceExtension->IoTarget, 7100 WDF_REQUEST_SEND_OPTION_SYNCHRONOUS, 7101 NULL); 7102 7103 return STATUS_SUCCESS; 7104 } 7105 #endif 7106 7107 _IRQL_requires_max_(PASSIVE_LEVEL) 7108 NTSTATUS 7109 DeviceHandleRawRead( 7110 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 7111 _In_ WDFREQUEST Request, 7112 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 7113 _Out_ size_t * DataLength 7114 ) 7115 /*++ 7116 7117 Routine Description: 7118 7119 Handle request of IOCTL_CDROM_RAW_READ 7120 7121 Arguments: 7122 7123 DeviceExtension - device context 7124 Request - request to be handled 7125 RequestParameters - request parameter 7126 DataLength - transferred data length 7127 7128 Return Value: 7129 7130 NTSTATUS 7131 7132 --*/ 7133 { 7134 // Determine whether the drive is currently in raw or cooked mode, 7135 // and which command to use to read the data. 7136 7137 NTSTATUS status = STATUS_SUCCESS; 7138 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); 7139 RAW_READ_INFO rawReadInfo = {0}; 7140 PVOID outputVirtAddr = NULL; 7141 ULONG startingSector; 7142 7143 PIRP irp = WdfRequestWdmGetIrp(Request); 7144 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(irp); 7145 7146 VOID* outputBuffer = NULL; 7147 7148 PAGED_CODE (); 7149 7150 *DataLength = 0; 7151 7152 if (TEST_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME) && 7153 (currentIrpStack->MinorFunction != CDROM_VOLUME_VERIFY_CHECKED) && 7154 !TEST_FLAG(currentIrpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME)) 7155 { 7156 // DO_VERIFY_VOLUME is set for the device object, 7157 // but this request is not itself a verify request. 7158 // So fail this request. 7159 (VOID) MediaReadCapacity(DeviceExtension->Device); 7160 7161 *DataLength = 0; 7162 //set the status for volume verification. 7163 status = STATUS_VERIFY_REQUIRED; 7164 } 7165 7166 if (NT_SUCCESS(status)) 7167 { 7168 // Since this ioctl is METHOD_OUT_DIRECT, we need to copy away 7169 // the input buffer before interpreting it. This prevents a 7170 // malicious app from messing with the input buffer while we 7171 // are interpreting it. This is done in dispacth. 7172 // 7173 // Here, we are going to get the input buffer out of saved place. 7174 rawReadInfo = *(PRAW_READ_INFO)currentIrpStack->Parameters.DeviceIoControl.Type3InputBuffer; 7175 7176 if (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength > 0) 7177 { 7178 // Make sure that any user buffer that we pass down to 7179 // the hardware is properly aligned 7180 NT_ASSERT(irp->MdlAddress); 7181 outputVirtAddr = MmGetMdlVirtualAddress(irp->MdlAddress); 7182 if ((ULONG_PTR)outputVirtAddr & DeviceExtension->AdapterDescriptor->AlignmentMask) 7183 { 7184 NT_ASSERT(!((ULONG_PTR)outputVirtAddr & DeviceExtension->AdapterDescriptor->AlignmentMask)); 7185 *DataLength = 0; 7186 status = STATUS_INVALID_PARAMETER; 7187 } 7188 } 7189 else 7190 { 7191 status = STATUS_INVALID_PARAMETER; 7192 } 7193 } 7194 7195 if (NT_SUCCESS(status)) 7196 { 7197 status = WdfRequestRetrieveOutputBuffer(Request, 7198 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 7199 &outputBuffer, 7200 NULL); 7201 } 7202 7203 if (NT_SUCCESS(status)) 7204 { 7205 switch (rawReadInfo.TrackMode) 7206 { 7207 case CDDA: 7208 case YellowMode2: 7209 case XAForm2: 7210 // no check needed. 7211 break; 7212 7213 case RawWithC2AndSubCode: 7214 if (!cdData->Mmc.ReadCdC2Pointers || !cdData->Mmc.ReadCdSubCode) 7215 { 7216 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, 7217 "Request to read C2 & Subcode rejected. " 7218 "Is C2 supported: %d Is Subcode supported: %d\n", 7219 cdData->Mmc.ReadCdC2Pointers, 7220 cdData->Mmc.ReadCdSubCode 7221 )); 7222 *DataLength = 0; 7223 status = STATUS_INVALID_DEVICE_REQUEST; 7224 } 7225 break; 7226 case RawWithC2: 7227 if (!cdData->Mmc.ReadCdC2Pointers) 7228 { 7229 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, 7230 "Request to read C2 rejected because drive does not " 7231 "report support for C2 pointers\n" 7232 )); 7233 *DataLength = 0; 7234 status = STATUS_INVALID_DEVICE_REQUEST; 7235 } 7236 break; 7237 case RawWithSubCode: 7238 7239 if (!cdData->Mmc.ReadCdSubCode) 7240 { 7241 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, 7242 "Request to read subcode rejected because drive does " 7243 "not report support for reading the subcode data\n" 7244 )); 7245 *DataLength = 0; 7246 status = STATUS_INVALID_DEVICE_REQUEST; 7247 } 7248 break; 7249 7250 default: 7251 *DataLength = 0; 7252 status = STATUS_INVALID_DEVICE_REQUEST; 7253 break; 7254 } 7255 } 7256 7257 if (NT_SUCCESS(status)) 7258 { 7259 PSCSI_REQUEST_BLOCK srb = DeviceExtension->ScratchContext.ScratchSrb; 7260 PCDB cdb = (PCDB)(srb->Cdb); 7261 7262 size_t transferByteCount; 7263 BOOLEAN shouldRetry = TRUE; 7264 ULONG timesAlreadyRetried = 0; 7265 LONGLONG retryIn100nsUnits = 0; 7266 7267 transferByteCount = RequestParameters.Parameters.DeviceIoControl.OutputBufferLength; 7268 7269 ScratchBuffer_BeginUse(DeviceExtension); 7270 7271 while (shouldRetry) 7272 { 7273 // Setup cdb depending upon the sector type we want. 7274 switch (rawReadInfo.TrackMode) 7275 { 7276 case CDDA: 7277 transferByteCount = rawReadInfo.SectorCount * RAW_SECTOR_SIZE; 7278 cdb->READ_CD.ExpectedSectorType = CD_DA_SECTOR; 7279 cdb->READ_CD.IncludeUserData = 1; 7280 cdb->READ_CD.HeaderCode = 3; 7281 cdb->READ_CD.IncludeSyncData = 1; 7282 break; 7283 7284 case YellowMode2: 7285 transferByteCount = rawReadInfo.SectorCount * RAW_SECTOR_SIZE; 7286 cdb->READ_CD.ExpectedSectorType = YELLOW_MODE2_SECTOR; 7287 cdb->READ_CD.IncludeUserData = 1; 7288 cdb->READ_CD.HeaderCode = 1; 7289 cdb->READ_CD.IncludeSyncData = 1; 7290 break; 7291 7292 case XAForm2: 7293 transferByteCount = rawReadInfo.SectorCount * RAW_SECTOR_SIZE; 7294 cdb->READ_CD.ExpectedSectorType = FORM2_MODE2_SECTOR; 7295 cdb->READ_CD.IncludeUserData = 1; 7296 cdb->READ_CD.HeaderCode = 3; 7297 cdb->READ_CD.IncludeSyncData = 1; 7298 break; 7299 7300 case RawWithC2AndSubCode: 7301 transferByteCount = rawReadInfo.SectorCount * CD_RAW_SECTOR_WITH_C2_AND_SUBCODE_SIZE; 7302 cdb->READ_CD.ExpectedSectorType = 0; // Any sector type 7303 cdb->READ_CD.IncludeUserData = 1; 7304 cdb->READ_CD.HeaderCode = 3; // Header and subheader returned 7305 cdb->READ_CD.IncludeSyncData = 1; 7306 cdb->READ_CD.ErrorFlags = 2; // C2 and block error 7307 cdb->READ_CD.SubChannelSelection = 1; // raw subchannel data 7308 break; 7309 7310 case RawWithC2: 7311 transferByteCount = rawReadInfo.SectorCount * CD_RAW_SECTOR_WITH_C2_SIZE; 7312 cdb->READ_CD.ExpectedSectorType = 0; // Any sector type 7313 cdb->READ_CD.IncludeUserData = 1; 7314 cdb->READ_CD.HeaderCode = 3; // Header and subheader returned 7315 cdb->READ_CD.IncludeSyncData = 1; 7316 cdb->READ_CD.ErrorFlags = 2; // C2 and block error 7317 break; 7318 7319 case RawWithSubCode: 7320 transferByteCount = rawReadInfo.SectorCount * CD_RAW_SECTOR_WITH_SUBCODE_SIZE; 7321 cdb->READ_CD.ExpectedSectorType = 0; // Any sector type 7322 cdb->READ_CD.IncludeUserData = 1; 7323 cdb->READ_CD.HeaderCode = 3; // Header and subheader returned 7324 cdb->READ_CD.IncludeSyncData = 1; 7325 cdb->READ_CD.SubChannelSelection = 1; // raw subchannel data 7326 break; 7327 7328 default: 7329 // should already checked before coming in loop. 7330 NT_ASSERT(FALSE); 7331 break; 7332 } 7333 7334 ScratchBuffer_SetupSrb(DeviceExtension, Request, (ULONG)transferByteCount, TRUE); 7335 // Restore the buffer, buffer size and MdlAddress. They got changed but we don't want to use the scratch buffer. 7336 { 7337 PIRP scratchIrp = WdfRequestWdmGetIrp(DeviceExtension->ScratchContext.ScratchRequest); 7338 scratchIrp->MdlAddress = irp->MdlAddress; 7339 srb->DataBuffer = outputVirtAddr; 7340 srb->DataTransferLength = (ULONG)transferByteCount; 7341 } 7342 // Calculate starting offset. 7343 startingSector = (ULONG)(rawReadInfo.DiskOffset.QuadPart >> DeviceExtension->SectorShift); 7344 7345 // Fill in CDB fields. 7346 srb->CdbLength = 12; 7347 7348 cdb->READ_CD.OperationCode = SCSIOP_READ_CD; 7349 cdb->READ_CD.TransferBlocks[2] = (UCHAR) (rawReadInfo.SectorCount & 0xFF); 7350 cdb->READ_CD.TransferBlocks[1] = (UCHAR) (rawReadInfo.SectorCount >> 8 ); 7351 cdb->READ_CD.TransferBlocks[0] = (UCHAR) (rawReadInfo.SectorCount >> 16); 7352 7353 cdb->READ_CD.StartingLBA[3] = (UCHAR) (startingSector & 0xFF); 7354 cdb->READ_CD.StartingLBA[2] = (UCHAR) ((startingSector >> 8)); 7355 cdb->READ_CD.StartingLBA[1] = (UCHAR) ((startingSector >> 16)); 7356 cdb->READ_CD.StartingLBA[0] = (UCHAR) ((startingSector >> 24)); 7357 7358 ScratchBuffer_SendSrb(DeviceExtension, TRUE, NULL); 7359 7360 if ((DeviceExtension->ScratchContext.ScratchSrb->SrbStatus == SRB_STATUS_ABORTED) && 7361 (DeviceExtension->ScratchContext.ScratchSrb->InternalStatus == STATUS_CANCELLED)) 7362 { 7363 shouldRetry = FALSE; 7364 status = STATUS_CANCELLED; 7365 } 7366 else 7367 { 7368 shouldRetry = RequestSenseInfoInterpretForScratchBuffer(DeviceExtension, 7369 timesAlreadyRetried, 7370 &status, 7371 &retryIn100nsUnits); 7372 if (shouldRetry) 7373 { 7374 LARGE_INTEGER t; 7375 t.QuadPart = -retryIn100nsUnits; 7376 timesAlreadyRetried++; 7377 KeDelayExecutionThread(KernelMode, FALSE, &t); 7378 // keep items clean 7379 ScratchBuffer_ResetItems(DeviceExtension, FALSE); 7380 } 7381 } 7382 } 7383 7384 if (NT_SUCCESS(status)) 7385 { 7386 *DataLength = srb->DataTransferLength; 7387 } 7388 7389 ScratchBuffer_EndUse(DeviceExtension); 7390 } 7391 7392 return status; 7393 } 7394 7395 _IRQL_requires_max_(APC_LEVEL) 7396 NTSTATUS 7397 DeviceHandlePlayAudioMsf( 7398 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 7399 _In_ WDFREQUEST Request, 7400 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 7401 _Out_ size_t * DataLength 7402 ) 7403 /*++ 7404 7405 Routine Description: 7406 7407 Handle request of IOCTL_CDROM_PLAY_AUDIO_MSF 7408 7409 Arguments: 7410 7411 DeviceExtension - device context 7412 Request - request to be handled 7413 RequestParameters - request parameter 7414 DataLength - transferred data length 7415 7416 Return Value: 7417 7418 NTSTATUS 7419 7420 --*/ 7421 { 7422 NTSTATUS status = STATUS_SUCCESS; 7423 PCDROM_PLAY_AUDIO_MSF inputBuffer = NULL; 7424 7425 PAGED_CODE (); 7426 7427 *DataLength = 0; 7428 7429 status = WdfRequestRetrieveInputBuffer(Request, 7430 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 7431 (PVOID*)&inputBuffer, 7432 NULL); 7433 7434 7435 if (NT_SUCCESS(status)) 7436 { 7437 ULONG transferSize = 0; 7438 CDB cdb; 7439 7440 ScratchBuffer_BeginUse(DeviceExtension); 7441 7442 RtlZeroMemory(&cdb, sizeof(CDB)); 7443 // Set up the CDB 7444 cdb.PLAY_AUDIO_MSF.OperationCode = SCSIOP_PLAY_AUDIO_MSF; 7445 7446 cdb.PLAY_AUDIO_MSF.StartingM = inputBuffer->StartingM; 7447 cdb.PLAY_AUDIO_MSF.StartingS = inputBuffer->StartingS; 7448 cdb.PLAY_AUDIO_MSF.StartingF = inputBuffer->StartingF; 7449 7450 cdb.PLAY_AUDIO_MSF.EndingM = inputBuffer->EndingM; 7451 cdb.PLAY_AUDIO_MSF.EndingS = inputBuffer->EndingS; 7452 cdb.PLAY_AUDIO_MSF.EndingF = inputBuffer->EndingF; 7453 7454 status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, transferSize, FALSE, &cdb, 10); 7455 7456 if (NT_SUCCESS(status)) 7457 { 7458 PLAY_ACTIVE(DeviceExtension) = TRUE; 7459 *DataLength = 0; 7460 } 7461 7462 // nothing to do after the command finishes. 7463 ScratchBuffer_EndUse(DeviceExtension); 7464 } 7465 7466 return status; 7467 } 7468 7469 _IRQL_requires_max_(APC_LEVEL) 7470 NTSTATUS 7471 DeviceHandleReadQChannel( 7472 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 7473 _In_ WDFREQUEST Request, 7474 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 7475 _Out_ size_t * DataLength 7476 ) 7477 /*++ 7478 7479 Routine Description: 7480 7481 Handle request of IOCTL_CDROM_READ_Q_CHANNEL 7482 7483 Arguments: 7484 7485 DeviceExtension - device context 7486 Request - request to be handled 7487 RequestParameters - request parameter 7488 DataLength - transferred data length 7489 7490 Return Value: 7491 7492 NTSTATUS 7493 7494 --*/ 7495 { 7496 NTSTATUS status = STATUS_SUCCESS; 7497 PVOID inputBuffer = NULL; 7498 PVOID outputBuffer = NULL; 7499 7500 PAGED_CODE (); 7501 7502 *DataLength = 0; 7503 7504 status = WdfRequestRetrieveInputBuffer(Request, 7505 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 7506 &inputBuffer, 7507 NULL); 7508 7509 if (NT_SUCCESS(status)) 7510 { 7511 status = WdfRequestRetrieveOutputBuffer(Request, 7512 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 7513 &outputBuffer, 7514 NULL); 7515 } 7516 7517 if (NT_SUCCESS(status)) 7518 { 7519 status = ReadQChannel(DeviceExtension, 7520 Request, 7521 inputBuffer, 7522 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 7523 outputBuffer, 7524 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 7525 DataLength); 7526 } 7527 7528 return status; 7529 } 7530 7531 _IRQL_requires_max_(APC_LEVEL) 7532 NTSTATUS 7533 ReadQChannel( 7534 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 7535 _In_opt_ WDFREQUEST OriginalRequest, 7536 _In_ PVOID InputBuffer, 7537 _In_ size_t InputBufferLength, 7538 _In_ PVOID OutputBuffer, 7539 _In_ size_t OutputBufferLength, 7540 _Out_ size_t * DataLength 7541 ) 7542 /*++ 7543 7544 Routine Description: 7545 7546 base function to handle request of IOCTL_CDROM_READ_Q_CHANNEL 7547 7548 Arguments: 7549 7550 DeviceExtension - device context 7551 OriginalRequest - original request to be handled 7552 InputBuffer - input buffer 7553 InputBufferLength - length of input buffer 7554 OutputBuffer - output buffer 7555 OutputBufferLength - length of output buffer 7556 7557 Return Value: 7558 7559 NTSTATUS 7560 DataLength - returned data length 7561 7562 --*/ 7563 { 7564 NTSTATUS status = STATUS_SUCCESS; 7565 ULONG transferByteCount = 0; 7566 CDB cdb; 7567 PCDROM_SUB_Q_DATA_FORMAT inputBuffer = (PCDROM_SUB_Q_DATA_FORMAT)InputBuffer; 7568 PSUB_Q_CHANNEL_DATA userChannelData = (PSUB_Q_CHANNEL_DATA)OutputBuffer; 7569 7570 PAGED_CODE (); 7571 7572 UNREFERENCED_PARAMETER(InputBufferLength); 7573 7574 *DataLength = 0; 7575 7576 // Set size of channel data -- however, this is dependent on 7577 // what information we are requesting (which Format) 7578 switch( inputBuffer->Format ) 7579 { 7580 case IOCTL_CDROM_CURRENT_POSITION: 7581 transferByteCount = sizeof(SUB_Q_CURRENT_POSITION); 7582 break; 7583 7584 case IOCTL_CDROM_MEDIA_CATALOG: 7585 transferByteCount = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER); 7586 break; 7587 7588 case IOCTL_CDROM_TRACK_ISRC: 7589 transferByteCount = sizeof(SUB_Q_TRACK_ISRC); 7590 break; 7591 } 7592 7593 ScratchBuffer_BeginUse(DeviceExtension); 7594 7595 RtlZeroMemory(&cdb, sizeof(CDB)); 7596 // Set up the CDB 7597 // Always logical unit 0, but only use MSF addressing 7598 // for IOCTL_CDROM_CURRENT_POSITION 7599 if (inputBuffer->Format==IOCTL_CDROM_CURRENT_POSITION) 7600 { 7601 cdb.SUBCHANNEL.Msf = CDB_USE_MSF; 7602 } 7603 7604 // Return subchannel data 7605 cdb.SUBCHANNEL.SubQ = CDB_SUBCHANNEL_BLOCK; 7606 7607 // Specify format of informatin to return 7608 cdb.SUBCHANNEL.Format = inputBuffer->Format; 7609 7610 // Specify which track to access (only used by Track ISRC reads) 7611 if (inputBuffer->Format==IOCTL_CDROM_TRACK_ISRC) 7612 { 7613 cdb.SUBCHANNEL.TrackNumber = inputBuffer->Track; 7614 } 7615 7616 cdb.SUBCHANNEL.AllocationLength[0] = (UCHAR) (transferByteCount >> 8); 7617 cdb.SUBCHANNEL.AllocationLength[1] = (UCHAR) (transferByteCount & 0xFF); 7618 cdb.SUBCHANNEL.OperationCode = SCSIOP_READ_SUB_CHANNEL; 7619 7620 status = ScratchBuffer_ExecuteCdb(DeviceExtension, OriginalRequest, transferByteCount, TRUE, &cdb, 10); 7621 7622 if (NT_SUCCESS(status)) 7623 { 7624 PSUB_Q_CHANNEL_DATA subQPtr = DeviceExtension->ScratchContext.ScratchSrb->DataBuffer; 7625 7626 #if DBG 7627 switch( inputBuffer->Format ) 7628 { 7629 case IOCTL_CDROM_CURRENT_POSITION: 7630 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,"ReadQChannel: Audio Status is %u\n", subQPtr->CurrentPosition.Header.AudioStatus )); 7631 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,"ReadQChannel: ADR = 0x%x\n", subQPtr->CurrentPosition.ADR )); 7632 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,"ReadQChannel: Control = 0x%x\n", subQPtr->CurrentPosition.Control )); 7633 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,"ReadQChannel: Track = %u\n", subQPtr->CurrentPosition.TrackNumber )); 7634 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,"ReadQChannel: Index = %u\n", subQPtr->CurrentPosition.IndexNumber )); 7635 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,"ReadQChannel: Absolute Address = %x\n", *((PULONG)subQPtr->CurrentPosition.AbsoluteAddress) )); 7636 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,"ReadQChannel: Relative Address = %x\n", *((PULONG)subQPtr->CurrentPosition.TrackRelativeAddress) )); 7637 break; 7638 7639 case IOCTL_CDROM_MEDIA_CATALOG: 7640 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,"ReadQChannel: Audio Status is %u\n", subQPtr->MediaCatalog.Header.AudioStatus )); 7641 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,"ReadQChannel: Mcval is %u\n", subQPtr->MediaCatalog.Mcval )); 7642 break; 7643 7644 case IOCTL_CDROM_TRACK_ISRC: 7645 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,"ReadQChannel: Audio Status is %u\n", subQPtr->TrackIsrc.Header.AudioStatus )); 7646 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,"ReadQChannel: Tcval is %u\n", subQPtr->TrackIsrc.Tcval )); 7647 break; 7648 } 7649 #endif 7650 7651 // Update the play active status. 7652 if (subQPtr->CurrentPosition.Header.AudioStatus == AUDIO_STATUS_IN_PROGRESS) 7653 { 7654 PLAY_ACTIVE(DeviceExtension) = TRUE; 7655 } 7656 else 7657 { 7658 PLAY_ACTIVE(DeviceExtension) = FALSE; 7659 } 7660 7661 // Check if output buffer is large enough to contain 7662 // the data. 7663 if (OutputBufferLength < DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength) 7664 { 7665 DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength = (ULONG)OutputBufferLength; 7666 } 7667 7668 // Copy our buffer into users. 7669 RtlMoveMemory(userChannelData, 7670 subQPtr, 7671 DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength); 7672 7673 *DataLength = DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength; 7674 } 7675 7676 // nothing to do after the command finishes. 7677 ScratchBuffer_EndUse(DeviceExtension); 7678 7679 return status; 7680 } 7681 7682 7683 _IRQL_requires_max_(APC_LEVEL) 7684 NTSTATUS 7685 DeviceHandlePauseAudio( 7686 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 7687 _In_ WDFREQUEST Request, 7688 _Out_ size_t * DataLength 7689 ) 7690 /*++ 7691 7692 Routine Description: 7693 7694 Handle request of IOCTL_CDROM_PAUSE_AUDIO 7695 7696 Arguments: 7697 7698 DeviceExtension - device context 7699 Request - request to be handled 7700 DataLength - transferred data length 7701 7702 Return Value: 7703 7704 NTSTATUS 7705 7706 --*/ 7707 { 7708 NTSTATUS status = STATUS_SUCCESS; 7709 7710 PAGED_CODE (); 7711 7712 *DataLength = 0; 7713 7714 if (NT_SUCCESS(status)) 7715 { 7716 ULONG transferSize = 0; 7717 CDB cdb; 7718 7719 ScratchBuffer_BeginUse(DeviceExtension); 7720 7721 RtlZeroMemory(&cdb, sizeof(CDB)); 7722 // Set up the CDB 7723 cdb.PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME; 7724 cdb.PAUSE_RESUME.Action = CDB_AUDIO_PAUSE; 7725 7726 status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, transferSize, FALSE, &cdb, 10); 7727 7728 if (NT_SUCCESS(status)) 7729 { 7730 PLAY_ACTIVE(DeviceExtension) = FALSE; 7731 *DataLength = 0; 7732 } 7733 7734 // nothing to do after the command finishes. 7735 ScratchBuffer_EndUse(DeviceExtension); 7736 } 7737 7738 return status; 7739 } 7740 7741 _IRQL_requires_max_(APC_LEVEL) 7742 NTSTATUS 7743 DeviceHandleResumeAudio( 7744 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 7745 _In_ WDFREQUEST Request, 7746 _Out_ size_t * DataLength 7747 ) 7748 /*++ 7749 7750 Routine Description: 7751 7752 Handle request of IOCTL_CDROM_RESUME_AUDIO 7753 7754 Arguments: 7755 7756 DeviceExtension - device context 7757 Request - request to be handled 7758 DataLength - transferred data length 7759 7760 Return Value: 7761 7762 NTSTATUS 7763 7764 --*/ 7765 { 7766 NTSTATUS status = STATUS_SUCCESS; 7767 7768 PAGED_CODE (); 7769 7770 *DataLength = 0; 7771 7772 if (NT_SUCCESS(status)) 7773 { 7774 ULONG transferSize = 0; 7775 CDB cdb; 7776 7777 ScratchBuffer_BeginUse(DeviceExtension); 7778 7779 RtlZeroMemory(&cdb, sizeof(CDB)); 7780 // Set up the CDB 7781 cdb.PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME; 7782 cdb.PAUSE_RESUME.Action = CDB_AUDIO_RESUME; 7783 7784 status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, transferSize, FALSE, &cdb, 10); 7785 7786 if (NT_SUCCESS(status)) 7787 { 7788 PLAY_ACTIVE(DeviceExtension) = TRUE; //not in original code. But we should set it. 7789 *DataLength = 0; 7790 } 7791 7792 // nothing to do after the command finishes. 7793 ScratchBuffer_EndUse(DeviceExtension); 7794 } 7795 7796 return status; 7797 } 7798 7799 _IRQL_requires_max_(APC_LEVEL) 7800 NTSTATUS 7801 DeviceHandleSeekAudioMsf( 7802 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 7803 _In_ WDFREQUEST Request, 7804 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 7805 _Out_ size_t * DataLength 7806 ) 7807 /*++ 7808 7809 Routine Description: 7810 7811 Handle request of IOCTL_CDROM_SEEK_AUDIO_MSF 7812 7813 Arguments: 7814 7815 DeviceExtension - device context 7816 Request - request to be handled 7817 RequestParameters - request parameter 7818 DataLength - transferred data length 7819 7820 Return Value: 7821 7822 NTSTATUS 7823 7824 --*/ 7825 { 7826 NTSTATUS status = STATUS_SUCCESS; 7827 PCDROM_SEEK_AUDIO_MSF inputBuffer = NULL; 7828 7829 PAGED_CODE (); 7830 7831 *DataLength = 0; 7832 7833 status = WdfRequestRetrieveInputBuffer(Request, 7834 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 7835 (PVOID*)&inputBuffer, 7836 NULL); 7837 7838 if (NT_SUCCESS(status)) 7839 { 7840 ULONG transferSize = 0; 7841 CDB cdb; 7842 ULONG logicalBlockAddress; 7843 7844 logicalBlockAddress = MSF_TO_LBA(inputBuffer->M, inputBuffer->S, inputBuffer->F); 7845 7846 ScratchBuffer_BeginUse(DeviceExtension); 7847 7848 RtlZeroMemory(&cdb, sizeof(CDB)); 7849 // Set up the CDB 7850 cdb.SEEK.OperationCode = SCSIOP_SEEK; 7851 cdb.SEEK.LogicalBlockAddress[0] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte3; 7852 cdb.SEEK.LogicalBlockAddress[1] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte2; 7853 cdb.SEEK.LogicalBlockAddress[2] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte1; 7854 cdb.SEEK.LogicalBlockAddress[3] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte0; 7855 7856 status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, transferSize, FALSE, &cdb, 10); 7857 7858 if (NT_SUCCESS(status)) 7859 { 7860 *DataLength = 0; 7861 } 7862 7863 // nothing to do after the command finishes. 7864 7865 ScratchBuffer_EndUse(DeviceExtension); 7866 } 7867 7868 return status; 7869 } 7870 7871 _IRQL_requires_max_(APC_LEVEL) 7872 NTSTATUS 7873 DeviceHandleStopAudio( 7874 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 7875 _In_ WDFREQUEST Request, 7876 _Out_ size_t * DataLength 7877 ) 7878 { 7879 NTSTATUS status = STATUS_SUCCESS; 7880 7881 PAGED_CODE (); 7882 7883 *DataLength = 0; 7884 7885 if (NT_SUCCESS(status)) 7886 { 7887 ULONG transferSize = 0; 7888 CDB cdb; 7889 7890 ScratchBuffer_BeginUse(DeviceExtension); 7891 7892 RtlZeroMemory(&cdb, sizeof(CDB)); 7893 // Set up the CDB 7894 cdb.START_STOP.OperationCode = SCSIOP_START_STOP_UNIT; 7895 cdb.START_STOP.Immediate = 1; 7896 cdb.START_STOP.Start = 0; 7897 cdb.START_STOP.LoadEject = 0; 7898 7899 status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, transferSize, FALSE, &cdb, 6); 7900 7901 if (NT_SUCCESS(status)) 7902 { 7903 PLAY_ACTIVE(DeviceExtension) = FALSE; 7904 *DataLength = 0; 7905 } 7906 7907 // nothing to do after the command finishes. 7908 ScratchBuffer_EndUse(DeviceExtension); 7909 } 7910 7911 return status; 7912 } 7913 7914 _IRQL_requires_max_(APC_LEVEL) 7915 NTSTATUS 7916 DeviceHandleGetSetVolume( 7917 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 7918 _In_ WDFREQUEST Request, 7919 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 7920 _Out_ size_t * DataLength 7921 ) 7922 /*++ 7923 7924 Routine Description: 7925 7926 Handle request of IOCTL_CDROM_GET_VOLUME 7927 IOCTL_CDROM_SET_VOLUME 7928 7929 Arguments: 7930 7931 DeviceExtension - device context 7932 Request - request to be handled 7933 RequestParameters - request parameter 7934 DataLength - transferred data length 7935 7936 Return Value: 7937 7938 NTSTATUS 7939 7940 --*/ 7941 { 7942 NTSTATUS status = STATUS_SUCCESS; 7943 7944 PAGED_CODE (); 7945 7946 *DataLength = 0; 7947 7948 if (NT_SUCCESS(status)) 7949 { 7950 ULONG transferSize = MODE_DATA_SIZE; 7951 CDB cdb; 7952 7953 ScratchBuffer_BeginUse(DeviceExtension); 7954 7955 RtlZeroMemory(&cdb, sizeof(CDB)); 7956 // Set up the CDB 7957 cdb.MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10; 7958 cdb.MODE_SENSE10.PageCode = CDROM_AUDIO_CONTROL_PAGE; 7959 cdb.MODE_SENSE10.AllocationLength[0] = (UCHAR)(MODE_DATA_SIZE >> 8); 7960 cdb.MODE_SENSE10.AllocationLength[1] = (UCHAR)(MODE_DATA_SIZE & 0xFF); 7961 7962 status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, transferSize, TRUE, &cdb, 10); 7963 7964 if (NT_SUCCESS(status)) 7965 { 7966 if (RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_VOLUME) 7967 { 7968 PAUDIO_OUTPUT audioOutput; 7969 PVOLUME_CONTROL volumeControl; 7970 ULONG bytesTransferred; 7971 7972 status = WdfRequestRetrieveOutputBuffer(Request, 7973 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 7974 (PVOID*)&volumeControl, 7975 NULL); 7976 if (NT_SUCCESS(status)) 7977 { 7978 audioOutput = ModeSenseFindSpecificPage((PCHAR)DeviceExtension->ScratchContext.ScratchSrb->DataBuffer, 7979 DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength, 7980 CDROM_AUDIO_CONTROL_PAGE, 7981 FALSE); 7982 7983 // Verify the page is as big as expected. 7984 bytesTransferred = (ULONG)((PCHAR)audioOutput - (PCHAR)DeviceExtension->ScratchContext.ScratchSrb->DataBuffer) + 7985 sizeof(AUDIO_OUTPUT); 7986 7987 if ((audioOutput != NULL) && 7988 (DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength >= bytesTransferred)) 7989 { 7990 ULONG i; 7991 for (i=0; i<4; i++) 7992 { 7993 volumeControl->PortVolume[i] = audioOutput->PortOutput[i].Volume; 7994 } 7995 7996 // Set bytes transferred in IRP. 7997 *DataLength = sizeof(VOLUME_CONTROL); 7998 7999 } 8000 else 8001 { 8002 *DataLength = 0; 8003 status = STATUS_INVALID_DEVICE_REQUEST; 8004 } 8005 } 8006 } 8007 else //IOCTL_CDROM_SET_VOLUME 8008 { 8009 PAUDIO_OUTPUT audioInput = NULL; 8010 PAUDIO_OUTPUT audioOutput = NULL; 8011 PVOLUME_CONTROL volumeControl = NULL; 8012 ULONG i,bytesTransferred,headerLength; 8013 8014 status = WdfRequestRetrieveInputBuffer(Request, 8015 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 8016 (PVOID*)&volumeControl, 8017 NULL); 8018 8019 if (NT_SUCCESS(status)) 8020 { 8021 audioInput = ModeSenseFindSpecificPage((PCHAR)DeviceExtension->ScratchContext.ScratchSrb->DataBuffer, 8022 DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength, 8023 CDROM_AUDIO_CONTROL_PAGE, 8024 FALSE); 8025 8026 // Check to make sure the mode sense data is valid before we go on 8027 if(audioInput == NULL) 8028 { 8029 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, 8030 "Mode Sense Page %d not found\n", 8031 CDROM_AUDIO_CONTROL_PAGE)); 8032 8033 *DataLength = 0; 8034 status = STATUS_INVALID_DEVICE_REQUEST; 8035 } 8036 } 8037 8038 if (NT_SUCCESS(status)) 8039 { 8040 // keep items clean; clear the command history 8041 ScratchBuffer_ResetItems(DeviceExtension, TRUE); 8042 8043 headerLength = sizeof(MODE_PARAMETER_HEADER10); 8044 bytesTransferred = sizeof(AUDIO_OUTPUT) + headerLength; 8045 8046 // use the scratch buffer as input buffer. 8047 // the content of this buffer will not be changed in the following loop. 8048 audioOutput = (PAUDIO_OUTPUT)((PCHAR)DeviceExtension->ScratchContext.ScratchBuffer + headerLength); 8049 8050 for (i=0; i<4; i++) 8051 { 8052 audioOutput->PortOutput[i].Volume = volumeControl->PortVolume[i]; 8053 audioOutput->PortOutput[i].ChannelSelection = audioInput->PortOutput[i].ChannelSelection; 8054 } 8055 8056 audioOutput->CodePage = CDROM_AUDIO_CONTROL_PAGE; 8057 audioOutput->ParameterLength = sizeof(AUDIO_OUTPUT) - 2; 8058 audioOutput->Immediate = MODE_SELECT_IMMEDIATE; 8059 8060 RtlZeroMemory(&cdb, sizeof(CDB)); 8061 // Set up the CDB 8062 cdb.MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10; 8063 cdb.MODE_SELECT10.ParameterListLength[0] = (UCHAR) (bytesTransferred >> 8); 8064 cdb.MODE_SELECT10.ParameterListLength[1] = (UCHAR) (bytesTransferred & 0xFF); 8065 cdb.MODE_SELECT10.PFBit = 1; 8066 8067 status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, bytesTransferred, FALSE, &cdb, 10); 8068 8069 } 8070 *DataLength = 0; 8071 } 8072 } 8073 8074 // nothing to do after the command finishes. 8075 ScratchBuffer_EndUse(DeviceExtension); 8076 } 8077 8078 return status; 8079 } 8080 8081 _IRQL_requires_max_(APC_LEVEL) 8082 NTSTATUS 8083 DeviceHandleReadDvdStructure( 8084 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 8085 _In_ WDFREQUEST Request, 8086 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 8087 _Out_ size_t * DataLength 8088 ) 8089 /*++ 8090 8091 Routine Description: 8092 8093 Handle request of IOCTL_DVD_READ_STRUCTURE 8094 8095 Arguments: 8096 8097 DeviceExtension - device context 8098 Request - request to be handled 8099 RequestParameters - request parameter 8100 DataLength - transferred data length 8101 8102 Return Value: 8103 8104 NTSTATUS 8105 8106 --*/ 8107 { 8108 NTSTATUS status = STATUS_SUCCESS; 8109 PVOID inputBuffer = NULL; 8110 PVOID outputBuffer = NULL; 8111 8112 PAGED_CODE (); 8113 8114 *DataLength = 0; 8115 8116 status = WdfRequestRetrieveInputBuffer(Request, 8117 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 8118 &inputBuffer, 8119 NULL); 8120 8121 if (NT_SUCCESS(status)) 8122 { 8123 status = WdfRequestRetrieveOutputBuffer(Request, 8124 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 8125 &outputBuffer, 8126 NULL); 8127 } 8128 8129 if (NT_SUCCESS(status)) 8130 { 8131 status = ReadDvdStructure(DeviceExtension, 8132 Request, 8133 inputBuffer, 8134 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 8135 outputBuffer, 8136 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 8137 DataLength); 8138 } 8139 8140 return status; 8141 } 8142 8143 _IRQL_requires_max_(APC_LEVEL) 8144 NTSTATUS 8145 ReadDvdStructure( 8146 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 8147 _In_opt_ WDFREQUEST OriginalRequest, 8148 _In_ PVOID InputBuffer, 8149 _In_ size_t InputBufferLength, 8150 _In_ PVOID OutputBuffer, 8151 _In_ size_t OutputBufferLength, 8152 _Out_ size_t * DataLength 8153 ) 8154 /*++ 8155 8156 Routine Description: 8157 8158 base function to handle request of IOCTL_DVD_START_SESSION 8159 IOCTL_DVD_READ_KEY 8160 8161 Arguments: 8162 8163 DeviceExtension - device context 8164 OriginalRequest - original request to be handled 8165 InputBuffer - input buffer 8166 InputBufferLength - length of input buffer 8167 OutputBuffer - output buffer 8168 OutputBufferLength - length of output buffer 8169 8170 Return Value: 8171 8172 NTSTATUS 8173 DataLength - returned data length 8174 8175 --*/ 8176 { 8177 NTSTATUS status = STATUS_SUCCESS; 8178 PDVD_READ_STRUCTURE request = (PDVD_READ_STRUCTURE)InputBuffer; 8179 PDVD_DESCRIPTOR_HEADER header = (PDVD_DESCRIPTOR_HEADER)OutputBuffer; 8180 CDB cdb; 8181 8182 USHORT dataLength; 8183 ULONG blockNumber; 8184 PFOUR_BYTE fourByte; 8185 8186 PAGED_CODE (); 8187 8188 UNREFERENCED_PARAMETER(InputBufferLength); 8189 8190 if (DeviceExtension->DeviceAdditionalData.DriveDeviceType != FILE_DEVICE_DVD) 8191 { 8192 *DataLength = 0; 8193 return STATUS_INVALID_DEVICE_REQUEST; 8194 } 8195 8196 dataLength = (USHORT)OutputBufferLength; 8197 blockNumber = (ULONG)(request->BlockByteOffset.QuadPart >> DeviceExtension->SectorShift); 8198 fourByte = (PFOUR_BYTE)&blockNumber; 8199 8200 ScratchBuffer_BeginUse(DeviceExtension); 8201 8202 RtlZeroMemory(&cdb, sizeof(CDB)); 8203 // Set up the CDB 8204 cdb.READ_DVD_STRUCTURE.OperationCode = SCSIOP_READ_DVD_STRUCTURE; 8205 cdb.READ_DVD_STRUCTURE.RMDBlockNumber[0] = fourByte->Byte3; 8206 cdb.READ_DVD_STRUCTURE.RMDBlockNumber[1] = fourByte->Byte2; 8207 cdb.READ_DVD_STRUCTURE.RMDBlockNumber[2] = fourByte->Byte1; 8208 cdb.READ_DVD_STRUCTURE.RMDBlockNumber[3] = fourByte->Byte0; 8209 cdb.READ_DVD_STRUCTURE.LayerNumber = request->LayerNumber; 8210 cdb.READ_DVD_STRUCTURE.Format = (UCHAR)request->Format; 8211 8212 #if DBG 8213 { 8214 if ((UCHAR)request->Format > DvdMaxDescriptor) 8215 { 8216 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, 8217 "READ_DVD_STRUCTURE format %x = %s (%x bytes)\n", 8218 (UCHAR)request->Format, 8219 READ_DVD_STRUCTURE_FORMAT_STRINGS[DvdMaxDescriptor], 8220 dataLength 8221 )); 8222 } 8223 else 8224 { 8225 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, 8226 "READ_DVD_STRUCTURE format %x = %s (%x bytes)\n", 8227 (UCHAR)request->Format, 8228 READ_DVD_STRUCTURE_FORMAT_STRINGS[(UCHAR)request->Format], 8229 dataLength 8230 )); 8231 } 8232 } 8233 #endif // DBG 8234 8235 if (request->Format == DvdDiskKeyDescriptor) 8236 { 8237 cdb.READ_DVD_STRUCTURE.AGID = (UCHAR)request->SessionId; 8238 } 8239 8240 cdb.READ_DVD_STRUCTURE.AllocationLength[0] = (UCHAR)(dataLength >> 8); 8241 cdb.READ_DVD_STRUCTURE.AllocationLength[1] = (UCHAR)(dataLength & 0xff); 8242 8243 status = ScratchBuffer_ExecuteCdb(DeviceExtension, OriginalRequest, dataLength, TRUE, &cdb, 12); 8244 8245 if (NT_SUCCESS(status)) 8246 { 8247 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 8248 "DvdDCCompletion - READ_STRUCTURE: descriptor format of %d\n", request->Format)); 8249 8250 RtlMoveMemory(header, 8251 DeviceExtension->ScratchContext.ScratchSrb->DataBuffer, 8252 DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength); 8253 8254 // Cook the data. There are a number of fields that really 8255 // should be byte-swapped for the caller. 8256 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 8257 "DvdDCCompletion - READ_STRUCTURE:\n" 8258 "\tHeader at %p\n" 8259 "\tDvdDCCompletion - READ_STRUCTURE: data at %p\n" 8260 "\tDataBuffer was at %p\n" 8261 "\tDataTransferLength was %lx\n", 8262 header, 8263 header->Data, 8264 DeviceExtension->ScratchContext.ScratchSrb->DataBuffer, 8265 DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength)); 8266 8267 // First the fields in the header 8268 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "READ_STRUCTURE: header->Length %lx -> ", 8269 header->Length)); 8270 8271 REVERSE_SHORT(&header->Length); 8272 8273 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "%lx\n", header->Length)); 8274 8275 // Now the fields in the descriptor 8276 if(request->Format == DvdPhysicalDescriptor) 8277 { 8278 ULONG tempLength = (DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength > (ULONG)FIELD_OFFSET(DVD_DESCRIPTOR_HEADER, Data)) 8279 ? (DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength - FIELD_OFFSET(DVD_DESCRIPTOR_HEADER, Data)) 8280 : 0; 8281 8282 PDVD_LAYER_DESCRIPTOR layer = (PDVD_LAYER_DESCRIPTOR)&(header->Data[0]); 8283 8284 // Make sure the buffer size is good for swapping bytes. 8285 if (tempLength >= RTL_SIZEOF_THROUGH_FIELD(DVD_LAYER_DESCRIPTOR, StartingDataSector)) 8286 { 8287 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "READ_STRUCTURE: StartingDataSector %lx -> ", 8288 layer->StartingDataSector)); 8289 REVERSE_LONG(&(layer->StartingDataSector)); 8290 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "%lx\n", layer->StartingDataSector)); 8291 } 8292 if (tempLength >= RTL_SIZEOF_THROUGH_FIELD(DVD_LAYER_DESCRIPTOR, EndDataSector)) 8293 { 8294 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "READ_STRUCTURE: EndDataSector %lx -> ", 8295 layer->EndDataSector)); 8296 REVERSE_LONG(&(layer->EndDataSector)); 8297 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "%lx\n", layer->EndDataSector)); 8298 } 8299 if (tempLength >= RTL_SIZEOF_THROUGH_FIELD(DVD_LAYER_DESCRIPTOR, EndLayerZeroSector)) 8300 { 8301 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "READ_STRUCTURE: EndLayerZeroSector %lx -> ", 8302 layer->EndLayerZeroSector)); 8303 REVERSE_LONG(&(layer->EndLayerZeroSector)); 8304 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "%lx\n", layer->EndLayerZeroSector)); 8305 } 8306 } 8307 8308 if (!NT_SUCCESS(status)) 8309 { 8310 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "Status is %lx\n", status)); 8311 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DvdDeviceControlCompletion - " 8312 "IOCTL_DVD_READ_STRUCTURE: data transfer length of %d\n", 8313 DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength)); 8314 } 8315 8316 *DataLength = DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength; 8317 } 8318 8319 ScratchBuffer_EndUse(DeviceExtension); 8320 8321 return status; 8322 } 8323 8324 _IRQL_requires_max_(APC_LEVEL) 8325 NTSTATUS 8326 DeviceHandleDvdEndSession( 8327 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 8328 _In_ WDFREQUEST Request, 8329 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 8330 _Out_ size_t * DataLength 8331 ) 8332 /*++ 8333 8334 Routine Description: 8335 8336 Handle request of IOCTL_DVD_END_SESSION 8337 8338 Arguments: 8339 8340 DeviceExtension - device context 8341 Request - request to be handled 8342 RequestParameters - request parameter 8343 DataLength - transferred data length 8344 8345 Return Value: 8346 8347 NTSTATUS 8348 8349 --*/ 8350 { 8351 NTSTATUS status = STATUS_SUCCESS; 8352 PDVD_SESSION_ID sessionId = NULL; 8353 8354 PAGED_CODE (); 8355 8356 *DataLength = 0; 8357 8358 status = WdfRequestRetrieveInputBuffer(Request, 8359 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 8360 (PVOID*)&sessionId, 8361 NULL); 8362 8363 if (NT_SUCCESS(status)) 8364 { 8365 ULONG transferSize = 0; 8366 CDB cdb; 8367 DVD_SESSION_ID currentSession = 0; 8368 DVD_SESSION_ID limitSession = 0; 8369 8370 if(*sessionId == DVD_END_ALL_SESSIONS) 8371 { 8372 currentSession = 0; 8373 limitSession = MAX_COPY_PROTECT_AGID - 1; 8374 } 8375 else 8376 { 8377 currentSession = *sessionId; 8378 limitSession = *sessionId; 8379 } 8380 8381 ScratchBuffer_BeginUse(DeviceExtension); 8382 8383 do 8384 { 8385 RtlZeroMemory(&cdb, sizeof(CDB)); 8386 // Set up the CDB 8387 cdb.SEND_KEY.OperationCode = SCSIOP_SEND_KEY; 8388 cdb.SEND_KEY.AGID = (UCHAR)(currentSession); 8389 cdb.SEND_KEY.KeyFormat = DVD_INVALIDATE_AGID; 8390 8391 status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, transferSize, FALSE, &cdb, 12); 8392 8393 currentSession++; 8394 } while ((currentSession <= limitSession) && NT_SUCCESS(status)); 8395 8396 // nothing to do after the command finishes. 8397 ScratchBuffer_EndUse(DeviceExtension); 8398 } 8399 8400 return status; 8401 } 8402 8403 _IRQL_requires_max_(APC_LEVEL) 8404 NTSTATUS 8405 DeviceHandleDvdStartSessionReadKey( 8406 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 8407 _In_ WDFREQUEST Request, 8408 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 8409 _Out_ size_t * DataLength 8410 ) 8411 /*++ 8412 8413 Routine Description: 8414 8415 Handle request of IOCTL_DVD_START_SESSION 8416 IOCTL_DVD_READ_KEY 8417 8418 Arguments: 8419 8420 DeviceExtension - device context 8421 Request - request to be handled 8422 RequestParameters - request parameter 8423 DataLength - transferred data length 8424 8425 Return Value: 8426 8427 NTSTATUS 8428 8429 --*/ 8430 { 8431 NTSTATUS status = STATUS_SUCCESS; 8432 PDVD_COPY_PROTECT_KEY keyParameters = NULL; 8433 PVOID outputBuffer = NULL; 8434 8435 PAGED_CODE (); 8436 8437 if (NT_SUCCESS(status)) 8438 { 8439 status = WdfRequestRetrieveOutputBuffer(Request, 8440 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 8441 &outputBuffer, 8442 NULL); 8443 } 8444 8445 if (NT_SUCCESS(status) && RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_DVD_READ_KEY) 8446 { 8447 status = WdfRequestRetrieveInputBuffer(Request, 8448 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 8449 (PVOID*)&keyParameters, 8450 NULL); 8451 } 8452 8453 if (NT_SUCCESS(status)) 8454 { 8455 status = DvdStartSessionReadKey(DeviceExtension, 8456 RequestParameters.Parameters.DeviceIoControl.IoControlCode, 8457 Request, 8458 keyParameters, 8459 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 8460 outputBuffer, 8461 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 8462 DataLength); 8463 } 8464 8465 return status; 8466 } 8467 8468 _IRQL_requires_max_(APC_LEVEL) 8469 NTSTATUS 8470 DvdStartSessionReadKey( 8471 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 8472 _In_ ULONG IoControlCode, 8473 _In_opt_ WDFREQUEST OriginalRequest, 8474 _In_opt_ PVOID InputBuffer, 8475 _In_ size_t InputBufferLength, 8476 _In_ PVOID OutputBuffer, 8477 _In_ size_t OutputBufferLength, 8478 _Out_ size_t * DataLength 8479 ) 8480 /*++ 8481 8482 Routine Description: 8483 8484 base function to handle request of IOCTL_DVD_START_SESSION 8485 IOCTL_DVD_READ_KEY 8486 8487 Arguments: 8488 8489 DeviceExtension - device context 8490 IoControlCode - IOCTL_DVD_READ_KEY or IOCTL_DVD_START_SESSION 8491 OriginalRequest - original request to be handled 8492 InputBuffer - input buffer 8493 InputBufferLength - length of input buffer 8494 OutputBuffer - output buffer 8495 OutputBufferLength - length of output buffer 8496 8497 Return Value: 8498 8499 NTSTATUS 8500 DataLength - returned data length 8501 8502 --*/ 8503 { 8504 NTSTATUS status = STATUS_SUCCESS; 8505 ULONG keyLength = 0; 8506 ULONG result = 0; 8507 ULONG allocationLength; 8508 PFOUR_BYTE fourByte; 8509 PDVD_COPY_PROTECT_KEY keyParameters = (PDVD_COPY_PROTECT_KEY)InputBuffer; 8510 8511 PAGED_CODE (); 8512 8513 UNREFERENCED_PARAMETER(InputBufferLength); 8514 8515 *DataLength = 0; 8516 8517 fourByte = (PFOUR_BYTE)&allocationLength; 8518 8519 if (IoControlCode == IOCTL_DVD_READ_KEY) 8520 { 8521 if (keyParameters == NULL) 8522 { 8523 status = STATUS_INTERNAL_ERROR; 8524 } 8525 8526 // First of all, initialize the DVD region of the drive, if it has not been set yet 8527 if (NT_SUCCESS(status) && 8528 (keyParameters->KeyType == DvdGetRpcKey) && 8529 DeviceExtension->DeviceAdditionalData.Mmc.IsCssDvd) 8530 { 8531 DevicePickDvdRegion(DeviceExtension->Device); 8532 } 8533 8534 if (NT_SUCCESS(status) && 8535 (keyParameters->KeyType == DvdDiskKey)) 8536 { 8537 // Special case - need to use READ DVD STRUCTURE command to get the disk key. 8538 PDVD_COPY_PROTECT_KEY keyHeader = NULL; 8539 PDVD_READ_STRUCTURE readStructureRequest = (PDVD_READ_STRUCTURE)keyParameters; 8540 8541 // save the key header so we can restore the interesting parts later 8542 keyHeader = ExAllocatePoolWithTag(NonPagedPoolNx, 8543 sizeof(DVD_COPY_PROTECT_KEY), 8544 DVD_TAG_READ_KEY); 8545 8546 if(keyHeader == NULL) 8547 { 8548 // Can't save the context so return an error 8549 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, 8550 "DvdDeviceControl - READ_KEY: unable to allocate context\n")); 8551 status = STATUS_INSUFFICIENT_RESOURCES; 8552 } 8553 8554 if (NT_SUCCESS(status)) 8555 { 8556 PREAD_DVD_STRUCTURES_HEADER rawKey = OutputBuffer; 8557 PDVD_COPY_PROTECT_KEY outputKey = OutputBuffer; 8558 8559 // save input parameters 8560 RtlCopyMemory(keyHeader, 8561 InputBuffer, 8562 sizeof(DVD_COPY_PROTECT_KEY)); 8563 8564 readStructureRequest->Format = DvdDiskKeyDescriptor; 8565 readStructureRequest->BlockByteOffset.QuadPart = 0; 8566 readStructureRequest->LayerNumber = 0; 8567 readStructureRequest->SessionId = keyHeader->SessionId; 8568 8569 status = ReadDvdStructure(DeviceExtension, 8570 OriginalRequest, 8571 InputBuffer, 8572 sizeof(DVD_READ_STRUCTURE), 8573 OutputBuffer, 8574 sizeof(READ_DVD_STRUCTURES_HEADER) + sizeof(DVD_DISK_KEY_DESCRIPTOR), 8575 DataLength); 8576 8577 // fill the output buffer, it's not touched in DeviceHandleReadDvdStructure() 8578 // for this specific request type: DvdDiskKeyDescriptor 8579 if (NT_SUCCESS(status)) 8580 { 8581 // Shift the data down to its new position. 8582 RtlMoveMemory(outputKey->KeyData, 8583 rawKey->Data, 8584 sizeof(DVD_DISK_KEY_DESCRIPTOR)); 8585 8586 RtlCopyMemory(outputKey, 8587 keyHeader, 8588 sizeof(DVD_COPY_PROTECT_KEY)); 8589 8590 outputKey->KeyLength = DVD_DISK_KEY_LENGTH; 8591 8592 *DataLength = DVD_DISK_KEY_LENGTH; 8593 } 8594 else 8595 { 8596 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, 8597 "StartSessionReadKey Failed with status %x, %xI64 (%x) bytes\n", 8598 status, 8599 (unsigned int)*DataLength, 8600 ((rawKey->Length[0] << 16) | rawKey->Length[1]) )); 8601 } 8602 8603 FREE_POOL(keyHeader); 8604 } 8605 8606 // special process finished. return from here. 8607 return status; 8608 } 8609 8610 if (NT_SUCCESS(status)) 8611 { 8612 status = RtlULongSub((ULONG)OutputBufferLength, 8613 (ULONG)sizeof(DVD_COPY_PROTECT_KEY), &result); 8614 } 8615 8616 if (NT_SUCCESS(status)) 8617 { 8618 status = RtlULongAdd(result, sizeof(CDVD_KEY_HEADER), &keyLength); 8619 } 8620 8621 if (NT_SUCCESS(status)) 8622 { 8623 //The data length field of REPORT KEY Command occupies two bytes 8624 keyLength = min(keyLength, MAXUSHORT); 8625 } 8626 } 8627 else //IOCTL_DVD_START_SESSION 8628 { 8629 keyParameters = NULL; 8630 keyLength = sizeof(CDVD_KEY_HEADER) + sizeof(CDVD_REPORT_AGID_DATA); 8631 status = STATUS_SUCCESS; 8632 } 8633 8634 if (NT_SUCCESS(status)) 8635 { 8636 CDB cdb; 8637 8638 allocationLength = keyLength; 8639 8640 // Defensive coding. Prefix cannot recognize this usage. 8641 UNREFERENCED_PARAMETER(allocationLength); 8642 8643 ScratchBuffer_BeginUse(DeviceExtension); 8644 8645 RtlZeroMemory(&cdb, sizeof(CDB)); 8646 // Set up the CDB 8647 cdb.REPORT_KEY.OperationCode = SCSIOP_REPORT_KEY; 8648 cdb.REPORT_KEY.AllocationLength[0] = fourByte->Byte1; 8649 cdb.REPORT_KEY.AllocationLength[1] = fourByte->Byte0; 8650 8651 // set the specific parameters.... 8652 if(IoControlCode == IOCTL_DVD_READ_KEY) 8653 { 8654 if(keyParameters->KeyType == DvdTitleKey) 8655 { 8656 ULONG logicalBlockAddress; 8657 8658 logicalBlockAddress = (ULONG)(keyParameters->Parameters.TitleOffset.QuadPart >> 8659 DeviceExtension->SectorShift); 8660 8661 fourByte = (PFOUR_BYTE)&(logicalBlockAddress); 8662 8663 cdb.REPORT_KEY.LogicalBlockAddress[0] = fourByte->Byte3; 8664 cdb.REPORT_KEY.LogicalBlockAddress[1] = fourByte->Byte2; 8665 cdb.REPORT_KEY.LogicalBlockAddress[2] = fourByte->Byte1; 8666 cdb.REPORT_KEY.LogicalBlockAddress[3] = fourByte->Byte0; 8667 } 8668 8669 cdb.REPORT_KEY.KeyFormat = (UCHAR)keyParameters->KeyType; 8670 cdb.REPORT_KEY.AGID = (UCHAR)keyParameters->SessionId; 8671 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 8672 "DvdStartSessionReadKey => sending irp %p (%s)\n", 8673 OriginalRequest, "READ_KEY")); 8674 } 8675 else 8676 { 8677 cdb.REPORT_KEY.KeyFormat = DVD_REPORT_AGID; 8678 cdb.REPORT_KEY.AGID = 0; 8679 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 8680 "DvdStartSessionReadKey => sending irp %p (%s)\n", 8681 OriginalRequest, "START_SESSION")); 8682 } 8683 8684 status = ScratchBuffer_ExecuteCdb(DeviceExtension, OriginalRequest, keyLength, TRUE, &cdb, 12); 8685 8686 if (NT_SUCCESS(status)) 8687 { 8688 if(IoControlCode == IOCTL_DVD_READ_KEY) 8689 { 8690 NTSTATUS tempStatus; 8691 PDVD_COPY_PROTECT_KEY copyProtectKey = (PDVD_COPY_PROTECT_KEY)OutputBuffer; 8692 PCDVD_KEY_HEADER keyHeader = DeviceExtension->ScratchContext.ScratchSrb->DataBuffer; 8693 ULONG dataLength; 8694 ULONG transferLength; 8695 8696 tempStatus = RtlULongSub(DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength, 8697 FIELD_OFFSET(CDVD_KEY_HEADER, Data), 8698 &transferLength); 8699 8700 dataLength = (keyHeader->DataLength[0] << 8) + keyHeader->DataLength[1]; 8701 8702 if (NT_SUCCESS(tempStatus) && (dataLength >= 2)) 8703 { 8704 // Adjust the data length to ignore the two reserved bytes in the 8705 // header. 8706 dataLength -= 2; 8707 8708 // take the minimum of the transferred length and the 8709 // length as specified in the header. 8710 if(dataLength < transferLength) 8711 { 8712 transferLength = dataLength; 8713 } 8714 8715 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 8716 "DvdDeviceControlCompletion: [%p] - READ_KEY with " 8717 "transfer length of (%d or %d) bytes\n", 8718 OriginalRequest, 8719 dataLength, 8720 DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength - 2)); 8721 8722 // Copy the key data into the return buffer 8723 if(copyProtectKey->KeyType == DvdTitleKey) 8724 { 8725 RtlMoveMemory(copyProtectKey->KeyData, 8726 keyHeader->Data + 1, 8727 transferLength - 1); 8728 8729 copyProtectKey->KeyData[transferLength - 1] = 0; 8730 8731 // If this is a title key then we need to copy the CGMS flags 8732 // as well. 8733 copyProtectKey->KeyFlags = *(keyHeader->Data); 8734 8735 } 8736 else 8737 { 8738 RtlMoveMemory(copyProtectKey->KeyData, 8739 keyHeader->Data, 8740 transferLength); 8741 } 8742 8743 copyProtectKey->KeyLength = sizeof(DVD_COPY_PROTECT_KEY); 8744 copyProtectKey->KeyLength += transferLength; 8745 8746 *DataLength = copyProtectKey->KeyLength; 8747 } 8748 else 8749 { 8750 //There is no valid data from drive. 8751 //This may happen when Key Format = 0x3f that does not require data back from drive. 8752 status = STATUS_SUCCESS; 8753 *DataLength = 0; 8754 } 8755 } 8756 else 8757 { 8758 PDVD_SESSION_ID sessionId = (PDVD_SESSION_ID)OutputBuffer; 8759 PCDVD_KEY_HEADER keyHeader = DeviceExtension->ScratchContext.ScratchSrb->DataBuffer; 8760 PCDVD_REPORT_AGID_DATA keyData = (PCDVD_REPORT_AGID_DATA)keyHeader->Data; 8761 8762 *sessionId = keyData->AGID; 8763 8764 *DataLength = sizeof(DVD_SESSION_ID); 8765 } 8766 } 8767 8768 // nothing to do after the command finishes. 8769 ScratchBuffer_EndUse(DeviceExtension); 8770 } 8771 8772 return status; 8773 } 8774 8775 8776 _IRQL_requires_max_(APC_LEVEL) 8777 NTSTATUS 8778 DeviceHandleDvdSendKey( 8779 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 8780 _In_ WDFREQUEST Request, 8781 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 8782 _Out_ size_t * DataLength 8783 ) 8784 /*++ 8785 8786 Routine Description: 8787 8788 Handle request of IOCTL_DVD_SEND_KEY 8789 IOCTL_DVD_SEND_KEY2 8790 8791 Arguments: 8792 8793 DeviceExtension - device context 8794 Request - request to be handled 8795 RequestParameters - request parameter 8796 DataLength - transferred data length 8797 8798 Return Value: 8799 8800 NTSTATUS 8801 8802 --*/ 8803 { 8804 NTSTATUS status = STATUS_SUCCESS; 8805 PVOID inputBuffer = NULL; 8806 8807 PAGED_CODE (); 8808 8809 *DataLength = 0; 8810 8811 status = WdfRequestRetrieveInputBuffer(Request, 8812 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 8813 &inputBuffer, 8814 NULL); 8815 8816 if (NT_SUCCESS(status)) 8817 { 8818 status = DvdSendKey(DeviceExtension, 8819 Request, 8820 inputBuffer, 8821 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 8822 DataLength); 8823 } 8824 8825 return status; 8826 } 8827 8828 _IRQL_requires_max_(APC_LEVEL) 8829 NTSTATUS 8830 DvdSendKey( 8831 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 8832 _In_opt_ WDFREQUEST OriginalRequest, 8833 _In_ PVOID InputBuffer, 8834 _In_ size_t InputBufferLength, 8835 _Out_ size_t * DataLength 8836 ) 8837 /*++ 8838 8839 Routine Description: 8840 8841 base function to handle request of IOCTL_DVD_SEND_KEY(2) 8842 NOTE: cdrom does not process this IOCTL if the input buffer length is bigger than Port transfer length. 8843 8844 Arguments: 8845 8846 DeviceExtension - device context 8847 OriginalRequest - original request to be handled 8848 InputBuffer - input buffer 8849 InputBufferLength - length of input buffer 8850 8851 Return Value: 8852 8853 NTSTATUS 8854 DataLength - returned data length 8855 8856 --*/ 8857 { 8858 NTSTATUS status = STATUS_SUCCESS; 8859 PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY)InputBuffer; 8860 8861 ULONG keyLength = 0; 8862 ULONG result = 0; 8863 PFOUR_BYTE fourByte; 8864 8865 PAGED_CODE (); 8866 8867 UNREFERENCED_PARAMETER(InputBufferLength); 8868 8869 *DataLength = 0; 8870 8871 if (NT_SUCCESS(status)) 8872 { 8873 if ((key->KeyLength < sizeof(DVD_COPY_PROTECT_KEY)) || 8874 ((key->KeyLength - sizeof(DVD_COPY_PROTECT_KEY)) > DeviceExtension->ScratchContext.ScratchBufferSize)) 8875 { 8876 NT_ASSERT(FALSE); 8877 status = STATUS_INTERNAL_ERROR; 8878 } 8879 } 8880 8881 if (NT_SUCCESS(status)) 8882 { 8883 status = RtlULongSub(key->KeyLength, sizeof(DVD_COPY_PROTECT_KEY), &result); 8884 } 8885 8886 if (NT_SUCCESS(status)) 8887 { 8888 status = RtlULongAdd(result, sizeof(CDVD_KEY_HEADER), &keyLength); 8889 } 8890 8891 if (NT_SUCCESS(status)) 8892 { 8893 keyLength = min(keyLength, DeviceExtension->ScratchContext.ScratchBufferSize); 8894 8895 if (keyLength < 2) 8896 { 8897 status = STATUS_INVALID_PARAMETER; 8898 } 8899 } 8900 8901 if (NT_SUCCESS(status)) 8902 { 8903 PCDVD_KEY_HEADER keyBuffer = NULL; 8904 CDB cdb; 8905 8906 ScratchBuffer_BeginUse(DeviceExtension); 8907 8908 // prepare the input buffer 8909 keyBuffer = (PCDVD_KEY_HEADER)DeviceExtension->ScratchContext.ScratchBuffer; 8910 8911 // keylength is decremented here by two because the 8912 // datalength does not include the header, which is two 8913 // bytes. keylength is immediately incremented later 8914 // by the same amount. 8915 keyLength -= 2; 8916 fourByte = (PFOUR_BYTE)&keyLength; 8917 keyBuffer->DataLength[0] = fourByte->Byte1; 8918 keyBuffer->DataLength[1] = fourByte->Byte0; 8919 keyLength += 2; 8920 8921 RtlMoveMemory(keyBuffer->Data, 8922 key->KeyData, 8923 key->KeyLength - sizeof(DVD_COPY_PROTECT_KEY)); 8924 8925 RtlZeroMemory(&cdb, sizeof(CDB)); 8926 // Set up the CDB 8927 cdb.REPORT_KEY.OperationCode = SCSIOP_SEND_KEY; 8928 8929 cdb.SEND_KEY.ParameterListLength[0] = fourByte->Byte1; 8930 cdb.SEND_KEY.ParameterListLength[1] = fourByte->Byte0; 8931 cdb.SEND_KEY.KeyFormat = (UCHAR)key->KeyType; 8932 cdb.SEND_KEY.AGID = (UCHAR)key->SessionId; 8933 8934 status = ScratchBuffer_ExecuteCdb(DeviceExtension, OriginalRequest, keyLength, FALSE, &cdb, 12); 8935 8936 // nothing to do after the command finishes. 8937 ScratchBuffer_EndUse(DeviceExtension); 8938 } 8939 8940 return status; 8941 } 8942 8943 8944 _IRQL_requires_max_(APC_LEVEL) 8945 NTSTATUS 8946 DeviceHandleSetReadAhead( 8947 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 8948 _In_ WDFREQUEST Request, 8949 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 8950 _Out_ size_t * DataLength 8951 ) 8952 /*++ 8953 8954 Routine Description: 8955 8956 Handle request of IOCTL_STORAGE_SET_READ_AHEAD 8957 8958 Arguments: 8959 8960 DeviceExtension - device context 8961 Request - request to be handled 8962 RequestParameters - request parameter 8963 DataLength - transferred data length 8964 8965 Return Value: 8966 8967 NTSTATUS 8968 8969 --*/ 8970 { 8971 NTSTATUS status = STATUS_SUCCESS; 8972 PSTORAGE_SET_READ_AHEAD readAhead = NULL; 8973 8974 PAGED_CODE (); 8975 8976 *DataLength = 0; 8977 8978 status = WdfRequestRetrieveInputBuffer(Request, 8979 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 8980 (PVOID*)&readAhead, 8981 NULL); 8982 8983 if (NT_SUCCESS(status)) 8984 { 8985 ULONG transferSize = 0; 8986 CDB cdb; 8987 ULONG blockAddress; 8988 PFOUR_BYTE fourByte = (PFOUR_BYTE)&blockAddress; 8989 8990 ScratchBuffer_BeginUse(DeviceExtension); 8991 8992 RtlZeroMemory(&cdb, sizeof(CDB)); 8993 // Set up the CDB 8994 cdb.SET_READ_AHEAD.OperationCode = SCSIOP_SET_READ_AHEAD; 8995 8996 blockAddress = (ULONG)(readAhead->TriggerAddress.QuadPart >> 8997 DeviceExtension->SectorShift); 8998 8999 // Defensive coding. Prefix cannot recognize this usage. 9000 UNREFERENCED_PARAMETER(blockAddress); 9001 9002 cdb.SET_READ_AHEAD.TriggerLBA[0] = fourByte->Byte3; 9003 cdb.SET_READ_AHEAD.TriggerLBA[1] = fourByte->Byte2; 9004 cdb.SET_READ_AHEAD.TriggerLBA[2] = fourByte->Byte1; 9005 cdb.SET_READ_AHEAD.TriggerLBA[3] = fourByte->Byte0; 9006 9007 blockAddress = (ULONG)(readAhead->TargetAddress.QuadPart >> 9008 DeviceExtension->SectorShift); 9009 9010 cdb.SET_READ_AHEAD.ReadAheadLBA[0] = fourByte->Byte3; 9011 cdb.SET_READ_AHEAD.ReadAheadLBA[1] = fourByte->Byte2; 9012 cdb.SET_READ_AHEAD.ReadAheadLBA[2] = fourByte->Byte1; 9013 cdb.SET_READ_AHEAD.ReadAheadLBA[3] = fourByte->Byte0; 9014 9015 status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, transferSize, FALSE, &cdb, 12); 9016 9017 if (NT_SUCCESS(status)) 9018 { 9019 *DataLength = 0; 9020 } 9021 9022 // nothing to do after the command finishes. 9023 ScratchBuffer_EndUse(DeviceExtension); 9024 } 9025 9026 return status; 9027 } 9028 9029 _IRQL_requires_max_(APC_LEVEL) 9030 NTSTATUS 9031 DeviceHandleSetSpeed( 9032 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 9033 _In_ WDFREQUEST Request, 9034 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 9035 _Out_ size_t * DataLength 9036 ) 9037 /*++ 9038 9039 Routine Description: 9040 9041 Handle request of IOCTL_CDROM_SET_SPEED 9042 9043 Arguments: 9044 9045 DeviceExtension - device context 9046 Request - request to be handled 9047 RequestParameters - request parameter 9048 DataLength - transferred data length 9049 9050 Return Value: 9051 9052 NTSTATUS 9053 9054 --*/ 9055 { 9056 NTSTATUS status = STATUS_SUCCESS; 9057 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData); 9058 PCDROM_SET_SPEED inputBuffer = NULL; 9059 9060 PAGED_CODE (); 9061 9062 *DataLength = 0; 9063 9064 status = WdfRequestRetrieveInputBuffer(Request, 9065 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 9066 (PVOID*)&inputBuffer, 9067 NULL); 9068 9069 if (NT_SUCCESS(status)) 9070 { 9071 ULONG transferSize = 0; 9072 CDB cdb; 9073 CDROM_SPEED_REQUEST requestType = inputBuffer->RequestType; 9074 9075 ScratchBuffer_BeginUse(DeviceExtension); 9076 9077 RtlZeroMemory(&cdb, sizeof(CDB)); 9078 // Set up the CDB 9079 if (requestType == CdromSetSpeed) 9080 { 9081 PCDROM_SET_SPEED speed = inputBuffer; 9082 9083 cdb.SET_CD_SPEED.OperationCode = SCSIOP_SET_CD_SPEED; 9084 cdb.SET_CD_SPEED.RotationControl = speed->RotationControl; 9085 REVERSE_BYTES_SHORT(&cdb.SET_CD_SPEED.ReadSpeed, &speed->ReadSpeed); 9086 REVERSE_BYTES_SHORT(&cdb.SET_CD_SPEED.WriteSpeed, &speed->WriteSpeed); 9087 } 9088 else 9089 { 9090 PCDROM_SET_STREAMING stream = (PCDROM_SET_STREAMING)inputBuffer; 9091 PPERFORMANCE_DESCRIPTOR perfDescriptor; 9092 9093 transferSize = sizeof(PERFORMANCE_DESCRIPTOR); 9094 9095 perfDescriptor = DeviceExtension->ScratchContext.ScratchBuffer; 9096 RtlZeroMemory(perfDescriptor, transferSize); 9097 9098 perfDescriptor->RandomAccess = stream->RandomAccess; 9099 perfDescriptor->Exact = stream->SetExact; 9100 perfDescriptor->RestoreDefaults = stream->RestoreDefaults; 9101 perfDescriptor->WriteRotationControl = stream->RotationControl; 9102 9103 REVERSE_BYTES(&perfDescriptor->StartLba, &stream->StartLba); 9104 REVERSE_BYTES(&perfDescriptor->EndLba, &stream->EndLba); 9105 REVERSE_BYTES(&perfDescriptor->ReadSize, &stream->ReadSize); 9106 REVERSE_BYTES(&perfDescriptor->ReadTime, &stream->ReadTime); 9107 REVERSE_BYTES(&perfDescriptor->WriteSize, &stream->WriteSize); 9108 REVERSE_BYTES(&perfDescriptor->WriteTime, &stream->WriteTime); 9109 9110 cdb.SET_STREAMING.OperationCode = SCSIOP_SET_STREAMING; 9111 REVERSE_BYTES_SHORT(&cdb.SET_STREAMING.ParameterListLength, &transferSize); 9112 9113 // set value in extension by user inputs. 9114 cdData->RestoreDefaults = stream->Persistent ? FALSE : TRUE; 9115 9116 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DeviceHandleSetSpeed: Restore default speed on media change set to %s\n", 9117 cdData->RestoreDefaults ? "true" : "false")); 9118 } 9119 9120 status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, transferSize, FALSE, &cdb, 12); 9121 9122 if (NT_SUCCESS(status)) 9123 { 9124 *DataLength = 0; 9125 } 9126 9127 // nothing to do after the command finishes. 9128 ScratchBuffer_EndUse(DeviceExtension); 9129 } 9130 9131 return status; 9132 } 9133 9134 9135