65.9K
CodeProject 正在变化。 阅读更多。
Home

SCSI over Net

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.98/5 (15投票s)

2018 年 3 月 28 日

CPOL

6分钟阅读

viewsIcon

16192

downloadIcon

31

本文将向您展示如何通过网络共享内置CD-ROM / 硬盘驱动器。

引言

传统上,CD-ROM驱动器的设备堆栈如下所示:

CD-ROM类驱动程序管理CD-ROM设备的FDO,而SCSI总线驱动程序管理总线设备的FDO及其子设备——CD-ROM设备的PDO。CD-ROM类驱动程序SCSI总线驱动程序发送请求,后者与硬件通信并返回响应。

为了通过网络共享CD-ROM设备,我们需要考虑客户端服务器部分。在服务器端,我们将用我们自己的SCSI服务器驱动程序替换CD-ROM类驱动程序,因此设备堆栈将如下所示:

在客户端,我们将用SCSI客户端驱动程序替换SCSI总线驱动程序,因此设备堆栈将如下所示:

在客户端,我们将从CD-ROM类驱动程序获取请求并通过网络将其发送到服务器端。在服务器端,我们将请求传递给SCSI总线驱动程序,并将响应发送回客户端。

背景

为了管理驱动程序,我们需要驱动程序包——位于同一目录中的infsys文件。Inf文件包含设备设置类GUID和我们的驱动程序可以安装的设备硬件ID

管理驱动程序的函数位于Difxapi.h中。我不会评论可以传递给这些函数的不同标志,我只使用了DRIVER_PACKAGE_FORCE

DWORD DriverPackageInstall(
  _In_     PCTSTR            DriverPackageInfPath,
  _In_     DWORD             Flags,
  _In_opt_ PCINSTALLERINFO_W pInstallerInfo,
  _Out_    BOOL              *pNeedReboot
);

DriverPackageInstall:

  1. 如果驱动程序未预安装——预安装驱动程序。
  2. 如果inf文件与设备的某些硬件ID匹配(驱动程序兼容)——为这些设备安装驱动程序(如果已为设备安装了另一个驱动程序——它将自动卸载)。
DWORD DriverPackagePreinstall(
  _In_ PCTSTR DriverPackageInfPath,
  _In_ DWORD  Flags
);

DriverPackagePreinstall:

  1. 预安装驱动程序。
DWORD DriverPackageUninstall(
  _In_     PCTSTR            DriverPackageInfPath,
  _In_     DWORD             Flags,
  _In_opt_ PCINSTALLERINFO_W pInstallerInfo,
  _Out_    BOOL              *pNeedReboot
);

DriverPackageUninstall:

  1. 如果驱动程序已为某些设备安装——为这些设备卸载驱动程序(如果另一个兼容驱动程序已预安装——它将自动为设备安装)。
  2. 卸载驱动程序

当我们预安装驱动程序时,系统会显示警告对话框,然后将驱动程序文件复制到驱动程序存储。当我们卸载驱动程序时,系统会从驱动程序存储中删除驱动程序文件。
当我们安装驱动程序时,如果驱动程序文件尚未复制,系统会将其复制到系统目录。

警告对话框如下所示:

其他管理驱动程序的函数位于Newdev.h中。这些函数可用于在特定设备的基础上管理驱动程序。我们将使用DiInstallDevice函数。

BOOL DiInstallDevice(
  _In_opt_  HWND             hwndParent,
  _In_      HDEVINFO         DeviceInfoSet,
  _In_      PSP_DEVINFO_DATA DeviceInfoData,
  _In_opt_  PSP_DRVINFO_DATA DriverInfoData,
  _In_      DWORD            Flags,
  _Out_opt_ PBOOL            NeedReboot
);

DiInstallDevice:

  1. 为指定设备安装驱动程序(驱动程序已预安装)。先前的驱动程序(如果有)将被卸载

Using the Code

为了测试目的,我们将使用同一台虚拟机作为服务器和客户端。

  1. inf文件简要说明

    服务器端
    Inf文件名 = scsiserver.inf
    设备设置类 = CDROM
    设备硬件ID = GenCdRom
    设备描述 = SCSI Server

    客户端
    Inf文件名 = scsiclient.inf
    设备设置类 = HDC
    设备硬件ID = VirtualSCSIBus
    设备描述 = SCSI Client

  2. 程序安装过程

    在服务器端,我们需要预安装服务器驱动程序。

    #include <Windows.h>
    #include <Difxapi.h>
    #include <stdio.h>
    
    #pragma comment(lib, "Difxapi.lib")
    
    int main(int argc, char* argv[])
    {
        DWORD dw;
    
        // preinstall driver
        dw = DriverPackagePreinstallW(L"C:\\scsiserver.inf", DRIVER_PACKAGE_FORCE);
    
        if (dw == ERROR_SUCCESS) wprintf(L"Success\n");
        else wprintf(L"Failure\n");
    
        getchar();
        return 0;
    }

    在客户端,我们需要添加根枚举设备,预安装客户端驱动程序,并为创建的设备安装客户端驱动程序。

    #include <Windows.h>
    #include <Devguid.h>
    #include <Setupapi.h>
    #include <Difxapi.h>
    #include <stdio.h>
    
    #pragma comment(lib, "Setupapi.lib")
    #pragma comment(lib, "Difxapi.lib")
    
    BOOL AddDevice(WCHAR *pHardwareId)
    {
        BOOL b, bSuccess;
        HDEVINFO hDevInfo;
        SP_DEVINFO_DATA DevInfoData;
    
        bSuccess = FALSE;
    
        hDevInfo = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_UNKNOWN, NULL);
    
        if (hDevInfo != INVALID_HANDLE_VALUE)
        {
            DevInfoData.cbSize = sizeof(DevInfoData);
    
            b = SetupDiCreateDeviceInfoW(hDevInfo, pHardwareId,
                &GUID_DEVCLASS_UNKNOWN, NULL, NULL, DICD_GENERATE_ID, &DevInfoData);
    
            if (b)
            {
                b = SetupDiSetDeviceRegistryPropertyW(hDevInfo, &DevInfoData, SPDRP_HARDWAREID,
                    (BYTE*)pHardwareId, (wcslen(pHardwareId) + 1) * sizeof(WCHAR));
    
                if (b)
                {
                    b = SetupDiCallClassInstaller(DIF_REGISTERDEVICE, hDevInfo, &DevInfoData);
    
                    if (b) bSuccess = TRUE;
                }
            }
    
            SetupDiDestroyDeviceInfoList(hDevInfo);
        }
    
        return bSuccess;
    }
    
    int main(int argc, char* argv[])
    {
        DWORD dw;
        BOOL b, bRebootRequired;
    
        // add root-enumerated device with Unknown setup class
        b = AddDevice(L"VirtualSCSIBus");
    
        if (b)
        {
            // preinstall and install driver (root-enumerated device setup class
            // will be ajusted according to driver)
            dw = DriverPackageInstallW(L"C:\\scsiclient.inf", DRIVER_PACKAGE_FORCE,
                 NULL, &bRebootRequired);
    
            if (dw == ERROR_SUCCESS)
            {
                wprintf(L"Success\n");
    
                if (bRebootRequired) wprintf(L"Reboot required\n");
            }
            else wprintf(L"Failure\n");
        }
        else wprintf(L"Failure\n");
    
        getchar();
        return 0;
    }
  3. 程序卸载过程

    在服务器端,我们需要卸载服务器驱动程序。

    #include <Windows.h>
    #include <Difxapi.h>
    #include <stdio.h>
    
    #pragma comment(lib, "Difxapi.lib")
    
    int main(int argc, char* argv[])
    {
        DWORD dw;
        BOOL bRebootRequired;
    
        // deinstall driver
        dw = DriverPackageUninstallW(L"C:\\scsiserver.inf", DRIVER_PACKAGE_FORCE,
             NULL, &bRebootRequired);
    
        if (dw == ERROR_SUCCESS)
        {
            wprintf(L"Success\n");
    
            if (bRebootRequired) wprintf(L"Reboot required\n");
        }
        else wprintf(L"Failure\n");
    
        getchar();
        return 0;
    }

    在客户端,我们需要为根枚举设备卸载客户端驱动程序,卸载客户端驱动程序并移除根枚举设备。

    #include <Windows.h>
    #include <Setupapi.h>
    #include <Difxapi.h>
    #define INITGUID
    #include <Devpkey.h>
    #include <stdio.h>
    
    #pragma comment(lib, "Setupapi.lib")
    #pragma comment(lib, "Difxapi.lib")
    
    BOOL RemoveDevice(WCHAR *pHardwareId)
    {
        BOOL b, bSuccess;
        HDEVINFO hDevInfo;
        SP_DEVINFO_DATA DevInfoData;
        WCHAR PropertyBuffer[1000];
        SP_REMOVEDEVICE_PARAMS params;
        DWORD PropertyDataType, Index;
        GUID ClassGuid;
    
        bSuccess = FALSE;
    
        hDevInfo = SetupDiGetClassDevsW(NULL, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT);
    
        if (hDevInfo != INVALID_HANDLE_VALUE)
        {
            Index = 0;
            DevInfoData.cbSize = sizeof(DevInfoData);
    
            while (SetupDiEnumDeviceInfo(hDevInfo, Index, &DevInfoData))
            {
                if ((!SetupDiGetDevicePropertyW(hDevInfo, &DevInfoData, 
                     &DEVPKEY_Device_Class, &PropertyDataType, (PBYTE)&ClassGuid,
                    sizeof(GUID), NULL, 0)) || (PropertyDataType != DEVPROP_TYPE_GUID))
                {
                    if (GetLastError() == ERROR_NOT_FOUND)
                    {
                        /* device has Unknown setup class */
    
                        b = SetupDiGetDeviceRegistryPropertyW(hDevInfo, &DevInfoData, 
                            SPDRP_HARDWAREID, &PropertyDataType, (BYTE*)PropertyBuffer, 
                            sizeof(PropertyBuffer), NULL);
    
                        if (b)
                        {
                            if (!wcscmp(PropertyBuffer, pHardwareId))
                            {
                                params.ClassInstallHeader.cbSize = sizeof
                                                     (SP_CLASSINSTALL_HEADER);
                                params.ClassInstallHeader.InstallFunction = DIF_REMOVE;
                                params.Scope = DICS_FLAG_GLOBAL;
    
                                b = SetupDiSetClassInstallParamsW(hDevInfo, &DevInfoData, 
                                          &params.ClassInstallHeader, sizeof(params));
    
                                if (b)
                                {
                                    b = SetupDiCallClassInstaller
                                        (DIF_REMOVE, hDevInfo, &DevInfoData);
    
                                    if (b) bSuccess = TRUE;
                                }
    
                                break;
                            }
                        }
                    }
                }
    
                ++Index;
            }
    
            SetupDiDestroyDeviceInfoList(hDevInfo);
        }
    
        return bSuccess;
    }
    
    int main(int argc, char* argv[])
    {
        DWORD dw;
        BOOL b, bRebootRequired;
    
        // uninstall (root-enumerated device setup class will be ajusted back to Unknown) 
        // and deinstall driver
        dw = DriverPackageUninstallW(L"C:\\scsiclient.inf", 
                          DRIVER_PACKAGE_FORCE, NULL, &bRebootRequired);
    
        if (dw == ERROR_SUCCESS)
        {
            // remove root-enumerated device with Unknown setup class
            b = RemoveDevice(L"VirtualSCSIBus");
    
            if (b) wprintf(L"Success\n");
            else wprintf(L"Failure\n");
    
            if (bRebootRequired) wprintf(L"Reboot required\n");
        }
        else wprintf(L"Failure\n");
    
        getchar();
        return 0;
    }
  4. 程序操作过程

    在每一侧,我们都有 { 驱动程序和用户模式程序 } 对。在任一侧,我们都需要启动用户模式程序并输入“Connect”命令。连接后,在服务器端,我们将输入“List”命令以查看可用的CD-ROM设备(它们的硬件ID)。接下来,我们将输入“Share”命令,后跟硬件ID以开始共享过程。在服务器端,CD-ROM设备将从资源管理器中消失,并显示在客户端。

    客户端

    服务器端

    要停止设备共享,我们需要在服务器端输入“Unshare”命令或在客户端断开连接。在客户端,CD-ROM设备将消失,我们将在服务器端将其找回。

    客户端

    服务器端

    Windows套接字用于通过网络传输数据。用户模式代码设计如下:

    1. 用户线程”——此线程专用于用户命令(等待它们)。
    2. 接收线程”——此线程负责接收 REQUEST_HEADER结构,该结构包含整个请求的长度和设备标签(以便我们知道此请求是针对哪个共享设备的,以及下次需要接收多少字节)。
    3. 设备线程”——每个共享设备都有自己的线程,该线程将发送请求,接收请求(除了REQUEST_HEADER结构,它将从“接收线程”获取),并在循环中与驱动程序交互。

    “接收线程”的需求源于TCP/IP的特性。当我们在网络上发送数据时,字节序列在另一侧保证相同。但是,如果我们从不同线程(A和B)同时发送数据,则不保证缓冲区A将在缓冲区B之前发送,反之亦然。此外,当我们接收数据时,我们不知道要期望多少字节——我们唯一能做的就是提供我们的缓冲区大小。这意味着一侧的任意数量的发送可能导致另一侧的任意数量的接收。为了解决这个问题,我们首先接收 REQUEST_HEADER,然后将信息传递给相应的“设备线程”,并允许它接收剩余数据。

服务器端代码(已截断)

#define IOCTL_GET_PNP_INFO               CTL_CODE(FILE_DEVICE_CONTROLLER, 
                                         0, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_EXECUTE_REQUEST            CTL_CODE(FILE_DEVICE_CONTROLLER, 
                                         1, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)

