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