1/* 2 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> 3 * 2005-2007 Takahiro Hirofuchi 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19#include <sys/types.h> 20#include <sys/stat.h> 21 22#include <errno.h> 23#include <unistd.h> 24 25#include "usbip_common.h" 26#include "usbip_host_driver.h" 27 28#undef PROGNAME 29#define PROGNAME "libusbip" 30 31struct usbip_host_driver *host_driver; 32 33#define SYSFS_OPEN_RETRIES 100 34 35/* only the first interface value is true! */ 36static int32_t read_attr_usbip_status(struct usbip_usb_device *udev) 37{ 38 char attrpath[SYSFS_PATH_MAX]; 39 struct sysfs_attribute *attr; 40 int value = 0; 41 int rc; 42 struct stat s; 43 int retries = SYSFS_OPEN_RETRIES; 44 45 /* This access is racy! 46 * 47 * Just after detach, our driver removes the sysfs 48 * files and recreates them. 49 * 50 * We may try and fail to open the usbip_status of 51 * an exported device in the (short) window where 52 * it has been removed and not yet recreated. 53 * 54 * This is a bug in the interface. Nothing we can do 55 * except work around it here by polling for the sysfs 56 * usbip_status to reappear. 57 */ 58 59 snprintf(attrpath, SYSFS_PATH_MAX, "%s/%s:%d.%d/usbip_status", 60 udev->path, udev->busid, udev->bConfigurationValue, 0); 61 62 while (retries > 0) { 63 if (stat(attrpath, &s) == 0) 64 break; 65 66 if (errno != ENOENT) { 67 dbg("stat failed: %s", attrpath); 68 return -1; 69 } 70 71 usleep(10000); /* 10ms */ 72 retries--; 73 } 74 75 if (retries == 0) 76 dbg("usbip_status not ready after %d retries", 77 SYSFS_OPEN_RETRIES); 78 else if (retries < SYSFS_OPEN_RETRIES) 79 dbg("warning: usbip_status ready after %d retries", 80 SYSFS_OPEN_RETRIES - retries); 81 82 attr = sysfs_open_attribute(attrpath); 83 if (!attr) { 84 dbg("sysfs_open_attribute failed: %s", attrpath); 85 return -1; 86 } 87 88 rc = sysfs_read_attribute(attr); 89 if (rc) { 90 dbg("sysfs_read_attribute failed: %s", attrpath); 91 sysfs_close_attribute(attr); 92 return -1; 93 } 94 95 value = atoi(attr->value); 96 97 sysfs_close_attribute(attr); 98 99 return value; 100} 101 102static struct usbip_exported_device *usbip_exported_device_new(char *sdevpath) 103{ 104 struct usbip_exported_device *edev = NULL; 105 size_t size; 106 int i; 107 108 edev = calloc(1, sizeof(*edev)); 109 if (!edev) { 110 dbg("calloc failed"); 111 return NULL; 112 } 113 114 edev->sudev = sysfs_open_device_path(sdevpath); 115 if (!edev->sudev) { 116 dbg("sysfs_open_device_path failed: %s", sdevpath); 117 goto err; 118 } 119 120 read_usb_device(edev->sudev, &edev->udev); 121 122 edev->status = read_attr_usbip_status(&edev->udev); 123 if (edev->status < 0) 124 goto err; 125 126 /* reallocate buffer to include usb interface data */ 127 size = sizeof(*edev) + edev->udev.bNumInterfaces * 128 sizeof(struct usbip_usb_interface); 129 130 edev = realloc(edev, size); 131 if (!edev) { 132 dbg("realloc failed"); 133 goto err; 134 } 135 136 for (i = 0; i < edev->udev.bNumInterfaces; i++) 137 read_usb_interface(&edev->udev, i, &edev->uinf[i]); 138 139 return edev; 140err: 141 if (edev && edev->sudev) 142 sysfs_close_device(edev->sudev); 143 if (edev) 144 free(edev); 145 146 return NULL; 147} 148 149static int check_new(struct dlist *dlist, struct sysfs_device *target) 150{ 151 struct sysfs_device *dev; 152 153 dlist_for_each_data(dlist, dev, struct sysfs_device) { 154 if (!strncmp(dev->bus_id, target->bus_id, SYSFS_BUS_ID_SIZE)) 155 /* device found and is not new */ 156 return 0; 157 } 158 return 1; 159} 160 161static void delete_nothing(void *unused_data) 162{ 163 /* 164 * NOTE: Do not delete anything, but the container will be deleted. 165 */ 166 (void) unused_data; 167} 168 169static int refresh_exported_devices(void) 170{ 171 /* sysfs_device of usb_interface */ 172 struct sysfs_device *suintf; 173 struct dlist *suintf_list; 174 /* sysfs_device of usb_device */ 175 struct sysfs_device *sudev; 176 struct dlist *sudev_list; 177 struct usbip_exported_device *edev; 178 179 sudev_list = dlist_new_with_delete(sizeof(struct sysfs_device), 180 delete_nothing); 181 182 suintf_list = sysfs_get_driver_devices(host_driver->sysfs_driver); 183 if (!suintf_list) { 184 /* 185 * Not an error condition. There are simply no devices bound to 186 * the driver yet. 187 */ 188 dbg("bind " USBIP_HOST_DRV_NAME ".ko to a usb device to be " 189 "exportable!"); 190 return 0; 191 } 192 193 /* collect unique USB devices (not interfaces) */ 194 dlist_for_each_data(suintf_list, suintf, struct sysfs_device) { 195 /* get usb device of this usb interface */ 196 sudev = sysfs_get_device_parent(suintf); 197 if (!sudev) { 198 dbg("sysfs_get_device_parent failed: %s", suintf->name); 199 continue; 200 } 201 202 if (check_new(sudev_list, sudev)) { 203 /* insert item at head of list */ 204 dlist_unshift(sudev_list, sudev); 205 } 206 } 207 208 dlist_for_each_data(sudev_list, sudev, struct sysfs_device) { 209 edev = usbip_exported_device_new(sudev->path); 210 if (!edev) { 211 dbg("usbip_exported_device_new failed"); 212 continue; 213 } 214 215 dlist_unshift(host_driver->edev_list, edev); 216 host_driver->ndevs++; 217 } 218 219 dlist_destroy(sudev_list); 220 221 return 0; 222} 223 224static struct sysfs_driver *open_sysfs_host_driver(void) 225{ 226 char bus_type[] = "usb"; 227 char sysfs_mntpath[SYSFS_PATH_MAX]; 228 char host_drv_path[SYSFS_PATH_MAX]; 229 struct sysfs_driver *host_drv; 230 int rc; 231 232 rc = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX); 233 if (rc < 0) { 234 dbg("sysfs_get_mnt_path failed"); 235 return NULL; 236 } 237 238 snprintf(host_drv_path, SYSFS_PATH_MAX, "%s/%s/%s/%s/%s", 239 sysfs_mntpath, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME, 240 USBIP_HOST_DRV_NAME); 241 242 host_drv = sysfs_open_driver_path(host_drv_path); 243 if (!host_drv) { 244 dbg("sysfs_open_driver_path failed"); 245 return NULL; 246 } 247 248 return host_drv; 249} 250 251static void usbip_exported_device_delete(void *dev) 252{ 253 struct usbip_exported_device *edev = dev; 254 sysfs_close_device(edev->sudev); 255 free(dev); 256} 257 258int usbip_host_driver_open(void) 259{ 260 int rc; 261 262 host_driver = calloc(1, sizeof(*host_driver)); 263 if (!host_driver) { 264 dbg("calloc failed"); 265 return -1; 266 } 267 268 host_driver->ndevs = 0; 269 host_driver->edev_list = 270 dlist_new_with_delete(sizeof(struct usbip_exported_device), 271 usbip_exported_device_delete); 272 if (!host_driver->edev_list) { 273 dbg("dlist_new_with_delete failed"); 274 goto err_free_host_driver; 275 } 276 277 host_driver->sysfs_driver = open_sysfs_host_driver(); 278 if (!host_driver->sysfs_driver) 279 goto err_destroy_edev_list; 280 281 rc = refresh_exported_devices(); 282 if (rc < 0) 283 goto err_close_sysfs_driver; 284 285 return 0; 286 287err_close_sysfs_driver: 288 sysfs_close_driver(host_driver->sysfs_driver); 289err_destroy_edev_list: 290 dlist_destroy(host_driver->edev_list); 291err_free_host_driver: 292 free(host_driver); 293 host_driver = NULL; 294 295 return -1; 296} 297 298void usbip_host_driver_close(void) 299{ 300 if (!host_driver) 301 return; 302 303 if (host_driver->edev_list) 304 dlist_destroy(host_driver->edev_list); 305 if (host_driver->sysfs_driver) 306 sysfs_close_driver(host_driver->sysfs_driver); 307 308 free(host_driver); 309 host_driver = NULL; 310} 311 312int usbip_host_refresh_device_list(void) 313{ 314 int rc; 315 316 if (host_driver->edev_list) 317 dlist_destroy(host_driver->edev_list); 318 319 host_driver->ndevs = 0; 320 host_driver->edev_list = 321 dlist_new_with_delete(sizeof(struct usbip_exported_device), 322 usbip_exported_device_delete); 323 if (!host_driver->edev_list) { 324 dbg("dlist_new_with_delete failed"); 325 return -1; 326 } 327 328 rc = refresh_exported_devices(); 329 if (rc < 0) 330 return -1; 331 332 return 0; 333} 334 335int usbip_host_export_device(struct usbip_exported_device *edev, int sockfd) 336{ 337 char attr_name[] = "usbip_sockfd"; 338 char attr_path[SYSFS_PATH_MAX]; 339 struct sysfs_attribute *attr; 340 char sockfd_buff[30]; 341 int ret; 342 343 if (edev->status != SDEV_ST_AVAILABLE) { 344 dbg("device not available: %s", edev->udev.busid); 345 switch (edev->status) { 346 case SDEV_ST_ERROR: 347 dbg("status SDEV_ST_ERROR"); 348 break; 349 case SDEV_ST_USED: 350 dbg("status SDEV_ST_USED"); 351 break; 352 default: 353 dbg("status unknown: 0x%x", edev->status); 354 } 355 return -1; 356 } 357 358 /* only the first interface is true */ 359 snprintf(attr_path, sizeof(attr_path), "%s/%s:%d.%d/%s", 360 edev->udev.path, edev->udev.busid, 361 edev->udev.bConfigurationValue, 0, attr_name); 362 363 attr = sysfs_open_attribute(attr_path); 364 if (!attr) { 365 dbg("sysfs_open_attribute failed: %s", attr_path); 366 return -1; 367 } 368 369 snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd); 370 dbg("write: %s", sockfd_buff); 371 372 ret = sysfs_write_attribute(attr, sockfd_buff, strlen(sockfd_buff)); 373 if (ret < 0) { 374 dbg("sysfs_write_attribute failed: sockfd %s to %s", 375 sockfd_buff, attr_path); 376 goto err_write_sockfd; 377 } 378 379 dbg("connect: %s", edev->udev.busid); 380 381err_write_sockfd: 382 sysfs_close_attribute(attr); 383 384 return ret; 385} 386 387struct usbip_exported_device *usbip_host_get_device(int num) 388{ 389 struct usbip_exported_device *edev; 390 struct dlist *dlist = host_driver->edev_list; 391 int cnt = 0; 392 393 dlist_for_each_data(dlist, edev, struct usbip_exported_device) { 394 if (num == cnt) 395 return edev; 396 else 397 cnt++; 398 } 399 400 return NULL; 401} 402