11ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2588b48caSValentina Manea /*
3588b48caSValentina Manea * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
4588b48caSValentina Manea * 2005-2007 Takahiro Hirofuchi
5e0546fd8SIgor Kotrasinski * Copyright (C) 2015-2016 Samsung Electronics
6e0546fd8SIgor Kotrasinski * Igor Kotrasinski <i.kotrasinsk@samsung.com>
7e0546fd8SIgor Kotrasinski * Krzysztof Opasiak <k.opasiak@samsung.com>
8588b48caSValentina Manea */
9588b48caSValentina Manea
10588b48caSValentina Manea #include <sys/stat.h>
11588b48caSValentina Manea
12588b48caSValentina Manea #include <limits.h>
13588b48caSValentina Manea #include <stdint.h>
14588b48caSValentina Manea #include <stdio.h>
15588b48caSValentina Manea #include <string.h>
16588b48caSValentina Manea
17588b48caSValentina Manea #include <fcntl.h>
18588b48caSValentina Manea #include <getopt.h>
19588b48caSValentina Manea #include <unistd.h>
20588b48caSValentina Manea #include <errno.h>
21588b48caSValentina Manea
22588b48caSValentina Manea #include "vhci_driver.h"
23588b48caSValentina Manea #include "usbip_common.h"
24588b48caSValentina Manea #include "usbip_network.h"
25588b48caSValentina Manea #include "usbip.h"
26588b48caSValentina Manea
27588b48caSValentina Manea static const char usbip_attach_usage_string[] =
28588b48caSValentina Manea "usbip attach <args>\n"
29588b48caSValentina Manea " -r, --remote=<host> The machine with exported USB devices\n"
30e0546fd8SIgor Kotrasinski " -b, --busid=<busid> Busid of the device on <host>\n"
31e0546fd8SIgor Kotrasinski " -d, --device=<devid> Id of the virtual UDC on <host>\n";
32588b48caSValentina Manea
usbip_attach_usage(void)33588b48caSValentina Manea void usbip_attach_usage(void)
34588b48caSValentina Manea {
35588b48caSValentina Manea printf("usage: %s", usbip_attach_usage_string);
36588b48caSValentina Manea }
37588b48caSValentina Manea
38588b48caSValentina Manea #define MAX_BUFF 100
record_connection(char * host,char * port,char * busid,int rhport)39588b48caSValentina Manea static int record_connection(char *host, char *port, char *busid, int rhport)
40588b48caSValentina Manea {
41588b48caSValentina Manea int fd;
42588b48caSValentina Manea char path[PATH_MAX+1];
43588b48caSValentina Manea char buff[MAX_BUFF+1];
44588b48caSValentina Manea int ret;
45588b48caSValentina Manea
46588b48caSValentina Manea ret = mkdir(VHCI_STATE_PATH, 0700);
47588b48caSValentina Manea if (ret < 0) {
48588b48caSValentina Manea /* if VHCI_STATE_PATH exists, then it better be a directory */
49588b48caSValentina Manea if (errno == EEXIST) {
50588b48caSValentina Manea struct stat s;
51588b48caSValentina Manea
52588b48caSValentina Manea ret = stat(VHCI_STATE_PATH, &s);
53588b48caSValentina Manea if (ret < 0)
54588b48caSValentina Manea return -1;
55588b48caSValentina Manea if (!(s.st_mode & S_IFDIR))
56588b48caSValentina Manea return -1;
57588b48caSValentina Manea } else
58588b48caSValentina Manea return -1;
59588b48caSValentina Manea }
60588b48caSValentina Manea
61588b48caSValentina Manea snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport);
62588b48caSValentina Manea
63588b48caSValentina Manea fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU);
64588b48caSValentina Manea if (fd < 0)
65588b48caSValentina Manea return -1;
66588b48caSValentina Manea
67588b48caSValentina Manea snprintf(buff, MAX_BUFF, "%s %s %s\n",
68588b48caSValentina Manea host, port, busid);
69588b48caSValentina Manea
70588b48caSValentina Manea ret = write(fd, buff, strlen(buff));
71588b48caSValentina Manea if (ret != (ssize_t) strlen(buff)) {
72588b48caSValentina Manea close(fd);
73588b48caSValentina Manea return -1;
74588b48caSValentina Manea }
75588b48caSValentina Manea
76588b48caSValentina Manea close(fd);
77588b48caSValentina Manea
78588b48caSValentina Manea return 0;
79588b48caSValentina Manea }
80588b48caSValentina Manea
import_device(int sockfd,struct usbip_usb_device * udev)81588b48caSValentina Manea static int import_device(int sockfd, struct usbip_usb_device *udev)
82588b48caSValentina Manea {
83588b48caSValentina Manea int rc;
84588b48caSValentina Manea int port;
851c9de5bfSYuyang Du uint32_t speed = udev->speed;
86588b48caSValentina Manea
87588b48caSValentina Manea rc = usbip_vhci_driver_open();
88588b48caSValentina Manea if (rc < 0) {
89*0c7f35d2SGalen Guyer err("open vhci_driver (is vhci_hcd loaded?)");
90a38711a8SNobuo Iwata goto err_out;
91588b48caSValentina Manea }
92588b48caSValentina Manea
93a38711a8SNobuo Iwata do {
941c9de5bfSYuyang Du port = usbip_vhci_get_free_port(speed);
95588b48caSValentina Manea if (port < 0) {
96588b48caSValentina Manea err("no free port");
97a38711a8SNobuo Iwata goto err_driver_close;
98588b48caSValentina Manea }
99588b48caSValentina Manea
100e55dea8eSYuyang Du dbg("got free port %d", port);
101e55dea8eSYuyang Du
102588b48caSValentina Manea rc = usbip_vhci_attach_device(port, sockfd, udev->busnum,
103588b48caSValentina Manea udev->devnum, udev->speed);
104a38711a8SNobuo Iwata if (rc < 0 && errno != EBUSY) {
105588b48caSValentina Manea err("import device");
106a38711a8SNobuo Iwata goto err_driver_close;
107588b48caSValentina Manea }
108a38711a8SNobuo Iwata } while (rc < 0);
109588b48caSValentina Manea
110588b48caSValentina Manea usbip_vhci_driver_close();
111588b48caSValentina Manea
112588b48caSValentina Manea return port;
113a38711a8SNobuo Iwata
114a38711a8SNobuo Iwata err_driver_close:
115a38711a8SNobuo Iwata usbip_vhci_driver_close();
116a38711a8SNobuo Iwata err_out:
117a38711a8SNobuo Iwata return -1;
118588b48caSValentina Manea }
119588b48caSValentina Manea
query_import_device(int sockfd,char * busid)120588b48caSValentina Manea static int query_import_device(int sockfd, char *busid)
121588b48caSValentina Manea {
122588b48caSValentina Manea int rc;
123588b48caSValentina Manea struct op_import_request request;
124588b48caSValentina Manea struct op_import_reply reply;
125588b48caSValentina Manea uint16_t code = OP_REP_IMPORT;
126ad81b15dSShuah Khan int status;
127588b48caSValentina Manea
128588b48caSValentina Manea memset(&request, 0, sizeof(request));
129588b48caSValentina Manea memset(&reply, 0, sizeof(reply));
130588b48caSValentina Manea
131588b48caSValentina Manea /* send a request */
132588b48caSValentina Manea rc = usbip_net_send_op_common(sockfd, OP_REQ_IMPORT, 0);
133588b48caSValentina Manea if (rc < 0) {
134588b48caSValentina Manea err("send op_common");
135588b48caSValentina Manea return -1;
136588b48caSValentina Manea }
137588b48caSValentina Manea
138588b48caSValentina Manea strncpy(request.busid, busid, SYSFS_BUS_ID_SIZE-1);
139588b48caSValentina Manea
140588b48caSValentina Manea PACK_OP_IMPORT_REQUEST(0, &request);
141588b48caSValentina Manea
142588b48caSValentina Manea rc = usbip_net_send(sockfd, (void *) &request, sizeof(request));
143588b48caSValentina Manea if (rc < 0) {
144588b48caSValentina Manea err("send op_import_request");
145588b48caSValentina Manea return -1;
146588b48caSValentina Manea }
147588b48caSValentina Manea
148588b48caSValentina Manea /* receive a reply */
149ad81b15dSShuah Khan rc = usbip_net_recv_op_common(sockfd, &code, &status);
150588b48caSValentina Manea if (rc < 0) {
151ad81b15dSShuah Khan err("Attach Request for %s failed - %s\n",
152ad81b15dSShuah Khan busid, usbip_op_common_status_string(status));
153588b48caSValentina Manea return -1;
154588b48caSValentina Manea }
155588b48caSValentina Manea
156588b48caSValentina Manea rc = usbip_net_recv(sockfd, (void *) &reply, sizeof(reply));
157588b48caSValentina Manea if (rc < 0) {
158588b48caSValentina Manea err("recv op_import_reply");
159588b48caSValentina Manea return -1;
160588b48caSValentina Manea }
161588b48caSValentina Manea
162588b48caSValentina Manea PACK_OP_IMPORT_REPLY(0, &reply);
163588b48caSValentina Manea
164588b48caSValentina Manea /* check the reply */
165588b48caSValentina Manea if (strncmp(reply.udev.busid, busid, SYSFS_BUS_ID_SIZE)) {
166588b48caSValentina Manea err("recv different busid %s", reply.udev.busid);
167588b48caSValentina Manea return -1;
168588b48caSValentina Manea }
169588b48caSValentina Manea
170588b48caSValentina Manea /* import a device */
171588b48caSValentina Manea return import_device(sockfd, &reply.udev);
172588b48caSValentina Manea }
173588b48caSValentina Manea
attach_device(char * host,char * busid)174588b48caSValentina Manea static int attach_device(char *host, char *busid)
175588b48caSValentina Manea {
176588b48caSValentina Manea int sockfd;
177588b48caSValentina Manea int rc;
178588b48caSValentina Manea int rhport;
179588b48caSValentina Manea
180588b48caSValentina Manea sockfd = usbip_net_tcp_connect(host, usbip_port_string);
181588b48caSValentina Manea if (sockfd < 0) {
182588b48caSValentina Manea err("tcp connect");
183588b48caSValentina Manea return -1;
184588b48caSValentina Manea }
185588b48caSValentina Manea
186588b48caSValentina Manea rhport = query_import_device(sockfd, busid);
187ad81b15dSShuah Khan if (rhport < 0)
188588b48caSValentina Manea return -1;
189588b48caSValentina Manea
190588b48caSValentina Manea close(sockfd);
191588b48caSValentina Manea
192588b48caSValentina Manea rc = record_connection(host, usbip_port_string, busid, rhport);
193588b48caSValentina Manea if (rc < 0) {
194588b48caSValentina Manea err("record connection");
195588b48caSValentina Manea return -1;
196588b48caSValentina Manea }
197588b48caSValentina Manea
198588b48caSValentina Manea return 0;
199588b48caSValentina Manea }
200588b48caSValentina Manea
usbip_attach(int argc,char * argv[])201588b48caSValentina Manea int usbip_attach(int argc, char *argv[])
202588b48caSValentina Manea {
203588b48caSValentina Manea static const struct option opts[] = {
204588b48caSValentina Manea { "remote", required_argument, NULL, 'r' },
205588b48caSValentina Manea { "busid", required_argument, NULL, 'b' },
206e0546fd8SIgor Kotrasinski { "device", required_argument, NULL, 'd' },
207588b48caSValentina Manea { NULL, 0, NULL, 0 }
208588b48caSValentina Manea };
209588b48caSValentina Manea char *host = NULL;
210588b48caSValentina Manea char *busid = NULL;
211588b48caSValentina Manea int opt;
212588b48caSValentina Manea int ret = -1;
213588b48caSValentina Manea
214588b48caSValentina Manea for (;;) {
215e0546fd8SIgor Kotrasinski opt = getopt_long(argc, argv, "d:r:b:", opts, NULL);
216588b48caSValentina Manea
217588b48caSValentina Manea if (opt == -1)
218588b48caSValentina Manea break;
219588b48caSValentina Manea
220588b48caSValentina Manea switch (opt) {
221588b48caSValentina Manea case 'r':
222588b48caSValentina Manea host = optarg;
223588b48caSValentina Manea break;
224e0546fd8SIgor Kotrasinski case 'd':
225588b48caSValentina Manea case 'b':
226588b48caSValentina Manea busid = optarg;
227588b48caSValentina Manea break;
228588b48caSValentina Manea default:
229588b48caSValentina Manea goto err_out;
230588b48caSValentina Manea }
231588b48caSValentina Manea }
232588b48caSValentina Manea
233588b48caSValentina Manea if (!host || !busid)
234588b48caSValentina Manea goto err_out;
235588b48caSValentina Manea
236588b48caSValentina Manea ret = attach_device(host, busid);
237588b48caSValentina Manea goto out;
238588b48caSValentina Manea
239588b48caSValentina Manea err_out:
240588b48caSValentina Manea usbip_attach_usage();
241588b48caSValentina Manea out:
242588b48caSValentina Manea return ret;
243588b48caSValentina Manea }
244