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 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");
 431