aboutsummaryrefslogtreecommitdiffstats
path: root/tools/usb/usbip/src
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2014-10-20 12:55:07 -0400
committerMark Brown <broonie@kernel.org>2014-10-20 13:27:32 -0400
commitb7a40242c82cd73cfcea305f23e67d068dd8401a (patch)
tree251b49d19cd7c371847ae1f951e1b537ca0e1c15 /tools/usb/usbip/src
parentd26833bfce5e56017bea9f1f50838f20e18e7b7e (diff)
parent9c6de47d53a3ce8df1642ae67823688eb98a190a (diff)
Merge branch 'fix/dw' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi into spi-dw
Conflicts: drivers/spi/spi-dw-mid.c
Diffstat (limited to 'tools/usb/usbip/src')
-rw-r--r--tools/usb/usbip/src/Makefile.am11
-rw-r--r--tools/usb/usbip/src/usbip.c201
-rw-r--r--tools/usb/usbip/src/usbip.h40
-rw-r--r--tools/usb/usbip/src/usbip_attach.c241
-rw-r--r--tools/usb/usbip/src/usbip_bind.c214
-rw-r--r--tools/usb/usbip/src/usbip_detach.c110
-rw-r--r--tools/usb/usbip/src/usbip_list.c283
-rw-r--r--tools/usb/usbip/src/usbip_network.c303
-rw-r--r--tools/usb/usbip/src/usbip_network.h185
-rw-r--r--tools/usb/usbip/src/usbip_port.c57
-rw-r--r--tools/usb/usbip/src/usbip_unbind.c141
-rw-r--r--tools/usb/usbip/src/usbipd.c679
-rw-r--r--tools/usb/usbip/src/utils.c52
-rw-r--r--tools/usb/usbip/src/utils.h25
14 files changed, 2542 insertions, 0 deletions
diff --git a/tools/usb/usbip/src/Makefile.am b/tools/usb/usbip/src/Makefile.am
new file mode 100644
index 000000000000..e81a4ebadeff
--- /dev/null
+++ b/tools/usb/usbip/src/Makefile.am
@@ -0,0 +1,11 @@
1AM_CPPFLAGS = -I$(top_srcdir)/libsrc -DUSBIDS_FILE='"@USBIDS_DIR@/usb.ids"'
2AM_CFLAGS = @EXTRA_CFLAGS@
3LDADD = $(top_builddir)/libsrc/libusbip.la
4
5sbin_PROGRAMS := usbip usbipd
6
7usbip_SOURCES := usbip.h utils.h usbip.c utils.c usbip_network.c \
8 usbip_attach.c usbip_detach.c usbip_list.c \
9 usbip_bind.c usbip_unbind.c usbip_port.c
10
11usbipd_SOURCES := usbip_network.h usbipd.c usbip_network.c
diff --git a/tools/usb/usbip/src/usbip.c b/tools/usb/usbip/src/usbip.c
new file mode 100644
index 000000000000..d7599d943529
--- /dev/null
+++ b/tools/usb/usbip/src/usbip.c
@@ -0,0 +1,201 @@
1/*
2 * command structure borrowed from udev
3 * (git://git.kernel.org/pub/scm/linux/hotplug/udev.git)
4 *
5 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
6 * 2005-2007 Takahiro Hirofuchi
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
24
25#include <getopt.h>
26#include <syslog.h>
27
28#include "usbip_common.h"
29#include "usbip_network.h"
30#include "usbip.h"
31
32static int usbip_help(int argc, char *argv[]);
33static int usbip_version(int argc, char *argv[]);
34
35static const char usbip_version_string[] = PACKAGE_STRING;
36
37static const char usbip_usage_string[] =
38 "usbip [--debug] [--log] [--tcp-port PORT] [version]\n"
39 " [help] <command> <args>\n";
40
41static void usbip_usage(void)
42{
43 printf("usage: %s", usbip_usage_string);
44}
45
46struct command {
47 const char *name;
48 int (*fn)(int argc, char *argv[]);
49 const char *help;
50 void (*usage)(void);
51};
52
53static const struct command cmds[] = {
54 {
55 .name = "help",
56 .fn = usbip_help,
57 .help = NULL,
58 .usage = NULL
59 },
60 {
61 .name = "version",
62 .fn = usbip_version,
63 .help = NULL,
64 .usage = NULL
65 },
66 {
67 .name = "attach",
68 .fn = usbip_attach,
69 .help = "Attach a remote USB device",
70 .usage = usbip_attach_usage
71 },
72 {
73 .name = "detach",
74 .fn = usbip_detach,
75 .help = "Detach a remote USB device",
76 .usage = usbip_detach_usage
77 },
78 {
79 .name = "list",
80 .fn = usbip_list,
81 .help = "List exportable or local USB devices",
82 .usage = usbip_list_usage
83 },
84 {
85 .name = "bind",
86 .fn = usbip_bind,
87 .help = "Bind device to " USBIP_HOST_DRV_NAME ".ko",
88 .usage = usbip_bind_usage
89 },
90 {
91 .name = "unbind",
92 .fn = usbip_unbind,
93 .help = "Unbind device from " USBIP_HOST_DRV_NAME ".ko",
94 .usage = usbip_unbind_usage
95 },
96 {
97 .name = "port",
98 .fn = usbip_port_show,
99 .help = "Show imported USB devices",
100 .usage = NULL
101 },
102 { NULL, NULL, NULL, NULL }
103};
104
105static int usbip_help(int argc, char *argv[])
106{
107 const struct command *cmd;
108 int i;
109 int ret = 0;
110
111 if (argc > 1 && argv++) {
112 for (i = 0; cmds[i].name != NULL; i++)
113 if (!strcmp(cmds[i].name, argv[0]) && cmds[i].usage) {
114 cmds[i].usage();
115 goto done;
116 }
117 ret = -1;
118 }
119
120 usbip_usage();
121 printf("\n");
122 for (cmd = cmds; cmd->name != NULL; cmd++)
123 if (cmd->help != NULL)
124 printf(" %-10s %s\n", cmd->name, cmd->help);
125 printf("\n");
126done:
127 return ret;
128}
129
130static int usbip_version(int argc, char *argv[])
131{
132 (void) argc;
133 (void) argv;
134
135 printf(PROGNAME " (%s)\n", usbip_version_string);
136 return 0;
137}
138
139static int run_command(const struct command *cmd, int argc, char *argv[])
140{
141 dbg("running command: `%s'", cmd->name);
142 return cmd->fn(argc, argv);
143}
144
145int main(int argc, char *argv[])
146{
147 static const struct option opts[] = {
148 { "debug", no_argument, NULL, 'd' },
149 { "log", no_argument, NULL, 'l' },
150 { "tcp-port", required_argument, NULL, 't' },
151 { NULL, 0, NULL, 0 }
152 };
153
154 char *cmd;
155 int opt;
156 int i, rc = -1;
157
158 usbip_use_stderr = 1;
159 opterr = 0;
160 for (;;) {
161 opt = getopt_long(argc, argv, "+dlt:", opts, NULL);
162
163 if (opt == -1)
164 break;
165
166 switch (opt) {
167 case 'd':
168 usbip_use_debug = 1;
169 break;
170 case 'l':
171 usbip_use_syslog = 1;
172 openlog("", LOG_PID, LOG_USER);
173 break;
174 case 't':
175 usbip_setup_port_number(optarg);
176 break;
177 case '?':
178 printf("usbip: invalid option\n");
179 default:
180 usbip_usage();
181 goto out;
182 }
183 }
184
185 cmd = argv[optind];
186 if (cmd) {
187 for (i = 0; cmds[i].name != NULL; i++)
188 if (!strcmp(cmds[i].name, cmd)) {
189 argc -= optind;
190 argv += optind;
191 optind = 0;
192 rc = run_command(&cmds[i], argc, argv);
193 goto out;
194 }
195 }
196
197 /* invalid command */
198 usbip_help(0, NULL);
199out:
200 return (rc > -1 ? EXIT_SUCCESS : EXIT_FAILURE);
201}
diff --git a/tools/usb/usbip/src/usbip.h b/tools/usb/usbip/src/usbip.h
new file mode 100644
index 000000000000..84fe66a9d8ad
--- /dev/null
+++ b/tools/usb/usbip/src/usbip.h
@@ -0,0 +1,40 @@
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#ifndef __USBIP_H
20#define __USBIP_H
21
22#ifdef HAVE_CONFIG_H
23#include "../config.h"
24#endif
25
26/* usbip commands */
27int usbip_attach(int argc, char *argv[]);
28int usbip_detach(int argc, char *argv[]);
29int usbip_list(int argc, char *argv[]);
30int usbip_bind(int argc, char *argv[]);
31int usbip_unbind(int argc, char *argv[]);
32int usbip_port_show(int argc, char *argv[]);
33
34void usbip_attach_usage(void);
35void usbip_detach_usage(void);
36void usbip_list_usage(void);
37void usbip_bind_usage(void);
38void usbip_unbind_usage(void);
39
40#endif /* __USBIP_H */
diff --git a/tools/usb/usbip/src/usbip_attach.c b/tools/usb/usbip/src/usbip_attach.c
new file mode 100644
index 000000000000..d58a14dfc094
--- /dev/null
+++ b/tools/usb/usbip/src/usbip_attach.c
@@ -0,0 +1,241 @@
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>
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>
29#include <errno.h>
30
31#include "vhci_driver.h"
32#include "usbip_common.h"
33#include "usbip_network.h"
34#include "usbip.h"
35
36static const char usbip_attach_usage_string[] =
37 "usbip attach <args>\n"
38 " -r, --remote=<host> The machine with exported USB devices\n"
39 " -b, --busid=<busid> Busid of the device on <host>\n";
40
41void usbip_attach_usage(void)
42{
43 printf("usage: %s", usbip_attach_usage_string);
44}
45
46#define MAX_BUFF 100
47static 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
54 ret = mkdir(VHCI_STATE_PATH, 0700);
55 if (ret < 0) {
56 /* if VHCI_STATE_PATH exists, then it better be a directory */
57 if (errno == EEXIST) {
58 struct stat s;
59
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 }
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
89static int import_device(int sockfd, struct usbip_usb_device *udev)
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
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
127 memset(&request, 0, sizeof(request));
128 memset(&reply, 0, sizeof(reply));
129
130 /* send a request */
131 rc = usbip_net_send_op_common(sockfd, OP_REQ_IMPORT, 0);
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
141 rc = usbip_net_send(sockfd, (void *) &request, sizeof(request));
142 if (rc < 0) {
143 err("send op_import_request");
144 return -1;
145 }
146
147 /* receive a reply */
148 rc = usbip_net_recv_op_common(sockfd, &code);
149 if (rc < 0) {
150 err("recv op_common");
151 return -1;
152 }
153
154 rc = usbip_net_recv(sockfd, (void *) &reply, sizeof(reply));
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
172static int attach_device(char *host, char *busid)
173{
174 int sockfd;
175 int rc;
176 int rhport;
177
178 sockfd = usbip_net_tcp_connect(host, usbip_port_string);
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
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 { NULL, 0, NULL, 0 }
207 };
208 char *host = NULL;
209 char *busid = NULL;
210 int opt;
211 int ret = -1;
212
213 for (;;) {
214 opt = getopt_long(argc, argv, "r:b:", opts, NULL);
215
216 if (opt == -1)
217 break;
218
219 switch (opt) {
220 case 'r':
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
237err_out:
238 usbip_attach_usage();
239out:
240 return ret;
241}
diff --git a/tools/usb/usbip/src/usbip_bind.c b/tools/usb/usbip/src/usbip_bind.c
new file mode 100644
index 000000000000..fa46141ae68b
--- /dev/null
+++ b/tools/usb/usbip/src/usbip_bind.c
@@ -0,0 +1,214 @@
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 <libudev.h>
20
21#include <errno.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
26#include <getopt.h>
27
28#include "usbip_common.h"
29#include "utils.h"
30#include "usbip.h"
31#include "sysfs_utils.h"
32
33enum unbind_status {
34 UNBIND_ST_OK,
35 UNBIND_ST_USBIP_HOST,
36 UNBIND_ST_FAILED
37};
38
39static const char usbip_bind_usage_string[] =
40 "usbip bind <args>\n"
41 " -b, --busid=<busid> Bind " USBIP_HOST_DRV_NAME ".ko to device "
42 "on <busid>\n";
43
44void usbip_bind_usage(void)
45{
46 printf("usage: %s", usbip_bind_usage_string);
47}
48
49/* call at unbound state */
50static int bind_usbip(char *busid)
51{
52 char attr_name[] = "bind";
53 char bind_attr_path[SYSFS_PATH_MAX];
54 int rc = -1;
55
56 snprintf(bind_attr_path, sizeof(bind_attr_path), "%s/%s/%s/%s/%s/%s",
57 SYSFS_MNT_PATH, SYSFS_BUS_NAME, SYSFS_BUS_TYPE,
58 SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME, attr_name);
59
60 rc = write_sysfs_attribute(bind_attr_path, busid, strlen(busid));
61 if (rc < 0) {
62 err("error binding device %s to driver: %s", busid,
63 strerror(errno));
64 return -1;
65 }
66
67 return 0;
68}
69
70/* buggy driver may cause dead lock */
71static int unbind_other(char *busid)
72{
73 enum unbind_status status = UNBIND_ST_OK;
74
75 char attr_name[] = "unbind";
76 char unbind_attr_path[SYSFS_PATH_MAX];
77 int rc = -1;
78
79 struct udev *udev;
80 struct udev_device *dev;
81 const char *driver;
82 const char *bDevClass;
83
84 /* Create libudev context. */
85 udev = udev_new();
86
87 /* Get the device. */
88 dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid);
89 if (!dev) {
90 dbg("unable to find device with bus ID %s", busid);
91 goto err_close_busid_dev;
92 }
93
94 /* Check what kind of device it is. */
95 bDevClass = udev_device_get_sysattr_value(dev, "bDeviceClass");
96 if (!bDevClass) {
97 dbg("unable to get bDevClass device attribute");
98 goto err_close_busid_dev;
99 }
100
101 if (!strncmp(bDevClass, "09", strlen(bDevClass))) {
102 dbg("skip unbinding of hub");
103 goto err_close_busid_dev;
104 }
105
106 /* Get the device driver. */
107 driver = udev_device_get_driver(dev);
108 if (!driver) {
109 /* No driver bound to this device. */
110 goto out;
111 }
112
113 if (!strncmp(USBIP_HOST_DRV_NAME, driver,
114 strlen(USBIP_HOST_DRV_NAME))) {
115 /* Already bound to usbip-host. */
116 status = UNBIND_ST_USBIP_HOST;
117 goto out;
118 }
119
120 /* Unbind device from driver. */
121 snprintf(unbind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s",
122 SYSFS_MNT_PATH, SYSFS_BUS_NAME, SYSFS_BUS_TYPE,
123 SYSFS_DRIVERS_NAME, driver, attr_name);
124
125 rc = write_sysfs_attribute(unbind_attr_path, busid, strlen(busid));
126 if (rc < 0) {
127 err("error unbinding device %s from driver", busid);
128 goto err_close_busid_dev;
129 }
130
131 goto out;
132
133err_close_busid_dev:
134 status = UNBIND_ST_FAILED;
135out:
136 udev_device_unref(dev);
137 udev_unref(udev);
138
139 return status;
140}
141
142static int bind_device(char *busid)
143{
144 int rc;
145 struct udev *udev;
146 struct udev_device *dev;
147
148 /* Check whether the device with this bus ID exists. */
149 udev = udev_new();
150 dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid);
151 if (!dev) {
152 err("device with the specified bus ID does not exist");
153 return -1;
154 }
155 udev_unref(udev);
156
157 rc = unbind_other(busid);
158 if (rc == UNBIND_ST_FAILED) {
159 err("could not unbind driver from device on busid %s", busid);
160 return -1;
161 } else if (rc == UNBIND_ST_USBIP_HOST) {
162 err("device on busid %s is already bound to %s", busid,
163 USBIP_HOST_DRV_NAME);
164 return -1;
165 }
166
167 rc = modify_match_busid(busid, 1);
168 if (rc < 0) {
169 err("unable to bind device on %s", busid);
170 return -1;
171 }
172
173 rc = bind_usbip(busid);
174 if (rc < 0) {
175 err("could not bind device to %s", USBIP_HOST_DRV_NAME);
176 modify_match_busid(busid, 0);
177 return -1;
178 }
179
180 info("bind device on busid %s: complete", busid);
181
182 return 0;
183}
184
185int usbip_bind(int argc, char *argv[])
186{
187 static const struct option opts[] = {
188 { "busid", required_argument, NULL, 'b' },
189 { NULL, 0, NULL, 0 }
190 };
191
192 int opt;
193 int ret = -1;
194
195 for (;;) {
196 opt = getopt_long(argc, argv, "b:", opts, NULL);
197
198 if (opt == -1)
199 break;
200
201 switch (opt) {
202 case 'b':
203 ret = bind_device(optarg);
204 goto out;
205 default:
206 goto err_out;
207 }
208 }
209
210err_out:
211 usbip_bind_usage();
212out:
213 return ret;
214}
diff --git a/tools/usb/usbip/src/usbip_detach.c b/tools/usb/usbip/src/usbip_detach.c
new file mode 100644
index 000000000000..05c6d15856eb
--- /dev/null
+++ b/tools/usb/usbip/src/usbip_detach.c
@@ -0,0 +1,110 @@
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 <ctype.h>
20#include <limits.h>
21#include <stdint.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
26#include <getopt.h>
27#include <unistd.h>
28
29#include "vhci_driver.h"
30#include "usbip_common.h"
31#include "usbip_network.h"
32#include "usbip.h"
33
34static const char usbip_detach_usage_string[] =
35 "usbip detach <args>\n"
36 " -p, --port=<port> " USBIP_VHCI_DRV_NAME
37 " port the device is on\n";
38
39void usbip_detach_usage(void)
40{
41 printf("usage: %s", usbip_detach_usage_string);
42}
43
44static int detach_port(char *port)
45{
46 int ret;
47 uint8_t portnum;
48 char path[PATH_MAX+1];
49
50 for (unsigned int i = 0; i < strlen(port); i++)
51 if (!isdigit(port[i])) {
52 err("invalid port %s", port);
53 return -1;
54 }
55
56 /* check max port */
57
58 portnum = atoi(port);
59
60 /* remove the port state file */
61
62 snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", portnum);
63
64 remove(path);
65 rmdir(VHCI_STATE_PATH);
66
67 ret = usbip_vhci_driver_open();
68 if (ret < 0) {
69 err("open vhci_driver");
70 return -1;
71 }
72
73 ret = usbip_vhci_detach_device(portnum);
74 if (ret < 0)
75 return -1;
76
77 usbip_vhci_driver_close();
78
79 return ret;
80}
81
82int usbip_detach(int argc, char *argv[])
83{
84 static const struct option opts[] = {
85 { "port", required_argument, NULL, 'p' },
86 { NULL, 0, NULL, 0 }
87 };
88 int opt;
89 int ret = -1;
90
91 for (;;) {
92 opt = getopt_long(argc, argv, "p:", opts, NULL);
93
94 if (opt == -1)
95 break;
96
97 switch (opt) {
98 case 'p':
99 ret = detach_port(optarg);
100 goto out;
101 default:
102 goto err_out;
103 }
104 }
105
106err_out:
107 usbip_detach_usage();
108out:
109 return ret;
110}
diff --git a/tools/usb/usbip/src/usbip_list.c b/tools/usb/usbip/src/usbip_list.c
new file mode 100644
index 000000000000..d5ce34a410e7
--- /dev/null
+++ b/tools/usb/usbip/src/usbip_list.c
@@ -0,0 +1,283 @@
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/types.h>
20#include <libudev.h>
21
22#include <errno.h>
23#include <stdbool.h>
24#include <stdint.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28
29#include <getopt.h>
30#include <netdb.h>
31#include <unistd.h>
32
33#include "usbip_common.h"
34#include "usbip_network.h"
35#include "usbip.h"
36
37static const char usbip_list_usage_string[] =
38 "usbip list [-p|--parsable] <args>\n"
39 " -p, --parsable Parsable list format\n"
40 " -r, --remote=<host> List the exportable USB devices on <host>\n"
41 " -l, --local List the local USB devices\n";
42
43void usbip_list_usage(void)
44{
45 printf("usage: %s", usbip_list_usage_string);
46}
47
48static int get_exported_devices(char *host, int sockfd)
49{
50 char product_name[100];
51 char class_name[100];
52 struct op_devlist_reply reply;
53 uint16_t code = OP_REP_DEVLIST;
54 struct usbip_usb_device udev;
55 struct usbip_usb_interface uintf;
56 unsigned int i;
57 int rc, j;
58
59 rc = usbip_net_send_op_common(sockfd, OP_REQ_DEVLIST, 0);
60 if (rc < 0) {
61 dbg("usbip_net_send_op_common failed");
62 return -1;
63 }
64
65 rc = usbip_net_recv_op_common(sockfd, &code);
66 if (rc < 0) {
67 dbg("usbip_net_recv_op_common failed");
68 return -1;
69 }
70
71 memset(&reply, 0, sizeof(reply));
72 rc = usbip_net_recv(sockfd, &reply, sizeof(reply));
73 if (rc < 0) {
74 dbg("usbip_net_recv_op_devlist failed");
75 return -1;
76 }
77 PACK_OP_DEVLIST_REPLY(0, &reply);
78 dbg("exportable devices: %d\n", reply.ndev);
79
80 if (reply.ndev == 0) {
81 info("no exportable devices found on %s", host);
82 return 0;
83 }
84
85 printf("Exportable USB devices\n");
86 printf("======================\n");
87 printf(" - %s\n", host);
88
89 for (i = 0; i < reply.ndev; i++) {
90 memset(&udev, 0, sizeof(udev));
91 rc = usbip_net_recv(sockfd, &udev, sizeof(udev));
92 if (rc < 0) {
93 dbg("usbip_net_recv failed: usbip_usb_device[%d]", i);
94 return -1;
95 }
96 usbip_net_pack_usb_device(0, &udev);
97
98 usbip_names_get_product(product_name, sizeof(product_name),
99 udev.idVendor, udev.idProduct);
100 usbip_names_get_class(class_name, sizeof(class_name),
101 udev.bDeviceClass, udev.bDeviceSubClass,
102 udev.bDeviceProtocol);
103 printf("%11s: %s\n", udev.busid, product_name);
104 printf("%11s: %s\n", "", udev.path);
105 printf("%11s: %s\n", "", class_name);
106
107 for (j = 0; j < udev.bNumInterfaces; j++) {
108 rc = usbip_net_recv(sockfd, &uintf, sizeof(uintf));
109 if (rc < 0) {
110 err("usbip_net_recv failed: usbip_usb_intf[%d]",
111 j);
112
113 return -1;
114 }
115 usbip_net_pack_usb_interface(0, &uintf);
116
117 usbip_names_get_class(class_name, sizeof(class_name),
118 uintf.bInterfaceClass,
119 uintf.bInterfaceSubClass,
120 uintf.bInterfaceProtocol);
121 printf("%11s: %2d - %s\n", "", j, class_name);
122 }
123
124 printf("\n");
125 }
126
127 return 0;
128}
129
130static int list_exported_devices(char *host)
131{
132 int rc;
133 int sockfd;
134
135 sockfd = usbip_net_tcp_connect(host, usbip_port_string);
136 if (sockfd < 0) {
137 err("could not connect to %s:%s: %s", host,
138 usbip_port_string, gai_strerror(sockfd));
139 return -1;
140 }
141 dbg("connected to %s:%s", host, usbip_port_string);
142
143 rc = get_exported_devices(host, sockfd);
144 if (rc < 0) {
145 err("failed to get device list from %s", host);
146 return -1;
147 }
148
149 close(sockfd);
150
151 return 0;
152}
153
154static void print_device(const char *busid, const char *vendor,
155 const char *product, bool parsable)
156{
157 if (parsable)
158 printf("busid=%s#usbid=%.4s:%.4s#", busid, vendor, product);
159 else
160 printf(" - busid %s (%.4s:%.4s)\n", busid, vendor, product);
161}
162
163static void print_product_name(char *product_name, bool parsable)
164{
165 if (!parsable)
166 printf(" %s\n", product_name);
167}
168
169static int list_devices(bool parsable)
170{
171 struct udev *udev;
172 struct udev_enumerate *enumerate;
173 struct udev_list_entry *devices, *dev_list_entry;
174 struct udev_device *dev;
175 const char *path;
176 const char *idVendor;
177 const char *idProduct;
178 const char *bConfValue;
179 const char *bNumIntfs;
180 const char *busid;
181 char product_name[128];
182 int ret = -1;
183
184 /* Create libudev context. */
185 udev = udev_new();
186
187 /* Create libudev device enumeration. */
188 enumerate = udev_enumerate_new(udev);
189
190 /* Take only USB devices that are not hubs and do not have
191 * the bInterfaceNumber attribute, i.e. are not interfaces.
192 */
193 udev_enumerate_add_match_subsystem(enumerate, "usb");
194 udev_enumerate_add_nomatch_sysattr(enumerate, "bDeviceClass", "09");
195 udev_enumerate_add_nomatch_sysattr(enumerate, "bInterfaceNumber", NULL);
196 udev_enumerate_scan_devices(enumerate);
197
198 devices = udev_enumerate_get_list_entry(enumerate);
199
200 /* Show information about each device. */
201 udev_list_entry_foreach(dev_list_entry, devices) {
202 path = udev_list_entry_get_name(dev_list_entry);
203 dev = udev_device_new_from_syspath(udev, path);
204
205 /* Get device information. */
206 idVendor = udev_device_get_sysattr_value(dev, "idVendor");
207 idProduct = udev_device_get_sysattr_value(dev, "idProduct");
208 bConfValue = udev_device_get_sysattr_value(dev, "bConfigurationValue");
209 bNumIntfs = udev_device_get_sysattr_value(dev, "bNumInterfaces");
210 busid = udev_device_get_sysname(dev);
211 if (!idVendor || !idProduct || !bConfValue || !bNumIntfs) {
212 err("problem getting device attributes: %s",
213 strerror(errno));
214 goto err_out;
215 }
216
217 /* Get product name. */
218 usbip_names_get_product(product_name, sizeof(product_name),
219 strtol(idVendor, NULL, 16),
220 strtol(idProduct, NULL, 16));
221
222 /* Print information. */
223 print_device(busid, idVendor, idProduct, parsable);
224 print_product_name(product_name, parsable);
225
226 printf("\n");
227
228 udev_device_unref(dev);
229 }
230
231 ret = 0;
232
233err_out:
234 udev_enumerate_unref(enumerate);
235 udev_unref(udev);
236
237 return ret;
238}
239
240int usbip_list(int argc, char *argv[])
241{
242 static const struct option opts[] = {
243 { "parsable", no_argument, NULL, 'p' },
244 { "remote", required_argument, NULL, 'r' },
245 { "local", no_argument, NULL, 'l' },
246 { NULL, 0, NULL, 0 }
247 };
248
249 bool parsable = false;
250 int opt;
251 int ret = -1;
252
253 if (usbip_names_init(USBIDS_FILE))
254 err("failed to open %s", USBIDS_FILE);
255
256 for (;;) {
257 opt = getopt_long(argc, argv, "pr:l", opts, NULL);
258
259 if (opt == -1)
260 break;
261
262 switch (opt) {
263 case 'p':
264 parsable = true;
265 break;
266 case 'r':
267 ret = list_exported_devices(optarg);
268 goto out;
269 case 'l':
270 ret = list_devices(parsable);
271 goto out;
272 default:
273 goto err_out;
274 }
275 }
276
277err_out:
278 usbip_list_usage();
279out:
280 usbip_names_free();
281
282 return ret;
283}
diff --git a/tools/usb/usbip/src/usbip_network.c b/tools/usb/usbip/src/usbip_network.c
new file mode 100644
index 000000000000..b4c37e76a6e0
--- /dev/null
+++ b/tools/usb/usbip/src/usbip_network.c
@@ -0,0 +1,303 @@
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/socket.h>
20
21#include <string.h>
22
23#include <arpa/inet.h>
24#include <netdb.h>
25#include <netinet/tcp.h>
26#include <unistd.h>
27
28#ifdef HAVE_LIBWRAP
29#include <tcpd.h>
30#endif
31
32#include "usbip_common.h"
33#include "usbip_network.h"
34
35int usbip_port = 3240;
36char *usbip_port_string = "3240";
37
38void usbip_setup_port_number(char *arg)
39{
40 dbg("parsing port arg '%s'", arg);
41 char *end;
42 unsigned long int port = strtoul(arg, &end, 10);
43
44 if (end == arg) {
45 err("port: could not parse '%s' as a decimal integer", arg);
46 return;
47 }
48
49 if (*end != '\0') {
50 err("port: garbage at end of '%s'", arg);
51 return;
52 }
53
54 if (port > UINT16_MAX) {
55 err("port: %s too high (max=%d)",
56 arg, UINT16_MAX);
57 return;
58 }
59
60 usbip_port = port;
61 usbip_port_string = arg;
62 info("using port %d (\"%s\")", usbip_port, usbip_port_string);
63}
64
65void usbip_net_pack_uint32_t(int pack, uint32_t *num)
66{
67 uint32_t i;
68
69 if (pack)
70 i = htonl(*num);
71 else
72 i = ntohl(*num);
73
74 *num = i;
75}
76
77void usbip_net_pack_uint16_t(int pack, uint16_t *num)
78{
79 uint16_t i;
80
81 if (pack)
82 i = htons(*num);
83 else
84 i = ntohs(*num);
85
86 *num = i;
87}
88
89void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev)
90{
91 usbip_net_pack_uint32_t(pack, &udev->busnum);
92 usbip_net_pack_uint32_t(pack, &udev->devnum);
93 usbip_net_pack_uint32_t(pack, &udev->speed);
94
95 usbip_net_pack_uint16_t(pack, &udev->idVendor);
96 usbip_net_pack_uint16_t(pack, &udev->idProduct);
97 usbip_net_pack_uint16_t(pack, &udev->bcdDevice);
98}
99
100void usbip_net_pack_usb_interface(int pack __attribute__((unused)),
101 struct usbip_usb_interface *udev
102 __attribute__((unused)))
103{
104 /* uint8_t members need nothing */
105}
106
107static ssize_t usbip_net_xmit(int sockfd, void *buff, size_t bufflen,
108 int sending)
109{
110 ssize_t nbytes;
111 ssize_t total = 0;
112
113 if (!bufflen)
114 return 0;
115
116 do {
117 if (sending)
118 nbytes = send(sockfd, buff, bufflen, 0);
119 else
120 nbytes = recv(sockfd, buff, bufflen, MSG_WAITALL);
121
122 if (nbytes <= 0)
123 return -1;
124
125 buff = (void *)((intptr_t) buff + nbytes);
126 bufflen -= nbytes;
127 total += nbytes;
128
129 } while (bufflen > 0);
130
131 return total;
132}
133
134ssize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen)
135{
136 return usbip_net_xmit(sockfd, buff, bufflen, 0);
137}
138
139ssize_t usbip_net_send(int sockfd, void *buff, size_t bufflen)
140{
141 return usbip_net_xmit(sockfd, buff, bufflen, 1);
142}
143
144int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status)
145{
146 struct op_common op_common;
147 int rc;
148
149 memset(&op_common, 0, sizeof(op_common));
150
151 op_common.version = USBIP_VERSION;
152 op_common.code = code;
153 op_common.status = status;
154
155 PACK_OP_COMMON(1, &op_common);
156
157 rc = usbip_net_send(sockfd, &op_common, sizeof(op_common));
158 if (rc < 0) {
159 dbg("usbip_net_send failed: %d", rc);
160 return -1;
161 }
162
163 return 0;
164}
165
166int usbip_net_recv_op_common(int sockfd, uint16_t *code)
167{
168 struct op_common op_common;
169 int rc;
170
171 memset(&op_common, 0, sizeof(op_common));
172
173 rc = usbip_net_recv(sockfd, &op_common, sizeof(op_common));
174 if (rc < 0) {
175 dbg("usbip_net_recv failed: %d", rc);
176 goto err;
177 }
178
179 PACK_OP_COMMON(0, &op_common);
180
181 if (op_common.version != USBIP_VERSION) {
182 dbg("version mismatch: %d %d", op_common.version,
183 USBIP_VERSION);
184 goto err;
185 }
186
187 switch (*code) {
188 case OP_UNSPEC:
189 break;
190 default:
191 if (op_common.code != *code) {
192 dbg("unexpected pdu %#0x for %#0x", op_common.code,
193 *code);
194 goto err;
195 }
196 }
197
198 if (op_common.status != ST_OK) {
199 dbg("request failed at peer: %d", op_common.status);
200 goto err;
201 }
202
203 *code = op_common.code;
204
205 return 0;
206err:
207 return -1;
208}
209
210int usbip_net_set_reuseaddr(int sockfd)
211{
212 const int val = 1;
213 int ret;
214
215 ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
216 if (ret < 0)
217 dbg("setsockopt: SO_REUSEADDR");
218
219 return ret;
220}
221
222int usbip_net_set_nodelay(int sockfd)
223{
224 const int val = 1;
225 int ret;
226
227 ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
228 if (ret < 0)
229 dbg("setsockopt: TCP_NODELAY");
230
231 return ret;
232}
233
234int usbip_net_set_keepalive(int sockfd)
235{
236 const int val = 1;
237 int ret;
238
239 ret = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val));
240 if (ret < 0)
241 dbg("setsockopt: SO_KEEPALIVE");
242
243 return ret;
244}
245
246int usbip_net_set_v6only(int sockfd)
247{
248 const int val = 1;
249 int ret;
250
251 ret = setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
252 if (ret < 0)
253 dbg("setsockopt: IPV6_V6ONLY");
254
255 return ret;
256}
257
258/*
259 * IPv6 Ready
260 */
261int usbip_net_tcp_connect(char *hostname, char *service)
262{
263 struct addrinfo hints, *res, *rp;
264 int sockfd;
265 int ret;
266
267 memset(&hints, 0, sizeof(hints));
268 hints.ai_family = AF_UNSPEC;
269 hints.ai_socktype = SOCK_STREAM;
270
271 /* get all possible addresses */
272 ret = getaddrinfo(hostname, service, &hints, &res);
273 if (ret < 0) {
274 dbg("getaddrinfo: %s service %s: %s", hostname, service,
275 gai_strerror(ret));
276 return ret;
277 }
278
279 /* try the addresses */
280 for (rp = res; rp; rp = rp->ai_next) {
281 sockfd = socket(rp->ai_family, rp->ai_socktype,
282 rp->ai_protocol);
283 if (sockfd < 0)
284 continue;
285
286 /* should set TCP_NODELAY for usbip */
287 usbip_net_set_nodelay(sockfd);
288 /* TODO: write code for heartbeat */
289 usbip_net_set_keepalive(sockfd);
290
291 if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) == 0)
292 break;
293
294 close(sockfd);
295 }
296
297 freeaddrinfo(res);
298
299 if (!rp)
300 return EAI_SYSTEM;
301
302 return sockfd;
303}
diff --git a/tools/usb/usbip/src/usbip_network.h b/tools/usb/usbip/src/usbip_network.h
new file mode 100644
index 000000000000..c1e875cf1078
--- /dev/null
+++ b/tools/usb/usbip/src/usbip_network.h
@@ -0,0 +1,185 @@
1/*
2 * Copyright (C) 2005-2007 Takahiro Hirofuchi
3 */
4
5#ifndef __USBIP_NETWORK_H
6#define __USBIP_NETWORK_H
7
8#ifdef HAVE_CONFIG_H
9#include "../config.h"
10#endif
11
12#include <sys/types.h>
13
14#include <stdint.h>
15
16extern int usbip_port;
17extern char *usbip_port_string;
18void usbip_setup_port_number(char *arg);
19
20/* ---------------------------------------------------------------------- */
21/* Common header for all the kinds of PDUs. */
22struct op_common {
23 uint16_t version;
24
25#define OP_REQUEST (0x80 << 8)
26#define OP_REPLY (0x00 << 8)
27 uint16_t code;
28
29 /* add more error code */
30#define ST_OK 0x00
31#define ST_NA 0x01
32 uint32_t status; /* op_code status (for reply) */
33
34} __attribute__((packed));
35
36#define PACK_OP_COMMON(pack, op_common) do {\
37 usbip_net_pack_uint16_t(pack, &(op_common)->version);\
38 usbip_net_pack_uint16_t(pack, &(op_common)->code);\
39 usbip_net_pack_uint32_t(pack, &(op_common)->status);\
40} while (0)
41
42/* ---------------------------------------------------------------------- */
43/* Dummy Code */
44#define OP_UNSPEC 0x00
45#define OP_REQ_UNSPEC OP_UNSPEC
46#define OP_REP_UNSPEC OP_UNSPEC
47
48/* ---------------------------------------------------------------------- */
49/* Retrieve USB device information. (still not used) */
50#define OP_DEVINFO 0x02
51#define OP_REQ_DEVINFO (OP_REQUEST | OP_DEVINFO)
52#define OP_REP_DEVINFO (OP_REPLY | OP_DEVINFO)
53
54struct op_devinfo_request {
55 char busid[SYSFS_BUS_ID_SIZE];
56} __attribute__((packed));
57
58struct op_devinfo_reply {
59 struct usbip_usb_device udev;
60 struct usbip_usb_interface uinf[];
61} __attribute__((packed));
62
63/* ---------------------------------------------------------------------- */
64/* Import a remote USB device. */
65#define OP_IMPORT 0x03
66#define OP_REQ_IMPORT (OP_REQUEST | OP_IMPORT)
67#define OP_REP_IMPORT (OP_REPLY | OP_IMPORT)
68
69struct op_import_request {
70 char busid[SYSFS_BUS_ID_SIZE];
71} __attribute__((packed));
72
73struct op_import_reply {
74 struct usbip_usb_device udev;
75// struct usbip_usb_interface uinf[];
76} __attribute__((packed));
77
78#define PACK_OP_IMPORT_REQUEST(pack, request) do {\
79} while (0)
80
81#define PACK_OP_IMPORT_REPLY(pack, reply) do {\
82 usbip_net_pack_usb_device(pack, &(reply)->udev);\
83} while (0)
84
85/* ---------------------------------------------------------------------- */
86/* Export a USB device to a remote host. */
87#define OP_EXPORT 0x06
88#define OP_REQ_EXPORT (OP_REQUEST | OP_EXPORT)
89#define OP_REP_EXPORT (OP_REPLY | OP_EXPORT)
90
91struct op_export_request {
92 struct usbip_usb_device udev;
93} __attribute__((packed));
94
95struct op_export_reply {
96 int returncode;
97} __attribute__((packed));
98
99
100#define PACK_OP_EXPORT_REQUEST(pack, request) do {\
101 usbip_net_pack_usb_device(pack, &(request)->udev);\
102} while (0)
103
104#define PACK_OP_EXPORT_REPLY(pack, reply) do {\
105} while (0)
106
107/* ---------------------------------------------------------------------- */
108/* un-Export a USB device from a remote host. */
109#define OP_UNEXPORT 0x07
110#define OP_REQ_UNEXPORT (OP_REQUEST | OP_UNEXPORT)
111#define OP_REP_UNEXPORT (OP_REPLY | OP_UNEXPORT)
112
113struct op_unexport_request {
114 struct usbip_usb_device udev;
115} __attribute__((packed));
116
117struct op_unexport_reply {
118 int returncode;
119} __attribute__((packed));
120
121#define PACK_OP_UNEXPORT_REQUEST(pack, request) do {\
122 usbip_net_pack_usb_device(pack, &(request)->udev);\
123} while (0)
124
125#define PACK_OP_UNEXPORT_REPLY(pack, reply) do {\
126} while (0)
127
128/* ---------------------------------------------------------------------- */
129/* Negotiate IPSec encryption key. (still not used) */
130#define OP_CRYPKEY 0x04
131#define OP_REQ_CRYPKEY (OP_REQUEST | OP_CRYPKEY)
132#define OP_REP_CRYPKEY (OP_REPLY | OP_CRYPKEY)
133
134struct op_crypkey_request {
135 /* 128bit key */
136 uint32_t key[4];
137} __attribute__((packed));
138
139struct op_crypkey_reply {
140 uint32_t __reserved;
141} __attribute__((packed));
142
143
144/* ---------------------------------------------------------------------- */
145/* Retrieve the list of exported USB devices. */
146#define OP_DEVLIST 0x05
147#define OP_REQ_DEVLIST (OP_REQUEST | OP_DEVLIST)
148#define OP_REP_DEVLIST (OP_REPLY | OP_DEVLIST)
149
150struct op_devlist_request {
151} __attribute__((packed));
152
153struct op_devlist_reply {
154 uint32_t ndev;
155 /* followed by reply_extra[] */
156} __attribute__((packed));
157
158struct op_devlist_reply_extra {
159 struct usbip_usb_device udev;
160 struct usbip_usb_interface uinf[];
161} __attribute__((packed));
162
163#define PACK_OP_DEVLIST_REQUEST(pack, request) do {\
164} while (0)
165
166#define PACK_OP_DEVLIST_REPLY(pack, reply) do {\
167 usbip_net_pack_uint32_t(pack, &(reply)->ndev);\
168} while (0)
169
170void usbip_net_pack_uint32_t(int pack, uint32_t *num);
171void usbip_net_pack_uint16_t(int pack, uint16_t *num);
172void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev);
173void usbip_net_pack_usb_interface(int pack, struct usbip_usb_interface *uinf);
174
175ssize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen);
176ssize_t usbip_net_send(int sockfd, void *buff, size_t bufflen);
177int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status);
178int usbip_net_recv_op_common(int sockfd, uint16_t *code);
179int usbip_net_set_reuseaddr(int sockfd);
180int usbip_net_set_nodelay(int sockfd);
181int usbip_net_set_keepalive(int sockfd);
182int usbip_net_set_v6only(int sockfd);
183int usbip_net_tcp_connect(char *hostname, char *port);
184
185#endif /* __USBIP_NETWORK_H */
diff --git a/tools/usb/usbip/src/usbip_port.c b/tools/usb/usbip/src/usbip_port.c
new file mode 100644
index 000000000000..a2e884fd9226
--- /dev/null
+++ b/tools/usb/usbip/src/usbip_port.c
@@ -0,0 +1,57 @@
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
16#include "vhci_driver.h"
17#include "usbip_common.h"
18
19static int list_imported_devices(void)
20{
21 int i;
22 struct usbip_imported_device *idev;
23 int ret;
24
25 ret = usbip_vhci_driver_open();
26 if (ret < 0) {
27 err("open vhci_driver");
28 return -1;
29 }
30
31 printf("Imported USB devices\n");
32 printf("====================\n");
33
34 for (i = 0; i < vhci_driver->nports; i++) {
35 idev = &vhci_driver->idev[i];
36
37 if (usbip_vhci_imported_device_dump(idev) < 0)
38 ret = -1;
39 }
40
41 usbip_vhci_driver_close();
42
43 return ret;
44
45}
46
47int usbip_port_show(__attribute__((unused)) int argc,
48 __attribute__((unused)) char *argv[])
49{
50 int ret;
51
52 ret = list_imported_devices();
53 if (ret < 0)
54 err("list imported devices");
55
56 return ret;
57}
diff --git a/tools/usb/usbip/src/usbip_unbind.c b/tools/usb/usbip/src/usbip_unbind.c
new file mode 100644
index 000000000000..a4a496c9cbaf
--- /dev/null
+++ b/tools/usb/usbip/src/usbip_unbind.c
@@ -0,0 +1,141 @@
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 <libudev.h>
20
21#include <errno.h>
22#include <stdio.h>
23#include <string.h>
24
25#include <getopt.h>
26
27#include "usbip_common.h"
28#include "utils.h"
29#include "usbip.h"
30#include "sysfs_utils.h"
31
32static const char usbip_unbind_usage_string[] =
33 "usbip unbind <args>\n"
34 " -b, --busid=<busid> Unbind " USBIP_HOST_DRV_NAME ".ko from "
35 "device on <busid>\n";
36
37void usbip_unbind_usage(void)
38{
39 printf("usage: %s", usbip_unbind_usage_string);
40}
41
42static int unbind_device(char *busid)
43{
44 char bus_type[] = "usb";
45 int rc, ret = -1;
46
47 char unbind_attr_name[] = "unbind";
48 char unbind_attr_path[SYSFS_PATH_MAX];
49 char rebind_attr_name[] = "rebind";
50 char rebind_attr_path[SYSFS_PATH_MAX];
51
52 struct udev *udev;
53 struct udev_device *dev;
54 const char *driver;
55
56 /* Create libudev context. */
57 udev = udev_new();
58
59 /* Check whether the device with this bus ID exists. */
60 dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid);
61 if (!dev) {
62 err("device with the specified bus ID does not exist");
63 goto err_close_udev;
64 }
65
66 /* Check whether the device is using usbip-host driver. */
67 driver = udev_device_get_driver(dev);
68 if (!driver || strcmp(driver, "usbip-host")) {
69 err("device is not bound to usbip-host driver");
70 goto err_close_udev;
71 }
72
73 /* Unbind device from driver. */
74 snprintf(unbind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s",
75 SYSFS_MNT_PATH, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME,
76 USBIP_HOST_DRV_NAME, unbind_attr_name);
77
78 rc = write_sysfs_attribute(unbind_attr_path, busid, strlen(busid));
79 if (rc < 0) {
80 err("error unbinding device %s from driver", busid);
81 goto err_close_udev;
82 }
83
84 /* Notify driver of unbind. */
85 rc = modify_match_busid(busid, 0);
86 if (rc < 0) {
87 err("unable to unbind device on %s", busid);
88 goto err_close_udev;
89 }
90
91 /* Trigger new probing. */
92 snprintf(rebind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s",
93 SYSFS_MNT_PATH, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME,
94 USBIP_HOST_DRV_NAME, rebind_attr_name);
95
96 rc = write_sysfs_attribute(rebind_attr_path, busid, strlen(busid));
97 if (rc < 0) {
98 err("error rebinding");
99 goto err_close_udev;
100 }
101
102 ret = 0;
103 info("unbind device on busid %s: complete", busid);
104
105err_close_udev:
106 udev_device_unref(dev);
107 udev_unref(udev);
108
109 return ret;
110}
111
112int usbip_unbind(int argc, char *argv[])
113{
114 static const struct option opts[] = {
115 { "busid", required_argument, NULL, 'b' },
116 { NULL, 0, NULL, 0 }
117 };
118
119 int opt;
120 int ret = -1;
121
122 for (;;) {
123 opt = getopt_long(argc, argv, "b:", opts, NULL);
124
125 if (opt == -1)
126 break;
127
128 switch (opt) {
129 case 'b':
130 ret = unbind_device(optarg);
131 goto out;
132 default:
133 goto err_out;
134 }
135 }
136
137err_out:
138 usbip_unbind_usage();
139out:
140 return ret;
141}
diff --git a/tools/usb/usbip/src/usbipd.c b/tools/usb/usbip/src/usbipd.c
new file mode 100644
index 000000000000..2f87f2d348ba
--- /dev/null
+++ b/tools/usb/usbip/src/usbipd.c
@@ -0,0 +1,679 @@
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#ifdef HAVE_CONFIG_H
20#include "../config.h"
21#endif
22
23#define _GNU_SOURCE
24#include <errno.h>
25#include <unistd.h>
26#include <netdb.h>
27#include <string.h>
28#include <stdlib.h>
29#include <sys/types.h>
30#include <sys/stat.h>
31#include <arpa/inet.h>
32#include <sys/socket.h>
33#include <netinet/in.h>
34
35#ifdef HAVE_LIBWRAP
36#include <tcpd.h>
37#endif
38
39#include <getopt.h>
40#include <signal.h>
41#include <poll.h>
42
43#include "usbip_host_driver.h"
44#include "usbip_common.h"
45#include "usbip_network.h"
46#include "list.h"
47
48#undef PROGNAME
49#define PROGNAME "usbipd"
50#define MAXSOCKFD 20
51
52#define MAIN_LOOP_TIMEOUT 10
53
54#define DEFAULT_PID_FILE "/var/run/" PROGNAME ".pid"
55
56static const char usbip_version_string[] = PACKAGE_STRING;
57
58static const char usbipd_help_string[] =
59 "usage: usbipd [options]\n"
60 "\n"
61 " -4, --ipv4\n"
62 " Bind to IPv4. Default is both.\n"
63 "\n"
64 " -6, --ipv6\n"
65 " Bind to IPv6. Default is both.\n"
66 "\n"
67 " -D, --daemon\n"
68 " Run as a daemon process.\n"
69 "\n"
70 " -d, --debug\n"
71 " Print debugging information.\n"
72 "\n"
73 " -PFILE, --pid FILE\n"
74 " Write process id to FILE.\n"
75 " If no FILE specified, use " DEFAULT_PID_FILE "\n"
76 "\n"
77 " -tPORT, --tcp-port PORT\n"
78 " Listen on TCP/IP port PORT.\n"
79 "\n"
80 " -h, --help\n"
81 " Print this help.\n"
82 "\n"
83 " -v, --version\n"
84 " Show version.\n";
85
86static void usbipd_help(void)
87{
88 printf("%s\n", usbipd_help_string);
89}
90
91static int recv_request_import(int sockfd)
92{
93 struct op_import_request req;
94 struct op_common reply;
95 struct usbip_exported_device *edev;
96 struct usbip_usb_device pdu_udev;
97 struct list_head *i;
98 int found = 0;
99 int error = 0;
100 int rc;
101
102 memset(&req, 0, sizeof(req));
103 memset(&reply, 0, sizeof(reply));
104
105 rc = usbip_net_recv(sockfd, &req, sizeof(req));
106 if (rc < 0) {
107 dbg("usbip_net_recv failed: import request");
108 return -1;
109 }
110 PACK_OP_IMPORT_REQUEST(0, &req);
111
112 list_for_each(i, &host_driver->edev_list) {
113 edev = list_entry(i, struct usbip_exported_device, node);
114 if (!strncmp(req.busid, edev->udev.busid, SYSFS_BUS_ID_SIZE)) {
115 info("found requested device: %s", req.busid);
116 found = 1;
117 break;
118 }
119 }
120
121 if (found) {
122 /* should set TCP_NODELAY for usbip */
123 usbip_net_set_nodelay(sockfd);
124
125 /* export device needs a TCP/IP socket descriptor */
126 rc = usbip_host_export_device(edev, sockfd);
127 if (rc < 0)
128 error = 1;
129 } else {
130 info("requested device not found: %s", req.busid);
131 error = 1;
132 }
133
134 rc = usbip_net_send_op_common(sockfd, OP_REP_IMPORT,
135 (!error ? ST_OK : ST_NA));
136 if (rc < 0) {
137 dbg("usbip_net_send_op_common failed: %#0x", OP_REP_IMPORT);
138 return -1;
139 }
140
141 if (error) {
142 dbg("import request busid %s: failed", req.busid);
143 return -1;
144 }
145
146 memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev));
147 usbip_net_pack_usb_device(1, &pdu_udev);
148
149 rc = usbip_net_send(sockfd, &pdu_udev, sizeof(pdu_udev));
150 if (rc < 0) {
151 dbg("usbip_net_send failed: devinfo");
152 return -1;
153 }
154
155 dbg("import request busid %s: complete", req.busid);
156
157 return 0;
158}
159
160static int send_reply_devlist(int connfd)
161{
162 struct usbip_exported_device *edev;
163 struct usbip_usb_device pdu_udev;
164 struct usbip_usb_interface pdu_uinf;
165 struct op_devlist_reply reply;
166 struct list_head *j;
167 int rc, i;
168
169 reply.ndev = 0;
170 /* number of exported devices */
171 list_for_each(j, &host_driver->edev_list) {
172 reply.ndev += 1;
173 }
174 info("exportable devices: %d", reply.ndev);
175
176 rc = usbip_net_send_op_common(connfd, OP_REP_DEVLIST, ST_OK);
177 if (rc < 0) {
178 dbg("usbip_net_send_op_common failed: %#0x", OP_REP_DEVLIST);
179 return -1;
180 }
181 PACK_OP_DEVLIST_REPLY(1, &reply);
182
183 rc = usbip_net_send(connfd, &reply, sizeof(reply));
184 if (rc < 0) {
185 dbg("usbip_net_send failed: %#0x", OP_REP_DEVLIST);
186 return -1;
187 }
188
189 list_for_each(j, &host_driver->edev_list) {
190 edev = list_entry(j, struct usbip_exported_device, node);
191 dump_usb_device(&edev->udev);
192 memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev));
193 usbip_net_pack_usb_device(1, &pdu_udev);
194
195 rc = usbip_net_send(connfd, &pdu_udev, sizeof(pdu_udev));
196 if (rc < 0) {
197 dbg("usbip_net_send failed: pdu_udev");
198 return -1;
199 }
200
201 for (i = 0; i < edev->udev.bNumInterfaces; i++) {
202 dump_usb_interface(&edev->uinf[i]);
203 memcpy(&pdu_uinf, &edev->uinf[i], sizeof(pdu_uinf));
204 usbip_net_pack_usb_interface(1, &pdu_uinf);
205
206 rc = usbip_net_send(connfd, &pdu_uinf,
207 sizeof(pdu_uinf));
208 if (rc < 0) {
209 err("usbip_net_send failed: pdu_uinf");
210 return -1;
211 }
212 }
213 }
214
215 return 0;
216}
217
218static int recv_request_devlist(int connfd)
219{
220 struct op_devlist_request req;
221 int rc;
222
223 memset(&req, 0, sizeof(req));
224
225 rc = usbip_net_recv(connfd, &req, sizeof(req));
226 if (rc < 0) {
227 dbg("usbip_net_recv failed: devlist request");
228 return -1;
229 }
230
231 rc = send_reply_devlist(connfd);
232 if (rc < 0) {
233 dbg("send_reply_devlist failed");
234 return -1;
235 }
236
237 return 0;
238}
239
240static int recv_pdu(int connfd)
241{
242 uint16_t code = OP_UNSPEC;
243 int ret;
244
245 ret = usbip_net_recv_op_common(connfd, &code);
246 if (ret < 0) {
247 dbg("could not receive opcode: %#0x", code);
248 return -1;
249 }
250
251 ret = usbip_host_refresh_device_list();
252 if (ret < 0) {
253 dbg("could not refresh device list: %d", ret);
254 return -1;
255 }
256
257 info("received request: %#0x(%d)", code, connfd);
258 switch (code) {
259 case OP_REQ_DEVLIST:
260 ret = recv_request_devlist(connfd);
261 break;
262 case OP_REQ_IMPORT:
263 ret = recv_request_import(connfd);
264 break;
265 case OP_REQ_DEVINFO:
266 case OP_REQ_CRYPKEY:
267 default:
268 err("received an unknown opcode: %#0x", code);
269 ret = -1;
270 }
271
272 if (ret == 0)
273 info("request %#0x(%d): complete", code, connfd);
274 else
275 info("request %#0x(%d): failed", code, connfd);
276
277 return ret;
278}
279
280#ifdef HAVE_LIBWRAP
281static int tcpd_auth(int connfd)
282{
283 struct request_info request;
284 int rc;
285
286 request_init(&request, RQ_DAEMON, PROGNAME, RQ_FILE, connfd, 0);
287 fromhost(&request);
288 rc = hosts_access(&request);
289 if (rc == 0)
290 return -1;
291
292 return 0;
293}
294#endif
295
296static int do_accept(int listenfd)
297{
298 int connfd;
299 struct sockaddr_storage ss;
300 socklen_t len = sizeof(ss);
301 char host[NI_MAXHOST], port[NI_MAXSERV];
302 int rc;
303
304 memset(&ss, 0, sizeof(ss));
305
306 connfd = accept(listenfd, (struct sockaddr *)&ss, &len);
307 if (connfd < 0) {
308 err("failed to accept connection");
309 return -1;
310 }
311
312 rc = getnameinfo((struct sockaddr *)&ss, len, host, sizeof(host),
313 port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
314 if (rc)
315 err("getnameinfo: %s", gai_strerror(rc));
316
317#ifdef HAVE_LIBWRAP
318 rc = tcpd_auth(connfd);
319 if (rc < 0) {
320 info("denied access from %s", host);
321 close(connfd);
322 return -1;
323 }
324#endif
325 info("connection from %s:%s", host, port);
326
327 return connfd;
328}
329
330int process_request(int listenfd)
331{
332 pid_t childpid;
333 int connfd;
334
335 connfd = do_accept(listenfd);
336 if (connfd < 0)
337 return -1;
338 childpid = fork();
339 if (childpid == 0) {
340 close(listenfd);
341 recv_pdu(connfd);
342 exit(0);
343 }
344 close(connfd);
345 return 0;
346}
347
348static void addrinfo_to_text(struct addrinfo *ai, char buf[],
349 const size_t buf_size)
350{
351 char hbuf[NI_MAXHOST];
352 char sbuf[NI_MAXSERV];
353 int rc;
354
355 buf[0] = '\0';
356
357 rc = getnameinfo(ai->ai_addr, ai->ai_addrlen, hbuf, sizeof(hbuf),
358 sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV);
359 if (rc)
360 err("getnameinfo: %s", gai_strerror(rc));
361
362 snprintf(buf, buf_size, "%s:%s", hbuf, sbuf);
363}
364
365static int listen_all_addrinfo(struct addrinfo *ai_head, int sockfdlist[],
366 int maxsockfd)
367{
368 struct addrinfo *ai;
369 int ret, nsockfd = 0;
370 const size_t ai_buf_size = NI_MAXHOST + NI_MAXSERV + 2;
371 char ai_buf[ai_buf_size];
372
373 for (ai = ai_head; ai && nsockfd < maxsockfd; ai = ai->ai_next) {
374 int sock;
375
376 addrinfo_to_text(ai, ai_buf, ai_buf_size);
377 dbg("opening %s", ai_buf);
378 sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
379 if (sock < 0) {
380 err("socket: %s: %d (%s)",
381 ai_buf, errno, strerror(errno));
382 continue;
383 }
384
385 usbip_net_set_reuseaddr(sock);
386 usbip_net_set_nodelay(sock);
387 /* We use seperate sockets for IPv4 and IPv6
388 * (see do_standalone_mode()) */
389 usbip_net_set_v6only(sock);
390
391 if (sock >= FD_SETSIZE) {
392 err("FD_SETSIZE: %s: sock=%d, max=%d",
393 ai_buf, sock, FD_SETSIZE);
394 close(sock);
395 continue;
396 }
397
398 ret = bind(sock, ai->ai_addr, ai->ai_addrlen);
399 if (ret < 0) {
400 err("bind: %s: %d (%s)",
401 ai_buf, errno, strerror(errno));
402 close(sock);
403 continue;
404 }
405
406 ret = listen(sock, SOMAXCONN);
407 if (ret < 0) {
408 err("listen: %s: %d (%s)",
409 ai_buf, errno, strerror(errno));
410 close(sock);
411 continue;
412 }
413
414 info("listening on %s", ai_buf);
415 sockfdlist[nsockfd++] = sock;
416 }
417
418 return nsockfd;
419}
420
421static struct addrinfo *do_getaddrinfo(char *host, int ai_family)
422{
423 struct addrinfo hints, *ai_head;
424 int rc;
425
426 memset(&hints, 0, sizeof(hints));
427 hints.ai_family = ai_family;
428 hints.ai_socktype = SOCK_STREAM;
429 hints.ai_flags = AI_PASSIVE;
430
431 rc = getaddrinfo(host, usbip_port_string, &hints, &ai_head);
432 if (rc) {
433 err("failed to get a network address %s: %s", usbip_port_string,
434 gai_strerror(rc));
435 return NULL;
436 }
437
438 return ai_head;
439}
440
441static void signal_handler(int i)
442{
443 dbg("received '%s' signal", strsignal(i));
444}
445
446static void set_signal(void)
447{
448 struct sigaction act;
449
450 memset(&act, 0, sizeof(act));
451 act.sa_handler = signal_handler;
452 sigemptyset(&act.sa_mask);
453 sigaction(SIGTERM, &act, NULL);
454 sigaction(SIGINT, &act, NULL);
455 act.sa_handler = SIG_IGN;
456 sigaction(SIGCLD, &act, NULL);
457}
458
459static const char *pid_file;
460
461static void write_pid_file(void)
462{
463 if (pid_file) {
464 dbg("creating pid file %s", pid_file);
465 FILE *fp;
466
467 fp = fopen(pid_file, "w");
468 if (!fp) {
469 err("pid_file: %s: %d (%s)",
470 pid_file, errno, strerror(errno));
471 return;
472 }
473 fprintf(fp, "%d\n", getpid());
474 fclose(fp);
475 }
476}
477
478static void remove_pid_file(void)
479{
480 if (pid_file) {
481 dbg("removing pid file %s", pid_file);
482 unlink(pid_file);
483 }
484}
485
486static int do_standalone_mode(int daemonize, int ipv4, int ipv6)
487{
488 struct addrinfo *ai_head;
489 int sockfdlist[MAXSOCKFD];
490 int nsockfd, family;
491 int i, terminate;
492 struct pollfd *fds;
493 struct timespec timeout;
494 sigset_t sigmask;
495
496 if (usbip_host_driver_open()) {
497 err("please load " USBIP_CORE_MOD_NAME ".ko and "
498 USBIP_HOST_DRV_NAME ".ko!");
499 return -1;
500 }
501
502 if (daemonize) {
503 if (daemon(0, 0) < 0) {
504 err("daemonizing failed: %s", strerror(errno));
505 usbip_host_driver_close();
506 return -1;
507 }
508 umask(0);
509 usbip_use_syslog = 1;
510 }
511 set_signal();
512 write_pid_file();
513
514 info("starting " PROGNAME " (%s)", usbip_version_string);
515
516 /*
517 * To suppress warnings on systems with bindv6only disabled
518 * (default), we use seperate sockets for IPv6 and IPv4 and set
519 * IPV6_V6ONLY on the IPv6 sockets.
520 */
521 if (ipv4 && ipv6)
522 family = AF_UNSPEC;
523 else if (ipv4)
524 family = AF_INET;
525 else
526 family = AF_INET6;
527
528 ai_head = do_getaddrinfo(NULL, family);
529 if (!ai_head) {
530 usbip_host_driver_close();
531 return -1;
532 }
533 nsockfd = listen_all_addrinfo(ai_head, sockfdlist,
534 sizeof(sockfdlist) / sizeof(*sockfdlist));
535 freeaddrinfo(ai_head);
536 if (nsockfd <= 0) {
537 err("failed to open a listening socket");
538 usbip_host_driver_close();
539 return -1;
540 }
541
542 dbg("listening on %d address%s", nsockfd, (nsockfd == 1) ? "" : "es");
543
544 fds = calloc(nsockfd, sizeof(struct pollfd));
545 for (i = 0; i < nsockfd; i++) {
546 fds[i].fd = sockfdlist[i];
547 fds[i].events = POLLIN;
548 }
549 timeout.tv_sec = MAIN_LOOP_TIMEOUT;
550 timeout.tv_nsec = 0;
551
552 sigfillset(&sigmask);
553 sigdelset(&sigmask, SIGTERM);
554 sigdelset(&sigmask, SIGINT);
555
556 terminate = 0;
557 while (!terminate) {
558 int r;
559
560 r = ppoll(fds, nsockfd, &timeout, &sigmask);
561 if (r < 0) {
562 dbg("%s", strerror(errno));
563 terminate = 1;
564 } else if (r) {
565 for (i = 0; i < nsockfd; i++) {
566 if (fds[i].revents & POLLIN) {
567 dbg("read event on fd[%d]=%d",
568 i, sockfdlist[i]);
569 process_request(sockfdlist[i]);
570 }
571 }
572 } else {
573 dbg("heartbeat timeout on ppoll()");
574 }
575 }
576
577 info("shutting down " PROGNAME);
578 free(fds);
579 usbip_host_driver_close();
580
581 return 0;
582}
583
584int main(int argc, char *argv[])
585{
586 static const struct option longopts[] = {
587 { "ipv4", no_argument, NULL, '4' },
588 { "ipv6", no_argument, NULL, '6' },
589 { "daemon", no_argument, NULL, 'D' },
590 { "daemon", no_argument, NULL, 'D' },
591 { "debug", no_argument, NULL, 'd' },
592 { "pid", optional_argument, NULL, 'P' },
593 { "tcp-port", required_argument, NULL, 't' },
594 { "help", no_argument, NULL, 'h' },
595 { "version", no_argument, NULL, 'v' },
596 { NULL, 0, NULL, 0 }
597 };
598
599 enum {
600 cmd_standalone_mode = 1,
601 cmd_help,
602 cmd_version
603 } cmd;
604
605 int daemonize = 0;
606 int ipv4 = 0, ipv6 = 0;
607 int opt, rc = -1;
608
609 pid_file = NULL;
610
611 usbip_use_stderr = 1;
612 usbip_use_syslog = 0;
613
614 if (geteuid() != 0)
615 err("not running as root?");
616
617 cmd = cmd_standalone_mode;
618 for (;;) {
619 opt = getopt_long(argc, argv, "46DdP::t:hv", longopts, NULL);
620
621 if (opt == -1)
622 break;
623
624 switch (opt) {
625 case '4':
626 ipv4 = 1;
627 break;
628 case '6':
629 ipv6 = 1;
630 break;
631 case 'D':
632 daemonize = 1;
633 break;
634 case 'd':
635 usbip_use_debug = 1;
636 break;
637 case 'h':
638 cmd = cmd_help;
639 break;
640 case 'P':
641 pid_file = optarg ? optarg : DEFAULT_PID_FILE;
642 break;
643 case 't':
644 usbip_setup_port_number(optarg);
645 break;
646 case 'v':
647 cmd = cmd_version;
648 break;
649 case '?':
650 usbipd_help();
651 default:
652 goto err_out;
653 }
654 }
655
656 if (!ipv4 && !ipv6)
657 ipv4 = ipv6 = 1;
658
659 switch (cmd) {
660 case cmd_standalone_mode:
661 rc = do_standalone_mode(daemonize, ipv4, ipv6);
662 remove_pid_file();
663 break;
664 case cmd_version:
665 printf(PROGNAME " (%s)\n", usbip_version_string);
666 rc = 0;
667 break;
668 case cmd_help:
669 usbipd_help();
670 rc = 0;
671 break;
672 default:
673 usbipd_help();
674 goto err_out;
675 }
676
677err_out:
678 return (rc > -1 ? EXIT_SUCCESS : EXIT_FAILURE);
679}
diff --git a/tools/usb/usbip/src/utils.c b/tools/usb/usbip/src/utils.c
new file mode 100644
index 000000000000..2b3d6d235015
--- /dev/null
+++ b/tools/usb/usbip/src/utils.c
@@ -0,0 +1,52 @@
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 <errno.h>
20#include <stdio.h>
21#include <string.h>
22
23#include "usbip_common.h"
24#include "utils.h"
25#include "sysfs_utils.h"
26
27int modify_match_busid(char *busid, int add)
28{
29 char attr_name[] = "match_busid";
30 char command[SYSFS_BUS_ID_SIZE + 4];
31 char match_busid_attr_path[SYSFS_PATH_MAX];
32 int rc;
33
34 snprintf(match_busid_attr_path, sizeof(match_busid_attr_path),
35 "%s/%s/%s/%s/%s/%s", SYSFS_MNT_PATH, SYSFS_BUS_NAME,
36 SYSFS_BUS_TYPE, SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME,
37 attr_name);
38
39 if (add)
40 snprintf(command, SYSFS_BUS_ID_SIZE + 4, "add %s", busid);
41 else
42 snprintf(command, SYSFS_BUS_ID_SIZE + 4, "del %s", busid);
43
44 rc = write_sysfs_attribute(match_busid_attr_path, command,
45 sizeof(command));
46 if (rc < 0) {
47 dbg("failed to write match_busid: %s", strerror(errno));
48 return -1;
49 }
50
51 return 0;
52}
diff --git a/tools/usb/usbip/src/utils.h b/tools/usb/usbip/src/utils.h
new file mode 100644
index 000000000000..5916fd3e02a6
--- /dev/null
+++ b/tools/usb/usbip/src/utils.h
@@ -0,0 +1,25 @@
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#ifndef __UTILS_H
20#define __UTILS_H
21
22int modify_match_busid(char *busid, int add);
23
24#endif /* __UTILS_H */
25