#define BUFFER_SIZE                      40 * 4096

#define OP_PLUGIN                        1
#define OP_PLUGOUT                       2
#define OP_REQUEST                       3

struct REQUEST_HEADER
{
    ULONG Id;
    ULONG Op;
    ULONG Irp[2];
    ULONG Length;
    ULONG MajorFunction;
    ULONG MinorFunction;
    ULONG IoControlCode;
    ULONG InputBufferLength;
    ULONG OutputBufferLength;
    NTSTATUS Status;
    ULONG Information;
};

struct DEVICE_CONTEXT
{
    LIST_ENTRY ListEntry;
    ULONG Id;
    HANDLE hThread;
    HANDLE hReceiveBeginEvent;
    HANDLE hReceiveEndEvent;
    REQUEST_HEADER* pHeader;
    REQUEST_HEADER* pBuffer;
    SOCKET Socket;
    BOOL End;
    WCHAR* pHardwareId;
};

struct RECEIVE_CONTEXT
{
    HANDLE hThread;
    SOCKET Socket;
    LIST_ENTRY DeviceList;
    CRITICAL_SECTION Section;
    REQUEST_HEADER Header;
    ULONG Id;
};

BOOL Send(DEVICE_CONTEXT *pDevContext)
{
    int iResult;

    iResult = send(pDevContext->Socket, 
    (CHAR*)pDevContext->pBuffer, pDevContext->pBuffer->Length, 0);

    return (iResult > 0);
}

BOOL Receive(RECEIVE_CONTEXT *pRecvContext)
{
    int iResult;

    iResult = recv(pRecvContext->Socket, 
    (CHAR*)&pRecvContext->Header, sizeof(REQUEST_HEADER), 0);

    return (iResult > 0);
}

BOOL Receive(DEVICE_CONTEXT *pDevContext)
{
    int iResult;
    ULONG Length;

    WaitForSingleObject(pDevContext->hReceiveBeginEvent, INFINITE);

    memcpy(pDevContext->pBuffer, pDevContext->pHeader, sizeof(REQUEST_HEADER));

    Length = pDevContext->pHeader->Length - sizeof(REQUEST_HEADER);

    if (Length) iResult = recv(pDevContext->Socket, 
    (CHAR*)((UCHAR*)pDevContext->pBuffer + sizeof(REQUEST_HEADER)), Length, 0);
    else iResult = 1;

    SetEvent(pDevContext->hReceiveEndEvent);

    return (iResult > 0);
}

void UnlockDeviceContext(RECEIVE_CONTEXT *pRecvContext, DEVICE_CONTEXT *pDevContext)
{
    pDevContext->pHeader = &pRecvContext->Header;

    SetEvent(pDevContext->hReceiveBeginEvent);

    WaitForSingleObject(pDevContext->hReceiveEndEvent, INFINITE);
}

void DeleteDeviceContext(DEVICE_CONTEXT *pDevContext)
{
    CloseHandle(pDevContext->hReceiveBeginEvent);

    CloseHandle(pDevContext->hReceiveEndEvent);

    CloseHandle(pDevContext->hThread);

    delete[] pDevContext->pHardwareId;

    delete[] (UCHAR*)pDevContext->pBuffer;

    delete pDevContext;
}

DEVICE_CONTEXT* CreateDeviceContext
(PTHREAD_START_ROUTINE StartRoutine, ULONG Id, SOCKET Socket, WCHAR *pHardwareId)
{
    DEVICE_CONTEXT *pDevContext;

    pDevContext = new DEVICE_CONTEXT;

    pDevContext->pBuffer = (REQUEST_HEADER*)new UCHAR[BUFFER_SIZE];

    pDevContext->hThread = CreateThread(NULL, 0, StartRoutine, 
                           pDevContext, CREATE_SUSPENDED, NULL);

    pDevContext->hReceiveBeginEvent = CreateEventW(NULL, FALSE, FALSE, NULL);

    pDevContext->hReceiveEndEvent = CreateEventW(NULL, FALSE, FALSE, NULL);

    pDevContext->Id = Id;
    pDevContext->Socket = Socket;
    pDevContext->End = FALSE;

    pDevContext->pHardwareId = new WCHAR[wcslen(pHardwareId) + 1];
    wcscpy(pDevContext->pHardwareId, pHardwareId);

    return pDevContext;
}

DWORD WINAPI DeviceThread(PVOID Parameter)
{
    HANDLE Handle;
    WCHAR *pDevicePath;
    OVERLAPPED Overlapped;
    DEVICE_CONTEXT *pDevContext;
    WCHAR *pDriverDescription;
    BOOL bNeedReboot;
    DWORD Bytes;

    pDevContext = (DEVICE_CONTEXT*)Parameter;

    pDriverDescription = GetInstalledDriver((GUID*)&GUID_DEVCLASS_CDROM, 
                         pDevContext->pHardwareId);

    InstallDriver((GUID*)&GUID_DEVCLASS_CDROM, 
    pDevContext->pHardwareId, L"SCSI Server", &bNeedReboot);

    Sleep(5000);        // we need to wait, otherwise it will not work properly

    pDevicePath = GetDevicePath(&g_ClassGuid, pDevContext->pHardwareId);

    Handle = CreateFileW(pDevicePath, GENERIC_READ | GENERIC_WRITE, 
    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 
    FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);

    DeviceIoControl(Handle, IOCTL_GET_PNP_INFO, NULL, 0, 
                    pDevContext->pBuffer, BUFFER_SIZE, NULL, NULL);

    pDevContext->pBuffer->Op = OP_PLUGIN;
    pDevContext->pBuffer->Id = pDevContext->Id;

    if (Send(pDevContext))
    {
        while (Receive(pDevContext))
        {
            if (pDevContext->pBuffer->Op == OP_PLUGOUT)
            {
                break;
            }
            else if (pDevContext->pBuffer->Op == OP_REQUEST)
            {
                if (pDevContext->End)
                {
                    pDevContext->pBuffer->Op = OP_PLUGOUT;
                    pDevContext->pBuffer->Length = sizeof(REQUEST_HEADER);

                    Send(pDevContext);
                    break;
                }
                else
                {
                    memset(&Overlapped, 0, sizeof(OVERLAPPED));

                    if (!DeviceIoControl(Handle, IOCTL_EXECUTE_REQUEST, NULL, 0, 
                    pDevContext->pBuffer, BUFFER_SIZE, NULL, &Overlapped))
                    {
                        /* ERROR_IO_PENDING */
                        GetOverlappedResultEx(Handle, &Overlapped, &Bytes, 3000, FALSE);
                    }

                    if (!Send(pDevContext)) break;
                }
            }
            else DbgRaiseAssertionFailure();
        }
    }

    CloseHandle(Handle);

    delete[] pDevicePath;

    Sleep(5000);        // we need to wait, otherwise it will not work properly

    InstallDriver((GUID*)&GUID_DEVCLASS_CDROM, 
    pDevContext->pHardwareId, pDriverDescription, &bNeedReboot);

    delete[] pDriverDescription;

    return 0;
}

DWORD WINAPI ReceiveThread(PVOID Parameter)
{
    DEVICE_CONTEXT *pDevContext;
    RECEIVE_CONTEXT *pRecvContext;

    pRecvContext = (RECEIVE_CONTEXT*)Parameter;

    while (Receive(pRecvContext))
    {
        pDevContext = FindDeviceContextById(pRecvContext, pRecvContext->Header.Id);

        if (pDevContext) UnlockDeviceContext(pRecvContext, pDevContext);
        else DbgRaiseAssertionFailure();
    }

    return 0;
}

DEVICE_CONTEXT* AddDeviceContext(RECEIVE_CONTEXT *pRecvContext, WCHAR *pHardwareId)
{
    DEVICE_CONTEXT *pDevContext;

    pDevContext = CreateDeviceContext(DeviceThread, 
    pRecvContext->Id++, pRecvContext->Socket, pHardwareId);

    EnterCriticalSection(&pRecvContext->Section);

    InsertToList(&pRecvContext->DeviceList, (LIST_ENTRY*)pDevContext);

    LeaveCriticalSection(&pRecvContext->Section);

    ResumeThread(pDevContext->hThread);

    return pDevContext;
}

void RemoveDeviceContext(RECEIVE_CONTEXT *pRecvContext, DEVICE_CONTEXT *pDevContext)
{
    EnterCriticalSection(&pRecvContext->Section);

    RemoveFromList((LIST_ENTRY*)pDevContext);

    LeaveCriticalSection(&pRecvContext->Section);

    DeleteDeviceContext(pDevContext);
}

RECEIVE_CONTEXT* CreateReceiveContext(SOCKET ServerSocket)
{
    RECEIVE_CONTEXT *pRecvContext;

    pRecvContext = new RECEIVE_CONTEXT;

    InitializeCriticalSection(&pRecvContext->Section);

    InitializeList(&pRecvContext->DeviceList);

    pRecvContext->Id = 0;
    pRecvContext->Socket = Accept(ServerSocket);

    pRecvContext->hThread = 
    CreateThread(NULL, 0, ReceiveThread, (PVOID)pRecvContext, CREATE_SUSPENDED, NULL);

    return pRecvContext;
}

void DeleteReceiveContext(RECEIVE_CONTEXT* pRecvContext)
{
    DEVICE_CONTEXT *pDevContext;

    while (pDevContext = GetFirstDeviceContext(pRecvContext))
    {
        pDevContext->End = TRUE;
        WaitForSingleObject(pDevContext->hThread, INFINITE);

        RemoveDeviceContext(pRecvContext, pDevContext);
    }

    Close(pRecvContext->Socket);

    WaitForSingleObject(pRecvContext->hThread, INFINITE);

    CloseHandle(pRecvContext->hThread);

    DeleteCriticalSection(&pRecvContext->Section);

    delete pRecvContext;
}

int main(int argc, char* argv[])
{
    WCHAR Command[200];
    SOCKET ServerSocket;
    RECEIVE_CONTEXT* pRecvContext;
    DEVICE_CONTEXT *pDevContext;

    ServerSocket = CreateServerSocket();
    pRecvContext = NULL;

    while (TRUE)
    {
        wscanf(L"%s", Command);

        if (!wcscmp(Command, L"Connect"))
        {
            if (!pRecvContext)
            {
                pRecvContext = CreateReceiveContext(ServerSocket);
                ResumeThread(pRecvContext->hThread);

                wprintf(L"Connected\n");
            }
        }
        else if (!wcscmp(Command, L"Disconnect"))
        {
            if (pRecvContext)
            {
                DeleteReceiveContext(pRecvContext);
                pRecvContext = NULL;

                wprintf(L"Disconnected\n");
            }
        }
        else if (!wcscmp(Command, L"List"))
        {
            PrintDevices();
        }
        else if (!wcscmp(Command, L"Exit"))
        {
            if (pRecvContext) DeleteReceiveContext(pRecvContext);

            break;
        }
        else if (!wcscmp(Command, L"Share"))
        {
            wscanf(L"%s", Command);

            AddDeviceContext(pRecvContext, Command);
        }
        else if (!wcscmp(Command, L"Unshare"))
        {
            wscanf(L"%s", Command);

            pDevContext = FindDeviceContextByHardwareId(pRecvContext, Command);

            if (pDevContext)
            {
                pDevContext->End = TRUE;
                WaitForSingleObject(pDevContext->hThread, INFINITE);

                RemoveDeviceContext(pRecvContext, pDevContext);
            }
        }
        else
        {
            wprintf(L"Unknown command\n");
        }
    }

    DeleteServerSocket(ServerSocket);

    return 0;
}

客户端代码(已截断)

