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