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