#define IOCTL_PLUGIN_DEVICE    CTL_CODE(FILE_DEVICE_CONTROLLER, 0, 
                               METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_PLUGOUT_DEVICE   CTL_CODE(FILE_DEVICE_CONTROLLER, 1, 
                               METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_FETCH_REQUEST    CTL_CODE(FILE_DEVICE_CONTROLLER, 2, 
                               METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
#define IOCTL_COMPLETE_REQUEST CTL_CODE(FILE_DEVICE_CONTROLLER, 3, 
                               METHOD_IN_DIRECT, FILE_ANY_ACCESS)

#define BUFFER_SIZE                    40 * 4096

#define OP_PLUGIN                      1
#define OP_PLUGOUT                     2
#define OP_REQUEST                     3

struct REQUEST_HEADER
{
    ULONG Id;
    ULONG Op;
    ULONG Irp[2];
    ULONG Length;
    ULONG MajorFunction;
    ULONG MinorFunction;
    ULONG IoControlCode;
    ULONG InputBufferLength;
    ULONG OutputBufferLength;
    NTSTATUS Status;
    ULONG Information;
};

struct DEVICE_CONTEXT
{
    LIST_ENTRY ListEntry;
    ULONG Id;
    HANDLE hThread;
    HANDLE hReceiveBeginEvent;
    HANDLE hReceiveEndEvent;
    REQUEST_HEADER* pHeader;
    REQUEST_HEADER* pBuffer;
    SOCKET Socket;
    BOOL End;
};

struct RECEIVE_CONTEXT
{
    HANDLE hThread;
    SOCKET Socket;
    LIST_ENTRY DeviceList;
    CRITICAL_SECTION Section;
    REQUEST_HEADER Header;
};

void UnlockDeviceContext(RECEIVE_CONTEXT *pRecvContext, DEVICE_CONTEXT *pDevContext)
{
    pDevContext->pHeader = &pRecvContext->Header;

    SetEvent(pDevContext->hReceiveBeginEvent);

    WaitForSingleObject(pDevContext->hReceiveEndEvent, INFINITE);
}

void DeleteDeviceContext(DEVICE_CONTEXT *pDevContext)
{
    CloseHandle(pDevContext->hReceiveBeginEvent);

    CloseHandle(pDevContext->hReceiveEndEvent);

    CloseHandle(pDevContext->hThread);

    delete[] (UCHAR*)pDevContext->pBuffer;

    delete pDevContext;
}

DEVICE_CONTEXT* CreateDeviceContext
(PTHREAD_START_ROUTINE StartRoutine, ULONG Id, SOCKET Socket)
{
    DEVICE_CONTEXT *pDevContext;

    pDevContext = new DEVICE_CONTEXT;

    pDevContext->pBuffer = (REQUEST_HEADER*)new UCHAR[BUFFER_SIZE];

    pDevContext->hThread = CreateThread(NULL, 0, StartRoutine, pDevContext, CREATE_SUSPENDED, NULL);

    pDevContext->hReceiveBeginEvent = CreateEventW(NULL, FALSE, FALSE, NULL);

    pDevContext->hReceiveEndEvent = CreateEventW(NULL, FALSE, FALSE, NULL);

    pDevContext->Id = Id;
    pDevContext->Socket = Socket;
    pDevContext->End = FALSE;

    return pDevContext;
}

BOOL Send(DEVICE_CONTEXT *pDevContext)
{
    int iResult;

    iResult = send(pDevContext->Socket, 
    (CHAR*)pDevContext->pBuffer, pDevContext->pBuffer->Length, 0);

    return (iResult > 0);
}

BOOL Receive(DEVICE_CONTEXT *pDevContext)
{
    int iResult;
    ULONG Length;

    WaitForSingleObject(pDevContext->hReceiveBeginEvent, INFINITE);

    memcpy(pDevContext->pBuffer, pDevContext->pHeader, sizeof(REQUEST_HEADER));

    Length = pDevContext->pHeader->Length - sizeof(REQUEST_HEADER);

    if (Length) iResult = recv(pDevContext->Socket, 
    (CHAR*)((UCHAR*)pDevContext->pBuffer + sizeof(REQUEST_HEADER)), Length, 0);
    else iResult = 1;

    SetEvent(pDevContext->hReceiveEndEvent);

    return (iResult > 0);
}

BOOL Receive(RECEIVE_CONTEXT *pRecvContext)
{
    int iResult;

    iResult = recv(pRecvContext->Socket, 
    (CHAR*)&pRecvContext->Header, sizeof(REQUEST_HEADER), 0);

    return (iResult > 0);
}

DWORD WINAPI DeviceThread(PVOID Parameter)
{
    HANDLE Handle;
    WCHAR *pDevicePath;
    OVERLAPPED Overlapped;
    DEVICE_CONTEXT *pDevContext;
    DWORD Bytes;

    pDevContext = (DEVICE_CONTEXT*)Parameter;

    pDevicePath = GetDevicePath(&g_ClassGuid, L"VirtualSCSIBus");

    Handle = CreateFileW(pDevicePath, GENERIC_READ | GENERIC_WRITE, 
    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, 
    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);

    if (Receive(pDevContext))
    {
        if (pDevContext->pBuffer->Op == OP_PLUGIN)
        {
            DeviceIoControl(Handle, IOCTL_PLUGIN_DEVICE, 
            pDevContext->pBuffer, pDevContext->pBuffer->Length, NULL, 0, NULL, NULL);

            memset(&Overlapped, 0, sizeof(OVERLAPPED));

            if (!DeviceIoControl(Handle, IOCTL_FETCH_REQUEST, NULL, 0, 
            pDevContext->pBuffer, BUFFER_SIZE, NULL, &Overlapped))
            {
                /* ERROR_IO_PENDING */
                GetOverlappedResultEx(Handle, &Overlapped, &Bytes, 3000, FALSE);
            }

            pDevContext->pBuffer->Op = OP_REQUEST;

            if (Send(pDevContext))
            {
                while (Receive(pDevContext))
                {
                    if (pDevContext->pBuffer->Op == OP_PLUGOUT)
                    {
                        break;
                    }
                    else if (pDevContext->pBuffer->Op == OP_REQUEST)
                    {
                        if (pDevContext->End)
                        {
                            pDevContext->pBuffer->Op = OP_PLUGOUT;
                            pDevContext->pBuffer->Length = sizeof(REQUEST_HEADER);

                            Send(pDevContext);
                            break;
                        }
                        else
                        {
                            DeviceIoControl(Handle, IOCTL_COMPLETE_REQUEST, 
                            pDevContext->pBuffer, pDevContext->pBuffer->Length, NULL, 0, NULL, NULL);

                            memset(&Overlapped, 0, sizeof(OVERLAPPED));

                            if (!DeviceIoControl(Handle, IOCTL_FETCH_REQUEST, 
                            NULL, 0, pDevContext->pBuffer, BUFFER_SIZE, NULL, &Overlapped))
                            {
                                /* ERROR_IO_PENDING */
                                GetOverlappedResultEx(Handle, &Overlapped, &Bytes, 3000, FALSE);
                            }

                            if (!Send(pDevContext)) break;
                        }
                    }
                    else DbgRaiseAssertionFailure();
                }
            }

            DeviceIoControl(Handle, IOCTL_PLUGOUT_DEVICE, NULL, 0, NULL, 0, NULL, NULL);
        }
        else DbgRaiseAssertionFailure();
    }

    CloseHandle(Handle);

    delete[] pDevicePath;

    return 0;
}

DEVICE_CONTEXT* AddDeviceContext(RECEIVE_CONTEXT *pRecvContext, ULONG Id)
{
    DEVICE_CONTEXT *pDevContext;

    pDevContext = CreateDeviceContext(DeviceThread, Id, pRecvContext->Socket);

    EnterCriticalSection(&pRecvContext->Section);

    InsertToList(&pRecvContext->DeviceList, (LIST_ENTRY*)pDevContext);

    LeaveCriticalSection(&pRecvContext->Section);

    ResumeThread(pDevContext->hThread);

    return pDevContext;
}

void RemoveDeviceContext(RECEIVE_CONTEXT *pRecvContext, DEVICE_CONTEXT *pDevContext)
{
    EnterCriticalSection(&pRecvContext->Section);

    RemoveFromList((LIST_ENTRY*)pDevContext);

    LeaveCriticalSection(&pRecvContext->Section);

    DeleteDeviceContext(pDevContext);
}

DWORD WINAPI ReceiveThread(PVOID Parameter)
{
    DEVICE_CONTEXT *pDevContext;
    RECEIVE_CONTEXT *pRecvContext;

    pRecvContext = (RECEIVE_CONTEXT*)Parameter;

    while (Receive(pRecvContext))
    {
        switch (pRecvContext->Header.Op)
        {
        case OP_PLUGIN:
            pDevContext = AddDeviceContext(pRecvContext, pRecvContext->Header.Id);

            UnlockDeviceContext(pRecvContext, pDevContext);
            break;
        case OP_PLUGOUT:
            pDevContext = FindDeviceContextById(pRecvContext, pRecvContext->Header.Id);

            if (pDevContext)
            {
                UnlockDeviceContext(pRecvContext, pDevContext);

                WaitForSingleObject(pDevContext->hThread, INFINITE);

                RemoveDeviceContext(pRecvContext, pDevContext);
            }
            else DbgRaiseAssertionFailure();

            break;
        case OP_REQUEST:
            pDevContext = FindDeviceContextById(pRecvContext, pRecvContext->Header.Id);

            if (pDevContext) UnlockDeviceContext(pRecvContext, pDevContext);
            else DbgRaiseAssertionFailure();

            break;
        default:
            DbgRaiseAssertionFailure();
        }
    }

    return 0;
}

RECEIVE_CONTEXT* CreateReceiveContext()
{
    RECEIVE_CONTEXT *pRecvContext;

    pRecvContext = new RECEIVE_CONTEXT;

    InitializeCriticalSection(&pRecvContext->Section);

    InitializeList(&pRecvContext->DeviceList);

    pRecvContext->Socket = Connect();

    pRecvContext->hThread = 
    CreateThread(NULL, 0, ReceiveThread, (PVOID)pRecvContext, CREATE_SUSPENDED, NULL);

    return pRecvContext;
}

void DeleteReceiveContext(RECEIVE_CONTEXT* pRecvContext)
{
    DEVICE_CONTEXT *pDevContext;

    while (pDevContext = GetFirstDeviceContext(pRecvContext))
    {
        pDevContext->End = TRUE;
        WaitForSingleObject(pDevContext->hThread, INFINITE);

        RemoveDeviceContext(pRecvContext, pDevContext);
    }

    Disconnect(pRecvContext->Socket);

    WaitForSingleObject(pRecvContext->hThread, INFINITE);

    CloseHandle(pRecvContext->hThread);

    DeleteCriticalSection(&pRecvContext->Section);

    delete pRecvContext;
}

int main(int argc, char* argv[])
{
    WCHAR Command[200];
    RECEIVE_CONTEXT* pRecvContext;

    pRecvContext = NULL;

    while (TRUE)
    {
        wscanf(L"%s", Command);

        if (!wcscmp(Command, L"Connect"))
        {
            if (!pRecvContext)
            {
                pRecvContext = CreateReceiveContext();
                ResumeThread(pRecvContext->hThread);

                wprintf(L"Connected\n");
            }
        }
        else if (!wcscmp(Command, L"Disconnect"))
        {
            if (pRecvContext)
            {
                DeleteReceiveContext(pRecvContext);
                pRecvContext = NULL;

                wprintf(L"Disconnected\n");
            }
        }
        else if (!wcscmp(Command, L"Exit"))
        {
            if (pRecvContext) DeleteReceiveContext(pRecvContext);

            break;
        }
        else
        {
            wprintf(L"Unknown command\n");
        }
    }

    return 0;
}

现在让我们将注意力转向内核模式部分。请参阅此文章,了解如何准备访客操作系统以进行调试。

要在Visual Studio中调试驱动程序,请转到Driver -> Test -> Configure Computers...

选择Add New Computer

输入计算机名称(可以是任何名称),然后选择Manually configure debuggers and do not provision

输入这些设置并单击Next

然后单击Finish

现在将两个驱动程序项目(客户端和服务器)添加到解决方案中。启动访客操作系统并等待操作系统选择窗口。在Visual Studio中,转到Debug -> Attach to Process...

如果进程不在列表中,请单击Refresh。之后,选择Attach。Visual Studio将打开Debugger Immediate Window

现在返回访客操作系统并选择启用调试器的启动项。

允许系统启动,转到Debug -> Break All

对于客户端驱动程序,DriverEntry将在程序安装期间或系统启动期间(之后)被调用。对于服务器端,DriverEntry将在我们启动设备共享时被调用。在DriverEntry之后,驱动程序的AddDevice例程将被调用,随后是一系列即插即用请求。

对于尚未加载的模块(服务器驱动程序),我们需要使用未解析的断点。输入以下命令:

bu scsiserver!DispatchDeviceControl

对于已加载的模块(客户端驱动程序),我们可以使用普通断点。我们可以输入以下命令:

bp scsiclient!DispatchDeviceControl

或者您可以像往常一样在代码编辑器中设置断点。请注意,相应的代码行必须变为红色(有时不会立即发生,所以我们需要等待)。现在转到Debug -> Continue。按照上述说明启动设备共享过程,我们的未解析断点将被命中(相应的代码行将变为黄色)。

现在您可以跟踪执行流,在其他分发例程上设置断点,并调试两个驱动程序。请求流如下:

  1. start
    {
        server: <code>IOCTL_GET_PNP_INFO</code> request from corresponding user mode program
        client: <code>IOCTL_PLUGIN_DEVICE</code> request for bus FDO from corresponding user mode program
        client: pnp requests from OS for newly created device PDO 
                to get information about it and to start it
    }
  2. loop
    {
        client: <code>device io control</code> requests / <code>device internal io control</code> 
                request for device PDO from cdrom class driver
        client: <code>IOCTL_FETCH_REQUEST</code> request for bus FDO from 
                corresponding user mode program
        server: <code>IOCTL_EXECUTE_REQUEST</code> request from corresponding user mode program
        client: <code>IOCTL_COMPLETE_REQUEST</code> request for bus FDO from 
                corresponding user mode program
    }
  3. 完成
    {
        client: <code>IOCTL_PLUGOUT_DEVICE</code> request for bus FDO from corresponding user mode program
        client: <code>IRP_MN_QUERY_DEVICE_RELATIONS</code> request (bus relations) from OS for bus FDO
        client: <code>IRP_MN_SURPRISE_REMOVAL</code> request from OS for device PDO
        client: <code>IRP_MN_REMOVE_DEVICE</code> request from OS for device PDO
    }

服务器端代码(已截断)

#define IOCTL_GET_PNP_INFO      CTL_CODE(FILE_DEVICE_CONTROLLER, 0, METHOD_BUFFERED,
                                FILE_ANY_ACCESS)
#define IOCTL_EXECUTE_REQUEST   CTL_CODE(FILE_DEVICE_CONTROLLER, 1, METHOD_OUT_DIRECT,
                                FILE_ANY_ACCESS)

struct PNP_ENTRY
{
    ULONG InfoOffset;
    ULONG InfoLength;
    NTSTATUS Status;
};

struct PNP_INFO
{
    PNP_ENTRY irp_mn_query_id[6];
    PNP_ENTRY irp_mn_query_device_text[2];
    PNP_ENTRY irp_mn_query_capabilities;
};

struct PACKED_SRB
{
    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];
};

struct REQUEST_HEADER
{
    ULONG Id;
    ULONG Op;
    ULONG Irp[2];
    ULONG Length;
    ULONG MajorFunction;
    ULONG MinorFunction;
    ULONG IoControlCode;
    ULONG InputBufferLength;
    ULONG OutputBufferLength;
    NTSTATUS Status;
    ULONG Information;
};

