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