1 /*
2  * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdint.h>
8 #include <string.h>
9 #include <stdio.h>
10 #include <assert.h>
11 
12 #include "btc_blufi_prf.h"
13 #include "blufi_int.h"
14 #include "esp_log.h"
15 #include "esp_blufi_api.h"
16 #include "esp_err.h"
17 #include "btc/btc_task.h"
18 #include "esp_blufi.h"
19 #include "osi/allocator.h"
20 #include "console/console.h"
21 
22 /*nimBLE Host*/
23 #include "nimble/nimble_port.h"
24 #include "nimble/nimble_port_freertos.h"
25 #include "host/ble_hs.h"
26 #include "host/util/util.h"
27 #include "host/ble_uuid.h"
28 #include "host/ble_gatt.h"
29 
30 #include "services/gap/ble_svc_gap.h"
31 #include "services/gatt/ble_svc_gatt.h"
32 
33 #if (BLUFI_INCLUDED == TRUE)
34 
35 static uint8_t own_addr_type;
36 
37 struct gatt_value gatt_values[SERVER_MAX_VALUES];
38 const static char *TAG = "BLUFI_EXAMPLE";
39 
40 enum {
41     GATT_VALUE_TYPE_CHR,
42     GATT_VALUE_TYPE_DSC,
43 };
44 
45 static int gatt_svr_access_cb(uint16_t conn_handle, uint16_t attr_handle,
46                               struct ble_gatt_access_ctxt *ctxt,
47                               void *arg);
48 
49 static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
50     {
51         /*** Service: Blufi */
52         .type = BLE_GATT_SVC_TYPE_PRIMARY,
53         .uuid = BLE_UUID16_DECLARE(BLUFI_SERVICE_UUID),
54         .characteristics = (struct ble_gatt_chr_def[])
55         { {
56                 /*** Characteristic: P2E */
57                 .uuid = BLE_UUID16_DECLARE(BLUFI_CHAR_P2E_UUID),
58                 .access_cb = gatt_svr_access_cb,
59                 .flags = BLE_GATT_CHR_F_WRITE,
60                 .arg = &gatt_values[0],
61                 .val_handle = &gatt_values[0].val_handle,
62             }, {
63                 /*** Characteristic: E2P  */
64                 .uuid = BLE_UUID16_DECLARE(BLUFI_CHAR_E2P_UUID),
65                 .access_cb = gatt_svr_access_cb,
66                 .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
67                 .arg = &gatt_values[1],
68                 .val_handle = &gatt_values[1].val_handle,
69             }, {
70                 0, /* No more characteristics in this service. */
71             }
72         },
73     },
74 
75     {
76         0, /* No more services. */
77     },
78 };
79 
esp_blufi_gatt_svr_register_cb(struct ble_gatt_register_ctxt * ctxt,void * arg)80 void esp_blufi_gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
81 {
82     char buf[BLE_UUID_STR_LEN];
83     switch (ctxt->op) {
84     case BLE_GATT_REGISTER_OP_SVC:
85         ESP_LOGI(TAG, "registered service %s with handle=%d\n",
86                  ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf),
87                  ctxt->svc.handle);
88         break;
89 
90     case BLE_GATT_REGISTER_OP_CHR:
91         ESP_LOGI(TAG, "registering characteristic %s with "
92                  "def_handle=%d val_handle=%d\n",
93                  ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf),
94                  ctxt->chr.def_handle,
95                  ctxt->chr.val_handle);
96         break;
97 
98     case BLE_GATT_REGISTER_OP_DSC:
99         ESP_LOGI(TAG, "registering descriptor %s with handle=%d\n",
100                  ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf),
101                  ctxt->dsc.handle);
102         break;
103 
104     default:
105         assert(0);
106         break;
107     }
108 }
109 
write_value(uint16_t conn_handle,uint16_t attr_handle,struct ble_gatt_access_ctxt * ctxt,void * arg)110 static size_t write_value(uint16_t conn_handle, uint16_t attr_handle,
111                           struct ble_gatt_access_ctxt *ctxt,
112                           void *arg)
113 {
114     struct gatt_value *value = (struct gatt_value *)arg;
115     uint16_t len;
116     int rc;
117     if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
118         if (ctxt->chr->flags & BLE_GATT_CHR_F_WRITE_AUTHOR) {
119             return BLE_ATT_ERR_INSUFFICIENT_AUTHOR;
120         }
121     } else {
122         if (ctxt->dsc->att_flags & BLE_ATT_F_WRITE_AUTHOR) {
123             return BLE_ATT_ERR_INSUFFICIENT_AUTHOR;
124         }
125     }
126 
127     /* Data may come in linked om. So retrieve all data */
128     if (SLIST_NEXT(ctxt->om, om_next) != NULL) {
129 	uint8_t *fw_buf = (uint8_t *)malloc(517 * sizeof(uint8_t));
130 	memset(fw_buf, 0x0, 517);
131 
132         memcpy(fw_buf, &ctxt->om->om_data[0], ctxt->om->om_len);
133         struct os_mbuf *last;
134         last = ctxt->om;
135         uint32_t offset = ctxt->om->om_len;
136 
137         while (SLIST_NEXT(last, om_next) != NULL) {
138               struct os_mbuf *temp = SLIST_NEXT(last, om_next);
139 	      memcpy(fw_buf + offset  , &temp->om_data[0], temp->om_len);
140 	      offset += temp->om_len;
141 	      last = SLIST_NEXT(last, om_next);
142               temp = NULL;
143         }
144 	btc_blufi_recv_handler(fw_buf, offset);
145 
146 	free(fw_buf);
147     }
148     else {
149         btc_blufi_recv_handler(&ctxt->om->om_data[0], ctxt->om->om_len);
150     }
151 
152     rc = ble_hs_mbuf_to_flat(ctxt->om, value->buf->om_data,
153                              value->buf->om_len, &len);
154     if (rc != 0) {
155         return BLE_ATT_ERR_UNLIKELY;
156     }
157     /* Maximum attribute value size is 512 bytes */
158     assert(value->buf->om_len < MAX_VAL_SIZE);
159 
160     return 0;
161 }
162 
read_value(uint16_t conn_handle,uint16_t attr_handle,struct ble_gatt_access_ctxt * ctxt,void * arg)163 static size_t read_value(uint16_t conn_handle, uint16_t attr_handle,
164                          struct ble_gatt_access_ctxt *ctxt,
165                          void *arg)
166 {
167     const struct gatt_value *value = (const struct gatt_value *) arg;
168     char str[BLE_UUID_STR_LEN];
169     int rc;
170 
171     memset(str, '\0', sizeof(str));
172 
173     if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
174         if (ctxt->chr->flags & BLE_GATT_CHR_F_READ_AUTHOR) {
175             return BLE_ATT_ERR_INSUFFICIENT_AUTHOR;
176         }
177 
178         ble_uuid_to_str(ctxt->chr->uuid, str);
179     } else {
180         if (ctxt->dsc->att_flags & BLE_ATT_F_READ_AUTHOR) {
181             return BLE_ATT_ERR_INSUFFICIENT_AUTHOR;
182         }
183 
184         ble_uuid_to_str(ctxt->dsc->uuid, str);
185     }
186 
187     rc = os_mbuf_append(ctxt->om, value->buf->om_data, value->buf->om_len);
188     return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
189 }
190 
gatt_svr_access_cb(uint16_t conn_handle,uint16_t attr_handle,struct ble_gatt_access_ctxt * ctxt,void * arg)191 static int gatt_svr_access_cb(uint16_t conn_handle, uint16_t attr_handle,
192                               struct ble_gatt_access_ctxt *ctxt,
193                               void *arg)
194 {
195     switch (ctxt->op) {
196     case BLE_GATT_ACCESS_OP_READ_CHR:
197         return read_value(conn_handle, attr_handle,
198                           ctxt, arg);
199     case BLE_GATT_ACCESS_OP_WRITE_CHR:
200         return write_value(conn_handle, attr_handle,
201                            ctxt, arg);
202     default:
203         assert(0);
204         return BLE_ATT_ERR_UNLIKELY;
205     }
206 
207     /* Unknown characteristic; the nimble stack should not have called this
208      * function.
209      */
210     assert(0);
211     return BLE_ATT_ERR_UNLIKELY;
212 }
213 
init_gatt_values(void)214 static void init_gatt_values(void)
215 {
216     int i = 0;
217     const struct ble_gatt_svc_def *svc;
218     const struct ble_gatt_chr_def *chr;
219     const struct ble_gatt_dsc_def *dsc;
220 
221     for (svc = gatt_svr_svcs; svc && svc->uuid; svc++) {
222         for (chr = svc->characteristics; chr && chr->uuid; chr++) {
223             assert(i < SERVER_MAX_VALUES);
224             gatt_values[i].type = GATT_VALUE_TYPE_CHR;
225             gatt_values[i].ptr = (void *)chr;
226             gatt_values[i].buf = os_msys_get(0, 0);
227             os_mbuf_extend(gatt_values[i].buf, 1);
228             ++i;
229 
230             for (dsc = chr->descriptors; dsc && dsc->uuid; dsc++) {
231                 assert(i < SERVER_MAX_VALUES);
232                 gatt_values[i].type = GATT_VALUE_TYPE_DSC;
233                 gatt_values[i].ptr = (void *)dsc;
234                 gatt_values[i].buf = os_msys_get(0, 0);
235                 os_mbuf_extend(gatt_values[i].buf, 1);
236                 ++i;
237             }
238         }
239     }
240 
241 }
242 
deinit_gatt_values(void)243 static void deinit_gatt_values(void)
244 {
245     int i = 0;
246     const struct ble_gatt_svc_def *svc;
247     const struct ble_gatt_chr_def *chr;
248     const struct ble_gatt_dsc_def *dsc;
249 
250     for (svc = gatt_svr_svcs; svc && svc->uuid; svc++) {
251         for (chr = svc->characteristics; chr && chr->uuid; chr++) {
252             if (i < SERVER_MAX_VALUES && gatt_values[i].buf != NULL) {
253                 os_mbuf_free(gatt_values[i].buf);  /* Free the buffer */
254                 gatt_values[i].buf = NULL;         /* Nullify the pointer to avoid dangling references */
255             }
256             ++i;
257 
258             for (dsc = chr->descriptors; dsc && dsc->uuid; dsc++) {
259                 if (i < SERVER_MAX_VALUES && gatt_values[i].buf != NULL) {
260                     os_mbuf_free(gatt_values[i].buf);  /* Free the buffer */
261                     gatt_values[i].buf = NULL;         /* Nullify the pointer to avoid dangling references */
262                 }
263                 ++i;
264             }
265         }
266     }
267 }
268 
esp_blufi_gatt_svr_init(void)269 int esp_blufi_gatt_svr_init(void)
270 {
271     int rc;
272     ble_svc_gap_init();
273     ble_svc_gatt_init();
274 
275     rc = ble_gatts_count_cfg(gatt_svr_svcs);
276     if (rc != 0) {
277         return rc;
278     }
279 
280     rc = ble_gatts_add_svcs(gatt_svr_svcs);
281     if (rc != 0) {
282         return rc;
283     }
284 
285     init_gatt_values();
286     return 0;
287 }
288 
esp_blufi_gatt_svr_deinit(void)289 int esp_blufi_gatt_svr_deinit(void)
290 {
291     deinit_gatt_values();
292 
293     ble_gatts_free_svcs();
294     /* Deinitialize BLE GATT and GAP services */
295     ble_svc_gatt_deinit();
296     ble_svc_gap_deinit();
297 
298     return 0;
299 }
300 
301 static int
esp_blufi_gap_event(struct ble_gap_event * event,void * arg)302 esp_blufi_gap_event(struct ble_gap_event *event, void *arg)
303 {
304     struct ble_gap_conn_desc desc;
305     int rc;
306 
307     switch (event->type) {
308     case BLE_GAP_EVENT_CONNECT:
309         /* A new connection was established or a connection attempt failed. */
310         ESP_LOGI(TAG, "connection %s; status=%d\n",
311                  event->connect.status == 0 ? "established" : "failed",
312                  event->connect.status);
313         if (event->connect.status == 0) {
314 
315             blufi_env.is_connected = true;
316             blufi_env.recv_seq = blufi_env.send_seq = 0;
317             btc_msg_t msg;
318             esp_blufi_cb_param_t param;
319             msg.sig = BTC_SIG_API_CB;
320             msg.pid = BTC_PID_BLUFI;
321             msg.act = ESP_BLUFI_EVENT_BLE_CONNECT;
322 
323             rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
324             assert(rc == 0);
325             memcpy(param.connect.remote_bda, desc.peer_id_addr.val, ESP_BLUFI_BD_ADDR_LEN);
326 
327             param.connect.conn_id = event->connect.conn_handle;
328             /* save connection handle */
329             blufi_env.conn_id = event->connect.conn_handle;
330             btc_transfer_context(&msg, &param, sizeof(esp_blufi_cb_param_t), NULL, NULL);
331         }
332         if (event->connect.status != 0) {
333             /* Connection failed; resume advertising. */
334             esp_blufi_adv_start();
335         }
336         return 0;
337     case BLE_GAP_EVENT_DISCONNECT:
338         ESP_LOGI(TAG, "disconnect; reason=%d\n", event->disconnect.reason);
339         memcpy(blufi_env.remote_bda, event->disconnect.conn.peer_id_addr.val, ESP_BLUFI_BD_ADDR_LEN);
340         blufi_env.is_connected = false;
341         blufi_env.recv_seq = blufi_env.send_seq = 0;
342         blufi_env.sec_mode = 0x0;
343         blufi_env.offset = 0;
344 
345         if (blufi_env.aggr_buf != NULL) {
346             osi_free(blufi_env.aggr_buf);
347             blufi_env.aggr_buf = NULL;
348         }
349 
350         btc_msg_t msg;
351         esp_blufi_cb_param_t param;
352 
353         msg.sig = BTC_SIG_API_CB;
354         msg.pid = BTC_PID_BLUFI;
355         msg.act = ESP_BLUFI_EVENT_BLE_DISCONNECT;
356         memcpy(param.disconnect.remote_bda, event->disconnect.conn.peer_id_addr.val, ESP_BLUFI_BD_ADDR_LEN);
357         btc_transfer_context(&msg, &param, sizeof(esp_blufi_cb_param_t), NULL, NULL);
358 
359         return 0;
360     case BLE_GAP_EVENT_CONN_UPDATE:
361         /* The central has updated the connection parameters. */
362         ESP_LOGI(TAG, "connection updated; status=%d\n",
363                  event->conn_update.status);
364         return 0;
365 
366     case BLE_GAP_EVENT_ADV_COMPLETE:
367         ESP_LOGI(TAG, "advertise complete; reason=%d",
368                  event->adv_complete.reason);
369         esp_blufi_adv_start();
370         return 0;
371 
372     case BLE_GAP_EVENT_SUBSCRIBE:
373         ESP_LOGI(TAG, "subscribe event; conn_handle=%d attr_handle=%d "
374                  "reason=%d prevn=%d curn=%d previ=%d curi=%d\n",
375                  event->subscribe.conn_handle,
376                  event->subscribe.attr_handle,
377                  event->subscribe.reason,
378                  event->subscribe.prev_notify,
379                  event->subscribe.cur_notify,
380                  event->subscribe.prev_indicate,
381                  event->subscribe.cur_indicate);
382         return 0;
383 
384     case BLE_GAP_EVENT_MTU:
385         ESP_LOGI(TAG, "mtu update event; conn_handle=%d cid=%d mtu=%d\n",
386                  event->mtu.conn_handle,
387                  event->mtu.channel_id,
388                  event->mtu.value);
389         blufi_env.frag_size = (event->mtu.value < BLUFI_MAX_DATA_LEN ? event->mtu.value : BLUFI_MAX_DATA_LEN) - BLUFI_MTU_RESERVED_SIZE;
390         return 0;
391 
392     }
393     return 0;
394 }
395 
esp_blufi_adv_start(void)396 void esp_blufi_adv_start(void)
397 {
398     int rc;
399 
400     rc = ble_hs_util_ensure_addr(0);
401     assert(rc == 0);
402 
403     /* Figure out address to use while advertising (no privacy for now) */
404     rc = ble_hs_id_infer_auto(0, &own_addr_type);
405     if (rc != 0) {
406         ESP_LOGI(TAG, "error determining address type; rc=%d ", rc);
407         return;
408     }
409 
410     /* Printing ADDR */
411     uint8_t addr_val[6] = {0};
412     rc = ble_hs_id_copy_addr(own_addr_type, addr_val, NULL);
413 
414     /* Begin advertising. */
415     struct ble_gap_adv_params adv_params;
416     struct ble_hs_adv_fields fields;
417     const char *name;
418 
419     /**
420      *  Set the advertisement data included in our advertisements:
421      *     o Flags (indicates advertisement type and other general info).
422      *     o Advertising tx power.
423      *     o Device name.
424      *     o 16-bit service UUIDs (alert notifications).
425      */
426 
427     memset(&fields, 0, sizeof fields);
428 
429     /* Advertise two flags:
430     *     o Discoverability in forthcoming advertisement (general)
431      *     o BLE-only (BR/EDR unsupported).
432      */
433     fields.flags = BLE_HS_ADV_F_DISC_GEN |
434                    BLE_HS_ADV_F_BREDR_UNSUP;
435 
436     /* Indicate that the TX power level field should be included; have the
437      * stack fill this value automatically.  This is done by assigning the
438      * special value BLE_HS_ADV_TX_PWR_LVL_AUTO.
439      */
440     fields.tx_pwr_lvl_is_present = 1;
441     fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
442 
443     name = ble_svc_gap_device_name();
444     fields.name = (uint8_t *)name;
445     fields.name_len = strlen(name);
446     fields.name_is_complete = 1;
447 
448     fields.uuids16 = (ble_uuid16_t[]) {
449         BLE_UUID16_INIT(BLUFI_APP_UUID)
450     };
451     fields.num_uuids16 = 1;
452     fields.uuids16_is_complete = 1;
453     rc = ble_gap_adv_set_fields(&fields);
454     if (rc != 0) {
455         ESP_LOGE(TAG, "error setting advertisement data; rc=%d\n", rc);
456         return;
457     }
458 
459     /* Begin advertising. */
460     memset(&adv_params, 0, sizeof adv_params);
461     adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
462     adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
463     rc = ble_gap_adv_start(own_addr_type, NULL, BLE_HS_FOREVER,
464                            &adv_params, esp_blufi_gap_event, NULL);
465     if (rc != 0) {
466         ESP_LOGE(TAG, "error enabling advertisement; rc=%d\n", rc);
467         return;
468     }
469 }
470 
esp_blufi_init(void)471 uint8_t esp_blufi_init(void)
472 {
473     blufi_env.enabled = true;
474     esp_blufi_cb_param_t param;
475     param.init_finish.state = ESP_BLUFI_INIT_OK;
476     btc_blufi_cb_to_app(ESP_BLUFI_EVENT_INIT_FINISH, &param);
477     return ESP_BLUFI_ERROR;
478 }
479 
esp_blufi_deinit(void)480 void esp_blufi_deinit(void)
481 {
482     blufi_env.enabled = false;
483     esp_blufi_cb_param_t param;
484     btc_msg_t msg;
485     memset (&msg, 0x0, sizeof (msg));
486     msg.sig = BTC_SIG_API_CB;
487     msg.pid = BTC_PID_BLUFI;
488     msg.act = ESP_BLUFI_EVENT_DEINIT_FINISH;
489     param.deinit_finish.state = ESP_BLUFI_DEINIT_OK;
490     btc_transfer_context(&msg, &param, sizeof(esp_blufi_cb_param_t), NULL, NULL);
491 }
492 
esp_blufi_send_notify(void * arg)493 void esp_blufi_send_notify(void *arg)
494 {
495     struct pkt_info *pkts = (struct pkt_info *) arg;
496     struct os_mbuf *om;
497     om = ble_hs_mbuf_from_flat(pkts->pkt, pkts->pkt_len);
498     if (om == NULL) {
499         ESP_LOGE(TAG, "Error in allocating memory");
500         return;
501     }
502     int rc = 0;
503     rc = ble_gatts_notify_custom(blufi_env.conn_id, gatt_values[1].val_handle, om);
504     if (rc != 0) {
505         ESP_LOGE(TAG, "Error in sending notification");
506     }
507 }
508 
esp_blufi_disconnect(void)509 void esp_blufi_disconnect(void)
510 {
511     ble_gap_terminate(blufi_env.conn_id, BLE_ERR_REM_USER_CONN_TERM);
512 }
513 
esp_blufi_adv_stop(void)514 void esp_blufi_adv_stop(void) {}
515 
esp_blufi_send_encap(void * arg)516 void esp_blufi_send_encap(void *arg)
517 {
518     struct blufi_hdr *hdr = (struct blufi_hdr *)arg;
519     if (blufi_env.is_connected == false) {
520         BTC_TRACE_WARNING("%s ble connection is broken\n", __func__);
521         return;
522     }
523     btc_blufi_send_notify((uint8_t *)hdr,
524                           ((hdr->fc & BLUFI_FC_CHECK) ?
525                            hdr->data_len + sizeof(struct blufi_hdr) + 2 :
526                            hdr->data_len + sizeof(struct blufi_hdr)));
527 }
528 
esp_blufi_btc_init(void)529 void esp_blufi_btc_init(void)
530 {
531     int rc;
532     rc = btc_init();
533     assert(rc == 0);
534 }
535 
esp_blufi_btc_deinit(void)536 void esp_blufi_btc_deinit(void)
537 {
538     btc_deinit();
539 }
540 
esp_blufi_handle_gap_events(struct ble_gap_event * event,void * arg)541 int esp_blufi_handle_gap_events(struct ble_gap_event *event, void *arg)
542 {
543     struct ble_gap_conn_desc desc;
544     int rc;
545 
546     if (event != NULL) {
547         switch (event->type) {
548         case BLE_GAP_EVENT_CONNECT:
549             if (event->connect.status == 0) {
550                 btc_msg_t msg;
551                 esp_blufi_cb_param_t param;
552 
553                 blufi_env.is_connected = true;
554                 blufi_env.recv_seq = blufi_env.send_seq = 0;
555                 blufi_env.conn_id  = event->connect.conn_handle;
556 
557                 msg.sig = BTC_SIG_API_CB;
558                 msg.pid = BTC_PID_BLUFI;
559                 msg.act = ESP_BLUFI_EVENT_BLE_CONNECT;
560 
561                 rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
562                 assert(rc == 0);
563                 memcpy(param.connect.remote_bda, desc.peer_id_addr.val, ESP_BLUFI_BD_ADDR_LEN);
564 
565                 param.connect.conn_id = event->connect.conn_handle;
566                 btc_transfer_context(&msg, &param, sizeof(esp_blufi_cb_param_t), NULL, NULL);
567             }
568             return 0;
569         case BLE_GAP_EVENT_DISCONNECT: {
570             btc_msg_t msg;
571             esp_blufi_cb_param_t param;
572 
573             blufi_env.is_connected = false;
574             blufi_env.recv_seq = blufi_env.send_seq = 0;
575             blufi_env.sec_mode = 0x0;
576             blufi_env.offset = 0;
577 
578             memcpy(blufi_env.remote_bda,
579                    event->disconnect.conn.peer_id_addr.val,
580                    ESP_BLUFI_BD_ADDR_LEN);
581 
582             if (blufi_env.aggr_buf != NULL) {
583                 osi_free(blufi_env.aggr_buf);
584                 blufi_env.aggr_buf = NULL;
585             }
586 
587             msg.sig = BTC_SIG_API_CB;
588             msg.pid = BTC_PID_BLUFI;
589             msg.act = ESP_BLUFI_EVENT_BLE_DISCONNECT;
590             memcpy(param.disconnect.remote_bda,
591                    event->disconnect.conn.peer_id_addr.val,
592                    ESP_BLUFI_BD_ADDR_LEN);
593             btc_transfer_context(&msg, &param, sizeof(esp_blufi_cb_param_t), NULL, NULL);
594             return 0;
595         }
596 
597         case BLE_GAP_EVENT_MTU:
598             blufi_env.frag_size = (event->mtu.value < BLUFI_MAX_DATA_LEN ? event->mtu.value :
599                                    BLUFI_MAX_DATA_LEN) - BLUFI_MTU_RESERVED_SIZE;
600             return 0;
601         }
602     }
603 
604     return 0;
605 }
606 
607 #endif
608