root/drivers/usb/usbip/stub_main.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. init_busid_table
  2. get_busid_idx
  3. get_busid_priv
  4. put_busid_priv
  5. add_match_busid
  6. del_match_busid
  7. match_busid_show
  8. match_busid_store
  9. do_rebind
  10. stub_device_rebind
  11. rebind_store
  12. stub_priv_pop_from_listhead
  13. stub_free_priv_and_urb
  14. stub_priv_pop
  15. stub_device_cleanup_urbs
  16. usbip_host_init
  17. usbip_host_exit

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

/* [<][>][^][v][top][bottom][index][help] */