Rewrite of urbdrc channel.

* Fix command line parsing
* Properly handle channel creation/destruction
* Use wStream API for parsing
This commit is contained in:
Armin Novak
2019-11-22 10:42:05 +01:00
parent 15ad496bba
commit 0927d7aa50
23 changed files with 3954 additions and 4613 deletions

View File

@@ -17,38 +17,12 @@
define_channel("urbdrc")
if(NOT WIN32)
find_package(DevD)
find_package(UDev)
find_package(UUID)
find_package(DbusGlib)
find_package(libusb-1.0)
endif()
if(DEVD_FOUND OR UDEV_FOUND)
include_directories(${UDEV_INCLUDE_DIR})
if(UUID_FOUND AND DBUS_GLIB_FOUND AND LIBUSB_1_FOUND)
include_directories(${UUID_INCLUDE_DIRS})
include_directories(${LIBUSB_1_INCLUDE_DIRS})
include_directories(${DBUS_GLIB_INCLUDE_DIRS})
set(URBDRC_DEPENDENCIES_FOUND TRUE)
message(STATUS "Found all URBDRC dependencies")
else()
if(NOT UUID_FOUND)
message(STATUS "URBDRC dependencie not found: UUID")
endif()
if(NOT DBUS_GLIB_FOUND)
message(STATUS "URBDRC dependencie not found: DBUS_GLIB")
endif()
if(NOT LIBUSB_1_FOUND)
message(STATUS "URBDRC dependencie not found: LIBUSB_1")
endif()
endif()
endif()
include_directories(common)
add_subdirectory(common)
if(WITH_CLIENT_CHANNELS)
if(URBDRC_DEPENDENCIES_FOUND)
add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME})
endif()
find_package(libusb-1.0 REQUIRED)
include_directories(${LIBUSB_1_INCLUDE_DIRS})
add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME})
endif()

View File

@@ -21,22 +21,15 @@ define_channel_client("urbdrc")
set(${MODULE_PREFIX}_SRCS
searchman.c
searchman.h
isoch_queue.c
isoch_queue.h
data_transfer.c
data_transfer.h
urbdrc_main.c
urbdrc_main.h
urbdrc_types.h)
include_directories(..)
$<TARGET_OBJECTS:urbdrc-common>
)
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry")
#set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} libusb-devman)
set(${MODULE_PREFIX}_LIBS)
if (UDEV_FOUND AND UDEV_LIBRARIES)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${UDEV_LIBRARIES})

File diff suppressed because it is too large Load Diff

View File

@@ -21,6 +21,8 @@
#ifndef FREERDP_CHANNEL_URBDRC_CLIENT_DATA_TRANSFER_H
#define FREERDP_CHANNEL_URBDRC_CLIENT_DATA_TRANSFER_H
#include <winpr/pool.h>
#include "urbdrc_main.h"
#define DEVICE_CTX(dev) ((dev)->ctx)
@@ -28,6 +30,7 @@
#define TRANSFER_CTX(transfer) (HANDLE_CTX((transfer)->dev_handle))
#define ITRANSFER_CTX(transfer) (TRANSFER_CTX(__USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer)))
void* urbdrc_process_udev_data_transfer(void* arg);
UINT urbdrc_process_udev_data_transfer(URBDRC_CHANNEL_CALLBACK* callback, URBDRC_PLUGIN* urbdrc,
IUDEVMAN* udevman, wStream* data);
#endif /* FREERDP_CHANNEL_URBDRC_CLIENT_DATA_TRANSFER_H */

View File

@@ -1,184 +0,0 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RemoteFX USB Redirection
*
* Copyright 2012 Atrust corp.
* Copyright 2012 Alfred Liu <alfred.liu@atruscorp.com>
*
* 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "isoch_queue.h"
static void isoch_queue_rewind(ISOCH_CALLBACK_QUEUE* queue)
{
queue->curr = queue->head;
}
static BOOL isoch_queue_has_next(ISOCH_CALLBACK_QUEUE* queue)
{
return (queue->curr != NULL);
}
static ISOCH_CALLBACK_DATA* isoch_queue_get_next(ISOCH_CALLBACK_QUEUE* queue)
{
ISOCH_CALLBACK_DATA* isoch;
isoch = queue->curr;
queue->curr = (ISOCH_CALLBACK_DATA*)queue->curr->next;
return isoch;
}
static ISOCH_CALLBACK_DATA* isoch_queue_register_data(ISOCH_CALLBACK_QUEUE* queue, void* callback,
void* dev)
{
ISOCH_CALLBACK_DATA* isoch;
isoch = (ISOCH_CALLBACK_DATA*)calloc(1, sizeof(ISOCH_CALLBACK_DATA));
if (!isoch)
return NULL;
isoch->device = dev;
isoch->callback = callback;
pthread_mutex_lock(&queue->isoch_loading);
if (queue->head == NULL)
{
/* linked queue is empty */
queue->head = isoch;
queue->tail = isoch;
}
else
{
/* append data to the end of the linked queue */
queue->tail->next = (void*)isoch;
isoch->prev = (void*)queue->tail;
queue->tail = isoch;
}
queue->isoch_num += 1;
pthread_mutex_unlock(&queue->isoch_loading);
return isoch;
}
static int isoch_queue_unregister_data(ISOCH_CALLBACK_QUEUE* queue, ISOCH_CALLBACK_DATA* isoch)
{
ISOCH_CALLBACK_DATA* p;
queue->rewind(queue);
while (queue->has_next(queue))
{
p = queue->get_next(queue);
if (p != isoch)
continue;
/* data exists */
/* set previous data to point to next data */
if (isoch->prev != NULL)
{
/* unregistered data is not the head */
p = (ISOCH_CALLBACK_DATA*)isoch->prev;
p->next = isoch->next;
}
else
{
/* unregistered data is the head, update head */
queue->head = (ISOCH_CALLBACK_DATA*)isoch->next;
}
/* set next data to point to previous data */
if (isoch->next != NULL)
{
/* unregistered data is not the tail */
p = (ISOCH_CALLBACK_DATA*)isoch->next;
p->prev = isoch->prev;
}
else
{
/* unregistered data is the tail, update tail */
queue->tail = (ISOCH_CALLBACK_DATA*)isoch->prev;
}
queue->isoch_num--;
if (isoch)
{
/* free data info */
isoch->out_data = NULL;
zfree(isoch);
}
return 1; /* unregistration successful */
}
/* if we reach this point, the isoch wasn't found */
return 0;
}
void isoch_queue_free(ISOCH_CALLBACK_QUEUE* queue)
{
ISOCH_CALLBACK_DATA* isoch;
pthread_mutex_lock(&queue->isoch_loading);
/** unregister all isochronous data*/
queue->rewind(queue);
while (queue->has_next(queue))
{
isoch = queue->get_next(queue);
if (isoch != NULL)
queue->unregister_data(queue, isoch);
}
pthread_mutex_unlock(&queue->isoch_loading);
pthread_mutex_destroy(&queue->isoch_loading);
/* free queue */
if (queue)
zfree(queue);
}
ISOCH_CALLBACK_QUEUE* isoch_queue_new()
{
ISOCH_CALLBACK_QUEUE* queue;
queue = (ISOCH_CALLBACK_QUEUE*)calloc(1, sizeof(ISOCH_CALLBACK_QUEUE));
if (!queue)
return NULL;
pthread_mutex_init(&queue->isoch_loading, NULL);
/* load service */
queue->get_next = isoch_queue_get_next;
queue->has_next = isoch_queue_has_next;
queue->rewind = isoch_queue_rewind;
queue->register_data = isoch_queue_register_data;
queue->unregister_data = isoch_queue_unregister_data;
queue->free = isoch_queue_free;
return queue;
}

View File

@@ -1,60 +0,0 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RemoteFX USB Redirection
*
* Copyright 2012 Atrust corp.
* Copyright 2012 Alfred Liu <alfred.liu@atruscorp.com>
*
* 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.
*/
#ifndef FREERDP_CHANNEL_URBDRC_CLIENT_ISOCH_QUEUE_H
#define FREERDP_CHANNEL_URBDRC_CLIENT_ISOCH_QUEUE_H
#include "urbdrc_types.h"
typedef struct _ISOCH_CALLBACK_DATA ISOCH_CALLBACK_DATA;
typedef struct _ISOCH_CALLBACK_QUEUE ISOCH_CALLBACK_QUEUE;
struct _ISOCH_CALLBACK_DATA
{
void* inode;
void* prev;
void* next;
void* device;
BYTE* out_data;
UINT32 out_size;
void* callback;
};
struct _ISOCH_CALLBACK_QUEUE
{
int isoch_num;
ISOCH_CALLBACK_DATA* curr; /* current point */
ISOCH_CALLBACK_DATA* head; /* head point in linked list */
ISOCH_CALLBACK_DATA* tail; /* tail point in linked list */
pthread_mutex_t isoch_loading;
/* Isochronous queue service */
void (*rewind)(ISOCH_CALLBACK_QUEUE* queue);
BOOL (*has_next)(ISOCH_CALLBACK_QUEUE* queue);
int (*unregister_data)(ISOCH_CALLBACK_QUEUE* queue, ISOCH_CALLBACK_DATA* isoch);
ISOCH_CALLBACK_DATA* (*get_next)(ISOCH_CALLBACK_QUEUE* queue);
ISOCH_CALLBACK_DATA* (*register_data)(ISOCH_CALLBACK_QUEUE* queue, void* callback, void* dev);
void (*free)(ISOCH_CALLBACK_QUEUE* queue);
};
ISOCH_CALLBACK_QUEUE* isoch_queue_new(void);
#endif /* FREERDP_CHANNEL_URBDRC_CLIENT_ISOCH_QUEUE_H */

View File

@@ -21,9 +21,7 @@ define_channel_client_subsystem("urbdrc" "libusb" "")
set(${MODULE_PREFIX}_SRCS
libusb_udevman.c
libusb_udevice.c
libusb_udevice.h
request_queue.c
request_queue.h)
libusb_udevice.h)
include_directories(..)
@@ -38,7 +36,7 @@ set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS}
${LIBUSB_1_LIBRARIES})
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr urbdrc-client)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})

File diff suppressed because it is too large Load Diff

View File

@@ -21,14 +21,10 @@
#ifndef FREERDP_CHANNEL_URBDRC_CLIENT_LIBUSB_UDEVICE_H
#define FREERDP_CHANNEL_URBDRC_CLIENT_LIBUSB_UDEVICE_H
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
#include <libusb.h>
#else
#include <libusb-1.0/libusb.h>
#endif
#include <semaphore.h>
#include "urbdrc_types.h"
#include "request_queue.h"
#include "urbdrc_main.h"
typedef struct libusb_device LIBUSB_DEVICE;
@@ -51,10 +47,11 @@ struct _UDEVICE
UINT32 UsbDevice; /* An unique interface ID */
UINT32 ReqCompletion; /* An unique interface ID */
UINT32 channel_id;
IWTSVirtualChannelManager* channelManager;
UINT32 channelID;
UINT16 status;
UINT16 bus_number;
UINT16 dev_number;
BYTE bus_number;
BYTE dev_number;
char path[17];
int port_number;
int isCompositeDevice;
@@ -66,18 +63,14 @@ struct _UDEVICE
MSUSB_CONFIG_DESCRIPTOR* MsConfig;
LIBUSB_CONFIG_DESCRIPTOR* LibusbConfig;
REQUEST_QUEUE* request_queue;
/* Used in isochronous transfer */
void* isoch_queue;
wHashTable* request_queue;
pthread_mutex_t mutex_isoch;
sem_t sem_id;
URBDRC_PLUGIN* urbdrc;
};
typedef UDEVICE* PUDEVICE;
int udev_new_by_id(UINT16 idVendor, UINT16 idProduct, IUDEVICE*** devArray);
IUDEVICE* udev_new_by_addr(int bus_number, int dev_number);
extern int libusb_debug;
size_t udev_new_by_id(URBDRC_PLUGIN* urbdrc, UINT16 idVendor, UINT16 idProduct,
IUDEVICE*** devArray);
IUDEVICE* udev_new_by_addr(URBDRC_PLUGIN* urbdrc, BYTE bus_number, BYTE dev_number);
#endif /* FREERDP_CHANNEL_URBDRC_CLIENT_LIBUSB_UDEVICE_H */

