linux/tools/usb/usbip/src/usbip_attach.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#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}
 242