QueueCallback.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. // QueueCallback.cpp - I/O Queue 回调实现
  2. #include <ntddk.h>
  3. #include <wdf.h>
  4. #include <initguid.h>
  5. #include <wdmsec.h>
  6. #include "QueueCallback.h"
  7. #include "ClientConnection.h"
  8. #include "DeviceContext.h"
  9. #include "../common/CommKitIoctl.h"
  10. namespace commkit_driver {
  11. // SDDL: System and Administrators have full access
  12. static const UNICODE_STRING SddlSysAdminFullAccess =
  13. RTL_CONSTANT_STRING(L"D:P(A;;GA;;;SY)(A;;GA;;;BA)");
  14. // 专用 Parallel 队列句柄:用于 READ_EVENTS 转发
  15. // WdfDeviceConfigureRequestDispatching 只能按请求类型路由(如 WdfRequestTypeDeviceControl),
  16. // 不能按具体 IOCTL 码路由。改为在 EvtIoDeviceControl 中用 WdfRequestForwardToIoQueue 转发。
  17. static WDFQUEUE g_read_events_queue = nullptr;
  18. NTSTATUS CreateControlDevice(WDFDRIVER driver) {
  19. NTSTATUS status;
  20. PWDFDEVICE_INIT init = WdfControlDeviceInitAllocate(
  21. driver, (PCUNICODE_STRING)&SddlSysAdminFullAccess);
  22. if (!init) {
  23. return STATUS_INSUFFICIENT_RESOURCES;
  24. }
  25. // 设置设备名
  26. DECLARE_UNICODE_STRING_SIZE(device_name, 64);
  27. RtlInitUnicodeString(&device_name, COMMKIT_DEVICE_NAME);
  28. status = WdfDeviceInitAssignName(init, &device_name);
  29. if (!NT_SUCCESS(status)) {
  30. WdfDeviceInitFree(init);
  31. return status;
  32. }
  33. // 创建设备
  34. WDFDEVICE control_device;
  35. WDF_OBJECT_ATTRIBUTES attrs;
  36. WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attrs, DEVICE_CONTEXT);
  37. status = WdfDeviceCreate(&init, &attrs, &control_device);
  38. if (!NT_SUCCESS(status)) {
  39. WdfDeviceInitFree(init);
  40. return status;
  41. }
  42. // 创建符号链接 \\DosDevices\\CommModifyKit → \\.\CommModifyKit
  43. DECLARE_UNICODE_STRING_SIZE(symbolic_link, 64);
  44. RtlInitUnicodeString(&symbolic_link, COMMKIT_DEVICE_DOS_NAME);
  45. status = WdfDeviceCreateSymbolicLink(control_device, &symbolic_link);
  46. if (!NT_SUCCESS(status)) {
  47. return status;
  48. }
  49. // 配置 I/O Queue 处理 IOCTL
  50. // 主队列:Sequential 派发,处理除 READ_EVENTS 外的所有 IOCTL
  51. // (ATTACH/DETACH/WRITE_PORT/READ_PORT/FREE_ALL 需要串行化避免竞争)
  52. WDF_IO_QUEUE_CONFIG queue_config;
  53. WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queue_config, WdfIoQueueDispatchSequential);
  54. queue_config.EvtIoDeviceControl = EvtIoDeviceControl;
  55. queue_config.EvtIoDefault = EvtIoDefault;
  56. WDFQUEUE queue;
  57. status = WdfIoQueueCreate(control_device, &queue_config,
  58. WDF_NO_OBJECT_ATTRIBUTES, &queue);
  59. if (!NT_SUCCESS(status)) {
  60. return status;
  61. }
  62. // 专用队列:Parallel 派发,仅处理 IOCTL_COMMKIT_READ_EVENTS
  63. // 独立于主队列,避免 WRITE_PORT/READ_PORT 同步阻塞时 EventLoop 无法读取事件
  64. // (否则高流量场景下环形缓冲溢出覆盖旧事件)
  65. WDF_IO_QUEUE_CONFIG read_events_config;
  66. WDF_IO_QUEUE_CONFIG_INIT(&read_events_config, WdfIoQueueDispatchParallel);
  67. read_events_config.EvtIoDeviceControl = EvtIoReadEvents;
  68. WDFQUEUE read_events_queue;
  69. status = WdfIoQueueCreate(control_device, &read_events_config,
  70. WDF_NO_OBJECT_ATTRIBUTES, &read_events_queue);
  71. if (!NT_SUCCESS(status)) {
  72. return status;
  73. }
  74. // 保存队列句柄供 EvtIoDeviceControl 转发 READ_EVENTS 请求
  75. g_read_events_queue = read_events_queue;
  76. // 标记控制设备已就绪
  77. WdfControlFinishInitializing(control_device);
  78. return STATUS_SUCCESS;
  79. }
  80. VOID EvtIoDeviceControl(WDFQUEUE queue, WDFREQUEST request,
  81. size_t output_buffer_length, size_t input_buffer_length,
  82. ULONG io_control_code) {
  83. UNREFERENCED_PARAMETER(queue);
  84. UNREFERENCED_PARAMETER(input_buffer_length);
  85. UNREFERENCED_PARAMETER(output_buffer_length);
  86. NTSTATUS status = STATUS_SUCCESS;
  87. ULONG info = 0;
  88. auto& conn = GetClientConnection();
  89. switch (io_control_code) {
  90. case IOCTL_COMMKIT_REGISTER_CALLBACK:
  91. status = conn.HandleRegisterCallback();
  92. break;
  93. case IOCTL_COMMKIT_ATTACH_PORT: {
  94. COMMKIT_PORT_REQUEST* req = nullptr;
  95. size_t buf_len = 0;
  96. status = WdfRequestRetrieveInputBuffer(request, sizeof(*req),
  97. (PVOID*)&req, &buf_len);
  98. if (NT_SUCCESS(status) && req) {
  99. status = conn.HandleAttachPort(req->ComNumber);
  100. }
  101. break;
  102. }
  103. case IOCTL_COMMKIT_DETACH_PORT: {
  104. COMMKIT_PORT_REQUEST* req = nullptr;
  105. size_t buf_len = 0;
  106. status = WdfRequestRetrieveInputBuffer(request, sizeof(*req),
  107. (PVOID*)&req, &buf_len);
  108. if (NT_SUCCESS(status) && req) {
  109. status = conn.HandleDetachPort(req->ComNumber);
  110. }
  111. break;
  112. }
  113. case IOCTL_COMMKIT_WRITE_PORT: {
  114. COMMKIT_DATA_REQUEST* req = nullptr;
  115. size_t buf_len = 0;
  116. status = WdfRequestRetrieveInputBuffer(request, sizeof(*req),
  117. (PVOID*)&req, &buf_len);
  118. if (NT_SUCCESS(status) && req) {
  119. // 校验 DataLen 不超过实际缓冲区容量,防止越界读取
  120. // Data 字段起始偏移 = sizeof(UINT32) * 2 = 8
  121. ULONG data_capacity = (buf_len > 8) ? (ULONG)(buf_len - 8) : 0;
  122. if (req->DataLen > data_capacity) {
  123. status = STATUS_INVALID_PARAMETER;
  124. } else {
  125. PVOID data = req->Data;
  126. status = conn.HandleWritePort(req->ComNumber, data, req->DataLen);
  127. }
  128. }
  129. break;
  130. }
  131. case IOCTL_COMMKIT_READ_PORT: {
  132. COMMKIT_DATA_REQUEST* req = nullptr;
  133. size_t buf_len = 0;
  134. status = WdfRequestRetrieveInputBuffer(request, sizeof(*req),
  135. (PVOID*)&req, &buf_len);
  136. if (NT_SUCCESS(status) && req) {
  137. ULONG data_capacity = (buf_len > 8) ? (ULONG)(buf_len - 8) : 0;
  138. if (req->DataLen > data_capacity) {
  139. status = STATUS_INVALID_PARAMETER;
  140. } else {
  141. PVOID data = req->Data;
  142. status = conn.HandleReadPort(req->ComNumber, data, req->DataLen);
  143. }
  144. }
  145. break;
  146. }
  147. case IOCTL_COMMKIT_READ_EVENTS:
  148. // 转发到专用 Parallel 队列,避免被 WRITE_PORT/READ_PORT 的同步阻塞拖慢
  149. if (g_read_events_queue) {
  150. NTSTATUS fwd = WdfRequestForwardToIoQueue(request, g_read_events_queue);
  151. if (NT_SUCCESS(fwd)) {
  152. return; // 转发成功,请求已移至专用队列,不再完成
  153. }
  154. // 转发失败,按错误完成
  155. }
  156. status = STATUS_INVALID_DEVICE_REQUEST;
  157. break;
  158. case IOCTL_COMMKIT_FREE_ALL:
  159. status = conn.HandleFreeAll();
  160. break;
  161. default:
  162. status = STATUS_INVALID_DEVICE_REQUEST;
  163. break;
  164. }
  165. WdfRequestCompleteWithInformation(request, status, info);
  166. }
  167. // 专用队列回调:处理 IOCTL_COMMKIT_READ_EVENTS
  168. // 独立于主队列,即使 WRITE_PORT/READ_PORT 阻塞,EventLoop 仍可读取事件
  169. VOID EvtIoReadEvents(WDFQUEUE queue, WDFREQUEST request,
  170. size_t output_buffer_length, size_t input_buffer_length,
  171. ULONG io_control_code) {
  172. UNREFERENCED_PARAMETER(queue);
  173. UNREFERENCED_PARAMETER(input_buffer_length);
  174. UNREFERENCED_PARAMETER(output_buffer_length);
  175. if (io_control_code != IOCTL_COMMKIT_READ_EVENTS) {
  176. WdfRequestComplete(request, STATUS_INVALID_DEVICE_REQUEST);
  177. return;
  178. }
  179. PVOID out_buf = nullptr;
  180. size_t out_len = 0;
  181. NTSTATUS status = WdfRequestRetrieveOutputBuffer(request, 0,
  182. (PVOID*)&out_buf, &out_len);
  183. if (NT_SUCCESS(status) && out_buf) {
  184. ULONG returned = 0;
  185. status = GetClientConnection().HandleReadEvents(out_buf, (ULONG)out_len, &returned);
  186. WdfRequestCompleteWithInformation(request, status, returned);
  187. } else {
  188. WdfRequestComplete(request, STATUS_INVALID_PARAMETER);
  189. }
  190. }
  191. VOID EvtIoDefault(WDFQUEUE queue, WDFREQUEST request) {
  192. UNREFERENCED_PARAMETER(queue);
  193. WdfRequestComplete(request, STATUS_INVALID_DEVICE_REQUEST);
  194. }
  195. } // namespace commkit_driver