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