VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/RemoteUSBBackend.cpp@ 93309

Last change on this file since 93309 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 39.4 KB
Line 
1/* $Id: RemoteUSBBackend.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * VirtualBox Remote USB backend
4 */
5
6/*
7 * Copyright (C) 2006-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#define LOG_GROUP LOG_GROUP_USB_REMOTE
19#include "LoggingNew.h"
20
21#include "ConsoleImpl.h"
22#include "ConsoleVRDPServer.h"
23#include "RemoteUSBBackend.h"
24#include "RemoteUSBDeviceImpl.h"
25
26#include <VBox/RemoteDesktop/VRDE.h>
27#include <VBox/vrdpusb.h>
28#include <VBox/err.h>
29#include <VBox/log.h>
30
31#include <VBox/vusb.h>
32
33#include <iprt/time.h>
34
35/** @page pg_vrdb_usb Async Remote USB
36 *
37 *
38 * USB backend functions are called in EMT so care must be taken to prevent
39 * delays in the functions execution.
40 *
41 * Among 11 backend functions 10 just return a success indicator.
42 *
43 * Such a function usually will check pending error code and if everything is ok,
44 * submit asynchronous RDP request and return success immediately.
45 *
46 * On actual completion of each request, the status will be saved as
47 * pending, so in case of an error all further functions will fail with
48 * device disconnected condition.
49 * @todo May be a device disconnect notification for console is required?
50 *
51 * The only remaining function that needs special processing is
52 * the reap_urb. It has a timeout parameter.
53 * Normally, the timeout is 0, as result of polling from VUSB frame timer.
54 * It is ok for async processing, the backend will periodically reap urbs from client.
55 * And already reaped URBs from client will be returned for the call.
56 * Exceptions:
57 * 1) during device initialization, when obtaining device descriptions
58 * the timeout is -1, and the request is expected to be processed synchronously.
59 * It looks like only 3 URBs with some information are retrieved that way.
60 * Probably, one can return this information in DEVICE_LIST together with the
61 * device description and when such request are submitted, just return
62 * the prefetched data.
63 * 2) during suspend timeout is non zero (10 or less milliseconds),
64 * and URB's are reaped for about 1 second. But here network delays
65 * will not affect the timeout, so it is ok.
66 *
67 *
68 * @section sub_vrdb_usb_dad Device attaching/detaching
69 *
70 * Devices are attached when client is connected or when a new device is connected to client.
71 * Devices are detached when client is disconnected (all devices) or a device is disconnected
72 * the client side.
73 *
74 * The backend polls the client for list of attached USB devices from RemoteUSBThread.
75 *
76 */
77
78/* Queued URB submitted to VRDP client. */
79typedef struct _REMOTEUSBQURB
80{
81 struct _REMOTEUSBQURB *next;
82 struct _REMOTEUSBQURB *prev;
83
84 PREMOTEUSBDEVICE pDevice; /* Device, the URB is queued for. */
85
86 uint32_t u32Handle; /* The handle of the URB. Generated by the Remote USB backend. */
87
88 void *pvData; /* Pointer to URB data allocated by VUSB. */
89 void *pvURB; /* Pointer to URB known to VUSB. */
90
91 uint32_t u32Len; /* Data length returned by the VRDP client. */
92 uint32_t u32Err; /* URB error code returned by the VRDP client. */
93
94 bool fCompleted; /* The URB has been returned back by VRDP client. */
95 bool fInput; /* This URB receives data from the client. */
96
97 uint32_t u32TransferredLen; /* For VRDE_USB_DIRECTION_OUT URBs = bytes written.
98 * For VRDE_USB_DIRECTION_IN URBs = bytes received.
99 */
100} REMOTEUSBQURB;
101
102/* Remote USB device instance data. */
103typedef struct _REMOTEUSBDEVICE
104{
105 struct _REMOTEUSBDEVICE *prev;
106 struct _REMOTEUSBDEVICE *next;
107
108 RemoteUSBBackend *pOwner;
109
110 VRDEUSBDEVID id; /* The remote identifier, assigned by client. */
111
112 uint32_t u32ClientId; /* The identifier of the remote client. */
113
114 REMOTEUSBQURB *pHeadQURBs; /* List of URBs queued for the device. */
115 REMOTEUSBQURB *pTailQURBs;
116
117 volatile uint32_t hURB; /* Source for URB's handles. */
118 bool fFailed; /* True if an operation has failed for the device. */
119 RTCRITSECT critsect; /* Protects the queued urb list. */
120 volatile bool fWokenUp; /* Flag whther the reaper was woken up. */
121} REMOTEUSBDEVICE;
122
123
124
125static void requestDevice(REMOTEUSBDEVICE *pDevice)
126{
127 int rc = RTCritSectEnter(&pDevice->critsect);
128 AssertRC(rc);
129}
130
131static void releaseDevice(REMOTEUSBDEVICE *pDevice)
132{
133 RTCritSectLeave(&pDevice->critsect);
134}
135
136static REMOTEUSBQURB *qurbAlloc(PREMOTEUSBDEVICE pDevice)
137{
138 /** @todo reuse URBs. */
139 REMOTEUSBQURB *pQURB = (REMOTEUSBQURB *)RTMemAllocZ (sizeof (REMOTEUSBQURB));
140
141 if (pQURB)
142 {
143 pQURB->pDevice = pDevice;
144 }
145
146 return pQURB;
147}
148
149static void qurbFree (REMOTEUSBQURB *pQURB)
150{
151 RTMemFree (pQURB);
152 return;
153}
154
155
156/* Called by VRDP server when the client responds to a request on USB channel. */
157DECLCALLBACK(int) USBClientResponseCallback(void *pv, uint32_t u32ClientId, uint8_t code, const void *pvRet, uint32_t cbRet)
158{
159 RT_NOREF(u32ClientId);
160 int rc = VINF_SUCCESS;
161
162 LogFlow(("USBClientResponseCallback: id = %d, pv = %p, code = %d, pvRet = %p, cbRet = %d\n",
163 u32ClientId, pv, code, pvRet, cbRet));
164
165 RemoteUSBBackend *pThis = (RemoteUSBBackend *)pv;
166
167 switch (code)
168 {
169 case VRDE_USB_REQ_DEVICE_LIST:
170 {
171 rc = pThis->saveDeviceList(pvRet, cbRet);
172 } break;
173
174 case VRDE_USB_REQ_NEGOTIATE:
175 {
176 if (pvRet && cbRet >= sizeof(VRDEUSBREQNEGOTIATERET))
177 {
178 VRDEUSBREQNEGOTIATERET *pret = (VRDEUSBREQNEGOTIATERET *)pvRet;
179
180 rc = pThis->negotiateResponse(pret, cbRet);
181 }
182 else
183 {
184 Log(("USBClientResponseCallback: WARNING: not enough data in response: pv = %p, cb = %d, expected %d.\n",
185 pvRet, cbRet, sizeof(VRDEUSBREQNEGOTIATERET)));
186
187 rc = VERR_INVALID_PARAMETER;
188 }
189 } break;
190
191 case VRDE_USB_REQ_REAP_URB:
192 {
193 rc = pThis->reapURB(pvRet, cbRet);
194
195 LogFlow(("USBClientResponseCallback: reap URB, rc = %Rrc.\n", rc));
196 } break;
197
198 case VRDE_USB_REQ_QUEUE_URB:
199 case VRDE_USB_REQ_CLOSE:
200 case VRDE_USB_REQ_CANCEL_URB:
201 {
202 /* Do nothing, actually this should not happen. */
203 Log(("USBClientResponseCallback: WARNING: response to a request %d is not expected!!!\n", code));
204 } break;
205
206 case VRDE_USB_REQ_OPEN:
207 case VRDE_USB_REQ_RESET:
208 case VRDE_USB_REQ_SET_CONFIG:
209 case VRDE_USB_REQ_CLAIM_INTERFACE:
210 case VRDE_USB_REQ_RELEASE_INTERFACE:
211 case VRDE_USB_REQ_INTERFACE_SETTING:
212 case VRDE_USB_REQ_CLEAR_HALTED_EP:
213 {
214 /*
215 * Device specific responses with status codes.
216 */
217 if (pvRet && cbRet >= sizeof(VRDEUSBREQRETHDR))
218 {
219 VRDEUSBREQRETHDR *pret = (VRDEUSBREQRETHDR *)pvRet;
220
221 if (pret->status != VRDE_USB_STATUS_SUCCESS)
222 {
223 REMOTEUSBDEVICE *pDevice = pThis->deviceFromId(pret->id);
224
225 if (!pDevice)
226 {
227 Log(("USBClientResponseCallback: WARNING: invalid device id %08X.\n", pret->id));
228 rc = VERR_INVALID_PARAMETER;
229 }
230 else
231 {
232 Log(("USBClientResponseCallback: WARNING: the operation failed, status %d\n", pret->status));
233 pDevice->fFailed = true;
234 }
235 }
236 }
237 else
238 {
239 Log(("USBClientResponseCallback: WARNING: not enough data in response: pv = %p, cb = %d, expected %d.\n",
240 pvRet, cbRet, sizeof(VRDEUSBREQRETHDR)));
241 }
242 } break;
243
244 default:
245 {
246 Log(("USBClientResponseCallback: WARNING: invalid code %d\n", code));
247 } break;
248 }
249
250 return rc;
251}
252
253/*
254 * Backend entry points.
255 */
256static DECLCALLBACK(int) iface_Open(PREMOTEUSBBACKEND pInstance, const char *pszAddress,
257 size_t cbAddress, PREMOTEUSBDEVICE *ppDevice)
258{
259 RT_NOREF(cbAddress);
260 int rc = VINF_SUCCESS;
261
262 RemoteUSBBackend *pThis = (RemoteUSBBackend *)pInstance;
263
264 REMOTEUSBDEVICE *pDevice = (REMOTEUSBDEVICE *)RTMemAllocZ(sizeof(REMOTEUSBDEVICE));
265
266 if (!pDevice)
267 {
268 rc = VERR_NO_MEMORY;
269 }
270 else
271 {
272 /* Parse given address string to find the device identifier.
273 * The format is "REMOTEUSB0xAAAABBBB&0xCCCCDDDD", where AAAABBBB is hex device identifier
274 * and CCCCDDDD is hex client id.
275 */
276 if (strncmp(pszAddress, REMOTE_USB_BACKEND_PREFIX_S, REMOTE_USB_BACKEND_PREFIX_LEN) != 0)
277 {
278 AssertFailed();
279 rc = VERR_INVALID_PARAMETER;
280 }
281 else
282 {
283 /* Initialize the device structure. */
284 pDevice->pOwner = pThis;
285 pDevice->fWokenUp = false;
286
287 rc = RTCritSectInit(&pDevice->critsect);
288 AssertRC(rc);
289
290 if (RT_SUCCESS(rc))
291 {
292 pDevice->id = RTStrToUInt32(&pszAddress[REMOTE_USB_BACKEND_PREFIX_LEN]);
293
294 size_t l = strlen(pszAddress);
295
296 if (l >= REMOTE_USB_BACKEND_PREFIX_LEN + strlen("0x12345678&0x87654321"))
297 {
298 const char *p = &pszAddress[REMOTE_USB_BACKEND_PREFIX_LEN + strlen("0x12345678")];
299 if (*p == '&')
300 {
301 pDevice->u32ClientId = RTStrToUInt32(p + 1);
302 }
303 else
304 {
305 AssertFailed();
306 rc = VERR_INVALID_PARAMETER;
307 }
308 }
309 else
310 {
311 AssertFailed();
312 rc = VERR_INVALID_PARAMETER;
313 }
314
315 if (RT_SUCCESS(rc))
316 {
317 VRDE_USB_REQ_OPEN_PARM parm;
318
319 parm.code = VRDE_USB_REQ_OPEN;
320 parm.id = pDevice->id;
321
322 pThis->VRDPServer()->SendUSBRequest(pDevice->u32ClientId, &parm, sizeof(parm));
323 }
324 }
325 }
326 }
327
328 if (RT_SUCCESS(rc))
329 {
330 *ppDevice = pDevice;
331
332 pThis->addDevice(pDevice);
333 }
334 else
335 {
336 RTMemFree(pDevice);
337 }
338
339 return rc;
340}
341
342static DECLCALLBACK(void) iface_Close(PREMOTEUSBDEVICE pDevice)
343{
344 RemoteUSBBackend *pThis = pDevice->pOwner;
345
346 VRDE_USB_REQ_CLOSE_PARM parm;
347
348 parm.code = VRDE_USB_REQ_CLOSE;
349 parm.id = pDevice->id;
350
351 pThis->VRDPServer()->SendUSBRequest(pDevice->u32ClientId, &parm, sizeof(parm));
352
353 pThis->removeDevice(pDevice);
354
355 if (RTCritSectIsInitialized(&pDevice->critsect))
356 {
357 RTCritSectDelete(&pDevice->critsect);
358 }
359
360 RTMemFree(pDevice);
361
362 return;
363}
364
365static DECLCALLBACK(int) iface_Reset(PREMOTEUSBDEVICE pDevice)
366{
367 RemoteUSBBackend *pThis = pDevice->pOwner;
368
369 if (pDevice->fFailed)
370 {
371 return VERR_VUSB_DEVICE_NOT_ATTACHED;
372 }
373
374 VRDE_USB_REQ_RESET_PARM parm;
375
376 parm.code = VRDE_USB_REQ_RESET;
377 parm.id = pDevice->id;
378
379 pThis->VRDPServer()->SendUSBRequest(pDevice->u32ClientId, &parm, sizeof(parm));
380
381 return VINF_SUCCESS;
382}
383
384static DECLCALLBACK(int) iface_SetConfig(PREMOTEUSBDEVICE pDevice, uint8_t u8Cfg)
385{
386 RemoteUSBBackend *pThis = pDevice->pOwner;
387
388 if (pDevice->fFailed)
389 {
390 return VERR_VUSB_DEVICE_NOT_ATTACHED;
391 }
392
393 VRDE_USB_REQ_SET_CONFIG_PARM parm;
394
395 parm.code = VRDE_USB_REQ_SET_CONFIG;
396 parm.id = pDevice->id;
397 parm.configuration = u8Cfg;
398
399 pThis->VRDPServer()->SendUSBRequest(pDevice->u32ClientId, &parm, sizeof(parm));
400
401 return VINF_SUCCESS;
402}
403
404static DECLCALLBACK(int) iface_ClaimInterface(PREMOTEUSBDEVICE pDevice, uint8_t u8Ifnum)
405{
406 RemoteUSBBackend *pThis = pDevice->pOwner;
407
408 if (pDevice->fFailed)
409 {
410 return VERR_VUSB_DEVICE_NOT_ATTACHED;
411 }
412
413 VRDE_USB_REQ_CLAIM_INTERFACE_PARM parm;
414
415 parm.code = VRDE_USB_REQ_CLAIM_INTERFACE;
416 parm.id = pDevice->id;
417 parm.iface = u8Ifnum;
418
419 pThis->VRDPServer()->SendUSBRequest(pDevice->u32ClientId, &parm, sizeof(parm));
420
421 return VINF_SUCCESS;
422}
423
424static DECLCALLBACK(int) iface_ReleaseInterface(PREMOTEUSBDEVICE pDevice, uint8_t u8Ifnum)
425{
426 RemoteUSBBackend *pThis = pDevice->pOwner;
427
428 if (pDevice->fFailed)
429 {
430 return VERR_VUSB_DEVICE_NOT_ATTACHED;
431 }
432
433 VRDE_USB_REQ_RELEASE_INTERFACE_PARM parm;
434
435 parm.code = VRDE_USB_REQ_RELEASE_INTERFACE;
436 parm.id = pDevice->id;
437 parm.iface = u8Ifnum;
438
439 pThis->VRDPServer()->SendUSBRequest(pDevice->u32ClientId, &parm, sizeof(parm));
440
441 return VINF_SUCCESS;
442}
443
444static DECLCALLBACK(int) iface_InterfaceSetting(PREMOTEUSBDEVICE pDevice, uint8_t u8Ifnum, uint8_t u8Setting)
445{
446 RemoteUSBBackend *pThis = pDevice->pOwner;
447
448 if (pDevice->fFailed)
449 {
450 return VERR_VUSB_DEVICE_NOT_ATTACHED;
451 }
452
453 VRDE_USB_REQ_INTERFACE_SETTING_PARM parm;
454
455 parm.code = VRDE_USB_REQ_INTERFACE_SETTING;
456 parm.id = pDevice->id;
457 parm.iface = u8Ifnum;
458 parm.setting = u8Setting;
459
460 pThis->VRDPServer()->SendUSBRequest(pDevice->u32ClientId, &parm, sizeof(parm));
461
462 return VINF_SUCCESS;
463}
464
465static DECLCALLBACK(int) iface_ClearHaltedEP(PREMOTEUSBDEVICE pDevice, uint8_t u8Ep)
466{
467 RemoteUSBBackend *pThis = pDevice->pOwner;
468
469 if (pDevice->fFailed)
470 {
471 return VERR_VUSB_DEVICE_NOT_ATTACHED;
472 }
473
474 VRDE_USB_REQ_CLEAR_HALTED_EP_PARM parm;
475
476 parm.code = VRDE_USB_REQ_CLEAR_HALTED_EP;
477 parm.id = pDevice->id;
478 parm.ep = u8Ep;
479
480 pThis->VRDPServer()->SendUSBRequest(pDevice->u32ClientId, &parm, sizeof(parm));
481
482 return VINF_SUCCESS;
483}
484
485static DECLCALLBACK(void) iface_CancelURB(PREMOTEUSBDEVICE pDevice, PREMOTEUSBQURB pRemoteURB)
486{
487 RemoteUSBBackend *pThis = pDevice->pOwner;
488
489 VRDE_USB_REQ_CANCEL_URB_PARM parm;
490
491 parm.code = VRDE_USB_REQ_CANCEL_URB;
492 parm.id = pDevice->id;
493 parm.handle = pRemoteURB->u32Handle;
494
495 pThis->VRDPServer()->SendUSBRequest(pDevice->u32ClientId, &parm, sizeof(parm));
496
497 requestDevice(pDevice);
498
499 /* Remove this urb from the queue. It is safe because if
500 * client will return the URB, it will be just ignored
501 * in reapURB.
502 */
503 if (pRemoteURB->prev)
504 {
505 pRemoteURB->prev->next = pRemoteURB->next;
506 }
507 else
508 {
509 pDevice->pHeadQURBs = pRemoteURB->next;
510 }
511
512 if (pRemoteURB->next)
513 {
514 pRemoteURB->next->prev = pRemoteURB->prev;
515 }
516 else
517 {
518 pDevice->pTailQURBs = pRemoteURB->prev;
519 }
520
521 qurbFree(pRemoteURB);
522
523 releaseDevice(pDevice);
524
525 return;
526}
527
528static DECLCALLBACK(int) iface_QueueURB(PREMOTEUSBDEVICE pDevice, uint8_t u8Type, uint8_t u8Ep, uint8_t u8Direction,
529 uint32_t u32Len, void *pvData, void *pvURB, PREMOTEUSBQURB *ppRemoteURB)
530{
531 int rc = VINF_SUCCESS;
532
533#ifdef DEBUG_sunlover
534 LogFlow(("RemoteUSBBackend::iface_QueueURB: u8Type = %d, u8Ep = %d, u8Direction = %d, data\n%.*Rhxd\n",
535 u8Type, u8Ep, u8Direction, u32Len, pvData));
536#endif /* DEBUG_sunlover */
537
538 if (pDevice->fFailed)
539 {
540 return VERR_VUSB_DEVICE_NOT_ATTACHED;
541 }
542
543 RemoteUSBBackend *pThis = pDevice->pOwner;
544
545 VRDE_USB_REQ_QUEUE_URB_PARM parm;
546 uint32_t u32Handle = 0;
547 uint32_t u32DataLen = 0;
548
549 REMOTEUSBQURB *qurb = qurbAlloc(pDevice);
550
551 if (qurb == NULL)
552 {
553 rc = VERR_NO_MEMORY;
554 goto l_leave;
555 }
556
557 /*
558 * Compute length of data which need to be transferred to the client.
559 */
560 switch(u8Direction)
561 {
562 case VUSB_DIRECTION_IN:
563 {
564 if (u8Type == VUSBXFERTYPE_MSG)
565 {
566 u32DataLen = 8; /* 8 byte header. */
567 // u32DataLen = u32Len; /// @todo do messages need all information?
568 }
569 } break;
570
571 case VUSB_DIRECTION_OUT:
572 {
573 u32DataLen = u32Len;
574 } break;
575
576 default:
577 {
578 AssertFailed();
579 rc = VERR_INVALID_PARAMETER;
580 goto l_leave;
581 }
582 }
583
584 parm.code = VRDE_USB_REQ_QUEUE_URB;
585 parm.id = pDevice->id;
586
587 u32Handle = pDevice->hURB++;
588 if (u32Handle == 0)
589 {
590 u32Handle = pDevice->hURB++;
591 }
592
593 LogFlow(("RemoteUSBBackend::iface_QueueURB: handle = %d\n", u32Handle));
594
595 parm.handle = u32Handle;
596
597 switch(u8Type)
598 {
599 case VUSBXFERTYPE_CTRL: parm.type = VRDE_USB_TRANSFER_TYPE_CTRL; break;
600 case VUSBXFERTYPE_ISOC: parm.type = VRDE_USB_TRANSFER_TYPE_ISOC; break;
601 case VUSBXFERTYPE_BULK: parm.type = VRDE_USB_TRANSFER_TYPE_BULK; break;
602 case VUSBXFERTYPE_INTR: parm.type = VRDE_USB_TRANSFER_TYPE_INTR; break;
603 case VUSBXFERTYPE_MSG: parm.type = VRDE_USB_TRANSFER_TYPE_MSG; break;
604 default: AssertFailed(); rc = VERR_INVALID_PARAMETER; goto l_leave;
605 }
606
607 parm.ep = u8Ep;
608
609 switch(u8Direction)
610 {
611 case VUSB_DIRECTION_SETUP: AssertFailed(); parm.direction = VRDE_USB_DIRECTION_SETUP; break;
612 case VUSB_DIRECTION_IN: parm.direction = VRDE_USB_DIRECTION_IN; break;
613 case VUSB_DIRECTION_OUT: parm.direction = VRDE_USB_DIRECTION_OUT; break;
614 default: AssertFailed(); rc = VERR_INVALID_PARAMETER; goto l_leave;
615 }
616
617 parm.urblen = u32Len;
618 parm.datalen = u32DataLen;
619
620 if (u32DataLen)
621 {
622 parm.data = pvData;
623 }
624
625 requestDevice (pDevice);
626
627 /* Add at tail of queued urb list. */
628 qurb->next = NULL;
629 qurb->prev = pDevice->pTailQURBs;
630 qurb->u32Err = VRDE_USB_XFER_OK;
631 qurb->u32Len = u32Len;
632 qurb->pvData = pvData;
633 qurb->pvURB = pvURB;
634 qurb->u32Handle = u32Handle;
635 qurb->fCompleted = false;
636 qurb->fInput = (u8Direction == VUSB_DIRECTION_IN);
637 qurb->u32TransferredLen = 0;
638
639 if (pDevice->pTailQURBs)
640 {
641 Assert(pDevice->pTailQURBs->next == NULL);
642 pDevice->pTailQURBs->next = qurb;
643 }
644 else
645 {
646 /* This is the first URB to be added. */
647 Assert(pDevice->pHeadQURBs == NULL);
648 pDevice->pHeadQURBs = qurb;
649 }
650
651 pDevice->pTailQURBs = qurb;
652
653 releaseDevice(pDevice);
654
655 *ppRemoteURB = qurb;
656
657 pThis->VRDPServer()->SendUSBRequest(pDevice->u32ClientId, &parm, sizeof(parm));
658
659l_leave:
660 if (RT_FAILURE(rc))
661 {
662 qurbFree(qurb);
663 }
664
665 return rc;
666}
667
668/* The function checks the URB queue for completed URBs. Also if the client
669 * has requested URB polling, the function will send URB poll requests.
670 */
671static DECLCALLBACK(int) iface_ReapURB(PREMOTEUSBDEVICE pDevice, uint32_t u32Millies, void **ppvURB,
672 uint32_t *pu32Len, uint32_t *pu32Err)
673{
674 int rc = VINF_SUCCESS;
675
676 LogFlow(("RemoteUSBBackend::iface_ReapURB %d ms\n", u32Millies));
677
678 if (pDevice->fFailed)
679 {
680 return VERR_VUSB_DEVICE_NOT_ATTACHED;
681 }
682
683 RemoteUSBBackend *pThis = pDevice->pOwner;
684
685 /* Wait for transaction completion. */
686 uint64_t u64StartTime = RTTimeMilliTS();
687
688 if (pThis->pollingEnabledURB())
689 {
690 VRDE_USB_REQ_REAP_URB_PARM parm;
691
692 parm.code = VRDE_USB_REQ_REAP_URB;
693
694 pThis->VRDPServer()->SendUSBRequest(pDevice->u32ClientId, &parm, sizeof(parm));
695 }
696
697 REMOTEUSBQURB *qurb = NULL;
698
699 for (;;)
700 {
701 uint32_t u32ClientId;
702
703 if (ASMAtomicXchgBool(&pDevice->fWokenUp, false))
704 break;
705
706 /* Scan queued URBs, look for completed. */
707 requestDevice(pDevice);
708
709 u32ClientId = pDevice->u32ClientId;
710
711 qurb = pDevice->pHeadQURBs;
712
713 while (qurb)
714 {
715 if (qurb->fCompleted)
716 {
717 /* Remove this completed urb from the queue. */
718 if (qurb->prev)
719 {
720 qurb->prev->next = qurb->next;
721 }
722 else
723 {
724 pDevice->pHeadQURBs = qurb->next;
725 }
726
727 if (qurb->next)
728 {
729 qurb->next->prev = qurb->prev;
730 }
731 else
732 {
733 pDevice->pTailQURBs = qurb->prev;
734 }
735
736 qurb->next = NULL;
737 qurb->prev = NULL;
738
739 break;
740 }
741
742 qurb = qurb->next;
743 }
744
745 releaseDevice(pDevice);
746
747 if ( qurb
748 || !pDevice->pHeadQURBs
749 || u32Millies == 0
750 || pDevice->fFailed
751 || (RTTimeMilliTS() - u64StartTime >= (uint64_t)u32Millies))
752 {
753 /* Got an URB or do not have to wait for an URB. */
754 break;
755 }
756
757 LogFlow(("RemoteUSBBackend::iface_ReapURB iteration.\n"));
758
759 RTThreadSleep(10);
760
761 if (pThis->pollingEnabledURB())
762 {
763 VRDE_USB_REQ_REAP_URB_PARM parm;
764
765 parm.code = VRDE_USB_REQ_REAP_URB;
766
767 pThis->VRDPServer()->SendUSBRequest(u32ClientId, &parm, sizeof(parm));
768 }
769 }
770
771 LogFlow(("RemoteUSBBackend::iface_ReapURB completed in %lld ms, qurb = %p\n", RTTimeMilliTS () - u64StartTime, qurb));
772
773 if (!qurb)
774 {
775 *ppvURB = NULL;
776 *pu32Len = 0;
777 *pu32Err = VUSBSTATUS_OK;
778 }
779 else
780 {
781 *ppvURB = qurb->pvURB;
782 *pu32Len = qurb->u32Len;
783 *pu32Err = qurb->u32Err;
784
785#ifdef LOG_ENABLED
786 Log(("URB len = %d, data = %p\n", qurb->u32Len, qurb->pvURB));
787 if (qurb->u32Len)
788 {
789 Log(("Received URB content:\n%.*Rhxd\n", qurb->u32Len, qurb->pvData));
790 }
791#endif
792
793 qurbFree(qurb);
794 }
795
796 return rc;
797}
798
799static DECLCALLBACK(int) iface_Wakeup(PREMOTEUSBDEVICE pDevice)
800{
801 ASMAtomicXchgBool(&pDevice->fWokenUp, true);
802 return VINF_SUCCESS;
803}
804
805void RemoteUSBBackend::AddRef(void)
806{
807 cRefs++;
808}
809
810void RemoteUSBBackend::Release(void)
811{
812 cRefs--;
813
814 if (cRefs <= 0)
815 {
816 delete this;
817 }
818}
819
820void RemoteUSBBackend::PollRemoteDevices(void)
821{
822 if ( mfWillBeDeleted
823 && menmPollRemoteDevicesStatus != PollRemoteDevicesStatus_Dereferenced)
824 {
825 /* Unmount all remote USB devices. */
826 mConsole->i_processRemoteUSBDevices(mu32ClientId, NULL, 0, false);
827
828 menmPollRemoteDevicesStatus = PollRemoteDevicesStatus_Dereferenced;
829
830 Release();
831
832 return;
833 }
834
835 switch(menmPollRemoteDevicesStatus)
836 {
837 case PollRemoteDevicesStatus_Negotiate:
838 {
839 VRDEUSBREQNEGOTIATEPARM parm;
840
841 parm.code = VRDE_USB_REQ_NEGOTIATE;
842 parm.version = VRDE_USB_VERSION;
843 /* VRDE_USB_VERSION_3: support VRDE_USB_REQ_DEVICE_LIST_EXT_RET. */
844 parm.flags = VRDE_USB_SERVER_CAPS_PORT_VERSION;
845
846 mServer->SendUSBRequest(mu32ClientId, &parm, sizeof(parm));
847
848 /* Reference the object. When the client disconnects and
849 * the backend is about to be deleted, the method must be called
850 * to disconnect the USB devices (as stated above).
851 */
852 AddRef();
853
854 /* Goto the disabled state. When a response will be received
855 * the state will be changed to the SendRequest.
856 */
857 menmPollRemoteDevicesStatus = PollRemoteDevicesStatus_WaitNegotiateResponse;
858 } break;
859
860 case PollRemoteDevicesStatus_WaitNegotiateResponse:
861 {
862 LogFlow(("USB::PollRemoteDevices: WaitNegotiateResponse\n"));
863 /* Do nothing. */
864 } break;
865
866 case PollRemoteDevicesStatus_SendRequest:
867 {
868 LogFlow(("USB::PollRemoteDevices: SendRequest\n"));
869
870 /* Send a request for device list. */
871 VRDE_USB_REQ_DEVICE_LIST_PARM parm;
872
873 parm.code = VRDE_USB_REQ_DEVICE_LIST;
874
875 mServer->SendUSBRequest(mu32ClientId, &parm, sizeof(parm));
876
877 menmPollRemoteDevicesStatus = PollRemoteDevicesStatus_WaitResponse;
878 } break;
879
880 case PollRemoteDevicesStatus_WaitResponse:
881 {
882 LogFlow(("USB::PollRemoteDevices: WaitResponse\n"));
883
884 if (mfHasDeviceList)
885 {
886 mConsole->i_processRemoteUSBDevices(mu32ClientId, (VRDEUSBDEVICEDESC *)mpvDeviceList, mcbDeviceList, mfDescExt);
887 LogFlow(("USB::PollRemoteDevices: WaitResponse after process\n"));
888
889 menmPollRemoteDevicesStatus = PollRemoteDevicesStatus_SendRequest;
890
891 mfHasDeviceList = false;
892 }
893 } break;
894
895 case PollRemoteDevicesStatus_Dereferenced:
896 {
897 LogFlow(("USB::PollRemoteDevices: Dereferenced\n"));
898 /* Do nothing. */
899 } break;
900
901 default:
902 {
903 AssertFailed();
904 } break;
905 }
906}
907
908void RemoteUSBBackend::NotifyDelete(void)
909{
910 mfWillBeDeleted = true;
911}
912
913/*
914 * The backend maintains a list of UUIDs of devices
915 * which are managed by the backend.
916 */
917bool RemoteUSBBackend::addUUID(const Guid *pUuid)
918{
919 unsigned i;
920 for (i = 0; i < RT_ELEMENTS(aGuids); i++)
921 {
922 if (aGuids[i].isZero())
923 {
924 aGuids[i] = *pUuid;
925 return true;
926 }
927 }
928
929 return false;
930}
931
932bool RemoteUSBBackend::findUUID(const Guid *pUuid)
933{
934 unsigned i;
935 for (i = 0; i < RT_ELEMENTS(aGuids); i++)
936 {
937 if (aGuids[i] == *pUuid)
938 {
939 return true;
940 }
941 }
942
943 return false;
944}
945
946void RemoteUSBBackend::removeUUID(const Guid *pUuid)
947{
948 unsigned i;
949 for (i = 0; i < RT_ELEMENTS(aGuids); i++)
950 {
951 if (aGuids[i] == *pUuid)
952 {
953 aGuids[i].clear();
954 break;
955 }
956 }
957}
958
959RemoteUSBBackend::RemoteUSBBackend(Console *console, ConsoleVRDPServer *server, uint32_t u32ClientId)
960 :
961 mConsole(console),
962 mServer(server),
963 cRefs(0),
964 mu32ClientId(u32ClientId),
965 mfHasDeviceList(false),
966 mpvDeviceList(NULL),
967 mcbDeviceList(0),
968 menmPollRemoteDevicesStatus(PollRemoteDevicesStatus_Negotiate),
969 mfPollURB(true),
970 mpDevices(NULL),
971 mfWillBeDeleted(false),
972 mClientVersion(0), /* VRDE_USB_VERSION_2: the client version. */
973 mfDescExt(false) /* VRDE_USB_VERSION_3: VRDE_USB_REQ_DEVICE_LIST_EXT_RET. */
974{
975 Assert(console);
976 Assert(server);
977
978 int rc = RTCritSectInit(&mCritsect);
979
980 if (RT_FAILURE(rc))
981 {
982 AssertFailed();
983 RT_ZERO(mCritsect);
984 }
985
986 mCallback.pInstance = (PREMOTEUSBBACKEND)this;
987 mCallback.pfnOpen = iface_Open;
988 mCallback.pfnClose = iface_Close;
989 mCallback.pfnReset = iface_Reset;
990 mCallback.pfnSetConfig = iface_SetConfig;
991 mCallback.pfnClaimInterface = iface_ClaimInterface;
992 mCallback.pfnReleaseInterface = iface_ReleaseInterface;
993 mCallback.pfnInterfaceSetting = iface_InterfaceSetting;
994 mCallback.pfnQueueURB = iface_QueueURB;
995 mCallback.pfnReapURB = iface_ReapURB;
996 mCallback.pfnClearHaltedEP = iface_ClearHaltedEP;
997 mCallback.pfnCancelURB = iface_CancelURB;
998 mCallback.pfnWakeup = iface_Wakeup;
999}
1000
1001RemoteUSBBackend::~RemoteUSBBackend()
1002{
1003 Assert(cRefs == 0);
1004
1005 if (RTCritSectIsInitialized(&mCritsect))
1006 {
1007 RTCritSectDelete(&mCritsect);
1008 }
1009
1010 RTMemFree(mpvDeviceList);
1011
1012 mServer->usbBackendRemoveFromList(this);
1013}
1014
1015int RemoteUSBBackend::negotiateResponse(const VRDEUSBREQNEGOTIATERET *pret, uint32_t cbRet)
1016{
1017 int rc = VINF_SUCCESS;
1018
1019 Log(("RemoteUSBBackend::negotiateResponse: flags = %02X.\n", pret->flags));
1020
1021 LogRel(("Remote USB: Received negotiate response. Flags 0x%02X.\n",
1022 pret->flags));
1023
1024 if (pret->flags & VRDE_USB_CAPS_FLAG_POLL)
1025 {
1026 Log(("RemoteUSBBackend::negotiateResponse: client requested URB polling.\n"));
1027 mfPollURB = true;
1028 }
1029 else
1030 {
1031 mfPollURB = false;
1032 }
1033
1034 /* VRDE_USB_VERSION_2: check the client version. */
1035 if (pret->flags & VRDE_USB_CAPS2_FLAG_VERSION)
1036 {
1037 /* This could be a client version > 1. */
1038 if (cbRet >= sizeof(VRDEUSBREQNEGOTIATERET_2))
1039 {
1040 VRDEUSBREQNEGOTIATERET_2 *pret2 = (VRDEUSBREQNEGOTIATERET_2 *)pret;
1041
1042 if (pret2->u32Version <= VRDE_USB_VERSION)
1043 {
1044 /* This is OK. The client wants a version supported by the server. */
1045 mClientVersion = pret2->u32Version;
1046 }
1047 else
1048 {
1049 LogRel(("VRDP: ERROR: unsupported remote USB protocol client version %d.\n", pret2->u32Version));
1050 rc = VERR_NOT_SUPPORTED;
1051 }
1052 }
1053 else
1054 {
1055 LogRel(("VRDP: ERROR: invalid remote USB negotiate request packet size %d.\n", cbRet));
1056 rc = VERR_NOT_SUPPORTED;
1057 }
1058 }
1059 else
1060 {
1061 /* This is a client version 1. */
1062 mClientVersion = VRDE_USB_VERSION_1;
1063 }
1064
1065 if (RT_SUCCESS(rc))
1066 {
1067 LogRel(("VRDP: remote USB protocol version %d.\n", mClientVersion));
1068
1069 /* VRDE_USB_VERSION_3: check the client capabilities: VRDE_USB_CLIENT_CAPS_*. */
1070 if (mClientVersion == VRDE_USB_VERSION_3)
1071 {
1072 if (cbRet >= sizeof(VRDEUSBREQNEGOTIATERET_3))
1073 {
1074 VRDEUSBREQNEGOTIATERET_3 *pret3 = (VRDEUSBREQNEGOTIATERET_3 *)pret;
1075
1076 mfDescExt = (pret3->u32Flags & VRDE_USB_CLIENT_CAPS_PORT_VERSION) != 0;
1077 }
1078 else
1079 {
1080 LogRel(("VRDP: ERROR: invalid remote USB negotiate request packet size %d.\n", cbRet));
1081 rc = VERR_NOT_SUPPORTED;
1082 }
1083 }
1084
1085 menmPollRemoteDevicesStatus = PollRemoteDevicesStatus_SendRequest;
1086 }
1087
1088 return rc;
1089}
1090
1091int RemoteUSBBackend::saveDeviceList(const void *pvList, uint32_t cbList)
1092{
1093 Log(("RemoteUSBBackend::saveDeviceList: pvList = %p, cbList = %d\n", pvList, cbList));
1094
1095 if (!mfHasDeviceList)
1096 {
1097 RTMemFree(mpvDeviceList);
1098 mpvDeviceList = NULL;
1099
1100 mcbDeviceList = cbList;
1101
1102 if (cbList > 0)
1103 {
1104 mpvDeviceList = RTMemAlloc(cbList);
1105 memcpy(mpvDeviceList, pvList, cbList);
1106 }
1107
1108 mfHasDeviceList = true;
1109 }
1110
1111 return VINF_SUCCESS;
1112}
1113
1114void RemoteUSBBackend::request(void)
1115{
1116 int rc = RTCritSectEnter(&mCritsect);
1117 AssertRC(rc);
1118}
1119
1120void RemoteUSBBackend::release(void)
1121{
1122 RTCritSectLeave(&mCritsect);
1123}
1124
1125PREMOTEUSBDEVICE RemoteUSBBackend::deviceFromId(VRDEUSBDEVID id)
1126{
1127 request();
1128
1129 REMOTEUSBDEVICE *pDevice = mpDevices;
1130
1131 while (pDevice && pDevice->id != id)
1132 {
1133 pDevice = pDevice->next;
1134 }
1135
1136 release();
1137
1138 return pDevice;
1139}
1140
1141void RemoteUSBBackend::addDevice(PREMOTEUSBDEVICE pDevice)
1142{
1143 request();
1144
1145 pDevice->next = mpDevices;
1146
1147 if (mpDevices)
1148 {
1149 mpDevices->prev = pDevice;
1150 }
1151
1152 mpDevices = pDevice;
1153
1154 release();
1155}
1156
1157void RemoteUSBBackend::removeDevice(PREMOTEUSBDEVICE pDevice)
1158{
1159 request();
1160
1161 if (pDevice->prev)
1162 {
1163 pDevice->prev->next = pDevice->next;
1164 }
1165 else
1166 {
1167 mpDevices = pDevice->next;
1168 }
1169
1170 if (pDevice->next)
1171 {
1172 pDevice->next->prev = pDevice->prev;
1173 }
1174
1175 release();
1176}
1177
1178int RemoteUSBBackend::reapURB(const void *pvBody, uint32_t cbBody)
1179{
1180 int rc = VINF_SUCCESS;
1181
1182 LogFlow(("RemoteUSBBackend::reapURB: pvBody = %p, cbBody = %d\n", pvBody, cbBody));
1183
1184 VRDEUSBREQREAPURBBODY *pBody = (VRDEUSBREQREAPURBBODY *)pvBody;
1185
1186 while (cbBody >= sizeof(VRDEUSBREQREAPURBBODY))
1187 {
1188 Log(("RemoteUSBBackend::reapURB: id = %d, flags = %02X, error = %d, handle %d, len = %d.\n",
1189 pBody->id, pBody->flags, pBody->error, pBody->handle, pBody->len));
1190
1191 uint8_t fu8ReapValidFlags;
1192
1193 if (mClientVersion == VRDE_USB_VERSION_1 || mClientVersion == VRDE_USB_VERSION_2)
1194 {
1195 fu8ReapValidFlags = VRDE_USB_REAP_VALID_FLAGS;
1196 }
1197 else
1198 {
1199 fu8ReapValidFlags = VRDE_USB_REAP_VALID_FLAGS_3;
1200 }
1201
1202 /* Verify client's data. */
1203 if ( (pBody->flags & ~fu8ReapValidFlags) != 0
1204 || sizeof(VRDEUSBREQREAPURBBODY) > cbBody
1205 || pBody->handle == 0)
1206 {
1207 LogFlow(("RemoteUSBBackend::reapURB: WARNING: invalid reply data. Skipping the reply.\n"));
1208 rc = VERR_INVALID_PARAMETER;
1209 break;
1210 }
1211
1212 PREMOTEUSBDEVICE pDevice = deviceFromId(pBody->id);
1213
1214 if (!pDevice)
1215 {
1216 LogFlow(("RemoteUSBBackend::reapURB: WARNING: invalid device id. Skipping the reply.\n"));
1217 rc = VERR_INVALID_PARAMETER;
1218 break;
1219 }
1220
1221 uint32_t cbBodyData = 0; /* Data contained in the URB body structure for input URBs. */
1222
1223 requestDevice(pDevice);
1224
1225 /* Search the queued URB for given handle. */
1226 REMOTEUSBQURB *qurb = pDevice->pHeadQURBs;
1227
1228 while (qurb && qurb->u32Handle != pBody->handle)
1229 {
1230 LogFlow(("RemoteUSBBackend::reapURB: searching: %p handle = %d.\n", qurb, qurb->u32Handle));
1231 qurb = qurb->next;
1232 }
1233
1234 if (!qurb)
1235 {
1236 LogFlow(("RemoteUSBBackend::reapURB: Queued URB not found, probably already canceled. Skipping the URB.\n"));
1237 }
1238 else
1239 {
1240 LogFlow(("RemoteUSBBackend::reapURB: qurb = %p\n", qurb));
1241
1242 /* Update the URB error field. */
1243 if (mClientVersion == VRDE_USB_VERSION_1)
1244 {
1245 switch(pBody->error)
1246 {
1247 case VRDE_USB_XFER_OK: qurb->u32Err = VUSBSTATUS_OK; break;
1248 case VRDE_USB_XFER_STALL: qurb->u32Err = VUSBSTATUS_STALL; break;
1249 case VRDE_USB_XFER_DNR: qurb->u32Err = VUSBSTATUS_DNR; break;
1250 case VRDE_USB_XFER_CRC: qurb->u32Err = VUSBSTATUS_CRC; break;
1251 default: Log(("RemoteUSBBackend::reapURB: Invalid error %d\n", pBody->error));
1252 qurb->u32Err = VUSBSTATUS_DNR; break;
1253 }
1254 }
1255 else if ( mClientVersion == VRDE_USB_VERSION_2
1256 || mClientVersion == VRDE_USB_VERSION_3)
1257 {
1258 switch(pBody->error)
1259 {
1260 case VRDE_USB_XFER_OK: qurb->u32Err = VUSBSTATUS_OK; break;
1261 case VRDE_USB_XFER_STALL: qurb->u32Err = VUSBSTATUS_STALL; break;
1262 case VRDE_USB_XFER_DNR: qurb->u32Err = VUSBSTATUS_DNR; break;
1263 case VRDE_USB_XFER_CRC: qurb->u32Err = VUSBSTATUS_CRC; break;
1264 case VRDE_USB_XFER_DO: qurb->u32Err = VUSBSTATUS_DATA_OVERRUN; break;
1265 case VRDE_USB_XFER_DU: qurb->u32Err = VUSBSTATUS_DATA_UNDERRUN; break;
1266
1267 /* Unmapped errors. */
1268 case VRDE_USB_XFER_BS:
1269 case VRDE_USB_XFER_DTM:
1270 case VRDE_USB_XFER_PCF:
1271 case VRDE_USB_XFER_UPID:
1272 case VRDE_USB_XFER_BO:
1273 case VRDE_USB_XFER_BU:
1274 case VRDE_USB_XFER_ERR:
1275 default: Log(("RemoteUSBBackend::reapURB: Invalid error %d\n", pBody->error));
1276 qurb->u32Err = VUSBSTATUS_DNR; break;
1277 }
1278 }
1279 else
1280 {
1281 qurb->u32Err = VUSBSTATUS_DNR;
1282 }
1283
1284 /* Get the URB data. */
1285 bool fURBCompleted = true;
1286
1287 if (qurb->fInput)
1288 {
1289 cbBodyData = pBody->len; /* VRDE_USB_DIRECTION_IN URBs include some data. */
1290 }
1291
1292 if ( qurb->u32Err == VUSBSTATUS_OK
1293 && qurb->fInput)
1294 {
1295 LogFlow(("RemoteUSBBackend::reapURB: copying data %d bytes\n", pBody->len));
1296
1297 uint32_t u32DataLen = qurb->u32TransferredLen + pBody->len;
1298
1299 if (u32DataLen > qurb->u32Len)
1300 {
1301 /* Received more data than expected for this URB. If there more fragments follow,
1302 * they will be discarded because the URB handle will not be valid anymore.
1303 */
1304 qurb->u32Err = VUSBSTATUS_DNR;
1305 }
1306 else
1307 {
1308 memcpy ((uint8_t *)qurb->pvData + qurb->u32TransferredLen, &pBody[1], pBody->len);
1309 }
1310
1311 if ( qurb->u32Err == VUSBSTATUS_OK
1312 && (pBody->flags & VRDE_USB_REAP_FLAG_FRAGMENT) != 0)
1313 {
1314 /* If the client sends fragmented packets, accumulate the URB data. */
1315 fURBCompleted = false;
1316 }
1317 }
1318
1319 qurb->u32TransferredLen += pBody->len; /* Update the value for all URBs. */
1320
1321 if (fURBCompleted)
1322 {
1323 /* Move the URB near the head of URB list, so that iface_ReapURB can
1324 * find it faster. Note that the order of completion must be preserved!
1325 */
1326 if (qurb->prev)
1327 {
1328 /* The URB is not in the head. Unlink it from its current position. */
1329 qurb->prev->next = qurb->next;
1330
1331 if (qurb->next)
1332 {
1333 qurb->next->prev = qurb->prev;
1334 }
1335 else
1336 {
1337 pDevice->pTailQURBs = qurb->prev;
1338 }
1339
1340 /* And insert it to its new place. */
1341 if (pDevice->pHeadQURBs->fCompleted)
1342 {
1343 /* At least one other completed URB; insert after the
1344 * last completed URB.
1345 */
1346 REMOTEUSBQURB *prev_qurb = pDevice->pHeadQURBs;
1347 while (prev_qurb->next && prev_qurb->next->fCompleted)
1348 prev_qurb = prev_qurb->next;
1349
1350 qurb->next = prev_qurb->next;
1351 qurb->prev = prev_qurb;
1352
1353 if (prev_qurb->next)
1354 prev_qurb->next->prev = qurb;
1355 else
1356 pDevice->pTailQURBs = qurb;
1357 prev_qurb->next = qurb;
1358 }
1359 else
1360 {
1361 /* No other completed URBs; insert at head. */
1362 qurb->next = pDevice->pHeadQURBs;
1363 qurb->prev = NULL;
1364
1365 pDevice->pHeadQURBs->prev = qurb;
1366 pDevice->pHeadQURBs = qurb;
1367 }
1368 }
1369
1370 qurb->u32Len = qurb->u32TransferredLen; /* Update the final length. */
1371 qurb->fCompleted = true;
1372 }
1373 }
1374
1375 releaseDevice (pDevice);
1376
1377 if (pBody->flags & VRDE_USB_REAP_FLAG_LAST)
1378 {
1379 break;
1380 }
1381
1382 /* There is probably a further URB body. */
1383 uint32_t cbBodySize = sizeof (VRDEUSBREQREAPURBBODY) + cbBodyData;
1384
1385 if (cbBodySize > cbBody)
1386 {
1387 rc = VERR_INVALID_PARAMETER;
1388 break;
1389 }
1390
1391 pBody = (VRDEUSBREQREAPURBBODY *)((uint8_t *)pBody + cbBodySize);
1392 cbBody -= cbBodySize;
1393 }
1394
1395 LogFlow(("RemoteUSBBackend::reapURB: returns %Rrc\n", rc));
1396
1397 return rc;
1398}
1399/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette