capilib.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include <linux/slab.h>
  3. #include <linux/kernel.h>
  4. #include <linux/module.h>
  5. #include <linux/isdn/capilli.h>
  6. #define DBG(format, arg...) do { \
  7. printk(KERN_DEBUG "%s: " format "\n" , __func__ , ## arg); \
  8. } while (0)
  9. struct capilib_msgidqueue {
  10. struct capilib_msgidqueue *next;
  11. u16 msgid;
  12. };
  13. struct capilib_ncci {
  14. struct list_head list;
  15. u16 applid;
  16. u32 ncci;
  17. u32 winsize;
  18. int nmsg;
  19. struct capilib_msgidqueue *msgidqueue;
  20. struct capilib_msgidqueue *msgidlast;
  21. struct capilib_msgidqueue *msgidfree;
  22. struct capilib_msgidqueue msgidpool[CAPI_MAXDATAWINDOW];
  23. };
  24. // ---------------------------------------------------------------------------
  25. // NCCI Handling
  26. static inline void mq_init(struct capilib_ncci *np)
  27. {
  28. u_int i;
  29. np->msgidqueue = NULL;
  30. np->msgidlast = NULL;
  31. np->nmsg = 0;
  32. memset(np->msgidpool, 0, sizeof(np->msgidpool));
  33. np->msgidfree = &np->msgidpool[0];
  34. for (i = 1; i < np->winsize; i++) {
  35. np->msgidpool[i].next = np->msgidfree;
  36. np->msgidfree = &np->msgidpool[i];
  37. }
  38. }
  39. static inline int mq_enqueue(struct capilib_ncci *np, u16 msgid)
  40. {
  41. struct capilib_msgidqueue *mq;
  42. if ((mq = np->msgidfree) == NULL)
  43. return 0;
  44. np->msgidfree = mq->next;
  45. mq->msgid = msgid;
  46. mq->next = NULL;
  47. if (np->msgidlast)
  48. np->msgidlast->next = mq;
  49. np->msgidlast = mq;
  50. if (!np->msgidqueue)
  51. np->msgidqueue = mq;
  52. np->nmsg++;
  53. return 1;
  54. }
  55. static inline int mq_dequeue(struct capilib_ncci *np, u16 msgid)
  56. {
  57. struct capilib_msgidqueue **pp;
  58. for (pp = &np->msgidqueue; *pp; pp = &(*pp)->next) {
  59. if ((*pp)->msgid == msgid) {
  60. struct capilib_msgidqueue *mq = *pp;
  61. *pp = mq->next;
  62. if (mq == np->msgidlast)
  63. np->msgidlast = NULL;
  64. mq->next = np->msgidfree;
  65. np->msgidfree = mq;
  66. np->nmsg--;
  67. return 1;
  68. }
  69. }
  70. return 0;
  71. }
  72. void capilib_new_ncci(struct list_head *head, u16 applid, u32 ncci, u32 winsize)
  73. {
  74. struct capilib_ncci *np;
  75. np = kmalloc(sizeof(*np), GFP_ATOMIC);
  76. if (!np) {
  77. printk(KERN_WARNING "capilib_new_ncci: no memory.\n");
  78. return;
  79. }
  80. if (winsize > CAPI_MAXDATAWINDOW) {
  81. printk(KERN_ERR "capi_new_ncci: winsize %d too big\n",
  82. winsize);
  83. winsize = CAPI_MAXDATAWINDOW;
  84. }
  85. np->applid = applid;
  86. np->ncci = ncci;
  87. np->winsize = winsize;
  88. mq_init(np);
  89. list_add_tail(&np->list, head);
  90. DBG("kcapi: appl %d ncci 0x%x up", applid, ncci);
  91. }
  92. EXPORT_SYMBOL(capilib_new_ncci);
  93. void capilib_free_ncci(struct list_head *head, u16 applid, u32 ncci)
  94. {
  95. struct list_head *l;
  96. struct capilib_ncci *np;
  97. list_for_each(l, head) {
  98. np = list_entry(l, struct capilib_ncci, list);
  99. if (np->applid != applid)
  100. continue;
  101. if (np->ncci != ncci)
  102. continue;
  103. printk(KERN_INFO "kcapi: appl %d ncci 0x%x down\n", applid, ncci);
  104. list_del(&np->list);
  105. kfree(np);
  106. return;
  107. }
  108. printk(KERN_ERR "capilib_free_ncci: ncci 0x%x not found\n", ncci);
  109. }
  110. EXPORT_SYMBOL(capilib_free_ncci);
  111. void capilib_release_appl(struct list_head *head, u16 applid)
  112. {
  113. struct list_head *l, *n;
  114. struct capilib_ncci *np;
  115. list_for_each_safe(l, n, head) {
  116. np = list_entry(l, struct capilib_ncci, list);
  117. if (np->applid != applid)
  118. continue;
  119. printk(KERN_INFO "kcapi: appl %d ncci 0x%x forced down\n", applid, np->ncci);
  120. list_del(&np->list);
  121. kfree(np);
  122. }
  123. }
  124. EXPORT_SYMBOL(capilib_release_appl);
  125. void capilib_release(struct list_head *head)
  126. {
  127. struct list_head *l, *n;
  128. struct capilib_ncci *np;
  129. list_for_each_safe(l, n, head) {
  130. np = list_entry(l, struct capilib_ncci, list);
  131. printk(KERN_INFO "kcapi: appl %d ncci 0x%x forced down\n", np->applid, np->ncci);
  132. list_del(&np->list);
  133. kfree(np);
  134. }
  135. }
  136. EXPORT_SYMBOL(capilib_release);
  137. u16 capilib_data_b3_req(struct list_head *head, u16 applid, u32 ncci, u16 msgid)
  138. {
  139. struct list_head *l;
  140. struct capilib_ncci *np;
  141. list_for_each(l, head) {
  142. np = list_entry(l, struct capilib_ncci, list);
  143. if (np->applid != applid)
  144. continue;
  145. if (np->ncci != ncci)
  146. continue;
  147. if (mq_enqueue(np, msgid) == 0)
  148. return CAPI_SENDQUEUEFULL;
  149. return CAPI_NOERROR;
  150. }
  151. printk(KERN_ERR "capilib_data_b3_req: ncci 0x%x not found\n", ncci);
  152. return CAPI_NOERROR;
  153. }
  154. EXPORT_SYMBOL(capilib_data_b3_req);
  155. void capilib_data_b3_conf(struct list_head *head, u16 applid, u32 ncci, u16 msgid)
  156. {
  157. struct list_head *l;
  158. struct capilib_ncci *np;
  159. list_for_each(l, head) {
  160. np = list_entry(l, struct capilib_ncci, list);
  161. if (np->applid != applid)
  162. continue;
  163. if (np->ncci != ncci)
  164. continue;
  165. if (mq_dequeue(np, msgid) == 0) {
  166. printk(KERN_ERR "kcapi: msgid %hu ncci 0x%x not on queue\n",
  167. msgid, ncci);
  168. }
  169. return;
  170. }
  171. printk(KERN_ERR "capilib_data_b3_conf: ncci 0x%x not found\n", ncci);
  172. }
  173. EXPORT_SYMBOL(capilib_data_b3_conf);