| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422 |
- // ClientConnection.cpp - 用户态连接管理实现
- #include <ntddk.h>
- #include <wdf.h>
- #include "ClientConnection.h"
- #include "EventRingBuffer.h"
- #include "SerialFilter.h" // g_sequence_counter
- #include "../common/CommKitIoctl.h"
- #include "../common/CommKitEvents.h"
- // 诊断计数器(全局命名空间)
- volatile LONG g_diag_evt_device_add_count = 0;
- volatile LONG g_diag_prepare_hardware_count = 0;
- volatile LONG g_diag_register_filter_count = 0;
- volatile LONG g_diag_irp_preprocess_ok = 0;
- volatile LONG g_diag_device_create_ok = 0;
- volatile LONG g_diag_last_failure_status = 0;
- namespace commkit_driver {
- // 全局实例
- ClientConnection g_ClientConnection;
- void ClientConnection::Initialize() {
- ports_count_ = 0;
- control_device_ = nullptr;
- callback_registered_ = FALSE;
- KeInitializeSpinLock(&ports_lock_);
- RtlZeroMemory(ports_table_, sizeof(ports_table_));
- }
- void ClientConnection::Cleanup() {
- // 释放所有端口的环形缓冲
- KIRQL old_irql;
- KeAcquireSpinLock(&ports_lock_, &old_irql);
- for (ULONG i = 0; i < ports_count_; ++i) {
- PDEVICE_CONTEXT ctx = ports_table_[i].Context;
- if (ctx && ctx->RingBuffer) {
- EventRingBuffer* ring = (EventRingBuffer*)ctx->RingBuffer;
- ring->Cleanup();
- ExFreePoolWithTag(ring, 'RBCK');
- ctx->RingBuffer = nullptr;
- }
- }
- ports_count_ = 0;
- KeReleaseSpinLock(&ports_lock_, old_irql);
- }
- void ClientConnection::RegisterFilterDevice(WDFDEVICE device) {
- InterlockedIncrement(&g_diag_register_filter_count);
- KIRQL old_irql;
- KeAcquireSpinLock(&ports_lock_, &old_irql);
- if (ports_count_ < 256) {
- PDEVICE_CONTEXT ctx = DeviceGetContext(device);
- ports_table_[ports_count_].ComNumber = 0; // 延迟到 UpdatePortComNumber
- ports_table_[ports_count_].Context = ctx;
- ports_count_++;
- ctx->ComNumber = 0;
- ctx->MonitoringEnabled = FALSE;
- ctx->WdfDevice = device;
- }
- KeReleaseSpinLock(&ports_lock_, old_irql);
- }
- void ClientConnection::UpdatePortComNumber(WDFDEVICE device, ULONG com_number) {
- KIRQL old_irql;
- KeAcquireSpinLock(&ports_lock_, &old_irql);
- for (ULONG i = 0; i < ports_count_; ++i) {
- if (ports_table_[i].Context &&
- ports_table_[i].Context->WdfDevice == device) {
- ports_table_[i].ComNumber = com_number;
- ports_table_[i].Context->ComNumber = com_number;
- break;
- }
- }
- KeReleaseSpinLock(&ports_lock_, old_irql);
- }
- void ClientConnection::UnregisterFilterDevice(ULONG com_number) {
- KIRQL old_irql;
- KeAcquireSpinLock(&ports_lock_, &old_irql);
- for (ULONG i = 0; i < ports_count_; ++i) {
- if (ports_table_[i].ComNumber == com_number) {
- // 移动最后一个元素到当前位置
- PDEVICE_CONTEXT ctx = ports_table_[i].Context;
- if (ctx && ctx->RingBuffer) {
- EventRingBuffer* ring = (EventRingBuffer*)ctx->RingBuffer;
- ring->Cleanup();
- ExFreePoolWithTag(ring, 'RBCK');
- ctx->RingBuffer = nullptr;
- }
- ports_table_[i] = ports_table_[ports_count_ - 1];
- ports_count_--;
- break;
- }
- }
- KeReleaseSpinLock(&ports_lock_, old_irql);
- }
- PDEVICE_CONTEXT ClientConnection::FindPortContext(ULONG com_number) {
- PDEVICE_CONTEXT result = nullptr;
- KIRQL old_irql;
- KeAcquireSpinLock(&ports_lock_, &old_irql);
- for (ULONG i = 0; i < ports_count_; ++i) {
- if (ports_table_[i].ComNumber == com_number) {
- result = ports_table_[i].Context;
- break;
- }
- }
- KeReleaseSpinLock(&ports_lock_, old_irql);
- return result;
- }
- NTSTATUS ClientConnection::HandleRegisterCallback() {
- callback_registered_ = TRUE;
- return STATUS_SUCCESS;
- }
- NTSTATUS ClientConnection::HandleAttachPort(ULONG com_number) {
- // 拒绝 com_number==0:EvtDevicePrepareHardware 解析失败时 ComNumber 保持 0,
- // 若允许 attach 会误匹配第一个未解析出编号的设备
- if (com_number == 0) {
- DbgPrint("[CommModifyKit] HandleAttachPort: com_number=0 rejected\n");
- return STATUS_INVALID_PARAMETER;
- }
- PDEVICE_CONTEXT ctx = FindPortContext(com_number);
- if (!ctx) {
- DbgPrint("[CommModifyKit] HandleAttachPort: COM%u NOT in ports_table (count=%u)\n",
- com_number, ports_count_);
- DbgPrint("[CommModifyKit] DIAG: EvtDeviceAdd=%ld, IRPpreproc=%ld, DevCreate=%ld, Register=%ld, PrepHW=%ld, LastFail=0x%lX\n",
- g_diag_evt_device_add_count, g_diag_irp_preprocess_ok,
- g_diag_device_create_ok, g_diag_register_filter_count, g_diag_prepare_hardware_count,
- g_diag_last_failure_status);
- // 打印 ports_table_ 里所有已注册的 COM 编号,便于诊断
- KIRQL old_irql;
- KeAcquireSpinLock(&ports_lock_, &old_irql);
- for (ULONG i = 0; i < ports_count_; ++i) {
- DbgPrint("[CommModifyKit] ports_table[%u].ComNumber=%u\n",
- i, ports_table_[i].ComNumber);
- }
- KeReleaseSpinLock(&ports_lock_, old_irql);
- return STATUS_DEVICE_DOES_NOT_EXIST;
- }
- DbgPrint("[CommModifyKit] HandleAttachPort: COM%u found in ports_table\n", com_number);
- // 如果未分配环形缓冲,先分配
- if (!ctx->RingBuffer) {
- EventRingBuffer* ring = (EventRingBuffer*)ExAllocatePool2(
- POOL_FLAG_NON_PAGED, sizeof(EventRingBuffer), 'RBCK');
- if (!ring) {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- // placement new 等价:手动调用构造
- RtlZeroMemory(ring, sizeof(EventRingBuffer));
- NTSTATUS status = ring->Initialize();
- if (!NT_SUCCESS(status)) {
- ring->Cleanup();
- ExFreePoolWithTag(ring, 'RBCK');
- return status;
- }
- ctx->RingBuffer = ring;
- }
- // 推入 OP_OPEN 事件(使用全局共享序列号,保证所有事件类型 Sequence 唯一递增)
- EventRingBuffer* ring = (EventRingBuffer*)ctx->RingBuffer;
- LONG cur = InterlockedIncrement(&g_sequence_counter);
- UINT64 timestamp = KeQueryInterruptTime(); // 100ns 单位
- ring->Push((ULONG)cur, timestamp, com_number, COMMKIT_OP_OPEN, 0, nullptr);
- ctx->MonitoringEnabled = TRUE;
- return STATUS_SUCCESS;
- }
- NTSTATUS ClientConnection::HandleDetachPort(ULONG com_number) {
- PDEVICE_CONTEXT ctx = FindPortContext(com_number);
- if (!ctx) {
- return STATUS_DEVICE_DOES_NOT_EXIST;
- }
- ctx->MonitoringEnabled = FALSE;
- // 推入 OP_CLOSE 事件(使用全局共享序列号)
- if (ctx->RingBuffer) {
- EventRingBuffer* ring = (EventRingBuffer*)ctx->RingBuffer;
- LONG cur = InterlockedIncrement(&g_sequence_counter);
- UINT64 timestamp = KeQueryInterruptTime();
- ring->Push((ULONG)cur, timestamp, com_number, COMMKIT_OP_CLOSE, 0, nullptr);
- }
- return STATUS_SUCCESS;
- }
- NTSTATUS ClientConnection::HandleWritePort(ULONG com_number, PVOID data, ULONG len,
- PULONG bytes_written) {
- *bytes_written = 0;
- PDEVICE_CONTEXT ctx = FindPortContext(com_number);
- if (!ctx || !ctx->LowerDevice) {
- return STATUS_DEVICE_DOES_NOT_EXIST;
- }
- // 获取保存的 FileObject(由 DispatchCreate 捕获)。
- // 串口驱动(尤其是虚拟串口如 ELTIMA)需要有效的 FileObject 才能正确处理
- // 写请求——没有 FileObject 时,写 IRP 可能返回 STATUS_SUCCESS 但数据不会
- // 路由到配对端口的读缓冲,导致其他工具收不到客户端写的数据。
- PFILE_OBJECT fo = nullptr;
- KIRQL old_irql;
- KeAcquireSpinLock(&ctx->FileObjectLock, &old_irql);
- fo = ctx->SavedFileObject;
- if (fo) {
- ObReferenceObject(fo); // 额外引用,防止 DispatchClose 期间被释放
- }
- KeReleaseSpinLock(&ctx->FileObjectLock, old_irql);
- DbgPrint("[CommModifyKit] HandleWritePort COM%u len=%u FileObject=%p\n",
- com_number, len, fo);
- if (!fo) {
- DbgPrint("[CommModifyKit] HandleWritePort WARNING: no SavedFileObject for COM%u "
- "(no user-mode app has the port open). Write may not be routed correctly.\n",
- com_number);
- }
- // 构造同步写 IRP 发送给下层串口设备
- // IoBuildSynchronousFsdRequest 内部用 MmProbeAndLockPages(KernelMode)
- // 创建 MDL,对 NonPaged pool 缓冲(METHOD_BUFFERED SystemBuffer)可正常工作
- KEVENT event;
- KeInitializeEvent(&event, NotificationEvent, FALSE);
- IO_STATUS_BLOCK io_status = {};
- PIRP irp = IoBuildSynchronousFsdRequest(
- IRP_MJ_WRITE, ctx->LowerDevice, data, len, nullptr, &event, &io_status);
- if (!irp) {
- if (fo) ObDereferenceObject(fo);
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- // 关键:将 RequestorMode 改为 UserMode
- // IoBuildSynchronousFsdRequest 默认设 KernelMode,但 ELTIMA 等虚拟串口驱动
- // 会检查 RequestorMode——对 KernelMode 写 IRP 只接受写入(返回 SUCCESS)
- // 但不路由数据到配对端口。改为 UserMode 让虚拟串口驱动正常路由数据。
- // 缓冲已由 IoBuildSynchronousFsdRequest 用 KernelMode 探测锁定,
- // MDL 有效,下层驱动通过 MmGetSystemAddressForMdlSafe 访问,不受影响。
- irp->RequestorMode = UserMode;
- // IoBuildSynchronousFsdRequest 不设置 FileObject,需手动设置
- if (fo) {
- PIO_STACK_LOCATION sl = IoGetNextIrpStackLocation(irp);
- sl->FileObject = fo;
- }
- NTSTATUS status = IoCallDriver(ctx->LowerDevice, irp);
- if (status == STATUS_PENDING) {
- KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, nullptr);
- status = io_status.Status;
- }
- *bytes_written = (ULONG)io_status.Information;
- DbgPrint("[CommModifyKit] HandleWritePort COM%u status=0x%08X written=%u\n",
- com_number, status, *bytes_written);
- // 释放 FileObject 额外引用
- if (fo) {
- ObDereferenceObject(fo);
- }
- // 注:此 IRP 直接发给 LowerDevice,绕过 SerialFilter::DispatchWrite,
- // 不会触发 OnWriteComplete 捕获。需手动将写入数据 Push 为 OP_WRITE 事件
- if (NT_SUCCESS(status) && *bytes_written > 0 && ctx->MonitoringEnabled && ctx->RingBuffer) {
- LONG seq = InterlockedIncrement(&g_sequence_counter);
- UINT64 timestamp = KeQueryInterruptTime();
- EventRingBuffer* ring = (EventRingBuffer*)ctx->RingBuffer;
- ring->Push((ULONG)seq, timestamp, com_number, COMMKIT_OP_WRITE,
- *bytes_written, data);
- }
- return status;
- }
- NTSTATUS ClientConnection::HandleReadPort(ULONG com_number, PVOID data, ULONG len,
- PULONG bytes_read) {
- *bytes_read = 0;
- PDEVICE_CONTEXT ctx = FindPortContext(com_number);
- if (!ctx || !ctx->LowerDevice) {
- return STATUS_DEVICE_DOES_NOT_EXIST;
- }
- // 获取保存的 FileObject(与 HandleWritePort 同理)
- PFILE_OBJECT fo = nullptr;
- KIRQL old_irql;
- KeAcquireSpinLock(&ctx->FileObjectLock, &old_irql);
- fo = ctx->SavedFileObject;
- if (fo) {
- ObReferenceObject(fo);
- }
- KeReleaseSpinLock(&ctx->FileObjectLock, old_irql);
- DbgPrint("[CommModifyKit] HandleReadPort COM%u len=%u FileObject=%p\n",
- com_number, len, fo);
- // 构造同步读 IRP 发送给下层串口设备
- KEVENT event;
- KeInitializeEvent(&event, NotificationEvent, FALSE);
- IO_STATUS_BLOCK io_status = {};
- PIRP irp = IoBuildSynchronousFsdRequest(
- IRP_MJ_READ, ctx->LowerDevice, data, len, nullptr, &event, &io_status);
- if (!irp) {
- if (fo) ObDereferenceObject(fo);
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- // 同 HandleWritePort:改为 UserMode 让虚拟串口驱动正常处理
- irp->RequestorMode = UserMode;
- // 设置 FileObject(同 HandleWritePort)
- if (fo) {
- PIO_STACK_LOCATION sl = IoGetNextIrpStackLocation(irp);
- sl->FileObject = fo;
- }
- NTSTATUS status = IoCallDriver(ctx->LowerDevice, irp);
- if (status == STATUS_PENDING) {
- KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, nullptr);
- status = io_status.Status;
- }
- *bytes_read = (ULONG)io_status.Information;
- DbgPrint("[CommModifyKit] HandleReadPort COM%u status=0x%08X read=%u\n",
- com_number, status, *bytes_read);
- if (fo) {
- ObDereferenceObject(fo);
- }
- // 注:此 IRP 直接发给 LowerDevice,绕过 SerialFilter::DispatchRead,
- // 不会触发 OnReadComplete 捕获。需手动将读取数据 Push 为 OP_READ 事件
- if (NT_SUCCESS(status) && *bytes_read > 0 && ctx->MonitoringEnabled && ctx->RingBuffer) {
- LONG seq = InterlockedIncrement(&g_sequence_counter);
- UINT64 timestamp = KeQueryInterruptTime();
- EventRingBuffer* ring = (EventRingBuffer*)ctx->RingBuffer;
- ring->Push((ULONG)seq, timestamp, com_number, COMMKIT_OP_READ,
- *bytes_read, data);
- }
- return status;
- }
- NTSTATUS ClientConnection::HandleReadEvents(PVOID out_buf, ULONG out_size, PULONG returned) {
- *returned = 0;
- if (!callback_registered_) {
- return STATUS_DEVICE_NOT_READY;
- }
- PCOMMKIT_EVENT events = (PCOMMKIT_EVENT)out_buf;
- ULONG max_count = out_size / sizeof(COMMKIT_EVENT);
- if (max_count == 0) {
- return STATUS_BUFFER_TOO_SMALL;
- }
- ULONG total_popped = 0;
- KIRQL old_irql;
- KeAcquireSpinLock(&ports_lock_, &old_irql);
- // 按端口顺序弹出事件到输出缓冲
- for (ULONG i = 0; i < ports_count_ && total_popped < max_count; ++i) {
- PDEVICE_CONTEXT ctx = ports_table_[i].Context;
- if (!ctx || !ctx->RingBuffer || !ctx->MonitoringEnabled) {
- continue;
- }
- EventRingBuffer* ring = (EventRingBuffer*)ctx->RingBuffer;
- LONG popped = ring->PopBatch(events + total_popped, max_count - total_popped);
- total_popped += (ULONG)popped;
- }
- KeReleaseSpinLock(&ports_lock_, old_irql);
- // 弹出后按 Sequence 升序排序(锁外执行,不持自旋锁做 O(n²) 操作)
- // 各端口 RingBuffer 内部 Sequence 是递增的,但跨端口弹出后顺序被打乱
- // (如 port0 的 seq=100-109 可能排在 port1 的 seq=95-99 之前)
- // 使用插入排序:事件批量小(通常 ≤16),O(n²) 开销可忽略
- if (total_popped > 1) {
- for (ULONG i = 1; i < total_popped; ++i) {
- COMMKIT_EVENT key = events[i];
- LONG j = (LONG)i - 1;
- while (j >= 0 && events[j].Sequence > key.Sequence) {
- events[j + 1] = events[j];
- j--;
- }
- events[j + 1] = key;
- }
- }
- *returned = total_popped * sizeof(COMMKIT_EVENT);
- return STATUS_SUCCESS;
- }
- NTSTATUS ClientConnection::HandleFreeAll() {
- KIRQL old_irql;
- KeAcquireSpinLock(&ports_lock_, &old_irql);
- for (ULONG i = 0; i < ports_count_; ++i) {
- PDEVICE_CONTEXT ctx = ports_table_[i].Context;
- if (ctx) {
- ctx->MonitoringEnabled = FALSE;
- if (ctx->RingBuffer) {
- ((EventRingBuffer*)ctx->RingBuffer)->Clear();
- }
- }
- }
- KeReleaseSpinLock(&ports_lock_, old_irql);
- callback_registered_ = FALSE;
- return STATUS_SUCCESS;
- }
- } // namespace commkit_driver
|