1 /******************************************************************************
2  *
3  *  Copyright (C) 2014 Google, Inc.
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at:
8  *
9  *  http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  ******************************************************************************/
18 #include <string.h>
19 #include "sdkconfig.h"
20 #include "esp_bt.h"
21 
22 #include "common/bt_defs.h"
23 #include "common/bt_trace.h"
24 #include "stack/hcidefs.h"
25 #include "stack/hcimsgs.h"
26 #include "stack/btu.h"
27 #include "common/bt_vendor_lib.h"
28 #include "hci/hci_internals.h"
29 #include "hci/hci_hal.h"
30 #include "hci/hci_layer.h"
31 #include "osi/allocator.h"
32 #include "hci/packet_fragmenter.h"
33 #include "osi/list.h"
34 #include "osi/alarm.h"
35 #include "osi/thread.h"
36 #include "osi/mutex.h"
37 #include "osi/fixed_queue.h"
38 
39 #define HCI_HOST_TASK_PINNED_TO_CORE    (TASK_PINNED_TO_CORE)
40 #define HCI_HOST_TASK_STACK_SIZE        (2048 + BT_TASK_EXTRA_STACK_SIZE)
41 #define HCI_HOST_TASK_PRIO              (BT_TASK_MAX_PRIORITIES - 3)
42 #define HCI_HOST_TASK_NAME              "hciT"
43 
44 typedef struct {
45     uint16_t opcode;
46     future_t *complete_future;
47     command_complete_cb complete_callback;
48     command_status_cb status_callback;
49     void *context;
50     BT_HDR *command;
51 } waiting_command_t;
52 
53 typedef struct {
54     bool timer_is_set;
55     osi_alarm_t *command_response_timer;
56     list_t *commands_pending_response;
57     osi_mutex_t commands_pending_response_lock;
58 } command_waiting_response_t;
59 
60 typedef struct {
61     int command_credits;
62     fixed_queue_t *command_queue;
63     fixed_queue_t *packet_queue;
64 
65     command_waiting_response_t cmd_waiting_q;
66 
67     /*
68       non_repeating_timer_t *command_response_timer;
69       list_t *commands_pending_response;
70       osi_mutex_t commands_pending_response_lock;
71     */
72 } hci_host_env_t;
73 
74 // Using a define here, because it can be stringified for the property lookup
75 static const uint32_t COMMAND_PENDING_TIMEOUT = 8000;
76 
77 // Our interface
78 static bool interface_created;
79 static hci_t interface;
80 static hci_host_env_t hci_host_env;
81 static osi_thread_t *hci_host_thread;
82 static bool hci_host_startup_flag;
83 
84 // Modules we import and callbacks we export
85 static const hci_hal_t *hal;
86 static const hci_hal_callbacks_t hal_callbacks;
87 static const packet_fragmenter_t *packet_fragmenter;
88 static const packet_fragmenter_callbacks_t packet_fragmenter_callbacks;
89 
90 static int hci_layer_init_env(void);
91 static void hci_layer_deinit_env(void);
92 static void hci_host_thread_handler(void *arg);
93 static void event_command_ready(fixed_queue_t *queue);
94 static void event_packet_ready(fixed_queue_t *queue);
95 static void restart_command_waiting_response_timer(command_waiting_response_t *cmd_wait_q);
96 static void command_timed_out(void *context);
97 static void hal_says_packet_ready(BT_HDR *packet);
98 static bool filter_incoming_event(BT_HDR *packet);
99 static serial_data_type_t event_to_data_type(uint16_t event);
100 static waiting_command_t *get_waiting_command(command_opcode_t opcode);
101 static void dispatch_reassembled(BT_HDR *packet);
102 
103 // Module lifecycle functions
hci_start_up(void)104 int hci_start_up(void)
105 {
106     if (hci_layer_init_env()) {
107         goto error;
108     }
109 
110     hci_host_thread = osi_thread_create(HCI_HOST_TASK_NAME, HCI_HOST_TASK_STACK_SIZE, HCI_HOST_TASK_PRIO, HCI_HOST_TASK_PINNED_TO_CORE, 2);
111     if (hci_host_thread == NULL) {
112         return -2;
113     }
114 
115     packet_fragmenter->init(&packet_fragmenter_callbacks);
116     hal->open(&hal_callbacks, hci_host_thread);
117 
118     hci_host_startup_flag = true;
119     return 0;
120 error:
121     hci_shut_down();
122     return -1;
123 }
124 
hci_shut_down(void)125 void hci_shut_down(void)
126 {
127     hci_host_startup_flag  = false;
128     hci_layer_deinit_env();
129 
130     packet_fragmenter->cleanup();
131 
132     //low_power_manager->cleanup();
133     hal->close();
134 
135     osi_thread_free(hci_host_thread);
136     hci_host_thread = NULL;
137 }
138 
139 
hci_host_task_post(uint32_t timeout)140 bool hci_host_task_post(uint32_t timeout)
141 {
142     return osi_thread_post(hci_host_thread, hci_host_thread_handler, NULL, 0, timeout);
143 }
144 
hci_layer_init_env(void)145 static int hci_layer_init_env(void)
146 {
147     command_waiting_response_t *cmd_wait_q;
148 
149     // The host is only allowed to send at most one command initially,
150     // as per the Bluetooth spec, Volume 2, Part E, 4.4 (Command Flow Control)
151     // This value can change when you get a command complete or command status event.
152     hci_host_env.command_credits = 1;
153     hci_host_env.command_queue = fixed_queue_new(QUEUE_SIZE_MAX);
154     if (hci_host_env.command_queue) {
155         fixed_queue_register_dequeue(hci_host_env.command_queue, event_command_ready);
156     } else {
157         HCI_TRACE_ERROR("%s unable to create pending command queue.", __func__);
158         return -1;
159     }
160 
161     hci_host_env.packet_queue = fixed_queue_new(QUEUE_SIZE_MAX);
162     if (hci_host_env.packet_queue) {
163         fixed_queue_register_dequeue(hci_host_env.packet_queue, event_packet_ready);
164     } else {
165         HCI_TRACE_ERROR("%s unable to create pending packet queue.", __func__);
166         return -1;
167     }
168 
169     // Init Commands waiting response list and timer
170     cmd_wait_q = &hci_host_env.cmd_waiting_q;
171     cmd_wait_q->timer_is_set = false;
172     cmd_wait_q->commands_pending_response = list_new(NULL);
173     if (!cmd_wait_q->commands_pending_response) {
174         HCI_TRACE_ERROR("%s unable to create list for commands pending response.", __func__);
175         return -1;
176     }
177     osi_mutex_new(&cmd_wait_q->commands_pending_response_lock);
178     cmd_wait_q->command_response_timer = osi_alarm_new("cmd_rsp_to", command_timed_out, cmd_wait_q, COMMAND_PENDING_TIMEOUT);
179     if (!cmd_wait_q->command_response_timer) {
180         HCI_TRACE_ERROR("%s unable to create command response timer.", __func__);
181         return -1;
182     }
183 #if (BLE_50_FEATURE_SUPPORT == TRUE)
184     btsnd_hcic_ble_sync_sem_init();
185 #endif // #if (BLE_50_FEATURE_SUPPORT == TRUE)
186 
187     return 0;
188 }
189 
hci_layer_deinit_env(void)190 static void hci_layer_deinit_env(void)
191 {
192     command_waiting_response_t *cmd_wait_q;
193 
194     if (hci_host_env.command_queue) {
195         fixed_queue_free(hci_host_env.command_queue, osi_free_func);
196     }
197     if (hci_host_env.packet_queue) {
198         fixed_queue_free(hci_host_env.packet_queue, osi_free_func);
199     }
200 
201     cmd_wait_q = &hci_host_env.cmd_waiting_q;
202     list_free(cmd_wait_q->commands_pending_response);
203     osi_mutex_free(&cmd_wait_q->commands_pending_response_lock);
204     osi_alarm_free(cmd_wait_q->command_response_timer);
205     cmd_wait_q->command_response_timer = NULL;
206 #if (BLE_50_FEATURE_SUPPORT == TRUE)
207     btsnd_hcic_ble_sync_sem_deinit();
208 #endif // #if (BLE_50_FEATURE_SUPPORT == TRUE)
209 }
210 
hci_host_thread_handler(void * arg)211 static void hci_host_thread_handler(void *arg)
212 {
213     /*
214      * Previous task handles RX queue and two TX Queues, Since there is
215      * a RX Thread Task in H4 layer which receives packet from driver layer.
216      * Now HCI Host Task has been optimized to only process TX Queue
217      * including command and data queue. And command queue has high priority,
218      * All packets will be directly copied to single queue in driver layer with
219      * H4 type header added (1 byte).
220      */
221     if (esp_vhci_host_check_send_available()) {
222         /*Now Target only allowed one packet per TX*/
223         BT_HDR *pkt = packet_fragmenter->fragment_current_packet();
224         if (pkt != NULL) {
225             packet_fragmenter->fragment_and_dispatch(pkt);
226         } else {
227             if (!fixed_queue_is_empty(hci_host_env.command_queue) &&
228                     hci_host_env.command_credits > 0) {
229                 fixed_queue_process(hci_host_env.command_queue);
230             } else if (!fixed_queue_is_empty(hci_host_env.packet_queue)) {
231                 fixed_queue_process(hci_host_env.packet_queue);
232             }
233         }
234     }
235 }
236 
transmit_command(BT_HDR * command,command_complete_cb complete_callback,command_status_cb status_callback,void * context)237 static void transmit_command(
238     BT_HDR *command,
239     command_complete_cb complete_callback,
240     command_status_cb status_callback,
241     void *context)
242 {
243     uint8_t *stream;
244     waiting_command_t *wait_entry = osi_calloc(sizeof(waiting_command_t));
245     if (!wait_entry) {
246         HCI_TRACE_ERROR("%s couldn't allocate space for wait entry.", __func__);
247         return;
248     }
249 
250     stream = command->data + command->offset;
251     STREAM_TO_UINT16(wait_entry->opcode, stream);
252     wait_entry->complete_callback = complete_callback;
253     wait_entry->status_callback = status_callback;
254     wait_entry->command = command;
255     wait_entry->context = context;
256 
257     // Store the command message type in the event field
258     // in case the upper layer didn't already
259     command->event = MSG_STACK_TO_HC_HCI_CMD;
260     HCI_TRACE_DEBUG("HCI Enqueue Comamnd opcode=0x%x\n", wait_entry->opcode);
261     BTTRC_DUMP_BUFFER(NULL, command->data + command->offset, command->len);
262 
263     fixed_queue_enqueue(hci_host_env.command_queue, wait_entry, FIXED_QUEUE_MAX_TIMEOUT);
264     hci_host_task_post(OSI_THREAD_MAX_TIMEOUT);
265 
266 }
267 
transmit_command_futured(BT_HDR * command)268 static future_t *transmit_command_futured(BT_HDR *command)
269 {
270     waiting_command_t *wait_entry = osi_calloc(sizeof(waiting_command_t));
271     assert(wait_entry != NULL);
272 
273     future_t *future = future_new();
274 
275     uint8_t *stream = command->data + command->offset;
276     STREAM_TO_UINT16(wait_entry->opcode, stream);
277     wait_entry->complete_future = future;
278     wait_entry->command = command;
279 
280     // Store the command message type in the event field
281     // in case the upper layer didn't already
282     command->event = MSG_STACK_TO_HC_HCI_CMD;
283 
284     fixed_queue_enqueue(hci_host_env.command_queue, wait_entry, FIXED_QUEUE_MAX_TIMEOUT);
285     hci_host_task_post(OSI_THREAD_MAX_TIMEOUT);
286     return future;
287 }
288 
transmit_downward(uint16_t type,void * data)289 static void transmit_downward(uint16_t type, void *data)
290 {
291     if (type == MSG_STACK_TO_HC_HCI_CMD) {
292         transmit_command((BT_HDR *)data, NULL, NULL, NULL);
293         HCI_TRACE_WARNING("%s legacy transmit of command. Use transmit_command instead.\n", __func__);
294     } else {
295         fixed_queue_enqueue(hci_host_env.packet_queue, data, FIXED_QUEUE_MAX_TIMEOUT);
296     }
297 
298     hci_host_task_post(OSI_THREAD_MAX_TIMEOUT);
299 }
300 
301 
302 // Command/packet transmitting functions
event_command_ready(fixed_queue_t * queue)303 static void event_command_ready(fixed_queue_t *queue)
304 {
305     waiting_command_t *wait_entry = NULL;
306     command_waiting_response_t *cmd_wait_q = &hci_host_env.cmd_waiting_q;
307 
308     wait_entry = fixed_queue_dequeue(queue, FIXED_QUEUE_MAX_TIMEOUT);
309 
310     if(wait_entry->opcode == HCI_HOST_NUM_PACKETS_DONE
311 #if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE)
312     || wait_entry->opcode == HCI_VENDOR_BLE_ADV_REPORT_FLOW_CONTROL
313 #endif
314     ){
315         packet_fragmenter->fragment_and_dispatch(wait_entry->command);
316         osi_free(wait_entry->command);
317         osi_free(wait_entry);
318         return;
319     }
320     hci_host_env.command_credits--;
321     // Move it to the list of commands awaiting response
322     osi_mutex_lock(&cmd_wait_q->commands_pending_response_lock, OSI_MUTEX_MAX_TIMEOUT);
323     list_append(cmd_wait_q->commands_pending_response, wait_entry);
324     osi_mutex_unlock(&cmd_wait_q->commands_pending_response_lock);
325 
326     // Send it off
327     packet_fragmenter->fragment_and_dispatch(wait_entry->command);
328 
329     restart_command_waiting_response_timer(cmd_wait_q);
330 }
331 
event_packet_ready(fixed_queue_t * queue)332 static void event_packet_ready(fixed_queue_t *queue)
333 {
334     BT_HDR *packet = (BT_HDR *)fixed_queue_dequeue(queue, FIXED_QUEUE_MAX_TIMEOUT);
335     // The queue may be the command queue or the packet queue, we don't care
336 
337     packet_fragmenter->fragment_and_dispatch(packet);
338 }
339 
340 // Callback for the fragmenter to send a fragment
transmit_fragment(BT_HDR * packet,bool send_transmit_finished)341 static void transmit_fragment(BT_HDR *packet, bool send_transmit_finished)
342 {
343     uint16_t event = packet->event & MSG_EVT_MASK;
344     serial_data_type_t type = event_to_data_type(event);
345 
346     hal->transmit_data(type, packet->data + packet->offset, packet->len);
347 
348     if (event != MSG_STACK_TO_HC_HCI_CMD && send_transmit_finished) {
349         osi_free(packet);
350     }
351 }
352 
fragmenter_transmit_finished(BT_HDR * packet,bool all_fragments_sent)353 static void fragmenter_transmit_finished(BT_HDR *packet, bool all_fragments_sent)
354 {
355     if (all_fragments_sent) {
356         osi_free(packet);
357     } else {
358         // This is kind of a weird case, since we're dispatching a partially sent packet
359         // up to a higher layer.
360         // TODO(zachoverflow): rework upper layer so this isn't necessary.
361         //osi_free(packet);
362 
363         /* dispatch_reassembled(packet) will send the packet back to the higher layer
364            when controller buffer is not enough. hci will send the remain packet back
365            to the l2cap layer and saved in the Link Queue (p_lcb->link_xmit_data_q).
366            The l2cap layer will resend the packet to lower layer when controller buffer
367            can be used.
368         */
369 
370         dispatch_reassembled(packet);
371         //data_dispatcher_dispatch(interface.event_dispatcher, packet->event & MSG_EVT_MASK, packet);
372     }
373 }
374 
restart_command_waiting_response_timer(command_waiting_response_t * cmd_wait_q)375 static void restart_command_waiting_response_timer(command_waiting_response_t *cmd_wait_q)
376 {
377     osi_mutex_lock(&cmd_wait_q->commands_pending_response_lock, OSI_MUTEX_MAX_TIMEOUT);
378     if (cmd_wait_q->timer_is_set) {
379         osi_alarm_cancel(cmd_wait_q->command_response_timer);
380         cmd_wait_q->timer_is_set = false;
381     }
382     if (!list_is_empty(cmd_wait_q->commands_pending_response)) {
383         osi_alarm_set(cmd_wait_q->command_response_timer, COMMAND_PENDING_TIMEOUT);
384         cmd_wait_q->timer_is_set = true;
385     }
386     osi_mutex_unlock(&cmd_wait_q->commands_pending_response_lock);
387 }
388 
command_timed_out(void * context)389 static void command_timed_out(void *context)
390 {
391     command_waiting_response_t *cmd_wait_q = (command_waiting_response_t *)context;
392     waiting_command_t *wait_entry;
393 
394     osi_mutex_lock(&cmd_wait_q->commands_pending_response_lock, OSI_MUTEX_MAX_TIMEOUT);
395     wait_entry = (list_is_empty(cmd_wait_q->commands_pending_response) ?
396                   NULL : list_front(cmd_wait_q->commands_pending_response));
397     osi_mutex_unlock(&cmd_wait_q->commands_pending_response_lock);
398 
399     if (wait_entry == NULL) {
400         HCI_TRACE_ERROR("%s with no commands pending response", __func__);
401     } else
402         // We shouldn't try to recover the stack from this command timeout.
403         // If it's caused by a software bug, fix it. If it's a hardware bug, fix it.
404     {
405         HCI_TRACE_ERROR("%s hci layer timeout waiting for response to a command. opcode: 0x%x", __func__, wait_entry->opcode);
406     }
407 }
408 
409 // Event/packet receiving functions
hal_says_packet_ready(BT_HDR * packet)410 static void hal_says_packet_ready(BT_HDR *packet)
411 {
412     if (packet->event != MSG_HC_TO_STACK_HCI_EVT) {
413         packet_fragmenter->reassemble_and_dispatch(packet);
414     } else if (!filter_incoming_event(packet)) {
415         dispatch_reassembled(packet);
416     }
417 }
418 
419 // Returns true if the event was intercepted and should not proceed to
420 // higher layers. Also inspects an incoming event for interesting
421 // information, like how many commands are now able to be sent.
filter_incoming_event(BT_HDR * packet)422 static bool filter_incoming_event(BT_HDR *packet)
423 {
424     waiting_command_t *wait_entry = NULL;
425     uint8_t *stream = packet->data + packet->offset;
426     uint8_t event_code;
427     command_opcode_t opcode;
428 
429     STREAM_TO_UINT8(event_code, stream);
430     STREAM_SKIP_UINT8(stream); // Skip the parameter total length field
431 
432     HCI_TRACE_DEBUG("Receive packet event_code=0x%x\n", event_code);
433 
434     if (event_code == HCI_COMMAND_COMPLETE_EVT) {
435         STREAM_TO_UINT8(hci_host_env.command_credits, stream);
436         STREAM_TO_UINT16(opcode, stream);
437         wait_entry = get_waiting_command(opcode);
438         if (!wait_entry) {
439             HCI_TRACE_WARNING("%s command complete event with no matching command. opcode: 0x%x.", __func__, opcode);
440         } else if (wait_entry->complete_callback) {
441             wait_entry->complete_callback(packet, wait_entry->context);
442 #if (BLE_50_FEATURE_SUPPORT == TRUE)
443             BlE_SYNC *sync_info =  btsnd_hcic_ble_get_sync_info();
444             if(!sync_info) {
445                 HCI_TRACE_WARNING("%s sync_info is NULL. opcode = 0x%x", __func__, opcode);
446             } else {
447                 if (sync_info->sync_sem && sync_info->opcode == opcode) {
448                     osi_sem_give(&sync_info->sync_sem);
449                     sync_info->opcode = 0;
450                 }
451             }
452 #endif // #if (BLE_50_FEATURE_SUPPORT == TRUE)
453         } else if (wait_entry->complete_future) {
454             future_ready(wait_entry->complete_future, packet);
455         }
456 
457         goto intercepted;
458     } else if (event_code == HCI_COMMAND_STATUS_EVT) {
459         uint8_t status;
460         STREAM_TO_UINT8(status, stream);
461         STREAM_TO_UINT8(hci_host_env.command_credits, stream);
462         STREAM_TO_UINT16(opcode, stream);
463 
464         // If a command generates a command status event, it won't be getting a command complete event
465 
466         wait_entry = get_waiting_command(opcode);
467         if (!wait_entry) {
468             HCI_TRACE_WARNING("%s command status event with no matching command. opcode: 0x%x", __func__, opcode);
469         } else if (wait_entry->status_callback) {
470             wait_entry->status_callback(status, wait_entry->command, wait_entry->context);
471         }
472 
473         goto intercepted;
474     }
475 
476     return false;
477 intercepted:
478     restart_command_waiting_response_timer(&hci_host_env.cmd_waiting_q);
479 
480     /*Tell HCI Host Task to continue TX Pending commands*/
481     if (hci_host_env.command_credits &&
482             !fixed_queue_is_empty(hci_host_env.command_queue)) {
483         hci_host_task_post(OSI_THREAD_MAX_TIMEOUT);
484     }
485 
486     if (wait_entry) {
487         // If it has a callback, it's responsible for freeing the packet
488         if (event_code == HCI_COMMAND_STATUS_EVT ||
489                 (!wait_entry->complete_callback && !wait_entry->complete_future)) {
490             osi_free(packet);
491         }
492 
493         // If it has a callback, it's responsible for freeing the command
494         if (event_code == HCI_COMMAND_COMPLETE_EVT || !wait_entry->status_callback) {
495             osi_free(wait_entry->command);
496         }
497 
498         osi_free(wait_entry);
499     } else {
500         osi_free(packet);
501     }
502 
503     return true;
504 }
505 
506 // Callback for the fragmenter to dispatch up a completely reassembled packet
dispatch_reassembled(BT_HDR * packet)507 static void dispatch_reassembled(BT_HDR *packet)
508 {
509     // Events should already have been dispatched before this point
510     //Tell Up-layer received packet.
511     if (btu_task_post(SIG_BTU_HCI_MSG, packet, OSI_THREAD_MAX_TIMEOUT) == false) {
512         osi_free(packet);
513     }
514 }
515 
516 // Misc internal functions
517 
518 // TODO(zachoverflow): we seem to do this a couple places, like the HCI inject module. #centralize
event_to_data_type(uint16_t event)519 static serial_data_type_t event_to_data_type(uint16_t event)
520 {
521     if (event == MSG_STACK_TO_HC_HCI_ACL) {
522         return DATA_TYPE_ACL;
523     } else if (event == MSG_STACK_TO_HC_HCI_SCO) {
524         return DATA_TYPE_SCO;
525     } else if (event == MSG_STACK_TO_HC_HCI_CMD) {
526         return DATA_TYPE_COMMAND;
527     } else {
528         HCI_TRACE_ERROR("%s invalid event type, could not translate 0x%x\n", __func__, event);
529     }
530 
531     return 0;
532 }
533 
get_waiting_command(command_opcode_t opcode)534 static waiting_command_t *get_waiting_command(command_opcode_t opcode)
535 {
536     command_waiting_response_t *cmd_wait_q = &hci_host_env.cmd_waiting_q;
537     osi_mutex_lock(&cmd_wait_q->commands_pending_response_lock, OSI_MUTEX_MAX_TIMEOUT);
538 
539     for (const list_node_t *node = list_begin(cmd_wait_q->commands_pending_response);
540             node != list_end(cmd_wait_q->commands_pending_response);
541             node = list_next(node)) {
542         waiting_command_t *wait_entry = list_node(node);
543         if (!wait_entry || wait_entry->opcode != opcode) {
544             continue;
545         }
546 
547         list_remove(cmd_wait_q->commands_pending_response, wait_entry);
548 
549         osi_mutex_unlock(&cmd_wait_q->commands_pending_response_lock);
550         return wait_entry;
551     }
552 
553     osi_mutex_unlock(&cmd_wait_q->commands_pending_response_lock);
554     return NULL;
555 }
556 
init_layer_interface(void)557 static void init_layer_interface(void)
558 {
559     if (!interface_created) {
560         interface.transmit_command = transmit_command;
561         interface.transmit_command_futured = transmit_command_futured;
562         interface.transmit_downward = transmit_downward;
563         interface_created = true;
564     }
565 }
566 
567 static const hci_hal_callbacks_t hal_callbacks = {
568     hal_says_packet_ready
569 };
570 
571 static const packet_fragmenter_callbacks_t packet_fragmenter_callbacks = {
572     transmit_fragment,
573     dispatch_reassembled,
574     fragmenter_transmit_finished
575 };
576 
hci_layer_get_interface(void)577 const hci_t *hci_layer_get_interface(void)
578 {
579     hal = hci_hal_h4_get_interface();
580     packet_fragmenter = packet_fragmenter_get_interface();
581 
582     init_layer_interface();
583     return &interface;
584 }
585