ccid.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  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. if (ccid->ccid_init == NULL)
  54. return -1;
  55. ccids_write_lock();
  56. err = -EEXIST;
  57. if (ccids[ccid->ccid_id] == NULL) {
  58. ccids[ccid->ccid_id] = ccid;
  59. err = 0;
  60. }
  61. ccids_write_unlock();
  62. if (err == 0)
  63. pr_info("CCID: Registered CCID %d (%s)\n",
  64. ccid->ccid_id, ccid->ccid_name);
  65. return err;
  66. }
  67. EXPORT_SYMBOL_GPL(ccid_register);
  68. int ccid_unregister(struct ccid *ccid)
  69. {
  70. ccids_write_lock();
  71. ccids[ccid->ccid_id] = NULL;
  72. ccids_write_unlock();
  73. pr_info("CCID: Unregistered CCID %d (%s)\n",
  74. ccid->ccid_id, ccid->ccid_name);
  75. return 0;
  76. }
  77. EXPORT_SYMBOL_GPL(ccid_unregister);
  78. struct ccid *ccid_init(unsigned char id, struct sock *sk)
  79. {
  80. struct ccid *ccid;
  81. #ifdef CONFIG_KMOD
  82. if (ccids[id] == NULL)
  83. request_module("net-dccp-ccid-%d", id);
  84. #endif
  85. ccids_read_lock();
  86. ccid = ccids[id];
  87. if (ccid == NULL)
  88. goto out;
  89. if (!try_module_get(ccid->ccid_owner))
  90. goto out_err;
  91. if (ccid->ccid_init(sk) != 0)
  92. goto out_module_put;
  93. out:
  94. ccids_read_unlock();
  95. return ccid;
  96. out_module_put:
  97. module_put(ccid->ccid_owner);
  98. out_err:
  99. ccid = NULL;
  100. goto out;
  101. }
  102. EXPORT_SYMBOL_GPL(ccid_init);
  103. void ccid_exit(struct ccid *ccid, struct sock *sk)
  104. {
  105. if (ccid == NULL)
  106. return;
  107. ccids_read_lock();
  108. if (ccids[ccid->ccid_id] != NULL) {
  109. if (ccid->ccid_exit != NULL)
  110. ccid->ccid_exit(sk);
  111. module_put(ccid->ccid_owner);
  112. }
  113. ccids_read_unlock();
  114. }
  115. EXPORT_SYMBOL_GPL(ccid_exit);