I am writing a windows kmdf driver for a virtual HID device using the vhf framework. The device takes any write reports submitted to it, modifies them slightly, and spits them out via VhfReadReportSubmit
. Unfortunately, I am getting stack-overflow BSODs when multiple reports come in parallel. I should note that I am relying on the vhf framework to buffer the submitted reports (this is the default) and thus, per documentation, there should be no restrictions on calling the VhfReadReportSubmit
function.
The relevant code from AddDevice
which calls VhfCreate
:
DeviceCtx* ctx = getCtx(device);
ctx->parallel_ops_counter = 0;
VHF_CONFIG_INIT(&vhfCfg, WdfDeviceWdmGetDeviceObject(device), sizeof(report_desc), report_desc);
vhfCfg.VhfClientContext = ctx;
vhfCfg.OperationContextSize = MAX_HID_REPORT_SIZE;
vhfCfg.EvtVhfAsyncOperationWriteReport = ForwardReport;
vhfCfg.VendorID = VENDOR_ID;
vhfCfg.ProductID = PRODUCT_ID;
status = VhfCreate(&vhfCfg, &ctx->vhfHandle);
and the ForwardReport
function, which gets called when someone sumbits a write report to the device (I've removed some trace messages for simplicity):
// FIXME: Submitting a lot of HID reports in parallel leads to a bugcheck (BSOD)
void ForwardReport(DeviceCtx* devCtx, VHFOPERATIONHANDLE op, void* opCtx, PHID_XFER_PACKET report) {
UNREFERENCED_PARAMETER(opCtx);
NTSTATUS status;
HID_XFER_PACKET packet_copy;
// Prevent BSOD (STACK_OVERFLOW) which for some unknown reason
// happens when too many HID reports are submitted in parallel
if (devCtx->parallel_ops_counter > MAX_PARALLEL_OPS) {
VhfAsyncOperationComplete(op, STATUS_INSUFFICIENT_RESOURCES); // STATUS_INTERNAL_ERROR
return;
}
devCtx->parallel_ops_counter++;
// Copy the report to a temporary buffer
if (report->reportBufferLen > MAX_HID_REPORT_SIZE) {
VhfAsyncOperationComplete(op, STATUS_BUFFER_OVERFLOW);
return;
}
packet_copy.reportBuffer = opCtx;
packet_copy.reportBufferLen = report->reportBufferLen;
packet_copy.reportId = report->reportId;
memcpy(opCtx, report->reportBuffer, report->reportBufferLen);
// Change the report channel
Packet* pkt = (Packet*)(packet_copy.reportBuffer);
if (IS_CLIENT_CHANNEL(pkt->channel)) {
pkt->channel = ENCODE_CLIENT_CHANNEL(pkt->channel);
} else if(IS_CONTROL_CHANNEL(pkt->channel)) {
pkt->channel = DECODE_CLIENT_CHANNEL(pkt->channel);
}
else if (pkt->channel == BROADCAST_CHANNEL_SERVER) {
pkt->channel = BROADCAST_CHANNEL_CLIENT;
}
else if (pkt->channel == BROADCAST_CHANNEL_CLIENT) {
pkt->channel = BROADCAST_CHANNEL_SERVER;
}
// Submit the changed report
status = VhfReadReportSubmit(devCtx->vhfHandle, &packet_copy);
// Set the operation return code
VhfAsyncOperationComplete(op, status);
devCtx->parallel_ops_counter--;
}
If I remove the MAX_PARALLEL_OPS
check, the driver regularly results in a BSOD. Is there anything I am doing wrong?