diff options
Diffstat (limited to 'drivers/staging/usbip')
39 files changed, 1112 insertions, 1252 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 d8957a55662..51d0c718873 100644 --- a/drivers/staging/usbip/stub_dev.c +++ b/drivers/staging/usbip/stub_dev.c @@ -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 e3fc749c1e7..facaaf003f1 100644 --- a/drivers/staging/usbip/usbip_common.c +++ b/drivers/staging/usbip/usbip_common.c @@ -55,7 +55,8 @@ 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_RW(usbip_debug); @@ -99,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); @@ -155,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", @@ -194,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       "); @@ -306,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, @@ -366,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); @@ -400,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)  { @@ -705,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 1091bb20de1..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); - -	/* search 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 04a5f20bea6..d7599d94352 100644 --- a/drivers/staging/usbip/userspace/src/usbip.c +++ b/drivers/staging/usbip/userspace/src/usbip.c @@ -93,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 }  }; 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 08584119652..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; 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 237e099337a..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");  	} @@ -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 c39a07f1d38..b4c37e76a6e 100644 --- a/drivers/staging/usbip/userspace/src/usbip_network.c +++ b/drivers/staging/usbip/userspace/src/usbip_network.c @@ -25,6 +25,10 @@  #include <netinet/tcp.h>  #include <unistd.h> +#ifdef HAVE_LIBWRAP +#include <tcpd.h> +#endif +  #include "usbip_common.h"  #include "usbip_network.h" @@ -239,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 2d0e4277b62..c1e875cf107 100644 --- a/drivers/staging/usbip/userspace/src/usbip_network.h +++ b/drivers/staging/usbip/userspace/src/usbip_network.h @@ -10,7 +10,6 @@  #endif  #include <sys/types.h> -#include <sysfs/libsysfs.h>  #include <stdint.h> @@ -180,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 1c76cfd274d..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" @@ -56,6 +57,13 @@ static const char usbip_version_string[] = PACKAGE_STRING;  static const char usbipd_help_string[] =  	"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" @@ -86,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; @@ -100,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; @@ -154,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); @@ -178,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); @@ -196,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;  			}  		} @@ -354,15 +362,17 @@ static void addrinfo_to_text(struct addrinfo *ai, char buf[],  	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;  	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) { +	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); @@ -374,6 +384,9 @@ static int listen_all_addrinfo(struct addrinfo *ai_head, int sockfdlist[])  		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 (sock >= FD_SETSIZE) {  			err("FD_SETSIZE: %s: sock=%d, max=%d", @@ -402,11 +415,6 @@ static int listen_all_addrinfo(struct addrinfo *ai_head, int sockfdlist[])  		sockfdlist[nsockfd++] = sock;  	} -	if (nsockfd == 0) -		return -1; - -	dbg("listening on %d address%s", nsockfd, (nsockfd == 1) ? "" : "es"); -  	return nsockfd;  } @@ -450,11 +458,13 @@ static void set_signal(void)  static const char *pid_file; -static void write_pid_file() +static void write_pid_file(void)  {  	if (pid_file) {  		dbg("creating pid file %s", pid_file); -		FILE *fp = fopen(pid_file, "w"); +		FILE *fp; + +		fp = fopen(pid_file, "w");  		if (!fp) {  			err("pid_file: %s: %d (%s)",  			    pid_file, errno, strerror(errno)); @@ -465,7 +475,7 @@ static void write_pid_file()  	}  } -static void remove_pid_file() +static void remove_pid_file(void)  {  	if (pid_file) {  		dbg("removing pid file %s", pid_file); @@ -473,11 +483,11 @@ static void remove_pid_file()  	}  } -static int do_standalone_mode(int daemonize) +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; @@ -501,21 +511,36 @@ static int do_standalone_mode(int daemonize)  	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]; @@ -551,7 +576,6 @@ static int do_standalone_mode(int daemonize)  	info("shutting down " PROGNAME);  	free(fds); -	freeaddrinfo(ai_head);  	usbip_host_driver_close();  	return 0; @@ -560,6 +584,9 @@ static int do_standalone_mode(int daemonize)  int main(int argc, char *argv[])  {  	static const struct option longopts[] = { +		{ "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' }, @@ -576,7 +603,9 @@ 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; @@ -587,12 +616,18 @@ int main(int argc, char *argv[])  	cmd = cmd_standalone_mode;  	for (;;) { -		opt = getopt_long(argc, argv, "DdP::t:hv", 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; @@ -618,9 +653,12 @@ 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: 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 9b51586d11d..211f43f67ea 100644 --- a/drivers/staging/usbip/vhci_sysfs.c +++ b/drivers/staging/usbip/vhci_sysfs.c @@ -47,8 +47,8 @@ static ssize_t status_show(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); @@ -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;  | 
