📄 ioctl.c
字号:
/*--
Copyright (C) Microsoft Corporation, 1999 - 1999
Module Name:
ioctl.c
Abstract:
The CDROM class driver tranlates IRPs to SRBs with embedded CDBs
and sends them to its devices through the port driver.
Environment:
kernel mode only
Notes:
SCSI Tape, CDRom and Disk class drivers share common routines
that can be found in the CLASS directory (..\ntos\dd\class).
Revision History:
--*/
#include "stddef.h"
#include "string.h"
#include "ntddk.h"
#include "ntddcdvd.h"
#include "classpnp.h"
#include "initguid.h"
#include "ntddstor.h"
#include "cdrom.h"
#include "ioctl.tmh"
#if DBG
PUCHAR READ_DVD_STRUCTURE_FORMAT_STRINGS[DvdMaxDescriptor+1] = {
"Physical",
"Copyright",
"DiskKey",
"BCA",
"Manufacturer",
"Unknown"
};
#endif // DBG
#define DEFAULT_CDROM_SECTORS_PER_TRACK 32
#define DEFAULT_TRACKS_PER_CYLINDER 64
NTSTATUS
CdRomDeviceControlDispatch(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This is the NT device control handler for CDROMs.
Arguments:
DeviceObject - for this CDROM
Irp - IO Request packet
Return Value:
NTSTATUS
--*/
{
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
PIO_STACK_LOCATION nextStack;
PCDROM_DATA cdData = (PCDROM_DATA)(commonExtension->DriverData);
BOOLEAN use6Byte = TEST_FLAG(cdData->XAFlags, XA_USE_6_BYTE);
SCSI_REQUEST_BLOCK srb = {0};
PCDB cdb = (PCDB)srb.Cdb;
PVOID outputBuffer;
ULONG bytesTransferred = 0;
NTSTATUS status;
NTSTATUS status2;
KIRQL irql;
ULONG ioctlCode;
ULONG baseCode;
ULONG functionCode;
RetryControl:
//
// Zero the SRB on stack.
//
RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
Irp->IoStatus.Information = 0;
//
// if this is a class driver ioctl then we need to change the base code
// to IOCTL_CDROM_BASE so that the switch statement can handle it.
//
// WARNING - currently the scsi class ioctl function codes are between
// 0x200 & 0x300. this routine depends on that fact
//
ioctlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
baseCode = ioctlCode >> 16;
functionCode = (ioctlCode & (~0xffffc003)) >> 2;
TraceLog((CdromDebugTrace,
"CdRomDeviceControl: Ioctl Code = %lx, Base Code = %lx,"
" Function Code = %lx\n",
ioctlCode,
baseCode,
functionCode
));
if((functionCode >= 0x200) && (functionCode <= 0x300)) {
ioctlCode = (ioctlCode & 0x0000ffff) | CTL_CODE(IOCTL_CDROM_BASE, 0, 0, 0);
TraceLog((CdromDebugTrace,
"CdRomDeviceControl: Class Code - new ioctl code is %lx\n",
ioctlCode));
irpStack->Parameters.DeviceIoControl.IoControlCode = ioctlCode;
}
switch (ioctlCode) {
case IOCTL_STORAGE_GET_MEDIA_TYPES_EX: {
PGET_MEDIA_TYPES mediaTypes = Irp->AssociatedIrp.SystemBuffer;
PDEVICE_MEDIA_INFO mediaInfo = &mediaTypes->MediaInfo[0];
ULONG sizeNeeded;
sizeNeeded = sizeof(GET_MEDIA_TYPES);
//
// IsMmc is static...
//
if (cdData->Mmc.IsMmc) {
sizeNeeded += sizeof(DEVICE_MEDIA_INFO) * 1; // return two media types
}
//
// Ensure that buffer is large enough.
//
if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
sizeNeeded) {
//
// Buffer too small.
//
Irp->IoStatus.Information = sizeNeeded;
status = STATUS_BUFFER_TOO_SMALL;
break;
}
RtlZeroMemory(Irp->AssociatedIrp.SystemBuffer, sizeNeeded);
//
// ISSUE-2000/5/11-henrygab - need to update GET_MEDIA_TYPES_EX
//
mediaTypes->DeviceType = CdRomGetDeviceType(DeviceObject);
mediaTypes->MediaInfoCount = 1;
mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = CD_ROM;
mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = 1;
mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_READ_ONLY;
mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart = fdoExtension->DiskGeometry.Cylinders.QuadPart;
mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder = fdoExtension->DiskGeometry.TracksPerCylinder;
mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack = fdoExtension->DiskGeometry.SectorsPerTrack;
mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = fdoExtension->DiskGeometry.BytesPerSector;
if (cdData->Mmc.IsMmc) {
//
// also report a removable disk
//
mediaTypes->MediaInfoCount += 1;
mediaInfo++;
mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = RemovableMedia;
mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = 1;
mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_READ_WRITE;
mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart = fdoExtension->DiskGeometry.Cylinders.QuadPart;
mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder = fdoExtension->DiskGeometry.TracksPerCylinder;
mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack = fdoExtension->DiskGeometry.SectorsPerTrack;
mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = fdoExtension->DiskGeometry.BytesPerSector;
mediaInfo--;
}
//
// Status will either be success, if media is present, or no media.
// It would be optimal to base from density code and medium type, but not all devices
// have values for these fields.
//
//
// Send a TUR to determine if media is present.
//
srb.CdbLength = 6;
cdb = (PCDB)srb.Cdb;
cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
//
// Set timeout value.
//
srb.TimeOutValue = fdoExtension->TimeOutValue;
status = ClassSendSrbSynchronous(DeviceObject,
&srb,
NULL,
0,
FALSE);
TraceLog((CdromDebugWarning,
"CdRomDeviceControl: GET_MEDIA_TYPES status of TUR - %lx\n",
status));
if (NT_SUCCESS(status)) {
//
// set the disk's media as current if we can write to it.
//
if (cdData->Mmc.IsMmc && cdData->Mmc.WriteAllowed) {
mediaInfo++;
SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics,
MEDIA_CURRENTLY_MOUNTED);
mediaInfo--;
} else {
SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics,
MEDIA_CURRENTLY_MOUNTED);
}
}
Irp->IoStatus.Information = sizeNeeded;
status = STATUS_SUCCESS;
break;
}
case IOCTL_CDROM_RAW_READ: {
LARGE_INTEGER startingOffset = {0};
ULONGLONG transferBytes;
ULONGLONG endOffset;
ULONGLONG mdlBytes;
ULONG startingSector;
RAW_READ_INFO rawReadInfo;
//
// Ensure that XA reads are supported.
//
if (TEST_FLAG(cdData->XAFlags, XA_NOT_SUPPORTED)) {
TraceLog((CdromDebugWarning,
"CdRomDeviceControl: XA Reads not supported. Flags (%x)\n",
cdData->XAFlags));
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
//
// Check that ending sector is on disc and buffers are there and of
// correct size.
//
if (!irpStack->Parameters.DeviceIoControl.Type3InputBuffer){
/*
* This is a call from user space. This is the only time that we need to validate parameters.
* Validate the input and get the input buffer into Type3InputBuffer
* so the rest of the code will be uniform.
*/
if (Irp->AssociatedIrp.SystemBuffer){
irpStack->Parameters.DeviceIoControl.Type3InputBuffer = Irp->AssociatedIrp.SystemBuffer;
if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(RAW_READ_INFO)){
status = STATUS_BUFFER_TOO_SMALL;
break;
}
}
else {
status = STATUS_INVALID_PARAMETER;
break;
}
}
/*
* Since this ioctl is METHOD_OUT_DIRECT, we need to copy away the input buffer before interpreting it.
* This prevents a malicious app from messing with the input buffer while we are interpreting it.
*/
rawReadInfo = *(PRAW_READ_INFO)irpStack->Parameters.DeviceIoControl.Type3InputBuffer;
startingOffset.QuadPart = rawReadInfo.DiskOffset.QuadPart;
startingSector = (ULONG)(rawReadInfo.DiskOffset.QuadPart >> fdoExtension->SectorShift);
transferBytes = (ULONGLONG)rawReadInfo.SectorCount * RAW_SECTOR_SIZE;
endOffset = (ULONGLONG)rawReadInfo.SectorCount * COOKED_SECTOR_SIZE;
endOffset += startingOffset.QuadPart;
//
// check for overflows....
//
if (rawReadInfo.SectorCount == 0) {
TraceLog((CdromDebugWarning,
"CdRomDeviceControl: Invalid I/O parameters for XA "
"Read (zero sectors requested)\n"));
status = STATUS_INVALID_PARAMETER;
break;
}
if (transferBytes < (ULONGLONG)(rawReadInfo.SectorCount)) {
TraceLog((CdromDebugWarning,
"CdRomDeviceControl: Invalid I/O parameters for XA "
"Read (TransferBytes Overflow)\n"));
status = STATUS_INVALID_PARAMETER;
break;
}
if (endOffset < (ULONGLONG)startingOffset.QuadPart) {
TraceLog((CdromDebugWarning,
"CdRomDeviceControl: Invalid I/O parameters for XA "
"Read (EndingOffset Overflow)\n"));
status = STATUS_INVALID_PARAMETER;
break;
}
if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
transferBytes) {
TraceLog((CdromDebugWarning,
"CdRomDeviceControl: Invalid I/O parameters for XA "
"Read (Bad buffer size)\n"));
status = STATUS_INVALID_PARAMETER;
break;
}
if (endOffset > (ULONGLONG)commonExtension->PartitionLength.QuadPart) {
TraceLog((CdromDebugWarning,
"CdRomDeviceControl: Invalid I/O parameters for XA "
"Read (Request Out of Bounds)\n"));
status = STATUS_INVALID_PARAMETER;
break;
}
//
// cannot validate the MdlAddress, since it is not included in any
// other location per the DDK and file system calls.
//
//
// validate the mdl describes at least the number of bytes
// requested from us.
//
mdlBytes = (ULONGLONG)MmGetMdlByteCount(Irp->MdlAddress);
if (mdlBytes < transferBytes) {
TraceLog((CdromDebugWarning,
"CdRomDeviceControl: Invalid MDL %s, Irp %p\n",
"size (5)", Irp));
status = STATUS_INVALID_PARAMETER;
break;
}
//
// check the buffer for alignment
// This is important for x86 as some busses (ie ATAPI)
// require word-aligned buffers.
//
if ( ((ULONG_PTR)MmGetMdlVirtualAddress(Irp->MdlAddress)) &
fdoExtension->AdapterDescriptor->AlignmentMask
)
{
TraceLog((CdromDebugWarning,
"CdRomDeviceControl: Invalid I/O parameters for "
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -