6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * Remote Desktop Protocol client:
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * USB Channel Process Functions
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * Copyright (C) 2006-2011 Oracle Corporation
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * available from http://www.virtualbox.org. This file is free software;
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * you can redistribute it and/or modify it under the terms of the GNU
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * General Public License (GPL) as published by the Free Software
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync/* DEBUG is defined in ../rdesktop.h */
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync/** Well-known locations for the Linux Usbfs virtual file system */
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsyncstatic const struct
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync /** Expected mount location for Usbfs */
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync /** Expected location of the "devices" file */
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync/** Location at which the USB device tree was found. NULL means not
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * found. */
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync/* A device list entry */
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync uint16_t oNext; /* Offset of the next structure. 0 if last. */
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync uint32_t id; /* Identifier of the device assigned by the client. */
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync uint16_t oManufacturer; /* Offset of manufacturer string. */
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync uint16_t oSerialNumber; /* Offset of serial string. */
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync uint16_t idPort; /* Physical USB port the device is connected to. */
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * @returns VBox status code.
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsyncstatic inline int op_usbproxy_back_open(PUSBPROXYDEV p, const char *pszAddress)
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync return g_USBProxyDeviceHost.pfnOpen (p, pszAddress, NULL);
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsyncstatic inline void op_usbproxy_back_close(PUSBPROXYDEV pDev)
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * @returns VBox status code.
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsyncstatic inline int op_usbproxy_back_reset(PUSBPROXYDEV pDev)
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync return g_USBProxyDeviceHost.pfnReset (pDev, false);
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * @returns VBox status code.
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsyncstatic inline int op_usbproxy_back_set_config(PUSBPROXYDEV pDev, int cfg)
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync return g_USBProxyDeviceHost.pfnSetConfig (pDev, cfg);
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * @returns VBox status code.
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsyncstatic inline int op_usbproxy_back_claim_interface(PUSBPROXYDEV pDev, int ifnum)
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync return g_USBProxyDeviceHost.pfnClaimInterface (pDev, ifnum);
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * @returns VBox status code.
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsyncstatic inline int op_usbproxy_back_release_interface(PUSBPROXYDEV pDev, int ifnum)
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync return g_USBProxyDeviceHost.pfnReleaseInterface (pDev, ifnum);
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * @returns VBox status code.
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsyncstatic inline int op_usbproxy_back_interface_setting(PUSBPROXYDEV pDev, int ifnum, int setting)
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync return g_USBProxyDeviceHost.pfnSetInterface (pDev, ifnum, setting);
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * @returns VBox status code.
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsyncstatic inline int op_usbproxy_back_queue_urb(PUSBPROXYDEV pDev, PVUSBURB pUrb)
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync return g_USBProxyDeviceHost.pfnUrbQueue(pDev, pUrb);
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsyncstatic inline PVUSBURB op_usbproxy_back_reap_urb(PUSBPROXYDEV pDev, unsigned cMillies)
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync return g_USBProxyDeviceHost.pfnUrbReap (pDev, cMillies);
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * @returns VBox status code.
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsyncstatic inline int op_usbproxy_back_clear_halted_ep(PUSBPROXYDEV pDev, unsigned EndPoint)
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync return g_USBProxyDeviceHost.pfnClearHaltedEndpoint (pDev, EndPoint);
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * @returns VBox status code.
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsyncstatic inline int op_usbproxy_back_cancel_urb(PUSBPROXYDEV pDev, PVUSBURB pUrb)
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync return g_USBProxyDeviceHost.pfnUrbCancel (pDev, pUrb);
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync/** Count the USB devices in a linked list of PUSBDEVICE structures. */
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync unsigned i = 0;
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync /** The space we set aside for the USB strings. Should always be enough,
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * as a USB device contains up to 256 characters of UTF-16 string data. */
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync /** The space we reserve for each wire format device entry */
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync DEV_ENTRY_SIZE = sizeof(DevListEntry) + MAX_STRINGS_LEN
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * Add a string to the end of a wire format device entry.
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * @param pBuf the start of the buffer containing the entry
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * @param iBuf the index into the buffer to add the string at
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * @param pcsz the string to add - optional
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * @param piString where to write back @a iBuf or zero if there is no string
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * @param piNext where to write back the index where the next string may
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsyncstatic void addStringToEntry(char *pBuf, uint16_t iBuf, const char *pcsz,
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync/** Fill in a device list entry in wire format from a PUSBDEVICE and return an
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * index to where the next string should start */
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsyncstatic void fillWireListEntry(char *pBuf, PUSBDEVICE pDevice,
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync pEntry->id = (pDevice->bPort << 8) + pDevice->bBus;
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync pEntry->bDeviceSubClass = pDevice->bDeviceSubClass;
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync addStringToEntry(pBuf, iNextString, pDevice->pszManufacturer,
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync addStringToEntry(pBuf, iNextString, pDevice->pszProduct,
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync addStringToEntry(pBuf, iNextString, pDevice->pszSerialNumber,
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync/** Allocate (and return) a buffer for a device list in VRDP wire format,
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * and populate from a PUSBDEVICE linked list. @a pLen takes the length of
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * the new list.
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * See @a Console::processRemoteUSBDevices for the receiving end. */
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsyncstatic void *buildWireListFromDevices(PUSBDEVICE pDevices, int *pLen)
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync pCurrent = pCurrent->pNext, iCurrent += iNext, --cDevs)
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync AssertReturnStmt(iCurrent + DEV_ENTRY_SIZE + 2 <= cbBuf,
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync fillWireListEntry(pBuf + iCurrent, pCurrent, &iNext);
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync DevListEntry *pEntry = (DevListEntry *)(pBuf + iCurrent);
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync /* Sanity tests */
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync for (i = iCurrent + sizeof(DevListEntry), cZeros = 0;
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync if (pBuf[i] == 0)
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync AssertReturnStmt(cZeros == RT_BOOL(pEntry->oManufacturer)
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync Assert(pEntry->oManufacturer == 0 || pBuf[iCurrent + pEntry->oManufacturer] != '\0');
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync Assert(pEntry->oProduct == 0 || pBuf[iCurrent + pEntry->oProduct] != '\0');
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync Assert(pEntry->oSerialNumber == 0 || pBuf[iCurrent + pEntry->oSerialNumber] != '\0');
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync AssertReturnStmt(cZeros == 0 || pBuf[iCurrent + iNext - 1] == '\0',
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync/** Build a list of the usable USB devices currently connected to the client
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * system using the VRDP wire protocol. The structure returned must be freed
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * using free(3) when it is no longer needed; returns NULL and sets *pLen to
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync * zero on failure. */
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync g_pUsbDevices = USBProxyLinuxGetDevices(g_pcszDevicesRoot, g_fUseSysfs);
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync pvDeviceList = buildWireListFromDevices(g_pUsbDevices, pLen);
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync out_uint32_le (s, len + sizeof (code)); /* The length of data after the 'len' field. */
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8);
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsyncrdpusb_send_reply (uint8_t code, uint8_t status, uint32_t devid)
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsyncrdpusb_send_access_denied (uint8_t code, uint32_t devid)
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync rdpusb_send_reply (code, VRDP_USB_STATUS_ACCESS_DENIED, devid);
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsyncstatic inline int
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync Log(("RDPUSB: rdpusb_reap_urbs: cbData = %d, enmStatus = %d\n", pUrb->cbData, pUrb->enmStatus));
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync s = rdpusb_init_packet(14 + datalen, RDPUSB_REQ_REAP_URB);
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync if (pUrb->pPrev || pUrb->pNext || pUrb == proxy->pUrbs)
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync /* Remove the URB from list. */
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync error("RDPUSB: not enough data len = %d, bytes left %d\n", len, s->end - s->p);
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync Log(("RDPUSB recv: len = %d, code = %d\n", len, code));
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync proxy = (PUSBPROXYDEV )xmalloc (sizeof (USBPROXYDEV));
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync error("RDPUSB: Out of memory allocating proxy backend data\n");
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync proxy->pvInstanceDataR3 = xmalloc(g_USBProxyDeviceHost.cbBackend);
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync error("RDPUSB: Out of memory allocating proxy backend data\n");
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync for (pDevice = g_pUsbDevices; pDevice; pDevice = pDevice->pNext)
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync if ((pDevice->bPort << 8) + pDevice->bBus == devid)
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync rc = pDevice ? op_usbproxy_back_open(proxy, pDevice->pszAddress)
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync /* No reply. */
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync rdpusb_send_reply (code, vrdp_usb_status (!rc, &proxy->Dev), devid);
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync rdpusb_send_reply (code, vrdp_usb_status (rc, &proxy->Dev), devid);
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync rc = op_usbproxy_back_claim_interface(proxy, ifnum);
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync rdpusb_send_reply (code, vrdp_usb_status (rc, &proxy->Dev), devid);
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync rc = op_usbproxy_back_release_interface(proxy, ifnum);
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync rdpusb_send_reply (code, vrdp_usb_status (rc, &proxy->Dev), devid);
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync rc = op_usbproxy_back_interface_setting(proxy, ifnum, setting);
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync rdpusb_send_reply (code, vrdp_usb_status (rc, &proxy->Dev), devid);
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync /* No reply. */
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync /* Allocate a single block for URB description and data buffer */
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync (urblen <= sizeof (pUrb->abData)? 0: urblen - sizeof (pUrb->abData))
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync /* No reply required. */
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync rdpusb_send_reply (code, vrdp_usb_status (rc, &proxy->Dev), devid);
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync /* No reply required. */
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync /* Remove URB from list. */
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync // xfree (pUrb);
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsyncrdpusb_add_fds(int *n, fd_set * rfds, fd_set * wfds)
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync// Log(("RDPUSB: rdpusb_add_fds: begin *n = %d\n", *n));
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync// Log(("RDPUSB: rdpusb_add_fds: adding %d\n", proxy->priv.File));
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync// Log(("RDPUSB: rdpusb_add_fds: end *n = %d\n", *n));
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync// Log(("RDPUSB: rdpusb_check_fds: begin\n"));
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync// Log(("RDPUSB: rdpusb_check_fds: end\n"));
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync if (RT_SUCCESS(USBProxyLinuxChooseMethod(&fUseUsbfs, &g_pcszDevicesRoot)))
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync channel_register("vrdpusb", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP,
6e9aa255e3376b2da5824c09c4c62bc233463bfevboxsync return false;