patches and low-level development discussion
 help / color / mirror / code / Atom feed
* [DEMO PATCH linux 0/3] usbip: tools: support USB over vsock(7)
@ 2021-10-13 13:53 Alyssa Ross
  2021-10-13 13:53 ` [DEMO PATCH linux 1/3] usbip: tools: in.usbipd: add Alyssa Ross
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Alyssa Ross @ 2021-10-13 13:53 UTC (permalink / raw)
  To: devel

This series implements USB over VSOCK sockets, as an alternative to
USB over IP.  This would allow, for example, a host system to share
its USB controller with a VM over VFIO, and then selectively attach to
certain specific USB devices exported by the VM over a VSOCK
connection.  If inter-guest VSOCK were to be implemented in the
kernel, or using a program like vsock-bridge[1] or socat[2], USB
devices could also be shared between VMs in this way, without having
to have a full-on networking setup between those VMs.

I've taken different approaches to implement the VSOCK support in each
of the usbip client and server.  For the server, I added a new
program, in.usbipd, that implements an inetd-style interface, taking a
socket from its environment.  This way, the socket could be a TCP
socket, a VSOCK socket, or something else entirely, and the program
doesn't have to care.  The usbip client, on the other hand, cares
about what type of socket it's communicating over, because it records
address information for the remote server.  Since this meant I had to
teach it about VSOCK anyway, to tell it how to find that information
for VSOCK sockets, it was easier to just extend the existing program
with an option to choose an alternative protocol family than to have
it take a socket from its environment.

I've tested this series by running in.usbipd in a NixOS VM, and then
attaching a device from it to my host system.  The following NixOS
configuration sets up an in.usbipd service listening on a VSOCK
socket:

  systemd.sockets.usbipd = {
    wantedBy = [ "sockets.target" ];
    listenStreams = [ "vsock::3240" ];
    socketConfig.Accept = "yes";
  };

  systemd.services."usbipd@" = {
    serviceConfig.ExecStart = "${usbip}/bin/in.usbipd";
    serviceConfig.StandardInput = "socket";
    serviceConfig.StandardOutput = "socket";
    serviceConfig.StandardError = "journal";
  };

[1]: https://github.com/stefano-garzarella/vsock-bridge
[2]: http://www.dest-unreach.org/socat/

Alyssa Ross (3):
  usbip: tools: in.usbipd: add
  usbip: tools: usbip: record protocol
  usbip: tools: usbip: support vsock(7) connections

 tools/usb/usbip/libsrc/vhci_driver.c |  26 ++-
 tools/usb/usbip/src/Makefile.am      |   4 +-
 tools/usb/usbip/src/in.usbipd.c      | 326 +++++++++++++++++++++++++++
 tools/usb/usbip/src/usbip_attach.c   |  54 ++++-
 tools/usb/usbip/src/usbip_list.c     |  43 +++-
 tools/usb/usbip/src/usbip_network.c  |  51 ++++-
 tools/usb/usbip/src/usbip_network.h  |   4 +-
 7 files changed, 470 insertions(+), 38 deletions(-)
 create mode 100644 tools/usb/usbip/src/in.usbipd.c


base-commit: 620b74d01b9d4393bef6742bf121908322c2fe0b
-- 
2.32.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [DEMO PATCH linux 1/3] usbip: tools: in.usbipd: add
  2021-10-13 13:53 [DEMO PATCH linux 0/3] usbip: tools: support USB over vsock(7) Alyssa Ross
@ 2021-10-13 13:53 ` Alyssa Ross
  2021-10-13 13:53 ` [DEMO PATCH linux 2/3] usbip: tools: usbip: record protocol Alyssa Ross
  2021-10-13 13:53 ` [DEMO PATCH linux 3/3] usbip: tools: usbip: support vsock(7) connections Alyssa Ross
  2 siblings, 0 replies; 4+ messages in thread
From: Alyssa Ross @ 2021-10-13 13:53 UTC (permalink / raw)
  To: devel

This is an inetd-style version of usbipd, which allows it to be easily
socket-activated, and work with other types of socket.  I implemented
this by just copying usbipd.c, and then deleting all the code that
created, bound, and listened on a socket.  In future, this could be
made more maintainable by having it share the bulk of its code with
usbipd.