View File

@@ -21,7 +21,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <libusb.h>
#include <winpr/crt.h>
#include <winpr/cmdline.h>
@@ -32,8 +34,6 @@
#include "libusb_udevice.h"
int libusb_debug;
#define BASIC_STATE_FUNC_DEFINED(_arg, _type) \
static _type udevman_get_##_arg(IUDEVMAN* idevman) \
{ \
@@ -62,28 +62,33 @@ struct _UDEVMAN
UINT32 defUsbDevice;
UINT16 flags;
int device_num;
UINT32 device_num;
int sem_timeout;
pthread_mutex_t devman_loading;
sem_t sem_urb_lock;
HANDLE devman_loading;
libusb_context* context;
libusb_hotplug_callback_handle handle;
HANDLE thread;
BOOL running;
};
typedef UDEVMAN* PUDEVMAN;
static BOOL poll_libusb_events(UDEVMAN* udevman);
static void udevman_rewind(IUDEVMAN* idevman)
{
UDEVMAN* udevman = (UDEVMAN*)idevman;
udevman->idev = udevman->head;
}
static int udevman_has_next(IUDEVMAN* idevman)
static BOOL udevman_has_next(IUDEVMAN* idevman)
{
UDEVMAN* udevman = (UDEVMAN*)idevman;
if (udevman->idev == NULL)
return 0;
if (!udevman || !udevman->idev)
return FALSE;
else
return 1;
return TRUE;
}
static IUDEVICE* udevman_get_next(IUDEVMAN* idevman)
@@ -95,36 +100,46 @@ static IUDEVICE* udevman_get_next(IUDEVMAN* idevman)
return pdev;
}
static IUDEVICE* udevman_get_udevice_by_addr(IUDEVMAN* idevman, int bus_number, int dev_number)
static IUDEVICE* udevman_get_udevice_by_addr(IUDEVMAN* idevman, BYTE bus_number, BYTE dev_number)
{
IUDEVICE* pdev;
IUDEVICE* dev = NULL;
if (!idevman)
return NULL;
idevman->loading_lock(idevman);
idevman->rewind(idevman);
while (idevman->has_next(idevman))
{
pdev = idevman->get_next(idevman);
IUDEVICE* pdev = idevman->get_next(idevman);
if ((pdev->get_bus_number(pdev) == bus_number) &&
(pdev->get_dev_number(pdev) == dev_number))
{
idevman->loading_unlock(idevman);
return pdev;
dev = pdev;
break;
}
}
idevman->loading_unlock(idevman);
WLog_WARN(TAG, "bus:%d dev:%d not exist in udevman", bus_number, dev_number);
return NULL;
return dev;
}
static int udevman_register_udevice(IUDEVMAN* idevman, int bus_number, int dev_number,
int UsbDevice, UINT16 idVendor, UINT16 idProduct, int flag)
static size_t udevman_register_udevice(IUDEVMAN* idevman, BYTE bus_number, BYTE dev_number,
UINT32 UsbDevice, UINT16 idVendor, UINT16 idProduct,
int flag)
{
UDEVMAN* udevman = (UDEVMAN*)idevman;
IUDEVICE* pdev = NULL;
IUDEVICE** devArray;
int i, num, addnum = 0;
URBDRC_PLUGIN* urbdrc;
size_t i, num, addnum = 0;
if (!idevman || !idevman->plugin)
return 0;
urbdrc = (URBDRC_PLUGIN*)idevman->plugin;
pdev = (IUDEVICE*)udevman_get_udevice_by_addr(idevman, bus_number, dev_number);
if (pdev != NULL)
@@ -132,26 +147,26 @@ static int udevman_register_udevice(IUDEVMAN* idevman, int bus_number, int dev_n
if (flag == UDEVMAN_FLAG_ADD_BY_ADDR)
{
pdev = udev_new_by_addr(bus_number, dev_number);
IUDEVICE* tdev = udev_new_by_addr(urbdrc, bus_number, dev_number);
if (pdev == NULL)
if (tdev == NULL)
return 0;
pdev->set_UsbDevice(pdev, UsbDevice);
tdev->set_UsbDevice(tdev, UsbDevice);
idevman->loading_lock(idevman);
if (udevman->head == NULL)
{
/* linked list is empty */
udevman->head = pdev;
udevman->tail = pdev;
udevman->head = tdev;
udevman->tail = tdev;
}
else
{
/* append device to the end of the linked list */
udevman->tail->set_p_next(udevman->tail, pdev);
pdev->set_p_prev(pdev, udevman->tail);
udevman->tail = pdev;
udevman->tail->set_p_next(udevman->tail, tdev);
tdev->set_p_prev(tdev, udevman->tail);
udevman->tail = tdev;
}
udevman->device_num += 1;
@@ -161,34 +176,35 @@ static int udevman_register_udevice(IUDEVMAN* idevman, int bus_number, int dev_n
{
addnum = 0;
/* register all device that match pid vid */
num = udev_new_by_id(idVendor, idProduct, &devArray);
num = udev_new_by_id(urbdrc, idVendor, idProduct, &devArray);
for (i = 0; i < num; i++)
{
pdev = devArray[i];
IUDEVICE* tdev = devArray[i];
if (udevman_get_udevice_by_addr(idevman, pdev->get_bus_number(pdev),
pdev->get_dev_number(pdev)) != NULL)
if (udevman_get_udevice_by_addr(idevman, tdev->get_bus_number(tdev),
tdev->get_dev_number(tdev)) != NULL)
{
zfree(pdev);
tdev->free(tdev);
devArray[i] = NULL;
continue;
}
pdev->set_UsbDevice(pdev, UsbDevice);
tdev->set_UsbDevice(tdev, UsbDevice);
idevman->loading_lock(idevman);
if (udevman->head == NULL)
{
/* linked list is empty */
udevman->head = pdev;
udevman->tail = pdev;
udevman->head = tdev;
udevman->tail = tdev;
}
else
{
/* append device to the end of the linked list */
udevman->tail->set_p_next(udevman->tail, pdev);
pdev->set_p_prev(pdev, udevman->tail);
udevman->tail = pdev;
udevman->tail->set_p_next(udevman->tail, tdev);
tdev->set_p_prev(tdev, udevman->tail);
udevman->tail = tdev;
}
udevman->device_num += 1;
@@ -196,28 +212,32 @@ static int udevman_register_udevice(IUDEVMAN* idevman, int bus_number, int dev_n
addnum++;
}
zfree(devArray);
free(devArray);
return addnum;
}
else
{
WLog_ERR(TAG, "udevman_register_udevice: function error!!");
WLog_Print(urbdrc->log, WLOG_ERROR, "udevman_register_udevice: Invalid flag=%08 " PRIx32,
flag);
return 0;
}
return 1;
}
static int udevman_unregister_udevice(IUDEVMAN* idevman, int bus_number, int dev_number)
static BOOL udevman_unregister_udevice(IUDEVMAN* idevman, BYTE bus_number, BYTE dev_number)
{
UDEVMAN* udevman = (UDEVMAN*)idevman;
UDEVICE *pdev, *dev;
int ret = 0, err = 0;
dev = (UDEVICE*)udevman_get_udevice_by_addr(idevman, bus_number, dev_number);
UDEVICE* pdev;
UDEVICE* dev = (UDEVICE*)udevman_get_udevice_by_addr(idevman, bus_number, dev_number);
if (!dev || !idevman)
return FALSE;
idevman->loading_lock(idevman);
idevman->rewind(idevman);
while (idevman->has_next(idevman) != 0)
while (idevman->has_next(idevman))
{
pdev = (UDEVICE*)idevman->get_next(idevman);
@@ -259,63 +279,158 @@ static int udevman_unregister_udevice(IUDEVMAN* idevman, int bus_number, int dev
if (dev)
{
/* reset device */
if (err != LIBUSB_ERROR_NO_DEVICE)
{
ret = libusb_reset_device(dev->libusb_handle);
if (ret < 0)
{
WLog_ERR(TAG, "libusb_reset_device: ERROR!!ret:%d", ret);
}
}
/* release all interface and attach kernel driver */
dev->iface.attach_kernel_driver((IUDEVICE*)dev);
if (dev->request_queue)
zfree(dev->request_queue);
/* free the config descriptor that send from windows */
msusb_msconfig_free(dev->MsConfig);
libusb_close(dev->libusb_handle);
libusb_close(dev->hub_handle);
sem_destroy(&dev->sem_id);
/* free device info */
if (dev->devDescriptor)
zfree(dev->devDescriptor);
if (dev)
zfree(dev);
return 1; /* unregistration successful */
dev->iface.free(&dev->iface);
return TRUE; /* unregistration successful */
}
/* if we reach this point, the device wasn't found */
return 0;
return FALSE;
}
static void udevman_parse_device_addr(char* str, int* id1, int* id2, char sign)
static BOOL udevman_cancel_all_device_requests(IUDEVMAN* idevman)
{
char s1[8];
char* s2;
ZeroMemory(s1, sizeof(s1));
s2 = (strchr(str, sign)) + 1;
strncpy(s1, str, strlen(str) - (strlen(s2) + 1));
*id1 = strtol(s1, NULL, 0);
*id2 = strtol(s2, NULL, 0);
UDEVMAN* udevman = (UDEVMAN*)idevman;
if (!idevman)
return FALSE;
idevman->loading_lock(idevman);
idevman->rewind(idevman);
while (idevman->has_next(idevman))
{
UDEVICE* dev = (UDEVICE*)idevman->get_next(idevman);
if (!dev)
continue;
dev->iface.cancel_all_transfer_request(&dev->iface);
}
idevman->loading_unlock(idevman);
return TRUE;
}
static void udevman_parse_device_pid_vid(char* str, int* id1, int* id2, char sign)
static BOOL udevman_unregister_all_udevices(IUDEVMAN* idevman)
{
char s1[8];
UDEVMAN* udevman = (UDEVMAN*)idevman;
if (!idevman)
return FALSE;
idevman->loading_lock(idevman);
idevman->rewind(idevman);
while (idevman->has_next(idevman))
{
UDEVICE* dev = (UDEVICE*)idevman->get_next(idevman);
if (!dev)
continue;
/* set previous device to point to next device */
if (dev->prev != NULL)
{
/* unregistered device is not the head */
UDEVICE* pdev = dev->prev;
pdev->next = dev->next;
}
else
{
/* unregistered device is the head, update head */
udevman->head = (IUDEVICE*)dev->next;
}
/* set next device to point to previous device */
if (dev->next != NULL)
{
/* unregistered device is not the tail */
UDEVICE* pdev = (UDEVICE*)dev->next;
pdev->prev = dev->prev;
}
else
{
/* unregistered device is the tail, update tail */
udevman->tail = (IUDEVICE*)dev->prev;
}
dev->iface.free(&dev->iface);
udevman->device_num--;
}
idevman->loading_unlock(idevman);
return TRUE;
}
static BOOL udevman_parse_device_addr(const char* str, size_t maxLen, UINT16* id1, UINT16* id2,
char sign)
{
unsigned long rc;
char s1[8] = { 0 };
char* s2;
ZeroMemory(s1, sizeof(s1));
size_t len = strnlen(str, maxLen);
size_t cpLen;
s2 = (strchr(str, sign)) + 1;
strncpy(s1, str, strlen(str) - (strlen(s2) + 1));
*id1 = strtol(s1, NULL, 16);
*id2 = strtol(s2, NULL, 16);
if (!s2)
return FALSE;
cpLen = len - (strnlen(s2, len) + 1);
if (cpLen >= sizeof(s1))
cpLen = sizeof(s1) - 1;
strncpy(s1, str, cpLen);
rc = strtoul(s1, NULL, 16);
if ((rc > UINT16_MAX) || (errno != 0))
return FALSE;
*id1 = rc;
rc = strtoul(s2, NULL, 16);
if ((rc > UINT16_MAX) || (errno != 0))
return FALSE;
*id2 = rc;
return TRUE;
}
static BOOL udevman_parse_device_pid_vid(const char* str, size_t maxLen, UINT16* id1, UINT16* id2,
char sign)
{
unsigned long rc;
char s1[8] = { 0 };
char* s2;
size_t len = strnlen(str, maxLen);
size_t cpLen;
s2 = (strchr(str, sign)) + 1;
if (!s2)
return FALSE;
cpLen = len - (strnlen(s2, len) + 1);
if (cpLen >= sizeof(s1))
cpLen = sizeof(s1) - 1;
strncpy(s1, str, cpLen);
errno = 0;
rc = strtoul(s1, NULL, 16);
if ((rc > UINT16_MAX) || (errno != 0))
return FALSE;
*id1 = rc;
rc = strtoul(s2, NULL, 16);
if ((rc > UINT16_MAX) || (errno != 0))
return FALSE;
*id2 = rc;
return TRUE;
}
static int udevman_check_device_exist_by_id(IUDEVMAN* idevman, UINT16 idVendor, UINT16 idProduct)
@@ -332,30 +447,17 @@ static int udevman_is_auto_add(IUDEVMAN* idevman)
return (udevman->flags & UDEVMAN_FLAG_ADD_BY_AUTO) ? 1 : 0;
}
static IUDEVICE* udevman_get_udevice_by_UsbDevice_try_again(IUDEVMAN* idevman, UINT32 UsbDevice)
{
UDEVICE* pdev;
idevman->loading_lock(idevman);
idevman->rewind(idevman);
while (idevman->has_next(idevman))
{
pdev = (UDEVICE*)idevman->get_next(idevman);
if (pdev->UsbDevice == UsbDevice)
{
idevman->loading_unlock(idevman);
return (IUDEVICE*)pdev;
}
}
idevman->loading_unlock(idevman);
return NULL;
}
static IUDEVICE* udevman_get_udevice_by_UsbDevice(IUDEVMAN* idevman, UINT32 UsbDevice)
{
UDEVICE* pdev;
URBDRC_PLUGIN* urbdrc;
if (!idevman || !idevman->plugin)
return NULL;
/* Mask highest 2 bits, must be ignored */
UsbDevice = UsbDevice & INTERFACE_ID_MASK;
urbdrc = (URBDRC_PLUGIN*)idevman->plugin;
idevman->loading_lock(idevman);
idevman->rewind(idevman);
@@ -371,57 +473,90 @@ static IUDEVICE* udevman_get_udevice_by_UsbDevice(IUDEVMAN* idevman, UINT32 UsbD
}
idevman->loading_unlock(idevman);
/* try again */
pdev = (UDEVICE*)idevman->get_udevice_by_UsbDevice_try_again(idevman, UsbDevice);
if (pdev)
{
return (IUDEVICE*)pdev;
}
WLog_ERR(TAG, "0x%" PRIx32 " ERROR!!", UsbDevice);
WLog_Print(urbdrc->log, WLOG_WARN, "Failed to find a USB device mapped to deviceId=%08" PRIx32,
UsbDevice);
return NULL;
}
static void udevman_loading_lock(IUDEVMAN* idevman)
{
UDEVMAN* udevman = (UDEVMAN*)idevman;
pthread_mutex_lock(&udevman->devman_loading);
WaitForSingleObject(udevman->devman_loading, INFINITE);
}
static void udevman_loading_unlock(IUDEVMAN* idevman)
{
UDEVMAN* udevman = (UDEVMAN*)idevman;
pthread_mutex_unlock(&udevman->devman_loading);
}
static void udevman_wait_urb(IUDEVMAN* idevman)
{
UDEVMAN* udevman = (UDEVMAN*)idevman;
sem_wait(&udevman->sem_urb_lock);
}
static void udevman_push_urb(IUDEVMAN* idevman)
{
UDEVMAN* udevman = (UDEVMAN*)idevman;
sem_post(&udevman->sem_urb_lock);
ReleaseMutex(udevman->devman_loading);
}
BASIC_STATE_FUNC_DEFINED(defUsbDevice, UINT32)
BASIC_STATE_FUNC_DEFINED(device_num, int)
BASIC_STATE_FUNC_DEFINED(device_num, UINT32)
BASIC_STATE_FUNC_DEFINED(sem_timeout, int)
static void udevman_free(IUDEVMAN* idevman)
{
UDEVMAN* udevman = (UDEVMAN*)idevman;
pthread_mutex_destroy(&udevman->devman_loading);
sem_destroy(&udevman->sem_urb_lock);
libusb_exit(NULL);
/* free udevman */
if (!udevman)
return;
if (udevman)
zfree(udevman);
libusb_hotplug_deregister_callback(udevman->context, udevman->handle);
udevman->running = FALSE;
WaitForSingleObject(udevman->thread, INFINITE);
/* Process remaining usb events */
while (poll_libusb_events(udevman))
;
udevman_unregister_all_udevices(idevman);
CloseHandle(udevman->devman_loading);
CloseHandle(udevman->thread);
libusb_exit(udevman->context);
free(udevman);
}
static int hotplug_callback(struct libusb_context* ctx, struct libusb_device* dev,
libusb_hotplug_event event, void* user_data)
{
int rc;
struct libusb_device_descriptor desc;
IUDEVMAN* idevman = (IUDEVMAN*)user_data;
const uint8_t bus = libusb_get_bus_number(dev);
const uint8_t addr = libusb_get_device_address(dev);
rc = libusb_get_device_descriptor(dev, &desc);
if (rc != LIBUSB_SUCCESS)
return rc;
switch (event)
{
case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED:
add_device(idevman, bus, addr, desc.iManufacturer, desc.iProduct);
break;
case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT:
del_device(idevman, bus, addr, desc.iManufacturer, desc.iProduct);
break;
default:
break;
}
return 0;
}
static BOOL udevman_initialize(IUDEVMAN* idevman, UINT32 channelId)
{
UDEVMAN* udevman = (UDEVMAN*)idevman;
if (!udevman)
return FALSE;
idevman->controlChannelId = channelId;
return TRUE;
}
static void udevman_load_interface(UDEVMAN* udevman)
@@ -435,7 +570,6 @@ static void udevman_load_interface(UDEVMAN* udevman)
udevman->iface.register_udevice = udevman_register_udevice;
udevman->iface.unregister_udevice = udevman_unregister_udevice;
udevman->iface.get_udevice_by_UsbDevice = udevman_get_udevice_by_UsbDevice;
udevman->iface.get_udevice_by_UsbDevice_try_again = udevman_get_udevice_by_UsbDevice_try_again;
/* Extension */
udevman->iface.check_device_exist_by_id = udevman_check_device_exist_by_id;
udevman->iface.isAutoAdd = udevman_is_auto_add;
@@ -446,47 +580,51 @@ static void udevman_load_interface(UDEVMAN* udevman)
/* control semaphore or mutex lock */
udevman->iface.loading_lock = udevman_loading_lock;
udevman->iface.loading_unlock = udevman_loading_unlock;
udevman->iface.push_urb = udevman_push_urb;
udevman->iface.wait_urb = udevman_wait_urb;
udevman->iface.initialize = udevman_initialize;
}
static void urbdrc_udevman_register_devices(UDEVMAN* udevman, char* devices)
static BOOL urbdrc_udevman_register_devices(UDEVMAN* udevman, const char* devices)
{
BOOL rc = FALSE;
char* token;
int idVendor;
int idProduct;
int bus_number;
int dev_number;
int success = 0;
char* tmp;
char hardware_id[16];
char* default_devices = "id";
const char* default_devices = "id";
UINT32 UsbDevice = BASE_USBDEVICE_NUM;
if (!devices)
devices = default_devices;
tmp = _strdup(default_devices);
else
tmp = _strdup(devices);
/* register all usb devices */
token = strtok(devices, "#");
token = strtok(tmp, "#");
while (token)
{
bus_number = 0;
dev_number = 0;
idVendor = 0;
idProduct = 0;
sprintf_s(hardware_id, ARRAYSIZE(hardware_id), "%s", token);
strcpy(hardware_id, token);
token = strtok(NULL, "#");
if (udevman->flags & UDEVMAN_FLAG_ADD_BY_VID_PID)
{
udevman_parse_device_pid_vid(hardware_id, &idVendor, &idProduct, ':');
success = udevman->iface.register_udevice((IUDEVMAN*)udevman, 0, 0, UsbDevice,
(UINT16)idVendor, (UINT16)idProduct,
UDEVMAN_FLAG_ADD_BY_VID_PID);
UINT16 idVendor, idProduct;
if (!udevman_parse_device_pid_vid(hardware_id, sizeof(hardware_id), &idVendor,
&idProduct, ':'))
goto fail;
success = udevman->iface.register_udevice((IUDEVMAN*)udevman, 0, 0, UsbDevice, idVendor,
idProduct, UDEVMAN_FLAG_ADD_BY_VID_PID);
}
else if (udevman->flags & UDEVMAN_FLAG_ADD_BY_ADDR)
{
udevman_parse_device_addr(hardware_id, &bus_number, &dev_number, ':');
UINT16 bus_number, dev_number;
if (!udevman_parse_device_addr(hardware_id, sizeof(hardware_id), &bus_number,
&dev_number, ':'))
goto fail;
success = udevman->iface.register_udevice((IUDEVMAN*)udevman, bus_number, dev_number,
UsbDevice, 0, 0, UDEVMAN_FLAG_ADD_BY_ADDR);
}
@@ -496,12 +634,18 @@ static void urbdrc_udevman_register_devices(UDEVMAN* udevman, char* devices)
}
udevman->defUsbDevice = UsbDevice;
rc = TRUE;
fail:
free(tmp);
return rc;
}
static void urbdrc_udevman_parse_addin_args(UDEVMAN* udevman, ADDIN_ARGV* args)
static UINT urbdrc_udevman_parse_addin_args(UDEVMAN* udevman, ADDIN_ARGV* args)
{
int status;
DWORD flags;
LPSTR devices = NULL;
const UINT16 mask = UDEVMAN_FLAG_ADD_BY_VID_PID | UDEVMAN_FLAG_ADD_BY_ADDR;
COMMAND_LINE_ARGUMENT_A* arg;
COMMAND_LINE_ARGUMENT_A urbdrc_udevman_args[] = {
{ "dbg", COMMAND_LINE_VALUE_FLAG, "", NULL, BoolValueFalse, -1, NULL, "debug" },
@@ -512,9 +656,14 @@ static void urbdrc_udevman_parse_addin_args(UDEVMAN* udevman, ADDIN_ARGV* args)
{ "auto", COMMAND_LINE_VALUE_FLAG, "", NULL, BoolValueFalse, -1, NULL, "FLAG_ADD_BY_AUTO" },
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
};
flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON;
status = CommandLineParseArgumentsA(args->argc, args->argv, urbdrc_udevman_args, flags, udevman,
NULL, NULL);
if (status != CHANNEL_RC_OK)
return status;
arg = urbdrc_udevman_args;
do
@@ -528,7 +677,7 @@ static void urbdrc_udevman_parse_addin_args(UDEVMAN* udevman, ADDIN_ARGV* args)
}
CommandLineSwitchCase(arg, "dev")
{
urbdrc_udevman_register_devices(udevman, arg->Value);
devices = arg->Value;
}
CommandLineSwitchCase(arg, "id")
{
@@ -547,6 +696,60 @@ static void urbdrc_udevman_parse_addin_args(UDEVMAN* udevman, ADDIN_ARGV* args)
}
CommandLineSwitchEnd(arg)
} while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
/* Can not add devices by address and VID/PID */
if ((udevman->flags & mask) == mask)
return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
/* Add listed devices after we know the format of addressing */
if (devices)
{
if (!urbdrc_udevman_register_devices(udevman, devices))
return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
}
return CHANNEL_RC_OK;
}
static BOOL poll_libusb_events(UDEVMAN* udevman)
{
int rc = LIBUSB_SUCCESS;
struct timeval tv = { 0, 500 };
if (libusb_try_lock_events(udevman->context))
{
if (libusb_event_handling_ok(udevman->context))
{
rc = libusb_handle_events_locked(udevman->context, &tv);
if (rc != LIBUSB_SUCCESS)
WLog_WARN(TAG, "libusb_handle_events_locked %d", rc);
}
libusb_unlock_events(udevman->context);
}
else
{
libusb_lock_event_waiters(udevman->context);
if (libusb_event_handler_active(udevman->context))
{
rc = libusb_wait_for_event(udevman->context, &tv);
if (rc < LIBUSB_SUCCESS)
WLog_WARN(TAG, "libusb_wait_for_event %d", rc);
}
libusb_unlock_event_waiters(udevman->context);
}
return rc > 0;
}
static DWORD poll_thread(LPVOID lpThreadParameter)
{
UDEVMAN* udevman = (UDEVMAN*)lpThreadParameter;
while (udevman->running)
{
poll_libusb_events(udevman);
}
return 0;
}
#ifdef BUILTIN_CHANNELS
@@ -554,31 +757,56 @@ static void urbdrc_udevman_parse_addin_args(UDEVMAN* udevman, ADDIN_ARGV* args)
#else
#define freerdp_urbdrc_client_subsystem_entry FREERDP_API freerdp_urbdrc_client_subsystem_entry
#endif
int freerdp_urbdrc_client_subsystem_entry(PFREERDP_URBDRC_SERVICE_ENTRY_POINTS pEntryPoints)
{
int rc;
UINT status;
UDEVMAN* udevman;
ADDIN_ARGV* args = pEntryPoints->args;
libusb_init(NULL);
udevman = (PUDEVMAN)malloc(sizeof(UDEVMAN));
udevman = (PUDEVMAN)calloc(1, sizeof(UDEVMAN));
if (!udevman)
return -1;
goto fail;
udevman->iface.plugin = pEntryPoints->plugin;
rc = libusb_init(&udevman->context);
if (rc != LIBUSB_SUCCESS)
goto fail;
udevman->device_num = 0;
udevman->idev = NULL;
udevman->head = NULL;
udevman->tail = NULL;
udevman->sem_timeout = 0;
udevman->flags = UDEVMAN_FLAG_ADD_BY_VID_PID;
pthread_mutex_init(&udevman->devman_loading, NULL);
sem_init(&udevman->sem_urb_lock, 0, MAX_URB_REQUSET_NUM);
udevman->devman_loading = CreateMutexA(NULL, FALSE, "devman_loading");
if (!udevman->devman_loading)
goto fail;
/* load usb device service management */
udevman_load_interface(udevman);
/* set debug flag, to enable Debug message for usb data transfer */
libusb_debug = 10;
urbdrc_udevman_parse_addin_args(udevman, args);
pEntryPoints->pRegisterUDEVMAN(pEntryPoints->plugin, (IUDEVMAN*)udevman);
status = urbdrc_udevman_parse_addin_args(udevman, args);
if (status != CHANNEL_RC_OK)
goto fail;
udevman->running = TRUE;
udevman->thread = CreateThread(NULL, 0, poll_thread, udevman, 0, NULL);
if (!udevman->thread)
goto fail;
rc = libusb_hotplug_register_callback(
udevman->context, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,
LIBUSB_HOTPLUG_NO_FLAGS, LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY,
LIBUSB_HOTPLUG_MATCH_ANY, hotplug_callback, udevman, &udevman->handle);
if (rc != LIBUSB_SUCCESS)
goto fail;
if (!pEntryPoints->pRegisterUDEVMAN(pEntryPoints->plugin, (IUDEVMAN*)udevman))
goto fail;
WLog_DBG(TAG, "UDEVMAN device registered.");
return 0;
fail:
udevman_free(&udevman->iface);
return -1;
}

View File

@@ -1,179 +0,0 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RemoteFX USB Redirection
*
* Copyright 2012 Atrust corp.
* Copyright 2012 Alfred Liu <alfred.liu@atruscorp.com>
*
* 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "request_queue.h"
TRANSFER_REQUEST* request_queue_get_next(REQUEST_QUEUE* queue)
{
TRANSFER_REQUEST* request;
request = queue->ireq;
queue->ireq = (TRANSFER_REQUEST*)queue->ireq->next;
return request;
}
int request_queue_has_next(REQUEST_QUEUE* queue)
{
if (queue->ireq == NULL)
return 0;
else
return 1;
}
TRANSFER_REQUEST* request_queue_register_request(REQUEST_QUEUE* queue, UINT32 RequestId,
struct libusb_transfer* transfer, BYTE endpoint)
{
TRANSFER_REQUEST* request;
request = (TRANSFER_REQUEST*)malloc(sizeof(TRANSFER_REQUEST));
request->prev = NULL;
request->next = NULL;
request->RequestId = RequestId;
request->transfer = transfer;
request->endpoint = endpoint;
request->submit = 0;
pthread_mutex_lock(&queue->request_loading);
if (queue->head == NULL)
{
/* linked queue is empty */
queue->head = request;
queue->tail = request;
}
else
{
/* append data to the end of the linked queue */
queue->tail->next = (void*)request;
request->prev = (void*)queue->tail;
queue->tail = request;
}
queue->request_num += 1;
pthread_mutex_unlock(&queue->request_loading);
return request;
}
void request_queue_rewind(REQUEST_QUEUE* queue)
{
queue->ireq = queue->head;
}
/* Get first*/
TRANSFER_REQUEST* request_queue_get_request_by_endpoint(REQUEST_QUEUE* queue, BYTE ep)
{
TRANSFER_REQUEST* request;
pthread_mutex_lock(&queue->request_loading);
queue->rewind(queue);
while (queue->has_next(queue))
{
request = queue->get_next(queue);
if (request->endpoint == ep)
{
pthread_mutex_unlock(&queue->request_loading);
return request;
}
}
pthread_mutex_unlock(&queue->request_loading);
WLog_ERR(TAG, "request_queue_get_request_by_id: ERROR!!");
return NULL;
}
int request_queue_unregister_request(REQUEST_QUEUE* queue, UINT32 RequestId)
{
TRANSFER_REQUEST *request, *request_temp;
pthread_mutex_lock(&queue->request_loading);
queue->rewind(queue);
while (queue->has_next(queue) != 0)
{
request = queue->get_next(queue);
if (request->RequestId == RequestId)
{
if (request->prev != NULL)
{
request_temp = (TRANSFER_REQUEST*)request->prev;
request_temp->next = (TRANSFER_REQUEST*)request->next;
}
else
{
queue->head = (TRANSFER_REQUEST*)request->next;
}
if (request->next != NULL)
{
request_temp = (TRANSFER_REQUEST*)request->next;
request_temp->prev = (TRANSFER_REQUEST*)request->prev;
}
else
{
queue->tail = (TRANSFER_REQUEST*)request->prev;
}
queue->request_num--;
if (request)
{
request->transfer = NULL;
zfree(request);
}
pthread_mutex_unlock(&queue->request_loading);
return 0;
}
}
pthread_mutex_unlock(&queue->request_loading);
/* it wasn't found */
return 1;
}
REQUEST_QUEUE* request_queue_new()
{
REQUEST_QUEUE* queue;
queue = (REQUEST_QUEUE*)malloc(sizeof(REQUEST_QUEUE));
queue->request_num = 0;
queue->ireq = NULL;
queue->head = NULL;
queue->tail = NULL;
pthread_mutex_init(&queue->request_loading, NULL);
/* load service */
queue->get_next = request_queue_get_next;
queue->has_next = request_queue_has_next;
queue->rewind = request_queue_rewind;
queue->register_request = request_queue_register_request;
queue->unregister_request = request_queue_unregister_request;
queue->get_request_by_ep = request_queue_get_request_by_endpoint;
return queue;
}

View File

@@ -1,62 +0,0 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RemoteFX USB Redirection
*
* Copyright 2012 Atrust corp.
* Copyright 2012 Alfred Liu <alfred.liu@atruscorp.com>
*
* 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.
*/
#ifndef FREERDP_CHANNEL_URBDRC_CLIENT_LIBUSB_REQUEST_QUEUE_H
#define FREERDP_CHANNEL_URBDRC_CLIENT_LIBUSB_REQUEST_QUEUE_H
#include "urbdrc_types.h"
typedef struct _TRANSFER_REQUEST TRANSFER_REQUEST;
typedef struct _REQUEST_QUEUE REQUEST_QUEUE;
struct _TRANSFER_REQUEST
{
void* request;
void* prev;
void* next;
UINT32 RequestId;
BYTE endpoint;
struct libusb_transfer* transfer;
int submit;
};
struct _REQUEST_QUEUE
{
int request_num;
TRANSFER_REQUEST* ireq; /* iterator request */
TRANSFER_REQUEST* head; /* head request in linked queue */
TRANSFER_REQUEST* tail; /* tail request in linked queue */
pthread_mutex_t request_loading;
/* request queue manager service */
void (*rewind)(REQUEST_QUEUE* queue);
int (*has_next)(REQUEST_QUEUE* queue);
int (*unregister_request)(REQUEST_QUEUE* queue, UINT32 RequestId);
TRANSFER_REQUEST* (*get_next)(REQUEST_QUEUE* queue);
TRANSFER_REQUEST* (*get_request_by_ep)(REQUEST_QUEUE* queue, BYTE ep);
TRANSFER_REQUEST* (*register_request)(REQUEST_QUEUE* queue, UINT32 RequestId,
struct libusb_transfer* transfer, BYTE endpoint);
};
REQUEST_QUEUE* request_queue_new(void);
#endif /* FREERDP_CHANNEL_URBDRC_CLIENT_LIBUSB_REQUEST_QUEUE_H */

View File

@@ -21,12 +21,12 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <winpr/crt.h>
#include <winpr/synch.h>
#include "searchman.h"
#include "urbdrc_main.h"
static void searchman_rewind(USB_SEARCHMAN* searchman)
{
@@ -44,18 +44,16 @@ static int searchman_has_next(USB_SEARCHMAN* searchman)
static USB_SEARCHDEV* searchman_get_next(USB_SEARCHMAN* searchman)
{
USB_SEARCHDEV* search;
search = searchman->idev;
searchman->idev = (USB_SEARCHDEV*)searchman->idev->next;
return search;
}
static BOOL searchman_list_add(USB_SEARCHMAN* searchman, UINT16 idVendor, UINT16 idProduct)
{
USB_SEARCHDEV* search;
search = (USB_SEARCHDEV*)calloc(1, sizeof(USB_SEARCHDEV));
if (!search)
return FALSE;
@@ -75,8 +73,8 @@ static BOOL searchman_list_add(USB_SEARCHMAN* searchman, UINT16 idVendor, UINT16
search->prev = (void*)searchman->tail;
searchman->tail = search;
}
searchman->usb_numbers += 1;
searchman->usb_numbers += 1;
return TRUE;
}
@@ -84,7 +82,6 @@ static int searchman_list_remove(USB_SEARCHMAN* searchman, UINT16 idVendor, UINT
{
USB_SEARCHDEV* search;
USB_SEARCHDEV* point;
searchman_rewind(searchman);
while (searchman_has_next(searchman) != 0)
@@ -94,8 +91,8 @@ static int searchman_list_remove(USB_SEARCHMAN* searchman, UINT16 idVendor, UINT
if (point->idVendor == idVendor && point->idProduct == idProduct)
{
/* set previous device to point to next device */
search = point;
if (search->prev != NULL)
{
/* unregistered device is not the head */
@@ -121,10 +118,9 @@ static int searchman_list_remove(USB_SEARCHMAN* searchman, UINT16 idVendor, UINT
/* unregistered device is the tail, update tail */
searchman->tail = (USB_SEARCHDEV*)search->prev;
}
searchman->usb_numbers--;
free(search);
return 1; /* unregistration successful */
}
}
@@ -133,42 +129,29 @@ static int searchman_list_remove(USB_SEARCHMAN* searchman, UINT16 idVendor, UINT
return 0;
}
static BOOL searchman_start(USB_SEARCHMAN* self, void* (*func)(void*))
{
pthread_t thread;
/* create search thread */
if (pthread_create(&thread, 0, func, self) != 0)
return FALSE;
if (pthread_detach(thread) != 0)
return FALSE;
self->started = 1;
return TRUE;
}
/* close thread */
static void searchman_close(USB_SEARCHMAN* self)
{
SetEvent(self->term_event);
}
static void searchman_list_show(USB_SEARCHMAN* self)
{
int num = 0;
USB_SEARCHDEV* usb;
WLog_DBG(TAG, "=========== Usb Search List =========");
URBDRC_PLUGIN* urbdrc;
if (!self || !self->urbdrc)
return;
urbdrc = self->urbdrc;
WLog_Print(urbdrc->log, WLOG_DEBUG, "=========== Usb Search List =========");
self->rewind(self);
while (self->has_next(self))
{
usb = self->get_next(self);
WLog_DBG(TAG, " USB %d: ", num++);
WLog_DBG(TAG, " idVendor: 0x%04" PRIX16 "", usb->idVendor);
WLog_DBG(TAG, " idProduct: 0x%04" PRIX16 "", usb->idProduct);
WLog_Print(urbdrc->log, WLOG_DEBUG, " USB %d: ", num++);
WLog_Print(urbdrc->log, WLOG_DEBUG, " idVendor: 0x%04" PRIX16 "", usb->idVendor);
WLog_Print(urbdrc->log, WLOG_DEBUG, " idProduct: 0x%04" PRIX16 "", usb->idProduct);
}
WLog_DBG(TAG, "================= END ===============");
WLog_Print(urbdrc->log, WLOG_DEBUG, "================= END ===============");
}
void searchman_free(USB_SEARCHMAN* self)
@@ -182,30 +165,19 @@ void searchman_free(USB_SEARCHMAN* self)
}
/* free searchman */
sem_destroy(&self->sem_term);
CloseHandle(self->term_event);
free(self);
}
USB_SEARCHMAN* searchman_new(void* urbdrc, UINT32 UsbDevice)
{
int ret;
USB_SEARCHMAN* searchman;
searchman = (USB_SEARCHMAN*)calloc(1, sizeof(USB_SEARCHMAN));
if (!searchman)
return NULL;
searchman->urbdrc = urbdrc;
searchman->UsbDevice = UsbDevice;
ret = pthread_mutex_init(&searchman->mutex, NULL);
if (ret != 0)
{
WLog_ERR(TAG, "searchman mutex initialization: searchman->mutex failed");
goto out_error_mutex;
}
/* load service */
searchman->add = searchman_list_add;
searchman->remove = searchman_list_remove;
@@ -213,25 +185,6 @@ USB_SEARCHMAN* searchman_new(void* urbdrc, UINT32 UsbDevice)
searchman->get_next = searchman_get_next;
searchman->has_next = searchman_has_next;
searchman->show = searchman_list_show;
searchman->start = searchman_start;
searchman->close = searchman_close;
searchman->free = searchman_free;
searchman->started = 0;
searchman->term_event = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!searchman->term_event)
goto out_error_event;
if (sem_init(&searchman->sem_term, 0, 0) < 0)
goto out_error_sem;
return searchman;
out_error_sem:
CloseHandle(searchman->term_event);
out_error_event:
pthread_mutex_destroy(&searchman->mutex);
out_error_mutex:
free(searchman);
return NULL;
}

View File

@@ -44,11 +44,6 @@ struct _USB_SEARCHMAN
USB_SEARCHDEV* head; /* head device in linked list */
USB_SEARCHDEV* tail; /* tail device in linked list */
pthread_mutex_t mutex;
HANDLE term_event;
sem_t sem_term;
int started;
/* for urbdrc channel call back */
void* urbdrc;
@@ -56,10 +51,6 @@ struct _USB_SEARCHMAN
void (*rewind)(USB_SEARCHMAN* seachman);
/* show all device in the list */
void (*show)(USB_SEARCHMAN* self);
/* start searchman */
BOOL (*start)(USB_SEARCHMAN* self, void* (*func)(void*));
/* close searchman */
void (*close)(USB_SEARCHMAN* self);
/* add a new usb device for search */
BOOL (*add)(USB_SEARCHMAN* seachman, UINT16 idVendor, UINT16 idProduct);
/* remove a usb device from list */

File diff suppressed because it is too large Load Diff

View File

@@ -21,14 +21,26 @@
#ifndef FREERDP_CHANNEL_URBDRC_CLIENT_MAIN_H
#define FREERDP_CHANNEL_URBDRC_CLIENT_MAIN_H
#include <winpr/pool.h>
#include <freerdp/channels/log.h>
#include "searchman.h"
#include "isoch_queue.h"
#define DEVICE_HARDWARE_ID_SIZE 32
#define DEVICE_COMPATIBILITY_ID_SIZE 36
#define DEVICE_INSTANCE_STR_SIZE 37
#define DEVICE_CONTAINER_STR_SIZE 39
#define TAG CHANNELS_TAG("urbdrc.client")
#ifdef WITH_DEBUG_DVC
#define DEBUG_DVC(...) WLog_DBG(TAG, __VA_ARGS__)
#else
#define DEBUG_DVC(...) \
do \
{ \
} while (0)
#endif
typedef struct _IUDEVICE IUDEVICE;
typedef struct _IUDEVMAN IUDEVMAN;
@@ -71,13 +83,14 @@ struct _URBDRC_PLUGIN
IUDEVMAN* udevman;
USB_SEARCHMAN* searchman;
UINT32 first_channel_id;
UINT32 vchannel_status;
char* subsystem;
UINT32 status;
wLog* log;
};
typedef void (*PREGISTERURBDRCSERVICE)(IWTSPlugin* plugin, IUDEVMAN* udevman);
typedef BOOL (*PREGISTERURBDRCSERVICE)(IWTSPlugin* plugin, IUDEVMAN* udevman);
struct _FREERDP_URBDRC_SERVICE_ENTRY_POINTS
{
IWTSPlugin* plugin;
@@ -96,27 +109,34 @@ struct _TRANSFER_DATA
URBDRC_CHANNEL_CALLBACK* callback;
URBDRC_PLUGIN* urbdrc;
IUDEVMAN* udevman;
BYTE* pBuffer;
UINT32 cbSize;
UINT32 UsbDevice;
IWTSVirtualChannel* channel;
wStream* s;
};
typedef void (*t_isoch_transfer_cb)(IUDEVICE* idev, URBDRC_CHANNEL_CALLBACK* callback, wStream* out,
UINT32 InterfaceId, BOOL noAck, UINT32 MessageId,
UINT32 RequestId, UINT32 NumberOfPackets, UINT32 status,
UINT32 StartFrame, UINT32 ErrorCount, UINT32 OutputBufferSize);
struct _IUDEVICE
{
/* Transfer */
int (*isoch_transfer)(IUDEVICE* idev, UINT32 RequestId, UINT32 EndpointAddress,
UINT32 TransferFlags, int NoAck, UINT32* ErrorCount, UINT32* UrbdStatus,
UINT32* StartFrame, UINT32 NumberOfPackets, BYTE* IsoPacket,
UINT32* BufferSize, BYTE* Buffer, int Timeout);
int (*isoch_transfer)(IUDEVICE* idev, URBDRC_CHANNEL_CALLBACK* callback, UINT32 MessageId,
UINT32 RequestId, UINT32 EndpointAddress, UINT32 TransferFlags,
UINT32 StartFrame, UINT32 ErrorCount, BOOL NoAck,
const BYTE* packetDescriptorData, UINT32 NumberOfPackets,
UINT32 BufferSize, const BYTE* Buffer, t_isoch_transfer_cb cb,
UINT32 Timeout);
int (*control_transfer)(IUDEVICE* idev, UINT32 RequestId, UINT32 EndpointAddress,
UINT32 TransferFlags, BYTE bmRequestType, BYTE Request, UINT16 Value,
UINT16 Index, UINT32* UrbdStatus, UINT32* BufferSize, BYTE* Buffer,
UINT32 Timeout);
BOOL(*control_transfer)
(IUDEVICE* idev, UINT32 RequestId, UINT32 EndpointAddress, UINT32 TransferFlags,
BYTE bmRequestType, BYTE Request, UINT16 Value, UINT16 Index, UINT32* UrbdStatus,
UINT32* BufferSize, BYTE* Buffer, UINT32 Timeout);
int (*bulk_or_interrupt_transfer)(IUDEVICE* idev, UINT32 RequestId, UINT32 EndpointAddress,
UINT32 TransferFlags, UINT32* UsbdStatus, UINT32* BufferSize,
BYTE* Buffer, UINT32 Timeout);
int (*bulk_or_interrupt_transfer)(IUDEVICE* idev, URBDRC_CHANNEL_CALLBACK* callback,
UINT32 MessageId, UINT32 RequestId, UINT32 EndpointAddress,
UINT32 TransferFlags, BOOL NoAck, UINT32 BufferSize,
t_isoch_transfer_cb cb, UINT32 Timeout);
int (*select_configuration)(IUDEVICE* idev, UINT32 bConfigurationValue);
@@ -125,8 +145,8 @@ struct _IUDEVICE
int (*control_pipe_request)(IUDEVICE* idev, UINT32 RequestId, UINT32 EndpointAddress,
UINT32* UsbdStatus, int command);
int (*control_query_device_text)(IUDEVICE* idev, UINT32 TextType, UINT32 LocaleId,
UINT32* BufferSize, BYTE* Buffer);
UINT32(*control_query_device_text)
(IUDEVICE* idev, UINT32 TextType, UINT16 LocaleId, UINT8* BufferSize, BYTE* Buffer);
int (*os_feature_descriptor_request)(IUDEVICE* idev, UINT32 RequestId, BYTE Recipient,
BYTE InterfaceNumber, BYTE Ms_PageIndex,
@@ -139,56 +159,43 @@ struct _IUDEVICE
int (*query_device_descriptor)(IUDEVICE* idev, int offset);
void (*detach_kernel_driver)(IUDEVICE* idev);
BOOL (*detach_kernel_driver)(IUDEVICE* idev);
void (*attach_kernel_driver)(IUDEVICE* idev);
int (*wait_action_completion)(IUDEVICE* idev);
void (*push_action)(IUDEVICE* idev);
void (*complete_action)(IUDEVICE* idev);
BOOL (*attach_kernel_driver)(IUDEVICE* idev);
/* Wait for 5 sec */
int (*wait_for_detach)(IUDEVICE* idev);
/* FIXME: Currently this is a way of stupid, SHOULD to improve it.
* Isochronous transfer must to FIFO */
void (*lock_fifo_isoch)(IUDEVICE* idev);
void (*unlock_fifo_isoch)(IUDEVICE* idev);
BOOL (*wait_for_detach)(IUDEVICE* idev);
int (*query_device_port_status)(IUDEVICE* idev, UINT32* UsbdStatus, UINT32* BufferSize,
BYTE* Buffer);
int (*request_queue_is_none)(IUDEVICE* idev);
MSUSB_CONFIG_DESCRIPTOR* (*complete_msconfig_setup)(IUDEVICE* idev,
MSUSB_CONFIG_DESCRIPTOR* MsConfig);
/* Basic state */
int (*isCompositeDevice)(IUDEVICE* idev);
int (*isSigToEnd)(IUDEVICE* idev);
int (*isExist)(IUDEVICE* idev);
int (*isAlreadySend)(IUDEVICE* idev);
int (*isChannelClosed)(IUDEVICE* idev);
void (*SigToEnd)(IUDEVICE* idev);
void (*setAlreadySend)(IUDEVICE* idev);
void (*setChannelClosed)(IUDEVICE* idev);
char* (*getPath)(IUDEVICE* idev);
BASIC_DEV_STATE_DEFINED(channel_id, UINT32);
void (*free)(IUDEVICE* idev);
BASIC_DEV_STATE_DEFINED(channelManager, IWTSVirtualChannelManager*);
BASIC_DEV_STATE_DEFINED(channelID, UINT32);
BASIC_DEV_STATE_DEFINED(UsbDevice, UINT32);
BASIC_DEV_STATE_DEFINED(ReqCompletion, UINT32);
BASIC_DEV_STATE_DEFINED(bus_number, UINT16);
BASIC_DEV_STATE_DEFINED(dev_number, UINT16);
BASIC_DEV_STATE_DEFINED(bus_number, BYTE);
BASIC_DEV_STATE_DEFINED(dev_number, BYTE);
BASIC_DEV_STATE_DEFINED(port_number, int);
BASIC_DEV_STATE_DEFINED(isoch_queue, void*);
BASIC_DEV_STATE_DEFINED(MsConfig, MSUSB_CONFIG_DESCRIPTOR*);
BASIC_DEV_STATE_DEFINED(p_udev, void*);
BASIC_DEV_STATE_DEFINED(p_prev, void*);
BASIC_DEV_STATE_DEFINED(p_next, void*);
/* Control semaphore or mutex lock */
};
struct _IUDEVMAN
@@ -198,13 +205,12 @@ struct _IUDEVMAN
/* Manage devices */
void (*rewind)(IUDEVMAN* idevman);
int (*has_next)(IUDEVMAN* idevman);
int (*unregister_udevice)(IUDEVMAN* idevman, int bus_number, int dev_number);
int (*register_udevice)(IUDEVMAN* idevman, int bus_number, int dev_number, int UsbDevice,
UINT16 idVendor, UINT16 idProduct, int flag);
BOOL (*has_next)(IUDEVMAN* idevman);
BOOL (*unregister_udevice)(IUDEVMAN* idevman, BYTE bus_number, BYTE dev_number);
size_t (*register_udevice)(IUDEVMAN* idevman, BYTE bus_number, BYTE dev_number,
UINT32 UsbDevice, UINT16 idVendor, UINT16 idProduct, int flag);
IUDEVICE* (*get_next)(IUDEVMAN* idevman);
IUDEVICE* (*get_udevice_by_UsbDevice)(IUDEVMAN* idevman, UINT32 UsbDevice);
IUDEVICE* (*get_udevice_by_UsbDevice_try_again)(IUDEVMAN* idevman, UINT32 UsbDevice);
/* Extension */
int (*check_device_exist_by_id)(IUDEVMAN* idevman, UINT16 idVendor, UINT16 idProduct);
@@ -212,14 +218,20 @@ struct _IUDEVMAN
/* Basic state */
BASIC_DEVMAN_STATE_DEFINED(defUsbDevice, UINT32);
BASIC_DEVMAN_STATE_DEFINED(device_num, int);
BASIC_DEVMAN_STATE_DEFINED(device_num, UINT32);
BASIC_DEVMAN_STATE_DEFINED(sem_timeout, int);
/* control semaphore or mutex lock */
void (*loading_lock)(IUDEVMAN* idevman);
void (*loading_unlock)(IUDEVMAN* idevman);
void (*push_urb)(IUDEVMAN* idevman);
void (*wait_urb)(IUDEVMAN* idevman);
BOOL (*initialize)(IUDEVMAN* idevman, UINT32 channelId);
IWTSPlugin* plugin;
UINT32 controlChannelId;
};
BOOL add_device(IUDEVMAN* idevman, BYTE busnum, BYTE devnum, UINT16 idVendor, UINT16 idProduct);
BOOL del_device(IUDEVMAN* idevman, BYTE busnum, BYTE devnum, UINT16 idVendor, UINT16 idProduct);
UINT stream_write_and_free(IWTSPlugin* plugin, IWTSVirtualChannel* channel, wStream* s);
#endif /* FREERDP_CHANNEL_URBDRC_CLIENT_MAIN_H */

View File

@@ -0,0 +1,26 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# 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.
set(SRCS
urbdrc_types.h
urbdrc_helpers.h
urbdrc_helpers.c
msusb.h
msusb.c)
add_library(urbdrc-common OBJECT ${SRCS})

View File

@@ -0,0 +1,402 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RemoteFX USB Redirection
*
* Copyright 2012 Atrust corp.
* Copyright 2012 Alfred Liu <alfred.liu@atruscorp.com>
*
* 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <freerdp/log.h>
#include <msusb.h>
#define TAG FREERDP_TAG("utils")
static MSUSB_PIPE_DESCRIPTOR* msusb_mspipe_new()
{
return (MSUSB_PIPE_DESCRIPTOR*)calloc(1, sizeof(MSUSB_PIPE_DESCRIPTOR));
}
static void msusb_mspipes_free(MSUSB_PIPE_DESCRIPTOR** MsPipes, UINT32 NumberOfPipes)
{
UINT32 pnum = 0;
if (MsPipes)
{
for (pnum = 0; pnum < NumberOfPipes && MsPipes[pnum]; pnum++)
free(MsPipes[pnum]);
free(MsPipes);
}
}
BOOL msusb_mspipes_replace(MSUSB_INTERFACE_DESCRIPTOR* MsInterface,
MSUSB_PIPE_DESCRIPTOR** NewMsPipes, UINT32 NewNumberOfPipes)
{
if (!MsInterface || !NewMsPipes)
return FALSE;
/* free orignal MsPipes */
msusb_mspipes_free(MsInterface->MsPipes, MsInterface->NumberOfPipes);
/* And replace it */
MsInterface->MsPipes = NewMsPipes;
MsInterface->NumberOfPipes = NewNumberOfPipes;
return TRUE;
}
static MSUSB_PIPE_DESCRIPTOR** msusb_mspipes_read(wStream* s, UINT32 NumberOfPipes)
{
UINT32 pnum;
MSUSB_PIPE_DESCRIPTOR** MsPipes;
if (Stream_GetRemainingCapacity(s) < 12 * NumberOfPipes)
return NULL;
MsPipes = (MSUSB_PIPE_DESCRIPTOR**)calloc(NumberOfPipes, sizeof(MSUSB_PIPE_DESCRIPTOR*));
if (!MsPipes)
return NULL;
for (pnum = 0; pnum < NumberOfPipes; pnum++)
{
MSUSB_PIPE_DESCRIPTOR* MsPipe = msusb_mspipe_new();
if (!MsPipe)
goto out_error;
Stream_Read_UINT16(s, MsPipe->MaximumPacketSize);
Stream_Seek(s, 2);
Stream_Read_UINT32(s, MsPipe->MaximumTransferSize);
Stream_Read_UINT32(s, MsPipe->PipeFlags);
/* Already set to zero by memset
MsPipe->PipeHandle = 0;
MsPipe->bEndpointAddress = 0;
MsPipe->bInterval = 0;
MsPipe->PipeType = 0;
MsPipe->InitCompleted = 0;
*/
MsPipes[pnum] = MsPipe;
}
return MsPipes;
out_error:
for (pnum = 0; pnum < NumberOfPipes; pnum++)
free(MsPipes[pnum]);
free(MsPipes);
return NULL;
}
static MSUSB_INTERFACE_DESCRIPTOR* msusb_msinterface_new()
{
return (MSUSB_INTERFACE_DESCRIPTOR*)calloc(1, sizeof(MSUSB_INTERFACE_DESCRIPTOR));
}
static void msusb_msinterface_free(MSUSB_INTERFACE_DESCRIPTOR* MsInterface)
{
if (MsInterface)
{
msusb_mspipes_free(MsInterface->MsPipes, MsInterface->NumberOfPipes);
MsInterface->MsPipes = NULL;
free(MsInterface);
}
}
static void msusb_msinterface_free_list(MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces,
UINT32 NumInterfaces)
{
UINT32 inum = 0;
if (MsInterfaces)
{
for (inum = 0; inum < NumInterfaces; inum++)
{
msusb_msinterface_free(MsInterfaces[inum]);
}
free(MsInterfaces);
}
}
BOOL msusb_msinterface_replace(MSUSB_CONFIG_DESCRIPTOR* MsConfig, BYTE InterfaceNumber,
MSUSB_INTERFACE_DESCRIPTOR* NewMsInterface)
{
if (!MsConfig || !MsConfig->MsInterfaces)
return FALSE;
msusb_msinterface_free(MsConfig->MsInterfaces[InterfaceNumber]);
MsConfig->MsInterfaces[InterfaceNumber] = NewMsInterface;
return TRUE;
}
MSUSB_INTERFACE_DESCRIPTOR* msusb_msinterface_read(wStream* s)
{
MSUSB_INTERFACE_DESCRIPTOR* MsInterface;
if (Stream_GetRemainingCapacity(s) < 12)
return NULL;
MsInterface = msusb_msinterface_new();
if (!MsInterface)
return NULL;
Stream_Read_UINT16(s, MsInterface->Length);
Stream_Read_UINT16(s, MsInterface->NumberOfPipesExpected);
Stream_Read_UINT8(s, MsInterface->InterfaceNumber);
Stream_Read_UINT8(s, MsInterface->AlternateSetting);
Stream_Seek(s, 2);
Stream_Read_UINT32(s, MsInterface->NumberOfPipes);
MsInterface->InterfaceHandle = 0;
MsInterface->bInterfaceClass = 0;
MsInterface->bInterfaceSubClass = 0;
MsInterface->bInterfaceProtocol = 0;
MsInterface->InitCompleted = 0;
MsInterface->MsPipes = NULL;
if (MsInterface->NumberOfPipes > 0)
{
MsInterface->MsPipes = msusb_mspipes_read(s, MsInterface->NumberOfPipes);
if (!MsInterface->MsPipes)
goto out_error;
}
return MsInterface;
out_error:
msusb_msinterface_free(MsInterface);
return NULL;
}
BOOL msusb_msinterface_write(MSUSB_INTERFACE_DESCRIPTOR* MsInterface, wStream* out)
{
MSUSB_PIPE_DESCRIPTOR** MsPipes;
MSUSB_PIPE_DESCRIPTOR* MsPipe;
UINT32 pnum = 0;
if (!MsInterface)
return FALSE;
if (!Stream_EnsureRemainingCapacity(out, 16 + MsInterface->NumberOfPipes * 20))
return FALSE;
/* Length */
Stream_Write_UINT16(out, MsInterface->Length);
/* InterfaceNumber */
Stream_Write_UINT8(out, MsInterface->InterfaceNumber);
/* AlternateSetting */
Stream_Write_UINT8(out, MsInterface->AlternateSetting);
/* bInterfaceClass */
Stream_Write_UINT8(out, MsInterface->bInterfaceClass);
/* bInterfaceSubClass */
Stream_Write_UINT8(out, MsInterface->bInterfaceSubClass);
/* bInterfaceProtocol */
Stream_Write_UINT8(out, MsInterface->bInterfaceProtocol);
/* Padding */
Stream_Write_UINT8(out, 0);
/* InterfaceHandle */
Stream_Write_UINT32(out, MsInterface->InterfaceHandle);
/* NumberOfPipes */
Stream_Write_UINT32(out, MsInterface->NumberOfPipes);
/* Pipes */
MsPipes = MsInterface->MsPipes;
for (pnum = 0; pnum < MsInterface->NumberOfPipes; pnum++)
{
MsPipe = MsPipes[pnum];
/* MaximumPacketSize */
Stream_Write_UINT16(out, MsPipe->MaximumPacketSize);
/* EndpointAddress */
Stream_Write_UINT8(out, MsPipe->bEndpointAddress);
/* Interval */
Stream_Write_UINT8(out, MsPipe->bInterval);
/* PipeType */
Stream_Write_UINT32(out, MsPipe->PipeType);
/* PipeHandle */
Stream_Write_UINT32(out, MsPipe->PipeHandle);
/* MaximumTransferSize */
Stream_Write_UINT32(out, MsPipe->MaximumTransferSize);
/* PipeFlags */
Stream_Write_UINT32(out, MsPipe->PipeFlags);
}
return TRUE;
}
static MSUSB_INTERFACE_DESCRIPTOR** msusb_msinterface_read_list(wStream* s, UINT32 NumInterfaces)
{
UINT32 inum;
MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces;
MsInterfaces =
(MSUSB_INTERFACE_DESCRIPTOR**)calloc(NumInterfaces, sizeof(MSUSB_INTERFACE_DESCRIPTOR*));
if (!MsInterfaces)
return NULL;
for (inum = 0; inum < NumInterfaces; inum++)
{
MsInterfaces[inum] = msusb_msinterface_read(s);
if (!MsInterfaces[inum])
goto fail;
}
return MsInterfaces;
fail:
for (inum = 0; inum < NumInterfaces; inum++)
msusb_msinterface_free(MsInterfaces[inum]);
free(MsInterfaces);
return NULL;
}
BOOL msusb_msconfig_write(MSUSB_CONFIG_DESCRIPTOR* MsConfg, wStream* out)
{
UINT32 inum = 0;
MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces;
MSUSB_INTERFACE_DESCRIPTOR* MsInterface;
if (!MsConfg)
return FALSE;
if (!Stream_EnsureRemainingCapacity(out, 8))
return FALSE;
/* ConfigurationHandle*/
Stream_Write_UINT32(out, MsConfg->ConfigurationHandle);
/* NumInterfaces*/
Stream_Write_UINT32(out, MsConfg->NumInterfaces);
/* Interfaces */
MsInterfaces = MsConfg->MsInterfaces;
for (inum = 0; inum < MsConfg->NumInterfaces; inum++)
{
MsInterface = MsInterfaces[inum];
if (!msusb_msinterface_write(MsInterface, out))
return FALSE;
}
return TRUE;
}
MSUSB_CONFIG_DESCRIPTOR* msusb_msconfig_new(void)
{
return (MSUSB_CONFIG_DESCRIPTOR*)calloc(1, sizeof(MSUSB_CONFIG_DESCRIPTOR));
}
void msusb_msconfig_free(MSUSB_CONFIG_DESCRIPTOR* MsConfig)
{
if (MsConfig)
{
msusb_msinterface_free_list(MsConfig->MsInterfaces, MsConfig->NumInterfaces);
MsConfig->MsInterfaces = NULL;
free(MsConfig);
}
}
MSUSB_CONFIG_DESCRIPTOR* msusb_msconfig_read(wStream* s, UINT32 NumInterfaces)
{
MSUSB_CONFIG_DESCRIPTOR* MsConfig;
BYTE lenConfiguration, typeConfiguration;
if (Stream_GetRemainingCapacity(s) < 6 + NumInterfaces * 2)
return NULL;
MsConfig = msusb_msconfig_new();
if (!MsConfig)
goto fail;
MsConfig->MsInterfaces = msusb_msinterface_read_list(s, NumInterfaces);
if (!MsConfig->MsInterfaces)
goto fail;
Stream_Read_UINT8(s, lenConfiguration);
Stream_Read_UINT8(s, typeConfiguration);
if (lenConfiguration != 0x9 || typeConfiguration != 0x2)
{
WLog_ERR(TAG, "len and type must be 0x9 and 0x2 , but it is 0x%" PRIx8 " and 0x%" PRIx8 "",
lenConfiguration, typeConfiguration);
goto fail;
}
Stream_Read_UINT16(s, MsConfig->wTotalLength);
Stream_Seek(s, 1);
Stream_Read_UINT8(s, MsConfig->bConfigurationValue);
MsConfig->NumInterfaces = NumInterfaces;
return MsConfig;
fail:
msusb_msconfig_free(MsConfig);
return NULL;
}
void msusb_msconfig_dump(MSUSB_CONFIG_DESCRIPTOR* MsConfig)
{
MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces;
MSUSB_INTERFACE_DESCRIPTOR* MsInterface;
MSUSB_PIPE_DESCRIPTOR** MsPipes;
MSUSB_PIPE_DESCRIPTOR* MsPipe;
UINT32 inum = 0, pnum = 0;
WLog_INFO(TAG, "=================MsConfig:========================");
WLog_INFO(TAG, "wTotalLength:%" PRIu16 "", MsConfig->wTotalLength);
WLog_INFO(TAG, "bConfigurationValue:%" PRIu8 "", MsConfig->bConfigurationValue);
WLog_INFO(TAG, "ConfigurationHandle:0x%08" PRIx32 "", MsConfig->ConfigurationHandle);
WLog_INFO(TAG, "InitCompleted:%d", MsConfig->InitCompleted);
WLog_INFO(TAG, "MsOutSize:%d", MsConfig->MsOutSize);
WLog_INFO(TAG, "NumInterfaces:%" PRIu32 "", MsConfig->NumInterfaces);
MsInterfaces = MsConfig->MsInterfaces;
for (inum = 0; inum < MsConfig->NumInterfaces; inum++)
{
MsInterface = MsInterfaces[inum];
WLog_INFO(TAG, " Interface: %" PRIu8 "", MsInterface->InterfaceNumber);
WLog_INFO(TAG, " Length: %" PRIu16 "", MsInterface->Length);
WLog_INFO(TAG, " NumberOfPipesExpected: %" PRIu16 "",
MsInterface->NumberOfPipesExpected);
WLog_INFO(TAG, " AlternateSetting: %" PRIu8 "", MsInterface->AlternateSetting);
WLog_INFO(TAG, " NumberOfPipes: %" PRIu32 "", MsInterface->NumberOfPipes);
WLog_INFO(TAG, " InterfaceHandle: 0x%08" PRIx32 "", MsInterface->InterfaceHandle);
WLog_INFO(TAG, " bInterfaceClass: 0x%02" PRIx8 "", MsInterface->bInterfaceClass);
WLog_INFO(TAG, " bInterfaceSubClass: 0x%02" PRIx8 "", MsInterface->bInterfaceSubClass);
WLog_INFO(TAG, " bInterfaceProtocol: 0x%02" PRIx8 "", MsInterface->bInterfaceProtocol);
WLog_INFO(TAG, " InitCompleted: %d", MsInterface->InitCompleted);
MsPipes = MsInterface->MsPipes;
for (pnum = 0; pnum < MsInterface->NumberOfPipes; pnum++)
{
MsPipe = MsPipes[pnum];
WLog_INFO(TAG, " Pipe: %d", pnum);
WLog_INFO(TAG, " MaximumPacketSize: 0x%04" PRIx16 "", MsPipe->MaximumPacketSize);
WLog_INFO(TAG, " MaximumTransferSize: 0x%08" PRIx32 "",
MsPipe->MaximumTransferSize);
WLog_INFO(TAG, " PipeFlags: 0x%08" PRIx32 "", MsPipe->PipeFlags);
WLog_INFO(TAG, " PipeHandle: 0x%08" PRIx32 "", MsPipe->PipeHandle);
WLog_INFO(TAG, " bEndpointAddress: 0x%02" PRIx8 "", MsPipe->bEndpointAddress);
WLog_INFO(TAG, " bInterval: %" PRIu8 "", MsPipe->bInterval);
WLog_INFO(TAG, " PipeType: 0x%02" PRIx8 "", MsPipe->PipeType);
WLog_INFO(TAG, " InitCompleted: %d", MsPipe->InitCompleted);
}
}
WLog_INFO(TAG, "==================================================");
}

View File

@@ -0,0 +1,97 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RemoteFX USB Redirection
*
* Copyright 2012 Atrust corp.
* Copyright 2012 Alfred Liu <alfred.liu@atruscorp.com>
*
* 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.
*/
#ifndef FREERDP_UTILS_MSCONFIG_H
#define FREERDP_UTILS_MSCONFIG_H
#include <winpr/stream.h>
#include <freerdp/api.h>
typedef struct _MSUSB_INTERFACE_DESCRIPTOR MSUSB_INTERFACE_DESCRIPTOR;
typedef struct _MSUSB_PIPE_DESCRIPTOR MSUSB_PIPE_DESCRIPTOR;
typedef struct _MSUSB_CONFIG_DESCRIPTOR MSUSB_CONFIG_DESCRIPTOR;
struct _MSUSB_PIPE_DESCRIPTOR
{
UINT16 MaximumPacketSize;
UINT32 MaximumTransferSize;
UINT32 PipeFlags;
UINT32 PipeHandle;
BYTE bEndpointAddress;
BYTE bInterval;
BYTE PipeType;
int InitCompleted;
};
struct _MSUSB_INTERFACE_DESCRIPTOR
{
UINT16 Length;
UINT16 NumberOfPipesExpected;
BYTE InterfaceNumber;
BYTE AlternateSetting;
UINT32 NumberOfPipes;
UINT32 InterfaceHandle;
BYTE bInterfaceClass;
BYTE bInterfaceSubClass;
BYTE bInterfaceProtocol;
MSUSB_PIPE_DESCRIPTOR** MsPipes;
int InitCompleted;
};
struct _MSUSB_CONFIG_DESCRIPTOR
{
UINT16 wTotalLength;
BYTE bConfigurationValue;
UINT32 ConfigurationHandle;
UINT32 NumInterfaces;
MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces;
int InitCompleted;
int MsOutSize;
};
#ifdef __cplusplus
extern "C"
{
#endif
/* MSUSB_PIPE exported functions */
FREERDP_API BOOL msusb_mspipes_replace(MSUSB_INTERFACE_DESCRIPTOR* MsInterface,
MSUSB_PIPE_DESCRIPTOR** NewMsPipes,
UINT32 NewNumberOfPipes);
/* MSUSB_INTERFACE exported functions */
FREERDP_API BOOL msusb_msinterface_replace(MSUSB_CONFIG_DESCRIPTOR* MsConfig,
BYTE InterfaceNumber,
MSUSB_INTERFACE_DESCRIPTOR* NewMsInterface);
FREERDP_API MSUSB_INTERFACE_DESCRIPTOR* msusb_msinterface_read(wStream* out);
FREERDP_API BOOL msusb_msinterface_write(MSUSB_INTERFACE_DESCRIPTOR* MsInterface, wStream* out);
/* MSUSB_CONFIG exported functions */
FREERDP_API MSUSB_CONFIG_DESCRIPTOR* msusb_msconfig_new(void);
FREERDP_API void msusb_msconfig_free(MSUSB_CONFIG_DESCRIPTOR* MsConfig);
FREERDP_API MSUSB_CONFIG_DESCRIPTOR* msusb_msconfig_read(wStream* s, UINT32 NumInterfaces);
FREERDP_API BOOL msusb_msconfig_write(MSUSB_CONFIG_DESCRIPTOR* MsConfg, wStream* out);
FREERDP_API void msusb_msconfig_dump(MSUSB_CONFIG_DESCRIPTOR* MsConfg);
#ifdef __cplusplus
}
#endif
#endif /* FREERDP_UTILS_MSCONFIG_H */

View File

@@ -0,0 +1,408 @@
/**
* 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.
*/
#include "urbdrc_helpers.h"
#include "urbdrc_types.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 = Stream_GetPosition(s);
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=%" PRIdz,
type, call_to_string(client, InterfaceId, FunctionId), FunctionId, InterfaceId,
MessageId, FunctionId, length);
}