struct DEVICE_EXTENSION
{
    DEVICE_OBJECT *pDeviceObject;
    IO_REMOVE_LOCK RemoveLock;
    DEVICE_OBJECT *pLowerDeviceObject;
    UNICODE_STRING SymbolicLinkName;
    MDL *pMdl;
    ULONG PnpLength;
    PNP_INFO PnpInfo;
};

#define IRP_TO_LIST_ENTRY(_Irp)    ((LIST_ENTRY*)(((UCHAR*)_Irp) +
                                     FIELD_OFFSET(IRP, Tail.Overlay.ListEntry)))
#define IRP_FROM_LIST_ENTRY(_ListEntry)    ((IRP*)(((UCHAR*)_ListEntry) -
                                       FIELD_OFFSET(IRP, Tail.Overlay.ListEntry)))

struct PNP_CONTEXT
{
    KEVENT Event;
    DEVICE_EXTENSION *pDeviceExtension;
    IO_STACK_LOCATION Stack;
};

NTSTATUS AllocatePnpRequest(PNP_CONTEXT *pPnpContext, IRP **ppIrp)
{
    IRP *pIrp;
    NTSTATUS Status;
    DEVICE_OBJECT *pDeviceObject;
    IO_STACK_LOCATION *pStackDst, *pStackSrc;

    pDeviceObject = pPnpContext->pDeviceExtension->pLowerDeviceObject;
    pStackSrc = &pPnpContext->Stack;

    pIrp = IoAllocateIrp(pDeviceObject->StackSize, FALSE);

    if (pIrp)
    {
        pStackDst = IoGetNextIrpStackLocation(pIrp);

        pStackDst->DeviceObject = pDeviceObject;

        pStackDst->MajorFunction = IRP_MJ_PNP;
        pStackDst->MinorFunction = pStackSrc->MinorFunction;

        switch (pStackSrc->MinorFunction)
        {
        case IRP_MN_QUERY_CAPABILITIES:
            pStackDst->Parameters.DeviceCapabilities.Capabilities =
                          pStackSrc->Parameters.DeviceCapabilities.Capabilities;
            break;
        case IRP_MN_QUERY_ID:
            pStackDst->Parameters.QueryId.IdType = pStackSrc->Parameters.QueryId.IdType;
            break;
        case IRP_MN_QUERY_DEVICE_TEXT:
            pStackDst->Parameters.QueryDeviceText.DeviceTextType =
                          pStackSrc->Parameters.QueryDeviceText.DeviceTextType;
            pStackDst->Parameters.QueryDeviceText.LocaleId =
                          pStackSrc->Parameters.QueryDeviceText.LocaleId;
            break;
        default:
            DbgRaiseAssertionFailure();
            break;
        }

        *ppIrp = pIrp;
        Status = STATUS_SUCCESS;
    }
    else Status = STATUS_INSUFFICIENT_RESOURCES;

    return Status;
}

NTSTATUS IoCompletionRoutine2(DEVICE_OBJECT *pDeviceObject, IRP *pIrp, void *pContext)
{
    PNP_INFO *pPnpInfo;
    PNP_ENTRY *pPnpEntry;
    IO_STACK_LOCATION *pStack;
    BUS_QUERY_ID_TYPE BusQueryIdType;
    DEVICE_TEXT_TYPE DeviceTextType;
    DEVICE_EXTENSION *pDeviceExtension;
    PNP_CONTEXT *pPnpContext;
    WCHAR *pString;

    pPnpContext = (PNP_CONTEXT*)pContext;

    pStack = &pPnpContext->Stack;
    pDeviceExtension = pPnpContext->pDeviceExtension;
    pPnpInfo = &pDeviceExtension->PnpInfo;

    switch (pStack->MinorFunction)
    {
    case IRP_MN_QUERY_CAPABILITIES:
        pPnpEntry = &pPnpInfo->irp_mn_query_capabilities;

        pPnpEntry->InfoOffset = pDeviceExtension->PnpLength;
        pPnpEntry->InfoLength = sizeof(DEVICE_CAPABILITIES);

        memcpy((UCHAR*)pPnpInfo + pPnpEntry->InfoOffset,
              pStack->Parameters.DeviceCapabilities.Capabilities, pPnpEntry->InfoLength);
        pDeviceExtension->PnpLength += pPnpEntry->InfoLength;

        pPnpEntry->Status = pIrp->IoStatus.Status;
        break;
    case IRP_MN_QUERY_ID:
        BusQueryIdType = pStack->Parameters.QueryId.IdType;
        pPnpEntry = &pPnpInfo->irp_mn_query_id[BusQueryIdType];

        pString = (WCHAR*)pIrp->IoStatus.Information;

        if (pString)
        {
            pPnpEntry->InfoOffset = pDeviceExtension->PnpLength;

            if ((BusQueryIdType == BusQueryHardwareIDs) ||
                           (BusQueryIdType == BusQueryCompatibleIDs))
            {
                pPnpEntry->InfoLength = MultiStringSize(pString);
            }
            else
            {
                pPnpEntry->InfoLength = StringSize(pString);
            }

            memcpy((UCHAR*)pPnpInfo + pPnpEntry->InfoOffset, pString, pPnpEntry->InfoLength);
            pDeviceExtension->PnpLength += pPnpEntry->InfoLength;

            ExFreePool(pString);
        }

        pPnpEntry->Status = pIrp->IoStatus.Status;
        break;
    case IRP_MN_QUERY_DEVICE_TEXT:
        DeviceTextType = pStack->Parameters.QueryDeviceText.DeviceTextType;
        pPnpEntry = &pPnpInfo->irp_mn_query_device_text[DeviceTextType];

        pString = (WCHAR*)pIrp->IoStatus.Information;

        if (pString)
        {
            pPnpEntry->InfoOffset = pDeviceExtension->PnpLength;
            pPnpEntry->InfoLength = StringSize(pString);

            memcpy((UCHAR*)pPnpInfo + pPnpEntry->InfoOffset, pString, pPnpEntry->InfoLength);
            pDeviceExtension->PnpLength += pPnpEntry->InfoLength;

            ExFreePool(pString);
        }

        pPnpEntry->Status = pIrp->IoStatus.Status;
        break;
    default:
        DbgRaiseAssertionFailure();
        break;
    }

    IoFreeIrp(pIrp);

    KeSetEvent(&pPnpContext->Event, IO_NO_INCREMENT, FALSE);

    return STATUS_MORE_PROCESSING_REQUIRED;
}

NTSTATUS IoCompletionRoutine3(DEVICE_OBJECT *pDeviceObject, IRP *pIrp2, void *pContext)
{
    IRP *pIrp;
    REQUEST_HEADER *pHeader;
    DEVICE_EXTENSION *pDeviceExtension;
    PACKED_SRB *pPackedSrb;
    SCSI_REQUEST_BLOCK *pSrb;
    SCSI_PASS_THROUGH *pPassThrough;

    pIrp = (IRP*)pContext;

    pDeviceExtension = (DEVICE_EXTENSION*)pIrp->Tail.Overlay.DriverContext[0];

    pHeader = (REQUEST_HEADER*)MmGetSystemAddressForMdlSafe
              (pIrp->MdlAddress, NormalPagePriority);

    pHeader->Status = pIrp2->IoStatus.Status;
    pHeader->Information = pIrp2->IoStatus.Information;

    if (pHeader->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)
    {
        pPackedSrb = (PACKED_SRB*)((UCHAR*)pHeader + sizeof(REQUEST_HEADER));
        pSrb = (SCSI_REQUEST_BLOCK*)((UCHAR*)pPackedSrb + (sizeof(PACKED_SRB) +
                pPackedSrb->DataTransferLength + pPackedSrb->SenseInfoBufferLength));

        pPackedSrb->SrbStatus = pSrb->SrbStatus;
        pPackedSrb->ScsiStatus = pSrb->ScsiStatus;

        pPackedSrb->SenseInfoBufferLength = pSrb->SenseInfoBufferLength;
        pPackedSrb->DataTransferLength = pSrb->DataTransferLength;

        pHeader->Length = sizeof(REQUEST_HEADER) + sizeof(PACKED_SRB);

        if (NT_SUCCESS(pHeader->Status))
        {
            if ((pSrb->DataTransferLength) && (pSrb->SrbFlags & SRB_FLAGS_DATA_IN))
            {
                pHeader->Length += pPackedSrb->DataTransferLength;
            }
        }
        else
        {
            if ((pSrb->SenseInfoBufferLength) &&
                         (pSrb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID))
            {
                pHeader->Length += pPackedSrb->SenseInfoBufferLength;

                if (pSrb->DataTransferLength)
                {
                    memmove((UCHAR*)pPackedSrb + sizeof(PACKED_SRB),
                       (UCHAR*)pPackedSrb + (sizeof(PACKED_SRB) +
                        pPackedSrb->DataTransferLength), pPackedSrb->SenseInfoBufferLength);
                }
            }
        }
    }
    else
    {
        pHeader->Length = sizeof(REQUEST_HEADER);

        if ((pHeader->IoControlCode == IOCTL_SCSI_GET_ADDRESS) ||
            (pHeader->IoControlCode == IOCTL_STORAGE_QUERY_PROPERTY))
        {
            pHeader->Length += pHeader->Information;
        }
        else if (pHeader->IoControlCode == IOCTL_SCSI_PASS_THROUGH)
        {
            pPassThrough = (SCSI_PASS_THROUGH*)((UCHAR*)pHeader + sizeof(REQUEST_HEADER));

            if (NT_SUCCESS(pHeader->Status))
            {
                if ((pPassThrough->DataTransferLength) &&
                           (pPassThrough->DataIn == SCSI_IOCTL_DATA_IN))
                {
                    pHeader->Length += pPassThrough->DataBufferOffset +
                                           pPassThrough->DataTransferLength;
                }
                else pHeader->Length += sizeof(SCSI_PASS_THROUGH);
            }
            else
            {
                if (pPassThrough->SenseInfoLength)
                {
                    pHeader->Length += pPassThrough->SenseInfoOffset +
                                               pPassThrough->SenseInfoLength;
                }
                else pHeader->Length += sizeof(SCSI_PASS_THROUGH);
            }
        }
    }

    IoFreeIrp(pIrp2);

    CompleteRequest(pIrp, STATUS_SUCCESS, 0);
    IoReleaseRemoveLock(&pDeviceExtension->RemoveLock, pIrp);

    return STATUS_MORE_PROCESSING_REQUIRED;
}

NTSTATUS AllocateRequest(DEVICE_EXTENSION *pDeviceExtension, MDL *pMdl, IRP **ppIrp2)
{
    IRP *pIrp2;
    PVOID pBuffer;
    NTSTATUS Status;
    IO_STACK_LOCATION *pStack;
    SCSI_REQUEST_BLOCK *pSrb;
    PACKED_SRB *pPackedSrb;
    DEVICE_OBJECT *pDeviceObject;
    REQUEST_HEADER *pHeader;

    pHeader = (REQUEST_HEADER*)MmGetSystemAddressForMdlSafe(pMdl, NormalPagePriority);
    pDeviceObject = pDeviceExtension->pLowerDeviceObject;

    pIrp2 = IoAllocateIrp(pDeviceObject->StackSize, FALSE);

    if (pIrp2)
    {
        pStack = IoGetNextIrpStackLocation(pIrp2);

        pStack->DeviceObject = pDeviceObject;

        pStack->MajorFunction = pHeader->MajorFunction;
        pStack->MinorFunction = pHeader->MinorFunction;

        if (pHeader->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)
        {
            pPackedSrb = (PACKED_SRB*)((UCHAR*)pHeader + sizeof(REQUEST_HEADER));
            pSrb = (SCSI_REQUEST_BLOCK*)((UCHAR*)pPackedSrb +
                       (sizeof(PACKED_SRB) + pPackedSrb->DataTransferLength +
                        pPackedSrb->SenseInfoBufferLength));

            pSrb->Length = sizeof(SCSI_REQUEST_BLOCK);
            pSrb->Function = pPackedSrb->Function;
            pSrb->SrbStatus = pPackedSrb->SrbStatus;
            pSrb->ScsiStatus = pPackedSrb->ScsiStatus;
            pSrb->PathId = pPackedSrb->PathId;
            pSrb->TargetId = pPackedSrb->TargetId;
            pSrb->Lun = pPackedSrb->Lun;
            pSrb->QueueTag = pPackedSrb->QueueTag;
            pSrb->QueueAction = pPackedSrb->QueueAction;
            pSrb->CdbLength = pPackedSrb->CdbLength;
            pSrb->SenseInfoBufferLength = pPackedSrb->SenseInfoBufferLength;
            pSrb->SrbFlags = pPackedSrb->SrbFlags;
            pSrb->DataTransferLength = pPackedSrb->DataTransferLength;
            pSrb->TimeOutValue = pPackedSrb->TimeOutValue;

            if (pPackedSrb->DataTransferLength)
            {
                pSrb->DataBuffer = (UCHAR*)pMdl->StartVa + pMdl->ByteOffset +
                                   (sizeof(REQUEST_HEADER) + sizeof(PACKED_SRB));

                IoBuildPartialMdl(pMdl, pDeviceExtension->pMdl, pSrb->DataBuffer,
                                   pPackedSrb->DataTransferLength);

                pIrp2->MdlAddress = pDeviceExtension->pMdl;
            }
            else pSrb->DataBuffer = NULL;

            if (pPackedSrb->SenseInfoBufferLength)
            {
                pSrb->SenseInfoBuffer = (UCHAR*)pPackedSrb + (sizeof(PACKED_SRB) +
                                         pPackedSrb->DataTransferLength);
            }
            else pSrb->SenseInfoBuffer = NULL;

            pSrb->NextSrb = NULL;
            pSrb->OriginalRequest = pIrp2;
            pSrb->SrbExtension = NULL;

            pSrb->QueueSortKey = pPackedSrb->QueueSortKey;
            memcpy(pSrb->Cdb, pPackedSrb->Cdb, sizeof(pSrb->Cdb));

            pStack->Parameters.Scsi.Srb = pSrb;
        }
        else
        {
            pStack->Parameters.DeviceIoControl.IoControlCode = pHeader->IoControlCode;

            pBuffer = (UCHAR*)pHeader + sizeof(REQUEST_HEADER);

            if (pHeader->IoControlCode == IOCTL_SCSI_GET_ADDRESS)
            {
                pStack->Parameters.DeviceIoControl.OutputBufferLength =
                                                pHeader->OutputBufferLength;
                pIrp2->AssociatedIrp.SystemBuffer = pBuffer;
            }
            else if (pHeader->IoControlCode == IOCTL_STORAGE_QUERY_PROPERTY)
            {
                pStack->Parameters.DeviceIoControl.InputBufferLength =
                                                 pHeader->InputBufferLength;
                pStack->Parameters.DeviceIoControl.OutputBufferLength =
                                                 pHeader->OutputBufferLength;
                pIrp2->AssociatedIrp.SystemBuffer = pBuffer;
            }
            else if (pHeader->IoControlCode == IOCTL_STORAGE_ENABLE_IDLE_POWER)
            {
                pStack->Parameters.DeviceIoControl.InputBufferLength =
                                                   pHeader->InputBufferLength;
                pIrp2->AssociatedIrp.SystemBuffer = pBuffer;
            }
            else if (pHeader->IoControlCode == IOCTL_SCSI_PASS_THROUGH)
            {
                pStack->Parameters.DeviceIoControl.InputBufferLength =
                                                      pHeader->InputBufferLength;
                pStack->Parameters.DeviceIoControl.OutputBufferLength =
                                                      pHeader->OutputBufferLength;
                pIrp2->AssociatedIrp.SystemBuffer = pBuffer;
            }
        }

        *ppIrp2 = pIrp2;
        Status = STATUS_SUCCESS;
    }
    else Status = STATUS_INSUFFICIENT_RESOURCES;

    return Status;
}

