Merge 3.9-rc5 into staging-next
[deliverable/linux.git] / drivers / staging / usbip / userspace / src / usbipd.c
CommitLineData
0945b4fe 1/*
e2ec6b4e 2 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
3 * 2005-2007 Takahiro Hirofuchi
0945b4fe 4 *
e2ec6b4e 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/>.
0945b4fe
TH
17 */
18
19#ifdef HAVE_CONFIG_H
20#include "../config.h"
21#endif
22
328f7f8a 23#define _GNU_SOURCE
d2c15e25 24#include <errno.h>
0945b4fe
TH
25#include <unistd.h>
26#include <netdb.h>
950a4cd8 27#include <string.h>
0945b4fe
TH
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
0945b4fe
TH
39#include <getopt.h>
40#include <signal.h>
328f7f8a 41#include <poll.h>
0945b4fe 42
7104b5df 43#include "usbip_host_driver.h"
d2c15e25 44#include "usbip_common.h"
0945b4fe
TH
45#include "usbip_network.h"
46
e2ec6b4e 47#undef PROGNAME
48#define PROGNAME "usbipd"
49#define MAXSOCKFD 20
50
328f7f8a 51#define MAIN_LOOP_TIMEOUT 10
0945b4fe 52
e2ec6b4e 53static const char usbip_version_string[] = PACKAGE_STRING;
54
55static const char usbipd_help_string[] =
56 "usage: usbipd [options] \n"
57 " -D, --daemon \n"
58 " Run as a daemon process. \n"
59 " \n"
60 " -d, --debug \n"
61 " Print debugging information. \n"
62 " \n"
5037307d 63 " -h, --help \n"
e2ec6b4e 64 " Print this help. \n"
65 " \n"
66 " -v, --version \n"
67 " Show version. \n";
68
69static void usbipd_help(void)
0945b4fe 70{
e2ec6b4e 71 printf("%s\n", usbipd_help_string);
72}
73
74static int recv_request_import(int sockfd)
75{
76 struct op_import_request req;
77 struct op_common reply;
0945b4fe 78 struct usbip_exported_device *edev;
e2ec6b4e 79 struct usbip_usb_device pdu_udev;
80 int found = 0;
81 int error = 0;
82 int rc;
0945b4fe 83
e2ec6b4e 84 memset(&req, 0, sizeof(req));
85 memset(&reply, 0, sizeof(reply));
0945b4fe 86
3c6e9e8f 87 rc = usbip_net_recv(sockfd, &req, sizeof(req));
e2ec6b4e 88 if (rc < 0) {
3c6e9e8f 89 dbg("usbip_net_recv failed: import request");
e2ec6b4e 90 return -1;
91 }
92 PACK_OP_IMPORT_REQUEST(0, &req);
0945b4fe 93
e2ec6b4e 94 dlist_for_each_data(host_driver->edev_list, edev,
95 struct usbip_exported_device) {
96 if (!strncmp(req.busid, edev->udev.busid, SYSFS_BUS_ID_SIZE)) {
97 info("found requested device: %s", req.busid);
98 found = 1;
99 break;
100 }
0945b4fe
TH
101 }
102
e2ec6b4e 103 if (found) {
104 /* should set TCP_NODELAY for usbip */
3c6e9e8f 105 usbip_net_set_nodelay(sockfd);
0945b4fe 106
e2ec6b4e 107 /* export device needs a TCP/IP socket descriptor */
108 rc = usbip_host_export_device(edev, sockfd);
109 if (rc < 0)
110 error = 1;
111 } else {
112 info("requested device not found: %s", req.busid);
113 error = 1;
0945b4fe
TH
114 }
115
3c6e9e8f 116 rc = usbip_net_send_op_common(sockfd, OP_REP_IMPORT,
117 (!error ? ST_OK : ST_NA));
e2ec6b4e 118 if (rc < 0) {
3c6e9e8f 119 dbg("usbip_net_send_op_common failed: %#0x", OP_REP_IMPORT);
e2ec6b4e 120 return -1;
121 }
122
123 if (error) {
124 dbg("import request busid %s: failed", req.busid);
125 return -1;
126 }
127
128 memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev));
3c6e9e8f 129 usbip_net_pack_usb_device(1, &pdu_udev);
e2ec6b4e 130
3c6e9e8f 131 rc = usbip_net_send(sockfd, &pdu_udev, sizeof(pdu_udev));
e2ec6b4e 132 if (rc < 0) {
3c6e9e8f 133 dbg("usbip_net_send failed: devinfo");
e2ec6b4e 134 return -1;
0945b4fe
TH
135 }
136
e2ec6b4e 137 dbg("import request busid %s: complete", req.busid);
138
139 return 0;
140}
0945b4fe 141
e2ec6b4e 142static int send_reply_devlist(int connfd)
143{
144 struct usbip_exported_device *edev;
145 struct usbip_usb_device pdu_udev;
146 struct usbip_usb_interface pdu_uinf;
147 struct op_devlist_reply reply;
148 int i;
149 int rc;
150
151 reply.ndev = 0;
152 /* number of exported devices */
153 dlist_for_each_data(host_driver->edev_list, edev,
154 struct usbip_exported_device) {
155 reply.ndev += 1;
156 }
157 info("exportable devices: %d", reply.ndev);
158
3c6e9e8f 159 rc = usbip_net_send_op_common(connfd, OP_REP_DEVLIST, ST_OK);
e2ec6b4e 160 if (rc < 0) {
3c6e9e8f 161 dbg("usbip_net_send_op_common failed: %#0x", OP_REP_DEVLIST);
e2ec6b4e 162 return -1;
163 }
164 PACK_OP_DEVLIST_REPLY(1, &reply);
165
3c6e9e8f 166 rc = usbip_net_send(connfd, &reply, sizeof(reply));
e2ec6b4e 167 if (rc < 0) {
3c6e9e8f 168 dbg("usbip_net_send failed: %#0x", OP_REP_DEVLIST);
e2ec6b4e 169 return -1;
170 }
171
172 dlist_for_each_data(host_driver->edev_list, edev,
173 struct usbip_exported_device) {
0945b4fe
TH
174 dump_usb_device(&edev->udev);
175 memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev));
3c6e9e8f 176 usbip_net_pack_usb_device(1, &pdu_udev);
0945b4fe 177
3c6e9e8f 178 rc = usbip_net_send(connfd, &pdu_udev, sizeof(pdu_udev));
e2ec6b4e 179 if (rc < 0) {
3c6e9e8f 180 dbg("usbip_net_send failed: pdu_udev");
e2ec6b4e 181 return -1;
0945b4fe
TH
182 }
183
e2ec6b4e 184 for (i = 0; i < edev->udev.bNumInterfaces; i++) {
0945b4fe
TH
185 dump_usb_interface(&edev->uinf[i]);
186 memcpy(&pdu_uinf, &edev->uinf[i], sizeof(pdu_uinf));
3c6e9e8f 187 usbip_net_pack_usb_interface(1, &pdu_uinf);
0945b4fe 188
3c6e9e8f 189 rc = usbip_net_send(connfd, &pdu_uinf,
190 sizeof(pdu_uinf));
e2ec6b4e 191 if (rc < 0) {
3c6e9e8f 192 dbg("usbip_net_send failed: pdu_uinf");
e2ec6b4e 193 return -1;
0945b4fe
TH
194 }
195 }
196 }
197
198 return 0;
199}
200
e2ec6b4e 201static int recv_request_devlist(int connfd)
0945b4fe 202{
0945b4fe 203 struct op_devlist_request req;
e2ec6b4e 204 int rc;
0945b4fe 205
950a4cd8 206 memset(&req, 0, sizeof(req));
0945b4fe 207
3c6e9e8f 208 rc = usbip_net_recv(connfd, &req, sizeof(req));
e2ec6b4e 209 if (rc < 0) {
3c6e9e8f 210 dbg("usbip_net_recv failed: devlist request");
0945b4fe
TH
211 return -1;
212 }
213
e2ec6b4e 214 rc = send_reply_devlist(connfd);
215 if (rc < 0) {
216 dbg("send_reply_devlist failed");
0945b4fe
TH
217 return -1;
218 }
219
220 return 0;
221}
222
e2ec6b4e 223static int recv_pdu(int connfd)
0945b4fe 224{
e2ec6b4e 225 uint16_t code = OP_UNSPEC;
0945b4fe 226 int ret;
0945b4fe 227
3c6e9e8f 228 ret = usbip_net_recv_op_common(connfd, &code);
0945b4fe 229 if (ret < 0) {
e2ec6b4e 230 dbg("could not receive opcode: %#0x", code);
0945b4fe
TH
231 return -1;
232 }
233
e2ec6b4e 234 ret = usbip_host_refresh_device_list();
235 if (ret < 0) {
236 dbg("could not refresh device list: %d", ret);
237 return -1;
0945b4fe
TH
238 }
239
e2ec6b4e 240 info("received request: %#0x(%d)", code, connfd);
241 switch (code) {
242 case OP_REQ_DEVLIST:
243 ret = recv_request_devlist(connfd);
244 break;
245 case OP_REQ_IMPORT:
246 ret = recv_request_import(connfd);
247 break;
248 case OP_REQ_DEVINFO:
249 case OP_REQ_CRYPKEY:
250 default:
251 err("received an unknown opcode: %#0x", code);
252 ret = -1;
0945b4fe
TH
253 }
254
e2ec6b4e 255 if (ret == 0)
256 info("request %#0x(%d): complete", code, connfd);
257 else
258 info("request %#0x(%d): failed", code, connfd);
0945b4fe 259
e2ec6b4e 260 return ret;
261}
0945b4fe 262
e2ec6b4e 263#ifdef HAVE_LIBWRAP
264static int tcpd_auth(int connfd)
265{
266 struct request_info request;
267 int rc;
0945b4fe 268
e2ec6b4e 269 request_init(&request, RQ_DAEMON, PROGNAME, RQ_FILE, connfd, 0);
270 fromhost(&request);
271 rc = hosts_access(&request);
272 if (rc == 0)
273 return -1;
0945b4fe
TH
274
275 return 0;
276}
e2ec6b4e 277#endif
0945b4fe 278
e2ec6b4e 279static int do_accept(int listenfd)
0945b4fe 280{
e2ec6b4e 281 int connfd;
282 struct sockaddr_storage ss;
283 socklen_t len = sizeof(ss);
284 char host[NI_MAXHOST], port[NI_MAXSERV];
285 int rc;
0945b4fe 286
e2ec6b4e 287 memset(&ss, 0, sizeof(ss));
0945b4fe 288
e2ec6b4e 289 connfd = accept(listenfd, (struct sockaddr *) &ss, &len);
290 if (connfd < 0) {
291 err("failed to accept connection");
292 return -1;
0945b4fe
TH
293 }
294
e2ec6b4e 295 rc = getnameinfo((struct sockaddr *) &ss, len, host, sizeof(host),
296 port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
297 if (rc)
298 err("getnameinfo: %s", gai_strerror(rc));
0945b4fe 299
e2ec6b4e 300#ifdef HAVE_LIBWRAP
301 rc = tcpd_auth(connfd);
302 if (rc < 0) {
303 info("denied access from %s", host);
304 close(connfd);
0945b4fe 305 return -1;
e2ec6b4e 306 }
307#endif
308 info("connection from %s:%s", host, port);
0945b4fe 309
e2ec6b4e 310 return connfd;
311}
0945b4fe 312
328f7f8a 313int process_request(int listenfd)
e2ec6b4e 314{
328f7f8a 315 pid_t childpid;
e2ec6b4e 316 int connfd;
0945b4fe 317
328f7f8a
IH
318 connfd = do_accept(listenfd);
319 if (connfd < 0)
320 return -1;
321 childpid = fork();
322 if (childpid == 0) {
323 close(listenfd);
e2ec6b4e 324 recv_pdu(connfd);
328f7f8a 325 exit(0);
e2ec6b4e 326 }
328f7f8a
IH
327 close(connfd);
328 return 0;
e2ec6b4e 329}
0945b4fe
TH
330
331static void log_addrinfo(struct addrinfo *ai)
332{
0945b4fe
TH
333 char hbuf[NI_MAXHOST];
334 char sbuf[NI_MAXSERV];
e2ec6b4e 335 int rc;
0945b4fe 336
e2ec6b4e 337 rc = getnameinfo(ai->ai_addr, ai->ai_addrlen, hbuf, sizeof(hbuf),
338 sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV);
339 if (rc)
340 err("getnameinfo: %s", gai_strerror(rc));
0945b4fe 341
e2ec6b4e 342 info("listening on %s:%s", hbuf, sbuf);
0945b4fe
TH
343}
344
e2ec6b4e 345static int listen_all_addrinfo(struct addrinfo *ai_head, int sockfdlist[])
0945b4fe
TH
346{
347 struct addrinfo *ai;
e2ec6b4e 348 int ret, nsockfd = 0;
0945b4fe 349
e2ec6b4e 350 for (ai = ai_head; ai && nsockfd < MAXSOCKFD; ai = ai->ai_next) {
351 sockfdlist[nsockfd] = socket(ai->ai_family, ai->ai_socktype,
352 ai->ai_protocol);
353 if (sockfdlist[nsockfd] < 0)
0945b4fe
TH
354 continue;
355
3c6e9e8f 356 usbip_net_set_reuseaddr(sockfdlist[nsockfd]);
357 usbip_net_set_nodelay(sockfdlist[nsockfd]);
0945b4fe 358
e2ec6b4e 359 if (sockfdlist[nsockfd] >= FD_SETSIZE) {
360 close(sockfdlist[nsockfd]);
361 sockfdlist[nsockfd] = -1;
0945b4fe
TH
362 continue;
363 }
364
e2ec6b4e 365 ret = bind(sockfdlist[nsockfd], ai->ai_addr, ai->ai_addrlen);
0945b4fe 366 if (ret < 0) {
e2ec6b4e 367 close(sockfdlist[nsockfd]);
368 sockfdlist[nsockfd] = -1;
0945b4fe
TH
369 continue;
370 }
371
e2ec6b4e 372 ret = listen(sockfdlist[nsockfd], SOMAXCONN);
0945b4fe 373 if (ret < 0) {
e2ec6b4e 374 close(sockfdlist[nsockfd]);
375 sockfdlist[nsockfd] = -1;
0945b4fe
TH
376 continue;
377 }
378
379 log_addrinfo(ai);
e2ec6b4e 380 nsockfd++;
0945b4fe
TH
381 }
382
e2ec6b4e 383 if (nsockfd == 0)
0945b4fe 384 return -1;
0945b4fe 385
e2ec6b4e 386 dbg("listening on %d address%s", nsockfd, (nsockfd == 1) ? "" : "es");
0945b4fe 387
e2ec6b4e 388 return nsockfd;
0945b4fe 389}
0945b4fe 390
e2ec6b4e 391static struct addrinfo *do_getaddrinfo(char *host, int ai_family)
0945b4fe 392{
e2ec6b4e 393 struct addrinfo hints, *ai_head;
394 int rc;
0945b4fe 395
e2ec6b4e 396 memset(&hints, 0, sizeof(hints));
397 hints.ai_family = ai_family;
398 hints.ai_socktype = SOCK_STREAM;
399 hints.ai_flags = AI_PASSIVE;
0945b4fe 400
e2ec6b4e 401 rc = getaddrinfo(host, USBIP_PORT_STRING, &hints, &ai_head);
402 if (rc) {
403 err("failed to get a network address %s: %s", USBIP_PORT_STRING,
404 gai_strerror(rc));
405 return NULL;
0945b4fe 406 }
0945b4fe 407
e2ec6b4e 408 return ai_head;
0945b4fe
TH
409}
410
0945b4fe
TH
411static void signal_handler(int i)
412{
328f7f8a 413 dbg("received '%s' signal", strsignal(i));
0945b4fe
TH
414}
415
416static void set_signal(void)
417{
418 struct sigaction act;
419
950a4cd8 420 memset(&act, 0, sizeof(act));
0945b4fe
TH
421 act.sa_handler = signal_handler;
422 sigemptyset(&act.sa_mask);
423 sigaction(SIGTERM, &act, NULL);
424 sigaction(SIGINT, &act, NULL);
328f7f8a
IH
425 act.sa_handler = SIG_IGN;
426 sigaction(SIGCLD, &act, NULL);
0945b4fe
TH
427}
428
328f7f8a 429static int do_standalone_mode(int daemonize)
0945b4fe 430{
0945b4fe 431 struct addrinfo *ai_head;
e2ec6b4e 432 int sockfdlist[MAXSOCKFD];
433 int nsockfd;
328f7f8a
IH
434 int i, terminate;
435 struct pollfd *fds;
436 struct timespec timeout;
437 sigset_t sigmask;
0945b4fe 438
e2ec6b4e 439 if (usbip_names_init(USBIDS_FILE))
440 err("failed to open %s", USBIDS_FILE);
0945b4fe 441
e2ec6b4e 442 if (usbip_host_driver_open()) {
443 err("please load " USBIP_CORE_MOD_NAME ".ko and "
444 USBIP_HOST_DRV_NAME ".ko!");
445 return -1;
446 }
0945b4fe
TH
447
448 if (daemonize) {
5037307d 449 if (daemon(0, 0) < 0) {
e2ec6b4e 450 err("daemonizing failed: %s", strerror(errno));
451 return -1;
452 }
328f7f8a 453 umask(0);
0945b4fe
TH
454 usbip_use_syslog = 1;
455 }
0945b4fe
TH
456 set_signal();
457
e2ec6b4e 458 ai_head = do_getaddrinfo(NULL, PF_UNSPEC);
0945b4fe 459 if (!ai_head)
e2ec6b4e 460 return -1;
0945b4fe 461
e2ec6b4e 462 info("starting " PROGNAME " (%s)", usbip_version_string);
0945b4fe 463
e2ec6b4e 464 nsockfd = listen_all_addrinfo(ai_head, sockfdlist);
465 if (nsockfd <= 0) {
466 err("failed to open a listening socket");
467 return -1;
468 }
328f7f8a 469 fds = calloc(nsockfd, sizeof(struct pollfd));
e2ec6b4e 470 for (i = 0; i < nsockfd; i++) {
328f7f8a
IH
471 fds[i].fd = sockfdlist[i];
472 fds[i].events = POLLIN;
473 }
474 timeout.tv_sec = MAIN_LOOP_TIMEOUT;
475 timeout.tv_nsec = 0;
476
477 sigfillset(&sigmask);
478 sigdelset(&sigmask, SIGTERM);
479 sigdelset(&sigmask, SIGINT);
480
481 terminate = 0;
482 while (!terminate) {
483 int r;
484
485 r = ppoll(fds, nsockfd, &timeout, &sigmask);
486 if (r < 0) {
487 dbg("%s", strerror(errno));
488 terminate = 1;
489 } else if (r) {
490 for (i = 0; i < nsockfd; i++) {
491 if (fds[i].revents & POLLIN) {
492 dbg("read event on fd[%d]=%d",
493 i, sockfdlist[i]);
494 process_request(sockfdlist[i]);
495 }
496 }
497 } else
498 dbg("heartbeat timeout on ppoll()");
0945b4fe 499 }
0945b4fe 500
e2ec6b4e 501 info("shutting down " PROGNAME);
328f7f8a 502 free(fds);
0945b4fe 503 freeaddrinfo(ai_head);
7104b5df 504 usbip_host_driver_close();
e2ec6b4e 505 usbip_names_free();
0945b4fe 506
e2ec6b4e 507 return 0;
0945b4fe
TH
508}
509
0945b4fe
TH
510int main(int argc, char *argv[])
511{
e2ec6b4e 512 static const struct option longopts[] = {
513 { "daemon", no_argument, NULL, 'D' },
514 { "debug", no_argument, NULL, 'd' },
515 { "help", no_argument, NULL, 'h' },
516 { "version", no_argument, NULL, 'v' },
517 { NULL, 0, NULL, 0 }
518 };
0945b4fe
TH
519
520 enum {
521 cmd_standalone_mode = 1,
522 cmd_help,
523 cmd_version
e2ec6b4e 524 } cmd;
0945b4fe 525
328f7f8a 526 int daemonize = 0;
e2ec6b4e 527 int opt, rc = -1;
0945b4fe
TH
528
529 usbip_use_stderr = 1;
530 usbip_use_syslog = 0;
531
532 if (geteuid() != 0)
e2ec6b4e 533 err("not running as root?");
0945b4fe 534
e2ec6b4e 535 cmd = cmd_standalone_mode;
0945b4fe 536 for (;;) {
e2ec6b4e 537 opt = getopt_long(argc, argv, "Ddhv", longopts, NULL);
0945b4fe 538
e2ec6b4e 539 if (opt == -1)
0945b4fe
TH
540 break;
541
e2ec6b4e 542 switch (opt) {
543 case 'D':
328f7f8a 544 daemonize = 1;
e2ec6b4e 545 break;
546 case 'd':
547 usbip_use_debug = 1;
0945b4fe 548 break;
e2ec6b4e 549 case 'h':
550 cmd = cmd_help;
0945b4fe 551 break;
e2ec6b4e 552 case 'v':
553 cmd = cmd_version;
0945b4fe 554 break;
e2ec6b4e 555 case '?':
556 usbipd_help();
0945b4fe 557 default:
e2ec6b4e 558 goto err_out;
559 }
0945b4fe
TH
560 }
561
e2ec6b4e 562 switch (cmd) {
563 case cmd_standalone_mode:
564 rc = do_standalone_mode(daemonize);
565 break;
566 case cmd_version:
567 printf(PROGNAME " (%s)\n", usbip_version_string);
568 rc = 0;
569 break;
570 case cmd_help:
571 usbipd_help();
572 rc = 0;
573 break;
574 default:
575 usbipd_help();
576 goto err_out;
577 }
578
579err_out:
580 return (rc > -1 ? EXIT_SUCCESS : EXIT_FAILURE);
0945b4fe 581}
This page took 0.282637 seconds and 5 git commands to generate.