usbip_list.c (9190B)
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, 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, &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, &reply, 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, &udev, 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(0, &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, &uintf, 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(0, &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(host, 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, idVendor, 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, idVendor_buf, 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(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}