SerialFilter.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. // SerialFilter.cpp - 串口 IRP 拦截实现
  2. // KMDF 过滤驱动模式:通过 WdfDeviceInitAssignWdmIrpPreprocessCallback 注册
  3. // 在预处理回调中注册完成例程,捕获 READ/WRITE 数据
  4. #include <ntddk.h>
  5. #include <wdf.h>
  6. #include "SerialFilter.h"
  7. #include "EventRingBuffer.h"
  8. #include "ClientConnection.h"
  9. #include "DeviceContext.h"
  10. #include "../common/CommKitEvents.h"
  11. namespace commkit_driver {
  12. // 全局原子序列号(所有事件类型共享,保证 Sequence 字段全局唯一递增)
  13. LONG g_sequence_counter = 0;
  14. // 获取当前时间戳(100ns 单位)
  15. static UINT64 GetCurrentTimeStamp() {
  16. return KeQueryInterruptTime();
  17. }
  18. void SerialFilter::CaptureIrpData(PDEVICE_CONTEXT ctx, PIRP irp, ULONG event_type) {
  19. if (!ctx || !ctx->MonitoringEnabled || !ctx->RingBuffer) {
  20. return;
  21. }
  22. PIO_STACK_LOCATION sl = IoGetCurrentIrpStackLocation(irp);
  23. if (!sl) return;
  24. // 仅在 IRP 成功完成时捕获
  25. if (!NT_SUCCESS(irp->IoStatus.Status)) {
  26. return;
  27. }
  28. ULONG data_size = 0;
  29. PVOID data_ptr = nullptr;
  30. // 根据 IRP 类型提取数据
  31. if (event_type == COMMKIT_OP_READ) {
  32. // 实际读取的字节数(IRP 完成后 Information = 读取字节数)
  33. data_size = (ULONG)irp->IoStatus.Information;
  34. if (data_size == 0) return;
  35. // 数据可能在 SystemBuffer / MdlAddress / UserBuffer
  36. if (irp->MdlAddress) {
  37. data_ptr = MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority);
  38. } else if (irp->AssociatedIrp.SystemBuffer) {
  39. data_ptr = irp->AssociatedIrp.SystemBuffer;
  40. }
  41. } else if (event_type == COMMKIT_OP_WRITE) {
  42. data_size = (ULONG)irp->IoStatus.Information;
  43. if (data_size == 0) {
  44. data_size = sl->Parameters.Write.Length;
  45. }
  46. if (data_size == 0) return;
  47. if (irp->MdlAddress) {
  48. data_ptr = MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority);
  49. } else if (irp->AssociatedIrp.SystemBuffer) {
  50. data_ptr = irp->AssociatedIrp.SystemBuffer;
  51. }
  52. }
  53. if (!data_ptr || data_size == 0) {
  54. return;
  55. }
  56. // 推入环形缓冲
  57. LONG seq = InterlockedIncrement(&g_sequence_counter);
  58. auto* ring = (EventRingBuffer*)ctx->RingBuffer;
  59. ring->Push((ULONG)seq, GetCurrentTimeStamp(),
  60. ctx->ComNumber, event_type,
  61. data_size, data_ptr);
  62. }
  63. NTSTATUS SerialFilter::OnReadComplete(PDEVICE_OBJECT dev, PIRP irp, PVOID ctx) {
  64. UNREFERENCED_PARAMETER(dev);
  65. PDEVICE_CONTEXT device_ctx = (PDEVICE_CONTEXT)ctx;
  66. if (device_ctx) {
  67. CaptureIrpData(device_ctx, irp, COMMKIT_OP_READ);
  68. }
  69. // 下层驱动返回 STATUS_PENDING 时需标记 IRP 为 pending
  70. if (irp->PendingReturned) {
  71. IoMarkIrpPending(irp);
  72. }
  73. return STATUS_SUCCESS;
  74. }
  75. NTSTATUS SerialFilter::OnWriteComplete(PDEVICE_OBJECT dev, PIRP irp, PVOID ctx) {
  76. UNREFERENCED_PARAMETER(dev);
  77. PDEVICE_CONTEXT device_ctx = (PDEVICE_CONTEXT)ctx;
  78. if (device_ctx) {
  79. CaptureIrpData(device_ctx, irp, COMMKIT_OP_WRITE);
  80. }
  81. if (irp->PendingReturned) {
  82. IoMarkIrpPending(irp);
  83. }
  84. return STATUS_SUCCESS;
  85. }
  86. NTSTATUS SerialFilter::DispatchCreate(WDFDEVICE dev, PIRP irp) {
  87. PDEVICE_CONTEXT ctx = DeviceGetContext(dev);
  88. ULONG com = ctx ? ctx->ComNumber : 0;
  89. // 从 IRP 栈位置获取 WDM FileObject,用于 HandleWritePort/HandleReadPort
  90. PIO_STACK_LOCATION sl = IoGetCurrentIrpStackLocation(irp);
  91. if (ctx && sl && sl->FileObject) {
  92. PFILE_OBJECT wdm_fo = sl->FileObject;
  93. ObReferenceObject(wdm_fo);
  94. KIRQL old_irql;
  95. KeAcquireSpinLock(&ctx->FileObjectLock, &old_irql);
  96. PFILE_OBJECT old_fo = ctx->SavedFileObject;
  97. ctx->SavedFileObject = wdm_fo;
  98. KeReleaseSpinLock(&ctx->FileObjectLock, old_irql);
  99. if (old_fo) {
  100. ObDereferenceObject(old_fo);
  101. }
  102. DbgPrint("[CommModifyKit] DispatchCreate COM%u: SavedFileObject=%p\n", com, wdm_fo);
  103. } else {
  104. DbgPrint("[CommModifyKit] DispatchCreate COM%u: no FileObject in IRP\n", com);
  105. }
  106. // OP_OPEN 事件
  107. if (ctx && ctx->MonitoringEnabled && ctx->RingBuffer) {
  108. EventRingBuffer* ring = (EventRingBuffer*)ctx->RingBuffer;
  109. LONG seq = InterlockedIncrement(&g_sequence_counter);
  110. UINT64 timestamp = KeQueryInterruptTime();
  111. ring->Push((ULONG)seq, timestamp, com, COMMKIT_OP_OPEN, 0, nullptr);
  112. }
  113. // 转发到下层设备(无 WdfDeviceInitSetFileObjectConfig,WDF 不查找 WDFFILEOBJECT)
  114. NTSTATUS fwd_status = WdfDeviceWdmDispatchPreprocessedIrp(dev, irp);
  115. DbgPrint("[CommModifyKit] DispatchCreate COM%u: forward status=0x%08X LowerDev=%p\n",
  116. com, fwd_status, ctx ? ctx->LowerDevice : nullptr);
  117. return fwd_status;
  118. }
  119. NTSTATUS SerialFilter::DispatchClose(WDFDEVICE dev, PIRP irp) {
  120. PDEVICE_CONTEXT ctx = DeviceGetContext(dev);
  121. ULONG com = ctx ? ctx->ComNumber : 0;
  122. // 释放捕获的 FileObject
  123. PIO_STACK_LOCATION sl = IoGetCurrentIrpStackLocation(irp);
  124. if (ctx && sl && sl->FileObject) {
  125. PFILE_OBJECT wdm_fo = sl->FileObject;
  126. KIRQL old_irql;
  127. KeAcquireSpinLock(&ctx->FileObjectLock, &old_irql);
  128. PFILE_OBJECT saved = ctx->SavedFileObject;
  129. if (saved == wdm_fo) {
  130. ctx->SavedFileObject = nullptr;
  131. } else {
  132. saved = nullptr;
  133. }
  134. KeReleaseSpinLock(&ctx->FileObjectLock, old_irql);
  135. if (saved) {
  136. ObDereferenceObject(saved);
  137. DbgPrint("[CommModifyKit] DispatchClose COM%u: SavedFileObject released\n", com);
  138. }
  139. }
  140. // OP_CLOSE 事件
  141. if (ctx && ctx->MonitoringEnabled && ctx->RingBuffer) {
  142. EventRingBuffer* ring = (EventRingBuffer*)ctx->RingBuffer;
  143. LONG seq = InterlockedIncrement(&g_sequence_counter);
  144. UINT64 timestamp = KeQueryInterruptTime();
  145. ring->Push((ULONG)seq, timestamp, com, COMMKIT_OP_CLOSE, 0, nullptr);
  146. }
  147. NTSTATUS fwd_status = WdfDeviceWdmDispatchPreprocessedIrp(dev, irp);
  148. DbgPrint("[CommModifyKit] DispatchClose COM%u: forward status=0x%08X LowerDev=%p\n",
  149. com, fwd_status, ctx ? ctx->LowerDevice : nullptr);
  150. return fwd_status;
  151. }
  152. NTSTATUS SerialFilter::DispatchRead(WDFDEVICE dev, PIRP irp) {
  153. PDEVICE_CONTEXT ctx = DeviceGetContext(dev);
  154. ULONG com = ctx ? ctx->ComNumber : 0;
  155. // 在转发前读取栈位置(转发后可能失效)
  156. PIO_STACK_LOCATION sl_before = IoGetCurrentIrpStackLocation(irp);
  157. ULONG req_len = sl_before ? sl_before->Parameters.Read.Length : 0;
  158. PFILE_OBJECT irp_fo = sl_before ? sl_before->FileObject : nullptr;
  159. PDEVICE_OBJECT lower_dev = ctx ? ctx->LowerDevice : nullptr;
  160. BOOLEAN monitored = (ctx && ctx->MonitoringEnabled && ctx->RingBuffer);
  161. NTSTATUS status;
  162. const char* fwd_method = "";
  163. if (monitored) {
  164. // 监控端口:设置完成例程后手动转发(捕获数据需要完成例程)
  165. IoSetCompletionRoutine(irp, OnReadComplete, ctx, TRUE, TRUE, TRUE);
  166. IoSkipCurrentIrpStackLocation(irp);
  167. status = IoCallDriver(lower_dev, irp);
  168. fwd_method = "IoCallDriver";
  169. } else {
  170. // 非监控端口:使用 WdfDeviceWdmDispatchPreprocessedIrp 转发
  171. // 原因:CREATE/CLOSE 使用 WdfDeviceWdmDispatchPreprocessedIrp,
  172. // READ/WRITE 若用 IoCallDriver 会绕过 WDF 内部 IRP 跟踪,
  173. // 导致 WDF 状态不一致,可能引发后续 IRP 异常。
  174. // 统一使用 WdfDeviceWdmDispatchPreprocessedIrp 确保 WDF 一致性。
  175. status = WdfDeviceWdmDispatchPreprocessedIrp(dev, irp);
  176. fwd_method = "WdfDispatch";
  177. }
  178. // 诊断:每个端口前 5 次 IRP 记录详细信息
  179. if (com > 0 && com <= 256) {
  180. static volatile LONG g_read_log_count[257] = {0};
  181. LONG count = InterlockedIncrement(&g_read_log_count[com]);
  182. if (count <= 5) {
  183. DbgPrint("[CommModifyKit] IRP_MJ_READ COM%u status=0x%08X reqLen=%u mon=%d FO=%p Low=%p [%s] (#%ld)\n",
  184. com, status, req_len, (int)monitored, irp_fo, lower_dev, fwd_method, count);
  185. }
  186. }
  187. return status;
  188. }
  189. NTSTATUS SerialFilter::DispatchWrite(WDFDEVICE dev, PIRP irp) {
  190. PDEVICE_CONTEXT ctx = DeviceGetContext(dev);
  191. ULONG com = ctx ? ctx->ComNumber : 0;
  192. PIO_STACK_LOCATION sl_before = IoGetCurrentIrpStackLocation(irp);
  193. ULONG req_len = sl_before ? sl_before->Parameters.Write.Length : 0;
  194. PFILE_OBJECT irp_fo = sl_before ? sl_before->FileObject : nullptr;
  195. PDEVICE_OBJECT lower_dev = ctx ? ctx->LowerDevice : nullptr;
  196. BOOLEAN monitored = (ctx && ctx->MonitoringEnabled && ctx->RingBuffer);
  197. NTSTATUS status;
  198. const char* fwd_method = "";
  199. if (monitored) {
  200. // 监控端口:设置完成例程后手动转发
  201. IoSetCompletionRoutine(irp, OnWriteComplete, ctx, TRUE, TRUE, TRUE);
  202. IoSkipCurrentIrpStackLocation(irp);
  203. status = IoCallDriver(lower_dev, irp);
  204. fwd_method = "IoCallDriver";
  205. } else {
  206. // 非监控端口:使用 WdfDeviceWdmDispatchPreprocessedIrp 转发(同 DispatchRead)
  207. status = WdfDeviceWdmDispatchPreprocessedIrp(dev, irp);
  208. fwd_method = "WdfDispatch";
  209. }
  210. if (com > 0 && com <= 256) {
  211. static volatile LONG g_write_log_count[257] = {0};
  212. LONG count = InterlockedIncrement(&g_write_log_count[com]);
  213. if (count <= 5) {
  214. DbgPrint("[CommModifyKit] IRP_MJ_WRITE COM%u status=0x%08X reqLen=%u mon=%d FO=%p Low=%p [%s] (#%ld)\n",
  215. com, status, req_len, (int)monitored, irp_fo, lower_dev, fwd_method, count);
  216. }
  217. }
  218. return status;
  219. }
  220. } // namespace commkit_driver