ReactOS 0.4.16-dev-336-gb667d82
ioctl.c
Go to the documentation of this file.
1/*--
2
3Copyright (C) Microsoft Corporation. All rights reserved.
4
5Module Name:
6
7 ioctl.c
8
9Abstract:
10
11 Include all funtions for processing IOCTLs
12
13Environment:
14
15 kernel mode only
16
17Notes:
18
19
20Revision 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
55VOID
56GetConfigurationDataConversionTypeAllToTypeOne(
57 _In_ FEATURE_NUMBER RequestedFeature,
59 _Out_ size_t * DataLength
60 );
61
63VOID
64GetConfigurationDataSynthesize(
65 _In_reads_bytes_(InputBufferSize) PVOID InputBuffer,
66 _In_ ULONG InputBufferSize,
67 _Out_writes_bytes_(OutputBufferSize) PVOID OutputBuffer,
68 _In_ size_t OutputBufferSize,
71 _Out_ size_t * DataLength
72 );
73
75PCDB
76RequestGetScsiPassThroughCdb(
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
129 _In_ WDFDEVICE Device,
130 _In_ WDFREQUEST Request
131 )
132/*++
133
134Routine Description:
135
136 All unknown IOCTLs will be forward to lower level driver.
137
138Arguments:
139
140 Device - device object
141 Request - request to be handled
142
143Return Value:
144
145 NTSTATUS
146
147--*/
148{
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
193DeviceIsPlayActive(
194 _In_ WDFDEVICE Device
195 )
196/*++
197
198Routine Description:
199
200 This routine determines if the cd is currently playing music.
201
202Arguments:
203
204 Device - Device object.
205
206Return Value:
207
208 BOOLEAN - TRUE if the device is playing music.
209
210--*/
211{
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
227 currentBuffer = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
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,
244 currentBuffer,
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
271 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
272 _In_ WDFREQUEST Request,
274 _Out_ size_t * DataLength)
275/*++
276
277Routine Description:
278
279 Handler for IOCTL_CDROM_GET_INQUIRY_DATA
280
281Arguments:
282
283 DeviceExtension - device context
284 Request - request to be handled
285 RequestParameters - request parameter
286 DataLength - transferred data length
287
288Return Value:
289
290 NTSTATUS
291
292--*/
293{
295 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData);
296
297 *DataLength = 0;
298
299 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength == 0)
300 {
302 }
303 else
304 {
305 PVOID outputBuffer = NULL;
306
308 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength);
309
310 status = WdfRequestRetrieveOutputBuffer(Request,
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
326 {
328 }
329 }
330
331 return status;
332}
333
334
337 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
338 _In_ WDFREQUEST Request,
339 _Out_ size_t * DataLength
340 )
341/*++
342
343Routine Description:
344
345 Handler for IOCTL_STORAGE_GET_MEDIA_TYPES_EX
346
347Arguments:
348
349 DeviceExtension - device context
350 Request - request to be handled
351 DataLength - transferred data length
352
353Return Value:
354
355 NTSTATUS
356
357--*/
358{
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.
371 {
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 {
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
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,
461 mediaInfo--;
462 }
463 else
464 {
465 SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics,
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
478 }
479
480 *DataLength = sizeNeeded;
481
482 return status;
483}
484
487RequestHandleGetDvdRegion(
488 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
489 _In_ WDFREQUEST Request,
490 _Out_ size_t * DataLength
491 )
492/*++
493
494Routine Description:
495
496 Handler for IOCTL_DVD_GET_REGION
497
498Arguments:
499
500 DeviceExtension - device context
501 Request - request to be handled
502 DataLength - transferred data length
503
504Return Value:
505
506 NTSTATUS
507
508--*/
509{
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 {
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,
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,
559 if (readStructure == NULL)
560 {
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,
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,
602 Request,
603 copyProtectKey,
605 copyProtectKey,
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"));
637 }
638 }
639
640 // Clean up
641 if (readStructure != NULL)
642 {
643 ExFreePool(readStructure);
644 }
645
646 return status;
647}
648
651 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
652 _In_ WDFREQUEST Request,
654 _Out_ size_t * DataLength
655 )
656/*++
657
658Routine Description:
659
660 Validate request of IOCTL_CDROM_RAW_READ
661
662Arguments:
663
664 DeviceExtension - device context
665 Request - request to be handled
666 RequestParameters - request parameter
667 DataLength - transferred data length
668
669Return Value:
670
671 NTSTATUS
672
673--*/
674{
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,
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);
715 }
716 }
717 else
718 {
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"));
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"));
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"));
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"));
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"));
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));
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",
827 DeviceExtension->AdapterDescriptor->AlignmentMask));
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 {
848 }
849 else
850 {
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 ));
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
888 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
889 _In_ WDFREQUEST Request,
891 _Out_ size_t * DataLength
892 )
893/*++
894
895Routine Description:
896
897 Validate request of IOCTL_CDROM_READ_TOC_EX
898
899Arguments:
900
901 DeviceExtension - device context
902 Request - request to be handled
903 RequestParameters - request parameter
904 DataLength - transferred data length
905
906Return Value:
907
908 NTSTATUS
909
910--*/
911{
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 {
922 }
923 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength <
925 {
928 }
929 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength >
930 ((USHORT)-1))
931 {
933 }
934 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength &
935 DeviceExtension->AdapterDescriptor->AlignmentMask)
936 {
938 }
939
940 if (NT_SUCCESS(status))
941 {
942 status = WdfRequestRetrieveInputBuffer(Request,
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 {
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 {
972 }
973 }
974 else
975 {
977 }
978 }
979
980 return status;
981}
982
985 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
987 _Out_ size_t * DataLength
988 )
989/*++
990
991Routine Description:
992
993 Validate request of IOCTL_CDROM_READ_TOC
994
995Arguments:
996
997 DeviceExtension - device context
998 RequestParameters - request parameter
999 DataLength - transferred data length
1000
1001Return Value:
1002
1003 NTSTATUS
1004
1005--*/
1006{
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.
1017 *DataLength = sizeof(CDROM_TOC);
1018 }
1019 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength &
1020 DeviceExtension->AdapterDescriptor->AlignmentMask)
1021 {
1023 }
1024
1025 return status;
1026}
1027
1030 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
1032 _Out_ size_t * DataLength
1033 )
1034/*++
1035
1036Routine Description:
1037
1038 Validate request of IOCTL_CDROM_GET_LAST_SESSION
1039
1040Arguments:
1041
1042 DeviceExtension - device context
1043 RequestParameters - request parameter
1044 DataLength - transferred data length
1045
1046Return Value:
1047
1048 NTSTATUS
1049
1050--*/
1051{
1053
1054 *DataLength = 0;
1055
1056 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength <
1057 sizeof(CDROM_TOC_SESSION_DATA))
1058 {
1061 }
1062 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength &
1063 DeviceExtension->AdapterDescriptor->AlignmentMask)
1064 {
1066 }
1067
1068 return status;
1069}
1070
1073 _In_ WDFREQUEST Request,
1075 _Out_ size_t * DataLength
1076 )
1077/*++
1078
1079Routine Description:
1080
1081 Validate request of IOCTL_CDROM_READ_Q_CHANNEL
1082
1083Arguments:
1084
1085 Request - request to be handled
1086 RequestParameters - request parameter
1087 DataLength - transferred data length
1088
1089Return Value:
1090
1091 NTSTATUS
1092
1093--*/
1094{
1096 PCDROM_SUB_Q_DATA_FORMAT inputBuffer = NULL;
1097 ULONG transferByteCount = 0;
1098
1099 *DataLength = 0;
1100
1101 if(RequestParameters.Parameters.DeviceIoControl.InputBufferLength <
1103 {
1105 }
1106
1107 if (NT_SUCCESS(status))
1108 {
1109 status = WdfRequestRetrieveInputBuffer(Request,
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
1134 }
1135 }
1136
1137 if (NT_SUCCESS(status))
1138 {
1139 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength <
1140 transferByteCount)
1141 {
1143 *DataLength = transferByteCount;
1144 }
1145 }
1146
1147 return status;
1148}
1149
1152 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
1154 _Out_ size_t * DataLength
1155 )
1156/*++
1157
1158Routine Description:
1159
1160 Validate request of IOCTL_DVD_READ_STRUCTURE
1161
1162Arguments:
1163
1164 DeviceExtension - device context
1165 RequestParameters - request parameter
1166 DataLength - transferred data length
1167
1168Return Value:
1169
1170 NTSTATUS
1171
1172--*/
1173{
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)));
1189 }
1190 else if(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength <
1192 {
1193
1194 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL,
1195 "RequestValidateDvdReadStructure - output buffer "
1196 "cannot hold header information\n"));
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"));
1208 }
1209 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength &
1210 DeviceExtension->AdapterDescriptor->AlignmentMask)
1211 {
1213 }
1214 else if (DeviceExtension->DeviceAdditionalData.DriveDeviceType != FILE_DEVICE_DVD)
1215 {
1216 // reject the request if it's not a DVD device.
1218 }
1219 }
1220
1221 return status;
1222}
1223
1226 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
1228 _Out_ size_t * DataLength
1229 )
1230/*++
1231
1232Routine Description:
1233
1234 Validate request of IOCTL_DVD_START_SESSION
1235
1236Arguments:
1237
1238 DeviceExtension - device context
1239 RequestParameters - request parameter
1240 DataLength - transferred data length
1241
1242Return Value:
1243
1244 NTSTATUS
1245
1246--*/
1247{
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"));
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.
1267 }
1268 }
1269
1270 return status;
1271}
1272
1275 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
1276 _In_ WDFREQUEST Request,
1278 _Out_ size_t * DataLength
1279 )
1280/*++
1281
1282Routine Description:
1283
1284 Validate request of IOCTL_DVD_SEND_KEY, IOCTL_DVD_SEND_KEY2
1285
1286Arguments:
1287
1288 DeviceExtension - device context
1289 Request - request to be handled
1290 RequestParameters - request parameter
1291 DataLength - transferred data length
1292
1293Return Value:
1294
1295 NTSTATUS
1296
1297--*/
1298{
1301
1302 *DataLength = 0;
1303
1304 status = WdfRequestRetrieveInputBuffer(Request,
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));
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)
1333 {
1334 if ((key->KeyType != DvdChallengeKey) &&
1335 (key->KeyType != DvdBusKey2) &&
1336 (key->KeyType != DvdInvalidateAGID))
1337 {
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 {
1352 }
1353 else if (DeviceExtension->DeviceAdditionalData.DriveDeviceType != FILE_DEVICE_DVD)
1354 {
1355 // reject the request if it's not a DVD device.
1357 }
1358 }
1359
1360 return status;
1361}
1362
1365 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
1366 _In_ WDFREQUEST Request,
1368 _Out_ size_t * DataLength
1369 )
1370/*++
1371
1372Routine Description:
1373
1374 Validate request of IOCTL_CDROM_GET_CONFIGURATION
1375
1376Arguments:
1377
1378 DeviceExtension - device context
1379 Request - request to be handled
1380 RequestParameters - request parameter
1381 DataLength - transferred data length
1382
1383Return Value:
1384
1385 NTSTATUS
1386
1387--*/
1388{
1390
1391 *DataLength = 0;
1392
1393 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength <
1395 {
1398 }
1399 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > 0xffff)
1400 {
1401 // output buffer is too large
1403 }
1404 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength &
1405 DeviceExtension->AdapterDescriptor->AlignmentMask)
1406 {
1407 // buffer is not proper size multiple
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 {
1424 }
1425
1426 //
1427 // also verify the arguments are reasonable.
1428 //
1429 if (NT_SUCCESS(status))
1430 {
1431 status = WdfRequestRetrieveInputBuffer(Request,
1433 &inputBuffer,
1434 NULL);
1435 }
1436
1437 if (NT_SUCCESS(status))
1438 {
1439 if (inputBuffer->Feature > 0xffff)
1440 {
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 {
1448 }
1449 else if (inputBuffer->Reserved[0] || inputBuffer->Reserved[1])
1450 {
1452 }
1453 }
1454 }
1455 else
1456
1457#endif
1458
1459 {
1461
1462 if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength <
1464 {
1466 }
1467
1468 // also verify the arguments are reasonable.
1469 if (NT_SUCCESS(status))
1470 {
1471 status = WdfRequestRetrieveInputBuffer(Request,
1473 &inputBuffer,
1474 NULL);
1475 }
1476
1477 if (NT_SUCCESS(status))
1478 {
1479 if (inputBuffer->Feature > 0xffff)
1480 {
1482 }
1483 else if ((inputBuffer->RequestType != SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE) &&
1486 {
1488 }
1489 else if (inputBuffer->Reserved[0] || inputBuffer->Reserved[1])
1490 {
1492 }
1493 }
1494 }
1495 }
1496
1497 return status;
1498}
1499
1502 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
1503 _In_ WDFREQUEST Request,
1505 _Out_ size_t * DataLength
1506 )
1507/*++
1508
1509Routine Description:
1510
1511 Validate request of IOCTL_CDROM_SET_SPEED
1512
1513Arguments:
1514
1515 DeviceExtension - device context
1516 Request - request to be handled
1517 RequestParameters - request parameter
1518 DataLength - transferred data length
1519
1520Return Value:
1521
1522 NTSTATUS
1523
1524--*/
1525{
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 {
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.
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 {
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
1577 }
1578 }
1579
1580 return status;
1581}
1582
1585 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
1586 _In_ WDFREQUEST Request,
1588 _Out_ size_t * DataLength
1589 )
1590/*++
1591
1592Routine Description:
1593
1594 Validate request of IOCTL_AACS_READ_MEDIA_KEY_BLOCK
1595
1596Arguments:
1597
1598 DeviceExtension - device context
1599 Request - request to be handled
1600 RequestParameters - request parameter
1601 DataLength - transferred data length
1602
1603Return Value:
1604
1605 NTSTATUS
1606
1607--*/
1608{
1610 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData);
1611 PAACS_LAYER_NUMBER layerNumber = NULL;
1612
1613 *DataLength = 0;
1614
1615 if (!cdData->Mmc.IsAACS)
1616 {
1618 }
1619 else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(AACS_LAYER_NUMBER))
1620 {
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;
1629 }
1630
1631 if (NT_SUCCESS(status))
1632 {
1633 status = WdfRequestRetrieveInputBuffer(Request,
1635 &layerNumber,
1636 NULL);
1637 }
1638
1639 if (NT_SUCCESS(status))
1640 {
1641 if (*layerNumber > 255)
1642 {
1644 }
1645 }
1646
1647 return status;
1648}
1649
1652 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
1654 _Out_ size_t * DataLength
1655 )
1656/*++
1657
1658Routine Description:
1659
1660 Validate request of IOCTL_AACS_START_SESSION
1661
1662Arguments:
1663
1664 DeviceExtension - device context
1665 RequestParameters - request parameter
1666 DataLength - transferred data length
1667
1668Return Value:
1669
1670 NTSTATUS
1671
1672--*/
1673{
1675 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData);
1676
1677 *DataLength = 0;
1678
1679 if (!cdData->Mmc.IsAACS)
1680 {
1682 }
1683 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(DVD_SESSION_ID))
1684 {
1685 *DataLength = sizeof(DVD_SESSION_ID);
1687 }
1688 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > sizeof(DVD_SESSION_ID))
1689 {
1691 }
1692
1693 return status;
1694}
1695
1698 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
1699 _In_ WDFREQUEST Request,
1701 _Out_ size_t * DataLength
1702 )
1703/*++
1704
1705Routine Description:
1706
1707 Validate request of IOCTL_AACS_SEND_CERTIFICATE
1708
1709Arguments:
1710
1711 DeviceExtension - device context
1712 Request - request to be handled
1713 RequestParameters - request parameter
1714 DataLength - transferred data length
1715
1716Return Value:
1717
1718 NTSTATUS
1719
1720--*/
1721{
1723 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData);
1724 PAACS_SEND_CERTIFICATE inputBuffer = NULL;
1725
1726 *DataLength = 0;
1727
1728 if (!cdData->Mmc.IsAACS)
1729 {
1731 }
1732 else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(AACS_SEND_CERTIFICATE))
1733 {
1735 }
1736
1737 if (NT_SUCCESS(status))
1738 {
1739 status = WdfRequestRetrieveInputBuffer(Request,
1741 &inputBuffer,
1742 NULL);
1743 }
1744
1745 if (NT_SUCCESS(status))
1746 {
1747 if (inputBuffer->SessionId > MAX_COPY_PROTECT_AGID)
1748 {
1750 }
1751 }
1752
1753 return status;
1754}
1755
1758 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
1759 _In_ WDFREQUEST Request,
1761 _Out_ size_t * DataLength
1762 )
1763/*++
1764
1765Routine Description:
1766
1767 Validate request of IOCTL_AACS_GET_CERTIFICATE
1768
1769Arguments:
1770
1771 DeviceExtension - device context
1772 Request - request to be handled
1773 RequestParameters - request parameter
1774 DataLength - transferred data length
1775
1776Return Value:
1777
1778 NTSTATUS
1779
1780--*/
1781{
1783 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData);
1784 PDVD_SESSION_ID sessionId = NULL;
1785
1786 *DataLength = 0;
1787
1788 if (!cdData->Mmc.IsAACS)
1789 {
1791 }
1792 else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(DVD_SESSION_ID))
1793 {
1795 }
1796 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(AACS_CERTIFICATE))
1797 {
1798 *DataLength = sizeof(AACS_CERTIFICATE);
1800 }
1801 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > sizeof(AACS_CERTIFICATE))
1802 {
1804 }
1805
1806 if (NT_SUCCESS(status))
1807 {
1808 status = WdfRequestRetrieveInputBuffer(Request,
1810 &sessionId,
1811 NULL);
1812 }
1813
1814 if (NT_SUCCESS(status))
1815 {
1816 if (*sessionId > MAX_COPY_PROTECT_AGID)
1817 {
1819 }
1820 }
1821
1822 return status;
1823}
1824
1827 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
1828 _In_ WDFREQUEST Request,
1830 _Out_ size_t * DataLength
1831 )
1832/*++
1833
1834Routine Description:
1835
1836 Validate request of IOCTL_AACS_GET_CHALLENGE_KEY
1837
1838Arguments:
1839
1840 DeviceExtension - device context
1841 Request - request to be handled
1842 RequestParameters - request parameter
1843 DataLength - transferred data length
1844
1845Return Value:
1846
1847 NTSTATUS
1848
1849--*/
1850{
1852 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData);
1853 PDVD_SESSION_ID sessionId = NULL;
1854
1855 *DataLength = 0;
1856
1857 if (!cdData->Mmc.IsAACS)
1858 {
1860 }
1861 else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(DVD_SESSION_ID))
1862 {
1864 }
1865 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(AACS_CHALLENGE_KEY))
1866 {
1867 *DataLength = sizeof(AACS_CHALLENGE_KEY);
1869 }
1870 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > sizeof(AACS_CHALLENGE_KEY))
1871 {
1873 }
1874
1875 if (NT_SUCCESS(status))
1876 {
1877 status = WdfRequestRetrieveInputBuffer(Request,
1879 &sessionId,
1880 NULL);
1881 }
1882
1883 if (NT_SUCCESS(status))
1884 {
1885 if (*sessionId > MAX_COPY_PROTECT_AGID)
1886 {
1888 }
1889 }
1890
1891 return status;
1892}
1893
1896 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
1897 _In_ WDFREQUEST Request,
1899 _Out_ size_t * DataLength
1900 )
1901/*++
1902
1903Routine Description:
1904
1905 Validate request of IOCTL_AACS_SEND_CHALLENGE_KEY
1906
1907Arguments:
1908
1909 DeviceExtension - device context
1910 Request - request to be handled
1911 RequestParameters - request parameter
1912 DataLength - transferred data length
1913
1914Return Value:
1915
1916 NTSTATUS
1917
1918--*/
1919{
1921 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData);
1922 PAACS_SEND_CHALLENGE_KEY inputBuffer = NULL;
1923
1924 *DataLength = 0;
1925
1926 if (!cdData->Mmc.IsAACS)
1927 {
1929 }
1930 else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(AACS_SEND_CHALLENGE_KEY))
1931 {
1933 }
1934
1935 if (NT_SUCCESS(status))
1936 {
1937 status = WdfRequestRetrieveInputBuffer(Request,
1939 &inputBuffer,
1940 NULL);
1941 }
1942
1943 if (NT_SUCCESS(status))
1944 {
1945 if (inputBuffer->SessionId > MAX_COPY_PROTECT_AGID)
1946 {
1948 }
1949 }
1950
1951 return status;
1952}
1953
1956 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
1957 _In_ WDFREQUEST Request,
1959 _Out_ size_t * DataLength
1960 )
1961/*++
1962
1963Routine Description:
1964
1965 Validate request of IOCTL_AACS_READ_VOLUME_ID
1966
1967Arguments:
1968
1969 DeviceExtension - device context
1970 Request - request to be handled
1971 RequestParameters - request parameter
1972 DataLength - transferred data length
1973
1974Return Value:
1975
1976 NTSTATUS
1977
1978--*/
1979{
1981 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData);
1982 PDVD_SESSION_ID sessionId = NULL;
1983
1984 *DataLength = 0;
1985
1986 if (!cdData->Mmc.IsAACS)
1987 {
1989 }
1990 else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(DVD_SESSION_ID))
1991 {
1993 }
1994 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(AACS_VOLUME_ID))
1995 {
1996 *DataLength = sizeof(AACS_VOLUME_ID);
1998 }
1999 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > sizeof(AACS_VOLUME_ID))
2000 {
2002 }
2003
2004 if (NT_SUCCESS(status))
2005 {
2006 status = WdfRequestRetrieveInputBuffer(Request,
2008 &sessionId,
2009 NULL);
2010 }
2011
2012 if (NT_SUCCESS(status))
2013 {
2014 if (*sessionId > MAX_COPY_PROTECT_AGID)
2015 {
2017 }
2018 }
2019
2020 return status;
2021}
2022
2025 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
2026 _In_ WDFREQUEST Request,
2028 _Out_ size_t * DataLength
2029 )
2030/*++
2031
2032Routine Description:
2033
2034 Validate request of IOCTL_AACS_READ_SERIAL_NUMBER
2035
2036Arguments:
2037
2038 DeviceExtension - device context
2039 Request - request to be handled
2040 RequestParameters - request parameter
2041 DataLength - transferred data length
2042
2043Return Value:
2044
2045 NTSTATUS
2046
2047--*/
2048{
2050 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData);
2051 PDVD_SESSION_ID sessionId = NULL;
2052
2053 *DataLength = 0;
2054
2055 if (!cdData->Mmc.IsAACS)
2056 {
2058 }
2059 else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(DVD_SESSION_ID))
2060 {
2062 }
2063 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(AACS_SERIAL_NUMBER))
2064 {
2065 *DataLength = sizeof(AACS_SERIAL_NUMBER);
2067 }
2068 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > sizeof(AACS_SERIAL_NUMBER))
2069 {
2071 }
2072
2073 if (NT_SUCCESS(status))
2074 {
2075 status = WdfRequestRetrieveInputBuffer(Request,
2077 &sessionId,
2078 NULL);
2079 }
2080
2081 if (NT_SUCCESS(status))
2082 {
2083 if (*sessionId > MAX_COPY_PROTECT_AGID)
2084 {
2086 }
2087 }
2088
2089 return status;
2090}
2091
2094 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
2095 _In_ WDFREQUEST Request,
2097 _Out_ size_t * DataLength
2098 )
2099/*++
2100
2101Routine Description:
2102
2103 Validate request of IOCTL_AACS_READ_MEDIA_ID
2104
2105Arguments:
2106
2107 DeviceExtension - device context
2108 Request - request to be handled
2109 RequestParameters - request parameter
2110 DataLength - transferred data length
2111
2112Return Value:
2113
2114 NTSTATUS
2115
2116--*/
2117{
2119 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData);
2120 PDVD_SESSION_ID sessionId = NULL;
2121
2122 *DataLength = 0;
2123
2124 if (!cdData->Mmc.IsAACS)
2125 {
2127 }
2128 else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(DVD_SESSION_ID))
2129 {
2131 }
2132 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(AACS_MEDIA_ID))
2133 {
2134 *DataLength = sizeof(AACS_MEDIA_ID);
2136 }
2137 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > sizeof(AACS_MEDIA_ID))
2138 {
2140 }
2141
2142 if (NT_SUCCESS(status))
2143 {
2144 status = WdfRequestRetrieveInputBuffer(Request,
2146 &sessionId,
2147 NULL);
2148 }
2149
2150 if (NT_SUCCESS(status))
2151 {
2152 if (*sessionId > MAX_COPY_PROTECT_AGID)
2153 {
2155 }
2156 }
2157
2158 return status;
2159}
2160
2163 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
2164 _In_ WDFREQUEST Request,
2166 _Out_ size_t * DataLength
2167 )
2168/*++
2169
2170Routine Description:
2171
2172 Validate request of IOCTL_AACS_READ_BINDING_NONCE
2173 IOCTL_AACS_GENERATE_BINDING_NONCE
2174
2175Arguments:
2176
2177 DeviceExtension - device context
2178 Request - request to be handled
2179 RequestParameters - request parameter
2180 DataLength - transferred data length
2181
2182Return Value:
2183
2184 NTSTATUS
2185
2186--*/
2187{
2189 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData);
2190 PAACS_READ_BINDING_NONCE inputBuffer = NULL;
2191
2192 *DataLength = 0;
2193
2194 if (!cdData->Mmc.IsAACS)
2195 {
2197 }
2198 else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(AACS_READ_BINDING_NONCE))
2199 {
2201 }
2202 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(AACS_BINDING_NONCE))
2203 {
2204 *DataLength = sizeof(AACS_BINDING_NONCE);
2206 }
2207 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > sizeof(AACS_BINDING_NONCE))
2208 {
2210 }
2211
2212 if (NT_SUCCESS(status))
2213 {
2214 status = WdfRequestRetrieveInputBuffer(Request,
2216 &inputBuffer,
2217 NULL);
2218 }
2219
2220 if (NT_SUCCESS(status))
2221 {
2222 if (inputBuffer->SessionId > MAX_COPY_PROTECT_AGID)
2223 {
2225 }
2226 else if (inputBuffer->NumberOfSectors > 255)
2227 {
2229 }
2230 else if (inputBuffer->StartLba > MAXULONG)
2231 {
2233 }
2234 }
2235
2236 return status;
2237}
2238
2241 _In_ WDFREQUEST Request,
2243 _Out_ size_t * DataLength
2244 )
2245/*++
2246
2247Routine Description:
2248
2249 Validate request of IOCTL_CDROM_EXCLUSIVE_ACCESS
2250
2251Arguments:
2252
2253 Request - request to be handled
2254 RequestParameters - request parameter
2255 DataLength - transferred data length
2256
2257Return Value:
2258
2259 NTSTATUS
2260
2261--*/
2262{
2264 PCDROM_EXCLUSIVE_ACCESS exclusiveAccess = NULL;
2265
2266 *DataLength = 0;
2267
2269 {
2270 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "RequestValidateExclusiveAccess: IOCTL must be called at passive level.\n"));
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"));
2278 }
2279
2280 if (NT_SUCCESS(status))
2281 {
2282 status = WdfRequestRetrieveInputBuffer(Request,
2284 &exclusiveAccess,
2285 NULL);
2286 }
2287
2288 if (NT_SUCCESS(status))
2289 {
2290 switch (exclusiveAccess->RequestType)
2291 {
2293 {
2294 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength <
2296 {
2297 //
2298 // Output buffer too small.
2299 //
2300 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "RequestValidateExclusiveAccess: Output buffer too small\n"));
2303 }
2304 break;
2305 }
2306
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"));
2317 }
2318 break;
2319 }
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"));
2335 }
2336 }
2337 }
2338
2339 return status;
2340}
2341
2344RequestHandleExclusiveAccessQueryLockState(
2345 _In_ WDFDEVICE Device,
2346 _In_ WDFREQUEST Request
2347 )
2348/*++
2349
2350Routine Description:
2351
2352 Handle request of IOCTL_CDROM_EXCLUSIVE_ACCESS with ExclusiveAccessQueryState
2353
2354Arguments:
2355
2356 DeviceExtension - device context
2357 Request - request to be handled
2358 RequestParameters - request parameter
2359 DataLength - transferred data length
2360
2361Return Value:
2362
2363 NTSTATUS
2364
2365--*/
2366{
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,
2376 &exclusiveLockState,
2377 NULL);
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,
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
2405RequestHandleExclusiveAccessLockDevice(
2406 _In_ WDFDEVICE Device,
2407 _In_ WDFREQUEST Request
2408 )
2409/*++
2410
2411Routine Description:
2412
2413 Handle request of IOCTL_CDROM_EXCLUSIVE_ACCESS with ExclusiveAccessLockDevice
2414
2415Arguments:
2416
2417 DeviceExtension - device context
2418 Request - request to be handled
2419 RequestParameters - request parameter
2420 DataLength - transferred data length
2421
2422Return Value:
2423
2424 NTSTATUS
2425
2426--*/
2427{
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 {
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
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
2483 }
2484 else
2485 {
2486 nameLength = idx+1; // Add 1 for the NULL character
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"));
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
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,
2528
2529 if (logEntry != NULL)
2530 {
2531 PUCHAR dumpDataPtr = (PUCHAR) logEntry->DumpData;
2532
2533 logEntry->FinalStatus = STATUS_SUCCESS;
2535 logEntry->SequenceNumber = 0;
2538 logEntry->RetryCount = 0;
2539 logEntry->UniqueErrorValue = 0x1;
2541
2542 RtlCopyMemory(dumpDataPtr,
2543 (PUCHAR)&cdData->CallerName,
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
2557 }
2558 }
2559
2560 RequestCompletion(deviceExtension, Request, status, 0);
2561
2562 return status;
2563}
2564
2567RequestHandleExclusiveAccessUnlockDevice(
2568 _In_ WDFDEVICE Device,
2569 _In_ WDFREQUEST Request
2570 )
2571/*++
2572
2573Routine Description:
2574
2575 Handle request of IOCTL_CDROM_EXCLUSIVE_ACCESS with ExclusiveAccessUnlockDevice
2576
2577Arguments:
2578
2579 Device - device handle
2580 Request - request to be handled
2581
2582Return Value:
2583
2584 NTSTATUS
2585
2586--*/
2587{
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.
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,
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
2629 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
2630 _In_ WDFREQUEST Request,
2632 _Out_ size_t * DataLength
2633 )
2634/*++
2635
2636Routine Description:
2637
2638 Handle request of IOCTL_STORAGE_QUERY_PROPERTY when the required data is cached.
2639
2640Arguments:
2641
2642 DeviceExtension - device context
2643 Request - request to be handled
2644 RequestParameters - request parameter
2645 DataLength - transferred data length
2646
2647Return Value:
2648
2649 NTSTATUS
2650
2651--*/
2652{
2654 PSTORAGE_PROPERTY_QUERY inputBuffer = NULL;
2655
2656 *DataLength = 0;
2657
2658 status = WdfRequestRetrieveInputBuffer(Request,
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;
2674 }
2675 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_DESCRIPTOR_HEADER))
2676 {
2677 // Buffer too small
2678 *DataLength = DeviceExtension->DeviceDescriptor->Size;
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
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
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
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 }
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;
2763 }
2764 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_DESCRIPTOR_HEADER))
2765 {
2766 // Buffer too small
2767 *DataLength = DeviceExtension->AdapterDescriptor->Size;
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
2782 DeviceExtension->AdapterDescriptor->Size);
2783
2784 RtlCopyMemory(outputDescriptor,
2785 DeviceExtension->AdapterDescriptor,
2786 *DataLength);
2787
2788 // set status
2790 }
2791 }
2792 }
2793 }
2794
2795 return status;
2796}
2797
2800 _In_ WDFDEVICE Device,
2801 _In_ WDFREQUEST Request
2802 )
2803/*++
2804
2805Routine Description:
2806
2807 Handle request of IOCTL_STORAGE_QUERY_PROPERTY with StorageDeviceUniqueIdProperty.
2808
2809Arguments:
2810
2811 DeviceExtension - device context
2812 Request - request to be handled
2813 RequestParameters - request parameter
2814 DataLength - transferred data length
2815
2816Return Value:
2817
2818 NTSTATUS
2819
2820--*/
2821{
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.
2845 {
2847 outLength = 0;
2849 }
2850 else if (inputBuffer->QueryType == PropertyExistsQuery)
2851 {
2852 outLength = 0;
2854 }
2855 else if (inputBuffer->QueryType != PropertyStandardQuery)
2856 {
2857 outLength = 0;
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;
2875 }
2876
2877 if (NT_SUCCESS(status) &&
2878 (outLength < sizeof(STORAGE_DESCRIPTOR_HEADER)))
2879 {
2880 outLength = 0;
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
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
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 {
2944 }
2945 else
2946 {
2947 outLength = (ULONG)WdfRequestGetInformation(Request);
2949 }
2950
2951 }
2952 else if (infoFound)
2953 {
2955
2956 // Exercise the compare routine. This should always succeed.
2959
2960 }
2961 else
2962 {
2964 }
2965 }
2966 }
2967
2968 RequestCompletion(deviceExtension, Request, status, outLength);
2969
2970 return status;
2971}
2972
2975 _In_ WDFDEVICE Device,
2976 _In_ WDFREQUEST Request
2977 )
2978/*++
2979
2980Routine Description:
2981
2982 Handle request of IOCTL_STORAGE_QUERY_PROPERTY with StorageDeviceWriteCacheProperty.
2983
2984Arguments:
2985
2986 DeviceExtension - device context
2987 Request - request to be handled
2988
2989Return Value:
2990
2991 NTSTATUS
2992
2993--*/
2994{
2996 PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device);
2999 PMODE_PARAMETER_HEADER modeData = NULL;
3000 PMODE_CACHING_PAGE pageData = NULL;
3001 size_t length = 0;
3002 ULONG information = 0;
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.
3020 {
3023 }
3024 else if (query->QueryType == PropertyExistsQuery)
3025 {
3026 information = 0;
3028 }
3029 else if (query->QueryType != PropertyStandardQuery)
3030 {
3032 }
3033 }
3034
3035 if (NT_SUCCESS(status))
3036 {
3037 length = requestParameters.Parameters.DeviceIoControl.OutputBufferLength;
3038
3039 if (length < sizeof(STORAGE_DESCRIPTOR_HEADER))
3040 {
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
3062 {
3063 // caller only wants header information, bail out.
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),
3078
3079 if (srb == NULL)
3080 {
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.
3098 srb->TimeOutValue = TimeOutValueGetCapValue(deviceExtension->TimeOutValue, 4);
3099 srb->QueueTag = SP_UNTAGGED;
3101 srb->SrbFlags = deviceExtension->SrbFlags;
3102
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
3128 }
3129
3130 modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
3133
3134 if (modeData == NULL)
3135 {
3136 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
3137 "RequestHandleQueryPropertyWriteCache: Unable to allocate mode data buffer\n"));
3139 }
3140 }
3141
3142 if (NT_SUCCESS(status))
3143 {
3145
3146 length = DeviceRetrieveModeSenseUsingScratch(deviceExtension,
3147 (PCHAR)modeData,
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,
3160
3161 if (length < sizeof(MODE_PARAMETER_HEADER))
3162 {
3163 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, "RequestHandleQueryPropertyWriteCache: Mode Sense failed\n"));
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,
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
3198
3199 writeCache->WriteCacheType = pageData->WriteCacheEnable
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.
3216
3217 length = DeviceRetrieveModeSenseUsingScratch(deviceExtension,
3218 (PCHAR) modeData,
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,
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;
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,
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
3271 }
3272
3274
3275 }
3276
3277 FREE_POOL(srb);
3278 FREE_POOL(modeData);
3279
3280 RequestCompletion(deviceExtension, Request, status, information);
3281
3282 return status;
3283}
3284
3287 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
3288 _In_ WDFREQUEST Request,
3290 _Out_ size_t * DataLength
3291 )
3292/*++
3293
3294Routine Description:
3295
3296 Validate request of IOCTL_DVD_READ_KEY
3297
3298Arguments:
3299
3300 DeviceExtension - device context
3301 Request - request to be handled
3302 RequestParameters - request parameter
3303 DataLength - transferred data length
3304
3305Return Value:
3306
3307 NTSTATUS
3308
3309--*/
3310{
3312 PDVD_COPY_PROTECT_KEY keyParameters = NULL;
3313 ULONG keyLength = 0;
3314
3315 *DataLength = 0;
3316
3317 status = WdfRequestRetrieveInputBuffer(Request,
3319 &keyParameters,
3320 NULL);
3321
3322 if (NT_SUCCESS(status))
3323 {
3325 {
3326 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL,
3327 "DvdDeviceControl: EstablishDriveKey - challenge "
3328 "key buffer too small\n"));
3330 }
3331 }
3332
3333 if (NT_SUCCESS(status))
3334 {
3335 switch(keyParameters->KeyType)
3336 {
3337
3338 case DvdChallengeKey:
3339 {
3341 keyLength = DVD_CHALLENGE_KEY_LENGTH;
3342 break;
3343 }
3344 case DvdBusKey1:
3345 case DvdBusKey2:
3346 {
3348 keyLength = DVD_BUS_KEY_LENGTH;
3349 break;
3350 }
3351 case DvdTitleKey:
3352 {
3354 keyLength = DVD_TITLE_KEY_LENGTH;
3355 break;
3356 }
3357 case DvdAsf:
3358 {
3360 keyLength = DVD_ASF_LENGTH;
3361 break;
3362 }
3363 case DvdDiskKey:
3364 {
3366 keyLength = DVD_DISK_KEY_LENGTH;
3367 break;
3368 }
3369 case DvdGetRpcKey:
3370 {
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"));
3389 *DataLength = keyLength;
3390 }
3391 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength &
3392 DeviceExtension->AdapterDescriptor->AlignmentMask)
3393 {
3395 }
3396 else if (DeviceExtension->DeviceAdditionalData.DriveDeviceType != FILE_DEVICE_DVD)
3397 {
3398 // reject the request if it's not a DVD device.
3400 }
3401 }
3402
3403 return status;
3404}
3405
3406
3409 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
3410 _In_ WDFREQUEST Request,
3412 _Out_ size_t * DataLength
3413 )
3414/*++
3415
3416Routine Description:
3417
3418 Handle request of IOCTL_DVD_END_SESSION
3419
3420Arguments:
3421
3422 DeviceExtension - device context
3423 Request - request to be handled
3424 RequestParameters - request parameter
3425 DataLength - transferred data length
3426
3427Return Value:
3428
3429 NTSTATUS
3430
3431--*/
3432{
3434 PDVD_SESSION_ID sessionId = NULL;
3435
3436 UNREFERENCED_PARAMETER(DeviceExtension);
3437
3438 *DataLength = 0;
3439
3440 status = WdfRequestRetrieveInputBuffer(Request,
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"));
3454 }
3455 }
3456
3457 return status;
3458}
3459
3460
3463 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
3464 _In_ WDFREQUEST Request,
3466 _Out_ size_t * DataLength
3467 )
3468/*++
3469
3470Routine Description:
3471
3472 Validate request of IOCTL_AACS_END_SESSION
3473
3474Arguments:
3475
3476 DeviceExtension - device context
3477 Request - request to be handled
3478 RequestParameters - request parameter
3479 DataLength - transferred data length
3480
3481Return Value:
3482
3483 NTSTATUS
3484
3485--*/
3486{
3488 PDVD_SESSION_ID sessionId = NULL;
3489 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData);
3490
3491 *DataLength = 0;
3492
3493 status = WdfRequestRetrieveInputBuffer(Request,
3495 &sessionId,
3496 NULL);
3497
3498 if (NT_SUCCESS(status))
3499 {
3500 if (!cdData->Mmc.IsAACS)
3501 {
3503 }
3504 else if(RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(DVD_SESSION_ID))
3505 {
3507 }
3508 }
3509
3510 return status;
3511}
3512
3513
3516 _In_ WDFREQUEST Request,
3518 _Out_ size_t * DataLength
3519 )
3520/*++
3521
3522Routine Description:
3523
3524 Validates an IOCTL_CDROM_ENABLE_STREAMING request
3525
3526Arguments:
3527
3528 Request - request to be handled
3529 RequestParameters - request parameters
3530 DataLength - transferred data length
3531
3532Return Value:
3533
3534 NTSTATUS
3535
3536--*/
3537{
3539
3540 PCDROM_STREAMING_CONTROL inputBuffer = NULL;
3541
3542 *DataLength = 0;
3543
3544 if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength <
3546 {
3548 }
3549
3550 if (NT_SUCCESS(status))
3551 {
3552 // Get the request type using CDROM_STREAMING_CONTROL structure
3553 status = WdfRequestRetrieveInputBuffer(Request,
3555 &inputBuffer,
3556 NULL);
3557 }
3558
3559 if (NT_SUCCESS(status))
3560 {
3561 if (inputBuffer->RequestType != CdromStreamingDisable &&
3565 {
3566 // Unknown request type
3568 }
3569 }
3570
3571 return status;
3572}
3573
3574
3577 _In_ WDFREQUEST Request,
3579 _Out_ size_t * DataLength
3580 )
3581/*++
3582
3583Routine Description:
3584
3585 Validates an IOCTL_CDROM_SEND_OPC_INFORMATION request
3586
3587Arguments:
3588
3589 Request - request to be handled
3590 RequestParameters - request parameters
3591 DataLength - transferred data length
3592
3593Return Value:
3594
3595 NTSTATUS
3596
3597--*/
3598{
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 {
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
3626 }
3627 }
3628
3629 return status;
3630}
3631
3632
3635 _In_ WDFREQUEST Request,
3637 _Out_ size_t * DataLength
3638 )
3639/*++
3640
3641Routine Description:
3642
3643 Validates an IOCTL_CDROM_GET_PERFORMANCE request
3644
3645Arguments:
3646
3647 Request - request to be handled
3648 RequestParameters - request parameter
3649 DataLength - transferred data length
3650
3651Return Value:
3652
3653 NTSTATUS
3654
3655--*/
3656{
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 <
3668 {
3670 }
3671
3672 if (NT_SUCCESS(status))
3673 {
3674 status = WdfRequestRetrieveInputBuffer(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 <
3688 {
3690 }
3691 if (NT_SUCCESS(status))
3692 {
3693 status = WdfRequestRetrieveInputBuffer(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 {
3708 }
3709 else if (performanceRequest->Exceptions != CdromNominalPerformance &&
3710 performanceRequest->Exceptions != CdromEntirePerformanceList &&
3711 performanceRequest->Exceptions != CdromPerformanceExceptionsOnly)
3712 {
3714 }
3715 else if (performanceRequest->Tolerance != Cdrom10Nominal20Exceptions)
3716 {
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 {
3728 }
3729 }
3730
3731 // finally, check output buffer length
3732 if (NT_SUCCESS(status))
3733 {
3734 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength <
3736 {
3739 }
3740 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength >
3741 ((USHORT)-1))
3742 {
3744 }
3745 }
3746
3747 return status;
3748}
3749
3750
3752PCDB
3753RequestGetScsiPassThroughCdb(
3754 _In_ PIRP Irp
3755 )
3756/*++
3757
3758Routine Description:
3759
3760 Get the CDB structure from the SCSI pass through
3761
3762Arguments:
3763
3764 Irp - request to be handled
3765
3766Return Value:
3767
3768 PCDB
3769
3770--*/
3771{
3772 PCDB cdb = NULL;
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
3848RequestHandleScsiPassThrough(
3849 _In_ WDFDEVICE Device,
3850 _In_ WDFREQUEST Request
3851 )
3852/*++
3853
3854Routine 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
3862Arguments:
3863
3864 Device - device object
3865 Request - request to be handled
3866
3867Return Value:
3868
3869 NTSTATUS
3870
3871--*/
3872{
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 {
3912
3913 nextStack->MinorFunction = 1;
3914 }
3915
3916
3917 status = RequestSend(deviceExtension,
3918 Request,
3919 deviceExtension->IoTarget,
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
3940 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
3941 _In_ WDFREQUEST Request,
3943 _Out_ size_t * DataLength
3944 )
3945/*++
3946
3947Routine Description:
3948
3949 Handle request of IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
3950
3951Arguments:
3952
3953 DeviceExtension - device context
3954 Request - request to be handled
3955 RequestParameters - request parameter
3956 DataLength - transferred data length
3957
3958Return Value:
3959
3960 NTSTATUS
3961
3962--*/
3963{
3965 PMOUNTDEV_UNIQUE_ID uniqueId = NULL;
3966
3967 *DataLength = 0;
3968
3969 if (!DeviceExtension->MountedDeviceInterfaceName.Buffer)
3970 {
3972 }
3973 else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTDEV_UNIQUE_ID))
3974 {
3975 *DataLength = sizeof(MOUNTDEV_UNIQUE_ID);
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);
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;
4009 }
4010
4011 return status;
4012}
4013
4016 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
4017 _In_ WDFREQUEST Request,
4019 _Out_ size_t * DataLength
4020 )
4021/*++
4022
4023Routine Description:
4024
4025 Handle request of IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
4026
4027Arguments:
4028
4029 DeviceExtension - device context
4030 Request - request to be handled
4031 RequestParameters - request parameter
4032 DataLength - transferred data length
4033
4034Return Value:
4035
4036 NTSTATUS
4037
4038--*/
4039{
4042
4043 *DataLength = 0;
4044
4045 NT_ASSERT(DeviceExtension->DeviceName.Buffer);
4046
4047 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTDEV_NAME))
4048 {
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 {
4064 name->NameLength = DeviceExtension->DeviceName.Length;
4065
4066 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength <
4067 (sizeof(USHORT) + DeviceExtension->DeviceName.Length))
4068 {
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
4081 *DataLength = sizeof(USHORT) + name->NameLength;
4082 }
4083
4084 return status;
4085}
4086
4089 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
4090 _In_ WDFREQUEST Request,
4092 _Out_ size_t * DataLength
4093 )
4094/*++
4095
4096Routine Description:
4097
4098 Handle request of IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME
4099
4100Arguments:
4101
4102 DeviceExtension - device context
4103 Request - request to be handled
4104 RequestParameters - request parameter
4105 DataLength - transferred data length
4106
4107Return Value:
4108
4109 NTSTATUS
4110
4111--*/
4112{
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 <
4126 {
4129 }
4130
4131 if (NT_SUCCESS(status))
4132 {
4133 valueName = ExAllocatePoolWithTag(PagedPool,
4134 DeviceExtension->DeviceName.Length + sizeof(WCHAR),
4136 if (valueName == NULL)
4137 {
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
4154 queryTable[0].Name = valueName;
4155 queryTable[0].EntryContext = &driveLetterName;
4157
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 {
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
4195
4196 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < *DataLength)
4197 {
4200 }
4201 }
4202
4203 if (NT_SUCCESS(status))
4204 {
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
4221RequestHandleReadTOC(
4222 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
4223 _In_ WDFREQUEST Request,
4225 _Out_ size_t * DataLength
4226 )
4227/*++
4228
4229Routine Description:
4230
4231 Handle request of IOCTL_CDROM_READ_TOC
4232 IOCTL_CDROM_GET_LAST_SESSION
4233
4234Arguments:
4235
4236 DeviceExtension - device context
4237 Request - request to be handled
4238 RequestParameters - request parameter
4239 DataLength - transferred data length
4240
4241Return Value:
4242
4243 NTSTATUS
4244
4245--*/
4246{
4248 VOID* outputBuffer = NULL;
4249
4250 PAGED_CODE ();
4251
4252 *DataLength = 0;
4253
4254 if (DeviceIsPlayActive(DeviceExtension->Device))
4255 {
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
4282 {
4283 // Set format to return first and last session numbers.
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
4314RequestHandleReadTocEx(
4315 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
4316 _In_ WDFREQUEST Request,
4318 _Out_ size_t * DataLength
4319 )
4320/*++
4321
4322Routine Description:
4323
4324 Handle request of IOCTL_CDROM_READ_TOC_EX
4325
4326Arguments:
4327
4328 DeviceExtension - device context
4329 Request - request to be handled
4330 RequestParameters - request parameter
4331 DataLength - transferred data length
4332
4333Return Value:
4334
4335 NTSTATUS
4336
4337--*/
4338{
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 {
4350 }
4351
4352 if (NT_SUCCESS(status))
4353 {
4354 status = WdfRequestRetrieveInputBuffer(Request,
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;
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
4412VOID
4413GetConfigurationDataConversionTypeAllToTypeOne(
4414 _In_ FEATURE_NUMBER RequestedFeature,
4416 _Out_ size_t * DataLength
4417 )
4418/*++
4419
4420Routine 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
4429Arguments:
4430
4431 RequestedFeature - device context
4432 Srb - request to be handled
4433 DataLength - transfer data length
4434
4435Return 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
4448
4449 PAGED_CODE ();
4450
4451 *DataLength = 0;
4452
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
4462 REVERSE_BYTES(&totalLength, header->DataLength);
4463
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 -
4490
4491 REVERSE_BYTES(header->DataLength, &headerLength);
4492
4493 *DataLength = totalLength;
4494
4495 return;
4496}
4497
4499VOID
4500GetConfigurationDataSynthesize(
4501 _In_reads_bytes_(InputBufferSize) PVOID InputBuffer,
4502 _In_ ULONG InputBufferSize,
4503 _Out_writes_bytes_(OutputBufferSize) PVOID OutputBuffer,
4504 _In_ size_t OutputBufferSize,
4507 _Out_ size_t * DataLength
4508 )
4509/*++
4510
4511Routine 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
4519Arguments:
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
4529Return 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
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
4560 REVERSE_BYTES(&validLength, header->DataLength);
4561
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
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
4596
4597 shouldCopy = TRUE;
4598 break;
4599
4601
4602 if (featureHeader->Current)
4603 {
4604 shouldCopy = TRUE;
4605 }
4606 break;
4607
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
4642 {
4643 headerLength = (ULONG) requiredLength - RTL_SIZEOF_THROUGH_FIELD(GET_CONFIGURATION_HEADER, DataLength);
4644
4646 REVERSE_BYTES(header->DataLength, &headerLength);
4647 }
4648
4649 *DataLength = transferedLength;
4650
4651 return;
4652}
4653
4654
4657RequestHandleGetConfiguration(
4658 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
4659 _In_ WDFREQUEST Request,
4661 _Out_ size_t * DataLength
4662 )
4663/*++
4664
4665Routine Description:
4666
4667 Handle request of IOCTL_CDROM_GET_CONFIGURATION
4668
4669Arguments:
4670
4671 DeviceExtension - device context
4672 Request - request to be handled
4673 RequestParameters - request parameter
4674 DataLength - transferred data length
4675
4676Return Value:
4677
4678 NTSTATUS
4679
4680--*/
4681{
4683 PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData);
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 {
4698 }
4699 else
4700 {
4701 status = WdfRequestRetrieveInputBuffer(Request,
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.
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.
4762 {
4763
4764 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
4765 "DeviceHandleGetConfiguration: Changing TYPE_ONE Get Config to TYPE_ALL\n"));
4767 }
4768
4769 status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, (ULONG)transferByteCount, TRUE, &cdb, 12);
4770
4771 if (NT_SUCCESS(status))
4772 {
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;
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);
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,
4824 );
4825 }
4826 }
4827
4828 return status;
4829}
4830
4833RequestHandleGetDriveGeometry(
4834 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
4835 _In_ WDFREQUEST Request,
4837 _Out_ size_t * DataLength
4838 )
4839/*++
4840
4841Routine 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
4850Arguments:
4851
4852 DeviceExtension - device context
4853 Request - request to be handled
4854 RequestParameters - request parameter
4855 DataLength - transferred data length
4856
4857Return Value:
4858
4859 NTSTATUS
4860
4861--*/
4862{
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 {
4887 {
4888 PGET_LENGTH_INFORMATION lengthInfo = (PGET_LENGTH_INFORMATION)outputBuffer;
4889
4890 lengthInfo->Length = DeviceExtension->PartitionLength;
4892 break;
4893 }
4896 {
4897 PDISK_GEOMETRY geometry = (PDISK_GEOMETRY)outputBuffer;
4898
4899 *geometry = DeviceExtension->DiskGeometry;
4900 *DataLength = sizeof(DISK_GEOMETRY);
4901 break;
4902 }
4905 {
4906 PDISK_GEOMETRY_EX geometryEx = (PDISK_GEOMETRY_EX)outputBuffer;
4907
4908 geometryEx->DiskSize = DeviceExtension->PartitionLength;
4909 geometryEx->Geometry = DeviceExtension->DiskGeometry;
4911 break;
4912 }
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
4933 break;
4934 }
4935 default:
4936 {
4938 break;
4939 }
4940 } // end of switch()
4941 }
4942
4943 return status;
4944}
4945
4948RequestHandleDiskVerify(
4949 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
4950 _In_ WDFREQUEST Request,
4952 _Out_ size_t * DataLength
4953 )
4954/*++
4955
4956Routine Description:
4957
4958 Handle request of IOCTL_DISK_VERIFY
4959
4960Arguments:
4961
4962 DeviceExtension - device context
4963 Request - request to be handled
4964 RequestParameters - request parameter
4965 DataLength - transferred data length
4966
4967Return Value:
4968
4969 NTSTATUS
4970
4971--*/
4972{
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 {
4984 }
4985
4986 if (NT_SUCCESS(status))
4987 {
4988 status = WdfRequestRetrieveInputBuffer(Request,
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->Start