16b7b368aSMatthias Ringwald /* 26b7b368aSMatthias Ringwald * Copyright (C) 2014 BlueKitchen GmbH 36b7b368aSMatthias Ringwald * 46b7b368aSMatthias Ringwald * Redistribution and use in source and binary forms, with or without 56b7b368aSMatthias Ringwald * modification, are permitted provided that the following conditions 66b7b368aSMatthias Ringwald * are met: 76b7b368aSMatthias Ringwald * 86b7b368aSMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 96b7b368aSMatthias Ringwald * notice, this list of conditions and the following disclaimer. 106b7b368aSMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 116b7b368aSMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 126b7b368aSMatthias Ringwald * documentation and/or other materials provided with the distribution. 136b7b368aSMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 146b7b368aSMatthias Ringwald * contributors may be used to endorse or promote products derived 156b7b368aSMatthias Ringwald * from this software without specific prior written permission. 166b7b368aSMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 176b7b368aSMatthias Ringwald * personal benefit and not for any commercial purpose or for 186b7b368aSMatthias Ringwald * monetary gain. 196b7b368aSMatthias Ringwald * 206b7b368aSMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 216b7b368aSMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 226b7b368aSMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 236b7b368aSMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 246b7b368aSMatthias Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 256b7b368aSMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 266b7b368aSMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 276b7b368aSMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 286b7b368aSMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 296b7b368aSMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 306b7b368aSMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 316b7b368aSMatthias Ringwald * SUCH DAMAGE. 326b7b368aSMatthias Ringwald * 336b7b368aSMatthias Ringwald * Please inquire about commercial licensing options at 346b7b368aSMatthias Ringwald * [email protected] 356b7b368aSMatthias Ringwald * 366b7b368aSMatthias Ringwald */ 376b7b368aSMatthias Ringwald 386b7b368aSMatthias Ringwald // ***************************************************************************** 396b7b368aSMatthias Ringwald /* EXAMPLE_START(sm_test): Security Manager Test 406b7b368aSMatthias Ringwald * 416b7b368aSMatthias Ringwald */ 426b7b368aSMatthias Ringwald // ***************************************************************************** 436b7b368aSMatthias Ringwald 446b7b368aSMatthias Ringwald #include <stdint.h> 456b7b368aSMatthias Ringwald #include <stdio.h> 466b7b368aSMatthias Ringwald #include <stdlib.h> 476b7b368aSMatthias Ringwald #include <string.h> 486b7b368aSMatthias Ringwald #include <unistd.h> 496b7b368aSMatthias Ringwald 506b7b368aSMatthias Ringwald #include "btstack_config.h" 516b7b368aSMatthias Ringwald 526b7b368aSMatthias Ringwald #include "ble/att_db.h" 536b7b368aSMatthias Ringwald #include "ble/att_server.h" 546b7b368aSMatthias Ringwald #include "ble/le_device_db.h" 556b7b368aSMatthias Ringwald #include "ble/sm.h" 566b7b368aSMatthias Ringwald #include "btstack_debug.h" 576b7b368aSMatthias Ringwald #include "btstack_event.h" 586b7b368aSMatthias Ringwald #include "btstack_memory.h" 596b7b368aSMatthias Ringwald #include "btstack_run_loop.h" 606b7b368aSMatthias Ringwald #include "gap.h" 616b7b368aSMatthias Ringwald #include "hci.h" 626b7b368aSMatthias Ringwald #include "hci_dump.h" 636b7b368aSMatthias Ringwald #include "l2cap.h" 646b7b368aSMatthias Ringwald #include "btstack_stdin.h" 656b7b368aSMatthias Ringwald 66b4394846SMatthias Ringwald #ifdef COVERAGE 67b4394846SMatthias Ringwald // guesswork: 68b4394846SMatthias Ringwald void __gcov_flush(void); 69b4394846SMatthias Ringwald #endif 70b4394846SMatthias Ringwald 716b7b368aSMatthias Ringwald #define HEARTBEAT_PERIOD_MS 1000 726b7b368aSMatthias Ringwald 736b7b368aSMatthias Ringwald const uint8_t adv_data[] = { 746b7b368aSMatthias Ringwald // Flags general discoverable, BR/EDR not supported 756b7b368aSMatthias Ringwald 0x02, 0x01, 0x06, 766b7b368aSMatthias Ringwald // Name 776b7b368aSMatthias Ringwald 0x0d, 0x09, 'S', 'M', ' ', 'P', 'e', 'r', 'i', 'p', 'h', 'e', 'a', 'l' 786b7b368aSMatthias Ringwald }; 796b7b368aSMatthias Ringwald const uint8_t adv_data_len = sizeof(adv_data); 806b7b368aSMatthias Ringwald 816b7b368aSMatthias Ringwald // test profile 826b7b368aSMatthias Ringwald #include "sm_test.h" 836b7b368aSMatthias Ringwald 846b7b368aSMatthias Ringwald static uint8_t sm_have_oob_data = 0; 856b7b368aSMatthias Ringwald static io_capability_t sm_io_capabilities = IO_CAPABILITY_DISPLAY_ONLY; 866b7b368aSMatthias Ringwald static uint8_t sm_auth_req = 0; 876b7b368aSMatthias Ringwald static uint8_t sm_failure = 0; 886b7b368aSMatthias Ringwald 896b7b368aSMatthias Ringwald // legacy pairing oob 906b7b368aSMatthias Ringwald static uint8_t sm_oob_tk_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; 916b7b368aSMatthias Ringwald 926b7b368aSMatthias Ringwald // sc pairing oob 936b7b368aSMatthias Ringwald static uint8_t sm_oob_local_random[16]; 946b7b368aSMatthias Ringwald static uint8_t sm_oob_peer_random[16]; 956b7b368aSMatthias Ringwald static uint8_t sm_oob_peer_confirm[16]; 966b7b368aSMatthias Ringwald 976b7b368aSMatthias Ringwald static int we_are_central = 0; 986b7b368aSMatthias Ringwald static bd_addr_t peer_address; 996b7b368aSMatthias Ringwald 1006b7b368aSMatthias Ringwald static int ui_passkey = 0; 1016b7b368aSMatthias Ringwald static int ui_digits_for_passkey = 0; 1026b7b368aSMatthias Ringwald static int ui_oob_confirm; 1036b7b368aSMatthias Ringwald static int ui_oob_random; 1046b7b368aSMatthias Ringwald static int ui_oob_pos; 1056b7b368aSMatthias Ringwald static int ui_oob_nibble; 1066b7b368aSMatthias Ringwald 1076b7b368aSMatthias Ringwald static btstack_timer_source_t heartbeat; 1086b7b368aSMatthias Ringwald static uint8_t counter = 0; 1096b7b368aSMatthias Ringwald 1106b7b368aSMatthias Ringwald static uint16_t connection_handle = 0; 1116b7b368aSMatthias Ringwald 1126b7b368aSMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration; 1136b7b368aSMatthias Ringwald static btstack_packet_callback_registration_t sm_event_callback_registration; 1146b7b368aSMatthias Ringwald 1156b7b368aSMatthias Ringwald typedef enum { 1166b7b368aSMatthias Ringwald TC_IDLE, 1176b7b368aSMatthias Ringwald TC_W4_SCAN_RESULT, 1186b7b368aSMatthias Ringwald TC_W4_CONNECT, 1196b7b368aSMatthias Ringwald TC_W4_SERVICE_RESULT, 1206b7b368aSMatthias Ringwald TC_W4_CHARACTERISTIC_RESULT, 1216b7b368aSMatthias Ringwald TC_W4_SUBSCRIBED, 1226b7b368aSMatthias Ringwald TC_SUBSCRIBED 1236b7b368aSMatthias Ringwald } gc_state_t; 1246b7b368aSMatthias Ringwald 1256b7b368aSMatthias Ringwald static gc_state_t state = TC_IDLE; 1266b7b368aSMatthias Ringwald 1276b7b368aSMatthias Ringwald static uint8_t le_counter_service_uuid[16] = { 0x00, 0x00, 0xFF, 0x10, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB}; 1286b7b368aSMatthias Ringwald static uint8_t le_counter_characteristic_uuid[16] = { 0x00, 0x00, 0xFF, 0x11, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB}; 1296b7b368aSMatthias Ringwald 1306b7b368aSMatthias Ringwald static gatt_client_service_t le_counter_service; 1316b7b368aSMatthias Ringwald static gatt_client_characteristic_t le_counter_characteristic; 1326b7b368aSMatthias Ringwald 1336b7b368aSMatthias Ringwald static gatt_client_notification_t notification_listener; 1346b7b368aSMatthias Ringwald static void heartbeat_handler(struct btstack_timer_source *ts){ 1356b7b368aSMatthias Ringwald // restart timer 1366b7b368aSMatthias Ringwald btstack_run_loop_set_timer(ts, HEARTBEAT_PERIOD_MS); 1376b7b368aSMatthias Ringwald btstack_run_loop_add_timer(ts); 1386b7b368aSMatthias Ringwald counter++; 1396b7b368aSMatthias Ringwald } 1406b7b368aSMatthias Ringwald 1416b7b368aSMatthias Ringwald static int get_oob_data_callback(uint8_t address_type, bd_addr_t addr, uint8_t * oob_data){ 1426b7b368aSMatthias Ringwald UNUSED(address_type); 1436b7b368aSMatthias Ringwald (void)addr; 1446b7b368aSMatthias Ringwald log_info("get_oob_data_callback for %s", bd_addr_to_str(addr)); 1456b7b368aSMatthias Ringwald if(!sm_have_oob_data) return 0; 1466b7b368aSMatthias Ringwald memcpy(oob_data, sm_oob_tk_data, 16); 1476b7b368aSMatthias Ringwald return 1; 1486b7b368aSMatthias Ringwald } 1496b7b368aSMatthias Ringwald 1506b7b368aSMatthias Ringwald static int get_sc_oob_data_callback(uint8_t address_type, bd_addr_t addr, uint8_t * oob_sc_peer_confirm, uint8_t * oob_sc_peer_random){ 1516b7b368aSMatthias Ringwald UNUSED(address_type); 1526b7b368aSMatthias Ringwald (void)addr; 1536b7b368aSMatthias Ringwald log_info("get_sc_oob_data_callback for %s", bd_addr_to_str(addr)); 1546b7b368aSMatthias Ringwald if(!sm_have_oob_data) return 0; 1556b7b368aSMatthias Ringwald memcpy(oob_sc_peer_confirm, sm_oob_peer_confirm, 16); 1566b7b368aSMatthias Ringwald memcpy(oob_sc_peer_random, sm_oob_peer_random, 16); 1576b7b368aSMatthias Ringwald return 1; 1586b7b368aSMatthias Ringwald } 1596b7b368aSMatthias Ringwald 1606b7b368aSMatthias Ringwald static void sc_local_oob_generated_callback(const uint8_t * confirm_value, const uint8_t * random_value){ 1616b7b368aSMatthias Ringwald printf("LOCAL_OOB_CONFIRM: "); 1626b7b368aSMatthias Ringwald printf_hexdump(confirm_value, 16); 1636b7b368aSMatthias Ringwald printf("LOCAL_OOB_RANDOM: "); 1646b7b368aSMatthias Ringwald printf_hexdump(random_value, 16); 1656b7b368aSMatthias Ringwald fflush(stdout); 1666b7b368aSMatthias Ringwald memcpy(sm_oob_local_random, random_value, 16); 1676b7b368aSMatthias Ringwald } 1686b7b368aSMatthias Ringwald 1696b7b368aSMatthias Ringwald // ATT Client Read Callback for Dynamic Data 1706b7b368aSMatthias Ringwald // - if buffer == NULL, don't copy data, just return size of value 1716b7b368aSMatthias Ringwald // - if buffer != NULL, copy data and return number bytes copied 1726b7b368aSMatthias Ringwald // @param offset defines start of attribute value 1736b7b368aSMatthias Ringwald static uint16_t att_read_callback(hci_con_handle_t con_handle, uint16_t attribute_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){ 1746b7b368aSMatthias Ringwald UNUSED(con_handle); 1756b7b368aSMatthias Ringwald UNUSED(buffer); 1766b7b368aSMatthias Ringwald printf("READ Callback, handle %04x, offset %u, buffer size %u\n", attribute_handle, offset, buffer_size); 1776b7b368aSMatthias Ringwald switch (attribute_handle){ 1786b7b368aSMatthias Ringwald default: 1796b7b368aSMatthias Ringwald break; 1806b7b368aSMatthias Ringwald } 1816b7b368aSMatthias Ringwald return 0; 1826b7b368aSMatthias Ringwald } 1836b7b368aSMatthias Ringwald 1846b7b368aSMatthias Ringwald // write requests 1856b7b368aSMatthias Ringwald static int att_write_callback(hci_con_handle_t con_handle, uint16_t attribute_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size){ 1866b7b368aSMatthias Ringwald UNUSED(con_handle); 1876b7b368aSMatthias Ringwald printf("WRITE Callback, handle %04x, mode %u, offset %u, data: ", attribute_handle, transaction_mode, offset); 1886b7b368aSMatthias Ringwald printf_hexdump(buffer, buffer_size); 1896b7b368aSMatthias Ringwald 1906b7b368aSMatthias Ringwald switch (attribute_handle){ 1916b7b368aSMatthias Ringwald case ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_CLIENT_CONFIGURATION_HANDLE: 1926b7b368aSMatthias Ringwald // short cut, send right away 1936b7b368aSMatthias Ringwald att_server_request_can_send_now_event(con_handle); 1946b7b368aSMatthias Ringwald break; 1956b7b368aSMatthias Ringwald default: 1966b7b368aSMatthias Ringwald break; 1976b7b368aSMatthias Ringwald } 1986b7b368aSMatthias Ringwald return 0; 1996b7b368aSMatthias Ringwald } 2006b7b368aSMatthias Ringwald 2016b7b368aSMatthias Ringwald static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 2026b7b368aSMatthias Ringwald UNUSED(packet_type); 2036b7b368aSMatthias Ringwald UNUSED(channel); 2046b7b368aSMatthias Ringwald UNUSED(size); 2056b7b368aSMatthias Ringwald 2066b7b368aSMatthias Ringwald int status; 2076b7b368aSMatthias Ringwald char message[30]; 2086b7b368aSMatthias Ringwald 2096b7b368aSMatthias Ringwald switch(state){ 2106b7b368aSMatthias Ringwald case TC_W4_SERVICE_RESULT: 2116b7b368aSMatthias Ringwald switch(hci_event_packet_get_type(packet)){ 2126b7b368aSMatthias Ringwald case GATT_EVENT_SERVICE_QUERY_RESULT: 2136b7b368aSMatthias Ringwald gatt_event_service_query_result_get_service(packet, &le_counter_service); 2146b7b368aSMatthias Ringwald break; 2156b7b368aSMatthias Ringwald case GATT_EVENT_QUERY_COMPLETE: 2166b7b368aSMatthias Ringwald if (packet[4] != 0){ 2176b7b368aSMatthias Ringwald printf("SERVICE_QUERY_RESULT - Error status %x.\n", packet[4]); 2186b7b368aSMatthias Ringwald gap_disconnect(connection_handle); 2196b7b368aSMatthias Ringwald break; 2206b7b368aSMatthias Ringwald } 2216b7b368aSMatthias Ringwald state = TC_W4_CHARACTERISTIC_RESULT; 2226b7b368aSMatthias Ringwald printf("Search for counter characteristic.\n"); 2236b7b368aSMatthias Ringwald gatt_client_discover_characteristics_for_service_by_uuid128(handle_gatt_client_event, connection_handle, &le_counter_service, le_counter_characteristic_uuid); 2246b7b368aSMatthias Ringwald break; 2256b7b368aSMatthias Ringwald default: 2266b7b368aSMatthias Ringwald break; 2276b7b368aSMatthias Ringwald } 2286b7b368aSMatthias Ringwald break; 2296b7b368aSMatthias Ringwald 2306b7b368aSMatthias Ringwald case TC_W4_CHARACTERISTIC_RESULT: 2316b7b368aSMatthias Ringwald switch(hci_event_packet_get_type(packet)){ 2326b7b368aSMatthias Ringwald case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT: 2336b7b368aSMatthias Ringwald gatt_event_characteristic_query_result_get_characteristic(packet, &le_counter_characteristic); 2346b7b368aSMatthias Ringwald break; 2356b7b368aSMatthias Ringwald case GATT_EVENT_QUERY_COMPLETE: 2366b7b368aSMatthias Ringwald if (packet[4] != 0){ 2376b7b368aSMatthias Ringwald printf("CHARACTERISTIC_QUERY_RESULT - Error status %x.\n", packet[4]); 2386b7b368aSMatthias Ringwald gap_disconnect(connection_handle); 2396b7b368aSMatthias Ringwald break; 2406b7b368aSMatthias Ringwald } 2416b7b368aSMatthias Ringwald state = TC_W4_SUBSCRIBED; 2426b7b368aSMatthias Ringwald printf("Configure counter for notify.\n"); 2436b7b368aSMatthias Ringwald status = gatt_client_write_client_characteristic_configuration(handle_gatt_client_event, connection_handle, &le_counter_characteristic, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION); 2446b7b368aSMatthias Ringwald break; 2456b7b368aSMatthias Ringwald default: 2466b7b368aSMatthias Ringwald break; 2476b7b368aSMatthias Ringwald } 2486b7b368aSMatthias Ringwald break; 2496b7b368aSMatthias Ringwald case TC_W4_SUBSCRIBED: 2506b7b368aSMatthias Ringwald switch(hci_event_packet_get_type(packet)){ 2516b7b368aSMatthias Ringwald case GATT_EVENT_QUERY_COMPLETE: 2526b7b368aSMatthias Ringwald // register handler for notifications 2536b7b368aSMatthias Ringwald state = TC_SUBSCRIBED; 2546b7b368aSMatthias Ringwald printf("Subscribed, start listening\n"); 2556b7b368aSMatthias Ringwald gatt_client_listen_for_characteristic_value_updates(¬ification_listener, handle_gatt_client_event, connection_handle, &le_counter_characteristic); 2566b7b368aSMatthias Ringwald break; 2576b7b368aSMatthias Ringwald default: 2586b7b368aSMatthias Ringwald break; 2596b7b368aSMatthias Ringwald } 2606b7b368aSMatthias Ringwald break; 2616b7b368aSMatthias Ringwald 2626b7b368aSMatthias Ringwald case TC_SUBSCRIBED: 2636b7b368aSMatthias Ringwald switch(hci_event_packet_get_type(packet)){ 2646b7b368aSMatthias Ringwald case GATT_EVENT_NOTIFICATION: 2656b7b368aSMatthias Ringwald memset(message, 0, sizeof(message)); 2666b7b368aSMatthias Ringwald memcpy(message, gatt_event_notification_get_value(packet), gatt_event_notification_get_value_length(packet)); 2676b7b368aSMatthias Ringwald printf("COUNTER: %s\n", message); 2686b7b368aSMatthias Ringwald log_info("COUNTER: %s", message); 2696b7b368aSMatthias Ringwald break; 2706b7b368aSMatthias Ringwald default: 2716b7b368aSMatthias Ringwald break; 2726b7b368aSMatthias Ringwald } 2736b7b368aSMatthias Ringwald 2746b7b368aSMatthias Ringwald default: 2756b7b368aSMatthias Ringwald break; 2766b7b368aSMatthias Ringwald } 2776b7b368aSMatthias Ringwald fflush(stdout); 2786b7b368aSMatthias Ringwald } 2796b7b368aSMatthias Ringwald 280090b2ae2SMatthias Ringwald static void hci_packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 2816b7b368aSMatthias Ringwald UNUSED(channel); 2826b7b368aSMatthias Ringwald UNUSED(size); 2836b7b368aSMatthias Ringwald bd_addr_t local_addr; 2846b7b368aSMatthias Ringwald switch (packet_type) { 2856b7b368aSMatthias Ringwald case HCI_EVENT_PACKET: 2866b7b368aSMatthias Ringwald switch (packet[0]) { 2876b7b368aSMatthias Ringwald case BTSTACK_EVENT_STATE: 2886b7b368aSMatthias Ringwald // bt stack activated, get started 2896b7b368aSMatthias Ringwald if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING){ 2906b7b368aSMatthias Ringwald gap_local_bd_addr(local_addr); 2916b7b368aSMatthias Ringwald printf("BD_ADDR: %s\n", bd_addr_to_str(local_addr)); 2926b7b368aSMatthias Ringwald // generate OOB data 2936b7b368aSMatthias Ringwald sm_generate_sc_oob_data(sc_local_oob_generated_callback); 2946b7b368aSMatthias Ringwald } 2956b7b368aSMatthias Ringwald break; 2966b7b368aSMatthias Ringwald case HCI_EVENT_LE_META: 2976b7b368aSMatthias Ringwald switch (hci_event_le_meta_get_subevent_code(packet)) { 2986b7b368aSMatthias Ringwald case HCI_SUBEVENT_LE_CONNECTION_COMPLETE: 299*092fc1dbSMatthias Ringwald connection_handle = hci_subevent_le_connection_complete_get_connection_handle(packet); 3006b7b368aSMatthias Ringwald printf("CONNECTED: Connection handle 0x%04x\n", connection_handle); 3016b7b368aSMatthias Ringwald break; 3026b7b368aSMatthias Ringwald default: 3036b7b368aSMatthias Ringwald break; 3046b7b368aSMatthias Ringwald } 3056b7b368aSMatthias Ringwald break; 3066b7b368aSMatthias Ringwald case HCI_EVENT_DISCONNECTION_COMPLETE: 307*092fc1dbSMatthias Ringwald if (hci_get_state() != HCI_STATE_WORKING) break; 308*092fc1dbSMatthias Ringwald connection_handle = hci_event_disconnection_complete_get_connection_handle(packet); 309*092fc1dbSMatthias Ringwald printf("DISCONNECTED: Connection handle 0x%04x\n", connection_handle); 3106b7b368aSMatthias Ringwald break; 311090b2ae2SMatthias Ringwald default: 312090b2ae2SMatthias Ringwald break; 313090b2ae2SMatthias Ringwald } 314090b2ae2SMatthias Ringwald } 315090b2ae2SMatthias Ringwald fflush(stdout); 316090b2ae2SMatthias Ringwald } 317090b2ae2SMatthias Ringwald 318090b2ae2SMatthias Ringwald static void sm_packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 319090b2ae2SMatthias Ringwald UNUSED(channel); 320090b2ae2SMatthias Ringwald UNUSED(size); 321090b2ae2SMatthias Ringwald switch (packet_type) { 322090b2ae2SMatthias Ringwald case HCI_EVENT_PACKET: 323090b2ae2SMatthias Ringwald switch (packet[0]) { 3246b7b368aSMatthias Ringwald case SM_EVENT_JUST_WORKS_REQUEST: 3256b7b368aSMatthias Ringwald printf("JUST_WORKS_REQUEST\n"); 3266b7b368aSMatthias Ringwald break; 3276b7b368aSMatthias Ringwald case SM_EVENT_NUMERIC_COMPARISON_REQUEST: 3286b7b368aSMatthias Ringwald printf("NUMERIC_COMPARISON_REQUEST\n"); 3296b7b368aSMatthias Ringwald break; 3306b7b368aSMatthias Ringwald case SM_EVENT_PASSKEY_INPUT_NUMBER: 3316b7b368aSMatthias Ringwald // display number 3326b7b368aSMatthias Ringwald printf("PASSKEY_INPUT_NUMBER\n"); 3336b7b368aSMatthias Ringwald ui_passkey = 0; 3346b7b368aSMatthias Ringwald ui_digits_for_passkey = 6; 3356b7b368aSMatthias Ringwald sm_keypress_notification(connection_handle, SM_KEYPRESS_PASSKEY_ENTRY_STARTED); 3366b7b368aSMatthias Ringwald break; 3376b7b368aSMatthias Ringwald case SM_EVENT_PASSKEY_DISPLAY_NUMBER: 3386b7b368aSMatthias Ringwald // display number 3396b7b368aSMatthias Ringwald printf("PASSKEY_DISPLAY_NUMBER: %06u\n", little_endian_read_32(packet, 11)); 3406b7b368aSMatthias Ringwald break; 3416b7b368aSMatthias Ringwald case SM_EVENT_PASSKEY_DISPLAY_CANCEL: 3426b7b368aSMatthias Ringwald break; 3436b7b368aSMatthias Ringwald case SM_EVENT_AUTHORIZATION_REQUEST: 3446b7b368aSMatthias Ringwald break; 3456b7b368aSMatthias Ringwald case SM_EVENT_PAIRING_COMPLETE: 3466b7b368aSMatthias Ringwald printf("\nPAIRING_COMPLETE: %u,%u\n", sm_event_pairing_complete_get_status(packet), sm_event_pairing_complete_get_reason(packet)); 3476b7b368aSMatthias Ringwald if (sm_event_pairing_complete_get_status(packet)) break; 3486b7b368aSMatthias Ringwald if (we_are_central){ 3496b7b368aSMatthias Ringwald printf("Search for LE Counter service.\n"); 3506b7b368aSMatthias Ringwald state = TC_W4_SERVICE_RESULT; 3516b7b368aSMatthias Ringwald gatt_client_discover_primary_services_by_uuid128(handle_gatt_client_event, connection_handle, le_counter_service_uuid); 3526b7b368aSMatthias Ringwald } 3536b7b368aSMatthias Ringwald break; 354090b2ae2SMatthias Ringwald default: 3556b7b368aSMatthias Ringwald break; 356090b2ae2SMatthias Ringwald } 357090b2ae2SMatthias Ringwald } 358090b2ae2SMatthias Ringwald fflush(stdout); 359090b2ae2SMatthias Ringwald } 360090b2ae2SMatthias Ringwald 361090b2ae2SMatthias Ringwald 362090b2ae2SMatthias Ringwald static void att_packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 363090b2ae2SMatthias Ringwald UNUSED(channel); 364090b2ae2SMatthias Ringwald UNUSED(size); 365090b2ae2SMatthias Ringwald switch (packet_type) { 366090b2ae2SMatthias Ringwald case HCI_EVENT_PACKET: 367090b2ae2SMatthias Ringwald switch (packet[0]) { 3686b7b368aSMatthias Ringwald case ATT_EVENT_CAN_SEND_NOW: 3696b7b368aSMatthias Ringwald att_server_notify(connection_handle, ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE, (uint8_t *) "Pairing Success!", 16); 3706b7b368aSMatthias Ringwald break; 3716b7b368aSMatthias Ringwald default: 3726b7b368aSMatthias Ringwald break; 3736b7b368aSMatthias Ringwald } 3746b7b368aSMatthias Ringwald } 3756b7b368aSMatthias Ringwald fflush(stdout); 3766b7b368aSMatthias Ringwald } 3776b7b368aSMatthias Ringwald 3786b7b368aSMatthias Ringwald static void stdin_process(char c){ 379b4394846SMatthias Ringwald log_info("stdin: %c (%02x)", c, c); 3806b7b368aSMatthias Ringwald // passkey input 3816b7b368aSMatthias Ringwald if (ui_digits_for_passkey && c >= '0' && c <= '9'){ 3826b7b368aSMatthias Ringwald printf("%c", c); 3836b7b368aSMatthias Ringwald fflush(stdout); 3846b7b368aSMatthias Ringwald ui_passkey = ui_passkey * 10 + c - '0'; 3856b7b368aSMatthias Ringwald ui_digits_for_passkey--; 3866b7b368aSMatthias Ringwald sm_keypress_notification(connection_handle, SM_KEYPRESS_PASSKEY_DIGIT_ENTERED); 3876b7b368aSMatthias Ringwald if (ui_digits_for_passkey == 0){ 3886b7b368aSMatthias Ringwald printf("\n"); 3896b7b368aSMatthias Ringwald fflush(stdout); 3906b7b368aSMatthias Ringwald sm_keypress_notification(connection_handle, SM_KEYPRESS_PASSKEY_ENTRY_COMPLETED); 3916b7b368aSMatthias Ringwald sm_passkey_input(connection_handle, ui_passkey); 3926b7b368aSMatthias Ringwald } 3936b7b368aSMatthias Ringwald return; 3946b7b368aSMatthias Ringwald } 3956b7b368aSMatthias Ringwald 3966b7b368aSMatthias Ringwald if (ui_oob_confirm){ 3976b7b368aSMatthias Ringwald if (c == ' ') return; 3986b7b368aSMatthias Ringwald ui_oob_nibble = (ui_oob_nibble << 4) | nibble_for_char(c); 3996b7b368aSMatthias Ringwald if ((ui_oob_pos & 1) == 1){ 4006b7b368aSMatthias Ringwald sm_oob_peer_confirm[ui_oob_pos >> 1] = ui_oob_nibble; 4016b7b368aSMatthias Ringwald ui_oob_nibble = 0; 4026b7b368aSMatthias Ringwald } 4036b7b368aSMatthias Ringwald ui_oob_pos++; 4046b7b368aSMatthias Ringwald if (ui_oob_pos == 32){ 4056b7b368aSMatthias Ringwald ui_oob_confirm = 0; 4066b7b368aSMatthias Ringwald printf("PEER_OOB_CONFIRM: "); 4076b7b368aSMatthias Ringwald printf_hexdump(sm_oob_peer_confirm, 16); 4086b7b368aSMatthias Ringwald fflush(stdout); 4096b7b368aSMatthias Ringwald } 4106b7b368aSMatthias Ringwald return; 4116b7b368aSMatthias Ringwald } 4126b7b368aSMatthias Ringwald 4136b7b368aSMatthias Ringwald if (ui_oob_random){ 4146b7b368aSMatthias Ringwald if (c == ' ') return; 4156b7b368aSMatthias Ringwald ui_oob_nibble = (ui_oob_nibble << 4) | nibble_for_char(c); 4166b7b368aSMatthias Ringwald if ((ui_oob_pos & 1) == 1){ 4176b7b368aSMatthias Ringwald sm_oob_peer_random[ui_oob_pos >> 1] = ui_oob_nibble; 4186b7b368aSMatthias Ringwald ui_oob_nibble = 0; 4196b7b368aSMatthias Ringwald } 4206b7b368aSMatthias Ringwald ui_oob_pos++; 4216b7b368aSMatthias Ringwald if (ui_oob_pos == 32){ 4226b7b368aSMatthias Ringwald ui_oob_random = 0; 4236b7b368aSMatthias Ringwald printf("PEER_OOB_RANDOM: "); 4246b7b368aSMatthias Ringwald printf_hexdump(sm_oob_peer_random, 16); 4256b7b368aSMatthias Ringwald fflush(stdout); 4266b7b368aSMatthias Ringwald } 4276b7b368aSMatthias Ringwald return; 4286b7b368aSMatthias Ringwald } 4296b7b368aSMatthias Ringwald 4306b7b368aSMatthias Ringwald 4316b7b368aSMatthias Ringwald switch (c){ 4326b7b368aSMatthias Ringwald case 'a': // accept just works 4336b7b368aSMatthias Ringwald printf("accepting just works\n"); 4346b7b368aSMatthias Ringwald sm_just_works_confirm(connection_handle); 4356b7b368aSMatthias Ringwald break; 4366b7b368aSMatthias Ringwald case 'c': 4376b7b368aSMatthias Ringwald printf("CENTRAL: connect to %s\n", bd_addr_to_str(peer_address)); 4386b7b368aSMatthias Ringwald gap_connect(peer_address, BD_ADDR_TYPE_LE_PUBLIC); 4396b7b368aSMatthias Ringwald break; 4406b7b368aSMatthias Ringwald case 'd': 4416b7b368aSMatthias Ringwald printf("decline bonding\n"); 4426b7b368aSMatthias Ringwald sm_bonding_decline(connection_handle); 4436b7b368aSMatthias Ringwald break; 4446b7b368aSMatthias Ringwald case 'o': 4456b7b368aSMatthias Ringwald printf("receive oob confirm value\n"); 4466b7b368aSMatthias Ringwald ui_oob_confirm = 1; 4476b7b368aSMatthias Ringwald ui_oob_pos = 0; 4486b7b368aSMatthias Ringwald break; 4496b7b368aSMatthias Ringwald case 'r': 4506b7b368aSMatthias Ringwald printf("receive oob random value\n"); 4516b7b368aSMatthias Ringwald ui_oob_random = 1; 4526b7b368aSMatthias Ringwald ui_oob_pos = 0; 4536b7b368aSMatthias Ringwald break; 4546b7b368aSMatthias Ringwald case 'p': 4556b7b368aSMatthias Ringwald printf("REQUEST_PAIRING\n"); 4566b7b368aSMatthias Ringwald sm_request_pairing(connection_handle); 4576b7b368aSMatthias Ringwald break; 4586b7b368aSMatthias Ringwald case 'x': 459b4394846SMatthias Ringwald #ifdef COVERAGE 460b4394846SMatthias Ringwald log_info("Flush gcov"); 461b4394846SMatthias Ringwald __gcov_flush(); 462b4394846SMatthias Ringwald #endif 463b4394846SMatthias Ringwald printf("EXIT\n"); 4646b7b368aSMatthias Ringwald exit(0); 4656b7b368aSMatthias Ringwald break; 4666b7b368aSMatthias Ringwald default: 4676b7b368aSMatthias Ringwald break; 4686b7b368aSMatthias Ringwald } 4696b7b368aSMatthias Ringwald fflush(stdout); 4706b7b368aSMatthias Ringwald return; 4716b7b368aSMatthias Ringwald } 4726b7b368aSMatthias Ringwald 4736b7b368aSMatthias Ringwald int btstack_main(int argc, const char * argv[]); 4746b7b368aSMatthias Ringwald int btstack_main(int argc, const char * argv[]){ 4756b7b368aSMatthias Ringwald 4766b7b368aSMatthias Ringwald int arg = 1; 4776b7b368aSMatthias Ringwald 4786b7b368aSMatthias Ringwald while (arg < argc) { 4796b7b368aSMatthias Ringwald if(!strcmp(argv[arg], "-a") || !strcmp(argv[arg], "--address")){ 4806b7b368aSMatthias Ringwald arg++; 4816b7b368aSMatthias Ringwald we_are_central = sscanf_bd_addr(argv[arg], peer_address); 4826b7b368aSMatthias Ringwald arg++; 4836b7b368aSMatthias Ringwald } 4846b7b368aSMatthias Ringwald if(!strcmp(argv[arg], "-i") || !strcmp(argv[arg], "--iocap")){ 4856b7b368aSMatthias Ringwald arg++; 4866b7b368aSMatthias Ringwald sm_io_capabilities = (io_capability_t) atoi(argv[arg++]); 4876b7b368aSMatthias Ringwald } 4886b7b368aSMatthias Ringwald if(!strcmp(argv[arg], "-r") || !strcmp(argv[arg], "--authreq")){ 4896b7b368aSMatthias Ringwald arg++; 4906b7b368aSMatthias Ringwald sm_auth_req = atoi(argv[arg++]); 4916b7b368aSMatthias Ringwald } 4926b7b368aSMatthias Ringwald if(!strcmp(argv[arg], "-f") || !strcmp(argv[arg], "--failure")){ 4936b7b368aSMatthias Ringwald arg++; 4946b7b368aSMatthias Ringwald sm_failure = atoi(argv[arg++]); 4956b7b368aSMatthias Ringwald } 4966b7b368aSMatthias Ringwald if(!strcmp(argv[arg], "-o") || !strcmp(argv[arg], "--oob")){ 4976b7b368aSMatthias Ringwald arg++; 4986b7b368aSMatthias Ringwald sm_have_oob_data = atoi(argv[arg++]); 4996b7b368aSMatthias Ringwald } 5006b7b368aSMatthias Ringwald } 5016b7b368aSMatthias Ringwald 5026b7b368aSMatthias Ringwald // parse command line flags 5036b7b368aSMatthias Ringwald 5046b7b368aSMatthias Ringwald printf("Security Manager Tester starting up...\n"); 5056b7b368aSMatthias Ringwald log_info("IO_CAPABILITIES: %u", (int) sm_io_capabilities); 5066b7b368aSMatthias Ringwald log_info("AUTH_REQ: %u", sm_auth_req); 5076b7b368aSMatthias Ringwald log_info("HAVE_OOB: %u", sm_have_oob_data); 5086b7b368aSMatthias Ringwald log_info("FAILURE: %u", sm_failure); 5096b7b368aSMatthias Ringwald if (we_are_central){ 5106b7b368aSMatthias Ringwald log_info("ROLE: CENTRAL"); 5116b7b368aSMatthias Ringwald } else { 5126b7b368aSMatthias Ringwald log_info("ROLE: PERIPHERAL"); 5136b7b368aSMatthias Ringwald 5146b7b368aSMatthias Ringwald // setup advertisements 5156b7b368aSMatthias Ringwald uint16_t adv_int_min = 0x0030; 5166b7b368aSMatthias Ringwald uint16_t adv_int_max = 0x0030; 5176b7b368aSMatthias Ringwald uint8_t adv_type = 0; 5186b7b368aSMatthias Ringwald bd_addr_t null_addr; 5196b7b368aSMatthias Ringwald memset(null_addr, 0, 6); 5206b7b368aSMatthias Ringwald gap_advertisements_set_params(adv_int_min, adv_int_max, adv_type, 0, null_addr, 0x07, 0x00); 5216b7b368aSMatthias Ringwald gap_advertisements_set_data(adv_data_len, (uint8_t*) adv_data); 5226b7b368aSMatthias Ringwald gap_advertisements_enable(1); 5236b7b368aSMatthias Ringwald } 5246b7b368aSMatthias Ringwald 5256b7b368aSMatthias Ringwald // inform about BTstack state 526090b2ae2SMatthias Ringwald hci_event_callback_registration.callback = &hci_packet_handler; 5276b7b368aSMatthias Ringwald hci_add_event_handler(&hci_event_callback_registration); 5286b7b368aSMatthias Ringwald 5296b7b368aSMatthias Ringwald // set up l2cap_le 5306b7b368aSMatthias Ringwald l2cap_init(); 5316b7b368aSMatthias Ringwald 5326b7b368aSMatthias Ringwald // setup le device db 5336b7b368aSMatthias Ringwald le_device_db_init(); 5346b7b368aSMatthias Ringwald 5356b7b368aSMatthias Ringwald // 5366b7b368aSMatthias Ringwald gatt_client_init(); 5376b7b368aSMatthias Ringwald 5386b7b368aSMatthias Ringwald // setup SM io capabilities & auth req 5396b7b368aSMatthias Ringwald sm_init(); 5406b7b368aSMatthias Ringwald sm_set_io_capabilities(sm_io_capabilities); 5416b7b368aSMatthias Ringwald sm_set_authentication_requirements(sm_auth_req); 5426b7b368aSMatthias Ringwald sm_register_oob_data_callback(get_oob_data_callback); 5436b7b368aSMatthias Ringwald sm_register_sc_oob_data_callback(get_sc_oob_data_callback); 5446b7b368aSMatthias Ringwald 5456b7b368aSMatthias Ringwald if (sm_failure < SM_REASON_NUMERIC_COMPARISON_FAILED && sm_failure != SM_REASON_PASSKEY_ENTRY_FAILED){ 5466b7b368aSMatthias Ringwald sm_test_set_pairing_failure(sm_failure); 5476b7b368aSMatthias Ringwald } 5486b7b368aSMatthias Ringwald 549090b2ae2SMatthias Ringwald sm_event_callback_registration.callback = &sm_packet_handler; 5506b7b368aSMatthias Ringwald sm_add_event_handler(&sm_event_callback_registration); 5516b7b368aSMatthias Ringwald 5526b7b368aSMatthias Ringwald // setup ATT server 5536b7b368aSMatthias Ringwald att_server_init(profile_data, att_read_callback, att_write_callback); 554090b2ae2SMatthias Ringwald att_server_register_packet_handler(&att_packet_handler); 5556b7b368aSMatthias Ringwald 5566b7b368aSMatthias Ringwald btstack_stdin_setup(stdin_process); 5576b7b368aSMatthias Ringwald 5586b7b368aSMatthias Ringwald // set one-shot timer 5596b7b368aSMatthias Ringwald heartbeat.process = &heartbeat_handler; 5606b7b368aSMatthias Ringwald btstack_run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS); 5616b7b368aSMatthias Ringwald btstack_run_loop_add_timer(&heartbeat); 5626b7b368aSMatthias Ringwald 5636b7b368aSMatthias Ringwald // turn on! 5646b7b368aSMatthias Ringwald hci_power_control(HCI_POWER_ON); 5656b7b368aSMatthias Ringwald 5666b7b368aSMatthias Ringwald return 0; 5676b7b368aSMatthias Ringwald } 5686b7b368aSMatthias Ringwald 5696b7b368aSMatthias Ringwald /* EXAMPLE_END */ 570