root/drivers/usb/mon/mon_main.c

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

DEFINITIONS

This source file includes following definitions.
  1. mon_reader_add
  2. mon_reader_del
  3. mon_bus_submit
  4. mon_submit
  5. mon_bus_submit_error
  6. mon_submit_error
  7. mon_bus_complete
  8. mon_complete
  9. mon_stop
  10. mon_bus_add
  11. mon_bus_remove
  12. mon_notify
  13. mon_dissolve
  14. mon_bus_drop
  15. mon_bus_init
  16. mon_bus0_init
  17. mon_bus_lookup
  18. mon_init
  19. mon_exit

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * The USB Monitor, inspired by Dave Harding's USBMon.
   4  *
   5  * mon_main.c: Main file, module initiation and exit, registrations, etc.
   6  *
   7  * Copyright (C) 2005 Pete Zaitcev (zaitcev@redhat.com)
   8  */
   9 
  10 #include <linux/kernel.h>
  11 #include <linux/module.h>
  12 #include <linux/usb.h>
  13 #include <linux/usb/hcd.h>
  14 #include <linux/slab.h>
  15 #include <linux/notifier.h>
  16 #include <linux/mutex.h>
  17 
  18 #include "usb_mon.h"
  19 
  20 
  21 static void mon_stop(struct mon_bus *mbus);
  22 static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus);
  23 static void mon_bus_drop(struct kref *r);
  24 static void mon_bus_init(struct usb_bus *ubus);
  25 
  26 DEFINE_MUTEX(mon_lock);
  27 
  28 struct mon_bus mon_bus0;                /* Pseudo bus meaning "all buses" */
  29 static LIST_HEAD(mon_buses);            /* All buses we know: struct mon_bus */
  30 
  31 /*
  32  * Link a reader into the bus.
  33  *
  34  * This must be called with mon_lock taken because of mbus->ref.
  35  */
  36 void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r)
  37 {
  38         unsigned long flags;
  39         struct list_head *p;
  40 
  41         spin_lock_irqsave(&mbus->lock, flags);
  42         if (mbus->nreaders == 0) {
  43                 if (mbus == &mon_bus0) {
  44                         list_for_each (p, &mon_buses) {
  45                                 struct mon_bus *m1;
  46                                 m1 = list_entry(p, struct mon_bus, bus_link);
  47                                 m1->u_bus->monitored = 1;
  48                         }
  49                 } else {
  50                         mbus->u_bus->monitored = 1;
  51                 }
  52         }
  53         mbus->nreaders++;
  54         list_add_tail(&r->r_link, &mbus->r_list);
  55         spin_unlock_irqrestore(&mbus->lock, flags);
  56 
  57         kref_get(&mbus->ref);
  58 }
  59 
  60 /*
  61  * Unlink reader from the bus.
  62  *
  63  * This is called with mon_lock taken, so we can decrement mbus->ref.
  64  */
  65 void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r)
  66 {
  67         unsigned long flags;
  68 
  69         spin_lock_irqsave(&mbus->lock, flags);
  70         list_del(&r->r_link);
  71         --mbus->nreaders;
  72         if (mbus->nreaders == 0)
  73                 mon_stop(mbus);
  74         spin_unlock_irqrestore(&mbus->lock, flags);
  75 
  76         kref_put(&mbus->ref, mon_bus_drop);
  77 }
  78 
  79 /*
  80  */
  81 static void mon_bus_submit(struct mon_bus *mbus, struct urb *urb)
  82 {
  83         unsigned long flags;
  84         struct list_head *pos;
  85         struct mon_reader *r;
  86 
  87         spin_lock_irqsave(&mbus->lock, flags);
  88         mbus->cnt_events++;
  89         list_for_each (pos, &mbus->r_list) {
  90                 r = list_entry(pos, struct mon_reader, r_link);
  91                 r->rnf_submit(r->r_data, urb);
  92         }
  93         spin_unlock_irqrestore(&mbus->lock, flags);
  94 }
  95 
  96 static void mon_submit(struct usb_bus *ubus, struct urb *urb)
  97 {
  98         struct mon_bus *mbus;
  99 
 100         mbus = ubus->mon_bus;
 101         if (mbus != NULL)
 102                 mon_bus_submit(mbus, urb);
 103         mon_bus_submit(&mon_bus0, urb);
 104 }
 105 
 106 /*
 107  */
 108 static void mon_bus_submit_error(struct mon_bus *mbus, struct urb *urb, int error)
 109 {
 110         unsigned long flags;
 111         struct list_head *pos;
 112         struct mon_reader *r;
 113 
 114         spin_lock_irqsave(&mbus->lock, flags);
 115         mbus->cnt_events++;
 116         list_for_each (pos, &mbus->r_list) {
 117                 r = list_entry(pos, struct mon_reader, r_link);
 118                 r->rnf_error(r->r_data, urb, error);
 119         }
 120         spin_unlock_irqrestore(&mbus->lock, flags);
 121 }
 122 
 123 static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error)
 124 {
 125         struct mon_bus *mbus;
 126 
 127         mbus = ubus->mon_bus;
 128         if (mbus != NULL)
 129                 mon_bus_submit_error(mbus, urb, error);
 130         mon_bus_submit_error(&mon_bus0, urb, error);
 131 }
 132 
 133 /*
 134  */
 135 static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb, int status)
 136 {
 137         unsigned long flags;
 138         struct list_head *pos;
 139         struct mon_reader *r;
 140 
 141         spin_lock_irqsave(&mbus->lock, flags);
 142         mbus->cnt_events++;
 143         list_for_each (pos, &mbus->r_list) {
 144                 r = list_entry(pos, struct mon_reader, r_link);
 145                 r->rnf_complete(r->r_data, urb, status);
 146         }
 147         spin_unlock_irqrestore(&mbus->lock, flags);
 148 }
 149 
 150 static void mon_complete(struct usb_bus *ubus, struct urb *urb, int status)
 151 {
 152         struct mon_bus *mbus;
 153 
 154         mbus = ubus->mon_bus;
 155         if (mbus != NULL)
 156                 mon_bus_complete(mbus, urb, status);
 157         mon_bus_complete(&mon_bus0, urb, status);
 158 }
 159 
 160 /* int (*unlink_urb) (struct urb *urb, int status); */
 161 
 162 /*
 163  * Stop monitoring.
 164  */
 165 static void mon_stop(struct mon_bus *mbus)
 166 {
 167         struct usb_bus *ubus;
 168         struct list_head *p;
 169 
 170         if (mbus == &mon_bus0) {
 171                 list_for_each (p, &mon_buses) {
 172                         mbus = list_entry(p, struct mon_bus, bus_link);
 173                         /*
 174                          * We do not change nreaders here, so rely on mon_lock.
 175                          */
 176                         if (mbus->nreaders == 0 && (ubus = mbus->u_bus) != NULL)
 177                                 ubus->monitored = 0;
 178                 }
 179         } else {
 180                 /*
 181                  * A stop can be called for a dissolved mon_bus in case of
 182                  * a reader staying across an rmmod foo_hcd, so test ->u_bus.
 183                  */
 184                 if (mon_bus0.nreaders == 0 && (ubus = mbus->u_bus) != NULL) {
 185                         ubus->monitored = 0;
 186                         mb();
 187                 }
 188         }
 189 }
 190 
 191 /*
 192  * Add a USB bus (usually by a modprobe foo-hcd)
 193  *
 194  * This does not return an error code because the core cannot care less
 195  * if monitoring is not established.
 196  */
 197 static void mon_bus_add(struct usb_bus *ubus)
 198 {
 199         mon_bus_init(ubus);
 200         mutex_lock(&mon_lock);
 201         if (mon_bus0.nreaders != 0)
 202                 ubus->monitored = 1;
 203         mutex_unlock(&mon_lock);
 204 }
 205 
 206 /*
 207  * Remove a USB bus (either from rmmod foo-hcd or from a hot-remove event).
 208  */
 209 static void mon_bus_remove(struct usb_bus *ubus)
 210 {
 211         struct mon_bus *mbus = ubus->mon_bus;
 212 
 213         mutex_lock(&mon_lock);
 214         list_del(&mbus->bus_link);
 215         if (mbus->text_inited)
 216                 mon_text_del(mbus);
 217         if (mbus->bin_inited)
 218                 mon_bin_del(mbus);
 219 
 220         mon_dissolve(mbus, ubus);
 221         kref_put(&mbus->ref, mon_bus_drop);
 222         mutex_unlock(&mon_lock);
 223 }
 224 
 225 static int mon_notify(struct notifier_block *self, unsigned long action,
 226                       void *dev)
 227 {
 228         switch (action) {
 229         case USB_BUS_ADD:
 230                 mon_bus_add(dev);
 231                 break;
 232         case USB_BUS_REMOVE:
 233                 mon_bus_remove(dev);
 234         }
 235         return NOTIFY_OK;
 236 }
 237 
 238 static struct notifier_block mon_nb = {
 239         .notifier_call =        mon_notify,
 240 };
 241 
 242 /*
 243  * Ops
 244  */
 245 static const struct usb_mon_operations mon_ops_0 = {
 246         .urb_submit =   mon_submit,
 247         .urb_submit_error = mon_submit_error,
 248         .urb_complete = mon_complete,
 249 };
 250 
 251 /*
 252  * Tear usb_bus and mon_bus apart.
 253  */
 254 static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus)
 255 {
 256 
 257         if (ubus->monitored) {
 258                 ubus->monitored = 0;
 259                 mb();
 260         }
 261 
 262         ubus->mon_bus = NULL;
 263         mbus->u_bus = NULL;
 264         mb();
 265 
 266         /* We want synchronize_irq() here, but that needs an argument. */
 267 }
 268 
 269 /*
 270  */
 271 static void mon_bus_drop(struct kref *r)
 272 {
 273         struct mon_bus *mbus = container_of(r, struct mon_bus, ref);
 274         kfree(mbus);
 275 }
 276 
 277 /*
 278  * Initialize a bus for us:
 279  *  - allocate mon_bus
 280  *  - refcount USB bus struct
 281  *  - link
 282  */
 283 static void mon_bus_init(struct usb_bus *ubus)
 284 {
 285         struct mon_bus *mbus;
 286 
 287         mbus = kzalloc(sizeof(struct mon_bus), GFP_KERNEL);
 288         if (mbus == NULL)
 289                 goto err_alloc;
 290         kref_init(&mbus->ref);
 291         spin_lock_init(&mbus->lock);
 292         INIT_LIST_HEAD(&mbus->r_list);
 293 
 294         /*
 295          * We don't need to take a reference to ubus, because we receive
 296          * a notification if the bus is about to be removed.
 297          */
 298         mbus->u_bus = ubus;
 299         ubus->mon_bus = mbus;
 300 
 301         mbus->text_inited = mon_text_add(mbus, ubus);
 302         mbus->bin_inited = mon_bin_add(mbus, ubus);
 303 
 304         mutex_lock(&mon_lock);
 305         list_add_tail(&mbus->bus_link, &mon_buses);
 306         mutex_unlock(&mon_lock);
 307         return;
 308 
 309 err_alloc:
 310         return;
 311 }
 312 
 313 static void mon_bus0_init(void)
 314 {
 315         struct mon_bus *mbus = &mon_bus0;
 316 
 317         kref_init(&mbus->ref);
 318         spin_lock_init(&mbus->lock);
 319         INIT_LIST_HEAD(&mbus->r_list);
 320 
 321         mbus->text_inited = mon_text_add(mbus, NULL);
 322         mbus->bin_inited = mon_bin_add(mbus, NULL);
 323 }
 324 
 325 /*
 326  * Search a USB bus by number. Notice that USB bus numbers start from one,
 327  * which we may later use to identify "all" with zero.
 328  *
 329  * This function must be called with mon_lock held.
 330  *
 331  * This is obviously inefficient and may be revised in the future.
 332  */
 333 struct mon_bus *mon_bus_lookup(unsigned int num)
 334 {
 335         struct list_head *p;
 336         struct mon_bus *mbus;
 337 
 338         if (num == 0) {
 339                 return &mon_bus0;
 340         }
 341         list_for_each (p, &mon_buses) {
 342                 mbus = list_entry(p, struct mon_bus, bus_link);
 343                 if (mbus->u_bus->busnum == num) {
 344                         return mbus;
 345                 }
 346         }
 347         return NULL;
 348 }
 349 
 350 static int __init mon_init(void)
 351 {
 352         struct usb_bus *ubus;
 353         int rc, id;
 354 
 355         if ((rc = mon_text_init()) != 0)
 356                 goto err_text;
 357         if ((rc = mon_bin_init()) != 0)
 358                 goto err_bin;
 359 
 360         mon_bus0_init();
 361 
 362         if (usb_mon_register(&mon_ops_0) != 0) {
 363                 printk(KERN_NOTICE TAG ": unable to register with the core\n");
 364                 rc = -ENODEV;
 365                 goto err_reg;
 366         }
 367         // MOD_INC_USE_COUNT(which_module?);
 368 
 369         mutex_lock(&usb_bus_idr_lock);
 370         idr_for_each_entry(&usb_bus_idr, ubus, id)
 371                 mon_bus_init(ubus);
 372         usb_register_notify(&mon_nb);
 373         mutex_unlock(&usb_bus_idr_lock);
 374         return 0;
 375 
 376 err_reg:
 377         mon_bin_exit();
 378 err_bin:
 379         mon_text_exit();
 380 err_text:
 381         return rc;
 382 }
 383 
 384 static void __exit mon_exit(void)
 385 {
 386         struct mon_bus *mbus;
 387         struct list_head *p;
 388 
 389         usb_unregister_notify(&mon_nb);
 390         usb_mon_deregister();
 391 
 392         mutex_lock(&mon_lock);
 393 
 394         while (!list_empty(&mon_buses)) {
 395                 p = mon_buses.next;
 396                 mbus = list_entry(p, struct mon_bus, bus_link);
 397                 list_del(p);
 398 
 399                 if (mbus->text_inited)
 400                         mon_text_del(mbus);
 401                 if (mbus->bin_inited)
 402                         mon_bin_del(mbus);
 403 
 404                 /*
 405                  * This never happens, because the open/close paths in
 406                  * file level maintain module use counters and so rmmod fails
 407                  * before reaching here. However, better be safe...
 408                  */
 409                 if (mbus->nreaders) {
 410                         printk(KERN_ERR TAG
 411                             ": Outstanding opens (%d) on usb%d, leaking...\n",
 412                             mbus->nreaders, mbus->u_bus->busnum);
 413                         kref_get(&mbus->ref); /* Force leak */
 414                 }
 415 
 416                 mon_dissolve(mbus, mbus->u_bus);
 417                 kref_put(&mbus->ref, mon_bus_drop);
 418         }
 419 
 420         mbus = &mon_bus0;
 421         if (mbus->text_inited)
 422                 mon_text_del(mbus);
 423         if (mbus->bin_inited)
 424                 mon_bin_del(mbus);
 425 
 426         mutex_unlock(&mon_lock);
 427 
 428         mon_text_exit();
 429         mon_bin_exit();
 430 }
 431 
 432 module_init(mon_init);
 433 module_exit(mon_exit);
 434 
 435 MODULE_LICENSE("GPL");

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