422 lines
11 KiB
C
422 lines
11 KiB
C
|
/**
|
||
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
||
|
* Server USB redirection channel - helper functions
|
||
|
*
|
||
|
* Copyright 2019 Armin Novak <armin.novak@thincast.com>
|
||
|
* Copyright 2019 Thincast Technologies GmbH
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
#ifdef HAVE_CONFIG_H
|
||
|
#include "config.h"
|
||
|
#endif
|
||
|
|
||
|
#include "urbdrc_helpers.h"
|
||
|
#include "urbdrc_types.h"
|
||
|
#include <winpr/print.h>
|
||
|
|
||
|
const char* mask_to_string(UINT32 mask)
|
||
|
{
|
||
|
switch (mask)
|
||
|
{
|
||
|
case STREAM_ID_NONE:
|
||
|
return "STREAM_ID_NONE";
|
||
|
|
||
|
case STREAM_ID_PROXY:
|
||
|
return "STREAM_ID_PROXY";
|
||
|
|
||
|
case STREAM_ID_STUB:
|
||
|
return "STREAM_ID_STUB";
|
||
|
|
||
|
default:
|
||
|
return "UNKNOWN";
|
||
|
}
|
||
|
}
|
||
|
const char* interface_to_string(UINT32 id)
|
||
|
{
|
||
|
switch (id)
|
||
|
{
|
||
|
case CAPABILITIES_NEGOTIATOR:
|
||
|
return "CAPABILITIES_NEGOTIATOR";
|
||
|
|
||
|
case SERVER_CHANNEL_NOTIFICATION:
|
||
|
return "SERVER_CHANNEL_NOTIFICATION";
|
||
|
|
||
|
case CLIENT_CHANNEL_NOTIFICATION:
|
||
|
return "CLIENT_CHANNEL_NOTIFICATION";
|
||
|
|
||
|
default:
|
||
|
return "DEVICE_MESSAGE";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static const char* call_to_string_none(BOOL client, UINT32 interfaceId, UINT32 functionId)
|
||
|
{
|
||
|
WINPR_UNUSED(interfaceId);
|
||
|
|
||
|
if (client)
|
||
|
return "RIM_EXCHANGE_CAPABILITY_RESPONSE [none |client]";
|
||
|
else
|
||
|
{
|
||
|
switch (functionId)
|
||
|
{
|
||
|
case RIM_EXCHANGE_CAPABILITY_REQUEST:
|
||
|
return "RIM_EXCHANGE_CAPABILITY_REQUEST [none |server]";
|
||
|
|
||
|
case RIMCALL_RELEASE:
|
||
|
return "RIMCALL_RELEASE [none |server]";
|
||
|
|
||
|
case RIMCALL_QUERYINTERFACE:
|
||
|
return "RIMCALL_QUERYINTERFACE [none |server]";
|
||
|
|
||
|
default:
|
||
|
return "UNKNOWN [none |server]";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static const char* call_to_string_proxy_server(UINT32 functionId)
|
||
|
{
|
||
|
switch (functionId)
|
||
|
{
|
||
|
case QUERY_DEVICE_TEXT:
|
||
|
return "QUERY_DEVICE_TEXT [proxy|server]";
|
||
|
|
||
|
case INTERNAL_IO_CONTROL:
|
||
|
return "INTERNAL_IO_CONTROL [proxy|server]";
|
||
|
|
||
|
case IO_CONTROL:
|
||
|
return "IO_CONTROL [proxy|server]";
|
||
|
|
||
|
case REGISTER_REQUEST_CALLBACK:
|
||
|
return "REGISTER_REQUEST_CALLBACK [proxy|server]";
|
||
|
|
||
|
case CANCEL_REQUEST:
|
||
|
return "CANCEL_REQUEST [proxy|server]";
|
||
|
|
||
|
case RETRACT_DEVICE:
|
||
|
return "RETRACT_DEVICE [proxy|server]";
|
||
|
|
||
|
case TRANSFER_IN_REQUEST:
|
||
|
return "TRANSFER_IN_REQUEST [proxy|server]";
|
||
|
|
||
|
default:
|
||
|
return "UNKNOWN [proxy|server]";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static const char* call_to_string_proxy_client(UINT32 functionId)
|
||
|
{
|
||
|
switch (functionId)
|
||
|
{
|
||
|
case URB_COMPLETION_NO_DATA:
|
||
|
return "URB_COMPLETION_NO_DATA [proxy|client]";
|
||
|
|
||
|
case URB_COMPLETION:
|
||
|
return "URB_COMPLETION [proxy|client]";
|
||
|
|
||
|
case IOCONTROL_COMPLETION:
|
||
|
return "IOCONTROL_COMPLETION [proxy|client]";
|
||
|
|
||
|
case TRANSFER_OUT_REQUEST:
|
||
|
return "TRANSFER_OUT_REQUEST [proxy|client]";
|
||
|
|
||
|
default:
|
||
|
return "UNKNOWN [proxy|client]";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static const char* call_to_string_proxy(BOOL client, UINT32 interfaceId, UINT32 functionId)
|
||
|
{
|
||
|
switch (interfaceId & INTERFACE_ID_MASK)
|
||
|
{
|
||
|
case CLIENT_DEVICE_SINK:
|
||
|
switch (functionId)
|
||
|
{
|
||
|
case ADD_VIRTUAL_CHANNEL:
|
||
|
return "ADD_VIRTUAL_CHANNEL [proxy|sink ]";
|
||
|
|
||
|
case ADD_DEVICE:
|
||
|
return "ADD_DEVICE [proxy|sink ]";
|
||
|
case RIMCALL_RELEASE:
|
||
|
return "RIMCALL_RELEASE [proxy|sink ]";
|
||
|
|
||
|
case RIMCALL_QUERYINTERFACE:
|
||
|
return "RIMCALL_QUERYINTERFACE [proxy|sink ]";
|
||
|
default:
|
||
|
return "UNKNOWN [proxy|sink ]";
|
||
|
}
|
||
|
|
||
|
case SERVER_CHANNEL_NOTIFICATION:
|
||
|
switch (functionId)
|
||
|
{
|
||
|
case CHANNEL_CREATED:
|
||
|
return "CHANNEL_CREATED [proxy|server]";
|
||
|
|
||
|
case RIMCALL_RELEASE:
|
||
|
return "RIMCALL_RELEASE [proxy|server]";
|
||
|
|
||
|
case RIMCALL_QUERYINTERFACE:
|
||
|
return "RIMCALL_QUERYINTERFACE [proxy|server]";
|
||
|
|
||
|
default:
|
||
|
return "UNKNOWN [proxy|server]";
|
||
|
}
|
||
|
|
||
|
case CLIENT_CHANNEL_NOTIFICATION:
|
||
|
switch (functionId)
|
||
|
{
|
||
|
case CHANNEL_CREATED:
|
||
|
return "CHANNEL_CREATED [proxy|client]";
|
||
|
case RIMCALL_RELEASE:
|
||
|
return "RIMCALL_RELEASE [proxy|client]";
|
||
|
case RIMCALL_QUERYINTERFACE:
|
||
|
return "RIMCALL_QUERYINTERFACE [proxy|client]";
|
||
|
default:
|
||
|
return "UNKNOWN [proxy|client]";
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
if (client)
|
||
|
return call_to_string_proxy_client(functionId);
|
||
|
else
|
||
|
return call_to_string_proxy_server(functionId);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static const char* call_to_string_stub(BOOL client, UINT32 interfaceId, UINT32 functionId)
|
||
|
{
|
||
|
return "QUERY_DEVICE_TEXT_RSP [stub |client]";
|
||
|
}
|
||
|
|
||
|
const char* call_to_string(BOOL client, UINT32 interface, UINT32 functionId)
|
||
|
{
|
||
|
const UINT32 mask = (interface & STREAM_ID_MASK) >> 30;
|
||
|
const UINT32 interfaceId = interface & INTERFACE_ID_MASK;
|
||
|
|
||
|
switch (mask)
|
||
|
{
|
||
|
case STREAM_ID_NONE:
|
||
|
return call_to_string_none(client, interfaceId, functionId);
|
||
|
|
||
|
case STREAM_ID_PROXY:
|
||
|
return call_to_string_proxy(client, interfaceId, functionId);
|
||
|
|
||
|
case STREAM_ID_STUB:
|
||
|
return call_to_string_stub(client, interfaceId, functionId);
|
||
|
|
||
|
default:
|
||
|
return "UNKNOWN[mask]";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const char* urb_function_string(UINT16 urb)
|
||
|
{
|
||
|
switch (urb)
|
||
|
{
|
||
|
case TS_URB_SELECT_CONFIGURATION:
|
||
|
return "TS_URB_SELECT_CONFIGURATION";
|
||
|
|
||
|
case TS_URB_SELECT_INTERFACE:
|
||
|
return "TS_URB_SELECT_INTERFACE";
|
||
|
|
||
|
case TS_URB_PIPE_REQUEST:
|
||
|
return "TS_URB_PIPE_REQUEST";
|
||
|
|
||
|
case TS_URB_TAKE_FRAME_LENGTH_CONTROL:
|
||
|
return "TS_URB_TAKE_FRAME_LENGTH_CONTROL";
|
||
|
|
||
|
case TS_URB_RELEASE_FRAME_LENGTH_CONTROL:
|
||
|
return "TS_URB_RELEASE_FRAME_LENGTH_CONTROL";
|
||
|
|
||
|
case TS_URB_GET_FRAME_LENGTH:
|
||
|
return "TS_URB_GET_FRAME_LENGTH";
|
||
|
|
||
|
case TS_URB_SET_FRAME_LENGTH:
|
||
|
return "TS_URB_SET_FRAME_LENGTH";
|
||
|
|
||
|
case TS_URB_GET_CURRENT_FRAME_NUMBER:
|
||
|
return "TS_URB_GET_CURRENT_FRAME_NUMBER";
|
||
|
|
||
|
case TS_URB_CONTROL_TRANSFER:
|
||
|
return "TS_URB_CONTROL_TRANSFER";
|
||
|
|
||
|
case TS_URB_BULK_OR_INTERRUPT_TRANSFER:
|
||
|
return "TS_URB_BULK_OR_INTERRUPT_TRANSFER";
|
||
|
|
||
|
case TS_URB_ISOCH_TRANSFER:
|
||
|
return "TS_URB_ISOCH_TRANSFER";
|
||
|
|
||
|
case TS_URB_GET_DESCRIPTOR_FROM_DEVICE:
|
||
|
return "TS_URB_GET_DESCRIPTOR_FROM_DEVICE";
|
||
|
|
||
|
case TS_URB_SET_DESCRIPTOR_TO_DEVICE:
|
||
|
return "TS_URB_SET_DESCRIPTOR_TO_DEVICE";
|
||
|
|
||
|
case TS_URB_SET_FEATURE_TO_DEVICE:
|
||
|
return "TS_URB_SET_FEATURE_TO_DEVICE";
|
||
|
|
||
|
case TS_URB_SET_FEATURE_TO_INTERFACE:
|
||
|
return "TS_URB_SET_FEATURE_TO_INTERFACE";
|
||
|
|
||
|
case TS_URB_SET_FEATURE_TO_ENDPOINT:
|
||
|
return "TS_URB_SET_FEATURE_TO_ENDPOINT";
|
||
|
|
||
|
case TS_URB_CLEAR_FEATURE_TO_DEVICE:
|
||
|
return "TS_URB_CLEAR_FEATURE_TO_DEVICE";
|
||
|
|
||
|
case TS_URB_CLEAR_FEATURE_TO_INTERFACE:
|
||
|
return "TS_URB_CLEAR_FEATURE_TO_INTERFACE";
|
||
|
|
||
|
case TS_URB_CLEAR_FEATURE_TO_ENDPOINT:
|
||
|
return "TS_URB_CLEAR_FEATURE_TO_ENDPOINT";
|
||
|
|
||
|
case TS_URB_GET_STATUS_FROM_DEVICE:
|
||
|
return "TS_URB_GET_STATUS_FROM_DEVICE";
|
||
|
|
||
|
case TS_URB_GET_STATUS_FROM_INTERFACE:
|
||
|
return "TS_URB_GET_STATUS_FROM_INTERFACE";
|
||
|
|
||
|
case TS_URB_GET_STATUS_FROM_ENDPOINT:
|
||
|
return "TS_URB_GET_STATUS_FROM_ENDPOINT";
|
||
|
|
||
|
case TS_URB_RESERVED_0X0016:
|
||
|
return "TS_URB_RESERVED_0X0016";
|
||
|
|
||
|
case TS_URB_VENDOR_DEVICE:
|
||
|
return "TS_URB_VENDOR_DEVICE";
|
||
|
|
||
|
case TS_URB_VENDOR_INTERFACE:
|
||
|
return "TS_URB_VENDOR_INTERFACE";
|
||
|
|
||
|
case TS_URB_VENDOR_ENDPOINT:
|
||
|
return "TS_URB_VENDOR_ENDPOINT";
|
||
|
|
||
|
case TS_URB_CLASS_DEVICE:
|
||
|
return "TS_URB_CLASS_DEVICE";
|
||
|
|
||
|
case TS_URB_CLASS_INTERFACE:
|
||
|
return "TS_URB_CLASS_INTERFACE";
|
||
|
|
||
|
case TS_URB_CLASS_ENDPOINT:
|
||
|
return "TS_URB_CLASS_ENDPOINT";
|
||
|
|
||
|
case TS_URB_RESERVE_0X001D:
|
||
|
return "TS_URB_RESERVE_0X001D";
|
||
|
|
||
|
case TS_URB_SYNC_RESET_PIPE_AND_CLEAR_STALL:
|
||
|
return "TS_URB_SYNC_RESET_PIPE_AND_CLEAR_STALL";
|
||
|
|
||
|
case TS_URB_CLASS_OTHER:
|
||
|
return "TS_URB_CLASS_OTHER";
|
||
|
|
||
|
case TS_URB_VENDOR_OTHER:
|
||
|
return "TS_URB_VENDOR_OTHER";
|
||
|
|
||
|
case TS_URB_GET_STATUS_FROM_OTHER:
|
||
|
return "TS_URB_GET_STATUS_FROM_OTHER";
|
||
|
|
||
|
case TS_URB_CLEAR_FEATURE_TO_OTHER:
|
||
|
return "TS_URB_CLEAR_FEATURE_TO_OTHER";
|
||
|
|
||
|
case TS_URB_SET_FEATURE_TO_OTHER:
|
||
|
return "TS_URB_SET_FEATURE_TO_OTHER";
|
||
|
|
||
|
case TS_URB_GET_DESCRIPTOR_FROM_ENDPOINT:
|
||
|
return "TS_URB_GET_DESCRIPTOR_FROM_ENDPOINT";
|
||
|
|
||
|
case TS_URB_SET_DESCRIPTOR_TO_ENDPOINT:
|
||
|
return "TS_URB_SET_DESCRIPTOR_TO_ENDPOINT";
|
||
|
|
||
|
case TS_URB_CONTROL_GET_CONFIGURATION_REQUEST:
|
||
|
return "TS_URB_CONTROL_GET_CONFIGURATION_REQUEST";
|
||
|
|
||
|
case TS_URB_CONTROL_GET_INTERFACE_REQUEST:
|
||
|
return "TS_URB_CONTROL_GET_INTERFACE_REQUEST";
|
||
|
|
||
|
case TS_URB_GET_DESCRIPTOR_FROM_INTERFACE:
|
||
|
return "TS_URB_GET_DESCRIPTOR_FROM_INTERFACE";
|
||
|
|
||
|
case TS_URB_SET_DESCRIPTOR_TO_INTERFACE:
|
||
|
return "TS_URB_SET_DESCRIPTOR_TO_INTERFACE";
|
||
|
|
||
|
case TS_URB_GET_OS_FEATURE_DESCRIPTOR_REQUEST:
|
||
|
return "TS_URB_GET_OS_FEATURE_DESCRIPTOR_REQUEST";
|
||
|
|
||
|
case TS_URB_RESERVE_0X002B:
|
||
|
return "TS_URB_RESERVE_0X002B";
|
||
|
|
||
|
case TS_URB_RESERVE_0X002C:
|
||
|
return "TS_URB_RESERVE_0X002C";
|
||
|
|
||
|
case TS_URB_RESERVE_0X002D:
|
||
|
return "TS_URB_RESERVE_0X002D";
|
||
|
|
||
|
case TS_URB_RESERVE_0X002E:
|
||
|
return "TS_URB_RESERVE_0X002E";
|
||
|
|
||
|
case TS_URB_RESERVE_0X002F:
|
||
|
return "TS_URB_RESERVE_0X002F";
|
||
|
|
||
|
case TS_URB_SYNC_RESET_PIPE:
|
||
|
return "TS_URB_SYNC_RESET_PIPE";
|
||
|
|
||
|
case TS_URB_SYNC_CLEAR_STALL:
|
||
|
return "TS_URB_SYNC_CLEAR_STALL";
|
||
|
|
||
|
case TS_URB_CONTROL_TRANSFER_EX:
|
||
|
return "TS_URB_CONTROL_TRANSFER_EX";
|
||
|
|
||
|
default:
|
||
|
return "UNKNOWN";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void urbdrc_dump_message(wLog* log, BOOL client, BOOL write, wStream* s)
|
||
|
{
|
||
|
const char* type = write ? "WRITE" : "READ";
|
||
|
UINT32 InterfaceId, MessageId, FunctionId;
|
||
|
size_t length, pos;
|
||
|
|
||
|
pos = Stream_GetPosition(s);
|
||
|
if (write)
|
||
|
{
|
||
|
length = pos;
|
||
|
Stream_SetPosition(s, 0);
|
||
|
}
|
||
|
else
|
||
|
length = Stream_GetRemainingLength(s);
|
||
|
|
||
|
if (length < 12)
|
||
|
return;
|
||
|
|
||
|
Stream_Read_UINT32(s, InterfaceId);
|
||
|
Stream_Read_UINT32(s, MessageId);
|
||
|
Stream_Read_UINT32(s, FunctionId);
|
||
|
Stream_SetPosition(s, pos);
|
||
|
|
||
|
WLog_Print(log, WLOG_DEBUG,
|
||
|
"[%-5s] %s [%08" PRIx32 "] InterfaceId=%08" PRIx32 ", MessageId=%08" PRIx32
|
||
|
", FunctionId=%08" PRIx32 ", length=%" PRIuz,
|
||
|
type, call_to_string(client, InterfaceId, FunctionId), FunctionId, InterfaceId,
|
||
|
MessageId, FunctionId, length);
|
||
|
#if defined(WITH_DEBUG_URBDRC)
|
||
|
if (write)
|
||
|
WLog_Print(log, WLOG_TRACE, "-------------------------- URBDRC sent: ---");
|
||
|
else
|
||
|
WLog_Print(log, WLOG_TRACE, "-------------------------- URBDRC received:");
|
||
|
winpr_HexLogDump(log, WLOG_TRACE, Stream_Buffer(s), length);
|
||
|
WLog_Print(log, WLOG_TRACE, "-------------------------- URBDRC end -----");
|
||
|
#endif
|
||
|
}
|