VirtualBox

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

Last change on this file since 56994 was 55401, checked in by vboxsync, 10 years ago

added a couple of missing Id headers

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