通过网络传递SCSI命令

时间:2018-03-15 16:27:03

标签: c++ windows networking scsi wdm

我想通过网络分享cdrom设备。

在客户端,我创建了根枚举设备(scsi总线)。在服务器端(cdrom设备所在的位置)我用我自己的设备堆栈替换设备堆栈(换句话说 - cdrom.sys被另一个驱动程序替换)。

使用Windows套接字将请求从客户端重定向到服务器。

通过网络(从客户端到服务器)传输的数据格式: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);
            }
        }
    }
}

分配请求和IO完成例程的服务器端代码:

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数据缓冲区访问的东西。你能帮我解决一下吗?谢谢。

0 个答案:

没有答案