NTSTATUS DispatchDeviceControl(DEVICE_OBJECT *pDeviceObject, IRP *pIrp)
{
    NTSTATUS Status;
    ULONG IoControlCode;
    IO_STACK_LOCATION *pStack;
    DEVICE_EXTENSION *pDeviceExtension;
    REQUEST_HEADER *pHeader;
    ULONG Information;
    IRP *pIrp2;

    Information = 0;

    pDeviceExtension = (DEVICE_EXTENSION*)pDeviceObject->DeviceExtension;
    pStack = IoGetCurrentIrpStackLocation(pIrp);

    Status = IoAcquireRemoveLock(&pDeviceExtension->RemoveLock, pIrp);

    if (NT_SUCCESS(Status))
    {
        IoControlCode = pStack->Parameters.DeviceIoControl.IoControlCode;

        if (IoControlCode == IOCTL_GET_PNP_INFO)
        {
            pHeader = (REQUEST_HEADER*)pIrp->AssociatedIrp.SystemBuffer;

            pHeader->Length = sizeof(REQUEST_HEADER)+pDeviceExtension->PnpLength;

            memcpy((UCHAR*)pHeader + sizeof(REQUEST_HEADER),
                       &pDeviceExtension->PnpInfo, pDeviceExtension->PnpLength);

            Information = pHeader->Length;
        }
        else if (IoControlCode == IOCTL_EXECUTE_REQUEST)
        {
            Status = AllocateRequest(pDeviceExtension, pIrp->MdlAddress, &pIrp2);

            if (NT_SUCCESS(Status))
            {
                pIrp->Tail.Overlay.DriverContext[0] = pDeviceExtension;

                IoSetCompletionRoutine(pIrp2, IoCompletionRoutine3, pIrp, TRUE, TRUE, TRUE);

                IoMarkIrpPending(pIrp);

                IoCallDriver(pDeviceExtension->pLowerDeviceObject, pIrp2);

                Status = STATUS_PENDING;
            }
        }
        else Status = STATUS_NOT_SUPPORTED;

        if (Status != STATUS_PENDING)
        {
            CompleteRequest(pIrp, Status, Information);
            IoReleaseRemoveLock(&pDeviceExtension->RemoveLock, pIrp);
        }
    }
    else
    {
        Status = STATUS_DEVICE_DOES_NOT_EXIST;
        CompleteRequest(pIrp, Status, Information);
    }

    return Status;
}

NTSTATUS DispatchPnp(DEVICE_OBJECT *pDeviceObject, IRP *pIrp)
{
    NTSTATUS Status;
    IO_STACK_LOCATION *pStack;
    DEVICE_EXTENSION *pDeviceExtension;
    POWER_STATE PowerState;
    ULONG_PTR Information;
    KEVENT Event;

    Information = 0;

    pDeviceExtension = (DEVICE_EXTENSION*)pDeviceObject->DeviceExtension;
    pStack = IoGetCurrentIrpStackLocation(pIrp);

    Status = IoAcquireRemoveLock(&pDeviceExtension->RemoveLock, pIrp);

    if (NT_SUCCESS(Status))
    {
        switch (pStack->MinorFunction)
        {
        case IRP_MN_START_DEVICE:
            KeInitializeEvent(&Event, NotificationEvent, FALSE);

            IoCopyCurrentIrpStackLocationToNext(pIrp);

            IoSetCompletionRoutine(pIrp, IoCompletionRoutine, &Event, TRUE, TRUE, TRUE);

            Status = IoCallDriver(pDeviceExtension->pLowerDeviceObject, pIrp);

            if (Status == STATUS_PENDING) KeWaitForSingleObject
                             (&Event, Executive, KernelMode, FALSE, NULL);

            Status = pIrp->IoStatus.Status;
            Information = pIrp->IoStatus.Information;

            if (NT_SUCCESS(Status))
            {
                Information = 0;

                Status = IoSetDeviceInterfaceState(&pDeviceExtension->SymbolicLinkName, TRUE);

                if (NT_SUCCESS(Status))
                {
                    PowerState.DeviceState = PowerDeviceD0;
                    PoSetPowerState(pDeviceObject, DevicePowerState, PowerState);
                }
            }

            CompleteRequest(pIrp, Status, Information);

            IoReleaseRemoveLock(&pDeviceExtension->RemoveLock, pIrp);
            break;
        case IRP_MN_REMOVE_DEVICE:
            PowerState.DeviceState = PowerDeviceD3;
            PoSetPowerState(pDeviceObject, DevicePowerState, PowerState);

            pIrp->IoStatus.Status = Status;
            pIrp->IoStatus.Information = Information;

            IoSkipCurrentIrpStackLocation(pIrp);
            Status = IoCallDriver(pDeviceExtension->pLowerDeviceObject, pIrp);

            IoReleaseRemoveLockAndWait(&pDeviceExtension->RemoveLock, pIrp);

            IoSetDeviceInterfaceState(&pDeviceExtension->SymbolicLinkName, FALSE);

            RtlFreeUnicodeString(&pDeviceExtension->SymbolicLinkName);

            IoFreeMdl(pDeviceExtension->pMdl);
            IoDetachDevice(pDeviceExtension->pLowerDeviceObject);
            IoDeleteDevice(pDeviceObject);
            break;
        case IRP_MN_SURPRISE_REMOVAL:
        case IRP_MN_QUERY_REMOVE_DEVICE:
        case IRP_MN_CANCEL_REMOVE_DEVICE:
        case IRP_MN_QUERY_STOP_DEVICE:
        case IRP_MN_CANCEL_STOP_DEVICE:
        case IRP_MN_STOP_DEVICE:
            pIrp->IoStatus.Status = Status;
            pIrp->IoStatus.Information = Information;

            IoSkipCurrentIrpStackLocation(pIrp);
            Status = IoCallDriver(pDeviceExtension->pLowerDeviceObject, pIrp);

            IoReleaseRemoveLock(&pDeviceExtension->RemoveLock, pIrp);
            break;
        default:
            Status = STATUS_NOT_SUPPORTED;

            pIrp->IoStatus.Status = Status;
            pIrp->IoStatus.Information = Information;

            IoSkipCurrentIrpStackLocation(pIrp);
            Status = IoCallDriver(pDeviceExtension->pLowerDeviceObject, pIrp);

            IoReleaseRemoveLock(&pDeviceExtension->RemoveLock, pIrp);
            break;
        }
    }
    else
    {
        Status = STATUS_DEVICE_DOES_NOT_EXIST;
        CompleteRequest(pIrp, Status, Information);
    }

    return Status;
}

NTSTATUS AddDevice(DRIVER_OBJECT *pDriverObject, DEVICE_OBJECT *pPhysicalDeviceObject)
{
    IRP *pIrp;
    MDL *pMdl;
    ULONG i, j;
    NTSTATUS Status;
    DEVICE_EXTENSION *pDeviceExtension;
    DEVICE_OBJECT *pDeviceObject, *pLowerDeviceObject;
    DEVICE_CAPABILITIES DeviceCapabilities;
    PNP_CONTEXT PnpContext;

    Status = IoCreateDevice(pDriverObject,
        sizeof(DEVICE_EXTENSION) - sizeof(PNP_INFO) + 2000,
        NULL,
        FILE_DEVICE_CONTROLLER,
        FILE_DEVICE_SECURE_OPEN,
        FALSE,
        &pDeviceObject);

    if (NT_SUCCESS(Status))
    {
        pDeviceExtension = (DEVICE_EXTENSION*)pDeviceObject->DeviceExtension;

        memset(pDeviceExtension, 0, sizeof(DEVICE_EXTENSION));

        pDeviceExtension->PnpLength = sizeof(PNP_INFO);

        pDeviceExtension->pDeviceObject = pDeviceObject;

        IoInitializeRemoveLock(&pDeviceExtension->RemoveLock, 0, 0, 0);

        pMdl = IoAllocateMdl(NULL, (32 + 1) * 4096, FALSE, FALSE, NULL);

        if (pMdl)
        {
            pLowerDeviceObject = IoAttachDeviceToDeviceStack
                                      (pDeviceObject, pPhysicalDeviceObject);

            if (pLowerDeviceObject)
            {
                Status = IoRegisterDeviceInterface(pPhysicalDeviceObject,
                          &g_ClassGuid, NULL, &pDeviceExtension->SymbolicLinkName);

                if (NT_SUCCESS(Status))
                {
                    pDeviceExtension->pMdl = pMdl;
                    pDeviceExtension->pLowerDeviceObject = pLowerDeviceObject;

                    PnpContext.pDeviceExtension = pDeviceExtension;
                    KeInitializeEvent(&PnpContext.Event, NotificationEvent, FALSE);

                    i = 0;
                    j = 0;

                    while (i < 3)
                    {
                        memset(&PnpContext.Stack, 0, sizeof(IO_STACK_LOCATION));

                        if (i == 0)
                        {
                            PnpContext.Stack.MinorFunction = IRP_MN_QUERY_CAPABILITIES;
                            PnpContext.Stack.Parameters.DeviceCapabilities.Capabilities =
                                                        &DeviceCapabilities;

                            memset(&DeviceCapabilities, 0, sizeof(DEVICE_CAPABILITIES));

                            DeviceCapabilities.Size = sizeof(DEVICE_CAPABILITIES);
                            DeviceCapabilities.Version = 1;

                            Status = AllocatePnpRequest(&PnpContext, &pIrp);

                            ++i;
                        }
                        else if (i == 1)
                        {
                            PnpContext.Stack.MinorFunction = IRP_MN_QUERY_ID;
                            PnpContext.Stack.Parameters.QueryId.IdType = (BUS_QUERY_ID_TYPE)j;

                            Status = AllocatePnpRequest(&PnpContext, &pIrp);

                            if (j == 5) { ++i; j = 0; }
                            else ++j;
                        }
                        else
                        {
                            PnpContext.Stack.MinorFunction = IRP_MN_QUERY_DEVICE_TEXT;
                            PnpContext.Stack.Parameters.QueryDeviceText.DeviceTextType =
                                                          (DEVICE_TEXT_TYPE)j;
                            PnpContext.Stack.Parameters.QueryDeviceText.LocaleId = 1033;

                            Status = AllocatePnpRequest(&PnpContext, &pIrp);

                            if (j == 1) { ++i; j = 0; }
                            else ++j;
                        }

                        if (NT_SUCCESS(Status))
                        {
                            IoSetCompletionRoutine
                             (pIrp, IoCompletionRoutine2, &PnpContext, TRUE, TRUE, TRUE);

                            Status = IoCallDriver(pLowerDeviceObject, pIrp);

                            if (Status == STATUS_PENDING)
                            {
                                KeWaitForSingleObject(&PnpContext.Event, Executive,
                                                         KernelMode, FALSE, NULL);
                            }

                            KeClearEvent(&PnpContext.Event);
                        }
                    }

                    pDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
                    Status = STATUS_SUCCESS;
                }
                else IoDetachDevice(pLowerDeviceObject);
            }
            else Status = STATUS_NO_SUCH_DEVICE;
        }
        else Status = STATUS_UNSUCCESSFUL;

        if (!NT_SUCCESS(Status))
        {
            if (pMdl) IoFreeMdl(pMdl);

            IoDeleteDevice(pDeviceObject);
        }
    }

    return Status;
}

客户端代码(已截断)

#define IOCTL_PLUGIN_DEVICE    CTL_CODE(FILE_DEVICE_CONTROLLER, 0, METHOD_BUFFERED,
                               FILE_ANY_ACCESS)
#define IOCTL_PLUGOUT_DEVICE   CTL_CODE(FILE_DEVICE_CONTROLLER, 1, METHOD_BUFFERED,
                               FILE_ANY_ACCESS)
