SCSI over Net






4.98/5 (15投票s)
本文将向您展示如何通过网络共享内置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总线驱动程序
,并将响应发送回客户端。
背景
为了管理驱动程序,我们需要驱动程序包
——位于同一目录中的inf和sys文件。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
:
- 如果驱动程序未
预安装
——预安装
驱动程序。 - 如果inf文件与设备的某些硬件ID匹配(驱动程序
兼容
)——为这些设备安装
驱动程序(如果已为设备安装
了另一个驱动程序——它将自动卸载
)。
DWORD DriverPackagePreinstall(
_In_ PCTSTR DriverPackageInfPath,
_In_ DWORD Flags
);
DriverPackagePreinstall
:
预安装
驱动程序。
DWORD DriverPackageUninstall(
_In_ PCTSTR DriverPackageInfPath,
_In_ DWORD Flags,
_In_opt_ PCINSTALLERINFO_W pInstallerInfo,
_Out_ BOOL *pNeedReboot
);
DriverPackageUninstall
:
- 如果驱动程序已为某些设备
安装
——为这些设备卸载
驱动程序(如果另一个兼容
驱动程序已预安装
——它将自动为设备安装
)。 卸载
驱动程序
当我们预安装
驱动程序时,系统会显示警告对话框,然后将驱动程序文件复制到驱动程序存储
。当我们卸载
驱动程序时,系统会从驱动程序存储
中删除驱动程序文件。
当我们安装
驱动程序时,如果驱动程序文件尚未复制,系统会将其复制到系统目录。
警告对话框如下所示:
其他管理驱动程序的函数位于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
:
- 为指定设备
安装
驱动程序(驱动程序已预安装
)。先前的驱动程序(如果有)将被卸载
。
Using the Code
为了测试目的,我们将使用同一台虚拟机作为服务器和客户端。
- inf文件简要说明
服务器端
Inf文件名 = scsiserver.inf
设备设置类 =CDROM
设备硬件ID =GenCdRom
设备描述 = SCSI Server客户端
Inf文件名 = scsiclient.inf
设备设置类 =HDC
设备硬件ID =VirtualSCSIBus
设备描述 = SCSI Client 程序安装
过程在服务器端,我们需要
预安装
服务器驱动程序。#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; }
程序卸载
过程在服务器端,我们需要
卸载
服务器驱动程序。#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, ¶ms.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; }
- 程序操作过程
在每一侧,我们都有 { 驱动程序和用户模式程序 } 对。在任一侧,我们都需要启动用户模式程序并输入“Connect”命令。连接后,在服务器端,我们将输入“List”命令以查看可用的CD-ROM设备(它们的硬件ID)。接下来,我们将输入“Share”命令,后跟硬件ID以开始共享过程。在服务器端,CD-ROM设备将从资源管理器中消失,并显示在客户端。
客户端
服务器端
要停止设备共享,我们需要在服务器端输入“Unshare”命令或在客户端断开连接。在客户端,CD-ROM设备将消失,我们将在服务器端将其找回。
客户端
服务器端
Windows套接字用于通过网络传输数据。用户模式代码设计如下:
- “用户线程”——此线程专用于用户命令(等待它们)。
- “接收线程”——此线程负责
接收
REQUEST_HEADER
结构,该结构包含整个请求的长度和设备标签(以便我们知道此请求是针对哪个共享设备的,以及下次需要接收
多少字节)。 - “设备线程”——每个共享设备都有自己的线程,该线程将
发送
请求,接收
请求(除了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。按照上述说明启动设备共享过程,我们的未解析断点将被命中(相应的代码行将变为黄色)。
现在您可以跟踪执行流,在其他分发例程上设置断点,并调试两个驱动程序。请求流如下:
- 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 }
- 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 }
- 完成
{ 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_DESCRIPTOR
的MaximumTransferLength
字段设置为32 * page size
(页面大小 = 4096)。我将BUFFER_SIZE
设置为40 * page size
。此外,当我们分配mdl
时,
pMdl = IoAllocateMdl(NULL, (32 + 1) * 4096, FALSE, FALSE, NULL);
相反,我们需要根据MaximumTransferLength
字段相应地设置这些长度。此外,驱动程序缺乏对设备扩展的同步访问,但在虚拟机上,一切正常(可能是因为默认情况下我们只有一个核心)。
等我适当休息后会修复这个问题。