VirtualBox

source: vbox/trunk/src/VBox/Devices/USB/usbip/USBProxyDevice-usbip.cpp@ 57273

Last change on this file since 57273 was 57273, checked in by vboxsync, 9 years ago

USBProxyDevice-usbip: More updates

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 44.6 KB
Line 
1/* $Id: USBProxyDevice-usbip.cpp 57273 2015-08-11 13:38:08Z vboxsync $ */
2/** @file
3 * USB device proxy - USB/IP backend.
4 */
5
6/*
7 * Copyright (C) 2014-2015 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
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_DRV_USBPROXY
23
24#include <VBox/log.h>
25#include <VBox/err.h>
26#include <VBox/vmm/pdm.h>
27
28#include <iprt/asm.h>
29#include <iprt/assert.h>
30#include <iprt/alloc.h>
31#include <iprt/string.h>
32#include <iprt/socket.h>
33#include <iprt/poll.h>
34#include <iprt/tcp.h>
35#include <iprt/pipe.h>
36#include <iprt/list.h>
37#include <iprt/semaphore.h>
38
39#include "../USBProxyDevice.h"
40
41
42/*******************************************************************************
43* Constants And Macros, Structures and Typedefs *
44*******************************************************************************/
45
46/** The USB version number used for the protocol. */
47#define USBIP_VERSION UINT16_C(0x0111)
48/** Request indicator in the command code. */
49#define USBIP_INDICATOR_REQ RT_BIT(15)
50
51/** Command/Reply code for OP_REQ/RET_DEVLIST. */
52#define USBIP_REQ_RET_DEVLIST UINT16_C(5)
53/** Command/Reply code for OP_REQ/REP_IMPORT. */
54#define USBIP_REQ_RET_IMPORT UINT16_C(3)
55/** USB submit command identifier. */
56#define USBIP_CMD_SUBMIT UINT32_C(1)
57/** USB submit status identifier. */
58#define USBIP_RET_SUBMIT UINT32_C(3)
59/** URB unlink (cancel) command identifier. */
60#define USBIP_CMD_UNLINK UINT32_C(2)
61/** URB unlink (cancel) reply identifier. */
62#define USBIP_RET_UNLINK UINT32_C(4)
63
64/** Short read is not okay for the specified URB. */
65#define USBIP_XFER_FLAGS_SHORT_NOT_OK RT_BIT_32(0)
66/** Queue the isochronous URB as soon as possible. */
67#define USBIP_XFER_FLAGS_ISO_ASAP RT_BIT_32(1)
68/** Don't use DMA mappings for this URB. */
69#define USBIP_XFER_FLAGS_NO_TRANSFER_DMA_MAP RT_BIT_32(2)
70/** Explain - only applies to UHCI. */
71#define USBIP_XFER_FLAGS_FSBR RT_BIT_32(4)
72
73/** URB direction - input. */
74#define USBIP_DIR_IN UINT32_C(0)
75/** URB direction - output. */
76#define USBIP_DIR_OUT UINT32_C(1)
77
78/** @name USB/IP error codes.
79 * @{ */
80/** Success indicator. */
81#define USBIP_STATUS_SUCCESS INT32_C(0)
82/** Pipe stalled. */
83#define USBIP_STATUS_PIPE_STALLED INT32_C(-32)
84/** @} */
85
86/**
87 * Exported device entry in the OP_RET_DEVLIST reply.
88 */
89#pragma pack(1)
90typedef struct UsbIpExportedDevice
91{
92 /** Path of the device, zero terminated string. */
93 char szPath[256];
94 /** Bus ID of the exported device, zero terminated string. */
95 char szBusId[32];
96 /** Bus number. */
97 uint32_t u32BusNum;
98 /** Device number. */
99 uint32_t u32DevNum;
100 /** Speed indicator of the device. */
101 uint32_t u32Speed;
102 /** Vendor ID of the device. */
103 uint16_t u16VendorId;
104 /** Product ID of the device. */
105 uint16_t u16ProductId;
106 /** Device release number. */
107 uint16_t u16BcdDevice;
108 /** Device class. */
109 uint8_t bDeviceClass;
110 /** Device Subclass. */
111 uint8_t bDeviceSubClass;
112 /** Device protocol. */
113 uint8_t bDeviceProtocol;
114 /** Configuration value. */
115 uint8_t bConfigurationValue;
116 /** Current configuration value of the device. */
117 uint8_t bNumConfigurations;
118 /** Number of interfaces for the device. */
119 uint8_t bNumInterfaces;
120} UsbIpExportedDevice;
121/** Pointer to a exported device entry. */
122typedef UsbIpExportedDevice *PUsbIpExportedDevice;
123#pragma pack()
124AssertCompileSize(UsbIpExportedDevice, 312);
125
126/**
127 * Interface descriptor entry for an exported device.
128 */
129#pragma pack(1)
130typedef struct UsbIpDeviceInterface
131{
132 /** Intefrace class. */
133 uint8_t bInterfaceClass;
134 /** Interface sub class. */
135 uint8_t bInterfaceSubClass;
136 /** Interface protocol identifier. */
137 uint8_t bInterfaceProtocol;
138 /** Padding byte for alignment. */
139 uint8_t bPadding;
140} UsbIpDeviceInterface;
141/** Pointer to an interface descriptor entry. */
142typedef UsbIpDeviceInterface *PUsbIpDeviceInterface;
143#pragma pack()
144
145/**
146 * USB/IP Import request.
147 */
148#pragma pack(1)
149typedef struct UsbIpReqImport
150{
151 /** Protocol version number. */
152 uint16_t u16Version;
153 /** Command code. */
154 uint16_t u16Cmd;
155 /** Status field, unused. */
156 int32_t u32Status;
157 /** Bus Id of the device as zero terminated string. */
158 char aszBusId[32];
159} UsbIpReqImport;
160/** Pointer to a import request. */
161typedef UsbIpReqImport *PUsbIpReqImport;
162#pragma pack()
163
164/**
165 * USB/IP Import reply.
166 *
167 * This is only the header, for successful
168 * imports the device details are sent to as
169 * defined in UsbIpExportedDevice.
170 */
171#pragma pack(1)
172typedef struct UsbIpRetImport
173{
174 /** Protocol version number. */
175 uint16_t u16Version;
176 /** Command code. */
177 uint16_t u16Cmd;
178 /** Status field, unused. */
179 int32_t u32Status;
180} UsbIpRetImport;
181/** Pointer to a import reply. */
182typedef UsbIpRetImport *PUsbIpRetImport;
183#pragma pack()
184
185/**
186 * Command/Reply header common to the submit and unlink commands
187 * replies.
188 */
189#pragma pack(1)
190typedef struct UsbIpReqRetHdr
191{
192 /** Request/Return code. */
193 uint32_t u32ReqRet;
194 /** Sequence number to identify the URB. */
195 uint32_t u32SeqNum;
196 /** Device id. */
197 uint32_t u32DevId;
198 /** Direction of the endpoint (host->device, device->host). */
199 uint32_t u32Direction;
200 /** Endpoint number. */
201 uint32_t u32Endpoint;
202} UsbIpReqRetHdr;
203/** Pointer to a request/reply header. */
204typedef UsbIpReqRetHdr *PUsbIpReqRetHdr;
205#pragma pack()
206
207/**
208 * USB/IP Submit request.
209 */
210#pragma pack(1)
211typedef struct UsbIpReqSubmit
212{
213 /** The request header. */
214 UsbIpReqRetHdr Hdr;
215 /** Transfer flags for the URB. */
216 uint32_t u32XferFlags;
217 /** Transfer buffer length. */
218 uint32_t u32TransferBufferLength;
219 /** Frame to transmit an ISO frame. */
220 uint32_t u32StartFrame;
221 /** Number of isochronous packets. */
222 uint32_t u32NumIsocPkts;
223 /** Maximum time for the request on the server side host controller. */
224 uint32_t u32Interval;
225 /** Setup data for a control URB. */
226 VUSBSETUP Setup;
227} UsbIpReqSubmit;
228/** Pointer to a submit request. */
229typedef UsbIpReqSubmit *PUsbIpReqSubmit;
230#pragma pack()
231
232/**
233 * USB/IP Submit reply.
234 */
235#pragma pack(1)
236typedef struct UsbIpRetSubmit
237{
238 /** The reply header. */
239 UsbIpReqRetHdr Hdr;
240 /** Status code. */
241 int32_t u32Status;
242 /** Actual length of the reply buffer. */
243 uint32_t u32ActualLength;
244 /** The actual selected frame for a isochronous transmit. */
245 uint32_t u32StartFrame;
246 /** Number of isochronous packets. */
247 uint32_t u32NumIsocPkts;
248 /** Number of failed isochronous packets. */
249 uint32_t u32ErrorCount;
250 /** Setup data for a control URB. */
251 VUSBSETUP Setup;
252} UsbIpRetSubmit;
253/** Pointer to a submit reply. */
254typedef UsbIpRetSubmit *PUsbIpRetSubmit;
255#pragma pack()
256
257/**
258 * Unlink URB request.
259 */
260#pragma pack(1)
261typedef struct UsbIpReqUnlink
262{
263 /** The request header. */
264 UsbIpReqRetHdr Hdr;
265 /** The sequence number to unlink. */
266 uint32_t u32SeqNum;
267} UsbIpReqUnlink;
268/** Pointer to a URB unlink request. */
269typedef UsbIpReqUnlink *PUsbIpReqUnlink;
270#pragma pack()
271
272/**
273 * Unlink URB reply.
274 */
275#pragma pack(1)
276typedef struct UsbIpRetUnlink
277{
278 /** The reply header. */
279 UsbIpReqRetHdr Hdr;
280 /** Status of the request. */
281 int32_t u32Status;
282} UsbIpRetUnlink;
283/** Pointer to a URB unlink request. */
284typedef UsbIpRetUnlink *PUsbIpRetUnlink;
285#pragma pack()
286
287/**
288 * Union of possible replies from the server during normal operation.
289 */
290#pragma pack(1)
291typedef union UsbIpRet
292{
293 /** The header. */
294 UsbIpReqRetHdr Hdr;
295 /** Submit reply. */
296 UsbIpRetSubmit RetSubmit;
297 /** Unlink reply. */
298 UsbIpRetUnlink RetUnlink;
299 /** Byte view. */
300 uint8_t abReply[1];
301} UsbIpRet;
302/** Pointer to a reply union. */
303typedef UsbIpRet *PUsbIpRet;
304#pragma pack()
305
306/**
307 * USB/IP backend specific data for one URB.
308 * Required for tracking in flight and landed URBs.
309 */
310typedef struct USBPROXYURBUSBIP
311{
312 /** List node for the in flight or landed URB list. */
313 RTLISTNODE NodeList;
314 /** Sequence number the assigned URB is identified by. */
315 uint32_t u32SeqNumUrb;
316 /** Pointer to the VUSB URB. */
317 PVUSBURB pVUsbUrb;
318} USBPROXYURBUSBIP;
319/** Pointer to a USB/IP URB. */
320typedef USBPROXYURBUSBIP *PUSBPROXYURBUSBIP;
321
322/**
323 * Backend data for the USB/IP USB Proxy device backend.
324 */
325typedef struct USBPROXYDEVUSBIP
326{
327 /** IPRT socket handle. */
328 RTSOCKET hSocket;
329 /** Pollset with the wakeup pipe and socket. */
330 RTPOLLSET hPollSet;
331 /** Pipe endpoint - read (in the pollset). */
332 RTPIPE hPipeR;
333 /** Pipe endpoint - write. */
334 RTPIPE hPipeW;
335 /** Flag whether the reaper thread was woken up. */
336 volatile bool fWokenUp;
337 /** Next sequence number to use for identifying submitted URBs. */
338 volatile uint32_t u32SeqNumNext;
339 /** Fast mutex protecting the lists below against concurrent access. */
340 RTSEMFASTMUTEX hMtxLists;
341 /** List of in flight URBs. */
342 RTLISTANCHOR ListUrbsInFlight;
343 /** List of landed URBs. */
344 RTLISTANCHOR ListUrbsLanded;
345 /** Port of the USB/IP host to connect to. */
346 uint32_t uPort;
347 /** USB/IP host address. */
348 char *pszHost;
349 /** USB Bus ID of the device to capture. */
350 char *pszBusId;
351 /** The device ID to use to identify the device. */
352 uint32_t u32DevId;
353 /** Temporary buffer for the next reply header */
354 UsbIpRet BufRet;
355 /** Number of bytes received so far. */
356 size_t cbRecv;
357 /** Number of bytes left to receive. */
358 size_t cbLeft;
359 /** Flag whether we are currently receiving data for an URB. */
360 bool fRecvData;
361 /** The URB we currently receive a response for. */
362 PUSBPROXYURBUSBIP pUrbUsbIp;
363} USBPROXYDEVUSBIP, *PUSBPROXYDEVUSBIP;
364
365/** Pollset id of the socket. */
366#define USBIP_POLL_ID_SOCKET 0
367/** Pollset id of the pipe. */
368#define USBIP_POLL_ID_PIPE 1
369
370/** USB/IP address prefix for identifcation. */
371#define USBIP_URI_PREFIX "usbip://"
372/** USB/IP address prefix length. */
373#define USBIP_URI_PREFIX_LEN (sizeof(USBIP_URI_PREFIX) - 1)
374
375/**
376 * Converts a request/reply header from network to host endianness.
377 *
378 * @returns nothing.
379 * @param pHdr The header to convert.
380 */
381DECLINLINE(void) usbProxyUsbIpReqRetHdrN2H(PUsbIpReqRetHdr pHdr)
382{
383 pHdr->u32ReqRet = RT_H2N_U32(pHdr->u32ReqRet);
384 pHdr->u32SeqNum = RT_H2N_U32(pHdr->u32SeqNum);
385 pHdr->u32DevId = RT_H2N_U32(pHdr->u32DevId);
386 pHdr->u32Direction = RT_H2N_U32(pHdr->u32Direction);
387 pHdr->u32Endpoint = RT_H2N_U32(pHdr->u32Endpoint);
388}
389
390/**
391 * Converts a request/reply header from host to network endianness.
392 *
393 * @returns nothing.
394 * @param pHdr The header to convert.
395 */
396DECLINLINE(void) usbProxyUsbIpReqRetHdrH2N(PUsbIpReqRetHdr pHdr)
397{
398 pHdr->u32ReqRet = RT_N2H_U32(pHdr->u32ReqRet);
399 pHdr->u32SeqNum = RT_N2H_U32(pHdr->u32SeqNum);
400 pHdr->u32DevId = RT_N2H_U32(pHdr->u32DevId);
401 pHdr->u32Direction = RT_N2H_U32(pHdr->u32Direction);
402 pHdr->u32Endpoint = RT_N2H_U32(pHdr->u32Endpoint);
403}
404
405/**
406 * Converts a submit request from host to network endianness.
407 *
408 * @returns nothing.
409 * @param pReqSubmit The submit request to convert.
410 */
411DECLINLINE(void) usbProxyUsbIpReqSubmitH2N(PUsbIpReqSubmit pReqSubmit)
412{
413 usbProxyUsbIpReqRetHdrH2N(&pReqSubmit->Hdr);
414 pReqSubmit->u32XferFlags = RT_H2N_U32(pReqSubmit->u32XferFlags);
415 pReqSubmit->u32TransferBufferLength = RT_H2N_U32(pReqSubmit->u32TransferBufferLength);
416 pReqSubmit->u32StartFrame = RT_H2N_U32(pReqSubmit->u32StartFrame);
417 pReqSubmit->u32NumIsocPkts = RT_H2N_U32(pReqSubmit->u32NumIsocPkts);
418 pReqSubmit->u32Interval = RT_H2N_U32(pReqSubmit->u32Interval);
419}
420
421/**
422 * Converts a submit reply from network to host endianness.
423 *
424 * @returns nothing.
425 * @param pReqSubmit The submit reply to convert.
426 */
427DECLINLINE(void) usbProxyUsbIpRetSubmitN2H(PUsbIpRetSubmit pRetSubmit)
428{
429 usbProxyUsbIpReqRetHdrN2H(&pRetSubmit->Hdr);
430 pRetSubmit->u32Status = RT_N2H_U32(pRetSubmit->u32Status);
431 pRetSubmit->u32ActualLength = RT_N2H_U32(pRetSubmit->u32ActualLength);
432 pRetSubmit->u32StartFrame = RT_N2H_U32(pRetSubmit->u32StartFrame);
433 pRetSubmit->u32NumIsocPkts = RT_N2H_U32(pRetSubmit->u32NumIsocPkts);
434 pRetSubmit->u32ErrorCount = RT_N2H_U32(pRetSubmit->u32ErrorCount);
435}
436
437/**
438 * Converts a unlink request from host to network endianness.
439 *
440 * @returns nothing.
441 * @param pReqUnlink The unlink request to convert.
442 */
443DECLINLINE(void) usbProxyUsbIpReqUnlinkH2N(PUsbIpReqUnlink pReqUnlink)
444{
445 usbProxyUsbIpReqRetHdrH2N(&pReqUnlink->Hdr);
446 pReqUnlink->u32SeqNum = RT_H2N_U32(pReqUnlink->u32SeqNum);
447}
448
449/**
450 * Converts a unlink reply from network to host endianness.
451 *
452 * @returns nothing.
453 * @param pRetUnlink The unlink reply to convert.
454 */
455DECLINLINE(void) usbProxyUsbIpRetUnlinkN2H(PUsbIpRetUnlink pRetUnlink)
456{
457 usbProxyUsbIpReqRetHdrN2H(&pRetUnlink->Hdr);
458 pRetUnlink->u32Status = RT_N2H_U32(pRetUnlink->u32Status);
459}
460
461/**
462 * Convert the given exported device structure from host to network byte order.
463 *
464 * @returns nothing.
465 * @param pDevice The device structure to convert.
466 */
467DECLINLINE(void) usbProxyUsbIpExportedDeviceN2H(PUsbIpExportedDevice pDevice)
468{
469 pDevice->u32BusNum = RT_N2H_U32(pDevice->u32BusNum);
470 pDevice->u32DevNum = RT_N2H_U32(pDevice->u32DevNum);
471 pDevice->u32Speed = RT_N2H_U16(pDevice->u32Speed);
472 pDevice->u16VendorId = RT_N2H_U16(pDevice->u16VendorId);
473 pDevice->u16ProductId = RT_N2H_U16(pDevice->u16ProductId);
474 pDevice->u16BcdDevice = RT_N2H_U16(pDevice->u16BcdDevice);
475}
476
477/**
478 * Converts a USB/IP status code to a VUSB status code.
479 *
480 * @returns VUSB status code.
481 * @param i32Status The USB/IP status code from the reply.
482 */
483DECLINLINE(VUSBSTATUS) usbProxyUsbIpVUsbStatusConvertFromStatus(int32_t i32Status)
484{
485 if (RT_LIKELY(i32Status == USBIP_STATUS_SUCCESS))
486 return VUSBSTATUS_OK;
487
488 switch (i32Status)
489 {
490 case USBIP_STATUS_PIPE_STALLED:
491 return VUSBSTATUS_STALL;
492 default:
493 return VUSBSTATUS_DNR;
494 }
495
496 return VUSBSTATUS_DNR;
497}
498
499/**
500 * Gets the next free sequence number.
501 *
502 * @returns Next free sequence number.
503 * @param pProxyDevUsbIp The USB/IP proxy device data.
504 */
505DECLINLINE(uint32_t) usbProxyUsbIpSeqNumGet(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
506{
507 return ASMAtomicIncU32(&pProxyDevUsbIp->u32SeqNumNext);
508}
509
510/**
511 * Links a given URB into the given list.
512 *
513 * @returns nothing.
514 * @param pProxyDevUsbIp The USB/IP proxy device data.
515 * @param pList The list to link the URB into.
516 * @param pUrbUsbIp The URB to link.
517 */
518DECLINLINE(void) usbProxyUsbIpLinkUrb(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PRTLISTANCHOR pList, PUSBPROXYURBUSBIP pUrbUsbIp)
519{
520 int rc = RTSemFastMutexRequest(pProxyDevUsbIp->hMtxLists);
521 AssertRC(rc);
522 RTListAppend(pList, &pUrbUsbIp->NodeList);
523 RTSemFastMutexRelease(pProxyDevUsbIp->hMtxLists);
524}
525
526/**
527 * Unlinks a given URB from the current assigned list.
528 *
529 * @returns nothing.
530 * @param pProxyDevUsbIp The USB/IP proxy device data.
531 * @param pUrbUsbIp The URB to unlink.
532 */
533DECLINLINE(void) usbProxyUsbIpUnlinkUrb(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PUSBPROXYURBUSBIP pUrbUsbIp)
534{
535 int rc = RTSemFastMutexRequest(pProxyDevUsbIp->hMtxLists);
536 AssertRC(rc);
537 RTListNodeRemove(&pUrbUsbIp->NodeList);
538 RTSemFastMutexRelease(pProxyDevUsbIp->hMtxLists);
539}
540
541/**
542 * Allocates a USB/IP proxy specific URB state.
543 *
544 * @returns Pointer to the USB/IP specific URB data or NULL on failure.
545 * @param pProxyDevUsbIp The USB/IP proxy device data.
546 */
547static PUSBPROXYURBUSBIP usbProxyUsbIpUrbAlloc(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
548{
549 NOREF(pProxyDevUsbIp);
550 return (PUSBPROXYURBUSBIP)RTMemAllocZ(sizeof(USBPROXYURBUSBIP));
551}
552
553/**
554 * Frees the given USB/IP URB state.
555 *
556 * @returns nothing.
557 * @param pProxyDevUsbIp The USB/IP proxy device data.
558 * @param pUrbUsbIp The USB/IP speciic URB data.
559 */
560static void usbProxyUsbIpUrbFree(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PUSBPROXYURBUSBIP pUrbUsbIp)
561{
562 NOREF(pProxyDevUsbIp);
563 RTMemFree(pUrbUsbIp);
564}
565
566/**
567 * Parse the string representation of the host address.
568 *
569 * @returns VBox status code.
570 * @param pProxyDevUsbIp The USB/IP proxy device data to parse the address for.
571 * @param pszAddress The address string to parse.
572 */
573static int usbProxyUsbIpParseAddress(PUSBPROXYDEVUSBIP pProxyDevUsbIp, const char *pszAddress)
574{
575 int rc = VINF_SUCCESS;
576
577 if (!RTStrNCmp(pszAddress, USBIP_URI_PREFIX, USBIP_URI_PREFIX_LEN))
578 {
579 pszAddress += USBIP_URI_PREFIX_LEN;
580
581 const char *pszPortStart = RTStrStr(pszAddress, ":");
582 if (pszPortStart)
583 {
584 pszPortStart++;
585
586 const char *pszBusIdStart = RTStrStr(pszPortStart, ":");
587 if (pszBusIdStart)
588 {
589 size_t cbHost = pszPortStart - pszAddress - 1;
590 size_t cbBusId = strlen(pszBusIdStart);
591
592 pszBusIdStart++;
593
594 rc = RTStrToUInt32Ex(pszPortStart, NULL, 10 /* uBase */, &pProxyDevUsbIp->uPort);
595 if ( rc == VINF_SUCCESS
596 || rc == VWRN_TRAILING_CHARS)
597 {
598 rc = RTStrAllocEx(&pProxyDevUsbIp->pszHost, cbHost + 1);
599 if (RT_SUCCESS(rc))
600 rc = RTStrAllocEx(&pProxyDevUsbIp->pszBusId, cbBusId + 1);
601 if (RT_SUCCESS(rc))
602 {
603 rc = RTStrCopyEx(pProxyDevUsbIp->pszHost, cbHost + 1, pszAddress, cbHost);
604 AssertRC(rc);
605
606 rc = RTStrCopyEx(pProxyDevUsbIp->pszBusId, cbBusId + 1, pszBusIdStart, cbBusId);
607 AssertRC(rc);
608
609 return VINF_SUCCESS;
610 }
611 }
612 else
613 rc = VERR_INVALID_PARAMETER;
614 }
615 else
616 rc = VERR_INVALID_PARAMETER;
617 }
618 else
619 rc = VERR_INVALID_PARAMETER;
620 }
621 else
622 rc = VERR_INVALID_PARAMETER;
623
624 return rc;
625}
626
627/**
628 * Connects to the USB/IP host and claims the device given in the proxy device data.
629 *
630 * @returns VBox status.
631 * @param pProxyDevUsbIp The USB/IP proxy device data.
632 */
633static int usbProxyUsbIpConnect(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
634{
635 int rc = VINF_SUCCESS;
636 rc = RTTcpClientConnect(pProxyDevUsbIp->pszHost, pProxyDevUsbIp->uPort, &pProxyDevUsbIp->hSocket);
637 if (RT_SUCCESS(rc))
638 {
639 /* Disable send coalescing. */
640 rc = RTTcpSetSendCoalescing(pProxyDevUsbIp->hSocket, false);
641 if (RT_FAILURE(rc))
642 LogRel(("UsbIp: Disabling send coalescing failed (rc=%Rrc), continuing nevertheless but expect reduced performance\n", rc));
643
644 /* Import the device, i.e. claim it for our use. */
645 UsbIpReqImport ReqImport;
646 ReqImport.u16Version = RT_H2N_U16(USBIP_VERSION);
647 ReqImport.u16Cmd = RT_H2N_U16(USBIP_INDICATOR_REQ | USBIP_REQ_RET_IMPORT);
648 ReqImport.u32Status = RT_H2N_U32(USBIP_STATUS_SUCCESS);
649 rc = RTStrCopy(&ReqImport.aszBusId[0], sizeof(ReqImport.aszBusId), pProxyDevUsbIp->pszBusId);
650 if (rc == VINF_SUCCESS)
651 {
652 rc = RTTcpWrite(pProxyDevUsbIp->hSocket, &ReqImport, sizeof(ReqImport));
653 if (RT_SUCCESS(rc))
654 {
655 /* Read the reply. */
656 UsbIpRetImport RetImport;
657 rc = RTTcpRead(pProxyDevUsbIp->hSocket, &RetImport, sizeof(RetImport), NULL);
658 if (RT_SUCCESS(rc))
659 {
660 RetImport.u16Version = RT_N2H_U16(RetImport.u16Version);
661 RetImport.u16Cmd = RT_N2H_U16(RetImport.u16Cmd);
662 RetImport.u32Status = RT_N2H_U32(RetImport.u32Status);
663 if ( RetImport.u16Version == USBIP_VERSION
664 && RetImport.u16Cmd == USBIP_REQ_RET_IMPORT
665 && RetImport.u32Status == USBIP_STATUS_SUCCESS)
666 {
667 /* Read the device data. */
668 UsbIpExportedDevice Device;
669 rc = RTTcpRead(pProxyDevUsbIp->hSocket, &Device, sizeof(Device), NULL);
670 if (RT_SUCCESS(rc))
671 {
672 usbProxyUsbIpExportedDeviceN2H(&Device);
673 pProxyDevUsbIp->u32DevId = (Device.u32BusNum << 16) | Device.u32DevNum;
674
675 rc = RTPollSetAddSocket(pProxyDevUsbIp->hPollSet, pProxyDevUsbIp->hSocket,
676 RTPOLL_EVT_READ | RTPOLL_EVT_ERROR, USBIP_POLL_ID_SOCKET);
677 }
678 }
679 else
680 {
681 /* Check what went wrong and leave a meaningful error message in the log. */
682 if (RetImport.u16Version != USBIP_VERSION)
683 LogRel(("UsbIp: Unexpected protocol version received from host (%#x vs. %#x)\n",
684 RetImport.u16Version, USBIP_VERSION));
685 else if (RetImport.u16Cmd != USBIP_REQ_RET_IMPORT)
686 LogRel(("UsbIp: Unexpected reply code received from host (%#x vs. %#x)\n",
687 RetImport.u16Cmd, USBIP_REQ_RET_IMPORT));
688 else if (RetImport.u32Status != 0)
689 LogRel(("UsbIp: Claiming the device has failed on the host with an unspecified error\n"));
690 else
691 AssertMsgFailed(("Something went wrong with if condition\n"));
692 }
693 }
694 }
695 }
696 else
697 {
698 LogRel(("UsbIp: Given bus ID is exceeds permitted protocol length: %u vs %u\n",
699 strlen(pProxyDevUsbIp->pszBusId) + 1, sizeof(ReqImport.aszBusId)));
700 rc = VERR_INVALID_PARAMETER;
701 }
702
703 if (RT_FAILURE(rc))
704 RTTcpClientCloseEx(pProxyDevUsbIp->hSocket, false /*fGracefulShutdown*/);
705 }
706 if (RT_FAILURE(rc))
707 LogRel(("UsbIp: Connecting to the host %s failed with %Rrc\n", pProxyDevUsbIp->pszHost, rc));
708 return rc;
709}
710
711/**
712 * Disconnects from the USB/IP host releasing the device given in the proxy device data.
713 *
714 * @returns VBox status code.
715 * @param pProxyDevUsbIp The USB/IP proxy device data.
716 */
717static int usbProxyUsbIpDisconnect(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
718{
719 int rc = VINF_SUCCESS;
720
721 rc = RTTcpClientCloseEx(pProxyDevUsbIp->hSocket, false /*fGracefulShutdown*/);
722 if (RT_SUCCESS(rc))
723 pProxyDevUsbIp->hSocket = NIL_RTSOCKET;
724 return rc;
725}
726
727/**
728 * Synchronously exchange a given control message with the remote device.
729 *
730 * @eturns VBox status code.
731 * @param pProxyDevUsbIp The USB/IP proxy device data.
732 * @param pSetup The setup message.
733 *
734 * @note This method is only used to implement the *SetConfig, *SetInterface and *ClearHaltedEp
735 * callbacks because the USB/IP protocol lacks dedicated requests for these.
736 * @remark It is assumed that this method is never called while usbProxyUsbIpUrbReap is called
737 * on another thread.
738 */
739static int usbProxyUsbIpCtrlUrbExchangeSync(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PVUSBSETUP pSetup)
740{
741 int rc = VINF_SUCCESS;
742
743 UsbIpReqSubmit ReqSubmit;
744 uint32_t u32SeqNum = usbProxyUsbIpSeqNumGet(pProxyDevUsbIp);
745 ReqSubmit.Hdr.u32ReqRet = USBIP_CMD_SUBMIT;
746 ReqSubmit.Hdr.u32SeqNum = u32SeqNum;
747 ReqSubmit.Hdr.u32DevId = pProxyDevUsbIp->u32DevId;
748 ReqSubmit.Hdr.u32Direction = USBIP_DIR_OUT;
749 ReqSubmit.Hdr.u32Endpoint = 0; /* Only default control endpoint is allowed for these kind of messages. */
750 ReqSubmit.u32XferFlags = 0;
751 ReqSubmit.u32TransferBufferLength = 0;
752 ReqSubmit.u32StartFrame = 0;
753 ReqSubmit.u32NumIsocPkts = 0;
754 ReqSubmit.u32Interval = 0;
755 memcpy(&ReqSubmit.Setup, pSetup, sizeof(ReqSubmit.Setup));
756 usbProxyUsbIpReqSubmitH2N(&ReqSubmit);
757
758 /* Send the command. */
759 rc = RTTcpWrite(pProxyDevUsbIp->hSocket, &ReqSubmit, sizeof(ReqSubmit));
760 if (RT_SUCCESS(rc))
761 {
762 /* Wait for the response. */
763 /** @todo: Don't wait indefinitely long. */
764 UsbIpRetSubmit RetSubmit;
765 rc = RTTcpRead(pProxyDevUsbIp->hSocket, &RetSubmit, sizeof(RetSubmit), NULL);
766 if (RT_SUCCESS(rc))
767 {
768 usbProxyUsbIpRetSubmitN2H(&RetSubmit);
769 rc = usbProxyUsbIpVUsbStatusConvertFromStatus(RetSubmit.u32Status);
770 }
771 }
772 return rc;
773}
774
775/**
776 * Returns the URB matching the given sequence number from the in flight list.
777 *
778 * @returns pointer to the URB matching the given sequence number or NULL
779 * @param pProxyDevUsbIp The USB/IP proxy device data.
780 * @param u32SeqNum The sequence number to search for.
781 */
782static PUSBPROXYURBUSBIP usbProxyUsbIpGetUrbFromSeqNum(PUSBPROXYDEVUSBIP pProxyDevUsbIp, uint32_t u32SeqNum)
783{
784 bool fFound = false;
785 PUSBPROXYURBUSBIP pIt;
786
787 RTListForEach(&pProxyDevUsbIp->ListUrbsInFlight, pIt, USBPROXYURBUSBIP, NodeList)
788 {
789 if (pIt->u32SeqNumUrb == u32SeqNum)
790 {
791 fFound = true;
792 break;
793 }
794 }
795
796 return fFound ? pIt : NULL;
797}
798
799/**
800 * Resets the receive state for a new reply.
801 *
802 * @returns nothing.
803 * @param pProxyDevUsbIp The USB/IP proxy device data.
804 */
805static void usbProxyUsbIpResetRecvState(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
806{
807 pProxyDevUsbIp->fRecvData = false;
808 pProxyDevUsbIp->cbRecv = 0;
809 pProxyDevUsbIp->cbLeft = sizeof(UsbIpReqRetHdr);
810}
811
812/*
813 * The USB proxy device functions.
814 */
815
816static DECLCALLBACK(int) usbProxyUsbIpOpen(PUSBPROXYDEV pProxyDev, const char *pszAddress, void *pvBackend)
817{
818 LogFlowFunc(("pProxyDev=%p pszAddress=%s, pvBackend=%p\n", pProxyDev, pszAddress, pvBackend));
819
820 PUSBPROXYDEVUSBIP pDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
821 int rc = VINF_SUCCESS;
822
823 RTListInit(&pDevUsbIp->ListUrbsInFlight);
824 RTListInit(&pDevUsbIp->ListUrbsLanded);
825 pDevUsbIp->hSocket = NIL_RTSOCKET;
826 pDevUsbIp->hPollSet = NIL_RTPOLLSET;
827 pDevUsbIp->hPipeW = NIL_RTPIPE;
828 pDevUsbIp->hPipeR = NIL_RTPIPE;
829 pDevUsbIp->fWokenUp = false;
830 pDevUsbIp->u32SeqNumNext = 0;
831 pDevUsbIp->pszHost = NULL;
832 pDevUsbIp->pszBusId = NULL;
833 usbProxyUsbIpResetRecvState(pDevUsbIp);
834
835 rc = RTSemFastMutexCreate(&pDevUsbIp->hMtxLists);
836 if (RT_SUCCESS(rc))
837 {
838 /* Setup wakeup pipe and poll set first. */
839 rc = RTPipeCreate(&pDevUsbIp->hPipeR, &pDevUsbIp->hPipeW, 0);
840 if (RT_SUCCESS(rc))
841 {
842 rc = RTPollSetCreate(&pDevUsbIp->hPollSet);
843 if (RT_SUCCESS(rc))
844 {
845 rc = RTPollSetAddPipe(pDevUsbIp->hPollSet, pDevUsbIp->hPipeR,
846 RTPOLL_EVT_READ, USBIP_POLL_ID_PIPE);
847 if (RT_SUCCESS(rc))
848 {
849 /* Connect to the USB/IP host. */
850 rc = usbProxyUsbIpParseAddress(pDevUsbIp, pszAddress);
851 if (RT_SUCCESS(rc))
852 rc = usbProxyUsbIpConnect(pDevUsbIp);
853 }
854
855 if (RT_FAILURE(rc))
856 {
857 RTPollSetRemove(pDevUsbIp->hPollSet, USBIP_POLL_ID_PIPE);
858 int rc2 = RTPollSetDestroy(pDevUsbIp->hPollSet);
859 AssertRC(rc2);
860 }
861 }
862
863 if (RT_FAILURE(rc))
864 {
865 int rc2 = RTPipeClose(pDevUsbIp->hPipeR);
866 AssertRC(rc2);
867 rc2 = RTPipeClose(pDevUsbIp->hPipeW);
868 AssertRC(rc2);
869 }
870 }
871 }
872
873 return rc;
874}
875
876static DECLCALLBACK(void) usbProxyUsbIpClose(PUSBPROXYDEV pProxyDev)
877{
878 int rc = VINF_SUCCESS;
879 LogFlowFunc(("pProxyDev = %p\n", pProxyDev));
880
881 PUSBPROXYDEVUSBIP pDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
882 /* Destroy the pipe and pollset if necessary. */
883 if (pDevUsbIp->hPollSet != NIL_RTPOLLSET)
884 {
885 if (pDevUsbIp->hSocket != NIL_RTSOCKET)
886 {
887 rc = RTPollSetRemove(pDevUsbIp->hPollSet, USBIP_POLL_ID_SOCKET);
888 Assert(RT_SUCCESS(rc) || rc == VERR_POLL_HANDLE_ID_NOT_FOUND);
889 }
890 rc = RTPollSetRemove(pDevUsbIp->hPollSet, USBIP_POLL_ID_PIPE);
891 AssertRC(rc);
892 rc = RTPollSetDestroy(pDevUsbIp->hPollSet);
893 AssertRC(rc);
894 rc = RTPipeClose(pDevUsbIp->hPipeR);
895 AssertRC(rc);
896 rc = RTPipeClose(pDevUsbIp->hPipeW);
897 AssertRC(rc);
898 }
899
900 if (pDevUsbIp->hSocket != NIL_RTSOCKET)
901 usbProxyUsbIpDisconnect(pDevUsbIp);
902 if (pDevUsbIp->pszHost)
903 RTStrFree(pDevUsbIp->pszHost);
904 if (pDevUsbIp->pszBusId)
905 RTStrFree(pDevUsbIp->pszBusId);
906
907 /* Clear the URB lists. */
908 rc = RTSemFastMutexRequest(pDevUsbIp->hMtxLists);
909 AssertRC(rc);
910 PUSBPROXYURBUSBIP pIter = NULL;
911 PUSBPROXYURBUSBIP pIterNext = NULL;
912 RTListForEachSafe(&pDevUsbIp->ListUrbsInFlight, pIter, pIterNext, USBPROXYURBUSBIP, NodeList)
913 {
914 RTListNodeRemove(&pIter->NodeList);
915 RTMemFree(pIter);
916 }
917
918 RTListForEachSafe(&pDevUsbIp->ListUrbsLanded, pIter, pIterNext, USBPROXYURBUSBIP, NodeList)
919 {
920 RTListNodeRemove(&pIter->NodeList);
921 RTMemFree(pIter);
922 }
923 RTSemFastMutexRelease(pDevUsbIp->hMtxLists);
924 RTSemFastMutexDestroy(pDevUsbIp->hMtxLists);
925}
926
927static DECLCALLBACK(int) usbProxyUsbIpReset(PUSBPROXYDEV pProxyDev, bool fResetOnLinux)
928{
929 LogFlowFunc(("pProxyDev = %p\n", pProxyDev));
930
931 PUSBPROXYDEVUSBIP pDev = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
932 return VINF_SUCCESS; /* No way to reset the device with the current protocol. */
933}
934
935static DECLCALLBACK(int) usbProxyUsbIpSetConfig(PUSBPROXYDEV pProxyDev, int iCfg)
936{
937 LogFlowFunc(("pProxyDev=%s cfg=%#x\n", pProxyDev->pUsbIns->pszName, iCfg));
938
939 PUSBPROXYDEVUSBIP pDev = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
940 VUSBSETUP Setup;
941
942 Setup.bmRequestType = 0;
943 Setup.bRequest = 0x09;
944 Setup.wValue = iCfg;
945 Setup.wIndex = 0;
946 Setup.wLength = 0;
947 return usbProxyUsbIpCtrlUrbExchangeSync(pDev, &Setup);
948}
949
950static DECLCALLBACK(int) usbProxyUsbIpClaimInterface(PUSBPROXYDEV pProxyDev, int ifnum)
951{
952 LogFlowFunc(("pProxyDev=%s ifnum=%#x\n", pProxyDev->pUsbIns->pszName, ifnum));
953 return VINF_SUCCESS;
954}
955
956static DECLCALLBACK(int) usbProxyUsbIpReleaseInterface(PUSBPROXYDEV pProxyDev, int ifnum)
957{
958 LogFlowFunc(("pProxyDev=%s ifnum=%#x\n", pProxyDev->pUsbIns->pszName, ifnum));
959 return VINF_SUCCESS;
960}
961
962static DECLCALLBACK(int) usbProxyUsbIpSetInterface(PUSBPROXYDEV pProxyDev, int ifnum, int setting)
963{
964 LogFlowFunc(("pProxyDev=%p ifnum=%#x setting=%#x\n", pProxyDev, ifnum, setting));
965
966 PUSBPROXYDEVUSBIP pDev = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
967 VUSBSETUP Setup;
968
969 Setup.bmRequestType = 0x1;
970 Setup.bRequest = 0x11; /* SET_INTERFACE */
971 Setup.wValue = setting;
972 Setup.wIndex = ifnum;
973 Setup.wLength = 0;
974 return usbProxyUsbIpCtrlUrbExchangeSync(pDev, &Setup);
975}
976
977static DECLCALLBACK(int) usbProxyUsbIpClearHaltedEp(PUSBPROXYDEV pProxyDev, unsigned int iEp)
978{
979 LogFlowFunc(("pProxyDev=%s ep=%u\n", pProxyDev->pUsbIns->pszName, iEp));
980
981 PUSBPROXYDEVUSBIP pDev = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
982 VUSBSETUP Setup;
983
984 Setup.bmRequestType = 0x2;
985 Setup.bRequest = 0x01; /* CLEAR_FEATURE */
986 Setup.wValue = 0x00; /* ENDPOINT_HALT */
987 Setup.wIndex = iEp;
988 Setup.wLength = 0;
989 return usbProxyUsbIpCtrlUrbExchangeSync(pDev, &Setup);
990}
991
992static DECLCALLBACK(int) usbProxyUsbIpUrbQueue(PUSBPROXYDEV pProxyDev, PVUSBURB pUrb)
993{
994 LogFlowFunc(("pUrb=%p\n", pUrb));
995
996 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
997
998 /* Allocate a USB/IP Urb. */
999 PUSBPROXYURBUSBIP pUrbUsbIp = usbProxyUsbIpUrbAlloc(pProxyDevUsbIp);
1000 if (!pUrbUsbIp)
1001 return VERR_NO_MEMORY;
1002
1003 pUrbUsbIp->u32SeqNumUrb = usbProxyUsbIpSeqNumGet(pProxyDevUsbIp);
1004
1005 UsbIpReqSubmit ReqSubmit;
1006 ReqSubmit.Hdr.u32ReqRet = USBIP_CMD_SUBMIT;
1007 ReqSubmit.Hdr.u32SeqNum = pUrbUsbIp->u32SeqNumUrb;
1008 ReqSubmit.Hdr.u32DevId = pProxyDevUsbIp->u32DevId;
1009 ReqSubmit.Hdr.u32Endpoint = pUrb->EndPt;
1010 ReqSubmit.Hdr.u32Direction = pUrb->enmDir == VUSBDIRECTION_IN ? USBIP_DIR_IN : USBIP_DIR_OUT;
1011 ReqSubmit.u32XferFlags = 0;
1012 if (pUrb->enmDir == VUSBDIRECTION_IN && pUrb->fShortNotOk)
1013 ReqSubmit.u32XferFlags |= USBIP_XFER_FLAGS_SHORT_NOT_OK;
1014
1015 ReqSubmit.u32TransferBufferLength = pUrb->cbData;
1016 ReqSubmit.u32StartFrame = 0;
1017 ReqSubmit.u32NumIsocPkts = 0;
1018 ReqSubmit.u32Interval = 0;
1019
1020 switch (pUrb->enmType)
1021 {
1022 case VUSBXFERTYPE_MSG:
1023 memcpy(&ReqSubmit.Setup, &pUrb->abData, sizeof(ReqSubmit.Setup));
1024 LogFlowFunc(("Message (Control) URB\n"));
1025 break;
1026 case VUSBXFERTYPE_ISOC:
1027 ReqSubmit.u32XferFlags |= USBIP_XFER_FLAGS_ISO_ASAP;
1028 ReqSubmit.u32NumIsocPkts = pUrb->cIsocPkts;
1029#if 0
1030 for (unsigned i = 0; i < pUrb->cIsocPkts; i++)
1031 {
1032 pUrbLnx->KUrb.iso_frame_desc[i].length = pUrb->aIsocPkts[i].cb;
1033 pUrbLnx->KUrb.iso_frame_desc[i].actual_length = 0;
1034 pUrbLnx->KUrb.iso_frame_desc[i].status = 0x7fff;
1035 }
1036#else /** @todo: Implement isochronous support */
1037 usbProxyUsbIpUrbFree(pProxyDevUsbIp, pUrbUsbIp);
1038 return VERR_NOT_SUPPORTED;
1039#endif
1040 break;
1041 case VUSBXFERTYPE_BULK:
1042 case VUSBXFERTYPE_INTR:
1043 break;
1044 default:
1045 usbProxyUsbIpUrbFree(pProxyDevUsbIp, pUrbUsbIp);
1046 return VERR_INVALID_PARAMETER; /** @todo: better status code. */
1047 }
1048 usbProxyUsbIpReqSubmitH2N(&ReqSubmit);
1049
1050 /* Send the command. */
1051 RTSGBUF SgBufReq;
1052 RTSGSEG aSegReq[2];
1053 aSegReq[0].pvSeg = &ReqSubmit;
1054 aSegReq[0].cbSeg = sizeof(ReqSubmit);
1055 aSegReq[1].pvSeg = &pUrb->abData[0];
1056 aSegReq[1].cbSeg = pUrb->cbData;
1057 RTSgBufInit(&SgBufReq, &aSegReq[0], RT_ELEMENTS(aSegReq));
1058
1059 int rc = RTTcpSgWrite(pProxyDevUsbIp->hSocket, &SgBufReq);
1060 if (RT_SUCCESS(rc))
1061 {
1062 /* Link the URB into the list of in flight URBs. */
1063 pUrb->Dev.pvPrivate = pUrbUsbIp;
1064 pUrbUsbIp->pVUsbUrb = pUrb;
1065 usbProxyUsbIpLinkUrb(pProxyDevUsbIp, &pProxyDevUsbIp->ListUrbsInFlight, pUrbUsbIp);
1066 }
1067 else
1068 usbProxyUsbIpUrbFree(pProxyDevUsbIp, pUrbUsbIp);
1069
1070 return rc;
1071}
1072
1073static DECLCALLBACK(PVUSBURB) usbProxyUsbIpUrbReap(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies)
1074{
1075 LogFlowFunc(("pProxyDev=%s\n", pProxyDev->pUsbIns->pszName));
1076
1077 PUSBPROXYDEVUSBIP pDev = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1078 PUSBPROXYURBUSBIP pUrbUsbIp = NULL;
1079 PVUSBURB pUrb = NULL;
1080 int rc = VINF_SUCCESS;
1081
1082 /* Any URBs pending delivery? */
1083 if (!RTListIsEmpty(&pDev->ListUrbsLanded))
1084 pUrbUsbIp = RTListGetFirst(&pDev->ListUrbsLanded, USBPROXYURBUSBIP, NodeList);
1085
1086 while (!pUrbUsbIp && RT_SUCCESS(rc) && cMillies)
1087 {
1088 if (!ASMAtomicXchgBool(&pDev->fWokenUp, false))
1089 {
1090 uint32_t uIdReady = 0;
1091 uint32_t fEventsRecv = 0;
1092 RTMSINTERVAL msStart = RTTimeMilliTS();
1093 RTMSINTERVAL msNow;
1094
1095 rc = RTPoll(pDev->hPollSet, cMillies, &fEventsRecv, &uIdReady);
1096 Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT);
1097
1098 msNow = RTTimeMilliTS();
1099 cMillies = msNow - msStart >= cMillies ? 0 : cMillies - (msNow - msStart);
1100
1101 if (RT_SUCCESS(rc))
1102 {
1103 if (uIdReady == USBIP_POLL_ID_SOCKET)
1104 {
1105 size_t cbRead = 0;
1106
1107 if (pDev->fRecvData)
1108 {
1109 /* Read data into the URB. */
1110 rc = RTTcpReadNB(pDev->hSocket, &pDev->pUrbUsbIp->pVUsbUrb->abData[pDev->cbRecv], pDev->cbLeft, &cbRead);
1111 if (RT_SUCCESS(rc))
1112 {
1113 if (!pDev->cbLeft)
1114 {
1115 pUrbUsbIp = pDev->pUrbUsbIp;
1116 usbProxyUsbIpResetRecvState(pDev);
1117 }
1118 }
1119 else
1120 {
1121 pUrbUsbIp = pDev->pUrbUsbIp;
1122 pUrbUsbIp->pVUsbUrb->enmStatus = VUSBSTATUS_DNR;
1123 usbProxyUsbIpResetRecvState(pDev);
1124 }
1125 }
1126 else
1127 {
1128 rc = RTTcpReadNB(pDev->hSocket, &pDev->BufRet.abReply[pDev->cbRecv], pDev->cbLeft, &cbRead);
1129 if (RT_SUCCESS(rc))
1130 {
1131 pDev->cbRecv += cbRead;
1132 pDev->cbLeft -= cbRead;
1133 }
1134
1135 /* Check whether we received a complete header. */
1136 if (!pDev->cbLeft)
1137 {
1138 if (pDev->cbRecv == sizeof(UsbIpReqRetHdr))
1139 {
1140 /*
1141 * Determine the residual amount of data to receive until
1142 * the complete reply header was received.
1143 */
1144 switch (RT_N2H_U32(pDev->BufRet.Hdr.u32ReqRet))
1145 {
1146 case USBIP_RET_SUBMIT:
1147 pDev->cbLeft = sizeof(UsbIpRetSubmit) - sizeof(UsbIpReqRetHdr);
1148 break;
1149 case USBIP_RET_UNLINK:
1150 pDev->cbLeft = sizeof(UsbIpRetUnlink) - sizeof(UsbIpReqRetHdr);
1151 break;
1152 default:
1153 AssertLogRelMsgFailed(("Invalid reply header received: %d\n",
1154 pDev->BufRet.Hdr.u32ReqRet));
1155 usbProxyUsbIpResetRecvState(pDev);
1156 }
1157 }
1158 else
1159 {
1160 AssertMsg(pDev->cbRecv > sizeof(UsbIpReqRetHdr), ("Invalid state\n"));
1161
1162 /* Get the URB from the in flight list. */
1163 pDev->pUrbUsbIp = usbProxyUsbIpGetUrbFromSeqNum(pDev, RT_N2H_U32(pDev->BufRet.Hdr.u32SeqNum));
1164 if (pDev->pUrbUsbIp)
1165 {
1166 /** @todo: Verify that the directions match. */
1167
1168 switch (RT_N2H_U32(pDev->BufRet.Hdr.u32ReqRet))
1169 {
1170 case USBIP_RET_SUBMIT:
1171 usbProxyUsbIpRetSubmitN2H(&pDev->BufRet.RetSubmit);
1172 pDev->pUrbUsbIp->pVUsbUrb->enmStatus = usbProxyUsbIpVUsbStatusConvertFromStatus(pDev->BufRet.RetSubmit.u32Status);
1173 if ( pDev->BufRet.Hdr.u32Direction == USBIP_DIR_IN
1174 && pDev->pUrbUsbIp->pVUsbUrb->enmStatus == VUSBSTATUS_OK)
1175 {
1176 pDev->fRecvData = true;
1177 pDev->cbRecv = 0;
1178 pDev->cbLeft = pDev->BufRet.RetSubmit.u32ActualLength;
1179 }
1180 else
1181 {
1182 Assert( pDev->BufRet.Hdr.u32Direction == USBIP_DIR_OUT
1183 || pDev->pUrbUsbIp->pVUsbUrb->enmStatus != VUSBSTATUS_OK);
1184 pUrbUsbIp = pDev->pUrbUsbIp;
1185 usbProxyUsbIpResetRecvState(pDev);
1186 }
1187 break;
1188 case USBIP_RET_UNLINK:
1189 usbProxyUsbIpRetUnlinkN2H(&pDev->BufRet.RetUnlink);
1190 pUrbUsbIp = pDev->pUrbUsbIp;
1191 pUrbUsbIp->pVUsbUrb->enmStatus = usbProxyUsbIpVUsbStatusConvertFromStatus(pDev->BufRet.RetUnlink.u32Status);
1192 usbProxyUsbIpResetRecvState(pDev);
1193 break;
1194 }
1195 }
1196 else
1197 {
1198 LogRel(("USB/IP: Received reply with sequence number doesn't match any local URB\n", pDev->BufRet.Hdr.u32SeqNum));
1199 usbProxyUsbIpResetRecvState(pDev);
1200 }
1201 }
1202 }
1203 }
1204 }
1205 else
1206 {
1207 uint8_t bRead = 0;
1208
1209 AssertLogRelMsg(uIdReady == USBIP_POLL_ID_PIPE, ("Invalid pollset ID given\n"));
1210 AssertMsg(pDev->fWokenUp, ("Pipe is not empty but no one woke the reaper thread\n"));
1211
1212 rc = RTPipeRead(pDev->hPipeR, &bRead, 1, NULL);
1213 AssertRC(rc);
1214 ASMAtomicXchgBool(&pDev->fWokenUp, false);
1215 }
1216 }
1217 }
1218 }
1219
1220 if (pUrbUsbIp)
1221 {
1222 pUrb = pUrbUsbIp->pVUsbUrb;
1223
1224 /* unlink from the pending delivery list */
1225 usbProxyUsbIpUnlinkUrb(pDev, pUrbUsbIp);
1226 usbProxyUsbIpUrbFree(pDev, pUrbUsbIp);
1227 }
1228
1229 return pUrb;
1230}
1231
1232static DECLCALLBACK(int) usbProxyUsbIpUrbCancel(PUSBPROXYDEV pProxyDev, PVUSBURB pUrb)
1233{
1234 LogFlowFunc(("pUrb=%p\n", pUrb));
1235
1236 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1237 PUSBPROXYURBUSBIP pUrbUsbIp = (PUSBPROXYURBUSBIP)pUrb->Dev.pvPrivate;
1238 UsbIpReqUnlink ReqUnlink;
1239
1240 uint32_t u32SeqNum = usbProxyUsbIpSeqNumGet(pProxyDevUsbIp);
1241 ReqUnlink.Hdr.u32ReqRet = USBIP_CMD_UNLINK;
1242 ReqUnlink.Hdr.u32SeqNum = u32SeqNum;
1243 ReqUnlink.Hdr.u32DevId = pProxyDevUsbIp->u32DevId;
1244 ReqUnlink.Hdr.u32Direction = USBIP_DIR_OUT;
1245 ReqUnlink.Hdr.u32Endpoint = pUrb->EndPt;
1246 ReqUnlink.u32SeqNum = pUrbUsbIp->u32SeqNumUrb;
1247
1248 return RTTcpWrite(pProxyDevUsbIp->hSocket, &ReqUnlink, sizeof(ReqUnlink));
1249}
1250
1251static DECLCALLBACK(int) usbProxyUsbIpWakeup(PUSBPROXYDEV pProxyDev)
1252{
1253 LogFlowFunc(("pProxyDev=%s\n", pProxyDev->pUsbIns->pszName));
1254
1255 PUSBPROXYDEVUSBIP pDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1256 int rc = VINF_SUCCESS;
1257
1258 if (!ASMAtomicXchgBool(&pDevUsbIp->fWokenUp, true))
1259 {
1260 size_t cbWritten = 0;
1261
1262 rc = RTPipeWrite(pDevUsbIp->hPipeW, "", 1, &cbWritten);
1263 Assert(RT_SUCCESS(rc) || cbWritten == 0);
1264 }
1265
1266 return rc;
1267}
1268
1269/**
1270 * The USB/IP USB Proxy Backend operations.
1271 */
1272extern const USBPROXYBACK g_USBProxyDeviceUsbIp =
1273{
1274 /* pszName */
1275 "usbip",
1276 /* cbBackend */
1277 sizeof(USBPROXYDEVUSBIP),
1278 usbProxyUsbIpOpen,
1279 NULL,
1280 usbProxyUsbIpClose,
1281 usbProxyUsbIpReset,
1282 usbProxyUsbIpSetConfig,
1283 usbProxyUsbIpClaimInterface,
1284 usbProxyUsbIpReleaseInterface,
1285 usbProxyUsbIpSetInterface,
1286 usbProxyUsbIpClearHaltedEp,
1287 usbProxyUsbIpUrbQueue,
1288 usbProxyUsbIpUrbCancel,
1289 usbProxyUsbIpUrbReap,
1290 usbProxyUsbIpWakeup,
1291 0
1292};
1293
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