1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 2015-2016 Samsung Electronics 4 * Igor Kotrasinski <i.kotrasinsk@samsung.com> 5 * Krzysztof Opasiak <k.opasiak@samsung.com> 6 * 7 * Refactored from usbip_host_driver.c, which is: 8 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> 9 * 2005-2007 Takahiro Hirofuchi 10 */ 11 12 #include <sys/types.h> 13 #include <sys/stat.h> 14 #include <fcntl.h> 15 16 #include <errno.h> 17 #include <unistd.h> 18 19 #include <libudev.h> 20 21 #include "usbip_common.h" 22 #include "usbip_host_common.h" 23 #include "list.h" 24 #include "sysfs_utils.h" 25 26 extern struct udev *udev_context; 27 28 static int32_t read_attr_usbip_status(struct usbip_usb_device *udev) 29 { 30 char status_attr_path[SYSFS_PATH_MAX]; 31 int size; 32 int fd; 33 int length; 34 char status[2] = { 0 }; 35 int value = 0; 36 37 size = snprintf(status_attr_path, sizeof(status_attr_path), 38 "%s/usbip_status", udev->path); 39 if (size < 0 || (unsigned int)size >= sizeof(status_attr_path)) { 40 err("usbip_status path length %i >= %lu or < 0", size, 41 (long unsigned)sizeof(status_attr_path)); 42 return -1; 43 } 44 45 46 fd = open(status_attr_path, O_RDONLY); 47 if (fd < 0) { 48 err("error opening attribute %s", status_attr_path); 49 return -1; 50 } 51 52 length = read(fd, status, 1); 53 if (length < 0) { 54 err("error reading attribute %s", status_attr_path); 55 close(fd); 56 return -1; 57 } 58 59 value = atoi(status); 60 close(fd); 61 return value; 62 } 63 64 static 65 struct usbip_exported_device *usbip_exported_device_new( 66 struct usbip_host_driver *hdriver, const char *sdevpath) 67 { 68 struct usbip_exported_device *edev = NULL; 69 struct usbip_exported_device *edev_old; 70 size_t size; 71 int i; 72 73 edev = calloc(1, sizeof(struct usbip_exported_device)); 74 75 edev->sudev = 76 udev_device_new_from_syspath(udev_context, sdevpath); 77 if (!edev->sudev) { 78 err("udev_device_new_from_syspath: %s", sdevpath); 79 goto err; 80 } 81 82 if (hdriver->ops.read_device(edev->sudev, &edev->udev) < 0) 83 goto err; 84 85 edev->status = read_attr_usbip_status(&edev->udev); 86 if (edev->status < 0) 87 goto err; 88 89 /* reallocate buffer to include usb interface data */ 90 size = sizeof(struct usbip_exported_device) + 91 edev->udev.bNumInterfaces * sizeof(struct usbip_usb_interface); 92 93 edev_old = edev; 94 edev = realloc(edev, size); 95 if (!edev) { 96 edev = edev_old; 97 dbg("realloc failed"); 98 goto err; 99 } 100 101 for (i = 0; i < edev->udev.bNumInterfaces; i++) { 102 /* vudc does not support reading interfaces */ 103 if (!hdriver->ops.read_interface) 104 break; 105 hdriver->ops.read_interface(&edev->udev, i, &edev->uinf[i]); 106 } 107 108 return edev; 109 err: 110 if (edev->sudev) 111 udev_device_unref(edev->sudev); 112 if (edev) 113 free(edev); 114 115 return NULL; 116 } 117 118 static int refresh_exported_devices(struct usbip_host_driver *hdriver) 119 { 120 struct usbip_exported_device *edev; 121 struct udev_enumerate *enumerate; 122 struct udev_list_entry *devices, *dev_list_entry; 123 struct udev_device *dev; 124 const char *path; 125 126 enumerate = udev_enumerate_new(udev_context); 127 udev_enumerate_add_match_subsystem(enumerate, hdriver->udev_subsystem); 128 udev_enumerate_scan_devices(enumerate); 129 130 devices = udev_enumerate_get_list_entry(enumerate); 131 132 udev_list_entry_foreach(dev_list_entry, devices) { 133 path = udev_list_entry_get_name(dev_list_entry); 134 dev = udev_device_new_from_syspath(udev_context, 135 path); 136 if (dev == NULL) 137 continue; 138 139 /* Check whether device uses usbip driver. */ 140 if (hdriver->ops.is_my_device(dev)) { 141 edev = usbip_exported_device_new(hdriver, path); 142 if (!edev) { 143 dbg("usbip_exported_device_new failed"); 144 continue; 145 } 146 147 list_add(&edev->node, &hdriver->edev_list); 148 hdriver->ndevs++; 149 } 150 } 151 152 return 0; 153 } 154 155 static void usbip_exported_device_destroy(struct list_head *devs) 156 { 157 struct list_head *i, *tmp; 158 struct usbip_exported_device *edev; 159 160 list_for_each_safe(i, tmp, devs) { 161 edev = list_entry(i, struct usbip_exported_device, node); 162 list_del(i); 163 free(edev); 164 } 165 } 166 167 int usbip_generic_driver_open(struct usbip_host_driver *hdriver) 168 { 169 int rc; 170 171 udev_context = udev_new(); 172 if (!udev_context) { 173 err("udev_new failed"); 174 return -1; 175 } 176 177 rc = refresh_exported_devices(hdriver); 178 if (rc < 0) 179 goto err; 180 return 0; 181 err: 182 udev_unref(udev_context); 183 return -1; 184 } 185 186 void usbip_generic_driver_close(struct usbip_host_driver *hdriver) 187 { 188 if (!hdriver) 189 return; 190 191 usbip_exported_device_destroy(&hdriver->edev_list); 192 193 udev_unref(udev_context); 194 } 195 196 int usbip_generic_refresh_device_list(struct usbip_host_driver *hdriver) 197 { 198 int rc; 199 200 usbip_exported_device_destroy(&hdriver->edev_list); 201 202 hdriver->ndevs = 0; 203 INIT_LIST_HEAD(&hdriver->edev_list); 204 205 rc = refresh_exported_devices(hdriver); 206 if (rc < 0) 207 return -1; 208 209 return 0; 210 } 211 212 int usbip_export_device(struct usbip_exported_device *edev, int sockfd) 213 { 214 char attr_name[] = "usbip_sockfd"; 215 char sockfd_attr_path[SYSFS_PATH_MAX]; 216 int size; 217 char sockfd_buff[30]; 218 int ret; 219 220 if (edev->status != SDEV_ST_AVAILABLE) { 221 dbg("device not available: %s", edev->udev.busid); 222 switch (edev->status) { 223 case SDEV_ST_ERROR: 224 dbg("status SDEV_ST_ERROR"); 225 ret = ST_DEV_ERR; 226 break; 227 case SDEV_ST_USED: 228 dbg("status SDEV_ST_USED"); 229 ret = ST_DEV_BUSY; 230 break; 231 default: 232 dbg("status unknown: 0x%x", edev->status); 233 ret = -1; 234 } 235 return ret; 236 } 237 238 /* only the first interface is true */ 239 size = snprintf(sockfd_attr_path, sizeof(sockfd_attr_path), "%s/%s", 240 edev->udev.path, attr_name); 241 if (size < 0 || (unsigned int)size >= sizeof(sockfd_attr_path)) { 242 err("exported device path length %i >= %lu or < 0", size, 243 (long unsigned)sizeof(sockfd_attr_path)); 244 return -1; 245 } 246 247 size = snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd); 248 if (size < 0 || (unsigned int)size >= sizeof(sockfd_buff)) { 249 err("socket length %i >= %lu or < 0", size, 250 (long unsigned)sizeof(sockfd_buff)); 251 return -1; 252 } 253 254 ret = write_sysfs_attribute(sockfd_attr_path, sockfd_buff, 255 strlen(sockfd_buff)); 256 if (ret < 0) { 257 err("write_sysfs_attribute failed: sockfd %s to %s", 258 sockfd_buff, sockfd_attr_path); 259 return ret; 260 } 261 262 info("connect: %s", edev->udev.busid); 263 264 return ret; 265 } 266 267 struct usbip_exported_device *usbip_generic_get_device( 268 struct usbip_host_driver *hdriver, int num) 269 { 270 struct list_head *i; 271 struct usbip_exported_device *edev; 272 int cnt = 0; 273 274 list_for_each(i, &hdriver->edev_list) { 275 edev = list_entry(i, struct usbip_exported_device, node); 276 if (num == cnt) 277 return edev; 278 cnt++; 279 } 280 281 return NULL; 282 } 283