xref: /btstack/example/le_mitm.c (revision ced70f9bfeafe291ec597a3a9cc862e39e0da3ce)
1 /*
2  * Copyright (C) 2019 BlueKitchen GmbH
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holders nor the names of
14  *    contributors may be used to endorse or promote products derived
15  *    from this software without specific prior written permission.
16  * 4. Any redistribution, use, or modification is done solely for
17  *    personal benefit and not for any commercial purpose or for
18  *    monetary gain.
19  *
20  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24  * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * Please inquire about commercial licensing options at
34  * [email protected]
35  *
36  */
37 
38 #define BTSTACK_FILE__ "le_mitm.c"
39 
40 // *****************************************************************************
41 /* EXAMPLE_START(le_mitm): LE Man-in-the-Middle Tool
42  *
43  * @text The example first does an LE scan and allows the user to select a Peripheral
44  * device. Then, it connects to the Peripheral and starts advertising with the same
45  * data as the Peripheral device.
46  * ATT Requests and responses are forwarded between the peripheral and the central
47  * Security requests are handled locally.
48  *
49  * @note A Bluetooth Controller that supports Central and Peripheral Role
50  * at the same time is required for this example. See chipset/README.md
51  *
52  */
53 // *****************************************************************************
54 
55 
56 #include <inttypes.h>
57 #include <stdint.h>
58 #include <stdio.h>
59 #include <string.h>
60 
61 #include "btstack.h"
62 
63 // Number of devices shown during scanning
64 #define MAX_NUM_DEVICES 36
65 
66 // Max number of ATT PTUs to queue (if malloc is not used)
67 #define MAX_NUM_ATT_PDUS 20
68 
69 // Max ATT MTU - can be increased if needed
70 #define MAX_ATT_MTU ATT_DEFAULT_MTU
71 
72 typedef struct {
73     bd_addr_t addr;
74     bd_addr_type_t addr_type;
75     int8_t  rssi;
76     uint8_t ad_len;
77     uint8_t ad_data[31];
78     uint8_t scan_len;
79     uint8_t scan_data[31];
80 } device_info_t;
81 
82 typedef struct {
83     btstack_linked_item_t  item;
84     hci_con_handle_t handle;
85     uint8_t len;
86     uint8_t data[MAX_ATT_MTU];
87 } att_pdu_t;
88 
89 typedef enum {
90     TC_OFF,
91     TC_SCANNING,
92     TC_W4_CONNECT,
93     TC_CONNECTED,
94 } app_state_t;
95 
96 static uint16_t devices_found;
97 static device_info_t devices[MAX_NUM_DEVICES];
98 
99 static uint16_t         remote_peripheral_index;
100 static bd_addr_t        remote_peripheral_addr;
101 static bd_addr_type_t   remote_peripheral_addr_type;
102 static hci_con_handle_t remote_peripheral_handle;
103 
104 static hci_con_handle_t remote_central_handle;
105 
106 static btstack_linked_list_t outgoing_att_pdus;
107 
108 static app_state_t state = TC_OFF;
109 static btstack_packet_callback_registration_t hci_event_callback_registration;
110 static btstack_packet_callback_registration_t sm_event_callback_registration;
111 
112 static const char * ad_types[] = {
113         "",
114         "Flags",
115         "Incomplete 16-bit UUIDs",
116         "Complete 16-bit UUIDs",
117         "Incomplete 32-bit UUIDs",
118         "Complete 32-bit UUIDs",
119         "Incomplete 128-bit UUIDs",
120         "Complete 128-bit UUIDs",
121         "Short Name",
122         "Complete Name",
123         "Tx Power Level",
124         "",
125         "",
126         "Class of Device",
127         "Simple Pairing Hash C",
128         "Simple Pairing Randomizer R",
129         "Device ID",
130         "Security Manager TK Value",
131         "Slave Connection Interval Range",
132         "",
133         "16-bit Solicitation UUIDs",
134         "128-bit Solicitation UUIDs",
135         "Service Data",
136         "Public Target Address",
137         "Random Target Address",
138         "Appearance",
139         "Advertising Interval"
140 };
141 
142 static const char * adv_failed_warning = "\n"
143  "[!] Start advertising failed!\n"
144  "[!] Make sure your Bluetooth Controller supports Central and Peripheral Roles at the same time.\n\n";
145 
146 // att pdu pool implementation
147 #ifndef HAVE_MALLOC
148 static att_pdu_t att_pdu_storage[MAX_NUM_ATT_PDUS];
149 static btstack_memory_pool_t att_pdu_pool;
150 static att_pdu_t * btstack_memory_att_pdu_get(void){
151     void * buffer = btstack_memory_pool_get(&att_pdu_pool);
152     if (buffer){
153         memset(buffer, 0, sizeof(att_pdu_t));
154     }
155     return (att_pdu_t *) buffer;
156 }
157 static void btstack_memory_att_pdu_free(att_pdu_t *att_pdu){
158     btstack_memory_pool_free(&att_pdu_pool, att_pdu);
159 }
160 #else
161 static att_pdu_t * btstack_memory_att_pdu_get(void){
162     void * buffer = malloc(sizeof(att_pdu_t));
163     if (buffer){
164         memset(buffer, 0, sizeof(att_pdu_t));
165     }
166     return (att_pdu_t *) buffer;
167 }
168 static void btstack_memory_att_pdu_free(att_pdu_t * att_pdu){
169     free(att_pdu);
170 }
171 #endif
172 
173 static void mitm_start_scan(btstack_timer_source_t * ts){
174     UNUSED(ts);
175     printf("[-] Start scanning\n");
176     printf("To select device, enter advertisement number:\n");
177     state = TC_SCANNING;
178     gap_set_scan_parameters(0,0x0030, 0x0030);
179     gap_start_scan();
180 }
181 
182 static void mitm_connect(uint16_t index){
183     // stop scanning, and connect to the device
184     gap_stop_scan();
185     state = TC_W4_CONNECT;
186     remote_peripheral_index = index;
187     memcpy(remote_peripheral_addr, devices[index].addr, 6);
188     remote_peripheral_addr_type = devices[index].addr_type;
189     printf("\n");
190     printf("[-] Connecting to Peripheral %s\n", bd_addr_to_str(remote_peripheral_addr));
191     gap_auto_connection_start(remote_peripheral_addr_type, remote_peripheral_addr);
192 }
193 
194 static void mitm_start_advertising(void){
195     // set adv + scan data if available
196     if (devices[remote_peripheral_index].ad_len > 0){
197         gap_advertisements_set_data(devices[remote_peripheral_index].ad_len, devices[remote_peripheral_index].ad_data);
198         printf("[-] Setup adv data (len %02u): ", devices[remote_peripheral_index].ad_len);
199         printf_hexdump(devices[remote_peripheral_index].ad_data, devices[remote_peripheral_index].ad_len);
200     }
201     if (devices[remote_peripheral_index].scan_len > 0){
202         gap_scan_response_set_data(devices[remote_peripheral_index].scan_len, devices[remote_peripheral_index].scan_data);
203         printf("[-] Setup scan data (len %02u): ", devices[remote_peripheral_index].scan_len);
204         printf_hexdump(devices[remote_peripheral_index].ad_data, devices[remote_peripheral_index].ad_len);
205     }
206     uint16_t adv_int_min = 0x0030;
207     uint16_t adv_int_max = 0x0030;
208     uint8_t adv_type = 0;
209     bd_addr_t null_addr;
210     memset(null_addr, 0, 6);
211     gap_advertisements_set_params(adv_int_min, adv_int_max, adv_type, 0, null_addr, 0x07, 0x00);
212     gap_advertisements_enable(1);
213 }
214 
215 static void mitm_print_advertisement(uint16_t index) {
216     // get character for index
217     char c;
218     if (index < 10) {
219         c = '0' + index;
220     } else {
221         c = 'a' + (index - 10);
222     }
223 
224     printf("%c. %s (%-3d dBm)", c, bd_addr_to_str(devices[index].addr), devices[index].rssi);
225 
226     ad_context_t context;
227     bd_addr_t address;
228     uint8_t uuid_128[16];
229     for (ad_iterator_init(&context, devices[index].ad_len, devices[index].ad_data); ad_iterator_has_more(
230             &context); ad_iterator_next(&context)) {
231         uint8_t data_type = ad_iterator_get_data_type(&context);
232         uint8_t size = ad_iterator_get_data_len(&context);
233         const uint8_t *data = ad_iterator_get_data(&context);
234 
235         if (data_type > 0 && data_type < 0x1B) {
236             printf(" - %s: ", ad_types[data_type]);
237         }
238         uint8_t i;
239         switch (data_type) {
240             case BLUETOOTH_DATA_TYPE_FLAGS:
241                 printf("0x%02x", data[0]);
242                 break;
243             case BLUETOOTH_DATA_TYPE_INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS:
244             case BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS:
245             case BLUETOOTH_DATA_TYPE_LIST_OF_16_BIT_SERVICE_SOLICITATION_UUIDS:
246                 for (i = 0; i < size; i += 2) {
247                     printf("%02X ", little_endian_read_16(data, i));
248                 }
249                 break;
250             case BLUETOOTH_DATA_TYPE_INCOMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS:
251             case BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_32_BIT_SERVICE_CLASS_UUIDS:
252             case BLUETOOTH_DATA_TYPE_LIST_OF_32_BIT_SERVICE_SOLICITATION_UUIDS:
253                 for (i = 0; i < size; i += 4) {
254                     printf("%04"PRIX32, little_endian_read_32(data, i));
255                 }
256                 break;
257             case BLUETOOTH_DATA_TYPE_INCOMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS:
258             case BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS:
259             case BLUETOOTH_DATA_TYPE_LIST_OF_128_BIT_SERVICE_SOLICITATION_UUIDS:
260                 reverse_128(data, uuid_128);
261                 printf("%s", uuid128_to_str(uuid_128));
262                 break;
263             case BLUETOOTH_DATA_TYPE_SHORTENED_LOCAL_NAME:
264             case BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME:
265                 for (i = 0; i < size; i++) {
266                     printf("%c", (char) (data[i]));
267                 }
268                 break;
269             case BLUETOOTH_DATA_TYPE_TX_POWER_LEVEL:
270                 printf("%d dBm", *(int8_t *) data);
271                 break;
272             case BLUETOOTH_DATA_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE:
273                 printf("Connection Interval Min = %u ms, Max = %u ms", little_endian_read_16(data, 0) * 5 / 4,
274                        little_endian_read_16(data, 2) * 5 / 4);
275                 break;
276             case BLUETOOTH_DATA_TYPE_SERVICE_DATA:
277                 printf_hexdump(data, size);
278                 break;
279             case BLUETOOTH_DATA_TYPE_PUBLIC_TARGET_ADDRESS:
280             case BLUETOOTH_DATA_TYPE_RANDOM_TARGET_ADDRESS:
281                 reverse_bd_addr(data, address);
282                 printf("%s", bd_addr_to_str(address));
283                 break;
284             case BLUETOOTH_DATA_TYPE_APPEARANCE:
285                 // https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml
286                 printf("%02X", little_endian_read_16(data, 0));
287                 break;
288             case BLUETOOTH_DATA_TYPE_ADVERTISING_INTERVAL:
289                 printf("%u ms", little_endian_read_16(data, 0) * 5 / 8);
290                 break;
291             case BLUETOOTH_DATA_TYPE_3D_INFORMATION_DATA:
292                 printf_hexdump(data, size);
293                 break;
294             case BLUETOOTH_DATA_TYPE_MANUFACTURER_SPECIFIC_DATA:
295             case BLUETOOTH_DATA_TYPE_CLASS_OF_DEVICE:
296             case BLUETOOTH_DATA_TYPE_SIMPLE_PAIRING_HASH_C:
297             case BLUETOOTH_DATA_TYPE_SIMPLE_PAIRING_RANDOMIZER_R:
298             case BLUETOOTH_DATA_TYPE_DEVICE_ID:
299             case BLUETOOTH_DATA_TYPE_SECURITY_MANAGER_OUT_OF_BAND_FLAGS:
300             default:
301                 break;
302         }
303     }
304     printf("\n");
305 }
306 
307 static void mitm_handle_adv(uint8_t * packet){
308     // get addr and type
309     bd_addr_t remote_addr;
310     gap_event_advertising_report_get_address(packet, remote_addr);
311     bd_addr_type_t remote_addr_type = gap_event_advertising_report_get_address_type(packet);
312     uint8_t adv_event_type = gap_event_advertising_report_get_advertising_event_type(packet);
313     bool is_scan_response = adv_event_type == 2 || adv_event_type == 4;
314 
315     // find remote in list
316     uint16_t i;
317     for (i=0;i<devices_found;i++) {
318         if (memcmp(remote_addr, devices[i].addr, 6) != 0) continue;
319         if (remote_addr_type != devices[i].addr_type) continue;
320         break;
321     }
322 
323     if (i == MAX_NUM_DEVICES) return;
324 
325     if (devices_found == i){
326         // skip first event with scan response data (should not happen)
327         if (is_scan_response) return;
328         memset(&devices[i], 0, sizeof(device_info_t));
329         devices[i].rssi = (int8_t) gap_event_advertising_report_get_rssi(packet);
330         devices[i].addr_type = remote_addr_type;
331         memcpy(devices[i].addr, remote_addr, 6);
332         devices[i].ad_len = gap_event_advertising_report_get_data_length(packet);
333         memcpy(devices[i].ad_data, gap_event_advertising_report_get_data(packet), devices[i].ad_len);
334         mitm_print_advertisement(i);
335         devices_found++;
336         return;
337     }
338 
339     // store scan data
340     if (!is_scan_response) return;
341     devices[i].scan_len = gap_event_advertising_report_get_data_length(packet);
342     memcpy(devices[i].scan_data, gap_event_advertising_report_get_data(packet), devices[i].scan_len);
343 }
344 
345 static void mitm_console_connected_menu(void){
346     printf("=== Connected menu ===\n");
347     printf("p - Pair Peripheral\n");
348 }
349 
350 static hci_con_handle_t mitm_opposite_handle(hci_con_handle_t handle){
351     if (handle == remote_peripheral_handle) {
352         return remote_central_handle;
353     } else {
354         return remote_peripheral_handle;
355     }
356 }
357 
358 static void mitm_request_to_send(void){
359     // request to send again if more packets queued
360     if (btstack_linked_list_empty(&outgoing_att_pdus)) return;
361     att_pdu_t * pdu = (att_pdu_t *) btstack_linked_list_get_first_item((&outgoing_att_pdus));
362     l2cap_request_can_send_fix_channel_now_event(pdu->handle, L2CAP_CID_ATTRIBUTE_PROTOCOL);
363 }
364 
365 static const char * mitm_name_for_handle(hci_con_handle_t handle){
366     if (handle == remote_peripheral_handle) return "Peripheral";
367     if (handle == remote_central_handle)    return "Central";
368     return "(unknown handle)'";
369 }
370 
371 static void hci_event_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
372     UNUSED(channel);
373     UNUSED(size);
374 
375     if (packet_type != HCI_EVENT_PACKET) return;
376 
377     uint8_t event = hci_event_packet_get_type(packet);
378     hci_con_handle_t connection_handle;
379     uint32_t passkey;
380 
381     switch (event) {
382         case BTSTACK_EVENT_STATE:
383             // BTstack activated, get started
384             if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING) {
385                 mitm_start_scan(NULL);
386                 state = TC_SCANNING;
387             } else {
388                 state = TC_OFF;
389             }
390             break;
391         case GAP_EVENT_ADVERTISING_REPORT:
392             if (state != TC_SCANNING) return;
393             mitm_handle_adv(packet);
394             break;
395         case HCI_EVENT_COMMAND_COMPLETE:
396             // warn if adv enable fails
397             if (hci_event_command_complete_get_command_opcode(packet) != hci_le_set_advertise_enable.opcode) break;
398             if (hci_event_command_complete_get_return_parameters(packet)[0] == ERROR_CODE_SUCCESS) break;
399             printf("%s", adv_failed_warning);
400             break;
401         case HCI_EVENT_META_GAP:
402             // wait for connection complete
403             if (hci_event_gap_meta_get_subevent_code(packet) !=  GAP_SUBEVENT_LE_CONNECTION_COMPLETE) break;
404             switch (state){
405                 case TC_W4_CONNECT:
406                     state = TC_CONNECTED;
407                     remote_peripheral_handle = gap_subevent_le_connection_complete_get_connection_handle(packet);
408                     printf("[-] Peripheral connected\n");
409                     mitm_start_advertising();
410                     printf ("You can connect now!\n");
411                     printf("\n");
412                     mitm_console_connected_menu();
413                     break;
414                 case TC_CONNECTED:
415                     remote_central_handle = gap_subevent_le_connection_complete_get_connection_handle(packet);
416                     printf("[-] Central connected!\n");
417                     break;
418                 default:
419                     break;
420             }
421             break;
422         case HCI_EVENT_DISCONNECTION_COMPLETE:
423             // unregister listener
424             connection_handle = HCI_CON_HANDLE_INVALID;
425             printf("[-] %s disconnected", mitm_name_for_handle(connection_handle));
426             if (connection_handle == remote_peripheral_handle){
427                 mitm_start_scan(NULL);
428                 state = TC_SCANNING;
429             }
430             break;
431         case SM_EVENT_JUST_WORKS_REQUEST:
432             connection_handle = sm_event_just_works_request_get_handle(packet);
433             printf("[-] %s request 'Just Works' pairing\n", mitm_name_for_handle(connection_handle));
434             sm_just_works_confirm(connection_handle);
435             break;
436         case SM_EVENT_NUMERIC_COMPARISON_REQUEST:
437             passkey = sm_event_numeric_comparison_request_get_passkey(packet);
438             connection_handle = sm_event_numeric_comparison_request_get_handle(packet);
439             printf("[-] %s accepting numeric comparison: %"PRIu32"\n", mitm_name_for_handle(connection_handle), passkey);
440             sm_numeric_comparison_confirm(connection_handle);
441             break;
442         case SM_EVENT_PASSKEY_DISPLAY_NUMBER:
443             passkey = sm_event_passkey_display_number_get_passkey(packet);
444             connection_handle = sm_event_passkey_display_number_get_handle(packet);
445             printf("[-] %s display passkey: %"PRIu32"\n", mitm_name_for_handle(connection_handle), passkey);
446             break;
447         case SM_EVENT_PAIRING_COMPLETE:
448             connection_handle = sm_event_pairing_complete_get_handle(packet);
449             switch (sm_event_pairing_complete_get_status(packet)){
450                 case ERROR_CODE_SUCCESS:
451                     printf("[-] %s pairing complete, success\n", mitm_name_for_handle(connection_handle));
452                     break;
453                 case ERROR_CODE_CONNECTION_TIMEOUT:
454                     printf("[-] %s pairing failed, timeout\n", mitm_name_for_handle(connection_handle));
455                     break;
456                 case ERROR_CODE_REMOTE_USER_TERMINATED_CONNECTION:
457                     printf("[-] %s pairing failed, disconnected\n", mitm_name_for_handle(connection_handle));
458                     break;
459                 case ERROR_CODE_AUTHENTICATION_FAILURE:
460                     printf("[-] %s pairing failed, reason = %u\n", mitm_name_for_handle(connection_handle), sm_event_pairing_complete_get_reason(packet));
461                     break;
462                 default:
463                     break;
464             }
465             break;
466         case SM_EVENT_REENCRYPTION_COMPLETE:
467             connection_handle = sm_event_reencryption_complete_get_handle(packet);
468             printf("[-] %s Re-encryption complete, success\n", mitm_name_for_handle(connection_handle));
469             break;
470         default:
471             break;
472     }
473 }
474 
475 static void att_packet_handler(uint8_t packet_type, uint16_t handle, uint8_t *packet, uint16_t size){
476     att_pdu_t * pdu;
477     switch (packet_type){
478         case ATT_DATA_PACKET:
479             printf("[%10s] ", mitm_name_for_handle(handle));
480             printf_hexdump(packet, size);
481             pdu = btstack_memory_att_pdu_get();
482             if (!pdu) break;
483             // handle att mtu exchange directly
484             if (packet[0] == ATT_EXCHANGE_MTU_REQUEST){
485                 pdu->handle = handle;
486                 pdu->len = 3;
487                 pdu->data[0] = ATT_EXCHANGE_MTU_RESPONSE;
488                 little_endian_store_16(pdu->data, 1, MAX_ATT_MTU);
489             } else {
490                 btstack_assert(size <= MAX_ATT_MTU);
491                 pdu->handle = mitm_opposite_handle(handle);
492                 pdu->len = (uint8_t) size;
493                 memcpy(pdu->data, packet, size);
494             }
495             btstack_linked_list_add_tail(&outgoing_att_pdus, (btstack_linked_item_t *) pdu);
496             mitm_request_to_send();
497             break;
498         case HCI_EVENT_PACKET:
499             if (packet[0] == L2CAP_EVENT_CAN_SEND_NOW) {
500                 // send next packet
501                 pdu = (att_pdu_t *) btstack_linked_list_pop(&outgoing_att_pdus);
502                 if (pdu == NULL) break;
503                 l2cap_send_connectionless(pdu->handle, L2CAP_CID_ATTRIBUTE_PROTOCOL, pdu->data, pdu->len);
504                 btstack_memory_att_pdu_free(pdu);
505                 // request to send again if more packets queued
506                 mitm_request_to_send();
507             }
508             break;
509         default:
510             break;
511     }
512 }
513 
514 static void stdin_process(char cmd) {
515     unsigned int index;
516     switch(state){
517         case TC_OFF:
518             break;
519         case TC_SCANNING:
520             if ((cmd >= '0') && (cmd <= '9')){
521                 index = cmd - '0';
522             } else if ((cmd >= 'a') && (cmd <= 'z')){
523                 index = cmd - 'a' + 10;
524             } else {
525                 break;
526             }
527             if (index >= devices_found) break;
528             mitm_connect(index);
529             break;
530         case TC_CONNECTED:
531             switch (cmd){
532                 case 'p':
533                     printf("[-] Start pairing / encryption with Peripheral\n");
534                     sm_request_pairing(remote_peripheral_handle);
535                     break;
536                 default:
537                     mitm_console_connected_menu();
538                     break;
539             }
540             break;
541         default:
542             break;
543     }
544 }
545 
546 int btstack_main(int argc, const char * argv[]);
547 int btstack_main(int argc, const char * argv[]){
548 
549     (void)argc;
550     (void)argv;
551 
552     l2cap_init();
553 
554     l2cap_register_fixed_channel(att_packet_handler, L2CAP_CID_ATTRIBUTE_PROTOCOL);
555 
556     sm_init();
557 
558     hci_event_callback_registration.callback = &hci_event_handler;
559     hci_add_event_handler(&hci_event_callback_registration);
560 
561     sm_event_callback_registration.callback = &hci_event_handler;
562     sm_add_event_handler(&sm_event_callback_registration);
563 
564 #ifndef HAVE_MALLOC
565     btstack_memory_pool_create(&att_pdu_pool, att_pdu_storage, MAX_NUM_ATT_PDUS, sizeof(att_pdu_t));
566 #endif
567 
568 #ifdef HAVE_BTSTACK_STDIN
569     btstack_stdin_setup(stdin_process);
570 #endif
571 
572     // turn on!
573     hci_power_control(HCI_POWER_ON);
574 
575     return 0;
576 }
577 /* EXAMPLE_END */
578