GNU Linux-libre 4.19.286-gnu1
[releases.git] / tools / usb / usbip / libsrc / usbip_common.c
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
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         { 0, NULL, NULL }
33 };
34
35 struct portst_string {
36         int num;
37         char *desc;
38 };
39
40 static 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
51 const 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
60 const 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
69 struct op_common_status_string {
70         int num;
71         char *desc;
72 };
73
74 static 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
84 const 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
99 void 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
110 void 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
141 int 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
173 err:
174
175         return num;
176 }
177
178
179 int 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
194 err:
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
206 int 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);
230         strncpy(udev->busid, name, SYSFS_BUS_ID_SIZE);
231
232         sscanf(name, "%u-%u", &busnum, &devnum);
233         udev->busnum = busnum;
234
235         return 0;
236 }
237
238 int read_usb_interface(struct usbip_usb_device *udev, int i,
239                        struct usbip_usb_interface *uinf)
240 {
241         char busid[SYSFS_BUS_ID_SIZE];
242         int size;
243         struct udev_device *sif;
244
245         size = snprintf(busid, sizeof(busid), "%s:%d.%d",
246                         udev->busid, udev->bConfigurationValue, i);
247         if (size < 0 || (unsigned int)size >= sizeof(busid)) {
248                 err("busid length %i >= %lu or < 0", size,
249                     (long unsigned)sizeof(busid));
250                 return -1;
251         }
252
253         sif = udev_device_new_from_subsystem_sysname(udev_context, "usb", busid);
254         if (!sif) {
255                 err("udev_device_new_from_subsystem_sysname %s failed", busid);
256                 return -1;
257         }
258
259         READ_ATTR(uinf, uint8_t,  sif, bInterfaceClass,         "%02x\n");
260         READ_ATTR(uinf, uint8_t,  sif, bInterfaceSubClass,      "%02x\n");
261         READ_ATTR(uinf, uint8_t,  sif, bInterfaceProtocol,      "%02x\n");
262
263         return 0;
264 }
265
266 int usbip_names_init(char *f)
267 {
268         return names_init(f);
269 }
270
271 void usbip_names_free(void)
272 {
273         names_free();
274 }
275
276 void usbip_names_get_product(char *buff, size_t size, uint16_t vendor,
277                              uint16_t product)
278 {
279         const char *prod, *vend;
280
281         prod = names_product(vendor, product);
282         if (!prod)
283                 prod = "unknown product";
284
285
286         vend = names_vendor(vendor);
287         if (!vend)
288                 vend = "unknown vendor";
289
290         snprintf(buff, size, "%s : %s (%04x:%04x)", vend, prod, vendor, product);
291 }
292
293 void usbip_names_get_class(char *buff, size_t size, uint8_t class,
294                            uint8_t subclass, uint8_t protocol)
295 {
296         const char *c, *s, *p;
297
298         if (class == 0 && subclass == 0 && protocol == 0) {
299                 snprintf(buff, size, "(Defined at Interface level) (%02x/%02x/%02x)", class, subclass, protocol);
300                 return;
301         }
302
303         p = names_protocol(class, subclass, protocol);
304         if (!p)
305                 p = "unknown protocol";
306
307         s = names_subclass(class, subclass);
308         if (!s)
309                 s = "unknown subclass";
310
311         c = names_class(class);
312         if (!c)
313                 c = "unknown class";
314
315         snprintf(buff, size, "%s / %s / %s (%02x/%02x/%02x)", c, s, p, class, subclass, protocol);
316 }