mirror of
https://github.com/reactos/reactos.git
synced 2024-08-30 23:28:58 +00:00
![Victor Perevertkin](/assets/img/avatar_default.png)
The source code is licensed under MS-PL license, taken from Windows Driver Samples repository (https://github.com/microsoft/Windows-driver-samples/tree/master/storage/class/classpnp/) Synched with commit 88541f70c4273ecd30c8c7c72135bc038a00fd88 The driver is written for Windows 8+, so we compile it with ntoskrnl_vista statically linked and with NTDDI_WIN8 defined CORE-17129
377 lines
9 KiB
C
377 lines
9 KiB
C
/*++
|
|
|
|
Copyright (C) Microsoft Corporation 2010
|
|
|
|
Module Name:
|
|
|
|
srblib.c
|
|
|
|
Abstract:
|
|
|
|
Header for SRB utility functions
|
|
|
|
Environment:
|
|
|
|
kernel mode only
|
|
|
|
Notes:
|
|
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "classp.h"
|
|
|
|
PVOID
|
|
DefaultStorageRequestBlockAllocateRoutine(
|
|
_In_ CLONG ByteSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Default allocation routine.
|
|
|
|
Arguments:
|
|
|
|
ByteSize - SRB size in bytes.
|
|
|
|
Return Value:
|
|
|
|
Pointer to the SRB buffer. NULL if SRB buffer could not be allocated.
|
|
|
|
--*/
|
|
{
|
|
return ExAllocatePoolWithTag(NonPagedPoolNx, ByteSize, '+brs');
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
pInitializeStorageRequestBlock(
|
|
_Inout_bytecount_(ByteSize) PSTORAGE_REQUEST_BLOCK Srb,
|
|
_In_ USHORT AddressType,
|
|
_In_ ULONG ByteSize,
|
|
_In_ ULONG NumSrbExData,
|
|
_In_ va_list ap
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize a STORAGE_REQUEST_BLOCK.
|
|
|
|
Arguments:
|
|
|
|
Srb - Pointer to STORAGE_REQUEST_BLOCK to initialize.
|
|
|
|
AddressType - Storage address type.
|
|
|
|
ByteSize - STORAGE_REQUEST_BLOCK size in bytes.
|
|
|
|
NumSrbExData - Number of SRB extended data.
|
|
|
|
ap - Variable argument list matching the SRB extended data in the
|
|
STORAGE_REQUEST_BLOCK.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PSTOR_ADDRESS address;
|
|
PSRBEX_DATA srbExData;
|
|
ULONG offset;
|
|
ULONG length = (ULONG)-1;
|
|
SRBEXDATATYPE type;
|
|
ULONG srbExDataLength = (ULONG)-1;
|
|
ULONG varLength;
|
|
ULONG i;
|
|
|
|
if (ByteSize < sizeof(STORAGE_REQUEST_BLOCK)) {
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
RtlZeroMemory(Srb, ByteSize);
|
|
|
|
Srb->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature);
|
|
Srb->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
|
|
Srb->Signature = SRB_SIGNATURE;
|
|
Srb->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
|
|
Srb->SrbLength = ByteSize;
|
|
Srb->NumSrbExData = NumSrbExData;
|
|
|
|
offset = sizeof(STORAGE_REQUEST_BLOCK);
|
|
if (NumSrbExData > 0) {
|
|
offset += ((NumSrbExData - 1) * sizeof(ULONG));
|
|
|
|
// Ensure offset is pointer type aligned
|
|
if (offset % sizeof(PVOID)) {
|
|
offset += (sizeof(PVOID) - (offset % sizeof(PVOID)));
|
|
}
|
|
}
|
|
Srb->AddressOffset = offset;
|
|
|
|
if (AddressType == STORAGE_ADDRESS_TYPE_BTL8)
|
|
{
|
|
if ((ByteSize < offset) ||
|
|
(ByteSize < (offset + sizeof(STOR_ADDR_BTL8)))) {
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
address = (PSTOR_ADDRESS)((PUCHAR)Srb + offset);
|
|
address->Type = STOR_ADDRESS_TYPE_BTL8;
|
|
address->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
|
|
offset += sizeof(STOR_ADDR_BTL8);
|
|
} else
|
|
{
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
for (i = 0; i < NumSrbExData && status == STATUS_SUCCESS; i++)
|
|
{
|
|
if (ByteSize <= offset) {
|
|
status = STATUS_BUFFER_OVERFLOW;
|
|
break;
|
|
}
|
|
srbExData = (PSRBEX_DATA)((PUCHAR)Srb + offset);
|
|
Srb->SrbExDataOffset[i] = offset;
|
|
|
|
type = va_arg(ap, SRBEXDATATYPE);
|
|
|
|
switch (type)
|
|
{
|
|
case SrbExDataTypeBidirectional:
|
|
length = sizeof(SRBEX_DATA_BIDIRECTIONAL);
|
|
srbExDataLength = SRBEX_DATA_BIDIRECTIONAL_LENGTH;
|
|
break;
|
|
case SrbExDataTypeScsiCdb16:
|
|
length = sizeof(SRBEX_DATA_SCSI_CDB16);
|
|
srbExDataLength = SRBEX_DATA_SCSI_CDB16_LENGTH;
|
|
break;
|
|
case SrbExDataTypeScsiCdb32:
|
|
length = sizeof(SRBEX_DATA_SCSI_CDB32);
|
|
srbExDataLength = SRBEX_DATA_SCSI_CDB32_LENGTH;
|
|
break;
|
|
case SrbExDataTypeScsiCdbVar:
|
|
varLength = va_arg(ap, ULONG);
|
|
length = sizeof(SRBEX_DATA_SCSI_CDB_VAR) + varLength;
|
|
srbExDataLength = SRBEX_DATA_SCSI_CDB_VAR_LENGTH_MIN + varLength;
|
|
break;
|
|
case SrbExDataTypeWmi:
|
|
length = sizeof(SRBEX_DATA_WMI);
|
|
srbExDataLength = SRBEX_DATA_WMI_LENGTH;
|
|
break;
|
|
case SrbExDataTypePower:
|
|
length = sizeof(SRBEX_DATA_POWER);
|
|
srbExDataLength = SRBEX_DATA_POWER_LENGTH;
|
|
break;
|
|
case SrbExDataTypePnP:
|
|
length = sizeof(SRBEX_DATA_PNP);
|
|
srbExDataLength = SRBEX_DATA_PNP_LENGTH;
|
|
break;
|
|
case SrbExDataTypeIoInfo:
|
|
length = sizeof(SRBEX_DATA_IO_INFO);
|
|
srbExDataLength = SRBEX_DATA_IO_INFO_LENGTH;
|
|
break;
|
|
default:
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
if (status == STATUS_SUCCESS)
|
|
{
|
|
NT_ASSERT(length != (ULONG)-1);
|
|
|
|
if (ByteSize < (offset + length)) {
|
|
status = STATUS_BUFFER_OVERFLOW;
|
|
break;
|
|
}
|
|
|
|
NT_ASSERT(srbExDataLength != (ULONG)-1);
|
|
|
|
srbExData->Type = type;
|
|
srbExData->Length = srbExDataLength;
|
|
offset += length;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
InitializeStorageRequestBlock(
|
|
_Inout_bytecount_(ByteSize) PSTORAGE_REQUEST_BLOCK Srb,
|
|
_In_ USHORT AddressType,
|
|
_In_ ULONG ByteSize,
|
|
_In_ ULONG NumSrbExData,
|
|
...
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize an extended SRB.
|
|
|
|
Arguments:
|
|
|
|
Srb - Pointer to SRB buffer to initialize.
|
|
|
|
AddressType - Storage address type.
|
|
|
|
ByteSize - STORAGE_REQUEST_BLOCK size in bytes.
|
|
|
|
NumSrbExData - Number of SRB extended data.
|
|
|
|
... - Variable argument list matching the SRB extended data in the
|
|
STORAGE_REQUEST_BLOCK.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
va_list ap;
|
|
va_start(ap, NumSrbExData);
|
|
status = pInitializeStorageRequestBlock(Srb, AddressType, ByteSize, NumSrbExData, ap);
|
|
va_end(ap);
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
CreateStorageRequestBlock(
|
|
_Inout_ PSTORAGE_REQUEST_BLOCK *Srb,
|
|
_In_ USHORT AddressType,
|
|
_In_opt_ PSRB_ALLOCATE_ROUTINE AllocateRoutine,
|
|
_Inout_opt_ ULONG *ByteSize,
|
|
_In_ ULONG NumSrbExData,
|
|
...
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create an extended SRB.
|
|
|
|
Arguments:
|
|
|
|
Srb - Pointer to buffer to store SRB pointer.
|
|
|
|
AddressType - Storage address type.
|
|
|
|
AllocateRoutine - Buffer allocation function (optional).
|
|
|
|
ByteSize - Pointer to ULONG to store size of SRB in bytes (optional).
|
|
|
|
NumSrbExData - Number of SRB extended data.
|
|
|
|
... - Variable argument list matching the SRB extended data in the
|
|
STORAGE_REQUEST_BLOCK.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
ULONG sizeNeeded = 0;
|
|
va_list ap;
|
|
ULONG i;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
// Ensure SrbExData offsets are pointer type aligned
|
|
sizeNeeded = sizeof(STORAGE_REQUEST_BLOCK);
|
|
if (NumSrbExData > 0) {
|
|
sizeNeeded += ((NumSrbExData - 1) * sizeof(ULONG));
|
|
if (sizeNeeded % sizeof(PVOID)) {
|
|
sizeNeeded += (sizeof(PVOID) - (sizeNeeded % sizeof(PVOID)));
|
|
}
|
|
}
|
|
|
|
if (AddressType == STORAGE_ADDRESS_TYPE_BTL8)
|
|
{
|
|
sizeNeeded += sizeof(STOR_ADDR_BTL8);
|
|
} else
|
|
{
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
va_start(ap, NumSrbExData);
|
|
|
|
for (i = 0; i < NumSrbExData && status == STATUS_SUCCESS; i++)
|
|
{
|
|
switch (va_arg(ap, SRBEXDATATYPE))
|
|
{
|
|
case SrbExDataTypeBidirectional:
|
|
sizeNeeded += sizeof(SRBEX_DATA_BIDIRECTIONAL);
|
|
break;
|
|
case SrbExDataTypeScsiCdb16:
|
|
sizeNeeded += sizeof(SRBEX_DATA_SCSI_CDB16);
|
|
break;
|
|
case SrbExDataTypeScsiCdb32:
|
|
sizeNeeded += sizeof(SRBEX_DATA_SCSI_CDB32);
|
|
break;
|
|
case SrbExDataTypeScsiCdbVar:
|
|
sizeNeeded += sizeof(SRBEX_DATA_SCSI_CDB_VAR) + va_arg(ap, ULONG);
|
|
break;
|
|
case SrbExDataTypeWmi:
|
|
sizeNeeded += sizeof(SRBEX_DATA_WMI);
|
|
break;
|
|
case SrbExDataTypePower:
|
|
sizeNeeded += sizeof(SRBEX_DATA_POWER);
|
|
break;
|
|
case SrbExDataTypePnP:
|
|
sizeNeeded += sizeof(SRBEX_DATA_PNP);
|
|
break;
|
|
case SrbExDataTypeIoInfo:
|
|
sizeNeeded += sizeof(SRBEX_DATA_IO_INFO);
|
|
break;
|
|
default:
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
}
|
|
va_end(ap);
|
|
|
|
if (status == STATUS_SUCCESS)
|
|
{
|
|
if (AllocateRoutine)
|
|
{
|
|
*Srb = AllocateRoutine(sizeNeeded);
|
|
if (*Srb == NULL)
|
|
{
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
|
|
if (ByteSize != NULL)
|
|
{
|
|
*ByteSize = sizeNeeded;
|
|
}
|
|
|
|
if (*Srb)
|
|
{
|
|
va_start(ap, NumSrbExData);
|
|
#ifdef _MSC_VER
|
|
#pragma prefast(suppress:26015, "pInitializeStorageRequestBlock will set the SrbLength field")
|
|
#endif
|
|
status = pInitializeStorageRequestBlock(*Srb, AddressType, sizeNeeded, NumSrbExData, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
|