VirtualBox

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

Last change on this file since 67414 was 65125, checked in by vboxsync, 8 years ago

Main: doxygen fixes

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