21#include <winpr/assert.h> 
   27#include <winpr/pool.h> 
   28#include <winpr/print.h> 
   31#include <winpr/synch.h> 
   32#include <winpr/string.h> 
   33#include <winpr/cmdline.h> 
   35#include <freerdp/dvc.h> 
   36#include <freerdp/addin.h> 
   37#include <freerdp/channels/log.h> 
   38#include <freerdp/channels/urbdrc.h> 
   40#include "urbdrc_types.h" 
   41#include "urbdrc_main.h" 
   42#include "data_transfer.h" 
   44#include <urbdrc_helpers.h> 
   46static IWTSVirtualChannel* get_channel(IUDEVMAN* idevman)
 
   48  IWTSVirtualChannelManager* channel_mgr = NULL;
 
   56  if (!urbdrc || !urbdrc->listener_callback)
 
   59  channel_mgr = urbdrc->listener_callback->channel_mgr;
 
   64  return channel_mgr->FindChannelById(channel_mgr, idevman->controlChannelId);
 
   67static int func_container_id_generate(IUDEVICE* pdev, 
char* strContainerId)
 
   71  UINT8 containerId[17] = { 0 };
 
   74  idVendor = (UINT16)pdev->query_device_descriptor(pdev, ID_VENDOR);
 
   75  idProduct = (UINT16)pdev->query_device_descriptor(pdev, ID_PRODUCT);
 
   76  path = pdev->getPath(pdev);
 
   79    p = (path + strlen(path)) - 8;
 
   83  (void)sprintf_s((
char*)containerId, 
sizeof(containerId), 
"%04" PRIX16 
"%04" PRIX16 
"%s",
 
   84                  idVendor, idProduct, p);
 
   86  (void)sprintf_s(strContainerId, DEVICE_CONTAINER_STR_SIZE,
 
   87                  "{%02" PRIx8 
"%02" PRIx8 
"%02" PRIx8 
"%02" PRIx8 
"-%02" PRIx8 
"%02" PRIx8
 
   88                  "-%02" PRIx8 
"%02" PRIx8 
"-%02" PRIx8 
"%02" PRIx8 
"-%02" PRIx8 
"%02" PRIx8
 
   89                  "%02" PRIx8 
"%02" PRIx8 
"%02" PRIx8 
"%02" PRIx8 
"}",
 
   90                  containerId[0], containerId[1], containerId[2], containerId[3], containerId[4],
 
   91                  containerId[5], containerId[6], containerId[7], containerId[8], containerId[9],
 
   92                  containerId[10], containerId[11], containerId[12], containerId[13],
 
   93                  containerId[14], containerId[15]);
 
   97static int func_instance_id_generate(IUDEVICE* pdev, 
char* strInstanceId, 
size_t len)
 
   99  char instanceId[17] = { 0 };
 
  100  (void)sprintf_s(instanceId, 
sizeof(instanceId), 
"\\%s", pdev->getPath(pdev));
 
  102  (void)sprintf_s(strInstanceId, len,
 
  103                  "%02" PRIx8 
"%02" PRIx8 
"%02" PRIx8 
"%02" PRIx8 
"-%02" PRIx8 
"%02" PRIx8
 
  104                  "-%02" PRIx8 
"%02" PRIx8 
"-%02" PRIx8 
"%02" PRIx8 
"-%02" PRIx8 
"%02" PRIx8
 
  105                  "%02" PRIx8 
"%02" PRIx8 
"%02" PRIx8 
"%02" PRIx8 
"",
 
  106                  instanceId[0], instanceId[1], instanceId[2], instanceId[3], instanceId[4],
 
  107                  instanceId[5], instanceId[6], instanceId[7], instanceId[8], instanceId[9],
 
  108                  instanceId[10], instanceId[11], instanceId[12], instanceId[13], instanceId[14],
 
  118  const UINT32 InterfaceId = ((STREAM_ID_NONE << 30) | CAPABILITIES_NEGOTIATOR);
 
  119  wStream* out = create_shared_message_header_with_functionid(InterfaceId, MessageId, Version, 4);
 
  122    return ERROR_OUTOFMEMORY;
 
  124  Stream_Write_UINT32(out, 0x00000000); 
 
  125  return stream_write_and_free(callback->plugin, callback->channel, out);
 
  136  WINPR_ASSERT(callback);
 
  138  WINPR_ASSERT(urbdrc);
 
  141    return ERROR_INVALID_PARAMETER;
 
  143  if (!Stream_CheckAndLogRequiredLengthWLog(urbdrc->log, s, 4))
 
  144    return ERROR_INVALID_DATA;
 
  146  UINT32 Version = Stream_Get_UINT32(s);
 
  148  if (Version > RIM_CAPABILITY_VERSION_01)
 
  150    WLog_Print(urbdrc->log, WLOG_WARN, 
"Unknown capability version %" PRIu32 
", expected %d",
 
  151               Version, RIM_CAPABILITY_VERSION_01);
 
  152    Version = RIM_CAPABILITY_VERSION_01;
 
  155  return urbdrc_send_capability_response(callback, MessageId, Version);
 
  160                                        UINT32 MajorVersion, UINT32 MinorVersion,
 
  163  WINPR_ASSERT(callback);
 
  165  const UINT32 InterfaceId = ((STREAM_ID_PROXY << 30) | CLIENT_CHANNEL_NOTIFICATION);
 
  167      create_shared_message_header_with_functionid(InterfaceId, MessageId, CHANNEL_CREATED, 12);
 
  170    return ERROR_OUTOFMEMORY;
 
  172  Stream_Write_UINT32(out, MajorVersion);
 
  173  Stream_Write_UINT32(out, MinorVersion);
 
  174  Stream_Write_UINT32(out, Capabilities); 
 
  175  return stream_write_and_free(callback->plugin, callback->channel, out);
 
  186  UINT32 MajorVersion = 0;
 
  187  UINT32 MinorVersion = 0;
 
  188  UINT32 Capabilities = 0;
 
  191  if (!callback || !s || !callback->plugin)
 
  192    return ERROR_INVALID_PARAMETER;
 
  196  if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
 
  197    return ERROR_INVALID_DATA;
 
  199  Stream_Read_UINT32(s, MajorVersion);
 
  200  Stream_Read_UINT32(s, MinorVersion);
 
  201  Stream_Read_UINT32(s, Capabilities);
 
  204  if ((MajorVersion != 1) || (MinorVersion != 0))
 
  206    WLog_Print(urbdrc->log, WLOG_WARN,
 
  207               "server supports USB channel version %" PRIu32 
".%" PRIu32, MajorVersion,
 
  209    WLog_Print(urbdrc->log, WLOG_WARN, 
"we only support channel version 1.0");
 
  213  if (Capabilities != 0)
 
  215    WLog_Print(urbdrc->log, WLOG_WARN,
 
  216               "[MS-RDPEUSB] 2.2.5.1 Channel Created Message (CHANNEL_CREATED) states " 
  217               "Capabilities must be 0, got %" PRIu32,
 
  222  return urbdrc_send_channel_created(callback, MessageId, MajorVersion, MinorVersion,
 
  226static UINT urdbrc_send_virtual_channel_add(IWTSPlugin* plugin, IWTSVirtualChannel* channel,
 
  229  const UINT32 InterfaceId = ((STREAM_ID_PROXY << 30) | CLIENT_DEVICE_SINK);
 
  230  wStream* out = create_shared_message_header_with_functionid(InterfaceId, MessageId,
 
  231                                                              ADD_VIRTUAL_CHANNEL, 0);
 
  234    return ERROR_OUTOFMEMORY;
 
  236  return stream_write_and_free(plugin, channel, out);
 
  239static BOOL write_string_block(
wStream* s, 
size_t count, 
const char** strings, 
const size_t* length,
 
  243  for (
size_t x = 0; x < count; x++)
 
  245    len += length[x] + 1ULL;
 
  251  if (!Stream_EnsureRemainingCapacity(s, len * 
sizeof(WCHAR) + 
sizeof(UINT32)))
 
  255  Stream_Write_UINT32(s, (UINT32)len); 
 
  258  for (
size_t x = 0; x < count; x++)
 
  260    size_t clength = length[x];
 
  261    const char* str = strings[x];
 
  263    const SSIZE_T w = Stream_Write_UTF16_String_From_UTF8(s, clength, str, clength, TRUE);
 
  264    if ((w < 0) || ((
size_t)w != clength))
 
  266    Stream_Write_UINT16(s, 0);
 
  270    Stream_Write_UINT16(s, 0);
 
  276                                   UINT32 bcdUSB, 
const char* strInstanceId, 
size_t InstanceIdLen,
 
  277                                   size_t nrHwIds, 
const char* HardwareIds[],
 
  278                                   const size_t HardwareIdsLen[], 
size_t nrCompatIds,
 
  279                                   const char* CompatibilityIds[],
 
  280                                   const size_t CompatibilityIdsLen[], 
const char* strContainerId,
 
  281                                   size_t ContainerIdLen)
 
  283  WINPR_ASSERT(callback);
 
  284  WINPR_ASSERT(HardwareIds);
 
  285  WINPR_ASSERT(HardwareIdsLen);
 
  286  WINPR_ASSERT(CompatibilityIds);
 
  287  WINPR_ASSERT(CompatibilityIdsLen);
 
  289  const UINT32 InterfaceId = ((STREAM_ID_PROXY << 30) | CLIENT_DEVICE_SINK);
 
  290  wStream* out = create_shared_message_header_with_functionid(InterfaceId, 0, ADD_DEVICE, 8);
 
  292    return ERROR_OUTOFMEMORY;
 
  294  Stream_Write_UINT32(out, 0x00000001); 
 
  295  Stream_Write_UINT32(out, UsbDevice);  
 
  297  if (!write_string_block(out, 1, &strInstanceId, &InstanceIdLen, FALSE))
 
  300  if (!write_string_block(out, nrHwIds, HardwareIds, HardwareIdsLen, TRUE))
 
  303  if (!write_string_block(out, nrCompatIds, CompatibilityIds, CompatibilityIdsLen, TRUE))
 
  306  if (!write_string_block(out, 1, &strContainerId, &ContainerIdLen, FALSE))
 
  310  if (!Stream_EnsureRemainingCapacity(out, 28))
 
  313  Stream_Write_UINT32(out, 0x0000001c);                                
 
  314  Stream_Write_UINT32(out, 2);  
 
  315  Stream_Write_UINT32(out, 0x600);  
 
  317  Stream_Write_UINT32(out, bcdUSB);
 
  318  Stream_Write_UINT32(out, 0x00000000); 
 
  321    Stream_Write_UINT32(out, 0x00000000); 
 
  323    Stream_Write_UINT32(out, 0x00000001); 
 
  325  Stream_Write_UINT32(out, 0x50); 
 
  326  return stream_write_and_free(callback->plugin, callback->channel, out);
 
  329  Stream_Free(out, TRUE);
 
  330  return ERROR_INTERNAL_ERROR;
 
  340  char HardwareIds[2][DEVICE_HARDWARE_ID_SIZE] = { { 0 } };
 
  341  const char* CHardwareIds[2] = { HardwareIds[0], HardwareIds[1] };
 
  342  char CompatibilityIds[4][DEVICE_COMPATIBILITY_ID_SIZE] = { { 0 } };
 
  343  const char* CCompatibilityIds[4] = { CompatibilityIds[0], CompatibilityIds[1],
 
  344                                     CompatibilityIds[2], CompatibilityIds[3] };
 
  345  char strContainerId[DEVICE_CONTAINER_STR_SIZE] = { 0 };
 
  346  char strInstanceId[DEVICE_INSTANCE_STR_SIZE] = { 0 };
 
  347  size_t CompatibilityIdLen[4] = { 0 };
 
  348  size_t HardwareIdsLen[2] = { 0 };
 
  349  const size_t nrHwIds = ARRAYSIZE(HardwareIds);
 
  350  size_t nrCompatIds = 3;
 
  353  pdev->detach_kernel_driver(pdev);
 
  355    const UINT16 idVendor = (UINT16)pdev->query_device_descriptor(pdev, ID_VENDOR);
 
  356    const UINT16 idProduct = (UINT16)pdev->query_device_descriptor(pdev, ID_PRODUCT);
 
  357    const UINT16 bcdDevice = (UINT16)pdev->query_device_descriptor(pdev, BCD_DEVICE);
 
  358    (void)sprintf_s(HardwareIds[1], DEVICE_HARDWARE_ID_SIZE,
 
  359                    "USB\\VID_%04" PRIX16 
"&PID_%04" PRIX16 
"", idVendor, idProduct);
 
  360    (void)sprintf_s(HardwareIds[0], DEVICE_HARDWARE_ID_SIZE,
 
  361                    "USB\\VID_%04" PRIX16 
"&PID_%04" PRIX16 
"&REV_%04" PRIX16 
"", idVendor,
 
  362                    idProduct, bcdDevice);
 
  365    const UINT8 bDeviceClass = (UINT8)pdev->query_device_descriptor(pdev, B_DEVICE_CLASS);
 
  366    const UINT8 bDeviceSubClass = (UINT8)pdev->query_device_descriptor(pdev, B_DEVICE_SUBCLASS);
 
  367    const UINT8 bDeviceProtocol = (UINT8)pdev->query_device_descriptor(pdev, B_DEVICE_PROTOCOL);
 
  369    if (!(pdev->isCompositeDevice(pdev)))
 
  371      (void)sprintf_s(CompatibilityIds[2], DEVICE_COMPATIBILITY_ID_SIZE,
 
  372                      "USB\\Class_%02" PRIX8 
"", bDeviceClass);
 
  373      (void)sprintf_s(CompatibilityIds[1], DEVICE_COMPATIBILITY_ID_SIZE,
 
  374                      "USB\\Class_%02" PRIX8 
"&SubClass_%02" PRIX8 
"", bDeviceClass,
 
  376      (void)sprintf_s(CompatibilityIds[0], DEVICE_COMPATIBILITY_ID_SIZE,
 
  377                      "USB\\Class_%02" PRIX8 
"&SubClass_%02" PRIX8 
"&Prot_%02" PRIX8 
"",
 
  378                      bDeviceClass, bDeviceSubClass, bDeviceProtocol);
 
  382      (void)sprintf_s(CompatibilityIds[3], DEVICE_COMPATIBILITY_ID_SIZE, 
"USB\\COMPOSITE");
 
  383      (void)sprintf_s(CompatibilityIds[2], DEVICE_COMPATIBILITY_ID_SIZE, 
"USB\\DevClass_00");
 
  384      (void)sprintf_s(CompatibilityIds[1], DEVICE_COMPATIBILITY_ID_SIZE,
 
  385                      "USB\\DevClass_00&SubClass_00");
 
  386      (void)sprintf_s(CompatibilityIds[0], DEVICE_COMPATIBILITY_ID_SIZE,
 
  387                      "USB\\DevClass_00&SubClass_00&Prot_00");
 
  391  func_instance_id_generate(pdev, strInstanceId, DEVICE_INSTANCE_STR_SIZE);
 
  392  func_container_id_generate(pdev, strContainerId);
 
  394  for (
size_t x = 0; x < nrHwIds; x++)
 
  396    HardwareIdsLen[x] = strnlen(HardwareIds[x], DEVICE_HARDWARE_ID_SIZE);
 
  399  for (
size_t x = 0; x < nrCompatIds; x++)
 
  401    CompatibilityIdLen[x] = strnlen(CompatibilityIds[x], DEVICE_COMPATIBILITY_ID_SIZE);
 
  404  const size_t InstanceIdLen = strnlen(strInstanceId, 
sizeof(strInstanceId));
 
  405  const size_t ContainerIdLen = strnlen(strContainerId, 
sizeof(strContainerId));
 
  407  const UINT32 UsbDevice = pdev->get_UsbDevice(pdev);
 
  408  const UINT32 bcdUSB =
 
  409      WINPR_ASSERTING_INT_CAST(uint32_t, pdev->query_device_descriptor(pdev, BCD_USB));
 
  410  return urbdrc_send_add_device(callback, UsbDevice, bcdUSB, strInstanceId, InstanceIdLen,
 
  411                                nrHwIds, CHardwareIds, HardwareIdsLen, nrCompatIds,
 
  412                                CCompatibilityIds, CompatibilityIdLen, strContainerId,
 
  423  UINT32 MessageId = 0;
 
  424  UINT32 FunctionId = 0;
 
  425  UINT32 InterfaceId = 0;
 
  426  UINT error = CHANNEL_RC_OK;
 
  429    return ERROR_INVALID_PARAMETER;
 
  431  if (!Stream_CheckAndLogRequiredLength(TAG, data, 8))
 
  432    return ERROR_INVALID_DATA;
 
  434  Stream_Rewind_UINT32(data);
 
  435  Stream_Read_UINT32(data, InterfaceId);
 
  436  Stream_Read_UINT32(data, MessageId);
 
  437  Stream_Read_UINT32(data, FunctionId);
 
  441    case RIM_EXCHANGE_CAPABILITY_REQUEST:
 
  442      if (InterfaceId != 0)
 
  446            "[MS-RDPEUSB] 2.2.3.1 Interface Manipulation Exchange Capabilities Request " 
  447            "(RIM_EXCHANGE_CAPABILITY_REQUEST))::InterfaceId expected 0, got %" PRIu32,
 
  449        return ERROR_INVALID_DATA;
 
  451      error = urbdrc_process_capability_request(callback, data, MessageId);
 
  454    case RIMCALL_RELEASE:
 
  458      error = ERROR_NOT_FOUND;
 
  465static BOOL urbdrc_announce_devices(IUDEVMAN* udevman)
 
  467  UINT error = ERROR_SUCCESS;
 
  469  udevman->loading_lock(udevman);
 
  470  udevman->rewind(udevman);
 
  472  while (udevman->has_next(udevman))
 
  474    IUDEVICE* pdev = udevman->get_next(udevman);
 
  476    if (!pdev->isAlreadySend(pdev))
 
  478      const UINT32 deviceId = pdev->get_UsbDevice(pdev);
 
  480          urdbrc_send_virtual_channel_add(udevman->plugin, get_channel(udevman), deviceId);
 
  482      if (cerror != ERROR_SUCCESS)
 
  487  udevman->loading_unlock(udevman);
 
  489  return error == ERROR_SUCCESS;
 
  496  IUDEVMAN* udevman = urbdrc->udevman;
 
  497  IWTSVirtualChannel* channel = callback->channel;
 
  498  IUDEVICE* pdev = NULL;
 
  500  UINT error = ERROR_INTERNAL_ERROR;
 
  501  UINT32 channelId = callback->channel_mgr->GetChannelId(channel);
 
  503  switch (urbdrc->vchannel_status)
 
  505    case INIT_CHANNEL_IN:
 
  507      error = ERROR_SUCCESS;
 
  508      udevman->initialize(udevman, channelId);
 
  510      if (!urbdrc_announce_devices(udevman))
 
  513      urbdrc->vchannel_status = INIT_CHANNEL_OUT;
 
  516    case INIT_CHANNEL_OUT:
 
  519      udevman->loading_lock(udevman);
 
  520      udevman->rewind(udevman);
 
  522      while (udevman->has_next(udevman))
 
  524        pdev = udevman->get_next(udevman);
 
  526        if (!pdev->isAlreadySend(pdev))
 
  528          const UINT32 channelID = callback->channel_mgr->GetChannelId(channel);
 
  530          pdev->setAlreadySend(pdev);
 
  531          pdev->set_channelManager(pdev, callback->channel_mgr);
 
  532          pdev->set_channelID(pdev, channelID);
 
  537      udevman->loading_unlock(udevman);
 
  538      error = ERROR_SUCCESS;
 
  540      if (found && pdev->isAlreadySend(pdev))
 
  541        error = urdbrc_send_usb_device_add(callback, pdev);
 
  546      WLog_Print(urbdrc->log, WLOG_ERROR, 
"vchannel_status unknown value %" PRIu32 
"",
 
  547                 urbdrc->vchannel_status);
 
  562  UINT32 MessageId = 0;
 
  563  UINT32 FunctionId = 0;
 
  564  UINT32 InterfaceId = 0;
 
  565  UINT error = CHANNEL_RC_OK;
 
  568  if (!callback || !data)
 
  569    return ERROR_INVALID_PARAMETER;
 
  574    return ERROR_INVALID_PARAMETER;
 
  576  if (!Stream_CheckAndLogRequiredLength(TAG, data, 8))
 
  577    return ERROR_INVALID_DATA;
 
  579  Stream_Rewind(data, 4);
 
  580  Stream_Read_UINT32(data, InterfaceId);
 
  581  Stream_Read_UINT32(data, MessageId);
 
  582  Stream_Read_UINT32(data, FunctionId);
 
  583  WLog_Print(urbdrc->log, WLOG_TRACE, 
"%s [%" PRIu32 
"]",
 
  584             call_to_string(FALSE, InterfaceId, FunctionId), FunctionId);
 
  588    case CHANNEL_CREATED:
 
  589      error = urbdrc_process_channel_create(callback, data, MessageId);
 
  592    case RIMCALL_RELEASE:
 
  593      error = urbdrc_device_control_channel(callback, data);
 
  597      WLog_Print(urbdrc->log, WLOG_TRACE, 
"unknown FunctionId 0x%" PRIX32 
"", FunctionId);
 
  610static UINT urbdrc_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, 
wStream* data)
 
  614  IUDEVMAN* udevman = NULL;
 
  615  UINT32 InterfaceId = 0;
 
  616  UINT error = ERROR_INTERNAL_ERROR;
 
  618  if (callback == NULL)
 
  619    return ERROR_INVALID_PARAMETER;
 
  621  if (callback->plugin == NULL)
 
  626  if (urbdrc->udevman == NULL)
 
  629  udevman = urbdrc->udevman;
 
  631  if (!Stream_CheckAndLogRequiredLength(TAG, data, 12))
 
  632    return ERROR_INVALID_DATA;
 
  634  urbdrc_dump_message(urbdrc->log, FALSE, FALSE, data);
 
  635  Stream_Read_UINT32(data, InterfaceId);
 
  640    case CAPABILITIES_NEGOTIATOR | (STREAM_ID_NONE << 30):
 
  641      error = urbdrc_exchange_capabilities(callback, data);
 
  644    case SERVER_CHANNEL_NOTIFICATION | (STREAM_ID_PROXY << 30):
 
  645      error = urbdrc_process_channel_notification(callback, data);
 
  649      error = urbdrc_process_udev_data_transfer(callback, urbdrc, udevman, data);
 
  650      WLog_DBG(TAG, 
"urbdrc_process_udev_data_transfer returned 0x%08" PRIx32, error);
 
  651      error = ERROR_SUCCESS; 
 
  663static UINT urbdrc_on_close(IWTSVirtualChannelCallback* pChannelCallback)
 
  671      IUDEVMAN* udevman = urbdrc->udevman;
 
  672      if (udevman && callback->channel_mgr)
 
  674        UINT32 control = callback->channel_mgr->GetChannelId(callback->channel);
 
  675        if (udevman->controlChannelId == control)
 
  676          udevman->status |= URBDRC_DEVICE_CHANNEL_CLOSED;
 
  679          IUDEVICE* pdev = udevman->get_udevice_by_ChannelID(udevman, control);
 
  681            pdev->markChannelClosed(pdev);
 
  687  return CHANNEL_RC_OK;
 
  695static UINT urbdrc_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
 
  696                                             IWTSVirtualChannel* pChannel,
 
  697                                             WINPR_ATTR_UNUSED BYTE* pData,
 
  698                                             WINPR_ATTR_UNUSED BOOL* pbAccept,
 
  699                                             IWTSVirtualChannelCallback** ppCallback)
 
  705    return ERROR_INVALID_PARAMETER;
 
  710    return ERROR_OUTOFMEMORY;
 
  712  callback->iface.OnDataReceived = urbdrc_on_data_received;
 
  713  callback->iface.OnClose = urbdrc_on_close;
 
  714  callback->plugin = listener_callback->plugin;
 
  715  callback->channel_mgr = listener_callback->channel_mgr;
 
  716  callback->channel = pChannel;
 
  717  *ppCallback = (IWTSVirtualChannelCallback*)callback;
 
  718  return CHANNEL_RC_OK;
 
  726static UINT urbdrc_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
 
  730  IUDEVMAN* udevman = NULL;
 
  731  char channelName[
sizeof(URBDRC_CHANNEL_NAME)] = { URBDRC_CHANNEL_NAME };
 
  733  if (!urbdrc || !urbdrc->udevman)
 
  734    return ERROR_INVALID_PARAMETER;
 
  736  if (urbdrc->initialized)
 
  738    WLog_ERR(TAG, 
"[%s] channel initialized twice, aborting", URBDRC_CHANNEL_NAME);
 
  739    return ERROR_INVALID_DATA;
 
  741  udevman = urbdrc->udevman;
 
  742  urbdrc->listener_callback =
 
  745  if (!urbdrc->listener_callback)
 
  746    return CHANNEL_RC_NO_MEMORY;
 
  748  urbdrc->listener_callback->iface.OnNewChannelConnection = urbdrc_on_new_channel_connection;
 
  749  urbdrc->listener_callback->plugin = pPlugin;
 
  750  urbdrc->listener_callback->channel_mgr = pChannelMgr;
 
  753  CharUpperA(channelName);
 
  754  status = pChannelMgr->CreateListener(pChannelMgr, channelName, 0,
 
  755                                       &urbdrc->listener_callback->iface, &urbdrc->listener);
 
  756  if (status != CHANNEL_RC_OK)
 
  759  status = CHANNEL_RC_OK;
 
  760  if (udevman->listener_created_callback)
 
  761    status = udevman->listener_created_callback(udevman);
 
  763  urbdrc->initialized = status == CHANNEL_RC_OK;
 
  772static UINT urbdrc_plugin_terminated(IWTSPlugin* pPlugin)
 
  775  IUDEVMAN* udevman = NULL;
 
  778    return ERROR_INVALID_DATA;
 
  779  if (urbdrc->listener_callback)
 
  781    IWTSVirtualChannelManager* mgr = urbdrc->listener_callback->channel_mgr;
 
  783      IFCALL(mgr->DestroyListener, mgr, urbdrc->listener);
 
  785  udevman = urbdrc->udevman;
 
  789    udevman->free(udevman);
 
  793  free(urbdrc->subsystem);
 
  794  free(urbdrc->listener_callback);
 
  796  return CHANNEL_RC_OK;
 
  799static BOOL urbdrc_register_udevman_addin(IWTSPlugin* pPlugin, IUDEVMAN* udevman)
 
  805    WLog_Print(urbdrc->log, WLOG_ERROR, 
"existing device, abort.");
 
  809  DEBUG_DVC(
"device registered.");
 
  810  urbdrc->udevman = udevman;
 
  819static UINT urbdrc_load_udevman_addin(IWTSPlugin* pPlugin, LPCSTR name, 
const ADDIN_ARGV* args)
 
  824  PVIRTUALCHANNELENTRY pvce =
 
  825      freerdp_load_channel_addin_entry(URBDRC_CHANNEL_NAME, name, NULL, 0);
 
  826  PFREERDP_URBDRC_DEVICE_ENTRY entry = WINPR_FUNC_PTR_CAST(pvce, PFREERDP_URBDRC_DEVICE_ENTRY);
 
  829    return ERROR_INVALID_OPERATION;
 
  831  entryPoints.plugin = pPlugin;
 
  832  entryPoints.pRegisterUDEVMAN = urbdrc_register_udevman_addin;
 
  833  entryPoints.args = args;
 
  835  const UINT error = entry(&entryPoints);
 
  838    WLog_Print(urbdrc->log, WLOG_ERROR, 
"%s entry returns error.", name);
 
  842  return CHANNEL_RC_OK;
 
  845static BOOL urbdrc_set_subsystem(
URBDRC_PLUGIN* urbdrc, 
const char* subsystem)
 
  847  free(urbdrc->subsystem);
 
  848  urbdrc->subsystem = _strdup(subsystem);
 
  849  return (urbdrc->subsystem != NULL);
 
  861    { 
"dbg", COMMAND_LINE_VALUE_FLAG, 
"", NULL, BoolValueFalse, -1, NULL, 
"debug" },
 
  862    { 
"sys", COMMAND_LINE_VALUE_REQUIRED, 
"<subsystem>", NULL, NULL, -1, NULL, 
"subsystem" },
 
  863    { 
"dev", COMMAND_LINE_VALUE_REQUIRED, 
"<device list>", NULL, NULL, -1, NULL, 
"devices" },
 
  864    { 
"encode", COMMAND_LINE_VALUE_FLAG, 
"", NULL, NULL, -1, NULL, 
"encode" },
 
  865    { 
"quality", COMMAND_LINE_VALUE_REQUIRED, 
"<[0-2] -> [high-medium-low]>", NULL, NULL, -1,
 
  867    { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
 
  871      COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
 
  874      CommandLineParseArgumentsA(args->argc, args->argv, urbdrc_args, flags, urbdrc, NULL, NULL);
 
  877    return ERROR_INVALID_DATA;
 
  883    if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
 
  886    CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, 
"dbg")
 
  888      WLog_SetLogLevel(urbdrc->log, WLOG_TRACE);
 
  890    CommandLineSwitchCase(arg, 
"sys")
 
  892      if (!urbdrc_set_subsystem(urbdrc, arg->Value))
 
  893        return ERROR_OUTOFMEMORY;
 
  895    CommandLineSwitchDefault(arg)
 
  898    CommandLineSwitchEnd(arg)
 
  899  } 
while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
 
  901  return CHANNEL_RC_OK;
 
  904BOOL add_device(IUDEVMAN* idevman, UINT32 flags, BYTE busnum, BYTE devnum, UINT16 idVendor,
 
  914  if (!urbdrc || !urbdrc->listener_callback)
 
  917  UINT32 mask = (DEVICE_ADD_FLAG_VENDOR | DEVICE_ADD_FLAG_PRODUCT);
 
  918  if ((flags & mask) == mask)
 
  919    regflags |= UDEVMAN_FLAG_ADD_BY_VID_PID;
 
  920  mask = (DEVICE_ADD_FLAG_BUS | DEVICE_ADD_FLAG_DEV);
 
  921  if ((flags & mask) == mask)
 
  922    regflags |= UDEVMAN_FLAG_ADD_BY_ADDR;
 
  924  const size_t success =
 
  925      idevman->register_udevice(idevman, busnum, devnum, idVendor, idProduct, regflags);
 
  927  if ((success > 0) && (flags & DEVICE_ADD_FLAG_REGISTER))
 
  929    if (!urbdrc_announce_devices(idevman))
 
  936BOOL del_device(IUDEVMAN* idevman, UINT32 flags, BYTE busnum, BYTE devnum, UINT16 idVendor,
 
  939  IUDEVICE* pdev = NULL;
 
  947  if (!urbdrc || !urbdrc->listener_callback)
 
  950  idevman->loading_lock(idevman);
 
  951  idevman->rewind(idevman);
 
  953  while (idevman->has_next(idevman))
 
  956    IUDEVICE* dev = idevman->get_next(idevman);
 
  958    if ((flags & (DEVICE_ADD_FLAG_BUS | DEVICE_ADD_FLAG_DEV | DEVICE_ADD_FLAG_VENDOR |
 
  959                  DEVICE_ADD_FLAG_PRODUCT)) == 0)
 
  961    if (flags & DEVICE_ADD_FLAG_BUS)
 
  963      if (dev->get_bus_number(dev) != busnum)
 
  966    if (flags & DEVICE_ADD_FLAG_DEV)
 
  968      if (dev->get_dev_number(dev) != devnum)
 
  971    if (flags & DEVICE_ADD_FLAG_VENDOR)
 
  973      int vid = dev->query_device_descriptor(dev, ID_VENDOR);
 
  977    if (flags & DEVICE_ADD_FLAG_PRODUCT)
 
  979      int pid = dev->query_device_descriptor(dev, ID_PRODUCT);
 
  980      if (pid != idProduct)
 
  992    pdev->setChannelClosed(pdev);
 
  994  idevman->loading_unlock(idevman);
 
 1003FREERDP_ENTRY_POINT(UINT VCAPITYPE urbdrc_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints))
 
 1008  urbdrc = (
URBDRC_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, URBDRC_CHANNEL_NAME);
 
 1009  args = pEntryPoints->GetPluginData(pEntryPoints);
 
 1016      return CHANNEL_RC_NO_MEMORY;
 
 1018    urbdrc->iface.Initialize = urbdrc_plugin_initialize;
 
 1019    urbdrc->iface.Terminated = urbdrc_plugin_terminated;
 
 1020    urbdrc->vchannel_status = INIT_CHANNEL_IN;
 
 1021    status = pEntryPoints->RegisterPlugin(pEntryPoints, URBDRC_CHANNEL_NAME, &urbdrc->iface);
 
 1024    if (status != CHANNEL_RC_OK)
 
 1030    urbdrc->log = WLog_Get(TAG);
 
 1036  status = urbdrc_process_addin_args(urbdrc, args);
 
 1038  if (status != CHANNEL_RC_OK)
 
 1041  if (!urbdrc->subsystem && !urbdrc_set_subsystem(urbdrc, 
"libusb"))
 
 1044  return urbdrc_load_udevman_addin(&urbdrc->iface, urbdrc->subsystem, args);
 
 1049UINT stream_write_and_free(IWTSPlugin* plugin, IWTSVirtualChannel* channel, 
wStream* out)
 
 1054    return ERROR_INVALID_PARAMETER;
 
 1056  if (!channel || !out || !urbdrc)
 
 1058    Stream_Free(out, TRUE);
 
 1059    return ERROR_INVALID_PARAMETER;
 
 1062  if (!channel->Write)
 
 1064    Stream_Free(out, TRUE);
 
 1065    return ERROR_INTERNAL_ERROR;
 
 1068  urbdrc_dump_message(urbdrc->log, TRUE, TRUE, out);
 
 1069  const size_t len = Stream_GetPosition(out);
 
 1070  UINT rc = ERROR_INTERNAL_ERROR;
 
 1071  if (len <= UINT32_MAX)
 
 1072    rc = channel->Write(channel, (UINT32)len, Stream_Buffer(out), NULL);
 
 1073  Stream_Free(out, TRUE);