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        uint32_t speed = udev->speed;
  98
  99        rc = usbip_vhci_driver_open();
 100        if (rc < 0) {
 101                err("open vhci_driver");
 102                return -1;
 103        }
 104
 105        port = usbip_vhci_get_free_port(speed);
 106        if (port < 0) {
 107                err("no free port");
 108                usbip_vhci_driver_close();
 109                return -1;
 110        }
 111
 112        dbg("got free port %d", port);
 113
 114        rc = usbip_vhci_attach_device(port, sockfd, udev->busnum,
 115                                      udev->devnum, udev->speed);
 116        if (rc < 0) {
 117                err("import device");
 118                usbip_vhci_driver_close();
 119                return -1;
 120        }
 121
 122        usbip_vhci_driver_close();
 123
 124        return port;
 125}
 126
 127static int query_import_device(int sockfd, char *busid)
 128{
 129        int rc;
 130        struct op_import_request request;
 131        struct op_import_reply   reply;
 132        uint16_t code = OP_REP_IMPORT;
 133
 134        memset(&request, 0, sizeof(request));
 135        memset(&reply, 0, sizeof(reply));
 136
 137        /* send a request */
 138        rc = usbip_net_send_op_common(sockfd, OP_REQ_IMPORT, 0);
 139        if (rc < 0) {
 140                err("send op_common");
 141                return -1;
 142        }
 143
 144        strncpy(request.busid, busid, SYSFS_BUS_ID_SIZE-1);
 145
 146        PACK_OP_IMPORT_REQUEST(0, &request);
 147
 148        rc = usbip_net_send(sockfd, (void *) &request, sizeof(request));
 149        if (rc < 0) {
 150                err("send op_import_request");
 151                return -1;
 152        }
 153
 154        /* receive a reply */
 155        rc = usbip_net_recv_op_common(sockfd, &code);
 156        if (rc < 0) {
 157                err("recv op_common");
 158                return -1;
 159        }
 160
 161        rc = usbip_net_recv(sockfd, (void *) &reply, sizeof(reply));
 162        if (rc < 0) {
 163                err("recv op_import_reply");
 164                return -1;
 165        }
 166
 167        PACK_OP_IMPORT_REPLY(0, &reply);
 168
 169        /* check the reply */
 170        if (strncmp(reply.udev.busid, busid, SYSFS_BUS_ID_SIZE)) {
 171                err("recv different busid %s", reply.udev.busid);
 172                return -1;
 173        }
 174
 175        /* import a device */
 176        return import_device(sockfd, &reply.udev);
 177}
 178
 179static int attach_device(char *host, char *busid)
 180{
 181        int sockfd;
 182        int rc;
 183        int rhport;
 184
 185        sockfd = usbip_net_tcp_connect(host, usbip_port_string);
 186        if (sockfd < 0) {
 187                err("tcp connect");
 188                return -1;
 189        }
 190
 191        rhport = query_import_device(sockfd, busid);
 192        if (rhport < 0) {
 193                err("query");
 194                return -1;
 195        }
 196
 197        close(sockfd);
 198
 199        rc = record_connection(host, usbip_port_string, busid, rhport);
 200        if (rc < 0) {
 201                err("record connection");
 202                return -1;
 203        }
 204
 205        return 0;
 206}
 207
 208int usbip_attach(int argc, char *argv[])
 209{
 210        static const struct option opts[] = {
 211                { "remote", required_argument, NULL, 'r' },
 212                { "busid",  required_argument, NULL, 'b' },
 213                { "device",  required_argument, NULL, 'd' },
 214                { NULL, 0,  NULL, 0 }
 215        };
 216        char *host = NULL;
 217        char *busid = NULL;
 218        int opt;
 219        int ret = -1;
 220
 221        for (;;) {
 222                opt = getopt_long(argc, argv, "d:r:b:", opts, NULL);
 223
 224                if (opt == -1)
 225                        break;
 226
 227                switch (opt) {
 228                case 'r':
 229                        host = optarg;
 230                        break;
 231                case 'd':
 232                case 'b':
 233                        busid = optarg;
 234                        break;
 235                default:
 236                        goto err_out;
 237                }
 238        }
 239
 240        if (!host || !busid)
 241                goto err_out;
 242
 243        ret = attach_device(host, busid);
 244        goto out;
 245
 246err_out:
 247        usbip_attach_usage();
 248out:
 249        return ret;
 250}
 251