#define IOCTL_FETCH_REQUEST    CTL_CODE(FILE_DEVICE_CONTROLLER, 2, METHOD_OUT_DIRECT,
                               FILE_ANY_ACCESS)
#define IOCTL_COMPLETE_REQUEST CTL_CODE(FILE_DEVICE_CONTROLLER, 3, METHOD_IN_DIRECT,
                               FILE_ANY_ACCESS)

struct PNP_ENTRY
{
    ULONG InfoOffset;
    ULONG InfoLength;
    NTSTATUS Status;
};

struct PNP_INFO
{
    PNP_ENTRY irp_mn_query_id[6];
    PNP_ENTRY irp_mn_query_device_text[2];
    PNP_ENTRY irp_mn_query_capabilities;
};

struct PACKED_SRB
{
    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];
};

struct REQUEST_HEADER
{
    ULONG Id;
    ULONG Op;
    ULONG Irp[2];
    ULONG Length;
    ULONG MajorFunction;
    ULONG MinorFunction;
    ULONG IoControlCode;
    ULONG InputBufferLength;
    ULONG OutputBufferLength;
    NTSTATUS Status;
    ULONG Information;
};

struct DEVICE_EXTENSION
{
    DEVICE_OBJECT *pDeviceObject;
    IO_REMOVE_LOCK RemoveLock;
    BOOLEAN Bus;
};

struct BUS_EXTENSION : public DEVICE_EXTENSION
{
    LIST_ENTRY StorageList;
    DEVICE_OBJECT *pPhysicalDeviceObject;
    DEVICE_OBJECT *pLowerDeviceObject;
    UNICODE_STRING SymbolicLinkName;
};

struct STORAGE_EXTENSION : public DEVICE_EXTENSION
{
    LIST_ENTRY IrpQueue;
    LIST_ENTRY IrpQueue2;
    LIST_ENTRY IrpQueue3;
    LIST_ENTRY ListEntry;
    BOOLEAN Marked;
    BOOLEAN Included;
    MDL *pMdl;
    PNP_INFO PnpInfo;
};

#define IRP_TO_LIST_ENTRY(_Irp)    ((LIST_ENTRY*)(((UCHAR*)_Irp) +
                                 FIELD_OFFSET(IRP, Tail.Overlay.ListEntry)))
#define IRP_FROM_LIST_ENTRY(_ListEntry)    ((IRP*)(((UCHAR*)_ListEntry) -
                                  FIELD_OFFSET(IRP, Tail.Overlay.ListEntry)))

#define STORAGE_EXTENSION_TO_LIST_ENTRY(_Extension)
   ((LIST_ENTRY*)(((UCHAR*)_Extension) + FIELD_OFFSET(STORAGE_EXTENSION, ListEntry)))
#define STORAGE_EXTENSION_FROM_LIST_ENTRY(_ListEntry)
   ((STORAGE_EXTENSION*)(((UCHAR*)_ListEntry) - FIELD_OFFSET(STORAGE_EXTENSION, ListEntry)))

void UnpackRequest(REQUEST_HEADER *pHeader, IRP *pIrp, STORAGE_EXTENSION *pStorageExtension)
{
    BOOLEAN Unmap;
    PVOID pBuffer;
    IO_STACK_LOCATION *pStack;
    PACKED_SRB *pPackedSrb;
    SCSI_REQUEST_BLOCK *pSrb;
    SCSI_PASS_THROUGH *pPassThrough;

    pStack = IoGetCurrentIrpStackLocation(pIrp);

    if (pHeader->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)
    {
        pPackedSrb = (PACKED_SRB*)((UCHAR*)pHeader + sizeof(REQUEST_HEADER));
        pSrb = pStack->Parameters.Scsi.Srb;

        pSrb->SrbStatus = pPackedSrb->SrbStatus;
        pSrb->ScsiStatus = pPackedSrb->ScsiStatus;

        pSrb->SenseInfoBufferLength = pPackedSrb->SenseInfoBufferLength;
        pSrb->DataTransferLength = pPackedSrb->DataTransferLength;

        if (NT_SUCCESS(pHeader->Status))
        {
            if ((pPackedSrb->DataTransferLength) && (pPackedSrb->SrbFlags & SRB_FLAGS_DATA_IN))
            {
                pBuffer = GetBuffer(pIrp->MdlAddress,
                          pStorageExtension->pMdl, pSrb->DataBuffer,
                          pPackedSrb->DataTransferLength, &Unmap);

                memcpy(pBuffer, (UCHAR*)pPackedSrb + sizeof(PACKED_SRB),
                                        pPackedSrb->DataTransferLength);

                if (Unmap) MmUnmapLockedPages(pBuffer, pStorageExtension->pMdl);
            }
            else
            {
                if (pPackedSrb->Function == SRB_FUNCTION_CLAIM_DEVICE)
                                    pSrb->DataBuffer = pStack->DeviceObject;
            }
        }
        else
        {
            if ((pPackedSrb->SenseInfoBufferLength) && (pPackedSrb->SrbStatus &
                                                 SRB_STATUS_AUTOSENSE_VALID))
            {
                memcpy(pSrb->SenseInfoBuffer, (UCHAR*)pPackedSrb + sizeof(PACKED_SRB),
                                           pPackedSrb->SenseInfoBufferLength);
            }
        }
    }
    else
    {
        if (pHeader->IoControlCode == IOCTL_SCSI_PASS_THROUGH)
        {
            pPassThrough = (SCSI_PASS_THROUGH*)((UCHAR*)pHeader + sizeof(REQUEST_HEADER));

            memcpy(pIrp->AssociatedIrp.SystemBuffer, pPassThrough, sizeof(SCSI_PASS_THROUGH));

            if (NT_SUCCESS(pHeader->Status))
            {
                if ((pPassThrough->DataTransferLength) &&
                                   (pPassThrough->DataIn == SCSI_IOCTL_DATA_IN))
                {
                    memcpy((UCHAR*)pIrp->AssociatedIrp.SystemBuffer +
                           pPassThrough->DataBufferOffset, (UCHAR*)pPassThrough +
                           pPassThrough->DataBufferOffset, pPassThrough->DataTransferLength);
                }
            }
            else
            {
                memcpy((UCHAR*)pIrp->AssociatedIrp.SystemBuffer +
                     pPassThrough->SenseInfoOffset, (UCHAR*)pPassThrough +
                     pPassThrough->SenseInfoOffset, pPassThrough->SenseInfoLength);
            }
        }
        else
        {
            if (NT_SUCCESS(pHeader->Status))
            {
                if ((pHeader->IoControlCode == IOCTL_SCSI_GET_ADDRESS) ||
                    (pHeader->IoControlCode == IOCTL_STORAGE_QUERY_PROPERTY))
                {
                    memcpy(pIrp->AssociatedIrp.SystemBuffer, (UCHAR*)pHeader +
                              sizeof(REQUEST_HEADER), pHeader->Information);
                }
            }
        }
    }
}

void PackRequest(IRP *pIrp, REQUEST_HEADER *pHeader, STORAGE_EXTENSION *pStorageExtension)
{
    BOOLEAN Unmap;
    PVOID pBuffer;
    IO_STACK_LOCATION *pStack;
    PACKED_SRB *pPackedSrb;
    SCSI_REQUEST_BLOCK *pSrb;
    SCSI_PASS_THROUGH *pPassThrough;

    pStack = IoGetCurrentIrpStackLocation(pIrp);

    *((IRP**)pHeader->Irp) = pIrp;

    pHeader->Status = 0;
    pHeader->Information = 0;

    pHeader->MajorFunction = pStack->MajorFunction;
    pHeader->MinorFunction = pStack->MinorFunction;

    if (pStack->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)
    {
        pHeader->IoControlCode = 0;
        pHeader->InputBufferLength = 0;
        pHeader->OutputBufferLength = 0;
        pHeader->Length = sizeof(REQUEST_HEADER) + sizeof(PACKED_SRB);

        pPackedSrb = (PACKED_SRB*)((UCHAR*)pHeader + sizeof(REQUEST_HEADER));
        pSrb = pStack->Parameters.Scsi.Srb;

        pPackedSrb->Function = pSrb->Function;
        pPackedSrb->SrbStatus = pSrb->SrbStatus;
        pPackedSrb->ScsiStatus = pSrb->ScsiStatus;
        pPackedSrb->PathId = pSrb->PathId;
        pPackedSrb->TargetId = pSrb->TargetId;
        pPackedSrb->Lun = pSrb->Lun;
        pPackedSrb->QueueTag = pSrb->QueueTag;
        pPackedSrb->QueueAction = pSrb->QueueAction;
        pPackedSrb->CdbLength = pSrb->CdbLength;
        pPackedSrb->SenseInfoBufferLength = pSrb->SenseInfoBufferLength;
        pPackedSrb->SrbFlags = pSrb->SrbFlags;
        pPackedSrb->DataTransferLength = pSrb->DataTransferLength;
        pPackedSrb->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*)pPackedSrb +
                  sizeof(PACKED_SRB), pBuffer, pSrb->DataTransferLength);

            if (Unmap) MmUnmapLockedPages(pBuffer, pStorageExtension->pMdl);

            pHeader->Length += pSrb->DataTransferLength;
        }

        pPackedSrb->QueueSortKey = pSrb->QueueSortKey;
        memcpy(pPackedSrb->Cdb, pSrb->Cdb, sizeof(pSrb->Cdb));
    }
    else
    {
        pHeader->IoControlCode = pStack->Parameters.DeviceIoControl.IoControlCode;
        pHeader->InputBufferLength = pStack->Parameters.DeviceIoControl.InputBufferLength;
        pHeader->OutputBufferLength = pStack->Parameters.DeviceIoControl.OutputBufferLength;

        pHeader->Length = sizeof(REQUEST_HEADER);

        if ((pHeader->IoControlCode == IOCTL_STORAGE_QUERY_PROPERTY) ||
            (pHeader->IoControlCode == IOCTL_STORAGE_ENABLE_IDLE_POWER))
        {
            pHeader->Length += pHeader->InputBufferLength;
            memcpy((UCHAR*)pHeader + sizeof(REQUEST_HEADER),
                    pIrp->AssociatedIrp.SystemBuffer, pHeader->InputBufferLength);
        }
        else if (pHeader->IoControlCode == IOCTL_SCSI_PASS_THROUGH)
        {
            pPassThrough = (SCSI_PASS_THROUGH*)pIrp->AssociatedIrp.SystemBuffer;

            memcpy((UCHAR*)pHeader + sizeof(REQUEST_HEADER), pPassThrough,
                                     sizeof(SCSI_PASS_THROUGH));

            if ((pPassThrough->DataTransferLength) &&
                           (pPassThrough->DataIn == SCSI_IOCTL_DATA_OUT))
            {
                pHeader->Length += pPassThrough->DataBufferOffset +
                                          pPassThrough->DataTransferLength;
                memcpy((UCHAR*)pHeader + sizeof(REQUEST_HEADER) +
                              pPassThrough->DataBufferOffset, (UCHAR*)pPassThrough +
                              pPassThrough->DataBufferOffset, pPassThrough->DataTransferLength);
            }
            else
            {
                pHeader->Length += sizeof(SCSI_PASS_THROUGH);
            }
        }
        else if ((pHeader->IoControlCode != IOCTL_STORAGE_POWER_ACTIVE) &&
            (pHeader->IoControlCode != IOCTL_SCSI_GET_ADDRESS))
        {
            DbgRaiseAssertionFailure();
        }
    }
}

