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