[PATCH v2 05/11] usbip: tools for userspace URBs transmission

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Originally, USB/IP transmits requests and response PDUs for preparation 
to transfer URBs in user space, after completion of the preparation, 
URBs are transmitted in kernel space.

To make easy to introduce application network protocols like WebSocket, 
the driver, usbip_ux.ko, forwards URBs to USB/IP user space utilities. 
Then, the utilities exchange URBs in userspace.

To do so, tools/usb/usbip/libsrc/usbip_ux.c includes tx/rx threads to 
read/wite URBs from usbip_ux.ko and transfer URBs in userspace. When 
usbip_ux.ko is installed, /dev/usbip-ux will be found, then the threads 
will be started. Otherwise, threads will not be started and original 
kernel space transmission is valid.

Signed-off-by: Nobuo Iwata <nobuo.iwata@xxxxxxxxxxxxxxx>
---
 tools/usb/usbip/libsrc/Makefile.am     |   1 +
 tools/usb/usbip/libsrc/usbip_ux.c      | 244 +++++++++++++++++++++++++
 tools/usb/usbip/libsrc/usbip_ux.h      |  30 +++
 tools/usb/usbip/libsrc/vhci_driver.c   |  10 +-
 tools/usb/usbip/src/usbip_attach.c     |  30 ++-
 tools/usb/usbip/src/usbip_connect.c    |  18 +-
 tools/usb/usbip/src/usbip_disconnect.c |  11 +-
 tools/usb/usbip/src/usbipd.c           |   5 +-
 tools/usb/usbip/src/usbipd_app.c       |  14 ++
 tools/usb/usbip/src/usbipd_dev.c       |  30 ++-
 10 files changed, 370 insertions(+), 23 deletions(-)

diff --git a/tools/usb/usbip/libsrc/Makefile.am b/tools/usb/usbip/libsrc/Makefile.am
index 7c8f8a4..5754425 100644
--- a/tools/usb/usbip/libsrc/Makefile.am
+++ b/tools/usb/usbip/libsrc/Makefile.am
@@ -5,4 +5,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_ux.c usbip_ux.h \
 		       sysfs_utils.c sysfs_utils.h
