stub_main.c (9085B)
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2003-2008 Takahiro Hirofuchi 4 */ 5 6#include <linux/string.h> 7#include <linux/module.h> 8#include <linux/device.h> 9#include <linux/scatterlist.h> 10 11#include "usbip_common.h" 12#include "stub.h" 13 14#define DRIVER_AUTHOR "Takahiro Hirofuchi" 15#define DRIVER_DESC "USB/IP Host Driver" 16 17struct kmem_cache *stub_priv_cache; 18 19/* 20 * busid_tables defines matching busids that usbip can grab. A user can change 21 * dynamically what device is locally used and what device is exported to a 22 * remote host. 23 */ 24#define MAX_BUSID 16 25static struct bus_id_priv busid_table[MAX_BUSID]; 26static DEFINE_SPINLOCK(busid_table_lock); 27 28static void init_busid_table(void) 29{ 30 int i; 31 32 /* 33 * This also sets the bus_table[i].status to 34 * STUB_BUSID_OTHER, which is 0. 35 */ 36 memset(busid_table, 0, sizeof(busid_table)); 37 38 for (i = 0; i < MAX_BUSID; i++) 39 spin_lock_init(&busid_table[i].busid_lock); 40} 41 42/* 43 * Find the index of the busid by name. 44 * Must be called with busid_table_lock held. 45 */ 46static int get_busid_idx(const char *busid) 47{ 48 int i; 49 int idx = -1; 50 51 for (i = 0; i < MAX_BUSID; i++) { 52 spin_lock(&busid_table[i].busid_lock); 53 if (busid_table[i].name[0]) 54 if (!strncmp(busid_table[i].name, busid, BUSID_SIZE)) { 55 idx = i; 56 spin_unlock(&busid_table[i].busid_lock); 57 break; 58 } 59 spin_unlock(&busid_table[i].busid_lock); 60 } 61 return idx; 62} 63 64/* Returns holding busid_lock. Should call put_busid_priv() to unlock */ 65struct bus_id_priv *get_busid_priv(const char *busid) 66{ 67 int idx; 68 struct bus_id_priv *bid = NULL; 69 70 spin_lock(&busid_table_lock); 71 idx = get_busid_idx(busid); 72 if (idx >= 0) { 73 bid = &(busid_table[idx]); 74 /* get busid_lock before returning */ 75 spin_lock(&bid->busid_lock); 76 } 77 spin_unlock(&busid_table_lock); 78 79 return bid; 80} 81 82void put_busid_priv(struct bus_id_priv *bid) 83{ 84 if (bid) 85 spin_unlock(&bid->busid_lock); 86} 87 88static int add_match_busid(char *busid) 89{ 90 int i; 91 int ret = -1; 92 93 spin_lock(&busid_table_lock); 94 /* already registered? */ 95 if (get_busid_idx(busid) >= 0) { 96 ret = 0; 97 goto out; 98 } 99 100 for (i = 0; i < MAX_BUSID; i++) { 101 spin_lock(&busid_table[i].busid_lock); 102 if (!busid_table[i].name[0]) { 103 strlcpy(busid_table[i].name, busid, BUSID_SIZE); 104 if ((busid_table[i].status != STUB_BUSID_ALLOC) && 105 (busid_table[i].status != STUB_BUSID_REMOV)) 106 busid_table[i].status = STUB_BUSID_ADDED; 107 ret = 0; 108 spin_unlock(&busid_table[i].busid_lock); 109 break; 110 } 111 spin_unlock(&busid_table[i].busid_lock); 112 } 113 114out: 115 spin_unlock(&busid_table_lock); 116 117 return ret; 118} 119 120int del_match_busid(char *busid) 121{ 122 int idx; 123 int ret = -1; 124 125 spin_lock(&busid_table_lock); 126 idx = get_busid_idx(busid); 127 if (idx < 0) 128 goto out; 129 130 /* found */ 131 ret = 0; 132 133 spin_lock(&busid_table[idx].busid_lock); 134 135 if (busid_table[idx].status == STUB_BUSID_OTHER) 136 memset(busid_table[idx].name, 0, BUSID_SIZE); 137 138 if ((busid_table[idx].status != STUB_BUSID_OTHER) && 139 (busid_table[idx].status != STUB_BUSID_ADDED)) 140 busid_table[idx].status = STUB_BUSID_REMOV; 141 142 spin_unlock(&busid_table[idx].busid_lock); 143out: 144 spin_unlock(&busid_table_lock); 145 146 return ret; 147} 148 149static ssize_t match_busid_show(struct device_driver *drv, char *buf) 150{ 151 int i; 152 char *out = buf; 153 154 spin_lock(&busid_table_lock); 155 for (i = 0; i < MAX_BUSID; i++) { 156 spin_lock(&busid_table[i].busid_lock); 157 if (busid_table[i].name[0]) 158 out += sprintf(out, "%s ", busid_table[i].name); 159 spin_unlock(&busid_table[i].busid_lock); 160 } 161 spin_unlock(&busid_table_lock); 162 out += sprintf(out, "\n"); 163 164 return out - buf; 165} 166 167static ssize_t match_busid_store(struct device_driver *dev, const char *buf, 168 size_t count) 169{ 170 int len; 171 char busid[BUSID_SIZE]; 172 173 if (count < 5) 174 return -EINVAL; 175 176 /* busid needs to include \0 termination */ 177 len = strlcpy(busid, buf + 4, BUSID_SIZE); 178 if (sizeof(busid) <= len) 179 return -EINVAL; 180 181 if (!strncmp(buf, "add ", 4)) { 182 if (add_match_busid(busid) < 0) 183 return -ENOMEM; 184 185 pr_debug("add busid %s\n", busid); 186 return count; 187 } 188 189 if (!strncmp(buf, "del ", 4)) { 190 if (del_match_busid(busid) < 0) 191 return -ENODEV; 192 193 pr_debug("del busid %s\n", busid); 194 return count; 195 } 196 197 return -EINVAL; 198} 199static DRIVER_ATTR_RW(match_busid); 200 201static int do_rebind(char *busid, struct bus_id_priv *busid_priv) 202{ 203 int ret = 0; 204 205 /* device_attach() callers should hold parent lock for USB */ 206 if (busid_priv->udev->dev.parent) 207 device_lock(busid_priv->udev->dev.parent); 208 ret = device_attach(&busid_priv->udev->dev); 209 if (busid_priv->udev->dev.parent) 210 device_unlock(busid_priv->udev->dev.parent); 211 if (ret < 0) 212 dev_err(&busid_priv->udev->dev, "rebind failed\n"); 213 return ret; 214} 215 216static void stub_device_rebind(void) 217{ 218#if IS_MODULE(CONFIG_USBIP_HOST) 219 struct bus_id_priv *busid_priv; 220 int i; 221 222 /* update status to STUB_BUSID_OTHER so probe ignores the device */ 223 spin_lock(&busid_table_lock); 224 for (i = 0; i < MAX_BUSID; i++) { 225 if (busid_table[i].name[0] && 226 busid_table[i].shutdown_busid) { 227 busid_priv = &(busid_table[i]); 228 busid_priv->status = STUB_BUSID_OTHER; 229 } 230 } 231 spin_unlock(&busid_table_lock); 232 233 /* now run rebind - no need to hold locks. driver files are removed */ 234 for (i = 0; i < MAX_BUSID; i++) { 235 if (busid_table[i].name[0] && 236 busid_table[i].shutdown_busid) { 237 busid_priv = &(busid_table[i]); 238 do_rebind(busid_table[i].name, busid_priv); 239 } 240 } 241#endif 242} 243 244static ssize_t rebind_store(struct device_driver *dev, const char *buf, 245 size_t count) 246{ 247 int ret; 248 int len; 249 struct bus_id_priv *bid; 250 251 /* buf length should be less that BUSID_SIZE */ 252 len = strnlen(buf, BUSID_SIZE); 253 254 if (!(len < BUSID_SIZE)) 255 return -EINVAL; 256 257 bid = get_busid_priv(buf); 258 if (!bid) 259 return -ENODEV; 260 261 /* mark the device for deletion so probe ignores it during rescan */ 262 bid->status = STUB_BUSID_OTHER; 263 /* release the busid lock */ 264 put_busid_priv(bid); 265 266 ret = do_rebind((char *) buf, bid); 267 if (ret < 0) 268 return ret; 269 270 /* delete device from busid_table */ 271 del_match_busid((char *) buf); 272 273 return count; 274} 275 276static DRIVER_ATTR_WO(rebind); 277 278static struct stub_priv *stub_priv_pop_from_listhead(struct list_head *listhead) 279{ 280 struct stub_priv *priv, *tmp; 281 282 list_for_each_entry_safe(priv, tmp, listhead, list) { 283 list_del_init(&priv->list); 284 return priv; 285 } 286 287 return NULL; 288} 289 290void stub_free_priv_and_urb(struct stub_priv *priv) 291{ 292 struct urb *urb; 293 int i; 294 295 for (i = 0; i < priv->num_urbs; i++) { 296 urb = priv->urbs[i]; 297 298 if (!urb) 299 return; 300 301 kfree(urb->setup_packet); 302 urb->setup_packet = NULL; 303 304 305 if (urb->transfer_buffer && !priv->sgl) { 306 kfree(urb->transfer_buffer); 307 urb->transfer_buffer = NULL; 308 } 309 310 if (urb->num_sgs) { 311 sgl_free(urb->sg); 312 urb->sg = NULL; 313 urb->num_sgs = 0; 314 } 315 316 usb_free_urb(urb); 317 } 318 if (!list_empty(&priv->list)) 319 list_del(&priv->list); 320 if (priv->sgl) 321 sgl_free(priv->sgl); 322 kfree(priv->urbs); 323 kmem_cache_free(stub_priv_cache, priv); 324} 325 326static struct stub_priv *stub_priv_pop(struct stub_device *sdev) 327{ 328 unsigned long flags; 329 struct stub_priv *priv; 330 331 spin_lock_irqsave(&sdev->priv_lock, flags); 332 333 priv = stub_priv_pop_from_listhead(&sdev->priv_init); 334 if (priv) 335 goto done; 336 337 priv = stub_priv_pop_from_listhead(&sdev->priv_tx); 338 if (priv) 339 goto done; 340 341 priv = stub_priv_pop_from_listhead(&sdev->priv_free); 342 343done: 344 spin_unlock_irqrestore(&sdev->priv_lock, flags); 345 346 return priv; 347} 348 349void stub_device_cleanup_urbs(struct stub_device *sdev) 350{ 351 struct stub_priv *priv; 352 int i; 353 354 dev_dbg(&sdev->udev->dev, "Stub device cleaning up urbs\n"); 355 356 while ((priv = stub_priv_pop(sdev))) { 357 for (i = 0; i < priv->num_urbs; i++) 358 usb_kill_urb(priv->urbs[i]); 359 360 stub_free_priv_and_urb(priv); 361 } 362} 363 364static int __init usbip_host_init(void) 365{ 366 int ret; 367 368 init_busid_table(); 369 370 stub_priv_cache = KMEM_CACHE(stub_priv, SLAB_HWCACHE_ALIGN); 371 if (!stub_priv_cache) { 372 pr_err("kmem_cache_create failed\n"); 373 return -ENOMEM; 374 } 375 376 ret = usb_register_device_driver(&stub_driver, THIS_MODULE); 377 if (ret) { 378 pr_err("usb_register failed %d\n", ret); 379 goto err_usb_register; 380 } 381 382 ret = driver_create_file(&stub_driver.drvwrap.driver, 383 &driver_attr_match_busid); 384 if (ret) { 385 pr_err("driver_create_file failed\n"); 386 goto err_create_file; 387 } 388 389 ret = driver_create_file(&stub_driver.drvwrap.driver, 390 &driver_attr_rebind); 391 if (ret) { 392 pr_err("driver_create_file failed\n"); 393 goto err_create_file; 394 } 395 396 return ret; 397 398err_create_file: 399 usb_deregister_device_driver(&stub_driver); 400err_usb_register: 401 kmem_cache_destroy(stub_priv_cache); 402 return ret; 403} 404 405static void __exit usbip_host_exit(void) 406{ 407 driver_remove_file(&stub_driver.drvwrap.driver, 408 &driver_attr_match_busid); 409 410 driver_remove_file(&stub_driver.drvwrap.driver, 411 &driver_attr_rebind); 412 413 /* 414 * deregister() calls stub_disconnect() for all devices. Device 415 * specific data is cleared in stub_disconnect(). 416 */ 417 usb_deregister_device_driver(&stub_driver); 418 419 /* initiate scan to attach devices */ 420 stub_device_rebind(); 421 422 kmem_cache_destroy(stub_priv_cache); 423} 424 425module_init(usbip_host_init); 426module_exit(usbip_host_exit); 427 428MODULE_AUTHOR(DRIVER_AUTHOR); 429MODULE_DESCRIPTION(DRIVER_DESC); 430MODULE_LICENSE("GPL");