linux/tools/usb/usbip/libsrc/vhci_driver.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2005-2007 Takahiro Hirofuchi
   3 */
   4
   5#include "usbip_common.h"
   6#include "vhci_driver.h"
   7#include <limits.h>
   8#include <netdb.h>
   9#include <libudev.h>
  10#include "sysfs_utils.h"
  11
  12#undef  PROGNAME
  13#define PROGNAME "libusbip"
  14
  15struct usbip_vhci_driver *vhci_driver;
  16struct udev *udev_context;
  17
  18static struct usbip_imported_device *
  19imported_device_init(struct usbip_imported_device *idev, char *busid)
  20{
  21        struct udev_device *sudev;
  22
  23        sudev = udev_device_new_from_subsystem_sysname(udev_context,
  24                                                       "usb", busid);
  25        if (!sudev) {
  26                dbg("udev_device_new_from_subsystem_sysname failed: %s", busid);
  27                goto err;
  28        }
  29        read_usb_device(sudev, &idev->udev);
  30        udev_device_unref(sudev);
  31
  32        return idev;
  33
  34err:
  35        return NULL;
  36}
  37
  38
  39
  40static int parse_status(const char *value)
  41{
  42        int ret = 0;
  43        char *c;
  44
  45
  46        for (int i = 0; i < vhci_driver->nports; i++)
  47                memset(&vhci_driver->idev[i], 0, sizeof(vhci_driver->idev[i]));
  48
  49
  50        /* skip a header line */
  51        c = strchr(value, '\n');
  52        if (!c)
  53                return -1;
  54        c++;
  55
  56        while (*c != '\0') {
  57                int port, status, speed, devid;
  58                unsigned long socket;
  59                char lbusid[SYSFS_BUS_ID_SIZE];
  60
  61                ret = sscanf(c, "%d %d %d %x %lx %31s\n",
  62                                &port, &status, &speed,
  63                                &devid, &socket, lbusid);
  64
  65                if (ret < 5) {
  66                        dbg("sscanf failed: %d", ret);
  67                        BUG();
  68                }
  69
  70                dbg("port %d status %d speed %d devid %x",
  71                                port, status, speed, devid);
  72                dbg("socket %lx lbusid %s", socket, lbusid);
  73
  74
  75                /* if a device is connected, look at it */
  76                {
  77                        struct usbip_imported_device *idev = &vhci_driver->idev[port];
  78
  79                        idev->port      = port;
  80                        idev->status    = status;
  81
  82                        idev->devid     = devid;
  83
  84                        idev->busnum    = (devid >> 16);
  85                        idev->devnum    = (devid & 0x0000ffff);
  86
  87                        if (idev->status != VDEV_ST_NULL
  88                            && idev->status != VDEV_ST_NOTASSIGNED) {
  89                                idev = imported_device_init(idev, lbusid);
  90                                if (!idev) {
  91                                        dbg("imported_device_init failed");
  92                                        return -1;
  93                                }
  94                        }
  95                }
  96
  97
  98                /* go to the next line */
  99                c = strchr(c, '\n');
 100                if (!c)
 101                        break;
 102                c++;
 103        }
 104
 105        dbg("exit");
 106
 107        return 0;
 108}
 109
 110static int refresh_imported_device_list(void)
 111{
 112        const char *attr_status;
 113
 114        attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device,
 115                                               "status");
 116        if (!attr_status) {
 117                err("udev_device_get_sysattr_value failed");
 118                return -1;
 119        }
 120
 121        return parse_status(attr_status);
 122}
 123
 124static int get_nports(void)
 125{
 126        char *c;
 127        int nports = 0;
 128        const char *attr_status;
 129
 130        attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device,
 131                                               "status");
 132        if (!attr_status) {
 133                err("udev_device_get_sysattr_value failed");
 134                return -1;
 135        }
 136
 137        /* skip a header line */
 138        c = strchr(attr_status, '\n');
 139        if (!c)
 140                return 0;
 141        c++;
 142
 143        while (*c != '\0') {
 144                /* go to the next line */
 145                c = strchr(c, '\n');
 146                if (!c)
 147                        return nports;
 148                c++;
 149                nports += 1;
 150        }
 151
 152        return nports;
 153}
 154
 155/*
 156 * Read the given port's record.
 157 *
 158 * To avoid buffer overflow we will read the entire line and
 159 * validate each part's size. The initial buffer is padded by 4 to
 160 * accommodate the 2 spaces, 1 newline and an additional character
 161 * which is needed to properly validate the 3rd part without it being
 162 * truncated to an acceptable length.
 163 */
 164static int read_record(int rhport, char *host, unsigned long host_len,
 165                char *port, unsigned long port_len, char *busid)
 166{
 167        int part;
 168        FILE *file;
 169        char path[PATH_MAX+1];
 170        char *buffer, *start, *end;
 171        char delim[] = {' ', ' ', '\n'};
 172        int max_len[] = {(int)host_len, (int)port_len, SYSFS_BUS_ID_SIZE};
 173        size_t buffer_len = host_len + port_len + SYSFS_BUS_ID_SIZE + 4;
 174
 175        buffer = malloc(buffer_len);
 176        if (!buffer)
 177                return -1;
 178
 179        snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport);
 180
 181        file = fopen(path, "r");
 182        if (!file) {
 183                err("fopen");
 184                free(buffer);
 185                return -1;
 186        }
 187
 188        if (fgets(buffer, buffer_len, file) == NULL) {
 189                err("fgets");
 190                free(buffer);
 191                fclose(file);
 192                return -1;
 193        }
 194        fclose(file);
 195
 196        /* validate the length of each of the 3 parts */
 197        start = buffer;
 198        for (part = 0; part < 3; part++) {
 199                end = strchr(start, delim[part]);
 200                if (end == NULL || (end - start) > max_len[part]) {
 201                        free(buffer);
 202                        return -1;
 203                }
 204                start = end + 1;
 205        }
 206
 207        if (sscanf(buffer, "%s %s %s\n", host, port, busid) != 3) {
 208                err("sscanf");
 209                free(buffer);
 210                return -1;
 211        }
 212
 213        free(buffer);
 214
 215        return 0;
 216}
 217
 218/* ---------------------------------------------------------------------- */
 219
 220int usbip_vhci_driver_open(void)
 221{
 222        udev_context = udev_new();
 223        if (!udev_context) {
 224                err("udev_new failed");
 225                return -1;
 226        }
 227
 228        vhci_driver = calloc(1, sizeof(struct usbip_vhci_driver));
 229
 230        /* will be freed in usbip_driver_close() */
 231        vhci_driver->hc_device =
 232                udev_device_new_from_subsystem_sysname(udev_context,
 233                                                       USBIP_VHCI_BUS_TYPE,
 234                                                       USBIP_VHCI_DRV_NAME);
 235        if (!vhci_driver->hc_device) {
 236                err("udev_device_new_from_subsystem_sysname failed");
 237                goto err;
 238        }
 239
 240        vhci_driver->nports = get_nports();
 241
 242        dbg("available ports: %d", vhci_driver->nports);
 243
 244        if (refresh_imported_device_list())
 245                goto err;
 246
 247        return 0;
 248
 249err:
 250        udev_device_unref(vhci_driver->hc_device);
 251
 252        if (vhci_driver)
 253                free(vhci_driver);
 254
 255        vhci_driver = NULL;
 256
 257        udev_unref(udev_context);
 258
 259        return -1;
 260}
 261
 262
 263void usbip_vhci_driver_close(void)
 264{
 265        if (!vhci_driver)
 266                return;
 267
 268        udev_device_unref(vhci_driver->hc_device);
 269
 270        free(vhci_driver);
 271
 272        vhci_driver = NULL;
 273
 274        udev_unref(udev_context);
 275}
 276
 277
 278int usbip_vhci_refresh_device_list(void)
 279{
 280
 281        if (refresh_imported_device_list())
 282                goto err;
 283
 284        return 0;
 285err:
 286        dbg("failed to refresh device list");
 287        return -1;
 288}
 289
 290
 291int usbip_vhci_get_free_port(void)
 292{
 293        for (int i = 0; i < vhci_driver->nports; i++) {
 294                if (vhci_driver->idev[i].status == VDEV_ST_NULL)
 295                        return i;
 296        }
 297
 298        return -1;
 299}
 300
 301int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid,
 302                uint32_t speed) {
 303        char buff[200]; /* what size should be ? */
 304        char attach_attr_path[SYSFS_PATH_MAX];
 305        char attr_attach[] = "attach";
 306        const char *path;
 307        int ret;
 308
 309        snprintf(buff, sizeof(buff), "%u %d %u %u",
 310                        port, sockfd, devid, speed);
 311        dbg("writing: %s", buff);
 312
 313        path = udev_device_get_syspath(vhci_driver->hc_device);
 314        snprintf(attach_attr_path, sizeof(attach_attr_path), "%s/%s",
 315                 path, attr_attach);
 316        dbg("attach attribute path: %s", attach_attr_path);
 317
 318        ret = write_sysfs_attribute(attach_attr_path, buff, strlen(buff));
 319        if (ret < 0) {
 320                dbg("write_sysfs_attribute failed");
 321                return -1;
 322        }
 323
 324        dbg("attached port: %d", port);
 325
 326        return 0;
 327}
 328
 329static unsigned long get_devid(uint8_t busnum, uint8_t devnum)
 330{
 331        return (busnum << 16) | devnum;
 332}
 333
 334/* will be removed */
 335int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum,
 336                uint8_t devnum, uint32_t speed)
 337{
 338        int devid = get_devid(busnum, devnum);
 339
 340        return usbip_vhci_attach_device2(port, sockfd, devid, speed);
 341}
 342
 343int usbip_vhci_detach_device(uint8_t port)
 344{
 345        char detach_attr_path[SYSFS_PATH_MAX];
 346        char attr_detach[] = "detach";
 347        char buff[200]; /* what size should be ? */
 348        const char *path;
 349        int ret;
 350
 351        snprintf(buff, sizeof(buff), "%u", port);
 352        dbg("writing: %s", buff);
 353
 354        path = udev_device_get_syspath(vhci_driver->hc_device);
 355        snprintf(detach_attr_path, sizeof(detach_attr_path), "%s/%s",
 356                 path, attr_detach);
 357        dbg("detach attribute path: %s", detach_attr_path);
 358
 359        ret = write_sysfs_attribute(detach_attr_path, buff, strlen(buff));
 360        if (ret < 0) {
 361                dbg("write_sysfs_attribute failed");
 362                return -1;
 363        }
 364
 365        dbg("detached port: %d", port);
 366
 367        return 0;
 368}
 369
 370int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev)
 371{
 372        char product_name[100];
 373        char host[NI_MAXHOST] = "unknown host";
 374        char serv[NI_MAXSERV] = "unknown port";
 375        char remote_busid[SYSFS_BUS_ID_SIZE];
 376        int ret;
 377        int read_record_error = 0;
 378
 379        if (idev->status == VDEV_ST_NULL || idev->status == VDEV_ST_NOTASSIGNED)
 380                return 0;
 381
 382        ret = read_record(idev->port, host, sizeof(host), serv, sizeof(serv),
 383                          remote_busid);
 384        if (ret) {
 385                err("read_record");
 386                read_record_error = 1;
 387        }
 388
 389        printf("Port %02d: <%s> at %s\n", idev->port,
 390               usbip_status_string(idev->status),
 391               usbip_speed_string(idev->udev.speed));
 392
 393        usbip_names_get_product(product_name, sizeof(product_name),
 394                                idev->udev.idVendor, idev->udev.idProduct);
 395
 396        printf("       %s\n",  product_name);
 397
 398        if (!read_record_error) {
 399                printf("%10s -> usbip://%s:%s/%s\n", idev->udev.busid,
 400                       host, serv, remote_busid);
 401                printf("%10s -> remote bus/dev %03d/%03d\n", " ",
 402                       idev->busnum, idev->devnum);
 403        } else {
 404                printf("%10s -> unknown host, remote port and remote busid\n",
 405                       idev->udev.busid);
 406                printf("%10s -> remote bus/dev %03d/%03d\n", " ",
 407                       idev->busnum, idev->devnum);
 408        }
 409
 410        return 0;
 411}
 412