VirtualBox

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

Last change on this file since 50874 was 50530, checked in by vboxsync, 11 years ago

USB: Split dev_usb logging group into dev_ehci and dev_ohci so the logging of those doesn't get mixed

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