xref: /openbmc/linux/tools/usb/usbip/src/usbip_list.c (revision a58977b2)
11ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2588b48caSValentina Manea /*
3588b48caSValentina Manea  * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
4588b48caSValentina Manea  *               2005-2007 Takahiro Hirofuchi
5e0546fd8SIgor Kotrasinski  * Copyright (C) 2015-2016 Samsung Electronics
6e0546fd8SIgor Kotrasinski  *               Igor Kotrasinski <i.kotrasinsk@samsung.com>
7e0546fd8SIgor Kotrasinski  *               Krzysztof Opasiak <k.opasiak@samsung.com>
8588b48caSValentina Manea  */
9588b48caSValentina Manea 
10588b48caSValentina Manea #include <sys/types.h>
11588b48caSValentina Manea #include <libudev.h>
12588b48caSValentina Manea 
13588b48caSValentina Manea #include <errno.h>
14588b48caSValentina Manea #include <stdbool.h>
15588b48caSValentina Manea #include <stdint.h>
16588b48caSValentina Manea #include <stdio.h>
17588b48caSValentina Manea #include <stdlib.h>
18588b48caSValentina Manea #include <string.h>
19588b48caSValentina Manea 
20588b48caSValentina Manea #include <getopt.h>
21588b48caSValentina Manea #include <netdb.h>
22588b48caSValentina Manea #include <unistd.h>
23588b48caSValentina Manea 
24e0546fd8SIgor Kotrasinski #include <dirent.h>
25e0546fd8SIgor Kotrasinski 
26e0546fd8SIgor Kotrasinski #include <linux/usb/ch9.h>
27e0546fd8SIgor Kotrasinski 
28588b48caSValentina Manea #include "usbip_common.h"
29588b48caSValentina Manea #include "usbip_network.h"
30588b48caSValentina Manea #include "usbip.h"
31588b48caSValentina Manea 
32588b48caSValentina Manea static const char usbip_list_usage_string[] =
33588b48caSValentina Manea 	"usbip list [-p|--parsable] <args>\n"
34588b48caSValentina Manea 	"    -p, --parsable         Parsable list format\n"
35588b48caSValentina Manea 	"    -r, --remote=<host>    List the exportable USB devices on <host>\n"
36*a58977b2SHongren Zheng (Zenithal) 	"    -l, --local            List the local USB devices\n"
37*a58977b2SHongren Zheng (Zenithal) 	"    -d, --device           List the local USB gadgets bound to usbip-vudc\n";
38588b48caSValentina Manea 
usbip_list_usage(void)39588b48caSValentina Manea void usbip_list_usage(void)
40588b48caSValentina Manea {
41588b48caSValentina Manea 	printf("usage: %s", usbip_list_usage_string);
42588b48caSValentina Manea }
43588b48caSValentina Manea 
get_exported_devices(char * host,int sockfd)44588b48caSValentina Manea static int get_exported_devices(char *host, int sockfd)
45588b48caSValentina Manea {
46588b48caSValentina Manea 	char product_name[100];
47588b48caSValentina Manea 	char class_name[100];
48588b48caSValentina Manea 	struct op_devlist_reply reply;
49588b48caSValentina Manea 	uint16_t code = OP_REP_DEVLIST;
50588b48caSValentina Manea 	struct usbip_usb_device udev;
51588b48caSValentina Manea 	struct usbip_usb_interface uintf;
52588b48caSValentina Manea 	unsigned int i;
53588b48caSValentina Manea 	int rc, j;
54ad81b15dSShuah Khan 	int status;
55588b48caSValentina Manea 
56588b48caSValentina Manea 	rc = usbip_net_send_op_common(sockfd, OP_REQ_DEVLIST, 0);
57588b48caSValentina Manea 	if (rc < 0) {
58588b48caSValentina Manea 		dbg("usbip_net_send_op_common failed");
59588b48caSValentina Manea 		return -1;
60588b48caSValentina Manea 	}
61588b48caSValentina Manea 
62ad81b15dSShuah Khan 	rc = usbip_net_recv_op_common(sockfd, &code, &status);
63588b48caSValentina Manea 	if (rc < 0) {
64ad81b15dSShuah Khan 		err("Exported Device List Request failed - %s\n",
65ad81b15dSShuah Khan 		    usbip_op_common_status_string(status));
66588b48caSValentina Manea 		return -1;
67588b48caSValentina Manea 	}
68588b48caSValentina Manea 
69588b48caSValentina Manea 	memset(&reply, 0, sizeof(reply));
70588b48caSValentina Manea 	rc = usbip_net_recv(sockfd, &reply, sizeof(reply));
71588b48caSValentina Manea 	if (rc < 0) {
72588b48caSValentina Manea 		dbg("usbip_net_recv_op_devlist failed");
73588b48caSValentina Manea 		return -1;
74588b48caSValentina Manea 	}
75588b48caSValentina Manea 	PACK_OP_DEVLIST_REPLY(0, &reply);
76588b48caSValentina Manea 	dbg("exportable devices: %d\n", reply.ndev);
77588b48caSValentina Manea 
78588b48caSValentina Manea 	if (reply.ndev == 0) {
79588b48caSValentina Manea 		info("no exportable devices found on %s", host);
80588b48caSValentina Manea 		return 0;
81588b48caSValentina Manea 	}
82588b48caSValentina Manea 
83588b48caSValentina Manea 	printf("Exportable USB devices\n");
84588b48caSValentina Manea 	printf("======================\n");
85588b48caSValentina Manea 	printf(" - %s\n", host);
86588b48caSValentina Manea 
87588b48caSValentina Manea 	for (i = 0; i < reply.ndev; i++) {
88588b48caSValentina Manea 		memset(&udev, 0, sizeof(udev));
89588b48caSValentina Manea 		rc = usbip_net_recv(sockfd, &udev, sizeof(udev));
90588b48caSValentina Manea 		if (rc < 0) {
91588b48caSValentina Manea 			dbg("usbip_net_recv failed: usbip_usb_device[%d]", i);
92588b48caSValentina Manea 			return -1;
93588b48caSValentina Manea 		}
94588b48caSValentina Manea 		usbip_net_pack_usb_device(0, &udev);
95588b48caSValentina Manea 
96588b48caSValentina Manea 		usbip_names_get_product(product_name, sizeof(product_name),
97588b48caSValentina Manea 					udev.idVendor, udev.idProduct);
98588b48caSValentina Manea 		usbip_names_get_class(class_name, sizeof(class_name),
99588b48caSValentina Manea 				      udev.bDeviceClass, udev.bDeviceSubClass,
100588b48caSValentina Manea 				      udev.bDeviceProtocol);
101588b48caSValentina Manea 		printf("%11s: %s\n", udev.busid, product_name);
102588b48caSValentina Manea 		printf("%11s: %s\n", "", udev.path);
103588b48caSValentina Manea 		printf("%11s: %s\n", "", class_name);
104588b48caSValentina Manea 
105588b48caSValentina Manea 		for (j = 0; j < udev.bNumInterfaces; j++) {
106588b48caSValentina Manea 			rc = usbip_net_recv(sockfd, &uintf, sizeof(uintf));
107588b48caSValentina Manea 			if (rc < 0) {
108588b48caSValentina Manea 				err("usbip_net_recv failed: usbip_usb_intf[%d]",
109588b48caSValentina Manea 						j);
110588b48caSValentina Manea 
111588b48caSValentina Manea 				return -1;
112588b48caSValentina Manea 			}
113588b48caSValentina Manea 			usbip_net_pack_usb_interface(0, &uintf);
114588b48caSValentina Manea 
115588b48caSValentina Manea 			usbip_names_get_class(class_name, sizeof(class_name),
116588b48caSValentina Manea 					uintf.bInterfaceClass,
117588b48caSValentina Manea 					uintf.bInterfaceSubClass,
118588b48caSValentina Manea 					uintf.bInterfaceProtocol);
119588b48caSValentina Manea 			printf("%11s: %2d - %s\n", "", j, class_name);
120588b48caSValentina Manea 		}
121588b48caSValentina Manea 
122588b48caSValentina Manea 		printf("\n");
123588b48caSValentina Manea 	}
124588b48caSValentina Manea 
125588b48caSValentina Manea 	return 0;
126588b48caSValentina Manea }
127588b48caSValentina Manea 
list_exported_devices(char * host)128588b48caSValentina Manea static int list_exported_devices(char *host)
129588b48caSValentina Manea {
130588b48caSValentina Manea 	int rc;
131588b48caSValentina Manea 	int sockfd;
132588b48caSValentina Manea 
133588b48caSValentina Manea 	sockfd = usbip_net_tcp_connect(host, usbip_port_string);
134588b48caSValentina Manea 	if (sockfd < 0) {
135588b48caSValentina Manea 		err("could not connect to %s:%s: %s", host,
136588b48caSValentina Manea 		    usbip_port_string, gai_strerror(sockfd));
137588b48caSValentina Manea 		return -1;
138588b48caSValentina Manea 	}
139588b48caSValentina Manea 	dbg("connected to %s:%s", host, usbip_port_string);
140588b48caSValentina Manea 
141588b48caSValentina Manea 	rc = get_exported_devices(host, sockfd);
142588b48caSValentina Manea 	if (rc < 0) {
143588b48caSValentina Manea 		err("failed to get device list from %s", host);
144588b48caSValentina Manea 		return -1;
145588b48caSValentina Manea 	}
146588b48caSValentina Manea 
147588b48caSValentina Manea 	close(sockfd);
148588b48caSValentina Manea 
149588b48caSValentina Manea 	return 0;
150588b48caSValentina Manea }
151588b48caSValentina Manea 
print_device(const char * busid,const char * vendor,const char * product,bool parsable)152588b48caSValentina Manea static void print_device(const char *busid, const char *vendor,
153588b48caSValentina Manea 			 const char *product, bool parsable)
154588b48caSValentina Manea {
155588b48caSValentina Manea 	if (parsable)
156588b48caSValentina Manea 		printf("busid=%s#usbid=%.4s:%.4s#", busid, vendor, product);
157588b48caSValentina Manea 	else
158588b48caSValentina Manea 		printf(" - busid %s (%.4s:%.4s)\n", busid, vendor, product);
159588b48caSValentina Manea }
160588b48caSValentina Manea 
print_product_name(char * product_name,bool parsable)161588b48caSValentina Manea static void print_product_name(char *product_name, bool parsable)
162588b48caSValentina Manea {
163588b48caSValentina Manea 	if (!parsable)
164588b48caSValentina Manea 		printf("   %s\n", product_name);
165588b48caSValentina Manea }
166588b48caSValentina Manea 
list_devices(bool parsable)167588b48caSValentina Manea static int list_devices(bool parsable)
168588b48caSValentina Manea {
169588b48caSValentina Manea 	struct udev *udev;
170588b48caSValentina Manea 	struct udev_enumerate *enumerate;
171588b48caSValentina Manea 	struct udev_list_entry *devices, *dev_list_entry;
172588b48caSValentina Manea 	struct udev_device *dev;
173588b48caSValentina Manea 	const char *path;
174588b48caSValentina Manea 	const char *idVendor;
175588b48caSValentina Manea 	const char *idProduct;
176588b48caSValentina Manea 	const char *bConfValue;
177588b48caSValentina Manea 	const char *bNumIntfs;
178588b48caSValentina Manea 	const char *busid;
179588b48caSValentina Manea 	char product_name[128];
180588b48caSValentina Manea 	int ret = -1;
181ef824501SShuah Khan 	const char *devpath;
182588b48caSValentina Manea 
183588b48caSValentina Manea 	/* Create libudev context. */
184588b48caSValentina Manea 	udev = udev_new();
185588b48caSValentina Manea 
186588b48caSValentina Manea 	/* Create libudev device enumeration. */
187588b48caSValentina Manea 	enumerate = udev_enumerate_new(udev);
188588b48caSValentina Manea 
189588b48caSValentina Manea 	/* Take only USB devices that are not hubs and do not have
190588b48caSValentina Manea 	 * the bInterfaceNumber attribute, i.e. are not interfaces.
191588b48caSValentina Manea 	 */
192588b48caSValentina Manea 	udev_enumerate_add_match_subsystem(enumerate, "usb");
193588b48caSValentina Manea 	udev_enumerate_add_nomatch_sysattr(enumerate, "bDeviceClass", "09");
194588b48caSValentina Manea 	udev_enumerate_add_nomatch_sysattr(enumerate, "bInterfaceNumber", NULL);
195588b48caSValentina Manea 	udev_enumerate_scan_devices(enumerate);
196588b48caSValentina Manea 
197588b48caSValentina Manea 	devices = udev_enumerate_get_list_entry(enumerate);
198588b48caSValentina Manea 
199588b48caSValentina Manea 	/* Show information about each device. */
200588b48caSValentina Manea 	udev_list_entry_foreach(dev_list_entry, devices) {
201588b48caSValentina Manea 		path = udev_list_entry_get_name(dev_list_entry);
202588b48caSValentina Manea 		dev = udev_device_new_from_syspath(udev, path);
203588b48caSValentina Manea 
204ef824501SShuah Khan 		/* Ignore devices attached to vhci_hcd */
205ef824501SShuah Khan 		devpath = udev_device_get_devpath(dev);
206ef824501SShuah Khan 		if (strstr(devpath, USBIP_VHCI_DRV_NAME)) {
207ef824501SShuah Khan 			dbg("Skip the device %s already attached to %s\n",
208ef824501SShuah Khan 			    devpath, USBIP_VHCI_DRV_NAME);
209ef824501SShuah Khan 			continue;
210ef824501SShuah Khan 		}
211ef824501SShuah Khan 
212588b48caSValentina Manea 		/* Get device information. */
213588b48caSValentina Manea 		idVendor = udev_device_get_sysattr_value(dev, "idVendor");
214588b48caSValentina Manea 		idProduct = udev_device_get_sysattr_value(dev, "idProduct");
215e0546fd8SIgor Kotrasinski 		bConfValue = udev_device_get_sysattr_value(dev,
216e0546fd8SIgor Kotrasinski 				"bConfigurationValue");
217e0546fd8SIgor Kotrasinski 		bNumIntfs = udev_device_get_sysattr_value(dev,
218e0546fd8SIgor Kotrasinski 				"bNumInterfaces");
219588b48caSValentina Manea 		busid = udev_device_get_sysname(dev);
220588b48caSValentina Manea 		if (!idVendor || !idProduct || !bConfValue || !bNumIntfs) {
221588b48caSValentina Manea 			err("problem getting device attributes: %s",
222588b48caSValentina Manea 			    strerror(errno));
223588b48caSValentina Manea 			goto err_out;
224588b48caSValentina Manea 		}
225588b48caSValentina Manea 
226588b48caSValentina Manea 		/* Get product name. */
227588b48caSValentina Manea 		usbip_names_get_product(product_name, sizeof(product_name),
228588b48caSValentina Manea 					strtol(idVendor, NULL, 16),
229588b48caSValentina Manea 					strtol(idProduct, NULL, 16));
230588b48caSValentina Manea 
231588b48caSValentina Manea 		/* Print information. */
232588b48caSValentina Manea 		print_device(busid, idVendor, idProduct, parsable);
233588b48caSValentina Manea 		print_product_name(product_name, parsable);
234588b48caSValentina Manea 
235588b48caSValentina Manea 		printf("\n");
236588b48caSValentina Manea 
237588b48caSValentina Manea 		udev_device_unref(dev);
238588b48caSValentina Manea 	}
239588b48caSValentina Manea 
240588b48caSValentina Manea 	ret = 0;
241588b48caSValentina Manea 
242588b48caSValentina Manea err_out:
243588b48caSValentina Manea 	udev_enumerate_unref(enumerate);
244588b48caSValentina Manea 	udev_unref(udev);
245588b48caSValentina Manea 
246588b48caSValentina Manea 	return ret;
247588b48caSValentina Manea }
248588b48caSValentina Manea 
list_gadget_devices(bool parsable)249e0546fd8SIgor Kotrasinski static int list_gadget_devices(bool parsable)
250e0546fd8SIgor Kotrasinski {
251e0546fd8SIgor Kotrasinski 	int ret = -1;
252e0546fd8SIgor Kotrasinski 	struct udev *udev;
253e0546fd8SIgor Kotrasinski 	struct udev_enumerate *enumerate;
254e0546fd8SIgor Kotrasinski 	struct udev_list_entry *devices, *dev_list_entry;
255e0546fd8SIgor Kotrasinski 	struct udev_device *dev;
256e0546fd8SIgor Kotrasinski 	const char *path;
257e0546fd8SIgor Kotrasinski 	const char *driver;
258e0546fd8SIgor Kotrasinski 
259e0546fd8SIgor Kotrasinski 	const struct usb_device_descriptor *d_desc;
260e0546fd8SIgor Kotrasinski 	const char *descriptors;
261e0546fd8SIgor Kotrasinski 	char product_name[128];
262e0546fd8SIgor Kotrasinski 
263e0546fd8SIgor Kotrasinski 	uint16_t idVendor;
264e0546fd8SIgor Kotrasinski 	char idVendor_buf[8];
265e0546fd8SIgor Kotrasinski 	uint16_t idProduct;
266e0546fd8SIgor Kotrasinski 	char idProduct_buf[8];
267e0546fd8SIgor Kotrasinski 	const char *busid;
268e0546fd8SIgor Kotrasinski 
269e0546fd8SIgor Kotrasinski 	udev = udev_new();
270e0546fd8SIgor Kotrasinski 	enumerate = udev_enumerate_new(udev);
271e0546fd8SIgor Kotrasinski 
272e0546fd8SIgor Kotrasinski 	udev_enumerate_add_match_subsystem(enumerate, "platform");
273e0546fd8SIgor Kotrasinski 
274e0546fd8SIgor Kotrasinski 	udev_enumerate_scan_devices(enumerate);
275e0546fd8SIgor Kotrasinski 	devices = udev_enumerate_get_list_entry(enumerate);
276e0546fd8SIgor Kotrasinski 
277e0546fd8SIgor Kotrasinski 	udev_list_entry_foreach(dev_list_entry, devices) {
278e0546fd8SIgor Kotrasinski 		path = udev_list_entry_get_name(dev_list_entry);
279e0546fd8SIgor Kotrasinski 		dev = udev_device_new_from_syspath(udev, path);
280e0546fd8SIgor Kotrasinski 
281e0546fd8SIgor Kotrasinski 		driver = udev_device_get_driver(dev);
282e0546fd8SIgor Kotrasinski 		/* We only have mechanism to enumerate gadgets bound to vudc */
283e0546fd8SIgor Kotrasinski 		if (driver == NULL || strcmp(driver, USBIP_DEVICE_DRV_NAME))
284e0546fd8SIgor Kotrasinski 			continue;
285e0546fd8SIgor Kotrasinski 
286e0546fd8SIgor Kotrasinski 		/* Get device information. */
287e0546fd8SIgor Kotrasinski 		descriptors = udev_device_get_sysattr_value(dev,
288e0546fd8SIgor Kotrasinski 				VUDC_DEVICE_DESCR_FILE);
289e0546fd8SIgor Kotrasinski 
290e0546fd8SIgor Kotrasinski 		if (!descriptors) {
291e0546fd8SIgor Kotrasinski 			err("problem getting device attributes: %s",
292e0546fd8SIgor Kotrasinski 			    strerror(errno));
293e0546fd8SIgor Kotrasinski 			goto err_out;
294e0546fd8SIgor Kotrasinski 		}
295e0546fd8SIgor Kotrasinski 
296e0546fd8SIgor Kotrasinski 		d_desc = (const struct usb_device_descriptor *) descriptors;
297e0546fd8SIgor Kotrasinski 
298e0546fd8SIgor Kotrasinski 		idVendor = le16toh(d_desc->idVendor);
299e0546fd8SIgor Kotrasinski 		sprintf(idVendor_buf, "0x%4x", idVendor);
300e0546fd8SIgor Kotrasinski 		idProduct = le16toh(d_desc->idProduct);
301e0546fd8SIgor Kotrasinski 		sprintf(idProduct_buf, "0x%4x", idVendor);
302e0546fd8SIgor Kotrasinski 		busid = udev_device_get_sysname(dev);
303e0546fd8SIgor Kotrasinski 
304e0546fd8SIgor Kotrasinski 		/* Get product name. */
305e0546fd8SIgor Kotrasinski 		usbip_names_get_product(product_name, sizeof(product_name),
306e0546fd8SIgor Kotrasinski 					le16toh(idVendor),
307e0546fd8SIgor Kotrasinski 					le16toh(idProduct));
308e0546fd8SIgor Kotrasinski 
309e0546fd8SIgor Kotrasinski 		/* Print information. */
310e0546fd8SIgor Kotrasinski 		print_device(busid, idVendor_buf, idProduct_buf, parsable);
311e0546fd8SIgor Kotrasinski 		print_product_name(product_name, parsable);
312e0546fd8SIgor Kotrasinski 
313e0546fd8SIgor Kotrasinski 		printf("\n");
314e0546fd8SIgor Kotrasinski 
315e0546fd8SIgor Kotrasinski 		udev_device_unref(dev);
316e0546fd8SIgor Kotrasinski 	}
317e0546fd8SIgor Kotrasinski 	ret = 0;
318e0546fd8SIgor Kotrasinski 
319e0546fd8SIgor Kotrasinski err_out:
320e0546fd8SIgor Kotrasinski 	udev_enumerate_unref(enumerate);
321e0546fd8SIgor Kotrasinski 	udev_unref(udev);
322e0546fd8SIgor Kotrasinski 
323e0546fd8SIgor Kotrasinski 	return ret;
324e0546fd8SIgor Kotrasinski }
325e0546fd8SIgor Kotrasinski 
usbip_list(int argc,char * argv[])326588b48caSValentina Manea int usbip_list(int argc, char *argv[])
327588b48caSValentina Manea {
328588b48caSValentina Manea 	static const struct option opts[] = {
329588b48caSValentina Manea 		{ "parsable", no_argument,       NULL, 'p' },
330588b48caSValentina Manea 		{ "remote",   required_argument, NULL, 'r' },
331588b48caSValentina Manea 		{ "local",    no_argument,       NULL, 'l' },
332e0546fd8SIgor Kotrasinski 		{ "device",    no_argument,       NULL, 'd' },
333588b48caSValentina Manea 		{ NULL,       0,                 NULL,  0  }
334588b48caSValentina Manea 	};
335588b48caSValentina Manea 
336588b48caSValentina Manea 	bool parsable = false;
337588b48caSValentina Manea 	int opt;
338588b48caSValentina Manea 	int ret = -1;
339588b48caSValentina Manea 
340588b48caSValentina Manea 	if (usbip_names_init(USBIDS_FILE))
341588b48caSValentina Manea 		err("failed to open %s", USBIDS_FILE);
342588b48caSValentina Manea 
343588b48caSValentina Manea 	for (;;) {
344e0546fd8SIgor Kotrasinski 		opt = getopt_long(argc, argv, "pr:ld", opts, NULL);
345588b48caSValentina Manea 
346588b48caSValentina Manea 		if (opt == -1)
347588b48caSValentina Manea 			break;
348588b48caSValentina Manea 
349588b48caSValentina Manea 		switch (opt) {
350588b48caSValentina Manea 		case 'p':
351588b48caSValentina Manea 			parsable = true;
352588b48caSValentina Manea 			break;
353588b48caSValentina Manea 		case 'r':
354588b48caSValentina Manea 			ret = list_exported_devices(optarg);
355588b48caSValentina Manea 			goto out;
356588b48caSValentina Manea 		case 'l':
357588b48caSValentina Manea 			ret = list_devices(parsable);
358588b48caSValentina Manea 			goto out;
359e0546fd8SIgor Kotrasinski 		case 'd':
360e0546fd8SIgor Kotrasinski 			ret = list_gadget_devices(parsable);
361e0546fd8SIgor Kotrasinski 			goto out;
362588b48caSValentina Manea 		default:
363588b48caSValentina Manea 			goto err_out;
364588b48caSValentina Manea 		}
365588b48caSValentina Manea 	}
366588b48caSValentina Manea 
367588b48caSValentina Manea err_out:
368588b48caSValentina Manea 	usbip_list_usage();
369588b48caSValentina Manea out:
370588b48caSValentina Manea 	usbip_names_free();
371588b48caSValentina Manea 
372588b48caSValentina Manea 	return ret;
373588b48caSValentina Manea }
374