linux/drivers/usb/usbip/stub_main.c
<<
>>
Prefs
   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 spinlock_t 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        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 */
  48static 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 */
  67struct 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
  84void put_busid_priv(struct bus_id_priv *bid)
  85{
  86        if (bid)
  87                spin_unlock(&bid->busid_lock);
  88}
  89
  90static 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
 116out:
 117        spin_unlock(&busid_table_lock);
 118
 119        return ret;
 120}
 121
 122int 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);
 145out:
 146        spin_unlock(&busid_table_lock);
 147
 148        return ret;
 149}
 150
 151static 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
 169static 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}
 201static DRIVER_ATTR_RW(match_busid);
 202
 203static 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
 218static 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
 246static 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
 278static DRIVER_ATTR_WO(rebind);
 279
 280static 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
 292void 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
 328static 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
 345done:
 346        spin_unlock_irqrestore(&sdev->priv_lock, flags);
 347
 348        return priv;
 349}
 350
 351void 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
 366static 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
 400err_create_file:
 401        usb_deregister_device_driver(&stub_driver);
 402err_usb_register:
 403        kmem_cache_destroy(stub_priv_cache);
 404        return ret;
 405}
 406
 407static 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
 427module_init(usbip_host_init);
 428module_exit(usbip_host_exit);
 429
 430MODULE_AUTHOR(DRIVER_AUTHOR);
 431MODULE_DESCRIPTION(DRIVER_DESC);
 432MODULE_LICENSE("GPL");
 433