1 /*
2 * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <string.h>
8
9 #include "btc_l2cap.h"
10 #include "stack/l2c_api.h"
11 #include "btc/btc_manage.h"
12 #include "btc/btc_task.h"
13 #include "bta/bta_jv_api.h"
14 #include "common/bt_trace.h"
15 #include "osi/allocator.h"
16 #include "esp_l2cap_bt_api.h"
17 #include "osi/list.h"
18 #include "freertos/ringbuf.h"
19 #include "osi/mutex.h"
20 #include "osi/alarm.h"
21 #include <sys/errno.h>
22 #include <sys/lock.h>
23 #include <sys/fcntl.h>
24 #include "esp_vfs.h"
25 #include "esp_vfs_dev.h"
26 #include "stack/port_api.h"
27 #include "freertos/FreeRTOS.h"
28 #include "freertos/event_groups.h"
29 #include "btc_sdp.h"
30
31 #include "btc/btc_task.h"
32 #include "stack/btu.h"
33
34 #if (defined BTC_L2CAP_INCLUDED && BTC_L2CAP_INCLUDED == TRUE)
35
36 #define SLOT_WRITE_BIT(i) (1UL << (i - 1))
37 #define SLOT_CLOSE_BIT(i) (1UL << (i + BTA_JV_MAX_L2C_CONN - 1))
38 #define VFS_WRITE_TIMEOUT (40 * 1000)
39 #define SLOT_TX_QUEUE_SIZE 10
40 #define SLOT_TX_QUEUE_LOW_WM 4
41 #define SLOT_TX_DATA_HIGH_WM (SLOT_TX_QUEUE_SIZE * BTA_JV_DEF_RFC_MTU)
42 #define VFS_CLOSE_TIMEOUT (20 * 1000)
43 #define BTC_L2CAP_ROLE_MASTER 0
44 #define BTC_L2CAP_ROLE_SLAVE 1
45
46 typedef struct {
47 bool peer_fc; /* true if flow control is set based on peer's request */
48 bool user_fc; /* true if flow control is set based on user's request */
49 fixed_queue_t *queue; /* Queue of buffers waiting to be sent */
50 uint32_t data_size; /* Number of data bytes in the queue */
51 } slot_data_t;
52
53 typedef struct {
54 bool connected;
55 bool is_server;
56 bool fix_chan; // unused
57 uint16_t psm;
58 uint8_t serial;
59 uint8_t max_session;
60 uint32_t id;
61 uint32_t handle;
62 int fd;
63 int tx_mtu;
64 uint8_t *write_data;
65 osi_alarm_t *close_alarm;
66 void *alarm_arg;
67 uint8_t role;
68 uint16_t security;
69 esp_bd_addr_t addr;
70 slot_data_t rx;
71 slot_data_t tx;
72 uint8_t service_uuid[16];
73 } l2cap_slot_t;
74
75
76 typedef struct {
77 l2cap_slot_t *l2cap_slots[BTA_JV_MAX_L2C_CONN + 1];
78 uint32_t l2cap_slot_id;
79 osi_mutex_t l2cap_slot_mutex;
80 EventGroupHandle_t tx_event_group;
81 esp_vfs_id_t l2cap_vfs_id;
82 } l2cap_local_param_t;
83
84 static l2cap_local_param_t l2cap_local_param;
85
86 /* L2CAP default options for OBEX connections */
87 static const tL2CAP_FCR_OPTS obex_l2c_fcr_opts_def =
88 {
89 L2CAP_FCR_ERTM_MODE, /* Mandatory for OBEX over l2cap */
90 OBX_FCR_OPT_TX_WINDOW_SIZE_BR_EDR,/* Tx window size */
91 OBX_FCR_OPT_MAX_TX_B4_DISCNT, /* Maximum transmissions before disconnecting */
92 OBX_FCR_OPT_RETX_TOUT, /* Retransmission timeout (2 secs) */
93 OBX_FCR_OPT_MONITOR_TOUT, /* Monitor timeout (12 secs) */
94 OBX_FCR_OPT_MAX_PDU_SIZE /* MPS segment size */
95 };
96 static const tL2CAP_ERTM_INFO obex_l2c_etm_opt =
97 {
98 L2CAP_FCR_ERTM_MODE, /* Mandatory for OBEX over l2cap */
99 L2CAP_FCR_CHAN_OPT_ERTM, /* Mandatory for OBEX over l2cap */
100 OBX_USER_RX_POOL_ID,
101 OBX_USER_TX_POOL_ID,
102 OBX_FCR_RX_POOL_ID,
103 OBX_FCR_TX_POOL_ID
104 };
105
106
107 #if L2CAP_DYNAMIC_MEMORY == FALSE
108 #define is_l2cap_init() (l2cap_local_param.l2cap_slot_mutex != NULL)
109 #else
110 #define is_l2cap_init() (&l2cap_local_param != NULL && l2cap_local_param.l2cap_slot_mutex != NULL)
111 #endif
112
l2cap_osi_free(void * p)113 static void l2cap_osi_free(void *p)
114 {
115 osi_free(p);
116 }
117
l2cap_find_slot_by_handle(uint32_t handle)118 static l2cap_slot_t *l2cap_find_slot_by_handle(uint32_t handle)
119 {
120 l2cap_slot_t *slot = NULL;
121
122 for (size_t i = 1; i <= BTA_JV_MAX_L2C_CONN; i++) {
123 slot = l2cap_local_param.l2cap_slots[i];
124 if (slot != NULL && slot->handle == handle) {
125 return slot;
126 }
127 }
128 return NULL;
129 }
130
l2cap_find_slot_by_id(uint32_t id)131 static l2cap_slot_t *l2cap_find_slot_by_id(uint32_t id)
132 {
133 l2cap_slot_t *slot = NULL;
134
135 for (size_t i = 1; i <= BTA_JV_MAX_L2C_CONN; i++) {
136 slot = l2cap_local_param.l2cap_slots[i];
137 if (slot != NULL && slot->id == id) {
138 return slot;
139 }
140 }
141 return NULL;
142 }
143
l2cap_find_slot_by_fd(int fd)144 static l2cap_slot_t *l2cap_find_slot_by_fd(int fd)
145 {
146 l2cap_slot_t *slot = NULL;
147
148 for (size_t i = 1; i <= BTA_JV_MAX_L2C_CONN; i++) {
149 slot = l2cap_local_param.l2cap_slots[i];
150 if (slot != NULL && slot->fd == fd) {
151 return slot;
152 }
153 }
154 return NULL;
155 }
156
init_slot_data(slot_data_t * slot_data,size_t queue_size)157 static int init_slot_data(slot_data_t *slot_data, size_t queue_size)
158 {
159 memset(slot_data, 0, sizeof(slot_data_t));
160 if ((slot_data->queue = fixed_queue_new(queue_size)) == NULL) {
161 return -1;
162 }
163 slot_data->data_size = 0;
164 return 0;
165 }
166
free_slot_data(slot_data_t * slot_data)167 static void free_slot_data(slot_data_t *slot_data)
168 {
169 fixed_queue_free(slot_data->queue, l2cap_osi_free);
170 slot_data->queue = NULL;
171 }
172
l2cap_malloc_slot(void)173 static l2cap_slot_t *l2cap_malloc_slot(void)
174 {
175 uint8_t err_no = 0;
176 l2cap_slot_t **slot = NULL;
177
178 if (++l2cap_local_param.l2cap_slot_id == 0) {
179 l2cap_local_param.l2cap_slot_id = 1;
180 }
181 for (size_t i = 1; i <= BTA_JV_MAX_L2C_CONN; i++) {
182 slot = &l2cap_local_param.l2cap_slots[i];
183 if ((*slot) == NULL) {
184 if (((*slot) = (l2cap_slot_t *)osi_malloc(sizeof(l2cap_slot_t))) == NULL) {
185 return NULL;
186 }
187 (*slot)->id = l2cap_local_param.l2cap_slot_id;
188 (*slot)->psm = 0;
189 (*slot)->serial = i;
190 (*slot)->handle = 0xffff;
191 (*slot)->fd = -1;
192 (*slot)->connected = false;
193 (*slot)->is_server = false;
194 (*slot)->write_data = NULL;
195 (*slot)->close_alarm = NULL;
196 (*slot)->alarm_arg = NULL;
197 /* clear the old event bits */
198 if (l2cap_local_param.tx_event_group) {
199 xEventGroupClearBits(l2cap_local_param.tx_event_group, SLOT_WRITE_BIT(i) | SLOT_CLOSE_BIT(i));
200 }
201
202 if (init_slot_data(&(*slot)->rx, QUEUE_SIZE_MAX)) {
203 BTC_TRACE_ERROR("%s unable to malloc rx queue!", __func__);
204 err_no = 1;
205 goto err;
206 }
207 if (init_slot_data(&(*slot)->tx, SLOT_TX_QUEUE_SIZE)) {
208 BTC_TRACE_ERROR("%s unable to malloc tx queue!", __func__);
209 err_no = 2;
210 goto err;
211 }
212 if (esp_vfs_register_fd(l2cap_local_param.l2cap_vfs_id, &(*slot)->fd) != ESP_OK) {
213 BTC_TRACE_ERROR("%s unable to register fd!", __func__);
214 err_no = 3;
215 goto err;
216 }
217
218 return (*slot);
219 }
220 }
221
222 return NULL;
223 err:
224 switch (err_no) {
225 case 3:
226 free_slot_data(&(*slot)->tx);
227 case 2:
228 free_slot_data(&(*slot)->rx);
229 case 1:
230 osi_free((*slot));
231 (*slot) = NULL;
232 break;
233 default:
234 break;
235 }
236 return (*slot);
237 }
238
l2cap_free_slot(l2cap_slot_t * slot)239 static void l2cap_free_slot(l2cap_slot_t *slot)
240 {
241 if (!slot) {
242 return;
243 }
244 l2cap_local_param.l2cap_slots[slot->serial] = NULL;
245 esp_vfs_unregister_fd(l2cap_local_param.l2cap_vfs_id, slot->fd);
246 xEventGroupSetBits(l2cap_local_param.tx_event_group, SLOT_CLOSE_BIT(slot->serial));
247 free_slot_data(&slot->tx);
248 free_slot_data(&slot->rx);
249 if (slot->close_alarm) {
250 osi_alarm_free(slot->close_alarm);
251 if (slot->alarm_arg) {
252 osi_free(slot->alarm_arg);
253 slot->alarm_arg = NULL;
254 }
255 }
256 osi_free(slot);
257 }
258
l2cap_free_pending_slots(void)259 static void l2cap_free_pending_slots(void)
260 {
261 l2cap_slot_t *slot = NULL;
262 for (size_t i = 1; i <= BTA_JV_MAX_L2C_CONN; i++) {
263 slot = l2cap_local_param.l2cap_slots[i];
264 if (slot) {
265 BTC_TRACE_WARNING("%s found slot(handle=0x%x) pending to close, close it now!", __func__, slot->handle);
266 l2cap_free_slot(slot);
267 }
268 }
269 }
270
close_timeout_handler(void * arg)271 static void close_timeout_handler(void *arg)
272 {
273 btc_msg_t msg;
274 bt_status_t status;
275 l2cap_slot_t *slot = (l2cap_slot_t *)arg;
276
277 msg.sig = BTC_SIG_API_CB;
278 msg.pid = BTC_PID_L2CAP;
279 msg.act = BTA_JV_L2CAP_CLOSE_EVT;
280
281 status = btc_transfer_context(&msg, slot->alarm_arg, sizeof(tBTA_JV), NULL, NULL);
282
283 if (slot->alarm_arg) {
284 osi_free(slot->alarm_arg);
285 slot->alarm_arg = NULL;
286 }
287
288 if (status != BT_STATUS_SUCCESS) {
289 BTC_TRACE_ERROR("%s btc_transfer_context failed", __func__);
290 }
291 }
292
btc_l2cap_cb_to_app(esp_bt_l2cap_cb_event_t event,esp_bt_l2cap_cb_param_t * param)293 static inline void btc_l2cap_cb_to_app(esp_bt_l2cap_cb_event_t event, esp_bt_l2cap_cb_param_t *param)
294 {
295 esp_bt_l2cap_cb_t btc_l2cap_cb = (esp_bt_l2cap_cb_t)btc_profile_cb_get(BTC_PID_L2CAP);
296 if (btc_l2cap_cb) {
297 btc_l2cap_cb(event, param);
298 }
299 }
300
btc_l2cap_inter_cb(tBTA_JV_EVT event,tBTA_JV * p_data,void * user_data)301 static void *btc_l2cap_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data)
302 {
303 bt_status_t status;
304 btc_msg_t msg;
305 uint32_t id = (uintptr_t)user_data;
306 l2cap_slot_t *slot = NULL;
307
308 switch (event) {
309 case BTA_JV_L2CAP_OPEN_EVT:
310 slot = l2cap_find_slot_by_id(id);
311 if (!slot) {
312 BTC_TRACE_ERROR("%s unable to find L2CAP slot, event:%d!", __func__, event);
313 p_data->l2c_open.status = ESP_BT_L2CAP_NO_CONNECTION;
314 break;
315 }
316 slot->connected = TRUE;
317 slot->handle = p_data->l2c_open.handle;
318 slot->tx_mtu = p_data->l2c_open.tx_mtu;
319 BTA_JvSetPmProfile(p_data->l2c_open.handle, BTA_JV_PM_ID_1, BTA_JV_CONN_OPEN);
320 break;
321 case BTA_JV_L2CAP_START_EVT:
322 slot = l2cap_find_slot_by_id(id);
323 if (!slot) {
324 BTC_TRACE_ERROR("%s unable to find L2CAP slot, event:%d!", __func__, event);
325 p_data->l2c_open.status = ESP_BT_L2CAP_NO_CONNECTION;
326 break;
327 }
328 slot->handle = p_data->l2c_start.handle;
329 break;
330 case BTA_JV_L2CAP_CLOSE_EVT:
331 slot = l2cap_find_slot_by_id(id);
332 if (!slot) {
333 BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
334 p_data->l2c_close.status = ESP_BT_L2CAP_NO_CONNECTION;
335 break;
336 }
337 p_data->l2c_close.status = BTA_JV_SUCCESS;
338 p_data->l2c_close.user_data = (void *)(uintptr_t)slot->id;
339 break;
340 case BTA_JV_L2CAP_CL_INIT_EVT:
341 slot = l2cap_find_slot_by_id(id);
342 if (!slot) {
343 BTC_TRACE_ERROR("%s unable to find L2CAP slot, event:%d!", __func__, event);
344 p_data->l2c_cl_init.status = ESP_BT_L2CAP_FAILURE;
345 break;
346 }
347
348 if (p_data->l2c_cl_init.status == BTA_JV_SUCCESS) {
349 slot->handle = p_data->l2c_cl_init.handle;
350 } else {
351 l2cap_free_slot(slot);
352 }
353 break;
354 case BTA_JV_L2CAP_DATA_IND_EVT:
355 // to do
356 break;
357 case BTA_JV_FREE_SCN_EVT:
358 slot = l2cap_find_slot_by_id(id);
359 if (slot) {
360 l2cap_free_slot(slot);
361 } else {
362 BTC_TRACE_ERROR("%s unable to find L2CAP slot, event:%d!", __func__, event);
363 p_data->free_scn.status = ESP_BT_L2CAP_NO_CONNECTION;
364 }
365 break;
366 default:
367 break;
368 }
369 msg.sig = BTC_SIG_API_CB;
370 msg.pid = BTC_PID_L2CAP;
371 msg.act = event;
372
373 status = btc_transfer_context(&msg, p_data, sizeof(tBTA_JV), NULL, NULL);
374 if (status != BT_STATUS_SUCCESS) {
375 BTC_TRACE_ERROR("%s btc_transfer_context failed\n", __func__);
376 }
377
378 return NULL;
379 }
380
btc_l2cap_dm_inter_cb(tBTA_JV_EVT event,tBTA_JV * p_data,void * user_data)381 static void btc_l2cap_dm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data)
382 {
383 bt_status_t status;
384 btc_msg_t msg;
385
386 switch (event) {
387 default:
388 msg.sig = BTC_SIG_API_CB;
389 msg.pid = BTC_PID_L2CAP;
390 msg.act = event;
391
392 status = btc_transfer_context(&msg, p_data, sizeof(tBTA_JV), NULL, NULL);
393 if (status != BT_STATUS_SUCCESS) {
394 BTC_TRACE_ERROR("%s btc_transfer_context failed\n", __func__);
395 }
396 break;
397 }
398
399 return;
400 }
401
btc_l2cap_init(void)402 static void btc_l2cap_init(void)
403 {
404 esp_bt_l2cap_status_t ret = ESP_BT_L2CAP_SUCCESS;
405 esp_bt_l2cap_cb_param_t param;
406
407 do {
408 if (is_l2cap_init()) {
409 BTC_TRACE_ERROR("%s L2CAP has been initiated, shall uninit first!", __func__);
410 ret = ESP_BT_L2CAP_NEED_DEINIT;
411 break;
412 }
413
414 #if L2CAP_DYNAMIC_MEMORY == TRUE
415 if ((l2cap_local_param_ptr = (l2cap_local_param_t *)osi_malloc(sizeof(l2cap_local_param_t))) == NULL) {
416 BTC_TRACE_ERROR("%s malloc failed\n", __func__);
417 ret = ESP_BT_L2CAP_NO_RESOURCE;
418 break;
419 }
420 memset((void *)l2cap_local_param_ptr, 0, sizeof(l2cap_local_param_t));
421 #endif
422 l2cap_local_param.l2cap_vfs_id = -1;
423
424 if (osi_mutex_new(&l2cap_local_param.l2cap_slot_mutex) != 0) {
425 #if L2CAP_DYNAMIC_MEMORY == TRUE
426 osi_free(l2cap_local_param_ptr);
427 l2cap_local_param_ptr = NULL;
428 #endif
429 BTC_TRACE_ERROR("%s osi_mutex_new failed\n", __func__);
430 ret = ESP_BT_L2CAP_NO_RESOURCE;
431 break;
432 }
433 if ((l2cap_local_param.tx_event_group = xEventGroupCreate()) == NULL) {
434 BTC_TRACE_ERROR("%s create tx_event_group failed\n", __func__);
435 osi_mutex_free(&l2cap_local_param.l2cap_slot_mutex);
436 #if L2CAP_DYNAMIC_MEMORY == TRUE
437 osi_free(l2cap_local_param_ptr);
438 l2cap_local_param_ptr = NULL;
439 #endif
440 ret = ESP_BT_L2CAP_NO_RESOURCE;
441 break;
442 }
443 l2cap_local_param.l2cap_slot_id = 0;
444 ret = BTA_JvEnable((tBTA_JV_DM_CBACK *)btc_l2cap_dm_inter_cb);
445 if (BTA_JV_ALREADY_DONE == ret) {
446 ret = ESP_BT_L2CAP_SUCCESS;
447 param.init.status = ESP_BT_L2CAP_SUCCESS;
448 btc_l2cap_cb_to_app(ESP_BT_L2CAP_INIT_EVT, ¶m);
449 }
450 } while (0);
451
452 if (ret != ESP_BT_L2CAP_SUCCESS) {
453 param.init.status = ret;
454 btc_l2cap_cb_to_app(ESP_BT_L2CAP_INIT_EVT, ¶m);
455 }
456 }
457
btc_l2cap_uninit(void)458 static void btc_l2cap_uninit(void)
459 {
460 esp_bt_l2cap_status_t ret = ESP_BT_L2CAP_SUCCESS;
461
462 do {
463 if (!is_l2cap_init()) {
464 BTC_TRACE_ERROR("%s L2CAP has not been initiated, shall init first!", __func__);
465 ret = ESP_BT_L2CAP_NEED_INIT;
466 break;
467 }
468 osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
469 // first, remove all connection
470 for (size_t i = 1; i <= BTA_JV_MAX_L2C_CONN; i++) {
471 if (l2cap_local_param.l2cap_slots[i] != NULL && !l2cap_local_param.l2cap_slots[i]->is_server) {
472 BTA_JvL2capClose(l2cap_local_param.l2cap_slots[i]->handle, (tBTA_JV_L2CAP_CBACK *)btc_l2cap_inter_cb,
473 (void *)l2cap_local_param.l2cap_slots[i]->id);
474 }
475 }
476 // second, remove all server
477 for (size_t i = 1; i <= BTA_JV_MAX_L2C_CONN; i++) {
478 if (l2cap_local_param.l2cap_slots[i] != NULL && l2cap_local_param.l2cap_slots[i]->is_server) {
479 if (l2cap_local_param.l2cap_slots[i]->handle != 0xffff) {
480 BTA_JvL2capStopServer(l2cap_local_param.l2cap_slots[i]->psm,
481 (void *)l2cap_local_param.l2cap_slots[i]->id);
482 }
483
484 BTA_JvFreeChannel(l2cap_local_param.l2cap_slots[i]->psm, BTA_JV_CONN_TYPE_L2CAP,
485 (tBTA_JV_RFCOMM_CBACK *)btc_l2cap_inter_cb, (void *)l2cap_local_param.l2cap_slots[i]->id);
486 }
487 }
488 BTA_JvDisable((tBTA_JV_L2CAP_CBACK *)btc_l2cap_inter_cb);
489 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
490 } while(0);
491
492 if (ret != ESP_BT_L2CAP_SUCCESS) {
493 esp_bt_l2cap_cb_param_t param;
494 param.uninit.status = ret;
495 btc_l2cap_cb_to_app(ESP_BT_L2CAP_UNINIT_EVT, ¶m);
496 }
497 }
498
btc_l2cap_start_srv(btc_l2cap_args_t * arg)499 static void btc_l2cap_start_srv(btc_l2cap_args_t *arg)
500 {
501 esp_bt_l2cap_status_t ret = ESP_BT_L2CAP_SUCCESS;
502 tL2CAP_CFG_INFO cfg;
503
504 do {
505 if (!is_l2cap_init()) {
506 BTC_TRACE_ERROR("%s L2CAP have not been init\n", __func__);
507 ret = ESP_BT_L2CAP_NEED_INIT;
508 break;
509 }
510 osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
511 l2cap_slot_t *slot = l2cap_malloc_slot();
512 if (!slot) {
513 BTC_TRACE_ERROR("%s unable to malloc L2CAP slot!", __func__);
514 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
515 ret = ESP_BT_L2CAP_NO_RESOURCE;
516 break;
517 }
518 /**
519 * make this slot become a listening slot
520 */
521 slot->is_server = true;
522 slot->security = arg->start_srv.sec_mask;
523 slot->role = BTC_L2CAP_ROLE_SLAVE;
524 slot->psm = arg->start_srv.local_psm;
525
526 /* Setup ETM settings */
527 memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
528 cfg.fcr_present = TRUE;
529 cfg.fcr = obex_l2c_fcr_opts_def;
530 BTA_JvL2capStartServer(slot->security, slot->role, &obex_l2c_etm_opt, slot->psm,
531 L2CAP_MAX_SDU_LENGTH, &cfg, (tBTA_JV_L2CAP_CBACK *)btc_l2cap_inter_cb, (void *)slot->id);
532 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
533 } while(0);
534
535 if (ret != ESP_BT_L2CAP_SUCCESS) {
536 esp_bt_l2cap_cb_param_t param;
537 param.start.status = ret;
538 param.start.handle = 0xffff;
539 param.start.sec_id = 0;
540 btc_l2cap_cb_to_app(ESP_BT_L2CAP_START_EVT, ¶m);
541 }
542 return;
543 }
544
btc_l2cap_stop_srv(btc_l2cap_args_t * arg)545 static void btc_l2cap_stop_srv(btc_l2cap_args_t *arg)
546 {
547 esp_bt_l2cap_status_t ret = ESP_BT_L2CAP_SUCCESS;
548 bool is_remove_all = false;
549 uint8_t i, j, srv_cnt = 0;
550 uint8_t *srv_psm_arr = osi_malloc(BTA_JV_MAX_L2C_CONN);
551
552 if (arg->stop_srv.psm == BTC_L2CAP_INVALID_PSM) {
553 is_remove_all = true;
554 }
555
556 do {
557 if (!is_l2cap_init()) {
558 BTC_TRACE_ERROR("%s L2CAP have not been init\n", __func__);
559 ret = ESP_BT_L2CAP_NEED_INIT;
560 break;
561 }
562 if (srv_psm_arr == NULL) {
563 BTC_TRACE_ERROR("%s malloc srv_psm_arr failed\n", __func__);
564 ret = ESP_BT_L2CAP_NO_RESOURCE;
565 break;
566 }
567
568 osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
569 // [1] find all server
570 for (i = 1; i <= BTA_JV_MAX_L2C_CONN; i++) {
571 if (l2cap_local_param.l2cap_slots[i] != NULL && l2cap_local_param.l2cap_slots[i]->is_server &&
572 l2cap_local_param.l2cap_slots[i]->handle != 0xffff) {
573 if (is_remove_all) {
574 srv_psm_arr[srv_cnt++] = l2cap_local_param.l2cap_slots[i]->psm;
575 } else if (l2cap_local_param.l2cap_slots[i]->psm == arg->stop_srv.psm) {
576 srv_psm_arr[srv_cnt++] = l2cap_local_param.l2cap_slots[i]->psm;
577 break;
578 }
579 }
580 }
581 if (srv_cnt == 0) {
582 if (is_remove_all) {
583 BTC_TRACE_ERROR("%s can not find any server!\n", __func__);
584 } else {
585 BTC_TRACE_ERROR("%s can not find server:%d!\n", __func__, arg->stop_srv.psm);
586 }
587 ret = ESP_BT_L2CAP_NO_SERVER;
588 break;
589 }
590
591 // [2] remove all local related connection
592 for (j = 0; j < srv_cnt; j++) {
593 for (i = 1; i <= BTA_JV_MAX_L2C_CONN; i++) {
594 if (l2cap_local_param.l2cap_slots[i] != NULL && l2cap_local_param.l2cap_slots[i]->connected &&
595 l2cap_local_param.l2cap_slots[i]->handle != 0xffff &&
596 l2cap_local_param.l2cap_slots[i]->psm == srv_psm_arr[j]) {
597 BTA_JvL2capClose(l2cap_local_param.l2cap_slots[i]->handle, (tBTA_JV_L2CAP_CBACK *)btc_l2cap_inter_cb,
598 (void *)l2cap_local_param.l2cap_slots[i]->id);
599 }
600 }
601 }
602
603 // [3] remove all server
604 for (j = 0; j < srv_cnt; j++) {
605 for (i = 1; i <= BTA_JV_MAX_L2C_CONN; i++) {
606 if (l2cap_local_param.l2cap_slots[i] != NULL && l2cap_local_param.l2cap_slots[i]->is_server &&
607 l2cap_local_param.l2cap_slots[i]->handle != 0xffff &&
608 l2cap_local_param.l2cap_slots[i]->psm == srv_psm_arr[j]) {
609
610 if (l2cap_local_param.l2cap_slots[i]->handle > 0) {
611 BTA_JvL2capStopServer(l2cap_local_param.l2cap_slots[i]->psm,
612 (void *)l2cap_local_param.l2cap_slots[i]->id);
613 }
614
615 BTA_JvFreeChannel(l2cap_local_param.l2cap_slots[i]->psm, BTA_JV_CONN_TYPE_L2CAP,
616 (tBTA_JV_RFCOMM_CBACK *)btc_l2cap_inter_cb, (void *)l2cap_local_param.l2cap_slots[i]->id);
617 }
618 }
619 }
620 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
621 } while (0);
622
623 if (ret != ESP_BT_L2CAP_SUCCESS) {
624 esp_bt_l2cap_cb_param_t param;
625 param.srv_stop.status = ret;
626 param.srv_stop.psm = BTC_L2CAP_INVALID_PSM;
627 btc_l2cap_cb_to_app(ESP_BT_L2CAP_SRV_STOP_EVT, ¶m);
628 }
629
630 if (srv_psm_arr) {
631 osi_free(srv_psm_arr);
632 srv_psm_arr = NULL;
633 }
634 }
635
btc_l2cap_connect(btc_l2cap_args_t * arg)636 static void btc_l2cap_connect(btc_l2cap_args_t *arg)
637 {
638 esp_bt_l2cap_status_t ret = ESP_BT_L2CAP_SUCCESS;
639 tL2CAP_CFG_INFO cfg;
640
641 do {
642 if (!is_l2cap_init()) {
643 BTC_TRACE_ERROR("%s L2CAP have not been init\n", __func__);
644 ret = ESP_BT_L2CAP_NEED_INIT;
645 break;
646 }
647 osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
648 l2cap_slot_t *slot = l2cap_malloc_slot();
649 if (!slot) {
650 BTC_TRACE_ERROR("%s unable to malloc L2CAP slot!", __func__);
651 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
652 ret = ESP_BT_L2CAP_NO_RESOURCE;
653 break;
654 }
655
656 slot->security = arg->connect.sec_mask;
657 slot->role = BTC_L2CAP_ROLE_MASTER;
658 slot->psm = arg->connect.remote_psm;
659 memcpy(slot->addr, arg->connect.peer_bd_addr, ESP_BD_ADDR_LEN);
660 memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
661 cfg.fcr_present = TRUE;
662 cfg.fcr = obex_l2c_fcr_opts_def;
663
664 BTA_JvL2capConnect(slot->security, slot->role, &obex_l2c_etm_opt, slot->psm,
665 L2CAP_MAX_SDU_LENGTH, &cfg, slot->addr, (tBTA_JV_L2CAP_CBACK *)btc_l2cap_inter_cb, (void *)slot->id);
666 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
667 } while (0);
668
669 if (ret != ESP_BT_L2CAP_SUCCESS) {
670 esp_bt_l2cap_cb_param_t param;
671 param.open.status = ret;
672 param.open.handle = 0;
673 param.open.fd = -1;
674 param.open.tx_mtu = 0;
675 memset(param.open.rem_bda, 0, ESP_BD_ADDR_LEN);
676 btc_l2cap_cb_to_app(ESP_BT_L2CAP_OPEN_EVT, ¶m);
677 }
678 }
679
btc_l2cap_write(uint32_t handle)680 static void btc_l2cap_write(uint32_t handle)
681 {
682 do {
683 if (!is_l2cap_init()) {
684 BTC_TRACE_ERROR("%s L2CAP have not been init\n", __func__);
685 break;
686 }
687 l2cap_slot_t *slot = NULL;
688 slot = l2cap_find_slot_by_handle(handle);
689 if (!slot || (slot && !slot->connected)) {
690 if (!slot) {
691 BTC_TRACE_ERROR("%s unable to find l2cap slot!", __func__);
692 } else {
693 BTC_TRACE_ERROR("%s l2cap has been disconnected already!", __func__);
694 }
695 break;
696 }
697
698 BT_HDR *p_buf;
699 if ((p_buf = fixed_queue_try_peek_first(slot->tx.queue)) != NULL && p_buf->layer_specific == 0) {
700 p_buf->event++;
701 p_buf->layer_specific = 1;
702 BTA_JvL2capWrite(handle, slot->id, p_buf->data + p_buf->offset, p_buf->len, (void *)slot->id);
703 }
704 } while (0);
705 }
706
btc_l2cap_disconnect(uint32_t handle)707 static void btc_l2cap_disconnect(uint32_t handle)
708 {
709 esp_bt_l2cap_status_t ret = ESP_BT_L2CAP_SUCCESS;
710
711 do {
712 if (!is_l2cap_init()) {
713 BTC_TRACE_ERROR("%s L2CAP have not been init\n", __func__);
714 ret = ESP_BT_L2CAP_NEED_INIT;
715 break;
716 }
717 l2cap_slot_t *slot = NULL;
718 slot = l2cap_find_slot_by_handle(handle);
719 if (!slot || (slot && !slot->connected)) {
720 if (!slot) {
721 BTC_TRACE_ERROR("%s unable to find L2CAP slot! disconnect fail!", __func__);
722 } else {
723 BTC_TRACE_ERROR("%s L2CAP has been disconnected already!", __func__);
724 }
725 ret = ESP_BT_L2CAP_NO_CONNECTION;
726 break;
727 }
728 BTA_JvL2capClose(handle, (tBTA_JV_L2CAP_CBACK *)btc_l2cap_inter_cb, (void *)slot->id);
729 } while(0);
730
731 if (ret != ESP_BT_L2CAP_SUCCESS) {
732 esp_bt_l2cap_cb_param_t param;
733 param.close.status = ret;
734 param.close.handle = 0;
735 param.close.async = FALSE;
736 btc_l2cap_cb_to_app(ESP_BT_L2CAP_CLOSE_EVT, ¶m);
737 }
738 }
739
btc_l2cap_call_handler(btc_msg_t * msg)740 void btc_l2cap_call_handler(btc_msg_t *msg)
741 {
742 btc_l2cap_args_t *arg = (btc_l2cap_args_t *)(msg->arg);
743 switch (msg->act) {
744 case BTC_L2CAP_ACT_INIT:
745 btc_l2cap_init();
746 break;
747 case BTC_L2CAP_ACT_UNINIT:
748 btc_l2cap_uninit();
749 break;
750 case BTC_L2CAP_ACT_CONNECT:
751 btc_l2cap_connect(arg);
752 break;
753 case BTC_L2CAP_ACT_START_SRV:
754 btc_l2cap_start_srv(arg);
755 break;
756 case BTC_L2CAP_ACT_STOP_SRV:
757 btc_l2cap_stop_srv(arg);
758 break;
759 default:
760 BTC_TRACE_ERROR("%s: Unhandled event (%d)!\n", __FUNCTION__, msg->act);
761 break;
762 }
763 }
764
btc_l2cap_cb_handler(btc_msg_t * msg)765 void btc_l2cap_cb_handler(btc_msg_t *msg)
766 {
767 esp_bt_l2cap_cb_param_t param;
768 tBTA_JV *p_data = (tBTA_JV *)msg->arg;
769 l2cap_slot_t *slot = NULL;
770 uint8_t event = msg->act;
771 uint8_t serial = 0;
772 uint32_t count = 0;
773
774 switch (event) {
775 case BTA_JV_ENABLE_EVT:
776 param.init.status = p_data->status;
777 btc_l2cap_cb_to_app(ESP_BT_L2CAP_INIT_EVT, ¶m);
778 break;
779 case BTA_JV_DISABLE_EVT:
780 param.uninit.status = ESP_BT_L2CAP_SUCCESS;
781 l2cap_free_pending_slots();
782 BTA_JvFree();
783 osi_mutex_free(&l2cap_local_param.l2cap_slot_mutex);
784 if (l2cap_local_param.tx_event_group) {
785 vEventGroupDelete(l2cap_local_param.tx_event_group);
786 l2cap_local_param.tx_event_group = NULL;
787 }
788 if (l2cap_local_param.l2cap_vfs_id != -1) {
789 esp_vfs_unregister_with_id(l2cap_local_param.l2cap_vfs_id);
790 l2cap_local_param.l2cap_vfs_id = -1;
791 }
792 #if L2CAP_DYNAMIC_MEMORY == TRUE
793 osi_free(l2cap_local_param_ptr);
794 l2cap_local_param_ptr = NULL;
795 #endif
796 btc_l2cap_cb_to_app(ESP_BT_L2CAP_UNINIT_EVT, ¶m);
797 break;
798 case BTA_JV_L2CAP_OPEN_EVT:
799 do {
800 osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
801 slot = l2cap_find_slot_by_handle(p_data->l2c_open.handle);
802 if (!slot) {
803 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
804 BTC_TRACE_ERROR("%s unable to find L2CAP slot, event:%d!", __func__, event);
805 param.open.status = ESP_BT_L2CAP_NO_CONNECTION;
806 break;
807 }
808 param.open.fd = slot->fd;
809 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
810 param.open.status = p_data->l2c_open.status;
811 } while (0);
812 param.open.handle = p_data->l2c_open.handle;
813 param.open.tx_mtu = p_data->l2c_open.tx_mtu;
814 memcpy(param.open.rem_bda, p_data->l2c_open.rem_bda, ESP_BD_ADDR_LEN);
815 btc_l2cap_cb_to_app(ESP_BT_L2CAP_OPEN_EVT, ¶m);
816 break;
817 case BTA_JV_L2CAP_CLOSE_EVT:
818 param.close.status = p_data->l2c_close.status;
819 param.close.handle = p_data->l2c_close.handle;
820 param.close.async = p_data->l2c_close.async;
821 bool need_call = true;
822 do {
823 osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
824 uint32_t id = (uintptr_t)p_data->l2c_close.user_data;
825 slot = l2cap_find_slot_by_id(id);
826 if (!slot) {
827 param.close.status = ESP_BT_L2CAP_NO_CONNECTION;
828 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
829 BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
830 break;
831 }
832 // if rx still has data, delay free slot
833 if (slot->close_alarm == NULL && slot->rx.queue && fixed_queue_length(slot->rx.queue) > 0) {
834 tBTA_JV *p_arg = NULL;
835 if ((p_arg = osi_malloc(sizeof(tBTA_JV))) == NULL) {
836 param.close.status = ESP_BT_L2CAP_NO_RESOURCE;
837 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
838 BTC_TRACE_ERROR("%s unable to malloc slot close_alarm arg!", __func__);
839 break;
840 }
841 memcpy(p_arg, p_data, sizeof(tBTA_JV));
842 slot->alarm_arg = (void *)p_arg;
843 if ((slot->close_alarm =
844 osi_alarm_new("slot", close_timeout_handler, (void *)slot, VFS_CLOSE_TIMEOUT)) == NULL) {
845 osi_free(p_arg);
846 slot->alarm_arg = NULL;
847 param.close.status = ESP_BT_L2CAP_NO_RESOURCE;
848 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
849 BTC_TRACE_ERROR("%s unable to malloc slot close_alarm!", __func__);
850 break;
851 }
852 if (osi_alarm_set(slot->close_alarm, VFS_CLOSE_TIMEOUT) != OSI_ALARM_ERR_PASS) {
853 osi_free(p_arg);
854 slot->alarm_arg = NULL;
855 osi_alarm_free(slot->close_alarm);
856 param.close.status = ESP_BT_L2CAP_BUSY;
857 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
858 BTC_TRACE_ERROR("%s set slot close_alarm failed!", __func__);
859 break;
860 }
861 BTC_TRACE_WARNING("%s slot rx data will be discard in %d milliseconds!",
862 __func__, VFS_CLOSE_TIMEOUT);
863 slot->connected = false;
864 need_call = false;
865 }
866 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
867 } while (0);
868
869 if (need_call) {
870 btc_l2cap_cb_to_app(ESP_BT_L2CAP_CLOSE_EVT, ¶m);
871 osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
872 l2cap_free_slot(slot);
873 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
874 }
875 break;
876 case BTA_JV_L2CAP_START_EVT:
877 param.start.status = p_data->l2c_start.status;
878 param.start.handle = p_data->l2c_start.handle;
879 param.start.sec_id = p_data->l2c_start.sec_id;
880 btc_l2cap_cb_to_app(ESP_BT_L2CAP_START_EVT, ¶m);
881 break;
882 case BTA_JV_L2CAP_CL_INIT_EVT:
883 param.cl_init.status = p_data->l2c_cl_init.status;
884 param.cl_init.handle = p_data->l2c_cl_init.handle;
885 param.cl_init.sec_id = p_data->l2c_cl_init.sec_id;
886 btc_l2cap_cb_to_app(ESP_BT_L2CAP_CL_INIT_EVT, ¶m);
887 break;
888 case BTA_JV_L2CAP_DATA_IND_EVT:
889 osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
890 slot = l2cap_find_slot_by_handle(p_data->data_ind.handle);
891 if (!slot) {
892 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
893 BTC_TRACE_ERROR("%s unable to find L2CAP slot, event:%d!", __func__, event);
894 break;
895 }
896 if (BTA_JvL2capReady(p_data->data_ind.handle, &count) == BTA_JV_SUCCESS && count > 0) {
897 BT_HDR *p_data_buf = osi_malloc(count + sizeof(BT_HDR));
898 if (p_data_buf == NULL) {
899 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
900 BTC_TRACE_ERROR("%s, %d count = %d malloc failed!", __func__, __LINE__, count);
901 break; // to do disconnect
902 }
903 memset(p_data_buf, 0, count + sizeof(BT_HDR));
904 p_data_buf->len = BTA_JvL2capRead(p_data->data_ind.handle, slot->id, p_data_buf->data, count);
905 if (p_data_buf->len > 0) {
906 fixed_queue_enqueue(slot->rx.queue, p_data_buf, FIXED_QUEUE_MAX_TIMEOUT);
907 } else {
908 osi_free(p_data_buf);
909 }
910 }
911 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
912 break;
913 case BTA_JV_L2CAP_CONG_EVT:
914 osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
915 slot = l2cap_find_slot_by_handle(p_data->l2c_cong.handle);
916 if (!slot) {
917 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
918 BTC_TRACE_ERROR("%s unable to find L2CAP slot, event:%d!", __func__, event);
919 break;
920 }
921 if (!p_data->l2c_cong.cong) {
922 BT_HDR *p_buf;
923 if ((p_buf = fixed_queue_try_peek_first(slot->tx.queue)) != NULL && p_buf->layer_specific == 0) {
924 p_buf->event++;
925 p_buf->layer_specific = 1;
926 BTA_JvL2capWrite(p_data->l2c_cong.handle, slot->id, p_buf->data + p_buf->offset, p_buf->len, (void *)slot->id);
927 }
928 }
929 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
930 break;
931 case BTA_JV_L2CAP_READ_EVT:
932 osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
933 slot = l2cap_find_slot_by_handle(p_data->l2c_read.handle);
934 if (!slot) {
935 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
936 BTC_TRACE_ERROR("%s unable to find L2CAP slot, event:%d!", __func__, event);
937 break;
938 }
939 if (BTA_JvL2capReady(p_data->l2c_read.handle, &count) == BTA_JV_SUCCESS && count > 0) {
940 BT_HDR *p_data_buf = osi_malloc(count + sizeof(BT_HDR));
941 if (p_data_buf == NULL) {
942 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
943 BTC_TRACE_ERROR("%s, %d count = %d malloc failed!", __func__, __LINE__, count);
944 break; // to do disconnect
945 }
946 memset(p_data_buf, 0, count + sizeof(BT_HDR));
947 p_data_buf->len = BTA_JvL2capRead(p_data->l2c_read.handle, slot->id, p_data_buf->data, count);
948 if (p_data_buf->len > 0) {
949 fixed_queue_enqueue(slot->rx.queue, p_data_buf, FIXED_QUEUE_MAX_TIMEOUT);
950 } else {
951 osi_free(p_data_buf);
952 }
953 }
954 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
955 break;
956 case BTA_JV_L2CAP_WRITE_EVT:
957 osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
958 slot = l2cap_find_slot_by_handle(p_data->l2c_write.handle);
959 if (!slot) {
960 BTC_TRACE_ERROR("%s unable to find L2CAP slot!, handle:%d", __func__, p_data->l2c_write.handle);
961 }
962 if (slot) {
963 BT_HDR *p_buf;
964 serial = slot->serial;
965 if ((p_buf = fixed_queue_try_peek_first(slot->tx.queue)) == NULL) {
966 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
967 break;
968 }
969 if (p_data->l2c_write.status == BTA_JV_SUCCESS) {
970 p_buf->len -= p_data->l2c_write.len;
971 p_buf->offset += p_data->l2c_write.len;
972 p_buf->layer_specific = 0;
973 if (p_buf->len == 0) {
974 osi_free(fixed_queue_dequeue(slot->tx.queue, FIXED_QUEUE_MAX_TIMEOUT));
975 if (fixed_queue_length(slot->tx.queue) <= SLOT_TX_QUEUE_LOW_WM) {
976 xEventGroupSetBits(l2cap_local_param.tx_event_group, SLOT_WRITE_BIT(serial));
977 }
978 }
979
980 if ((p_buf = fixed_queue_try_peek_first(slot->tx.queue)) != NULL && p_buf->layer_specific == 0 &&
981 !p_data->l2c_write.cong) {
982 p_buf->layer_specific = 1;
983 p_buf->event++;
984 BTA_JvL2capWrite(p_data->l2c_write.handle, slot->id, p_buf->data + p_buf->offset, p_buf->len, (void *)slot->id);
985 }
986 }
987 }
988 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
989 break;
990 case BTA_JV_FREE_SCN_EVT:
991 param.srv_stop.status = p_data->free_scn.status;
992 param.srv_stop.psm = p_data->free_scn.scn;
993 btc_l2cap_cb_to_app(ESP_BT_L2CAP_SRV_STOP_EVT, ¶m);
994 break;
995 default:
996 break;
997 }
998
999 return;
1000 }
1001
l2cap_vfs_write(int fd,const void * data,size_t size)1002 static ssize_t l2cap_vfs_write(int fd, const void * data, size_t size)
1003 {
1004 assert(data != NULL);
1005 errno = 0;
1006 if (size == 0) {
1007 return 0;
1008 }
1009 if (!is_l2cap_init()) {
1010 BTC_TRACE_ERROR("%s L2CAP have not been init\n", __func__);
1011 errno = ESRCH;
1012 return -1;
1013 }
1014
1015 l2cap_slot_t *slot = NULL;
1016 uint8_t serial = 0;
1017 osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
1018 slot = l2cap_find_slot_by_fd(fd);
1019 if (!slot) {
1020 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
1021 BTC_TRACE_ERROR("%s unable to find L2CAP slot!", __func__);
1022 errno = ENOENT;
1023 return -1;
1024 }
1025 serial = slot->serial;
1026 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
1027
1028 ssize_t sent = 0, write_size = 0;
1029 size_t tx_len;
1030 BT_HDR *p_buf = NULL;
1031 bool enqueue_status= false;
1032 EventBits_t tx_event_group_val = 0;
1033 while (1) {
1034 tx_event_group_val = 0;
1035 if (size) {
1036 if (p_buf == NULL) {
1037 write_size = size < slot->tx_mtu ? size : slot->tx_mtu;
1038 if ((p_buf = osi_malloc(sizeof(BT_HDR) + write_size)) == NULL) {
1039 BTC_TRACE_ERROR("%s malloc failed!", __func__);
1040 errno = ENOMEM;
1041 sent = -1;
1042 break;
1043 }
1044 p_buf->offset = 0;
1045 p_buf->len = write_size;
1046 p_buf->event = 0; // indicate the p_buf be sent count
1047 p_buf->layer_specific = 0; // indicate the p_buf whether to be sent, 0 - ready to send; 1 - have sent
1048 memcpy((UINT8 *)(p_buf + 1), data + sent, write_size);
1049 }
1050 } else {
1051 break;
1052 }
1053
1054 osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
1055 if ((slot = l2cap_local_param.l2cap_slots[serial]) != NULL) {
1056 tx_len = fixed_queue_length(slot->tx.queue);
1057 enqueue_status = fixed_queue_enqueue(slot->tx.queue, p_buf, 0);
1058 if (!enqueue_status) {
1059 BTC_TRACE_DEBUG("%s tx_len:%d, fd:%d\n", __func__, fixed_queue_length(slot->tx.queue), fd);
1060 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
1061 //block until under water level, be closed or time out
1062 tx_event_group_val =
1063 xEventGroupWaitBits(l2cap_local_param.tx_event_group, SLOT_WRITE_BIT(serial) | SLOT_CLOSE_BIT(serial), pdTRUE,
1064 pdFALSE, VFS_WRITE_TIMEOUT / portTICK_PERIOD_MS);
1065 if (tx_event_group_val & SLOT_CLOSE_BIT(serial)) {
1066 BTC_TRACE_ERROR("%s exit for L2CAP close, fd:%d!", __func__, fd);
1067 errno = EPIPE;
1068 sent = -1;
1069 break;
1070 } else if (tx_event_group_val & SLOT_WRITE_BIT(serial)) {
1071 continue;
1072 } else if (tx_event_group_val == 0) {
1073 BTC_TRACE_ERROR("%s exit for time out, fd:%d!", __func__, fd);
1074 errno = EBUSY;
1075 sent = -1;
1076 break;
1077 }
1078 }
1079 if (tx_len == 0) {
1080 btc_l2cap_write(slot->handle);
1081 }
1082 sent += write_size;
1083 size -= write_size;
1084 p_buf = NULL;
1085 } else {
1086 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
1087 errno = EPIPE;
1088 sent = -1;
1089 break;
1090 }
1091 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
1092 }
1093
1094 //errors occur, need to cleanup
1095 if (p_buf) {
1096 osi_free(p_buf);
1097 p_buf = NULL;
1098 }
1099
1100 return sent;
1101 }
1102
l2cap_vfs_close(int fd)1103 static int l2cap_vfs_close(int fd)
1104 {
1105 errno = 0;
1106 if (!is_l2cap_init()) {
1107 BTC_TRACE_ERROR("%s L2CAP have not been init\n", __func__);
1108 errno = ESRCH;
1109 return -1;
1110 }
1111 l2cap_slot_t *slot = NULL;
1112 osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
1113 slot = l2cap_find_slot_by_fd(fd);
1114 if (!slot) {
1115 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
1116 BTC_TRACE_ERROR("%s unable to find L2CAP slot!", __func__);
1117 errno = ENOENT;
1118 return -1;
1119 }
1120 btc_l2cap_disconnect(slot->handle);
1121 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
1122 return 0;
1123 }
1124
l2cap_vfs_read(int fd,void * dst,size_t size)1125 static ssize_t l2cap_vfs_read(int fd, void * dst, size_t size)
1126 {
1127 assert(dst != NULL);
1128 errno = 0;
1129 if (!is_l2cap_init()) {
1130 BTC_TRACE_ERROR("%s L2CAP have not been init\n", __func__);
1131 errno = ESRCH;
1132 return -1;
1133 }
1134
1135 l2cap_slot_t *slot = NULL;
1136 uint8_t serial = 0;
1137 osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
1138 slot = l2cap_find_slot_by_fd(fd);
1139 if (!slot) {
1140 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
1141 BTC_TRACE_ERROR("%s unable to find L2CAP slot!", __func__);
1142 errno = ENOENT;
1143 return -1;
1144 }
1145 serial = slot->serial;
1146 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
1147
1148 ssize_t item_size = 0;
1149 BT_HDR *p_buf;
1150 while (1) {
1151 osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
1152 if ((slot = l2cap_local_param.l2cap_slots[serial]) != NULL) {
1153 if (fixed_queue_length(slot->rx.queue) > 0) {
1154 // free unused p_buf
1155 if ((p_buf = (BT_HDR *)fixed_queue_try_peek_first(slot->rx.queue)) != NULL && p_buf->len == 0) {
1156 osi_free(fixed_queue_dequeue(slot->rx.queue, FIXED_QUEUE_MAX_TIMEOUT));
1157 p_buf = NULL;
1158 }
1159 if (size == 0 || (p_buf = (BT_HDR *)fixed_queue_try_peek_first(slot->rx.queue)) == NULL) {
1160 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
1161 break;
1162 }
1163 } else {
1164 /**
1165 * If close_alarm is not NULL, it means that we have received the BTA_JV_L2CAP_CLOSE_EVT.
1166 * And we can trigger close_alarm immediately.
1167 */
1168 if (slot->close_alarm && osi_alarm_is_active(slot->close_alarm)) {
1169 osi_alarm_cancel(slot->close_alarm);
1170 osi_alarm_set(slot->close_alarm, 0);
1171 }
1172 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
1173 break;
1174 }
1175 } else {
1176 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
1177 BTC_TRACE_ERROR("%s peer close, data will be discarded!\n", __func__);
1178 errno = EPIPE;
1179 item_size = -1;
1180 break;
1181 }
1182 osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
1183
1184 if (p_buf->len <= size) {
1185 memcpy(dst, p_buf->data + p_buf->offset, p_buf->len);
1186 size -= p_buf->len;
1187 item_size += p_buf->len;
1188 dst += p_buf->len;
1189 p_buf->offset += p_buf->len;
1190 p_buf->len = 0; // indicate the p_buf is unused
1191 } else {
1192 memcpy(dst, p_buf->data + p_buf->offset, size);
1193 item_size += size;
1194 p_buf->offset += size;
1195 p_buf->len -= size;
1196 size = 0;
1197 }
1198 }
1199 return item_size;
1200 }
1201
btc_l2cap_vfs_register(void)1202 esp_err_t btc_l2cap_vfs_register(void)
1203 {
1204 esp_err_t ret = ESP_OK;
1205
1206 do {
1207 if (!is_l2cap_init()) {
1208 BTC_TRACE_ERROR("%s L2CAP have not been init\n", __func__);
1209 ret = ESP_FAIL;
1210 break;
1211 }
1212
1213 esp_vfs_t vfs = {
1214 .flags = ESP_VFS_FLAG_DEFAULT,
1215 .write = l2cap_vfs_write,
1216 .open = NULL,
1217 .fstat = NULL,
1218 .close = l2cap_vfs_close,
1219 .read = l2cap_vfs_read,
1220 .fcntl = NULL
1221 };
1222
1223 // No FD range is registered here: l2cap_vfs_id is used to register/unregister
1224 // file descriptors
1225 if (esp_vfs_register_with_id(&vfs, NULL, &l2cap_local_param.l2cap_vfs_id) != ESP_OK) {
1226 ret = ESP_FAIL;
1227 break;
1228 }
1229 } while (0);
1230
1231 return ret;
1232 }
1233
btc_l2cap_vfs_unregister(void)1234 esp_err_t btc_l2cap_vfs_unregister(void)
1235 {
1236 esp_err_t ret = ESP_OK;
1237 do {
1238 if (!is_l2cap_init()) {
1239 BTC_TRACE_ERROR("%s L2CAP have not been init\n", __func__);
1240 ret = ESP_FAIL;
1241 break;
1242 }
1243
1244 if (l2cap_local_param.l2cap_vfs_id != -1) {
1245 if (esp_vfs_unregister_with_id(l2cap_local_param.l2cap_vfs_id) != ESP_OK) {
1246 ret = ESP_FAIL;
1247 }
1248 }
1249 l2cap_local_param.l2cap_vfs_id = -1;
1250 } while (0);
1251
1252 return ret;
1253 }
1254
1255 #endif ///defined BTC_L2CAP_INCLUDED && BTC_L2CAP_INCLUDED == TRUE
1256