Я хочу поделиться устройством CDROM по сети.
На стороне клиента я создаю корневое перечисляемое устройство (scsi bus). На стороне сервера (где находится устройство cdrom) я заменяю FDO стека устройств своим (другими словами — cdrom.sys заменяется другим драйвером).
Запросы перенаправляются с клиента на сервер с помощью оконных сокетов.
Формат данных, передаваемых по сети (от клиента к серверу): USER_HEADER, USER_SCSI_REQUEST_BLOCK, [data to be transferred to device]
Формат данных, передаваемых по сети (от сервера к клиенту):
USER_HEADER, USER_SCSI_REQUEST_BLOCK, [data to be transferred from device / sense data]
Структуры определены следующим образом:
struct USER_HEADER
{
ULONG Id;
ULONG Length;
ULONG MajorFunction;
ULONG MinorFunction;
ULONG IoControlCode;
ULONG InputBufferLength;
ULONG OutputBufferLength;
NTSTATUS Status;
ULONG Information;
};
struct USER_SCSI_REQUEST_BLOCK
{
UCHAR Function;
UCHAR SrbStatus;
UCHAR ScsiStatus;
UCHAR PathId;
UCHAR TargetId;
UCHAR Lun;
UCHAR QueueTag;
UCHAR QueueAction;
UCHAR CdbLength;
UCHAR SenseInfoBufferLength;
ULONG SrbFlags;
ULONG DataTransferLength;
ULONG TimeOutValue;
ULONG QueueSortKey;
UCHAR Cdb[16];
};
Код на стороне клиента для упаковки и распаковки запросов, отправленных с cdrom.sys:
PVOID GetBuffer(MDL *pSourceMdl, MDL *pTargetMdl, PVOID pBuffer, ULONG Length, BOOLEAN *pUnmap)
{
PVOID pBuffer2;
if (pSourceMdl->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA | MDL_SOURCE_IS_NONPAGED_POOL))
{
pBuffer2 = (UCHAR*)pSourceMdl->MappedSystemVa + ((UCHAR*)pBuffer - ((UCHAR*)pSourceMdl->StartVa + pSourceMdl->ByteOffset));
*pUnmap = FALSE;
}
else
{
IoBuildPartialMdl(pSourceMdl, pTargetMdl, pBuffer, Length);
pBuffer2 = MmMapLockedPagesSpecifyCache(pTargetMdl, KernelMode, MmCached, NULL, FALSE, NormalPagePriority);
*pUnmap = TRUE;
}
return pBuffer2;
}
void PackRequest(IRP *pIrp, USER_HEADER *pUserHeader, STORAGE_EXTENSION *pStorageExtension)
{
BOOLEAN Unmap;
PVOID pBuffer;
IO_STACK_LOCATION *pStack;
USER_SCSI_REQUEST_BLOCK *pUserSrb;
SCSI_REQUEST_BLOCK *pSrb;
pStack = IoGetCurrentIrpStackLocation(pIrp);
pIrp->Tail.Overlay.DriverContext[0] = (PVOID)pStorageExtension->Id;
pUserHeader->Id = pStorageExtension->Id;
++pStorageExtension->Id;
pUserHeader->Status = 0;
pUserHeader->Information = 0;
pUserHeader->MajorFunction = pStack->MajorFunction;
pUserHeader->MinorFunction = pStack->MinorFunction;
if (pStack->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)
{
pUserHeader->IoControlCode = 0;
pUserHeader->InputBufferLength = 0;
pUserHeader->OutputBufferLength = 0;
pUserHeader->Length = sizeof(USER_HEADER) + sizeof(USER_SCSI_REQUEST_BLOCK);
pUserSrb = (USER_SCSI_REQUEST_BLOCK*)((UCHAR*)pUserHeader + sizeof(USER_HEADER));
pSrb = pStack->Parameters.Scsi.Srb;
pUserSrb->Function = pSrb->Function;
pUserSrb->SrbStatus = pSrb->SrbStatus;
pUserSrb->ScsiStatus = pSrb->ScsiStatus;
pUserSrb->PathId = pSrb->PathId;
pUserSrb->TargetId = pSrb->TargetId;
pUserSrb->Lun = pSrb->Lun;
pUserSrb->QueueTag = pSrb->QueueTag;
pUserSrb->QueueAction = pSrb->QueueAction;
pUserSrb->CdbLength = pSrb->CdbLength;
pUserSrb->SenseInfoBufferLength = pSrb->SenseInfoBufferLength;
pUserSrb->SrbFlags = pSrb->SrbFlags;
pUserSrb->DataTransferLength = pSrb->DataTransferLength;
pUserSrb->TimeOutValue = pSrb->TimeOutValue;
if ((pSrb->DataTransferLength) && (pSrb->SrbFlags & SRB_FLAGS_DATA_OUT))
{
pBuffer = GetBuffer(pIrp->MdlAddress, pStorageExtension->pMdl, pSrb->DataBuffer, pSrb->DataTransferLength, &Unmap);
memcpy((UCHAR*)pUserSrb + sizeof(USER_SCSI_REQUEST_BLOCK), pBuffer, pSrb->DataTransferLength);
if (Unmap) MmUnmapLockedPages(pBuffer, pStorageExtension->pMdl);
pUserHeader->Length += pSrb->DataTransferLength;
}
pUserSrb->QueueSortKey = pSrb->QueueSortKey;
memcpy(pUserSrb->Cdb, pSrb->Cdb, sizeof(pSrb->Cdb));
}
else
{
pUserHeader->IoControlCode = pStack->Parameters.DeviceIoControl.IoControlCode;
pUserHeader->InputBufferLength = pStack->Parameters.DeviceIoControl.InputBufferLength;
pUserHeader->OutputBufferLength = pStack->Parameters.DeviceIoControl.OutputBufferLength;
pUserHeader->Length = sizeof(USER_HEADER);
if ((pUserHeader->IoControlCode == IOCTL_STORAGE_QUERY_PROPERTY) ||
(pUserHeader->IoControlCode == IOCTL_STORAGE_ENABLE_IDLE_POWER))
{
pUserHeader->Length += pUserHeader->InputBufferLength;
memcpy((UCHAR*)pUserHeader + sizeof(USER_HEADER), pIrp->AssociatedIrp.SystemBuffer, pUserHeader->InputBufferLength);
}
else if ((pUserHeader->IoControlCode != IOCTL_STORAGE_POWER_ACTIVE) &&
(pUserHeader->IoControlCode != IOCTL_SCSI_GET_ADDRESS))
{
__debugbreak();
}
}
}
void UnpackRequest(USER_HEADER *pUserHeader, IRP *pIrp, STORAGE_EXTENSION *pStorageExtension)
{
BOOLEAN Unmap;
PVOID pBuffer;
IO_STACK_LOCATION *pStack;
USER_SCSI_REQUEST_BLOCK *pUserSrb;
SCSI_REQUEST_BLOCK *pSrb;
pStack = IoGetCurrentIrpStackLocation(pIrp);
if (pUserHeader->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)
{
pUserSrb = (USER_SCSI_REQUEST_BLOCK*)((UCHAR*)pUserHeader + sizeof(USER_HEADER));
pSrb = pStack->Parameters.Scsi.Srb;
pSrb->SrbStatus = pUserSrb->SrbStatus;
pSrb->ScsiStatus = pUserSrb->ScsiStatus;
pSrb->SenseInfoBufferLength = pUserSrb->SenseInfoBufferLength;
pSrb->DataTransferLength = pUserSrb->DataTransferLength;
if (NT_SUCCESS(pUserHeader->Status))
{
if ((pUserSrb->DataTransferLength) && (pUserSrb->SrbFlags & SRB_FLAGS_DATA_IN))
{
pBuffer = GetBuffer(pIrp->MdlAddress, pStorageExtension->pMdl, pSrb->DataBuffer, pUserSrb->DataTransferLength, &Unmap);
memcpy(pBuffer, (UCHAR*)pUserSrb + sizeof(USER_SCSI_REQUEST_BLOCK), pUserSrb->DataTransferLength);
if (Unmap) MmUnmapLockedPages(pBuffer, pStorageExtension->pMdl);
}
else
{
if (pUserSrb->Function == SRB_FUNCTION_CLAIM_DEVICE) pSrb->DataBuffer = pStack->DeviceObject;
}
}
else
{
if ((pUserSrb->SenseInfoBufferLength) && (pUserSrb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID))
{
memcpy(pSrb->SenseInfoBuffer, (UCHAR*)pUserSrb + sizeof(USER_SCSI_REQUEST_BLOCK), pUserSrb->SenseInfoBufferLength);
}
}
}
else
{
if (NT_SUCCESS(pUserHeader->Status))
{
if ((pUserHeader->IoControlCode == IOCTL_SCSI_GET_ADDRESS) ||
(pUserHeader->IoControlCode == IOCTL_STORAGE_QUERY_PROPERTY))
{
memcpy(pIrp->AssociatedIrp.SystemBuffer, (UCHAR*)pUserHeader + sizeof(USER_HEADER), pUserHeader->Information);
}
}
}
}
Код на стороне сервера для распределения запроса и процедуры завершения ввода-вывода:
NTSTATUS AllocateRequest(DEVICE_EXTENSION *pDeviceExtension, IRP *pIrp, IRP **ppIrp2)
{
IRP *pIrp2;
PVOID pBuffer;
NTSTATUS Status;
IO_STACK_LOCATION *pStack;
SCSI_REQUEST_BLOCK *pSrb;
USER_SCSI_REQUEST_BLOCK *pUserSrb;
DEVICE_OBJECT *pDeviceObject;
USER_HEADER *pUserHeader;
pUserHeader = (USER_HEADER*)MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);
pDeviceObject = pDeviceExtension->pLowerDeviceObject;
pIrp2 = IoAllocateIrp(pDeviceObject->StackSize, FALSE);
if (pIrp2)
{
pStack = IoGetNextIrpStackLocation(pIrp2);
pStack->DeviceObject = pDeviceObject;
pIrp2->Tail.Overlay.Thread = PsGetCurrentThread();
pStack->MajorFunction = pUserHeader->MajorFunction;
pStack->MinorFunction = pUserHeader->MinorFunction;
if (pUserHeader->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)
{
pUserSrb = (USER_SCSI_REQUEST_BLOCK*)((UCHAR*)pUserHeader + sizeof(USER_HEADER));
pSrb = (SCSI_REQUEST_BLOCK*)((UCHAR*)pUserSrb + (sizeof(USER_SCSI_REQUEST_BLOCK) + pUserSrb->DataTransferLength + pUserSrb->SenseInfoBufferLength));
pSrb->Length = sizeof(SCSI_REQUEST_BLOCK);
pSrb->Function = pUserSrb->Function;
pSrb->SrbStatus = pUserSrb->SrbStatus;
pSrb->ScsiStatus = pUserSrb->ScsiStatus;
pSrb->PathId = pUserSrb->PathId;
pSrb->TargetId = pUserSrb->TargetId;
pSrb->Lun = pUserSrb->Lun;
pSrb->QueueTag = pUserSrb->QueueTag;
pSrb->QueueAction = pUserSrb->QueueAction;
pSrb->CdbLength = pUserSrb->CdbLength;
pSrb->SenseInfoBufferLength = pUserSrb->SenseInfoBufferLength;
pSrb->SrbFlags = pUserSrb->SrbFlags;
pSrb->DataTransferLength = pUserSrb->DataTransferLength;
pSrb->TimeOutValue = pUserSrb->TimeOutValue;
if (pUserSrb->DataTransferLength)
{
pSrb->DataBuffer = (UCHAR*)pIrp->MdlAddress->StartVa + pIrp->MdlAddress->ByteOffset + (sizeof(USER_HEADER) + sizeof(USER_SCSI_REQUEST_BLOCK));
IoBuildPartialMdl(pIrp->MdlAddress, pDeviceExtension->pMdl, pSrb->DataBuffer, pUserSrb->DataTransferLength);
pIrp2->MdlAddress = pDeviceExtension->pMdl;
}
else pSrb->DataBuffer = NULL;
if (pUserSrb->SenseInfoBufferLength)
{
pSrb->SenseInfoBuffer = (UCHAR*)pUserSrb + (sizeof(USER_SCSI_REQUEST_BLOCK) + pUserSrb->DataTransferLength);
}
else pSrb->SenseInfoBuffer = NULL;
pSrb->NextSrb = NULL;
pSrb->OriginalRequest = pIrp2;
pSrb->SrbExtension = NULL;
pSrb->QueueSortKey = pUserSrb->QueueSortKey;
memcpy(pSrb->Cdb, pUserSrb->Cdb, sizeof(pSrb->Cdb));
pStack->Parameters.Scsi.Srb = pSrb;
}
else
{
pStack->Parameters.DeviceIoControl.IoControlCode = pUserHeader->IoControlCode;
pBuffer = (UCHAR*)pUserHeader + sizeof(USER_HEADER);
if (pUserHeader->IoControlCode == IOCTL_SCSI_GET_ADDRESS)
{
pStack->Parameters.DeviceIoControl.OutputBufferLength = pUserHeader->OutputBufferLength;
pIrp2->AssociatedIrp.SystemBuffer = pBuffer;
}
else if (pUserHeader->IoControlCode == IOCTL_STORAGE_QUERY_PROPERTY)
{
pStack->Parameters.DeviceIoControl.InputBufferLength = pUserHeader->InputBufferLength;
pStack->Parameters.DeviceIoControl.OutputBufferLength = pUserHeader->OutputBufferLength;
pIrp2->AssociatedIrp.SystemBuffer = pBuffer;
}
else if (pUserHeader->IoControlCode == IOCTL_STORAGE_ENABLE_IDLE_POWER)
{
pStack->Parameters.DeviceIoControl.InputBufferLength = pUserHeader->InputBufferLength;
pIrp2->AssociatedIrp.SystemBuffer = pBuffer;
}
}
*ppIrp2 = pIrp2;
Status = STATUS_SUCCESS;
}
else Status = STATUS_INSUFFICIENT_RESOURCES;
return Status;
}
NTSTATUS IoCompletionRoutine3(DEVICE_OBJECT *pDeviceObject, IRP *pIrp2, void *pContext)
{
IRP *pIrp;
USER_HEADER *pUserHeader;
DEVICE_EXTENSION *pDeviceExtension;
USER_SCSI_REQUEST_BLOCK *pUserSrb;
SCSI_REQUEST_BLOCK *pSrb;
pDeviceExtension = (DEVICE_EXTENSION*)pIrp2->Tail.Overlay.DriverContext[0];
pIrp = (IRP*)pIrp2->Tail.Overlay.DriverContext[1];
pUserHeader = (USER_HEADER*)MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);
pUserHeader->Status = pIrp2->IoStatus.Status;
pUserHeader->Information = pIrp2->IoStatus.Information;
if (pUserHeader->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)
{
pUserSrb = (USER_SCSI_REQUEST_BLOCK*)((UCHAR*)pUserHeader + sizeof(USER_HEADER));
pSrb = (SCSI_REQUEST_BLOCK*)((UCHAR*)pUserSrb + (sizeof(USER_SCSI_REQUEST_BLOCK) + pUserSrb->DataTransferLength + pUserSrb->SenseInfoBufferLength));
pUserSrb->SrbStatus = pSrb->SrbStatus;
pUserSrb->ScsiStatus = pSrb->ScsiStatus;
pUserSrb->SenseInfoBufferLength = pSrb->SenseInfoBufferLength;
pUserSrb->DataTransferLength = pSrb->DataTransferLength;
pUserHeader->Length = sizeof(USER_HEADER) + sizeof(USER_SCSI_REQUEST_BLOCK);
if (NT_SUCCESS(pUserHeader->Status))
{
if ((pSrb->DataTransferLength) && (pSrb->SrbFlags & SRB_FLAGS_DATA_IN))
{
pUserHeader->Length += pUserSrb->DataTransferLength;
}
}
else
{
if ((pSrb->SenseInfoBufferLength) && (pSrb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID))
{
pUserHeader->Length += pUserSrb->SenseInfoBufferLength;
if (pSrb->DataTransferLength)
{
memmove((UCHAR*)pUserSrb + sizeof(USER_SCSI_REQUEST_BLOCK), (UCHAR*)pUserSrb + (sizeof(USER_SCSI_REQUEST_BLOCK) + pUserSrb->DataTransferLength), pUserSrb->SenseInfoBufferLength);
}
}
}
}
else
{
pUserHeader->Length = sizeof(USER_HEADER);
if (pUserHeader->IoControlCode == IOCTL_SCSI_GET_ADDRESS)
{
pUserHeader->Length += pUserHeader->Information;
}
else if (pUserHeader->IoControlCode == IOCTL_STORAGE_QUERY_PROPERTY)
{
pUserHeader->Length += pUserHeader->Information;
}
}
IoFreeIrp(pIrp2);
CompleteRequest(pIrp, STATUS_SUCCESS, 0);
IoReleaseRemoveLock(&pDeviceExtension->RemoveLock, pIrp);
return STATUS_MORE_PROCESSING_REQUIRED;
}
Все работает нормально (запросы передаются между сервером и клиентом, без BSOD и т. Д.), Но устройство cdrom просто не отображается на стороне клиента. Я думал, что это может быть что-то с доступом к буферу данных SRB. Можете ли вы помочь мне разобраться? Спасибо.
Задача ещё не решена.
Других решений пока нет …