linux/tools/usb/usbip/libsrc/usbip_common.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2005-2007 Takahiro Hirofuchi
   4 */
   5
   6#include <libudev.h>
   7#include "usbip_common.h"
   8#include "names.h"
   9
  10#undef  PROGNAME
  11#define PROGNAME "libusbip"
  12
  13int usbip_use_syslog;
  14int usbip_use_stderr;
  15int usbip_use_debug;
  16
  17extern struct udev *udev_context;
  18
  19struct speed_string {
  20        int num;
  21        char *speed;
  22        char *desc;
  23};
  24
  25static const struct speed_string speed_strings[] = {
  26        { USB_SPEED_UNKNOWN, "unknown", "Unknown Speed"},
  27        { USB_SPEED_LOW,  "1.5", "Low Speed(1.5Mbps)"  },
  28        { USB_SPEED_FULL, "12",  "Full Speed(12Mbps)" },
  29        { USB_SPEED_HIGH, "480", "High Speed(480Mbps)" },
  30        { USB_SPEED_WIRELESS, "53.3-480", "Wireless"},
  31        { USB_SPEED_SUPER, "5000", "Super Speed(5000Mbps)" },
  32        { 0, NULL, NULL }
  33};
  34
  35struct portst_string {
  36        int num;
  37        char *desc;
  38};
  39
  40static struct portst_string portst_strings[] = {
  41        { SDEV_ST_AVAILABLE,    "Device Available" },
  42        { SDEV_ST_USED,         "Device in Use" },
  43        { SDEV_ST_ERROR,        "Device Error"},
  44        { VDEV_ST_NULL,         "Port Available"},
  45        { VDEV_ST_NOTASSIGNED,  "Port Initializing"},
  46        { VDEV_ST_USED,         "Port in Use"},
  47        { VDEV_ST_ERROR,        "Port Error"},
  48        { 0, NULL}
  49};
  50
  51const char *usbip_status_string(int32_t status)
  52{
  53        for (int i = 0; portst_strings[i].desc != NULL; i++)
  54                if (portst_strings[i].num == status)
  55                        return portst_strings[i].desc;
  56
  57        return "Unknown Status";
  58}
  59
  60const char *usbip_speed_string(int num)
  61{
  62        for (int i = 0; speed_strings[i].speed != NULL; i++)
  63                if (speed_strings[i].num == num)
  64                        return speed_strings[i].desc;
  65
  66        return "Unknown Speed";
  67}
  68
  69struct op_common_status_string {
  70        int num;
  71        char *desc;
  72};
  73
  74static struct op_common_status_string op_common_status_strings[] = {
  75        { ST_OK,        "Request Completed Successfully" },
  76        { ST_NA,        "Request Failed" },
  77        { ST_DEV_BUSY,  "Device busy (exported)" },
  78        { ST_DEV_ERR,   "Device in error state" },
  79        { ST_NODEV,     "Device not found" },
  80        { ST_ERROR,     "Unexpected response" },
  81        { 0, NULL}
  82};
  83
  84const char *usbip_op_common_status_string(int status)
  85{
  86        for (int i = 0; op_common_status_strings[i].desc != NULL; i++)
  87                if (op_common_status_strings[i].num == status)
  88                        return op_common_status_strings[i].desc;
  89
  90        return "Unknown Op Common Status";
  91}
  92
  93#define DBG_UDEV_INTEGER(name)\
  94        dbg("%-20s = %x", to_string(name), (int) udev->name)
  95
  96#define DBG_UINF_INTEGER(name)\
  97        dbg("%-20s = %x", to_string(name), (int) uinf->name)
  98
  99void dump_usb_interface(struct usbip_usb_interface *uinf)
 100{
 101        char buff[100];
 102
 103        usbip_names_get_class(buff, sizeof(buff),
 104                        uinf->bInterfaceClass,
 105                        uinf->bInterfaceSubClass,
 106                        uinf->bInterfaceProtocol);
 107        dbg("%-20s = %s", "Interface(C/SC/P)", buff);
 108}
 109
 110void dump_usb_device(struct usbip_usb_device *udev)
 111{
 112        char buff[100];
 113
 114        dbg("%-20s = %s", "path",  udev->path);
 115        dbg("%-20s = %s", "busid", udev->busid);
 116
 117        usbip_names_get_class(buff, sizeof(buff),
 118                        udev->bDeviceClass,
 119                        udev->bDeviceSubClass,
 120                        udev->bDeviceProtocol);
 121        dbg("%-20s = %s", "Device(C/SC/P)", buff);
 122
 123        DBG_UDEV_INTEGER(bcdDevice);
 124
 125        usbip_names_get_product(buff, sizeof(buff),
 126                        udev->idVendor,
 127                        udev->idProduct);
 128        dbg("%-20s = %s", "Vendor/Product", buff);
 129
 130        DBG_UDEV_INTEGER(bNumConfigurations);
 131        DBG_UDEV_INTEGER(bNumInterfaces);
 132
 133        dbg("%-20s = %s", "speed",
 134                        usbip_speed_string(udev->speed));
 135
 136        DBG_UDEV_INTEGER(busnum);
 137        DBG_UDEV_INTEGER(devnum);
 138}
 139
 140
 141int read_attr_value(struct udev_device *dev, const char *name,
 142                    const char *format)
 143{
 144        const char *attr;
 145        int num = 0;
 146        int ret;
 147
 148        attr = udev_device_get_sysattr_value(dev, name);
 149        if (!attr) {
 150                err("udev_device_get_sysattr_value failed");
 151                goto err;
 152        }
 153
 154        /* The client chooses the device configuration
 155         * when attaching it so right after being bound
 156         * to usbip-host on the server the device will
 157         * have no configuration.
 158         * Therefore, attributes such as bConfigurationValue
 159         * and bNumInterfaces will not exist and sscanf will
 160         * fail. Check for these cases and don't treat them
 161         * as errors.
 162         */
 163
 164        ret = sscanf(attr, format, &num);
 165        if (ret < 1) {
 166                if (strcmp(name, "bConfigurationValue") &&
 167                                strcmp(name, "bNumInterfaces")) {
 168                        err("sscanf failed for attribute %s", name);
 169                        goto err;
 170                }
 171        }
 172
 173err:
 174
 175        return num;
 176}
 177
 178
 179int read_attr_speed(struct udev_device *dev)
 180{
 181        const char *speed;
 182
 183        speed = udev_device_get_sysattr_value(dev, "speed");
 184        if (!speed) {
 185                err("udev_device_get_sysattr_value failed");
 186                goto err;
 187        }
 188
 189        for (int i = 0; speed_strings[i].speed != NULL; i++) {
 190                if (!strcmp(speed, speed_strings[i].speed))
 191                        return speed_strings[i].num;
 192        }
 193
 194err:
 195
 196        return USB_SPEED_UNKNOWN;
 197}
 198
 199#define READ_ATTR(object, type, dev, name, format)                            \
 200        do {                                                                  \
 201                (object)->name = (type) read_attr_value(dev, to_string(name), \
 202                                                        format);              \
 203        } while (0)
 204
 205
 206int read_usb_device(struct udev_device *sdev, struct usbip_usb_device *udev)
 207{
 208        uint32_t busnum, devnum;
 209        const char *path, *name;
 210
 211        READ_ATTR(udev, uint8_t,  sdev, bDeviceClass,           "%02x\n");
 212        READ_ATTR(udev, uint8_t,  sdev, bDeviceSubClass,        "%02x\n");
 213        READ_ATTR(udev, uint8_t,  sdev, bDeviceProtocol,        "%02x\n");
 214
 215        READ_ATTR(udev, uint16_t, sdev, idVendor,               "%04x\n");
 216        READ_ATTR(udev, uint16_t, sdev, idProduct,              "%04x\n");
 217        READ_ATTR(udev, uint16_t, sdev, bcdDevice,              "%04x\n");
 218
 219        READ_ATTR(udev, uint8_t,  sdev, bConfigurationValue,    "%02x\n");
 220        READ_ATTR(udev, uint8_t,  sdev, bNumConfigurations,     "%02x\n");
 221        READ_ATTR(udev, uint8_t,  sdev, bNumInterfaces,         "%02x\n");
 222
 223        READ_ATTR(udev, uint8_t,  sdev, devnum,                 "%d\n");
 224        udev->speed = read_attr_speed(sdev);
 225
 226        path = udev_device_get_syspath(sdev);
 227        name = udev_device_get_sysname(sdev);
 228
 229        strncpy(udev->path,  path,  SYSFS_PATH_MAX - 1);
 230        udev->path[SYSFS_PATH_MAX - 1] = '\0';
 231        strncpy(udev->busid, name, SYSFS_BUS_ID_SIZE - 1);
 232        udev->busid[SYSFS_BUS_ID_SIZE - 1] = '\0';
 233
 234        sscanf(name, "%u-%u", &busnum, &devnum);
 235        udev->busnum = busnum;
 236
 237        return 0;
 238}
 239
 240int read_usb_interface(struct usbip_usb_device *udev, int i,
 241                       struct usbip_usb_interface *uinf)
 242{
 243        char busid[SYSFS_BUS_ID_SIZE];
 244        int size;
 245        struct udev_device *sif;
 246
 247        size = snprintf(busid, sizeof(busid), "%s:%d.%d",
 248                        udev->busid, udev->bConfigurationValue, i);
 249        if (size < 0 || (unsigned int)size >= sizeof(busid)) {
 250                err("busid length %i >= %lu or < 0", size,
 251                    (long unsigned)sizeof(busid));
 252                return -1;
 253        }
 254
 255        sif = udev_device_new_from_subsystem_sysname(udev_context, "usb", busid);
 256        if (!sif) {
 257                err("udev_device_new_from_subsystem_sysname %s failed", busid);
 258                return -1;
 259        }
 260
 261        READ_ATTR(uinf, uint8_t,  sif, bInterfaceClass,         "%02x\n");
 262        READ_ATTR(uinf, uint8_t,  sif, bInterfaceSubClass,      "%02x\n");
 263        READ_ATTR(uinf, uint8_t,  sif, bInterfaceProtocol,      "%02x\n");
 264
 265        return 0;
 266}
 267
 268int usbip_names_init(char *f)
 269{
 270        return names_init(f);
 271}
 272
 273void usbip_names_free(void)
 274{
 275        names_free();
 276}
 277
 278void usbip_names_get_product(char *buff, size_t size, uint16_t vendor,
 279                             uint16_t product)
 280{
 281        const char *prod, *vend;
 282
 283        prod = names_product(vendor, product);
 284        if (!prod)
 285                prod = "unknown product";
 286
 287
 288        vend = names_vendor(vendor);
 289        if (!vend)
 290                vend = "unknown vendor";
 291
 292        snprintf(buff, size, "%s : %s (%04x:%04x)", vend, prod, vendor, product);
 293}
 294
 295void usbip_names_get_class(char *buff, size_t size, uint8_t class,
 296                           uint8_t subclass, uint8_t protocol)
 297{
 298        const char *c, *s, *p;
 299
 300        if (class == 0 && subclass == 0 && protocol == 0) {
 301                snprintf(buff, size, "(Defined at Interface level) (%02x/%02x/%02x)", class, subclass, protocol);
 302                return;
 303        }
 304
 305        p = names_protocol(class, subclass, protocol);
 306        if (!p)
 307                p = "unknown protocol";
 308
 309        s = names_subclass(class, subclass);
 310        if (!s)
 311                s = "unknown subclass";
 312
 313        c = names_class(class);
 314        if (!c)
 315                c = "unknown class";
 316
 317        snprintf(buff, size, "%s / %s / %s (%02x/%02x/%02x)", c, s, p, class, subclass, protocol);
 318}
 319