FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
urbdrc_main.c
1
21#include <winpr/assert.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <errno.h>
26
27#include <winpr/pool.h>
28#include <winpr/print.h>
29
30#include <winpr/crt.h>
31#include <winpr/synch.h>
32#include <winpr/string.h>
33#include <winpr/cmdline.h>
34
35#include <freerdp/dvc.h>
36#include <freerdp/addin.h>
37#include <freerdp/channels/log.h>
38#include <freerdp/channels/urbdrc.h>
39
40#include "urbdrc_types.h"
41#include "urbdrc_main.h"
42#include "data_transfer.h"
43
44#include <urbdrc_helpers.h>
45
46static IWTSVirtualChannel* get_channel(IUDEVMAN* idevman)
47{
48 IWTSVirtualChannelManager* channel_mgr = NULL;
49 URBDRC_PLUGIN* urbdrc = NULL;
50
51 if (!idevman)
52 return NULL;
53
54 urbdrc = (URBDRC_PLUGIN*)idevman->plugin;
55
56 if (!urbdrc || !urbdrc->listener_callback)
57 return NULL;
58
59 channel_mgr = urbdrc->listener_callback->channel_mgr;
60
61 if (!channel_mgr)
62 return NULL;
63
64 return channel_mgr->FindChannelById(channel_mgr, idevman->controlChannelId);
65}
66
67static int func_container_id_generate(IUDEVICE* pdev, char* strContainerId)
68{
69 char* p = NULL;
70 char* path = NULL;
71 UINT8 containerId[17] = { 0 };
72 UINT16 idVendor = 0;
73 UINT16 idProduct = 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);
77
78 if (strlen(path) > 8)
79 p = (path + strlen(path)) - 8;
80 else
81 p = path;
82
83 (void)sprintf_s((char*)containerId, sizeof(containerId), "%04" PRIX16 "%04" PRIX16 "%s",
84 idVendor, idProduct, p);
85 /* format */
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]);
94 return 0;
95}
96
97static int func_instance_id_generate(IUDEVICE* pdev, char* strInstanceId, size_t len)
98{
99 char instanceId[17] = { 0 };
100 (void)sprintf_s(instanceId, sizeof(instanceId), "\\%s", pdev->getPath(pdev));
101 /* format */
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],
109 instanceId[15]);
110 return 0;
111}
112
113/* [MS-RDPEUSB] 2.2.3.2 Interface Manipulation Exchange Capabilities Response
114 * (RIM_EXCHANGE_CAPABILITY_RESPONSE) */
115static UINT urbdrc_send_capability_response(GENERIC_CHANNEL_CALLBACK* callback, UINT32 MessageId,
116 UINT32 Version)
117{
118 const UINT32 InterfaceId = ((STREAM_ID_NONE << 30) | CAPABILITIES_NEGOTIATOR);
119 wStream* out = create_shared_message_header_with_functionid(InterfaceId, MessageId, Version, 4);
120
121 if (!out)
122 return ERROR_OUTOFMEMORY;
123
124 Stream_Write_UINT32(out, 0x00000000); /* HRESULT */
125 return stream_write_and_free(callback->plugin, callback->channel, out);
126}
127
133static UINT urbdrc_process_capability_request(GENERIC_CHANNEL_CALLBACK* callback, wStream* s,
134 UINT32 MessageId)
135{
136 WINPR_ASSERT(callback);
137 URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)callback->plugin;
138 WINPR_ASSERT(urbdrc);
139
140 if (!callback || !s)
141 return ERROR_INVALID_PARAMETER;
142
143 if (!Stream_CheckAndLogRequiredLengthWLog(urbdrc->log, s, 4))
144 return ERROR_INVALID_DATA;
145
146 UINT32 Version = Stream_Get_UINT32(s);
147
148 if (Version > RIM_CAPABILITY_VERSION_01)
149 {
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;
153 }
154
155 return urbdrc_send_capability_response(callback, MessageId, Version);
156}
157
158/* [MS-RDPEUSB] 2.2.5.1 Channel Created Message (CHANNEL_CREATED) */
159static UINT urbdrc_send_channel_created(GENERIC_CHANNEL_CALLBACK* callback, UINT32 MessageId,
160 UINT32 MajorVersion, UINT32 MinorVersion,
161 UINT32 Capabilities)
162{
163 WINPR_ASSERT(callback);
164
165 const UINT32 InterfaceId = ((STREAM_ID_PROXY << 30) | CLIENT_CHANNEL_NOTIFICATION);
166 wStream* out =
167 create_shared_message_header_with_functionid(InterfaceId, MessageId, CHANNEL_CREATED, 12);
168
169 if (!out)
170 return ERROR_OUTOFMEMORY;
171
172 Stream_Write_UINT32(out, MajorVersion);
173 Stream_Write_UINT32(out, MinorVersion);
174 Stream_Write_UINT32(out, Capabilities); /* capabilities version */
175 return stream_write_and_free(callback->plugin, callback->channel, out);
176}
177
183static UINT urbdrc_process_channel_create(GENERIC_CHANNEL_CALLBACK* callback, wStream* s,
184 UINT32 MessageId)
185{
186 UINT32 MajorVersion = 0;
187 UINT32 MinorVersion = 0;
188 UINT32 Capabilities = 0;
189 URBDRC_PLUGIN* urbdrc = NULL;
190
191 if (!callback || !s || !callback->plugin)
192 return ERROR_INVALID_PARAMETER;
193
194 urbdrc = (URBDRC_PLUGIN*)callback->plugin;
195
196 if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
197 return ERROR_INVALID_DATA;
198
199 Stream_Read_UINT32(s, MajorVersion);
200 Stream_Read_UINT32(s, MinorVersion);
201 Stream_Read_UINT32(s, Capabilities);
202
203 /* Version check, we only support version 1.0 */
204 if ((MajorVersion != 1) || (MinorVersion != 0))
205 {
206 WLog_Print(urbdrc->log, WLOG_WARN,
207 "server supports USB channel version %" PRIu32 ".%" PRIu32);
208 WLog_Print(urbdrc->log, WLOG_WARN, "we only support channel version 1.0");
209 MajorVersion = 1;
210 MinorVersion = 0;
211 }
212 if (Capabilities != 0)
213 {
214 WLog_Print(urbdrc->log, WLOG_WARN,
215 "[MS-RDPEUSB] 2.2.5.1 Channel Created Message (CHANNEL_CREATED) states "
216 "Capabilities must be 0, got %" PRIu32,
217 Capabilities);
218 Capabilities = 0;
219 }
220
221 return urbdrc_send_channel_created(callback, MessageId, MajorVersion, MinorVersion,
222 Capabilities);
223}
224
225static UINT urdbrc_send_virtual_channel_add(IWTSPlugin* plugin, IWTSVirtualChannel* channel,
226 UINT32 MessageId)
227{
228 const UINT32 InterfaceId = ((STREAM_ID_PROXY << 30) | CLIENT_DEVICE_SINK);
229 wStream* out = create_shared_message_header_with_functionid(InterfaceId, MessageId,
230 ADD_VIRTUAL_CHANNEL, 0);
231
232 if (!out)
233 return ERROR_OUTOFMEMORY;
234
235 return stream_write_and_free(plugin, channel, out);
236}
237
238static BOOL write_string_block(wStream* s, size_t count, const char** strings, const size_t* length,
239 BOOL isMultiSZ)
240{
241 size_t len = 0;
242 for (size_t x = 0; x < count; x++)
243 {
244 len += length[x] + 1ULL;
245 }
246
247 if (isMultiSZ)
248 len++;
249
250 if (!Stream_EnsureRemainingCapacity(s, len * sizeof(WCHAR) + sizeof(UINT32)))
251 return FALSE;
252
253 /* Write number of characters (including '\0') of all strings */
254 Stream_Write_UINT32(s, (UINT32)len); /* cchHwIds */
255 /* HardwareIds 1 */
256
257 for (size_t x = 0; x < count; x++)
258 {
259 size_t clength = length[x];
260 const char* str = strings[x];
261
262 const SSIZE_T w = Stream_Write_UTF16_String_From_UTF8(s, clength, str, clength, TRUE);
263 if ((w < 0) || ((size_t)w != clength))
264 return FALSE;
265 Stream_Write_UINT16(s, 0);
266 }
267
268 if (isMultiSZ)
269 Stream_Write_UINT16(s, 0);
270 return TRUE;
271}
272
273/* [MS-RDPEUSB] 2.2.4.2 Add Device Message (ADD_DEVICE) */
274static UINT urbdrc_send_add_device(GENERIC_CHANNEL_CALLBACK* callback, UINT32 UsbDevice,
275 UINT32 bcdUSB, const char* strInstanceId, size_t InstanceIdLen,
276 size_t nrHwIds, const char* HardwareIds[],
277 const size_t HardwareIdsLen[], size_t nrCompatIds,
278 const char* CompatibilityIds[],
279 const size_t CompatibilityIdsLen[], const char* strContainerId,
280 size_t ContainerIdLen)
281{
282 WINPR_ASSERT(callback);
283 WINPR_ASSERT(HardwareIds);
284 WINPR_ASSERT(HardwareIdsLen);
285 WINPR_ASSERT(CompatibilityIds);
286 WINPR_ASSERT(CompatibilityIdsLen);
287
288 const UINT32 InterfaceId = ((STREAM_ID_PROXY << 30) | CLIENT_DEVICE_SINK);
289 wStream* out = create_shared_message_header_with_functionid(InterfaceId, 0, ADD_DEVICE, 8);
290 if (!out)
291 return ERROR_OUTOFMEMORY;
292
293 Stream_Write_UINT32(out, 0x00000001); /* NumUsbDevice */
294 Stream_Write_UINT32(out, UsbDevice); /* UsbDevice */
295
296 if (!write_string_block(out, 1, &strInstanceId, &InstanceIdLen, FALSE))
297 goto fail;
298
299 if (!write_string_block(out, nrHwIds, HardwareIds, HardwareIdsLen, TRUE))
300 goto fail;
301
302 if (!write_string_block(out, nrCompatIds, CompatibilityIds, CompatibilityIdsLen, TRUE))
303 goto fail;
304
305 if (!write_string_block(out, 1, &strContainerId, &ContainerIdLen, FALSE))
306 goto fail;
307
308 /* USB_DEVICE_CAPABILITIES 28 bytes */
309 if (!Stream_EnsureRemainingCapacity(out, 28))
310 goto fail;
311
312 Stream_Write_UINT32(out, 0x0000001c); /* CbSize */
313 Stream_Write_UINT32(out, 2); /* UsbBusInterfaceVersion, 0 ,1 or 2 */ // TODO: Get from libusb
314 Stream_Write_UINT32(out, 0x600); /* USBDI_Version, 0x500 or 0x600 */ // TODO: Get from libusb
315 /* Supported_USB_Version, 0x110,0x110 or 0x200(usb2.0) */
316 Stream_Write_UINT32(out, bcdUSB);
317 Stream_Write_UINT32(out, 0x00000000); /* HcdCapabilities, MUST always be zero */
318
319 if (bcdUSB < 0x200)
320 Stream_Write_UINT32(out, 0x00000000); /* DeviceIsHighSpeed */
321 else
322 Stream_Write_UINT32(out, 0x00000001); /* DeviceIsHighSpeed */
323
324 Stream_Write_UINT32(out, 0x50); /* NoAckIsochWriteJitterBufferSizeInMs, >=10 or <=512 */
325 return stream_write_and_free(callback->plugin, callback->channel, out);
326
327fail:
328 Stream_Free(out, TRUE);
329 return ERROR_INTERNAL_ERROR;
330}
331
337static UINT urdbrc_send_usb_device_add(GENERIC_CHANNEL_CALLBACK* callback, IUDEVICE* pdev)
338{
339 char HardwareIds[2][DEVICE_HARDWARE_ID_SIZE] = { { 0 } };
340 const char* CHardwareIds[2] = { HardwareIds[0], HardwareIds[1] };
341 char CompatibilityIds[4][DEVICE_COMPATIBILITY_ID_SIZE] = { { 0 } };
342 const char* CCompatibilityIds[4] = { CompatibilityIds[0], CompatibilityIds[1],
343 CompatibilityIds[2], CompatibilityIds[3] };
344 char strContainerId[DEVICE_CONTAINER_STR_SIZE] = { 0 };
345 char strInstanceId[DEVICE_INSTANCE_STR_SIZE] = { 0 };
346 size_t CompatibilityIdLen[4] = { 0 };
347 size_t HardwareIdsLen[2] = { 0 };
348 const size_t nrHwIds = ARRAYSIZE(HardwareIds);
349 size_t nrCompatIds = 3;
350
351 /* USB kernel driver detach!! */
352 pdev->detach_kernel_driver(pdev);
353 {
354 const UINT16 idVendor = (UINT16)pdev->query_device_descriptor(pdev, ID_VENDOR);
355 const UINT16 idProduct = (UINT16)pdev->query_device_descriptor(pdev, ID_PRODUCT);
356 const UINT16 bcdDevice = (UINT16)pdev->query_device_descriptor(pdev, BCD_DEVICE);
357 (void)sprintf_s(HardwareIds[1], DEVICE_HARDWARE_ID_SIZE,
358 "USB\\VID_%04" PRIX16 "&PID_%04" PRIX16 "", idVendor, idProduct);
359 (void)sprintf_s(HardwareIds[0], DEVICE_HARDWARE_ID_SIZE,
360 "USB\\VID_%04" PRIX16 "&PID_%04" PRIX16 "&REV_%04" PRIX16 "", idVendor,
361 idProduct, bcdDevice);
362 }
363 {
364 const UINT8 bDeviceClass = (UINT8)pdev->query_device_descriptor(pdev, B_DEVICE_CLASS);
365 const UINT8 bDeviceSubClass = (UINT8)pdev->query_device_descriptor(pdev, B_DEVICE_SUBCLASS);
366 const UINT8 bDeviceProtocol = (UINT8)pdev->query_device_descriptor(pdev, B_DEVICE_PROTOCOL);
367
368 if (!(pdev->isCompositeDevice(pdev)))
369 {
370 (void)sprintf_s(CompatibilityIds[2], DEVICE_COMPATIBILITY_ID_SIZE,
371 "USB\\Class_%02" PRIX8 "", bDeviceClass);
372 (void)sprintf_s(CompatibilityIds[1], DEVICE_COMPATIBILITY_ID_SIZE,
373 "USB\\Class_%02" PRIX8 "&SubClass_%02" PRIX8 "", bDeviceClass,
374 bDeviceSubClass);
375 (void)sprintf_s(CompatibilityIds[0], DEVICE_COMPATIBILITY_ID_SIZE,
376 "USB\\Class_%02" PRIX8 "&SubClass_%02" PRIX8 "&Prot_%02" PRIX8 "",
377 bDeviceClass, bDeviceSubClass, bDeviceProtocol);
378 }
379 else
380 {
381 (void)sprintf_s(CompatibilityIds[3], DEVICE_COMPATIBILITY_ID_SIZE, "USB\\COMPOSITE");
382 (void)sprintf_s(CompatibilityIds[2], DEVICE_COMPATIBILITY_ID_SIZE, "USB\\DevClass_00");
383 (void)sprintf_s(CompatibilityIds[1], DEVICE_COMPATIBILITY_ID_SIZE,
384 "USB\\DevClass_00&SubClass_00");
385 (void)sprintf_s(CompatibilityIds[0], DEVICE_COMPATIBILITY_ID_SIZE,
386 "USB\\DevClass_00&SubClass_00&Prot_00");
387 nrCompatIds = 4;
388 }
389 }
390 func_instance_id_generate(pdev, strInstanceId, DEVICE_INSTANCE_STR_SIZE);
391 func_container_id_generate(pdev, strContainerId);
392
393 for (size_t x = 0; x < nrHwIds; x++)
394 {
395 HardwareIdsLen[x] = strnlen(HardwareIds[x], DEVICE_HARDWARE_ID_SIZE);
396 }
397
398 for (size_t x = 0; x < nrCompatIds; x++)
399 {
400 CompatibilityIdLen[x] = strnlen(CompatibilityIds[x], DEVICE_COMPATIBILITY_ID_SIZE);
401 }
402
403 const size_t InstanceIdLen = strnlen(strInstanceId, sizeof(strInstanceId));
404 const size_t ContainerIdLen = strnlen(strContainerId, sizeof(strContainerId));
405
406 const UINT32 UsbDevice = pdev->get_UsbDevice(pdev);
407 const UINT32 bcdUSB =
408 WINPR_ASSERTING_INT_CAST(uint32_t, pdev->query_device_descriptor(pdev, BCD_USB));
409 return urbdrc_send_add_device(callback, UsbDevice, bcdUSB, strInstanceId, InstanceIdLen,
410 nrHwIds, CHardwareIds, HardwareIdsLen, nrCompatIds,
411 CCompatibilityIds, CompatibilityIdLen, strContainerId,
412 ContainerIdLen);
413}
414
420static UINT urbdrc_exchange_capabilities(GENERIC_CHANNEL_CALLBACK* callback, wStream* data)
421{
422 UINT32 MessageId = 0;
423 UINT32 FunctionId = 0;
424 UINT32 InterfaceId = 0;
425 UINT error = CHANNEL_RC_OK;
426
427 if (!data)
428 return ERROR_INVALID_PARAMETER;
429
430 if (!Stream_CheckAndLogRequiredLength(TAG, data, 8))
431 return ERROR_INVALID_DATA;
432
433 Stream_Rewind_UINT32(data);
434 Stream_Read_UINT32(data, InterfaceId);
435 Stream_Read_UINT32(data, MessageId);
436 Stream_Read_UINT32(data, FunctionId);
437
438 switch (FunctionId)
439 {
440 case RIM_EXCHANGE_CAPABILITY_REQUEST:
441 if (InterfaceId != 0)
442 {
443 WLog_ERR(
444 TAG,
445 "[MS-RDPEUSB] 2.2.3.1 Interface Manipulation Exchange Capabilities Request "
446 "(RIM_EXCHANGE_CAPABILITY_REQUEST))::InterfaceId expected 0, got %" PRIu32,
447 InterfaceId);
448 return ERROR_INVALID_DATA;
449 }
450 error = urbdrc_process_capability_request(callback, data, MessageId);
451 break;
452
453 case RIMCALL_RELEASE:
454 break;
455
456 default:
457 error = ERROR_NOT_FOUND;
458 break;
459 }
460
461 return error;
462}
463
464static BOOL urbdrc_announce_devices(IUDEVMAN* udevman)
465{
466 UINT error = ERROR_SUCCESS;
467
468 udevman->loading_lock(udevman);
469 udevman->rewind(udevman);
470
471 while (udevman->has_next(udevman))
472 {
473 IUDEVICE* pdev = udevman->get_next(udevman);
474
475 if (!pdev->isAlreadySend(pdev))
476 {
477 const UINT32 deviceId = pdev->get_UsbDevice(pdev);
478 UINT cerror =
479 urdbrc_send_virtual_channel_add(udevman->plugin, get_channel(udevman), deviceId);
480
481 if (cerror != ERROR_SUCCESS)
482 break;
483 }
484 }
485
486 udevman->loading_unlock(udevman);
487
488 return error == ERROR_SUCCESS;
489}
490
491static UINT urbdrc_device_control_channel(GENERIC_CHANNEL_CALLBACK* callback,
492 WINPR_ATTR_UNUSED wStream* s)
493{
494 URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)callback->plugin;
495 IUDEVMAN* udevman = urbdrc->udevman;
496 IWTSVirtualChannel* channel = callback->channel;
497 IUDEVICE* pdev = NULL;
498 BOOL found = FALSE;
499 UINT error = ERROR_INTERNAL_ERROR;
500 UINT32 channelId = callback->channel_mgr->GetChannelId(channel);
501
502 switch (urbdrc->vchannel_status)
503 {
504 case INIT_CHANNEL_IN:
505 /* Control channel was established */
506 error = ERROR_SUCCESS;
507 udevman->initialize(udevman, channelId);
508
509 if (!urbdrc_announce_devices(udevman))
510 goto fail;
511
512 urbdrc->vchannel_status = INIT_CHANNEL_OUT;
513 break;
514
515 case INIT_CHANNEL_OUT:
516 /* A new device channel was created, add the channel
517 * to the device */
518 udevman->loading_lock(udevman);
519 udevman->rewind(udevman);
520
521 while (udevman->has_next(udevman))
522 {
523 pdev = udevman->get_next(udevman);
524
525 if (!pdev->isAlreadySend(pdev))
526 {
527 const UINT32 channelID = callback->channel_mgr->GetChannelId(channel);
528 found = TRUE;
529 pdev->setAlreadySend(pdev);
530 pdev->set_channelManager(pdev, callback->channel_mgr);
531 pdev->set_channelID(pdev, channelID);
532 break;
533 }
534 }
535
536 udevman->loading_unlock(udevman);
537 error = ERROR_SUCCESS;
538
539 if (found && pdev->isAlreadySend(pdev))
540 error = urdbrc_send_usb_device_add(callback, pdev);
541
542 break;
543
544 default:
545 WLog_Print(urbdrc->log, WLOG_ERROR, "vchannel_status unknown value %" PRIu32 "",
546 urbdrc->vchannel_status);
547 break;
548 }
549
550fail:
551 return error;
552}
553
559static UINT urbdrc_process_channel_notification(GENERIC_CHANNEL_CALLBACK* callback, wStream* data)
560{
561 UINT32 MessageId = 0;
562 UINT32 FunctionId = 0;
563 UINT32 InterfaceId = 0;
564 UINT error = CHANNEL_RC_OK;
565 URBDRC_PLUGIN* urbdrc = NULL;
566
567 if (!callback || !data)
568 return ERROR_INVALID_PARAMETER;
569
570 urbdrc = (URBDRC_PLUGIN*)callback->plugin;
571
572 if (!urbdrc)
573 return ERROR_INVALID_PARAMETER;
574
575 if (!Stream_CheckAndLogRequiredLength(TAG, data, 8))
576 return ERROR_INVALID_DATA;
577
578 Stream_Rewind(data, 4);
579 Stream_Read_UINT32(data, InterfaceId);
580 Stream_Read_UINT32(data, MessageId);
581 Stream_Read_UINT32(data, FunctionId);
582 WLog_Print(urbdrc->log, WLOG_TRACE, "%s [%" PRIu32 "]",
583 call_to_string(FALSE, InterfaceId, FunctionId), FunctionId);
584
585 switch (FunctionId)
586 {
587 case CHANNEL_CREATED:
588 error = urbdrc_process_channel_create(callback, data, MessageId);
589 break;
590
591 case RIMCALL_RELEASE:
592 error = urbdrc_device_control_channel(callback, data);
593 break;
594
595 default:
596 WLog_Print(urbdrc->log, WLOG_TRACE, "unknown FunctionId 0x%" PRIX32 "", FunctionId);
597 error = 1;
598 break;
599 }
600
601 return error;
602}
603
609static UINT urbdrc_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data)
610{
611 GENERIC_CHANNEL_CALLBACK* callback = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback;
612 URBDRC_PLUGIN* urbdrc = NULL;
613 IUDEVMAN* udevman = NULL;
614 UINT32 InterfaceId = 0;
615 UINT error = ERROR_INTERNAL_ERROR;
616
617 if (callback == NULL)
618 return ERROR_INVALID_PARAMETER;
619
620 if (callback->plugin == NULL)
621 return error;
622
623 urbdrc = (URBDRC_PLUGIN*)callback->plugin;
624
625 if (urbdrc->udevman == NULL)
626 return error;
627
628 udevman = urbdrc->udevman;
629
630 if (!Stream_CheckAndLogRequiredLength(TAG, data, 12))
631 return ERROR_INVALID_DATA;
632
633 urbdrc_dump_message(urbdrc->log, FALSE, FALSE, data);
634 Stream_Read_UINT32(data, InterfaceId);
635
636 /* Need to check InterfaceId and mask values */
637 switch (InterfaceId)
638 {
639 case CAPABILITIES_NEGOTIATOR | (STREAM_ID_NONE << 30):
640 error = urbdrc_exchange_capabilities(callback, data);
641 break;
642
643 case SERVER_CHANNEL_NOTIFICATION | (STREAM_ID_PROXY << 30):
644 error = urbdrc_process_channel_notification(callback, data);
645 break;
646
647 default:
648 error = urbdrc_process_udev_data_transfer(callback, urbdrc, udevman, data);
649 WLog_DBG(TAG, "urbdrc_process_udev_data_transfer returned 0x%08" PRIx32, error);
650 error = ERROR_SUCCESS; /* Ignore errors, the device may have been unplugged. */
651 break;
652 }
653
654 return error;
655}
656
662static UINT urbdrc_on_close(IWTSVirtualChannelCallback* pChannelCallback)
663{
664 GENERIC_CHANNEL_CALLBACK* callback = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback;
665 if (callback)
666 {
667 URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)callback->plugin;
668 if (urbdrc)
669 {
670 IUDEVMAN* udevman = urbdrc->udevman;
671 if (udevman && callback->channel_mgr)
672 {
673 UINT32 control = callback->channel_mgr->GetChannelId(callback->channel);
674 if (udevman->controlChannelId == control)
675 udevman->status |= URBDRC_DEVICE_CHANNEL_CLOSED;
676 else
677 { /* Need to notify the local backend the device is gone */
678 IUDEVICE* pdev = udevman->get_udevice_by_ChannelID(udevman, control);
679 if (pdev)
680 pdev->markChannelClosed(pdev);
681 }
682 }
683 }
684 }
685 free(callback);
686 return CHANNEL_RC_OK;
687}
688
694static UINT urbdrc_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
695 IWTSVirtualChannel* pChannel,
696 WINPR_ATTR_UNUSED BYTE* pData,
697 WINPR_ATTR_UNUSED BOOL* pbAccept,
698 IWTSVirtualChannelCallback** ppCallback)
699{
700 GENERIC_LISTENER_CALLBACK* listener_callback = (GENERIC_LISTENER_CALLBACK*)pListenerCallback;
701 GENERIC_CHANNEL_CALLBACK* callback = NULL;
702
703 if (!ppCallback)
704 return ERROR_INVALID_PARAMETER;
705
706 callback = (GENERIC_CHANNEL_CALLBACK*)calloc(1, sizeof(GENERIC_CHANNEL_CALLBACK));
707
708 if (!callback)
709 return ERROR_OUTOFMEMORY;
710
711 callback->iface.OnDataReceived = urbdrc_on_data_received;
712 callback->iface.OnClose = urbdrc_on_close;
713 callback->plugin = listener_callback->plugin;
714 callback->channel_mgr = listener_callback->channel_mgr;
715 callback->channel = pChannel;
716 *ppCallback = (IWTSVirtualChannelCallback*)callback;
717 return CHANNEL_RC_OK;
718}
719
725static UINT urbdrc_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
726{
727 UINT status = 0;
728 URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)pPlugin;
729 IUDEVMAN* udevman = NULL;
730 char channelName[sizeof(URBDRC_CHANNEL_NAME)] = { URBDRC_CHANNEL_NAME };
731
732 if (!urbdrc || !urbdrc->udevman)
733 return ERROR_INVALID_PARAMETER;
734
735 if (urbdrc->initialized)
736 {
737 WLog_ERR(TAG, "[%s] channel initialized twice, aborting", URBDRC_CHANNEL_NAME);
738 return ERROR_INVALID_DATA;
739 }
740 udevman = urbdrc->udevman;
741 urbdrc->listener_callback =
743
744 if (!urbdrc->listener_callback)
745 return CHANNEL_RC_NO_MEMORY;
746
747 urbdrc->listener_callback->iface.OnNewChannelConnection = urbdrc_on_new_channel_connection;
748 urbdrc->listener_callback->plugin = pPlugin;
749 urbdrc->listener_callback->channel_mgr = pChannelMgr;
750
751 /* [MS-RDPEUSB] 2.1 Transport defines the channel name in uppercase letters */
752 CharUpperA(channelName);
753 status = pChannelMgr->CreateListener(pChannelMgr, channelName, 0,
754 &urbdrc->listener_callback->iface, &urbdrc->listener);
755 if (status != CHANNEL_RC_OK)
756 return status;
757
758 status = CHANNEL_RC_OK;
759 if (udevman->listener_created_callback)
760 status = udevman->listener_created_callback(udevman);
761
762 urbdrc->initialized = status == CHANNEL_RC_OK;
763 return status;
764}
765
771static UINT urbdrc_plugin_terminated(IWTSPlugin* pPlugin)
772{
773 URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)pPlugin;
774 IUDEVMAN* udevman = NULL;
775
776 if (!urbdrc)
777 return ERROR_INVALID_DATA;
778 if (urbdrc->listener_callback)
779 {
780 IWTSVirtualChannelManager* mgr = urbdrc->listener_callback->channel_mgr;
781 if (mgr)
782 IFCALL(mgr->DestroyListener, mgr, urbdrc->listener);
783 }
784 udevman = urbdrc->udevman;
785
786 if (udevman)
787 {
788 udevman->free(udevman);
789 udevman = NULL;
790 }
791
792 free(urbdrc->subsystem);
793 free(urbdrc->listener_callback);
794 free(urbdrc);
795 return CHANNEL_RC_OK;
796}
797
798static BOOL urbdrc_register_udevman_addin(IWTSPlugin* pPlugin, IUDEVMAN* udevman)
799{
800 URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)pPlugin;
801
802 if (urbdrc->udevman)
803 {
804 WLog_Print(urbdrc->log, WLOG_ERROR, "existing device, abort.");
805 return FALSE;
806 }
807
808 DEBUG_DVC("device registered.");
809 urbdrc->udevman = udevman;
810 return TRUE;
811}
812
818static UINT urbdrc_load_udevman_addin(IWTSPlugin* pPlugin, LPCSTR name, const ADDIN_ARGV* args)
819{
820 URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)pPlugin;
821 FREERDP_URBDRC_SERVICE_ENTRY_POINTS entryPoints = { 0 };
822
823 PVIRTUALCHANNELENTRY pvce =
824 freerdp_load_channel_addin_entry(URBDRC_CHANNEL_NAME, name, NULL, 0);
825 PFREERDP_URBDRC_DEVICE_ENTRY entry = WINPR_FUNC_PTR_CAST(pvce, PFREERDP_URBDRC_DEVICE_ENTRY);
826
827 if (!entry)
828 return ERROR_INVALID_OPERATION;
829
830 entryPoints.plugin = pPlugin;
831 entryPoints.pRegisterUDEVMAN = urbdrc_register_udevman_addin;
832 entryPoints.args = args;
833
834 const UINT error = entry(&entryPoints);
835 if (error)
836 {
837 WLog_Print(urbdrc->log, WLOG_ERROR, "%s entry returns error.", name);
838 return error;
839 }
840
841 return CHANNEL_RC_OK;
842}
843
844static BOOL urbdrc_set_subsystem(URBDRC_PLUGIN* urbdrc, const char* subsystem)
845{
846 free(urbdrc->subsystem);
847 urbdrc->subsystem = _strdup(subsystem);
848 return (urbdrc->subsystem != NULL);
849}
850
856static UINT urbdrc_process_addin_args(URBDRC_PLUGIN* urbdrc, const ADDIN_ARGV* args)
857{
858 int status = 0;
859 COMMAND_LINE_ARGUMENT_A urbdrc_args[] = {
860 { "dbg", COMMAND_LINE_VALUE_FLAG, "", NULL, BoolValueFalse, -1, NULL, "debug" },
861 { "sys", COMMAND_LINE_VALUE_REQUIRED, "<subsystem>", NULL, NULL, -1, NULL, "subsystem" },
862 { "dev", COMMAND_LINE_VALUE_REQUIRED, "<device list>", NULL, NULL, -1, NULL, "devices" },
863 { "encode", COMMAND_LINE_VALUE_FLAG, "", NULL, NULL, -1, NULL, "encode" },
864 { "quality", COMMAND_LINE_VALUE_REQUIRED, "<[0-2] -> [high-medium-low]>", NULL, NULL, -1,
865 NULL, "quality" },
866 { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
867 };
868
869 const DWORD flags =
870 COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
871 const COMMAND_LINE_ARGUMENT_A* arg = NULL;
872 status =
873 CommandLineParseArgumentsA(args->argc, args->argv, urbdrc_args, flags, urbdrc, NULL, NULL);
874
875 if (status < 0)
876 return ERROR_INVALID_DATA;
877
878 arg = urbdrc_args;
879
880 do
881 {
882 if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
883 continue;
884
885 CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "dbg")
886 {
887 WLog_SetLogLevel(urbdrc->log, WLOG_TRACE);
888 }
889 CommandLineSwitchCase(arg, "sys")
890 {
891 if (!urbdrc_set_subsystem(urbdrc, arg->Value))
892 return ERROR_OUTOFMEMORY;
893 }
894 CommandLineSwitchDefault(arg)
895 {
896 }
897 CommandLineSwitchEnd(arg)
898 } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
899
900 return CHANNEL_RC_OK;
901}
902
903BOOL add_device(IUDEVMAN* idevman, UINT32 flags, BYTE busnum, BYTE devnum, UINT16 idVendor,
904 UINT16 idProduct)
905{
906 UINT32 regflags = 0;
907
908 if (!idevman)
909 return FALSE;
910
911 URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)idevman->plugin;
912
913 if (!urbdrc || !urbdrc->listener_callback)
914 return FALSE;
915
916 UINT32 mask = (DEVICE_ADD_FLAG_VENDOR | DEVICE_ADD_FLAG_PRODUCT);
917 if ((flags & mask) == mask)
918 regflags |= UDEVMAN_FLAG_ADD_BY_VID_PID;
919 mask = (DEVICE_ADD_FLAG_BUS | DEVICE_ADD_FLAG_DEV);
920 if ((flags & mask) == mask)
921 regflags |= UDEVMAN_FLAG_ADD_BY_ADDR;
922
923 const size_t success =
924 idevman->register_udevice(idevman, busnum, devnum, idVendor, idProduct, regflags);
925
926 if ((success > 0) && (flags & DEVICE_ADD_FLAG_REGISTER))
927 {
928 if (!urbdrc_announce_devices(idevman))
929 return FALSE;
930 }
931
932 return TRUE;
933}
934
935BOOL del_device(IUDEVMAN* idevman, UINT32 flags, BYTE busnum, BYTE devnum, UINT16 idVendor,
936 UINT16 idProduct)
937{
938 IUDEVICE* pdev = NULL;
939 URBDRC_PLUGIN* urbdrc = NULL;
940
941 if (!idevman)
942 return FALSE;
943
944 urbdrc = (URBDRC_PLUGIN*)idevman->plugin;
945
946 if (!urbdrc || !urbdrc->listener_callback)
947 return FALSE;
948
949 idevman->loading_lock(idevman);
950 idevman->rewind(idevman);
951
952 while (idevman->has_next(idevman))
953 {
954 BOOL match = TRUE;
955 IUDEVICE* dev = idevman->get_next(idevman);
956
957 if ((flags & (DEVICE_ADD_FLAG_BUS | DEVICE_ADD_FLAG_DEV | DEVICE_ADD_FLAG_VENDOR |
958 DEVICE_ADD_FLAG_PRODUCT)) == 0)
959 match = FALSE;
960 if (flags & DEVICE_ADD_FLAG_BUS)
961 {
962 if (dev->get_bus_number(dev) != busnum)
963 match = FALSE;
964 }
965 if (flags & DEVICE_ADD_FLAG_DEV)
966 {
967 if (dev->get_dev_number(dev) != devnum)
968 match = FALSE;
969 }
970 if (flags & DEVICE_ADD_FLAG_VENDOR)
971 {
972 int vid = dev->query_device_descriptor(dev, ID_VENDOR);
973 if (vid != idVendor)
974 match = FALSE;
975 }
976 if (flags & DEVICE_ADD_FLAG_PRODUCT)
977 {
978 int pid = dev->query_device_descriptor(dev, ID_PRODUCT);
979 if (pid != idProduct)
980 match = FALSE;
981 }
982
983 if (match)
984 {
985 pdev = dev;
986 break;
987 }
988 }
989
990 if (pdev)
991 pdev->setChannelClosed(pdev);
992
993 idevman->loading_unlock(idevman);
994 return TRUE;
995}
996
1002FREERDP_ENTRY_POINT(UINT VCAPITYPE urbdrc_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints))
1003{
1004 UINT status = 0;
1005 const ADDIN_ARGV* args = NULL;
1006 URBDRC_PLUGIN* urbdrc = NULL;
1007 urbdrc = (URBDRC_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, URBDRC_CHANNEL_NAME);
1008 args = pEntryPoints->GetPluginData(pEntryPoints);
1009
1010 if (urbdrc == NULL)
1011 {
1012 urbdrc = (URBDRC_PLUGIN*)calloc(1, sizeof(URBDRC_PLUGIN));
1013
1014 if (!urbdrc)
1015 return CHANNEL_RC_NO_MEMORY;
1016
1017 urbdrc->iface.Initialize = urbdrc_plugin_initialize;
1018 urbdrc->iface.Terminated = urbdrc_plugin_terminated;
1019 urbdrc->vchannel_status = INIT_CHANNEL_IN;
1020 status = pEntryPoints->RegisterPlugin(pEntryPoints, URBDRC_CHANNEL_NAME, &urbdrc->iface);
1021
1022 /* After we register the plugin free will be taken care of by dynamic channel */
1023 if (status != CHANNEL_RC_OK)
1024 {
1025 free(urbdrc);
1026 goto fail;
1027 }
1028
1029 urbdrc->log = WLog_Get(TAG);
1030
1031 if (!urbdrc->log)
1032 goto fail;
1033 }
1034
1035 status = urbdrc_process_addin_args(urbdrc, args);
1036
1037 if (status != CHANNEL_RC_OK)
1038 goto fail;
1039
1040 if (!urbdrc->subsystem && !urbdrc_set_subsystem(urbdrc, "libusb"))
1041 goto fail;
1042
1043 return urbdrc_load_udevman_addin(&urbdrc->iface, urbdrc->subsystem, args);
1044fail:
1045 return status;
1046}
1047
1048UINT stream_write_and_free(IWTSPlugin* plugin, IWTSVirtualChannel* channel, wStream* out)
1049{
1050 URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)plugin;
1051
1052 if (!out)
1053 return ERROR_INVALID_PARAMETER;
1054
1055 if (!channel || !out || !urbdrc)
1056 {
1057 Stream_Free(out, TRUE);
1058 return ERROR_INVALID_PARAMETER;
1059 }
1060
1061 if (!channel->Write)
1062 {
1063 Stream_Free(out, TRUE);
1064 return ERROR_INTERNAL_ERROR;
1065 }
1066
1067 urbdrc_dump_message(urbdrc->log, TRUE, TRUE, out);
1068 const size_t len = Stream_GetPosition(out);
1069 UINT rc = ERROR_INTERNAL_ERROR;
1070 if (len <= UINT32_MAX)
1071 rc = channel->Write(channel, (UINT32)len, Stream_Buffer(out), NULL);
1072 Stream_Free(out, TRUE);
1073 return rc;
1074}
Definition urbdrc_main.h:73