[PATCH v14 05/10] usbip: exporting devices: modifications to daemon

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

 



Refactoring to the daemon to reuse common portion for new application 
side daemon. It's divided into two portions.

usbipd.c : common code for both device and application side daemon.
usbipd_dev.c : device-side specific code extracted from usbipd.c.

To do so, host driver dependent headers and declaration (i.e. static 
struct usbip_host_driver *driver;) are moved from usbipd.c to 
usbipd_dev.c.

usbipd_driver_ops is introduced to call device-side specific driver 
operations from usbipd.c. It will also be used for application-side 
specific driver operation in succeeding patch. 
usbipd_driver_<somethig>()s are wrappers for the operations.

usbipd_recv_pdu_op is introduced to share recv_pdu() routine.

In diagram below, usbipd EXISTING-1 is the device-side daemon and NEW-1 
is the application side daemon.

EXISTING) - invites devices from application(vhci)-side
         +------+                               +------------------+
 device--+ STUB |                               | application/VHCI |
         +------+                               +------------------+
         (server)                               (client)
 1) # usbipd ... start daemon
 = = =
 2) # usbip list --local
 3) # usbip bind
                  <--- list bound devices ---  4) # usbip list --remote
                  <--- import a device ------  5) # usbip attach
 = = =
                     X disconnected            6) # usbip detach
 7) usbip unbind

NEW) - dedicates devices from device(stub)-side
         +------+                               +------------------+
 device--+ STUB |                               | application/VHCI |
         +------+                               +------------------+
         (client)                               (server)
                                            1) # usbipa ... start daemon
 = = =
 2) # usbip list --local
 3) # usbip connect    --- export a device ------>
 = = =
 4) # usbip disconnect --- un-export a device --->

 Bind and unbind are done in connect and disconnect internally.

usbip_net_set_nodelay() was in the middle of device side daemon 
procedure. There's no effect by the defferring. It is moved to right 
after accept() to affect it both device and application side. In the 
client operation, it's already in right after connect().

In send_reply_devlist(), driver->ndevs is used insted of counting list.

Signed-off-by: Nobuo Iwata <nobuo.iwata@xxxxxxxxxxxxxxx>
---
 tools/usb/usbip/src/Makefile.am  |   2 +-
 tools/usb/usbip/src/usbipd.c     | 236 ++++++-------------------------
 tools/usb/usbip/src/usbipd.h     |  84 +++++++++++
 tools/usb/usbip/src/usbipd_dev.c | 230 ++++++++++++++++++++++++++++++
 4 files changed, 360 insertions(+), 192 deletions(-)

diff --git a/tools/usb/usbip/src/Makefile.am b/tools/usb/usbip/src/Makefile.am
index 42760c3..1aa5156 100644
--- a/tools/usb/usbip/src/Makefile.am
+++ b/tools/usb/usbip/src/Makefile.am
@@ -9,4 +9,4 @@ usbip_SOURCES := usbip.h utils.h usbip.c utils.c usbip_network.c \
 		 usbip_bind.c usbip_unbind.c usbip_port.c \
 		 usbip_connect.c usbip_disconnect.c
 
-usbipd_SOURCES := usbip_network.h usbipd.c usbip_network.c
+usbipd_SOURCES := usbip_network.h usbipd.c usbipd_dev.c usbip_network.c
diff --git a/tools/usb/usbip/src/usbipd.c b/tools/usb/usbip/src/usbipd.c
index 009afb4..14fdb40 100644
--- a/tools/usb/usbip/src/usbipd.c
+++ b/tools/usb/usbip/src/usbipd.c
@@ -4,6 +4,7 @@
  * Copyright (C) 2015-2016 Samsung Electronics
  *               Igor Kotrasinski <i.kotrasinsk@xxxxxxxxxxx>
  *               Krzysztof Opasiak <k.opasiak@xxxxxxxxxxx>
+ * Copyright (C) 2015-2016 Nobuo Iwata <nobuo.iwata@xxxxxxxxxxxxxxx>
  *
  * 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
@@ -43,25 +44,19 @@
 #include <signal.h>
 #include <poll.h>
 
