cmtp.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. *
  4. * BlueZ - Bluetooth protocol stack for Linux
  5. *
  6. * Copyright (C) 2002-2011 Marcel Holtmann <marcel@holtmann.org>
  7. *
  8. *
  9. */
  10. #ifdef HAVE_CONFIG_H
  11. #include <config.h>
  12. #endif
  13. #define _GNU_SOURCE
  14. #include <stdio.h>
  15. #include <errno.h>
  16. #include <unistd.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include "parser.h"
  20. #define TABLE_SIZE 10
  21. static struct {
  22. uint16_t handle;
  23. uint16_t cid;
  24. struct frame msg[16];
  25. } table[TABLE_SIZE];
  26. static void add_segment(uint8_t bid, struct frame *frm, int len)
  27. {
  28. uint16_t handle = frm->handle, cid = frm->cid;
  29. struct frame *msg;
  30. void *data;
  31. int i, pos = -1;
  32. if (bid > 15)
  33. return;
  34. for (i = 0; i < TABLE_SIZE; i++) {
  35. if (table[i].handle == handle && table[i].cid == cid) {
  36. pos = i;
  37. break;
  38. }
  39. if (pos < 0 && !table[i].handle && !table[i].cid)
  40. pos = i;
  41. }
  42. if (pos < 0)
  43. return;
  44. table[pos].handle = handle;
  45. table[pos].cid = cid;
  46. msg = &table[pos].msg[bid];
  47. data = malloc(msg->data_len + len);
  48. if (!data)
  49. return;
  50. if (msg->data_len > 0)
  51. memcpy(data, msg->data, msg->data_len);
  52. memcpy(data + msg->data_len, frm->ptr, len);
  53. free(msg->data);
  54. msg->data = data;
  55. msg->data_len += len;
  56. msg->ptr = msg->data;
  57. msg->len = msg->data_len;
  58. msg->in = frm->in;
  59. msg->ts = frm->ts;
  60. msg->handle = handle;
  61. msg->cid = cid;
  62. }
  63. static void free_segment(uint8_t bid, struct frame *frm)
  64. {
  65. uint16_t handle = frm->handle, cid = frm->cid;
  66. struct frame *msg;
  67. int i, len = 0, pos = -1;
  68. if (bid > 15)
  69. return;
  70. for (i = 0; i < TABLE_SIZE; i++)
  71. if (table[i].handle == handle && table[i].cid == cid) {
  72. pos = i;
  73. break;
  74. }
  75. if (pos < 0)
  76. return;
  77. msg = &table[pos].msg[bid];
  78. if (msg->data)
  79. free(msg->data);
  80. msg->data = NULL;
  81. msg->data_len = 0;
  82. for (i = 0; i < 16; i++)
  83. len += table[pos].msg[i].data_len;
  84. if (!len) {
  85. table[pos].handle = 0;
  86. table[pos].cid = 0;
  87. }
  88. }
  89. static struct frame *get_segment(uint8_t bid, struct frame *frm)
  90. {
  91. uint16_t handle = frm->handle, cid = frm->cid;
  92. int i;
  93. if (bid > 15)
  94. return NULL;
  95. for (i = 0; i < TABLE_SIZE; i++)
  96. if (table[i].handle == handle && table[i].cid == cid)
  97. return &table[i].msg[bid];
  98. return NULL;
  99. }
  100. static char *bst2str(uint8_t bst)
  101. {
  102. switch (bst) {
  103. case 0x00:
  104. return "complete CAPI Message";
  105. case 0x01:
  106. return "segmented CAPI Message";
  107. case 0x02:
  108. return "error";
  109. case 0x03:
  110. return "reserved";
  111. default:
  112. return "unknown";
  113. }
  114. }
  115. void cmtp_dump(int level, struct frame *frm)
  116. {
  117. struct frame *msg;
  118. uint8_t hdr, bid;
  119. uint16_t len;
  120. while (frm->len > 0) {
  121. hdr = p_get_u8(frm);
  122. bid = (hdr & 0x3c) >> 2;
  123. switch ((hdr & 0xc0) >> 6) {
  124. case 0x01:
  125. len = p_get_u8(frm);
  126. break;
  127. case 0x02:
  128. len = htons(p_get_u16(frm));
  129. break;
  130. default:
  131. len = 0;
  132. break;
  133. }
  134. p_indent(level, frm);
  135. printf("CMTP: %s: id %d len %d\n", bst2str(hdr & 0x03), bid, len);
  136. switch (hdr & 0x03) {
  137. case 0x00:
  138. add_segment(bid, frm, len);
  139. msg = get_segment(bid, frm);
  140. if (!msg)
  141. break;
  142. if (!p_filter(FILT_CAPI))
  143. capi_dump(level + 1, msg);
  144. else
  145. raw_dump(level, msg);
  146. free_segment(bid, frm);
  147. break;
  148. case 0x01:
  149. add_segment(bid, frm, len);
  150. break;
  151. default:
  152. free_segment(bid, frm);
  153. break;
  154. }
  155. frm->ptr += len;
  156. frm->len -= len;
  157. }
  158. }