View File

@@ -0,0 +1,45 @@
/**
* 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.
*/
#ifndef FREERDP_CHANNEL_URBDRC_HELPERS_H
#define FREERDP_CHANNEL_URBDRC_HELPERS_H
#include <winpr/wtypes.h>
#ifdef __cplusplus
extern "C"
{
#endif
#include <winpr/wlog.h>
#include <winpr/stream.h>
const char* urb_function_string(UINT16 urb);
const char* mask_to_string(UINT32 mask);
const char* interface_to_string(UINT32 id);
const char* call_to_string(BOOL client, UINT32 interface, UINT32 functionId);
void urbdrc_dump_message(wLog* log, BOOL client, BOOL write, wStream* s);
#ifdef __cplusplus
}
#endif
#endif /* FREERDP_CHANNEL_URBDRC_HELPERS_H */

View File

@@ -27,24 +27,12 @@
#include <freerdp/dvc.h>
#include <freerdp/types.h>
#include <freerdp/channels/log.h>
#include <freerdp/utils/msusb.h>
#include <uuid.h>
#include <pthread.h>
#include <semaphore.h>
#include <msusb.h>
#include <winpr/stream.h>
#define TAG CHANNELS_TAG("urbdrc.client")
#ifdef WITH_DEBUG_DVC
#define DEBUG_DVC(...) WLog_DBG(TAG, __VA_ARGS__)
#else
#define DEBUG_DVC(...) \
do \
{ \
} while (0)
#endif
#define RIM_CAPABILITY_VERSION_01 0x00000001
#define CAPABILITIES_NEGOTIATOR 0x00000000
#define CLIENT_DEVICE_SINK 0x00000001
@@ -53,6 +41,7 @@
#define BASE_USBDEVICE_NUM 0x00000005
#define RIMCALL_RELEASE 0x00000001
#define RIMCALL_QUERYINTERFACE 0x00000002
#define RIM_EXCHANGE_CAPABILITY_REQUEST 0x00000100
#define CHANNEL_CREATED 0x00000100
#define ADD_VIRTUAL_CHANNEL 0x00000100
@@ -88,15 +77,18 @@
#define USB_v2_0 0x200
#define USB_v3_0 0x300
#define STREAM_ID_NONE 0x0
#define STREAM_ID_PROXY 0x1
#define STREAM_ID_STUB 0x2
#define STREAM_ID_NONE 0x0UL
#define STREAM_ID_PROXY 0x1UL
#define STREAM_ID_STUB 0x2UL
#define STREAM_ID_MASK 0xC0000000
#define INTERFACE_ID_MASK 0x3FFFFFFF
#define CANCEL_REQUEST 0x00000100
#define REGISTER_REQUEST_CALLBACK 0x00000101
#define IO_CONTROL 0x00000102
#define INTERNAL_IO_CONTROL 0x00000103
#define QUERY_DEVICE_TEXT 0x00000104
#define TRANSFER_IN_REQUEST 0x00000105
#define TRANSFER_OUT_REQUEST 0x00000106
#define RETRACT_DEVICE 0x00000107
@@ -142,63 +134,64 @@ enum device_descriptor_table
#define IOCTL_INTERNAL_USB_CYCLE_PORT 0x0022001F
#define IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION 0x00220027
#define URB_FUNCTION_SELECT_CONFIGURATION 0x0000
#define URB_FUNCTION_SELECT_INTERFACE 0x0001
#define URB_FUNCTION_ABORT_PIPE 0x0002
#define URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL 0x0003
#define URB_FUNCTION_RELEASE_FRAME_LENGTH_CONTROL 0x0004
#define URB_FUNCTION_GET_FRAME_LENGTH 0x0005
#define URB_FUNCTION_SET_FRAME_LENGTH 0x0006
#define URB_FUNCTION_GET_CURRENT_FRAME_NUMBER 0x0007
#define URB_FUNCTION_CONTROL_TRANSFER 0x0008
#define URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER 0x0009
#define URB_FUNCTION_ISOCH_TRANSFER 0x000A
#define URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE 0x000B
#define URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE 0x000C
#define URB_FUNCTION_SET_FEATURE_TO_DEVICE 0x000D
#define URB_FUNCTION_SET_FEATURE_TO_INTERFACE 0x000E
#define URB_FUNCTION_SET_FEATURE_TO_ENDPOINT 0x000F
#define URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE 0x0010
#define URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE 0x0011
#define URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT 0x0012
#define URB_FUNCTION_GET_STATUS_FROM_DEVICE 0x0013
#define URB_FUNCTION_GET_STATUS_FROM_INTERFACE 0x0014
#define URB_FUNCTION_GET_STATUS_FROM_ENDPOINT 0x0015
#define URB_FUNCTION_RESERVED_0X0016 0x0016
#define URB_FUNCTION_VENDOR_DEVICE 0x0017
#define URB_FUNCTION_VENDOR_INTERFACE 0x0018
#define URB_FUNCTION_VENDOR_ENDPOINT 0x0019
#define URB_FUNCTION_CLASS_DEVICE 0x001A
#define URB_FUNCTION_CLASS_INTERFACE 0x001B
#define URB_FUNCTION_CLASS_ENDPOINT 0x001C
#define URB_FUNCTION_RESERVE_0X001D 0x001D
#define URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL 0x001E
#define URB_FUNCTION_CLASS_OTHER 0x001F
#define URB_FUNCTION_VENDOR_OTHER 0x0020
#define URB_FUNCTION_GET_STATUS_FROM_OTHER 0x0021
#define URB_FUNCTION_CLEAR_FEATURE_TO_OTHER 0x0022
#define URB_FUNCTION_SET_FEATURE_TO_OTHER 0x0023
#define URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT 0x0024
#define URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT 0x0025
#define URB_FUNCTION_GET_CONFIGURATION 0x0026
#define URB_FUNCTION_GET_INTERFACE 0x0027
#define URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE 0x0028
#define URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE 0x0029
#define URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR 0x002A
#define URB_FUNCTION_RESERVE_0X002B 0x002B
#define URB_FUNCTION_RESERVE_0X002C 0x002C
#define URB_FUNCTION_RESERVE_0X002D 0x002D
#define URB_FUNCTION_RESERVE_0X002E 0x002E
#define URB_FUNCTION_RESERVE_0X002F 0x002F
#define TS_URB_SELECT_CONFIGURATION 0x0000
#define TS_URB_SELECT_INTERFACE 0x0001
#define TS_URB_PIPE_REQUEST 0x0002
#define TS_URB_TAKE_FRAME_LENGTH_CONTROL 0x0003
#define TS_URB_RELEASE_FRAME_LENGTH_CONTROL 0x0004
#define TS_URB_GET_FRAME_LENGTH 0x0005
#define TS_URB_SET_FRAME_LENGTH 0x0006
#define TS_URB_GET_CURRENT_FRAME_NUMBER 0x0007
#define TS_URB_CONTROL_TRANSFER 0x0008
#define TS_URB_BULK_OR_INTERRUPT_TRANSFER 0x0009
#define TS_URB_ISOCH_TRANSFER 0x000A
#define TS_URB_GET_DESCRIPTOR_FROM_DEVICE 0x000B
#define TS_URB_SET_DESCRIPTOR_TO_DEVICE 0x000C
#define TS_URB_SET_FEATURE_TO_DEVICE 0x000D
#define TS_URB_SET_FEATURE_TO_INTERFACE 0x000E
#define TS_URB_SET_FEATURE_TO_ENDPOINT 0x000F
#define TS_URB_CLEAR_FEATURE_TO_DEVICE 0x0010
#define TS_URB_CLEAR_FEATURE_TO_INTERFACE 0x0011
#define TS_URB_CLEAR_FEATURE_TO_ENDPOINT 0x0012
#define TS_URB_GET_STATUS_FROM_DEVICE 0x0013
#define TS_URB_GET_STATUS_FROM_INTERFACE 0x0014
#define TS_URB_GET_STATUS_FROM_ENDPOINT 0x0015
#define TS_URB_RESERVED_0X0016 0x0016
#define TS_URB_VENDOR_DEVICE 0x0017
#define TS_URB_VENDOR_INTERFACE 0x0018
#define TS_URB_VENDOR_ENDPOINT 0x0019
#define TS_URB_CLASS_DEVICE 0x001A
#define TS_URB_CLASS_INTERFACE 0x001B
#define TS_URB_CLASS_ENDPOINT 0x001C
#define TS_URB_RESERVE_0X001D 0x001D
#define TS_URB_SYNC_RESET_PIPE_AND_CLEAR_STALL 0x001E
#define TS_URB_CLASS_OTHER 0x001F
#define TS_URB_VENDOR_OTHER 0x0020
#define TS_URB_GET_STATUS_FROM_OTHER 0x0021
#define TS_URB_CLEAR_FEATURE_TO_OTHER 0x0022
#define TS_URB_SET_FEATURE_TO_OTHER 0x0023
#define TS_URB_GET_DESCRIPTOR_FROM_ENDPOINT 0x0024
#define TS_URB_SET_DESCRIPTOR_TO_ENDPOINT 0x0025
#define TS_URB_CONTROL_GET_CONFIGURATION_REQUEST 0x0026
#define TS_URB_CONTROL_GET_INTERFACE_REQUEST 0x0027
#define TS_URB_GET_DESCRIPTOR_FROM_INTERFACE 0x0028
#define TS_URB_SET_DESCRIPTOR_TO_INTERFACE 0x0029
#define TS_URB_GET_OS_FEATURE_DESCRIPTOR_REQUEST 0x002A
#define TS_URB_RESERVE_0X002B 0x002B
#define TS_URB_RESERVE_0X002C 0x002C
#define TS_URB_RESERVE_0X002D 0x002D
#define TS_URB_RESERVE_0X002E 0x002E
#define TS_URB_RESERVE_0X002F 0x002F
// USB 2.0 calls start at 0x0030
#define URB_FUNCTION_SYNC_RESET_PIPE 0x0030
#define URB_FUNCTION_SYNC_CLEAR_STALL 0x0031
#define URB_FUNCTION_CONTROL_TRANSFER_EX 0x0032
#define TS_URB_SYNC_RESET_PIPE 0x0030
#define TS_URB_SYNC_CLEAR_STALL 0x0031
#define TS_URB_CONTROL_TRANSFER_EX 0x0032
#define USBD_STATUS_SUCCESS 0x0
#define USBD_STATUS_PENDING 0x40000000
#define USBD_STATUS_CANCELED 0xC0010000
#define USBD_STATUS_INVALID_URB_FUNCTION 0x80000200
#define USBD_STATUS_CRC 0xC0000001
#define USBD_STATUS_BTSTUFF 0xC0000002
#define USBD_STATUS_DATA_TOGGLE_MISMATCH 0xC0000003
@@ -303,7 +296,6 @@ enum device_descriptor_table
#define URBDRC_DEVICE_INITIALIZED 0x01
#define URBDRC_DEVICE_NOT_FOUND 0x02
#define URBDRC_DEVICE_SIGNAL_END 0x04
#define URBDRC_DEVICE_CHANNEL_CLOSED 0x08
#define URBDRC_DEVICE_ALREADY_SEND 0x10
#define URBDRC_DEVICE_DETACH_KERNEL 0x20
@@ -313,30 +305,4 @@ enum device_descriptor_table
#define UDEVMAN_FLAG_ADD_BY_AUTO 0x04
#define UDEVMAN_FLAG_DEBUG 0x08
#define MAX_URB_REQUSET_NUM 0x80
#define LOG_LEVEL 1
#define dummy_wait_obj(void) \
do \
{ \
sleep(5); \
} while (0)
#define dummy_wait_s_obj(_s) \
do \
{ \
sleep(_s); \
} while (0)
#define ISOCH_FIFO 1
#define WAIT_COMPLETE_SLEEP 10000 /* for cpu high loading */
#define urbdrc_get_mstime(_t) \
do \
{ \
struct timeval _tp; \
gettimeofday(&_tp, 0); \
_t = (_tp.tv_sec * 1000) + (_tp.tv_usec / 1000); \
} while (0)
#endif /* FREERDP_CHANNEL_URBDRC_CLIENT_TYPES_H */

View File

@@ -0,0 +1,30 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Server USB redirection Virtual Channel
*
* 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.
*/
#ifndef FREERDP_CHANNEL_URBDRC_H
#define FREERDP_CHANNEL_URBDRC_H
#include <freerdp/api.h>
#include <freerdp/dvc.h>
#include <freerdp/types.h>
#define URBDRC_CHANNEL_NAME "urbdrc"
#endif /* FREERDP_CHANNEL_URBDRC_H */