-#include "usbip_host_driver.h"
-#include "usbip_host_common.h"
-#include "usbip_device_driver.h"
 #include "usbip_common.h"
 #include "usbip_network.h"
+#include "usbipd.h"
 #include "list.h"
 
-#undef  PROGNAME
-#define PROGNAME "usbipd"
 #define MAXSOCKFD 20
 
 #define MAIN_LOOP_TIMEOUT 10
 
-#define DEFAULT_PID_FILE "/var/run/" PROGNAME ".pid"
-
 static const char usbip_version_string[] = PACKAGE_STRING;
 
 static const char usbipd_help_string[] =
-	"usage: usbipd [options]\n"
+	"usage: %s [options]\n"
 	"\n"
 	"	-4, --ipv4\n"
 	"		Bind to IPv4. Default is both.\n"
@@ -82,7 +77,7 @@ static const char usbipd_help_string[] =
 	"\n"
 	"	-PFILE, --pid FILE\n"
 	"		Write process id to FILE.\n"
-	"		If no FILE specified, use " DEFAULT_PID_FILE "\n"
+	"		If no FILE specified, use %s.\n"
 	"\n"
 	"	-tPORT, --tcp-port PORT\n"
 	"		Listen on TCP/IP port PORT.\n"
@@ -93,164 +88,16 @@ static const char usbipd_help_string[] =
 	"	-v, --version\n"
 	"		Show version.\n";
 
-static struct usbip_host_driver *driver;
-
 static void usbipd_help(void)
 {
-	printf("%s\n", usbipd_help_string);
-}
-
-static int recv_request_import(int sockfd)
-{
-	struct op_import_request req;
-	struct usbip_exported_device *edev;
-	struct usbip_usb_device pdu_udev;
-	struct list_head *i;
-	int found = 0;
-	int error = 0;
-	int rc;
-
-	memset(&req, 0, sizeof(req));
-
-	rc = usbip_net_recv(sockfd, &req, sizeof(req));
-	if (rc < 0) {
-		dbg("usbip_net_recv failed: import request");
-		return -1;
-	}
-	PACK_OP_IMPORT_REQUEST(0, &req);
-
-	list_for_each(i, &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;
-			break;
-		}
-	}
-
-	if (found) {
-		/* should set TCP_NODELAY for usbip */
-		usbip_net_set_nodelay(sockfd);
-
-		/* export device needs a TCP/IP socket descriptor */
-		rc = usbip_export_device(edev, sockfd);
-		if (rc < 0)
-			error = 1;
-	} else {
-		info("requested device not found: %s", req.busid);
-		error = 1;
-	}
-
-	rc = usbip_net_send_op_common(sockfd, OP_REP_IMPORT,
-				      (!error ? ST_OK : ST_NA));
-	if (rc < 0) {
-		dbg("usbip_net_send_op_common failed: %#0x", OP_REP_IMPORT);
-		return -1;
-	}
-
-	if (error) {
-		dbg("import request busid %s: failed", req.busid);
-		return -1;
-	}
-
-	memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev));
-	usbip_net_pack_usb_device(1, &pdu_udev);
-
-	rc = usbip_net_send(sockfd, &pdu_udev, sizeof(pdu_udev));
-	if (rc < 0) {
-		dbg("usbip_net_send failed: devinfo");
-		return -1;
-	}
-
-	dbg("import request busid %s: complete", req.busid);
-
-	return 0;
-}
-
-static int send_reply_devlist(int connfd)
-{
-	struct usbip_exported_device *edev;
-	struct usbip_usb_device pdu_udev;
-	struct usbip_usb_interface pdu_uinf;
-	struct op_devlist_reply reply;
-	struct list_head *j;
-	int rc, i;
-
-	reply.ndev = 0;
-	/* number of exported devices */
-	list_for_each(j, &driver->edev_list) {
-		reply.ndev += 1;
-	}
-	info("exportable devices: %d", reply.ndev);
-
-	rc = usbip_net_send_op_common(connfd, OP_REP_DEVLIST, ST_OK);
-	if (rc < 0) {
-		dbg("usbip_net_send_op_common failed: %#0x", OP_REP_DEVLIST);
-		return -1;
-	}
-	PACK_OP_DEVLIST_REPLY(1, &reply);
-
-	rc = usbip_net_send(connfd, &reply, sizeof(reply));
-	if (rc < 0) {
-		dbg("usbip_net_send failed: %#0x", OP_REP_DEVLIST);
-		return -1;
-	}
-
-	list_for_each(j, &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);
-
-		rc = usbip_net_send(connfd, &pdu_udev, sizeof(pdu_udev));
-		if (rc < 0) {
-			dbg("usbip_net_send failed: pdu_udev");
-			return -1;
-		}
-
-		for (i = 0; i < edev->udev.bNumInterfaces; i++) {
-			dump_usb_interface(&edev->uinf[i]);
-			memcpy(&pdu_uinf, &edev->uinf[i], sizeof(pdu_uinf));
-			usbip_net_pack_usb_interface(1, &pdu_uinf);
-
-			rc = usbip_net_send(connfd, &pdu_uinf,
-					sizeof(pdu_uinf));
-			if (rc < 0) {
-				err("usbip_net_send failed: pdu_uinf");
-				return -1;
-			}
-		}
-	}
-
-	return 0;
-}
-
-static int recv_request_devlist(int connfd)
-{
-	struct op_devlist_request req;
-	int rc;
-
-	memset(&req, 0, sizeof(req));
-
-	rc = usbip_net_recv(connfd, &req, sizeof(req));
-	if (rc < 0) {
-		dbg("usbip_net_recv failed: devlist request");
-		return -1;
-	}
-
-	rc = send_reply_devlist(connfd);
-	if (rc < 0) {
-		dbg("send_reply_devlist failed");
-		return -1;
-	}
-
-	return 0;
+	printf(usbipd_help_string, usbip_progname, usbip_default_pid_file);
 }
 
