mirror of
https://github.com/morgan9e/FreeRDP
synced 2026-04-14 00:14:11 +09:00
[channels,urbdrc] refactor send routines
This commit is contained in:
@@ -51,6 +51,51 @@ static void usb_process_get_port_status(IUDEVICE* pdev, wStream* out)
|
||||
}
|
||||
}
|
||||
|
||||
/* [MS-RDPEUSB] 2.2.10.1.1TS_URB_RESULT_HEADER */
|
||||
static BOOL write_urb_result_header(wStream* s, UINT16 Size, UINT32 status)
|
||||
{
|
||||
if (!Stream_EnsureRemainingCapacity(s, 8ULL + Size))
|
||||
return FALSE;
|
||||
Stream_Write_UINT16(s, Size);
|
||||
Stream_Seek_UINT16(s);
|
||||
Stream_Write_UINT32(s, status);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* [MS-RDPEUSB] 2.2.7.2 URB Completion (URB_COMPLETION)
|
||||
* 2.2.7.3 URB Completion No Data (URB_COMPLETION_NO_DATA)
|
||||
*/
|
||||
static wStream* create_urb_completion_message(UINT32 InterfaceId, UINT32 MessageId,
|
||||
UINT32 RequestId, UINT32 FunctionId)
|
||||
{
|
||||
wStream* out =
|
||||
create_shared_message_header_with_functionid(InterfaceId, MessageId, FunctionId, 4);
|
||||
if (!out)
|
||||
return NULL;
|
||||
|
||||
Stream_Write_UINT32(out, RequestId);
|
||||
return out;
|
||||
}
|
||||
|
||||
static UINT send_urb_completion_message(GENERIC_CHANNEL_CALLBACK* callback, wStream* out,
|
||||
HRESULT hResult, UINT32 OutputSize, const void* data)
|
||||
{
|
||||
WINPR_ASSERT(callback);
|
||||
UINT status = ERROR_OUTOFMEMORY;
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(out, 8ULL + OutputSize))
|
||||
goto fail;
|
||||
|
||||
Stream_Write_INT32(out, hResult);
|
||||
Stream_Write_UINT32(out, OutputSize);
|
||||
Stream_Write(out, data, OutputSize);
|
||||
return stream_write_and_free(callback->plugin, callback->channel, out);
|
||||
|
||||
fail:
|
||||
Stream_Free(out, TRUE);
|
||||
return status;
|
||||
}
|
||||
|
||||
static UINT urb_write_completion(WINPR_ATTR_UNUSED IUDEVICE* pdev,
|
||||
GENERIC_CHANNEL_CALLBACK* callback, BOOL noAck, wStream* out,
|
||||
UINT32 InterfaceId, UINT32 MessageId, UINT32 RequestId,
|
||||
@@ -66,20 +111,23 @@ static UINT urb_write_completion(WINPR_ATTR_UNUSED IUDEVICE* pdev,
|
||||
}
|
||||
|
||||
Stream_SetPosition(out, 0);
|
||||
Stream_Write_UINT32(out, InterfaceId); /** interface */
|
||||
Stream_Write_UINT32(out, MessageId); /** message id */
|
||||
|
||||
if (OutputBufferSize != 0)
|
||||
Stream_Write_UINT32(out, URB_COMPLETION);
|
||||
else
|
||||
Stream_Write_UINT32(out, URB_COMPLETION_NO_DATA);
|
||||
const UINT32 FunctionId = (OutputBufferSize != 0) ? URB_COMPLETION : URB_COMPLETION_NO_DATA;
|
||||
if (!write_shared_message_header_with_functionid(out, InterfaceId, MessageId, FunctionId))
|
||||
{
|
||||
Stream_Free(out, TRUE);
|
||||
return ERROR_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
Stream_Write_UINT32(out, RequestId); /** RequestId */
|
||||
Stream_Write_UINT32(out, 8); /** CbTsUrbResult */
|
||||
/** TsUrbResult TS_URB_RESULT_HEADER */
|
||||
Stream_Write_UINT16(out, 8); /** Size */
|
||||
Stream_Write_UINT16(out, 0); /* Padding */
|
||||
Stream_Write_UINT32(out, usbd_status); /** UsbdStatus */
|
||||
|
||||
if (!write_urb_result_header(out, 8, usbd_status))
|
||||
{
|
||||
Stream_Free(out, TRUE);
|
||||
return ERROR_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
Stream_Write_UINT32(out, 0); /** HResult */
|
||||
Stream_Write_UINT32(out, OutputBufferSize); /** OutputBufferSize */
|
||||
Stream_Seek(out, OutputBufferSize);
|
||||
@@ -102,14 +150,11 @@ static wStream* urb_create_iocompletion(UINT32 InterfaceField, UINT32 MessageId,
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
wStream* out = Stream_New(NULL, OutputBufferSize + 28ull);
|
||||
|
||||
wStream* out = create_shared_message_header_with_functionid(
|
||||
InterfaceId, MessageId, IOCONTROL_COMPLETION, OutputBufferSize + 16ull);
|
||||
if (!out)
|
||||
return NULL;
|
||||
|
||||
Stream_Write_UINT32(out, InterfaceId); /** interface */
|
||||
Stream_Write_UINT32(out, MessageId); /** message id */
|
||||
Stream_Write_UINT32(out, IOCONTROL_COMPLETION); /** function id */
|
||||
Stream_Write_UINT32(out, RequestId); /** RequestId */
|
||||
Stream_Write_UINT32(out, USBD_STATUS_SUCCESS); /** HResult */
|
||||
Stream_Write_UINT32(out, OutputBufferSize); /** Information */
|
||||
@@ -134,29 +179,21 @@ static UINT urbdrc_process_register_request_callback(IUDEVICE* pdev,
|
||||
|
||||
WLog_Print(urbdrc->log, WLOG_DEBUG, "urbdrc_process_register_request_callback");
|
||||
|
||||
if (Stream_GetRemainingLength(s) >= 8)
|
||||
{
|
||||
Stream_Read_UINT32(s, NumRequestCompletion); /** must be 1 */
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4ULL * NumRequestCompletion))
|
||||
return ERROR_INVALID_DATA;
|
||||
for (uint32_t x = 0; x < NumRequestCompletion; x++)
|
||||
{
|
||||
/** RequestCompletion:
|
||||
* unique Request Completion interface for the client to use */
|
||||
Stream_Read_UINT32(s, RequestCompletion);
|
||||
pdev->set_ReqCompletion(pdev, RequestCompletion);
|
||||
}
|
||||
}
|
||||
else if (Stream_GetRemainingLength(s) >= 4) /** Unregister the device */
|
||||
{
|
||||
Stream_Read_UINT32(s, RequestCompletion);
|
||||
|
||||
if (pdev->get_ReqCompletion(pdev) == RequestCompletion)
|
||||
pdev->setChannelClosed(pdev);
|
||||
}
|
||||
else
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4ULL))
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(s, NumRequestCompletion); /** must be 1 */
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4ULL * NumRequestCompletion))
|
||||
return ERROR_INVALID_DATA;
|
||||
for (uint32_t x = 0; x < NumRequestCompletion; x++)
|
||||
{
|
||||
/** RequestCompletion:
|
||||
* unique Request Completion interface for the client to use */
|
||||
Stream_Read_UINT32(s, RequestCompletion);
|
||||
pdev->set_ReqCompletion(pdev, RequestCompletion);
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -368,16 +405,31 @@ static UINT urbdrc_process_internal_io_control(IUDEVICE* pdev, GENERIC_CHANNEL_C
|
||||
return stream_write_and_free(callback->plugin, callback->channel, out);
|
||||
}
|
||||
|
||||
/* [MS-RDPEUSB] 2.2.6.6 Query Device Text Response Message (QUERY_DEVICE_TEXT_RSP) */
|
||||
static UINT urbdrc_send_query_device_text_response(GENERIC_CHANNEL_CALLBACK* callback,
|
||||
UINT32 InterfaceId, UINT32 MessageId, HRESULT hr,
|
||||
const BYTE* text, uint8_t bytelen)
|
||||
{
|
||||
WINPR_ASSERT(callback);
|
||||
|
||||
const uint8_t charlen = bytelen / sizeof(WCHAR);
|
||||
wStream* out = create_shared_message_header_with_functionid(InterfaceId, MessageId, charlen,
|
||||
8ULL + bytelen);
|
||||
|
||||
if (!out)
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
Stream_Write(out, text, bytelen); /* '\0' terminated unicode */
|
||||
Stream_Write_INT32(out, hr); /** HResult */
|
||||
return stream_write_and_free(callback->plugin, callback->channel, out);
|
||||
}
|
||||
|
||||
static UINT urbdrc_process_query_device_text(IUDEVICE* pdev, GENERIC_CHANNEL_CALLBACK* callback,
|
||||
wStream* s, UINT32 MessageId, IUDEVMAN* udevman)
|
||||
{
|
||||
UINT32 out_size = 0;
|
||||
UINT32 TextType = 0;
|
||||
UINT32 LocaleId = 0;
|
||||
UINT32 InterfaceId = 0;
|
||||
UINT8 bufferSize = 0xFF;
|
||||
UINT32 hr = 0;
|
||||
wStream* out = NULL;
|
||||
BYTE DeviceDescription[0x100] = { 0 };
|
||||
|
||||
if (!pdev || !callback || !s || !udevman)
|
||||
@@ -390,25 +442,11 @@ static UINT urbdrc_process_query_device_text(IUDEVICE* pdev, GENERIC_CHANNEL_CAL
|
||||
if (LocaleId > UINT16_MAX)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
hr = pdev->control_query_device_text(pdev, TextType, (UINT16)LocaleId, &bufferSize,
|
||||
DeviceDescription);
|
||||
InterfaceId = ((STREAM_ID_STUB << 30) | pdev->get_UsbDevice(pdev));
|
||||
out_size = 16 + bufferSize;
|
||||
|
||||
if (bufferSize != 0)
|
||||
out_size += 2;
|
||||
|
||||
out = Stream_New(NULL, out_size);
|
||||
|
||||
if (!out)
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
Stream_Write_UINT32(out, InterfaceId); /** interface */
|
||||
Stream_Write_UINT32(out, MessageId); /** message id */
|
||||
Stream_Write_UINT32(out, bufferSize / 2); /** cchDeviceDescription in WCHAR */
|
||||
Stream_Write(out, DeviceDescription, bufferSize); /* '\0' terminated unicode */
|
||||
Stream_Write_UINT32(out, hr); /** HResult */
|
||||
return stream_write_and_free(callback->plugin, callback->channel, out);
|
||||
HRESULT hr = (HRESULT)pdev->control_query_device_text(pdev, TextType, (UINT16)LocaleId,
|
||||
&bufferSize, DeviceDescription);
|
||||
const UINT32 InterfaceId = ((STREAM_ID_STUB << 30) | pdev->get_UsbDevice(pdev));
|
||||
return urbdrc_send_query_device_text_response(callback, InterfaceId, MessageId, hr,
|
||||
DeviceDescription, bufferSize);
|
||||
}
|
||||
|
||||
static void func_select_all_interface_for_msconfig(IUDEVICE* pdev,
|
||||
@@ -427,18 +465,51 @@ static void func_select_all_interface_for_msconfig(IUDEVICE* pdev,
|
||||
}
|
||||
}
|
||||
|
||||
/* [MS-RDPEUSB] 2.2.10.2 TS_URB_SELECT_CONFIGURATION_RESULT */
|
||||
static UINT send_urb_select_configuration_result(GENERIC_CHANNEL_CALLBACK* callback,
|
||||
UINT32 InterfaceId, UINT32 MessageId,
|
||||
UINT32 RequestId, UINT32 UrbStatus,
|
||||
const MSUSB_CONFIG_DESCRIPTOR* MsConfig)
|
||||
{
|
||||
wStream* out =
|
||||
create_urb_completion_message(InterfaceId, MessageId, RequestId, URB_COMPLETION_NO_DATA);
|
||||
if (!out)
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
const int size = 8 + ((MsConfig) ? MsConfig->MsOutSize : 8);
|
||||
const uint16_t usize = WINPR_ASSERTING_INT_CAST(uint16_t, size);
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(out, 4))
|
||||
goto fail;
|
||||
Stream_Write_UINT32(out, usize); /* CbTsUrbResult */
|
||||
|
||||
if (!write_urb_result_header(out, usize, UrbStatus))
|
||||
goto fail;
|
||||
|
||||
/** TS_URB_SELECT_CONFIGURATION_RESULT */
|
||||
if (MsConfig)
|
||||
msusb_msconfig_write(MsConfig, out);
|
||||
else
|
||||
{
|
||||
Stream_Write_UINT32(out, 0); /** ConfigurationHandle */
|
||||
Stream_Write_UINT32(out, 0); /** NumInterfaces */
|
||||
}
|
||||
|
||||
return send_urb_completion_message(callback, out, 0, 0, NULL);
|
||||
|
||||
fail:
|
||||
Stream_Free(out, TRUE);
|
||||
return ERROR_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
static UINT urb_select_configuration(IUDEVICE* pdev, GENERIC_CHANNEL_CALLBACK* callback, wStream* s,
|
||||
UINT32 RequestField, UINT32 MessageId, IUDEVMAN* udevman,
|
||||
int transferDir)
|
||||
{
|
||||
MSUSB_CONFIG_DESCRIPTOR* MsConfig = NULL;
|
||||
size_t out_size = 0;
|
||||
UINT32 InterfaceId = 0;
|
||||
UINT32 NumInterfaces = 0;
|
||||
UINT32 usbd_status = 0;
|
||||
BYTE ConfigurationDescriptorIsValid = 0;
|
||||
wStream* out = NULL;
|
||||
size_t MsOutSize = 0;
|
||||
URBDRC_PLUGIN* urbdrc = NULL;
|
||||
const BOOL noAck = (RequestField & 0x80000000U) != 0;
|
||||
const UINT32 RequestId = RequestField & 0x7FFFFFFF;
|
||||
@@ -460,7 +531,7 @@ static UINT urb_select_configuration(IUDEVICE* pdev, GENERIC_CHANNEL_CALLBACK* c
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev));
|
||||
const UINT32 InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev));
|
||||
Stream_Read_UINT8(s, ConfigurationDescriptorIsValid);
|
||||
Stream_Seek(s, 3); /* Padding */
|
||||
Stream_Read_UINT32(s, NumInterfaces);
|
||||
@@ -486,109 +557,56 @@ static UINT urb_select_configuration(IUDEVICE* pdev, GENERIC_CHANNEL_CALLBACK* c
|
||||
}
|
||||
}
|
||||
|
||||
if (MsConfig)
|
||||
MsOutSize = WINPR_ASSERTING_INT_CAST(size_t, MsConfig->MsOutSize);
|
||||
|
||||
if (MsOutSize > 0)
|
||||
{
|
||||
if (MsOutSize > SIZE_MAX - 36)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
out_size = 36 + MsOutSize;
|
||||
}
|
||||
else
|
||||
out_size = 44;
|
||||
|
||||
out = Stream_New(NULL, out_size);
|
||||
|
||||
if (!out)
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
Stream_Write_UINT32(out, InterfaceId); /** interface */
|
||||
Stream_Write_UINT32(out, MessageId); /** message id */
|
||||
Stream_Write_UINT32(out, URB_COMPLETION_NO_DATA); /** function id */
|
||||
Stream_Write_UINT32(out, RequestId); /** RequestId */
|
||||
|
||||
if (MsOutSize > 0)
|
||||
{
|
||||
/** CbTsUrbResult */
|
||||
Stream_Write_UINT32(out, 8U + (UINT32)MsOutSize);
|
||||
/** TS_URB_RESULT_HEADER Size*/
|
||||
Stream_Write_UINT16(out, WINPR_ASSERTING_INT_CAST(uint16_t, 8U + (UINT32)MsOutSize));
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream_Write_UINT32(out, 16);
|
||||
Stream_Write_UINT16(out, 16);
|
||||
}
|
||||
|
||||
/** Padding, MUST be ignored upon receipt */
|
||||
Stream_Write_UINT16(out, TS_URB_SELECT_CONFIGURATION);
|
||||
Stream_Write_UINT32(out, usbd_status); /** UsbdStatus */
|
||||
|
||||
/** TS_URB_SELECT_CONFIGURATION_RESULT */
|
||||
if (MsOutSize > 0)
|
||||
msusb_msconfig_write(MsConfig, out);
|
||||
else
|
||||
{
|
||||
Stream_Write_UINT32(out, 0); /** ConfigurationHandle */
|
||||
Stream_Write_UINT32(out, NumInterfaces); /** NumInterfaces */
|
||||
}
|
||||
|
||||
Stream_Write_UINT32(out, 0); /** HResult */
|
||||
Stream_Write_UINT32(out, 0); /** OutputBufferSize */
|
||||
|
||||
if (!noAck)
|
||||
return stream_write_and_free(callback->plugin, callback->channel, out);
|
||||
else
|
||||
Stream_Free(out, TRUE);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
if (noAck)
|
||||
return CHANNEL_RC_OK;
|
||||
return send_urb_select_configuration_result(callback, InterfaceId, MessageId, RequestId,
|
||||
usbd_status, MsConfig);
|
||||
}
|
||||
|
||||
static UINT urb_select_interface_response(GENERIC_CHANNEL_CALLBACK* callback, UINT32 RequestId,
|
||||
UINT32 InterfaceId, UINT32 MessageId,
|
||||
MSUSB_INTERFACE_DESCRIPTOR* MsInterface,
|
||||
UINT32 OutputBufferSize)
|
||||
/* [MS-RDPEUSB[ 2.2.10.3 TS_URB_SELECT_INTERFACE_RESULT */
|
||||
static UINT urb_select_interface_result(GENERIC_CHANNEL_CALLBACK* callback, UINT32 RequestId,
|
||||
UINT32 InterfaceId, UINT32 MessageId,
|
||||
MSUSB_INTERFACE_DESCRIPTOR* MsInterface,
|
||||
UINT32 ConfigurationHandle)
|
||||
{
|
||||
WINPR_ASSERT(callback);
|
||||
WINPR_ASSERT(MsInterface);
|
||||
|
||||
URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)callback->plugin;
|
||||
WINPR_ASSERT(urbdrc);
|
||||
|
||||
const size_t interface_size = 16ULL + (MsInterface->NumberOfPipes * 20ULL);
|
||||
const size_t out_size = 36ULL + interface_size;
|
||||
if (out_size > OutputBufferSize)
|
||||
{
|
||||
WLog_Print(urbdrc->log, WLOG_DEBUG, "out_size %" PRIu32 " > OutputBufferSize %" PRIu32,
|
||||
out_size, OutputBufferSize);
|
||||
return ERROR_BAD_CONFIGURATION;
|
||||
}
|
||||
|
||||
wStream* out = Stream_New(NULL, out_size);
|
||||
const UINT32 NumInterfaces = 1;
|
||||
const uint32_t interface_size = 16U + (MsInterface->NumberOfPipes * 20U);
|
||||
wStream* out =
|
||||
create_urb_completion_message(InterfaceId, MessageId, RequestId, URB_COMPLETION_NO_DATA);
|
||||
|
||||
if (!out)
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
Stream_Write_UINT32(out, InterfaceId); /** interface */
|
||||
Stream_Write_UINT32(out, MessageId); /** message id */
|
||||
Stream_Write_UINT32(out, URB_COMPLETION_NO_DATA); /** function id */
|
||||
Stream_Write_UINT32(out, RequestId); /** RequestId */
|
||||
Stream_Write_UINT32(
|
||||
out, WINPR_ASSERTING_INT_CAST(uint32_t, 8ULL + interface_size)); /** CbTsUrbResult */
|
||||
/** TS_URB_RESULT_HEADER */
|
||||
Stream_Write_UINT16(out, WINPR_ASSERTING_INT_CAST(uint16_t, 8 + interface_size)); /** Size */
|
||||
/** Padding, MUST be ignored upon receipt */
|
||||
Stream_Write_UINT16(out, TS_URB_SELECT_INTERFACE);
|
||||
Stream_Write_UINT32(out, USBD_STATUS_SUCCESS); /** UsbdStatus */
|
||||
/** TS_URB_SELECT_INTERFACE_RESULT */
|
||||
const uint32_t size = 8U + interface_size;
|
||||
const uint16_t usize = WINPR_ASSERTING_INT_CAST(uint16_t, size);
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(out, 4))
|
||||
goto fail;
|
||||
Stream_Write_UINT32(out, usize); /* CbTsUrbResult */
|
||||
|
||||
if (!write_urb_result_header(out, usize, USBD_STATUS_SUCCESS))
|
||||
goto fail;
|
||||
|
||||
if (!msusb_msinterface_write(MsInterface, out))
|
||||
goto fail;
|
||||
Stream_Write_UINT32(out, 0); /** HResult */
|
||||
Stream_Write_UINT32(out, 0); /** OutputBufferSize */
|
||||
|
||||
return stream_write_and_free(callback->plugin, callback->channel, out);
|
||||
if (!Stream_EnsureRemainingCapacity(out, 8))
|
||||
goto fail;
|
||||
Stream_Write_UINT32(out, ConfigurationHandle); /** ConfigurationHandle */
|
||||
Stream_Write_UINT32(out, NumInterfaces); /** ConfigurationHandle */
|
||||
|
||||
for (size_t x = 0; x < NumInterfaces; x++)
|
||||
{
|
||||
const MSUSB_INTERFACE_DESCRIPTOR* ifc = &MsInterface[x];
|
||||
if (!msusb_msinterface_write(ifc, out))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return send_urb_completion_message(callback, out, 0, 0, NULL);
|
||||
|
||||
fail:
|
||||
Stream_Free(out, TRUE);
|
||||
|
||||
@@ -630,6 +648,15 @@ static UINT urb_select_interface(IUDEVICE* pdev, GENERIC_CHANNEL_CALLBACK* callb
|
||||
}
|
||||
|
||||
const UINT32 OutputBufferSize = Stream_Get_UINT32(s);
|
||||
if (OutputBufferSize != 0)
|
||||
{
|
||||
WLog_Print(urbdrc->log, WLOG_ERROR,
|
||||
"[MS-RDPEUSB] 2.2.9.3 TS_URB_SELECT_INTERFACE::OutputBufferSize must be 0, got "
|
||||
"%" PRIu32,
|
||||
OutputBufferSize);
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
pdev->select_interface(pdev, MsInterface->InterfaceNumber, MsInterface->AlternateSetting);
|
||||
/* replace device's MsInterface */
|
||||
MSUSB_CONFIG_DESCRIPTOR* MsConfig = pdev->get_MsConfig(pdev);
|
||||
@@ -646,8 +673,8 @@ static UINT urb_select_interface(IUDEVICE* pdev, GENERIC_CHANNEL_CALLBACK* callb
|
||||
if (noAck)
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
return urb_select_interface_response(callback, RequestId, InterfaceId, MessageId, MsInterface,
|
||||
OutputBufferSize);
|
||||
return urb_select_interface_result(callback, RequestId, InterfaceId, MessageId, MsInterface,
|
||||
ConfigurationHandle);
|
||||
}
|
||||
|
||||
static UINT urb_control_transfer(IUDEVICE* pdev, GENERIC_CHANNEL_CALLBACK* callback, wStream* s,
|
||||
@@ -818,21 +845,23 @@ static void urb_isoch_transfer_cb(WINPR_ATTR_UNUSED IUDEVICE* pdev,
|
||||
{
|
||||
UINT32 packetSize = (status == 0) ? NumberOfPackets * 12 : 0;
|
||||
Stream_SetPosition(out, 0);
|
||||
/* fill the send data */
|
||||
Stream_Write_UINT32(out, InterfaceId); /** interface */
|
||||
Stream_Write_UINT32(out, MessageId); /** message id */
|
||||
|
||||
if (OutputBufferSize == 0)
|
||||
Stream_Write_UINT32(out, URB_COMPLETION_NO_DATA); /** function id */
|
||||
else
|
||||
Stream_Write_UINT32(out, URB_COMPLETION); /** function id */
|
||||
const UINT32 FunctionId = (OutputBufferSize == 0) ? URB_COMPLETION_NO_DATA : URB_COMPLETION;
|
||||
if (!write_shared_message_header_with_functionid(out, InterfaceId, MessageId, FunctionId))
|
||||
{
|
||||
Stream_Free(out, TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
Stream_Write_UINT32(out, RequestId); /** RequestId */
|
||||
Stream_Write_UINT32(out, 20 + packetSize); /** CbTsUrbResult */
|
||||
/** TsUrbResult TS_URB_RESULT_HEADER */
|
||||
Stream_Write_UINT16(out, WINPR_ASSERTING_INT_CAST(uint16_t, 20 + packetSize)); /** Size */
|
||||
Stream_Write_UINT16(out, 0); /* Padding */
|
||||
Stream_Write_UINT32(out, status); /** UsbdStatus */
|
||||
if (!write_urb_result_header(out, WINPR_ASSERTING_INT_CAST(uint16_t, 20 + packetSize),
|
||||
status))
|
||||
{
|
||||
Stream_Free(out, TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
Stream_Write_UINT32(out, StartFrame); /** StartFrame */
|
||||
|
||||
if (status == 0)
|
||||
@@ -1325,24 +1354,42 @@ static UINT urb_pipe_request(IUDEVICE* pdev, GENERIC_CHANNEL_CALLBACK* callback,
|
||||
return urb_write_completion(pdev, callback, noAck, out, InterfaceId, MessageId, RequestId, ret,
|
||||
0);
|
||||
}
|
||||
/* [MS-RDPEUSB] 2.2.10.4 TS_URB_GET_CURRENT_FRAME_NUMBER_RESULT */
|
||||
static UINT urb_send_current_frame_number_result(GENERIC_CHANNEL_CALLBACK* callback,
|
||||
UINT32 RequestId, UINT32 MessageId,
|
||||
UINT32 CompletionId, UINT32 FrameNumber)
|
||||
{
|
||||
WINPR_ASSERT(callback);
|
||||
|
||||
const UINT32 InterfaceId = ((STREAM_ID_PROXY << 30) | CompletionId);
|
||||
wStream* out =
|
||||
create_urb_completion_message(InterfaceId, MessageId, RequestId, URB_COMPLETION_NO_DATA);
|
||||
|
||||
if (!out)
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
Stream_Write_UINT32(out, 12); /** CbTsUrbResult */
|
||||
if (!write_urb_result_header(out, 12, USBD_STATUS_SUCCESS))
|
||||
{
|
||||
Stream_Free(out, TRUE);
|
||||
return ERROR_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
Stream_Write_UINT32(out, FrameNumber); /** FrameNumber */
|
||||
return send_urb_completion_message(callback, out, 0, 0, NULL);
|
||||
}
|
||||
|
||||
static UINT urb_get_current_frame_number(IUDEVICE* pdev, GENERIC_CHANNEL_CALLBACK* callback,
|
||||
wStream* s, UINT32 RequestField, UINT32 MessageId,
|
||||
IUDEVMAN* udevman, int transferDir)
|
||||
{
|
||||
UINT32 out_size = 0;
|
||||
UINT32 InterfaceId = 0;
|
||||
UINT32 OutputBufferSize = 0;
|
||||
UINT32 dummy_frames = 0;
|
||||
wStream* out = NULL;
|
||||
URBDRC_PLUGIN* urbdrc = NULL;
|
||||
const BOOL noAck = (RequestField & 0x80000000U) != 0;
|
||||
const UINT32 RequestId = RequestField & 0x7FFFFFFF;
|
||||
|
||||
if (!callback || !s || !udevman || !pdev)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
urbdrc = (URBDRC_PLUGIN*)callback->plugin;
|
||||
URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)callback->plugin;
|
||||
|
||||
if (!urbdrc)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
@@ -1357,44 +1404,20 @@ static UINT urb_get_current_frame_number(IUDEVICE* pdev, GENERIC_CHANNEL_CALLBAC
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev));
|
||||
Stream_Read_UINT32(s, OutputBufferSize);
|
||||
/** Fixme: Need to fill actual frame number!!*/
|
||||
dummy_frames = GetTickCount();
|
||||
out_size = 40;
|
||||
|
||||
if (out_size > OutputBufferSize)
|
||||
const UINT32 OutputBufferSize = Stream_Get_UINT32(s);
|
||||
if (OutputBufferSize != 0)
|
||||
{
|
||||
WLog_Print(urbdrc->log, WLOG_DEBUG, "out_size %" PRIu32 " > OutputBufferSize %" PRIu32,
|
||||
out_size, OutputBufferSize);
|
||||
return ERROR_BAD_CONFIGURATION;
|
||||
WLog_Print(urbdrc->log, WLOG_WARN, "OutputBufferSize=%" PRIu32 ", expected 0");
|
||||
}
|
||||
/** Fixme: Need to fill actual frame number!!*/
|
||||
const UINT32 dummy_frames = GetTickCount();
|
||||
const UINT32 CompletionId = pdev->get_ReqCompletion(pdev);
|
||||
|
||||
out = Stream_New(NULL, out_size);
|
||||
if (noAck)
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
if (!out)
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
Stream_Write_UINT32(out, InterfaceId); /** interface */
|
||||
Stream_Write_UINT32(out, MessageId); /** message id */
|
||||
Stream_Write_UINT32(out, URB_COMPLETION_NO_DATA);
|
||||
Stream_Write_UINT32(out, RequestId); /** RequestId */
|
||||
Stream_Write_UINT32(out, 12); /** CbTsUrbResult */
|
||||
/** TsUrbResult TS_URB_RESULT_HEADER */
|
||||
Stream_Write_UINT16(out, 12); /** Size */
|
||||
/** Padding, MUST be ignored upon receipt */
|
||||
Stream_Write_UINT16(out, TS_URB_GET_CURRENT_FRAME_NUMBER);
|
||||
Stream_Write_UINT32(out, USBD_STATUS_SUCCESS); /** UsbdStatus */
|
||||
Stream_Write_UINT32(out, dummy_frames); /** FrameNumber */
|
||||
Stream_Write_UINT32(out, 0); /** HResult */
|
||||
Stream_Write_UINT32(out, 0); /** OutputBufferSize */
|
||||
|
||||
if (!noAck)
|
||||
return stream_write_and_free(callback->plugin, callback->channel, out);
|
||||
else
|
||||
Stream_Free(out, TRUE);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
return urb_send_current_frame_number_result(callback, RequestId, MessageId, CompletionId,
|
||||
dummy_frames);
|
||||
}
|
||||
|
||||
/* Unused function for current server */
|
||||
|
||||
@@ -110,6 +110,21 @@ static int func_instance_id_generate(IUDEVICE* pdev, char* strInstanceId, size_t
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* [MS-RDPEUSB] 2.2.3.2 Interface Manipulation Exchange Capabilities Response
|
||||
* (RIM_EXCHANGE_CAPABILITY_RESPONSE) */
|
||||
static UINT urbdrc_send_capability_response(GENERIC_CHANNEL_CALLBACK* callback, UINT32 MessageId,
|
||||
UINT32 Version)
|
||||
{
|
||||
const UINT32 InterfaceId = ((STREAM_ID_NONE << 30) | CAPABILITIES_NEGOTIATOR);
|
||||
wStream* out = create_shared_message_header_with_functionid(InterfaceId, MessageId, Version, 4);
|
||||
|
||||
if (!out)
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
Stream_Write_UINT32(out, 0x00000000); /* HRESULT */
|
||||
return stream_write_and_free(callback->plugin, callback->channel, out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
@@ -118,33 +133,45 @@ static int func_instance_id_generate(IUDEVICE* pdev, char* strInstanceId, size_t
|
||||
static UINT urbdrc_process_capability_request(GENERIC_CHANNEL_CALLBACK* callback, wStream* s,
|
||||
UINT32 MessageId)
|
||||
{
|
||||
UINT32 InterfaceId = 0;
|
||||
UINT32 Version = 0;
|
||||
UINT32 out_size = 0;
|
||||
wStream* out = NULL;
|
||||
WINPR_ASSERT(callback);
|
||||
URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)callback->plugin;
|
||||
WINPR_ASSERT(urbdrc);
|
||||
|
||||
if (!callback || !s)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
|
||||
if (!Stream_CheckAndLogRequiredLengthWLog(urbdrc->log, s, 4))
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(s, Version);
|
||||
UINT32 Version = Stream_Get_UINT32(s);
|
||||
|
||||
if (Version > RIM_CAPABILITY_VERSION_01)
|
||||
{
|
||||
WLog_Print(urbdrc->log, WLOG_WARN, "Unknown capability version %" PRIu32 ", expected %d",
|
||||
Version, RIM_CAPABILITY_VERSION_01);
|
||||
Version = RIM_CAPABILITY_VERSION_01;
|
||||
}
|
||||
|
||||
InterfaceId = ((STREAM_ID_NONE << 30) | CAPABILITIES_NEGOTIATOR);
|
||||
out_size = 16;
|
||||
out = Stream_New(NULL, out_size);
|
||||
return urbdrc_send_capability_response(callback, MessageId, Version);
|
||||
}
|
||||
|
||||
/* [MS-RDPEUSB] 2.2.5.1 Channel Created Message (CHANNEL_CREATED) */
|
||||
static UINT urbdrc_send_channel_created(GENERIC_CHANNEL_CALLBACK* callback, UINT32 MessageId,
|
||||
UINT32 MajorVersion, UINT32 MinorVersion,
|
||||
UINT32 Capabilities)
|
||||
{
|
||||
WINPR_ASSERT(callback);
|
||||
|
||||
const UINT32 InterfaceId = ((STREAM_ID_PROXY << 30) | CLIENT_CHANNEL_NOTIFICATION);
|
||||
wStream* out =
|
||||
create_shared_message_header_with_functionid(InterfaceId, MessageId, CHANNEL_CREATED, 12);
|
||||
|
||||
if (!out)
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
Stream_Write_UINT32(out, InterfaceId); /* interface id */
|
||||
Stream_Write_UINT32(out, MessageId); /* message id */
|
||||
Stream_Write_UINT32(out, Version); /* usb protocol version */
|
||||
Stream_Write_UINT32(out, 0x00000000); /* HRESULT */
|
||||
Stream_Write_UINT32(out, MajorVersion);
|
||||
Stream_Write_UINT32(out, MinorVersion);
|
||||
Stream_Write_UINT32(out, Capabilities); /* capabilities version */
|
||||
return stream_write_and_free(callback->plugin, callback->channel, out);
|
||||
}
|
||||
|
||||
@@ -156,12 +183,9 @@ static UINT urbdrc_process_capability_request(GENERIC_CHANNEL_CALLBACK* callback
|
||||
static UINT urbdrc_process_channel_create(GENERIC_CHANNEL_CALLBACK* callback, wStream* s,
|
||||
UINT32 MessageId)
|
||||
{
|
||||
UINT32 InterfaceId = 0;
|
||||
UINT32 out_size = 0;
|
||||
UINT32 MajorVersion = 0;
|
||||
UINT32 MinorVersion = 0;
|
||||
UINT32 Capabilities = 0;
|
||||
wStream* out = NULL;
|
||||
URBDRC_PLUGIN* urbdrc = NULL;
|
||||
|
||||
if (!callback || !s || !callback->plugin)
|
||||
@@ -185,38 +209,126 @@ static UINT urbdrc_process_channel_create(GENERIC_CHANNEL_CALLBACK* callback, wS
|
||||
MajorVersion = 1;
|
||||
MinorVersion = 0;
|
||||
}
|
||||
if (Capabilities != 0)
|
||||
{
|
||||
WLog_Print(urbdrc->log, WLOG_WARN,
|
||||
"[MS-RDPEUSB] 2.2.5.1 Channel Created Message (CHANNEL_CREATED) states "
|
||||
"Capabilities must be 0, got %" PRIu32,
|
||||
Capabilities);
|
||||
Capabilities = 0;
|
||||
}
|
||||
|
||||
InterfaceId = ((STREAM_ID_PROXY << 30) | CLIENT_CHANNEL_NOTIFICATION);
|
||||
out_size = 24;
|
||||
out = Stream_New(NULL, out_size);
|
||||
|
||||
if (!out)
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
Stream_Write_UINT32(out, InterfaceId); /* interface id */
|
||||
Stream_Write_UINT32(out, MessageId); /* message id */
|
||||
Stream_Write_UINT32(out, CHANNEL_CREATED); /* function id */
|
||||
Stream_Write_UINT32(out, MajorVersion);
|
||||
Stream_Write_UINT32(out, MinorVersion);
|
||||
Stream_Write_UINT32(out, Capabilities); /* capabilities version */
|
||||
return stream_write_and_free(callback->plugin, callback->channel, out);
|
||||
return urbdrc_send_channel_created(callback, MessageId, MajorVersion, MinorVersion,
|
||||
Capabilities);
|
||||
}
|
||||
|
||||
static UINT urdbrc_send_virtual_channel_add(IWTSPlugin* plugin, IWTSVirtualChannel* channel,
|
||||
UINT32 MessageId)
|
||||
{
|
||||
const UINT32 InterfaceId = ((STREAM_ID_PROXY << 30) | CLIENT_DEVICE_SINK);
|
||||
wStream* out = Stream_New(NULL, 12);
|
||||
wStream* out = create_shared_message_header_with_functionid(InterfaceId, MessageId,
|
||||
ADD_VIRTUAL_CHANNEL, 0);
|
||||
|
||||
if (!out)
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
Stream_Write_UINT32(out, InterfaceId); /* interface */
|
||||
Stream_Write_UINT32(out, MessageId); /* message id */
|
||||
Stream_Write_UINT32(out, ADD_VIRTUAL_CHANNEL); /* function id */
|
||||
return stream_write_and_free(plugin, channel, out);
|
||||
}
|
||||
|
||||
static BOOL write_string_block(wStream* s, size_t count, const char** strings, const size_t* length,
|
||||
BOOL isMultiSZ)
|
||||
{
|
||||
size_t len = 0;
|
||||
for (size_t x = 0; x < count; x++)
|
||||
{
|
||||
len += length[x] + 1ULL;
|
||||
}
|
||||
|
||||
if (isMultiSZ)
|
||||
len++;
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(s, len * sizeof(WCHAR) + sizeof(UINT32)))
|
||||
return FALSE;
|
||||
|
||||
/* Write number of characters (including '\0') of all strings */
|
||||
Stream_Write_UINT32(s, (UINT32)len); /* cchHwIds */
|
||||
/* HardwareIds 1 */
|
||||
|
||||
for (size_t x = 0; x < count; x++)
|
||||
{
|
||||
size_t clength = length[x];
|
||||
const char* str = strings[x];
|
||||
|
||||
const SSIZE_T w = Stream_Write_UTF16_String_From_UTF8(s, clength, str, clength, TRUE);
|
||||
if ((w < 0) || ((size_t)w != clength))
|
||||
return FALSE;
|
||||
Stream_Write_UINT16(s, 0);
|
||||
}
|
||||
|
||||
if (isMultiSZ)
|
||||
Stream_Write_UINT16(s, 0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* [MS-RDPEUSB] 2.2.4.2 Add Device Message (ADD_DEVICE) */
|
||||
static UINT urbdrc_send_add_device(GENERIC_CHANNEL_CALLBACK* callback, UINT32 UsbDevice,
|
||||
UINT32 bcdUSB, const char* strInstanceId, size_t InstanceIdLen,
|
||||
size_t nrHwIds, const char* HardwareIds[],
|
||||
const size_t HardwareIdsLen[], size_t nrCompatIds,
|
||||
const char* CompatibilityIds[],
|
||||
const size_t CompatibilityIdsLen[], const char* strContainerId,
|
||||
size_t ContainerIdLen)
|
||||
{
|
||||
WINPR_ASSERT(callback);
|
||||
WINPR_ASSERT(HardwareIds);
|
||||
WINPR_ASSERT(HardwareIdsLen);
|
||||
WINPR_ASSERT(CompatibilityIds);
|
||||
WINPR_ASSERT(CompatibilityIdsLen);
|
||||
|
||||
const UINT32 InterfaceId = ((STREAM_ID_PROXY << 30) | CLIENT_DEVICE_SINK);
|
||||
wStream* out = create_shared_message_header_with_functionid(InterfaceId, 0, ADD_DEVICE, 8);
|
||||
if (!out)
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
Stream_Write_UINT32(out, 0x00000001); /* NumUsbDevice */
|
||||
Stream_Write_UINT32(out, UsbDevice); /* UsbDevice */
|
||||
|
||||
if (!write_string_block(out, 1, &strInstanceId, &InstanceIdLen, FALSE))
|
||||
goto fail;
|
||||
|
||||
if (!write_string_block(out, nrHwIds, HardwareIds, HardwareIdsLen, TRUE))
|
||||
goto fail;
|
||||
|
||||
if (!write_string_block(out, nrCompatIds, CompatibilityIds, CompatibilityIdsLen, TRUE))
|
||||
goto fail;
|
||||
|
||||
if (!write_string_block(out, 1, &strContainerId, &ContainerIdLen, FALSE))
|
||||
goto fail;
|
||||
|
||||
/* USB_DEVICE_CAPABILITIES 28 bytes */
|
||||
if (!Stream_EnsureRemainingCapacity(out, 28))
|
||||
goto fail;
|
||||
|
||||
Stream_Write_UINT32(out, 0x0000001c); /* CbSize */
|
||||
Stream_Write_UINT32(out, 2); /* UsbBusInterfaceVersion, 0 ,1 or 2 */ // TODO: Get from libusb
|
||||
Stream_Write_UINT32(out, 0x600); /* USBDI_Version, 0x500 or 0x600 */ // TODO: Get from libusb
|
||||
/* Supported_USB_Version, 0x110,0x110 or 0x200(usb2.0) */
|
||||
Stream_Write_UINT32(out, bcdUSB);
|
||||
Stream_Write_UINT32(out, 0x00000000); /* HcdCapabilities, MUST always be zero */
|
||||
|
||||
if (bcdUSB < 0x200)
|
||||
Stream_Write_UINT32(out, 0x00000000); /* DeviceIsHighSpeed */
|
||||
else
|
||||
Stream_Write_UINT32(out, 0x00000001); /* DeviceIsHighSpeed */
|
||||
|
||||
Stream_Write_UINT32(out, 0x50); /* NoAckIsochWriteJitterBufferSizeInMs, >=10 or <=512 */
|
||||
return stream_write_and_free(callback->plugin, callback->channel, out);
|
||||
|
||||
fail:
|
||||
Stream_Free(out, TRUE);
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
@@ -224,22 +336,18 @@ static UINT urdbrc_send_virtual_channel_add(IWTSPlugin* plugin, IWTSVirtualChann
|
||||
*/
|
||||
static UINT urdbrc_send_usb_device_add(GENERIC_CHANNEL_CALLBACK* callback, IUDEVICE* pdev)
|
||||
{
|
||||
wStream* out = NULL;
|
||||
UINT32 InterfaceId = 0;
|
||||
char HardwareIds[2][DEVICE_HARDWARE_ID_SIZE] = { { 0 } };
|
||||
char CompatibilityIds[3][DEVICE_COMPATIBILITY_ID_SIZE] = { { 0 } };
|
||||
const char* CHardwareIds[2] = { HardwareIds[0], HardwareIds[1] };
|
||||
char CompatibilityIds[4][DEVICE_COMPATIBILITY_ID_SIZE] = { { 0 } };
|
||||
const char* CCompatibilityIds[4] = { CompatibilityIds[0], CompatibilityIds[1],
|
||||
CompatibilityIds[2], CompatibilityIds[3] };
|
||||
char strContainerId[DEVICE_CONTAINER_STR_SIZE] = { 0 };
|
||||
char strInstanceId[DEVICE_INSTANCE_STR_SIZE] = { 0 };
|
||||
const char* composite_str = "USB\\COMPOSITE";
|
||||
const size_t composite_len = 13;
|
||||
size_t size = 0;
|
||||
size_t CompatibilityIdLen[3];
|
||||
size_t HardwareIdsLen[2];
|
||||
size_t ContainerIdLen = 0;
|
||||
size_t InstanceIdLen = 0;
|
||||
size_t cchCompatIds = 0;
|
||||
UINT32 bcdUSB = 0;
|
||||
InterfaceId = ((STREAM_ID_PROXY << 30) | CLIENT_DEVICE_SINK);
|
||||
size_t CompatibilityIdLen[4] = { 0 };
|
||||
size_t HardwareIdsLen[2] = { 0 };
|
||||
const size_t nrHwIds = ARRAYSIZE(HardwareIds);
|
||||
size_t nrCompatIds = 3;
|
||||
|
||||
/* USB kernel driver detach!! */
|
||||
pdev->detach_kernel_driver(pdev);
|
||||
{
|
||||
@@ -270,111 +378,38 @@ static UINT urdbrc_send_usb_device_add(GENERIC_CHANNEL_CALLBACK* callback, IUDEV
|
||||
}
|
||||
else
|
||||
{
|
||||
(void)sprintf_s(CompatibilityIds[3], DEVICE_COMPATIBILITY_ID_SIZE, "USB\\COMPOSITE");
|
||||
(void)sprintf_s(CompatibilityIds[2], DEVICE_COMPATIBILITY_ID_SIZE, "USB\\DevClass_00");
|
||||
(void)sprintf_s(CompatibilityIds[1], DEVICE_COMPATIBILITY_ID_SIZE,
|
||||
"USB\\DevClass_00&SubClass_00");
|
||||
(void)sprintf_s(CompatibilityIds[0], DEVICE_COMPATIBILITY_ID_SIZE,
|
||||
"USB\\DevClass_00&SubClass_00&Prot_00");
|
||||
nrCompatIds = 4;
|
||||
}
|
||||
}
|
||||
func_instance_id_generate(pdev, strInstanceId, DEVICE_INSTANCE_STR_SIZE);
|
||||
func_container_id_generate(pdev, strContainerId);
|
||||
CompatibilityIdLen[0] = strnlen(CompatibilityIds[0], sizeof(CompatibilityIds[0]));
|
||||
CompatibilityIdLen[1] = strnlen(CompatibilityIds[1], sizeof(CompatibilityIds[1]));
|
||||
CompatibilityIdLen[2] = strnlen(CompatibilityIds[2], sizeof(CompatibilityIds[2]));
|
||||
HardwareIdsLen[0] = strnlen(HardwareIds[0], sizeof(HardwareIds[0]));
|
||||
HardwareIdsLen[1] = strnlen(HardwareIds[1], sizeof(HardwareIds[1]));
|
||||
cchCompatIds =
|
||||
CompatibilityIdLen[0] + 1 + CompatibilityIdLen[1] + 1 + CompatibilityIdLen[2] + 2;
|
||||
InstanceIdLen = strnlen(strInstanceId, sizeof(strInstanceId));
|
||||
ContainerIdLen = strnlen(strContainerId, sizeof(strContainerId));
|
||||
|
||||
if (pdev->isCompositeDevice(pdev))
|
||||
cchCompatIds += composite_len + 1;
|
||||
|
||||
size = 24;
|
||||
size += (InstanceIdLen + 1) * 2 + (HardwareIdsLen[0] + 1) * 2 + 4 +
|
||||
(HardwareIdsLen[1] + 1) * 2 + 2 + 4 + (cchCompatIds)*2 + (ContainerIdLen + 1) * 2 + 4 +
|
||||
28;
|
||||
out = Stream_New(NULL, size);
|
||||
|
||||
if (!out)
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
Stream_Write_UINT32(out, InterfaceId); /* interface */
|
||||
Stream_Write_UINT32(out, 0);
|
||||
Stream_Write_UINT32(out, ADD_DEVICE); /* function id */
|
||||
Stream_Write_UINT32(out, 0x00000001); /* NumUsbDevice */
|
||||
Stream_Write_UINT32(out, pdev->get_UsbDevice(pdev)); /* UsbDevice */
|
||||
Stream_Write_UINT32(out, (UINT32)InstanceIdLen + 1); /* cchDeviceInstanceId */
|
||||
if (Stream_Write_UTF16_String_From_UTF8(out, InstanceIdLen, strInstanceId, InstanceIdLen,
|
||||
TRUE) < 0)
|
||||
goto fail;
|
||||
Stream_Write_UINT16(out, 0);
|
||||
const size_t len = HardwareIdsLen[0] + HardwareIdsLen[1] + 3;
|
||||
if (len > UINT32_MAX)
|
||||
goto fail;
|
||||
Stream_Write_UINT32(out, (UINT32)len); /* cchHwIds */
|
||||
/* HardwareIds 1 */
|
||||
if (Stream_Write_UTF16_String_From_UTF8(out, HardwareIdsLen[0], HardwareIds[0],
|
||||
HardwareIdsLen[0], TRUE) < 0)
|
||||
goto fail;
|
||||
Stream_Write_UINT16(out, 0);
|
||||
if (Stream_Write_UTF16_String_From_UTF8(out, HardwareIdsLen[1], HardwareIds[1],
|
||||
HardwareIdsLen[1], TRUE) < 0)
|
||||
goto fail;
|
||||
Stream_Write_UINT16(out, 0);
|
||||
Stream_Write_UINT16(out, 0); /* add "\0" */
|
||||
Stream_Write_UINT32(out, (UINT32)cchCompatIds); /* cchCompatIds */
|
||||
/* CompatibilityIds */
|
||||
if (Stream_Write_UTF16_String_From_UTF8(out, CompatibilityIdLen[0], CompatibilityIds[0],
|
||||
CompatibilityIdLen[0], TRUE) < 0)
|
||||
goto fail;
|
||||
Stream_Write_UINT16(out, 0);
|
||||
if (Stream_Write_UTF16_String_From_UTF8(out, CompatibilityIdLen[1], CompatibilityIds[1],
|
||||
CompatibilityIdLen[1], TRUE) < 0)
|
||||
goto fail;
|
||||
Stream_Write_UINT16(out, 0);
|
||||
if (Stream_Write_UTF16_String_From_UTF8(out, CompatibilityIdLen[2], CompatibilityIds[2],
|
||||
CompatibilityIdLen[2], TRUE) < 0)
|
||||
goto fail;
|
||||
Stream_Write_UINT16(out, 0);
|
||||
|
||||
if (pdev->isCompositeDevice(pdev))
|
||||
for (size_t x = 0; x < nrHwIds; x++)
|
||||
{
|
||||
if (Stream_Write_UTF16_String_From_UTF8(out, composite_len, composite_str, composite_len,
|
||||
TRUE) < 0)
|
||||
goto fail;
|
||||
Stream_Write_UINT16(out, 0);
|
||||
HardwareIdsLen[x] = strnlen(HardwareIds[x], DEVICE_HARDWARE_ID_SIZE);
|
||||
}
|
||||
|
||||
Stream_Write_UINT16(out, 0x0000); /* add "\0" */
|
||||
Stream_Write_UINT32(out, (UINT32)ContainerIdLen + 1); /* cchContainerId */
|
||||
/* ContainerId */
|
||||
if (Stream_Write_UTF16_String_From_UTF8(out, ContainerIdLen, strContainerId, ContainerIdLen,
|
||||
TRUE) < 0)
|
||||
goto fail;
|
||||
Stream_Write_UINT16(out, 0);
|
||||
/* USB_DEVICE_CAPABILITIES 28 bytes */
|
||||
Stream_Write_UINT32(out, 0x0000001c); /* CbSize */
|
||||
Stream_Write_UINT32(out, 2); /* UsbBusInterfaceVersion, 0 ,1 or 2 */ // TODO: Get from libusb
|
||||
Stream_Write_UINT32(out, 0x600); /* USBDI_Version, 0x500 or 0x600 */ // TODO: Get from libusb
|
||||
/* Supported_USB_Version, 0x110,0x110 or 0x200(usb2.0) */
|
||||
bcdUSB = WINPR_ASSERTING_INT_CAST(uint32_t, pdev->query_device_descriptor(pdev, BCD_USB));
|
||||
Stream_Write_UINT32(out, bcdUSB);
|
||||
Stream_Write_UINT32(out, 0x00000000); /* HcdCapabilities, MUST always be zero */
|
||||
for (size_t x = 0; x < nrCompatIds; x++)
|
||||
{
|
||||
CompatibilityIdLen[x] = strnlen(CompatibilityIds[x], DEVICE_COMPATIBILITY_ID_SIZE);
|
||||
}
|
||||
|
||||
if (bcdUSB < 0x200)
|
||||
Stream_Write_UINT32(out, 0x00000000); /* DeviceIsHighSpeed */
|
||||
else
|
||||
Stream_Write_UINT32(out, 0x00000001); /* DeviceIsHighSpeed */
|
||||
const size_t InstanceIdLen = strnlen(strInstanceId, sizeof(strInstanceId));
|
||||
const size_t ContainerIdLen = strnlen(strContainerId, sizeof(strContainerId));
|
||||
|
||||
Stream_Write_UINT32(out, 0x50); /* NoAckIsochWriteJitterBufferSizeInMs, >=10 or <=512 */
|
||||
return stream_write_and_free(callback->plugin, callback->channel, out);
|
||||
|
||||
fail:
|
||||
Stream_Free(out, TRUE);
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
const UINT32 UsbDevice = pdev->get_UsbDevice(pdev);
|
||||
const UINT32 bcdUSB =
|
||||
WINPR_ASSERTING_INT_CAST(uint32_t, pdev->query_device_descriptor(pdev, BCD_USB));
|
||||
return urbdrc_send_add_device(callback, UsbDevice, bcdUSB, strInstanceId, InstanceIdLen,
|
||||
nrHwIds, CHardwareIds, HardwareIdsLen, nrCompatIds,
|
||||
CCompatibilityIds, CompatibilityIdLen, strContainerId,
|
||||
ContainerIdLen);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user