linux/drivers/staging/usbip/userspace/src/usbipd.c
<<
>>
Prefs
   1/*
   2 *
   3 * Copyright (C) 2005-2007 Takahiro Hirofuchi
   4 */
   5
   6#ifdef HAVE_CONFIG_H
   7#include "../config.h"
   8#endif
   9
  10#include <unistd.h>
  11#include <netdb.h>
  12#include <strings.h>
  13#include <stdlib.h>
  14#include <sys/types.h>
  15#include <sys/stat.h>
  16#include <arpa/inet.h>
  17#include <sys/socket.h>
  18#include <netinet/in.h>
  19
  20#ifdef HAVE_LIBWRAP
  21#include <tcpd.h>
  22#endif
  23
  24#define _GNU_SOURCE
  25#include <getopt.h>
  26#include <signal.h>
  27
  28#include "usbip.h"
  29#include "usbip_network.h"
  30
  31#include <glib.h>
  32
  33static const char version[] = PACKAGE_STRING;
  34
  35
  36static int send_reply_devlist(int sockfd)
  37{
  38        int ret;
  39        struct usbip_exported_device *edev;
  40        struct op_devlist_reply reply;
  41
  42
  43        reply.ndev = 0;
  44
  45        /* how many devices are exported ? */
  46        dlist_for_each_data(stub_driver->edev_list, edev, struct usbip_exported_device) {
  47                reply.ndev += 1;
  48        }
  49
  50        dbg("%d devices are exported", reply.ndev);
  51
  52        ret = usbip_send_op_common(sockfd, OP_REP_DEVLIST,  ST_OK);
  53        if (ret < 0) {
  54                err("send op_common");
  55                return ret;
  56        }
  57
  58        PACK_OP_DEVLIST_REPLY(1, &reply);
  59
  60        ret = usbip_send(sockfd, (void *) &reply, sizeof(reply));
  61        if (ret < 0) {
  62                err("send op_devlist_reply");
  63                return ret;
  64        }
  65
  66        dlist_for_each_data(stub_driver->edev_list, edev, struct usbip_exported_device) {
  67                struct usb_device pdu_udev;
  68
  69                dump_usb_device(&edev->udev);
  70                memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev));
  71                pack_usb_device(1, &pdu_udev);
  72
  73                ret = usbip_send(sockfd, (void *) &pdu_udev, sizeof(pdu_udev));
  74                if (ret < 0) {
  75                        err("send pdu_udev");
  76                        return ret;
  77                }
  78
  79                for (int i=0; i < edev->udev.bNumInterfaces; i++) {
  80                        struct usb_interface pdu_uinf;
  81
  82                        dump_usb_interface(&edev->uinf[i]);
  83                        memcpy(&pdu_uinf, &edev->uinf[i], sizeof(pdu_uinf));
  84                        pack_usb_interface(1, &pdu_uinf);
  85
  86                        ret = usbip_send(sockfd, (void *) &pdu_uinf, sizeof(pdu_uinf));
  87                        if (ret < 0) {
  88                                err("send pdu_uinf");
  89                                return ret;
  90                        }
  91                }
  92        }
  93
  94        return 0;
  95}
  96
  97
  98static int recv_request_devlist(int sockfd)
  99{
 100        int ret;
 101        struct op_devlist_request req;
 102
 103        bzero(&req, sizeof(req));
 104
 105        ret = usbip_recv(sockfd, (void *) &req, sizeof(req));
 106        if (ret < 0) {
 107                err("recv devlist request");
 108                return -1;
 109        }
 110
 111        ret = send_reply_devlist(sockfd);
 112        if (ret < 0) {
 113                err("send devlist reply");
 114                return -1;
 115        }
 116
 117        return 0;
 118}
 119
 120
 121static int recv_request_import(int sockfd)
 122{
 123        int ret;
 124        struct op_import_request req;
 125        struct op_common reply;
 126        struct usbip_exported_device *edev;
 127        int found = 0;
 128        int error = 0;
 129
 130        bzero(&req, sizeof(req));
 131        bzero(&reply, sizeof(reply));
 132
 133        ret = usbip_recv(sockfd, (void *) &req, sizeof(req));
 134        if (ret < 0) {
 135                err("recv import request");
 136                return -1;
 137        }
 138
 139        PACK_OP_IMPORT_REQUEST(0, &req);
 140
 141        dlist_for_each_data(stub_driver->edev_list, edev, struct usbip_exported_device) {
 142                if (!strncmp(req.busid, edev->udev.busid, SYSFS_BUS_ID_SIZE)) {
 143                        dbg("found requested device %s", req.busid);
 144                        found = 1;
 145                        break;
 146                }
 147        }
 148
 149        if (found) {
 150                /* should set TCP_NODELAY for usbip */
 151                usbip_set_nodelay(sockfd);
 152
 153                /* export_device needs a TCP/IP socket descriptor */
 154                ret = usbip_stub_export_device(edev, sockfd);
 155                if (ret < 0)
 156                        error = 1;
 157        } else {
 158                info("not found requested device %s", req.busid);
 159                error = 1;
 160        }
 161
 162
 163        ret = usbip_send_op_common(sockfd, OP_REP_IMPORT, (!error ? ST_OK : ST_NA));
 164        if (ret < 0) {
 165                err("send import reply");
 166                return -1;
 167        }
 168
 169        if (!error) {
 170                struct usb_device pdu_udev;
 171
 172                memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev));
 173                pack_usb_device(1, &pdu_udev);
 174
 175                ret = usbip_send(sockfd, (void *) &pdu_udev, sizeof(pdu_udev));
 176                if (ret < 0) {
 177                        err("send devinfo");
 178                        return -1;
 179                }
 180        }
 181
 182        return 0;
 183}
 184
 185
 186
 187static int recv_pdu(int sockfd)
 188{
 189        int ret;
 190        uint16_t code = OP_UNSPEC;
 191
 192
 193        ret = usbip_recv_op_common(sockfd, &code);
 194        if (ret < 0) {
 195                err("recv op_common, %d", ret);
 196                return ret;
 197        }
 198
 199
 200        ret = usbip_stub_refresh_device_list();
 201        if (ret < 0)
 202                return -1;
 203
 204        switch(code) {
 205                case OP_REQ_DEVLIST:
 206                        ret = recv_request_devlist(sockfd);
 207                        break;
 208
 209                case OP_REQ_IMPORT:
 210                        ret = recv_request_import(sockfd);
 211                        break;
 212
 213                case OP_REQ_DEVINFO:
 214                case OP_REQ_CRYPKEY:
 215
 216                default:
 217                        err("unknown op_code, %d", code);
 218                        ret = -1;
 219        }
 220
 221
 222        return ret;
 223}
 224
 225
 226
 227
 228static void log_addrinfo(struct addrinfo *ai)
 229{
 230        int ret;
 231        char hbuf[NI_MAXHOST];
 232        char sbuf[NI_MAXSERV];
 233
 234        ret = getnameinfo(ai->ai_addr, ai->ai_addrlen, hbuf, sizeof(hbuf),
 235                        sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV);
 236        if (ret)
 237                err("getnameinfo, %s", gai_strerror(ret));
 238
 239        info("listen at [%s]:%s", hbuf, sbuf);
 240}
 241
 242static struct addrinfo *my_getaddrinfo(char *host, int ai_family)
 243{
 244        int ret;
 245        struct addrinfo hints, *ai_head;
 246
 247        bzero(&hints, sizeof(hints));
 248
 249        hints.ai_family   = ai_family;
 250        hints.ai_socktype = SOCK_STREAM;
 251        hints.ai_flags    = AI_PASSIVE;
 252
 253        ret = getaddrinfo(host, USBIP_PORT_STRING, &hints, &ai_head);
 254        if (ret) {
 255                err("%s: %s", USBIP_PORT_STRING, gai_strerror(ret));
 256                return NULL;
 257        }
 258
 259        return ai_head;
 260}
 261
 262#define MAXSOCK 20
 263static int listen_all_addrinfo(struct addrinfo *ai_head, int lsock[])
 264{
 265        struct addrinfo *ai;
 266        int n = 0;              /* number of sockets */
 267
 268        for (ai = ai_head; ai && n < MAXSOCK; ai = ai->ai_next) {
 269                int ret;
 270
 271                lsock[n] = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
 272                if (lsock[n] < 0)
 273                        continue;
 274
 275                usbip_set_reuseaddr(lsock[n]);
 276                usbip_set_nodelay(lsock[n]);
 277
 278                if (lsock[n] >= FD_SETSIZE) {
 279                        close(lsock[n]);
 280                        lsock[n] = -1;
 281                        continue;
 282                }
 283
 284                ret = bind(lsock[n], ai->ai_addr, ai->ai_addrlen);
 285                if (ret < 0) {
 286                        close(lsock[n]);
 287                        lsock[n] = -1;
 288                        continue;
 289                }
 290
 291                ret = listen(lsock[n], SOMAXCONN);
 292                if (ret < 0) {
 293                        close(lsock[n]);
 294                        lsock[n] = -1;
 295                        continue;
 296                }
 297
 298                log_addrinfo(ai);
 299
 300                /* next if succeed */
 301                n++;
 302        }
 303
 304        if (n == 0) {
 305                err("no socket to listen to");
 306                return -1;
 307        }
 308
 309        dbg("listen %d address%s", n, (n==1)?"":"es");
 310
 311        return n;
 312}
 313
 314#ifdef HAVE_LIBWRAP
 315static int tcpd_auth(int csock)
 316{
 317        int ret;
 318        struct request_info request;
 319
 320        request_init(&request, RQ_DAEMON, "usbipd", RQ_FILE, csock, 0);
 321
 322        fromhost(&request);
 323
 324        ret = hosts_access(&request);
 325        if (!ret)
 326                return -1;
 327
 328        return 0;
 329}
 330#endif
 331
 332static int my_accept(int lsock)
 333{
 334        int csock;
 335        struct sockaddr_storage ss;
 336        socklen_t len = sizeof(ss);
 337        char host[NI_MAXHOST], port[NI_MAXSERV];
 338        int ret;
 339
 340        bzero(&ss, sizeof(ss));
 341
 342        csock = accept(lsock, (struct sockaddr *) &ss, &len);
 343        if (csock < 0) {
 344                err("accept");
 345                return -1;
 346        }
 347
 348        ret = getnameinfo((struct sockaddr *) &ss, len,
 349                        host, sizeof(host), port, sizeof(port),
 350                        (NI_NUMERICHOST | NI_NUMERICSERV));
 351        if (ret)
 352                err("getnameinfo, %s", gai_strerror(ret));
 353
 354#ifdef HAVE_LIBWRAP
 355        ret = tcpd_auth(csock);
 356        if (ret < 0) {
 357                info("deny access from %s", host);
 358                close(csock);
 359                return -1;
 360        }
 361#endif
 362
 363        info("connected from %s:%s", host, port);
 364
 365        return csock;
 366}
 367
 368
 369GMainLoop *main_loop;
 370
 371static void signal_handler(int i)
 372{
 373        dbg("signal catched, code %d", i);
 374
 375        if (main_loop)
 376                g_main_loop_quit(main_loop);
 377}
 378
 379static void set_signal(void)
 380{
 381        struct sigaction act;
 382
 383        bzero(&act, sizeof(act));
 384        act.sa_handler = signal_handler;
 385        sigemptyset(&act.sa_mask);
 386        sigaction(SIGTERM, &act, NULL);
 387        sigaction(SIGINT, &act, NULL);
 388}
 389
 390
 391gboolean process_comming_request(GIOChannel *gio, GIOCondition condition,
 392                                 gpointer data __attribute__((unused)))
 393{
 394        int ret;
 395
 396        if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
 397                g_error("unknown condition");
 398
 399
 400        if (condition & G_IO_IN) {
 401                int lsock;
 402                int csock;
 403
 404                lsock = g_io_channel_unix_get_fd(gio);
 405
 406                csock = my_accept(lsock);
 407                if (csock < 0)
 408                        return TRUE;
 409
 410                ret = recv_pdu(csock);
 411                if (ret < 0)
 412                        err("process recieved pdu");
 413
 414                close(csock);
 415        }
 416
 417        return TRUE;
 418}
 419
 420
 421static void do_standalone_mode(gboolean daemonize)
 422{
 423        int ret;
 424        int lsock[MAXSOCK];
 425        struct addrinfo *ai_head;
 426        int n;
 427
 428
 429
 430        ret = usbip_names_init(USBIDS_FILE);
 431        if (ret)
 432                err("open usb.ids");
 433
 434        ret = usbip_stub_driver_open();
 435        if (ret < 0)
 436                g_error("driver open failed");
 437
 438        if (daemonize) {
 439                if (daemon(0,0) < 0)
 440                        g_error("daemonizing failed: %s", g_strerror(errno));
 441
 442                usbip_use_syslog = 1;
 443        }
 444
 445        set_signal();
 446
 447        ai_head = my_getaddrinfo(NULL, PF_UNSPEC);
 448        if (!ai_head)
 449                return;
 450
 451        n = listen_all_addrinfo(ai_head, lsock);
 452        if (n <= 0)
 453                g_error("no socket to listen to");
 454
 455        for (int i = 0; i < n; i++) {
 456                GIOChannel *gio;
 457
 458                gio = g_io_channel_unix_new(lsock[i]);
 459                g_io_add_watch(gio, (G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL),
 460                                process_comming_request, NULL);
 461        }
 462
 463
 464        info("usbipd start (%s)", version);
 465
 466
 467        main_loop = g_main_loop_new(FALSE, FALSE);
 468        g_main_loop_run(main_loop);
 469
 470        info("shutdown");
 471
 472        freeaddrinfo(ai_head);
 473        usbip_names_free();
 474        usbip_stub_driver_close();
 475
 476        return;
 477}
 478
 479
 480static const char help_message[] = "\
 481Usage: usbipd [options]                         \n\
 482        -D, --daemon                            \n\
 483                Run as a daemon process.        \n\
 484                                                \n\
 485        -d, --debug                             \n\
 486                Print debugging information.    \n\
 487                                                \n\
 488        -v, --version                           \n\
 489                Show version.                   \n\
 490                                                \n\
 491        -h, --help                              \n\
 492                Print this help.                \n";
 493
 494static void show_help(void)
 495{
 496        printf("%s", help_message);
 497}
 498
 499static const struct option longopts[] = {
 500        {"daemon",      no_argument,    NULL, 'D'},
 501        {"debug",       no_argument,    NULL, 'd'},
 502        {"version",     no_argument,    NULL, 'v'},
 503        {"help",        no_argument,    NULL, 'h'},
 504        {NULL,          0,              NULL,  0}
 505};
 506
 507int main(int argc, char *argv[])
 508{
 509        gboolean daemonize = FALSE;
 510
 511        enum {
 512                cmd_standalone_mode = 1,
 513                cmd_help,
 514                cmd_version
 515        } cmd = cmd_standalone_mode;
 516
 517
 518        usbip_use_stderr = 1;
 519        usbip_use_syslog = 0;
 520
 521        if (geteuid() != 0)
 522                g_warning("running non-root?");
 523
 524        for (;;) {
 525                int c;
 526                int index = 0;
 527
 528                c = getopt_long(argc, argv, "vhdD", longopts, &index);
 529
 530                if (c == -1)
 531                        break;
 532
 533                switch (c) {
 534                        case 'd':
 535                                usbip_use_debug = 1;
 536                                continue;
 537                        case 'v':
 538                                cmd = cmd_version;
 539                                break;
 540                        case 'h':
 541                                cmd = cmd_help;
 542                                break;
 543                        case 'D':
 544                                daemonize = TRUE;
 545                                break;
 546                        case '?':
 547                                show_help();
 548                                exit(EXIT_FAILURE);
 549                        default:
 550                                err("getopt");
 551                }
 552        }
 553
 554        switch (cmd) {
 555                case cmd_standalone_mode:
 556                        do_standalone_mode(daemonize);
 557                        break;
 558                case cmd_version:
 559                        printf("%s\n", version);
 560                        break;
 561                case cmd_help:
 562                        show_help();
 563                        break;
 564                default:
 565                        info("unknown cmd");
 566                        show_help();
 567        }
 568
 569        return 0;
 570}
 571