VirtualBox

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

Last change on this file since 96622 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 64.6 KB
Line 
1/* $Id: USBProxyDevice-usbip.cpp 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * USB device proxy - USB/IP backend.
4 */
5
6/*
7 * Copyright (C) 2014-2022 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_DRV_USBPROXY
33
34#include <VBox/log.h>
35#include <VBox/err.h>
36#include <VBox/vmm/pdm.h>
37
38#include <iprt/asm.h>
39#include <iprt/assert.h>
40#include <iprt/alloc.h>
41#include <iprt/string.h>
42#include <iprt/socket.h>
43#include <iprt/poll.h>
44#include <iprt/tcp.h>
45#include <iprt/pipe.h>
46#include <iprt/list.h>
47#include <iprt/semaphore.h>
48
49#include "../USBProxyDevice.h"
50
51
52/*********************************************************************************************************************************
53* Constants And Macros, Structures and Typedefs *
54*********************************************************************************************************************************/
55
56/** The USB version number used for the protocol. */
57#define USBIP_VERSION UINT16_C(0x0111)
58/** Request indicator in the command code. */
59#define USBIP_INDICATOR_REQ RT_BIT(15)
60
61/** Command/Reply code for OP_REQ/RET_DEVLIST. */
62#define USBIP_REQ_RET_DEVLIST UINT16_C(5)
63/** Command/Reply code for OP_REQ/REP_IMPORT. */
64#define USBIP_REQ_RET_IMPORT UINT16_C(3)
65/** USB submit command identifier. */
66#define USBIP_CMD_SUBMIT UINT32_C(1)
67/** USB submit status identifier. */
68#define USBIP_RET_SUBMIT UINT32_C(3)
69/** URB unlink (cancel) command identifier. */
70#define USBIP_CMD_UNLINK UINT32_C(2)
71/** URB unlink (cancel) reply identifier. */
72#define USBIP_RET_UNLINK UINT32_C(4)
73
74/** Short read is not okay for the specified URB. */
75#define USBIP_XFER_FLAGS_SHORT_NOT_OK RT_BIT_32(0)
76/** Queue the isochronous URB as soon as possible. */
77#define USBIP_XFER_FLAGS_ISO_ASAP RT_BIT_32(1)
78/** Don't use DMA mappings for this URB. */
79#define USBIP_XFER_FLAGS_NO_TRANSFER_DMA_MAP RT_BIT_32(2)
80/** Explain - only applies to UHCI. */
81#define USBIP_XFER_FLAGS_FSBR RT_BIT_32(4)
82
83/** URB direction - input. */
84#define USBIP_DIR_IN UINT32_C(1)
85/** URB direction - output. */
86#define USBIP_DIR_OUT UINT32_C(0)
87
88/** @name USB/IP error codes.
89 * @{ */
90/** Success indicator. */
91#define USBIP_STATUS_SUCCESS INT32_C(0)
92/** Pipe stalled. */
93#define USBIP_STATUS_PIPE_STALLED INT32_C(-32)
94/** URB was unlinked by a call to usb_unlink_urb(). */
95#define USBIP_STATUS_URB_UNLINKED INT32_C(-104)
96/** Short read. */
97#define USBIP_STATUS_SHORT_READ INT32_C(-121)
98/** @} */
99
100/**
101 * Exported device entry in the OP_RET_DEVLIST reply.
102 */
103#pragma pack(1)
104typedef struct UsbIpExportedDevice
105{
106 /** Path of the device, zero terminated string. */
107 char szPath[256];
108 /** Bus ID of the exported device, zero terminated string. */
109 char szBusId[32];
110 /** Bus number. */
111 uint32_t u32BusNum;
112 /** Device number. */
113 uint32_t u32DevNum;
114 /** Speed indicator of the device. */
115 uint32_t u32Speed;
116 /** Vendor ID of the device. */
117 uint16_t u16VendorId;
118 /** Product ID of the device. */
119 uint16_t u16ProductId;
120 /** Device release number. */
121 uint16_t u16BcdDevice;
122 /** Device class. */
123 uint8_t bDeviceClass;
124 /** Device Subclass. */
125 uint8_t bDeviceSubClass;
126 /** Device protocol. */
127 uint8_t bDeviceProtocol;
128 /** Configuration value. */
129 uint8_t bConfigurationValue;
130 /** Current configuration value of the device. */
131 uint8_t bNumConfigurations;
132 /** Number of interfaces for the device. */
133 uint8_t bNumInterfaces;
134} UsbIpExportedDevice;
135/** Pointer to a exported device entry. */
136typedef UsbIpExportedDevice *PUsbIpExportedDevice;
137#pragma pack()
138AssertCompileSize(UsbIpExportedDevice, 312);
139
140/**
141 * Interface descriptor entry for an exported device.
142 */
143#pragma pack(1)
144typedef struct UsbIpDeviceInterface
145{
146 /** Intefrace class. */
147 uint8_t bInterfaceClass;
148 /** Interface sub class. */
149 uint8_t bInterfaceSubClass;
150 /** Interface protocol identifier. */
151 uint8_t bInterfaceProtocol;
152 /** Padding byte for alignment. */
153 uint8_t bPadding;
154} UsbIpDeviceInterface;
155/** Pointer to an interface descriptor entry. */
156typedef UsbIpDeviceInterface *PUsbIpDeviceInterface;
157#pragma pack()
158
159/**
160 * USB/IP Import request.
161 */
162#pragma pack(1)
163typedef struct UsbIpReqImport
164{
165 /** Protocol version number. */
166 uint16_t u16Version;
167 /** Command code. */
168 uint16_t u16Cmd;
169 /** Status field, unused. */
170 int32_t u32Status;
171 /** Bus Id of the device as zero terminated string. */
172 char aszBusId[32];
173} UsbIpReqImport;
174/** Pointer to a import request. */
175typedef UsbIpReqImport *PUsbIpReqImport;
176#pragma pack()
177
178/**
179 * USB/IP Import reply.
180 *
181 * This is only the header, for successful
182 * imports the device details are sent to as
183 * defined in UsbIpExportedDevice.
184 */
185#pragma pack(1)
186typedef struct UsbIpRetImport
187{
188 /** Protocol version number. */
189 uint16_t u16Version;
190 /** Command code. */
191 uint16_t u16Cmd;
192 /** Status field, unused. */
193 int32_t u32Status;
194} UsbIpRetImport;
195/** Pointer to a import reply. */
196typedef UsbIpRetImport *PUsbIpRetImport;
197#pragma pack()
198
199/**
200 * Command/Reply header common to the submit and unlink commands
201 * replies.
202 */
203#pragma pack(1)
204typedef struct UsbIpReqRetHdr
205{
206 /** Request/Return code. */
207 uint32_t u32ReqRet;
208 /** Sequence number to identify the URB. */
209 uint32_t u32SeqNum;
210 /** Device id. */
211 uint32_t u32DevId;
212 /** Direction of the endpoint (host->device, device->host). */
213 uint32_t u32Direction;
214 /** Endpoint number. */
215 uint32_t u32Endpoint;
216} UsbIpReqRetHdr;
217/** Pointer to a request/reply header. */
218typedef UsbIpReqRetHdr *PUsbIpReqRetHdr;
219#pragma pack()
220
221/**
222 * USB/IP Submit request.
223 */
224#pragma pack(1)
225typedef struct UsbIpReqSubmit
226{
227 /** The request header. */
228 UsbIpReqRetHdr Hdr;
229 /** Transfer flags for the URB. */
230 uint32_t u32XferFlags;
231 /** Transfer buffer length. */
232 uint32_t u32TransferBufferLength;
233 /** Frame to transmit an ISO frame. */
234 uint32_t u32StartFrame;
235 /** Number of isochronous packets. */
236 uint32_t u32NumIsocPkts;
237 /** Maximum time for the request on the server side host controller. */
238 uint32_t u32Interval;
239 /** Setup data for a control URB. */
240 VUSBSETUP Setup;
241} UsbIpReqSubmit;
242/** Pointer to a submit request. */
243typedef UsbIpReqSubmit *PUsbIpReqSubmit;
244#pragma pack()
245AssertCompileSize(UsbIpReqSubmit, 48);
246
247/**
248 * USB/IP Submit reply.
249 */
250#pragma pack(1)
251typedef struct UsbIpRetSubmit
252{
253 /** The reply header. */
254 UsbIpReqRetHdr Hdr;
255 /** Status code. */
256 int32_t u32Status;
257 /** Actual length of the reply buffer. */
258 uint32_t u32ActualLength;
259 /** The actual selected frame for a isochronous transmit. */
260 uint32_t u32StartFrame;
261 /** Number of isochronous packets. */
262 uint32_t u32NumIsocPkts;
263 /** Number of failed isochronous packets. */
264 uint32_t u32ErrorCount;
265 /** Setup data for a control URB. */
266 VUSBSETUP Setup;
267} UsbIpRetSubmit;
268/** Pointer to a submit reply. */
269typedef UsbIpRetSubmit *PUsbIpRetSubmit;
270#pragma pack()
271AssertCompileSize(UsbIpRetSubmit, 48);
272
273/**
274 * Unlink URB request.
275 */
276#pragma pack(1)
277typedef struct UsbIpReqUnlink
278{
279 /** The request header. */
280 UsbIpReqRetHdr Hdr;
281 /** The sequence number to unlink. */
282 uint32_t u32SeqNum;
283 /** Padding - unused. */
284 uint8_t abPadding[24];
285} UsbIpReqUnlink;
286/** Pointer to a URB unlink request. */
287typedef UsbIpReqUnlink *PUsbIpReqUnlink;
288#pragma pack()
289AssertCompileSize(UsbIpReqUnlink, 48);
290
291/**
292 * Unlink URB reply.
293 */
294#pragma pack(1)
295typedef struct UsbIpRetUnlink
296{
297 /** The reply header. */
298 UsbIpReqRetHdr Hdr;
299 /** Status of the request. */
300 int32_t u32Status;
301 /** Padding - unused. */
302 uint8_t abPadding[24];
303} UsbIpRetUnlink;
304/** Pointer to a URB unlink request. */
305typedef UsbIpRetUnlink *PUsbIpRetUnlink;
306#pragma pack()
307AssertCompileSize(UsbIpRetUnlink, 48);
308
309/**
310 * Union of possible replies from the server during normal operation.
311 */
312#pragma pack(1)
313typedef union UsbIpRet
314{
315 /** The header. */
316 UsbIpReqRetHdr Hdr;
317 /** Submit reply. */
318 UsbIpRetSubmit RetSubmit;
319 /** Unlink reply. */
320 UsbIpRetUnlink RetUnlink;
321 /** Byte view. */
322 uint8_t abReply[1];
323} UsbIpRet;
324/** Pointer to a reply union. */
325typedef UsbIpRet *PUsbIpRet;
326#pragma pack()
327
328/**
329 * Isochronous packet descriptor.
330*/
331#pragma pack(1)
332typedef struct UsbIpIsocPktDesc
333{
334 /** Offset */
335 uint32_t u32Offset;
336 /** Length of the packet including padding. */
337 uint32_t u32Length;
338 /** Size of the transmitted data. */
339 uint32_t u32ActualLength;
340 /** Completion status for this packet. */
341 int32_t i32Status;
342} UsbIpIsocPktDesc;
343/** Pointer to a isochronous packet descriptor. */
344typedef UsbIpIsocPktDesc *PUsbIpIsocPktDesc;
345#pragma pack()
346
347/**
348 * USB/IP backend specific data for one URB.
349 * Required for tracking in flight and landed URBs.
350 */
351typedef struct USBPROXYURBUSBIP
352{
353 /** List node for the in flight or landed URB list. */
354 RTLISTNODE NodeList;
355 /** Sequence number the assigned URB is identified by. */
356 uint32_t u32SeqNumUrb;
357 /** Sequence number of the unlink command if the URB was cancelled. */
358 uint32_t u32SeqNumUrbUnlink;
359 /** Flag whether the URB was cancelled. */
360 bool fCancelled;
361 /** USB xfer type. */
362 VUSBXFERTYPE enmType;
363 /** USB xfer direction. */
364 VUSBDIRECTION enmDir;
365 /** Completion status. */
366 VUSBSTATUS enmStatus;
367 /** Pointer to the VUSB URB. */
368 PVUSBURB pVUsbUrb;
369} USBPROXYURBUSBIP;
370/** Pointer to a USB/IP URB. */
371typedef USBPROXYURBUSBIP *PUSBPROXYURBUSBIP;
372
373/**
374 * USB/IP data receive states.
375 */
376typedef enum USBPROXYUSBIPRECVSTATE
377{
378 /** Invalid receive state. */
379 USBPROXYUSBIPRECVSTATE_INVALID = 0,
380 /** Currently receiving the common header structure. */
381 USBPROXYUSBIPRECVSTATE_HDR_COMMON,
382 /** Currently receieving the rest of the header structure. */
383 USBPROXYUSBIPRECVSTATE_HDR_RESIDUAL,
384 /** Currently receiving data into the URB buffer. */
385 USBPROXYUSBIPRECVSTATE_URB_BUFFER,
386 /** Currently receiving the isochronous packet descriptors. */
387 USBPROXYUSBIPRECVSTATE_ISOC_PKT_DESCS,
388 /** Usual 32bit hack. */
389 USBPROXYUSBIPRECVSTATE_32BIT_HACK = 0x7fffffff
390} USBPROXYUSBIPRECVSTATE;
391/** Pointer to an receive state. */
392typedef USBPROXYUSBIPRECVSTATE *PUSBPROXYUSBIPRECVSTATE;
393
394/**
395 * Backend data for the USB/IP USB Proxy device backend.
396 */
397typedef struct USBPROXYDEVUSBIP
398{
399 /** IPRT socket handle. */
400 RTSOCKET hSocket;
401 /** Pollset with the wakeup pipe and socket. */
402 RTPOLLSET hPollSet;
403 /** Pipe endpoint - read (in the pollset). */
404 RTPIPE hPipeR;
405 /** Pipe endpoint - write. */
406 RTPIPE hPipeW;
407 /** Next sequence number to use for identifying submitted URBs. */
408 volatile uint32_t u32SeqNumNext;
409 /** Fast mutex protecting the lists below against concurrent access. */
410 RTSEMFASTMUTEX hMtxLists;
411 /** List of in flight URBs. */
412 RTLISTANCHOR ListUrbsInFlight;
413 /** List of landed URBs. */
414 RTLISTANCHOR ListUrbsLanded;
415 /** List of URBs to submit. */
416 RTLISTANCHOR ListUrbsToQueue;
417 /** Port of the USB/IP host to connect to. */
418 uint32_t uPort;
419 /** USB/IP host address. */
420 char *pszHost;
421 /** USB Bus ID of the device to capture. */
422 char *pszBusId;
423 /** The device ID to use to identify the device. */
424 uint32_t u32DevId;
425 /** Temporary buffer for the next reply header */
426 UsbIpRet BufRet;
427 /** Temporary buffer to hold all isochronous packet descriptors. */
428 UsbIpIsocPktDesc aIsocPktDesc[8];
429 /** Pointer to the current buffer to write received data to. */
430 uint8_t *pbRecv;
431 /** Number of bytes received so far. */
432 size_t cbRecv;
433 /** Number of bytes left to receive. until we advance the state machine and process the data */
434 size_t cbLeft;
435 /** The current receiving state. */
436 USBPROXYUSBIPRECVSTATE enmRecvState;
437 /** The URB we currently receive a response for. */
438 PUSBPROXYURBUSBIP pUrbUsbIp;
439} USBPROXYDEVUSBIP, *PUSBPROXYDEVUSBIP;
440
441/** Pollset id of the socket. */
442#define USBIP_POLL_ID_SOCKET 0
443/** Pollset id of the pipe. */
444#define USBIP_POLL_ID_PIPE 1
445
446/** USB/IP address prefix for identifcation. */
447#define USBIP_URI_PREFIX "usbip://"
448/** USB/IP address prefix length. */
449#define USBIP_URI_PREFIX_LEN (sizeof(USBIP_URI_PREFIX) - 1)
450
451/** Waking reason for the USB I/P reaper: New URBs to queue. */
452#define USBIP_REAPER_WAKEUP_REASON_QUEUE 'Q'
453/** Waking reason for the USB I/P reaper: External wakeup. */
454#define USBIP_REAPER_WAKEUP_REASON_EXTERNAL 'E'
455
456/**
457 * Converts a request/reply header from network to host endianness.
458 *
459 * @returns nothing.
460 * @param pHdr The header to convert.
461 */
462DECLINLINE(void) usbProxyUsbIpReqRetHdrN2H(PUsbIpReqRetHdr pHdr)
463{
464 pHdr->u32ReqRet = RT_H2N_U32(pHdr->u32ReqRet);
465 pHdr->u32SeqNum = RT_H2N_U32(pHdr->u32SeqNum);
466 pHdr->u32DevId = RT_H2N_U32(pHdr->u32DevId);
467 pHdr->u32Direction = RT_H2N_U32(pHdr->u32Direction);
468 pHdr->u32Endpoint = RT_H2N_U32(pHdr->u32Endpoint);
469}
470
471/**
472 * Converts a request/reply header from host to network endianness.
473 *
474 * @returns nothing.
475 * @param pHdr The header to convert.
476 */
477DECLINLINE(void) usbProxyUsbIpReqRetHdrH2N(PUsbIpReqRetHdr pHdr)
478{
479 pHdr->u32ReqRet = RT_N2H_U32(pHdr->u32ReqRet);
480 pHdr->u32SeqNum = RT_N2H_U32(pHdr->u32SeqNum);
481 pHdr->u32DevId = RT_N2H_U32(pHdr->u32DevId);
482 pHdr->u32Direction = RT_N2H_U32(pHdr->u32Direction);
483 pHdr->u32Endpoint = RT_N2H_U32(pHdr->u32Endpoint);
484}
485
486/**
487 * Converts a submit request from host to network endianness.
488 *
489 * @returns nothing.
490 * @param pReqSubmit The submit request to convert.
491 */
492DECLINLINE(void) usbProxyUsbIpReqSubmitH2N(PUsbIpReqSubmit pReqSubmit)
493{
494 usbProxyUsbIpReqRetHdrH2N(&pReqSubmit->Hdr);
495 pReqSubmit->u32XferFlags = RT_H2N_U32(pReqSubmit->u32XferFlags);
496 pReqSubmit->u32TransferBufferLength = RT_H2N_U32(pReqSubmit->u32TransferBufferLength);
497 pReqSubmit->u32StartFrame = RT_H2N_U32(pReqSubmit->u32StartFrame);
498 pReqSubmit->u32NumIsocPkts = RT_H2N_U32(pReqSubmit->u32NumIsocPkts);
499 pReqSubmit->u32Interval = RT_H2N_U32(pReqSubmit->u32Interval);
500}
501
502/**
503 * Converts a submit reply from network to host endianness.
504 *
505 * @returns nothing.
506 * @param pReqSubmit The submit reply to convert.
507 */
508DECLINLINE(void) usbProxyUsbIpRetSubmitN2H(PUsbIpRetSubmit pRetSubmit)
509{
510 usbProxyUsbIpReqRetHdrN2H(&pRetSubmit->Hdr);
511 pRetSubmit->u32Status = RT_N2H_U32(pRetSubmit->u32Status);
512 pRetSubmit->u32ActualLength = RT_N2H_U32(pRetSubmit->u32ActualLength);
513 pRetSubmit->u32StartFrame = RT_N2H_U32(pRetSubmit->u32StartFrame);
514 pRetSubmit->u32NumIsocPkts = RT_N2H_U32(pRetSubmit->u32NumIsocPkts);
515 pRetSubmit->u32ErrorCount = RT_N2H_U32(pRetSubmit->u32ErrorCount);
516}
517
518/**
519 * Converts a isochronous packet descriptor from host to network endianness.
520 *
521 * @returns nothing.
522 * @param pIsocPktDesc The packet descriptor to convert.
523 */
524DECLINLINE(void) usbProxyUsbIpIsocPktDescH2N(PUsbIpIsocPktDesc pIsocPktDesc)
525{
526 pIsocPktDesc->u32Offset = RT_H2N_U32(pIsocPktDesc->u32Offset);
527 pIsocPktDesc->u32Length = RT_H2N_U32(pIsocPktDesc->u32Length);
528 pIsocPktDesc->u32ActualLength = RT_H2N_U32(pIsocPktDesc->u32ActualLength);
529 pIsocPktDesc->i32Status = RT_H2N_U32(pIsocPktDesc->i32Status);
530}
531
532/**
533 * Converts a isochronous packet descriptor from network to host endianness.
534 *
535 * @returns nothing.
536 * @param pIsocPktDesc The packet descriptor to convert.
537 */
538DECLINLINE(void) usbProxyUsbIpIsocPktDescN2H(PUsbIpIsocPktDesc pIsocPktDesc)
539{
540 pIsocPktDesc->u32Offset = RT_N2H_U32(pIsocPktDesc->u32Offset);
541 pIsocPktDesc->u32Length = RT_N2H_U32(pIsocPktDesc->u32Length);
542 pIsocPktDesc->u32ActualLength = RT_N2H_U32(pIsocPktDesc->u32ActualLength);
543 pIsocPktDesc->i32Status = RT_N2H_U32(pIsocPktDesc->i32Status);
544}
545
546/**
547 * Converts a unlink request from host to network endianness.
548 *
549 * @returns nothing.
550 * @param pReqUnlink The unlink request to convert.
551 */
552DECLINLINE(void) usbProxyUsbIpReqUnlinkH2N(PUsbIpReqUnlink pReqUnlink)
553{
554 usbProxyUsbIpReqRetHdrH2N(&pReqUnlink->Hdr);
555 pReqUnlink->u32SeqNum = RT_H2N_U32(pReqUnlink->u32SeqNum);
556}
557
558/**
559 * Converts a unlink reply from network to host endianness.
560 *
561 * @returns nothing.
562 * @param pRetUnlink The unlink reply to convert.
563 */
564DECLINLINE(void) usbProxyUsbIpRetUnlinkN2H(PUsbIpRetUnlink pRetUnlink)
565{
566 usbProxyUsbIpReqRetHdrN2H(&pRetUnlink->Hdr);
567 pRetUnlink->u32Status = RT_N2H_U32(pRetUnlink->u32Status);
568}
569
570/**
571 * Convert the given exported device structure from host to network byte order.
572 *
573 * @returns nothing.
574 * @param pDevice The device structure to convert.
575 */
576DECLINLINE(void) usbProxyUsbIpExportedDeviceN2H(PUsbIpExportedDevice pDevice)
577{
578 pDevice->u32BusNum = RT_N2H_U32(pDevice->u32BusNum);
579 pDevice->u32DevNum = RT_N2H_U32(pDevice->u32DevNum);
580 pDevice->u32Speed = RT_N2H_U16(pDevice->u32Speed);
581 pDevice->u16VendorId = RT_N2H_U16(pDevice->u16VendorId);
582 pDevice->u16ProductId = RT_N2H_U16(pDevice->u16ProductId);
583 pDevice->u16BcdDevice = RT_N2H_U16(pDevice->u16BcdDevice);
584}
585
586/**
587 * Converts a USB/IP status code to a VUSB status code.
588 *
589 * @returns VUSB status code.
590 * @param i32Status The USB/IP status code from the reply.
591 */
592DECLINLINE(VUSBSTATUS) usbProxyUsbIpVUsbStatusConvertFromStatus(int32_t i32Status)
593{
594 if (RT_LIKELY( i32Status == USBIP_STATUS_SUCCESS
595 || i32Status == USBIP_STATUS_SHORT_READ))
596 return VUSBSTATUS_OK;
597
598 switch (i32Status)
599 {
600 case USBIP_STATUS_PIPE_STALLED:
601 return VUSBSTATUS_STALL;
602 default:
603 return VUSBSTATUS_DNR;
604 }
605 /* not reached */
606}
607
608/**
609 * Gets the next free sequence number.
610 *
611 * @returns Next free sequence number.
612 * @param pProxyDevUsbIp The USB/IP proxy device data.
613 */
614DECLINLINE(uint32_t) usbProxyUsbIpSeqNumGet(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
615{
616 uint32_t u32SeqNum = ASMAtomicIncU32(&pProxyDevUsbIp->u32SeqNumNext);
617 if (RT_UNLIKELY(!u32SeqNum))
618 u32SeqNum = ASMAtomicIncU32(&pProxyDevUsbIp->u32SeqNumNext);
619
620 return u32SeqNum;
621}
622
623/**
624 * Links a given URB into the given list.
625 *
626 * @returns nothing.
627 * @param pProxyDevUsbIp The USB/IP proxy device data.
628 * @param pList The list to link the URB into.
629 * @param pUrbUsbIp The URB to link.
630 */
631DECLINLINE(void) usbProxyUsbIpLinkUrb(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PRTLISTANCHOR pList, PUSBPROXYURBUSBIP pUrbUsbIp)
632{
633 int rc = RTSemFastMutexRequest(pProxyDevUsbIp->hMtxLists);
634 AssertRC(rc);
635 RTListAppend(pList, &pUrbUsbIp->NodeList);
636 RTSemFastMutexRelease(pProxyDevUsbIp->hMtxLists);
637}
638
639/**
640 * Unlinks a given URB from the current assigned list.
641 *
642 * @returns nothing.
643 * @param pProxyDevUsbIp The USB/IP proxy device data.
644 * @param pUrbUsbIp The URB to unlink.
645 */
646DECLINLINE(void) usbProxyUsbIpUnlinkUrb(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PUSBPROXYURBUSBIP pUrbUsbIp)
647{
648 int rc = RTSemFastMutexRequest(pProxyDevUsbIp->hMtxLists);
649 AssertRC(rc);
650 RTListNodeRemove(&pUrbUsbIp->NodeList);
651 RTSemFastMutexRelease(pProxyDevUsbIp->hMtxLists);
652}
653
654/**
655 * Allocates a USB/IP proxy specific URB state.
656 *
657 * @returns Pointer to the USB/IP specific URB data or NULL on failure.
658 * @param pProxyDevUsbIp The USB/IP proxy device data.
659 */
660static PUSBPROXYURBUSBIP usbProxyUsbIpUrbAlloc(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
661{
662 NOREF(pProxyDevUsbIp);
663 return (PUSBPROXYURBUSBIP)RTMemAllocZ(sizeof(USBPROXYURBUSBIP));
664}
665
666/**
667 * Frees the given USB/IP URB state.
668 *
669 * @returns nothing.
670 * @param pProxyDevUsbIp The USB/IP proxy device data.
671 * @param pUrbUsbIp The USB/IP speciic URB data.
672 */
673static void usbProxyUsbIpUrbFree(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PUSBPROXYURBUSBIP pUrbUsbIp)
674{
675 NOREF(pProxyDevUsbIp);
676 RTMemFree(pUrbUsbIp);
677}
678
679/**
680 * Parse the string representation of the host address.
681 *
682 * @returns VBox status code.
683 * @param pProxyDevUsbIp The USB/IP proxy device data to parse the address for.
684 * @param pszAddress The address string to parse.
685 */
686static int usbProxyUsbIpParseAddress(PUSBPROXYDEVUSBIP pProxyDevUsbIp, const char *pszAddress)
687{
688 int rc = VINF_SUCCESS;
689
690 if (!RTStrNCmp(pszAddress, USBIP_URI_PREFIX, USBIP_URI_PREFIX_LEN))
691 {
692 pszAddress += USBIP_URI_PREFIX_LEN;
693
694 const char *pszPortStart = RTStrStr(pszAddress, ":");
695 if (pszPortStart)
696 {
697 pszPortStart++;
698
699 const char *pszBusIdStart = RTStrStr(pszPortStart, ":");
700 if (pszBusIdStart)
701 {
702 size_t cbHost = pszPortStart - pszAddress - 1;
703 size_t cbBusId = strlen(pszBusIdStart);
704
705 pszBusIdStart++;
706
707 rc = RTStrToUInt32Ex(pszPortStart, NULL, 10 /* uBase */, &pProxyDevUsbIp->uPort);
708 if ( rc == VINF_SUCCESS
709 || rc == VWRN_TRAILING_CHARS)
710 {
711 rc = RTStrAllocEx(&pProxyDevUsbIp->pszHost, cbHost + 1);
712 if (RT_SUCCESS(rc))
713 rc = RTStrAllocEx(&pProxyDevUsbIp->pszBusId, cbBusId + 1);
714 if (RT_SUCCESS(rc))
715 {
716 rc = RTStrCopyEx(pProxyDevUsbIp->pszHost, cbHost + 1, pszAddress, cbHost);
717 AssertRC(rc);
718
719 rc = RTStrCopyEx(pProxyDevUsbIp->pszBusId, cbBusId + 1, pszBusIdStart, cbBusId);
720 AssertRC(rc);
721
722 return VINF_SUCCESS;
723 }
724 }
725 else
726 rc = VERR_INVALID_PARAMETER;
727 }
728 else
729 rc = VERR_INVALID_PARAMETER;
730 }
731 else
732 rc = VERR_INVALID_PARAMETER;
733 }
734 else
735 rc = VERR_INVALID_PARAMETER;
736
737 return rc;
738}
739
740/**
741 * Connects to the USB/IP host and claims the device given in the proxy device data.
742 *
743 * @returns VBox status code.
744 * @param pProxyDevUsbIp The USB/IP proxy device data.
745 */
746static int usbProxyUsbIpConnect(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
747{
748 int rc = VINF_SUCCESS;
749 rc = RTTcpClientConnect(pProxyDevUsbIp->pszHost, pProxyDevUsbIp->uPort, &pProxyDevUsbIp->hSocket);
750 if (RT_SUCCESS(rc))
751 {
752 /* Disable send coalescing. */
753 rc = RTTcpSetSendCoalescing(pProxyDevUsbIp->hSocket, false);
754 if (RT_FAILURE(rc))
755 LogRel(("UsbIp: Disabling send coalescing failed (rc=%Rrc), continuing nevertheless but expect reduced performance\n", rc));
756
757 /* Import the device, i.e. claim it for our use. */
758 UsbIpReqImport ReqImport;
759 ReqImport.u16Version = RT_H2N_U16(USBIP_VERSION);
760 ReqImport.u16Cmd = RT_H2N_U16(USBIP_INDICATOR_REQ | USBIP_REQ_RET_IMPORT);
761 ReqImport.u32Status = RT_H2N_U32(USBIP_STATUS_SUCCESS);
762 rc = RTStrCopy(&ReqImport.aszBusId[0], sizeof(ReqImport.aszBusId), pProxyDevUsbIp->pszBusId);
763 if (rc == VINF_SUCCESS)
764 {
765 rc = RTTcpWrite(pProxyDevUsbIp->hSocket, &ReqImport, sizeof(ReqImport));
766 if (RT_SUCCESS(rc))
767 {
768 /* Read the reply. */
769 UsbIpRetImport RetImport;
770 rc = RTTcpRead(pProxyDevUsbIp->hSocket, &RetImport, sizeof(RetImport), NULL);
771 if (RT_SUCCESS(rc))
772 {
773 RetImport.u16Version = RT_N2H_U16(RetImport.u16Version);
774 RetImport.u16Cmd = RT_N2H_U16(RetImport.u16Cmd);
775 RetImport.u32Status = RT_N2H_U32(RetImport.u32Status);
776 if ( RetImport.u16Version == USBIP_VERSION
777 && RetImport.u16Cmd == USBIP_REQ_RET_IMPORT
778 && RetImport.u32Status == USBIP_STATUS_SUCCESS)
779 {
780 /* Read the device data. */
781 UsbIpExportedDevice Device;
782 rc = RTTcpRead(pProxyDevUsbIp->hSocket, &Device, sizeof(Device), NULL);
783 if (RT_SUCCESS(rc))
784 {
785 usbProxyUsbIpExportedDeviceN2H(&Device);
786 pProxyDevUsbIp->u32DevId = (Device.u32BusNum << 16) | Device.u32DevNum;
787
788 rc = RTPollSetAddSocket(pProxyDevUsbIp->hPollSet, pProxyDevUsbIp->hSocket,
789 RTPOLL_EVT_READ | RTPOLL_EVT_ERROR, USBIP_POLL_ID_SOCKET);
790 }
791 }
792 else
793 {
794 /* Check what went wrong and leave a meaningful error message in the log. */
795 if (RetImport.u16Version != USBIP_VERSION)
796 LogRel(("UsbIp: Unexpected protocol version received from host (%#x vs. %#x)\n",
797 RetImport.u16Version, USBIP_VERSION));
798 else if (RetImport.u16Cmd != USBIP_REQ_RET_IMPORT)
799 LogRel(("UsbIp: Unexpected reply code received from host (%#x vs. %#x)\n",
800 RetImport.u16Cmd, USBIP_REQ_RET_IMPORT));
801 else if (RetImport.u32Status != 0)
802 LogRel(("UsbIp: Claiming the device has failed on the host with an unspecified error\n"));
803 else
804 AssertMsgFailed(("Something went wrong with if condition\n"));
805 }
806 }
807 }
808 }
809 else
810 {
811 LogRel(("UsbIp: Given bus ID is exceeds permitted protocol length: %u vs %u\n",
812 strlen(pProxyDevUsbIp->pszBusId) + 1, sizeof(ReqImport.aszBusId)));
813 rc = VERR_INVALID_PARAMETER;
814 }
815
816 if (RT_FAILURE(rc))
817 RTTcpClientCloseEx(pProxyDevUsbIp->hSocket, false /*fGracefulShutdown*/);
818 }
819 if (RT_FAILURE(rc))
820 LogRel(("UsbIp: Connecting to the host %s failed with %Rrc\n", pProxyDevUsbIp->pszHost, rc));
821 return rc;
822}
823
824/**
825 * Disconnects from the USB/IP host releasing the device given in the proxy device data.
826 *
827 * @returns VBox status code.
828 * @param pProxyDevUsbIp The USB/IP proxy device data.
829 */
830static int usbProxyUsbIpDisconnect(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
831{
832 int rc = RTPollSetRemove(pProxyDevUsbIp->hPollSet, USBIP_POLL_ID_SOCKET);
833 Assert(RT_SUCCESS(rc) || rc == VERR_POLL_HANDLE_ID_NOT_FOUND);
834
835 rc = RTTcpClientCloseEx(pProxyDevUsbIp->hSocket, false /*fGracefulShutdown*/);
836 if (RT_SUCCESS(rc))
837 pProxyDevUsbIp->hSocket = NIL_RTSOCKET;
838 return rc;
839}
840
841/**
842 * Returns the URB matching the given sequence number from the in flight list.
843 *
844 * @returns pointer to the URB matching the given sequence number or NULL
845 * @param pProxyDevUsbIp The USB/IP proxy device data.
846 * @param u32SeqNum The sequence number to search for.
847 */
848static PUSBPROXYURBUSBIP usbProxyUsbIpGetInFlightUrbFromSeqNum(PUSBPROXYDEVUSBIP pProxyDevUsbIp, uint32_t u32SeqNum)
849{
850 bool fFound = false;
851
852 int rc = RTSemFastMutexRequest(pProxyDevUsbIp->hMtxLists);
853 AssertRC(rc);
854 PUSBPROXYURBUSBIP pIt;
855 RTListForEach(&pProxyDevUsbIp->ListUrbsInFlight, pIt, USBPROXYURBUSBIP, NodeList)
856 {
857 if (pIt->u32SeqNumUrb == u32SeqNum)
858 {
859 fFound = true;
860 break;
861 }
862 }
863 RTSemFastMutexRelease(pProxyDevUsbIp->hMtxLists);
864
865 return fFound ? pIt : NULL;
866}
867
868/**
869 * Returns the URB matching the given sequence number from the cancel list.
870 *
871 * @returns pointer to the URB matching the given sequence number or NULL
872 * @param pProxyDevUsbIp The USB/IP proxy device data.
873 * @param u32SeqNum The sequence number to search for.
874 */
875static PUSBPROXYURBUSBIP usbProxyUsbIpGetCancelledUrbFromSeqNum(PUSBPROXYDEVUSBIP pProxyDevUsbIp, uint32_t u32SeqNum)
876{
877 bool fFound = false;
878
879 int rc = RTSemFastMutexRequest(pProxyDevUsbIp->hMtxLists);
880 AssertRC(rc);
881 PUSBPROXYURBUSBIP pIt;
882 RTListForEach(&pProxyDevUsbIp->ListUrbsInFlight, pIt, USBPROXYURBUSBIP, NodeList)
883 {
884 if ( pIt->u32SeqNumUrbUnlink == u32SeqNum
885 && pIt->fCancelled == true)
886 {
887 fFound = true;
888 break;
889 }
890 }
891 RTSemFastMutexRelease(pProxyDevUsbIp->hMtxLists);
892
893 return fFound ? pIt : NULL;
894}
895
896/**
897 * Resets the receive state for a new reply.
898 *
899 * @returns nothing.
900 * @param pProxyDevUsbIp The USB/IP proxy device data.
901 */
902static void usbProxyUsbIpResetRecvState(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
903{
904 pProxyDevUsbIp->enmRecvState = USBPROXYUSBIPRECVSTATE_HDR_COMMON;
905 pProxyDevUsbIp->pbRecv = (uint8_t *)&pProxyDevUsbIp->BufRet;
906 pProxyDevUsbIp->cbRecv = 0;
907 pProxyDevUsbIp->cbLeft = sizeof(UsbIpReqRetHdr);
908}
909
910static void usbProxyUsbIpRecvStateAdvance(PUSBPROXYDEVUSBIP pProxyDevUsbIp, USBPROXYUSBIPRECVSTATE enmState,
911 uint8_t *pbData, size_t cbData)
912{
913 pProxyDevUsbIp->enmRecvState = enmState;
914 pProxyDevUsbIp->cbRecv = 0;
915 pProxyDevUsbIp->cbLeft = cbData;
916 pProxyDevUsbIp->pbRecv = pbData;
917}
918
919/**
920 * Handles reception of a USB/IP PDU.
921 *
922 * @returns VBox status code.
923 * @param pProxyDevUsbIp The USB/IP proxy device data.
924 * @param ppUrbUsbIp Where to store the pointer to the USB/IP URB which completed.
925 * Will be NULL if the received PDU is not complete and we have
926 * have to wait for more data or on failure.
927 */
928static int usbProxyUsbIpRecvPdu(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PUSBPROXYURBUSBIP *ppUrbUsbIp)
929{
930 int rc = VINF_SUCCESS;
931 size_t cbRead = 0;
932 PUSBPROXYURBUSBIP pUrbUsbIp = NULL;
933
934 Assert(pProxyDevUsbIp->cbLeft);
935
936 /* Read any available data first. */
937 rc = RTTcpReadNB(pProxyDevUsbIp->hSocket, pProxyDevUsbIp->pbRecv, pProxyDevUsbIp->cbLeft, &cbRead);
938 if (RT_SUCCESS(rc))
939 {
940 pProxyDevUsbIp->cbRecv += cbRead;
941 pProxyDevUsbIp->cbLeft -= cbRead;
942 pProxyDevUsbIp->pbRecv += cbRead;
943
944 /* Process the received data if there is nothing to receive left for the current state. */
945 if (!pProxyDevUsbIp->cbLeft)
946 {
947 switch (pProxyDevUsbIp->enmRecvState)
948 {
949 case USBPROXYUSBIPRECVSTATE_HDR_COMMON:
950 {
951 Assert(pProxyDevUsbIp->cbRecv == sizeof(UsbIpReqRetHdr));
952
953 /*
954 * Determine the residual amount of data to receive until
955 * the complete reply header was received.
956 */
957 switch (RT_N2H_U32(pProxyDevUsbIp->BufRet.Hdr.u32ReqRet))
958 {
959 case USBIP_RET_SUBMIT:
960 pProxyDevUsbIp->cbLeft = sizeof(UsbIpRetSubmit) - sizeof(UsbIpReqRetHdr);
961 pProxyDevUsbIp->enmRecvState = USBPROXYUSBIPRECVSTATE_HDR_RESIDUAL;
962 break;
963 case USBIP_RET_UNLINK:
964 pProxyDevUsbIp->cbLeft = sizeof(UsbIpRetUnlink) - sizeof(UsbIpReqRetHdr);
965 pProxyDevUsbIp->enmRecvState = USBPROXYUSBIPRECVSTATE_HDR_RESIDUAL;
966 break;
967 default:
968 AssertLogRelMsgFailed(("Invalid reply header received: %d\n",
969 pProxyDevUsbIp->BufRet.Hdr.u32ReqRet));
970 usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
971 }
972
973 break;
974 }
975 case USBPROXYUSBIPRECVSTATE_HDR_RESIDUAL:
976 {
977 switch (RT_N2H_U32(pProxyDevUsbIp->BufRet.Hdr.u32ReqRet))
978 {
979 case USBIP_RET_SUBMIT:
980 /* Get the URB from the in flight list. */
981 pProxyDevUsbIp->pUrbUsbIp = usbProxyUsbIpGetInFlightUrbFromSeqNum(pProxyDevUsbIp, RT_N2H_U32(pProxyDevUsbIp->BufRet.Hdr.u32SeqNum));
982 if (pProxyDevUsbIp->pUrbUsbIp)
983 {
984 usbProxyUsbIpRetSubmitN2H(&pProxyDevUsbIp->BufRet.RetSubmit);
985
986 /* We still have to receive the transfer buffer, even in case of an error. */
987 pProxyDevUsbIp->pUrbUsbIp->enmStatus = usbProxyUsbIpVUsbStatusConvertFromStatus(pProxyDevUsbIp->BufRet.RetSubmit.u32Status);
988 if (pProxyDevUsbIp->pUrbUsbIp->enmDir == VUSBDIRECTION_IN)
989 {
990 uint8_t *pbData = NULL;
991 size_t cbRet = 0;
992
993 AssertPtr(pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb);
994 if (pProxyDevUsbIp->pUrbUsbIp->enmType == VUSBXFERTYPE_MSG)
995 {
996 /* Preserve the setup request. */
997 pbData = &pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->abData[sizeof(VUSBSETUP)];
998 cbRet = pProxyDevUsbIp->BufRet.RetSubmit.u32ActualLength + sizeof(VUSBSETUP);
999 }
1000 else
1001 {
1002 pbData = &pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->abData[0];
1003 cbRet = pProxyDevUsbIp->BufRet.RetSubmit.u32ActualLength;
1004 }
1005
1006 if (pProxyDevUsbIp->BufRet.RetSubmit.u32ActualLength)
1007 {
1008 if (RT_LIKELY(pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->cbData >= cbRet))
1009 {
1010 pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->cbData = (uint32_t)cbRet;
1011 usbProxyUsbIpRecvStateAdvance(pProxyDevUsbIp, USBPROXYUSBIPRECVSTATE_URB_BUFFER,
1012 pbData, pProxyDevUsbIp->BufRet.RetSubmit.u32ActualLength);
1013 }
1014 else
1015 {
1016 /*
1017 * Bogus length returned from the USB/IP remote server.
1018 * Error out because there is no way to find the end of the current
1019 * URB and the beginning of the next one. The error will cause closing the
1020 * connection to the rogue remote and all URBs get completed with an error.
1021 */
1022 LogRelMax(10, ("USB/IP: Received reply with sequence number %u contains invalid length %zu (max %zu)\n",
1023 pProxyDevUsbIp->BufRet.Hdr.u32SeqNum, cbRet,
1024 pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->cbData));
1025 rc = VERR_NET_PROTOCOL_ERROR;
1026 }
1027 }
1028 else
1029 {
1030 pUrbUsbIp = pProxyDevUsbIp->pUrbUsbIp;
1031 usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
1032 }
1033 }
1034 else
1035 {
1036 Assert(pProxyDevUsbIp->pUrbUsbIp->enmDir == VUSBDIRECTION_OUT);
1037 pUrbUsbIp = pProxyDevUsbIp->pUrbUsbIp;
1038 usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
1039 }
1040 }
1041 else
1042 {
1043 LogRel(("USB/IP: Received reply with sequence number %u doesn't match any local URB\n",
1044 RT_N2H_U32(pProxyDevUsbIp->BufRet.Hdr.u32SeqNum)));
1045 usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
1046 rc = VERR_NET_PROTOCOL_ERROR;
1047 }
1048 break;
1049 case USBIP_RET_UNLINK:
1050 pProxyDevUsbIp->pUrbUsbIp = usbProxyUsbIpGetCancelledUrbFromSeqNum(pProxyDevUsbIp, RT_N2H_U32(pProxyDevUsbIp->BufRet.Hdr.u32SeqNum));
1051 if (pProxyDevUsbIp->pUrbUsbIp)
1052 {
1053 usbProxyUsbIpRetUnlinkN2H(&pProxyDevUsbIp->BufRet.RetUnlink);
1054 pUrbUsbIp = pProxyDevUsbIp->pUrbUsbIp;
1055 pUrbUsbIp->pVUsbUrb->enmStatus = usbProxyUsbIpVUsbStatusConvertFromStatus(pProxyDevUsbIp->BufRet.RetUnlink.u32Status);
1056 }
1057 /* else: Probably received the data for the URB and is complete already. */
1058
1059 usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
1060 break;
1061 }
1062
1063 break;
1064 }
1065 case USBPROXYUSBIPRECVSTATE_URB_BUFFER:
1066 if (pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->enmType == VUSBXFERTYPE_ISOC)
1067 usbProxyUsbIpRecvStateAdvance(pProxyDevUsbIp, USBPROXYUSBIPRECVSTATE_ISOC_PKT_DESCS,
1068 (uint8_t *)&pProxyDevUsbIp->aIsocPktDesc[0],
1069 pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->cIsocPkts * sizeof(UsbIpIsocPktDesc));
1070 else
1071 {
1072 pUrbUsbIp = pProxyDevUsbIp->pUrbUsbIp;
1073 usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
1074 }
1075 break;
1076 case USBPROXYUSBIPRECVSTATE_ISOC_PKT_DESCS:
1077 /* Process all received isochronous packet descriptors. */
1078 for (unsigned i = 0; i < pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->cIsocPkts; i++)
1079 {
1080 PVUSBURBISOCPTK pIsocPkt = &pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->aIsocPkts[i];
1081 PUsbIpIsocPktDesc pIsocPktUsbIp = &pProxyDevUsbIp->aIsocPktDesc[i];
1082
1083 usbProxyUsbIpIsocPktDescN2H(pIsocPktUsbIp);
1084 pIsocPkt->enmStatus = usbProxyUsbIpVUsbStatusConvertFromStatus(pIsocPktUsbIp->i32Status);
1085
1086 if (RT_LIKELY( pIsocPktUsbIp->u32Offset < pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->cbData
1087 && pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->cbData - pIsocPktUsbIp->u32Offset >= pIsocPktUsbIp->u32ActualLength))
1088 {
1089 pIsocPkt->off = pIsocPktUsbIp->u32Offset;
1090 pIsocPkt->cb = pIsocPktUsbIp->u32ActualLength;
1091 }
1092 else
1093 {
1094 /*
1095 * The offset and length value in the isoc packet descriptor are bogus and would cause a buffer overflow later on, leave an
1096 * error message and disconnect from the rogue remote end.
1097 */
1098 LogRelMax(10, ("USB/IP: Received reply with sequence number %u contains invalid isoc packet descriptor %u (offset=%u length=%u)\n",
1099 pProxyDevUsbIp->BufRet.Hdr.u32SeqNum, i,
1100 pIsocPktUsbIp->u32Offset, pIsocPktUsbIp->u32ActualLength));
1101 rc = VERR_NET_PROTOCOL_ERROR;
1102 break;
1103 }
1104 }
1105
1106 pUrbUsbIp = pProxyDevUsbIp->pUrbUsbIp;
1107 usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
1108 break;
1109 default:
1110 AssertLogRelMsgFailed(("USB/IP: Invalid receive state %d\n", pProxyDevUsbIp->enmRecvState));
1111 }
1112 }
1113 }
1114
1115 if (RT_SUCCESS(rc))
1116 *ppUrbUsbIp = pUrbUsbIp;
1117 else
1118 {
1119 /* Complete all URBs with DNR error and mark device as unplugged, the current one is still in the in flight list. */
1120 pProxyDevUsbIp->pUrbUsbIp = NULL;
1121 usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
1122 usbProxyUsbIpDisconnect(pProxyDevUsbIp);
1123
1124 rc = RTSemFastMutexRequest(pProxyDevUsbIp->hMtxLists);
1125 AssertRC(rc);
1126 PUSBPROXYURBUSBIP pIt;
1127 PUSBPROXYURBUSBIP pItNext;
1128 RTListForEachSafe(&pProxyDevUsbIp->ListUrbsInFlight, pIt, pItNext, USBPROXYURBUSBIP, NodeList)
1129 {
1130 if (pIt->pVUsbUrb) /* can be NULL for requests created by usbProxyUsbIpCtrlUrbExchangeSync(). */
1131 pIt->pVUsbUrb->enmStatus = VUSBSTATUS_CRC;
1132 RTListNodeRemove(&pIt->NodeList);
1133 RTListAppend(&pProxyDevUsbIp->ListUrbsLanded, &pIt->NodeList);
1134 }
1135 RTSemFastMutexRelease(pProxyDevUsbIp->hMtxLists);
1136 }
1137
1138 return rc;
1139}
1140
1141/**
1142 * Worker for queueing an URB on the main I/O thread.
1143 *
1144 * @returns VBox status code.
1145 * @param pProxyDevUsbIp The USB/IP proxy device data.
1146 * @param pUrbUsbIp The USB/IP URB to queue.
1147 */
1148static int usbProxyUsbIpUrbQueueWorker(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PUSBPROXYURBUSBIP pUrbUsbIp)
1149{
1150 PVUSBURB pUrb = pUrbUsbIp->pVUsbUrb;
1151
1152 pUrbUsbIp->u32SeqNumUrb = usbProxyUsbIpSeqNumGet(pProxyDevUsbIp);
1153 pUrbUsbIp->enmType = pUrb->enmType;
1154 pUrbUsbIp->enmStatus = pUrb->enmStatus;
1155 pUrbUsbIp->enmDir = pUrb->enmDir;
1156
1157 UsbIpReqSubmit ReqSubmit;
1158
1159 RT_ZERO(ReqSubmit);
1160 ReqSubmit.Hdr.u32ReqRet = USBIP_CMD_SUBMIT;
1161 ReqSubmit.Hdr.u32SeqNum = pUrbUsbIp->u32SeqNumUrb;
1162 ReqSubmit.Hdr.u32DevId = pProxyDevUsbIp->u32DevId;
1163 ReqSubmit.Hdr.u32Endpoint = pUrb->EndPt;
1164 ReqSubmit.Hdr.u32Direction = pUrb->enmDir == VUSBDIRECTION_IN ? USBIP_DIR_IN : USBIP_DIR_OUT;
1165 ReqSubmit.u32XferFlags = 0;
1166 if (pUrb->enmDir == VUSBDIRECTION_IN && pUrb->fShortNotOk)
1167 ReqSubmit.u32XferFlags |= USBIP_XFER_FLAGS_SHORT_NOT_OK;
1168
1169 ReqSubmit.u32TransferBufferLength = pUrb->cbData;
1170 ReqSubmit.u32StartFrame = 0;
1171 ReqSubmit.u32NumIsocPkts = 0;
1172 ReqSubmit.u32Interval = 0;
1173
1174 RTSGSEG aSegReq[3]; /* Maximum number of segments used for a Isochronous transfer. */
1175 UsbIpIsocPktDesc aIsocPktsDesc[8];
1176 unsigned cSegsUsed = 1;
1177 aSegReq[0].pvSeg = &ReqSubmit;
1178 aSegReq[0].cbSeg = sizeof(ReqSubmit);
1179
1180 switch (pUrb->enmType)
1181 {
1182 case VUSBXFERTYPE_MSG:
1183 memcpy(&ReqSubmit.Setup, &pUrb->abData, sizeof(ReqSubmit.Setup));
1184 ReqSubmit.u32TransferBufferLength -= sizeof(VUSBSETUP);
1185 if (pUrb->enmDir == VUSBDIRECTION_OUT)
1186 {
1187 aSegReq[cSegsUsed].cbSeg = pUrb->cbData - sizeof(VUSBSETUP);
1188 aSegReq[cSegsUsed].pvSeg = pUrb->abData + sizeof(VUSBSETUP);
1189 if (aSegReq[cSegsUsed].cbSeg)
1190 cSegsUsed++;
1191 }
1192 LogFlowFunc(("Message (Control) URB\n"));
1193 break;
1194 case VUSBXFERTYPE_ISOC:
1195 LogFlowFunc(("Isochronous URB\n"));
1196 ReqSubmit.u32XferFlags |= USBIP_XFER_FLAGS_ISO_ASAP;
1197 ReqSubmit.u32NumIsocPkts = pUrb->cIsocPkts;
1198 if (pUrb->enmDir == VUSBDIRECTION_OUT)
1199 {
1200 aSegReq[cSegsUsed].cbSeg = pUrb->cbData;
1201 aSegReq[cSegsUsed].pvSeg = pUrb->abData;
1202 cSegsUsed++;
1203 }
1204
1205 for (unsigned i = 0; i < pUrb->cIsocPkts; i++)
1206 {
1207 aIsocPktsDesc[i].u32Offset = pUrb->aIsocPkts[i].off;
1208 aIsocPktsDesc[i].u32Length = pUrb->aIsocPkts[i].cb;
1209 aIsocPktsDesc[i].u32ActualLength = 0; /** @todo */
1210 aIsocPktsDesc[i].i32Status = pUrb->aIsocPkts[i].enmStatus;
1211 usbProxyUsbIpIsocPktDescH2N(&aIsocPktsDesc[i]);
1212 }
1213
1214 if (pUrb->cIsocPkts)
1215 {
1216 aSegReq[cSegsUsed].cbSeg = pUrb->cIsocPkts * sizeof(UsbIpIsocPktDesc);
1217 aSegReq[cSegsUsed].pvSeg = &aIsocPktsDesc[0];
1218 cSegsUsed++;
1219 }
1220
1221 break;
1222 case VUSBXFERTYPE_BULK:
1223 case VUSBXFERTYPE_INTR:
1224 LogFlowFunc(("Bulk URB\n"));
1225 if (pUrb->enmDir == VUSBDIRECTION_OUT)
1226 {
1227 aSegReq[cSegsUsed].cbSeg = pUrb->cbData;
1228 aSegReq[cSegsUsed].pvSeg = pUrb->abData;
1229 cSegsUsed++;
1230 }
1231 break;
1232 default:
1233 return VERR_INVALID_PARAMETER; /** @todo better status code. */
1234 }
1235
1236 usbProxyUsbIpReqSubmitH2N(&ReqSubmit);
1237
1238 Assert(cSegsUsed <= RT_ELEMENTS(aSegReq));
1239
1240 /* Send the command. */
1241 RTSGBUF SgBufReq;
1242 RTSgBufInit(&SgBufReq, &aSegReq[0], cSegsUsed);
1243
1244 int rc = RTTcpSgWrite(pProxyDevUsbIp->hSocket, &SgBufReq);
1245 if (RT_SUCCESS(rc))
1246 {
1247 /* Link the URB into the list of in flight URBs. */
1248 usbProxyUsbIpLinkUrb(pProxyDevUsbIp, &pProxyDevUsbIp->ListUrbsInFlight, pUrbUsbIp);
1249 }
1250
1251 return rc;
1252}
1253
1254/**
1255 * Queues all pending URBs from the list.
1256 *
1257 * @returns VBox status code.
1258 * @param pProxyDevUsbIp The USB/IP proxy device data.
1259 */
1260static int usbProxyUsbIpUrbsQueuePending(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
1261{
1262 RTLISTANCHOR ListUrbsPending;
1263
1264 int rc = RTSemFastMutexRequest(pProxyDevUsbIp->hMtxLists);
1265 AssertRC(rc);
1266 RTListMove(&ListUrbsPending, &pProxyDevUsbIp->ListUrbsToQueue);
1267 RTSemFastMutexRelease(pProxyDevUsbIp->hMtxLists);
1268
1269 PUSBPROXYURBUSBIP pIter;
1270 PUSBPROXYURBUSBIP pIterNext;
1271 RTListForEachSafe(&ListUrbsPending, pIter, pIterNext, USBPROXYURBUSBIP, NodeList)
1272 {
1273 RTListNodeRemove(&pIter->NodeList);
1274 rc = usbProxyUsbIpUrbQueueWorker(pProxyDevUsbIp, pIter);
1275 if (RT_FAILURE(rc))
1276 {
1277 /* Complete URB with an error and place into landed list. */
1278 pIter->pVUsbUrb->enmStatus = VUSBSTATUS_DNR;
1279 usbProxyUsbIpLinkUrb(pProxyDevUsbIp, &pProxyDevUsbIp->ListUrbsLanded, pIter);
1280 }
1281 }
1282
1283 return VINF_SUCCESS;
1284}
1285
1286/**
1287 * Kick the reaper thread.
1288 *
1289 * @returns VBox status code.
1290 * @param pProxyDevUsbIp The USB/IP proxy device data.
1291 * @param bReason The wakeup reason.
1292 */
1293static char usbProxyReaperKick(PUSBPROXYDEVUSBIP pProxyDevUsbIp, char bReason)
1294{
1295 int rc = VINF_SUCCESS;
1296 size_t cbWritten = 0;
1297
1298 rc = RTPipeWrite(pProxyDevUsbIp->hPipeW, &bReason, 1, &cbWritten);
1299 Assert(RT_SUCCESS(rc) || cbWritten == 0);
1300
1301 return rc;
1302}
1303
1304/**
1305 * Drain the wakeup pipe.
1306 *
1307 * @returns Wakeup reason.
1308 * @param pProxyDevUsbIp The USB/IP proxy device data.
1309 */
1310static char usbProxyUsbIpWakeupPipeDrain(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
1311{
1312 char bRead = 0;
1313 size_t cbRead = 0;
1314 int rc = RTPipeRead(pProxyDevUsbIp->hPipeR, &bRead, 1, &cbRead);
1315 Assert(RT_SUCCESS(rc) && cbRead == 1); NOREF(rc);
1316
1317 return bRead;
1318}
1319
1320/**
1321 * Executes the poll/receive loop either until a URB is received (with an optional matching sequence number) or
1322 * the given timeout has elapsed.
1323 *
1324 * @returns Pointer to the received USB/IP URB or NULL on timeout or error.
1325 * @param pProxyDevUsbIp The USB/IP proxy device data.
1326 * @param u32SeqNumRet The sequence number of a specific reply to return the URB for, 0 if
1327 * any received URB is accepted.
1328 * @param fPollWakePipe Flag whether to poll the wakeup pipe.
1329 * @param cMillies Maximum number of milliseconds to wait for an URB to arrive.
1330 */
1331static PUSBPROXYURBUSBIP usbProxyUsbIpPollWorker(PUSBPROXYDEVUSBIP pProxyDevUsbIp, uint32_t u32SeqNumRet,
1332 bool fPollWakePipe, RTMSINTERVAL cMillies)
1333{
1334 int rc = VINF_SUCCESS;
1335 PUSBPROXYURBUSBIP pUrbUsbIp = NULL;
1336
1337 if (!fPollWakePipe)
1338 {
1339 rc = RTPollSetEventsChange(pProxyDevUsbIp->hPollSet, USBIP_POLL_ID_PIPE, RTPOLL_EVT_ERROR);
1340 AssertRC(rc);
1341 }
1342
1343 while (!pUrbUsbIp && RT_SUCCESS(rc) && cMillies)
1344 {
1345 uint32_t uIdReady = 0;
1346 uint32_t fEventsRecv = 0;
1347 RTMSINTERVAL msStart = RTTimeMilliTS();
1348 RTMSINTERVAL msNow;
1349
1350 rc = RTPoll(pProxyDevUsbIp->hPollSet, cMillies, &fEventsRecv, &uIdReady);
1351 Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT);
1352 if (RT_SUCCESS(rc))
1353 {
1354 msNow = RTTimeMilliTS();
1355 cMillies = msNow - msStart >= cMillies ? 0 : cMillies - (msNow - msStart);
1356
1357 if (uIdReady == USBIP_POLL_ID_SOCKET)
1358 {
1359 rc = usbProxyUsbIpRecvPdu(pProxyDevUsbIp, &pUrbUsbIp);
1360 if ( RT_SUCCESS(rc)
1361 && pUrbUsbIp)
1362 {
1363 /* Link the URB into the landed list if a specifc reply is requested and the URB doesn't match. */
1364 if ( u32SeqNumRet != 0
1365 && pUrbUsbIp->u32SeqNumUrb != u32SeqNumRet)
1366 {
1367 usbProxyUsbIpUnlinkUrb(pProxyDevUsbIp, pUrbUsbIp);
1368 usbProxyUsbIpLinkUrb(pProxyDevUsbIp, &pProxyDevUsbIp->ListUrbsLanded, pUrbUsbIp);
1369 pUrbUsbIp = NULL;
1370 }
1371 }
1372 }
1373 else
1374 {
1375 AssertLogRelMsg(uIdReady == USBIP_POLL_ID_PIPE, ("Invalid pollset ID given\n"));
1376
1377 char bReason = usbProxyUsbIpWakeupPipeDrain(pProxyDevUsbIp);
1378 if (bReason == USBIP_REAPER_WAKEUP_REASON_QUEUE)
1379 usbProxyUsbIpUrbsQueuePending(pProxyDevUsbIp);
1380 else
1381 {
1382 Assert(bReason == USBIP_REAPER_WAKEUP_REASON_EXTERNAL);
1383 break;
1384 }
1385 }
1386 }
1387 }
1388
1389 if (!fPollWakePipe)
1390 {
1391 rc = RTPollSetEventsChange(pProxyDevUsbIp->hPollSet, USBIP_POLL_ID_PIPE, RTPOLL_EVT_READ);
1392 AssertRC(rc);
1393 }
1394
1395 return pUrbUsbIp;
1396}
1397
1398/**
1399 * Synchronously exchange a given control message with the remote device.
1400 *
1401 * @eturns VBox status code.
1402 * @param pProxyDevUsbIp The USB/IP proxy device data.
1403 * @param pSetup The setup message.
1404 *
1405 * @note This method is only used to implement the *SetConfig, *SetInterface and *ClearHaltedEp
1406 * callbacks because the USB/IP protocol lacks dedicated requests for these.
1407 * @remark It is assumed that this method is never called while usbProxyUsbIpUrbReap is called
1408 * on another thread.
1409 */
1410static int usbProxyUsbIpCtrlUrbExchangeSync(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PVUSBSETUP pSetup)
1411{
1412 int rc = VINF_SUCCESS;
1413
1414 UsbIpReqSubmit ReqSubmit;
1415 USBPROXYURBUSBIP UsbIpUrb;
1416
1417 RT_ZERO(ReqSubmit);
1418
1419 uint32_t u32SeqNum = usbProxyUsbIpSeqNumGet(pProxyDevUsbIp);
1420 ReqSubmit.Hdr.u32ReqRet = USBIP_CMD_SUBMIT;
1421 ReqSubmit.Hdr.u32SeqNum = u32SeqNum;
1422 ReqSubmit.Hdr.u32DevId = pProxyDevUsbIp->u32DevId;
1423 ReqSubmit.Hdr.u32Direction = USBIP_DIR_OUT;
1424 ReqSubmit.Hdr.u32Endpoint = 0; /* Only default control endpoint is allowed for these kind of messages. */
1425 ReqSubmit.u32XferFlags = 0;
1426 ReqSubmit.u32TransferBufferLength = 0;
1427 ReqSubmit.u32StartFrame = 0;
1428 ReqSubmit.u32NumIsocPkts = 0;
1429 ReqSubmit.u32Interval = 0;
1430 memcpy(&ReqSubmit.Setup, pSetup, sizeof(ReqSubmit.Setup));
1431 usbProxyUsbIpReqSubmitH2N(&ReqSubmit);
1432
1433 UsbIpUrb.u32SeqNumUrb = u32SeqNum;
1434 UsbIpUrb.u32SeqNumUrbUnlink = 0;
1435 UsbIpUrb.fCancelled = false;
1436 UsbIpUrb.enmType = VUSBXFERTYPE_MSG;
1437 UsbIpUrb.enmDir = VUSBDIRECTION_OUT;
1438 UsbIpUrb.pVUsbUrb = NULL;
1439
1440 /* Send the command. */
1441 rc = RTTcpWrite(pProxyDevUsbIp->hSocket, &ReqSubmit, sizeof(ReqSubmit));
1442 if (RT_SUCCESS(rc))
1443 {
1444 usbProxyUsbIpLinkUrb(pProxyDevUsbIp, &pProxyDevUsbIp->ListUrbsInFlight, &UsbIpUrb);
1445 PUSBPROXYURBUSBIP pUrbUsbIp = usbProxyUsbIpPollWorker(pProxyDevUsbIp, u32SeqNum, false /*fPollWakePipe*/,
1446 30 * RT_MS_1SEC);
1447 Assert( !pUrbUsbIp
1448 || pUrbUsbIp == &UsbIpUrb); /* The returned URB should point to the URB we submitted. */
1449 usbProxyUsbIpUnlinkUrb(pProxyDevUsbIp, &UsbIpUrb);
1450
1451 if (!pUrbUsbIp)
1452 rc = VERR_TIMEOUT;
1453 }
1454
1455 return rc;
1456}
1457
1458
1459/*
1460 * The USB proxy device functions.
1461 */
1462
1463/**
1464 * @interface_method_impl{USBPROXYBACK,pfnOpen}
1465 */
1466static DECLCALLBACK(int) usbProxyUsbIpOpen(PUSBPROXYDEV pProxyDev, const char *pszAddress)
1467{
1468 LogFlowFunc(("pProxyDev=%p pszAddress=%s\n", pProxyDev, pszAddress));
1469
1470 PUSBPROXYDEVUSBIP pDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1471 int rc = VINF_SUCCESS;
1472
1473 RTListInit(&pDevUsbIp->ListUrbsInFlight);
1474 RTListInit(&pDevUsbIp->ListUrbsLanded);
1475 RTListInit(&pDevUsbIp->ListUrbsToQueue);
1476 pDevUsbIp->hSocket = NIL_RTSOCKET;
1477 pDevUsbIp->hPollSet = NIL_RTPOLLSET;
1478 pDevUsbIp->hPipeW = NIL_RTPIPE;
1479 pDevUsbIp->hPipeR = NIL_RTPIPE;
1480 pDevUsbIp->u32SeqNumNext = 0;
1481 pDevUsbIp->pszHost = NULL;
1482 pDevUsbIp->pszBusId = NULL;
1483 usbProxyUsbIpResetRecvState(pDevUsbIp);
1484
1485 rc = RTSemFastMutexCreate(&pDevUsbIp->hMtxLists);
1486 if (RT_SUCCESS(rc))
1487 {
1488 /* Setup wakeup pipe and poll set first. */
1489 rc = RTPipeCreate(&pDevUsbIp->hPipeR, &pDevUsbIp->hPipeW, 0);
1490 if (RT_SUCCESS(rc))
1491 {
1492 rc = RTPollSetCreate(&pDevUsbIp->hPollSet);
1493 if (RT_SUCCESS(rc))
1494 {
1495 rc = RTPollSetAddPipe(pDevUsbIp->hPollSet, pDevUsbIp->hPipeR,
1496 RTPOLL_EVT_READ, USBIP_POLL_ID_PIPE);
1497 if (RT_SUCCESS(rc))
1498 {
1499 /* Connect to the USB/IP host. */
1500 rc = usbProxyUsbIpParseAddress(pDevUsbIp, pszAddress);
1501 if (RT_SUCCESS(rc))
1502 rc = usbProxyUsbIpConnect(pDevUsbIp);
1503 }
1504
1505 if (RT_FAILURE(rc))
1506 {
1507 RTPollSetRemove(pDevUsbIp->hPollSet, USBIP_POLL_ID_PIPE);
1508 int rc2 = RTPollSetDestroy(pDevUsbIp->hPollSet);
1509 AssertRC(rc2);
1510 }
1511 }
1512
1513 if (RT_FAILURE(rc))
1514 {
1515 int rc2 = RTPipeClose(pDevUsbIp->hPipeR);
1516 AssertRC(rc2);
1517 rc2 = RTPipeClose(pDevUsbIp->hPipeW);
1518 AssertRC(rc2);
1519 }
1520 }
1521 }
1522
1523 return rc;
1524}
1525
1526
1527/**
1528 * @interface_method_impl{USBPROXYBACK,pfnClose}
1529 */
1530static DECLCALLBACK(void) usbProxyUsbIpClose(PUSBPROXYDEV pProxyDev)
1531{
1532 int rc = VINF_SUCCESS;
1533 LogFlowFunc(("pProxyDev = %p\n", pProxyDev));
1534
1535 PUSBPROXYDEVUSBIP pDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1536 if (pDevUsbIp->hSocket != NIL_RTSOCKET)
1537 usbProxyUsbIpDisconnect(pDevUsbIp);
1538
1539 /* Destroy the pipe and pollset if necessary. */
1540 if (pDevUsbIp->hPollSet != NIL_RTPOLLSET)
1541 {
1542 rc = RTPollSetRemove(pDevUsbIp->hPollSet, USBIP_POLL_ID_PIPE);
1543 AssertRC(rc);
1544 rc = RTPollSetDestroy(pDevUsbIp->hPollSet);
1545 AssertRC(rc);
1546 rc = RTPipeClose(pDevUsbIp->hPipeR);
1547 AssertRC(rc);
1548 rc = RTPipeClose(pDevUsbIp->hPipeW);
1549 AssertRC(rc);
1550 }
1551
1552 if (pDevUsbIp->pszHost)
1553 RTStrFree(pDevUsbIp->pszHost);
1554 if (pDevUsbIp->pszBusId)
1555 RTStrFree(pDevUsbIp->pszBusId);
1556
1557 /* Clear the URB lists. */
1558 rc = RTSemFastMutexRequest(pDevUsbIp->hMtxLists);
1559 AssertRC(rc);
1560 PUSBPROXYURBUSBIP pIter;
1561 PUSBPROXYURBUSBIP pIterNext;
1562 RTListForEachSafe(&pDevUsbIp->ListUrbsInFlight, pIter, pIterNext, USBPROXYURBUSBIP, NodeList)
1563 {
1564 RTListNodeRemove(&pIter->NodeList);
1565 RTMemFree(pIter);
1566 }
1567
1568 RTListForEachSafe(&pDevUsbIp->ListUrbsLanded, pIter, pIterNext, USBPROXYURBUSBIP, NodeList)
1569 {
1570 RTListNodeRemove(&pIter->NodeList);
1571 RTMemFree(pIter);
1572 }
1573 RTSemFastMutexRelease(pDevUsbIp->hMtxLists);
1574 RTSemFastMutexDestroy(pDevUsbIp->hMtxLists);
1575}
1576
1577
1578/**
1579 * @interface_method_impl{USBPROXYBACK,pfnReset}
1580 */
1581static DECLCALLBACK(int) usbProxyUsbIpReset(PUSBPROXYDEV pProxyDev, bool fResetOnLinux)
1582{
1583 LogFlowFunc(("pProxyDev = %p\n", pProxyDev));
1584
1585 int rc = VINF_SUCCESS;
1586 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1587 VUSBSETUP Setup;
1588
1589 if (fResetOnLinux)
1590 {
1591 Setup.bmRequestType = RT_BIT(5) | 0x03; /* Port request. */
1592 Setup.bRequest = 0x03; /* SET_FEATURE */
1593 Setup.wValue = 4; /* Port feature: Reset */
1594 Setup.wIndex = 0; /* Port number, irrelevant */
1595 Setup.wLength = 0;
1596 rc = usbProxyUsbIpCtrlUrbExchangeSync(pProxyDevUsbIp, &Setup);
1597 if (RT_SUCCESS(rc))
1598 {
1599 pProxyDev->iActiveCfg = -1;
1600 pProxyDev->cIgnoreSetConfigs = 2;
1601 }
1602 }
1603
1604 return rc;
1605}
1606
1607
1608/**
1609 * @interface_method_impl{USBPROXYBACK,pfnSetConfig}
1610 */
1611static DECLCALLBACK(int) usbProxyUsbIpSetConfig(PUSBPROXYDEV pProxyDev, int iCfg)
1612{
1613 LogFlowFunc(("pProxyDev=%s cfg=%#x\n", pProxyDev->pUsbIns->pszName, iCfg));
1614
1615 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1616 VUSBSETUP Setup;
1617
1618 Setup.bmRequestType = 0;
1619 Setup.bRequest = 0x09;
1620 Setup.wValue = iCfg;
1621 Setup.wIndex = 0;
1622 Setup.wLength = 0;
1623 return usbProxyUsbIpCtrlUrbExchangeSync(pProxyDevUsbIp, &Setup);
1624}
1625
1626
1627/**
1628 * @interface_method_impl{USBPROXYBACK,pfnClaimInterface}
1629 */
1630static DECLCALLBACK(int) usbProxyUsbIpClaimInterface(PUSBPROXYDEV pProxyDev, int iIf)
1631{
1632 RT_NOREF(pProxyDev, iIf);
1633 LogFlowFunc(("pProxyDev=%s iIf=%#x\n", pProxyDev->pUsbIns->pszName, iIf));
1634 return VINF_SUCCESS;
1635}
1636
1637
1638/**
1639 * @interface_method_impl{USBPROXYBACK,pfnReleaseInterface}
1640 */
1641static DECLCALLBACK(int) usbProxyUsbIpReleaseInterface(PUSBPROXYDEV pProxyDev, int iIf)
1642{
1643 RT_NOREF(pProxyDev, iIf);
1644 LogFlowFunc(("pProxyDev=%s iIf=%#x\n", pProxyDev->pUsbIns->pszName, iIf));
1645 return VINF_SUCCESS;
1646}
1647
1648
1649/**
1650 * @interface_method_impl{USBPROXYBACK,pfnSetInterface}
1651 */
1652static DECLCALLBACK(int) usbProxyUsbIpSetInterface(PUSBPROXYDEV pProxyDev, int iIf, int setting)
1653{
1654 LogFlowFunc(("pProxyDev=%p iIf=%#x setting=%#x\n", pProxyDev, iIf, setting));
1655
1656 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1657 VUSBSETUP Setup;
1658
1659 Setup.bmRequestType = 0x1;
1660 Setup.bRequest = 0x0b; /* SET_INTERFACE */
1661 Setup.wValue = setting;
1662 Setup.wIndex = iIf;
1663 Setup.wLength = 0;
1664 return usbProxyUsbIpCtrlUrbExchangeSync(pProxyDevUsbIp, &Setup);
1665}
1666
1667
1668/**
1669 * @interface_method_impl{USBPROXYBACK,pfnClearHaltedEndpoint}
1670 */
1671static DECLCALLBACK(int) usbProxyUsbIpClearHaltedEp(PUSBPROXYDEV pProxyDev, unsigned int iEp)
1672{
1673 LogFlowFunc(("pProxyDev=%s ep=%u\n", pProxyDev->pUsbIns->pszName, iEp));
1674
1675 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1676 VUSBSETUP Setup;
1677
1678 Setup.bmRequestType = 0x2;
1679 Setup.bRequest = 0x01; /* CLEAR_FEATURE */
1680 Setup.wValue = 0x00; /* ENDPOINT_HALT */
1681 Setup.wIndex = iEp;
1682 Setup.wLength = 0;
1683 return usbProxyUsbIpCtrlUrbExchangeSync(pProxyDevUsbIp, &Setup);
1684}
1685
1686
1687/**
1688 * @interface_method_impl{USBPROXYBACK,pfnUrbQueue}
1689 */
1690static DECLCALLBACK(int) usbProxyUsbIpUrbQueue(PUSBPROXYDEV pProxyDev, PVUSBURB pUrb)
1691{
1692 LogFlowFunc(("pUrb=%p\n", pUrb));
1693
1694 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1695
1696 /* Allocate a USB/IP Urb. */
1697 PUSBPROXYURBUSBIP pUrbUsbIp = usbProxyUsbIpUrbAlloc(pProxyDevUsbIp);
1698 if (!pUrbUsbIp)
1699 return VERR_NO_MEMORY;
1700
1701 pUrbUsbIp->fCancelled = false;
1702 pUrbUsbIp->pVUsbUrb = pUrb;
1703 pUrb->Dev.pvPrivate = pUrbUsbIp;
1704
1705 int rc = RTSemFastMutexRequest(pProxyDevUsbIp->hMtxLists);
1706 AssertRC(rc);
1707 RTListAppend(&pProxyDevUsbIp->ListUrbsToQueue, &pUrbUsbIp->NodeList);
1708 RTSemFastMutexRelease(pProxyDevUsbIp->hMtxLists);
1709
1710 return usbProxyReaperKick(pProxyDevUsbIp, USBIP_REAPER_WAKEUP_REASON_QUEUE);
1711}
1712
1713
1714/**
1715 * @interface_method_impl{USBPROXYBACK,pfnUrbReap}
1716 */
1717static DECLCALLBACK(PVUSBURB) usbProxyUsbIpUrbReap(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies)
1718{
1719 LogFlowFunc(("pProxyDev=%s\n", pProxyDev->pUsbIns->pszName));
1720
1721 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1722 PUSBPROXYURBUSBIP pUrbUsbIp = NULL;
1723 PVUSBURB pUrb = NULL;
1724 int rc = VINF_SUCCESS;
1725
1726 /* Queue new URBs first. */
1727 rc = usbProxyUsbIpUrbsQueuePending(pProxyDevUsbIp);
1728 AssertRC(rc);
1729
1730 /* Any URBs pending delivery? */
1731 if (!RTListIsEmpty(&pProxyDevUsbIp->ListUrbsLanded))
1732 pUrbUsbIp = RTListGetFirst(&pProxyDevUsbIp->ListUrbsLanded, USBPROXYURBUSBIP, NodeList);
1733 else
1734 pUrbUsbIp = usbProxyUsbIpPollWorker(pProxyDevUsbIp, 0, true /*fPollWakePipe*/, cMillies);
1735
1736 if (pUrbUsbIp)
1737 {
1738 pUrb = pUrbUsbIp->pVUsbUrb;
1739 pUrb->enmStatus = pUrbUsbIp->enmStatus;
1740
1741 /* unlink from the pending delivery list */
1742 usbProxyUsbIpUnlinkUrb(pProxyDevUsbIp, pUrbUsbIp);
1743 usbProxyUsbIpUrbFree(pProxyDevUsbIp, pUrbUsbIp);
1744 }
1745
1746 return pUrb;
1747}
1748
1749
1750/**
1751 * @interface_method_impl{USBPROXYBACK,pfnUrbCancel}
1752 */
1753static DECLCALLBACK(int) usbProxyUsbIpUrbCancel(PUSBPROXYDEV pProxyDev, PVUSBURB pUrb)
1754{
1755 LogFlowFunc(("pUrb=%p\n", pUrb));
1756
1757 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1758 PUSBPROXYURBUSBIP pUrbUsbIp = (PUSBPROXYURBUSBIP)pUrb->Dev.pvPrivate;
1759 UsbIpReqUnlink ReqUnlink;
1760
1761 RT_ZERO(ReqUnlink);
1762
1763 uint32_t u32SeqNum = usbProxyUsbIpSeqNumGet(pProxyDevUsbIp);
1764 ReqUnlink.Hdr.u32ReqRet = USBIP_CMD_UNLINK;
1765 ReqUnlink.Hdr.u32SeqNum = u32SeqNum;
1766 ReqUnlink.Hdr.u32DevId = pProxyDevUsbIp->u32DevId;
1767 ReqUnlink.Hdr.u32Direction = USBIP_DIR_OUT;
1768 ReqUnlink.Hdr.u32Endpoint = pUrb->EndPt;
1769 ReqUnlink.u32SeqNum = pUrbUsbIp->u32SeqNumUrb;
1770
1771 usbProxyUsbIpReqUnlinkH2N(&ReqUnlink);
1772 int rc = RTTcpWrite(pProxyDevUsbIp->hSocket, &ReqUnlink, sizeof(ReqUnlink));
1773 if (RT_SUCCESS(rc))
1774 {
1775 pUrbUsbIp->u32SeqNumUrbUnlink = u32SeqNum;
1776 pUrbUsbIp->fCancelled = true;
1777 }
1778
1779 return rc;
1780}
1781
1782
1783/**
1784 * @interface_method_impl{USBPROXYBACK,pfnWakeup}
1785 */
1786static DECLCALLBACK(int) usbProxyUsbIpWakeup(PUSBPROXYDEV pProxyDev)
1787{
1788 LogFlowFunc(("pProxyDev=%s\n", pProxyDev->pUsbIns->pszName));
1789
1790 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1791 return usbProxyReaperKick(pProxyDevUsbIp, USBIP_REAPER_WAKEUP_REASON_EXTERNAL);
1792}
1793
1794
1795/**
1796 * The USB/IP USB Proxy Backend operations.
1797 */
1798extern const USBPROXYBACK g_USBProxyDeviceUsbIp =
1799{
1800 /* pszName */
1801 "usbip",
1802 /* cbBackend */
1803 sizeof(USBPROXYDEVUSBIP),
1804 usbProxyUsbIpOpen,
1805 NULL,
1806 usbProxyUsbIpClose,
1807 usbProxyUsbIpReset,
1808 usbProxyUsbIpSetConfig,
1809 usbProxyUsbIpClaimInterface,
1810 usbProxyUsbIpReleaseInterface,
1811 usbProxyUsbIpSetInterface,
1812 usbProxyUsbIpClearHaltedEp,
1813 usbProxyUsbIpUrbQueue,
1814 usbProxyUsbIpUrbCancel,
1815 usbProxyUsbIpUrbReap,
1816 usbProxyUsbIpWakeup,
1817 0
1818};
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