diff options
Diffstat (limited to 'drivers/staging/usbip')
39 files changed, 1269 insertions, 1313 deletions
diff --git a/drivers/staging/usbip/Kconfig b/drivers/staging/usbip/Kconfig index 88600098047..bd99e9e47e5 100644 --- a/drivers/staging/usbip/Kconfig +++ b/drivers/staging/usbip/Kconfig @@ -1,7 +1,6 @@ config USBIP_CORE tristate "USB/IP support" depends on USB && NET - default N ---help--- This enables pushing USB packets over IP to allow remote machines direct access to USB devices. It provides the @@ -18,7 +17,6 @@ config USBIP_CORE config USBIP_VHCI_HCD tristate "VHCI hcd" depends on USBIP_CORE - default N ---help--- This enables the USB/IP virtual host controller driver, which is run on the remote machine. @@ -29,7 +27,6 @@ config USBIP_VHCI_HCD config USBIP_HOST tristate "Host driver" depends on USBIP_CORE - default N ---help--- This enables the USB/IP host driver, which is run on the machine that is sharing the USB devices. @@ -40,6 +37,5 @@ config USBIP_HOST config USBIP_DEBUG bool "Debug messages for USB/IP" depends on USBIP_CORE - default N ---help--- This enables the debug messages from the USB/IP drivers. diff --git a/drivers/staging/usbip/stub.h b/drivers/staging/usbip/stub.h index a73e437ec21..266e2b0ce9a 100644 --- a/drivers/staging/usbip/stub.h +++ b/drivers/staging/usbip/stub.h @@ -86,6 +86,7 @@ struct bus_id_priv { char status; int interf_count; struct stub_device *sdev; + struct usb_device *udev; char shutdown_busid; }; @@ -93,7 +94,7 @@ struct bus_id_priv { extern struct kmem_cache *stub_priv_cache; /* stub_dev.c */ -extern struct usb_driver stub_driver; +extern struct usb_device_driver stub_driver; /* stub_main.c */ struct bus_id_priv *get_busid_priv(const char *busid); diff --git a/drivers/staging/usbip/stub_dev.c b/drivers/staging/usbip/stub_dev.c index 83d629afdfe..51d0c718873 100644 --- a/drivers/staging/usbip/stub_dev.c +++ b/drivers/staging/usbip/stub_dev.c @@ -56,8 +56,8 @@ MODULE_DEVICE_TABLE(usb, stub_table); * usbip_status shows the status of usbip-host as long as this driver is bound * to the target device. */ -static ssize_t show_status(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t usbip_status_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct stub_device *sdev = dev_get_drvdata(dev); int status; @@ -73,7 +73,7 @@ static ssize_t show_status(struct device *dev, struct device_attribute *attr, return snprintf(buf, PAGE_SIZE, "%d\n", status); } -static DEVICE_ATTR(usbip_status, S_IRUGO, show_status, NULL); +static DEVICE_ATTR_RO(usbip_status); /* * usbip_sockfd gets a socket descriptor of an established TCP connection that @@ -86,16 +86,20 @@ static ssize_t store_sockfd(struct device *dev, struct device_attribute *attr, struct stub_device *sdev = dev_get_drvdata(dev); int sockfd = 0; struct socket *socket; - ssize_t err = -EINVAL; + int rv; if (!sdev) { dev_err(dev, "sdev is null\n"); return -ENODEV; } - sscanf(buf, "%d", &sockfd); + rv = sscanf(buf, "%d", &sockfd); + if (rv != 1) + return -EINVAL; if (sockfd != -1) { + int err; + dev_info(dev, "stub up\n"); spin_lock_irq(&sdev->ud.lock); @@ -105,7 +109,7 @@ static ssize_t store_sockfd(struct device *dev, struct device_attribute *attr, goto err; } - socket = sockfd_to_socket(sockfd); + socket = sockfd_lookup(sockfd, &err); if (!socket) goto err; @@ -138,7 +142,7 @@ static ssize_t store_sockfd(struct device *dev, struct device_attribute *attr, err: spin_unlock_irq(&sdev->ud.lock); - return err; + return -EINVAL; } static DEVICE_ATTR(usbip_sockfd, S_IWUSR, NULL, store_sockfd); @@ -208,7 +212,7 @@ static void stub_shutdown_connection(struct usbip_device *ud) * not touch NULL socket. */ if (ud->tcp_socket) { - fput(ud->tcp_socket->file); + sockfd_put(ud->tcp_socket); ud->tcp_socket = NULL; } @@ -279,21 +283,19 @@ static void stub_device_unusable(struct usbip_device *ud) * * Allocates and initializes a new stub_device struct. */ -static struct stub_device *stub_device_alloc(struct usb_device *udev, - struct usb_interface *interface) +static struct stub_device *stub_device_alloc(struct usb_device *udev) { struct stub_device *sdev; - int busnum = interface_to_busnum(interface); - int devnum = interface_to_devnum(interface); + int busnum = udev->bus->busnum; + int devnum = udev->devnum; - dev_dbg(&interface->dev, "allocating stub device"); + dev_dbg(&udev->dev, "allocating stub device"); /* yes, it's a new device */ sdev = kzalloc(sizeof(struct stub_device), GFP_KERNEL); if (!sdev) return NULL; - sdev->interface = usb_get_intf(interface); sdev->udev = usb_get_dev(udev); /* @@ -322,7 +324,7 @@ static struct stub_device *stub_device_alloc(struct usb_device *udev, usbip_start_eh(&sdev->ud); - dev_dbg(&interface->dev, "register new interface\n"); + dev_dbg(&udev->dev, "register new device\n"); return sdev; } @@ -332,33 +334,23 @@ static void stub_device_free(struct stub_device *sdev) kfree(sdev); } -/* - * If a usb device has multiple active interfaces, this driver is bound to all - * the active interfaces. However, usbip exports *a* usb device (i.e., not *an* - * active interface). Currently, a userland program must ensure that it - * looks at the usbip's sysfs entries of only the first active interface. - * - * TODO: use "struct usb_device_driver" to bind a usb device. - * However, it seems it is not fully supported in mainline kernel yet - * (2.6.19.2). - */ -static int stub_probe(struct usb_interface *interface, - const struct usb_device_id *id) +static int stub_probe(struct usb_device *udev) { - struct usb_device *udev = interface_to_usbdev(interface); struct stub_device *sdev = NULL; - const char *udev_busid = dev_name(interface->dev.parent); + const char *udev_busid = dev_name(&udev->dev); int err = 0; struct bus_id_priv *busid_priv; + int rc; - dev_dbg(&interface->dev, "Enter\n"); + dev_dbg(&udev->dev, "Enter\n"); /* check we should claim or not by busid_table */ busid_priv = get_busid_priv(udev_busid); if (!busid_priv || (busid_priv->status == STUB_BUSID_REMOV) || (busid_priv->status == STUB_BUSID_OTHER)) { - dev_info(&interface->dev, "%s is not in match_busid table... " - "skip!\n", udev_busid); + dev_info(&udev->dev, + "%s is not in match_busid table... skip!\n", + udev_busid); /* * Return value should be ENODEV or ENOXIO to continue trying @@ -375,64 +367,48 @@ static int stub_probe(struct usb_interface *interface, } if (!strcmp(udev->bus->bus_name, "vhci_hcd")) { - dev_dbg(&udev->dev, "%s is attached on vhci_hcd... skip!\n", - udev_busid); - return -ENODEV; - } - - if (busid_priv->status == STUB_BUSID_ALLOC) { - sdev = busid_priv->sdev; - if (!sdev) - return -ENODEV; - - busid_priv->interf_count++; - dev_info(&interface->dev, "usbip-host: register new interface " - "(bus %u dev %u ifn %u)\n", - udev->bus->busnum, udev->devnum, - interface->cur_altsetting->desc.bInterfaceNumber); - - /* set private data to usb_interface */ - usb_set_intfdata(interface, sdev); - - err = stub_add_files(&interface->dev); - if (err) { - dev_err(&interface->dev, "stub_add_files for %s\n", - udev_busid); - usb_set_intfdata(interface, NULL); - busid_priv->interf_count--; - return err; - } + dev_dbg(&udev->dev, + "%s is attached on vhci_hcd... skip!\n", + udev_busid); - usb_get_intf(interface); - return 0; + return -ENODEV; } /* ok, this is my device */ - sdev = stub_device_alloc(udev, interface); + sdev = stub_device_alloc(udev); if (!sdev) return -ENOMEM; - dev_info(&interface->dev, "usbip-host: register new device " - "(bus %u dev %u ifn %u)\n", udev->bus->busnum, udev->devnum, - interface->cur_altsetting->desc.bInterfaceNumber); + dev_info(&udev->dev, + "usbip-host: register new device (bus %u dev %u)\n", + udev->bus->busnum, udev->devnum); - busid_priv->interf_count = 0; busid_priv->shutdown_busid = 0; - /* set private data to usb_interface */ - usb_set_intfdata(interface, sdev); - busid_priv->interf_count++; + /* set private data to usb_device */ + dev_set_drvdata(&udev->dev, sdev); busid_priv->sdev = sdev; + busid_priv->udev = udev; - err = stub_add_files(&interface->dev); + /* + * Claim this hub port. + * It doesn't matter what value we pass as owner + * (struct dev_state) as long as it is unique. + */ + rc = usb_hub_claim_port(udev->parent, udev->portnum, + (struct usb_dev_state *) udev); + if (rc) { + dev_dbg(&udev->dev, "unable to claim port\n"); + return rc; + } + + err = stub_add_files(&udev->dev); if (err) { - dev_err(&interface->dev, "stub_add_files for %s\n", udev_busid); - usb_set_intfdata(interface, NULL); - usb_put_intf(interface); + dev_err(&udev->dev, "stub_add_files for %s\n", udev_busid); + dev_set_drvdata(&udev->dev, NULL); usb_put_dev(udev); kthread_stop_put(sdev->ud.eh); - busid_priv->interf_count = 0; busid_priv->sdev = NULL; stub_device_free(sdev); return err; @@ -457,13 +433,14 @@ static void shutdown_busid(struct bus_id_priv *busid_priv) * called in usb_disconnect() or usb_deregister() * but only if actconfig(active configuration) exists */ -static void stub_disconnect(struct usb_interface *interface) +static void stub_disconnect(struct usb_device *udev) { struct stub_device *sdev; - const char *udev_busid = dev_name(interface->dev.parent); + const char *udev_busid = dev_name(&udev->dev); struct bus_id_priv *busid_priv; + int rc; - dev_dbg(&interface->dev, "Enter\n"); + dev_dbg(&udev->dev, "Enter\n"); busid_priv = get_busid_priv(udev_busid); if (!busid_priv) { @@ -471,41 +448,37 @@ static void stub_disconnect(struct usb_interface *interface) return; } - sdev = usb_get_intfdata(interface); + sdev = dev_get_drvdata(&udev->dev); /* get stub_device */ if (!sdev) { - dev_err(&interface->dev, "could not get device"); + dev_err(&udev->dev, "could not get device"); return; } - usb_set_intfdata(interface, NULL); + dev_set_drvdata(&udev->dev, NULL); /* * NOTE: rx/tx threads are invoked for each usb_device. */ - stub_remove_files(&interface->dev); + stub_remove_files(&udev->dev); - /* If usb reset is called from event handler */ - if (busid_priv->sdev->ud.eh == current) { - busid_priv->interf_count--; + /* release port */ + rc = usb_hub_release_port(udev->parent, udev->portnum, + (struct usb_dev_state *) udev); + if (rc) { + dev_dbg(&udev->dev, "unable to release port\n"); return; } - if (busid_priv->interf_count > 1) { - busid_priv->interf_count--; - shutdown_busid(busid_priv); - usb_put_intf(interface); + /* If usb reset is called from event handler */ + if (busid_priv->sdev->ud.eh == current) return; - } - - busid_priv->interf_count = 0; /* shutdown the current connection */ shutdown_busid(busid_priv); usb_put_dev(sdev->udev); - usb_put_intf(interface); /* free sdev */ busid_priv->sdev = NULL; @@ -519,28 +492,34 @@ static void stub_disconnect(struct usb_interface *interface) } } -/* - * Presence of pre_reset and post_reset prevents the driver from being unbound - * when the device is being reset - */ +#ifdef CONFIG_PM + +/* These functions need usb_port_suspend and usb_port_resume, + * which reside in drivers/usb/core/usb.h. Skip for now. */ -static int stub_pre_reset(struct usb_interface *interface) +static int stub_suspend(struct usb_device *udev, pm_message_t message) { - dev_dbg(&interface->dev, "pre_reset\n"); + dev_dbg(&udev->dev, "stub_suspend\n"); + return 0; } -static int stub_post_reset(struct usb_interface *interface) +static int stub_resume(struct usb_device *udev, pm_message_t message) { - dev_dbg(&interface->dev, "post_reset\n"); + dev_dbg(&udev->dev, "stub_resume\n"); + return 0; } -struct usb_driver stub_driver = { +#endif /* CONFIG_PM */ + +struct usb_device_driver stub_driver = { .name = "usbip-host", .probe = stub_probe, .disconnect = stub_disconnect, - .id_table = stub_table, - .pre_reset = stub_pre_reset, - .post_reset = stub_post_reset, +#ifdef CONFIG_PM + .suspend = stub_suspend, + .resume = stub_resume, +#endif + .supports_autosuspend = 0, }; diff --git a/drivers/staging/usbip/stub_main.c b/drivers/staging/usbip/stub_main.c index 33027cce670..9c5832abbdf 100644 --- a/drivers/staging/usbip/stub_main.c +++ b/drivers/staging/usbip/stub_main.c @@ -19,6 +19,7 @@ #include <linux/string.h> #include <linux/module.h> +#include <linux/device.h> #include "usbip_common.h" #include "stub.h" @@ -187,6 +188,34 @@ static ssize_t store_match_busid(struct device_driver *dev, const char *buf, static DRIVER_ATTR(match_busid, S_IRUSR | S_IWUSR, show_match_busid, store_match_busid); +static ssize_t rebind_store(struct device_driver *dev, const char *buf, + size_t count) +{ + int ret; + int len; + struct bus_id_priv *bid; + + /* buf length should be less that BUSID_SIZE */ + len = strnlen(buf, BUSID_SIZE); + + if (!(len < BUSID_SIZE)) + return -EINVAL; + + bid = get_busid_priv(buf); + if (!bid) + return -ENODEV; + + ret = device_attach(&bid->udev->dev); + if (ret < 0) { + dev_err(&bid->udev->dev, "rebind failed\n"); + return ret; + } + + return count; +} + +static DRIVER_ATTR_WO(rebind); + static struct stub_priv *stub_priv_pop_from_listhead(struct list_head *listhead) { struct stub_priv *priv, *tmp; @@ -254,15 +283,22 @@ static int __init usbip_host_init(void) return -ENOMEM; } - ret = usb_register(&stub_driver); - if (ret < 0) { + ret = usb_register_device_driver(&stub_driver, THIS_MODULE); + if (ret) { pr_err("usb_register failed %d\n", ret); goto err_usb_register; } ret = driver_create_file(&stub_driver.drvwrap.driver, &driver_attr_match_busid); - if (ret < 0) { + if (ret) { + pr_err("driver_create_file failed\n"); + goto err_create_file; + } + + ret = driver_create_file(&stub_driver.drvwrap.driver, + &driver_attr_rebind); + if (ret) { pr_err("driver_create_file failed\n"); goto err_create_file; } @@ -271,7 +307,7 @@ static int __init usbip_host_init(void) return ret; err_create_file: - usb_deregister(&stub_driver); + usb_deregister_device_driver(&stub_driver); err_usb_register: kmem_cache_destroy(stub_priv_cache); return ret; @@ -282,11 +318,14 @@ static void __exit usbip_host_exit(void) driver_remove_file(&stub_driver.drvwrap.driver, &driver_attr_match_busid); + driver_remove_file(&stub_driver.drvwrap.driver, + &driver_attr_rebind); + /* * deregister() calls stub_disconnect() for all devices. Device * specific data is cleared in stub_disconnect(). */ - usb_deregister(&stub_driver); + usb_deregister_device_driver(&stub_driver); kmem_cache_destroy(stub_priv_cache); } diff --git a/drivers/staging/usbip/stub_rx.c b/drivers/staging/usbip/stub_rx.c index db48a789d30..e0b6d6b4272 100644 --- a/drivers/staging/usbip/stub_rx.c +++ b/drivers/staging/usbip/stub_rx.c @@ -102,11 +102,13 @@ static int tweak_clear_halt_cmd(struct urb *urb) ret = usb_clear_halt(urb->dev, target_pipe); if (ret < 0) - dev_err(&urb->dev->dev, "usb_clear_halt error: devnum %d endp " - "%d ret %d\n", urb->dev->devnum, target_endp, ret); + dev_err(&urb->dev->dev, + "usb_clear_halt error: devnum %d endp %d ret %d\n", + urb->dev->devnum, target_endp, ret); else - dev_info(&urb->dev->dev, "usb_clear_halt done: devnum %d endp " - "%d\n", urb->dev->devnum, target_endp); + dev_info(&urb->dev->dev, + "usb_clear_halt done: devnum %d endp %d\n", + urb->dev->devnum, target_endp); return ret; } @@ -127,42 +129,32 @@ static int tweak_set_interface_cmd(struct urb *urb) ret = usb_set_interface(urb->dev, interface, alternate); if (ret < 0) - dev_err(&urb->dev->dev, "usb_set_interface error: inf %u alt " - "%u ret %d\n", interface, alternate, ret); + dev_err(&urb->dev->dev, + "usb_set_interface error: inf %u alt %u ret %d\n", + interface, alternate, ret); else - dev_info(&urb->dev->dev, "usb_set_interface done: inf %u alt " - "%u\n", interface, alternate); + dev_info(&urb->dev->dev, + "usb_set_interface done: inf %u alt %u\n", + interface, alternate); return ret; } static int tweak_set_configuration_cmd(struct urb *urb) { + struct stub_priv *priv = (struct stub_priv *) urb->context; + struct stub_device *sdev = priv->sdev; struct usb_ctrlrequest *req; __u16 config; + int err; req = (struct usb_ctrlrequest *) urb->setup_packet; config = le16_to_cpu(req->wValue); - /* - * I have never seen a multi-config device. Very rare. - * For most devices, this will be called to choose a default - * configuration only once in an initialization phase. - * - * set_configuration may change a device configuration and its device - * drivers will be unbound and assigned for a new device configuration. - * This means this usbip driver will be also unbound when called, then - * eventually reassigned to the device as far as driver matching - * condition is kept. - * - * Unfortunately, an existing usbip connection will be dropped - * due to this driver unbinding. So, skip here. - * A user may need to set a special configuration value before - * exporting the device. - */ - dev_info(&urb->dev->dev, "usb_set_configuration %d to %s... skip!\n", - config, dev_name(&urb->dev->dev)); - + err = usb_set_configuration(sdev->udev, config); + if (err && err != -ENODEV) + dev_err(&sdev->udev->dev, "can't set config #%d, error %d\n", + config, err); return 0; } @@ -546,7 +538,7 @@ static void stub_rx_pdu(struct usbip_device *ud) int ret; struct usbip_header pdu; struct stub_device *sdev = container_of(ud, struct stub_device, ud); - struct device *dev = &sdev->interface->dev; + struct device *dev = &sdev->udev->dev; usbip_dbg_stub_rx("Enter\n"); diff --git a/drivers/staging/usbip/stub_tx.c b/drivers/staging/usbip/stub_tx.c index cd5326ae38c..dbcabc9dbe0 100644 --- a/drivers/staging/usbip/stub_tx.c +++ b/drivers/staging/usbip/stub_tx.c @@ -74,12 +74,12 @@ void stub_complete(struct urb *urb) /* OK */ break; case -ENOENT: - dev_info(&urb->dev->dev, "stopped by a call to usb_kill_urb() " - "because of cleaning up a virtual connection\n"); + dev_info(&urb->dev->dev, + "stopped by a call to usb_kill_urb() because of cleaning up a virtual connection\n"); return; case -ECONNRESET: - dev_info(&urb->dev->dev, "unlinked by a call to " - "usb_unlink_urb()\n"); + dev_info(&urb->dev->dev, + "unlinked by a call to usb_unlink_urb()\n"); break; case -EPIPE: dev_info(&urb->dev->dev, "endpoint %d is stalled\n", @@ -89,8 +89,9 @@ void stub_complete(struct urb *urb) dev_info(&urb->dev->dev, "device removed?\n"); break; default: - dev_info(&urb->dev->dev, "urb completion with non-zero status " - "%d\n", urb->status); + dev_info(&urb->dev->dev, + "urb completion with non-zero status %d\n", + urb->status); break; } @@ -178,7 +179,7 @@ static int stub_send_ret_submit(struct stub_device *sdev) else iovnum = 2; - iov = kzalloc(iovnum * sizeof(struct kvec), GFP_KERNEL); + iov = kcalloc(iovnum, sizeof(struct kvec), GFP_KERNEL); if (!iov) { usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_MALLOC); @@ -217,6 +218,7 @@ static int stub_send_ret_submit(struct stub_device *sdev) */ int i; + for (i = 0; i < urb->number_of_packets; i++) { iov[iovnum].iov_base = urb->transfer_buffer + urb->iso_frame_desc[i].offset; @@ -228,8 +230,7 @@ static int stub_send_ret_submit(struct stub_device *sdev) if (txsize != sizeof(pdu_header) + urb->actual_length) { dev_err(&sdev->interface->dev, - "actual length of urb %d does not " - "match iso packet sizes %zu\n", + "actual length of urb %d does not match iso packet sizes %zu\n", urb->actual_length, txsize-sizeof(pdu_header)); kfree(iov); diff --git a/drivers/staging/usbip/uapi/usbip.h b/drivers/staging/usbip/uapi/usbip.h new file mode 100644 index 00000000000..fa5db30ede3 --- /dev/null +++ b/drivers/staging/usbip/uapi/usbip.h @@ -0,0 +1,26 @@ +/* + * usbip.h + * + * USBIP uapi defines and function prototypes etc. +*/ + +#ifndef _UAPI_LINUX_USBIP_H +#define _UAPI_LINUX_USBIP_H + +/* usbip device status - exported in usbip device sysfs status */ +enum usbip_device_status { + /* sdev is available. */ + SDEV_ST_AVAILABLE = 0x01, + /* sdev is now used. */ + SDEV_ST_USED, + /* sdev is unusable because of a fatal error. */ + SDEV_ST_ERROR, + + /* vdev does not connect a remote device. */ + VDEV_ST_NULL, + /* vdev is used, but the USB address is not assigned yet */ + VDEV_ST_NOTASSIGNED, + VDEV_ST_USED, + VDEV_ST_ERROR +}; +#endif /* _UAPI_LINUX_USBIP_H */ diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c index 7b97df6f2a4..facaaf003f1 100644 --- a/drivers/staging/usbip/usbip_common.c +++ b/drivers/staging/usbip/usbip_common.c @@ -45,19 +45,21 @@ MODULE_PARM_DESC(usbip_debug_flag, "debug flags (defined in usbip_common.h)"); struct device_attribute dev_attr_usbip_debug; EXPORT_SYMBOL_GPL(dev_attr_usbip_debug); -static ssize_t show_flag(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t usbip_debug_show(struct device *dev, + struct device_attribute *attr, char *buf) { return sprintf(buf, "%lx\n", usbip_debug_flag); } -static ssize_t store_flag(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t usbip_debug_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) { - sscanf(buf, "%lx", &usbip_debug_flag); + if (sscanf(buf, "%lx", &usbip_debug_flag) != 1) + return -EINVAL; return count; } -DEVICE_ATTR(usbip_debug, (S_IRUGO | S_IWUSR), show_flag, store_flag); +DEVICE_ATTR_RW(usbip_debug); static void usbip_dump_buffer(char *buff, int bufflen) { @@ -98,26 +100,8 @@ static void usbip_dump_usb_device(struct usb_device *udev) struct device *dev = &udev->dev; int i; - dev_dbg(dev, " devnum(%d) devpath(%s) ", - udev->devnum, udev->devpath); - - switch (udev->speed) { - case USB_SPEED_HIGH: - pr_debug("SPD_HIGH "); - break; - case USB_SPEED_FULL: - pr_debug("SPD_FULL "); - break; - case USB_SPEED_LOW: - pr_debug("SPD_LOW "); - break; - case USB_SPEED_UNKNOWN: - pr_debug("SPD_UNKNOWN "); - break; - default: - pr_debug("SPD_ERROR "); - break; - } + dev_dbg(dev, " devnum(%d) devpath(%s) usb speed(%s)", + udev->devnum, udev->devpath, usb_speed_string(udev->speed)); pr_debug("tt %p, ttport %d\n", udev->tt, udev->ttport); @@ -154,8 +138,9 @@ static void usbip_dump_usb_device(struct usb_device *udev) dev_dbg(dev, "parent %p, bus %p\n", udev->parent, udev->bus); - dev_dbg(dev, "descriptor %p, config %p, actconfig %p, " - "rawdescriptors %p\n", &udev->descriptor, udev->config, + dev_dbg(dev, + "descriptor %p, config %p, actconfig %p, rawdescriptors %p\n", + &udev->descriptor, udev->config, udev->actconfig, udev->rawdescriptors); dev_dbg(dev, "have_langid %d, string_langid %d\n", @@ -193,8 +178,8 @@ static void usbip_dump_usb_ctrlrequest(struct usb_ctrlrequest *cmd) } pr_debug(" "); - pr_debug("bRequestType(%02X) bRequest(%02X) wValue(%04X) wIndex(%04X) " - "wLength(%04X) ", cmd->bRequestType, cmd->bRequest, + pr_debug("bRequestType(%02X) bRequest(%02X) wValue(%04X) wIndex(%04X) wLength(%04X) ", + cmd->bRequestType, cmd->bRequest, cmd->wValue, cmd->wIndex, cmd->wLength); pr_debug("\n "); @@ -305,8 +290,7 @@ void usbip_dump_header(struct usbip_header *pdu) switch (pdu->base.command) { case USBIP_CMD_SUBMIT: - pr_debug("USBIP_CMD_SUBMIT: " - "x_flags %u x_len %u sf %u #p %d iv %d\n", + pr_debug("USBIP_CMD_SUBMIT: x_flags %u x_len %u sf %u #p %d iv %d\n", pdu->u.cmd_submit.transfer_flags, pdu->u.cmd_submit.transfer_buffer_length, pdu->u.cmd_submit.start_frame, @@ -365,7 +349,6 @@ int usbip_recv(struct socket *sock, void *buf, int size) msg.msg_namelen = 0; msg.msg_control = NULL; msg.msg_controllen = 0; - msg.msg_namelen = 0; msg.msg_flags = MSG_NOSIGNAL; result = kernel_recvmsg(sock, &msg, &iov, 1, size, MSG_WAITALL); @@ -399,31 +382,6 @@ err: } EXPORT_SYMBOL_GPL(usbip_recv); -struct socket *sockfd_to_socket(unsigned int sockfd) -{ - struct socket *socket; - struct file *file; - struct inode *inode; - - file = fget(sockfd); - if (!file) { - pr_err("invalid sockfd\n"); - return NULL; - } - - inode = file_inode(file); - - if (!inode || !S_ISSOCK(inode->i_mode)) { - fput(file); - return NULL; - } - - socket = SOCKET_I(inode); - - return socket; -} -EXPORT_SYMBOL_GPL(sockfd_to_socket); - /* there may be more cases to tweak the flags. */ static unsigned int tweak_transfer_flags(unsigned int flags) { @@ -704,8 +662,7 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) if (total_length != urb->actual_length) { dev_err(&urb->dev->dev, - "total length of iso packets %d not equal to actual " - "length of buffer %d\n", + "total length of iso packets %d not equal to actual length of buffer %d\n", total_length, urb->actual_length); if (ud->side == USBIP_STUB) diff --git a/drivers/staging/usbip/usbip_common.h b/drivers/staging/usbip/usbip_common.h index 7e6c5436d97..4da3866a037 100644 --- a/drivers/staging/usbip/usbip_common.h +++ b/drivers/staging/usbip/usbip_common.h @@ -29,6 +29,7 @@ #include <linux/types.h> #include <linux/usb.h> #include <linux/wait.h> +#include "uapi/usbip.h" #define USBIP_VERSION "1.0.0" @@ -235,22 +236,6 @@ enum usbip_side { USBIP_STUB, }; -enum usbip_status { - /* sdev is available. */ - SDEV_ST_AVAILABLE = 0x01, - /* sdev is now used. */ - SDEV_ST_USED, - /* sdev is unusable because of a fatal error. */ - SDEV_ST_ERROR, - - /* vdev does not connect a remote device. */ - VDEV_ST_NULL, - /* vdev is used, but the USB address is not assigned yet */ - VDEV_ST_NOTASSIGNED, - VDEV_ST_USED, - VDEV_ST_ERROR -}; - /* event handler */ #define USBIP_EH_SHUTDOWN (1 << 0) #define USBIP_EH_BYE (1 << 1) @@ -271,7 +256,7 @@ enum usbip_status { /* a common structure for stub_device and vhci_device */ struct usbip_device { enum usbip_side side; - enum usbip_status status; + enum usbip_device_status status; /* lock for status */ spinlock_t lock; @@ -314,7 +299,6 @@ void usbip_dump_urb(struct urb *purb); void usbip_dump_header(struct usbip_header *pdu); int usbip_recv(struct socket *sock, void *buf, int size); -struct socket *sockfd_to_socket(unsigned int sockfd); void usbip_pack_pdu(struct usbip_header *pdu, struct urb *urb, int cmd, int pack); @@ -337,12 +321,14 @@ int usbip_event_happened(struct usbip_device *ud); static inline int interface_to_busnum(struct usb_interface *interface) { struct usb_device *udev = interface_to_usbdev(interface); + return udev->bus->busnum; } static inline int interface_to_devnum(struct usb_interface *interface) { struct usb_device *udev = interface_to_usbdev(interface); + return udev->devnum; } diff --git a/drivers/staging/usbip/userspace/README b/drivers/staging/usbip/userspace/README index 00a1658b272..831f49fea3c 100644 --- a/drivers/staging/usbip/userspace/README +++ b/drivers/staging/usbip/userspace/README @@ -9,8 +9,8 @@ - USB/IP device drivers Found in the staging directory of the Linux kernel. - - sysfsutils >= 2.0.0 - sysfsutils library + - libudev >= 2.0 + libudev library - libwrap0-dev tcp wrapper library @@ -19,6 +19,10 @@ - libtool, automake >= 1.9, autoconf >= 2.5.0, pkg-config +[Optional] + - hwdata + Contains USB device identification data. + [Install] 0. Generate configuration scripts. @@ -191,7 +195,6 @@ Detach the imported device: - Shutdown firewall. - usbip now uses TCP port 3240. - Disable SELinux. - - If possible, compile your kernel with CONFIG_USB_DEBUG flag and try again. - Check the kernel and daemon messages. diff --git a/drivers/staging/usbip/userspace/configure.ac b/drivers/staging/usbip/userspace/configure.ac index 2be4060f903..607d05c5ccf 100644 --- a/drivers/staging/usbip/userspace/configure.ac +++ b/drivers/staging/usbip/userspace/configure.ac @@ -1,7 +1,7 @@ dnl Process this file with autoconf to produce a configure script. AC_PREREQ(2.59) -AC_INIT([usbip-utils], [1.1.1], [linux-usb@vger.kernel.org]) +AC_INIT([usbip-utils], [2.0], [linux-usb@vger.kernel.org]) AC_DEFINE([USBIP_VERSION], [0x00000111], [binary-coded decimal version number]) CURRENT=0 @@ -44,11 +44,11 @@ AC_FUNC_REALLOC AC_CHECK_FUNCS([memset mkdir regcomp socket strchr strerror strstr dnl strtoul]) -AC_CHECK_HEADER([sysfs/libsysfs.h], - [AC_CHECK_LIB([sysfs], [sysfs_open_directory_list], - [LIBS="$LIBS -lsysfs"], - [AC_MSG_ERROR([Missing sysfs2 library!])])], - [AC_MSG_ERROR([Missing /usr/include/sysfs/libsysfs.h])]) +AC_CHECK_HEADER([libudev.h], + [AC_CHECK_LIB([udev], [udev_new], + [LIBS="$LIBS -ludev"], + [AC_MSG_ERROR([Missing udev library!])])], + [AC_MSG_ERROR([Missing /usr/include/libudev.h])]) # Checks for libwrap library. AC_MSG_CHECKING([whether to use the libwrap (TCP wrappers) library]) @@ -70,7 +70,6 @@ AC_ARG_WITH([tcp-wrappers], [AC_MSG_RESULT([not found]); exit 1]) else AC_MSG_RESULT([no]); - LIBS="$saved_LIBS" fi], dnl [ACTION-IF-NOT-GIVEN] [AC_MSG_RESULT([(default)]) diff --git a/drivers/staging/usbip/userspace/doc/usbip.8 b/drivers/staging/usbip/userspace/doc/usbip.8 index ccdadc87c47..a6097be25d2 100644 --- a/drivers/staging/usbip/userspace/doc/usbip.8 +++ b/drivers/staging/usbip/userspace/doc/usbip.8 @@ -3,7 +3,7 @@ usbip \- manage USB/IP devices .SH SYNOPSIS .B usbip -[\foptions\R] <\fIcommand\fR> <\fIargs\fR> +[\fIoptions\fR] <\fIcommand\fR> <\fIargs\fR> .SH DESCRIPTION On a USB/IP server, devices can be listed, bound, and unbound using @@ -23,6 +23,12 @@ Print debugging information. Log to syslog. .PP +.HP +\fB\-\-tcp-port PORT\fR +.IP +Connect to PORT on remote host (used for attach and list --remote). +.PP + .SH COMMANDS .HP \fBversion\fR diff --git a/drivers/staging/usbip/userspace/doc/usbipd.8 b/drivers/staging/usbip/userspace/doc/usbipd.8 index d896936f178..ac4635db3f0 100644 --- a/drivers/staging/usbip/userspace/doc/usbipd.8 +++ b/drivers/staging/usbip/userspace/doc/usbipd.8 @@ -14,10 +14,22 @@ Devices have to explicitly be exported using before usbipd makes them available to other hosts. The daemon accepts connections from USB/IP clients -on TCP port 3240. +on TCP port 3240 by default. .SH OPTIONS .HP +\fB\-4\fR, \fB\-\-ipv4\fR +.IP +Bind to IPv4. Default is both. +.PP + +.HP +\fB\-6\fR, \fB\-\-ipv6\fR +.IP +Bind to IPv6. Default is both. +.PP + +.HP \fB\-D\fR, \fB\-\-daemon\fR .IP Run as a daemon process. @@ -29,6 +41,19 @@ Run as a daemon process. Print debugging information. .PP +.HP +\fB\-PFILE\fR, \fB\-\-pid FILE\fR +.IP +Write process id to FILE. +.br +If no FILE specified, use /var/run/usbipd.pid +.PP + +\fB\-tPORT\fR, \fB\-\-tcp\-port PORT\fR +.IP +Listen on TCP/IP port PORT. +.PP + \fB\-h\fR, \fB\-\-help\fR .IP Print the program help message and exit. diff --git a/drivers/staging/usbip/userspace/libsrc/Makefile.am b/drivers/staging/usbip/userspace/libsrc/Makefile.am index 4921189e026..7c8f8a4d54e 100644 --- a/drivers/staging/usbip/userspace/libsrc/Makefile.am +++ b/drivers/staging/usbip/userspace/libsrc/Makefile.am @@ -4,4 +4,5 @@ libusbip_la_LDFLAGS = -version-info @LIBUSBIP_VERSION@ lib_LTLIBRARIES := libusbip.la libusbip_la_SOURCES := names.c names.h usbip_host_driver.c usbip_host_driver.h \ - usbip_common.c usbip_common.h vhci_driver.c vhci_driver.h + usbip_common.c usbip_common.h vhci_driver.c vhci_driver.h \ + sysfs_utils.c sysfs_utils.h diff --git a/drivers/staging/usbip/userspace/libsrc/list.h b/drivers/staging/usbip/userspace/libsrc/list.h new file mode 100644 index 00000000000..8d0c936e184 --- /dev/null +++ b/drivers/staging/usbip/userspace/libsrc/list.h @@ -0,0 +1,136 @@ +#ifndef _LIST_H +#define _LIST_H + +/* Stripped down implementation of linked list taken + * from the Linux Kernel. + */ + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +#define POISON_POINTER_DELTA 0 +#define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA) +#define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA) + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void __list_del_entry(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +#endif diff --git a/drivers/staging/usbip/userspace/libsrc/names.c b/drivers/staging/usbip/userspace/libsrc/names.c index 3c8d28b771e..81ff8522405 100644 --- a/drivers/staging/usbip/userspace/libsrc/names.c +++ b/drivers/staging/usbip/userspace/libsrc/names.c @@ -169,14 +169,14 @@ static void *my_malloc(size_t size) struct pool *p; p = calloc(1, sizeof(struct pool)); - if (!p) { - free(p); + if (!p) return NULL; - } p->mem = calloc(1, size); - if (!p->mem) + if (!p->mem) { + free(p); return NULL; + } p->next = pool_head; pool_head = p; diff --git a/drivers/staging/usbip/userspace/libsrc/sysfs_utils.c b/drivers/staging/usbip/userspace/libsrc/sysfs_utils.c new file mode 100644 index 00000000000..36ac88ece0b --- /dev/null +++ b/drivers/staging/usbip/userspace/libsrc/sysfs_utils.c @@ -0,0 +1,31 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> + +#include "sysfs_utils.h" +#include "usbip_common.h" + +int write_sysfs_attribute(const char *attr_path, const char *new_value, + size_t len) +{ + int fd; + int length; + + fd = open(attr_path, O_WRONLY); + if (fd < 0) { + dbg("error opening attribute %s", attr_path); + return -1; + } + + length = write(fd, new_value, len); + if (length < 0) { + dbg("error writing to attribute %s", attr_path); + close(fd); + return -1; + } + + close(fd); + + return 0; +} diff --git a/drivers/staging/usbip/userspace/libsrc/sysfs_utils.h b/drivers/staging/usbip/userspace/libsrc/sysfs_utils.h new file mode 100644 index 00000000000..32ac1d105d1 --- /dev/null +++ b/drivers/staging/usbip/userspace/libsrc/sysfs_utils.h @@ -0,0 +1,8 @@ + +#ifndef __SYSFS_UTILS_H +#define __SYSFS_UTILS_H + +int write_sysfs_attribute(const char *attr_path, const char *new_value, + size_t len); + +#endif diff --git a/drivers/staging/usbip/userspace/libsrc/usbip_common.c b/drivers/staging/usbip/userspace/libsrc/usbip_common.c index 17e08e022c0..ac73710473d 100644 --- a/drivers/staging/usbip/userspace/libsrc/usbip_common.c +++ b/drivers/staging/usbip/userspace/libsrc/usbip_common.c @@ -2,6 +2,7 @@ * Copyright (C) 2005-2007 Takahiro Hirofuchi */ +#include <libudev.h> #include "usbip_common.h" #include "names.h" @@ -12,6 +13,8 @@ int usbip_use_syslog; int usbip_use_stderr; int usbip_use_debug; +extern struct udev *udev_context; + struct speed_string { int num; char *speed; @@ -23,6 +26,8 @@ static const struct speed_string speed_strings[] = { { USB_SPEED_LOW, "1.5", "Low Speed(1.5Mbps)" }, { USB_SPEED_FULL, "12", "Full Speed(12Mbps)" }, { USB_SPEED_HIGH, "480", "High Speed(480Mbps)" }, + { USB_SPEED_WIRELESS, "53.3-480", "Wireless"}, + { USB_SPEED_SUPER, "5000", "Super Speed(5000Mbps)" }, { 0, NULL, NULL } }; @@ -70,6 +75,7 @@ const char *usbip_speed_string(int num) void dump_usb_interface(struct usbip_usb_interface *uinf) { char buff[100]; + usbip_names_get_class(buff, sizeof(buff), uinf->bInterfaceClass, uinf->bInterfaceSubClass, @@ -81,7 +87,6 @@ void dump_usb_device(struct usbip_usb_device *udev) { char buff[100]; - dbg("%-20s = %s", "path", udev->path); dbg("%-20s = %s", "busid", udev->busid); @@ -109,75 +114,61 @@ void dump_usb_device(struct usbip_usb_device *udev) } -int read_attr_value(struct sysfs_device *dev, const char *name, +int read_attr_value(struct udev_device *dev, const char *name, const char *format) { - char attrpath[SYSFS_PATH_MAX]; - struct sysfs_attribute *attr; + const char *attr; int num = 0; int ret; - snprintf(attrpath, sizeof(attrpath), "%s/%s", dev->path, name); - - attr = sysfs_open_attribute(attrpath); + attr = udev_device_get_sysattr_value(dev, name); if (!attr) { - dbg("sysfs_open_attribute failed: %s", attrpath); - return 0; - } - - ret = sysfs_read_attribute(attr); - if (ret < 0) { - dbg("sysfs_read_attribute failed"); + err("udev_device_get_sysattr_value failed"); goto err; } - ret = sscanf(attr->value, format, &num); + /* The client chooses the device configuration + * when attaching it so right after being bound + * to usbip-host on the server the device will + * have no configuration. + * Therefore, attributes such as bConfigurationValue + * and bNumInterfaces will not exist and sscanf will + * fail. Check for these cases and don't treat them + * as errors. + */ + + ret = sscanf(attr, format, &num); if (ret < 1) { - dbg("sscanf failed"); - goto err; + if (strcmp(name, "bConfigurationValue") && + strcmp(name, "bNumInterfaces")) { + err("sscanf failed for attribute %s", name); + goto err; + } } err: - sysfs_close_attribute(attr); return num; } -int read_attr_speed(struct sysfs_device *dev) +int read_attr_speed(struct udev_device *dev) { - char attrpath[SYSFS_PATH_MAX]; - struct sysfs_attribute *attr; - char speed[100]; - int ret; - - snprintf(attrpath, sizeof(attrpath), "%s/%s", dev->path, "speed"); + const char *speed; - attr = sysfs_open_attribute(attrpath); - if (!attr) { - dbg("sysfs_open_attribute failed: %s", attrpath); - return 0; - } - - ret = sysfs_read_attribute(attr); - if (ret < 0) { - dbg("sysfs_read_attribute failed"); - goto err; - } - - ret = sscanf(attr->value, "%s\n", speed); - if (ret < 1) { - dbg("sscanf failed"); + speed = udev_device_get_sysattr_value(dev, "speed"); + if (!speed) { + err("udev_device_get_sysattr_value failed"); goto err; } -err: - sysfs_close_attribute(attr); for (int i = 0; speed_strings[i].speed != NULL; i++) { if (!strcmp(speed, speed_strings[i].speed)) return speed_strings[i].num; } +err: + return USB_SPEED_UNKNOWN; } @@ -188,9 +179,10 @@ err: } while (0) -int read_usb_device(struct sysfs_device *sdev, struct usbip_usb_device *udev) +int read_usb_device(struct udev_device *sdev, struct usbip_usb_device *udev) { uint32_t busnum, devnum; + const char *path, *name; READ_ATTR(udev, uint8_t, sdev, bDeviceClass, "%02x\n"); READ_ATTR(udev, uint8_t, sdev, bDeviceSubClass, "%02x\n"); @@ -207,10 +199,13 @@ int read_usb_device(struct sysfs_device *sdev, struct usbip_usb_device *udev) READ_ATTR(udev, uint8_t, sdev, devnum, "%d\n"); udev->speed = read_attr_speed(sdev); - strncpy(udev->path, sdev->path, SYSFS_PATH_MAX); - strncpy(udev->busid, sdev->name, SYSFS_BUS_ID_SIZE); + path = udev_device_get_syspath(sdev); + name = udev_device_get_sysname(sdev); - sscanf(sdev->name, "%u-%u", &busnum, &devnum); + strncpy(udev->path, path, SYSFS_PATH_MAX); + strncpy(udev->busid, name, SYSFS_BUS_ID_SIZE); + + sscanf(name, "%u-%u", &busnum, &devnum); udev->busnum = busnum; return 0; @@ -220,13 +215,13 @@ int read_usb_interface(struct usbip_usb_device *udev, int i, struct usbip_usb_interface *uinf) { char busid[SYSFS_BUS_ID_SIZE]; - struct sysfs_device *sif; + struct udev_device *sif; sprintf(busid, "%s:%d.%d", udev->busid, udev->bConfigurationValue, i); - sif = sysfs_open_device("usb", busid); + sif = udev_device_new_from_subsystem_sysname(udev_context, "usb", busid); if (!sif) { - dbg("sysfs_open_device(\"usb\", \"%s\") failed", busid); + err("udev_device_new_from_subsystem_sysname %s failed", busid); return -1; } @@ -234,8 +229,6 @@ int read_usb_interface(struct usbip_usb_device *udev, int i, READ_ATTR(uinf, uint8_t, sif, bInterfaceSubClass, "%02x\n"); READ_ATTR(uinf, uint8_t, sif, bInterfaceProtocol, "%02x\n"); - sysfs_close_device(sif); - return 0; } @@ -244,7 +237,7 @@ int usbip_names_init(char *f) return names_init(f); } -void usbip_names_free() +void usbip_names_free(void) { names_free(); } diff --git a/drivers/staging/usbip/userspace/libsrc/usbip_common.h b/drivers/staging/usbip/userspace/libsrc/usbip_common.h index 938ad1c3694..5a0e95edf4d 100644 --- a/drivers/staging/usbip/userspace/libsrc/usbip_common.h +++ b/drivers/staging/usbip/userspace/libsrc/usbip_common.h @@ -5,7 +5,7 @@ #ifndef __USBIP_COMMON_H #define __USBIP_COMMON_H -#include <sysfs/libsysfs.h> +#include <libudev.h> #include <stdint.h> #include <stdio.h> @@ -14,6 +14,8 @@ #include <syslog.h> #include <unistd.h> +#include <linux/usb/ch9.h> +#include "../../uapi/usbip.h" #ifndef USBIDS_FILE #define USBIDS_FILE "/usr/share/hwdata/usb.ids" @@ -28,6 +30,15 @@ #define USBIP_HOST_DRV_NAME "usbip-host" #define USBIP_VHCI_DRV_NAME "vhci_hcd" +/* sysfs constants */ +#define SYSFS_MNT_PATH "/sys" +#define SYSFS_BUS_NAME "bus" +#define SYSFS_BUS_TYPE "usb" +#define SYSFS_DRIVERS_NAME "drivers" + +#define SYSFS_PATH_MAX 256 +#define SYSFS_BUS_ID_SIZE 32 + extern int usbip_use_syslog; extern int usbip_use_stderr; extern int usbip_use_debug ; @@ -36,7 +47,7 @@ extern int usbip_use_debug ; #define pr_fmt(fmt) "%s: %s: " fmt "\n", PROGNAME #define dbg_fmt(fmt) pr_fmt("%s:%d:[%s] " fmt), "debug", \ - __FILE__, __LINE__, __FUNCTION__ + __FILE__, __LINE__, __func__ #define err(fmt, args...) \ do { \ @@ -76,30 +87,6 @@ extern int usbip_use_debug ; abort(); \ } while (0) -enum usb_device_speed { - USB_SPEED_UNKNOWN = 0, /* enumerating */ - USB_SPEED_LOW, USB_SPEED_FULL, /* usb 1.1 */ - USB_SPEED_HIGH, /* usb 2.0 */ - USB_SPEED_VARIABLE /* wireless (usb 2.5) */ -}; - -/* FIXME: how to sync with drivers/usbip_common.h ? */ -enum usbip_device_status { - /* sdev is available. */ - SDEV_ST_AVAILABLE = 0x01, - /* sdev is now used. */ - SDEV_ST_USED, - /* sdev is unusable because of a fatal error. */ - SDEV_ST_ERROR, - - /* vdev does not connect a remote device. */ - VDEV_ST_NULL, - /* vdev is used, but the USB address is not assigned yet */ - VDEV_ST_NOTASSIGNED, - VDEV_ST_USED, - VDEV_ST_ERROR -}; - struct usbip_usb_interface { uint8_t bInterfaceClass; uint8_t bInterfaceSubClass; @@ -131,8 +118,8 @@ struct usbip_usb_device { void dump_usb_interface(struct usbip_usb_interface *); void dump_usb_device(struct usbip_usb_device *); -int read_usb_device(struct sysfs_device *sdev, struct usbip_usb_device *udev); -int read_attr_value(struct sysfs_device *dev, const char *name, +int read_usb_device(struct udev_device *sdev, struct usbip_usb_device *udev); +int read_attr_value(struct udev_device *dev, const char *name, const char *format); int read_usb_interface(struct usbip_usb_device *udev, int i, struct usbip_usb_interface *uinf); diff --git a/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c b/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c index 71a449cf50d..92caef7474c 100644 --- a/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c +++ b/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c @@ -18,102 +18,65 @@ #include <sys/types.h> #include <sys/stat.h> +#include <fcntl.h> #include <errno.h> #include <unistd.h> +#include <libudev.h> + #include "usbip_common.h" #include "usbip_host_driver.h" +#include "list.h" +#include "sysfs_utils.h" #undef PROGNAME #define PROGNAME "libusbip" struct usbip_host_driver *host_driver; +struct udev *udev_context; -#define SYSFS_OPEN_RETRIES 100 - -/* only the first interface value is true! */ static int32_t read_attr_usbip_status(struct usbip_usb_device *udev) { - char attrpath[SYSFS_PATH_MAX]; - struct sysfs_attribute *attr; + char status_attr_path[SYSFS_PATH_MAX]; + int fd; + int length; + char status; int value = 0; - int rc; - struct stat s; - int retries = SYSFS_OPEN_RETRIES; - - /* This access is racy! - * - * Just after detach, our driver removes the sysfs - * files and recreates them. - * - * We may try and fail to open the usbip_status of - * an exported device in the (short) window where - * it has been removed and not yet recreated. - * - * This is a bug in the interface. Nothing we can do - * except work around it here by polling for the sysfs - * usbip_status to reappear. - */ - - snprintf(attrpath, SYSFS_PATH_MAX, "%s/%s:%d.%d/usbip_status", - udev->path, udev->busid, udev->bConfigurationValue, 0); - - while (retries > 0) { - if (stat(attrpath, &s) == 0) - break; - - if (errno != ENOENT) { - dbg("stat failed: %s", attrpath); - return -1; - } - - usleep(10000); /* 10ms */ - retries--; - } - if (retries == 0) - dbg("usbip_status not ready after %d retries", - SYSFS_OPEN_RETRIES); - else if (retries < SYSFS_OPEN_RETRIES) - dbg("warning: usbip_status ready after %d retries", - SYSFS_OPEN_RETRIES - retries); + snprintf(status_attr_path, SYSFS_PATH_MAX, "%s/usbip_status", + udev->path); - attr = sysfs_open_attribute(attrpath); - if (!attr) { - dbg("sysfs_open_attribute failed: %s", attrpath); + if ((fd = open(status_attr_path, O_RDONLY)) < 0) { + err("error opening attribute %s", status_attr_path); return -1; } - rc = sysfs_read_attribute(attr); - if (rc) { - dbg("sysfs_read_attribute failed: %s", attrpath); - sysfs_close_attribute(attr); + length = read(fd, &status, 1); + if (length < 0) { + err("error reading attribute %s", status_attr_path); + close(fd); return -1; } - value = atoi(attr->value); - - sysfs_close_attribute(attr); + value = atoi(&status); return value; } -static struct usbip_exported_device *usbip_exported_device_new(char *sdevpath) +static +struct usbip_exported_device *usbip_exported_device_new(const char *sdevpath) { struct usbip_exported_device *edev = NULL; + struct usbip_exported_device *edev_old; size_t size; int i; - edev = calloc(1, sizeof(*edev)); - if (!edev) { - dbg("calloc failed"); - return NULL; - } + edev = calloc(1, sizeof(struct usbip_exported_device)); - edev->sudev = sysfs_open_device_path(sdevpath); + edev->sudev = udev_device_new_from_syspath(udev_context, sdevpath); if (!edev->sudev) { - dbg("sysfs_open_device_path failed: %s", sdevpath); + err("udev_device_new_from_syspath: %s", sdevpath); goto err; } @@ -124,11 +87,13 @@ static struct usbip_exported_device *usbip_exported_device_new(char *sdevpath) goto err; /* reallocate buffer to include usb interface data */ - size = sizeof(*edev) + edev->udev.bNumInterfaces * + size = sizeof(struct usbip_exported_device) + edev->udev.bNumInterfaces * sizeof(struct usbip_usb_interface); + edev_old = edev; edev = realloc(edev, size); if (!edev) { + edev = edev_old; dbg("realloc failed"); goto err; } @@ -138,160 +103,91 @@ static struct usbip_exported_device *usbip_exported_device_new(char *sdevpath) return edev; err: - if (edev && edev->sudev) - sysfs_close_device(edev->sudev); + if (edev->sudev) + udev_device_unref(edev->sudev); if (edev) free(edev); return NULL; } -static int check_new(struct dlist *dlist, struct sysfs_device *target) -{ - struct sysfs_device *dev; - - dlist_for_each_data(dlist, dev, struct sysfs_device) { - if (!strncmp(dev->bus_id, target->bus_id, SYSFS_BUS_ID_SIZE)) - /* device found and is not new */ - return 0; - } - return 1; -} - -static void delete_nothing(void *unused_data) -{ - /* - * NOTE: Do not delete anything, but the container will be deleted. - */ - (void) unused_data; -} - static int refresh_exported_devices(void) { - /* sysfs_device of usb_interface */ - struct sysfs_device *suintf; - struct dlist *suintf_list; - /* sysfs_device of usb_device */ - struct sysfs_device *sudev; - struct dlist *sudev_list; struct usbip_exported_device *edev; - - sudev_list = dlist_new_with_delete(sizeof(struct sysfs_device), - delete_nothing); - - suintf_list = sysfs_get_driver_devices(host_driver->sysfs_driver); - if (!suintf_list) { - /* - * Not an error condition. There are simply no devices bound to - * the driver yet. - */ - dbg("bind " USBIP_HOST_DRV_NAME ".ko to a usb device to be " - "exportable!"); - return 0; - } - - /* collect unique USB devices (not interfaces) */ - dlist_for_each_data(suintf_list, suintf, struct sysfs_device) { - /* get usb device of this usb interface */ - sudev = sysfs_get_device_parent(suintf); - if (!sudev) { - dbg("sysfs_get_device_parent failed: %s", suintf->name); + struct udev_enumerate *enumerate; + struct udev_list_entry *devices, *dev_list_entry; + struct udev_device *dev; + const char *path; + const char *driver; + + enumerate = udev_enumerate_new(udev_context); + udev_enumerate_add_match_subsystem(enumerate, "usb"); + udev_enumerate_scan_devices(enumerate); + + devices = udev_enumerate_get_list_entry(enumerate); + + udev_list_entry_foreach(dev_list_entry, devices) { + path = udev_list_entry_get_name(dev_list_entry); + dev = udev_device_new_from_syspath(udev_context, path); + if (dev == NULL) continue; - } - - if (check_new(sudev_list, sudev)) { - /* insert item at head of list */ - dlist_unshift(sudev_list, sudev); - } - } - dlist_for_each_data(sudev_list, sudev, struct sysfs_device) { - edev = usbip_exported_device_new(sudev->path); - if (!edev) { - dbg("usbip_exported_device_new failed"); - continue; + /* Check whether device uses usbip-host driver. */ + driver = udev_device_get_driver(dev); + if (driver != NULL && !strcmp(driver, USBIP_HOST_DRV_NAME)) { + edev = usbip_exported_device_new(path); + if (!edev) { + dbg("usbip_exported_device_new failed"); + continue; + } + + list_add(&edev->node, &host_driver->edev_list); + host_driver->ndevs++; } - - dlist_unshift(host_driver->edev_list, edev); - host_driver->ndevs++; } - dlist_destroy(sudev_list); - return 0; } -static struct sysfs_driver *open_sysfs_host_driver(void) +static void usbip_exported_device_destroy(void) { - char bus_type[] = "usb"; - char sysfs_mntpath[SYSFS_PATH_MAX]; - char host_drv_path[SYSFS_PATH_MAX]; - struct sysfs_driver *host_drv; - int rc; - - rc = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX); - if (rc < 0) { - dbg("sysfs_get_mnt_path failed"); - return NULL; - } - - snprintf(host_drv_path, SYSFS_PATH_MAX, "%s/%s/%s/%s/%s", - sysfs_mntpath, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME, - USBIP_HOST_DRV_NAME); + struct list_head *i, *tmp; + struct usbip_exported_device *edev; - host_drv = sysfs_open_driver_path(host_drv_path); - if (!host_drv) { - dbg("sysfs_open_driver_path failed"); - return NULL; + list_for_each_safe(i, tmp, &host_driver->edev_list) { + edev = list_entry(i, struct usbip_exported_device, node); + list_del(i); + free(edev); } - - return host_drv; -} - -static void usbip_exported_device_delete(void *dev) -{ - struct usbip_exported_device *edev = dev; - sysfs_close_device(edev->sudev); - free(dev); } int usbip_host_driver_open(void) { int rc; - host_driver = calloc(1, sizeof(*host_driver)); - if (!host_driver) { - dbg("calloc failed"); + udev_context = udev_new(); + if (!udev_context) { + err("udev_new failed"); return -1; } - host_driver->ndevs = 0; - host_driver->edev_list = - dlist_new_with_delete(sizeof(struct usbip_exported_device), - usbip_exported_device_delete); - if (!host_driver->edev_list) { - dbg("dlist_new_with_delete failed"); - goto err_free_host_driver; - } + host_driver = calloc(1, sizeof(*host_driver)); - host_driver->sysfs_driver = open_sysfs_host_driver(); - if (!host_driver->sysfs_driver) - goto err_destroy_edev_list; + host_driver->ndevs = 0; + INIT_LIST_HEAD(&host_driver->edev_list); rc = refresh_exported_devices(); if (rc < 0) - goto err_close_sysfs_driver; + goto err_free_host_driver; return 0; -err_close_sysfs_driver: - sysfs_close_driver(host_driver->sysfs_driver); -err_destroy_edev_list: - dlist_destroy(host_driver->edev_list); err_free_host_driver: free(host_driver); host_driver = NULL; + udev_unref(udev_context); + return -1; } @@ -300,30 +196,22 @@ void usbip_host_driver_close(void) if (!host_driver) return; - if (host_driver->edev_list) - dlist_destroy(host_driver->edev_list); - if (host_driver->sysfs_driver) - sysfs_close_driver(host_driver->sysfs_driver); + usbip_exported_device_destroy(); free(host_driver); host_driver = NULL; + + udev_unref(udev_context); } int usbip_host_refresh_device_list(void) { int rc; - if (host_driver->edev_list) - dlist_destroy(host_driver->edev_list); + usbip_exported_device_destroy(); host_driver->ndevs = 0; - host_driver->edev_list = - dlist_new_with_delete(sizeof(struct usbip_exported_device), - usbip_exported_device_delete); - if (!host_driver->edev_list) { - dbg("dlist_new_with_delete failed"); - return -1; - } + INIT_LIST_HEAD(&host_driver->edev_list); rc = refresh_exported_devices(); if (rc < 0) @@ -335,8 +223,7 @@ int usbip_host_refresh_device_list(void) int usbip_host_export_device(struct usbip_exported_device *edev, int sockfd) { char attr_name[] = "usbip_sockfd"; - char attr_path[SYSFS_PATH_MAX]; - struct sysfs_attribute *attr; + char sockfd_attr_path[SYSFS_PATH_MAX]; char sockfd_buff[30]; int ret; @@ -356,41 +243,32 @@ int usbip_host_export_device(struct usbip_exported_device *edev, int sockfd) } /* only the first interface is true */ - snprintf(attr_path, sizeof(attr_path), "%s/%s:%d.%d/%s", - edev->udev.path, edev->udev.busid, - edev->udev.bConfigurationValue, 0, attr_name); - - attr = sysfs_open_attribute(attr_path); - if (!attr) { - dbg("sysfs_open_attribute failed: %s", attr_path); - return -1; - } + snprintf(sockfd_attr_path, sizeof(sockfd_attr_path), "%s/%s", + edev->udev.path, attr_name); snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd); - dbg("write: %s", sockfd_buff); - ret = sysfs_write_attribute(attr, sockfd_buff, strlen(sockfd_buff)); + ret = write_sysfs_attribute(sockfd_attr_path, sockfd_buff, + strlen(sockfd_buff)); if (ret < 0) { - dbg("sysfs_write_attribute failed: sockfd %s to %s", - sockfd_buff, attr_path); - goto err_write_sockfd; + err("write_sysfs_attribute failed: sockfd %s to %s", + sockfd_buff, sockfd_attr_path); + return ret; } - dbg("connect: %s", edev->udev.busid); - -err_write_sockfd: - sysfs_close_attribute(attr); + info("connect: %s", edev->udev.busid); return ret; } struct usbip_exported_device *usbip_host_get_device(int num) { + struct list_head *i; struct usbip_exported_device *edev; - struct dlist *dlist = host_driver->edev_list; int cnt = 0; - dlist_for_each_data(dlist, edev, struct usbip_exported_device) { + list_for_each(i, &host_driver->edev_list) { + edev = list_entry(i, struct usbip_exported_device, node); if (num == cnt) return edev; else diff --git a/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.h b/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.h index 34fd14cbfc4..2a31f855c61 100644 --- a/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.h +++ b/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.h @@ -21,18 +21,19 @@ #include <stdint.h> #include "usbip_common.h" +#include "list.h" struct usbip_host_driver { int ndevs; - struct sysfs_driver *sysfs_driver; /* list of exported device */ - struct dlist *edev_list; + struct list_head edev_list; }; struct usbip_exported_device { - struct sysfs_device *sudev; + struct udev_device *sudev; int32_t status; struct usbip_usb_device udev; + struct list_head node; struct usbip_usb_interface uinf[]; }; diff --git a/drivers/staging/usbip/userspace/libsrc/vhci_driver.c b/drivers/staging/usbip/userspace/libsrc/vhci_driver.c index 25e62e9f0a3..ad920477353 100644 --- a/drivers/staging/usbip/userspace/libsrc/vhci_driver.c +++ b/drivers/staging/usbip/userspace/libsrc/vhci_driver.c @@ -4,44 +4,30 @@ #include "usbip_common.h" #include "vhci_driver.h" +#include <limits.h> +#include <netdb.h> +#include <libudev.h> +#include "sysfs_utils.h" #undef PROGNAME #define PROGNAME "libusbip" struct usbip_vhci_driver *vhci_driver; +struct udev *udev_context; static struct usbip_imported_device * imported_device_init(struct usbip_imported_device *idev, char *busid) { - struct sysfs_device *sudev; + struct udev_device *sudev; - sudev = sysfs_open_device("usb", busid); + sudev = udev_device_new_from_subsystem_sysname(udev_context, + "usb", busid); if (!sudev) { - dbg("sysfs_open_device failed: %s", busid); + dbg("udev_device_new_from_subsystem_sysname failed: %s", busid); goto err; } read_usb_device(sudev, &idev->udev); - sysfs_close_device(sudev); - - /* add class devices of this imported device */ - struct usbip_class_device *cdev; - dlist_for_each_data(vhci_driver->cdev_list, cdev, - struct usbip_class_device) { - if (!strncmp(cdev->dev_path, idev->udev.path, - strlen(idev->udev.path))) { - struct usbip_class_device *new_cdev; - /* - * alloc and copy because dlist is linked - * from only one list - */ - new_cdev = calloc(1, sizeof(*new_cdev)); - if (!new_cdev) - goto err; - - memcpy(new_cdev, cdev, sizeof(*new_cdev)); - dlist_unshift(idev->cdev_list, (void *) new_cdev); - } - } + udev_device_unref(sudev); return idev; @@ -51,7 +37,7 @@ err: -static int parse_status(char *value) +static int parse_status(const char *value) { int ret = 0; char *c; @@ -72,7 +58,7 @@ static int parse_status(char *value) unsigned long socket; char lbusid[SYSFS_BUS_ID_SIZE]; - ret = sscanf(c, "%d %d %d %x %lx %s\n", + ret = sscanf(c, "%d %d %d %x %lx %31s\n", &port, &status, &speed, &devid, &socket, lbusid); @@ -98,12 +84,6 @@ static int parse_status(char *value) idev->busnum = (devid >> 16); idev->devnum = (devid & 0x0000ffff); - idev->cdev_list = dlist_new(sizeof(struct usbip_class_device)); - if (!idev->cdev_list) { - dbg("dlist_new failed"); - return -1; - } - if (idev->status != VDEV_ST_NULL && idev->status != VDEV_ST_NOTASSIGNED) { idev = imported_device_init(idev, lbusid); @@ -127,156 +107,35 @@ static int parse_status(char *value) return 0; } - -static int check_usbip_device(struct sysfs_class_device *cdev) -{ - /* /sys/class/video4linux/video0/device */ - char class_path[SYSFS_PATH_MAX]; - /* /sys/devices/platform/vhci_hcd/usb6/6-1:1.1 */ - char dev_path[SYSFS_PATH_MAX]; - int ret; - struct usbip_class_device *usbip_cdev; - - snprintf(class_path, sizeof(class_path), "%s/device", cdev->path); - - ret = sysfs_get_link(class_path, dev_path, sizeof(dev_path)); - if (ret == 0) { - if (!strncmp(dev_path, vhci_driver->hc_device->path, - strlen(vhci_driver->hc_device->path))) { - /* found usbip device */ - usbip_cdev = calloc(1, sizeof(*usbip_cdev)); - if (!usbip_cdev) { - dbg("calloc failed"); - return -1; - } - dlist_unshift(vhci_driver->cdev_list, usbip_cdev); - strncpy(usbip_cdev->class_path, class_path, - sizeof(usbip_cdev->class_path)); - strncpy(usbip_cdev->dev_path, dev_path, - sizeof(usbip_cdev->dev_path)); - dbg("found: %s %s", class_path, dev_path); - } - } - - return 0; -} - - -static int search_class_for_usbip_device(char *cname) -{ - struct sysfs_class *class; - struct dlist *cdev_list; - struct sysfs_class_device *cdev; - int ret = 0; - - class = sysfs_open_class(cname); - if (!class) { - dbg("sysfs_open_class failed"); - return -1; - } - - dbg("class: %s", class->name); - - cdev_list = sysfs_get_class_devices(class); - if (!cdev_list) - /* nothing */ - goto out; - - dlist_for_each_data(cdev_list, cdev, struct sysfs_class_device) { - dbg("cdev: %s", cdev->name); - ret = check_usbip_device(cdev); - if (ret < 0) - goto out; - } - -out: - sysfs_close_class(class); - - return ret; -} - - -static int refresh_class_device_list(void) -{ - int ret; - struct dlist *cname_list; - char *cname; - char sysfs_mntpath[SYSFS_PATH_MAX]; - char class_path[SYSFS_PATH_MAX]; - - ret = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX); - if (ret < 0) { - dbg("sysfs_get_mnt_path failed"); - return -1; - } - - snprintf(class_path, sizeof(class_path), "%s/%s", sysfs_mntpath, - SYSFS_CLASS_NAME); - - /* search under /sys/class */ - cname_list = sysfs_open_directory_list(class_path); - if (!cname_list) { - dbg("sysfs_open_directory failed"); - return -1; - } - - dlist_for_each_data(cname_list, cname, char) { - ret = search_class_for_usbip_device(cname); - if (ret < 0) { - sysfs_close_list(cname_list); - return -1; - } - } - - sysfs_close_list(cname_list); - - /* seach under /sys/block */ - ret = search_class_for_usbip_device(SYSFS_BLOCK_NAME); - if (ret < 0) - return -1; - - return 0; -} - - static int refresh_imported_device_list(void) { - struct sysfs_attribute *attr_status; + const char *attr_status; - - attr_status = sysfs_get_device_attr(vhci_driver->hc_device, "status"); + attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device, + "status"); if (!attr_status) { - dbg("sysfs_get_device_attr(\"status\") failed: %s", - vhci_driver->hc_device->name); + err("udev_device_get_sysattr_value failed"); return -1; } - dbg("name: %s path: %s len: %d method: %d value: %s", - attr_status->name, attr_status->path, attr_status->len, - attr_status->method, attr_status->value); - - return parse_status(attr_status->value); + return parse_status(attr_status); } static int get_nports(void) { char *c; int nports = 0; - struct sysfs_attribute *attr_status; + const char *attr_status; - attr_status = sysfs_get_device_attr(vhci_driver->hc_device, "status"); + attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device, + "status"); if (!attr_status) { - dbg("sysfs_get_device_attr(\"status\") failed: %s", - vhci_driver->hc_device->name); + err("udev_device_get_sysattr_value failed"); return -1; } - dbg("name: %s path: %s len: %d method: %d value: %s", - attr_status->name, attr_status->path, attr_status->len, - attr_status->method, attr_status->value); - /* skip a header line */ - c = strchr(attr_status->value, '\n'); + c = strchr(attr_status, '\n'); if (!c) return 0; c++; @@ -293,79 +152,88 @@ static int get_nports(void) return nports; } -static int get_hc_busid(char *sysfs_mntpath, char *hc_busid) +/* + * Read the given port's record. + * + * To avoid buffer overflow we will read the entire line and + * validate each part's size. The initial buffer is padded by 4 to + * accommodate the 2 spaces, 1 newline and an additional character + * which is needed to properly validate the 3rd part without it being + * truncated to an acceptable length. + */ +static int read_record(int rhport, char *host, unsigned long host_len, + char *port, unsigned long port_len, char *busid) { - struct sysfs_driver *sdriver; - char sdriver_path[SYSFS_PATH_MAX]; - - struct sysfs_device *hc_dev; - struct dlist *hc_devs; - - int found = 0; + int part; + FILE *file; + char path[PATH_MAX+1]; + char *buffer, *start, *end; + char delim[] = {' ', ' ', '\n'}; + int max_len[] = {(int)host_len, (int)port_len, SYSFS_BUS_ID_SIZE}; + size_t buffer_len = host_len + port_len + SYSFS_BUS_ID_SIZE + 4; + + buffer = malloc(buffer_len); + if (!buffer) + return -1; - snprintf(sdriver_path, SYSFS_PATH_MAX, "%s/%s/%s/%s/%s", sysfs_mntpath, - SYSFS_BUS_NAME, USBIP_VHCI_BUS_TYPE, SYSFS_DRIVERS_NAME, - USBIP_VHCI_DRV_NAME); + snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport); - sdriver = sysfs_open_driver_path(sdriver_path); - if (!sdriver) { - dbg("sysfs_open_driver_path failed: %s", sdriver_path); - dbg("make sure " USBIP_CORE_MOD_NAME ".ko and " - USBIP_VHCI_DRV_NAME ".ko are loaded!"); + file = fopen(path, "r"); + if (!file) { + err("fopen"); + free(buffer); return -1; } - hc_devs = sysfs_get_driver_devices(sdriver); - if (!hc_devs) { - dbg("sysfs_get_driver failed"); - goto err; + if (fgets(buffer, buffer_len, file) == NULL) { + err("fgets"); + free(buffer); + fclose(file); + return -1; } - - /* assume only one vhci_hcd */ - dlist_for_each_data(hc_devs, hc_dev, struct sysfs_device) { - strncpy(hc_busid, hc_dev->bus_id, SYSFS_BUS_ID_SIZE); - found = 1; + fclose(file); + + /* validate the length of each of the 3 parts */ + start = buffer; + for (part = 0; part < 3; part++) { + end = strchr(start, delim[part]); + if (end == NULL || (end - start) > max_len[part]) { + free(buffer); + return -1; + } + start = end + 1; } -err: - sysfs_close_driver(sdriver); + if (sscanf(buffer, "%s %s %s\n", host, port, busid) != 3) { + err("sscanf"); + free(buffer); + return -1; + } - if (found) - return 0; + free(buffer); - dbg("%s not found", hc_busid); - return -1; + return 0; } - /* ---------------------------------------------------------------------- */ int usbip_vhci_driver_open(void) { - int ret; - char hc_busid[SYSFS_BUS_ID_SIZE]; - - vhci_driver = (struct usbip_vhci_driver *) calloc(1, sizeof(*vhci_driver)); - if (!vhci_driver) { - dbg("calloc failed"); + udev_context = udev_new(); + if (!udev_context) { + err("udev_new failed"); return -1; } - ret = sysfs_get_mnt_path(vhci_driver->sysfs_mntpath, SYSFS_PATH_MAX); - if (ret < 0) { - dbg("sysfs_get_mnt_path failed"); - goto err; - } - - ret = get_hc_busid(vhci_driver->sysfs_mntpath, hc_busid); - if (ret < 0) - goto err; + vhci_driver = calloc(1, sizeof(struct usbip_vhci_driver)); /* will be freed in usbip_driver_close() */ - vhci_driver->hc_device = sysfs_open_device(USBIP_VHCI_BUS_TYPE, - hc_busid); + vhci_driver->hc_device = + udev_device_new_from_subsystem_sysname(udev_context, + USBIP_VHCI_BUS_TYPE, + USBIP_VHCI_DRV_NAME); if (!vhci_driver->hc_device) { - dbg("sysfs_open_device failed"); + err("udev_device_new_from_subsystem_sysname failed"); goto err; } @@ -373,85 +241,48 @@ int usbip_vhci_driver_open(void) dbg("available ports: %d", vhci_driver->nports); - vhci_driver->cdev_list = dlist_new(sizeof(struct usbip_class_device)); - if (!vhci_driver->cdev_list) - goto err; - - if (refresh_class_device_list()) - goto err; - if (refresh_imported_device_list()) goto err; - return 0; - err: - if (vhci_driver->cdev_list) - dlist_destroy(vhci_driver->cdev_list); - if (vhci_driver->hc_device) - sysfs_close_device(vhci_driver->hc_device); + udev_device_unref(vhci_driver->hc_device); + if (vhci_driver) free(vhci_driver); vhci_driver = NULL; + + udev_unref(udev_context); + return -1; } -void usbip_vhci_driver_close() +void usbip_vhci_driver_close(void) { if (!vhci_driver) return; - if (vhci_driver->cdev_list) - dlist_destroy(vhci_driver->cdev_list); - - for (int i = 0; i < vhci_driver->nports; i++) { - if (vhci_driver->idev[i].cdev_list) - dlist_destroy(vhci_driver->idev[i].cdev_list); - } + udev_device_unref(vhci_driver->hc_device); - if (vhci_driver->hc_device) - sysfs_close_device(vhci_driver->hc_device); free(vhci_driver); vhci_driver = NULL; + + udev_unref(udev_context); } int usbip_vhci_refresh_device_list(void) { - if (vhci_driver->cdev_list) - dlist_destroy(vhci_driver->cdev_list); - - - for (int i = 0; i < vhci_driver->nports; i++) { - if (vhci_driver->idev[i].cdev_list) - dlist_destroy(vhci_driver->idev[i].cdev_list); - } - - vhci_driver->cdev_list = dlist_new(sizeof(struct usbip_class_device)); - if (!vhci_driver->cdev_list) - goto err; - - if (refresh_class_device_list()) - goto err; if (refresh_imported_device_list()) goto err; return 0; err: - if (vhci_driver->cdev_list) - dlist_destroy(vhci_driver->cdev_list); - - for (int i = 0; i < vhci_driver->nports; i++) { - if (vhci_driver->idev[i].cdev_list) - dlist_destroy(vhci_driver->idev[i].cdev_list); - } - dbg("failed to refresh device list"); return -1; } @@ -469,24 +300,24 @@ int usbip_vhci_get_free_port(void) int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid, uint32_t speed) { - struct sysfs_attribute *attr_attach; char buff[200]; /* what size should be ? */ + char attach_attr_path[SYSFS_PATH_MAX]; + char attr_attach[] = "attach"; + const char *path; int ret; - attr_attach = sysfs_get_device_attr(vhci_driver->hc_device, "attach"); - if (!attr_attach) { - dbg("sysfs_get_device_attr(\"attach\") failed: %s", - vhci_driver->hc_device->name); - return -1; - } - - snprintf(buff, sizeof(buff), "%u %u %u %u", + snprintf(buff, sizeof(buff), "%u %d %u %u", port, sockfd, devid, speed); dbg("writing: %s", buff); - ret = sysfs_write_attribute(attr_attach, buff, strlen(buff)); + path = udev_device_get_syspath(vhci_driver->hc_device); + snprintf(attach_attr_path, sizeof(attach_attr_path), "%s/%s", + path, attr_attach); + dbg("attach attribute path: %s", attach_attr_path); + + ret = write_sysfs_attribute(attach_attr_path, buff, strlen(buff)); if (ret < 0) { - dbg("sysfs_write_attribute failed"); + dbg("write_sysfs_attribute failed"); return -1; } @@ -511,23 +342,23 @@ int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum, int usbip_vhci_detach_device(uint8_t port) { - struct sysfs_attribute *attr_detach; + char detach_attr_path[SYSFS_PATH_MAX]; + char attr_detach[] = "detach"; char buff[200]; /* what size should be ? */ + const char *path; int ret; - attr_detach = sysfs_get_device_attr(vhci_driver->hc_device, "detach"); - if (!attr_detach) { - dbg("sysfs_get_device_attr(\"detach\") failed: %s", - vhci_driver->hc_device->name); - return -1; - } - snprintf(buff, sizeof(buff), "%u", port); dbg("writing: %s", buff); - ret = sysfs_write_attribute(attr_detach, buff, strlen(buff)); + path = udev_device_get_syspath(vhci_driver->hc_device); + snprintf(detach_attr_path, sizeof(detach_attr_path), "%s/%s", + path, attr_detach); + dbg("detach attribute path: %s", detach_attr_path); + + ret = write_sysfs_attribute(detach_attr_path, buff, strlen(buff)); if (ret < 0) { - dbg("sysfs_write_attribute failed"); + dbg("write_sysfs_attribute failed"); return -1; } @@ -535,3 +366,46 @@ int usbip_vhci_detach_device(uint8_t port) return 0; } + +int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev) +{ + char product_name[100]; + char host[NI_MAXHOST] = "unknown host"; + char serv[NI_MAXSERV] = "unknown port"; + char remote_busid[SYSFS_BUS_ID_SIZE]; + int ret; + int read_record_error = 0; + + if (idev->status == VDEV_ST_NULL || idev->status == VDEV_ST_NOTASSIGNED) + return 0; + + ret = read_record(idev->port, host, sizeof(host), serv, sizeof(serv), + remote_busid); + if (ret) { + err("read_record"); + read_record_error = 1; + } + + printf("Port %02d: <%s> at %s\n", idev->port, + usbip_status_string(idev->status), + usbip_speed_string(idev->udev.speed)); + + usbip_names_get_product(product_name, sizeof(product_name), + idev->udev.idVendor, idev->udev.idProduct); + + printf(" %s\n", product_name); + + if (!read_record_error) { + printf("%10s -> usbip://%s:%s/%s\n", idev->udev.busid, + host, serv, remote_busid); + printf("%10s -> remote bus/dev %03d/%03d\n", " ", + idev->busnum, idev->devnum); + } else { + printf("%10s -> unknown host, remote port and remote busid\n", + idev->udev.busid); + printf("%10s -> remote bus/dev %03d/%03d\n", " ", + idev->busnum, idev->devnum); + } + + return 0; +} diff --git a/drivers/staging/usbip/userspace/libsrc/vhci_driver.h b/drivers/staging/usbip/userspace/libsrc/vhci_driver.h index 89949aa7c31..fa2316cf2ca 100644 --- a/drivers/staging/usbip/userspace/libsrc/vhci_driver.h +++ b/drivers/staging/usbip/userspace/libsrc/vhci_driver.h @@ -5,7 +5,7 @@ #ifndef __VHCI_DRIVER_H #define __VHCI_DRIVER_H -#include <sysfs/libsysfs.h> +#include <libudev.h> #include <stdint.h> #include "usbip_common.h" @@ -13,11 +13,6 @@ #define USBIP_VHCI_BUS_TYPE "platform" #define MAXNPORT 128 -struct usbip_class_device { - char class_path[SYSFS_PATH_MAX]; - char dev_path[SYSFS_PATH_MAX]; -}; - struct usbip_imported_device { uint8_t port; uint32_t status; @@ -28,18 +23,13 @@ struct usbip_imported_device { uint8_t devnum; /* usbip_class_device list */ - struct dlist *cdev_list; struct usbip_usb_device udev; }; struct usbip_vhci_driver { - char sysfs_mntpath[SYSFS_PATH_MAX]; /* /sys/devices/platform/vhci_hcd */ - struct sysfs_device *hc_device; - - /* usbip_class_device list */ - struct dlist *cdev_list; + struct udev_device *hc_device; int nports; struct usbip_imported_device idev[MAXNPORT]; @@ -64,4 +54,6 @@ int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum, int usbip_vhci_detach_device(uint8_t port); +int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev); + #endif /* __VHCI_DRIVER_H */ diff --git a/drivers/staging/usbip/userspace/src/Makefile.am b/drivers/staging/usbip/userspace/src/Makefile.am index a1130036139..e81a4ebadef 100644 --- a/drivers/staging/usbip/userspace/src/Makefile.am +++ b/drivers/staging/usbip/userspace/src/Makefile.am @@ -6,7 +6,6 @@ sbin_PROGRAMS := usbip usbipd usbip_SOURCES := usbip.h utils.h usbip.c utils.c usbip_network.c \ usbip_attach.c usbip_detach.c usbip_list.c \ - usbip_bind.c usbip_unbind.c - + usbip_bind.c usbip_unbind.c usbip_port.c usbipd_SOURCES := usbip_network.h usbipd.c usbip_network.c diff --git a/drivers/staging/usbip/userspace/src/usbip.c b/drivers/staging/usbip/userspace/src/usbip.c index fff4b768e70..d7599d94352 100644 --- a/drivers/staging/usbip/userspace/src/usbip.c +++ b/drivers/staging/usbip/userspace/src/usbip.c @@ -26,6 +26,7 @@ #include <syslog.h> #include "usbip_common.h" +#include "usbip_network.h" #include "usbip.h" static int usbip_help(int argc, char *argv[]); @@ -34,7 +35,7 @@ static int usbip_version(int argc, char *argv[]); static const char usbip_version_string[] = PACKAGE_STRING; static const char usbip_usage_string[] = - "usbip [--debug] [--log] [version]\n" + "usbip [--debug] [--log] [--tcp-port PORT] [version]\n" " [help] <command> <args>\n"; static void usbip_usage(void) @@ -92,6 +93,12 @@ static const struct command cmds[] = { .help = "Unbind device from " USBIP_HOST_DRV_NAME ".ko", .usage = usbip_unbind_usage }, + { + .name = "port", + .fn = usbip_port_show, + .help = "Show imported USB devices", + .usage = NULL + }, { NULL, NULL, NULL, NULL } }; @@ -138,9 +145,10 @@ static int run_command(const struct command *cmd, int argc, char *argv[]) int main(int argc, char *argv[]) { static const struct option opts[] = { - { "debug", no_argument, NULL, 'd' }, - { "log", no_argument, NULL, 'l' }, - { NULL, 0, NULL, 0 } + { "debug", no_argument, NULL, 'd' }, + { "log", no_argument, NULL, 'l' }, + { "tcp-port", required_argument, NULL, 't' }, + { NULL, 0, NULL, 0 } }; char *cmd; @@ -150,7 +158,7 @@ int main(int argc, char *argv[]) usbip_use_stderr = 1; opterr = 0; for (;;) { - opt = getopt_long(argc, argv, "+d", opts, NULL); + opt = getopt_long(argc, argv, "+dlt:", opts, NULL); if (opt == -1) break; @@ -163,6 +171,9 @@ int main(int argc, char *argv[]) usbip_use_syslog = 1; openlog("", LOG_PID, LOG_USER); break; + case 't': + usbip_setup_port_number(optarg); + break; case '?': printf("usbip: invalid option\n"); default: diff --git a/drivers/staging/usbip/userspace/src/usbip.h b/drivers/staging/usbip/userspace/src/usbip.h index 14d4a475b68..84fe66a9d8a 100644 --- a/drivers/staging/usbip/userspace/src/usbip.h +++ b/drivers/staging/usbip/userspace/src/usbip.h @@ -29,6 +29,7 @@ int usbip_detach(int argc, char *argv[]); int usbip_list(int argc, char *argv[]); int usbip_bind(int argc, char *argv[]); int usbip_unbind(int argc, char *argv[]); +int usbip_port_show(int argc, char *argv[]); void usbip_attach_usage(void); void usbip_detach_usage(void); diff --git a/drivers/staging/usbip/userspace/src/usbip_attach.c b/drivers/staging/usbip/userspace/src/usbip_attach.c index 0ec16e54fb0..d58a14dfc09 100644 --- a/drivers/staging/usbip/userspace/src/usbip_attach.c +++ b/drivers/staging/usbip/userspace/src/usbip_attach.c @@ -17,7 +17,6 @@ */ #include <sys/stat.h> -#include <sysfs/libsysfs.h> #include <limits.h> #include <stdint.h> @@ -57,6 +56,7 @@ static int record_connection(char *host, char *port, char *busid, int rhport) /* if VHCI_STATE_PATH exists, then it better be a directory */ if (errno == EEXIST) { struct stat s; + ret = stat(VHCI_STATE_PATH, &s); if (ret < 0) return -1; @@ -144,7 +144,7 @@ static int query_import_device(int sockfd, char *busid) return -1; } - /* recieve a reply */ + /* receive a reply */ rc = usbip_net_recv_op_common(sockfd, &code); if (rc < 0) { err("recv op_common"); @@ -175,7 +175,7 @@ static int attach_device(char *host, char *busid) int rc; int rhport; - sockfd = usbip_net_tcp_connect(host, USBIP_PORT_STRING); + sockfd = usbip_net_tcp_connect(host, usbip_port_string); if (sockfd < 0) { err("tcp connect"); return -1; @@ -189,7 +189,7 @@ static int attach_device(char *host, char *busid) close(sockfd); - rc = record_connection(host, USBIP_PORT_STRING, busid, rhport); + rc = record_connection(host, usbip_port_string, busid, rhport); if (rc < 0) { err("record connection"); return -1; diff --git a/drivers/staging/usbip/userspace/src/usbip_bind.c b/drivers/staging/usbip/userspace/src/usbip_bind.c index 9ecaf6e574d..fa46141ae68 100644 --- a/drivers/staging/usbip/userspace/src/usbip_bind.c +++ b/drivers/staging/usbip/userspace/src/usbip_bind.c @@ -16,7 +16,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <sysfs/libsysfs.h> +#include <libudev.h> #include <errno.h> #include <stdio.h> @@ -28,6 +28,7 @@ #include "usbip_common.h" #include "utils.h" #include "usbip.h" +#include "sysfs_utils.h" enum unbind_status { UNBIND_ST_OK, @@ -48,167 +49,92 @@ void usbip_bind_usage(void) /* call at unbound state */ static int bind_usbip(char *busid) { - char bus_type[] = "usb"; char attr_name[] = "bind"; - char sysfs_mntpath[SYSFS_PATH_MAX]; char bind_attr_path[SYSFS_PATH_MAX]; - char intf_busid[SYSFS_BUS_ID_SIZE]; - struct sysfs_device *busid_dev; - struct sysfs_attribute *bind_attr; - struct sysfs_attribute *bConfValue; - struct sysfs_attribute *bNumIntfs; - int i, failed = 0; - int rc, ret = -1; - - rc = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX); - if (rc < 0) { - err("sysfs must be mounted: %s", strerror(errno)); - return -1; - } + int rc = -1; snprintf(bind_attr_path, sizeof(bind_attr_path), "%s/%s/%s/%s/%s/%s", - sysfs_mntpath, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME, - USBIP_HOST_DRV_NAME, attr_name); - - bind_attr = sysfs_open_attribute(bind_attr_path); - if (!bind_attr) { - dbg("problem getting bind attribute: %s", strerror(errno)); - return -1; - } + SYSFS_MNT_PATH, SYSFS_BUS_NAME, SYSFS_BUS_TYPE, + SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME, attr_name); - busid_dev = sysfs_open_device(bus_type, busid); - if (!busid_dev) { - dbg("sysfs_open_device %s failed: %s", busid, strerror(errno)); - goto err_close_bind_attr; - } - - bConfValue = sysfs_get_device_attr(busid_dev, "bConfigurationValue"); - bNumIntfs = sysfs_get_device_attr(busid_dev, "bNumInterfaces"); - - if (!bConfValue || !bNumIntfs) { - dbg("problem getting device attributes: %s", + rc = write_sysfs_attribute(bind_attr_path, busid, strlen(busid)); + if (rc < 0) { + err("error binding device %s to driver: %s", busid, strerror(errno)); - goto err_close_busid_dev; - } - - for (i = 0; i < atoi(bNumIntfs->value); i++) { - snprintf(intf_busid, SYSFS_BUS_ID_SIZE, "%s:%.1s.%d", busid, - bConfValue->value, i); - - rc = sysfs_write_attribute(bind_attr, intf_busid, - SYSFS_BUS_ID_SIZE); - if (rc < 0) { - dbg("bind driver at %s failed", intf_busid); - failed = 1; - } + return -1; } - if (!failed) - ret = 0; - -err_close_busid_dev: - sysfs_close_device(busid_dev); -err_close_bind_attr: - sysfs_close_attribute(bind_attr); - - return ret; + return 0; } /* buggy driver may cause dead lock */ static int unbind_other(char *busid) { - char bus_type[] = "usb"; - char intf_busid[SYSFS_BUS_ID_SIZE]; - struct sysfs_device *busid_dev; - struct sysfs_device *intf_dev; - struct sysfs_driver *intf_drv; - struct sysfs_attribute *unbind_attr; - struct sysfs_attribute *bConfValue; - struct sysfs_attribute *bDevClass; - struct sysfs_attribute *bNumIntfs; - int i, rc; enum unbind_status status = UNBIND_ST_OK; - busid_dev = sysfs_open_device(bus_type, busid); - if (!busid_dev) { - dbg("sysfs_open_device %s failed: %s", busid, strerror(errno)); - return -1; + char attr_name[] = "unbind"; + char unbind_attr_path[SYSFS_PATH_MAX]; + int rc = -1; + + struct udev *udev; + struct udev_device *dev; + const char *driver; + const char *bDevClass; + + /* Create libudev context. */ + udev = udev_new(); + + /* Get the device. */ + dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid); + if (!dev) { + dbg("unable to find device with bus ID %s", busid); + goto err_close_busid_dev; } - bConfValue = sysfs_get_device_attr(busid_dev, "bConfigurationValue"); - bDevClass = sysfs_get_device_attr(busid_dev, "bDeviceClass"); - bNumIntfs = sysfs_get_device_attr(busid_dev, "bNumInterfaces"); - if (!bConfValue || !bDevClass || !bNumIntfs) { - dbg("problem getting device attributes: %s", - strerror(errno)); + /* Check what kind of device it is. */ + bDevClass = udev_device_get_sysattr_value(dev, "bDeviceClass"); + if (!bDevClass) { + dbg("unable to get bDevClass device attribute"); goto err_close_busid_dev; } - if (!strncmp(bDevClass->value, "09", bDevClass->len)) { + if (!strncmp(bDevClass, "09", strlen(bDevClass))) { dbg("skip unbinding of hub"); goto err_close_busid_dev; } - for (i = 0; i < atoi(bNumIntfs->value); i++) { - snprintf(intf_busid, SYSFS_BUS_ID_SIZE, "%s:%.1s.%d", busid, - bConfValue->value, i); - intf_dev = sysfs_open_device(bus_type, intf_busid); - if (!intf_dev) { - dbg("could not open interface device: %s", - strerror(errno)); - goto err_close_busid_dev; - } - - dbg("%s -> %s", intf_dev->name, intf_dev->driver_name); - - if (!strncmp("unknown", intf_dev->driver_name, SYSFS_NAME_LEN)) - /* unbound interface */ - continue; - - if (!strncmp(USBIP_HOST_DRV_NAME, intf_dev->driver_name, - SYSFS_NAME_LEN)) { - /* already bound to usbip-host */ - status = UNBIND_ST_USBIP_HOST; - continue; - } - - /* unbinding */ - intf_drv = sysfs_open_driver(bus_type, intf_dev->driver_name); - if (!intf_drv) { - dbg("could not open interface driver on %s: %s", - intf_dev->name, strerror(errno)); - goto err_close_intf_dev; - } + /* Get the device driver. */ + driver = udev_device_get_driver(dev); + if (!driver) { + /* No driver bound to this device. */ + goto out; + } - unbind_attr = sysfs_get_driver_attr(intf_drv, "unbind"); - if (!unbind_attr) { - dbg("problem getting interface driver attribute: %s", - strerror(errno)); - goto err_close_intf_drv; - } + if (!strncmp(USBIP_HOST_DRV_NAME, driver, + strlen(USBIP_HOST_DRV_NAME))) { + /* Already bound to usbip-host. */ + status = UNBIND_ST_USBIP_HOST; + goto out; + } - rc = sysfs_write_attribute(unbind_attr, intf_dev->bus_id, - SYSFS_BUS_ID_SIZE); - if (rc < 0) { - /* NOTE: why keep unbinding other interfaces? */ - dbg("unbind driver at %s failed", intf_dev->bus_id); - status = UNBIND_ST_FAILED; - } + /* Unbind device from driver. */ + snprintf(unbind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s", + SYSFS_MNT_PATH, SYSFS_BUS_NAME, SYSFS_BUS_TYPE, + SYSFS_DRIVERS_NAME, driver, attr_name); - sysfs_close_driver(intf_drv); - sysfs_close_device(intf_dev); + rc = write_sysfs_attribute(unbind_attr_path, busid, strlen(busid)); + if (rc < 0) { + err("error unbinding device %s from driver", busid); + goto err_close_busid_dev; } goto out; -err_close_intf_drv: - sysfs_close_driver(intf_drv); -err_close_intf_dev: - sysfs_close_device(intf_dev); err_close_busid_dev: status = UNBIND_ST_FAILED; out: - sysfs_close_device(busid_dev); + udev_device_unref(dev); + udev_unref(udev); return status; } @@ -216,6 +142,17 @@ out: static int bind_device(char *busid) { int rc; + struct udev *udev; + struct udev_device *dev; + + /* Check whether the device with this bus ID exists. */ + udev = udev_new(); + dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid); + if (!dev) { + err("device with the specified bus ID does not exist"); + return -1; + } + udev_unref(udev); rc = unbind_other(busid); if (rc == UNBIND_ST_FAILED) { @@ -240,7 +177,7 @@ static int bind_device(char *busid) return -1; } - printf("bind device on busid %s: complete\n", busid); + info("bind device on busid %s: complete", busid); return 0; } diff --git a/drivers/staging/usbip/userspace/src/usbip_detach.c b/drivers/staging/usbip/userspace/src/usbip_detach.c index 13308df613a..05c6d15856e 100644 --- a/drivers/staging/usbip/userspace/src/usbip_detach.c +++ b/drivers/staging/usbip/userspace/src/usbip_detach.c @@ -16,8 +16,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <sysfs/libsysfs.h> - #include <ctype.h> #include <limits.h> #include <stdint.h> diff --git a/drivers/staging/usbip/userspace/src/usbip_list.c b/drivers/staging/usbip/userspace/src/usbip_list.c index ff56255f497..d5ce34a410e 100644 --- a/drivers/staging/usbip/userspace/src/usbip_list.c +++ b/drivers/staging/usbip/userspace/src/usbip_list.c @@ -17,7 +17,7 @@ */ #include <sys/types.h> -#include <sysfs/libsysfs.h> +#include <libudev.h> #include <errno.h> #include <stdbool.h> @@ -54,7 +54,7 @@ static int get_exported_devices(char *host, int sockfd) struct usbip_usb_device udev; struct usbip_usb_interface uintf; unsigned int i; - int j, rc; + int rc, j; rc = usbip_net_send_op_common(sockfd, OP_REQ_DEVLIST, 0); if (rc < 0) { @@ -107,19 +107,20 @@ static int get_exported_devices(char *host, int sockfd) for (j = 0; j < udev.bNumInterfaces; j++) { rc = usbip_net_recv(sockfd, &uintf, sizeof(uintf)); if (rc < 0) { - dbg("usbip_net_recv failed: usbip_usb_intf[%d]", - j); + err("usbip_net_recv failed: usbip_usb_intf[%d]", + j); return -1; } usbip_net_pack_usb_interface(0, &uintf); usbip_names_get_class(class_name, sizeof(class_name), - uintf.bInterfaceClass, - uintf.bInterfaceSubClass, - uintf.bInterfaceProtocol); + uintf.bInterfaceClass, + uintf.bInterfaceSubClass, + uintf.bInterfaceProtocol); printf("%11s: %2d - %s\n", "", j, class_name); } + printf("\n"); } @@ -131,13 +132,13 @@ static int list_exported_devices(char *host) int rc; int sockfd; - sockfd = usbip_net_tcp_connect(host, USBIP_PORT_STRING); + sockfd = usbip_net_tcp_connect(host, usbip_port_string); if (sockfd < 0) { err("could not connect to %s:%s: %s", host, - USBIP_PORT_STRING, gai_strerror(sockfd)); + usbip_port_string, gai_strerror(sockfd)); return -1; } - dbg("connected to %s:%s", host, USBIP_PORT_STRING); + dbg("connected to %s:%s", host, usbip_port_string); rc = get_exported_devices(host, sockfd); if (rc < 0) { @@ -150,8 +151,8 @@ static int list_exported_devices(char *host) return 0; } -static void print_device(char *busid, char *vendor, char *product, - bool parsable) +static void print_device(const char *busid, const char *vendor, + const char *product, bool parsable) { if (parsable) printf("busid=%s#usbid=%.4s:%.4s#", busid, vendor, product); @@ -165,106 +166,73 @@ static void print_product_name(char *product_name, bool parsable) printf(" %s\n", product_name); } -static void print_interface(char *busid, char *driver, bool parsable) -{ - if (parsable) - printf("%s=%s#", busid, driver); - else - printf("%9s%s -> %s\n", "", busid, driver); -} - -static int is_device(void *x) -{ - struct sysfs_attribute *devpath; - struct sysfs_device *dev = x; - int ret = 0; - - devpath = sysfs_get_device_attr(dev, "devpath"); - if (devpath && *devpath->value != '0') - ret = 1; - - return ret; -} - -static int devcmp(void *a, void *b) -{ - return strcmp(a, b); -} - static int list_devices(bool parsable) { - char bus_type[] = "usb"; - char busid[SYSFS_BUS_ID_SIZE]; + struct udev *udev; + struct udev_enumerate *enumerate; + struct udev_list_entry *devices, *dev_list_entry; + struct udev_device *dev; + const char *path; + const char *idVendor; + const char *idProduct; + const char *bConfValue; + const char *bNumIntfs; + const char *busid; char product_name[128]; - struct sysfs_bus *ubus; - struct sysfs_device *dev; - struct sysfs_device *intf; - struct sysfs_attribute *idVendor; - struct sysfs_attribute *idProduct; - struct sysfs_attribute *bConfValue; - struct sysfs_attribute *bNumIntfs; - struct dlist *devlist; - int i; int ret = -1; - ubus = sysfs_open_bus(bus_type); - if (!ubus) { - err("could not open %s bus: %s", bus_type, strerror(errno)); - return -1; - } - - devlist = sysfs_get_bus_devices(ubus); - if (!devlist) { - err("could not get %s bus devices: %s", bus_type, - strerror(errno)); - goto err_out; - } - - /* remove interfaces and root hubs from device list */ - dlist_filter_sort(devlist, is_device, devcmp); - - if (!parsable) { - printf("Local USB devices\n"); - printf("=================\n"); - } - dlist_for_each_data(devlist, dev, struct sysfs_device) { - idVendor = sysfs_get_device_attr(dev, "idVendor"); - idProduct = sysfs_get_device_attr(dev, "idProduct"); - bConfValue = sysfs_get_device_attr(dev, "bConfigurationValue"); - bNumIntfs = sysfs_get_device_attr(dev, "bNumInterfaces"); + /* Create libudev context. */ + udev = udev_new(); + + /* Create libudev device enumeration. */ + enumerate = udev_enumerate_new(udev); + + /* Take only USB devices that are not hubs and do not have + * the bInterfaceNumber attribute, i.e. are not interfaces. + */ + udev_enumerate_add_match_subsystem(enumerate, "usb"); + udev_enumerate_add_nomatch_sysattr(enumerate, "bDeviceClass", "09"); + udev_enumerate_add_nomatch_sysattr(enumerate, "bInterfaceNumber", NULL); + udev_enumerate_scan_devices(enumerate); + + devices = udev_enumerate_get_list_entry(enumerate); + + /* Show information about each device. */ + udev_list_entry_foreach(dev_list_entry, devices) { + path = udev_list_entry_get_name(dev_list_entry); + dev = udev_device_new_from_syspath(udev, path); + + /* Get device information. */ + idVendor = udev_device_get_sysattr_value(dev, "idVendor"); + idProduct = udev_device_get_sysattr_value(dev, "idProduct"); + bConfValue = udev_device_get_sysattr_value(dev, "bConfigurationValue"); + bNumIntfs = udev_device_get_sysattr_value(dev, "bNumInterfaces"); + busid = udev_device_get_sysname(dev); if (!idVendor || !idProduct || !bConfValue || !bNumIntfs) { err("problem getting device attributes: %s", strerror(errno)); goto err_out; } - /* get product name */ + /* Get product name. */ usbip_names_get_product(product_name, sizeof(product_name), - strtol(idVendor->value, NULL, 16), - strtol(idProduct->value, NULL, 16)); - print_device(dev->bus_id, idVendor->value, idProduct->value, - parsable); + strtol(idVendor, NULL, 16), + strtol(idProduct, NULL, 16)); + + /* Print information. */ + print_device(busid, idVendor, idProduct, parsable); print_product_name(product_name, parsable); - for (i = 0; i < atoi(bNumIntfs->value); i++) { - snprintf(busid, sizeof(busid), "%s:%.1s.%d", - dev->bus_id, bConfValue->value, i); - intf = sysfs_open_device(bus_type, busid); - if (!intf) { - err("could not open device interface: %s", - strerror(errno)); - goto err_out; - } - print_interface(busid, intf->driver_name, parsable); - sysfs_close_device(intf); - } printf("\n"); + + udev_device_unref(dev); } ret = 0; err_out: - sysfs_close_bus(ubus); + udev_enumerate_unref(enumerate); + udev_unref(udev); return ret; } diff --git a/drivers/staging/usbip/userspace/src/usbip_network.c b/drivers/staging/usbip/userspace/src/usbip_network.c index b12448ec69a..b4c37e76a6e 100644 --- a/drivers/staging/usbip/userspace/src/usbip_network.c +++ b/drivers/staging/usbip/userspace/src/usbip_network.c @@ -25,9 +25,43 @@ #include <netinet/tcp.h> #include <unistd.h> +#ifdef HAVE_LIBWRAP +#include <tcpd.h> +#endif + #include "usbip_common.h" #include "usbip_network.h" +int usbip_port = 3240; +char *usbip_port_string = "3240"; + +void usbip_setup_port_number(char *arg) +{ + dbg("parsing port arg '%s'", arg); + char *end; + unsigned long int port = strtoul(arg, &end, 10); + + if (end == arg) { + err("port: could not parse '%s' as a decimal integer", arg); + return; + } + + if (*end != '\0') { + err("port: garbage at end of '%s'", arg); + return; + } + + if (port > UINT16_MAX) { + err("port: %s too high (max=%d)", + arg, UINT16_MAX); + return; + } + + usbip_port = port; + usbip_port_string = arg; + info("using port %d (\"%s\")", usbip_port, usbip_port_string); +} + void usbip_net_pack_uint32_t(int pack, uint32_t *num) { uint32_t i; @@ -209,6 +243,18 @@ int usbip_net_set_keepalive(int sockfd) return ret; } +int usbip_net_set_v6only(int sockfd) +{ + const int val = 1; + int ret; + + ret = setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)); + if (ret < 0) + dbg("setsockopt: IPV6_V6ONLY"); + + return ret; +} + /* * IPv6 Ready */ diff --git a/drivers/staging/usbip/userspace/src/usbip_network.h b/drivers/staging/usbip/userspace/src/usbip_network.h index 1bbefc993fb..c1e875cf107 100644 --- a/drivers/staging/usbip/userspace/src/usbip_network.h +++ b/drivers/staging/usbip/userspace/src/usbip_network.h @@ -10,12 +10,12 @@ #endif #include <sys/types.h> -#include <sysfs/libsysfs.h> #include <stdint.h> -#define USBIP_PORT 3240 -#define USBIP_PORT_STRING "3240" +extern int usbip_port; +extern char *usbip_port_string; +void usbip_setup_port_number(char *arg); /* ---------------------------------------------------------------------- */ /* Common header for all the kinds of PDUs. */ @@ -179,6 +179,7 @@ int usbip_net_recv_op_common(int sockfd, uint16_t *code); int usbip_net_set_reuseaddr(int sockfd); int usbip_net_set_nodelay(int sockfd); int usbip_net_set_keepalive(int sockfd); +int usbip_net_set_v6only(int sockfd); int usbip_net_tcp_connect(char *hostname, char *port); #endif /* __USBIP_NETWORK_H */ diff --git a/drivers/staging/usbip/userspace/src/usbip_port.c b/drivers/staging/usbip/userspace/src/usbip_port.c new file mode 100644 index 00000000000..a2e884fd922 --- /dev/null +++ b/drivers/staging/usbip/userspace/src/usbip_port.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> + * 2005-2007 Takahiro Hirofuchi + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "vhci_driver.h" +#include "usbip_common.h" + +static int list_imported_devices(void) +{ + int i; + struct usbip_imported_device *idev; + int ret; + + ret = usbip_vhci_driver_open(); + if (ret < 0) { + err("open vhci_driver"); + return -1; + } + + printf("Imported USB devices\n"); + printf("====================\n"); + + for (i = 0; i < vhci_driver->nports; i++) { + idev = &vhci_driver->idev[i]; + + if (usbip_vhci_imported_device_dump(idev) < 0) + ret = -1; + } + + usbip_vhci_driver_close(); + + return ret; + +} + +int usbip_port_show(__attribute__((unused)) int argc, + __attribute__((unused)) char *argv[]) +{ + int ret; + + ret = list_imported_devices(); + if (ret < 0) + err("list imported devices"); + + return ret; +} diff --git a/drivers/staging/usbip/userspace/src/usbip_unbind.c b/drivers/staging/usbip/userspace/src/usbip_unbind.c index d5a9ab6af2a..a4a496c9cba 100644 --- a/drivers/staging/usbip/userspace/src/usbip_unbind.c +++ b/drivers/staging/usbip/userspace/src/usbip_unbind.c @@ -16,7 +16,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <sysfs/libsysfs.h> +#include <libudev.h> #include <errno.h> #include <stdio.h> @@ -27,6 +27,7 @@ #include "usbip_common.h" #include "utils.h" #include "usbip.h" +#include "sysfs_utils.h" static const char usbip_unbind_usage_string[] = "usbip unbind <args>\n" @@ -41,115 +42,69 @@ void usbip_unbind_usage(void) static int unbind_device(char *busid) { char bus_type[] = "usb"; - struct sysfs_driver *usbip_host_drv; - struct sysfs_device *dev; - struct dlist *devlist; - int verified = 0; int rc, ret = -1; - char attr_name[] = "bConfigurationValue"; - char sysfs_mntpath[SYSFS_PATH_MAX]; - char busid_attr_path[SYSFS_PATH_MAX]; - struct sysfs_attribute *busid_attr; - char *val = NULL; - int len; - - /* verify the busid device is using usbip-host */ - usbip_host_drv = sysfs_open_driver(bus_type, USBIP_HOST_DRV_NAME); - if (!usbip_host_drv) { - err("could not open %s driver: %s", USBIP_HOST_DRV_NAME, - strerror(errno)); - return -1; - } + char unbind_attr_name[] = "unbind"; + char unbind_attr_path[SYSFS_PATH_MAX]; + char rebind_attr_name[] = "rebind"; + char rebind_attr_path[SYSFS_PATH_MAX]; - devlist = sysfs_get_driver_devices(usbip_host_drv); - if (!devlist) { - err("%s is not in use by any devices", USBIP_HOST_DRV_NAME); - goto err_close_usbip_host_drv; - } + struct udev *udev; + struct udev_device *dev; + const char *driver; - dlist_for_each_data(devlist, dev, struct sysfs_device) { - if (!strncmp(busid, dev->name, strlen(busid)) && - !strncmp(dev->driver_name, USBIP_HOST_DRV_NAME, - strlen(USBIP_HOST_DRV_NAME))) { - verified = 1; - break; - } - } + /* Create libudev context. */ + udev = udev_new(); - if (!verified) { - err("device on busid %s is not using %s", busid, - USBIP_HOST_DRV_NAME); - goto err_close_usbip_host_drv; + /* Check whether the device with this bus ID exists. */ + dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid); + if (!dev) { + err("device with the specified bus ID does not exist"); + goto err_close_udev; } - /* - * NOTE: A read and write of an attribute value of the device busid - * refers to must be done to start probing. That way a rebind of the - * default driver for the device occurs. - * - * This seems very hackish and adds a lot of pointless code. I think it - * should be done in the kernel by the driver after del_match_busid is - * finished! - */ - - rc = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX); - if (rc < 0) { - err("sysfs must be mounted: %s", strerror(errno)); - return -1; + /* Check whether the device is using usbip-host driver. */ + driver = udev_device_get_driver(dev); + if (!driver || strcmp(driver, "usbip-host")) { + err("device is not bound to usbip-host driver"); + goto err_close_udev; } - snprintf(busid_attr_path, sizeof(busid_attr_path), "%s/%s/%s/%s/%s/%s", - sysfs_mntpath, SYSFS_BUS_NAME, bus_type, SYSFS_DEVICES_NAME, - busid, attr_name); + /* Unbind device from driver. */ + snprintf(unbind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s", + SYSFS_MNT_PATH, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME, + USBIP_HOST_DRV_NAME, unbind_attr_name); - /* read a device attribute */ - busid_attr = sysfs_open_attribute(busid_attr_path); - if (!busid_attr) { - err("could not open %s/%s: %s", busid, attr_name, - strerror(errno)); - return -1; - } - - if (sysfs_read_attribute(busid_attr) < 0) { - err("problem reading attribute: %s", strerror(errno)); - goto err_out; + rc = write_sysfs_attribute(unbind_attr_path, busid, strlen(busid)); + if (rc < 0) { + err("error unbinding device %s from driver", busid); + goto err_close_udev; } - len = busid_attr->len; - val = malloc(len); - *val = *busid_attr->value; - sysfs_close_attribute(busid_attr); - - /* notify driver of unbind */ + /* Notify driver of unbind. */ rc = modify_match_busid(busid, 0); if (rc < 0) { err("unable to unbind device on %s", busid); - goto err_out; + goto err_close_udev; } - /* write the device attribute */ - busid_attr = sysfs_open_attribute(busid_attr_path); - if (!busid_attr) { - err("could not open %s/%s: %s", busid, attr_name, - strerror(errno)); - return -1; - } + /* Trigger new probing. */ + snprintf(rebind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s", + SYSFS_MNT_PATH, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME, + USBIP_HOST_DRV_NAME, rebind_attr_name); - rc = sysfs_write_attribute(busid_attr, val, len); + rc = write_sysfs_attribute(rebind_attr_path, busid, strlen(busid)); if (rc < 0) { - err("problem writing attribute: %s", strerror(errno)); - goto err_out; + err("error rebinding"); + goto err_close_udev; } - sysfs_close_attribute(busid_attr); ret = 0; - printf("unbind device on busid %s: complete\n", busid); + info("unbind device on busid %s: complete", busid); -err_out: - free(val); -err_close_usbip_host_drv: - sysfs_close_driver(usbip_host_drv); +err_close_udev: + udev_device_unref(dev); + udev_unref(udev); return ret; } diff --git a/drivers/staging/usbip/userspace/src/usbipd.c b/drivers/staging/usbip/userspace/src/usbipd.c index 3e913b861dc..2f87f2d348b 100644 --- a/drivers/staging/usbip/userspace/src/usbipd.c +++ b/drivers/staging/usbip/userspace/src/usbipd.c @@ -43,6 +43,7 @@ #include "usbip_host_driver.h" #include "usbip_common.h" #include "usbip_network.h" +#include "list.h" #undef PROGNAME #define PROGNAME "usbipd" @@ -50,21 +51,37 @@ #define MAIN_LOOP_TIMEOUT 10 +#define DEFAULT_PID_FILE "/var/run/" PROGNAME ".pid" + static const char usbip_version_string[] = PACKAGE_STRING; static const char usbipd_help_string[] = - "usage: usbipd [options] \n" - " -D, --daemon \n" - " Run as a daemon process. \n" - " \n" - " -d, --debug \n" - " Print debugging information. \n" - " \n" - " -h, --help \n" - " Print this help. \n" - " \n" - " -v, --version \n" - " Show version. \n"; + "usage: usbipd [options]\n" + "\n" + " -4, --ipv4\n" + " Bind to IPv4. Default is both.\n" + "\n" + " -6, --ipv6\n" + " Bind to IPv6. Default is both.\n" + "\n" + " -D, --daemon\n" + " Run as a daemon process.\n" + "\n" + " -d, --debug\n" + " Print debugging information.\n" + "\n" + " -PFILE, --pid FILE\n" + " Write process id to FILE.\n" + " If no FILE specified, use " DEFAULT_PID_FILE "\n" + "\n" + " -tPORT, --tcp-port PORT\n" + " Listen on TCP/IP port PORT.\n" + "\n" + " -h, --help\n" + " Print this help.\n" + "\n" + " -v, --version\n" + " Show version.\n"; static void usbipd_help(void) { @@ -77,6 +94,7 @@ static int recv_request_import(int sockfd) struct op_common reply; struct usbip_exported_device *edev; struct usbip_usb_device pdu_udev; + struct list_head *i; int found = 0; int error = 0; int rc; @@ -91,8 +109,8 @@ static int recv_request_import(int sockfd) } PACK_OP_IMPORT_REQUEST(0, &req); - dlist_for_each_data(host_driver->edev_list, edev, - struct usbip_exported_device) { + list_for_each(i, &host_driver->edev_list) { + edev = list_entry(i, struct usbip_exported_device, node); if (!strncmp(req.busid, edev->udev.busid, SYSFS_BUS_ID_SIZE)) { info("found requested device: %s", req.busid); found = 1; @@ -145,13 +163,12 @@ static int send_reply_devlist(int connfd) struct usbip_usb_device pdu_udev; struct usbip_usb_interface pdu_uinf; struct op_devlist_reply reply; - int i; - int rc; + struct list_head *j; + int rc, i; reply.ndev = 0; /* number of exported devices */ - dlist_for_each_data(host_driver->edev_list, edev, - struct usbip_exported_device) { + list_for_each(j, &host_driver->edev_list) { reply.ndev += 1; } info("exportable devices: %d", reply.ndev); @@ -169,8 +186,8 @@ static int send_reply_devlist(int connfd) return -1; } - dlist_for_each_data(host_driver->edev_list, edev, - struct usbip_exported_device) { + list_for_each(j, &host_driver->edev_list) { + edev = list_entry(j, struct usbip_exported_device, node); dump_usb_device(&edev->udev); memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev)); usbip_net_pack_usb_device(1, &pdu_udev); @@ -187,9 +204,9 @@ static int send_reply_devlist(int connfd) usbip_net_pack_usb_interface(1, &pdu_uinf); rc = usbip_net_send(connfd, &pdu_uinf, - sizeof(pdu_uinf)); + sizeof(pdu_uinf)); if (rc < 0) { - dbg("usbip_net_send failed: pdu_uinf"); + err("usbip_net_send failed: pdu_uinf"); return -1; } } @@ -286,13 +303,13 @@ static int do_accept(int listenfd) memset(&ss, 0, sizeof(ss)); - connfd = accept(listenfd, (struct sockaddr *) &ss, &len); + connfd = accept(listenfd, (struct sockaddr *)&ss, &len); if (connfd < 0) { err("failed to accept connection"); return -1; } - rc = getnameinfo((struct sockaddr *) &ss, len, host, sizeof(host), + rc = getnameinfo((struct sockaddr *)&ss, len, host, sizeof(host), port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV); if (rc) err("getnameinfo: %s", gai_strerror(rc)); @@ -328,63 +345,76 @@ int process_request(int listenfd) return 0; } -static void log_addrinfo(struct addrinfo *ai) +static void addrinfo_to_text(struct addrinfo *ai, char buf[], + const size_t buf_size) { char hbuf[NI_MAXHOST]; char sbuf[NI_MAXSERV]; int rc; + buf[0] = '\0'; + rc = getnameinfo(ai->ai_addr, ai->ai_addrlen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV); if (rc) err("getnameinfo: %s", gai_strerror(rc)); - info("listening on %s:%s", hbuf, sbuf); + snprintf(buf, buf_size, "%s:%s", hbuf, sbuf); } -static int listen_all_addrinfo(struct addrinfo *ai_head, int sockfdlist[]) +static int listen_all_addrinfo(struct addrinfo *ai_head, int sockfdlist[], + int maxsockfd) { struct addrinfo *ai; int ret, nsockfd = 0; - - for (ai = ai_head; ai && nsockfd < MAXSOCKFD; ai = ai->ai_next) { - sockfdlist[nsockfd] = socket(ai->ai_family, ai->ai_socktype, - ai->ai_protocol); - if (sockfdlist[nsockfd] < 0) + const size_t ai_buf_size = NI_MAXHOST + NI_MAXSERV + 2; + char ai_buf[ai_buf_size]; + + for (ai = ai_head; ai && nsockfd < maxsockfd; ai = ai->ai_next) { + int sock; + + addrinfo_to_text(ai, ai_buf, ai_buf_size); + dbg("opening %s", ai_buf); + sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (sock < 0) { + err("socket: %s: %d (%s)", + ai_buf, errno, strerror(errno)); continue; + } - usbip_net_set_reuseaddr(sockfdlist[nsockfd]); - usbip_net_set_nodelay(sockfdlist[nsockfd]); + usbip_net_set_reuseaddr(sock); + usbip_net_set_nodelay(sock); + /* We use seperate sockets for IPv4 and IPv6 + * (see do_standalone_mode()) */ + usbip_net_set_v6only(sock); - if (sockfdlist[nsockfd] >= FD_SETSIZE) { - close(sockfdlist[nsockfd]); - sockfdlist[nsockfd] = -1; + if (sock >= FD_SETSIZE) { + err("FD_SETSIZE: %s: sock=%d, max=%d", + ai_buf, sock, FD_SETSIZE); + close(sock); continue; } - ret = bind(sockfdlist[nsockfd], ai->ai_addr, ai->ai_addrlen); + ret = bind(sock, ai->ai_addr, ai->ai_addrlen); if (ret < 0) { - close(sockfdlist[nsockfd]); - sockfdlist[nsockfd] = -1; + err("bind: %s: %d (%s)", + ai_buf, errno, strerror(errno)); + close(sock); continue; } - ret = listen(sockfdlist[nsockfd], SOMAXCONN); + ret = listen(sock, SOMAXCONN); if (ret < 0) { - close(sockfdlist[nsockfd]); - sockfdlist[nsockfd] = -1; + err("listen: %s: %d (%s)", + ai_buf, errno, strerror(errno)); + close(sock); continue; } - log_addrinfo(ai); - nsockfd++; + info("listening on %s", ai_buf); + sockfdlist[nsockfd++] = sock; } - if (nsockfd == 0) - return -1; - - dbg("listening on %d address%s", nsockfd, (nsockfd == 1) ? "" : "es"); - return nsockfd; } @@ -398,9 +428,9 @@ static struct addrinfo *do_getaddrinfo(char *host, int ai_family) hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; - rc = getaddrinfo(host, USBIP_PORT_STRING, &hints, &ai_head); + rc = getaddrinfo(host, usbip_port_string, &hints, &ai_head); if (rc) { - err("failed to get a network address %s: %s", USBIP_PORT_STRING, + err("failed to get a network address %s: %s", usbip_port_string, gai_strerror(rc)); return NULL; } @@ -426,11 +456,38 @@ static void set_signal(void) sigaction(SIGCLD, &act, NULL); } -static int do_standalone_mode(int daemonize) +static const char *pid_file; + +static void write_pid_file(void) +{ + if (pid_file) { + dbg("creating pid file %s", pid_file); + FILE *fp; + + fp = fopen(pid_file, "w"); + if (!fp) { + err("pid_file: %s: %d (%s)", + pid_file, errno, strerror(errno)); + return; + } + fprintf(fp, "%d\n", getpid()); + fclose(fp); + } +} + +static void remove_pid_file(void) +{ + if (pid_file) { + dbg("removing pid file %s", pid_file); + unlink(pid_file); + } +} + +static int do_standalone_mode(int daemonize, int ipv4, int ipv6) { struct addrinfo *ai_head; int sockfdlist[MAXSOCKFD]; - int nsockfd; + int nsockfd, family; int i, terminate; struct pollfd *fds; struct timespec timeout; @@ -452,22 +509,38 @@ static int do_standalone_mode(int daemonize) usbip_use_syslog = 1; } set_signal(); + write_pid_file(); - ai_head = do_getaddrinfo(NULL, PF_UNSPEC); + info("starting " PROGNAME " (%s)", usbip_version_string); + + /* + * To suppress warnings on systems with bindv6only disabled + * (default), we use seperate sockets for IPv6 and IPv4 and set + * IPV6_V6ONLY on the IPv6 sockets. + */ + if (ipv4 && ipv6) + family = AF_UNSPEC; + else if (ipv4) + family = AF_INET; + else + family = AF_INET6; + + ai_head = do_getaddrinfo(NULL, family); if (!ai_head) { usbip_host_driver_close(); return -1; } - - info("starting " PROGNAME " (%s)", usbip_version_string); - - nsockfd = listen_all_addrinfo(ai_head, sockfdlist); + nsockfd = listen_all_addrinfo(ai_head, sockfdlist, + sizeof(sockfdlist) / sizeof(*sockfdlist)); + freeaddrinfo(ai_head); if (nsockfd <= 0) { err("failed to open a listening socket"); - freeaddrinfo(ai_head); usbip_host_driver_close(); return -1; } + + dbg("listening on %d address%s", nsockfd, (nsockfd == 1) ? "" : "es"); + fds = calloc(nsockfd, sizeof(struct pollfd)); for (i = 0; i < nsockfd; i++) { fds[i].fd = sockfdlist[i]; @@ -496,13 +569,13 @@ static int do_standalone_mode(int daemonize) process_request(sockfdlist[i]); } } - } else + } else { dbg("heartbeat timeout on ppoll()"); + } } info("shutting down " PROGNAME); free(fds); - freeaddrinfo(ai_head); usbip_host_driver_close(); return 0; @@ -511,11 +584,16 @@ static int do_standalone_mode(int daemonize) int main(int argc, char *argv[]) { static const struct option longopts[] = { - { "daemon", no_argument, NULL, 'D' }, - { "debug", no_argument, NULL, 'd' }, - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'v' }, - { NULL, 0, NULL, 0 } + { "ipv4", no_argument, NULL, '4' }, + { "ipv6", no_argument, NULL, '6' }, + { "daemon", no_argument, NULL, 'D' }, + { "daemon", no_argument, NULL, 'D' }, + { "debug", no_argument, NULL, 'd' }, + { "pid", optional_argument, NULL, 'P' }, + { "tcp-port", required_argument, NULL, 't' }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'v' }, + { NULL, 0, NULL, 0 } }; enum { @@ -525,8 +603,11 @@ int main(int argc, char *argv[]) } cmd; int daemonize = 0; + int ipv4 = 0, ipv6 = 0; int opt, rc = -1; + pid_file = NULL; + usbip_use_stderr = 1; usbip_use_syslog = 0; @@ -535,12 +616,18 @@ int main(int argc, char *argv[]) cmd = cmd_standalone_mode; for (;;) { - opt = getopt_long(argc, argv, "Ddhv", longopts, NULL); + opt = getopt_long(argc, argv, "46DdP::t:hv", longopts, NULL); if (opt == -1) break; switch (opt) { + case '4': + ipv4 = 1; + break; + case '6': + ipv6 = 1; + break; case 'D': daemonize = 1; break; @@ -550,6 +637,12 @@ int main(int argc, char *argv[]) case 'h': cmd = cmd_help; break; + case 'P': + pid_file = optarg ? optarg : DEFAULT_PID_FILE; + break; + case 't': + usbip_setup_port_number(optarg); + break; case 'v': cmd = cmd_version; break; @@ -560,9 +653,13 @@ int main(int argc, char *argv[]) } } + if (!ipv4 && !ipv6) + ipv4 = ipv6 = 1; + switch (cmd) { case cmd_standalone_mode: - rc = do_standalone_mode(daemonize); + rc = do_standalone_mode(daemonize, ipv4, ipv6); + remove_pid_file(); break; case cmd_version: printf(PROGNAME " (%s)\n", usbip_version_string); diff --git a/drivers/staging/usbip/userspace/src/utils.c b/drivers/staging/usbip/userspace/src/utils.c index 2d4966e6289..2b3d6d23501 100644 --- a/drivers/staging/usbip/userspace/src/utils.c +++ b/drivers/staging/usbip/userspace/src/utils.c @@ -16,61 +16,37 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <sysfs/libsysfs.h> - #include <errno.h> #include <stdio.h> #include <string.h> #include "usbip_common.h" #include "utils.h" +#include "sysfs_utils.h" int modify_match_busid(char *busid, int add) { - char bus_type[] = "usb"; char attr_name[] = "match_busid"; - char buff[SYSFS_BUS_ID_SIZE + 4]; - char sysfs_mntpath[SYSFS_PATH_MAX]; + char command[SYSFS_BUS_ID_SIZE + 4]; char match_busid_attr_path[SYSFS_PATH_MAX]; - struct sysfs_attribute *match_busid_attr; - int rc, ret = 0; - - if (strnlen(busid, SYSFS_BUS_ID_SIZE) > SYSFS_BUS_ID_SIZE - 1) { - dbg("busid is too long"); - return -1; - } - - rc = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX); - if (rc < 0) { - err("sysfs must be mounted: %s", strerror(errno)); - return -1; - } + int rc; snprintf(match_busid_attr_path, sizeof(match_busid_attr_path), - "%s/%s/%s/%s/%s/%s", sysfs_mntpath, SYSFS_BUS_NAME, bus_type, - SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME, attr_name); - - match_busid_attr = sysfs_open_attribute(match_busid_attr_path); - if (!match_busid_attr) { - dbg("problem getting match_busid attribute: %s", - strerror(errno)); - return -1; - } + "%s/%s/%s/%s/%s/%s", SYSFS_MNT_PATH, SYSFS_BUS_NAME, + SYSFS_BUS_TYPE, SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME, + attr_name); if (add) - snprintf(buff, SYSFS_BUS_ID_SIZE + 4, "add %s", busid); + snprintf(command, SYSFS_BUS_ID_SIZE + 4, "add %s", busid); else - snprintf(buff, SYSFS_BUS_ID_SIZE + 4, "del %s", busid); + snprintf(command, SYSFS_BUS_ID_SIZE + 4, "del %s", busid); - dbg("write \"%s\" to %s", buff, match_busid_attr->path); - - rc = sysfs_write_attribute(match_busid_attr, buff, sizeof(buff)); + rc = write_sysfs_attribute(match_busid_attr_path, command, + sizeof(command)); if (rc < 0) { dbg("failed to write match_busid: %s", strerror(errno)); - ret = -1; + return -1; } - sysfs_close_attribute(match_busid_attr); - - return ret; + return 0; } diff --git a/drivers/staging/usbip/vhci_hcd.c b/drivers/staging/usbip/vhci_hcd.c index d7974cb2cc6..0007d30e45b 100644 --- a/drivers/staging/usbip/vhci_hcd.c +++ b/drivers/staging/usbip/vhci_hcd.c @@ -205,8 +205,6 @@ static int vhci_hub_status(struct usb_hcd *hcd, char *buf) } } - pr_info("changed %d\n", changed); - if ((hcd->state == HC_STATE_SUSPENDED) && (changed == 1)) usb_hcd_resume_root_hub(hcd); @@ -220,8 +218,7 @@ static inline void hub_descriptor(struct usb_hub_descriptor *desc) memset(desc, 0, sizeof(*desc)); desc->bDescriptorType = 0x29; desc->bDescLength = 9; - desc->wHubCharacteristics = (__force __u16) - (__constant_cpu_to_le16(0x0001)); + desc->wHubCharacteristics = (__constant_cpu_to_le16(0x0001)); desc->bNbrPorts = VHCI_NPORTS; desc->u.hs.DeviceRemovable[0] = 0xff; desc->u.hs.DeviceRemovable[1] = 0xff; @@ -274,14 +271,14 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, } break; case USB_PORT_FEAT_POWER: - usbip_dbg_vhci_rh(" ClearPortFeature: " - "USB_PORT_FEAT_POWER\n"); + usbip_dbg_vhci_rh( + " ClearPortFeature: USB_PORT_FEAT_POWER\n"); dum->port_status[rhport] = 0; dum->resuming = 0; break; case USB_PORT_FEAT_C_RESET: - usbip_dbg_vhci_rh(" ClearPortFeature: " - "USB_PORT_FEAT_C_RESET\n"); + usbip_dbg_vhci_rh( + " ClearPortFeature: USB_PORT_FEAT_C_RESET\n"); switch (dum->vdev[rhport].speed) { case USB_SPEED_HIGH: dum->port_status[rhport] |= @@ -340,16 +337,17 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, if (dum->vdev[rhport].ud.status == VDEV_ST_NOTASSIGNED) { - usbip_dbg_vhci_rh(" enable rhport %d " - "(status %u)\n", - rhport, - dum->vdev[rhport].ud.status); + usbip_dbg_vhci_rh( + " enable rhport %d (status %u)\n", + rhport, + dum->vdev[rhport].ud.status); dum->port_status[rhport] |= USB_PORT_STAT_ENABLE; } } - ((u16 *) buf)[0] = cpu_to_le16(dum->port_status[rhport]); - ((u16 *) buf)[1] = cpu_to_le16(dum->port_status[rhport] >> 16); + ((__le16 *) buf)[0] = cpu_to_le16(dum->port_status[rhport]); + ((__le16 *) buf)[1] = + cpu_to_le16(dum->port_status[rhport] >> 16); usbip_dbg_vhci_rh(" GetPortStatus bye %x %x\n", ((u16 *)buf)[0], ((u16 *)buf)[1]); @@ -361,12 +359,12 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, case SetPortFeature: switch (wValue) { case USB_PORT_FEAT_SUSPEND: - usbip_dbg_vhci_rh(" SetPortFeature: " - "USB_PORT_FEAT_SUSPEND\n"); + usbip_dbg_vhci_rh( + " SetPortFeature: USB_PORT_FEAT_SUSPEND\n"); break; case USB_PORT_FEAT_RESET: - usbip_dbg_vhci_rh(" SetPortFeature: " - "USB_PORT_FEAT_RESET\n"); + usbip_dbg_vhci_rh( + " SetPortFeature: USB_PORT_FEAT_RESET\n"); /* if it's already running, disconnect first */ if (dum->port_status[rhport] & USB_PORT_STAT_ENABLE) { dum->port_status[rhport] &= @@ -537,10 +535,9 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, goto no_need_xmit; case USB_REQ_GET_DESCRIPTOR: - if (ctrlreq->wValue == (USB_DT_DEVICE << 8)) - usbip_dbg_vhci_hc("Not yet?: " - "Get_Descriptor to device 0 " - "(get max pipe size)\n"); + if (ctrlreq->wValue == cpu_to_le16(USB_DT_DEVICE << 8)) + usbip_dbg_vhci_hc( + "Not yet?:Get_Descriptor to device 0 (get max pipe size)\n"); if (vdev->udev) usb_put_dev(vdev->udev); @@ -549,8 +546,9 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, default: /* NOT REACHED */ - dev_err(dev, "invalid request to devnum 0 bRequest %u, " - "wValue %u\n", ctrlreq->bRequest, + dev_err(dev, + "invalid request to devnum 0 bRequest %u, wValue %u\n", + ctrlreq->bRequest, ctrlreq->wValue); ret = -EINVAL; goto no_need_xmit; @@ -637,6 +635,7 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { int ret = 0; + ret = usb_hcd_check_unlink_urb(hcd, urb, status); if (ret) { spin_unlock(&the_controller->lock); @@ -790,7 +789,7 @@ static void vhci_shutdown_connection(struct usbip_device *ud) /* active connection is closed */ if (vdev->ud.tcp_socket) { - fput(vdev->ud.tcp_socket->file); + sockfd_put(vdev->ud.tcp_socket); vdev->ud.tcp_socket = NULL; } pr_info("release socket\n"); @@ -837,7 +836,7 @@ static void vhci_device_reset(struct usbip_device *ud) vdev->udev = NULL; if (ud->tcp_socket) { - fput(ud->tcp_socket->file); + sockfd_put(ud->tcp_socket); ud->tcp_socket = NULL; } ud->status = VDEV_ST_NULL; @@ -887,6 +886,7 @@ static int vhci_start(struct usb_hcd *hcd) for (rhport = 0; rhport < VHCI_NPORTS; rhport++) { struct vhci_device *vdev = &vhci->vdev[rhport]; + vhci_device_init(vdev); vdev->rhport = rhport; } @@ -918,7 +918,7 @@ static void vhci_stop(struct usb_hcd *hcd) sysfs_remove_group(&vhci_dev(vhci)->kobj, &dev_attr_group); /* 2. shutdown all the ports of vhci_hcd */ - for (rhport = 0 ; rhport < VHCI_NPORTS; rhport++) { + for (rhport = 0; rhport < VHCI_NPORTS; rhport++) { struct vhci_device *vdev = &vhci->vdev[rhport]; usbip_event_add(&vdev->ud, VDEV_EVENT_REMOVED); @@ -999,12 +999,6 @@ static int vhci_hcd_probe(struct platform_device *pdev) usbip_dbg_vhci_hc("name %s id %d\n", pdev->name, pdev->id); - /* will be removed */ - if (pdev->dev.dma_mask) { - dev_info(&pdev->dev, "vhci_hcd DMA not supported\n"); - return -EINVAL; - } - /* * Allocate and initialize hcd. * Our private data is also allocated automatically. @@ -1077,8 +1071,9 @@ static int vhci_hcd_suspend(struct platform_device *pdev, pm_message_t state) spin_unlock(&the_controller->lock); if (connected > 0) { - dev_info(&pdev->dev, "We have %d active connection%s. Do not " - "suspend.\n", connected, (connected == 1 ? "" : "s")); + dev_info(&pdev->dev, + "We have %d active connection%s. Do not suspend.\n", + connected, (connected == 1 ? "" : "s")); ret = -EBUSY; } else { dev_info(&pdev->dev, "suspend vhci_hcd"); @@ -1114,7 +1109,7 @@ static struct platform_driver vhci_driver = { .suspend = vhci_hcd_suspend, .resume = vhci_hcd_resume, .driver = { - .name = (char *) driver_name, + .name = driver_name, .owner = THIS_MODULE, }, }; @@ -1131,7 +1126,7 @@ static void the_pdev_release(struct device *dev) static struct platform_device the_pdev = { /* should be the same name as driver_name */ - .name = (char *) driver_name, + .name = driver_name, .id = -1, .dev = { .release = the_pdev_release, @@ -1146,11 +1141,11 @@ static int __init vhci_hcd_init(void) return -ENODEV; ret = platform_driver_register(&vhci_driver); - if (ret < 0) + if (ret) goto err_driver_register; ret = platform_device_register(&the_pdev); - if (ret < 0) + if (ret) goto err_platform_device_register; pr_info(DRIVER_DESC " v" USBIP_VERSION "\n"); diff --git a/drivers/staging/usbip/vhci_sysfs.c b/drivers/staging/usbip/vhci_sysfs.c index c66e9c05c76..211f43f67ea 100644 --- a/drivers/staging/usbip/vhci_sysfs.c +++ b/drivers/staging/usbip/vhci_sysfs.c @@ -27,7 +27,7 @@ /* TODO: refine locking ?*/ /* Sysfs entry to show port status */ -static ssize_t show_status(struct device *dev, struct device_attribute *attr, +static ssize_t status_show(struct device *dev, struct device_attribute *attr, char *out) { char *s = out; @@ -47,8 +47,8 @@ static ssize_t show_status(struct device *dev, struct device_attribute *attr, * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a * port number and its peer IP address. */ - out += sprintf(out, "prt sta spd bus dev socket " - "local_busid\n"); + out += sprintf(out, + "prt sta spd bus dev socket local_busid\n"); for (i = 0; i < VHCI_NPORTS; i++) { struct vhci_device *vdev = port_to_vdev(i); @@ -74,7 +74,7 @@ static ssize_t show_status(struct device *dev, struct device_attribute *attr, return out - s; } -static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); +static DEVICE_ATTR_RO(status); /* Sysfs entry to shutdown a virtual connection */ static int vhci_port_disconnect(__u32 rhport) @@ -114,7 +114,8 @@ static ssize_t store_detach(struct device *dev, struct device_attribute *attr, int err; __u32 rhport = 0; - sscanf(buf, "%u", &rhport); + if (sscanf(buf, "%u", &rhport) != 1) + return -EINVAL; /* check rhport */ if (rhport >= VHCI_NPORTS) { @@ -149,7 +150,8 @@ static int valid_args(__u32 rhport, enum usb_device_speed speed) case USB_SPEED_WIRELESS: break; default: - pr_err("speed %d\n", speed); + pr_err("Failed attach request for unsupported USB speed: %s\n", + usb_speed_string(speed)); return -EINVAL; } @@ -174,6 +176,7 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, struct socket *socket; int sockfd = 0; __u32 rhport = 0, devid = 0, speed = 0; + int err; /* * @rhport: port number of vhci_hcd @@ -181,7 +184,8 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, * @devid: unique device identifier in a remote host * @speed: usb device speed in a remote host */ - sscanf(buf, "%u %u %u %u", &rhport, &sockfd, &devid, &speed); + if (sscanf(buf, "%u %u %u %u", &rhport, &sockfd, &devid, &speed) != 4) + return -EINVAL; usbip_dbg_vhci_sysfs("rhport(%u) sockfd(%u) devid(%u) speed(%u)\n", rhport, sockfd, devid, speed); @@ -191,8 +195,7 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, return -EINVAL; /* Extract socket from fd. */ - /* The correct way to clean this up is to fput(socket->file). */ - socket = sockfd_to_socket(sockfd); + socket = sockfd_lookup(sockfd, &err); if (!socket) return -EINVAL; @@ -208,14 +211,15 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, spin_unlock(&vdev->ud.lock); spin_unlock(&the_controller->lock); - fput(socket->file); + sockfd_put(socket); dev_err(dev, "port %d already used\n", rhport); return -EINVAL; } - dev_info(dev, "rhport(%u) sockfd(%d) devid(%u) speed(%u)\n", - rhport, sockfd, devid, speed); + dev_info(dev, + "rhport(%u) sockfd(%d) devid(%u) speed(%u) speed_str(%s)\n", + rhport, sockfd, devid, speed, usb_speed_string(speed)); vdev->devid = devid; vdev->speed = speed; |