-static int recv_pdu(int connfd)
+static int usbipd_recv_pdu(int connfd)
 {
 	uint16_t code = OP_UNSPEC;
 	int ret;
+	struct usbipd_recv_pdu_op *op;
 
 	ret = usbip_net_recv_op_common(connfd, &code);
 	if (ret < 0) {
@@ -258,23 +105,26 @@ static int recv_pdu(int connfd)
 		return -1;
 	}
 
-	ret = usbip_refresh_device_list(driver);
+	ret = usbipd_refresh_device_list();
 	if (ret < 0) {
 		dbg("could not refresh device list: %d", ret);
 		return -1;
 	}
 
 	info("received request: %#0x(%d)", code, connfd);
-	switch (code) {
-	case OP_REQ_DEVLIST:
-		ret = recv_request_devlist(connfd);
-		break;
-	case OP_REQ_IMPORT:
-		ret = recv_request_import(connfd);
-		break;
-	case OP_REQ_DEVINFO:
-	case OP_REQ_CRYPKEY:
-	default:
+	for (op = usbipd_recv_pdu_ops; op->code != OP_UNSPEC; op++) {
+		if (op->code == code) {
+			if (op->proc)
+				ret = (*(op->proc))(connfd);
+			else {
+				err("received an unsupported opcode: %#0x",
+				    code);
+				ret = -1;
+			}
+			break;
+		}
+	}
+	if (op->code == OP_UNSPEC) {
 		err("received an unknown opcode: %#0x", code);
 		ret = -1;
 	}
@@ -293,7 +143,7 @@ static int tcpd_auth(int connfd)
 	struct request_info request;
 	int rc;
 
-	request_init(&request, RQ_DAEMON, PROGNAME, RQ_FILE, connfd, 0);
+	request_init(&request, RQ_DAEMON, usbip_progname, RQ_FILE, connfd, 0);
 	fromhost(&request);
 	rc = hosts_access(&request);
 	if (rc == 0)
@@ -334,6 +184,9 @@ static int do_accept(int listenfd)
 #endif
 	info("connection from %s:%s", host, port);
 
+	/* should set TCP_NODELAY for usbip */
+	usbip_net_set_nodelay(connfd);
+
 	return connfd;
 }
 
@@ -348,7 +201,7 @@ int process_request(int listenfd)
 	childpid = fork();
 	if (childpid == 0) {
 		close(listenfd);
-		recv_pdu(connfd);
+		usbipd_recv_pdu(connfd);
 		exit(0);
 	}
 	close(connfd);
@@ -496,14 +349,13 @@ static int do_standalone_mode(int daemonize, int ipv4, int ipv6)
 	struct timespec timeout;
 	sigset_t sigmask;
 
-	if (usbip_driver_open(driver))
-		return -1;
+	if (usbipd_driver_open())
+		goto err_out;
 
 	if (daemonize) {
 		if (daemon(0, 0) < 0) {
 			err("daemonizing failed: %s", strerror(errno));
-			usbip_driver_close(driver);
-			return -1;
+			goto err_driver_close;
 		}
 		umask(0);
 		usbip_use_syslog = 1;
@@ -511,7 +363,7 @@ static int do_standalone_mode(int daemonize, int ipv4, int ipv6)
 	set_signal();
 	write_pid_file();
 
-	info("starting " PROGNAME " (%s)", usbip_version_string);
+	info("starting %s (%s)", usbip_progname, usbip_version_string);
 
 	/*
 	 * To suppress warnings on systems with bindv6only disabled
@@ -526,17 +378,15 @@ static int do_standalone_mode(int daemonize, int ipv4, int ipv6)
 		family = AF_INET6;
 
 	ai_head = do_getaddrinfo(NULL, family);
-	if (!ai_head) {
-		usbip_driver_close(driver);
-		return -1;
-	}
+	if (!ai_head)
+		goto err_driver_close;
+
 	nsockfd = listen_all_addrinfo(ai_head, sockfdlist,
 		sizeof(sockfdlist) / sizeof(*sockfdlist));
 	freeaddrinfo(ai_head);
 	if (nsockfd <= 0) {
 		err("failed to open a listening socket");
-		usbip_driver_close(driver);
-		return -1;
+		goto err_driver_close;
 	}
 
 	dbg("listening on %d address%s", nsockfd, (nsockfd == 1) ? "" : "es");
@@ -574,11 +424,16 @@ static int do_standalone_mode(int daemonize, int ipv4, int ipv6)
 		}
 	}
 
-	info("shutting down " PROGNAME);
+	info("shutting down %s", usbip_progname);
 	free(fds);
-	usbip_driver_close(driver);
+	usbipd_driver_close();
 
 	return 0;
+
+err_driver_close:
+	usbipd_driver_close();
+err_out:
+	return -1;
 }
 
 int main(int argc, char *argv[])
@@ -587,7 +442,6 @@ int main(int argc, char *argv[])
 		{ "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' },
 		{ "device",   no_argument,       NULL, 'e' },
 		{ "pid",      optional_argument, NULL, 'P' },
@@ -616,7 +470,7 @@ int main(int argc, char *argv[])
 		err("not running as root?");
 
 	cmd = cmd_standalone_mode;
-	driver = &host_driver;
+	usbipd_driver_init();
 	for (;;) {
 		opt = getopt_long(argc, argv, "46DdeP::t:hv", longopts, NULL);
 
@@ -640,7 +494,7 @@ int main(int argc, char *argv[])
 			cmd = cmd_help;
 			break;
 		case 'P':
-			pid_file = optarg ? optarg : DEFAULT_PID_FILE;
+			pid_file = optarg ? optarg : usbip_default_pid_file;
 			break;
 		case 't':
 			usbip_setup_port_number(optarg);
@@ -649,7 +503,7 @@ int main(int argc, char *argv[])
 			cmd = cmd_version;
 			break;
 		case 'e':
-			driver = &device_driver;
+			usbipd_driver_set(USBIPD_DRIVER_TYPE_DEVICE);
 			break;
 		case '?':
 			usbipd_help();
@@ -667,7 +521,7 @@ int main(int argc, char *argv[])
 		remove_pid_file();
 		break;
 	case cmd_version:
-		printf(PROGNAME " (%s)\n", usbip_version_string);
+		printf("%s (%s)\n", usbip_progname, usbip_version_string);
 		rc = 0;
 		break;
 	case cmd_help:
diff --git a/tools/usb/usbip/src/usbipd.h b/tools/usb/usbip/src/usbipd.h
new file mode 100644
index 0000000..9b69717
--- /dev/null
+++ b/tools/usb/usbip/src/usbipd.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2011 matt mooney <mfm@xxxxxxxxxxxxx>
+ *               2005-2007 Takahiro Hirofuchi
+ * Copyright (C) 2015-2016 Nobuo Iwata <nobuo.iwata@xxxxxxxxxxxxxxx>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __USBIPD_H
+#define __USBIPD_H
+
+#include "usbip_common.h"
+
+#ifdef HAVE_CONFIG_H
+#include "../config.h"
+#endif
+
+extern char *usbip_progname;
+extern char *usbip_default_pid_file;
+
+struct usbipd_recv_pdu_op {
+	uint16_t code;
+	int (*proc)(int connfd);
+};
+
+extern struct usbipd_recv_pdu_op usbipd_recv_pdu_ops[];
+
+struct usbipd_driver_ops {
+	void (*init)(void);
+	int (*set)(int type);
+	int (*open)(void);
+	void (*close)(void);
+	int (*refresh_device_list)(void);
+};
+
+extern struct usbipd_driver_ops usbipd_driver_ops;
+
+static inline void usbipd_driver_init(void)
+{
+	if (usbipd_driver_ops.init)
+		(*(usbipd_driver_ops.init))();
+}
+
+#define USBIPD_DRIVER_TYPE_HOST		0
+#define USBIPD_DRIVER_TYPE_DEVICE	1
+
+static inline void usbipd_driver_set(int type)
+{
+	if (usbipd_driver_ops.set)
+		(*(usbipd_driver_ops.set))(type);
+}
+
+static inline int usbipd_driver_open(void)
+{
+	if (usbipd_driver_ops.open)
+		return (*(usbipd_driver_ops.open))();
+	return 0;
+}
+
+static inline void usbipd_driver_close(void)
+{
+	if (usbipd_driver_ops.close)
+		(*(usbipd_driver_ops.close))();
+}
+
+static inline int usbipd_refresh_device_list(void)
+{
+	if (usbipd_driver_ops.refresh_device_list)
+		return (*(usbipd_driver_ops.refresh_device_list))();
+	return 0;
+}
+
+#endif /* __USBIPD_H */
diff --git a/tools/usb/usbip/src/usbipd_dev.c b/tools/usb/usbip/src/usbipd_dev.c
new file mode 100644
index 0000000..0d59edd
--- /dev/null
+++ b/tools/usb/usbip/src/usbipd_dev.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2011 matt mooney <mfm@xxxxxxxxxxxxx>
+ *               2005-2007 Takahiro Hirofuchi
+ * Copyright (C) 2015-2016 Nobuo Iwata <nobuo.iwata@xxxxxxxxxxxxxxx>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "../config.h"
+#endif
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include "usbip_host_driver.h"
+#include "usbip_host_common.h"
+#include "usbip_device_driver.h"
+#include "usbip_common.h"
+#include "usbip_network.h"
+#include "usbipd.h"
+#include "list.h"
+
+char *usbip_progname = "usbipd";
+char *usbip_default_pid_file = "/var/run/usbipd";
+
+static struct usbip_host_driver *driver;
+
+static void driver_init(void)
+{
+	driver = &host_driver;
+}
+
+static int driver_set(int type)
+{
+	switch (type) {
+	case USBIPD_DRIVER_TYPE_HOST:
+		driver = &host_driver;
+		break;
+	case USBIPD_DRIVER_TYPE_DEVICE:
+		driver = &device_driver;
+		break;
+	default:
+		err("unknown driver type to set %d", type);
+		return -1;
+	}
+	return 0;
+}
+
+static int driver_open(void)
+{
+	return usbip_driver_open(driver);
+}
+
+static void driver_close(void)
+{
+	usbip_driver_close(driver);
+}
+
+static int refresh_device_list(void)
+{
+	return usbip_refresh_device_list(driver);
+}
+
+struct usbipd_driver_ops usbipd_driver_ops = {
+	.init = driver_init,
+	.set = driver_set,
+	.open = driver_open,
+	.close = driver_close,
+	.refresh_device_list = refresh_device_list,
+};
+
+static int recv_request_import(int sockfd)
+{
+	struct op_import_request req;
+	struct usbip_exported_device *edev;
+	struct usbip_usb_device pdu_udev;
+	struct list_head *i;
+	int found = 0;
+	int error = 0;
+	int rc;
+
+	memset(&req, 0, sizeof(req));
+
+	rc = usbip_net_recv(sockfd, &req, sizeof(req));
+	if (rc < 0) {
+		dbg("usbip_net_recv failed: import request");
+		return -1;
+	}
+	PACK_OP_IMPORT_REQUEST(0, &req);
+
+	list_for_each(i, &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;
+			break;
+		}
+	}
+
+	if (found) {
+		/* export device needs a TCP/IP socket descriptor */
+		rc = usbip_export_device(edev, sockfd);
+		if (rc < 0)
+			error = 1;
+	} else {
+		info("requested device not found: %s", req.busid);
+		error = 1;
+	}
+
+	rc = usbip_net_send_op_common(sockfd, OP_REP_IMPORT,
+				      (!error ? ST_OK : ST_NA));
+	if (rc < 0) {
+		dbg("usbip_net_send_op_common failed: %#0x", OP_REP_IMPORT);
+		return -1;
+	}
+
+	if (error) {
+		dbg("import request busid %s: failed", req.busid);
+		return -1;
+	}
+
+	memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev));
+	usbip_net_pack_usb_device(1, &pdu_udev);
+
+	rc = usbip_net_send(sockfd, &pdu_udev, sizeof(pdu_udev));
+	if (rc < 0) {
+		dbg("usbip_net_send failed: devinfo");
+		return -1;
+	}
+
+	dbg("import request busid %s: complete", req.busid);
+
+	return 0;
+}
+
+static int send_reply_devlist(int connfd)
+{
+	struct usbip_exported_device *edev;
+	struct usbip_usb_device pdu_udev;
+	struct usbip_usb_interface pdu_uinf;
+	struct op_devlist_reply reply;
+	struct list_head *j;
+	int rc, i;
+
+	reply.ndev = driver->ndevs;
+	info("importable devices: %d", reply.ndev);
+
+	rc = usbip_net_send_op_common(connfd, OP_REP_DEVLIST, ST_OK);
+	if (rc < 0) {
+		dbg("usbip_net_send_op_common failed: %#0x", OP_REP_DEVLIST);
+		return -1;
+	}
+	PACK_OP_DEVLIST_REPLY(1, &reply);
+
+	rc = usbip_net_send(connfd, &reply, sizeof(reply));
+	if (rc < 0) {
+		dbg("usbip_net_send failed: %#0x", OP_REP_DEVLIST);
+		return -1;
+	}
+
+	list_for_each(j, &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);
+
+		rc = usbip_net_send(connfd, &pdu_udev, sizeof(pdu_udev));
+		if (rc < 0) {
+			dbg("usbip_net_send failed: pdu_udev");
+			return -1;
+		}
+
+		for (i = 0; i < edev->udev.bNumInterfaces; i++) {
+			dump_usb_interface(&edev->uinf[i]);
+			memcpy(&pdu_uinf, &edev->uinf[i], sizeof(pdu_uinf));
+			usbip_net_pack_usb_interface(1, &pdu_uinf);
+
+			rc = usbip_net_send(connfd, &pdu_uinf,
+					sizeof(pdu_uinf));
+			if (rc < 0) {
+				err("usbip_net_send failed: pdu_uinf");
+				return -1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int recv_request_devlist(int connfd)
+{
+	int rc;
+
+	rc = send_reply_devlist(connfd);
+	if (rc < 0) {
+		dbg("send_reply_devlist failed");
+		return -1;
+	}
+
+	return 0;
+}
+
+struct usbipd_recv_pdu_op usbipd_recv_pdu_ops[] = {
+	{OP_REQ_DEVLIST, recv_request_devlist},
+	{OP_REQ_IMPORT, recv_request_import},
+	{OP_REQ_DEVINFO, NULL},
+	{OP_REQ_CRYPKEY, NULL},
+	{OP_UNSPEC, NULL}
+};
-- 
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