VirtualBox

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

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

*: scm cleanup run.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 48.6 KB
Line 
1/* $Id: USBProxyDevice-usbip.cpp 57358 2015-08-14 15:16:38Z 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(1)
75/** URB direction - output. */
76#define USBIP_DIR_OUT UINT32_C(0)
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 /** Next sequence number to use for identifying submitted URBs. */
336 volatile uint32_t u32SeqNumNext;
337 /** Fast mutex protecting the lists below against concurrent access. */
338 RTSEMFASTMUTEX hMtxLists;
339 /** List of in flight URBs. */
340 RTLISTANCHOR ListUrbsInFlight;
341 /** List of landed URBs. */
342 RTLISTANCHOR ListUrbsLanded;
343 /** List of URBs to submit. */
344 RTLISTANCHOR ListUrbsToQueue;
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/** Waking reason for the USB I/P reaper: New URBs to queue. */
376#define USBIP_REAPER_WAKEUP_REASON_QUEUE 'Q'
377/** Waking reason for the USB I/P reaper: External wakeup. */
378#define USBIP_REAPER_WAKEUP_REASON_EXTERNAL 'E'
379
380/**
381 * Converts a request/reply header from network to host endianness.
382 *
383 * @returns nothing.
384 * @param pHdr The header to convert.
385 */
386DECLINLINE(void) usbProxyUsbIpReqRetHdrN2H(PUsbIpReqRetHdr pHdr)
387{
388 pHdr->u32ReqRet = RT_H2N_U32(pHdr->u32ReqRet);
389 pHdr->u32SeqNum = RT_H2N_U32(pHdr->u32SeqNum);
390 pHdr->u32DevId = RT_H2N_U32(pHdr->u32DevId);
391 pHdr->u32Direction = RT_H2N_U32(pHdr->u32Direction);
392 pHdr->u32Endpoint = RT_H2N_U32(pHdr->u32Endpoint);
393}
394
395/**
396 * Converts a request/reply header from host to network endianness.
397 *
398 * @returns nothing.
399 * @param pHdr The header to convert.
400 */
401DECLINLINE(void) usbProxyUsbIpReqRetHdrH2N(PUsbIpReqRetHdr pHdr)
402{
403 pHdr->u32ReqRet = RT_N2H_U32(pHdr->u32ReqRet);
404 pHdr->u32SeqNum = RT_N2H_U32(pHdr->u32SeqNum);
405 pHdr->u32DevId = RT_N2H_U32(pHdr->u32DevId);
406 pHdr->u32Direction = RT_N2H_U32(pHdr->u32Direction);
407 pHdr->u32Endpoint = RT_N2H_U32(pHdr->u32Endpoint);
408}
409
410/**
411 * Converts a submit request from host to network endianness.
412 *
413 * @returns nothing.
414 * @param pReqSubmit The submit request to convert.
415 */
416DECLINLINE(void) usbProxyUsbIpReqSubmitH2N(PUsbIpReqSubmit pReqSubmit)
417{
418 usbProxyUsbIpReqRetHdrH2N(&pReqSubmit->Hdr);
419 pReqSubmit->u32XferFlags = RT_H2N_U32(pReqSubmit->u32XferFlags);
420 pReqSubmit->u32TransferBufferLength = RT_H2N_U32(pReqSubmit->u32TransferBufferLength);
421 pReqSubmit->u32StartFrame = RT_H2N_U32(pReqSubmit->u32StartFrame);
422 pReqSubmit->u32NumIsocPkts = RT_H2N_U32(pReqSubmit->u32NumIsocPkts);
423 pReqSubmit->u32Interval = RT_H2N_U32(pReqSubmit->u32Interval);
424}
425
426/**
427 * Converts a submit reply from network to host endianness.
428 *
429 * @returns nothing.
430 * @param pReqSubmit The submit reply to convert.
431 */
432DECLINLINE(void) usbProxyUsbIpRetSubmitN2H(PUsbIpRetSubmit pRetSubmit)
433{
434 usbProxyUsbIpReqRetHdrN2H(&pRetSubmit->Hdr);
435 pRetSubmit->u32Status = RT_N2H_U32(pRetSubmit->u32Status);
436 pRetSubmit->u32ActualLength = RT_N2H_U32(pRetSubmit->u32ActualLength);
437 pRetSubmit->u32StartFrame = RT_N2H_U32(pRetSubmit->u32StartFrame);
438 pRetSubmit->u32NumIsocPkts = RT_N2H_U32(pRetSubmit->u32NumIsocPkts);
439 pRetSubmit->u32ErrorCount = RT_N2H_U32(pRetSubmit->u32ErrorCount);
440}
441
442/**
443 * Converts a unlink request from host to network endianness.
444 *
445 * @returns nothing.
446 * @param pReqUnlink The unlink request to convert.
447 */
448DECLINLINE(void) usbProxyUsbIpReqUnlinkH2N(PUsbIpReqUnlink pReqUnlink)
449{
450 usbProxyUsbIpReqRetHdrH2N(&pReqUnlink->Hdr);
451 pReqUnlink->u32SeqNum = RT_H2N_U32(pReqUnlink->u32SeqNum);
452}
453
454/**
455 * Converts a unlink reply from network to host endianness.
456 *
457 * @returns nothing.
458 * @param pRetUnlink The unlink reply to convert.
459 */
460DECLINLINE(void) usbProxyUsbIpRetUnlinkN2H(PUsbIpRetUnlink pRetUnlink)
461{
462 usbProxyUsbIpReqRetHdrN2H(&pRetUnlink->Hdr);
463 pRetUnlink->u32Status = RT_N2H_U32(pRetUnlink->u32Status);
464}
465
466/**
467 * Convert the given exported device structure from host to network byte order.
468 *
469 * @returns nothing.
470 * @param pDevice The device structure to convert.
471 */
472DECLINLINE(void) usbProxyUsbIpExportedDeviceN2H(PUsbIpExportedDevice pDevice)
473{
474 pDevice->u32BusNum = RT_N2H_U32(pDevice->u32BusNum);
475 pDevice->u32DevNum = RT_N2H_U32(pDevice->u32DevNum);
476 pDevice->u32Speed = RT_N2H_U16(pDevice->u32Speed);
477 pDevice->u16VendorId = RT_N2H_U16(pDevice->u16VendorId);
478 pDevice->u16ProductId = RT_N2H_U16(pDevice->u16ProductId);
479 pDevice->u16BcdDevice = RT_N2H_U16(pDevice->u16BcdDevice);
480}
481
482/**
483 * Converts a USB/IP status code to a VUSB status code.
484 *
485 * @returns VUSB status code.
486 * @param i32Status The USB/IP status code from the reply.
487 */
488DECLINLINE(VUSBSTATUS) usbProxyUsbIpVUsbStatusConvertFromStatus(int32_t i32Status)
489{
490 if (RT_LIKELY(i32Status == USBIP_STATUS_SUCCESS))
491 return VUSBSTATUS_OK;
492
493 switch (i32Status)
494 {
495 case USBIP_STATUS_PIPE_STALLED:
496 return VUSBSTATUS_STALL;
497 default:
498 return VUSBSTATUS_DNR;
499 }
500
501 return VUSBSTATUS_DNR;
502}
503
504/**
505 * Gets the next free sequence number.
506 *
507 * @returns Next free sequence number.
508 * @param pProxyDevUsbIp The USB/IP proxy device data.
509 */
510DECLINLINE(uint32_t) usbProxyUsbIpSeqNumGet(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
511{
512 return ASMAtomicIncU32(&pProxyDevUsbIp->u32SeqNumNext);
513}
514
515/**
516 * Links a given URB into the given list.
517 *
518 * @returns nothing.
519 * @param pProxyDevUsbIp The USB/IP proxy device data.
520 * @param pList The list to link the URB into.
521 * @param pUrbUsbIp The URB to link.
522 */
523DECLINLINE(void) usbProxyUsbIpLinkUrb(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PRTLISTANCHOR pList, PUSBPROXYURBUSBIP pUrbUsbIp)
524{
525 int rc = RTSemFastMutexRequest(pProxyDevUsbIp->hMtxLists);
526 AssertRC(rc);
527 RTListAppend(pList, &pUrbUsbIp->NodeList);
528 RTSemFastMutexRelease(pProxyDevUsbIp->hMtxLists);
529}
530
531/**
532 * Unlinks a given URB from the current assigned list.
533 *
534 * @returns nothing.
535 * @param pProxyDevUsbIp The USB/IP proxy device data.
536 * @param pUrbUsbIp The URB to unlink.
537 */
538DECLINLINE(void) usbProxyUsbIpUnlinkUrb(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PUSBPROXYURBUSBIP pUrbUsbIp)
539{
540 int rc = RTSemFastMutexRequest(pProxyDevUsbIp->hMtxLists);
541 AssertRC(rc);
542 RTListNodeRemove(&pUrbUsbIp->NodeList);
543 RTSemFastMutexRelease(pProxyDevUsbIp->hMtxLists);
544}
545
546/**
547 * Allocates a USB/IP proxy specific URB state.
548 *
549 * @returns Pointer to the USB/IP specific URB data or NULL on failure.
550 * @param pProxyDevUsbIp The USB/IP proxy device data.
551 */
552static PUSBPROXYURBUSBIP usbProxyUsbIpUrbAlloc(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
553{
554 NOREF(pProxyDevUsbIp);
555 return (PUSBPROXYURBUSBIP)RTMemAllocZ(sizeof(USBPROXYURBUSBIP));
556}
557
558/**
559 * Frees the given USB/IP URB state.
560 *
561 * @returns nothing.
562 * @param pProxyDevUsbIp The USB/IP proxy device data.
563 * @param pUrbUsbIp The USB/IP speciic URB data.
564 */
565static void usbProxyUsbIpUrbFree(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PUSBPROXYURBUSBIP pUrbUsbIp)
566{
567 NOREF(pProxyDevUsbIp);
568 RTMemFree(pUrbUsbIp);
569}
570
571/**
572 * Parse the string representation of the host address.
573 *
574 * @returns VBox status code.
575 * @param pProxyDevUsbIp The USB/IP proxy device data to parse the address for.
576 * @param pszAddress The address string to parse.
577 */
578static int usbProxyUsbIpParseAddress(PUSBPROXYDEVUSBIP pProxyDevUsbIp, const char *pszAddress)
579{
580 int rc = VINF_SUCCESS;
581
582 if (!RTStrNCmp(pszAddress, USBIP_URI_PREFIX, USBIP_URI_PREFIX_LEN))
583 {
584 pszAddress += USBIP_URI_PREFIX_LEN;
585
586 const char *pszPortStart = RTStrStr(pszAddress, ":");
587 if (pszPortStart)
588 {
589 pszPortStart++;
590
591 const char *pszBusIdStart = RTStrStr(pszPortStart, ":");
592 if (pszBusIdStart)
593 {
594 size_t cbHost = pszPortStart - pszAddress - 1;
595 size_t cbBusId = strlen(pszBusIdStart);
596
597 pszBusIdStart++;
598
599 rc = RTStrToUInt32Ex(pszPortStart, NULL, 10 /* uBase */, &pProxyDevUsbIp->uPort);
600 if ( rc == VINF_SUCCESS
601 || rc == VWRN_TRAILING_CHARS)
602 {
603 rc = RTStrAllocEx(&pProxyDevUsbIp->pszHost, cbHost + 1);
604 if (RT_SUCCESS(rc))
605 rc = RTStrAllocEx(&pProxyDevUsbIp->pszBusId, cbBusId + 1);
606 if (RT_SUCCESS(rc))
607 {
608 rc = RTStrCopyEx(pProxyDevUsbIp->pszHost, cbHost + 1, pszAddress, cbHost);
609 AssertRC(rc);
610
611 rc = RTStrCopyEx(pProxyDevUsbIp->pszBusId, cbBusId + 1, pszBusIdStart, cbBusId);
612 AssertRC(rc);
613
614 return VINF_SUCCESS;
615 }
616 }
617 else
618 rc = VERR_INVALID_PARAMETER;
619 }
620 else
621 rc = VERR_INVALID_PARAMETER;
622 }
623 else
624 rc = VERR_INVALID_PARAMETER;
625 }
626 else
627 rc = VERR_INVALID_PARAMETER;
628
629 return rc;
630}
631
632/**
633 * Connects to the USB/IP host and claims the device given in the proxy device data.
634 *
635 * @returns VBox status.
636 * @param pProxyDevUsbIp The USB/IP proxy device data.
637 */
638static int usbProxyUsbIpConnect(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
639{
640 int rc = VINF_SUCCESS;
641 rc = RTTcpClientConnect(pProxyDevUsbIp->pszHost, pProxyDevUsbIp->uPort, &pProxyDevUsbIp->hSocket);
642 if (RT_SUCCESS(rc))
643 {
644 /* Disable send coalescing. */
645 rc = RTTcpSetSendCoalescing(pProxyDevUsbIp->hSocket, false);
646 if (RT_FAILURE(rc))
647 LogRel(("UsbIp: Disabling send coalescing failed (rc=%Rrc), continuing nevertheless but expect reduced performance\n", rc));
648
649 /* Import the device, i.e. claim it for our use. */
650 UsbIpReqImport ReqImport;
651 ReqImport.u16Version = RT_H2N_U16(USBIP_VERSION);
652 ReqImport.u16Cmd = RT_H2N_U16(USBIP_INDICATOR_REQ | USBIP_REQ_RET_IMPORT);
653 ReqImport.u32Status = RT_H2N_U32(USBIP_STATUS_SUCCESS);
654 rc = RTStrCopy(&ReqImport.aszBusId[0], sizeof(ReqImport.aszBusId), pProxyDevUsbIp->pszBusId);
655 if (rc == VINF_SUCCESS)
656 {
657 rc = RTTcpWrite(pProxyDevUsbIp->hSocket, &ReqImport, sizeof(ReqImport));
658 if (RT_SUCCESS(rc))
659 {
660 /* Read the reply. */
661 UsbIpRetImport RetImport;
662 rc = RTTcpRead(pProxyDevUsbIp->hSocket, &RetImport, sizeof(RetImport), NULL);
663 if (RT_SUCCESS(rc))
664 {
665 RetImport.u16Version = RT_N2H_U16(RetImport.u16Version);
666 RetImport.u16Cmd = RT_N2H_U16(RetImport.u16Cmd);
667 RetImport.u32Status = RT_N2H_U32(RetImport.u32Status);
668 if ( RetImport.u16Version == USBIP_VERSION
669 && RetImport.u16Cmd == USBIP_REQ_RET_IMPORT
670 && RetImport.u32Status == USBIP_STATUS_SUCCESS)
671 {
672 /* Read the device data. */
673 UsbIpExportedDevice Device;
674 rc = RTTcpRead(pProxyDevUsbIp->hSocket, &Device, sizeof(Device), NULL);
675 if (RT_SUCCESS(rc))
676 {
677 usbProxyUsbIpExportedDeviceN2H(&Device);
678 pProxyDevUsbIp->u32DevId = (Device.u32BusNum << 16) | Device.u32DevNum;
679
680 rc = RTPollSetAddSocket(pProxyDevUsbIp->hPollSet, pProxyDevUsbIp->hSocket,
681 RTPOLL_EVT_READ | RTPOLL_EVT_ERROR, USBIP_POLL_ID_SOCKET);
682 }
683 }
684 else
685 {
686 /* Check what went wrong and leave a meaningful error message in the log. */
687 if (RetImport.u16Version != USBIP_VERSION)
688 LogRel(("UsbIp: Unexpected protocol version received from host (%#x vs. %#x)\n",
689 RetImport.u16Version, USBIP_VERSION));
690 else if (RetImport.u16Cmd != USBIP_REQ_RET_IMPORT)
691 LogRel(("UsbIp: Unexpected reply code received from host (%#x vs. %#x)\n",
692 RetImport.u16Cmd, USBIP_REQ_RET_IMPORT));
693 else if (RetImport.u32Status != 0)
694 LogRel(("UsbIp: Claiming the device has failed on the host with an unspecified error\n"));
695 else
696 AssertMsgFailed(("Something went wrong with if condition\n"));
697 }
698 }
699 }
700 }
701 else
702 {
703 LogRel(("UsbIp: Given bus ID is exceeds permitted protocol length: %u vs %u\n",
704 strlen(pProxyDevUsbIp->pszBusId) + 1, sizeof(ReqImport.aszBusId)));
705 rc = VERR_INVALID_PARAMETER;
706 }
707
708 if (RT_FAILURE(rc))
709 RTTcpClientCloseEx(pProxyDevUsbIp->hSocket, false /*fGracefulShutdown*/);
710 }
711 if (RT_FAILURE(rc))
712 LogRel(("UsbIp: Connecting to the host %s failed with %Rrc\n", pProxyDevUsbIp->pszHost, rc));
713 return rc;
714}
715
716/**
717 * Disconnects from the USB/IP host releasing the device given in the proxy device data.
718 *
719 * @returns VBox status code.
720 * @param pProxyDevUsbIp The USB/IP proxy device data.
721 */
722static int usbProxyUsbIpDisconnect(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
723{
724 int rc = VINF_SUCCESS;
725
726 rc = RTTcpClientCloseEx(pProxyDevUsbIp->hSocket, false /*fGracefulShutdown*/);
727 if (RT_SUCCESS(rc))
728 pProxyDevUsbIp->hSocket = NIL_RTSOCKET;
729 return rc;
730}
731
732/**
733 * Synchronously exchange a given control message with the remote device.
734 *
735 * @eturns VBox status code.
736 * @param pProxyDevUsbIp The USB/IP proxy device data.
737 * @param pSetup The setup message.
738 *
739 * @note This method is only used to implement the *SetConfig, *SetInterface and *ClearHaltedEp
740 * callbacks because the USB/IP protocol lacks dedicated requests for these.
741 * @remark It is assumed that this method is never called while usbProxyUsbIpUrbReap is called
742 * on another thread.
743 */
744static int usbProxyUsbIpCtrlUrbExchangeSync(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PVUSBSETUP pSetup)
745{
746 int rc = VINF_SUCCESS;
747
748 UsbIpReqSubmit ReqSubmit;
749 uint32_t u32SeqNum = usbProxyUsbIpSeqNumGet(pProxyDevUsbIp);
750 ReqSubmit.Hdr.u32ReqRet = USBIP_CMD_SUBMIT;
751 ReqSubmit.Hdr.u32SeqNum = u32SeqNum;
752 ReqSubmit.Hdr.u32DevId = pProxyDevUsbIp->u32DevId;
753 ReqSubmit.Hdr.u32Direction = USBIP_DIR_OUT;
754 ReqSubmit.Hdr.u32Endpoint = 0; /* Only default control endpoint is allowed for these kind of messages. */
755 ReqSubmit.u32XferFlags = 0;
756 ReqSubmit.u32TransferBufferLength = 0;
757 ReqSubmit.u32StartFrame = 0;
758 ReqSubmit.u32NumIsocPkts = 0;
759 ReqSubmit.u32Interval = 0;
760 memcpy(&ReqSubmit.Setup, pSetup, sizeof(ReqSubmit.Setup));
761 usbProxyUsbIpReqSubmitH2N(&ReqSubmit);
762
763 /* Send the command. */
764 rc = RTTcpWrite(pProxyDevUsbIp->hSocket, &ReqSubmit, sizeof(ReqSubmit));
765 if (RT_SUCCESS(rc))
766 {
767 /* Wait for the response. */
768 /** @todo: Don't wait indefinitely long. */
769 UsbIpRetSubmit RetSubmit;
770 rc = RTTcpRead(pProxyDevUsbIp->hSocket, &RetSubmit, sizeof(RetSubmit), NULL);
771 if (RT_SUCCESS(rc))
772 {
773 usbProxyUsbIpRetSubmitN2H(&RetSubmit);
774 rc = usbProxyUsbIpVUsbStatusConvertFromStatus(RetSubmit.u32Status);
775 }
776 }
777 return rc;
778}
779
780/**
781 * Returns the URB matching the given sequence number from the in flight list.
782 *
783 * @returns pointer to the URB matching the given sequence number or NULL
784 * @param pProxyDevUsbIp The USB/IP proxy device data.
785 * @param u32SeqNum The sequence number to search for.
786 */
787static PUSBPROXYURBUSBIP usbProxyUsbIpGetUrbFromSeqNum(PUSBPROXYDEVUSBIP pProxyDevUsbIp, uint32_t u32SeqNum)
788{
789 bool fFound = false;
790 PUSBPROXYURBUSBIP pIt;
791
792 RTListForEach(&pProxyDevUsbIp->ListUrbsInFlight, pIt, USBPROXYURBUSBIP, NodeList)
793 {
794 if (pIt->u32SeqNumUrb == u32SeqNum)
795 {
796 fFound = true;
797 break;
798 }
799 }
800
801 return fFound ? pIt : NULL;
802}
803
804/**
805 * Resets the receive state for a new reply.
806 *
807 * @returns nothing.
808 * @param pProxyDevUsbIp The USB/IP proxy device data.
809 */
810static void usbProxyUsbIpResetRecvState(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
811{
812 pProxyDevUsbIp->fRecvData = false;
813 pProxyDevUsbIp->cbRecv = 0;
814 pProxyDevUsbIp->cbLeft = sizeof(UsbIpReqRetHdr);
815}
816
817/**
818 * Handles reception of a USB/IP PDU.
819 *
820 * @returns VBox status code.
821 * @param pProxyDevUsbIp The USB/IP proxy device data.
822 * @param ppUrbUsbIp Where to store the pointer to the USB/IP URB which completed.
823 * Will be NULL if the received PDU is not complete and we have
824 * have to wait for more data or on failure.
825 */
826static int usbProxyUsbIpRecvPdu(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PUSBPROXYURBUSBIP *ppUrbUsbIp)
827{
828 int rc = VINF_SUCCESS;
829 size_t cbRead = 0;
830 PUSBPROXYURBUSBIP pUrbUsbIp = NULL;
831
832 if (pProxyDevUsbIp->fRecvData)
833 {
834 /* Read data into the URB. */
835 rc = RTTcpReadNB(pProxyDevUsbIp->hSocket, &pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->abData[pProxyDevUsbIp->cbRecv], pProxyDevUsbIp->cbLeft, &cbRead);
836 if (RT_SUCCESS(rc))
837 {
838 pProxyDevUsbIp->cbRecv += cbRead;
839 pProxyDevUsbIp->cbLeft -= cbRead;
840
841 if (!pProxyDevUsbIp->cbLeft)
842 {
843 pUrbUsbIp = pProxyDevUsbIp->pUrbUsbIp;
844 usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
845 }
846 }
847 else
848 {
849 pUrbUsbIp = pProxyDevUsbIp->pUrbUsbIp;
850 pUrbUsbIp->pVUsbUrb->enmStatus = VUSBSTATUS_DNR;
851 usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
852 }
853 }
854 else
855 {
856 rc = RTTcpReadNB(pProxyDevUsbIp->hSocket, &pProxyDevUsbIp->BufRet.abReply[pProxyDevUsbIp->cbRecv], pProxyDevUsbIp->cbLeft, &cbRead);
857 if (RT_SUCCESS(rc))
858 {
859 pProxyDevUsbIp->cbRecv += cbRead;
860 pProxyDevUsbIp->cbLeft -= cbRead;
861 }
862
863 /* Check whether we received a complete header. */
864 if (!pProxyDevUsbIp->cbLeft)
865 {
866 if (pProxyDevUsbIp->cbRecv == sizeof(UsbIpReqRetHdr))
867 {
868 /*
869 * Determine the residual amount of data to receive until
870 * the complete reply header was received.
871 */
872 switch (RT_N2H_U32(pProxyDevUsbIp->BufRet.Hdr.u32ReqRet))
873 {
874 case USBIP_RET_SUBMIT:
875 pProxyDevUsbIp->cbLeft = sizeof(UsbIpRetSubmit) - sizeof(UsbIpReqRetHdr);
876 break;
877 case USBIP_RET_UNLINK:
878 pProxyDevUsbIp->cbLeft = sizeof(UsbIpRetUnlink) - sizeof(UsbIpReqRetHdr);
879 break;
880 default:
881 AssertLogRelMsgFailed(("Invalid reply header received: %d\n",
882 pProxyDevUsbIp->BufRet.Hdr.u32ReqRet));
883 usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
884 }
885 }
886 else
887 {
888 AssertMsg(pProxyDevUsbIp->cbRecv > sizeof(UsbIpReqRetHdr), ("Invalid state\n"));
889
890 /* Get the URB from the in flight list. */
891 pProxyDevUsbIp->pUrbUsbIp = usbProxyUsbIpGetUrbFromSeqNum(pProxyDevUsbIp, RT_N2H_U32(pProxyDevUsbIp->BufRet.Hdr.u32SeqNum));
892 if (pProxyDevUsbIp->pUrbUsbIp)
893 {
894 /** @todo: Verify that the directions match, verify that the length doesn't exceed the buffer. */
895
896 switch (RT_N2H_U32(pProxyDevUsbIp->BufRet.Hdr.u32ReqRet))
897 {
898 case USBIP_RET_SUBMIT:
899 usbProxyUsbIpRetSubmitN2H(&pProxyDevUsbIp->BufRet.RetSubmit);
900 pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->enmStatus = usbProxyUsbIpVUsbStatusConvertFromStatus(pProxyDevUsbIp->BufRet.RetSubmit.u32Status);
901 if ( pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->enmDir == VUSBDIRECTION_IN
902 && pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->enmStatus == VUSBSTATUS_OK)
903 {
904 pProxyDevUsbIp->fRecvData = true;
905 if (pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->enmType == VUSBXFERTYPE_MSG)
906 {
907 /* Preserve the setup request. */
908 pProxyDevUsbIp->cbRecv = sizeof(VUSBSETUP);
909 pProxyDevUsbIp->cbLeft = pProxyDevUsbIp->BufRet.RetSubmit.u32ActualLength;
910 pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->cbData = pProxyDevUsbIp->BufRet.RetSubmit.u32ActualLength + sizeof(VUSBSETUP);
911 }
912 else
913 {
914 pProxyDevUsbIp->cbRecv = 0;
915 pProxyDevUsbIp->cbLeft = pProxyDevUsbIp->BufRet.RetSubmit.u32ActualLength;
916 pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->cbData = pProxyDevUsbIp->BufRet.RetSubmit.u32ActualLength;
917 }
918 }
919 else
920 {
921 Assert( pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->enmDir == VUSBDIRECTION_OUT
922 || pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->enmStatus != VUSBSTATUS_OK);
923 pUrbUsbIp = pProxyDevUsbIp->pUrbUsbIp;
924 usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
925 }
926 break;
927 case USBIP_RET_UNLINK:
928 usbProxyUsbIpRetUnlinkN2H(&pProxyDevUsbIp->BufRet.RetUnlink);
929 pUrbUsbIp = pProxyDevUsbIp->pUrbUsbIp;
930 pUrbUsbIp->pVUsbUrb->enmStatus = usbProxyUsbIpVUsbStatusConvertFromStatus(pProxyDevUsbIp->BufRet.RetUnlink.u32Status);
931 usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
932 break;
933 }
934 }
935 else
936 {
937 LogRel(("USB/IP: Received reply with sequence number doesn't match any local URB\n", pProxyDevUsbIp->BufRet.Hdr.u32SeqNum));
938 usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
939 }
940 }
941 }
942 }
943
944 if (RT_SUCCESS(rc))
945 *ppUrbUsbIp = pUrbUsbIp;
946
947 return rc;
948}
949
950/**
951 * Worker for queueing an URB on the main I/O thread.
952 *
953 * @returns VBox status code.
954 * @param pProxyDevUsbIp The USB/IP proxy device data.
955 * @param pUrbUsbIp The USB/IP URB to queue.
956 */
957static int usbProxyUsbIpUrbQueueWorker(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PUSBPROXYURBUSBIP pUrbUsbIp)
958{
959 size_t cbData = 0;
960 void *pvData = NULL;
961 PVUSBURB pUrb = pUrbUsbIp->pVUsbUrb;
962
963 pUrbUsbIp->u32SeqNumUrb = usbProxyUsbIpSeqNumGet(pProxyDevUsbIp);
964
965 UsbIpReqSubmit ReqSubmit;
966 ReqSubmit.Hdr.u32ReqRet = USBIP_CMD_SUBMIT;
967 ReqSubmit.Hdr.u32SeqNum = pUrbUsbIp->u32SeqNumUrb;
968 ReqSubmit.Hdr.u32DevId = pProxyDevUsbIp->u32DevId;
969 ReqSubmit.Hdr.u32Endpoint = pUrb->EndPt;
970 ReqSubmit.Hdr.u32Direction = pUrb->enmDir == VUSBDIRECTION_IN ? USBIP_DIR_IN : USBIP_DIR_OUT;
971 ReqSubmit.u32XferFlags = 0;
972 if (pUrb->enmDir == VUSBDIRECTION_IN && pUrb->fShortNotOk)
973 ReqSubmit.u32XferFlags |= USBIP_XFER_FLAGS_SHORT_NOT_OK;
974
975 ReqSubmit.u32TransferBufferLength = pUrb->cbData;
976 ReqSubmit.u32StartFrame = 0;
977 ReqSubmit.u32NumIsocPkts = 0;
978 ReqSubmit.u32Interval = 0;
979
980 switch (pUrb->enmType)
981 {
982 case VUSBXFERTYPE_MSG:
983 memcpy(&ReqSubmit.Setup, &pUrb->abData, sizeof(ReqSubmit.Setup));
984 if (pUrb->enmDir == VUSBDIRECTION_OUT)
985 {
986 cbData = pUrb->cbData - sizeof(VUSBSETUP);
987 pvData = pUrb->abData + sizeof(VUSBSETUP);
988 }
989 else
990 cbData = 0;
991 LogFlowFunc(("Message (Control) URB\n"));
992 break;
993 case VUSBXFERTYPE_ISOC:
994 cbData = pUrb->cbData;
995 pvData = pUrb->abData;
996
997 ReqSubmit.u32XferFlags |= USBIP_XFER_FLAGS_ISO_ASAP;
998 ReqSubmit.u32NumIsocPkts = pUrb->cIsocPkts;
999#if 0
1000 for (unsigned i = 0; i < pUrb->cIsocPkts; i++)
1001 {
1002 pUrbLnx->KUrb.iso_frame_desc[i].length = pUrb->aIsocPkts[i].cb;
1003 pUrbLnx->KUrb.iso_frame_desc[i].actual_length = 0;
1004 pUrbLnx->KUrb.iso_frame_desc[i].status = 0x7fff;
1005 }
1006#else /** @todo: Implement isochronous support */
1007 usbProxyUsbIpUrbFree(pProxyDevUsbIp, pUrbUsbIp);
1008 return VERR_NOT_SUPPORTED;
1009#endif
1010 break;
1011 case VUSBXFERTYPE_BULK:
1012 case VUSBXFERTYPE_INTR:
1013 if (pUrb->enmDir == VUSBDIRECTION_OUT)
1014 {
1015 cbData = pUrb->cbData;
1016 pvData = pUrb->abData;
1017 }
1018 else
1019 cbData = 0;
1020 break;
1021 default:
1022 usbProxyUsbIpUrbFree(pProxyDevUsbIp, pUrbUsbIp);
1023 return VERR_INVALID_PARAMETER; /** @todo: better status code. */
1024 }
1025
1026 usbProxyUsbIpReqSubmitH2N(&ReqSubmit);
1027
1028 /* Send the command. */
1029 RTSGBUF SgBufReq;
1030 RTSGSEG aSegReq[2];
1031 aSegReq[0].pvSeg = &ReqSubmit;
1032 aSegReq[0].cbSeg = sizeof(ReqSubmit);
1033 aSegReq[1].pvSeg = pvData;
1034 aSegReq[1].cbSeg = cbData;
1035 RTSgBufInit(&SgBufReq, &aSegReq[0], RT_ELEMENTS(aSegReq));
1036
1037 int rc = RTTcpSgWrite(pProxyDevUsbIp->hSocket, &SgBufReq);
1038 if (RT_SUCCESS(rc))
1039 {
1040 /* Link the URB into the list of in flight URBs. */
1041 usbProxyUsbIpLinkUrb(pProxyDevUsbIp, &pProxyDevUsbIp->ListUrbsInFlight, pUrbUsbIp);
1042 }
1043
1044 return rc;
1045}
1046
1047/**
1048 * Queues all pending URBs from the list.
1049 *
1050 * @returns VBox status code.
1051 * @param pProxyDevUsbIp The USB/IP proxy device data.
1052 */
1053static int usbProxyUsbIpUrbsQueuePending(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
1054{
1055 RTLISTANCHOR ListUrbsPending;
1056
1057 RTListInit(&ListUrbsPending);
1058 int rc = RTSemFastMutexRequest(pProxyDevUsbIp->hMtxLists);
1059 AssertRC(rc);
1060 RTListMove(&ListUrbsPending, &pProxyDevUsbIp->ListUrbsToQueue);
1061 RTSemFastMutexRelease(pProxyDevUsbIp->hMtxLists);
1062
1063 PUSBPROXYURBUSBIP pIter = NULL;
1064 PUSBPROXYURBUSBIP pIterNext = NULL;
1065 RTListForEachSafe(&ListUrbsPending, pIter, pIterNext, USBPROXYURBUSBIP, NodeList)
1066 {
1067 RTListNodeRemove(&pIter->NodeList);
1068 rc = usbProxyUsbIpUrbQueueWorker(pProxyDevUsbIp, pIter);
1069 if (RT_FAILURE(rc))
1070 {
1071 /** @todo: Complete the URB with an error. */
1072 usbProxyUsbIpUrbFree(pProxyDevUsbIp, pIter);
1073 }
1074 }
1075
1076 return VINF_SUCCESS;
1077}
1078
1079/**
1080 * Kick the reaper thread.
1081 *
1082 * @returns VBox status code.
1083 * @param pProxyDevUsbIp The USB/IP proxy device data.
1084 * @param bReason The wakeup reason.
1085 */
1086static char usbProxyReaperKick(PUSBPROXYDEVUSBIP pProxyDevUsbIp, char bReason)
1087{
1088 int rc = VINF_SUCCESS;
1089 size_t cbWritten = 0;
1090
1091 rc = RTPipeWrite(pProxyDevUsbIp->hPipeW, &bReason, 1, &cbWritten);
1092 Assert(RT_SUCCESS(rc) || cbWritten == 0);
1093
1094 return rc;
1095}
1096
1097/**
1098 * Drain the wakeup pipe.
1099 *
1100 * @returns Wakeup reason.
1101 * @param pProxyDevUsbIp The USB/IP proxy device data.
1102 */
1103static char usbProxyUsbIpWakeupPipeDrain(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
1104{
1105 char bRead = 0;
1106 size_t cbRead = 0;
1107
1108 int rc = RTPipeRead(pProxyDevUsbIp->hPipeR, &bRead, 1, &cbRead);
1109 Assert(RT_SUCCESS(rc) && cbRead == 1);
1110
1111 return bRead;
1112}
1113
1114/*
1115 * The USB proxy device functions.
1116 */
1117
1118static DECLCALLBACK(int) usbProxyUsbIpOpen(PUSBPROXYDEV pProxyDev, const char *pszAddress, void *pvBackend)
1119{
1120 LogFlowFunc(("pProxyDev=%p pszAddress=%s, pvBackend=%p\n", pProxyDev, pszAddress, pvBackend));
1121
1122 PUSBPROXYDEVUSBIP pDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1123 int rc = VINF_SUCCESS;
1124
1125 RTListInit(&pDevUsbIp->ListUrbsInFlight);
1126 RTListInit(&pDevUsbIp->ListUrbsLanded);
1127 RTListInit(&pDevUsbIp->ListUrbsToQueue);
1128 pDevUsbIp->hSocket = NIL_RTSOCKET;
1129 pDevUsbIp->hPollSet = NIL_RTPOLLSET;
1130 pDevUsbIp->hPipeW = NIL_RTPIPE;
1131 pDevUsbIp->hPipeR = NIL_RTPIPE;
1132 pDevUsbIp->u32SeqNumNext = 0;
1133 pDevUsbIp->pszHost = NULL;
1134 pDevUsbIp->pszBusId = NULL;
1135 usbProxyUsbIpResetRecvState(pDevUsbIp);
1136
1137 rc = RTSemFastMutexCreate(&pDevUsbIp->hMtxLists);
1138 if (RT_SUCCESS(rc))
1139 {
1140 /* Setup wakeup pipe and poll set first. */
1141 rc = RTPipeCreate(&pDevUsbIp->hPipeR, &pDevUsbIp->hPipeW, 0);
1142 if (RT_SUCCESS(rc))
1143 {
1144 rc = RTPollSetCreate(&pDevUsbIp->hPollSet);
1145 if (RT_SUCCESS(rc))
1146 {
1147 rc = RTPollSetAddPipe(pDevUsbIp->hPollSet, pDevUsbIp->hPipeR,
1148 RTPOLL_EVT_READ, USBIP_POLL_ID_PIPE);
1149 if (RT_SUCCESS(rc))
1150 {
1151 /* Connect to the USB/IP host. */
1152 rc = usbProxyUsbIpParseAddress(pDevUsbIp, pszAddress);
1153 if (RT_SUCCESS(rc))
1154 rc = usbProxyUsbIpConnect(pDevUsbIp);
1155 }
1156
1157 if (RT_FAILURE(rc))
1158 {
1159 RTPollSetRemove(pDevUsbIp->hPollSet, USBIP_POLL_ID_PIPE);
1160 int rc2 = RTPollSetDestroy(pDevUsbIp->hPollSet);
1161 AssertRC(rc2);
1162 }
1163 }
1164
1165 if (RT_FAILURE(rc))
1166 {
1167 int rc2 = RTPipeClose(pDevUsbIp->hPipeR);
1168 AssertRC(rc2);
1169 rc2 = RTPipeClose(pDevUsbIp->hPipeW);
1170 AssertRC(rc2);
1171 }
1172 }
1173 }
1174
1175 return rc;
1176}
1177
1178static DECLCALLBACK(void) usbProxyUsbIpClose(PUSBPROXYDEV pProxyDev)
1179{
1180 int rc = VINF_SUCCESS;
1181 LogFlowFunc(("pProxyDev = %p\n", pProxyDev));
1182
1183 PUSBPROXYDEVUSBIP pDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1184 /* Destroy the pipe and pollset if necessary. */
1185 if (pDevUsbIp->hPollSet != NIL_RTPOLLSET)
1186 {
1187 if (pDevUsbIp->hSocket != NIL_RTSOCKET)
1188 {
1189 rc = RTPollSetRemove(pDevUsbIp->hPollSet, USBIP_POLL_ID_SOCKET);
1190 Assert(RT_SUCCESS(rc) || rc == VERR_POLL_HANDLE_ID_NOT_FOUND);
1191 }
1192 rc = RTPollSetRemove(pDevUsbIp->hPollSet, USBIP_POLL_ID_PIPE);
1193 AssertRC(rc);
1194 rc = RTPollSetDestroy(pDevUsbIp->hPollSet);
1195 AssertRC(rc);
1196 rc = RTPipeClose(pDevUsbIp->hPipeR);
1197 AssertRC(rc);
1198 rc = RTPipeClose(pDevUsbIp->hPipeW);
1199 AssertRC(rc);
1200 }
1201
1202 if (pDevUsbIp->hSocket != NIL_RTSOCKET)
1203 usbProxyUsbIpDisconnect(pDevUsbIp);
1204 if (pDevUsbIp->pszHost)
1205 RTStrFree(pDevUsbIp->pszHost);
1206 if (pDevUsbIp->pszBusId)
1207 RTStrFree(pDevUsbIp->pszBusId);
1208
1209 /* Clear the URB lists. */
1210 rc = RTSemFastMutexRequest(pDevUsbIp->hMtxLists);
1211 AssertRC(rc);
1212 PUSBPROXYURBUSBIP pIter = NULL;
1213 PUSBPROXYURBUSBIP pIterNext = NULL;
1214 RTListForEachSafe(&pDevUsbIp->ListUrbsInFlight, pIter, pIterNext, USBPROXYURBUSBIP, NodeList)
1215 {
1216 RTListNodeRemove(&pIter->NodeList);
1217 RTMemFree(pIter);
1218 }
1219
1220 RTListForEachSafe(&pDevUsbIp->ListUrbsLanded, pIter, pIterNext, USBPROXYURBUSBIP, NodeList)
1221 {
1222 RTListNodeRemove(&pIter->NodeList);
1223 RTMemFree(pIter);
1224 }
1225 RTSemFastMutexRelease(pDevUsbIp->hMtxLists);
1226 RTSemFastMutexDestroy(pDevUsbIp->hMtxLists);
1227}
1228
1229static DECLCALLBACK(int) usbProxyUsbIpReset(PUSBPROXYDEV pProxyDev, bool fResetOnLinux)
1230{
1231 LogFlowFunc(("pProxyDev = %p\n", pProxyDev));
1232
1233 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1234 return VINF_SUCCESS; /* No way to reset the device with the current protocol. */
1235}
1236
1237static DECLCALLBACK(int) usbProxyUsbIpSetConfig(PUSBPROXYDEV pProxyDev, int iCfg)
1238{
1239 LogFlowFunc(("pProxyDev=%s cfg=%#x\n", pProxyDev->pUsbIns->pszName, iCfg));
1240
1241 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1242 VUSBSETUP Setup;
1243
1244 Setup.bmRequestType = 0;
1245 Setup.bRequest = 0x09;
1246 Setup.wValue = iCfg;
1247 Setup.wIndex = 0;
1248 Setup.wLength = 0;
1249 return usbProxyUsbIpCtrlUrbExchangeSync(pProxyDevUsbIp, &Setup);
1250}
1251
1252static DECLCALLBACK(int) usbProxyUsbIpClaimInterface(PUSBPROXYDEV pProxyDev, int ifnum)
1253{
1254 LogFlowFunc(("pProxyDev=%s ifnum=%#x\n", pProxyDev->pUsbIns->pszName, ifnum));
1255 return VINF_SUCCESS;
1256}
1257
1258static DECLCALLBACK(int) usbProxyUsbIpReleaseInterface(PUSBPROXYDEV pProxyDev, int ifnum)
1259{
1260 LogFlowFunc(("pProxyDev=%s ifnum=%#x\n", pProxyDev->pUsbIns->pszName, ifnum));
1261 return VINF_SUCCESS;
1262}
1263
1264static DECLCALLBACK(int) usbProxyUsbIpSetInterface(PUSBPROXYDEV pProxyDev, int ifnum, int setting)
1265{
1266 LogFlowFunc(("pProxyDev=%p ifnum=%#x setting=%#x\n", pProxyDev, ifnum, setting));
1267
1268 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1269 VUSBSETUP Setup;
1270
1271 Setup.bmRequestType = 0x1;
1272 Setup.bRequest = 0x11; /* SET_INTERFACE */
1273 Setup.wValue = setting;
1274 Setup.wIndex = ifnum;
1275 Setup.wLength = 0;
1276 return usbProxyUsbIpCtrlUrbExchangeSync(pProxyDevUsbIp, &Setup);
1277}
1278
1279static DECLCALLBACK(int) usbProxyUsbIpClearHaltedEp(PUSBPROXYDEV pProxyDev, unsigned int iEp)
1280{
1281 LogFlowFunc(("pProxyDev=%s ep=%u\n", pProxyDev->pUsbIns->pszName, iEp));
1282
1283 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1284 VUSBSETUP Setup;
1285
1286 Setup.bmRequestType = 0x2;
1287 Setup.bRequest = 0x01; /* CLEAR_FEATURE */
1288 Setup.wValue = 0x00; /* ENDPOINT_HALT */
1289 Setup.wIndex = iEp;
1290 Setup.wLength = 0;
1291 return usbProxyUsbIpCtrlUrbExchangeSync(pProxyDevUsbIp, &Setup);
1292}
1293
1294static DECLCALLBACK(int) usbProxyUsbIpUrbQueue(PUSBPROXYDEV pProxyDev, PVUSBURB pUrb)
1295{
1296 LogFlowFunc(("pUrb=%p\n", pUrb));
1297
1298 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1299
1300 /* Allocate a USB/IP Urb. */
1301 PUSBPROXYURBUSBIP pUrbUsbIp = usbProxyUsbIpUrbAlloc(pProxyDevUsbIp);
1302 if (!pUrbUsbIp)
1303 return VERR_NO_MEMORY;
1304
1305 pUrbUsbIp->pVUsbUrb = pUrb;
1306 pUrb->Dev.pvPrivate = pUrbUsbIp;
1307
1308 int rc = RTSemFastMutexRequest(pProxyDevUsbIp->hMtxLists);
1309 AssertRC(rc);
1310 RTListAppend(&pProxyDevUsbIp->ListUrbsToQueue, &pUrbUsbIp->NodeList);
1311 RTSemFastMutexRelease(pProxyDevUsbIp->hMtxLists);
1312
1313 return usbProxyReaperKick(pProxyDevUsbIp, USBIP_REAPER_WAKEUP_REASON_QUEUE);
1314}
1315
1316static DECLCALLBACK(PVUSBURB) usbProxyUsbIpUrbReap(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies)
1317{
1318 LogFlowFunc(("pProxyDev=%s\n", pProxyDev->pUsbIns->pszName));
1319
1320 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1321 PUSBPROXYURBUSBIP pUrbUsbIp = NULL;
1322 PVUSBURB pUrb = NULL;
1323 int rc = VINF_SUCCESS;
1324
1325 /* Queue new URBs first. */
1326 rc = usbProxyUsbIpUrbsQueuePending(pProxyDevUsbIp);
1327 AssertRC(rc);
1328
1329 /* Any URBs pending delivery? */
1330 if (!RTListIsEmpty(&pProxyDevUsbIp->ListUrbsLanded))
1331 pUrbUsbIp = RTListGetFirst(&pProxyDevUsbIp->ListUrbsLanded, USBPROXYURBUSBIP, NodeList);
1332
1333 while (!pUrbUsbIp && RT_SUCCESS(rc) && cMillies)
1334 {
1335 uint32_t uIdReady = 0;
1336 uint32_t fEventsRecv = 0;
1337 RTMSINTERVAL msStart = RTTimeMilliTS();
1338 RTMSINTERVAL msNow;
1339
1340 rc = RTPoll(pProxyDevUsbIp->hPollSet, cMillies, &fEventsRecv, &uIdReady);
1341 Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT);
1342 if (RT_SUCCESS(rc))
1343 {
1344 msNow = RTTimeMilliTS();
1345 cMillies = msNow - msStart >= cMillies ? 0 : cMillies - (msNow - msStart);
1346
1347 if (uIdReady == USBIP_POLL_ID_SOCKET)
1348 rc = usbProxyUsbIpRecvPdu(pProxyDevUsbIp, &pUrbUsbIp);
1349 else
1350 {
1351 AssertLogRelMsg(uIdReady == USBIP_POLL_ID_PIPE, ("Invalid pollset ID given\n"));
1352
1353 char bReason = usbProxyUsbIpWakeupPipeDrain(pProxyDevUsbIp);
1354 if (bReason == USBIP_REAPER_WAKEUP_REASON_QUEUE)
1355 usbProxyUsbIpUrbsQueuePending(pProxyDevUsbIp);
1356 else
1357 {
1358 Assert(bReason == USBIP_REAPER_WAKEUP_REASON_EXTERNAL);
1359 break;
1360 }
1361 }
1362 }
1363 }
1364
1365 if (pUrbUsbIp)
1366 {
1367 pUrb = pUrbUsbIp->pVUsbUrb;
1368
1369 /* unlink from the pending delivery list */
1370 usbProxyUsbIpUnlinkUrb(pProxyDevUsbIp, pUrbUsbIp);
1371 usbProxyUsbIpUrbFree(pProxyDevUsbIp, pUrbUsbIp);
1372 }
1373
1374 return pUrb;
1375}
1376
1377static DECLCALLBACK(int) usbProxyUsbIpUrbCancel(PUSBPROXYDEV pProxyDev, PVUSBURB pUrb)
1378{
1379 LogFlowFunc(("pUrb=%p\n", pUrb));
1380
1381 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1382 PUSBPROXYURBUSBIP pUrbUsbIp = (PUSBPROXYURBUSBIP)pUrb->Dev.pvPrivate;
1383 UsbIpReqUnlink ReqUnlink;
1384
1385 uint32_t u32SeqNum = usbProxyUsbIpSeqNumGet(pProxyDevUsbIp);
1386 ReqUnlink.Hdr.u32ReqRet = USBIP_CMD_UNLINK;
1387 ReqUnlink.Hdr.u32SeqNum = u32SeqNum;
1388 ReqUnlink.Hdr.u32DevId = pProxyDevUsbIp->u32DevId;
1389 ReqUnlink.Hdr.u32Direction = USBIP_DIR_OUT;
1390 ReqUnlink.Hdr.u32Endpoint = pUrb->EndPt;
1391 ReqUnlink.u32SeqNum = pUrbUsbIp->u32SeqNumUrb;
1392
1393 usbProxyUsbIpReqUnlinkH2N(&ReqUnlink);
1394 return RTTcpWrite(pProxyDevUsbIp->hSocket, &ReqUnlink, sizeof(ReqUnlink));
1395}
1396
1397static DECLCALLBACK(int) usbProxyUsbIpWakeup(PUSBPROXYDEV pProxyDev)
1398{
1399 LogFlowFunc(("pProxyDev=%s\n", pProxyDev->pUsbIns->pszName));
1400
1401 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1402 return usbProxyReaperKick(pProxyDevUsbIp, USBIP_REAPER_WAKEUP_REASON_EXTERNAL);
1403}
1404
1405/**
1406 * The USB/IP USB Proxy Backend operations.
1407 */
1408extern const USBPROXYBACK g_USBProxyDeviceUsbIp =
1409{
1410 /* pszName */
1411 "usbip",
1412 /* cbBackend */
1413 sizeof(USBPROXYDEVUSBIP),
1414 usbProxyUsbIpOpen,
1415 NULL,
1416 usbProxyUsbIpClose,
1417 usbProxyUsbIpReset,
1418 usbProxyUsbIpSetConfig,
1419 usbProxyUsbIpClaimInterface,
1420 usbProxyUsbIpReleaseInterface,
1421 usbProxyUsbIpSetInterface,
1422 usbProxyUsbIpClearHaltedEp,
1423 usbProxyUsbIpUrbQueue,
1424 usbProxyUsbIpUrbCancel,
1425 usbProxyUsbIpUrbReap,
1426 usbProxyUsbIpWakeup,
1427 0
1428};
1429
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