ReactOS  0.4.15-dev-1201-gb2cf5a4
ioctl.c
Go to the documentation of this file.
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 
55 VOID
56 GetConfigurationDataConversionTypeAllToTypeOne(
57  _In_ FEATURE_NUMBER RequestedFeature,
59  _Out_ size_t * DataLength
60  );
61 
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,
70  _In_ ULONG RequestType,
71  _Out_ size_t * DataLength
72  );
73 
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
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 {
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 
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 {
213  PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device);
214  PSUB_Q_CURRENT_POSITION currentBuffer;
215  size_t bytesRead = 0;
216 
217  PAGED_CODE ();
218 
219  // if we don't think it is playing audio, don't bother checking.
220  if (!deviceExtension->DeviceAdditionalData.PlayActive)
221  {
222  return FALSE;
223  }
224 
225  // Allocate the required memory
227  currentBuffer = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
228  sizeof(SUB_Q_CURRENT_POSITION),
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
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 {
295  PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData);
296 
297  *DataLength = 0;
298 
299  if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength == 0)
300  {
302  }
303  else
304  {
305  PVOID outputBuffer = NULL;
306 
308  RequestParameters.Parameters.DeviceIoControl.OutputBufferLength);
309 
310  status = WdfRequestRetrieveOutputBuffer(Request,
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  {
328  }
329  }
330 
331  return status;
332 }
333 
334 
335 NTSTATUS
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 {
360  PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData);
361 
362  PGET_MEDIA_TYPES mediaTypes = NULL;
363  PDEVICE_MEDIA_INFO mediaInfo = NULL; //&mediaTypes->MediaInfo[0];
364  ULONG sizeNeeded = 0;
365  PZERO_POWER_ODD_INFO zpoddInfo = DeviceExtension->ZeroPowerODDInfo;
366 
367  *DataLength = 0;
368 
369  // Must run below dispatch level.
371  {
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 
445 
446  status = DeviceSendSrbSynchronously(DeviceExtension->Device,
447  &srb,
448  NULL,
449  0,
450  FALSE,
451  Request);
452 
453  if (NT_SUCCESS(status))
454  {
455  // set the disk's media as current if we can write to it.
456  if (cdData->Mmc.IsMmc && cdData->Mmc.WriteAllowed)
457  {
458  mediaInfo++;
459  SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics,
461  mediaInfo--;
462  }
463  else
464  {
465  SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics,
467  }
468  }
469  else
470  {
471  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
472  "RequestHandleGetMediaTypeEx: GET_MEDIA_TYPES status of TUR - %lx\n", status));
473  }
474  }
475 
476  // per legacy cdrom behavior, always return success
478  }
479 
480  *DataLength = sizeNeeded;
481 
482  return status;
483 }
484 
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 {
511 
512  PVOID outputBuffer = NULL;
513  size_t bytesReturned = 0;
514 
515  PDVD_COPY_PROTECT_KEY copyProtectKey = NULL;
516  ULONG keyLength = 0;
517  PDVD_DESCRIPTOR_HEADER dvdHeader;
518  PDVD_COPYRIGHT_DESCRIPTOR copyRightDescriptor;
519  PDVD_REGION dvdRegion = NULL;
520  PDVD_READ_STRUCTURE readStructure = NULL;
521  PDVD_RPC_KEY rpcKey;
522 
523  PAGED_CODE ();
524 
525  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL,
526  "RequestHandleGetDvdRegion: [%p] IOCTL_DVD_GET_REGION\n", Request));
527 
528  *DataLength = 0;
529 
530  // reject the request if it's not a DVD device.
531  if (DeviceExtension->DeviceAdditionalData.DriveDeviceType != FILE_DEVICE_DVD)
532  {
534  }
535 
536  if (NT_SUCCESS(status))
537  {
538  status = WdfRequestRetrieveOutputBuffer(Request,
539  sizeof(DVD_REGION),
540  &outputBuffer,
541  NULL);
542  }
543 
544  if (NT_SUCCESS(status))
545  {
546  // figure out how much data buffer we need
547  keyLength = max((sizeof(DVD_DESCRIPTOR_HEADER) + sizeof(DVD_COPYRIGHT_DESCRIPTOR)),
548  sizeof(DVD_READ_STRUCTURE));
549  keyLength = max(keyLength,
551 
552  // round the size to nearest ULONGLONG -- why?
553  // could this be to deal with device alignment issues?
554  keyLength += sizeof(ULONGLONG) - (keyLength & (sizeof(ULONGLONG) - 1));
555 
556  readStructure = ExAllocatePoolWithTag(NonPagedPoolNx,
557  keyLength,
559  if (readStructure == NULL)
560  {
562  }
563  }
564 
565  if (NT_SUCCESS(status))
566  {
567  RtlZeroMemory (readStructure, keyLength);
568  readStructure->Format = DvdCopyrightDescriptor;
569 
570  // use READ_STRUCTURE to read copyright descriptor
571  status = ReadDvdStructure(DeviceExtension,
572  Request,
573  readStructure,
574  keyLength,
575  readStructure,
577  &bytesReturned);
578  }
579 
580  if (NT_SUCCESS(status))
581  {
582  // we got the copyright descriptor, so now get the region if possible
583  dvdHeader = (PDVD_DESCRIPTOR_HEADER) readStructure;
584  copyRightDescriptor = (PDVD_COPYRIGHT_DESCRIPTOR) dvdHeader->Data;
585 
586  // the original irp's systembuffer has a copy of the info that
587  // should be passed down in the request
588  dvdRegion = outputBuffer;
589 
590  dvdRegion->CopySystem = copyRightDescriptor->CopyrightProtectionType;
591  dvdRegion->RegionData = copyRightDescriptor->RegionManagementInformation;
592 
593  // now reuse the buffer to request the copy protection info
594  copyProtectKey = (PDVD_COPY_PROTECT_KEY) readStructure;
595  RtlZeroMemory (copyProtectKey, DVD_RPC_KEY_LENGTH);
596  copyProtectKey->KeyLength = DVD_RPC_KEY_LENGTH;
597  copyProtectKey->KeyType = DvdGetRpcKey;
598 
599  // send a request for READ_KEY
600  status = DvdStartSessionReadKey(DeviceExtension,
602  Request,
603  copyProtectKey,
605  copyProtectKey,
607  &bytesReturned);
608  }
609 
610  if (NT_SUCCESS(status))
611  {
612  // the request succeeded. if a supported scheme is returned,
613  // then return the information to the caller
614  rpcKey = (PDVD_RPC_KEY) copyProtectKey->KeyData;
615 
616  if (rpcKey->RpcScheme == 1)
617  {
618  if (rpcKey->TypeCode)
619  {
620  dvdRegion->SystemRegion = ~rpcKey->RegionMask;
621  dvdRegion->ResetCount = rpcKey->UserResetsAvailable;
622  }
623  else
624  {
625  // the drive has not been set for any region
626  dvdRegion->SystemRegion = 0;
627  dvdRegion->ResetCount = rpcKey->UserResetsAvailable;
628  }
629 
630  *DataLength = sizeof(DVD_REGION);
631  }
632  else
633  {
634  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
635  "RequestHandleGetDvdRegion => rpcKey->RpcScheme != 1\n"));
637  }
638  }
639 
640  // Clean up
641  if (readStructure != NULL)
642  {
643  ExFreePool(readStructure);
644  }
645 
646  return status;
647 }
648 
649 NTSTATUS
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 {
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);
715  }
716  }
717  else
718  {
720  }
721  }
722 
723  if (NT_SUCCESS(status))
724  {
725  // Since this ioctl is METHOD_OUT_DIRECT, we need to copy away the input buffer before interpreting it.
726  // This prevents a malicious app from messing with the input buffer while we are interpreting it.
727  rawReadInfo = *(PRAW_READ_INFO)RequestParameters.Parameters.DeviceIoControl.Type3InputBuffer;
728 
729  startingOffset.QuadPart = rawReadInfo.DiskOffset.QuadPart;
730 
731  if ((rawReadInfo.TrackMode == CDDA) ||
732  (rawReadInfo.TrackMode == YellowMode2) ||
733  (rawReadInfo.TrackMode == XAForm2) )
734  {
735  transferBytes = (ULONGLONG)rawReadInfo.SectorCount * RAW_SECTOR_SIZE;
736  }
737  else if (rawReadInfo.TrackMode == RawWithSubCode)
738  {
739  transferBytes = (ULONGLONG)rawReadInfo.SectorCount * CD_RAW_SECTOR_WITH_SUBCODE_SIZE;
740  }
741  else if (rawReadInfo.TrackMode == RawWithC2)
742  {
743  transferBytes = (ULONGLONG)rawReadInfo.SectorCount * CD_RAW_SECTOR_WITH_C2_SIZE;
744  }
745  else if (rawReadInfo.TrackMode == RawWithC2AndSubCode)
746  {
747  transferBytes = (ULONGLONG)rawReadInfo.SectorCount * CD_RAW_SECTOR_WITH_C2_AND_SUBCODE_SIZE;
748  }
749  else
750  {
751  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
752  "RequestValidateRawRead: Invalid TrackMode type %x for XA read\n",
753  rawReadInfo.TrackMode
754  ));
755  }
756 
757  endOffset = (ULONGLONG)rawReadInfo.SectorCount * COOKED_SECTOR_SIZE;
758  endOffset += startingOffset.QuadPart;
759 
760  // check for overflows....
761  if (rawReadInfo.SectorCount == 0)
762  {
763  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
764  "RequestValidateRawRead: Invalid I/O parameters for XA "
765  "Read (zero sectors requested)\n"));
767  }
768  else if (transferBytes < (ULONGLONG)(rawReadInfo.SectorCount))
769  {
770  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
771  "RequestValidateRawRead: Invalid I/O parameters for XA "
772  "Read (TransferBytes Overflow)\n"));
774  }
775  else if (endOffset < (ULONGLONG)startingOffset.QuadPart)
776  {
777  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
778  "RequestValidateRawRead: Invalid I/O parameters for XA "
779  "Read (EndingOffset Overflow)\n"));
781  }
782  else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < transferBytes)
783  {
784  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
785  "RequestValidateRawRead: Invalid I/O parameters for XA "
786  "Read (Bad buffer size)\n"));
788  }
789  else if (endOffset > (ULONGLONG)DeviceExtension->PartitionLength.QuadPart)
790  {
791  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
792  "RequestValidateRawRead: Invalid I/O parameters for XA "
793  "Read (Request Out of Bounds)\n"));
795  }
796  }
797 
798  if (NT_SUCCESS(status))
799  {
800  // cannot validate the MdlAddress, since it is not included in any
801  // other location per the DDK and file system calls.
802 
803  // validate the mdl describes at least the number of bytes
804  // requested from us.
805  mdlBytes = (ULONGLONG)MmGetMdlByteCount(irp->MdlAddress);
806  if (mdlBytes < transferBytes)
807  {
808  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
809  "RequestValidateRawRead: Invalid MDL %s, Irp %p\n",
810  "size (5)", irp));
812  }
813  }
814 
815  if (NT_SUCCESS(status))
816  {
817  // check the buffer for alignment
818  // This is important for x86 as some busses (ie ATAPI)
819  // require word-aligned buffers.
820  if ( ((ULONG_PTR)MmGetMdlVirtualAddress(irp->MdlAddress)) &
821  DeviceExtension->AdapterDescriptor->AlignmentMask )
822  {
823  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
824  "RequestValidateRawRead: Invalid I/O parameters for "
825  "XA Read (Buffer %p not aligned with mask %x\n",
826  RequestParameters.Parameters.DeviceIoControl.Type3InputBuffer,
827  DeviceExtension->AdapterDescriptor->AlignmentMask));
829  }
830  }
831 
832  if (NT_SUCCESS(status))
833  {
834  // Validate the request is not too large for the adapter
835  BOOLEAN bufferIsPageAligned = FALSE;
836  ULONG maxLength = 0;
837 
838  // if buffer is not page-aligned, then subtract one as the
839  // transfer could cross a page boundary.
840  if ((((ULONG_PTR)MmGetMdlVirtualAddress(irp->MdlAddress)) & (PAGE_SIZE-1)) == 0)
841  {
842  bufferIsPageAligned = TRUE;
843  }
844 
845  if (bufferIsPageAligned)
846  {
848  }
849  else
850  {
852  }
853 
854  if (transferBytes > maxLength)
855  {
856  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
857  "RequestValidateRawRead: The XA Read (type %x) would require %I64x bytes, "
858  "but the adapter can only handle %x bytes (for a%saligned buffer)\n",
859  rawReadInfo.TrackMode,
860  transferBytes,
861  maxLength,
862  (bufferIsPageAligned ? " " : "n un")
863  ));
865  }
866  }
867 
868  if (NT_SUCCESS(status))
869  {
870  //
871  // HACKHACK - REF #0001
872  // The retry count will be in this irp's IRP_MN function,
873  // as the new irp was freed, and we therefore cannot use
874  // this irp's next stack location for this function.
875  // This may be a good location to store this info for
876  // when we remove RAW_READ (mode switching), as we will
877  // no longer have the nextIrpStackLocation to play with
878  // when that occurs
879  //
880  currentStack->MinorFunction = MAXIMUM_RETRIES; // HACKHACK - REF #0001
881  }
882 
883  return status;
884 }
885 
886 NTSTATUS
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 {
913 
914  PCDROM_READ_TOC_EX inputBuffer = NULL;
915 
916  *DataLength = 0;
917 
918  if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength <
919  sizeof(CDROM_READ_TOC_EX))
920  {
922  }
923  else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength <
925  {
928  }
929  else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength >
930  ((USHORT)-1))
931  {
933  }
934  else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength &
935  DeviceExtension->AdapterDescriptor->AlignmentMask)
936  {
938  }
939 
940  if (NT_SUCCESS(status))
941  {
942  status = WdfRequestRetrieveInputBuffer(Request,
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  {
955  }
956  // NOTE: when adding new formats, ensure that first two bytes
957  // specify the amount of additional data available.
958  else if ((inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_TOC ) ||
959  (inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_FULL_TOC) ||
960  (inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_CDTEXT ))
961  {
962  // SessionTrack field is used
963  }
964  else if ((inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_SESSION) ||
965  (inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_PMA) ||
966  (inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_ATIP))
967  {
968  // SessionTrack field is reserved
969  if (inputBuffer->SessionTrack != 0)
970  {
972  }
973  }
974  else
975  {
977  }
978  }
979 
980  return status;
981 }
982 
983 NTSTATUS
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 {
1008 
1009  *DataLength = 0;
1010 
1011  if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength <
1012  sizeof(CDROM_TOC))
1013  {
1014  // they didn't request the entire TOC -- use _EX version
1015  // for partial transfers and such.
1017  *DataLength = sizeof(CDROM_TOC);
1018  }
1019  else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength &
1020  DeviceExtension->AdapterDescriptor->AlignmentMask)
1021  {
1023  }
1024 
1025  return status;
1026 }
1027 
1028 NTSTATUS
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 {
1053 
1054  *DataLength = 0;
1055 
1056  if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength <
1057  sizeof(CDROM_TOC_SESSION_DATA))
1058  {
1061  }
1062  else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength &
1063  DeviceExtension->AdapterDescriptor->AlignmentMask)
1064  {
1066  }
1067 
1068  return status;
1069 }
1070 
1071 NTSTATUS
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 {
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  {
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
1134  }
1135  }
1136 
1137  if (NT_SUCCESS(status))
1138  {
1139  if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength <
1140  transferByteCount)
1141  {
1143  *DataLength = transferByteCount;
1144  }
1145  }
1146 
1147  return status;
1148 }
1149 
1150 NTSTATUS
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 {
1175 
1176  *DataLength = 0;
1177 
1178  if (NT_SUCCESS(status))
1179  {
1180  if(RequestParameters.Parameters.DeviceIoControl.InputBufferLength <
1181  sizeof(DVD_READ_STRUCTURE))
1182  {
1183  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL,
1184  "RequestValidateDvdReadStructure - input buffer "
1185  "length too small (was %d should be %d)\n",
1186  (int)RequestParameters.Parameters.DeviceIoControl.InputBufferLength,
1187  sizeof(DVD_READ_STRUCTURE)));
1189  }
1190  else if(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength <
1192  {
1193 
1194  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL,
1195  "RequestValidateDvdReadStructure - output buffer "
1196  "cannot hold header information\n"));
1199  }
1200  else if(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength >
1201  MAXUSHORT)
1202  {
1203  // key length must fit in two bytes
1204  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL,
1205  "RequestValidateDvdReadStructure - output buffer "
1206  "too large\n"));
1208  }
1209  else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength &
1210  DeviceExtension->AdapterDescriptor->AlignmentMask)
1211  {
1213  }
1214  else if (DeviceExtension->DeviceAdditionalData.DriveDeviceType != FILE_DEVICE_DVD)
1215  {
1216  // reject the request if it's not a DVD device.
1218  }
1219  }
1220 
1221  return status;
1222 }
1223 
1224 NTSTATUS
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 {
1249 
1250  *DataLength = 0;
1251 
1252  if (NT_SUCCESS(status))
1253  {
1254  if(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength <
1255  sizeof(DVD_SESSION_ID))
1256  {
1257  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL,
1258  "RequestValidateDvdStartSession: DVD_START_SESSION - output "
1259  "buffer too small\n"));
1261  *DataLength = sizeof(DVD_SESSION_ID);
1262  }
1263  else if (DeviceExtension->DeviceAdditionalData.DriveDeviceType != FILE_DEVICE_DVD)
1264  {
1265  // reject the request if it's not a DVD device.
1267  }
1268  }
1269 
1270  return status;
1271 }
1272 
1273 NTSTATUS
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 {
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));
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  {
1339  }
1340  }
1341  else if ((key->KeyType != DvdChallengeKey) &&
1342  (key->KeyType != DvdBusKey1) &&
1343  (key->KeyType != DvdBusKey2) &&
1344  (key->KeyType != DvdTitleKey) &&
1345  (key->KeyType != DvdAsf) &&
1346  (key->KeyType != DvdSetRpcKey) &&
1347  (key->KeyType != DvdGetRpcKey) &&
1348  (key->KeyType != DvdDiskKey) &&
1349  (key->KeyType != DvdInvalidateAGID))
1350  {
1352  }
1353  else if (DeviceExtension->DeviceAdditionalData.DriveDeviceType != FILE_DEVICE_DVD)
1354  {
1355  // reject the request if it's not a DVD device.
1357  }
1358  }
1359 
1360  return status;
1361 }
1362 
1363 NTSTATUS
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 {
1390 
1391  *DataLength = 0;
1392 
1393  if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength <
1394  sizeof(GET_CONFIGURATION_HEADER))
1395  {
1398  }
1399  else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > 0xffff)
1400  {
1401  // output buffer is too large
1403  }
1404  else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength &
1405  DeviceExtension->AdapterDescriptor->AlignmentMask)
1406  {
1407  // buffer is not proper size multiple
1409  }
1410 
1411  if (NT_SUCCESS(status))
1412  {
1413 
1414 #if BUILD_WOW64_ENABLED && defined(_WIN64)
1415 
1416  if (WdfRequestIsFrom32BitProcess(Request))
1417  {
1418  PGET_CONFIGURATION_IOCTL_INPUT32 inputBuffer = NULL;
1419 
1420  if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength <
1421  sizeof(GET_CONFIGURATION_IOCTL_INPUT32))
1422  {
1424  }
1425 
1426  //
1427  // also verify the arguments are reasonable.
1428  //
1429  if (NT_SUCCESS(status))
1430  {
1431  status = WdfRequestRetrieveInputBuffer(Request,
1432  RequestParameters.Parameters.DeviceIoControl.InputBufferLength,
1433  &inputBuffer,
1434  NULL);
1435  }
1436 
1437  if (NT_SUCCESS(status))
1438  {
1439  if (inputBuffer->Feature > 0xffff)
1440  {
1442  }
1443  else if ((inputBuffer->RequestType != SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE) &&
1444  (inputBuffer->RequestType != SCSI_GET_CONFIGURATION_REQUEST_TYPE_CURRENT) &&
1445  (inputBuffer->RequestType != SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL))
1446  {
1448  }
1449  else if (inputBuffer->Reserved[0] || inputBuffer->Reserved[1])
1450  {
1452  }
1453  }
1454  }
1455  else
1456 
1457 #endif
1458 
1459  {
1460  PGET_CONFIGURATION_IOCTL_INPUT inputBuffer = NULL;
1461 
1462  if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength <
1464  {
1466  }
1467 
1468  // also verify the arguments are reasonable.
1469  if (NT_SUCCESS(status))
1470  {
1471  status = WdfRequestRetrieveInputBuffer(Request,
1472  RequestParameters.Parameters.DeviceIoControl.InputBufferLength,
1473  &inputBuffer,
1474  NULL);
1475  }
1476 
1477  if (NT_SUCCESS(status))
1478  {
1479  if (inputBuffer->Feature > 0xffff)
1480  {
1482  }
1483  else if ((inputBuffer->RequestType != SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE) &&
1486  {
1488  }
1489  else if (inputBuffer->Reserved[0] || inputBuffer->Reserved[1])
1490  {
1492  }
1493  }
1494  }
1495  }
1496 
1497  return status;
1498 }
1499 
1500 NTSTATUS
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 {
1527  PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData);
1528  PCDROM_SET_SPEED inputBuffer = NULL;
1529  ULONG requiredLength = 0;
1530 
1531  *DataLength = 0;
1532 
1533  if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(CDROM_SET_SPEED))
1534  {
1536  }
1537 
1538  if (NT_SUCCESS(status))
1539  {
1540  // Get the request type using CDROM_SET_SPEED structure
1541  status = WdfRequestRetrieveInputBuffer(Request,
1542  sizeof(CDROM_SET_SPEED),
1543  &inputBuffer,
1544  NULL);
1545 
1546  }
1547 
1548  if (NT_SUCCESS(status))
1549  {
1550  if (inputBuffer->RequestType > CdromSetStreaming)
1551  {
1552  // Unknown request type.
1554  }
1555  else if (inputBuffer->RequestType == CdromSetSpeed)
1556  {
1557  requiredLength = sizeof(CDROM_SET_SPEED);
1558  }
1559  else
1560  {
1561  // Don't send SET STREAMING command if this is not a MMC compliant device
1562  if (cdData->Mmc.IsMmc == FALSE)
1563  {
1565  }
1566 
1567  requiredLength = sizeof(CDROM_SET_STREAMING);
1568  }
1569  }
1570 
1571  if (NT_SUCCESS(status))
1572  {
1573  if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < requiredLength)
1574  {
1575  // Input buffer too small
1577  }
1578  }
1579 
1580  return status;
1581 }
1582 
1583 NTSTATUS
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 {
1610  PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData);
1611  PAACS_LAYER_NUMBER layerNumber = NULL;
1612 
1613  *DataLength = 0;
1614 
1615  if (!cdData->Mmc.IsAACS)
1616  {
1618  }
1619  else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(AACS_LAYER_NUMBER))
1620  {
1622  }
1623  else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < 8)
1624  {
1625  // This is a variable-length structure, but we're pretty sure
1626  // it can never be less than eight bytes...
1627  *DataLength = 8;
1629  }
1630 
1631  if (NT_SUCCESS(status))
1632  {
1633  status = WdfRequestRetrieveInputBuffer(Request,
1634  RequestParameters.Parameters.DeviceIoControl.InputBufferLength,
1635  &layerNumber,
1636  NULL);
1637  }
1638 
1639  if (NT_SUCCESS(status))
1640  {
1641  if (*layerNumber > 255)
1642  {
1644  }
1645  }
1646 
1647  return status;
1648 }
1649 
1650 NTSTATUS
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 {
1675  PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData);
1676 
1677  *DataLength = 0;
1678 
1679  if (!cdData->Mmc.IsAACS)
1680  {
1682  }
1683  else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(DVD_SESSION_ID))
1684  {
1685  *DataLength = sizeof(DVD_SESSION_ID);
1687  }
1688  else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > sizeof(DVD_SESSION_ID))
1689  {
1691  }
1692 
1693  return status;
1694 }
1695 
1696 NTSTATUS
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 {
1723  PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData);
1724  PAACS_SEND_CERTIFICATE inputBuffer = NULL;
1725 
1726  *DataLength = 0;
1727 
1728  if (!cdData->Mmc.IsAACS)
1729  {
1731  }
1732  else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(AACS_SEND_CERTIFICATE))
1733  {
1735  }
1736 
1737  if (NT_SUCCESS(status))
1738  {
1739  status = WdfRequestRetrieveInputBuffer(Request,
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  {
1750  }
1751  }
1752 
1753  return status;
1754 }
1755 
1756 NTSTATUS
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 {
1783  PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData);
1784  PDVD_SESSION_ID sessionId = NULL;
1785 
1786  *DataLength = 0;
1787 
1788  if (!cdData->Mmc.IsAACS)
1789  {
1791  }
1792  else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(DVD_SESSION_ID))
1793  {
1795  }
1796  else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(AACS_CERTIFICATE))
1797  {
1798  *DataLength = sizeof(AACS_CERTIFICATE);
1800  }
1801  else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > sizeof(AACS_CERTIFICATE))
1802  {
1804  }
1805 
1806  if (NT_SUCCESS(status))
1807  {
1808  status = WdfRequestRetrieveInputBuffer(Request,
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  {
1819  }
1820  }
1821 
1822  return status;
1823 }
1824 
1825 NTSTATUS
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 {
1852  PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData);
1853  PDVD_SESSION_ID sessionId = NULL;
1854 
1855  *DataLength = 0;
1856 
1857  if (!cdData->Mmc.IsAACS)
1858  {
1860  }
1861  else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(DVD_SESSION_ID))
1862  {
1864  }
1865  else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(AACS_CHALLENGE_KEY))
1866  {
1867  *DataLength = sizeof(AACS_CHALLENGE_KEY);
1869  }
1870  else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > sizeof(AACS_CHALLENGE_KEY))
1871  {
1873  }
1874 
1875  if (NT_SUCCESS(status))
1876  {
1877  status = WdfRequestRetrieveInputBuffer(Request,
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  {
1888  }
1889  }
1890 
1891  return status;
1892 }
1893 
1894 NTSTATUS
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 {
1921  PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData);
1922  PAACS_SEND_CHALLENGE_KEY inputBuffer = NULL;
1923 
1924  *DataLength = 0;
1925 
1926  if (!cdData->Mmc.IsAACS)
1927  {
1929  }
1930  else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(AACS_SEND_CHALLENGE_KEY))
1931  {
1933  }
1934 
1935  if (NT_SUCCESS(status))
1936  {
1937  status = WdfRequestRetrieveInputBuffer(Request,
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  {
1948  }
1949  }
1950 
1951  return status;
1952 }
1953 
1954 NTSTATUS
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 {
1981  PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData);
1982  PDVD_SESSION_ID sessionId = NULL;
1983 
1984  *DataLength = 0;
1985 
1986  if (!cdData->Mmc.IsAACS)
1987  {
1989  }
1990  else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(DVD_SESSION_ID))
1991  {
1993  }
1994  else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(AACS_VOLUME_ID))
1995  {
1996  *DataLength = sizeof(AACS_VOLUME_ID);
1998  }
1999  else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > sizeof(AACS_VOLUME_ID))
2000  {
2002  }
2003 
2004  if (NT_SUCCESS(status))
2005  {
2006  status = WdfRequestRetrieveInputBuffer(Request,
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  {
2017  }
2018  }
2019 
2020  return status;
2021 }
2022 
2023 NTSTATUS
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 {
2050  PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData);
2051  PDVD_SESSION_ID sessionId = NULL;
2052 
2053  *DataLength = 0;
2054 
2055  if (!cdData->Mmc.IsAACS)
2056  {
2058  }
2059  else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(DVD_SESSION_ID))
2060  {
2062  }
2063  else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(AACS_SERIAL_NUMBER))
2064  {
2065  *DataLength = sizeof(AACS_SERIAL_NUMBER);
2067  }
2068  else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > sizeof(AACS_SERIAL_NUMBER))
2069  {
2071  }
2072 
2073  if (NT_SUCCESS(status))
2074  {
2075  status = WdfRequestRetrieveInputBuffer(Request,
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  {
2086  }
2087  }
2088 
2089  return status;
2090 }
2091 
2092 NTSTATUS
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 {
2119  PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData);
2120  PDVD_SESSION_ID sessionId = NULL;
2121 
2122  *DataLength = 0;
2123 
2124  if (!cdData->Mmc.IsAACS)
2125  {
2127  }
2128  else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(DVD_SESSION_ID))
2129  {
2131  }
2132  else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(AACS_MEDIA_ID))
2133  {
2134  *DataLength = sizeof(AACS_MEDIA_ID);
2136  }
2137  else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > sizeof(AACS_MEDIA_ID))
2138  {
2140  }
2141 
2142  if (NT_SUCCESS(status))
2143  {
2144  status = WdfRequestRetrieveInputBuffer(Request,
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  {
2155  }
2156  }
2157 
2158  return status;
2159 }
2160 
2161 NTSTATUS
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 {
2189  PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData);
2190  PAACS_READ_BINDING_NONCE inputBuffer = NULL;
2191 
2192  *DataLength = 0;
2193 
2194  if (!cdData->Mmc.IsAACS)
2195  {
2197  }
2198  else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(AACS_READ_BINDING_NONCE))
2199  {
2201  }
2202  else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(AACS_BINDING_NONCE))
2203  {
2204  *DataLength = sizeof(AACS_BINDING_NONCE);
2206  }
2207  else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > sizeof(AACS_BINDING_NONCE))
2208  {
2210  }
2211 
2212  if (NT_SUCCESS(status))
2213  {
2214  status = WdfRequestRetrieveInputBuffer(Request,
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  {
2225  }
2226  else if (inputBuffer->NumberOfSectors > 255)
2227  {
2229  }
2230  else if (inputBuffer->StartLba > MAXULONG)
2231  {
2233  }
2234  }
2235 
2236  return status;
2237 }
2238 
2239 NTSTATUS
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 {
2264  PCDROM_EXCLUSIVE_ACCESS exclusiveAccess = NULL;
2265 
2266  *DataLength = 0;
2267 
2269  {
2270  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "RequestValidateExclusiveAccess: IOCTL must be called at passive level.\n"));
2272  }
2273  else if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(CDROM_EXCLUSIVE_ACCESS))
2274  {
2275 
2276  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "RequestValidateExclusiveAccess: Input buffer too small\n"));
2278  }
2279 
2280  if (NT_SUCCESS(status))
2281  {
2282  status = WdfRequestRetrieveInputBuffer(Request,
2283  RequestParameters.Parameters.DeviceIoControl.InputBufferLength,
2284  &exclusiveAccess,
2285  NULL);
2286  }
2287 
2288  if (NT_SUCCESS(status))
2289  {
2290  switch (exclusiveAccess->RequestType)
2291  {
2293  {
2294  if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength <
2296  {
2297  //
2298  // Output buffer too small.
2299  //
2300  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "RequestValidateExclusiveAccess: Output buffer too small\n"));
2303  }
2304  break;
2305  }
2306 
2308  {
2309  if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength <
2310  sizeof(CDROM_EXCLUSIVE_LOCK))
2311  {
2312  //
2313  // Input buffer too small
2314  //
2315  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "RequestValidateExclusiveAccess: Input buffer too small\n"));
2317  }
2318  break;
2319  }
2321  {
2322  //
2323  // Nothing to check
2324  //
2325  break;
2326  }
2327 
2328  default:
2329  {
2330  //
2331  // Unknown request type.
2332  //
2333  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "RequestValidateExclusiveAccess: Invalid request type\n"));
2335  }
2336  }
2337  }
2338 
2339  return status;
2340 }
2341 
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 {
2368  PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device);
2369  PCDROM_DATA cdData = &deviceExtension->DeviceAdditionalData;
2370  PCDROM_EXCLUSIVE_LOCK_STATE exclusiveLockState = NULL;
2371 
2372  PAGED_CODE();
2373 
2374  status = WdfRequestRetrieveOutputBuffer(Request,
2376  &exclusiveLockState,
2377  NULL);
2379 
2380  RtlZeroMemory(exclusiveLockState, sizeof(CDROM_EXCLUSIVE_LOCK_STATE));
2381 
2382  if (EXCLUSIVE_MODE(cdData))
2383  {
2384  // Device is locked for exclusive use
2385  exclusiveLockState->LockState = TRUE;
2386 
2387  RtlCopyMemory(&exclusiveLockState->CallerName,
2388  &cdData->CallerName,
2390 
2391  }
2392  else
2393  {
2394  // Device is not locked
2395  exclusiveLockState->LockState = FALSE;
2396  }
2397 
2398  RequestCompletion(deviceExtension, Request, status, sizeof(CDROM_EXCLUSIVE_LOCK_STATE));
2399 
2400  return status;
2401 }
2402 
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 {
2429  PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device);
2430  PCDROM_DATA cdData = &deviceExtension->DeviceAdditionalData;
2431  PCDROM_EXCLUSIVE_LOCK exclusiveLock = NULL;
2432  PIO_ERROR_LOG_PACKET logEntry;
2433 
2434  WDFFILEOBJECT fileObject = NULL;
2435  ULONG idx = 0;
2436  ULONG nameLength = 0;
2437 
2438  PAGED_CODE();
2439 
2440  fileObject = WdfRequestGetFileObject(Request);
2441 
2442  if (fileObject == NULL)
2443  {
2445 
2446  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL,
2447  "RequestHandleExclusiveAccessLockDevice: FileObject is NULL, cannot grant exclusive access\n"));
2448  }
2449 
2450  if (NT_SUCCESS(status))
2451  {
2452  status = WdfRequestRetrieveInputBuffer(Request,
2453  sizeof(CDROM_EXCLUSIVE_LOCK),
2454  &exclusiveLock,
2455  NULL);
2456  }
2457 
2458  if (NT_SUCCESS(status))
2459  {
2460  // Validate the caller name string
2461  for (idx = 0; (idx < CDROM_EXCLUSIVE_CALLER_LENGTH) && (exclusiveLock->CallerName[idx] != '\0'); idx++)
2462  {
2463  if (!ValidChar(exclusiveLock->CallerName[idx]))
2464  {
2465  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL,
2466  "RequestHandleExclusiveAccessLockDevice: Invalid characters in caller name\n"));
2467  // error out
2469  break;
2470  }
2471  }
2472  }
2473 
2474  if (NT_SUCCESS(status))
2475  {
2476  if ((idx == 0) || (idx >= CDROM_EXCLUSIVE_CALLER_LENGTH))
2477  {
2478 
2479  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL,
2480  "RequestHandleExclusiveAccessLockDevice: Not a valid null terminated string.\n"));
2481  //error out
2483  }
2484  else
2485  {
2486  nameLength = idx+1; // Add 1 for the NULL character
2488  }
2489  }
2490 
2491  // If the file system is still mounted on this device fail the request,
2492  // unless the force lock flag is set.
2493  if (NT_SUCCESS(status))
2494  {
2495  if ((TEST_FLAG(exclusiveLock->Access.Flags, CDROM_LOCK_IGNORE_VOLUME) == FALSE) &&
2496  IsVolumeMounted(deviceExtension->DeviceObject))
2497  {
2498  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL,
2499  "RequestHandleExclusiveAccessLockDevice: Unable to lock device, file system mounted\n"));
2501  }
2502  }
2503 
2504  // Lock the device for exclusive access if the device is not already locked
2505  if (NT_SUCCESS(status))
2506  {
2507  if (InterlockedCompareExchangePointer((PVOID)&cdData->ExclusiveOwner, (PVOID)fileObject, NULL) == NULL)
2508  {
2509  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
2510  "RequestHandleExclusiveAccessLockDevice: Entering exclusive mode! Device locked by file object %p\n", fileObject));
2511 
2512  // Zero out the CallerName before storing it in the extension
2514  RtlCopyMemory(&cdData->CallerName,
2515  &exclusiveLock->CallerName,
2516  nameLength);
2517 
2518  // Send Exclusive Lock notification
2519  DeviceSendNotification(deviceExtension,
2520  &GUID_IO_CDROM_EXCLUSIVE_LOCK,
2521  0,
2522  NULL);
2523 
2524  // Log an informational event with the caller name
2525  logEntry = IoAllocateErrorLogEntry(
2526  deviceExtension->DeviceObject,
2528 
2529  if (logEntry != NULL)
2530  {
2531  PUCHAR dumpDataPtr = (PUCHAR) logEntry->DumpData;
2532 
2533  logEntry->FinalStatus = STATUS_SUCCESS;
2534  logEntry->ErrorCode = IO_CDROM_EXCLUSIVE_LOCK;
2535  logEntry->SequenceNumber = 0;
2538  logEntry->RetryCount = 0;
2539  logEntry->UniqueErrorValue = 0x1;
2541 
2542  RtlCopyMemory(dumpDataPtr,
2543  (PUCHAR)&cdData->CallerName,
2545 
2546  // Write the error log packet.
2547  IoWriteErrorLogEntry(logEntry);
2548  }
2549 
2550  }
2551  else
2552  {
2553  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL,
2554  "RequestHandleExclusiveAccessLockDevice: Unable to lock device, device already locked.\n"));
2555 
2557  }
2558  }
2559 
2560  RequestCompletion(deviceExtension, Request, status, 0);
2561 
2562  return status;
2563 }
2564 
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 {
2589  PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device);
2590  PCDROM_EXCLUSIVE_ACCESS exclusiveAccess = NULL;
2591  WDFFILEOBJECT fileObject = NULL;
2592 
2593  PAGED_CODE();
2594 
2595  fileObject = WdfRequestGetFileObject(Request);
2596 
2597  if (fileObject == NULL)
2598  {
2599  // The device can be unlocked from exclusive mode only via the file object which locked it.
2601 
2602  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL,
2603  "RequestHandleExclusiveAccessUnlockDevice: FileObject is NULL, cannot release exclusive access\n"));
2604  }
2605 
2606  if (NT_SUCCESS(status))
2607  {
2608  status = WdfRequestRetrieveInputBuffer(Request,
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
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 {
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;
2674  }
2675  else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_DESCRIPTOR_HEADER))
2676  {
2677  // Buffer too small
2678  *DataLength = DeviceExtension->DeviceDescriptor->Size;
2680  }
2681  else
2682  {
2683  PSTORAGE_DEVICE_DESCRIPTOR outputDescriptor = NULL;
2684  CHAR* localDescriptorBuffer = (CHAR*)DeviceExtension->DeviceDescriptor;
2685 
2686  status = WdfRequestRetrieveOutputBuffer(Request,
2687  RequestParameters.Parameters.DeviceIoControl.OutputBufferLength,
2688  &outputDescriptor,
2689  NULL);
2690 
2691  if (NT_SUCCESS(status))
2692  {
2693  // transfer as much data out as the buffer will allow
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  }
2752  }
2753  }
2754  } //end of StorageDeviceProperty
2755  else if (inputBuffer->PropertyId == StorageAdapterProperty)
2756  {
2757  if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength == 0)
2758  {
2759  // According to MSDN, an output buffer of size 0 can be used to determine if a property exists
2760  // so this must be a success case with no data transferred
2761  *DataLength = 0;
2763  }
2764  else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_DESCRIPTOR_HEADER))
2765  {
2766  // Buffer too small
2767  *DataLength = DeviceExtension->AdapterDescriptor->Size;
2769  }
2770  else
2771  {
2772  PSTORAGE_ADAPTER_DESCRIPTOR outputDescriptor = NULL;
2773 
2774  status = WdfRequestRetrieveOutputBuffer(Request,
2775  RequestParameters.Parameters.DeviceIoControl.OutputBufferLength,
2776  &outputDescriptor,
2777  NULL);
2778  if (NT_SUCCESS(status))
2779  {
2780  // copy as much data out as the buffer will allow
2781  *DataLength = min(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength,
2782  DeviceExtension->AdapterDescriptor->Size);
2783 
2784  RtlCopyMemory(outputDescriptor,
2785  DeviceExtension->AdapterDescriptor,
2786  *DataLength);
2787 
2788  // set status
2790  }
2791  }
2792  }
2793  }
2794 
2795  return status;
2796 }
2797 
2798 NTSTATUS
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 {
2823  PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device);
2824  PSTORAGE_PROPERTY_QUERY inputBuffer = NULL;
2825  PSTORAGE_DESCRIPTOR_HEADER descHeader = NULL;
2826  size_t outLength = 0;
2827  WDF_REQUEST_PARAMETERS requestParameters;
2828 
2829  // Get the Request parameters
2830  WDF_REQUEST_PARAMETERS_INIT(&requestParameters);
2831  WdfRequestGetParameters(Request, &requestParameters);
2832 
2833  status = WdfRequestRetrieveInputBuffer(Request,
2834  requestParameters.Parameters.DeviceIoControl.InputBufferLength,
2835  &inputBuffer,
2836  NULL);
2837 
2838  if (NT_SUCCESS(status))
2839  {
2840  BOOLEAN overflow = FALSE;
2841  BOOLEAN infoFound = FALSE;
2842 
2843  // Must run at less then dispatch.
2845  {
2846  NT_ASSERT(FALSE);
2847  outLength = 0;
2849  }
2850  else if (inputBuffer->QueryType == PropertyExistsQuery)
2851  {
2852  outLength = 0;
2854  }
2855  else if (inputBuffer->QueryType != PropertyStandardQuery)
2856  {
2857  outLength = 0;
2859  }
2860  else
2861  {
2862  // Check AdditionalParameters validity.
2863  if (inputBuffer->AdditionalParameters[0] == DUID_INCLUDE_SOFTWARE_IDS)
2864  {
2865  // Do nothing
2866  }
2867  else if (inputBuffer->AdditionalParameters[0] == DUID_HARDWARE_IDS_ONLY)
2868  {
2869  // Do nothing
2870  }
2871  else
2872  {
2873  outLength = 0;
2875  }
2876 
2877  if (NT_SUCCESS(status) &&
2878  (outLength < sizeof(STORAGE_DESCRIPTOR_HEADER)))
2879  {
2880  outLength = 0;
2882  }
2883  }
2884 
2885  // From this point forward the status depends on the overflow
2886  // and infoFound flags.
2887  if (NT_SUCCESS(status))
2888  {
2889  outLength = requestParameters.Parameters.DeviceIoControl.OutputBufferLength;
2890  status = WdfRequestRetrieveOutputBuffer(Request,
2891  requestParameters.Parameters.DeviceIoControl.OutputBufferLength,
2892  &descHeader,
2893  NULL);
2894  }
2895 
2896  if (NT_SUCCESS(status))
2897  {
2898  RtlZeroMemory(descHeader, outLength);
2899 
2900  descHeader->Version = DUID_VERSION_1;
2901  descHeader->Size = sizeof(STORAGE_DEVICE_UNIQUE_IDENTIFIER);
2902 
2903  // Try to build device unique id from StorageDeviceIdProperty.
2904  status = RequestDuidGetDeviceIdProperty(deviceExtension,
2905  Request,
2906  requestParameters,
2907  &outLength);
2908 
2910  {
2911  overflow = TRUE;
2912  }
2913 
2914  if (NT_SUCCESS(status))
2915  {
2916  infoFound = TRUE;
2917  }
2918 
2919  // Try to build device unique id from StorageDeviceProperty.
2920  status = RequestDuidGetDeviceProperty(deviceExtension,
2921  Request,
2922  requestParameters,
2923  &outLength);
2924 
2926  {
2927  overflow = TRUE;
2928  }
2929 
2930  if (NT_SUCCESS(status))
2931  {
2932  infoFound = TRUE;
2933  }
2934 
2935  // Return overflow, success, or a generic error.
2936  if (overflow)
2937  {
2938  // If output buffer is STORAGE_DESCRIPTOR_HEADER, then return
2939  // success to the user. Otherwise, send an error so the user
2940  // knows a larger buffer is required.
2941  if (outLength == sizeof(STORAGE_DESCRIPTOR_HEADER))
2942  {
2944  }
2945  else
2946  {
2947  outLength = (ULONG)WdfRequestGetInformation(Request);
2949  }
2950 
2951  }
2952  else if (infoFound)
2953  {
2955 
2956  // Exercise the compare routine. This should always succeed.
2958  (PSTORAGE_DEVICE_UNIQUE_IDENTIFIER)descHeader));
2959 
2960  }
2961  else
2962  {
2964  }
2965  }
2966  }
2967 
2968  RequestCompletion(deviceExtension, Request, status, outLength);
2969 
2970  return status;
2971 }
2972 
2973 NTSTATUS
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 {
2996  PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device);
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.
3020  {
3021  NT_ASSERT(FALSE);
3023  }
3024  else if (query->QueryType == PropertyExistsQuery)
3025  {
3026  information = 0;
3028  }
3029  else if (query->QueryType != PropertyStandardQuery)
3030  {
3032  }
3033  }
3034 
3035  if (NT_SUCCESS(status))
3036  {
3037  length = requestParameters.Parameters.DeviceIoControl.OutputBufferLength;
3038 
3039  if (length < sizeof(STORAGE_DESCRIPTOR_HEADER))
3040  {
3042  }
3043  }
3044 
3045  if (NT_SUCCESS(status))
3046  {
3047  status = WdfRequestRetrieveOutputBuffer(Request,
3048  requestParameters.Parameters.DeviceIoControl.OutputBufferLength,
3049  &writeCache,
3050  NULL);
3051  }
3052 
3053  if (NT_SUCCESS(status))
3054  {
3055  RtlZeroMemory(writeCache, length);
3056 
3057  // Set version and required size.
3058  writeCache->Version = sizeof(STORAGE_WRITE_CACHE_PROPERTY);
3059  writeCache->Size = sizeof(STORAGE_WRITE_CACHE_PROPERTY);
3060 
3061  if (length < sizeof(STORAGE_WRITE_CACHE_PROPERTY))
3062  {
3063  // caller only wants header information, bail out.
3066 
3067  RequestCompletion(deviceExtension, Request, status, information);
3068  return status;
3069  }
3070  }
3071 
3072  if (NT_SUCCESS(status))
3073  {
3074  srb = ExAllocatePoolWithTag(NonPagedPoolNx,
3075  sizeof(SCSI_REQUEST_BLOCK) +
3076  (sizeof(ULONG_PTR) * 2),
3077  CDROM_TAG_SRB);
3078 
3079  if (srb == NULL)
3080  {
3082  }
3083  }
3084 
3085  if (NT_SUCCESS(status))
3086  {
3087  RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
3088 
3089  // Set known values
3090  writeCache->NVCacheEnabled = FALSE;
3091  writeCache->UserDefinedPowerProtection = TEST_FLAG(deviceExtension->DeviceFlags, DEV_POWER_PROTECTED);
3092 
3093  // Check for flush cache support by sending a sync cache command
3094  // to the device.
3095 
3096  // Set timeout value and mark the request as not being a tagged request.
3098  srb->TimeOutValue = TimeOutValueGetCapValue(deviceExtension->TimeOutValue, 4);
3099  srb->QueueTag = SP_UNTAGGED;
3101  srb->SrbFlags = deviceExtension->SrbFlags;
3102 
3104  srb->CdbLength = 10;
3105 
3106  srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE;
3107 
3108  status = DeviceSendSrbSynchronously(Device,
3109  srb,
3110  NULL,
3111  0,
3112  TRUE, //flush drive cache
3113  Request);
3114 
3115  if (NT_SUCCESS(status))
3116  {
3117  writeCache->FlushCacheSupported = TRUE;
3118  }
3119  else
3120  {
3121  // Device does not support sync cache
3122  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
3123  "RequestHandleQueryPropertyWriteCache: Synchronize cache failed with status 0x%X\n", status));
3124  writeCache->FlushCacheSupported = FALSE;
3125 
3126  // Reset the status if there was any failure
3128  }
3129 
3130  modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
3133 
3134  if (modeData == NULL)
3135  {
3136  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
3137  "RequestHandleQueryPropertyWriteCache: Unable to allocate mode data buffer\n"));
3139  }
3140  }
3141 
3142  if (NT_SUCCESS(status))
3143  {
3145 
3146  length = DeviceRetrieveModeSenseUsingScratch(deviceExtension,
3147  (PCHAR)modeData,
3151 
3152  if (length < sizeof(MODE_PARAMETER_HEADER))
3153  {
3154  // Retry the request in case of a check condition.
3155  length = DeviceRetrieveModeSenseUsingScratch(deviceExtension,
3156  (PCHAR)modeData,
3160 
3161  if (length < sizeof(MODE_PARAMETER_HEADER))
3162  {
3163  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, "RequestHandleQueryPropertyWriteCache: Mode Sense failed\n"));
3165  }
3166  }
3167  }
3168 
3169  if (NT_SUCCESS(status))
3170  {
3171  // If the length is greater than length indicated by the mode data reset
3172  // the data to the mode data.
3173  if (length > (ULONG) (modeData->ModeDataLength + 1))
3174  {
3175  length = modeData->ModeDataLength + 1;
3176  }
3177 
3178  // Look for caching page in the returned mode page data.
3179  pageData = ModeSenseFindSpecificPage((PCHAR)modeData,
3180  length,
3182  TRUE);
3183 
3184  // Check if valid caching page exists.
3185  if (pageData == NULL)
3186  {
3187  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "RequestHandleQueryPropertyWriteCache: Unable to find caching mode page.\n"));
3188 
3189  // Set write cache value as unknown.
3190  writeCache->WriteCacheEnabled = WriteCacheEnableUnknown;
3191  writeCache->WriteCacheType = WriteCacheTypeUnknown;
3192  }
3193  else
3194  {
3195  writeCache->WriteCacheEnabled = pageData->WriteCacheEnable
3198 
3199  writeCache->WriteCacheType = pageData->WriteCacheEnable
3202  }
3203 
3204  // Check write through support.
3205  if (modeData->DeviceSpecificParameter & MODE_DSP_FUA_SUPPORTED)
3206  {
3207  writeCache->WriteThroughSupported = WriteThroughSupported;
3208  }
3209  else
3210  {
3211  writeCache->WriteThroughSupported = WriteThroughNotSupported;
3212  }
3213 
3214  // Get the changeable caching mode page and check write cache is changeable.
3216 
3217  length = DeviceRetrieveModeSenseUsingScratch(deviceExtension,
3218  (PCHAR) modeData,
3222 
3223  if (length < sizeof(MODE_PARAMETER_HEADER))
3224  {
3225  // Retry the request in case of a check condition.
3226  length = DeviceRetrieveModeSenseUsingScratch(deviceExtension,
3227  (PCHAR) modeData,
3231 
3232  if (length < sizeof(MODE_PARAMETER_HEADER))
3233  {
3234  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "RequestHandleQueryPropertyWriteCache: Mode Sense failed\n"));
3235 
3236  // If the device fails to return changeable pages, then
3237  // set the write cache changeable value to unknown.
3238  writeCache->WriteCacheChangeable = WriteCacheChangeUnknown;
3240  }
3241  }
3242  }
3243 
3244  if (NT_SUCCESS(status))
3245  {
3246  // If the length is greater than length indicated by the mode data reset
3247  // the data to the mode data.
3248  if (length > (ULONG) (modeData->ModeDataLength + 1))
3249  {
3250  length = modeData->ModeDataLength + 1;
3251  }
3252 
3253  // Look for caching page in the returned mode page data.
3254  pageData = ModeSenseFindSpecificPage((PCHAR)modeData,
3255  length,
3257  TRUE);
3258  // Check if valid caching page exists.
3259  if (pageData == NULL)
3260  {
3261  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "RequestHandleQueryPropertyWriteCache: Unable to find caching mode page.\n"));
3262 
3263  // Set write cache changeable value to unknown.
3264  writeCache->WriteCacheChangeable = WriteCacheChangeUnknown;
3265  }
3266  else
3267  {
3268  writeCache->WriteCacheChangeable = pageData->WriteCacheEnable
3271  }
3272 
3274 
3275  }
3276 
3277  FREE_POOL(srb);
3278  FREE_POOL(modeData);
3279 
3280  RequestCompletion(deviceExtension, Request, status, information);
3281 
3282  return status;
3283 }
3284 
3285 NTSTATUS
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 {
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"));
3330  }
3331  }
3332 
3333  if (NT_SUCCESS(status))
3334  {
3335  switch(keyParameters->KeyType)
3336  {
3337 
3338  case DvdChallengeKey:
3339  {
3341  keyLength = DVD_CHALLENGE_KEY_LENGTH;
3342  break;
3343  }
3344  case DvdBusKey1:
3345  case DvdBusKey2:
3346  {
3348  keyLength = DVD_BUS_KEY_LENGTH;
3349  break;
3350  }
3351  case DvdTitleKey:
3352  {
3354  keyLength = DVD_TITLE_KEY_LENGTH;
3355  break;
3356  }
3357  case DvdAsf:
3358  {
3360  keyLength = DVD_ASF_LENGTH;
3361  break;
3362  }
3363  case DvdDiskKey:
3364  {
3366  keyLength = DVD_DISK_KEY_LENGTH;
3367  break;
3368  }
3369  case DvdGetRpcKey:
3370  {
3372  keyLength = DVD_RPC_KEY_LENGTH;
3373  break;
3374  }
3375  default:
3376  {
3377  keyLength = sizeof(DVD_COPY_PROTECT_KEY);
3378  break;
3379  }
3380  }
3381 
3382  if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < keyLength)
3383  {
3384 
3385  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL,
3386  "DvdDeviceControl: EstablishDriveKey - output "
3387  "buffer too small\n"));
3389  *DataLength = keyLength;
3390  }
3391  else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength &
3392  DeviceExtension->AdapterDescriptor->AlignmentMask)
3393  {
3395  }
3396  else if (DeviceExtension->DeviceAdditionalData.DriveDeviceType != FILE_DEVICE_DVD)
3397  {
3398  // reject the request if it's not a DVD device.
3400  }
3401  }
3402 
3403  return status;
3404 }
3405 
3406 
3407 NTSTATUS
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 {
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"));
3454  }
3455  }
3456 
3457  return status;
3458 }
3459 
3460 
3461 NTSTATUS
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 {
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  {
3503  }
3504  else if(RequestParameters.Parameters.DeviceIoControl.InputBufferLength != sizeof(DVD_SESSION_ID))
3505  {
3507  }
3508  }
3509 
3510  return status;
3511 }
3512 
3513 
3514 NTSTATUS
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 {
3539 
3540  PCDROM_STREAMING_CONTROL inputBuffer = NULL;
3541 
3542  *DataLength = 0;
3543 
3544  if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength <
3545  sizeof(CDROM_STREAMING_CONTROL))
3546  {
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 &&
3565  {
3566  // Unknown request type
3568  }
3569  }
3570 
3571  return status;
3572 }
3573 
3574 
3575 NTSTATUS
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 {
3600 
3601  PCDROM_SIMPLE_OPC_INFO inputBuffer = NULL;
3602 
3603  *DataLength = 0;
3604 
3605  if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength <
3606  sizeof(CDROM_SIMPLE_OPC_INFO))
3607  {
3609  }
3610 
3611  if (NT_SUCCESS(status))
3612  {
3613  // Get the request type using CDROM_SIMPLE_OPC_INFO structure
3614  status = WdfRequestRetrieveInputBuffer(Request,
3615  sizeof(CDROM_SIMPLE_OPC_INFO),
3616  &inputBuffer,
3617  NULL);
3618  }
3619 
3620  if (NT_SUCCESS(status))
3621  {
3622  if (inputBuffer->RequestType != SimpleOpcInfo)
3623  {
3624  // Unknown request type
3626  }
3627  }
3628 
3629  return status;
3630 }
3631 
3632 
3633 NTSTATUS
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 {
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  {
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  {
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  {
3708  }
3709  else if (performanceRequest->Exceptions != CdromNominalPerformance &&
3710  performanceRequest->Exceptions != CdromEntirePerformanceList &&
3711  performanceRequest->Exceptions != CdromPerformanceExceptionsOnly)
3712  {
3714  }
3715  else if (performanceRequest->Tolerance != Cdrom10Nominal20Exceptions)
3716  {
3718  }
3719  }
3720  else if (writeSpeedRequest->RequestType == CdromWriteSpeedRequest)
3721  {
3722  // No additional checks here: all remaining fields are ignored
3723  // if RequestType == CdromWriteSpeedRequest.
3724  }
3725  else
3726  {
3728  }
3729  }
3730 
3731  // finally, check output buffer length
3732  if (NT_SUCCESS(status))
3733  {
3734  if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength <
3735  sizeof(CDROM_PERFORMANCE_HEADER))
3736  {
3739  }
3740  else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength >
3741  ((USHORT)-1))
3742  {
3744  }
3745  }
3746 
3747  return status;
3748 }
3749 
3750 
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;
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 
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 {
3874  PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device);
3875  PIRP irp = WdfRequestWdmGetIrp(Request);
3876  PZERO_POWER_ODD_INFO zpoddInfo = deviceExtension->ZeroPowerODDInfo;
3877  PCDB cdb = NULL;
3878  BOOLEAN isSoftEject = FALSE;
3879 
3880 #if DBG
3881  PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request);
3882 #endif
3883 
3884 
3885  PAGED_CODE();
3886 
3887 #if DBG
3888  // SPTI is always processed in sync manner.
3889  NT_ASSERT(requestContext->SyncRequired);
3890 #endif
3891 
3892  if ((zpoddInfo != NULL) &&
3893  (zpoddInfo->LoadingMechanism == LOADING_MECHANISM_TRAY) &&
3894  (zpoddInfo->Load == 0)) // Drawer
3895  {
3896  cdb = RequestGetScsiPassThroughCdb(irp);
3897 
3898  if ((cdb != NULL) &&
3899  (cdb->AsByte[0] == SCSIOP_START_STOP_UNIT) &&
3900  (cdb->START_STOP.LoadEject == 1) &&
3901  (cdb->START_STOP.Start == 0))
3902  {
3903  isSoftEject = TRUE;
3904  }
3905  }
3906 
3907  WdfRequestFormatRequestUsingCurrentType(Request);
3908 
3909  // Special for SPTI, set the MinorFunction.
3910  {
3912 
3913  nextStack->MinorFunction = 1;
3914  }
3915 
3916 
3917  status = RequestSend(deviceExtension,
3918  Request,
3919  deviceExtension->IoTarget,
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
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 {
3965  PMOUNTDEV_UNIQUE_ID uniqueId = NULL;
3966 
3967  *DataLength = 0;
3968 
3969  if (!DeviceExtension->MountedDeviceInterfaceName.Buffer)
3970  {
3972  }
3973  else if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTDEV_UNIQUE_ID))
3974  {
3975  *DataLength = sizeof(MOUNTDEV_UNIQUE_ID);
3977  }
3978 
3979  if (NT_SUCCESS(status))
3980  {
3981  status = WdfRequestRetrieveOutputBuffer(Request,
3982  RequestParameters.Parameters.DeviceIoControl.OutputBufferLength,
3983  &uniqueId,
3984  NULL);
3985  }
3986 
3987  if (NT_SUCCESS(status))
3988  {
3989  RtlZeroMemory(uniqueId, RequestParameters.Parameters.DeviceIoControl.OutputBufferLength);
3990 
3991  uniqueId->UniqueIdLength = DeviceExtension->MountedDeviceInterfaceName.Length;
3992 
3993  if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength <
3994  (sizeof(USHORT) + DeviceExtension->MountedDeviceInterfaceName.Length))
3995  {
3996  *DataLength = sizeof(MOUNTDEV_UNIQUE_ID);
3998  }
3999  }
4000 
4001  if (NT_SUCCESS(status))
4002  {
4003  RtlCopyMemory(uniqueId->UniqueId,
4004  DeviceExtension->MountedDeviceInterfaceName.Buffer,
4005  uniqueId->UniqueIdLength);
4006 
4007  *DataLength = sizeof(USHORT) + uniqueId->UniqueIdLength;
4009  }
4010 
4011  return status;
4012 }
4013 
4014 NTSTATUS
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 {
4042 
4043  *DataLength = 0;
4044 
4045  NT_ASSERT(DeviceExtension->DeviceName.Buffer);
4046 
4047  if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTDEV_NAME))
4048  {
4050  *DataLength = sizeof(MOUNTDEV_NAME);
4051  }
4052 
4053  if (NT_SUCCESS(status))
4054  {
4055  status = WdfRequestRetrieveOutputBuffer(Request,
4056  RequestParameters.Parameters.DeviceIoControl.OutputBufferLength,
4057  &name,
4058  NULL);
4059  }
4060 
4061  if (NT_SUCCESS(status))
4062  {
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  {
4070  *DataLength = sizeof(MOUNTDEV_NAME);
4071  }
4072  }
4073 
4074  if (NT_SUCCESS(status))
4075  {
4076  RtlCopyMemory(name->Name,
4077  DeviceExtension->DeviceName.Buffer,
4078  name->NameLength);
4079 
4081  *DataLength = sizeof(USHORT) + name->NameLength;
4082  }
4083 
4084  return status;
4085 }
4086 
4087 NTSTATUS
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 {
4114 
4115  PMOUNTDEV_SUGGESTED_LINK_NAME suggestedName = NULL;
4116 
4117  WCHAR driveLetterNameBuffer[10] = {0};
4118  RTL_QUERY_REGISTRY_TABLE queryTable[2] = {0};
4119  PWSTR valueName = NULL;
4120  UNICODE_STRING driveLetterName = {0};
4121 
4122  *DataLength = 0;
4123 
4124  if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength <
4126  {
4129  }
4130 
4131  if (NT_SUCCESS(status))
4132  {
4133  valueName = ExAllocatePoolWithTag(PagedPool,
4134  DeviceExtension->DeviceName.Length + sizeof(WCHAR),
4136  if (valueName == NULL)
4137  {
4139  }
4140  }
4141 
4142  if (NT_SUCCESS(status))
4143  {
4144  RtlCopyMemory(valueName,
4145  DeviceExtension->DeviceName.Buffer,
4146  DeviceExtension->DeviceName.Length);
4147  valueName[DeviceExtension->DeviceName.Length/sizeof(WCHAR)] = 0;
4148 
4149  driveLetterName.Buffer = driveLetterNameBuffer;
4150  driveLetterName.MaximumLength = sizeof(driveLetterNameBuffer);
4151  driveLetterName.Length = 0;
4152 
4154  queryTable[0].Name = valueName;
4155  queryTable[0].EntryContext = &driveLetterName;
4157 
4159  L"\\Registry\\Machine\\System\\DISK", // why hard coded?
4160  queryTable, NULL, NULL);
4161  }
4162 
4163  if (NT_SUCCESS(status))
4164  {
4165  if ((driveLetterName.Length == 4) &&
4166  (driveLetterName.Buffer[0] == '%') &&
4167  (driveLetterName.Buffer[1] == ':'))
4168  {
4169  driveLetterName.Buffer[0] = 0xFF;
4170  }
4171  else if ((driveLetterName.Length != 4) ||
4172  (driveLetterName.Buffer[0] < FirstDriveLetter) ||
4173  (driveLetterName.Buffer[0] > LastDriveLetter) ||
4174  (driveLetterName.Buffer[1] != ':'))
4175  {
4177  }
4178  }
4179 
4180  if (NT_SUCCESS(status))
4181  {
4182  status = WdfRequestRetrieveOutputBuffer(Request,
4183  RequestParameters.Parameters.DeviceIoControl.OutputBufferLength,
4184  &suggestedName,
4185  NULL);
4186  }
4187 
4188  if (NT_SUCCESS(status))
4189  {
4190  RtlZeroMemory(suggestedName, RequestParameters.Parameters.DeviceIoControl.OutputBufferLength);
4191  suggestedName->UseOnlyIfThereAreNoOtherLinks = TRUE;
4192  suggestedName->NameLength = 28;
4193 
4195 
4196  if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < *DataLength)
4197  {
4200  }
4201  }
4202 
4203  if (NT_SUCCESS(status))
4204  {
4206  L"\\Registry\\Machine\\System\\DISK",
4207  valueName);
4208 
4209  RtlCopyMemory(suggestedName->Name, L"\\DosDevices\\", 24);
4210  suggestedName->Name[12] = driveLetterName.Buffer[0];
4211  suggestedName->Name[13] = ':';
4212  }
4213 
4214  FREE_POOL(valueName);
4215 
4216  return status;
4217 }
4218 
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 {
4248  VOID* outputBuffer = NULL;
4249 
4250  PAGED_CODE ();
4251 
4252  *DataLength = 0;
4253 
4254  if (DeviceIsPlayActive(DeviceExtension->Device))
4255  {
4257  }
4258 
4259  if (NT_SUCCESS(status))
4260  {
4261  status = WdfRequestRetrieveOutputBuffer(Request,
4262  RequestParameters.Parameters.DeviceIoControl.OutputBufferLength,
4263  &outputBuffer,
4264  NULL);
4265  }
4266 
4267  // handle the request
4268  if (NT_SUCCESS(status))
4269  {
4270  size_t transferSize;
4271  CDB cdb;
4272 
4273  transferSize = min(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, sizeof(CDROM_TOC));
4274 
4275  RtlZeroMemory(outputBuffer, transferSize);
4276 
4277  ScratchBuffer_BeginUse(DeviceExtension);
4278 
4279  RtlZeroMemory(&cdb, sizeof(CDB));
4280  // Set up the CDB
4281  if (RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_LAST_SESSION)
4282  {
4283  // Set format to return first and last session numbers.
4285  }
4286  else
4287  {
4288  // Use MSF addressing
4289  cdb.READ_TOC.Msf = 1;
4290  }
4291 
4292  cdb.READ_TOC.OperationCode = SCSIOP_READ_TOC;
4293  cdb.READ_TOC.AllocationLength[0] = (UCHAR)(transferSize >> 8);
4294  cdb.READ_TOC.AllocationLength[1] = (UCHAR)(transferSize & 0xFF);
4295 
4296  status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, (ULONG)transferSize, TRUE, &cdb, 10);
4297 
4298  if (NT_SUCCESS(status))
4299  {
4300  *DataLength = DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength;
4301  RtlCopyMemory(outputBuffer,
4302  DeviceExtension->ScratchContext.ScratchBuffer,
4303  *DataLength);
4304  }
4305 
4306  ScratchBuffer_EndUse(DeviceExtension);
4307  }
4308 
4309  return status;
4310 }
4311 
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 {
4340  PCDROM_READ_TOC_EX inputBuffer = NULL;
4341  VOID* outputBuffer = NULL;
4342 
4343  PAGED_CODE ();
4344 
4345  *DataLength = 0;
4346 
4347  if (DeviceIsPlayActive(DeviceExtension->Device))
4348  {
4350  }
4351 
4352  if (NT_SUCCESS(status))
4353  {
4354  status = WdfRequestRetrieveInputBuffer(Request,
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;
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 
4412 VOID
4413 GetConfigurationDataConversionTypeAllToTypeOne(
4414  _In_ FEATURE_NUMBER RequestedFeature,
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 
4448 
4449  PAGED_CODE ();
4450 
4451  *DataLength = 0;
4452 
4454  {
4455  // do not have valid data.
4456  return;
4457  }
4458 
4459  // Calculate the length of valid data available in the
4460  // capabilities buffer from the DataLength field
4461  header = (PGET_CONFIGURATION_HEADER) Srb->DataBuffer;
4462  REVERSE_BYTES(&totalLength, header->DataLength);
4463 
4465 
4466  // Make sure the we have enough data in the SRB
4467  totalLength = min(totalLength, Srb->DataTransferLength);
4468 
4469  // If we have received enough data from the device
4470  // check for the given feature.
4471  if (totalLength >= (sizeof(GET_CONFIGURATION_HEADER) + sizeof(FEATURE_HEADER)))
4472  {
4473  // Feature information is present. Verify the feature.
4474  featureHeader = (PFEATURE_HEADER)((PUCHAR)Srb->DataBuffer + sizeof(GET_CONFIGURATION_HEADER));
4475 
4476  thisFeature = (featureHeader->FeatureCode[0] << 8) | (featureHeader->FeatureCode[1]);
4477 
4478  if (thisFeature == RequestedFeature)
4479  {
4480  // Calculate the feature length
4481  featureLength = sizeof(FEATURE_HEADER) + featureHeader->AdditionalLength;
4482  }
4483  }
4484 
4485  // Calculate the total size
4486  totalLength = sizeof(GET_CONFIGURATION_HEADER) + featureLength;
4487 
4488  headerLength = totalLength -
4490 
4491  REVERSE_BYTES(header->DataLength, &headerLength);
4492 
4493  *DataLength = totalLength;
4494 
4495  return;
4496 }
4497 
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,
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 
4546 
4547  PAGED_CODE ();
4548 
4549  if (InputBufferSize < sizeof (GET_CONFIGURATION_HEADER))
4550  {
4551  // do not have valid data.
4552  *DataLength = 0;
4553 
4554  return;
4555  }
4556 
4557  // Calculate the length of valid data available in the
4558  // capabilities buffer from the DataLength field
4560  REVERSE_BYTES(&validLength, header->DataLength);
4561 
4563 
4564  // Make sure we have enough data
4565  validLength = min(validLength, InputBufferSize);
4566 
4567  // Copy the header first
4568  copyLength = min(OutputBufferSize, sizeof (GET_CONFIGURATION_HEADER));
4569 
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 
4596 
4597  shouldCopy = TRUE;
4598  break;
4599 
4601 
4602  if (featureHeader->Current)
4603  {
4604  shouldCopy = TRUE;
4605  }
4606  break;
4607 
4609 
4610  if (featureCode == StartingFeature)
4611  {
4612  shouldCopy = TRUE;
4613  }
4614  break;
4615 
4616  default:
4617 
4618  break;
4619  }
4620  }
4621 
4622  if (shouldCopy != FALSE)
4623  {
4624  copyLength = min(featureLength, bytesRemaining);
4625  copyLength = min(copyLength, OutputBufferSize - transferedLength);
4626 
4627  RtlMoveMemory((PUCHAR) OutputBuffer + transferedLength,
4628  buffer,
4629  copyLength);
4630 
4631  transferedLength += copyLength;
4632  requiredLength += featureLength;
4633  }
4634 
4635  buffer += min(featureLength, bytesRemaining);
4636  bytesRemaining -= min(featureLength, bytesRemaining);
4637  }
4638  }
4639 
4640  // Adjust Data Length field in header
4642  {
4643  headerLength = (ULONG) requiredLength - RTL_SIZEOF_THROUGH_FIELD(GET_CONFIGURATION_HEADER, DataLength);
4644 
4646  REVERSE_BYTES(header->DataLength, &headerLength);
4647  }
4648 
4649  *DataLength = transferedLength;
4650 
4651  return;
4652 }
4653 
4654 
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 {
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  {
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) &&
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) &&
4762  {
4763 
4764  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
4765  "DeviceHandleGetConfiguration: Changing TYPE_ONE Get Config to TYPE_ALL\n"));
4767  }
4768 
4769  status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, (ULONG)transferByteCount, TRUE, &cdb, 12);
4770 
4771  if (NT_SUCCESS(status))
4772  {
4773  if ((inputBuffer->RequestType == SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE) &&
4775  {
4776 
4777  if (DeviceExtension->ScratchContext.ScratchSrb->DataTransferLength < sizeof(GET_CONFIGURATION_HEADER))
4778  {
4779  // Not enough data to calculate the data length.
4780  // So assume feature is not present
4781  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DeviceHandleGetConfiguration: No get config header!\n"));
4782  *DataLength = 0;
4784  }
4785  else
4786  {
4787  //Some CDROM devices do not handle the GET CONFIGURATION commands with
4788  //TYPE ONE request. The command will time out causing a bus reset.
4789  //To avoid this problem we set a device flag during start device if the device
4790  //fails a TYPE ONE request. If this flag is set the TYPE ONE requests will be
4791  //tried as TYPE ALL request and the data will be converted to TYPE ONE format
4792  //in this routine.
4793  GetConfigurationDataConversionTypeAllToTypeOne(inputBuffer->Feature, DeviceExtension->ScratchContext.ScratchSrb, DataLength);
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 
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 {
4864  VOID* outputBuffer = NULL;
4865 
4866  PAGED_CODE ();
4867 
4868  *DataLength = 0;
4869 
4870  status = WdfRequestRetrieveOutputBuffer(Request,
4871  RequestParameters.Parameters.DeviceIoControl.OutputBufferLength,
4872  &outputBuffer,
4873  NULL);
4874 
4875  // Issue ReadCapacity to update device extension
4876  // with information for current media.
4877  if (NT_SUCCESS(status))
4878  {
4879  status = MediaReadCapacity(DeviceExtension->Device);
4880  }
4881 
4882  if (NT_SUCCESS(status))
4883  {
4884  switch(RequestParameters.Parameters.DeviceIoControl.IoControlCode)
4885  {
4887  {
4888  PGET_LENGTH_INFORMATION lengthInfo = (PGET_LENGTH_INFORMATION)outputBuffer;
4889 
4890  lengthInfo->Length = DeviceExtension->PartitionLength;
4892  break;
4893  }
4896  {
4897  PDISK_GEOMETRY geometry = (PDISK_GEOMETRY)outputBuffer;
4898 
4899  *geometry = DeviceExtension->DiskGeometry;
4900  *DataLength = sizeof(DISK_GEOMETRY);
4901  break;
4902  }
4905  {
4906  PDISK_GEOMETRY_EX geometryEx = (PDISK_GEOMETRY_EX)outputBuffer;
4907 
4908  geometryEx->DiskSize = DeviceExtension->PartitionLength;
4909  geometryEx->Geometry = DeviceExtension->DiskGeometry;
4911  break;
4912  }
4914  {
4915  PSTORAGE_READ_CAPACITY readCapacity = (PSTORAGE_READ_CAPACITY)outputBuffer;
4916 
4917  readCapacity->Version = sizeof(STORAGE_READ_CAPACITY);
4918  readCapacity->Size = sizeof(STORAGE_READ_CAPACITY);
4919 
4920  readCapacity->BlockLength = DeviceExtension->DiskGeometry.BytesPerSector;
4921  if (readCapacity->BlockLength > 0)
4922  {
4923  readCapacity->NumberOfBlocks.QuadPart = DeviceExtension->PartitionLength.QuadPart/readCapacity->BlockLength;
4924  }
4925  else
4926  {
4927  readCapacity->NumberOfBlocks.QuadPart = 0;
4928  }
4929 
4930  readCapacity->DiskLength = DeviceExtension->PartitionLength;
4931 
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 
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 {
4974  PCDROM_DATA cdData = &(DeviceExtension->DeviceAdditionalData);
4975  PVERIFY_INFORMATION verifyInfo = NULL;
4976 
4977  PAGED_CODE ();
4978 
4979  *DataLength = 0;
4980 
4981  if (!cdData->Mmc.WriteAllowed)
4982  {
4984  }
4985 
4986  if (NT_SUCCESS(status))
4987  {
4988  status = WdfRequestRetrieveInputBuffer(Request,
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  {
5009  }
5010  else
5011  {
5012  ULONG transferSize = 0;
5013  ULONG timeoutValue = 0;
5014  CDB cdb;
5015  ULONG sectorOffset;
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)&sectorOffset)->Byte3;
5032  cdb.CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&sectorOffset)->Byte2;
5033  cdb.CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&sectorOffset)->Byte1;
5034  cdb.CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&sectorOffset)->Byte0;
5035 
5036  cdb.CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&sectorCount)->Byte1;
5037  cdb.CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&sectorCount)->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 
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 {
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 
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 {
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  {
5182  {
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  {
5201  *DataLength = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry[1]);
5202  RtlZeroMemory(outputBuffer, *DataLength);
5203  break;
5205  *DataLength = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[1]);
5206  RtlZeroMemory(outputBuffer, *DataLength);
5207  break;
5209  *DataLength = sizeof(PARTITION_INFORMATION);
5210  RtlZeroMemory(outputBuffer, *DataLength);
5211  break;
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.
5225  {
5227  layout = (PDRIVE_LAYOUT_INFORMATION)outputBuffer;
5228  layout->PartitionCount = 1;
5229  layout->Signature = 1;
5230  outputBuffer = (PVOID)(layout->PartitionEntry);
5232  }
5234  {
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);
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.
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
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 {
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 
5324  *DataLength = sizeof(STORAGE_DEVICE_NUMBER);
5325  }
5326  }
5327  else
5328  {
5330  *DataLength = sizeof(STORAGE_DEVICE_NUMBER);
5331  }
5332 
5333  return status;
5334 }
5335 
5336 NTSTATUS
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 {
5363 
5364  *DataLength = 0;
5365 
5366  if(RequestParameters.Parameters.DeviceIoControl.OutputBufferLength >=
5367  sizeof(STORAGE_HOTPLUG_INFO))
5368  {
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 
5379  *DataLength = sizeof(STORAGE_HOTPLUG_INFO);
5380  }
5381  }
5382  else
5383  {
5385  *DataLength = sizeof(STORAGE_HOTPLUG_INFO);
5386  }
5387 
5388  return status;
5389 }
5390 
5391 NTSTATUS
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 {
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.
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  {
5442  }
5443 
5444  if (info->MediaRemovable != DeviceExtension->PrivateFdoData->HotplugInfo.MediaRemovable)
5445  {
5447  }
5448 
5449  if (info->MediaHotplug != DeviceExtension->PrivateFdoData->HotplugInfo.MediaHotplug)
5450  {
5452  }
5453 
5454  if (info->WriteCacheEnableOverride != DeviceExtension->PrivateFdoData->HotplugInfo.WriteCacheEnableOverride)
5455  {
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,
5469  }
5470 
5471  return status;
5472 }
5473 
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 {
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  {
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)) {
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))) {
5541  } else if ((eventBuffer->Events &
5544  }
5545  }
5546  }
5547 
5548  }
5549 
5550  if (NT_SUCCESS(status))
5551  {
5552  if (info->MediaChangeDetectionDisableCount != 0)