Commit | Line | Data |
---|---|---|
e9837bbb | 1 | /* |
2 | * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> | |
3 | * 2005-2007 Takahiro Hirofuchi | |
4 | * | |
5 | * This program is free software: you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation, either version 2 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
17 | */ | |
18 | ||
19 | #include <sys/stat.h> | |
e9837bbb | 20 | |
21 | #include <limits.h> | |
22 | #include <stdint.h> | |
23 | #include <stdio.h> | |
24 | #include <string.h> | |
25 | ||
26 | #include <fcntl.h> | |
27 | #include <getopt.h> | |
28 | #include <unistd.h> | |
82692d20 | 29 | #include <errno.h> |
e9837bbb | 30 | |
31 | #include "vhci_driver.h" | |
32 | #include "usbip_common.h" | |
33 | #include "usbip_network.h" | |
34 | #include "usbip.h" | |
35 | ||
36 | static const char usbip_attach_usage_string[] = | |
37 | "usbip attach <args>\n" | |
80e4b943 | 38 | " -r, --remote=<host> The machine with exported USB devices\n" |
e9837bbb | 39 | " -b, --busid=<busid> Busid of the device on <host>\n"; |
40 | ||
41 | void usbip_attach_usage(void) | |
42 | { | |
43 | printf("usage: %s", usbip_attach_usage_string); | |
44 | } | |
45 | ||
46 | #define MAX_BUFF 100 | |
47 | static int record_connection(char *host, char *port, char *busid, int rhport) | |
48 | { | |
49 | int fd; | |
50 | char path[PATH_MAX+1]; | |
51 | char buff[MAX_BUFF+1]; | |
52 | int ret; | |
53 | ||
549fb100 | 54 | ret = mkdir(VHCI_STATE_PATH, 0700); |
82692d20 IH |
55 | if (ret < 0) { |
56 | /* if VHCI_STATE_PATH exists, then it better be a directory */ | |
57 | if (errno == EEXIST) { | |
58 | struct stat s; | |
3eed8c03 | 59 | |
82692d20 IH |
60 | ret = stat(VHCI_STATE_PATH, &s); |
61 | if (ret < 0) | |
62 | return -1; | |
63 | if (!(s.st_mode & S_IFDIR)) | |
64 | return -1; | |
65 | } else | |
66 | return -1; | |
67 | } | |
e9837bbb | 68 | |
69 | snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport); | |
70 | ||
71 | fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU); | |
72 | if (fd < 0) | |
73 | return -1; | |
74 | ||
75 | snprintf(buff, MAX_BUFF, "%s %s %s\n", | |
76 | host, port, busid); | |
77 | ||
78 | ret = write(fd, buff, strlen(buff)); | |
79 | if (ret != (ssize_t) strlen(buff)) { | |
80 | close(fd); | |
81 | return -1; | |
82 | } | |
83 | ||
84 | close(fd); | |
85 | ||
86 | return 0; | |
87 | } | |
88 | ||
35dd0c2d | 89 | static int import_device(int sockfd, struct usbip_usb_device *udev) |
e9837bbb | 90 | { |
91 | int rc; | |
92 | int port; | |
93 | ||
94 | rc = usbip_vhci_driver_open(); | |
95 | if (rc < 0) { | |
96 | err("open vhci_driver"); | |
97 | return -1; | |
98 | } | |
99 | ||
100 | port = usbip_vhci_get_free_port(); | |
101 | if (port < 0) { | |
102 | err("no free port"); | |
103 | usbip_vhci_driver_close(); | |
104 | return -1; | |
105 | } | |
106 | ||
107 | rc = usbip_vhci_attach_device(port, sockfd, udev->busnum, | |
108 | udev->devnum, udev->speed); | |
109 | if (rc < 0) { | |
110 | err("import device"); | |
111 | usbip_vhci_driver_close(); | |
112 | return -1; | |
113 | } | |
114 | ||
115 | usbip_vhci_driver_close(); | |
116 | ||
117 | return port; | |
118 | } | |
119 | ||
120 | static 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 | ||
127 | memset(&request, 0, sizeof(request)); | |
128 | memset(&reply, 0, sizeof(reply)); | |
129 | ||
130 | /* send a request */ | |
3c6e9e8f | 131 | rc = usbip_net_send_op_common(sockfd, OP_REQ_IMPORT, 0); |
e9837bbb | 132 | if (rc < 0) { |
133 | err("send op_common"); | |
134 | return -1; | |
135 | } | |
136 | ||
137 | strncpy(request.busid, busid, SYSFS_BUS_ID_SIZE-1); | |
138 | ||
139 | PACK_OP_IMPORT_REQUEST(0, &request); | |
140 | ||
3c6e9e8f | 141 | rc = usbip_net_send(sockfd, (void *) &request, sizeof(request)); |
e9837bbb | 142 | if (rc < 0) { |
143 | err("send op_import_request"); | |
144 | return -1; | |
145 | } | |
146 | ||
6ec16a4c | 147 | /* receive a reply */ |
3c6e9e8f | 148 | rc = usbip_net_recv_op_common(sockfd, &code); |
e9837bbb | 149 | if (rc < 0) { |
150 | err("recv op_common"); | |
151 | return -1; | |
152 | } | |
153 | ||
3c6e9e8f | 154 | rc = usbip_net_recv(sockfd, (void *) &reply, sizeof(reply)); |
e9837bbb | 155 | if (rc < 0) { |
156 | err("recv op_import_reply"); | |
157 | return -1; | |
158 | } | |
159 | ||
160 | PACK_OP_IMPORT_REPLY(0, &reply); | |
161 | ||
162 | /* check the reply */ | |
163 | if (strncmp(reply.udev.busid, busid, SYSFS_BUS_ID_SIZE)) { | |
164 | err("recv different busid %s", reply.udev.busid); | |
165 | return -1; | |
166 | } | |
167 | ||
168 | /* import a device */ | |
169 | return import_device(sockfd, &reply.udev); | |
170 | } | |
171 | ||
172 | static int attach_device(char *host, char *busid) | |
173 | { | |
174 | int sockfd; | |
175 | int rc; | |
176 | int rhport; | |
177 | ||
7182f8f8 | 178 | sockfd = usbip_net_tcp_connect(host, usbip_port_string); |
e9837bbb | 179 | if (sockfd < 0) { |
180 | err("tcp connect"); | |
181 | return -1; | |
182 | } | |
183 | ||
184 | rhport = query_import_device(sockfd, busid); | |
185 | if (rhport < 0) { | |
186 | err("query"); | |
187 | return -1; | |
188 | } | |
189 | ||
190 | close(sockfd); | |
191 | ||
7182f8f8 | 192 | rc = record_connection(host, usbip_port_string, busid, rhport); |
e9837bbb | 193 | if (rc < 0) { |
194 | err("record connection"); | |
195 | return -1; | |
196 | } | |
197 | ||
198 | return 0; | |
199 | } | |
200 | ||
201 | int usbip_attach(int argc, char *argv[]) | |
202 | { | |
203 | static const struct option opts[] = { | |
80e4b943 KK |
204 | { "remote", required_argument, NULL, 'r' }, |
205 | { "busid", required_argument, NULL, 'b' }, | |
206 | { NULL, 0, NULL, 0 } | |
e9837bbb | 207 | }; |
208 | char *host = NULL; | |
209 | char *busid = NULL; | |
210 | int opt; | |
211 | int ret = -1; | |
212 | ||
213 | for (;;) { | |
80e4b943 | 214 | opt = getopt_long(argc, argv, "r:b:", opts, NULL); |
e9837bbb | 215 | |
216 | if (opt == -1) | |
217 | break; | |
218 | ||
219 | switch (opt) { | |
80e4b943 | 220 | case 'r': |
e9837bbb | 221 | host = optarg; |
222 | break; | |
223 | case 'b': | |
224 | busid = optarg; | |
225 | break; | |
226 | default: | |
227 | goto err_out; | |
228 | } | |
229 | } | |
230 | ||
231 | if (!host || !busid) | |
232 | goto err_out; | |
233 | ||
234 | ret = attach_device(host, busid); | |
235 | goto out; | |
236 | ||
237 | err_out: | |
238 | usbip_attach_usage(); | |
239 | out: | |
240 | return ret; | |
241 | } |