VirtualBox

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

Last change on this file since 95294 was 94342, checked in by vboxsync, 3 years ago

Main,VMM/PDMUsb,Devices/USB,VRDP: Drop passing pointers through CFGM in favor of using VMM2USERMETHODS::pfnQueryGenericObject, bugref:10053

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