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, ¶m, 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, ¶m, 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, ¶m);
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, ¶m, 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, ¶m, 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, ¶m, 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