VirtualBox

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

Last change on this file was 103154, checked in by vboxsync, 4 months ago

Devices/USB/USBProxyDevice-usbip.cpp: u32Status is actually signed, fix warnings, bugref:3409

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 64.3 KB
Line 
1/* $Id: USBProxyDevice-usbip.cpp 103154 2024-01-31 16:16:34Z vboxsync $ */
2/** @file
3 * USB device proxy - USB/IP backend.
4 */
5
6/*
7 * Copyright (C) 2014-2023 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 i32Status;
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 i32Status;
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 i32Status;
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 i32Status;
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 * @param pHdr The header to convert.
460 */
461DECLINLINE(void) usbProxyUsbIpReqRetHdrN2H(PUsbIpReqRetHdr pHdr)
462{
463 pHdr->u32ReqRet = RT_H2N_U32(pHdr->u32ReqRet);
464 pHdr->u32SeqNum = RT_H2N_U32(pHdr->u32SeqNum);
465 pHdr->u32DevId = RT_H2N_U32(pHdr->u32DevId);
466 pHdr->u32Direction = RT_H2N_U32(pHdr->u32Direction);
467 pHdr->u32Endpoint = RT_H2N_U32(pHdr->u32Endpoint);
468}
469
470/**
471 * Converts a request/reply header from host to network endianness.
472 *
473 * @param pHdr The header to convert.
474 */
475DECLINLINE(void) usbProxyUsbIpReqRetHdrH2N(PUsbIpReqRetHdr pHdr)
476{
477 pHdr->u32ReqRet = RT_N2H_U32(pHdr->u32ReqRet);
478 pHdr->u32SeqNum = RT_N2H_U32(pHdr->u32SeqNum);
479 pHdr->u32DevId = RT_N2H_U32(pHdr->u32DevId);
480 pHdr->u32Direction = RT_N2H_U32(pHdr->u32Direction);
481 pHdr->u32Endpoint = RT_N2H_U32(pHdr->u32Endpoint);
482}
483
484/**
485 * Converts a submit request from host to network endianness.
486 *
487 * @param pReqSubmit The submit request to convert.
488 */
489DECLINLINE(void) usbProxyUsbIpReqSubmitH2N(PUsbIpReqSubmit pReqSubmit)
490{
491 usbProxyUsbIpReqRetHdrH2N(&pReqSubmit->Hdr);
492 pReqSubmit->u32XferFlags = RT_H2N_U32(pReqSubmit->u32XferFlags);
493 pReqSubmit->u32TransferBufferLength = RT_H2N_U32(pReqSubmit->u32TransferBufferLength);
494 pReqSubmit->u32StartFrame = RT_H2N_U32(pReqSubmit->u32StartFrame);
495 pReqSubmit->u32NumIsocPkts = RT_H2N_U32(pReqSubmit->u32NumIsocPkts);
496 pReqSubmit->u32Interval = RT_H2N_U32(pReqSubmit->u32Interval);
497}
498
499/**
500 * Converts a submit reply from network to host endianness.
501 *
502 * @param pReqSubmit The submit reply to convert.
503 */
504DECLINLINE(void) usbProxyUsbIpRetSubmitN2H(PUsbIpRetSubmit pRetSubmit)
505{
506 usbProxyUsbIpReqRetHdrN2H(&pRetSubmit->Hdr);
507 pRetSubmit->i32Status = RT_N2H_S32(pRetSubmit->i32Status);
508 pRetSubmit->u32ActualLength = RT_N2H_U32(pRetSubmit->u32ActualLength);
509 pRetSubmit->u32StartFrame = RT_N2H_U32(pRetSubmit->u32StartFrame);
510 pRetSubmit->u32NumIsocPkts = RT_N2H_U32(pRetSubmit->u32NumIsocPkts);
511 pRetSubmit->u32ErrorCount = RT_N2H_U32(pRetSubmit->u32ErrorCount);
512}
513
514/**
515 * Converts a isochronous packet descriptor from host to network endianness.
516 *
517 * @param pIsocPktDesc The packet descriptor to convert.
518 */
519DECLINLINE(void) usbProxyUsbIpIsocPktDescH2N(PUsbIpIsocPktDesc pIsocPktDesc)
520{
521 pIsocPktDesc->u32Offset = RT_H2N_U32(pIsocPktDesc->u32Offset);
522 pIsocPktDesc->u32Length = RT_H2N_U32(pIsocPktDesc->u32Length);
523 pIsocPktDesc->u32ActualLength = RT_H2N_U32(pIsocPktDesc->u32ActualLength);
524 pIsocPktDesc->i32Status = RT_H2N_U32(pIsocPktDesc->i32Status);
525}
526
527/**
528 * Converts a isochronous packet descriptor from network to host endianness.
529 *
530 * @param pIsocPktDesc The packet descriptor to convert.
531 */
532DECLINLINE(void) usbProxyUsbIpIsocPktDescN2H(PUsbIpIsocPktDesc pIsocPktDesc)
533{
534 pIsocPktDesc->u32Offset = RT_N2H_U32(pIsocPktDesc->u32Offset);
535 pIsocPktDesc->u32Length = RT_N2H_U32(pIsocPktDesc->u32Length);
536 pIsocPktDesc->u32ActualLength = RT_N2H_U32(pIsocPktDesc->u32ActualLength);
537 pIsocPktDesc->i32Status = RT_N2H_U32(pIsocPktDesc->i32Status);
538}
539
540/**
541 * Converts a unlink request from host to network endianness.
542 *
543 * @param pReqUnlink The unlink request to convert.
544 */
545DECLINLINE(void) usbProxyUsbIpReqUnlinkH2N(PUsbIpReqUnlink pReqUnlink)
546{
547 usbProxyUsbIpReqRetHdrH2N(&pReqUnlink->Hdr);
548 pReqUnlink->u32SeqNum = RT_H2N_U32(pReqUnlink->u32SeqNum);
549}
550
551/**
552 * Converts a unlink reply from network to host endianness.
553 *
554 * @param pRetUnlink The unlink reply to convert.
555 */
556DECLINLINE(void) usbProxyUsbIpRetUnlinkN2H(PUsbIpRetUnlink pRetUnlink)
557{
558 usbProxyUsbIpReqRetHdrN2H(&pRetUnlink->Hdr);
559 pRetUnlink->i32Status = RT_N2H_S32(pRetUnlink->i32Status);
560}
561
562/**
563 * Convert the given exported device structure from host to network byte order.
564 *
565 * @param pDevice The device structure to convert.
566 */
567DECLINLINE(void) usbProxyUsbIpExportedDeviceN2H(PUsbIpExportedDevice pDevice)
568{
569 pDevice->u32BusNum = RT_N2H_U32(pDevice->u32BusNum);
570 pDevice->u32DevNum = RT_N2H_U32(pDevice->u32DevNum);
571 pDevice->u32Speed = RT_N2H_U16(pDevice->u32Speed);
572 pDevice->u16VendorId = RT_N2H_U16(pDevice->u16VendorId);
573 pDevice->u16ProductId = RT_N2H_U16(pDevice->u16ProductId);
574 pDevice->u16BcdDevice = RT_N2H_U16(pDevice->u16BcdDevice);
575}
576
577/**
578 * Converts a USB/IP status code to a VUSB status code.
579 *
580 * @returns VUSB status code.
581 * @param i32Status The USB/IP status code from the reply.
582 */
583DECLINLINE(VUSBSTATUS) usbProxyUsbIpVUsbStatusConvertFromStatus(int32_t i32Status)
584{
585 if (RT_LIKELY( i32Status == USBIP_STATUS_SUCCESS
586 || i32Status == USBIP_STATUS_SHORT_READ))
587 return VUSBSTATUS_OK;
588
589 switch (i32Status)
590 {
591 case USBIP_STATUS_PIPE_STALLED:
592 return VUSBSTATUS_STALL;
593 default:
594 return VUSBSTATUS_DNR;
595 }
596 /* not reached */
597}
598
599/**
600 * Gets the next free sequence number.
601 *
602 * @returns Next free sequence number.
603 * @param pProxyDevUsbIp The USB/IP proxy device data.
604 */
605DECLINLINE(uint32_t) usbProxyUsbIpSeqNumGet(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
606{
607 uint32_t u32SeqNum = ASMAtomicIncU32(&pProxyDevUsbIp->u32SeqNumNext);
608 if (RT_UNLIKELY(!u32SeqNum))
609 u32SeqNum = ASMAtomicIncU32(&pProxyDevUsbIp->u32SeqNumNext);
610
611 return u32SeqNum;
612}
613
614/**
615 * Links a given URB into the given list.
616 *
617 * @param pProxyDevUsbIp The USB/IP proxy device data.
618 * @param pList The list to link the URB into.
619 * @param pUrbUsbIp The URB to link.
620 */
621DECLINLINE(void) usbProxyUsbIpLinkUrb(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PRTLISTANCHOR pList, PUSBPROXYURBUSBIP pUrbUsbIp)
622{
623 int rc = RTSemFastMutexRequest(pProxyDevUsbIp->hMtxLists);
624 AssertRC(rc);
625 RTListAppend(pList, &pUrbUsbIp->NodeList);
626 RTSemFastMutexRelease(pProxyDevUsbIp->hMtxLists);
627}
628
629/**
630 * Unlinks a given URB from the current assigned list.
631 *
632 * @param pProxyDevUsbIp The USB/IP proxy device data.
633 * @param pUrbUsbIp The URB to unlink.
634 */
635DECLINLINE(void) usbProxyUsbIpUnlinkUrb(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PUSBPROXYURBUSBIP pUrbUsbIp)
636{
637 int rc = RTSemFastMutexRequest(pProxyDevUsbIp->hMtxLists);
638 AssertRC(rc);
639 RTListNodeRemove(&pUrbUsbIp->NodeList);
640 RTSemFastMutexRelease(pProxyDevUsbIp->hMtxLists);
641}
642
643/**
644 * Allocates a USB/IP proxy specific URB state.
645 *
646 * @returns Pointer to the USB/IP specific URB data or NULL on failure.
647 * @param pProxyDevUsbIp The USB/IP proxy device data.
648 */
649static PUSBPROXYURBUSBIP usbProxyUsbIpUrbAlloc(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
650{
651 NOREF(pProxyDevUsbIp);
652 return (PUSBPROXYURBUSBIP)RTMemAllocZ(sizeof(USBPROXYURBUSBIP));
653}
654
655/**
656 * Frees the given USB/IP URB state.
657 *
658 * @param pProxyDevUsbIp The USB/IP proxy device data.
659 * @param pUrbUsbIp The USB/IP speciic URB data.
660 */
661static void usbProxyUsbIpUrbFree(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PUSBPROXYURBUSBIP pUrbUsbIp)
662{
663 NOREF(pProxyDevUsbIp);
664 RTMemFree(pUrbUsbIp);
665}
666
667/**
668 * Parse the string representation of the host address.
669 *
670 * @returns VBox status code.
671 * @param pProxyDevUsbIp The USB/IP proxy device data to parse the address for.
672 * @param pszAddress The address string to parse.
673 */
674static int usbProxyUsbIpParseAddress(PUSBPROXYDEVUSBIP pProxyDevUsbIp, const char *pszAddress)
675{
676 int rc = VINF_SUCCESS;
677
678 if (!RTStrNCmp(pszAddress, USBIP_URI_PREFIX, USBIP_URI_PREFIX_LEN))
679 {
680 pszAddress += USBIP_URI_PREFIX_LEN;
681
682 const char *pszPortStart = RTStrStr(pszAddress, ":");
683 if (pszPortStart)
684 {
685 pszPortStart++;
686
687 const char *pszBusIdStart = RTStrStr(pszPortStart, ":");
688 if (pszBusIdStart)
689 {
690 size_t cbHost = pszPortStart - pszAddress - 1;
691 size_t cbBusId = strlen(pszBusIdStart);
692
693 pszBusIdStart++;
694
695 rc = RTStrToUInt32Ex(pszPortStart, NULL, 10 /* uBase */, &pProxyDevUsbIp->uPort);
696 if ( rc == VINF_SUCCESS
697 || rc == VWRN_TRAILING_CHARS)
698 {
699 rc = RTStrAllocEx(&pProxyDevUsbIp->pszHost, cbHost + 1);
700 if (RT_SUCCESS(rc))
701 rc = RTStrAllocEx(&pProxyDevUsbIp->pszBusId, cbBusId + 1);
702 if (RT_SUCCESS(rc))
703 {
704 rc = RTStrCopyEx(pProxyDevUsbIp->pszHost, cbHost + 1, pszAddress, cbHost);
705 AssertRC(rc);
706
707 rc = RTStrCopyEx(pProxyDevUsbIp->pszBusId, cbBusId + 1, pszBusIdStart, cbBusId);
708 AssertRC(rc);
709
710 return VINF_SUCCESS;
711 }
712 }
713 else
714 rc = VERR_INVALID_PARAMETER;
715 }
716 else
717 rc = VERR_INVALID_PARAMETER;
718 }
719 else
720 rc = VERR_INVALID_PARAMETER;
721 }
722 else
723 rc = VERR_INVALID_PARAMETER;
724
725 return rc;
726}
727
728/**
729 * Connects to the USB/IP host and claims the device given in the proxy device data.
730 *
731 * @returns VBox status code.
732 * @param pProxyDevUsbIp The USB/IP proxy device data.
733 */
734static int usbProxyUsbIpConnect(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
735{
736 int rc = VINF_SUCCESS;
737 rc = RTTcpClientConnect(pProxyDevUsbIp->pszHost, pProxyDevUsbIp->uPort, &pProxyDevUsbIp->hSocket);
738 if (RT_SUCCESS(rc))
739 {
740 /* Disable send coalescing. */
741 rc = RTTcpSetSendCoalescing(pProxyDevUsbIp->hSocket, false);
742 if (RT_FAILURE(rc))
743 LogRel(("UsbIp: Disabling send coalescing failed (rc=%Rrc), continuing nevertheless but expect reduced performance\n", rc));
744
745 /* Import the device, i.e. claim it for our use. */
746 UsbIpReqImport ReqImport;
747 ReqImport.u16Version = RT_H2N_U16(USBIP_VERSION);
748 ReqImport.u16Cmd = RT_H2N_U16(USBIP_INDICATOR_REQ | USBIP_REQ_RET_IMPORT);
749 ReqImport.i32Status = RT_H2N_S32(USBIP_STATUS_SUCCESS);
750 rc = RTStrCopy(&ReqImport.aszBusId[0], sizeof(ReqImport.aszBusId), pProxyDevUsbIp->pszBusId);
751 if (rc == VINF_SUCCESS)
752 {
753 rc = RTTcpWrite(pProxyDevUsbIp->hSocket, &ReqImport, sizeof(ReqImport));
754 if (RT_SUCCESS(rc))
755 {
756 /* Read the reply. */
757 UsbIpRetImport RetImport;
758 rc = RTTcpRead(pProxyDevUsbIp->hSocket, &RetImport, sizeof(RetImport), NULL);
759 if (RT_SUCCESS(rc))
760 {
761 RetImport.u16Version = RT_N2H_U16(RetImport.u16Version);
762 RetImport.u16Cmd = RT_N2H_U16(RetImport.u16Cmd);
763 RetImport.i32Status = RT_N2H_S32(RetImport.i32Status);
764 if ( RetImport.u16Version == USBIP_VERSION
765 && RetImport.u16Cmd == USBIP_REQ_RET_IMPORT
766 && RetImport.i32Status == USBIP_STATUS_SUCCESS)
767 {
768 /* Read the device data. */
769 UsbIpExportedDevice Device;
770 rc = RTTcpRead(pProxyDevUsbIp->hSocket, &Device, sizeof(Device), NULL);
771 if (RT_SUCCESS(rc))
772 {
773 usbProxyUsbIpExportedDeviceN2H(&Device);
774 pProxyDevUsbIp->u32DevId = (Device.u32BusNum << 16) | Device.u32DevNum;
775
776 rc = RTPollSetAddSocket(pProxyDevUsbIp->hPollSet, pProxyDevUsbIp->hSocket,
777 RTPOLL_EVT_READ | RTPOLL_EVT_ERROR, USBIP_POLL_ID_SOCKET);
778 }
779 }
780 else
781 {
782 /* Check what went wrong and leave a meaningful error message in the log. */
783 if (RetImport.u16Version != USBIP_VERSION)
784 LogRel(("UsbIp: Unexpected protocol version received from host (%#x vs. %#x)\n",
785 RetImport.u16Version, USBIP_VERSION));
786 else if (RetImport.u16Cmd != USBIP_REQ_RET_IMPORT)
787 LogRel(("UsbIp: Unexpected reply code received from host (%#x vs. %#x)\n",
788 RetImport.u16Cmd, USBIP_REQ_RET_IMPORT));
789 else if (RetImport.i32Status != 0)
790 LogRel(("UsbIp: Claiming the device has failed on the host with an unspecified error\n"));
791 else
792 AssertMsgFailed(("Something went wrong with if condition\n"));
793 }
794 }
795 }
796 }
797 else
798 {
799 LogRel(("UsbIp: Given bus ID is exceeds permitted protocol length: %u vs %u\n",
800 strlen(pProxyDevUsbIp->pszBusId) + 1, sizeof(ReqImport.aszBusId)));
801 rc = VERR_INVALID_PARAMETER;
802 }
803
804 if (RT_FAILURE(rc))
805 RTTcpClientCloseEx(pProxyDevUsbIp->hSocket, false /*fGracefulShutdown*/);
806 }
807 if (RT_FAILURE(rc))
808 LogRel(("UsbIp: Connecting to the host %s failed with %Rrc\n", pProxyDevUsbIp->pszHost, rc));
809 return rc;
810}
811
812/**
813 * Disconnects from the USB/IP host releasing the device given in the proxy device data.
814 *
815 * @returns VBox status code.
816 * @param pProxyDevUsbIp The USB/IP proxy device data.
817 */
818static int usbProxyUsbIpDisconnect(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
819{
820 int rc = RTPollSetRemove(pProxyDevUsbIp->hPollSet, USBIP_POLL_ID_SOCKET);
821 Assert(RT_SUCCESS(rc) || rc == VERR_POLL_HANDLE_ID_NOT_FOUND);
822
823 rc = RTTcpClientCloseEx(pProxyDevUsbIp->hSocket, false /*fGracefulShutdown*/);
824 if (RT_SUCCESS(rc))
825 pProxyDevUsbIp->hSocket = NIL_RTSOCKET;
826 return rc;
827}
828
829/**
830 * Returns the URB matching the given sequence number from the in flight list.
831 *
832 * @returns pointer to the URB matching the given sequence number or NULL
833 * @param pProxyDevUsbIp The USB/IP proxy device data.
834 * @param u32SeqNum The sequence number to search for.
835 */
836static PUSBPROXYURBUSBIP usbProxyUsbIpGetInFlightUrbFromSeqNum(PUSBPROXYDEVUSBIP pProxyDevUsbIp, uint32_t u32SeqNum)
837{
838 bool fFound = false;
839
840 int rc = RTSemFastMutexRequest(pProxyDevUsbIp->hMtxLists);
841 AssertRC(rc);
842 PUSBPROXYURBUSBIP pIt;
843 RTListForEach(&pProxyDevUsbIp->ListUrbsInFlight, pIt, USBPROXYURBUSBIP, NodeList)
844 {
845 if (pIt->u32SeqNumUrb == u32SeqNum)
846 {
847 fFound = true;
848 break;
849 }
850 }
851 RTSemFastMutexRelease(pProxyDevUsbIp->hMtxLists);
852
853 return fFound ? pIt : NULL;
854}
855
856/**
857 * Returns the URB matching the given sequence number from the cancel list.
858 *
859 * @returns pointer to the URB matching the given sequence number or NULL
860 * @param pProxyDevUsbIp The USB/IP proxy device data.
861 * @param u32SeqNum The sequence number to search for.
862 */
863static PUSBPROXYURBUSBIP usbProxyUsbIpGetCancelledUrbFromSeqNum(PUSBPROXYDEVUSBIP pProxyDevUsbIp, uint32_t u32SeqNum)
864{
865 bool fFound = false;
866
867 int rc = RTSemFastMutexRequest(pProxyDevUsbIp->hMtxLists);
868 AssertRC(rc);
869 PUSBPROXYURBUSBIP pIt;
870 RTListForEach(&pProxyDevUsbIp->ListUrbsInFlight, pIt, USBPROXYURBUSBIP, NodeList)
871 {
872 if ( pIt->u32SeqNumUrbUnlink == u32SeqNum
873 && pIt->fCancelled == true)
874 {
875 fFound = true;
876 break;
877 }
878 }
879 RTSemFastMutexRelease(pProxyDevUsbIp->hMtxLists);
880
881 return fFound ? pIt : NULL;
882}
883
884/**
885 * Resets the receive state for a new reply.
886 *
887 * @param pProxyDevUsbIp The USB/IP proxy device data.
888 */
889static void usbProxyUsbIpResetRecvState(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
890{
891 pProxyDevUsbIp->enmRecvState = USBPROXYUSBIPRECVSTATE_HDR_COMMON;
892 pProxyDevUsbIp->pbRecv = (uint8_t *)&pProxyDevUsbIp->BufRet;
893 pProxyDevUsbIp->cbRecv = 0;
894 pProxyDevUsbIp->cbLeft = sizeof(UsbIpReqRetHdr);
895}
896
897static void usbProxyUsbIpRecvStateAdvance(PUSBPROXYDEVUSBIP pProxyDevUsbIp, USBPROXYUSBIPRECVSTATE enmState,
898 uint8_t *pbData, size_t cbData)
899{
900 pProxyDevUsbIp->enmRecvState = enmState;
901 pProxyDevUsbIp->cbRecv = 0;
902 pProxyDevUsbIp->cbLeft = cbData;
903 pProxyDevUsbIp->pbRecv = pbData;
904}
905
906/**
907 * Handles reception of a USB/IP PDU.
908 *
909 * @returns VBox status code.
910 * @param pProxyDevUsbIp The USB/IP proxy device data.
911 * @param ppUrbUsbIp Where to store the pointer to the USB/IP URB which completed.
912 * Will be NULL if the received PDU is not complete and we have
913 * have to wait for more data or on failure.
914 */
915static int usbProxyUsbIpRecvPdu(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PUSBPROXYURBUSBIP *ppUrbUsbIp)
916{
917 int rc = VINF_SUCCESS;
918 size_t cbRead = 0;
919 PUSBPROXYURBUSBIP pUrbUsbIp = NULL;
920
921 Assert(pProxyDevUsbIp->cbLeft);
922
923 /* Read any available data first. */
924 rc = RTTcpReadNB(pProxyDevUsbIp->hSocket, pProxyDevUsbIp->pbRecv, pProxyDevUsbIp->cbLeft, &cbRead);
925 if (RT_SUCCESS(rc))
926 {
927 pProxyDevUsbIp->cbRecv += cbRead;
928 pProxyDevUsbIp->cbLeft -= cbRead;
929 pProxyDevUsbIp->pbRecv += cbRead;
930
931 /* Process the received data if there is nothing to receive left for the current state. */
932 if (!pProxyDevUsbIp->cbLeft)
933 {
934 switch (pProxyDevUsbIp->enmRecvState)
935 {
936 case USBPROXYUSBIPRECVSTATE_HDR_COMMON:
937 {
938 Assert(pProxyDevUsbIp->cbRecv == sizeof(UsbIpReqRetHdr));
939
940 /*
941 * Determine the residual amount of data to receive until
942 * the complete reply header was received.
943 */
944 switch (RT_N2H_U32(pProxyDevUsbIp->BufRet.Hdr.u32ReqRet))
945 {
946 case USBIP_RET_SUBMIT:
947 pProxyDevUsbIp->cbLeft = sizeof(UsbIpRetSubmit) - sizeof(UsbIpReqRetHdr);
948 pProxyDevUsbIp->enmRecvState = USBPROXYUSBIPRECVSTATE_HDR_RESIDUAL;
949 break;
950 case USBIP_RET_UNLINK:
951 pProxyDevUsbIp->cbLeft = sizeof(UsbIpRetUnlink) - sizeof(UsbIpReqRetHdr);
952 pProxyDevUsbIp->enmRecvState = USBPROXYUSBIPRECVSTATE_HDR_RESIDUAL;
953 break;
954 default:
955 AssertLogRelMsgFailed(("Invalid reply header received: %d\n",
956 pProxyDevUsbIp->BufRet.Hdr.u32ReqRet));
957 usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
958 }
959
960 break;
961 }
962 case USBPROXYUSBIPRECVSTATE_HDR_RESIDUAL:
963 {
964 switch (RT_N2H_U32(pProxyDevUsbIp->BufRet.Hdr.u32ReqRet))
965 {
966 case USBIP_RET_SUBMIT:
967 /* Get the URB from the in flight list. */
968 pProxyDevUsbIp->pUrbUsbIp = usbProxyUsbIpGetInFlightUrbFromSeqNum(pProxyDevUsbIp, RT_N2H_U32(pProxyDevUsbIp->BufRet.Hdr.u32SeqNum));
969 if (pProxyDevUsbIp->pUrbUsbIp)
970 {
971 usbProxyUsbIpRetSubmitN2H(&pProxyDevUsbIp->BufRet.RetSubmit);
972
973 /* We still have to receive the transfer buffer, even in case of an error. */
974 pProxyDevUsbIp->pUrbUsbIp->enmStatus = usbProxyUsbIpVUsbStatusConvertFromStatus(pProxyDevUsbIp->BufRet.RetSubmit.i32Status);
975 if (pProxyDevUsbIp->pUrbUsbIp->enmDir == VUSBDIRECTION_IN)
976 {
977 uint8_t *pbData = NULL;
978 size_t cbRet = 0;
979
980 AssertPtr(pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb);
981 if (pProxyDevUsbIp->pUrbUsbIp->enmType == VUSBXFERTYPE_MSG)
982 {
983 /* Preserve the setup request. */
984 pbData = &pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->abData[sizeof(VUSBSETUP)];
985 cbRet = pProxyDevUsbIp->BufRet.RetSubmit.u32ActualLength + sizeof(VUSBSETUP);
986 }
987 else
988 {
989 pbData = &pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->abData[0];
990 cbRet = pProxyDevUsbIp->BufRet.RetSubmit.u32ActualLength;
991 }
992
993 if (pProxyDevUsbIp->BufRet.RetSubmit.u32ActualLength)
994 {
995 if (RT_LIKELY(pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->cbData >= cbRet))
996 {
997 pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->cbData = (uint32_t)cbRet;
998 usbProxyUsbIpRecvStateAdvance(pProxyDevUsbIp, USBPROXYUSBIPRECVSTATE_URB_BUFFER,
999 pbData, pProxyDevUsbIp->BufRet.RetSubmit.u32ActualLength);
1000 }
1001 else
1002 {
1003 /*
1004 * Bogus length returned from the USB/IP remote server.
1005 * Error out because there is no way to find the end of the current
1006 * URB and the beginning of the next one. The error will cause closing the
1007 * connection to the rogue remote and all URBs get completed with an error.
1008 */
1009 LogRelMax(10, ("USB/IP: Received reply with sequence number %u contains invalid length %zu (max %zu)\n",
1010 pProxyDevUsbIp->BufRet.Hdr.u32SeqNum, cbRet,
1011 pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->cbData));
1012 rc = VERR_NET_PROTOCOL_ERROR;
1013 }
1014 }
1015 else
1016 {
1017 pUrbUsbIp = pProxyDevUsbIp->pUrbUsbIp;
1018 usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
1019 }
1020 }
1021 else
1022 {
1023 Assert(pProxyDevUsbIp->pUrbUsbIp->enmDir == VUSBDIRECTION_OUT);
1024 pUrbUsbIp = pProxyDevUsbIp->pUrbUsbIp;
1025 usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
1026 }
1027 }
1028 else
1029 {
1030 LogRel(("USB/IP: Received reply with sequence number %u doesn't match any local URB\n",
1031 RT_N2H_U32(pProxyDevUsbIp->BufRet.Hdr.u32SeqNum)));
1032 usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
1033 rc = VERR_NET_PROTOCOL_ERROR;
1034 }
1035 break;
1036 case USBIP_RET_UNLINK:
1037 pProxyDevUsbIp->pUrbUsbIp = usbProxyUsbIpGetCancelledUrbFromSeqNum(pProxyDevUsbIp, RT_N2H_U32(pProxyDevUsbIp->BufRet.Hdr.u32SeqNum));
1038 if (pProxyDevUsbIp->pUrbUsbIp)
1039 {
1040 usbProxyUsbIpRetUnlinkN2H(&pProxyDevUsbIp->BufRet.RetUnlink);
1041 pUrbUsbIp = pProxyDevUsbIp->pUrbUsbIp;
1042 pUrbUsbIp->pVUsbUrb->enmStatus = usbProxyUsbIpVUsbStatusConvertFromStatus(pProxyDevUsbIp->BufRet.RetUnlink.i32Status);
1043 }
1044 /* else: Probably received the data for the URB and is complete already. */
1045
1046 usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
1047 break;
1048 }
1049
1050 break;
1051 }
1052 case USBPROXYUSBIPRECVSTATE_URB_BUFFER:
1053 if (pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->enmType == VUSBXFERTYPE_ISOC)
1054 usbProxyUsbIpRecvStateAdvance(pProxyDevUsbIp, USBPROXYUSBIPRECVSTATE_ISOC_PKT_DESCS,
1055 (uint8_t *)&pProxyDevUsbIp->aIsocPktDesc[0],
1056 pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->cIsocPkts * sizeof(UsbIpIsocPktDesc));
1057 else
1058 {
1059 pUrbUsbIp = pProxyDevUsbIp->pUrbUsbIp;
1060 usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
1061 }
1062 break;
1063 case USBPROXYUSBIPRECVSTATE_ISOC_PKT_DESCS:
1064 /* Process all received isochronous packet descriptors. */
1065 for (unsigned i = 0; i < pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->cIsocPkts; i++)
1066 {
1067 PVUSBURBISOCPTK pIsocPkt = &pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->aIsocPkts[i];
1068 PUsbIpIsocPktDesc pIsocPktUsbIp = &pProxyDevUsbIp->aIsocPktDesc[i];
1069
1070 usbProxyUsbIpIsocPktDescN2H(pIsocPktUsbIp);
1071 pIsocPkt->enmStatus = usbProxyUsbIpVUsbStatusConvertFromStatus(pIsocPktUsbIp->i32Status);
1072
1073 if (RT_LIKELY( pIsocPktUsbIp->u32Offset < pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->cbData
1074 && pProxyDevUsbIp->pUrbUsbIp->pVUsbUrb->cbData - pIsocPktUsbIp->u32Offset >= pIsocPktUsbIp->u32ActualLength))
1075 {
1076 pIsocPkt->off = pIsocPktUsbIp->u32Offset;
1077 pIsocPkt->cb = pIsocPktUsbIp->u32ActualLength;
1078 }
1079 else
1080 {
1081 /*
1082 * The offset and length value in the isoc packet descriptor are bogus and would cause a buffer overflow later on, leave an
1083 * error message and disconnect from the rogue remote end.
1084 */
1085 LogRelMax(10, ("USB/IP: Received reply with sequence number %u contains invalid isoc packet descriptor %u (offset=%u length=%u)\n",
1086 pProxyDevUsbIp->BufRet.Hdr.u32SeqNum, i,
1087 pIsocPktUsbIp->u32Offset, pIsocPktUsbIp->u32ActualLength));
1088 rc = VERR_NET_PROTOCOL_ERROR;
1089 break;
1090 }
1091 }
1092
1093 pUrbUsbIp = pProxyDevUsbIp->pUrbUsbIp;
1094 usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
1095 break;
1096 default:
1097 AssertLogRelMsgFailed(("USB/IP: Invalid receive state %d\n", pProxyDevUsbIp->enmRecvState));
1098 }
1099 }
1100 }
1101
1102 if (RT_SUCCESS(rc))
1103 *ppUrbUsbIp = pUrbUsbIp;
1104 else
1105 {
1106 /* Complete all URBs with DNR error and mark device as unplugged, the current one is still in the in flight list. */
1107 pProxyDevUsbIp->pUrbUsbIp = NULL;
1108 usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
1109 usbProxyUsbIpDisconnect(pProxyDevUsbIp);
1110
1111 rc = RTSemFastMutexRequest(pProxyDevUsbIp->hMtxLists);
1112 AssertRC(rc);
1113 PUSBPROXYURBUSBIP pIt;
1114 PUSBPROXYURBUSBIP pItNext;
1115 RTListForEachSafe(&pProxyDevUsbIp->ListUrbsInFlight, pIt, pItNext, USBPROXYURBUSBIP, NodeList)
1116 {
1117 if (pIt->pVUsbUrb) /* can be NULL for requests created by usbProxyUsbIpCtrlUrbExchangeSync(). */
1118 pIt->pVUsbUrb->enmStatus = VUSBSTATUS_CRC;
1119 RTListNodeRemove(&pIt->NodeList);
1120 RTListAppend(&pProxyDevUsbIp->ListUrbsLanded, &pIt->NodeList);
1121 }
1122 RTSemFastMutexRelease(pProxyDevUsbIp->hMtxLists);
1123 }
1124
1125 return rc;
1126}
1127
1128/**
1129 * Worker for queueing an URB on the main I/O thread.
1130 *
1131 * @returns VBox status code.
1132 * @param pProxyDevUsbIp The USB/IP proxy device data.
1133 * @param pUrbUsbIp The USB/IP URB to queue.
1134 */
1135static int usbProxyUsbIpUrbQueueWorker(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PUSBPROXYURBUSBIP pUrbUsbIp)
1136{
1137 PVUSBURB pUrb = pUrbUsbIp->pVUsbUrb;
1138
1139 pUrbUsbIp->u32SeqNumUrb = usbProxyUsbIpSeqNumGet(pProxyDevUsbIp);
1140 pUrbUsbIp->enmType = pUrb->enmType;
1141 pUrbUsbIp->enmStatus = pUrb->enmStatus;
1142 pUrbUsbIp->enmDir = pUrb->enmDir;
1143
1144 UsbIpReqSubmit ReqSubmit;
1145
1146 RT_ZERO(ReqSubmit);
1147 ReqSubmit.Hdr.u32ReqRet = USBIP_CMD_SUBMIT;
1148 ReqSubmit.Hdr.u32SeqNum = pUrbUsbIp->u32SeqNumUrb;
1149 ReqSubmit.Hdr.u32DevId = pProxyDevUsbIp->u32DevId;
1150 ReqSubmit.Hdr.u32Endpoint = pUrb->EndPt;
1151 ReqSubmit.Hdr.u32Direction = pUrb->enmDir == VUSBDIRECTION_IN ? USBIP_DIR_IN : USBIP_DIR_OUT;
1152 ReqSubmit.u32XferFlags = 0;
1153 if (pUrb->enmDir == VUSBDIRECTION_IN && pUrb->fShortNotOk)
1154 ReqSubmit.u32XferFlags |= USBIP_XFER_FLAGS_SHORT_NOT_OK;
1155
1156 ReqSubmit.u32TransferBufferLength = pUrb->cbData;
1157 ReqSubmit.u32StartFrame = 0;
1158 ReqSubmit.u32NumIsocPkts = 0;
1159 ReqSubmit.u32Interval = 0;
1160
1161 RTSGSEG aSegReq[3]; /* Maximum number of segments used for a Isochronous transfer. */
1162 UsbIpIsocPktDesc aIsocPktsDesc[8];
1163 unsigned cSegsUsed = 1;
1164 aSegReq[0].pvSeg = &ReqSubmit;
1165 aSegReq[0].cbSeg = sizeof(ReqSubmit);
1166
1167 switch (pUrb->enmType)
1168 {
1169 case VUSBXFERTYPE_MSG:
1170 memcpy(&ReqSubmit.Setup, &pUrb->abData, sizeof(ReqSubmit.Setup));
1171 ReqSubmit.u32TransferBufferLength -= sizeof(VUSBSETUP);
1172 if (pUrb->enmDir == VUSBDIRECTION_OUT)
1173 {
1174 aSegReq[cSegsUsed].cbSeg = pUrb->cbData - sizeof(VUSBSETUP);
1175 aSegReq[cSegsUsed].pvSeg = pUrb->abData + sizeof(VUSBSETUP);
1176 if (aSegReq[cSegsUsed].cbSeg)
1177 cSegsUsed++;
1178 }
1179 LogFlowFunc(("Message (Control) URB\n"));
1180 break;
1181 case VUSBXFERTYPE_ISOC:
1182 LogFlowFunc(("Isochronous URB\n"));
1183 ReqSubmit.u32XferFlags |= USBIP_XFER_FLAGS_ISO_ASAP;
1184 ReqSubmit.u32NumIsocPkts = pUrb->cIsocPkts;
1185 if (pUrb->enmDir == VUSBDIRECTION_OUT)
1186 {
1187 aSegReq[cSegsUsed].cbSeg = pUrb->cbData;
1188 aSegReq[cSegsUsed].pvSeg = pUrb->abData;
1189 cSegsUsed++;
1190 }
1191
1192 for (unsigned i = 0; i < pUrb->cIsocPkts; i++)
1193 {
1194 aIsocPktsDesc[i].u32Offset = pUrb->aIsocPkts[i].off;
1195 aIsocPktsDesc[i].u32Length = pUrb->aIsocPkts[i].cb;
1196 aIsocPktsDesc[i].u32ActualLength = 0; /** @todo */
1197 aIsocPktsDesc[i].i32Status = pUrb->aIsocPkts[i].enmStatus;
1198 usbProxyUsbIpIsocPktDescH2N(&aIsocPktsDesc[i]);
1199 }
1200
1201 if (pUrb->cIsocPkts)
1202 {
1203 aSegReq[cSegsUsed].cbSeg = pUrb->cIsocPkts * sizeof(UsbIpIsocPktDesc);
1204 aSegReq[cSegsUsed].pvSeg = &aIsocPktsDesc[0];
1205 cSegsUsed++;
1206 }
1207
1208 break;
1209 case VUSBXFERTYPE_BULK:
1210 case VUSBXFERTYPE_INTR:
1211 LogFlowFunc(("Bulk URB\n"));
1212 if (pUrb->enmDir == VUSBDIRECTION_OUT)
1213 {
1214 aSegReq[cSegsUsed].cbSeg = pUrb->cbData;
1215 aSegReq[cSegsUsed].pvSeg = pUrb->abData;
1216 cSegsUsed++;
1217 }
1218 break;
1219 default:
1220 return VERR_INVALID_PARAMETER; /** @todo better status code. */
1221 }
1222
1223 usbProxyUsbIpReqSubmitH2N(&ReqSubmit);
1224
1225 Assert(cSegsUsed <= RT_ELEMENTS(aSegReq));
1226
1227 /* Send the command. */
1228 RTSGBUF SgBufReq;
1229 RTSgBufInit(&SgBufReq, &aSegReq[0], cSegsUsed);
1230
1231 int rc = RTTcpSgWrite(pProxyDevUsbIp->hSocket, &SgBufReq);
1232 if (RT_SUCCESS(rc))
1233 {
1234 /* Link the URB into the list of in flight URBs. */
1235 usbProxyUsbIpLinkUrb(pProxyDevUsbIp, &pProxyDevUsbIp->ListUrbsInFlight, pUrbUsbIp);
1236 }
1237
1238 return rc;
1239}
1240
1241/**
1242 * Queues all pending URBs from the list.
1243 *
1244 * @returns VBox status code.
1245 * @param pProxyDevUsbIp The USB/IP proxy device data.
1246 */
1247static int usbProxyUsbIpUrbsQueuePending(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
1248{
1249 RTLISTANCHOR ListUrbsPending;
1250
1251 int rc = RTSemFastMutexRequest(pProxyDevUsbIp->hMtxLists);
1252 AssertRC(rc);
1253 RTListMove(&ListUrbsPending, &pProxyDevUsbIp->ListUrbsToQueue);
1254 RTSemFastMutexRelease(pProxyDevUsbIp->hMtxLists);
1255
1256 PUSBPROXYURBUSBIP pIter;
1257 PUSBPROXYURBUSBIP pIterNext;
1258 RTListForEachSafe(&ListUrbsPending, pIter, pIterNext, USBPROXYURBUSBIP, NodeList)
1259 {
1260 RTListNodeRemove(&pIter->NodeList);
1261 rc = usbProxyUsbIpUrbQueueWorker(pProxyDevUsbIp, pIter);
1262 if (RT_FAILURE(rc))
1263 {
1264 /* Complete URB with an error and place into landed list. */
1265 pIter->pVUsbUrb->enmStatus = VUSBSTATUS_DNR;
1266 usbProxyUsbIpLinkUrb(pProxyDevUsbIp, &pProxyDevUsbIp->ListUrbsLanded, pIter);
1267 }
1268 }
1269
1270 return VINF_SUCCESS;
1271}
1272
1273/**
1274 * Kick the reaper thread.
1275 *
1276 * @returns VBox status code.
1277 * @param pProxyDevUsbIp The USB/IP proxy device data.
1278 * @param bReason The wakeup reason.
1279 */
1280static int usbProxyReaperKick(PUSBPROXYDEVUSBIP pProxyDevUsbIp, char bReason)
1281{
1282 int rc = VINF_SUCCESS;
1283 size_t cbWritten = 0;
1284
1285 rc = RTPipeWrite(pProxyDevUsbIp->hPipeW, &bReason, 1, &cbWritten);
1286 Assert(RT_SUCCESS(rc) || cbWritten == 0);
1287
1288 return rc;
1289}
1290
1291/**
1292 * Drain the wakeup pipe.
1293 *
1294 * @returns Wakeup reason.
1295 * @param pProxyDevUsbIp The USB/IP proxy device data.
1296 */
1297static char usbProxyUsbIpWakeupPipeDrain(PUSBPROXYDEVUSBIP pProxyDevUsbIp)
1298{
1299 char bRead = 0;
1300 size_t cbRead = 0;
1301 int rc = RTPipeRead(pProxyDevUsbIp->hPipeR, &bRead, 1, &cbRead);
1302 Assert(RT_SUCCESS(rc) && cbRead == 1); NOREF(rc);
1303
1304 return bRead;
1305}
1306
1307/**
1308 * Executes the poll/receive loop either until a URB is received (with an optional matching sequence number) or
1309 * the given timeout has elapsed.
1310 *
1311 * @returns Pointer to the received USB/IP URB or NULL on timeout or error.
1312 * @param pProxyDevUsbIp The USB/IP proxy device data.
1313 * @param u32SeqNumRet The sequence number of a specific reply to return the URB for, 0 if
1314 * any received URB is accepted.
1315 * @param fPollWakePipe Flag whether to poll the wakeup pipe.
1316 * @param cMillies Maximum number of milliseconds to wait for an URB to arrive.
1317 */
1318static PUSBPROXYURBUSBIP usbProxyUsbIpPollWorker(PUSBPROXYDEVUSBIP pProxyDevUsbIp, uint32_t u32SeqNumRet,
1319 bool fPollWakePipe, RTMSINTERVAL cMillies)
1320{
1321 int rc = VINF_SUCCESS;
1322 PUSBPROXYURBUSBIP pUrbUsbIp = NULL;
1323
1324 if (!fPollWakePipe)
1325 {
1326 rc = RTPollSetEventsChange(pProxyDevUsbIp->hPollSet, USBIP_POLL_ID_PIPE, RTPOLL_EVT_ERROR);
1327 AssertRC(rc);
1328 }
1329
1330 while (!pUrbUsbIp && RT_SUCCESS(rc) && cMillies)
1331 {
1332 uint32_t uIdReady = 0;
1333 uint32_t fEventsRecv = 0;
1334 RTMSINTERVAL msStart = RTTimeMilliTS();
1335 RTMSINTERVAL msNow;
1336
1337 rc = RTPoll(pProxyDevUsbIp->hPollSet, cMillies, &fEventsRecv, &uIdReady);
1338 Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT);
1339 if (RT_SUCCESS(rc))
1340 {
1341 msNow = RTTimeMilliTS();
1342 cMillies = msNow - msStart >= cMillies ? 0 : cMillies - (msNow - msStart);
1343
1344 if (uIdReady == USBIP_POLL_ID_SOCKET)
1345 {
1346 rc = usbProxyUsbIpRecvPdu(pProxyDevUsbIp, &pUrbUsbIp);
1347 if ( RT_SUCCESS(rc)
1348 && pUrbUsbIp)
1349 {
1350 /* Link the URB into the landed list if a specifc reply is requested and the URB doesn't match. */
1351 if ( u32SeqNumRet != 0
1352 && pUrbUsbIp->u32SeqNumUrb != u32SeqNumRet)
1353 {
1354 usbProxyUsbIpUnlinkUrb(pProxyDevUsbIp, pUrbUsbIp);
1355 usbProxyUsbIpLinkUrb(pProxyDevUsbIp, &pProxyDevUsbIp->ListUrbsLanded, pUrbUsbIp);
1356 pUrbUsbIp = NULL;
1357 }
1358 }
1359 }
1360 else
1361 {
1362 AssertLogRelMsg(uIdReady == USBIP_POLL_ID_PIPE, ("Invalid pollset ID given\n"));
1363
1364 char bReason = usbProxyUsbIpWakeupPipeDrain(pProxyDevUsbIp);
1365 if (bReason == USBIP_REAPER_WAKEUP_REASON_QUEUE)
1366 usbProxyUsbIpUrbsQueuePending(pProxyDevUsbIp);
1367 else
1368 {
1369 Assert(bReason == USBIP_REAPER_WAKEUP_REASON_EXTERNAL);
1370 break;
1371 }
1372 }
1373 }
1374 }
1375
1376 if (!fPollWakePipe)
1377 {
1378 rc = RTPollSetEventsChange(pProxyDevUsbIp->hPollSet, USBIP_POLL_ID_PIPE, RTPOLL_EVT_READ);
1379 AssertRC(rc);
1380 }
1381
1382 return pUrbUsbIp;
1383}
1384
1385/**
1386 * Synchronously exchange a given control message with the remote device.
1387 *
1388 * @eturns VBox status code.
1389 * @param pProxyDevUsbIp The USB/IP proxy device data.
1390 * @param pSetup The setup message.
1391 *
1392 * @note This method is only used to implement the *SetConfig, *SetInterface and *ClearHaltedEp
1393 * callbacks because the USB/IP protocol lacks dedicated requests for these.
1394 * @remark It is assumed that this method is never called while usbProxyUsbIpUrbReap is called
1395 * on another thread.
1396 */
1397static int usbProxyUsbIpCtrlUrbExchangeSync(PUSBPROXYDEVUSBIP pProxyDevUsbIp, PVUSBSETUP pSetup)
1398{
1399 int rc = VINF_SUCCESS;
1400
1401 UsbIpReqSubmit ReqSubmit;
1402 USBPROXYURBUSBIP UsbIpUrb;
1403
1404 RT_ZERO(ReqSubmit);
1405
1406 uint32_t u32SeqNum = usbProxyUsbIpSeqNumGet(pProxyDevUsbIp);
1407 ReqSubmit.Hdr.u32ReqRet = USBIP_CMD_SUBMIT;
1408 ReqSubmit.Hdr.u32SeqNum = u32SeqNum;
1409 ReqSubmit.Hdr.u32DevId = pProxyDevUsbIp->u32DevId;
1410 ReqSubmit.Hdr.u32Direction = USBIP_DIR_OUT;
1411 ReqSubmit.Hdr.u32Endpoint = 0; /* Only default control endpoint is allowed for these kind of messages. */
1412 ReqSubmit.u32XferFlags = 0;
1413 ReqSubmit.u32TransferBufferLength = 0;
1414 ReqSubmit.u32StartFrame = 0;
1415 ReqSubmit.u32NumIsocPkts = 0;
1416 ReqSubmit.u32Interval = 0;
1417 memcpy(&ReqSubmit.Setup, pSetup, sizeof(ReqSubmit.Setup));
1418 usbProxyUsbIpReqSubmitH2N(&ReqSubmit);
1419
1420 UsbIpUrb.u32SeqNumUrb = u32SeqNum;
1421 UsbIpUrb.u32SeqNumUrbUnlink = 0;
1422 UsbIpUrb.fCancelled = false;
1423 UsbIpUrb.enmType = VUSBXFERTYPE_MSG;
1424 UsbIpUrb.enmDir = VUSBDIRECTION_OUT;
1425 UsbIpUrb.pVUsbUrb = NULL;
1426
1427 /* Send the command. */
1428 rc = RTTcpWrite(pProxyDevUsbIp->hSocket, &ReqSubmit, sizeof(ReqSubmit));
1429 if (RT_SUCCESS(rc))
1430 {
1431 usbProxyUsbIpLinkUrb(pProxyDevUsbIp, &pProxyDevUsbIp->ListUrbsInFlight, &UsbIpUrb);
1432 PUSBPROXYURBUSBIP pUrbUsbIp = usbProxyUsbIpPollWorker(pProxyDevUsbIp, u32SeqNum, false /*fPollWakePipe*/,
1433 30 * RT_MS_1SEC);
1434 Assert( !pUrbUsbIp
1435 || pUrbUsbIp == &UsbIpUrb); /* The returned URB should point to the URB we submitted. */
1436 usbProxyUsbIpUnlinkUrb(pProxyDevUsbIp, &UsbIpUrb);
1437
1438 if (!pUrbUsbIp)
1439 rc = VERR_TIMEOUT;
1440 }
1441
1442 return rc;
1443}
1444
1445
1446/*
1447 * The USB proxy device functions.
1448 */
1449
1450/**
1451 * @interface_method_impl{USBPROXYBACK,pfnOpen}
1452 */
1453static DECLCALLBACK(int) usbProxyUsbIpOpen(PUSBPROXYDEV pProxyDev, const char *pszAddress)
1454{
1455 LogFlowFunc(("pProxyDev=%p pszAddress=%s\n", pProxyDev, pszAddress));
1456
1457 PUSBPROXYDEVUSBIP pDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1458 int rc = VINF_SUCCESS;
1459
1460 RTListInit(&pDevUsbIp->ListUrbsInFlight);
1461 RTListInit(&pDevUsbIp->ListUrbsLanded);
1462 RTListInit(&pDevUsbIp->ListUrbsToQueue);
1463 pDevUsbIp->hSocket = NIL_RTSOCKET;
1464 pDevUsbIp->hPollSet = NIL_RTPOLLSET;
1465 pDevUsbIp->hPipeW = NIL_RTPIPE;
1466 pDevUsbIp->hPipeR = NIL_RTPIPE;
1467 pDevUsbIp->u32SeqNumNext = 0;
1468 pDevUsbIp->pszHost = NULL;
1469 pDevUsbIp->pszBusId = NULL;
1470 usbProxyUsbIpResetRecvState(pDevUsbIp);
1471
1472 rc = RTSemFastMutexCreate(&pDevUsbIp->hMtxLists);
1473 if (RT_SUCCESS(rc))
1474 {
1475 /* Setup wakeup pipe and poll set first. */
1476 rc = RTPipeCreate(&pDevUsbIp->hPipeR, &pDevUsbIp->hPipeW, 0);
1477 if (RT_SUCCESS(rc))
1478 {
1479 rc = RTPollSetCreate(&pDevUsbIp->hPollSet);
1480 if (RT_SUCCESS(rc))
1481 {
1482 rc = RTPollSetAddPipe(pDevUsbIp->hPollSet, pDevUsbIp->hPipeR,
1483 RTPOLL_EVT_READ, USBIP_POLL_ID_PIPE);
1484 if (RT_SUCCESS(rc))
1485 {
1486 /* Connect to the USB/IP host. */
1487 rc = usbProxyUsbIpParseAddress(pDevUsbIp, pszAddress);
1488 if (RT_SUCCESS(rc))
1489 rc = usbProxyUsbIpConnect(pDevUsbIp);
1490 }
1491
1492 if (RT_FAILURE(rc))
1493 {
1494 RTPollSetRemove(pDevUsbIp->hPollSet, USBIP_POLL_ID_PIPE);
1495 int rc2 = RTPollSetDestroy(pDevUsbIp->hPollSet);
1496 AssertRC(rc2);
1497 }
1498 }
1499
1500 if (RT_FAILURE(rc))
1501 {
1502 int rc2 = RTPipeClose(pDevUsbIp->hPipeR);
1503 AssertRC(rc2);
1504 rc2 = RTPipeClose(pDevUsbIp->hPipeW);
1505 AssertRC(rc2);
1506 }
1507 }
1508 }
1509
1510 return rc;
1511}
1512
1513
1514/**
1515 * @interface_method_impl{USBPROXYBACK,pfnClose}
1516 */
1517static DECLCALLBACK(void) usbProxyUsbIpClose(PUSBPROXYDEV pProxyDev)
1518{
1519 int rc = VINF_SUCCESS;
1520 LogFlowFunc(("pProxyDev = %p\n", pProxyDev));
1521
1522 PUSBPROXYDEVUSBIP pDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1523 if (pDevUsbIp->hSocket != NIL_RTSOCKET)
1524 usbProxyUsbIpDisconnect(pDevUsbIp);
1525
1526 /* Destroy the pipe and pollset if necessary. */
1527 if (pDevUsbIp->hPollSet != NIL_RTPOLLSET)
1528 {
1529 rc = RTPollSetRemove(pDevUsbIp->hPollSet, USBIP_POLL_ID_PIPE);
1530 AssertRC(rc);
1531 rc = RTPollSetDestroy(pDevUsbIp->hPollSet);
1532 AssertRC(rc);
1533 rc = RTPipeClose(pDevUsbIp->hPipeR);
1534 AssertRC(rc);
1535 rc = RTPipeClose(pDevUsbIp->hPipeW);
1536 AssertRC(rc);
1537 }
1538
1539 if (pDevUsbIp->pszHost)
1540 RTStrFree(pDevUsbIp->pszHost);
1541 if (pDevUsbIp->pszBusId)
1542 RTStrFree(pDevUsbIp->pszBusId);
1543
1544 /* Clear the URB lists. */
1545 rc = RTSemFastMutexRequest(pDevUsbIp->hMtxLists);
1546 AssertRC(rc);
1547 PUSBPROXYURBUSBIP pIter;
1548 PUSBPROXYURBUSBIP pIterNext;
1549 RTListForEachSafe(&pDevUsbIp->ListUrbsInFlight, pIter, pIterNext, USBPROXYURBUSBIP, NodeList)
1550 {
1551 RTListNodeRemove(&pIter->NodeList);
1552 RTMemFree(pIter);
1553 }
1554
1555 RTListForEachSafe(&pDevUsbIp->ListUrbsLanded, pIter, pIterNext, USBPROXYURBUSBIP, NodeList)
1556 {
1557 RTListNodeRemove(&pIter->NodeList);
1558 RTMemFree(pIter);
1559 }
1560 RTSemFastMutexRelease(pDevUsbIp->hMtxLists);
1561 RTSemFastMutexDestroy(pDevUsbIp->hMtxLists);
1562}
1563
1564
1565/**
1566 * @interface_method_impl{USBPROXYBACK,pfnReset}
1567 */
1568static DECLCALLBACK(int) usbProxyUsbIpReset(PUSBPROXYDEV pProxyDev, bool fResetOnLinux)
1569{
1570 LogFlowFunc(("pProxyDev = %p\n", pProxyDev));
1571
1572 int rc = VINF_SUCCESS;
1573 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1574 VUSBSETUP Setup;
1575
1576 if (fResetOnLinux)
1577 {
1578 Setup.bmRequestType = RT_BIT(5) | 0x03; /* Port request. */
1579 Setup.bRequest = 0x03; /* SET_FEATURE */
1580 Setup.wValue = 4; /* Port feature: Reset */
1581 Setup.wIndex = 0; /* Port number, irrelevant */
1582 Setup.wLength = 0;
1583 rc = usbProxyUsbIpCtrlUrbExchangeSync(pProxyDevUsbIp, &Setup);
1584 if (RT_SUCCESS(rc))
1585 {
1586 pProxyDev->iActiveCfg = -1;
1587 pProxyDev->cIgnoreSetConfigs = 2;
1588 }
1589 }
1590
1591 return rc;
1592}
1593
1594
1595/**
1596 * @interface_method_impl{USBPROXYBACK,pfnSetConfig}
1597 */
1598static DECLCALLBACK(int) usbProxyUsbIpSetConfig(PUSBPROXYDEV pProxyDev, int iCfg)
1599{
1600 LogFlowFunc(("pProxyDev=%s cfg=%#x\n", pProxyDev->pUsbIns->pszName, iCfg));
1601
1602 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1603 VUSBSETUP Setup;
1604
1605 Setup.bmRequestType = 0;
1606 Setup.bRequest = 0x09;
1607 Setup.wValue = iCfg;
1608 Setup.wIndex = 0;
1609 Setup.wLength = 0;
1610 return usbProxyUsbIpCtrlUrbExchangeSync(pProxyDevUsbIp, &Setup);
1611}
1612
1613
1614/**
1615 * @interface_method_impl{USBPROXYBACK,pfnClaimInterface}
1616 */
1617static DECLCALLBACK(int) usbProxyUsbIpClaimInterface(PUSBPROXYDEV pProxyDev, int iIf)
1618{
1619 RT_NOREF(pProxyDev, iIf);
1620 LogFlowFunc(("pProxyDev=%s iIf=%#x\n", pProxyDev->pUsbIns->pszName, iIf));
1621 return VINF_SUCCESS;
1622}
1623
1624
1625/**
1626 * @interface_method_impl{USBPROXYBACK,pfnReleaseInterface}
1627 */
1628static DECLCALLBACK(int) usbProxyUsbIpReleaseInterface(PUSBPROXYDEV pProxyDev, int iIf)
1629{
1630 RT_NOREF(pProxyDev, iIf);
1631 LogFlowFunc(("pProxyDev=%s iIf=%#x\n", pProxyDev->pUsbIns->pszName, iIf));
1632 return VINF_SUCCESS;
1633}
1634
1635
1636/**
1637 * @interface_method_impl{USBPROXYBACK,pfnSetInterface}
1638 */
1639static DECLCALLBACK(int) usbProxyUsbIpSetInterface(PUSBPROXYDEV pProxyDev, int iIf, int setting)
1640{
1641 LogFlowFunc(("pProxyDev=%p iIf=%#x setting=%#x\n", pProxyDev, iIf, setting));
1642
1643 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1644 VUSBSETUP Setup;
1645
1646 Setup.bmRequestType = 0x1;
1647 Setup.bRequest = 0x0b; /* SET_INTERFACE */
1648 Setup.wValue = setting;
1649 Setup.wIndex = iIf;
1650 Setup.wLength = 0;
1651 return usbProxyUsbIpCtrlUrbExchangeSync(pProxyDevUsbIp, &Setup);
1652}
1653
1654
1655/**
1656 * @interface_method_impl{USBPROXYBACK,pfnClearHaltedEndpoint}
1657 */
1658static DECLCALLBACK(int) usbProxyUsbIpClearHaltedEp(PUSBPROXYDEV pProxyDev, unsigned int iEp)
1659{
1660 LogFlowFunc(("pProxyDev=%s ep=%u\n", pProxyDev->pUsbIns->pszName, iEp));
1661
1662 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1663 VUSBSETUP Setup;
1664
1665 Setup.bmRequestType = 0x2;
1666 Setup.bRequest = 0x01; /* CLEAR_FEATURE */
1667 Setup.wValue = 0x00; /* ENDPOINT_HALT */
1668 Setup.wIndex = iEp;
1669 Setup.wLength = 0;
1670 return usbProxyUsbIpCtrlUrbExchangeSync(pProxyDevUsbIp, &Setup);
1671}
1672
1673
1674/**
1675 * @interface_method_impl{USBPROXYBACK,pfnUrbQueue}
1676 */
1677static DECLCALLBACK(int) usbProxyUsbIpUrbQueue(PUSBPROXYDEV pProxyDev, PVUSBURB pUrb)
1678{
1679 LogFlowFunc(("pUrb=%p\n", pUrb));
1680
1681 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1682
1683 /* Allocate a USB/IP Urb. */
1684 PUSBPROXYURBUSBIP pUrbUsbIp = usbProxyUsbIpUrbAlloc(pProxyDevUsbIp);
1685 if (!pUrbUsbIp)
1686 return VERR_NO_MEMORY;
1687
1688 pUrbUsbIp->fCancelled = false;
1689 pUrbUsbIp->pVUsbUrb = pUrb;
1690 pUrb->Dev.pvPrivate = pUrbUsbIp;
1691
1692 int rc = RTSemFastMutexRequest(pProxyDevUsbIp->hMtxLists);
1693 AssertRC(rc);
1694 RTListAppend(&pProxyDevUsbIp->ListUrbsToQueue, &pUrbUsbIp->NodeList);
1695 RTSemFastMutexRelease(pProxyDevUsbIp->hMtxLists);
1696
1697 return usbProxyReaperKick(pProxyDevUsbIp, USBIP_REAPER_WAKEUP_REASON_QUEUE);
1698}
1699
1700
1701/**
1702 * @interface_method_impl{USBPROXYBACK,pfnUrbReap}
1703 */
1704static DECLCALLBACK(PVUSBURB) usbProxyUsbIpUrbReap(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies)
1705{
1706 LogFlowFunc(("pProxyDev=%s\n", pProxyDev->pUsbIns->pszName));
1707
1708 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1709 PUSBPROXYURBUSBIP pUrbUsbIp = NULL;
1710 PVUSBURB pUrb = NULL;
1711 int rc = VINF_SUCCESS;
1712
1713 /* Queue new URBs first. */
1714 rc = usbProxyUsbIpUrbsQueuePending(pProxyDevUsbIp);
1715 AssertRC(rc);
1716
1717 /* Any URBs pending delivery? */
1718 if (!RTListIsEmpty(&pProxyDevUsbIp->ListUrbsLanded))
1719 pUrbUsbIp = RTListGetFirst(&pProxyDevUsbIp->ListUrbsLanded, USBPROXYURBUSBIP, NodeList);
1720 else
1721 pUrbUsbIp = usbProxyUsbIpPollWorker(pProxyDevUsbIp, 0, true /*fPollWakePipe*/, cMillies);
1722
1723 if (pUrbUsbIp)
1724 {
1725 pUrb = pUrbUsbIp->pVUsbUrb;
1726 pUrb->enmStatus = pUrbUsbIp->enmStatus;
1727
1728 /* unlink from the pending delivery list */
1729 usbProxyUsbIpUnlinkUrb(pProxyDevUsbIp, pUrbUsbIp);
1730 usbProxyUsbIpUrbFree(pProxyDevUsbIp, pUrbUsbIp);
1731 }
1732
1733 return pUrb;
1734}
1735
1736
1737/**
1738 * @interface_method_impl{USBPROXYBACK,pfnUrbCancel}
1739 */
1740static DECLCALLBACK(int) usbProxyUsbIpUrbCancel(PUSBPROXYDEV pProxyDev, PVUSBURB pUrb)
1741{
1742 LogFlowFunc(("pUrb=%p\n", pUrb));
1743
1744 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1745 PUSBPROXYURBUSBIP pUrbUsbIp = (PUSBPROXYURBUSBIP)pUrb->Dev.pvPrivate;
1746 UsbIpReqUnlink ReqUnlink;
1747
1748 RT_ZERO(ReqUnlink);
1749
1750 uint32_t u32SeqNum = usbProxyUsbIpSeqNumGet(pProxyDevUsbIp);
1751 ReqUnlink.Hdr.u32ReqRet = USBIP_CMD_UNLINK;
1752 ReqUnlink.Hdr.u32SeqNum = u32SeqNum;
1753 ReqUnlink.Hdr.u32DevId = pProxyDevUsbIp->u32DevId;
1754 ReqUnlink.Hdr.u32Direction = USBIP_DIR_OUT;
1755 ReqUnlink.Hdr.u32Endpoint = pUrb->EndPt;
1756 ReqUnlink.u32SeqNum = pUrbUsbIp->u32SeqNumUrb;
1757
1758 usbProxyUsbIpReqUnlinkH2N(&ReqUnlink);
1759 int rc = RTTcpWrite(pProxyDevUsbIp->hSocket, &ReqUnlink, sizeof(ReqUnlink));
1760 if (RT_SUCCESS(rc))
1761 {
1762 pUrbUsbIp->u32SeqNumUrbUnlink = u32SeqNum;
1763 pUrbUsbIp->fCancelled = true;
1764 }
1765
1766 return rc;
1767}
1768
1769
1770/**
1771 * @interface_method_impl{USBPROXYBACK,pfnWakeup}
1772 */
1773static DECLCALLBACK(int) usbProxyUsbIpWakeup(PUSBPROXYDEV pProxyDev)
1774{
1775 LogFlowFunc(("pProxyDev=%s\n", pProxyDev->pUsbIns->pszName));
1776
1777 PUSBPROXYDEVUSBIP pProxyDevUsbIp = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVUSBIP);
1778 return usbProxyReaperKick(pProxyDevUsbIp, USBIP_REAPER_WAKEUP_REASON_EXTERNAL);
1779}
1780
1781
1782/**
1783 * The USB/IP USB Proxy Backend operations.
1784 */
1785extern const USBPROXYBACK g_USBProxyDeviceUsbIp =
1786{
1787 /* pszName */
1788 "usbip",
1789 /* cbBackend */
1790 sizeof(USBPROXYDEVUSBIP),
1791 usbProxyUsbIpOpen,
1792 NULL,
1793 usbProxyUsbIpClose,
1794 usbProxyUsbIpReset,
1795 usbProxyUsbIpSetConfig,
1796 usbProxyUsbIpClaimInterface,
1797 usbProxyUsbIpReleaseInterface,
1798 usbProxyUsbIpSetInterface,
1799 usbProxyUsbIpClearHaltedEp,
1800 usbProxyUsbIpUrbQueue,
1801 usbProxyUsbIpUrbCancel,
1802 usbProxyUsbIpUrbReap,
1803 usbProxyUsbIpWakeup,
1804 0
1805};
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use