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