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 * Copyright (C) 2015-2016 Samsung Electronics
   5 *               Igor Kotrasinski <i.kotrasinsk@samsung.com>
   6 *               Krzysztof Opasiak <k.opasiak@samsung.com>
   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 <sys/stat.h>
  23
  24#include <limits.h>
  25#include <stdint.h>
  26#include <stdio.h>
  27#include <string.h>
  28
  29#include <fcntl.h>
  30#include <getopt.h>
  31#include <unistd.h>
  32#include <errno.h>
  33
  34#include "vhci_driver.h"
  35#include "usbip_common.h"
  36#include "usbip_network.h"
  37#include "usbip.h"
  38
  39static const char usbip_attach_usage_string[] =
  40        "usbip attach <args>\n"
  41        "    -r, --remote=<host>      The machine with exported USB devices\n"
  42        "    -b, --busid=<busid>    Busid of the device on <host>\n"
  43        "    -d, --device=<devid>    Id of the virtual UDC on <host>\n";
  44
  45void usbip_attach_usage(void)
  46{
  47        printf("usage: %s", usbip_attach_usage_string);
  48}
  49
  50#define MAX_BUFF 100
  51static int record_connection(char *host, char *port, char *busid, int rhport)
  52{
  53        int fd;
  54        char path[PATH_MAX+1];
  55        char buff[MAX_BUFF+1];
  56        int ret;
  57
  58        ret = mkdir(VHCI_STATE_PATH, 0700);
  59        if (ret < 0) {
  60                /* if VHCI_STATE_PATH exists, then it better be a directory */
  61                if (errno == EEXIST) {
  62                        struct stat s;
  63
  64                        ret = stat(VHCI_STATE_PATH, &s);
  65                        if (ret < 0)
  66                                return -1;
  67                        if (!(s.st_mode & S_IFDIR))
  68                                return -1;
  69                } else
  70                        return -1;
  71        }
  72
  73        snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport);
  74
  75        fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU);
  76        if (fd < 0)
  77                return -1;
  78
  79        snprintf(buff, MAX_BUFF, "%s %s %s\n",
  80                        host, port, busid);
  81
  82        ret = write(fd, buff, strlen(buff));
  83        if (ret != (ssize_t) strlen(buff)) {
  84                close(fd);
  85                return -1;
  86        }
  87
  88        close(fd);
  89
  90        return 0;
  91}
  92
  93static int import_device(int sockfd, struct usbip_usb_device *udev)
  94{
  95        int rc;
  96        int port;
  97
  98        rc = usbip_vhci_driver_open();
  99        if (rc < 0) {
 100                err("open vhci_driver");
 101                return -1;
 102        }
 103
 104        port = usbip_vhci_get_free_port();
 105        if (port < 0) {
 106                err("no free port");
 107                usbip_vhci_driver_close();
 108                return -1;
 109        }
 110
 111        rc = usbip_vhci_attach_device(port, sockfd, udev->busnum,
 112                                      udev->devnum, udev->speed);
 113        if (rc < 0) {
 114                err("import device");
 115                usbip_vhci_driver_close();
 116                return -1;
 117        }
 118
 119        usbip_vhci_driver_close();
 120
 121        return port;
 122}
 123
 124static int query_import_device(int sockfd, char *busid)
 125{
 126        int rc;
 127        struct op_import_request request;
 128        struct op_import_reply   reply;
 129        uint16_t code = OP_REP_IMPORT;
 130
 131        memset(&request, 0, sizeof(request));
 132        memset(&reply, 0, sizeof(reply));
 133
 134        /* send a request */
 135        rc = usbip_net_send_op_common(sockfd, OP_REQ_IMPORT, 0);
 136        if (rc < 0) {
 137                err("send op_common");
 138                return -1;
 139        }
 140
 141        strncpy(request.busid, busid, SYSFS_BUS_ID_SIZE-1);
 142
 143        PACK_OP_IMPORT_REQUEST(0, &request);
 144
 145        rc = usbip_net_send(sockfd, (void *) &request, sizeof(request));
 146        if (rc < 0) {
 147                err("send op_import_request");
 148                return -1;
 149        }
 150
 151        /* receive a reply */
 152        rc = usbip_net_recv_op_common(sockfd, &code);
 153        if (rc < 0) {
 154                err("recv op_common");
 155                return -1;
 156        }
 157
 158        rc = usbip_net_recv(sockfd, (void *) &reply, sizeof(reply));
 159        if (rc < 0) {
 160                err("recv op_import_reply");
 161                return -1;
 162        }
 163
 164        PACK_OP_IMPORT_REPLY(0, &reply);
 165
 166        /* check the reply */
 167        if (strncmp(reply.udev.busid, busid, SYSFS_BUS_ID_SIZE)) {
 168                err("recv different busid %s", reply.udev.busid);
 169                return -1;
 170        }
 171
 172        /* import a device */
 173        return import_device(sockfd, &reply.udev);
 174}
 175
 176static int attach_device(char *host, char *busid)
 177{
 178        int sockfd;
 179        int rc;
 180        int rhport;
 181
 182        sockfd = usbip_net_tcp_connect(host, usbip_port_string);
 183        if (sockfd < 0) {
 184                err("tcp connect");
 185                return -1;
 186        }
 187
 188        rhport = query_import_device(sockfd, busid);
 189        if (rhport < 0) {
 190                err("query");
 191                return -1;
 192        }
 193
 194        close(sockfd);
 195
 196        rc = record_connection(host, usbip_port_string, busid, rhport);
 197        if (rc < 0) {
 198                err("record connection");
 199                return -1;
 200        }
 201
 202        return 0;
 203}
 204
 205int usbip_attach(int argc, char *argv[])
 206{
 207        static const struct option opts[] = {
 208                { "remote", required_argument, NULL, 'r' },
 209                { "busid",  required_argument, NULL, 'b' },
 210                { "device",  required_argument, NULL, 'd' },
 211                { NULL, 0,  NULL, 0 }
 212        };
 213        char *host = NULL;
 214        char *busid = NULL;
 215        int opt;
 216        int ret = -1;
 217
 218        for (;;) {
 219                opt = getopt_long(argc, argv, "d:r:b:", opts, NULL);
 220
 221                if (opt == -1)
 222                        break;
 223
 224                switch (opt) {
 225                case 'r':
 226                        host = optarg;
 227                        break;
 228                case 'd':
 229                case 'b':
 230                        busid = optarg;
 231                        break;
 232                default:
 233                        goto err_out;
 234                }
 235        }
 236
 237        if (!host || !busid)
 238                goto err_out;
 239
 240        ret = attach_device(host, busid);
 241        goto out;
 242
 243err_out:
 244        usbip_attach_usage();
 245out:
 246        return ret;
 247}
 248