NTSTATUS DispatchPnp(DEVICE_OBJECT *pDeviceObject, IRP *pIrp)
{
    NTSTATUS Status;
    IO_STACK_LOCATION *pStack;
    DEVICE_EXTENSION *pDeviceExtension;
    BUS_EXTENSION *pBusExtension;
    STORAGE_EXTENSION *pStorageExtension;
    POWER_STATE PowerState;
    ULONG_PTR Information;
    DEVICE_RELATIONS *pDeviceRelations;
    DEVICE_TEXT_TYPE DeviceTextType;
    BUS_QUERY_ID_TYPE BusQueryIdType;
    LIST_ENTRY *pListEntry;
    PNP_ENTRY *pPnpEntry;
    KEVENT Event;
    ULONG Count, i;

    Information = 0;

    pDeviceExtension = (DEVICE_EXTENSION*)pDeviceObject->DeviceExtension;
    pStack = IoGetCurrentIrpStackLocation(pIrp);

    Status = IoAcquireRemoveLock(&pDeviceExtension->RemoveLock, pIrp);

    if (NT_SUCCESS(Status))
    {
        if (pDeviceExtension->Bus)
        {
            pBusExtension = (BUS_EXTENSION*)pDeviceExtension;

            switch (pStack->MinorFunction)
            {
            case IRP_MN_START_DEVICE:
                KeInitializeEvent(&Event, NotificationEvent, FALSE);

                IoCopyCurrentIrpStackLocationToNext(pIrp);

                IoSetCompletionRoutine(pIrp, IoCompletionRoutine, &Event, TRUE, TRUE, TRUE);

                Status = IoCallDriver(pBusExtension->pLowerDeviceObject, pIrp);

                if (Status == STATUS_PENDING) KeWaitForSingleObject
                              (&Event, Executive, KernelMode, FALSE, NULL);

                Status = pIrp->IoStatus.Status;
                Information = pIrp->IoStatus.Information;

                if (NT_SUCCESS(Status))
                {
                    Information = 0;

                    Status = IoSetDeviceInterfaceState(&pBusExtension->SymbolicLinkName, TRUE);

                    if (NT_SUCCESS(Status))
                    {
                        PowerState.DeviceState = PowerDeviceD0;
                        PoSetPowerState(pDeviceObject, DevicePowerState, PowerState);
                    }
                }

                CompleteRequest(pIrp, Status, Information);

                IoReleaseRemoveLock(&pBusExtension->RemoveLock, pIrp);
                break;
            case IRP_MN_QUERY_DEVICE_RELATIONS:
                if (pStack->Parameters.QueryDeviceRelations.Type == BusRelations)
                {
                    Count = 0;
                    pListEntry = pBusExtension->StorageList.Flink;

                    while (pListEntry != &pBusExtension->StorageList)
                    {
                        pStorageExtension = STORAGE_EXTENSION_FROM_LIST_ENTRY(pListEntry);

                        if (!pStorageExtension->Marked) ++Count;

                        pListEntry = pListEntry->Flink;
                    }

                    pDeviceRelations = (DEVICE_RELATIONS*)ExAllocatePool
                   (PagedPool, sizeof(DEVICE_RELATIONS) + (sizeof(PDEVICE_OBJECT) * Count));

                    if (pDeviceRelations)
                    {
                        pDeviceRelations->Count = Count;

                        i = 0;
                        pListEntry = pBusExtension->StorageList.Flink;

                        while (pListEntry != &pBusExtension->StorageList)
                        {
                            pStorageExtension = STORAGE_EXTENSION_FROM_LIST_ENTRY(pListEntry);

                            if (!pStorageExtension->Marked)
                            {
                                ObReferenceObject(pStorageExtension->pDeviceObject);
                                pDeviceRelations->Objects[i] = pStorageExtension->pDeviceObject;
                                pStorageExtension->Included = TRUE;
                                ++i;
                            }
                            else
                            {
                                pStorageExtension->Included = FALSE;
                                RemoveEntryList(pListEntry);
                            }

                            pListEntry = pListEntry->Flink;
                        }

                        Information = (ULONG_PTR)pDeviceRelations;
                    }
                    else Status = STATUS_INSUFFICIENT_RESOURCES;
                }
                else Status = STATUS_NOT_SUPPORTED;

                pIrp->IoStatus.Status = Status;
                pIrp->IoStatus.Information = Information;

                IoSkipCurrentIrpStackLocation(pIrp);
                Status = IoCallDriver(pBusExtension->pLowerDeviceObject, pIrp);

                IoReleaseRemoveLock(&pBusExtension->RemoveLock, pIrp);
                break;
            case IRP_MN_REMOVE_DEVICE:
                PowerState.DeviceState = PowerDeviceD3;
                PoSetPowerState(pDeviceObject, DevicePowerState, PowerState);

                pIrp->IoStatus.Status = Status;
                pIrp->IoStatus.Information = Information;

                IoSkipCurrentIrpStackLocation(pIrp);
                Status = IoCallDriver(pBusExtension->pLowerDeviceObject, pIrp);

                IoReleaseRemoveLockAndWait(&pBusExtension->RemoveLock, pIrp);

                IoSetDeviceInterfaceState(&pBusExtension->SymbolicLinkName, FALSE);

                RtlFreeUnicodeString(&pBusExtension->SymbolicLinkName);

                IoDetachDevice(pBusExtension->pLowerDeviceObject);
                IoDeleteDevice(pDeviceObject);
                break;
            case IRP_MN_SURPRISE_REMOVAL:
            case IRP_MN_QUERY_REMOVE_DEVICE:
            case IRP_MN_CANCEL_REMOVE_DEVICE:
            case IRP_MN_QUERY_STOP_DEVICE:
            case IRP_MN_CANCEL_STOP_DEVICE:
            case IRP_MN_STOP_DEVICE:
                pIrp->IoStatus.Status = Status;
                pIrp->IoStatus.Information = Information;

                IoSkipCurrentIrpStackLocation(pIrp);
                Status = IoCallDriver(pBusExtension->pLowerDeviceObject, pIrp);

                IoReleaseRemoveLock(&pBusExtension->RemoveLock, pIrp);
                break;
            default:
                Status = STATUS_NOT_SUPPORTED;

                pIrp->IoStatus.Status = Status;
                pIrp->IoStatus.Information = Information;

                IoSkipCurrentIrpStackLocation(pIrp);
                Status = IoCallDriver(pBusExtension->pLowerDeviceObject, pIrp);

                IoReleaseRemoveLock(&pBusExtension->RemoveLock, pIrp);
                break;
            }
        }
        else
        {
            pStorageExtension = (STORAGE_EXTENSION*)pDeviceExtension;

            switch (pStack->MinorFunction)
            {
            case IRP_MN_START_DEVICE:
                PowerState.DeviceState = PowerDeviceD0;
                PoSetPowerState(pDeviceObject, DevicePowerState, PowerState);

                CompleteRequest(pIrp, Status, Information);
                IoReleaseRemoveLock(&pStorageExtension->RemoveLock, pIrp);
                break;
            case IRP_MN_QUERY_REMOVE_DEVICE:
            case IRP_MN_SURPRISE_REMOVAL:
                CompleteOutstandingRequests(pStorageExtension);
                pStorageExtension->Marked = TRUE;

                CompleteRequest(pIrp, Status, Information);
                IoReleaseRemoveLock(&pStorageExtension->RemoveLock, pIrp);
                break;
            case IRP_MN_CANCEL_REMOVE_DEVICE:
                pStorageExtension->Marked = FALSE;

                CompleteRequest(pIrp, Status, Information);
                IoReleaseRemoveLock(&pStorageExtension->RemoveLock, pIrp);
                break;
            case IRP_MN_QUERY_STOP_DEVICE:
            case IRP_MN_CANCEL_STOP_DEVICE:
            case IRP_MN_STOP_DEVICE:
                CompleteRequest(pIrp, Status, Information);
                IoReleaseRemoveLock(&pStorageExtension->RemoveLock, pIrp);
                break;
            case IRP_MN_REMOVE_DEVICE:
                if (pStorageExtension->Included)
                {
                    CompleteRequest(pIrp, Status, Information);
                    IoReleaseRemoveLock(&pStorageExtension->RemoveLock, pIrp);
                }
                else
                {
                    PowerState.DeviceState = PowerDeviceD3;
                    PoSetPowerState(pDeviceObject, DevicePowerState, PowerState);

                    CompleteRequest(pIrp, Status, Information);
                    IoReleaseRemoveLockAndWait(&pStorageExtension->RemoveLock, pIrp);

                    IoFreeMdl(pStorageExtension->pMdl);
                    IoDeleteDevice(pDeviceObject);
                }

                break;
            case IRP_MN_QUERY_DEVICE_RELATIONS:
                if (pStack->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation)
                {
                    pDeviceRelations = (DEVICE_RELATIONS*)ExAllocatePool
                                       (PagedPool, sizeof(DEVICE_RELATIONS));

                    if (pDeviceRelations)
                    {
                        ObReferenceObject(pDeviceObject);

                        pDeviceRelations->Count = 1;
                        pDeviceRelations->Objects[0] = pDeviceObject;

                        Information = (ULONG_PTR)pDeviceRelations;
                    }
                    else Status = STATUS_INSUFFICIENT_RESOURCES;
                }
                else Status = STATUS_NOT_SUPPORTED;

                CompleteRequest(pIrp, Status, Information);
                IoReleaseRemoveLock(&pStorageExtension->RemoveLock, pIrp);
                break;
            case IRP_MN_QUERY_DEVICE_TEXT:
                DeviceTextType = pStack->Parameters.QueryDeviceText.DeviceTextType;
                pPnpEntry =
                   &pStorageExtension->PnpInfo.irp_mn_query_device_text[DeviceTextType];

                Status = pPnpEntry->Status;

                if (NT_SUCCESS(Status) && pPnpEntry->InfoOffset)
                {
                    Information = (ULONG_PTR)ExAllocatePool(PagedPool, pPnpEntry->InfoLength);

                    if (Information)
                    {
                        memcpy((UCHAR*)Information, (UCHAR*)&pStorageExtension->PnpInfo +
                                      pPnpEntry->InfoOffset, pPnpEntry->InfoLength);
                    }
                    else Status = STATUS_INSUFFICIENT_RESOURCES;
                }

                CompleteRequest(pIrp, Status, Information);
                IoReleaseRemoveLock(&pStorageExtension->RemoveLock, pIrp);
                break;
            case IRP_MN_QUERY_ID:
                BusQueryIdType = pStack->Parameters.QueryId.IdType;
                pPnpEntry = &pStorageExtension->PnpInfo.irp_mn_query_id[BusQueryIdType];

                Status = pPnpEntry->Status;

                if (NT_SUCCESS(Status) && pPnpEntry->InfoOffset)
                {
                    Information = (ULONG_PTR)ExAllocatePool(PagedPool, pPnpEntry->InfoLength);

                    if (Information)
                    {
                        memcpy((UCHAR*)Information, (UCHAR*)&pStorageExtension->PnpInfo +
                                   pPnpEntry->InfoOffset, pPnpEntry->InfoLength);
                    }
                    else Status = STATUS_INSUFFICIENT_RESOURCES;
                }

                CompleteRequest(pIrp, Status, Information);
                IoReleaseRemoveLock(&pStorageExtension->RemoveLock, pIrp);
                break;
            case IRP_MN_QUERY_CAPABILITIES:
                pPnpEntry = &pStorageExtension->PnpInfo.irp_mn_query_capabilities;

                Status = pPnpEntry->Status;

                if (NT_SUCCESS(Status) && pPnpEntry->InfoOffset)
                {
                    memcpy(pStack->Parameters.DeviceCapabilities.Capabilities,
                       (UCHAR*)&pStorageExtension->PnpInfo + pPnpEntry->InfoOffset,
                       pPnpEntry->InfoLength);
                }

                CompleteRequest(pIrp, Status, Information);
                IoReleaseRemoveLock(&pStorageExtension->RemoveLock, pIrp);
                break;
            default:
                Status = STATUS_NOT_SUPPORTED;

                CompleteRequest(pIrp, Status, Information);
                IoReleaseRemoveLock(&pStorageExtension->RemoveLock, pIrp);
                break;
            }
        }
    }
    else
    {
        Status = STATUS_DEVICE_DOES_NOT_EXIST;
        CompleteRequest(pIrp, Status, Information);
    }

    return Status;
}

