brintos

brintos / linux-shallow public Read only

0
0
Text · 4.7 KiB · 531a415 Raw
244 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>4 *               2005-2007 Takahiro Hirofuchi5 * Copyright (C) 2015-2016 Samsung Electronics6 *               Igor Kotrasinski <i.kotrasinsk@samsung.com>7 *               Krzysztof Opasiak <k.opasiak@samsung.com>8 */9 10#include <sys/stat.h>11 12#include <limits.h>13#include <stdint.h>14#include <stdio.h>15#include <string.h>16 17#include <fcntl.h>18#include <getopt.h>19#include <unistd.h>20#include <errno.h>21 22#include "vhci_driver.h"23#include "usbip_common.h"24#include "usbip_network.h"25#include "usbip.h"26 27static const char usbip_attach_usage_string[] =28	"usbip attach <args>\n"29	"    -r, --remote=<host>      The machine with exported USB devices\n"30	"    -b, --busid=<busid>    Busid of the device on <host>\n"31	"    -d, --device=<devid>    Id of the virtual UDC on <host>\n";32 33void usbip_attach_usage(void)34{35	printf("usage: %s", usbip_attach_usage_string);36}37 38#define MAX_BUFF 10039static int record_connection(char *host, char *port, char *busid, int rhport)40{41	int fd;42	char path[PATH_MAX+1];43	char buff[MAX_BUFF+1];44	int ret;45 46	ret = mkdir(VHCI_STATE_PATH, 0700);47	if (ret < 0) {48		/* if VHCI_STATE_PATH exists, then it better be a directory */49		if (errno == EEXIST) {50			struct stat s;51 52			ret = stat(VHCI_STATE_PATH, &s);53			if (ret < 0)54				return -1;55			if (!(s.st_mode & S_IFDIR))56				return -1;57		} else58			return -1;59	}60 61	snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport);62 63	fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU);64	if (fd < 0)65		return -1;66 67	snprintf(buff, MAX_BUFF, "%s %s %s\n",68			host, port, busid);69 70	ret = write(fd, buff, strlen(buff));71	if (ret != (ssize_t) strlen(buff)) {72		close(fd);73		return -1;74	}75 76	close(fd);77 78	return 0;79}80 81static int import_device(int sockfd, struct usbip_usb_device *udev)82{83	int rc;84	int port;85	uint32_t speed = udev->speed;86 87	rc = usbip_vhci_driver_open();88	if (rc < 0) {89		err("open vhci_driver (is vhci_hcd loaded?)");90		goto err_out;91	}92 93	do {94		port = usbip_vhci_get_free_port(speed);95		if (port < 0) {96			err("no free port");97			goto err_driver_close;98		}99 100		dbg("got free port %d", port);101 102		rc = usbip_vhci_attach_device(port, sockfd, udev->busnum,103					      udev->devnum, udev->speed);104		if (rc < 0 && errno != EBUSY) {105			err("import device");106			goto err_driver_close;107		}108	} while (rc < 0);109 110	usbip_vhci_driver_close();111 112	return port;113 114err_driver_close:115	usbip_vhci_driver_close();116err_out:117	return -1;118}119 120static int query_import_device(int sockfd, char *busid)121{122	int rc;123	struct op_import_request request;124	struct op_import_reply   reply;125	uint16_t code = OP_REP_IMPORT;126	int status;127 128	memset(&request, 0, sizeof(request));129	memset(&reply, 0, sizeof(reply));130 131	/* send a request */132	rc = usbip_net_send_op_common(sockfd, OP_REQ_IMPORT, 0);133	if (rc < 0) {134		err("send op_common");135		return -1;136	}137 138	strncpy(request.busid, busid, SYSFS_BUS_ID_SIZE-1);139 140	PACK_OP_IMPORT_REQUEST(0, &request);141 142	rc = usbip_net_send(sockfd, (void *) &request, sizeof(request));143	if (rc < 0) {144		err("send op_import_request");145		return -1;146	}147 148	/* receive a reply */149	rc = usbip_net_recv_op_common(sockfd, &code, &status);150	if (rc < 0) {151		err("Attach Request for %s failed - %s\n",152		    busid, usbip_op_common_status_string(status));153		return -1;154	}155 156	rc = usbip_net_recv(sockfd, (void *) &reply, sizeof(reply));157	if (rc < 0) {158		err("recv op_import_reply");159		return -1;160	}161 162	PACK_OP_IMPORT_REPLY(0, &reply);163 164	/* check the reply */165	if (strncmp(reply.udev.busid, busid, SYSFS_BUS_ID_SIZE)) {166		err("recv different busid %s", reply.udev.busid);167		return -1;168	}169 170	/* import a device */171	return import_device(sockfd, &reply.udev);172}173 174static int attach_device(char *host, char *busid)175{176	int sockfd;177	int rc;178	int rhport;179 180	sockfd = usbip_net_tcp_connect(host, usbip_port_string);181	if (sockfd < 0) {182		err("tcp connect");183		return -1;184	}185 186	rhport = query_import_device(sockfd, busid);187	if (rhport < 0)188		return -1;189 190	close(sockfd);191 192	rc = record_connection(host, usbip_port_string, busid, rhport);193	if (rc < 0) {194		err("record connection");195		return -1;196	}197 198	return 0;199}200 201int usbip_attach(int argc, char *argv[])202{203	static const struct option opts[] = {204		{ "remote", required_argument, NULL, 'r' },205		{ "busid",  required_argument, NULL, 'b' },206		{ "device",  required_argument, NULL, 'd' },207		{ NULL, 0,  NULL, 0 }208	};209	char *host = NULL;210	char *busid = NULL;211	int opt;212	int ret = -1;213 214	for (;;) {215		opt = getopt_long(argc, argv, "d:r:b:", opts, NULL);216 217		if (opt == -1)218			break;219 220		switch (opt) {221		case 'r':222			host = optarg;223			break;224		case 'd':225		case 'b':226			busid = optarg;227			break;228		default:229			goto err_out;230		}231	}232 233	if (!host || !busid)234		goto err_out;235 236	ret = attach_device(host, busid);237	goto out;238 239err_out:240	usbip_attach_usage();241out:242	return ret;243}244