diff --git a/sdk/include/ViGEm/km/BusShared.h b/sdk/include/ViGEm/km/BusShared.h index d9fd632..6196def 100644 --- a/sdk/include/ViGEm/km/BusShared.h +++ b/sdk/include/ViGEm/km/BusShared.h @@ -424,6 +424,8 @@ VOID FORCEINLINE DS4_SUBMIT_REPORT_INIT( DS4_REPORT_INIT(&Report->Report); } +#include + typedef struct _DS4_SUBMIT_REPORT_EX { // diff --git a/sys/Ds4Pdo.cpp b/sys/Ds4Pdo.cpp index df9b25c..a384de0 100644 --- a/sys/Ds4Pdo.cpp +++ b/sys/Ds4Pdo.cpp @@ -1088,8 +1088,13 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::UsbControlTransfer(PURB Urb) NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::SubmitReportImpl(PVOID NewReport) { - NTSTATUS status; - WDFREQUEST usbRequest; + NTSTATUS status; + WDFREQUEST usbRequest; + + /* + * The logic here is unusual to keep backwards compatibility with the + * original API that didn't allow submitting the full report. + */ status = WdfIoQueueRetrieveNextRequest(this->_PendingUsbInRequests, &usbRequest); @@ -1100,19 +1105,52 @@ NTSTATUS ViGEm::Bus::Targets::EmulationTargetDS4::SubmitReportImpl(PVOID NewRepo PIRP pendingIrp = WdfRequestWdmGetIrp(usbRequest); // Get USB request block - PURB urb = static_cast(URB_FROM_IRP(pendingIrp)); + const auto urb = static_cast(URB_FROM_IRP(pendingIrp)); // Get transfer buffer - auto Buffer = static_cast(urb->UrbBulkOrInterruptTransfer.TransferBuffer); + const auto buffer = static_cast(urb->UrbBulkOrInterruptTransfer.TransferBuffer); + // Set correct buffer size urb->UrbBulkOrInterruptTransfer.TransferBufferLength = DS4_REPORT_SIZE; - /* Copy report to cache and transfer buffer - * Skip first byte as it contains the never changing report id */ - RtlCopyBytes(this->_Report + 1, &(static_cast(NewReport))->Report, sizeof(DS4_REPORT)); + // Cast to expected struct + const auto pSubmit = static_cast(NewReport); - if (Buffer) - RtlCopyBytes(Buffer, this->_Report, DS4_REPORT_SIZE); + /* + * Copy report to cache and transfer buffer + * Skip first byte as it contains the never changing report ID + */ + + // + // "Old" API which only allows to update partial report + // + if (pSubmit->Size == sizeof(DS4_SUBMIT_REPORT)) + { + TraceDbg(TRACE_DS4, "Received DS4_SUBMIT_REPORT update"); + + RtlCopyBytes( + &this->_Report[1], + &(static_cast(NewReport))->Report, + sizeof((static_cast(NewReport))->Report) + ); + } + + // + // "Extended" API allowing complete report update + // + if (pSubmit->Size == sizeof(DS4_SUBMIT_REPORT_EX)) + { + TraceDbg(TRACE_DS4, "Received DS4_SUBMIT_REPORT_EX update"); + + RtlCopyBytes( + &this->_Report[1], + &(static_cast(NewReport))->Report, + sizeof((static_cast(NewReport))->Report) + ); + } + + if (buffer) + RtlCopyBytes(buffer, this->_Report, DS4_REPORT_SIZE); // Complete pending request WdfRequestComplete(usbRequest, status); diff --git a/sys/Queue.cpp b/sys/Queue.cpp index 22cec1e..ca4d424 100644 --- a/sys/Queue.cpp +++ b/sys/Queue.cpp @@ -300,25 +300,54 @@ VOID Bus_EvtIoDeviceControl( break; } - if ((sizeof(DS4_SUBMIT_REPORT) == ds4Submit->Size) && (length == InputBufferLength)) + // + // Check if buffer is within expected bounds + // + if (length < sizeof(DS4_SUBMIT_REPORT) || length > sizeof(DS4_SUBMIT_REPORT_EX)) { - // This request only supports a single PDO at a time - if (ds4Submit->SerialNo == 0) - { - TraceEvents(TRACE_LEVEL_ERROR, - TRACE_QUEUE, - "Invalid serial 0 submitted"); + TraceDbg( + TRACE_QUEUE, + "Unexpected buffer size: %d", + static_cast(length) + ); - status = STATUS_INVALID_PARAMETER; - break; - } - - if (!EmulationTargetPDO::GetPdoByTypeAndSerial(Device, DualShock4Wired, ds4Submit->SerialNo, &pdo)) - status = STATUS_DEVICE_DOES_NOT_EXIST; - else - status = pdo->SubmitReport(ds4Submit); + status = STATUS_INVALID_BUFFER_SIZE; + break; } + // + // Check if this makes sense before passing it on + // + if (length != ds4Submit->Size) + { + TraceDbg( + TRACE_QUEUE, + "Invalid buffer size: %d", + ds4Submit->Size + ); + + status = STATUS_INVALID_BUFFER_SIZE; + break; + } + + // + // This request only supports a single PDO at a time + // + if (ds4Submit->SerialNo == 0) + { + TraceEvents(TRACE_LEVEL_ERROR, + TRACE_QUEUE, + "Invalid serial 0 submitted"); + + status = STATUS_INVALID_PARAMETER; + break; + } + + if (!EmulationTargetPDO::GetPdoByTypeAndSerial(Device, DualShock4Wired, ds4Submit->SerialNo, &pdo)) + status = STATUS_DEVICE_DOES_NOT_EXIST; + else + status = pdo->SubmitReport(ds4Submit); + break; #pragma endregion