diff --git a/tools/usb/usbip/libsrc/usbip_ux.c b/tools/usb/usbip/libsrc/usbip_ux.c
new file mode 100644
index 0000000..183be7c
--- /dev/null
+++ b/tools/usb/usbip/libsrc/usbip_ux.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2015 Nobuo Iwata
+ *
+ * USB/IP URB transmission in userspace.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include "usbip_common.h"
+#include "usbip_ux.h"
+
+#undef  PROGNAME
+#define PROGNAME "libusbip"
+
+#define DEVNAME "/dev/" USBIP_UX_DEV_NAME
+
+#define BLEN 1500
+
+#ifdef DEBUG
+void dump_buff(char *buff, size_t bufflen, char *label)
+{
+#define DUMP_BUFF 80
+#define WORK_BUFF 16
+	size_t i = 0, j;
+	char b[DUMP_BUFF];
+	char bb[WORK_BUFF];
+
+	dbg("dump %s for %zd bytes", label, bufflen);
+	for(i=0;i<bufflen;i++) {
+		j = i % 16;
+		if (j == 0) {
+			b[0] = 0;
+			sprintf(bb, "%04zx  %02x", i, *(buff+i) & 0xff);
+		} else if (j == 8) {
+			sprintf(bb, "  %02x", *(buff+i) & 0xff);
+		} else {
+			sprintf(bb, " %02x", *(buff+i) & 0xff);
+		}
+		strncat(b, bb, WORK_BUFF);
+		if (j == 15 || i == bufflen-1) {
+			dbg("%s", b);
+		}
+	}
+}
+#else
+#define dump_buff(buff, bufflen, label) while(0){}
+#endif
+
+static void *usbip_ux_rx(void *arg)
+{
+	usbip_ux_t *ux = (usbip_ux_t*)arg;
+	ssize_t received, written, ret;
+	int good = 1;
+	char buf[BLEN];
+
+	while(good) {
+		received = recv(ux->sockfd, buf, BLEN, 0);
+		if (received == 0) {
+			dbg("connection closed on sock:%p", ux->kaddr.sock);
+			break;
+		} else if (received < 0) {
+			dbg("receive error on sock:%p", ux->kaddr.sock);
+			break;
+		}
+		dump_buff(buf, received, "ux received");
+		written = 0;
+		while(written < received) {
+			ret = write(ux->devfd, buf+written, received-written);
+			if (ret < 0) {
+				dbg("write error for sock:%p", ux->kaddr.sock);
+				good = 0;
+				break;
+			}
+			written += ret;
+		}
+	}
+	dbg("end of ux-rx for sock:%p", ux->kaddr.sock);
+	ioctl(ux->devfd, USBIP_UX_IOCINTR);
+	return 0;
+}
+
+static void *usbip_ux_tx(void *arg)
+{
+	usbip_ux_t *ux = (usbip_ux_t*)arg;
+	ssize_t sent, reads;
+	char buf[BLEN];
+
+	for(;;) {
+		reads = read(ux->devfd, buf, BLEN);
+		if (reads == 0) {
+#ifdef DEBUG
+			dbg("end of read on sock:%p continue.", ux->kaddr.sock);
+#endif
+			sched_yield();
+			continue;
+		} else 	if (reads < 0) {
+			dbg("read error on sock:%p", ux->kaddr.sock);
+			break;
+		}
+		dump_buff(buf, reads, "ux sending");
+		sent = send(ux->sockfd, buf, reads, 0);
+		if (sent < 0) {
+			dbg("connection closed on sock:%p", ux->kaddr.sock);
+			break;
+		} else if (sent < reads) {
+			dbg("send error on sock:%p %zd < %zd", ux->kaddr.sock,
+				sent, reads);
+			break;
+		}
+	}
+	dbg("end of ux-tx for sock:%p", ux->kaddr.sock);
+	shutdown(ux->sockfd, SHUT_RDWR);
+	return 0;
+}
+
+/*
+ * Setup user space mode.
+ * Null will be set in ux if usbip_ux.ko is not installed.
+ */
+int usbip_ux_setup(int sockfd, usbip_ux_t **uxp)
+{
+	usbip_ux_t *ux;
+	int fd, ret;
+	
+	*uxp = NULL;
+
+	fd = open(DEVNAME, O_RDWR);
+	if (fd < 0) {
+		dbg("failed to open %s", DEVNAME);
+		dbg("URBs will be transferred in kernel space");
+		return 0;
+	}
+	ux = (usbip_ux_t*)malloc(sizeof(usbip_ux_t));
+	if (ux == NULL) {
+		dbg("failed to alloc ux data");
+		goto err1;
+	}
+	ux->devfd = fd;
+	ux->started = 0;
+	ux->sockfd = sockfd;
+	ret = ioctl(ux->devfd, USBIP_UX_IOCSETSOCKFD, sockfd);
+	if (ret) {
+		dbg("failed to set sock fd");
+		goto err2;
+	}
+	ret = ioctl(ux->devfd, USBIP_UX_IOCGETKADDR, &ux->kaddr);
+	if (ret) {
+		dbg("failed to get kaddr");
+		goto err2;
+	}
+	dbg("successfully prepared userspace transmission sock:%p ux:%p pid:%d",
+		 ux->kaddr.sock, ux->kaddr.ux, getpid());
+	*uxp = ux;
+	return 0;
+err2:
+	free(ux);
+err1:
+	close(ux->devfd);
+	return -1;
+}
+
+/*
+ * Only for error handling before start.
+ */
+void usbip_ux_cleanup(usbip_ux_t **ux)
+{
+	if (*ux == NULL) return;
+	close((*ux)->devfd);
+	free(*ux);
+	*ux = NULL;
+}
+
+/*
+ * Starts transmission threads.
+ */
+int usbip_ux_start(usbip_ux_t *ux)
+{
+	int ret;
+
+	if (ux == NULL) return 0;
+	ret = pthread_create(&ux->rx, NULL, usbip_ux_rx, ux);
+	if (ret) {
+		dbg("failed to start recv thread");
+		goto err;
+	}
+	ret = pthread_create(&ux->tx, NULL, usbip_ux_tx, ux);
+	if (ret) {
+		dbg("failed to start send thread");
+		goto err;
+	}
+	ux->started = 1;
+	dbg("successfully started userspace transmission");
+	return 0;
+err:
+	close(ux->devfd);
+	return -1;
+}
+
+/*
+ * Waits end of usespace transmission.
+ * Will return on following conditions.
+ * 1) Detached or unbound
+ * 2) Broken connection
+ * 3) Closed usbip-ux device
+ */
+void usbip_ux_join(usbip_ux_t *ux)
+{
+	if (ux == NULL) return;
+	dbg("waiting on userspace transmission threads");
+	pthread_join((ux)->tx, NULL);
+	pthread_join((ux)->rx, NULL);
+}
+
+void usbip_ux_interrupt(usbip_ux_t *ux)
+{
+	if (ux == NULL) return;
+	ioctl((ux)->devfd, USBIP_UX_IOCINTR);
+}
+
+void usbip_ux_interrupt_pgrp(void)
+{
+	int fd;
+
+	fd = open(DEVNAME, O_RDWR);
+	if (fd < 0) {
+		dbg("failed to open %s", DEVNAME);
+		return;
+	}
+	ioctl(fd, USBIP_UX_IOCINTRPGRP);
+	close(fd);
+}
+
+int usbip_ux_installed(void)
+{
+	struct stat buf;
+
+	if (stat(DEVNAME, &buf)) {
+		return 0;
+	}
+	return 1;
+}
diff --git a/tools/usb/usbip/libsrc/usbip_ux.h b/tools/usb/usbip/libsrc/usbip_ux.h
new file mode 100644
index 0000000..7506a1c
--- /dev/null
+++ b/tools/usb/usbip/libsrc/usbip_ux.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 Nobuo Iwata
+ *
+ * USB/IP URB transmission in userspace.
+ */
+
+#ifndef __USBIP_UX_H
+#define __USBIP_UX_H
+
+#include <pthread.h>
+#include "../../../../include/uapi/linux/usbip_ux.h"
+#include "usbip_common.h"
+
+typedef struct usbip_ux {
+	int sockfd;
+	int devfd;
+	int started;
+	pthread_t tx, rx;
+	struct usbip_ux_kaddr kaddr;
+} usbip_ux_t;
+
+int usbip_ux_setup(int sockfd, usbip_ux_t **uxp);
+void usbip_ux_cleanup(usbip_ux_t **ux);
+int usbip_ux_start(usbip_ux_t *ux);
+void usbip_ux_join(usbip_ux_t *ux);
+void usbip_ux_interrupt(usbip_ux_t *ux);
+void usbip_ux_interrupt_pgrp();
+int usbip_ux_installed(void);
+
+#endif /* !__USBIP_UX_H */
diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c
index 797949d..5a6f395 100644
--- a/tools/usb/usbip/libsrc/vhci_driver.c
+++ b/tools/usb/usbip/libsrc/vhci_driver.c
@@ -58,21 +58,21 @@ static int parse_status(const char *value)
 
 	while (*c != '\0') {
 		int port, status, speed, devid;
-		unsigned long socket;
+		unsigned long socket, ux;
 		char lbusid[SYSFS_BUS_ID_SIZE];
 
-		ret = sscanf(c, "%d %d %d %x %lx %31s\n",
+		ret = sscanf(c, "%d %d %d %x %lx %lx %31s\n",
 				&port, &status, &speed,
-				&devid, &socket, lbusid);
+				&devid, &socket, &ux, lbusid);
 
-		if (ret < 5) {
+		if (ret < 7) {
 			dbg("sscanf failed: %d", ret);
 			BUG();
 		}
 
 		dbg("port %d status %d speed %d devid %x",
 				port, status, speed, devid);
-		dbg("socket %lx lbusid %s", socket, lbusid);
+		dbg("socket %lx ux %lx lbusid %s", socket, ux, lbusid);
 
 
 		/* if a device is connected, look at it */
diff --git a/tools/usb/usbip/src/usbip_attach.c b/tools/usb/usbip/src/usbip_attach.c
index 0817e92..b25bc03 100644
--- a/tools/usb/usbip/src/usbip_attach.c
+++ b/tools/usb/usbip/src/usbip_attach.c
@@ -32,6 +32,7 @@
 #include "vhci_driver.h"
 #include "usbip_common.h"
 #include "usbip_network.h"
+#include "usbip_ux.h"
 #include "usbip.h"
 
 static const char usbip_attach_usage_string[] =
@@ -130,31 +131,48 @@ static int query_import_device(int sockfd, char *busid)
 static int attach_device(char *host, char *busid)
 {
 	int sockfd;
+	usbip_ux_t *ux;
 	int rc;
 	int rhport;
 
 	sockfd = usbip_net_tcp_connect(host, usbip_port_string);
 	if (sockfd < 0) {
 		err("tcp connect");
-		return -1;
+		goto err0;
+	}
+
+	rc = usbip_ux_setup(sockfd, &ux);
+	if (rc) {
+		err("ux setup");
+		goto err1;
 	}
 
 	rhport = query_import_device(sockfd, busid);
 	if (rhport < 0) {
 		err("query");
-		close(sockfd);
-		return -1;
+		goto err2;
 	}
 
-	close(sockfd);
-
 	rc = usbip_vhci_create_record(host, usbip_port_string, busid, rhport);
 	if (rc < 0) {
 		err("record connection");
-		return -1;
+		goto err2;
 	}
 
+	if (ux != NULL) {
+		usbip_ux_start(ux);
+		usbip_ux_join(ux);
+	}
+	usbip_ux_cleanup(&ux);
+	close(sockfd);
+
 	return 0;
+err2:
+	usbip_ux_cleanup(&ux);
+err1:
+	close(sockfd);
+err0:
+	return -1;
 }
 
 int usbip_attach(int argc, char *argv[])
diff --git a/tools/usb/usbip/src/usbip_connect.c b/tools/usb/usbip/src/usbip_connect.c
index b30cccf..c5aa8eb 100644
--- a/tools/usb/usbip/src/usbip_connect.c
+++ b/tools/usb/usbip/src/usbip_connect.c
@@ -30,6 +30,7 @@
 #include "usbip_host_driver.h"
 #include "usbip_common.h"
 #include "usbip_network.h"
+#include "usbip_ux.h"
 #include "usbip.h"
 
 static const char usbip_connect_usage_string[] =
@@ -140,6 +141,7 @@ static int export_device(char *busid, int sockfd)
 static int connect_device(char *host, char *busid)
 {
 	int sockfd;
+	usbip_ux_t *ux;
 	int rc;
 
 	rc = usbip_bind_device(busid);
@@ -154,15 +156,29 @@ static int connect_device(char *host, char *busid)
 		goto err1;
 	}
 
+	rc = usbip_ux_setup(sockfd, &ux);
+	if (rc) {
+		err("ux setup");
+		goto err2;
+	}
+
 	rc = export_device(busid, sockfd);
 	if (rc < 0) {
 		err("export");
-		goto err2;
+		goto err3;
 	}
 
+	if (ux != NULL) {
+		usbip_ux_start(ux);
+		usbip_ux_join(ux);
+		usbip_unbind_device(busid);
+	}
+	usbip_ux_cleanup(&ux);
 	close(sockfd);
 
 	return 0;
+err3:
+	usbip_ux_cleanup(&ux);
 err2:
 	close(sockfd);
 err1:
diff --git a/tools/usb/usbip/src/usbip_disconnect.c b/tools/usb/usbip/src/usbip_disconnect.c
index b9cbe1d..8adabe6 100644
--- a/tools/usb/usbip/src/usbip_disconnect.c
+++ b/tools/usb/usbip/src/usbip_disconnect.c
@@ -30,6 +30,7 @@
 #include "usbip_host_driver.h"
 #include "usbip_common.h"
 #include "usbip_network.h"
+#include "usbip_ux.h"
 #include "usbip.h"
 
 static const char usbip_disconnect_usage_string[] =
@@ -150,10 +151,12 @@ static int disconnect_device(char *host, char *busid)
 
 	close(sockfd);
 
-	rc = usbip_unbind_device(busid);
-	if (rc) {
-		err("unbind");
-		return -1;
+	if (!usbip_ux_installed()) {
+		rc = usbip_unbind_device(busid);
+		if (rc) {
+			err("unbind");
+			return -1;
+		}
 	}
 
 	return 0;
diff --git a/tools/usb/usbip/src/usbipd.c b/tools/usb/usbip/src/usbipd.c
index c63a76f..8939af3 100644
--- a/tools/usb/usbip/src/usbipd.c
+++ b/tools/usb/usbip/src/usbipd.c
@@ -43,6 +43,7 @@
 
 #include "usbip_common.h"
 #include "usbip_network.h"
+#include "usbip_ux.h"
 #include "list.h"
 
 extern char *usbip_progname;
@@ -55,7 +56,7 @@ extern char *usbip_default_pid_file;
 
 static const char usbip_version_string[] = PACKAGE_STRING;
 
-static const char usbipd_help_string[] =
+static const char usbipd_help_string =
 	"usage: %s [options]\n"
 	"\n"
 	"	-4, --ipv4\n"
@@ -152,6 +153,7 @@ int process_request(int listenfd)
 	if (childpid == 0) {
 		close(listenfd);
 		usbip_recv_pdu(connfd, host, port);
+		close(connfd);
 		exit(0);
 	}
 	close(connfd);
@@ -254,6 +256,7 @@ static struct addrinfo *do_getaddrinfo(char *host, int ai_family)
 static void signal_handler(int i)
 {
 	dbg("received '%s' signal", strsignal(i));
+	usbip_ux_interrupt_pgrp();
 }
 
 static void set_signal(void)
diff --git a/tools/usb/usbip/src/usbipd_app.c b/tools/usb/usbip/src/usbipd_app.c
index f029b64..16af965 100644
--- a/tools/usb/usbip/src/usbipd_app.c
+++ b/tools/usb/usbip/src/usbipd_app.c
@@ -32,6 +32,7 @@
 #include "vhci_driver.h"
 #include "usbip_common.h"
 #include "usbip_network.h"
+#include "usbip_ux.h"
 
 char *usbip_progname = "usbipa";
 char *usbip_default_pid_file = "/var/run/usbipa";
@@ -78,6 +79,7 @@ static int recv_request_export(int sockfd, char *host, char *port)
 {
 	struct op_export_request req;
 	struct op_export_reply reply;
+	usbip_ux_t *ux;
 	int rhport = 0;
 	int error = 0;
 	int rc;
@@ -92,6 +94,12 @@ static int recv_request_export(int sockfd, char *host, char *port)
 	}
 	PACK_OP_EXPORT_REQUEST(0, &req);
 
+	rc = usbip_ux_setup(sockfd, &ux);
+	if (rc) {
+		dbg("usbip_ux_setup failed: export");
+		return -1;
+	}
+
 	rhport = import_device(sockfd, &req.udev);
 	if (rhport < 0) {
 		dbg("export request busid %s: failed", req.udev.busid);
@@ -126,6 +134,12 @@ static int recv_request_export(int sockfd, char *host, char *port)
 
 	dbg("export request busid %s: complete", req.udev.busid);
 
+	if (ux != NULL) {
+		usbip_ux_start(ux);
+		usbip_ux_join(ux);
+	}
+	usbip_ux_cleanup(&ux);
+
 	return 0;
 }
 
diff --git a/tools/usb/usbip/src/usbipd_dev.c b/tools/usb/usbip/src/usbipd_dev.c
index 7991e3e..7d124c2 100644
--- a/tools/usb/usbip/src/usbipd_dev.c
+++ b/tools/usb/usbip/src/usbipd_dev.c
@@ -36,6 +36,7 @@
 #include "usbip_host_driver.h"
 #include "usbip_common.h"
 #include "usbip_network.h"
+#include "usbip_ux.h"
 #include "list.h"
 
 char *usbip_progname = "usbipd";
@@ -62,6 +63,7 @@ static int recv_request_import(int sockfd)
 	struct op_common reply;
 	struct usbip_exported_device *edev;
 	struct usbip_usb_device pdu_udev;
+	usbip_ux_t *ux;
 	struct list_head *i;
 	int found = 0;
 	int error = 0;
@@ -87,13 +89,20 @@ static int recv_request_import(int sockfd)
 	}
 
 	if (found) {
-		/* should set TCP_NODELAY for usbip */
-		usbip_net_set_nodelay(sockfd);
-
-		/* export device needs a TCP/IP socket descriptor */
-		rc = usbip_host_export_device(edev, sockfd);
-		if (rc < 0)
+		rc = usbip_ux_setup(sockfd, &ux);
+		if (rc) {
 			error = 1;
+		} else {
+			/* should set TCP_NODELAY for usbip */
+			usbip_net_set_nodelay(sockfd);
+
+			/* export device needs a TCP/IP socket descriptor */
+			rc = usbip_host_export_device(edev, sockfd);
+			if (rc < 0) {
+				usbip_ux_cleanup(&ux);
+				error = 1;
+			}
+		}
 	} else {
 		info("requested device not found: %s", req.busid);
 		error = 1;
@@ -103,11 +112,13 @@ static int recv_request_import(int sockfd)
 				      (!error ? ST_OK : ST_NA));
 	if (rc < 0) {
 		dbg("usbip_net_send_op_common failed: %#0x", OP_REP_IMPORT);
+		usbip_ux_cleanup(&ux);
 		return -1;
 	}
 
 	if (error) {
 		dbg("import request busid %s: failed", req.busid);
+		usbip_ux_cleanup(&ux);
 		return -1;
 	}
 
@@ -117,11 +128,18 @@ static int recv_request_import(int sockfd)
 	rc = usbip_net_send(sockfd, &pdu_udev, sizeof(pdu_udev));
 	if (rc < 0) {
 		dbg("usbip_net_send failed: devinfo");
+		usbip_ux_cleanup(&ux);
 		return -1;
 	}
 
 	dbg("import request busid %s: complete", req.busid);
 
+	if (ux != NULL) {
+		usbip_ux_start(ux);
+		usbip_ux_join(ux);
+	}
+	usbip_ux_cleanup(&ux);
+
 	return 0;
 }
 
-- 
2.1.0

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux