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