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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
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, &param);
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