NTSTATUS DispatchDeviceControl(DEVICE_OBJECT *pDeviceObject, IRP *pIrp)
{
    NTSTATUS Status;
    ULONG IoControlCode;
    IO_STACK_LOCATION *pStack;
    DEVICE_EXTENSION *pDeviceExtension;
    STORAGE_EXTENSION *pStorageExtension;
    BUS_EXTENSION *pBusExtension;
    PNP_INFO *pPnpInfo;
    LIST_ENTRY *pListEntry;
    IRP *pIrp2;
    MDL *pMdl;
    REQUEST_HEADER *pHeader;

    pDeviceExtension = (DEVICE_EXTENSION*)pDeviceObject->DeviceExtension;
    pStack = IoGetCurrentIrpStackLocation(pIrp);

    Status = IoAcquireRemoveLock(&pDeviceExtension->RemoveLock, pIrp);

    if (NT_SUCCESS(Status))
    {
        if (pDeviceExtension->Bus)
        {
            pBusExtension = (BUS_EXTENSION*)pDeviceExtension;
            IoControlCode = pStack->Parameters.DeviceIoControl.IoControlCode;

            if (IoControlCode == IOCTL_PLUGIN_DEVICE)
            {
                pHeader = (REQUEST_HEADER*)pIrp->AssociatedIrp.SystemBuffer;
                pPnpInfo = (PNP_INFO*)((UCHAR*)pHeader + sizeof(REQUEST_HEADER));

                Status = IoCreateDevice(pDeviceObject->DriverObject,
                    sizeof(STORAGE_EXTENSION) + (pHeader->Length -
                           (sizeof(REQUEST_HEADER) + sizeof(PNP_INFO))),
                    NULL,
                    FILE_DEVICE_MASS_STORAGE,
                    FILE_DEVICE_SECURE_OPEN | FILE_AUTOGENERATED_DEVICE_NAME,
                    FALSE,
                    &pDeviceObject);

                if (NT_SUCCESS(Status))
                {
                    pMdl = IoAllocateMdl(NULL, (32 + 1) * 4096, FALSE, FALSE, NULL);

                    if (pMdl)
                    {
                        pStorageExtension = (STORAGE_EXTENSION*)pDeviceObject->DeviceExtension;

                        memset(pStorageExtension, 0, sizeof(STORAGE_EXTENSION) - sizeof(PNP_INFO));
                        memcpy(&pStorageExtension->PnpInfo, 
                        pPnpInfo, pHeader->Length - sizeof(REQUEST_HEADER));

                        pStorageExtension->pDeviceObject = pDeviceObject;
                        pStorageExtension->Bus = FALSE;
                        pStorageExtension->Included = FALSE;
                        pStorageExtension->Marked = FALSE;

                        InitializeListHead(&pStorageExtension->IrpQueue);
                        InitializeListHead(&pStorageExtension->IrpQueue2);
                        InitializeListHead(&pStorageExtension->IrpQueue3);

                        IoInitializeRemoveLock(&pStorageExtension->RemoveLock, 0, 0, 0);

                        InsertTailList(&pBusExtension->StorageList, 
                        STORAGE_EXTENSION_TO_LIST_ENTRY(pStorageExtension));

                        pStorageExtension->pMdl = pMdl;

                        ObReferenceObject(pDeviceObject);
                        pStack->FileObject->FsContext = pDeviceObject;

                        pDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;

                        IoInvalidateDeviceRelations(pBusExtension->pPhysicalDeviceObject, BusRelations);
                    }
                    else
                    {
                        Status = STATUS_INSUFFICIENT_RESOURCES;
                        IoDeleteDevice(pDeviceObject);
                    }
                }
            }
            else if (IoControlCode == IOCTL_PLUGOUT_DEVICE)
            {
                pDeviceObject = (DEVICE_OBJECT*)pStack->FileObject->FsContext;

                if (pDeviceObject)
                {
                    pStorageExtension = (STORAGE_EXTENSION*)pDeviceObject->DeviceExtension;

                    CompleteOutstandingRequests(pStorageExtension);
                    pStorageExtension->Marked = TRUE;

                    IoInvalidateDeviceRelations(pBusExtension->pPhysicalDeviceObject, BusRelations);
                }
                else Status = STATUS_DEVICE_DOES_NOT_EXIST;
            }
            else if (IoControlCode == IOCTL_FETCH_REQUEST)
            {
                pDeviceObject = (DEVICE_OBJECT*)pStack->FileObject->FsContext;

                if (pDeviceObject)
                {
                    pStorageExtension = (STORAGE_EXTENSION*)pDeviceObject->DeviceExtension;

                    Status = IoAcquireRemoveLock(&pStorageExtension->RemoveLock, pIrp);

                    if (NT_SUCCESS(Status))
                    {
                        if (!pStorageExtension->Marked)
                        {
                            if (!IsListEmpty(&pStorageExtension->IrpQueue))
                            {
                                pListEntry = pStorageExtension->IrpQueue.Flink;
                                RemoveEntryList(pListEntry);
                                InsertTailList(&pStorageExtension->IrpQueue2, pListEntry);

                                pHeader = (REQUEST_HEADER*)
                                MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);
                                PackRequest(IRP_FROM_LIST_ENTRY(pListEntry), pHeader, pStorageExtension);

                                IoReleaseRemoveLock(&pStorageExtension->RemoveLock, pIrp);
                            }
                            else
                            {
                                InsertTailList(&pStorageExtension->IrpQueue3, IRP_TO_LIST_ENTRY(pIrp));

                                IoMarkIrpPending(pIrp);
                                Status = STATUS_PENDING;
                            }
                        }
                        else
                        {
                            IoReleaseRemoveLock(&pStorageExtension->RemoveLock, pIrp);
                            Status = STATUS_DEVICE_DOES_NOT_EXIST;
                        }
                    }
                    else Status = STATUS_DEVICE_DOES_NOT_EXIST;
                }
                else Status = STATUS_DEVICE_DOES_NOT_EXIST;
            }
            else if (IoControlCode == IOCTL_COMPLETE_REQUEST)
            {
                pDeviceObject = (DEVICE_OBJECT*)pStack->FileObject->FsContext;

                if (pDeviceObject)
                {
                    pStorageExtension = (STORAGE_EXTENSION*)pDeviceObject->DeviceExtension;

                    if (!pStorageExtension->Marked)
                    {
                        pHeader = (REQUEST_HEADER*)pIrp->AssociatedIrp.SystemBuffer;

                        pIrp2 = *((IRP**)pHeader->Irp);
                        RemoveEntryList(IRP_TO_LIST_ENTRY(pIrp2));

                        UnpackRequest(pHeader, pIrp2, pStorageExtension);

                        CompleteRequest(pIrp2, pHeader->Status, pHeader->Information);
                        IoReleaseRemoveLock(&pStorageExtension->RemoveLock, pIrp2);
                    }
                    else Status = STATUS_DEVICE_DOES_NOT_EXIST;
                }
                else Status = STATUS_DEVICE_DOES_NOT_EXIST;
            }
            else Status = STATUS_NOT_SUPPORTED;

            if (Status != STATUS_PENDING) CompleteRequest(pIrp, Status, 0);

            IoReleaseRemoveLock(&pDeviceExtension->RemoveLock, pIrp);
        }
        else
        {
            pStorageExtension = (STORAGE_EXTENSION*)pDeviceExtension;

            if (!pStorageExtension->Marked)
            {
                if (RequestSupported(pIrp))
                {
                    if (!IsListEmpty(&pStorageExtension->IrpQueue3))
                    {
                        pListEntry = pStorageExtension->IrpQueue3.Flink;
                        RemoveEntryList(pListEntry);

                        InsertTailList(&pStorageExtension->IrpQueue2, IRP_TO_LIST_ENTRY(pIrp));

                        pIrp2 = IRP_FROM_LIST_ENTRY(pListEntry);
                        pHeader = (REQUEST_HEADER*)
                        MmGetSystemAddressForMdlSafe(pIrp2->MdlAddress, NormalPagePriority);
                        PackRequest(pIrp, pHeader, pStorageExtension);

                        CompleteRequest(pIrp2, STATUS_SUCCESS, 0);
                        IoReleaseRemoveLock(&pStorageExtension->RemoveLock, pIrp2);
                    }
                    else
                    {
                        InsertTailList(&pStorageExtension->IrpQueue, IRP_TO_LIST_ENTRY(pIrp));
                    }

                    IoMarkIrpPending(pIrp);
                    Status = STATUS_PENDING;
                }
                else
                {
                    Status = STATUS_NOT_SUPPORTED;

                    CompleteRequest(pIrp, Status, 0);
                    IoReleaseRemoveLock(&pDeviceExtension->RemoveLock, pIrp);
                }
            }
            else
            {
                Status = STATUS_DEVICE_DOES_NOT_EXIST;

                CompleteRequest(pIrp, Status, 0);
                IoReleaseRemoveLock(&pDeviceExtension->RemoveLock, pIrp);
            }
        }
    }
    else
    {
        Status = STATUS_DEVICE_DOES_NOT_EXIST;
        CompleteRequest(pIrp, Status, 0);
    }

    return Status;
}

NTSTATUS DispatchInternalDeviceControl(DEVICE_OBJECT *pDeviceObject, IRP *pIrp)
{
    NTSTATUS Status;
    IO_STACK_LOCATION *pStack;
    SCSI_REQUEST_BLOCK *pSrb;
    DEVICE_EXTENSION *pDeviceExtension;
    STORAGE_EXTENSION *pStorageExtension;
    LIST_ENTRY *pListEntry;
    IRP *pIrp2;
    REQUEST_HEADER *pHeader;

    pDeviceExtension = (DEVICE_EXTENSION*)pDeviceObject->DeviceExtension;
    pStack = IoGetCurrentIrpStackLocation(pIrp);

    Status = IoAcquireRemoveLock(&pDeviceExtension->RemoveLock, pIrp);

    if (NT_SUCCESS(Status))
    {
        if (!pDeviceExtension->Bus)
        {
            pStorageExtension = (STORAGE_EXTENSION*)pDeviceExtension;
            pSrb = pStack->Parameters.Scsi.Srb;

            if (!pStorageExtension->Marked)
            {
                if (!IsListEmpty(&pStorageExtension->IrpQueue3))
                {
                    pListEntry = pStorageExtension->IrpQueue3.Flink;
                    RemoveEntryList(pListEntry);

                    InsertTailList(&pStorageExtension->IrpQueue2, IRP_TO_LIST_ENTRY(pIrp));

                    pIrp2 = IRP_FROM_LIST_ENTRY(pListEntry);
                    pHeader = (REQUEST_HEADER*)MmGetSystemAddressForMdlSafe
                    (pIrp2->MdlAddress, NormalPagePriority);
                    PackRequest(pIrp, pHeader, pStorageExtension);

                    CompleteRequest(pIrp2, STATUS_SUCCESS, 0);
                    IoReleaseRemoveLock(&pStorageExtension->RemoveLock, pIrp2);
                }
                else
                {
                    InsertTailList(&pStorageExtension->IrpQueue, IRP_TO_LIST_ENTRY(pIrp));
                }

                IoMarkIrpPending(pIrp);

                pSrb->SrbStatus = SRB_STATUS_PENDING;
                Status = STATUS_PENDING;
            }
            else
            {
                pSrb->SrbStatus = SRB_STATUS_NO_DEVICE;
                Status = STATUS_DEVICE_DOES_NOT_EXIST;

                CompleteRequest(pIrp, Status, 0);
                IoReleaseRemoveLock(&pDeviceExtension->RemoveLock, pIrp);
            }
        }
        else
        {
            Status = STATUS_NOT_SUPPORTED;

            CompleteRequest(pIrp, Status, 0);
            IoReleaseRemoveLock(&pDeviceExtension->RemoveLock, pIrp);
        }
    }
    else
    {
        if (!pDeviceExtension->Bus)
        {
            pSrb = pStack->Parameters.Scsi.Srb;
            pSrb->SrbStatus = SRB_STATUS_NO_DEVICE;
        }

        Status = STATUS_DEVICE_DOES_NOT_EXIST;
        CompleteRequest(pIrp, Status, 0);
    }

    return Status;
}

NTSTATUS DispatchCreate(DEVICE_OBJECT *pDeviceObject, IRP *pIrp)
{
    NTSTATUS Status;

    Status = STATUS_SUCCESS;
    CompleteRequest(pIrp, Status, 0);
    return Status;
}

NTSTATUS DispatchCleanup(DEVICE_OBJECT *pDeviceObject, IRP *pIrp)  // handle reference
                                               // count on a file object has reached zero
{
    NTSTATUS Status;
    BUS_EXTENSION *pBusExtension;
    DEVICE_EXTENSION *pDeviceExtension;
    STORAGE_EXTENSION *pStorageExtension;
    IO_STACK_LOCATION *pStack;

    pDeviceExtension = (DEVICE_EXTENSION*)pDeviceObject->DeviceExtension;
    pStack = IoGetCurrentIrpStackLocation(pIrp);

    Status = IoAcquireRemoveLock(&pDeviceExtension->RemoveLock, pIrp);

    if (NT_SUCCESS(Status))
    {
        if (pDeviceExtension->Bus)
        {
            pBusExtension = (BUS_EXTENSION*)pDeviceObject->DeviceExtension;

            pDeviceObject = (DEVICE_OBJECT*)pStack->FileObject->FsContext;

            if (pDeviceObject)
            {
                pStorageExtension = (STORAGE_EXTENSION*)pDeviceObject->DeviceExtension;

                CompleteOutstandingRequests(pStorageExtension);
                pStorageExtension->Marked = TRUE;

                IoInvalidateDeviceRelations(pBusExtension->pPhysicalDeviceObject, BusRelations);
            }
        }

        CompleteRequest(pIrp, Status, 0);
        IoReleaseRemoveLock(&pDeviceExtension->RemoveLock, pIrp);
    }
    else
    {
        Status = STATUS_SUCCESS;
        CompleteRequest(pIrp, Status, 0);
    }

    return Status;
}

NTSTATUS DispatchClose(DEVICE_OBJECT *pDeviceObject, IRP *pIrp)   // reference count
                                                      // on a file object has reached zero
{
    NTSTATUS Status;
    DEVICE_EXTENSION *pDeviceExtension;
    IO_STACK_LOCATION *pStack;

    pDeviceExtension = (DEVICE_EXTENSION*)pDeviceObject->DeviceExtension;
    pStack = IoGetCurrentIrpStackLocation(pIrp);

    if (pDeviceExtension->Bus)
    {
        pDeviceObject = (DEVICE_OBJECT*)pStack->FileObject->FsContext;

        if (pDeviceObject) ObDereferenceObject(pDeviceObject);
    }

    Status = STATUS_SUCCESS;
    CompleteRequest(pIrp, Status, 0);
    return Status;
}

NTSTATUS AddDevice(DRIVER_OBJECT *pDriverObject, DEVICE_OBJECT *pPhysicalDeviceObject)
{
    NTSTATUS Status;
    BUS_EXTENSION *pBusExtension;
    DEVICE_OBJECT *pDeviceObject, *pLowerDeviceObject;

    Status = IoCreateDevice(pDriverObject,
        sizeof(BUS_EXTENSION),
        NULL,
        FILE_DEVICE_CONTROLLER,
        FILE_DEVICE_SECURE_OPEN,
        FALSE,
        &pDeviceObject);

    if (NT_SUCCESS(Status))
    {
        pBusExtension = (BUS_EXTENSION*)pDeviceObject->DeviceExtension;

        memset(pBusExtension, 0, sizeof(BUS_EXTENSION));

        pBusExtension->pDeviceObject = pDeviceObject;
        pBusExtension->Bus = TRUE;

        IoInitializeRemoveLock(&pBusExtension->RemoveLock, 0, 0, 0);

        InitializeListHead(&pBusExtension->StorageList);

        pBusExtension->pPhysicalDeviceObject = pPhysicalDeviceObject;

        pLowerDeviceObject = IoAttachDeviceToDeviceStack(pDeviceObject, pPhysicalDeviceObject);

        if (pLowerDeviceObject)
        {
            pBusExtension->pLowerDeviceObject = pLowerDeviceObject;

            Status = IoRegisterDeviceInterface(pPhysicalDeviceObject,
            &g_ClassGuid, NULL, &pBusExtension->SymbolicLinkName);

            if (NT_SUCCESS(Status)) pDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
            else IoDetachDevice(pLowerDeviceObject);
        }
        else Status = STATUS_NO_SUCH_DEVICE;

        if (!NT_SUCCESS(Status)) IoDeleteDevice(pDeviceObject);
    }

    return Status;
}

注意事项

关于缓冲区大小的一点说明。在我的系统上,IOCTL_STORAGE_QUERY_PROPERTY(属性ID = StorageAdapterProperty)返回的STORAGE_ADAPTER_DESCRIPTORMaximumTransferLength字段设置为32 * page size(页面大小 = 4096)。我将BUFFER_SIZE设置为40 * page size。此外,当我们分配mdl时,

pMdl = IoAllocateMdl(NULL, (32 + 1) * 4096, FALSE, FALSE, NULL);

相反,我们需要根据MaximumTransferLength字段相应地设置这些长度。此外,驱动程序缺乏对设备扩展的同步访问,但在虚拟机上,一切正常(可能是因为默认情况下我们只有一个核心)。

等我适当休息后会修复这个问题。

© . All rights reserved.