linux/drivers/staging/usbip/userspace/src/usbipd.c
<<
>>
Prefs
   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
  47#undef  PROGNAME
  48#define PROGNAME "usbipd"
  49#define MAXSOCKFD 20
  50
  51#define MAIN_LOOP_TIMEOUT 10
  52
  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"
  63        "       -h, --help                              \n"
  64        "               Print this help.                \n"
  65        "                                               \n"
  66        "       -v, --version                           \n"
  67        "               Show version.                   \n";
  68
  69static void usbipd_help(void)
  70{
  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;
  78        struct usbip_exported_device *edev;
  79        struct usbip_usb_device pdu_udev;
  80        int found = 0;
  81        int error = 0;
  82        int rc;
  83
  84        memset(&req, 0, sizeof(req));
  85        memset(&reply, 0, sizeof(reply));
  86
  87        rc = usbip_net_recv(sockfd, &req, sizeof(req));
  88        if (rc < 0) {
  89                dbg("usbip_net_recv failed: import request");
  90                return -1;
  91        }
  92        PACK_OP_IMPORT_REQUEST(0, &req);
  93
  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                }
 101        }
 102
 103        if (found) {
 104                /* should set TCP_NODELAY for usbip */
 105                usbip_net_set_nodelay(sockfd);
 106
 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;
 114        }
 115
 116        rc = usbip_net_send_op_common(sockfd, OP_REP_IMPORT,
 117                                      (!error ? ST_OK : ST_NA));
 118        if (rc < 0) {
 119                dbg("usbip_net_send_op_common failed: %#0x", OP_REP_IMPORT);
 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));
 129        usbip_net_pack_usb_device(1, &pdu_udev);
 130
 131        rc = usbip_net_send(sockfd, &pdu_udev, sizeof(pdu_udev));
 132        if (rc < 0) {
 133                dbg("usbip_net_send failed: devinfo");
 134                return -1;
 135        }
 136
 137        dbg("import request busid %s: complete", req.busid);
 138
 139        return 0;
 140}
 141
 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
 159        rc = usbip_net_send_op_common(connfd, OP_REP_DEVLIST, ST_OK);
 160        if (rc < 0) {
 161                dbg("usbip_net_send_op_common failed: %#0x", OP_REP_DEVLIST);
 162                return -1;
 163        }
 164        PACK_OP_DEVLIST_REPLY(1, &reply);
 165
 166        rc = usbip_net_send(connfd, &reply, sizeof(reply));
 167        if (rc < 0) {
 168                dbg("usbip_net_send failed: %#0x", OP_REP_DEVLIST);
 169                return -1;
 170        }
 171
 172        dlist_for_each_data(host_driver->edev_list, edev,
 173                            struct usbip_exported_device) {
 174                dump_usb_device(&edev->udev);
 175                memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev));
 176                usbip_net_pack_usb_device(1, &pdu_udev);
 177
 178                rc = usbip_net_send(connfd, &pdu_udev, sizeof(pdu_udev));
 179                if (rc < 0) {
 180                        dbg("usbip_net_send failed: pdu_udev");
 181                        return -1;
 182                }
 183
 184                for (i = 0; i < edev->udev.bNumInterfaces; i++) {
 185                        dump_usb_interface(&edev->uinf[i]);
 186                        memcpy(&pdu_uinf, &edev->uinf[i], sizeof(pdu_uinf));
 187                        usbip_net_pack_usb_interface(1, &pdu_uinf);
 188
 189                        rc = usbip_net_send(connfd, &pdu_uinf,
 190                                            sizeof(pdu_uinf));
 191                        if (rc < 0) {
 192                                dbg("usbip_net_send failed: pdu_uinf");
 193                                return -1;
 194                        }
 195                }
 196        }
 197
 198        return 0;
 199}
 200
 201static int recv_request_devlist(int connfd)
 202{
 203        struct op_devlist_request req;
 204        int rc;
 205
 206        memset(&req, 0, sizeof(req));
 207
 208        rc = usbip_net_recv(connfd, &req, sizeof(req));
 209        if (rc < 0) {
 210                dbg("usbip_net_recv failed: devlist request");
 211                return -1;
 212        }
 213
 214        rc = send_reply_devlist(connfd);
 215        if (rc < 0) {
 216                dbg("send_reply_devlist failed");
 217                return -1;
 218        }
 219
 220        return 0;
 221}
 222
 223static int recv_pdu(int connfd)
 224{
 225        uint16_t code = OP_UNSPEC;
 226        int ret;
 227
 228        ret = usbip_net_recv_op_common(connfd, &code);
 229        if (ret < 0) {
 230                dbg("could not receive opcode: %#0x", code);
 231                return -1;
 232        }
 233
 234        ret = usbip_host_refresh_device_list();
 235        if (ret < 0) {
 236                dbg("could not refresh device list: %d", ret);
 237                return -1;
 238        }
 239
 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;
 253        }
 254
 255        if (ret == 0)
 256                info("request %#0x(%d): complete", code, connfd);
 257        else
 258                info("request %#0x(%d): failed", code, connfd);
 259
 260        return ret;
 261}
 262
 263#ifdef HAVE_LIBWRAP
 264static int tcpd_auth(int connfd)
 265{
 266        struct request_info request;
 267        int rc;
 268
 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;
 274
 275        return 0;
 276}
 277#endif
 278
 279static int do_accept(int listenfd)
 280{
 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;
 286
 287        memset(&ss, 0, sizeof(ss));
 288
 289        connfd = accept(listenfd, (struct sockaddr *) &ss, &len);
 290        if (connfd < 0) {
 291                err("failed to accept connection");
 292                return -1;
 293        }
 294
 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));
 299
 300#ifdef HAVE_LIBWRAP
 301        rc = tcpd_auth(connfd);
 302        if (rc < 0) {
 303                info("denied access from %s", host);
 304                close(connfd);
 305                return -1;
 306        }
 307#endif
 308        info("connection from %s:%s", host, port);
 309
 310        return connfd;
 311}
 312
 313int process_request(int listenfd)
 314{
 315        pid_t childpid;
 316        int connfd;
 317
 318        connfd = do_accept(listenfd);
 319        if (connfd < 0)
 320                return -1;
 321        childpid = fork();
 322        if (childpid == 0) {
 323                close(listenfd);
 324                recv_pdu(connfd);
 325                exit(0);
 326        }
 327        close(connfd);
 328        return 0;
 329}
 330
 331static void log_addrinfo(struct addrinfo *ai)
 332{
 333        char hbuf[NI_MAXHOST];
 334        char sbuf[NI_MAXSERV];
 335        int rc;
 336
 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));
 341
 342        info("listening on %s:%s", hbuf, sbuf);
 343}
 344
 345static int listen_all_addrinfo(struct addrinfo *ai_head, int sockfdlist[])
 346{
 347        struct addrinfo *ai;
 348        int ret, nsockfd = 0;
 349
 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)
 354                        continue;
 355
 356                usbip_net_set_reuseaddr(sockfdlist[nsockfd]);
 357                usbip_net_set_nodelay(sockfdlist[nsockfd]);
 358
 359                if (sockfdlist[nsockfd] >= FD_SETSIZE) {
 360                        close(sockfdlist[nsockfd]);
 361                        sockfdlist[nsockfd] = -1;
 362                        continue;
 363                }
 364
 365                ret = bind(sockfdlist[nsockfd], ai->ai_addr, ai->ai_addrlen);
 366                if (ret < 0) {
 367                        close(sockfdlist[nsockfd]);
 368                        sockfdlist[nsockfd] = -1;
 369                        continue;
 370                }
 371
 372                ret = listen(sockfdlist[nsockfd], SOMAXCONN);
 373                if (ret < 0) {
 374                        close(sockfdlist[nsockfd]);
 375                        sockfdlist[nsockfd] = -1;
 376                        continue;
 377                }
 378
 379                log_addrinfo(ai);
 380                nsockfd++;
 381        }
 382
 383        if (nsockfd == 0)
 384                return -1;
 385
 386        dbg("listening on %d address%s", nsockfd, (nsockfd == 1) ? "" : "es");
 387
 388        return nsockfd;
 389}
 390
 391static struct addrinfo *do_getaddrinfo(char *host, int ai_family)
 392{
 393        struct addrinfo hints, *ai_head;
 394        int rc;
 395
 396        memset(&hints, 0, sizeof(hints));
 397        hints.ai_family   = ai_family;
 398        hints.ai_socktype = SOCK_STREAM;
 399        hints.ai_flags    = AI_PASSIVE;
 400
 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;
 406        }
 407
 408        return ai_head;
 409}
 410
 411static void signal_handler(int i)
 412{
 413        dbg("received '%s' signal", strsignal(i));
 414}
 415
 416static void set_signal(void)
 417{
 418        struct sigaction act;
 419
 420        memset(&act, 0, sizeof(act));
 421        act.sa_handler = signal_handler;
 422        sigemptyset(&act.sa_mask);
 423        sigaction(SIGTERM, &act, NULL);
 424        sigaction(SIGINT, &act, NULL);
 425        act.sa_handler = SIG_IGN;
 426        sigaction(SIGCLD, &act, NULL);
 427}
 428
 429static int do_standalone_mode(int daemonize)
 430{
 431        struct addrinfo *ai_head;
 432        int sockfdlist[MAXSOCKFD];
 433        int nsockfd;
 434        int i, terminate;
 435        struct pollfd *fds;
 436        struct timespec timeout;
 437        sigset_t sigmask;
 438
 439        if (usbip_host_driver_open()) {
 440                err("please load " USBIP_CORE_MOD_NAME ".ko and "
 441                    USBIP_HOST_DRV_NAME ".ko!");
 442                return -1;
 443        }
 444
 445        if (daemonize) {
 446                if (daemon(0, 0) < 0) {
 447                        err("daemonizing failed: %s", strerror(errno));
 448                        usbip_host_driver_close();
 449                        return -1;
 450                }
 451                umask(0);
 452                usbip_use_syslog = 1;
 453        }
 454        set_signal();
 455
 456        ai_head = do_getaddrinfo(NULL, PF_UNSPEC);
 457        if (!ai_head) {
 458                usbip_host_driver_close();
 459                return -1;
 460        }
 461
 462        info("starting " PROGNAME " (%s)", usbip_version_string);
 463
 464        nsockfd = listen_all_addrinfo(ai_head, sockfdlist);
 465        if (nsockfd <= 0) {
 466                err("failed to open a listening socket");
 467                freeaddrinfo(ai_head);
 468                usbip_host_driver_close();
 469                return -1;
 470        }
 471        fds = calloc(nsockfd, sizeof(struct pollfd));
 472        for (i = 0; i < nsockfd; i++) {
 473                fds[i].fd = sockfdlist[i];
 474                fds[i].events = POLLIN;
 475        }
 476        timeout.tv_sec = MAIN_LOOP_TIMEOUT;
 477        timeout.tv_nsec = 0;
 478
 479        sigfillset(&sigmask);
 480        sigdelset(&sigmask, SIGTERM);
 481        sigdelset(&sigmask, SIGINT);
 482
 483        terminate = 0;
 484        while (!terminate) {
 485                int r;
 486
 487                r = ppoll(fds, nsockfd, &timeout, &sigmask);
 488                if (r < 0) {
 489                        dbg("%s", strerror(errno));
 490                        terminate = 1;
 491                } else if (r) {
 492                        for (i = 0; i < nsockfd; i++) {
 493                                if (fds[i].revents & POLLIN) {
 494                                        dbg("read event on fd[%d]=%d",
 495                                            i, sockfdlist[i]);
 496                                        process_request(sockfdlist[i]);
 497                                }
 498                        }
 499                } else
 500                        dbg("heartbeat timeout on ppoll()");
 501        }
 502
 503        info("shutting down " PROGNAME);
 504        free(fds);
 505        freeaddrinfo(ai_head);
 506        usbip_host_driver_close();
 507
 508        return 0;
 509}
 510
 511int main(int argc, char *argv[])
 512{
 513        static const struct option longopts[] = {
 514                { "daemon",  no_argument, NULL, 'D' },
 515                { "debug",   no_argument, NULL, 'd' },
 516                { "help",    no_argument, NULL, 'h' },
 517                { "version", no_argument, NULL, 'v' },
 518                { NULL,      0,           NULL,  0  }
 519        };
 520
 521        enum {
 522                cmd_standalone_mode = 1,
 523                cmd_help,
 524                cmd_version
 525        } cmd;
 526
 527        int daemonize = 0;
 528        int opt, rc = -1;
 529
 530        usbip_use_stderr = 1;
 531        usbip_use_syslog = 0;
 532
 533        if (geteuid() != 0)
 534                err("not running as root?");
 535
 536        cmd = cmd_standalone_mode;
 537        for (;;) {
 538                opt = getopt_long(argc, argv, "Ddhv", longopts, NULL);
 539
 540                if (opt == -1)
 541                        break;
 542
 543                switch (opt) {
 544                case 'D':
 545                        daemonize = 1;
 546                        break;
 547                case 'd':
 548                        usbip_use_debug = 1;
 549                        break;
 550                case 'h':
 551                        cmd = cmd_help;
 552                        break;
 553                case 'v':
 554                        cmd = cmd_version;
 555                        break;
 556                case '?':
 557                        usbipd_help();
 558                default:
 559                        goto err_out;
 560                }
 561        }
 562
 563        switch (cmd) {
 564        case cmd_standalone_mode:
 565                rc = do_standalone_mode(daemonize);
 566                break;
 567        case cmd_version:
 568                printf(PROGNAME " (%s)\n", usbip_version_string);
 569                rc = 0;
 570                break;
 571        case cmd_help:
 572                usbipd_help();
 573                rc = 0;
 574                break;
 575        default:
 576                usbipd_help();
 577                goto err_out;
 578        }
 579
 580err_out:
 581        return (rc > -1 ? EXIT_SUCCESS : EXIT_FAILURE);
 582}
 583