Signed-off-by: Alyssa Ross <hi@alyssa.is>
---
 tools/usb/usbip/src/Makefile.am |   4 +-
 tools/usb/usbip/src/in.usbipd.c | 326 ++++++++++++++++++++++++++++++++
 2 files changed, 329 insertions(+), 1 deletion(-)
 create mode 100644 tools/usb/usbip/src/in.usbipd.c

diff --git a/tools/usb/usbip/src/Makefile.am b/tools/usb/usbip/src/Makefile.am
index e26f39e0579d..d64613733fd5 100644
--- a/tools/usb/usbip/src/Makefile.am
+++ b/tools/usb/usbip/src/Makefile.am
@@ -3,10 +3,12 @@ AM_CPPFLAGS = -I$(top_srcdir)/libsrc -DUSBIDS_FILE='"@USBIDS_DIR@/usb.ids"'
 AM_CFLAGS   = @EXTRA_CFLAGS@
 LDADD       = $(top_builddir)/libsrc/libusbip.la
 
-sbin_PROGRAMS := usbip usbipd
+sbin_PROGRAMS := usbip usbipd in.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_port.c
 
 usbipd_SOURCES := usbip_network.h usbipd.c usbip_network.c
+
+in_usbipd_SOURCES := usbip_network.h in.usbipd.c usbip_network.c
diff --git a/tools/usb/usbip/src/in.usbipd.c b/tools/usb/usbip/src/in.usbipd.c
new file mode 100644
index 000000000000..fc60f485fb4c
--- /dev/null
+++ b/tools/usb/usbip/src/in.usbipd.c
@@ -0,0 +1,326 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ *               2005-2007 Takahiro Hirofuchi
+ * Copyright (C) 2015-2016 Samsung Electronics
+ *               Igor Kotrasinski <i.kotrasinsk@samsung.com>
+ *               Krzysztof Opasiak <k.opasiak@samsung.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "../config.h"
+#endif
+
+#define _GNU_SOURCE
+
+#include <getopt.h>
+
+#include "usbip_host_driver.h"
+#include "usbip_device_driver.h"
+#include "usbip_network.h"
+
+#undef  PROGNAME
+#define PROGNAME "in.usbipd"
+#define MAXSOCKFD 20
+
+#define MAIN_LOOP_TIMEOUT 10
+
+static const char usbip_version_string[] = PACKAGE_STRING;
+
+static const char in_usbipd_help_string[] =
+	"usage: in.usbipd [options]\n"
+	"\n"
+	"	-e, --device\n"
+	"		Run in device mode.\n"
+	"		Rather than drive an attached device, create\n"
+	"		a virtual UDC to bind gadgets to.\n"
+	"\n"
+	"	-d, --debug\n"
+	"		Print debugging information.\n"
+	"\n"
+	"	-h, --help\n"
+	"		Print this help.\n"
+	"\n"
+	"	-v, --version\n"
+	"		Show version.\n";
+
+static struct usbip_host_driver *driver;
+
+static void in_usbipd_help(void)
+{
+	printf("%s\n", in_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 status = ST_OK;
+	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 */
+		status = usbip_export_device(edev, sockfd);
+		if (status < 0)
+			status = ST_NA;
+	} else {
+		info("requested device not found: %s", req.busid);
+		status = ST_NODEV;
+	}
+
+	rc = usbip_net_send_op_common(sockfd, OP_REP_IMPORT, status);
+	if (rc < 0) {
+		dbg("usbip_net_send_op_common failed: %#0x", OP_REP_IMPORT);
+		return -1;
+	}
+
+	if (status) {
+		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;
+
+	/*
+	 * Exclude devices that are already exported to a client from
+	 * the exportable device list to avoid:
+	 *	- import requests for devices that are exported only to
+	 *	  fail the request.
+	 *	- revealing devices that are imported by a client to
+	 *	  another client.
+	 */
+
+	reply.ndev = 0;
+	/* number of exported devices */
+	list_for_each(j, &driver->edev_list) {
+		edev = list_entry(j, struct usbip_exported_device, node);
+		if (edev->status != SDEV_ST_USED)
+			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);
+		if (edev->status == SDEV_ST_USED)
+			continue;
+
+		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;
+}
+
+static int recv_pdu(int connfd)
+{
+	uint16_t code = OP_UNSPEC;
+	int ret;
+	int status;
+
+	ret = usbip_net_recv_op_common(connfd, &code, &status);
+	if (ret < 0) {
+		dbg("could not receive opcode: %#0x", code);
+		return -1;
+	}
+
+	ret = usbip_refresh_device_list(driver);
+	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:
+		err("received an unknown opcode: %#0x", code);
+		ret = -1;
+	}
+
+	if (ret == 0)
+		info("request %#0x(%d): complete", code, connfd);
+	else
+		info("request %#0x(%d): failed", code, connfd);
+
+	return ret;
+}
+
+int main(int argc, char *argv[])
+{
+	static const struct option longopts[] = {
+		{ "debug",    no_argument, NULL, 'd' },
+		{ "device",   no_argument, NULL, 'e' },
+		{ "help",     no_argument, NULL, 'h' },
+		{ "version",  no_argument, NULL, 'v' },
+		{ NULL,	      0,           NULL,  0  }
+	};
+
+	enum {
+		cmd_standalone_mode = 1,
+		cmd_help,
+		cmd_version
+	} cmd;
+
+	int opt, rc = -1;
+
+	usbip_use_stderr = 1;
+	usbip_use_syslog = 0;
+
+	if (geteuid() != 0)
+		err("not running as root?");
+
+	cmd = cmd_standalone_mode;
+	driver = &host_driver;
+	for (;;) {
+		opt = getopt_long(argc, argv, "dehv", longopts, NULL);
+
+		if (opt == -1)
+			break;
+
+		switch (opt) {
+		case 'd':
+			usbip_use_debug = 1;
+			break;
+		case 'h':
+			cmd = cmd_help;
+			break;
+		case 'v':
+			cmd = cmd_version;
+			break;
+		case 'e':
+			driver = &device_driver;
+			break;
+		case '?':
+			in_usbipd_help();
+		default:
+			goto err_out;
+		}
+	}
+
+	switch (cmd) {
+	case cmd_standalone_mode:
+		rc = recv_pdu(0);
+		break;
+	case cmd_version:
+		printf(PROGNAME " (%s)\n", usbip_version_string);
+		rc = 0;
+		break;
+	case cmd_help:
+		in_usbipd_help();
+		rc = 0;
+		break;
+	default:
+		in_usbipd_help();
+		goto err_out;
+	}
+
+err_out:
+	return (rc > -1 ? EXIT_SUCCESS : EXIT_FAILURE);
+}
-- 
2.32.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [DEMO PATCH linux 2/3] usbip: tools: usbip: record protocol
  2021-10-13 13:53 [DEMO PATCH linux 0/3] usbip: tools: support USB over vsock(7) Alyssa Ross
  2021-10-13 13:53 ` [DEMO PATCH linux 1/3] usbip: tools: in.usbipd: add Alyssa Ross
@ 2021-10-13 13:53 ` Alyssa Ross
  2021-10-13 13:53 ` [DEMO PATCH linux 3/3] usbip: tools: usbip: support vsock(7) connections Alyssa Ross
  2 siblings, 0 replies; 4+ messages in thread
From: Alyssa Ross @ 2021-10-13 13:53 UTC (permalink / raw)
  To: devel

This is the first step toward supporting protocol families other than
IP in the USB/IP client.  This changes the format of the connection
records in the filesystem, so all USB/IP devices should be detached
before applying this change.  The output format for "usbip port"
remains the same in the default case.  If VSOCK is being used, it will
display URLs starting with usbvsock:// instead of usbip://.

Signed-off-by: Alyssa Ross <hi@alyssa.is>
---
 tools/usb/usbip/libsrc/vhci_driver.c | 26 +++++++++++++------------
 tools/usb/usbip/src/usbip_attach.c   | 29 ++++++++++++++++++++++++----
 2 files changed, 39 insertions(+), 16 deletions(-)

diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c
index 8159fd98680b..98945078ccf4 100644
--- a/tools/usb/usbip/libsrc/vhci_driver.c
+++ b/tools/usb/usbip/libsrc/vhci_driver.c
@@ -184,16 +184,17 @@ static int get_ncontrollers(void)
  * 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)
+static int read_record(int rhport, char *proto, unsigned long proto_len,
+		char *host, unsigned long host_len, char *port,
+		unsigned long port_len, char *busid)
 {
 	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;
+	char delim[] = {' ', ' ', ' ', '\n'};
+	int max_len[] = {(int)proto_len, (int)host_len, (int)port_len, SYSFS_BUS_ID_SIZE};
+	size_t buffer_len = proto_len + host_len + port_len + SYSFS_BUS_ID_SIZE + 5;
 
 	buffer = malloc(buffer_len);
 	if (!buffer)
@@ -218,7 +219,7 @@ static int read_record(int rhport, char *host, unsigned long host_len,
 
 	/* validate the length of each of the 3 parts */
 	start = buffer;
-	for (part = 0; part < 3; part++) {
+	for (part = 0; part < 4; part++) {
 		end = strchr(start, delim[part]);
 		if (end == NULL || (end - start) > max_len[part]) {
 			free(buffer);
@@ -227,7 +228,7 @@ static int read_record(int rhport, char *host, unsigned long host_len,
 		start = end + 1;
 	}
 
-	if (sscanf(buffer, "%s %s %s\n", host, port, busid) != 3) {
+	if (sscanf(buffer, "%s %s %s %s\n", proto, host, port, busid) != 4) {
 		err("sscanf");
 		free(buffer);
 		return -1;
@@ -426,6 +427,7 @@ int usbip_vhci_detach_device(uint8_t port)
 int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev)
 {
 	char product_name[100];
+	char proto[] = "unknown protocol";
 	char host[NI_MAXHOST] = "unknown host";
 	char serv[NI_MAXSERV] = "unknown port";
 	char remote_busid[SYSFS_BUS_ID_SIZE];
@@ -435,8 +437,8 @@ int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev)
 	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);
+	ret = read_record(idev->port, proto, sizeof(proto), host, sizeof(host),
+			  serv, sizeof(serv), remote_busid);
 	if (ret) {
 		err("read_record");
 		read_record_error = 1;
@@ -452,12 +454,12 @@ int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev)
 	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 -> usb%s://%s:%s/%s\n", idev->udev.busid,
+		       proto, 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",
+		printf("%10s -> unknown protocol, host, remote port and remote busid\n",
 		       idev->udev.busid);
 		printf("%10s -> remote bus/dev %03d/%03d\n", " ",
 		       idev->busnum, idev->devnum);
diff --git a/tools/usb/usbip/src/usbip_attach.c b/tools/usb/usbip/src/usbip_attach.c
index b4aeb9f1f493..b202c7513bc3 100644
--- a/tools/usb/usbip/src/usbip_attach.c
+++ b/tools/usb/usbip/src/usbip_attach.c
@@ -8,6 +8,7 @@
  */
 
 #include <sys/stat.h>
+#include <sys/socket.h>
 
 #include <limits.h>
 #include <stdint.h>
@@ -36,7 +37,7 @@ void usbip_attach_usage(void)
 }
 
 #define MAX_BUFF 100
-static int record_connection(char *host, char *port, char *busid, int rhport)
+static int record_connection(char *proto, char *host, char *port, char *busid, int rhport)
 {
 	int fd;
 	char path[PATH_MAX+1];
@@ -64,8 +65,8 @@ static int record_connection(char *host, char *port, char *busid, int rhport)
 	if (fd < 0)
 		return -1;
 
-	snprintf(buff, MAX_BUFF, "%s %s %s\n",
-			host, port, busid);
+	snprintf(buff, MAX_BUFF, "%s %s %s %s\n",
+			proto, host, port, busid);
 
 	ret = write(fd, buff, strlen(buff));
 	if (ret != (ssize_t) strlen(buff)) {
@@ -171,11 +172,28 @@ static int query_import_device(int sockfd, char *busid)
 	return import_device(sockfd, &reply.udev);
 }
 
+static int get_protocol_family(int fd, char **proto)
+{
+	struct sockaddr addr;
+	socklen_t addrlen = sizeof addr;
+	if (getsockname(fd, &addr, &addrlen) == -1)
+		return -1;
+
+	switch (addr.sa_family) {
+	case AF_INET:
+	case AF_INET6:
+		*proto = "ip";
+		return 0;
+	}
+	return -1;
+}
+
 static int attach_device(char *host, char *busid)
 {
 	int sockfd;
 	int rc;
 	int rhport;
+	char *pf;
 
 	sockfd = usbip_net_tcp_connect(host, usbip_port_string);
 	if (sockfd < 0) {
@@ -183,13 +201,16 @@ static int attach_device(char *host, char *busid)
 		return -1;
 	}
 
+	if (get_protocol_family(sockfd, &pf) == -1)
+		return -1;
+
 	rhport = query_import_device(sockfd, busid);
 	if (rhport < 0)
 		return -1;
 
 	close(sockfd);
 
-	rc = record_connection(host, usbip_port_string, busid, rhport);
+	rc = record_connection(pf, host, usbip_port_string, busid, rhport);
 	if (rc < 0) {
 		err("record connection");
 		return -1;
-- 
2.32.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [DEMO PATCH linux 3/3] usbip: tools: usbip: support vsock(7) connections
  2021-10-13 13:53 [DEMO PATCH linux 0/3] usbip: tools: support USB over vsock(7) Alyssa Ross
  2021-10-13 13:53 ` [DEMO PATCH linux 1/3] usbip: tools: in.usbipd: add Alyssa Ross
  2021-10-13 13:53 ` [DEMO PATCH linux 2/3] usbip: tools: usbip: record protocol Alyssa Ross
@ 2021-10-13 13:53 ` Alyssa Ross
  2 siblings, 0 replies; 4+ messages in thread
