xref: /openbmc/linux/tools/usb/usbip/src/usbip_list.c (revision 151f4e2b)
1 /*
2  * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
3  *               2005-2007 Takahiro Hirofuchi
4  * Copyright (C) 2015-2016 Samsung Electronics
5  *               Igor Kotrasinski <i.kotrasinsk@samsung.com>
6  *               Krzysztof Opasiak <k.opasiak@samsung.com>
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <sys/types.h>
23 #include <libudev.h>
24 
25 #include <errno.h>
26 #include <stdbool.h>
27 #include <stdint.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 
32 #include <getopt.h>
33 #include <netdb.h>
34 #include <unistd.h>
35 
36 #include <dirent.h>
37 
38 #include <linux/usb/ch9.h>
39 
40 #include "usbip_common.h"
41 #include "usbip_network.h"
42 #include "usbip.h"
43 
44 static const char usbip_list_usage_string[] =
45 	"usbip list [-p|--parsable] <args>\n"
46 	"    -p, --parsable         Parsable list format\n"
47 	"    -r, --remote=<host>    List the exportable USB devices on <host>\n"
48 	"    -l, --local            List the local USB devices\n";
49 
50 void usbip_list_usage(void)
51 {
52 	printf("usage: %s", usbip_list_usage_string);
53 }
54 
55 static int get_exported_devices(char *host, int sockfd)
56 {
57 	char product_name[100];
58 	char class_name[100];
59 	struct op_devlist_reply reply;
60 	uint16_t code = OP_REP_DEVLIST;
61 	struct usbip_usb_device udev;
62 	struct usbip_usb_interface uintf;
63 	unsigned int i;
64 	int rc, j;
65 	int status;
66 
67 	rc = usbip_net_send_op_common(sockfd, OP_REQ_DEVLIST, 0);
68 	if (rc < 0) {
69 		dbg("usbip_net_send_op_common failed");
70 		return -1;
71 	}
72 
73 	rc = usbip_net_recv_op_common(sockfd, &code, &status);
74 	if (rc < 0) {
75 		err("Exported Device List Request failed - %s\n",
76 		    usbip_op_common_status_string(status));
77 		return -1;
78 	}
79 
80 	memset(&reply, 0, sizeof(reply));
81 	rc = usbip_net_recv(sockfd, &reply, sizeof(reply));
82 	if (rc < 0) {
83 		dbg("usbip_net_recv_op_devlist failed");
84 		return -1;
85 	}
86 	PACK_OP_DEVLIST_REPLY(0, &reply);
87 	dbg("exportable devices: %d\n", reply.ndev);
88 
89 	if (reply.ndev == 0) {
90 		info("no exportable devices found on %s", host);
91 		return 0;
92 	}
93 
94 	printf("Exportable USB devices\n");
95 	printf("======================\n");
96 	printf(" - %s\n", host);
97 
98 	for (i = 0; i < reply.ndev; i++) {
99 		memset(&udev, 0, sizeof(udev));
100 		rc = usbip_net_recv(sockfd, &udev, sizeof(udev));
101 		if (rc < 0) {
102 			dbg("usbip_net_recv failed: usbip_usb_device[%d]", i);
103 			return -1;
104 		}
105 		usbip_net_pack_usb_device(0, &udev);
106 
107 		usbip_names_get_product(product_name, sizeof(product_name),
108 					udev.idVendor, udev.idProduct);
109 		usbip_names_get_class(class_name, sizeof(class_name),
110 				      udev.bDeviceClass, udev.bDeviceSubClass,
111 				      udev.bDeviceProtocol);
112 		printf("%11s: %s\n", udev.busid, product_name);
113 		printf("%11s: %s\n", "", udev.path);
114 		printf("%11s: %s\n", "", class_name);
115 
116 		for (j = 0; j < udev.bNumInterfaces; j++) {
117 			rc = usbip_net_recv(sockfd, &uintf, sizeof(uintf));
118 			if (rc < 0) {
119 				err("usbip_net_recv failed: usbip_usb_intf[%d]",
120 						j);
121 
122 				return -1;
123 			}
124 			usbip_net_pack_usb_interface(0, &uintf);
125 
126 			usbip_names_get_class(class_name, sizeof(class_name),
127 					uintf.bInterfaceClass,
128 					uintf.bInterfaceSubClass,
129 					uintf.bInterfaceProtocol);
130 			printf("%11s: %2d - %s\n", "", j, class_name);
131 		}
132 
133 		printf("\n");
134 	}
135 
136 	return 0;
137 }
138 
139 static int list_exported_devices(char *host)
140 {
141 	int rc;
142 	int sockfd;
143 
144 	sockfd = usbip_net_tcp_connect(host, usbip_port_string);
145 	if (sockfd < 0) {
146 		err("could not connect to %s:%s: %s", host,
147 		    usbip_port_string, gai_strerror(sockfd));
148 		return -1;
149 	}
150 	dbg("connected to %s:%s", host, usbip_port_string);
151 
152 	rc = get_exported_devices(host, sockfd);
153 	if (rc < 0) {
154 		err("failed to get device list from %s", host);
155 		return -1;
156 	}
157 
158 	close(sockfd);
159 
160 	return 0;
161 }
162 
163 static void print_device(const char *busid, const char *vendor,
164 			 const char *product, bool parsable)
165 {
166 	if (parsable)
167 		printf("busid=%s#usbid=%.4s:%.4s#", busid, vendor, product);
168 	else
169 		printf(" - busid %s (%.4s:%.4s)\n", busid, vendor, product);
170 }
171 
172 static void print_product_name(char *product_name, bool parsable)
173 {
174 	if (!parsable)
175 		printf("   %s\n", product_name);
176 }
177 
178 static int list_devices(bool parsable)
179 {
180 	struct udev *udev;
181 	struct udev_enumerate *enumerate;
182 	struct udev_list_entry *devices, *dev_list_entry;
183 	struct udev_device *dev;
184 	const char *path;
185 	const char *idVendor;
186 	const char *idProduct;
187 	const char *bConfValue;
188 	const char *bNumIntfs;
189 	const char *busid;
190 	char product_name[128];
191 	int ret = -1;
192 	const char *devpath;
193 
194 	/* Create libudev context. */
195 	udev = udev_new();
196 
197 	/* Create libudev device enumeration. */
198 	enumerate = udev_enumerate_new(udev);
199 
200 	/* Take only USB devices that are not hubs and do not have
201 	 * the bInterfaceNumber attribute, i.e. are not interfaces.
202 	 */
203 	udev_enumerate_add_match_subsystem(enumerate, "usb");
204 	udev_enumerate_add_nomatch_sysattr(enumerate, "bDeviceClass", "09");
205 	udev_enumerate_add_nomatch_sysattr(enumerate, "bInterfaceNumber", NULL);
206 	udev_enumerate_scan_devices(enumerate);
207 
208 	devices = udev_enumerate_get_list_entry(enumerate);
209 
210 	/* Show information about each device. */
211 	udev_list_entry_foreach(dev_list_entry, devices) {
212 		path = udev_list_entry_get_name(dev_list_entry);
213 		dev = udev_device_new_from_syspath(udev, path);
214 
215 		/* Ignore devices attached to vhci_hcd */
216 		devpath = udev_device_get_devpath(dev);
217 		if (strstr(devpath, USBIP_VHCI_DRV_NAME)) {
218 			dbg("Skip the device %s already attached to %s\n",
219 			    devpath, USBIP_VHCI_DRV_NAME);
220 			continue;
221 		}
222 
223 		/* Get device information. */
224 		idVendor = udev_device_get_sysattr_value(dev, "idVendor");
225 		idProduct = udev_device_get_sysattr_value(dev, "idProduct");
226 		bConfValue = udev_device_get_sysattr_value(dev,
227 				"bConfigurationValue");
228 		bNumIntfs = udev_device_get_sysattr_value(dev,
229 				"bNumInterfaces");
230 		busid = udev_device_get_sysname(dev);
231 		if (!idVendor || !idProduct || !bConfValue || !bNumIntfs) {
232 			err("problem getting device attributes: %s",
233 			    strerror(errno));
234 			goto err_out;
235 		}
236 
237 		/* Get product name. */
238 		usbip_names_get_product(product_name, sizeof(product_name),
239 					strtol(idVendor, NULL, 16),
240 					strtol(idProduct, NULL, 16));
241 
242 		/* Print information. */
243 		print_device(busid, idVendor, idProduct, parsable);
244 		print_product_name(product_name, parsable);
245 
246 		printf("\n");
247 
248 		udev_device_unref(dev);
249 	}
250 
251 	ret = 0;
252 
253 err_out:
254 	udev_enumerate_unref(enumerate);
255 	udev_unref(udev);
256 
257 	return ret;
258 }
259 
260 static int list_gadget_devices(bool parsable)
261 {
262 	int ret = -1;
263 	struct udev *udev;
264 	struct udev_enumerate *enumerate;
265 	struct udev_list_entry *devices, *dev_list_entry;
266 	struct udev_device *dev;
267 	const char *path;
268 	const char *driver;
269 
270 	const struct usb_device_descriptor *d_desc;
271 	const char *descriptors;
272 	char product_name[128];
273 
274 	uint16_t idVendor;
275 	char idVendor_buf[8];
276 	uint16_t idProduct;
277 	char idProduct_buf[8];
278 	const char *busid;
279 
280 	udev = udev_new();
281 	enumerate = udev_enumerate_new(udev);
282 
283 	udev_enumerate_add_match_subsystem(enumerate, "platform");
284 
285 	udev_enumerate_scan_devices(enumerate);
286 	devices = udev_enumerate_get_list_entry(enumerate);
287 
288 	udev_list_entry_foreach(dev_list_entry, devices) {
289 		path = udev_list_entry_get_name(dev_list_entry);
290 		dev = udev_device_new_from_syspath(udev, path);
291 
292 		driver = udev_device_get_driver(dev);
293 		/* We only have mechanism to enumerate gadgets bound to vudc */
294 		if (driver == NULL || strcmp(driver, USBIP_DEVICE_DRV_NAME))
295 			continue;
296 
297 		/* Get device information. */
298 		descriptors = udev_device_get_sysattr_value(dev,
299 				VUDC_DEVICE_DESCR_FILE);
300 
301 		if (!descriptors) {
302 			err("problem getting device attributes: %s",
303 			    strerror(errno));
304 			goto err_out;
305 		}
306 
307 		d_desc = (const struct usb_device_descriptor *) descriptors;
308 
309 		idVendor = le16toh(d_desc->idVendor);
310 		sprintf(idVendor_buf, "0x%4x", idVendor);
311 		idProduct = le16toh(d_desc->idProduct);
312 		sprintf(idProduct_buf, "0x%4x", idVendor);
313 		busid = udev_device_get_sysname(dev);
314 
315 		/* Get product name. */
316 		usbip_names_get_product(product_name, sizeof(product_name),
317 					le16toh(idVendor),
318 					le16toh(idProduct));
319 
320 		/* Print information. */
321 		print_device(busid, idVendor_buf, idProduct_buf, parsable);
322 		print_product_name(product_name, parsable);
323 
324 		printf("\n");
325 
326 		udev_device_unref(dev);
327 	}
328 	ret = 0;
329 
330 err_out:
331 	udev_enumerate_unref(enumerate);
332 	udev_unref(udev);
333 
334 	return ret;
335 }
336 
337 int usbip_list(int argc, char *argv[])
338 {
339 	static const struct option opts[] = {
340 		{ "parsable", no_argument,       NULL, 'p' },
341 		{ "remote",   required_argument, NULL, 'r' },
342 		{ "local",    no_argument,       NULL, 'l' },
343 		{ "device",    no_argument,       NULL, 'd' },
344 		{ NULL,       0,                 NULL,  0  }
345 	};
346 
347 	bool parsable = false;
348 	int opt;
349 	int ret = -1;
350 
351 	if (usbip_names_init(USBIDS_FILE))
352 		err("failed to open %s", USBIDS_FILE);
353 
354 	for (;;) {
355 		opt = getopt_long(argc, argv, "pr:ld", opts, NULL);
356 
357 		if (opt == -1)
358 			break;
359 
360 		switch (opt) {
361 		case 'p':
362 			parsable = true;
363 			break;
364 		case 'r':
365 			ret = list_exported_devices(optarg);
366 			goto out;
367 		case 'l':
368 			ret = list_devices(parsable);
369 			goto out;
370 		case 'd':
371 			ret = list_gadget_devices(parsable);
372 			goto out;
373 		default:
374 			goto err_out;
375 		}
376 	}
377 
378 err_out:
379 	usbip_list_usage();
380 out:
381 	usbip_names_free();
382 
383 	return ret;
384 }
385