seos_l2cap.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. #include "seos_l2cap_i.h"
  2. #define TAG "SeosL2Cap"
  3. #define ACL_START_NO_FLUSH 0x00
  4. #define ACL_CONT 0x01
  5. #define ACL_START 0x02
  6. #define CID_ATT 0x0004
  7. #define CID_LE_SIGNAL 0x0005
  8. // 5.4.2. HCI ACL Data packets
  9. #define SEOS_MAX_ACLDATA_SEND_LENGTH 23
  10. struct l2cap_header {
  11. uint16_t payload_len;
  12. uint16_t cid;
  13. } __packed;
  14. SeosL2Cap* seos_l2cap_alloc(Seos* seos) {
  15. SeosL2Cap* seos_l2cap = malloc(sizeof(SeosL2Cap));
  16. memset(seos_l2cap, 0, sizeof(SeosL2Cap));
  17. // TODO: match MTU
  18. seos_l2cap->tx_accumulator = bit_buffer_alloc(256);
  19. seos_l2cap->rx_accumulator = bit_buffer_alloc(256);
  20. seos_l2cap->seos = seos;
  21. seos_l2cap->seos_hci = seos_hci_alloc(seos);
  22. // Callback to lower level services to call this one
  23. seos_hci_set_receive_callback(seos_l2cap->seos_hci, seos_l2cap_recv, seos_l2cap);
  24. seos_hci_set_completed_packets_callback(
  25. seos_l2cap->seos_hci, seos_l2cap_send_next_chunk, seos_l2cap);
  26. seos_hci_set_central_connection_callback(
  27. seos_l2cap->seos_hci, seos_l2cap_central_connection, seos_l2cap);
  28. return seos_l2cap;
  29. }
  30. void seos_l2cap_free(SeosL2Cap* seos_l2cap) {
  31. furi_assert(seos_l2cap);
  32. bit_buffer_free(seos_l2cap->tx_accumulator);
  33. bit_buffer_free(seos_l2cap->rx_accumulator);
  34. seos_hci_free(seos_l2cap->seos_hci);
  35. free(seos_l2cap);
  36. }
  37. void seos_l2cap_start(SeosL2Cap* seos_l2cap, BleMode mode, FlowMode flow_mode) {
  38. seos_hci_start(seos_l2cap->seos_hci, mode, flow_mode);
  39. }
  40. void seos_l2cap_stop(SeosL2Cap* seos_l2cap) {
  41. seos_hci_stop(seos_l2cap->seos_hci);
  42. }
  43. void seos_l2cap_recv(void* context, uint16_t handle, uint8_t flags, BitBuffer* pdu) {
  44. SeosL2Cap* seos_l2cap = (SeosL2Cap*)context;
  45. seos_l2cap->handle = handle;
  46. // seos_log_bitbuffer(TAG, "recv", pdu);
  47. // uint8_t Broadcast_Flag = flags >> 2;
  48. uint8_t Packet_Boundary_Flag = flags & 0x03;
  49. const uint8_t* data = bit_buffer_get_data(pdu);
  50. struct l2cap_header* header = (struct l2cap_header*)(data);
  51. switch(Packet_Boundary_Flag) {
  52. case ACL_CONT:
  53. if(bit_buffer_get_size_bytes(seos_l2cap->rx_accumulator) == 0) {
  54. FURI_LOG_I(TAG, "Request to att continue when no previous data received");
  55. seos_log_bitbuffer(TAG, "cont", pdu);
  56. return;
  57. }
  58. // No header this time
  59. bit_buffer_append_bytes(seos_l2cap->rx_accumulator, data, bit_buffer_get_size_bytes(pdu));
  60. // Check for overage
  61. if(bit_buffer_get_size_bytes(seos_l2cap->rx_accumulator) > seos_l2cap->pdu_len) {
  62. FURI_LOG_W(
  63. TAG,
  64. "Oh shit, too much data: %d > %d",
  65. bit_buffer_get_size_bytes(seos_l2cap->rx_accumulator),
  66. seos_l2cap->pdu_len);
  67. seos_log_bitbuffer(TAG, "cont", seos_l2cap->rx_accumulator);
  68. }
  69. // Full PDU
  70. if(bit_buffer_get_size_bytes(seos_l2cap->rx_accumulator) == seos_l2cap->pdu_len) {
  71. // FURI_LOG_I(TAG, "Complete reassembled PDU");
  72. // When we've accumulated, we've skipped copying the header, so we can pass the accumulator directly in.
  73. if(seos_l2cap->receive_callback) {
  74. seos_l2cap->receive_callback(
  75. seos_l2cap->receive_callback_context, seos_l2cap->rx_accumulator);
  76. }
  77. }
  78. break;
  79. case ACL_START:
  80. case ACL_START_NO_FLUSH:
  81. uint16_t payload_len = header->payload_len;
  82. uint16_t cid = header->cid;
  83. if(bit_buffer_get_size_bytes(pdu) < header->payload_len) {
  84. // FURI_LOG_W(TAG, "Incomplete PDU");
  85. seos_l2cap->pdu_len = payload_len;
  86. bit_buffer_reset(seos_l2cap->rx_accumulator);
  87. bit_buffer_append_bytes(
  88. seos_l2cap->rx_accumulator,
  89. data + sizeof(struct l2cap_header),
  90. bit_buffer_get_size_bytes(pdu) - sizeof(struct l2cap_header));
  91. return;
  92. }
  93. if(cid == CID_ATT) {
  94. BitBuffer* payload = bit_buffer_alloc(payload_len);
  95. bit_buffer_append_bytes(payload, data + sizeof(struct l2cap_header), payload_len);
  96. if(seos_l2cap->receive_callback) {
  97. seos_l2cap->receive_callback(seos_l2cap->receive_callback_context, payload);
  98. }
  99. bit_buffer_free(payload);
  100. } else if(cid == CID_LE_SIGNAL) {
  101. seos_log_bitbuffer(TAG, "LE Signal", pdu);
  102. } else {
  103. FURI_LOG_W(TAG, "Unhandled CID: %d", cid);
  104. }
  105. break;
  106. default:
  107. FURI_LOG_W(TAG, "unhandled Packet_Boundary_Flag %d", Packet_Boundary_Flag);
  108. break;
  109. }
  110. }
  111. void seos_l2cap_central_connection(void* context) {
  112. SeosL2Cap* seos_l2cap = (SeosL2Cap*)context;
  113. if(seos_l2cap->central_connection_callback) {
  114. seos_l2cap->central_connection_callback(seos_l2cap->central_connection_context);
  115. }
  116. }
  117. void seos_l2cap_send_chunk(void* context) {
  118. SeosL2Cap* seos_l2cap = (SeosL2Cap*)context;
  119. // FURI_LOG_D(TAG, "seos_l2cap_send_chunk");
  120. uint16_t cid = CID_ATT;
  121. uint8_t Packet_Boundary_Flag = 0x00;
  122. bool continuation = bit_buffer_get_size_bytes(seos_l2cap->tx_accumulator) <
  123. seos_l2cap->pdu_len;
  124. if(continuation) {
  125. Packet_Boundary_Flag = 0x01;
  126. }
  127. uint16_t tx_len =
  128. MIN((size_t)SEOS_MAX_ACLDATA_SEND_LENGTH,
  129. bit_buffer_get_size_bytes(seos_l2cap->tx_accumulator));
  130. if(tx_len == 0) {
  131. seos_l2cap->pdu_len = 0;
  132. return;
  133. }
  134. BitBuffer* response = bit_buffer_alloc(tx_len + sizeof(cid) + sizeof(tx_len));
  135. if(!continuation) {
  136. //pdu length
  137. bit_buffer_append_bytes(
  138. response, (uint8_t*)&seos_l2cap->pdu_len, sizeof(seos_l2cap->pdu_len));
  139. // cid
  140. bit_buffer_append_bytes(response, (uint8_t*)&cid, sizeof(cid));
  141. }
  142. // tx
  143. bit_buffer_append_bytes(response, bit_buffer_get_data(seos_l2cap->tx_accumulator), tx_len);
  144. FURI_LOG_D(TAG, "send_chunk: %d/%d bytes", tx_len, seos_l2cap->pdu_len);
  145. seos_hci_acldata_send(seos_l2cap->seos_hci, Packet_Boundary_Flag, response);
  146. bit_buffer_free(response);
  147. // trim off send bytes
  148. int new_len = bit_buffer_get_size_bytes(seos_l2cap->tx_accumulator) - tx_len;
  149. if(new_len <= 0) {
  150. bit_buffer_reset(seos_l2cap->tx_accumulator);
  151. seos_l2cap->pdu_len = 0;
  152. // FURI_LOG_D(TAG, "TX accumulator empty");
  153. return;
  154. }
  155. BitBuffer* tmp = bit_buffer_alloc(new_len);
  156. bit_buffer_append_bytes(
  157. tmp, bit_buffer_get_data(seos_l2cap->tx_accumulator) + tx_len, new_len);
  158. bit_buffer_reset(seos_l2cap->tx_accumulator);
  159. bit_buffer_append_bytes(
  160. seos_l2cap->tx_accumulator, bit_buffer_get_data(tmp), bit_buffer_get_size_bytes(tmp));
  161. bit_buffer_free(tmp);
  162. // FURI_LOG_D(TAG, "tx accumulator length = %d", bit_buffer_get_size_bytes(seos_l2cap->tx_accumulator));
  163. }
  164. void seos_l2cap_send(SeosL2Cap* seos_l2cap, BitBuffer* content) {
  165. // seos_log_buffer("seos_l2cap_send", content);
  166. if(bit_buffer_get_size_bytes(seos_l2cap->tx_accumulator) > 0) {
  167. FURI_LOG_W(TAG, "Failed to add message to L2CAP accumulator: it isn't empty");
  168. return;
  169. }
  170. bit_buffer_append_bytes(
  171. seos_l2cap->tx_accumulator,
  172. bit_buffer_get_data(content),
  173. bit_buffer_get_size_bytes(content));
  174. seos_l2cap->pdu_len = bit_buffer_get_size_bytes(content);
  175. seos_l2cap_send_chunk(seos_l2cap);
  176. }
  177. void seos_l2cap_send_next_chunk(void* context) {
  178. SeosL2Cap* seos_l2cap = (SeosL2Cap*)context;
  179. if(bit_buffer_get_size_bytes(seos_l2cap->tx_accumulator) > 0) {
  180. seos_l2cap_send_chunk(seos_l2cap);
  181. }
  182. }
  183. void seos_l2cap_set_receive_callback(
  184. SeosL2Cap* seos_l2cap,
  185. SeosL2CapReceiveCallback callback,
  186. void* context) {
  187. seos_l2cap->receive_callback = callback;
  188. seos_l2cap->receive_callback_context = context;
  189. }
  190. void seos_l2cap_set_central_connection_callback(
  191. SeosL2Cap* seos_l2cap,
  192. SeosL2CapCentralConnectionCallback callback,
  193. void* context) {
  194. seos_l2cap->central_connection_callback = callback;
  195. seos_l2cap->central_connection_context = context;
  196. }