From: Alyssa Ross @ 2021-10-13 13:53 UTC (permalink / raw)
  To: devel

"usbip list" and "usbip attach" can now both be given a "-P vsock" to
tell them to use vsock sockets instead of ip sockets.

Signed-off-by: Alyssa Ross <hi@alyssa.is>
---
 tools/usb/usbip/src/usbip_attach.c  | 25 +++++++++-----
 tools/usb/usbip/src/usbip_list.c    | 43 +++++++++++++++++-------
 tools/usb/usbip/src/usbip_network.c | 51 ++++++++++++++++++++++++++++-
 tools/usb/usbip/src/usbip_network.h |  4 ++-
 4 files changed, 102 insertions(+), 21 deletions(-)

diff --git a/tools/usb/usbip/src/usbip_attach.c b/tools/usb/usbip/src/usbip_attach.c
index b202c7513bc3..74adf9f09d01 100644
--- a/tools/usb/usbip/src/usbip_attach.c
+++ b/tools/usb/usbip/src/usbip_attach.c
@@ -26,10 +26,11 @@
 #include "usbip.h"
 
 static const char usbip_attach_usage_string[] =
-	"usbip attach <args>\n"
-	"    -r, --remote=<host>      The machine with exported USB devices\n"
+	"usbip attach [-P|--proto] <args>\n"
+	"    -P, --proto            Protocol family (ip or vsock)\n"
+	"    -r, --remote=<host>    The machine with exported USB devices\n"
 	"    -b, --busid=<busid>    Busid of the device on <host>\n"
