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
46/* Must be called with loading_lock held.
47 *
48 * Do not look the control channel up with FindChannelById here: that takes the lock of the dynamic
49 * channel table while loading_lock is held, and drdynvc closes channels (urbdrc_on_close, which
50 * takes loading_lock) with the table lock held. A hotplug event during a disconnect then deadlocks
51 * the libusb event thread against the drdynvc thread and the client never exits. */
52WINPR_ATTR_NODISCARD
53static IWTSVirtualChannel* get_channel(IUDEVMAN* idevman)
54{
55 if (!idevman)
56 return nullptr;
57
58 return idevman->controlChannel;
59}
60
61static int func_container_id_generate(IUDEVICE* pdev, char* strContainerId)
62{
63 const char* p = nullptr;
64 UINT8 containerId[17] = WINPR_C_ARRAY_INIT;
65 UINT16 idVendor = 0;
66 UINT16 idProduct = 0;
67 idVendor = (UINT16)pdev->query_device_descriptor(pdev, ID_VENDOR);
68 idProduct = (UINT16)pdev->query_device_descriptor(pdev, ID_PRODUCT);
69 const char* path = pdev->getPath(pdev);
70
71 const size_t plen = strlen(path);
72 if (plen > 8)
73 p = &path[plen - 8];
74 else
75 p = path;
76
77 (void)sprintf_s((char*)containerId, sizeof(containerId), "%04" PRIX16 "%04" PRIX16 "%s",
78 idVendor, idProduct, p);
79 /* format */
80 (void)sprintf_s(strContainerId, DEVICE_CONTAINER_STR_SIZE,
81 "{%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "-%02" PRIx8 "%02" PRIx8
82 "-%02" PRIx8 "%02" PRIx8 "-%02" PRIx8 "%02" PRIx8 "-%02" PRIx8 "%02" PRIx8
83 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "}",
84 containerId[0], containerId[1], containerId[2], containerId[3], containerId[4],
85 containerId[5], containerId[6], containerId[7], containerId[8], containerId[9],
86 containerId[10], containerId[11], containerId[12], containerId[13],
87 containerId[14], containerId[15]);
88 return 0;
89}
90
91static int func_instance_id_generate(IUDEVICE* pdev, char* strInstanceId, size_t len)
92{
93 char instanceId[17] = WINPR_C_ARRAY_INIT;
94 (void)sprintf_s(instanceId, sizeof(instanceId), "\\%s", pdev->getPath(pdev));
95 /* format */
96 (void)sprintf_s(strInstanceId, len,
97 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "-%02" PRIx8 "%02" PRIx8
98 "-%02" PRIx8 "%02" PRIx8 "-%02" PRIx8 "%02" PRIx8 "-%02" PRIx8 "%02" PRIx8
99 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "",
100 instanceId[0], instanceId[1], instanceId[2], instanceId[3], instanceId[4],
101 instanceId[5], instanceId[6], instanceId[7], instanceId[8], instanceId[9],
102 instanceId[10], instanceId[11], instanceId[12], instanceId[13], instanceId[14],
103 instanceId[15]);
104 return 0;
105}
106
107/* [MS-RDPEUSB] 2.2.3.2 Interface Manipulation Exchange Capabilities Response
108 * (RIM_EXCHANGE_CAPABILITY_RESPONSE) */
109static UINT urbdrc_send_capability_response(GENERIC_CHANNEL_CALLBACK* callback, UINT32 MessageId,
110 UINT32 Version)
111{
112 const UINT32 InterfaceId = ((STREAM_ID_NONE << 30) | CAPABILITIES_NEGOTIATOR);
113 wStream* out = create_shared_message_header_with_functionid(InterfaceId, MessageId, Version, 4);
114
115 if (!out)
116 return ERROR_OUTOFMEMORY;
117
118 Stream_Write_UINT32(out, 0x00000000); /* HRESULT */
119 return stream_write_and_free(callback->plugin, callback->channel, out);
120}
121
127static UINT urbdrc_process_capability_request(GENERIC_CHANNEL_CALLBACK* callback, wStream* s,
128 UINT32 MessageId)
129{
130 WINPR_ASSERT(callback);
131 URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)callback->plugin;
132 WINPR_ASSERT(urbdrc);
133
134 if (!callback || !s)
135 return ERROR_INVALID_PARAMETER;
136
137 if (!Stream_CheckAndLogRequiredLengthWLog(urbdrc->log, s, 4))
138 return ERROR_INVALID_DATA;
139
140 UINT32 Version = Stream_Get_UINT32(s);
141
142 if (Version > RIM_CAPABILITY_VERSION_01)
143 {
144 WLog_Print(urbdrc->log, WLOG_WARN, "Unknown capability version %" PRIu32 ", expected %d",
145 Version, RIM_CAPABILITY_VERSION_01);
146 Version = RIM_CAPABILITY_VERSION_01;
147 }
148
149 return urbdrc_send_capability_response(callback, MessageId, Version);
150}
151
152/* [MS-RDPEUSB] 2.2.5.1 Channel Created Message (CHANNEL_CREATED) */
153static UINT urbdrc_send_channel_created(GENERIC_CHANNEL_CALLBACK* callback, UINT32 MessageId,
154 UINT32 MajorVersion, UINT32 MinorVersion,
155 UINT32 Capabilities)
156{
157 WINPR_ASSERT(callback);
158
159 const UINT32 InterfaceId = ((STREAM_ID_PROXY << 30) | CLIENT_CHANNEL_NOTIFICATION);
160 wStream* out =
161 create_shared_message_header_with_functionid(InterfaceId, MessageId, CHANNEL_CREATED, 12);
162
163 if (!out)
164 return ERROR_OUTOFMEMORY;
165
166 Stream_Write_UINT32(out, MajorVersion);
167 Stream_Write_UINT32(out, MinorVersion);
168 Stream_Write_UINT32(out, Capabilities); /* capabilities version */
169 return stream_write_and_free(callback->plugin, callback->channel, out);
170}
171
177static UINT urbdrc_process_channel_create(GENERIC_CHANNEL_CALLBACK* callback, wStream* s,
178 UINT32 MessageId)
179{
180 UINT32 MajorVersion = 0;
181 UINT32 MinorVersion = 0;
182 UINT32 Capabilities = 0;
183 URBDRC_PLUGIN* urbdrc = nullptr;
184
185 if (!callback || !s || !callback->plugin)
186 return ERROR_INVALID_PARAMETER;
187
188 urbdrc = (URBDRC_PLUGIN*)callback->plugin;
189
190 if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
191 return ERROR_INVALID_DATA;
192
193 Stream_Read_UINT32(s, MajorVersion);
194 Stream_Read_UINT32(s, MinorVersion);
195 Stream_Read_UINT32(s, Capabilities);
196
197 /* Version check, we only support version 1.0 */
198 if ((MajorVersion != 1) || (MinorVersion != 0))
199 {
200 WLog_Print(urbdrc->log, WLOG_WARN,
201 "server supports USB channel version %" PRIu32 ".%" PRIu32, MajorVersion,
202 MinorVersion);
203 WLog_Print(urbdrc->log, WLOG_WARN, "we only support channel version 1.0");
204 MajorVersion = 1;
205 MinorVersion = 0;
206 }
207 if (Capabilities != 0)
208 {
209 WLog_Print(urbdrc->log, WLOG_WARN,
210 "[MS-RDPEUSB] 2.2.5.1 Channel Created Message (CHANNEL_CREATED) states "
211 "Capabilities must be 0, got %" PRIu32,
212 Capabilities);
213 Capabilities = 0;
214 }
215
216 return urbdrc_send_channel_created(callback, MessageId, MajorVersion, MinorVersion,
217 Capabilities);
218}
219
220static UINT urdbrc_send_virtual_channel_add(IWTSPlugin* plugin, IWTSVirtualChannel* channel,
221 UINT32 MessageId)
222{
223 const UINT32 InterfaceId = ((STREAM_ID_PROXY << 30) | CLIENT_DEVICE_SINK);
224 wStream* out = create_shared_message_header_with_functionid(InterfaceId, MessageId,
225 ADD_VIRTUAL_CHANNEL, 0);
226
227 if (!out)
228 return ERROR_OUTOFMEMORY;
229
230 return stream_write_and_free(plugin, channel, out);
231}
232
233static BOOL write_string_block(wStream* s, size_t count, const char** strings, const size_t* length,
234 BOOL isMultiSZ)
235{
236 size_t len = 0;
237 for (size_t x = 0; x < count; x++)
238 {
239 const SSIZE_T wlen = ConvertUtf8NToWChar(strings[x], length[x], nullptr, 0);
240 if (wlen < 0)
241 return FALSE;
242 len += WINPR_ASSERTING_INT_CAST(size_t, wlen) + 1ULL;
243 }
244
245 if (isMultiSZ)
246 len++;
247
248 if (!Stream_EnsureRemainingCapacity(s, len * sizeof(WCHAR) + sizeof(UINT32)))
249 return FALSE;
250
251 /* Write number of characters (including '\0') of all strings */
252 Stream_Write_UINT32(s, WINPR_ASSERTING_INT_CAST(UINT32, len)); /* cchHwIds */
253 /* HardwareIds 1 */
254
255 for (size_t x = 0; x < count; x++)
256 {
257 size_t clength = length[x];
258 const char* str = strings[x];
259 const SSIZE_T wlen = ConvertUtf8NToWChar(str, clength, nullptr, 0);
260 if (wlen < 0)
261 return FALSE;
262 const size_t wlength = WINPR_ASSERTING_INT_CAST(size_t, wlen);
263
264 const SSIZE_T w = Stream_Write_UTF16_String_From_UTF8(s, wlength, str, clength, TRUE);
265 if ((w < 0) || ((size_t)w != wlength))
266 return FALSE;
267 Stream_Write_UINT16(s, 0);
268 }
269
270 if (isMultiSZ)
271 Stream_Write_UINT16(s, 0);
272 return TRUE;
273}
274
275/* [MS-RDPEUSB] 2.2.4.2 Add Device Message (ADD_DEVICE) */
276static UINT urbdrc_send_add_device(GENERIC_CHANNEL_CALLBACK* callback, UINT32 UsbDevice,
277 UINT32 bcdUSB, enum device_speed deviceSpeed,
278 const char* strInstanceId, size_t InstanceIdLen, size_t nrHwIds,
279 const char* HardwareIds[], const size_t HardwareIdsLen[],
280 size_t nrCompatIds, const char* CompatibilityIds[],
281 const size_t CompatibilityIdsLen[], const char* strContainerId,
282 size_t ContainerIdLen)
283{
284 WINPR_ASSERT(callback);
285 WINPR_ASSERT(HardwareIds);
286 WINPR_ASSERT(HardwareIdsLen);
287 WINPR_ASSERT(CompatibilityIds);
288 WINPR_ASSERT(CompatibilityIdsLen);
289
290 const UINT32 InterfaceId = ((STREAM_ID_PROXY << 30) | CLIENT_DEVICE_SINK);
291 wStream* out = create_shared_message_header_with_functionid(InterfaceId, 0, ADD_DEVICE, 8);
292 if (!out)
293 return ERROR_OUTOFMEMORY;
294
295 Stream_Write_UINT32(out, 0x00000001); /* NumUsbDevice */
296 Stream_Write_UINT32(out, UsbDevice); /* UsbDevice */
297
298 if (!write_string_block(out, 1, &strInstanceId, &InstanceIdLen, FALSE))
299 goto fail;
300
301 if (!write_string_block(out, nrHwIds, HardwareIds, HardwareIdsLen, TRUE))
302 goto fail;
303
304 if (!write_string_block(out, nrCompatIds, CompatibilityIds, CompatibilityIdsLen, TRUE))
305 goto fail;
306
307 if (!write_string_block(out, 1, &strContainerId, &ContainerIdLen, FALSE))
308 goto fail;
309
310 /* USB_DEVICE_CAPABILITIES 28 bytes */
311 if (!Stream_EnsureRemainingCapacity(out, 28))
312 goto fail;
313
314 Stream_Write_UINT32(out, 0x0000001c); /* CbSize */
315 Stream_Write_UINT32(out, 2); /* UsbBusInterfaceVersion, 0 ,1 or 2 */ // TODO: Get from libusb
316 Stream_Write_UINT32(out, 0x600); /* USBDI_Version, 0x500 or 0x600 */ // TODO: Get from libusb
317 /* Supported_USB_Version, 0x110,0x110 or 0x200(usb2.0) */
318 Stream_Write_UINT32(out, bcdUSB);
319 Stream_Write_UINT32(out, 0x00000000); /* HcdCapabilities, MUST always be zero */
320
321 /* [MS-RDPEUSB] 2.2.11 distinguishes only full from high speed, so every
322 * faster device is reported as high speed. */
323 UINT32 DeviceIsHighSpeed = 0;
324 switch (deviceSpeed)
325 {
326 case DEVICE_SPEED_LOW:
327 case DEVICE_SPEED_FULL:
328 DeviceIsHighSpeed = 0x00000000;
329 break;
330
331 case DEVICE_SPEED_UNKNOWN:
332 /* The negotiated speed is unavailable or not recognised, so fall
333 * back to the USB version the device claims. It only bounds the
334 * speed, which is why it is not used when the bus can be asked. */
335 DeviceIsHighSpeed = (bcdUSB < 0x200) ? 0x00000000 : 0x00000001;
336 break;
337
338 default:
339 DeviceIsHighSpeed = 0x00000001;
340 break;
341 }
342
343 Stream_Write_UINT32(out, DeviceIsHighSpeed); /* DeviceIsHighSpeed */
344
345 Stream_Write_UINT32(out, 0x50); /* NoAckIsochWriteJitterBufferSizeInMs, >=10 or <=512 */
346 return stream_write_and_free(callback->plugin, callback->channel, out);
347
348fail:
349 Stream_Free(out, TRUE);
350 return ERROR_INTERNAL_ERROR;
351}
352
358static UINT urdbrc_send_usb_device_add(GENERIC_CHANNEL_CALLBACK* callback, IUDEVICE* pdev)
359{
360 char HardwareIds[2][DEVICE_HARDWARE_ID_SIZE] = { WINPR_C_ARRAY_INIT };
361 const char* CHardwareIds[2] = { HardwareIds[0], HardwareIds[1] };
362 char CompatibilityIds[4][DEVICE_COMPATIBILITY_ID_SIZE] = { WINPR_C_ARRAY_INIT };
363 const char* CCompatibilityIds[4] = { CompatibilityIds[0], CompatibilityIds[1],
364 CompatibilityIds[2], CompatibilityIds[3] };
365 char strContainerId[DEVICE_CONTAINER_STR_SIZE] = WINPR_C_ARRAY_INIT;
366 char strInstanceId[DEVICE_INSTANCE_STR_SIZE] = WINPR_C_ARRAY_INIT;
367 size_t CompatibilityIdLen[4] = WINPR_C_ARRAY_INIT;
368 size_t HardwareIdsLen[2] = WINPR_C_ARRAY_INIT;
369 const size_t nrHwIds = ARRAYSIZE(HardwareIds);
370 size_t nrCompatIds = 3;
371
372 /* USB kernel driver detach!! */
373 if (!pdev->detach_kernel_driver(pdev))
374 return ERROR_INTERNAL_ERROR;
375
376 {
377 const UINT16 idVendor = (UINT16)pdev->query_device_descriptor(pdev, ID_VENDOR);
378 const UINT16 idProduct = (UINT16)pdev->query_device_descriptor(pdev, ID_PRODUCT);
379 const UINT16 bcdDevice = (UINT16)pdev->query_device_descriptor(pdev, BCD_DEVICE);
380 (void)sprintf_s(HardwareIds[1], DEVICE_HARDWARE_ID_SIZE,
381 "USB\\VID_%04" PRIX16 "&PID_%04" PRIX16 "", idVendor, idProduct);
382 (void)sprintf_s(HardwareIds[0], DEVICE_HARDWARE_ID_SIZE,
383 "USB\\VID_%04" PRIX16 "&PID_%04" PRIX16 "&REV_%04" PRIX16 "", idVendor,
384 idProduct, bcdDevice);
385 }
386 {
387 const UINT8 bDeviceClass = (UINT8)pdev->query_device_descriptor(pdev, B_DEVICE_CLASS);
388 const UINT8 bDeviceSubClass = (UINT8)pdev->query_device_descriptor(pdev, B_DEVICE_SUBCLASS);
389 const UINT8 bDeviceProtocol = (UINT8)pdev->query_device_descriptor(pdev, B_DEVICE_PROTOCOL);
390
391 if (!(pdev->isCompositeDevice(pdev)))
392 {
393 (void)sprintf_s(CompatibilityIds[2], DEVICE_COMPATIBILITY_ID_SIZE,
394 "USB\\Class_%02" PRIX8 "", bDeviceClass);
395 (void)sprintf_s(CompatibilityIds[1], DEVICE_COMPATIBILITY_ID_SIZE,
396 "USB\\Class_%02" PRIX8 "&SubClass_%02" PRIX8 "", bDeviceClass,
397 bDeviceSubClass);
398 (void)sprintf_s(CompatibilityIds[0], DEVICE_COMPATIBILITY_ID_SIZE,
399 "USB\\Class_%02" PRIX8 "&SubClass_%02" PRIX8 "&Prot_%02" PRIX8 "",
400 bDeviceClass, bDeviceSubClass, bDeviceProtocol);
401 }
402 else
403 {
404 (void)sprintf_s(CompatibilityIds[3], DEVICE_COMPATIBILITY_ID_SIZE, "USB\\COMPOSITE");
405 (void)sprintf_s(CompatibilityIds[2], DEVICE_COMPATIBILITY_ID_SIZE, "USB\\DevClass_00");
406 (void)sprintf_s(CompatibilityIds[1], DEVICE_COMPATIBILITY_ID_SIZE,
407 "USB\\DevClass_00&SubClass_00");
408 (void)sprintf_s(CompatibilityIds[0], DEVICE_COMPATIBILITY_ID_SIZE,
409 "USB\\DevClass_00&SubClass_00&Prot_00");
410 nrCompatIds = 4;
411 }
412 }
413 func_instance_id_generate(pdev, strInstanceId, DEVICE_INSTANCE_STR_SIZE);
414 func_container_id_generate(pdev, strContainerId);
415
416 for (size_t x = 0; x < nrHwIds; x++)
417 {
418 HardwareIdsLen[x] = strnlen(HardwareIds[x], DEVICE_HARDWARE_ID_SIZE);
419 }
420
421 for (size_t x = 0; x < nrCompatIds; x++)
422 {
423 CompatibilityIdLen[x] = strnlen(CompatibilityIds[x], DEVICE_COMPATIBILITY_ID_SIZE);
424 }
425
426 const size_t InstanceIdLen = strnlen(strInstanceId, sizeof(strInstanceId));
427 const size_t ContainerIdLen = strnlen(strContainerId, sizeof(strContainerId));
428
429 const UINT32 UsbDevice = pdev->get_UsbDevice(pdev);
430 const UINT32 bcdUSB =
431 WINPR_ASSERTING_INT_CAST(uint32_t, pdev->query_device_descriptor(pdev, BCD_USB));
432 const enum device_speed deviceSpeed = pdev->query_device_speed(pdev);
433 return urbdrc_send_add_device(callback, UsbDevice, bcdUSB, deviceSpeed, strInstanceId,
434 InstanceIdLen, nrHwIds, CHardwareIds, HardwareIdsLen, nrCompatIds,
435 CCompatibilityIds, CompatibilityIdLen, strContainerId,
436 ContainerIdLen);
437}
438
444static UINT urbdrc_exchange_capabilities(GENERIC_CHANNEL_CALLBACK* callback, wStream* data)
445{
446 UINT32 MessageId = 0;
447 UINT32 FunctionId = 0;
448 UINT32 InterfaceId = 0;
449 UINT error = CHANNEL_RC_OK;
450
451 if (!data)
452 return ERROR_INVALID_PARAMETER;
453
454 if (!Stream_CheckAndLogRequiredLength(TAG, data, 8))
455 return ERROR_INVALID_DATA;
456
457 Stream_Rewind_UINT32(data);
458 Stream_Read_UINT32(data, InterfaceId);
459 Stream_Read_UINT32(data, MessageId);
460 Stream_Read_UINT32(data, FunctionId);
461
462 switch (FunctionId)
463 {
464 case RIM_EXCHANGE_CAPABILITY_REQUEST:
465 if (InterfaceId != 0)
466 {
467 WLog_ERR(
468 TAG,
469 "[MS-RDPEUSB] 2.2.3.1 Interface Manipulation Exchange Capabilities Request "
470 "(RIM_EXCHANGE_CAPABILITY_REQUEST))::InterfaceId expected 0, got %" PRIu32,
471 InterfaceId);
472 return ERROR_INVALID_DATA;
473 }
474 error = urbdrc_process_capability_request(callback, data, MessageId);
475 break;
476
477 case RIMCALL_RELEASE:
478 break;
479
480 default:
481 error = ERROR_NOT_FOUND;
482 break;
483 }
484
485 return error;
486}
487
488static BOOL urbdrc_announce_devices(IUDEVMAN* udevman)
489{
490 UINT error = ERROR_SUCCESS;
491
492 udevman->loading_lock(udevman);
493 udevman->rewind(udevman);
494
495 while (udevman->has_next(udevman))
496 {
497 IUDEVICE* pdev = udevman->get_next(udevman);
498
499 if (!pdev->isAlreadySend(pdev))
500 {
501 UINT cerror = ERROR_SUCCESS;
502 const UINT32 deviceId = pdev->get_UsbDevice(pdev);
503 udevman->loading_lock(udevman);
504 if (!pdev->isChannelClosed(pdev))
505 {
506 IWTSVirtualChannel* channel = get_channel(udevman);
507 if (channel)
508 cerror = urdbrc_send_virtual_channel_add(udevman->plugin, channel, deviceId);
509 }
510 udevman->loading_unlock(udevman);
511 if (cerror != ERROR_SUCCESS)
512 break;
513 }
514 }
515
516 udevman->loading_unlock(udevman);
517
518 return error == ERROR_SUCCESS;
519}
520
521static UINT urbdrc_device_control_channel(GENERIC_CHANNEL_CALLBACK* callback,
522 WINPR_ATTR_UNUSED wStream* s)
523{
524 URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)callback->plugin;
525 IUDEVMAN* udevman = urbdrc->udevman;
526 IWTSVirtualChannel* channel = callback->channel;
527 IUDEVICE* pdev = nullptr;
528 BOOL found = FALSE;
529 UINT error = ERROR_INTERNAL_ERROR;
530 UINT32 channelId = callback->channel_mgr->GetChannelId(channel);
531
532 switch (urbdrc->vchannel_status)
533 {
534 case INIT_CHANNEL_IN:
535 /* Control channel was established */
536 error = ERROR_SUCCESS;
537 if (!udevman->initialize(udevman, channelId))
538 goto fail;
539
540 udevman->loading_lock(udevman);
541 udevman->controlChannel = channel;
542 udevman->loading_unlock(udevman);
543
544 if (!urbdrc_announce_devices(udevman))
545 goto fail;
546
547 urbdrc->vchannel_status = INIT_CHANNEL_OUT;
548 break;
549
550 case INIT_CHANNEL_OUT:
551 /* A new device channel was created, add the channel
552 * to the device */
553 udevman->loading_lock(udevman);
554 udevman->rewind(udevman);
555
556 while (udevman->has_next(udevman))
557 {
558 pdev = udevman->get_next(udevman);
559
560 if (!pdev->isAlreadySend(pdev))
561 {
562 const UINT32 channelID = callback->channel_mgr->GetChannelId(channel);
563 found = TRUE;
564 pdev->setAlreadySend(pdev);
565 pdev->set_channelManager(pdev, callback->channel_mgr);
566 pdev->set_channelID(pdev, channelID);
567 pdev->set_channelCallback(pdev, callback);
568 break;
569 }
570 }
571
572 udevman->loading_unlock(udevman);
573 error = ERROR_SUCCESS;
574
575 if (found && pdev->isAlreadySend(pdev))
576 error = urdbrc_send_usb_device_add(callback, pdev);
577
578 break;
579
580 default:
581 WLog_Print(urbdrc->log, WLOG_ERROR, "vchannel_status unknown value %" PRIu32 "",
582 urbdrc->vchannel_status);
583 break;
584 }
585
586fail:
587 return error;
588}
589
595static UINT urbdrc_process_channel_notification(GENERIC_CHANNEL_CALLBACK* callback, wStream* data)
596{
597 UINT32 MessageId = 0;
598 UINT32 FunctionId = 0;
599 UINT32 InterfaceId = 0;
600 UINT error = CHANNEL_RC_OK;
601 URBDRC_PLUGIN* urbdrc = nullptr;
602
603 if (!callback || !data)
604 return ERROR_INVALID_PARAMETER;
605
606 urbdrc = (URBDRC_PLUGIN*)callback->plugin;
607
608 if (!urbdrc)
609 return ERROR_INVALID_PARAMETER;
610
611 if (!Stream_CheckAndLogRequiredLength(TAG, data, 8))
612 return ERROR_INVALID_DATA;
613
614 Stream_Rewind(data, 4);
615 Stream_Read_UINT32(data, InterfaceId);
616 Stream_Read_UINT32(data, MessageId);
617 Stream_Read_UINT32(data, FunctionId);
618 WLog_Print(urbdrc->log, WLOG_TRACE, "%s [%" PRIu32 "]",
619 call_to_string(FALSE, InterfaceId, FunctionId), FunctionId);
620
621 switch (FunctionId)
622 {
623 case CHANNEL_CREATED:
624 error = urbdrc_process_channel_create(callback, data, MessageId);
625 break;
626
627 case RIMCALL_RELEASE:
628 error = urbdrc_device_control_channel(callback, data);
629 break;
630
631 default:
632 WLog_Print(urbdrc->log, WLOG_TRACE, "unknown FunctionId 0x%" PRIX32 "", FunctionId);
633 error = 1;
634 break;
635 }
636
637 return error;
638}
639
645static UINT urbdrc_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data)
646{
647 GENERIC_CHANNEL_CALLBACK* callback = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback;
648 URBDRC_PLUGIN* urbdrc = nullptr;
649 IUDEVMAN* udevman = nullptr;
650 UINT32 InterfaceId = 0;
651 UINT error = ERROR_INTERNAL_ERROR;
652
653 if (callback == nullptr)
654 return ERROR_INVALID_PARAMETER;
655
656 if (callback->plugin == nullptr)
657 return error;
658
659 urbdrc = (URBDRC_PLUGIN*)callback->plugin;
660
661 if (urbdrc->udevman == nullptr)
662 return error;
663
664 udevman = urbdrc->udevman;
665
666 if (!Stream_CheckAndLogRequiredLength(TAG, data, 12))
667 return ERROR_INVALID_DATA;
668
669 urbdrc_dump_message(urbdrc->log, FALSE, FALSE, data);
670 Stream_Read_UINT32(data, InterfaceId);
671
672 /* Need to check InterfaceId and mask values */
673 switch (InterfaceId)
674 {
675 case CAPABILITIES_NEGOTIATOR | (STREAM_ID_NONE << 30):
676 error = urbdrc_exchange_capabilities(callback, data);
677 break;
678
679 case SERVER_CHANNEL_NOTIFICATION | (STREAM_ID_PROXY << 30):
680 error = urbdrc_process_channel_notification(callback, data);
681 break;
682
683 default:
684 error = urbdrc_process_udev_data_transfer(callback, urbdrc, udevman, data);
685 WLog_DBG(TAG, "urbdrc_process_udev_data_transfer returned 0x%08" PRIx32, error);
686 error = ERROR_SUCCESS; /* Ignore errors, the device may have been unplugged. */
687 break;
688 }
689
690 return error;
691}
692
693/* Must be called with loading_lock held.
694 *
695 * Pending transfers of a device keep the GENERIC_CHANNEL_CALLBACK of the channel the device is
696 * bound to. Before that callback is freed every such device has to go: markChannelClosed cancels
697 * the transfers and waits for them to complete. Do that for every device bound to the channel,
698 * not just the first one, and no matter what was closed before (the control channel may already
699 * be gone). */
700static void urbdrc_close_devices(IUDEVMAN* udevman, UINT32 channelId)
701{
702 udevman->rewind(udevman);
703
704 while (udevman->has_next(udevman))
705 {
706 IUDEVICE* pdev = udevman->get_next(udevman);
707
708 /* Need to notify the local backend the device is gone.
709 * This unregisters the device and leaves the iterator at its successor. */
710 if (pdev->isAlreadySend(pdev) && (pdev->get_channelID(pdev) == channelId))
711 pdev->markChannelClosed(pdev);
712 }
713}
714
720static UINT urbdrc_on_close(IWTSVirtualChannelCallback* pChannelCallback)
721{
722 GENERIC_CHANNEL_CALLBACK* callback = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback;
723 if (callback)
724 {
725 URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)callback->plugin;
726 if (urbdrc)
727 {
728 IUDEVMAN* udevman = urbdrc->udevman;
729 if (udevman && callback->channel_mgr)
730 {
731 udevman->loading_lock(udevman);
732 if (udevman->controlChannel == callback->channel)
733 {
734 udevman->controlChannel = nullptr;
735 udevman->status |= URBDRC_DEVICE_CHANNEL_CLOSED;
736 udevman->controlChannelId = 0;
737 }
738 urbdrc_close_devices(udevman,
739 callback->channel_mgr->GetChannelId(callback->channel));
740 udevman->loading_unlock(udevman);
741 }
742 }
743 }
744 free(callback);
745 return CHANNEL_RC_OK;
746}
747
753static UINT urbdrc_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
754 IWTSVirtualChannel* pChannel,
755 WINPR_ATTR_UNUSED BYTE* pData,
756 WINPR_ATTR_UNUSED BOOL* pbAccept,
757 IWTSVirtualChannelCallback** ppCallback)
758{
759 GENERIC_LISTENER_CALLBACK* listener_callback = (GENERIC_LISTENER_CALLBACK*)pListenerCallback;
760 GENERIC_CHANNEL_CALLBACK* callback = nullptr;
761
762 if (!ppCallback)
763 return ERROR_INVALID_PARAMETER;
764
765 callback = (GENERIC_CHANNEL_CALLBACK*)calloc(1, sizeof(GENERIC_CHANNEL_CALLBACK));
766
767 if (!callback)
768 return ERROR_OUTOFMEMORY;
769
770 callback->iface.OnDataReceived = urbdrc_on_data_received;
771 callback->iface.OnClose = urbdrc_on_close;
772 callback->plugin = listener_callback->plugin;
773 callback->channel_mgr = listener_callback->channel_mgr;
774 callback->channel = pChannel;
775 *ppCallback = (IWTSVirtualChannelCallback*)callback;
776 return CHANNEL_RC_OK;
777}
778
784static UINT urbdrc_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
785{
786 UINT status = 0;
787 URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)pPlugin;
788 IUDEVMAN* udevman = nullptr;
789 char channelName[sizeof(URBDRC_CHANNEL_NAME)] = { URBDRC_CHANNEL_NAME };
790
791 if (!urbdrc || !urbdrc->udevman)
792 return ERROR_INVALID_PARAMETER;
793
794 if (urbdrc->initialized)
795 {
796 WLog_ERR(TAG, "[%s] channel initialized twice, aborting", URBDRC_CHANNEL_NAME);
797 return ERROR_INVALID_DATA;
798 }
799 udevman = urbdrc->udevman;
800 urbdrc->listener_callback =
802
803 if (!urbdrc->listener_callback)
804 return CHANNEL_RC_NO_MEMORY;
805
806 urbdrc->listener_callback->iface.OnNewChannelConnection = urbdrc_on_new_channel_connection;
807 urbdrc->listener_callback->plugin = pPlugin;
808 urbdrc->listener_callback->channel_mgr = pChannelMgr;
809
810 /* [MS-RDPEUSB] 2.1 Transport defines the channel name in uppercase letters */
811 CharUpperA(channelName);
812 status = pChannelMgr->CreateListener(pChannelMgr, channelName, 0,
813 &urbdrc->listener_callback->iface, &urbdrc->listener);
814 if (status != CHANNEL_RC_OK)
815 return status;
816
817 status = CHANNEL_RC_OK;
818 if (udevman->listener_created_callback)
819 status = udevman->listener_created_callback(udevman);
820
821 urbdrc->initialized = status == CHANNEL_RC_OK;
822 return status;
823}
824
830static UINT urbdrc_plugin_terminated(IWTSPlugin* pPlugin)
831{
832 URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)pPlugin;
833 IUDEVMAN* udevman = nullptr;
834
835 if (!urbdrc)
836 return ERROR_INVALID_DATA;
837 if (urbdrc->listener_callback)
838 {
839 IWTSVirtualChannelManager* mgr = urbdrc->listener_callback->channel_mgr;
840 if (mgr)
841 IFCALL(mgr->DestroyListener, mgr, urbdrc->listener);
842 }
843 udevman = urbdrc->udevman;
844
845 if (udevman)
846 {
847 udevman->free(udevman);
848 udevman = nullptr;
849 }
850
851 free(urbdrc->subsystem);
852 free(urbdrc->listener_callback);
853 free(urbdrc);
854 return CHANNEL_RC_OK;
855}
856
857static BOOL urbdrc_register_udevman_addin(IWTSPlugin* pPlugin, IUDEVMAN* udevman)
858{
859 URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)pPlugin;
860
861 if (urbdrc->udevman)
862 {
863 WLog_Print(urbdrc->log, WLOG_ERROR, "existing device, abort.");
864 return FALSE;
865 }
866
867 DEBUG_DVC("device registered.");
868 urbdrc->udevman = udevman;
869 return TRUE;
870}
871
877static UINT urbdrc_load_udevman_addin(IWTSPlugin* pPlugin, LPCSTR name, const ADDIN_ARGV* args)
878{
879 URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)pPlugin;
880 FREERDP_URBDRC_SERVICE_ENTRY_POINTS entryPoints = WINPR_C_ARRAY_INIT;
881
882 PVIRTUALCHANNELENTRY pvce =
883 freerdp_load_channel_addin_entry(URBDRC_CHANNEL_NAME, name, nullptr, 0);
884 PFREERDP_URBDRC_DEVICE_ENTRY entry = WINPR_FUNC_PTR_CAST(pvce, PFREERDP_URBDRC_DEVICE_ENTRY);
885
886 if (!entry)
887 return ERROR_INVALID_OPERATION;
888
889 entryPoints.plugin = pPlugin;
890 entryPoints.pRegisterUDEVMAN = urbdrc_register_udevman_addin;
891 entryPoints.args = args;
892
893 const UINT error = entry(&entryPoints);
894 if (error)
895 {
896 WLog_Print(urbdrc->log, WLOG_ERROR, "%s entry returns error.", name);
897 return error;
898 }
899
900 return CHANNEL_RC_OK;
901}
902
903static BOOL urbdrc_set_subsystem(URBDRC_PLUGIN* urbdrc, const char* subsystem)
904{
905 free(urbdrc->subsystem);
906 urbdrc->subsystem = _strdup(subsystem);
907 return (urbdrc->subsystem != nullptr);
908}
909
915static UINT urbdrc_process_addin_args(URBDRC_PLUGIN* urbdrc, const ADDIN_ARGV* args)
916{
917 int status = 0;
918 COMMAND_LINE_ARGUMENT_A urbdrc_args[] = {
919 { "dbg", COMMAND_LINE_VALUE_FLAG, "", nullptr, BoolValueFalse, -1, nullptr, "debug" },
920 { "sys", COMMAND_LINE_VALUE_REQUIRED, "<subsystem>", nullptr, nullptr, -1, nullptr,
921 "subsystem" },
922 { "dev", COMMAND_LINE_VALUE_REQUIRED, "<device list>", nullptr, nullptr, -1, nullptr,
923 "devices" },
924 { "encode", COMMAND_LINE_VALUE_FLAG, "", nullptr, nullptr, -1, nullptr, "encode" },
925 { "quality", COMMAND_LINE_VALUE_REQUIRED, "<[0-2] -> [high-medium-low]>", nullptr, nullptr,
926 -1, nullptr, "quality" },
927 { nullptr, 0, nullptr, nullptr, nullptr, -1, nullptr, nullptr }
928 };
929
930 const DWORD flags =
931 COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
932 const COMMAND_LINE_ARGUMENT_A* arg = nullptr;
933 status = CommandLineParseArgumentsA(args->argc, args->argv, urbdrc_args, flags, urbdrc, nullptr,
934 nullptr);
935
936 if (status < 0)
937 return ERROR_INVALID_DATA;
938
939 arg = urbdrc_args;
940
941 do
942 {
943 if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
944 continue;
945
946 CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "dbg")
947 {
948 if (!WLog_SetLogLevel(urbdrc->log, WLOG_TRACE))
949 return ERROR_INTERNAL_ERROR;
950 }
951 CommandLineSwitchCase(arg, "sys")
952 {
953 if (!urbdrc_set_subsystem(urbdrc, arg->Value))
954 return ERROR_OUTOFMEMORY;
955 }
956 CommandLineSwitchDefault(arg)
957 {
958 }
959 CommandLineSwitchEnd(arg)
960 } while ((arg = CommandLineFindNextArgumentA(arg)) != nullptr);
961
962 return CHANNEL_RC_OK;
963}
964
965BOOL add_device(IUDEVMAN* idevman, UINT32 flags, BYTE busnum, BYTE devnum, UINT16 idVendor,
966 UINT16 idProduct)
967{
968 UINT32 regflags = 0;
969
970 if (!idevman)
971 return FALSE;
972
973 URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)idevman->plugin;
974
975 if (!urbdrc || !urbdrc->listener_callback)
976 return FALSE;
977
978 UINT32 mask = (DEVICE_ADD_FLAG_VENDOR | DEVICE_ADD_FLAG_PRODUCT);
979 if ((flags & mask) == mask)
980 regflags |= UDEVMAN_FLAG_ADD_BY_VID_PID;
981 mask = (DEVICE_ADD_FLAG_BUS | DEVICE_ADD_FLAG_DEV);
982 if ((flags & mask) == mask)
983 regflags |= UDEVMAN_FLAG_ADD_BY_ADDR;
984
985 const size_t success =
986 idevman->register_udevice(idevman, busnum, devnum, idVendor, idProduct, regflags);
987
988 if ((success > 0) && (flags & DEVICE_ADD_FLAG_REGISTER))
989 {
990 if (!urbdrc_announce_devices(idevman))
991 return FALSE;
992 }
993
994 return TRUE;
995}
996
997BOOL del_device(IUDEVMAN* idevman, UINT32 flags, BYTE busnum, BYTE devnum, UINT16 idVendor,
998 UINT16 idProduct)
999{
1000 IUDEVICE* pdev = nullptr;
1001 URBDRC_PLUGIN* urbdrc = nullptr;
1002
1003 if (!idevman)
1004 return FALSE;
1005
1006 urbdrc = (URBDRC_PLUGIN*)idevman->plugin;
1007
1008 if (!urbdrc || !urbdrc->listener_callback)
1009 return FALSE;
1010
1011 idevman->loading_lock(idevman);
1012 idevman->rewind(idevman);
1013
1014 while (idevman->has_next(idevman))
1015 {
1016 BOOL match = TRUE;
1017 IUDEVICE* dev = idevman->get_next(idevman);
1018
1019 if ((flags & (DEVICE_ADD_FLAG_BUS | DEVICE_ADD_FLAG_DEV | DEVICE_ADD_FLAG_VENDOR |
1020 DEVICE_ADD_FLAG_PRODUCT)) == 0)
1021 match = FALSE;
1022 if (flags & DEVICE_ADD_FLAG_BUS)
1023 {
1024 if (dev->get_bus_number(dev) != busnum)
1025 match = FALSE;
1026 }
1027 if (flags & DEVICE_ADD_FLAG_DEV)
1028 {
1029 if (dev->get_dev_number(dev) != devnum)
1030 match = FALSE;
1031 }
1032 if (flags & DEVICE_ADD_FLAG_VENDOR)
1033 {
1034 int vid = dev->query_device_descriptor(dev, ID_VENDOR);
1035 if (vid != idVendor)
1036 match = FALSE;
1037 }
1038 if (flags & DEVICE_ADD_FLAG_PRODUCT)
1039 {
1040 int pid = dev->query_device_descriptor(dev, ID_PRODUCT);
1041 if (pid != idProduct)
1042 match = FALSE;
1043 }
1044
1045 if (match)
1046 {
1047 pdev = dev;
1048 break;
1049 }
1050 }
1051
1052 if (pdev)
1053 pdev->setChannelClosed(pdev);
1054
1055 idevman->loading_unlock(idevman);
1056 return TRUE;
1057}
1058
1064FREERDP_ENTRY_POINT(UINT VCAPITYPE urbdrc_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints))
1065{
1066 UINT status = 0;
1067 const ADDIN_ARGV* args = nullptr;
1068 URBDRC_PLUGIN* urbdrc = nullptr;
1069 urbdrc = (URBDRC_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, URBDRC_CHANNEL_NAME);
1070 args = pEntryPoints->GetPluginData(pEntryPoints);
1071
1072 if (urbdrc == nullptr)
1073 {
1074 urbdrc = (URBDRC_PLUGIN*)calloc(1, sizeof(URBDRC_PLUGIN));
1075
1076 if (!urbdrc)
1077 return CHANNEL_RC_NO_MEMORY;
1078
1079 urbdrc->iface.Initialize = urbdrc_plugin_initialize;
1080 urbdrc->iface.Terminated = urbdrc_plugin_terminated;
1081 urbdrc->vchannel_status = INIT_CHANNEL_IN;
1082 status = pEntryPoints->RegisterPlugin(pEntryPoints, URBDRC_CHANNEL_NAME, &urbdrc->iface);
1083
1084 /* After we register the plugin free will be taken care of by dynamic channel */
1085 if (status != CHANNEL_RC_OK)
1086 {
1087 free(urbdrc);
1088 goto fail;
1089 }
1090
1091 urbdrc->log = WLog_Get(TAG);
1092
1093 if (!urbdrc->log)
1094 goto fail;
1095 }
1096
1097 status = urbdrc_process_addin_args(urbdrc, args);
1098
1099 if (status != CHANNEL_RC_OK)
1100 goto fail;
1101
1102 if (!urbdrc->subsystem && !urbdrc_set_subsystem(urbdrc, "libusb"))
1103 goto fail;
1104
1105 return urbdrc_load_udevman_addin(&urbdrc->iface, urbdrc->subsystem, args);
1106fail:
1107 return status;
1108}
1109
1110UINT stream_write_and_free(IWTSPlugin* plugin, IWTSVirtualChannel* channel, wStream* out)
1111{
1112 URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)plugin;
1113
1114 if (!out)
1115 return ERROR_INVALID_PARAMETER;
1116
1117 if (!channel || !out || !urbdrc)
1118 {
1119 Stream_Free(out, TRUE);
1120 return ERROR_INVALID_PARAMETER;
1121 }
1122
1123 if (!channel->Write)
1124 {
1125 Stream_Free(out, TRUE);
1126 return ERROR_INTERNAL_ERROR;
1127 }
1128
1129 urbdrc_dump_message(urbdrc->log, TRUE, TRUE, out);
1130 const size_t len = Stream_GetPosition(out);
1131 UINT rc = ERROR_INTERNAL_ERROR;
1132 if (len <= UINT32_MAX)
1133 rc = channel->Write(channel, (UINT32)len, Stream_Buffer(out), nullptr);
1134 Stream_Free(out, TRUE);
1135 return rc;
1136}
Definition urbdrc_main.h:75