374 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>4 * 2005-2007 Takahiro Hirofuchi5 * Copyright (C) 2015-2016 Samsung Electronics6 * 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 else158 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 have190 * 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}374