-	"    -d, --device=<devid>    Id of the virtual UDC on <host>\n";
+	"    -d, --device=<devid>   Id of the virtual UDC on <host>\n";
 
 void usbip_attach_usage(void)
 {
@@ -184,20 +185,23 @@ static int get_protocol_family(int fd, char **proto)
 	case AF_INET6:
 		*proto = "ip";
 		return 0;
+	case AF_VSOCK:
+		*proto = "vsock";
+		return 0;
 	}
 	return -1;
 }
 
-static int attach_device(char *host, char *busid)
+static int attach_device(char *proto, char *host, char *busid)
 {
 	int sockfd;
 	int rc;
 	int rhport;
 	char *pf;
 
-	sockfd = usbip_net_tcp_connect(host, usbip_port_string);
+	sockfd = usbip_net_connect(proto, host, usbip_port_string);
 	if (sockfd < 0) {
-		err("tcp connect");
+		err("connect");
 		return -1;
 	}
 
@@ -222,23 +226,28 @@ static int attach_device(char *host, char *busid)
 int usbip_attach(int argc, char *argv[])
 {
 	static const struct option opts[] = {
+		{ "proto", required_argument, NULL, 'P' },
 		{ "remote", required_argument, NULL, 'r' },
 		{ "busid",  required_argument, NULL, 'b' },
 		{ "device",  required_argument, NULL, 'd' },
 		{ NULL, 0,  NULL, 0 }
 	};
+	char *proto = NULL;
 	char *host = NULL;
 	char *busid = NULL;
 	int opt;
 	int ret = -1;
 
 	for (;;) {
-		opt = getopt_long(argc, argv, "d:r:b:", opts, NULL);
+		opt = getopt_long(argc, argv, "P:d:r:b:", opts, NULL);
 
 		if (opt == -1)
 			break;
 
 		switch (opt) {
+		case 'P':
+			proto = optarg;
+			break;
 		case 'r':
 			host = optarg;
 			break;
@@ -254,7 +263,7 @@ int usbip_attach(int argc, char *argv[])
 	if (!host || !busid)
 		goto err_out;
 
-	ret = attach_device(host, busid);
+	ret = attach_device(proto, host, busid);
 	goto out;
 
 err_out:
diff --git a/tools/usb/usbip/src/usbip_list.c b/tools/usb/usbip/src/usbip_list.c
index 3d810bcca02f..f479e15f9ae7 100644
--- a/tools/usb/usbip/src/usbip_list.c
+++ b/tools/usb/usbip/src/usbip_list.c
@@ -30,7 +30,8 @@
 #include "usbip.h"
 
 static const char usbip_list_usage_string[] =
-	"usbip list [-p|--parsable] <args>\n"
+	"usbip list [-P|--proto] [-p|--parsable] <args>\n"
+	"    -P, --proto            Protocol family (ip or vsock)\n"
 	"    -p, --parsable         Parsable list format\n"
 	"    -r, --remote=<host>    List the exportable USB devices on <host>\n"
 	"    -l, --local            List the local USB devices\n"
@@ -125,12 +126,12 @@ static int get_exported_devices(char *host, int sockfd)
 	return 0;
 }
 
-static int list_exported_devices(char *host)
+static int list_exported_devices(char *proto, char *host)
 {
 	int rc;
 	int sockfd;
 
-	sockfd = usbip_net_tcp_connect(host, usbip_port_string);
+	sockfd = usbip_net_connect(proto, host, usbip_port_string);
 	if (sockfd < 0) {
 		err("could not connect to %s:%s: %s", host,
 		    usbip_port_string, gai_strerror(sockfd));
@@ -326,44 +327,64 @@ static int list_gadget_devices(bool parsable)
 int usbip_list(int argc, char *argv[])
 {
 	static const struct option opts[] = {
+		{ "proto",    required_argument, NULL, 'P' },
 		{ "parsable", no_argument,       NULL, 'p' },
 		{ "remote",   required_argument, NULL, 'r' },
 		{ "local",    no_argument,       NULL, 'l' },
-		{ "device",    no_argument,       NULL, 'd' },
+		{ "device",   no_argument,       NULL, 'd' },
 		{ NULL,       0,                 NULL,  0  }
 	};
 
 	bool parsable = false;
+	char *proto = NULL, *host = NULL;
 	int opt;
+	int mode = -1;
 	int ret = -1;
 
 	if (usbip_names_init(USBIDS_FILE))
 		err("failed to open %s", USBIDS_FILE);
 
 	for (;;) {
-		opt = getopt_long(argc, argv, "pr:ld", opts, NULL);
+		opt = getopt_long(argc, argv, "P:pr:ld", opts, NULL);
 
 		if (opt == -1)
 			break;
 
 		switch (opt) {
+		case 'P':
+			proto = optarg;
+			break;
 		case 'p':
 			parsable = true;
 			break;
 		case 'r':
-			ret = list_exported_devices(optarg);
-			goto out;
+			host = optarg;
+			/* fall through */
 		case 'l':
-			ret = list_devices(parsable);
-			goto out;
 		case 'd':
-			ret = list_gadget_devices(parsable);
-			goto out;
+			if (mode != -1) {
+				err("-%c and -%c are mutually exclusive", mode, opt);
+				goto out;
+			}
+			mode = opt;
+			break;
 		default:
 			goto err_out;
 		}
 	}
 
+	switch (mode) {
+	case 'r':
+		ret = list_exported_devices(proto, host);
+		goto out;
+	case 'l':
+		ret = list_devices(parsable);
+		goto out;
+	case 'd':
+		ret = list_gadget_devices(parsable);
+		goto out;
+	}
+
 err_out:
 	usbip_list_usage();
 out:
diff --git a/tools/usb/usbip/src/usbip_network.c b/tools/usb/usbip/src/usbip_network.c
index ed4dc8c14269..c096dbb6afb3 100644
--- a/tools/usb/usbip/src/usbip_network.c
+++ b/tools/usb/usbip/src/usbip_network.c
@@ -9,10 +9,14 @@
 #include <string.h>
 
 #include <arpa/inet.h>
+#include <errno.h>
+#include <limits.h>
 #include <netdb.h>
 #include <netinet/tcp.h>
 #include <unistd.h>
 
+#include <linux/vm_sockets.h>
+
 #ifdef HAVE_LIBWRAP
 #include <tcpd.h>
 #endif
@@ -258,7 +262,7 @@ int usbip_net_set_v6only(int sockfd)
 /*
  * IPv6 Ready
  */
-int usbip_net_tcp_connect(char *hostname, char *service)
+int usbip_net_ip_connect(char *hostname, char *service)
 {
 	struct addrinfo hints, *res, *rp;
 	int sockfd;
@@ -301,3 +305,48 @@ int usbip_net_tcp_connect(char *hostname, char *service)
 
 	return sockfd;
 }
+
+int usbip_net_vsock_connect(char *cid_s, char *port_s)
+{
+	char *cid_end, *port_end;
+	int sockfd;
+	unsigned long cid, port;
+	struct sockaddr_vm addr = { 0 };
+	socklen_t addrlen = sizeof addr;
+
+	errno = 0;
+	cid = strtoul(cid_s, &cid_end, 0);
+	port = strtoul(port_s, &port_end, 0);
+	if (*cid_end || *port_end) {
+		errno = EINVAL;
+		return EAI_SYSTEM;
+	}
+	if (errno)
+		return EAI_SYSTEM;
+	if (cid > UINT_MAX || port > UINT_MAX) {
+		errno = ERANGE;
+		return EAI_SYSTEM;
+	}
+
+	addr.svm_family = AF_VSOCK;
+	addr.svm_port = port;
+	addr.svm_cid = cid;
+
+	sockfd = socket(AF_VSOCK, SOCK_STREAM, 0);
+	if (sockfd == -1)
+		return EAI_SYSTEM;
+	if (connect(sockfd, (struct sockaddr *)&addr, addrlen) == -1)
+		return EAI_SYSTEM;
+	return sockfd;
+}
+
+int usbip_net_connect(char *proto, char *host, char *service)
+{
+	if (!proto || !strcmp(proto, "ip"))
+		return usbip_net_ip_connect(host, service);
+	if (!strcmp(proto, "vsock"))
+		return usbip_net_vsock_connect(host, service);
+
+	errno = EPROTONOSUPPORT;
+	return EAI_SYSTEM;
+}
diff --git a/tools/usb/usbip/src/usbip_network.h b/tools/usb/usbip/src/usbip_network.h
index 83b4c5344f72..fc2579525bc3 100644
--- a/tools/usb/usbip/src/usbip_network.h
+++ b/tools/usb/usbip/src/usbip_network.h
@@ -173,6 +173,8 @@ 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);
+int usbip_net_ip_connect(char *hostname, char *port);
+int usbip_net_vsock_connect(char *cid, char *port);
+int usbip_net_connect(char *proto, char *host, char *port);
 
 #endif /* __USBIP_NETWORK_H */
-- 
2.32.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2021-10-13 13:54 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-13 13:53 [DEMO PATCH linux 0/3] usbip: tools: support USB over vsock(7) Alyssa Ross
2021-10-13 13:53 ` [DEMO PATCH linux 1/3] usbip: tools: in.usbipd: add Alyssa Ross
2021-10-13 13:53 ` [DEMO PATCH linux 2/3] usbip: tools: usbip: record protocol Alyssa Ross
2021-10-13 13:53 ` [DEMO PATCH linux 3/3] usbip: tools: usbip: support vsock(7) connections Alyssa Ross

Code repositories for project(s) associated with this public inbox

	https://spectrum-os.org/git/crosvm
	https://spectrum-os.org/git/doc
	https://spectrum-os.org/git/mktuntap
	https://spectrum-os.org/git/nixpkgs
	https://spectrum-os.org/git/spectrum
	https://spectrum-os.org/git/ucspi-vsock
	https://spectrum-os.org/git/www

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).