0

ネットワーク経由で cdrom デバイスを共有したい。

クライアント側では、ルート列挙型デバイス (SCSI バス) を作成します。サーバー側 (cdrom デバイスが存在する場所) では、デバイス スタックの FDO を独自のものに置き換えます (つまり、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 データ バッファ アクセスに関するものではないかと思いました。それを理解するのを手伝ってもらえますか?ありがとうございました。

4

0 に答える 0