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