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

source code of linux/tools/usb/usbip/src/usbip_list.c