ccid.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. /*
  2. * net/dccp/ccid.c
  3. *
  4. * An implementation of the DCCP protocol
  5. * Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  6. *
  7. * CCID infrastructure
  8. *
  9. * This program is free software; you can redistribute it and/or modify it
  10. * under the terms of the GNU General Public License version 2 as
  11. * published by the Free Software Foundation.
  12. */
  13. #include "ccid.h"
  14. static struct ccid *ccids[CCID_MAX];
  15. #if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
  16. static atomic_t ccids_lockct = ATOMIC_INIT(0);
  17. static DEFINE_SPINLOCK(ccids_lock);
  18. /*
  19. * The strategy is: modifications ccids vector are short, do not sleep and
  20. * veeery rare, but read access should be free of any exclusive locks.
  21. */
  22. static void ccids_write_lock(void)
  23. {
  24. spin_lock(&ccids_lock);
  25. while (atomic_read(&ccids_lockct) != 0) {
  26. spin_unlock(&ccids_lock);
  27. yield();
  28. spin_lock(&ccids_lock);
  29. }
  30. }
  31. static inline void ccids_write_unlock(void)
  32. {
  33. spin_unlock(&ccids_lock);
  34. }
  35. static inline void ccids_read_lock(void)
  36. {
  37. atomic_inc(&ccids_lockct);
  38. spin_unlock_wait(&ccids_lock);
  39. }
  40. static inline void ccids_read_unlock(void)
  41. {
  42. atomic_dec(&ccids_lockct);
  43. }
  44. #else
  45. #define ccids_write_lock() do { } while(0)
  46. #define ccids_write_unlock() do { } while(0)
  47. #define ccids_read_lock() do { } while(0)
  48. #define ccids_read_unlock() do { } while(0)
  49. #endif
  50. int ccid_register(struct ccid *ccid)
  51. {
  52. int err;
  53. ccids_write_lock();
  54. err = -EEXIST;
  55. if (ccids[ccid->ccid_id] == NULL) {
  56. ccids[ccid->ccid_id] = ccid;
  57. err = 0;
  58. }
  59. ccids_write_unlock();
  60. if (err == 0)
  61. pr_info("CCID: Registered CCID %d (%s)\n",
  62. ccid->ccid_id, ccid->ccid_name);
  63. return err;
  64. }
  65. EXPORT_SYMBOL_GPL(ccid_register);
  66. int ccid_unregister(struct ccid *ccid)
  67. {
  68. ccids_write_lock();
  69. ccids[ccid->ccid_id] = NULL;
  70. ccids_write_unlock();
  71. pr_info("CCID: Unregistered CCID %d (%s)\n",
  72. ccid->ccid_id, ccid->ccid_name);
  73. return 0;
  74. }
  75. EXPORT_SYMBOL_GPL(ccid_unregister);
  76. struct ccid *ccid_init(unsigned char id, struct sock *sk)
  77. {
  78. struct ccid *ccid;
  79. #ifdef CONFIG_KMOD
  80. if (ccids[id] == NULL)
  81. request_module("net-dccp-ccid-%d", id);
  82. #endif
  83. ccids_read_lock();
  84. ccid = ccids[id];
  85. if (ccid == NULL)
  86. goto out;
  87. if (!try_module_get(ccid->ccid_owner))
  88. goto out_err;
  89. if (ccid->ccid_init != NULL && ccid->ccid_init(sk) != 0)
  90. goto out_module_put;
  91. out:
  92. ccids_read_unlock();
  93. return ccid;
  94. out_module_put:
  95. module_put(ccid->ccid_owner);
  96. out_err:
  97. ccid = NULL;
  98. goto out;
  99. }
  100. EXPORT_SYMBOL_GPL(ccid_init);
  101. void ccid_exit(struct ccid *ccid, struct sock *sk)
  102. {
  103. if (ccid == NULL)
  104. return;
  105. ccids_read_lock();
  106. if (ccids[ccid->ccid_id] != NULL) {
  107. if (ccid->ccid_exit != NULL)
  108. ccid->ccid_exit(sk);
  109. module_put(ccid->ccid_owner);
  110. }
  111. ccids_read_unlock();
  112. }
  113. EXPORT_SYMBOL_GPL(ccid_exit);