1 /* 2 * Copyright (C) 2005-2007 Takahiro Hirofuchi 3 */ 4 5 #include "usbip_common.h" 6 #include "vhci_driver.h" 7 #include <limits.h> 8 #include <netdb.h> 9 #include <libudev.h> 10 #include "sysfs_utils.h" 11 12 #undef PROGNAME 13 #define PROGNAME "libusbip" 14 15 struct usbip_vhci_driver *vhci_driver; 16 struct udev *udev_context; 17 18 static struct usbip_imported_device * 19 imported_device_init(struct usbip_imported_device *idev, char *busid) 20 { 21 struct udev_device *sudev; 22 23 sudev = udev_device_new_from_subsystem_sysname(udev_context, 24 "usb", busid); 25 if (!sudev) { 26 dbg("udev_device_new_from_subsystem_sysname failed: %s", busid); 27 goto err; 28 } 29 read_usb_device(sudev, &idev->udev); 30 udev_device_unref(sudev); 31 32 return idev; 33 34 err: 35 return NULL; 36 } 37 38 39 40 static int parse_status(const char *value) 41 { 42 int ret = 0; 43 char *c; 44 45 46 for (int i = 0; i < vhci_driver->nports; i++) 47 memset(&vhci_driver->idev[i], 0, sizeof(vhci_driver->idev[i])); 48 49 50 /* skip a header line */ 51 c = strchr(value, '\n'); 52 if (!c) 53 return -1; 54 c++; 55 56 while (*c != '\0') { 57 int port, status, speed, devid; 58 unsigned long socket; 59 char lbusid[SYSFS_BUS_ID_SIZE]; 60 61 ret = sscanf(c, "%d %d %d %x %lx %31s\n", 62 &port, &status, &speed, 63 &devid, &socket, lbusid); 64 65 if (ret < 5) { 66 dbg("sscanf failed: %d", ret); 67 BUG(); 68 } 69 70 dbg("port %d status %d speed %d devid %x", 71 port, status, speed, devid); 72 dbg("socket %lx lbusid %s", socket, lbusid); 73 74 75 /* if a device is connected, look at it */ 76 { 77 struct usbip_imported_device *idev = &vhci_driver->idev[port]; 78 79 idev->port = port; 80 idev->status = status; 81 82 idev->devid = devid; 83 84 idev->busnum = (devid >> 16); 85 idev->devnum = (devid & 0x0000ffff); 86 87 if (idev->status != VDEV_ST_NULL 88 && idev->status != VDEV_ST_NOTASSIGNED) { 89 idev = imported_device_init(idev, lbusid); 90 if (!idev) { 91 dbg("imported_device_init failed"); 92 return -1; 93 } 94 } 95 } 96 97 98 /* go to the next line */ 99 c = strchr(c, '\n'); 100 if (!c) 101 break; 102 c++; 103 } 104 105 dbg("exit"); 106 107 return 0; 108 } 109 110 static int refresh_imported_device_list(void) 111 { 112 const char *attr_status; 113 114 attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device, 115 "status"); 116 if (!attr_status) { 117 err("udev_device_get_sysattr_value failed"); 118 return -1; 119 } 120 121 return parse_status(attr_status); 122 } 123 124 static int get_nports(void) 125 { 126 const char *attr_nports; 127 128 attr_nports = udev_device_get_sysattr_value(vhci_driver->hc_device, "nports"); 129 if (!attr_nports) { 130 err("udev_device_get_sysattr_value nports failed"); 131 return -1; 132 } 133 134 return (int)strtoul(attr_nports, NULL, 10); 135 } 136 137 /* 138 * Read the given port's record. 139 * 140 * To avoid buffer overflow we will read the entire line and 141 * validate each part's size. The initial buffer is padded by 4 to 142 * accommodate the 2 spaces, 1 newline and an additional character 143 * which is needed to properly validate the 3rd part without it being 144 * truncated to an acceptable length. 145 */ 146 static int read_record(int rhport, char *host, unsigned long host_len, 147 char *port, unsigned long port_len, char *busid) 148 { 149 int part; 150 FILE *file; 151 char path[PATH_MAX+1]; 152 char *buffer, *start, *end; 153 char delim[] = {' ', ' ', '\n'}; 154 int max_len[] = {(int)host_len, (int)port_len, SYSFS_BUS_ID_SIZE}; 155 size_t buffer_len = host_len + port_len + SYSFS_BUS_ID_SIZE + 4; 156 157 buffer = malloc(buffer_len); 158 if (!buffer) 159 return -1; 160 161 snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport); 162 163 file = fopen(path, "r"); 164 if (!file) { 165 err("fopen"); 166 free(buffer); 167 return -1; 168 } 169 170 if (fgets(buffer, buffer_len, file) == NULL) { 171 err("fgets"); 172 free(buffer); 173 fclose(file); 174 return -1; 175 } 176 fclose(file); 177 178 /* validate the length of each of the 3 parts */ 179 start = buffer; 180 for (part = 0; part < 3; part++) { 181 end = strchr(start, delim[part]); 182 if (end == NULL || (end - start) > max_len[part]) { 183 free(buffer); 184 return -1; 185 } 186 start = end + 1; 187 } 188 189 if (sscanf(buffer, "%s %s %s\n", host, port, busid) != 3) { 190 err("sscanf"); 191 free(buffer); 192 return -1; 193 } 194 195 free(buffer); 196 197 return 0; 198 } 199 200 /* ---------------------------------------------------------------------- */ 201 202 int usbip_vhci_driver_open(void) 203 { 204 udev_context = udev_new(); 205 if (!udev_context) { 206 err("udev_new failed"); 207 return -1; 208 } 209 210 vhci_driver = calloc(1, sizeof(struct usbip_vhci_driver)); 211 212 /* will be freed in usbip_driver_close() */ 213 vhci_driver->hc_device = 214 udev_device_new_from_subsystem_sysname(udev_context, 215 USBIP_VHCI_BUS_TYPE, 216 USBIP_VHCI_DRV_NAME); 217 if (!vhci_driver->hc_device) { 218 err("udev_device_new_from_subsystem_sysname failed"); 219 goto err; 220 } 221 222 vhci_driver->nports = get_nports(); 223 224 dbg("available ports: %d", vhci_driver->nports); 225 226 if (refresh_imported_device_list()) 227 goto err; 228 229 return 0; 230 231 err: 232 udev_device_unref(vhci_driver->hc_device); 233 234 if (vhci_driver) 235 free(vhci_driver); 236 237 vhci_driver = NULL; 238 239 udev_unref(udev_context); 240 241 return -1; 242 } 243 244 245 void usbip_vhci_driver_close(void) 246 { 247 if (!vhci_driver) 248 return; 249 250 udev_device_unref(vhci_driver->hc_device); 251 252 free(vhci_driver); 253 254 vhci_driver = NULL; 255 256 udev_unref(udev_context); 257 } 258 259 260 int usbip_vhci_refresh_device_list(void) 261 { 262 263 if (refresh_imported_device_list()) 264 goto err; 265 266 return 0; 267 err: 268 dbg("failed to refresh device list"); 269 return -1; 270 } 271 272 273 int usbip_vhci_get_free_port(void) 274 { 275 for (int i = 0; i < vhci_driver->nports; i++) { 276 if (vhci_driver->idev[i].status == VDEV_ST_NULL) 277 return i; 278 } 279 280 return -1; 281 } 282 283 int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid, 284 uint32_t speed) { 285 char buff[200]; /* what size should be ? */ 286 char attach_attr_path[SYSFS_PATH_MAX]; 287 char attr_attach[] = "attach"; 288 const char *path; 289 int ret; 290 291 snprintf(buff, sizeof(buff), "%u %d %u %u", 292 port, sockfd, devid, speed); 293 dbg("writing: %s", buff); 294 295 path = udev_device_get_syspath(vhci_driver->hc_device); 296 snprintf(attach_attr_path, sizeof(attach_attr_path), "%s/%s", 297 path, attr_attach); 298 dbg("attach attribute path: %s", attach_attr_path); 299 300 ret = write_sysfs_attribute(attach_attr_path, buff, strlen(buff)); 301 if (ret < 0) { 302 dbg("write_sysfs_attribute failed"); 303 return -1; 304 } 305 306 dbg("attached port: %d", port); 307 308 return 0; 309 } 310 311 static unsigned long get_devid(uint8_t busnum, uint8_t devnum) 312 { 313 return (busnum << 16) | devnum; 314 } 315 316 /* will be removed */ 317 int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum, 318 uint8_t devnum, uint32_t speed) 319 { 320 int devid = get_devid(busnum, devnum); 321 322 return usbip_vhci_attach_device2(port, sockfd, devid, speed); 323 } 324 325 int usbip_vhci_detach_device(uint8_t port) 326 { 327 char detach_attr_path[SYSFS_PATH_MAX]; 328 char attr_detach[] = "detach"; 329 char buff[200]; /* what size should be ? */ 330 const char *path; 331 int ret; 332 333 snprintf(buff, sizeof(buff), "%u", port); 334 dbg("writing: %s", buff); 335 336 path = udev_device_get_syspath(vhci_driver->hc_device); 337 snprintf(detach_attr_path, sizeof(detach_attr_path), "%s/%s", 338 path, attr_detach); 339 dbg("detach attribute path: %s", detach_attr_path); 340 341 ret = write_sysfs_attribute(detach_attr_path, buff, strlen(buff)); 342 if (ret < 0) { 343 dbg("write_sysfs_attribute failed"); 344 return -1; 345 } 346 347 dbg("detached port: %d", port); 348 349 return 0; 350 } 351 352 int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev) 353 { 354 char product_name[100]; 355 char host[NI_MAXHOST] = "unknown host"; 356 char serv[NI_MAXSERV] = "unknown port"; 357 char remote_busid[SYSFS_BUS_ID_SIZE]; 358 int ret; 359 int read_record_error = 0; 360 361 if (idev->status == VDEV_ST_NULL || idev->status == VDEV_ST_NOTASSIGNED) 362 return 0; 363 364 ret = read_record(idev->port, host, sizeof(host), serv, sizeof(serv), 365 remote_busid); 366 if (ret) { 367 err("read_record"); 368 read_record_error = 1; 369 } 370 371 printf("Port %02d: <%s> at %s\n", idev->port, 372 usbip_status_string(idev->status), 373 usbip_speed_string(idev->udev.speed)); 374 375 usbip_names_get_product(product_name, sizeof(product_name), 376 idev->udev.idVendor, idev->udev.idProduct); 377 378 printf(" %s\n", product_name); 379 380 if (!read_record_error) { 381 printf("%10s -> usbip://%s:%s/%s\n", idev->udev.busid, 382 host, serv, remote_busid); 383 printf("%10s -> remote bus/dev %03d/%03d\n", " ", 384 idev->busnum, idev->devnum); 385 } else { 386 printf("%10s -> unknown host, remote port and remote busid\n", 387 idev->udev.busid); 388 printf("%10s -> remote bus/dev %03d/%03d\n", " ", 389 idev->busnum, idev->devnum); 390 } 391 392 return 0; 393 } 394