1b3d26436SMilanka Ringwald /* 2b3d26436SMilanka Ringwald * Copyright (C) 2014 BlueKitchen GmbH 3b3d26436SMilanka Ringwald * 4b3d26436SMilanka Ringwald * Redistribution and use in source and binary forms, with or without 5b3d26436SMilanka Ringwald * modification, are permitted provided that the following conditions 6b3d26436SMilanka Ringwald * are met: 7b3d26436SMilanka Ringwald * 8b3d26436SMilanka Ringwald * 1. Redistributions of source code must retain the above copyright 9b3d26436SMilanka Ringwald * notice, this list of conditions and the following disclaimer. 10b3d26436SMilanka Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11b3d26436SMilanka Ringwald * notice, this list of conditions and the following disclaimer in the 12b3d26436SMilanka Ringwald * documentation and/or other materials provided with the distribution. 13b3d26436SMilanka Ringwald * 3. Neither the name of the copyright holders nor the names of 14b3d26436SMilanka Ringwald * contributors may be used to endorse or promote products derived 15b3d26436SMilanka Ringwald * from this software without specific prior written permission. 16b3d26436SMilanka Ringwald * 4. Any redistribution, use, or modification is done solely for 17b3d26436SMilanka Ringwald * personal benefit and not for any commercial purpose or for 18b3d26436SMilanka Ringwald * monetary gain. 19b3d26436SMilanka Ringwald * 20b3d26436SMilanka Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21b3d26436SMilanka Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22b3d26436SMilanka Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23b3d26436SMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24b3d26436SMilanka Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25b3d26436SMilanka Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26b3d26436SMilanka Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27b3d26436SMilanka Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28b3d26436SMilanka Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29b3d26436SMilanka Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30b3d26436SMilanka Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31b3d26436SMilanka Ringwald * SUCH DAMAGE. 32b3d26436SMilanka Ringwald * 33b3d26436SMilanka Ringwald * Please inquire about commercial licensing options at 34b3d26436SMilanka Ringwald * [email protected] 35b3d26436SMilanka Ringwald * 36b3d26436SMilanka Ringwald */ 37b3d26436SMilanka Ringwald 38b3d26436SMilanka Ringwald #define BTSTACK_FILE__ "bond_management_service_server.c" 39b3d26436SMilanka Ringwald 40b3d26436SMilanka Ringwald #include "bluetooth.h" 41b3d26436SMilanka Ringwald #include "btstack_defines.h" 42b3d26436SMilanka Ringwald #include "hci.h" 43*0317c1b4SMilanka Ringwald #include "gap.h" 44b3d26436SMilanka Ringwald #include "btstack_util.h" 45b3d26436SMilanka Ringwald #include "btstack_debug.h" 46b3d26436SMilanka Ringwald 47b3d26436SMilanka Ringwald #include "bluetooth_gatt.h" 48b3d26436SMilanka Ringwald #include "ble/att_db.h" 49b3d26436SMilanka Ringwald #include "ble/att_server.h" 50b3d26436SMilanka Ringwald #include "ble/le_device_db.h" 51b3d26436SMilanka Ringwald 52b3d26436SMilanka Ringwald #include "ble/gatt-service/bond_management_service_server.h" 53b3d26436SMilanka Ringwald 54b3d26436SMilanka Ringwald // characteristic: Control Point 55b3d26436SMilanka Ringwald static uint16_t bm_control_point_value_handle; 56b3d26436SMilanka Ringwald 57b3d26436SMilanka Ringwald static const char * bm_authorization_string; 58b3d26436SMilanka Ringwald 59b3d26436SMilanka Ringwald // characteristic: Feature 60b3d26436SMilanka Ringwald static uint16_t bm_supported_features_value_handle; 61b3d26436SMilanka Ringwald static uint32_t bm_supported_features; 62b3d26436SMilanka Ringwald 63b3d26436SMilanka Ringwald static att_service_handler_t bond_management_service; 64b3d26436SMilanka Ringwald 65b3d26436SMilanka Ringwald #ifdef ENABLE_CLASSIC 66b3d26436SMilanka Ringwald static void bond_management_delete_bonding_information_classic(hci_connection_t * connection, bool delete_own_bonding, bool delete_all_bonding_but_active){ 67b3d26436SMilanka Ringwald bd_addr_t entry_address; 68b3d26436SMilanka Ringwald link_key_t link_key; 69b3d26436SMilanka Ringwald link_key_type_t type; 70b3d26436SMilanka Ringwald btstack_link_key_iterator_t it; 71b3d26436SMilanka Ringwald 72b3d26436SMilanka Ringwald int ok = gap_link_key_iterator_init(&it); 73b3d26436SMilanka Ringwald if (!ok) { 74b3d26436SMilanka Ringwald log_error("could not initialize iterator"); 75b3d26436SMilanka Ringwald return; 76b3d26436SMilanka Ringwald } 77b3d26436SMilanka Ringwald 78b3d26436SMilanka Ringwald while (gap_link_key_iterator_get_next(&it, entry_address, link_key, &type)){ 79b3d26436SMilanka Ringwald if (memcmp(connection->address, entry_address, 6) == 0){ 80b3d26436SMilanka Ringwald if (delete_own_bonding){ 81b3d26436SMilanka Ringwald gap_drop_link_key_for_bd_addr(entry_address); 82b3d26436SMilanka Ringwald } 83b3d26436SMilanka Ringwald } else { 84b3d26436SMilanka Ringwald if (delete_all_bonding_but_active){ 85b3d26436SMilanka Ringwald gap_drop_link_key_for_bd_addr(entry_address); 86b3d26436SMilanka Ringwald } 87b3d26436SMilanka Ringwald } 88b3d26436SMilanka Ringwald } 89b3d26436SMilanka Ringwald gap_link_key_iterator_done(&it); 90b3d26436SMilanka Ringwald 91b3d26436SMilanka Ringwald } 92b3d26436SMilanka Ringwald #endif 93b3d26436SMilanka Ringwald 94b3d26436SMilanka Ringwald static void bond_management_delete_bonding_information_le(hci_connection_t * connection, bool delete_own_bonding, bool delete_all_bonding_but_active){ 95b3d26436SMilanka Ringwald bd_addr_t entry_address; 96b3d26436SMilanka Ringwald bd_addr_type_t device_address_type = connection->address_type; 97b3d26436SMilanka Ringwald 98b3d26436SMilanka Ringwald uint16_t i; 99b3d26436SMilanka Ringwald for (i=0; i < le_device_db_max_count(); i++){ 100b3d26436SMilanka Ringwald int entry_address_type = (int) BD_ADDR_TYPE_UNKNOWN; 101b3d26436SMilanka Ringwald le_device_db_info(i, &entry_address_type, entry_address, NULL); 102b3d26436SMilanka Ringwald // skip unused entries 103b3d26436SMilanka Ringwald if (entry_address_type == (int) BD_ADDR_TYPE_UNKNOWN) continue; 104b3d26436SMilanka Ringwald 105b3d26436SMilanka Ringwald if ((entry_address_type == (int) device_address_type) && (memcmp(entry_address, connection->address, 6) == 0)){ 106b3d26436SMilanka Ringwald if (delete_own_bonding){ 107*0317c1b4SMilanka Ringwald gap_delete_bonding((bd_addr_type_t)entry_address_type, entry_address); 108b3d26436SMilanka Ringwald } 109b3d26436SMilanka Ringwald } else { 110b3d26436SMilanka Ringwald if (delete_all_bonding_but_active){ 111*0317c1b4SMilanka Ringwald gap_delete_bonding((bd_addr_type_t)entry_address_type, entry_address); 112b3d26436SMilanka Ringwald } 113b3d26436SMilanka Ringwald } 114b3d26436SMilanka Ringwald } 115b3d26436SMilanka Ringwald } 116b3d26436SMilanka Ringwald 117b3d26436SMilanka Ringwald static uint16_t bond_management_service_read_callback(hci_con_handle_t con_handle, uint16_t attribute_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){ 118b3d26436SMilanka Ringwald UNUSED(con_handle); 119b3d26436SMilanka Ringwald UNUSED(attribute_handle); 120b3d26436SMilanka Ringwald UNUSED(offset); 121b3d26436SMilanka Ringwald UNUSED(buffer_size); 122b3d26436SMilanka Ringwald 123b3d26436SMilanka Ringwald if (attribute_handle == bm_supported_features_value_handle){ 124b3d26436SMilanka Ringwald uint16_t relevant_octets = 0; 125b3d26436SMilanka Ringwald 126b3d26436SMilanka Ringwald // The server shall only include the number of octets needed for returning the highest set feature bit 127b3d26436SMilanka Ringwald if (bm_supported_features > 0xFFFF){ 128b3d26436SMilanka Ringwald relevant_octets = 3; 129b3d26436SMilanka Ringwald } else if (bm_supported_features > 0xFF) { 130b3d26436SMilanka Ringwald relevant_octets = 2; 131b3d26436SMilanka Ringwald } else if (bm_supported_features > 0x00){ 132b3d26436SMilanka Ringwald relevant_octets = 1; 133b3d26436SMilanka Ringwald } 134b3d26436SMilanka Ringwald 135b3d26436SMilanka Ringwald uint8_t feature_buffer[3]; 136b3d26436SMilanka Ringwald if (buffer != NULL){ 137b3d26436SMilanka Ringwald little_endian_store_24(feature_buffer, 0, bm_supported_features); 138b3d26436SMilanka Ringwald (void) memcpy(buffer, feature_buffer, relevant_octets); 139b3d26436SMilanka Ringwald } 140b3d26436SMilanka Ringwald return relevant_octets; 141b3d26436SMilanka Ringwald } 142b3d26436SMilanka Ringwald 143b3d26436SMilanka Ringwald return 0; 144b3d26436SMilanka Ringwald } 145b3d26436SMilanka Ringwald 146b3d26436SMilanka Ringwald static int bond_management_service_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){ 147b3d26436SMilanka Ringwald UNUSED(transaction_mode); 148b3d26436SMilanka Ringwald UNUSED(offset); 149b3d26436SMilanka Ringwald UNUSED(buffer_size); 150b3d26436SMilanka Ringwald 151b3d26436SMilanka Ringwald hci_connection_t * connection = hci_connection_for_handle(con_handle); 152b3d26436SMilanka Ringwald btstack_assert(connection != NULL); 153b3d26436SMilanka Ringwald 154b3d26436SMilanka Ringwald if (attribute_handle == bm_control_point_value_handle){ 155b3d26436SMilanka Ringwald if (buffer_size == 0){ 156b3d26436SMilanka Ringwald return BOND_MANAGEMENT_CONTROL_POINT_OPCODE_NOT_SUPPORTED; 157b3d26436SMilanka Ringwald } 158b3d26436SMilanka Ringwald 159b3d26436SMilanka Ringwald uint8_t cmd = buffer[0]; 160b3d26436SMilanka Ringwald // check if command/auth is supported 161b3d26436SMilanka Ringwald if (cmd > BOND_MANAGEMENT_CMD_DELETE_ALL_BUT_ACTIVE_BOND_LE) { 162b3d26436SMilanka Ringwald return BOND_MANAGEMENT_CONTROL_POINT_OPCODE_NOT_SUPPORTED; 163b3d26436SMilanka Ringwald } 164b3d26436SMilanka Ringwald uint16_t authorisation_code_size = buffer_size - 1; 165b3d26436SMilanka Ringwald if (authorisation_code_size > 511){ 166b3d26436SMilanka Ringwald return BOND_MANAGEMENT_OPERATION_FAILED; 167b3d26436SMilanka Ringwald } 168b3d26436SMilanka Ringwald 169b3d26436SMilanka Ringwald uint8_t auth_provided = authorisation_code_size > 0 ? 1 : 0; 170b3d26436SMilanka Ringwald uint32_t requested_feature_mask = 1UL << (2*(cmd-1) + auth_provided); 171*0317c1b4SMilanka Ringwald 172b3d26436SMilanka Ringwald if ((bm_supported_features & requested_feature_mask) == 0){ 173b3d26436SMilanka Ringwald // abort, feature not allowed 174b3d26436SMilanka Ringwald return BOND_MANAGEMENT_CONTROL_POINT_OPCODE_NOT_SUPPORTED; 175b3d26436SMilanka Ringwald } 176b3d26436SMilanka Ringwald 177b3d26436SMilanka Ringwald if (auth_provided == 1){ 178*0317c1b4SMilanka Ringwald if (!bm_authorization_string){ 179*0317c1b4SMilanka Ringwald return ATT_ERROR_INSUFFICIENT_AUTHORIZATION; 180*0317c1b4SMilanka Ringwald } 181b3d26436SMilanka Ringwald if (strlen(bm_authorization_string) != authorisation_code_size){ 182*0317c1b4SMilanka Ringwald return ATT_ERROR_INSUFFICIENT_AUTHORIZATION; 183b3d26436SMilanka Ringwald } 184b3d26436SMilanka Ringwald if (memcmp(bm_authorization_string, (const char *)&buffer[1], authorisation_code_size) != 0){ 185*0317c1b4SMilanka Ringwald return ATT_ERROR_INSUFFICIENT_AUTHORIZATION; 186b3d26436SMilanka Ringwald } 187b3d26436SMilanka Ringwald } 188b3d26436SMilanka Ringwald 189b3d26436SMilanka Ringwald switch (cmd){ 190b3d26436SMilanka Ringwald #ifdef ENABLE_CLASSIC 191b3d26436SMilanka Ringwald case BOND_MANAGEMENT_CMD_DELETE_ACTIVE_BOND_CLASSIC_AND_LE: 192b3d26436SMilanka Ringwald bond_management_delete_bonding_information_classic(connection, true, false); 193b3d26436SMilanka Ringwald bond_management_delete_bonding_information_le(connection, true, false); 194b3d26436SMilanka Ringwald break; 195b3d26436SMilanka Ringwald case BOND_MANAGEMENT_CMD_DELETE_ACTIVE_BOND_CLASSIC: 196b3d26436SMilanka Ringwald bond_management_delete_bonding_information_classic(connection, true, false); 197b3d26436SMilanka Ringwald break; 198b3d26436SMilanka Ringwald case BOND_MANAGEMENT_CMD_DELETE_ALL_BONDS_CLASSIC_AND_LE: 199b3d26436SMilanka Ringwald bond_management_delete_bonding_information_classic(connection, true, true); 200b3d26436SMilanka Ringwald bond_management_delete_bonding_information_le(connection, true, true); 201b3d26436SMilanka Ringwald break; 202b3d26436SMilanka Ringwald case BOND_MANAGEMENT_CMD_DELETE_ALL_BONDS_CLASSIC: 203b3d26436SMilanka Ringwald bond_management_delete_bonding_information_classic(connection, true, true); 204b3d26436SMilanka Ringwald break; 205b3d26436SMilanka Ringwald case BOND_MANAGEMENT_CMD_DELETE_ALL_BUT_ACTIVE_BOND_CLASSIC_AND_LE: 206b3d26436SMilanka Ringwald bond_management_delete_bonding_information_classic(connection, false, true); 207b3d26436SMilanka Ringwald bond_management_delete_bonding_information_le(connection, false, true); 208b3d26436SMilanka Ringwald break; 209b3d26436SMilanka Ringwald case BOND_MANAGEMENT_CMD_DELETE_ALL_BUT_ACTIVE_BOND_CLASSIC: 210b3d26436SMilanka Ringwald bond_management_delete_bonding_information_classic(connection, false, true); 211b3d26436SMilanka Ringwald break; 212b3d26436SMilanka Ringwald #endif 213b3d26436SMilanka Ringwald case BOND_MANAGEMENT_CMD_DELETE_ACTIVE_BOND_LE: 214b3d26436SMilanka Ringwald bond_management_delete_bonding_information_le(connection, true, false); 215b3d26436SMilanka Ringwald break; 216b3d26436SMilanka Ringwald case BOND_MANAGEMENT_CMD_DELETE_ALL_BONDS_LE: 217b3d26436SMilanka Ringwald bond_management_delete_bonding_information_le(connection, true, true); 218b3d26436SMilanka Ringwald break; 219b3d26436SMilanka Ringwald case BOND_MANAGEMENT_CMD_DELETE_ALL_BUT_ACTIVE_BOND_LE: 220b3d26436SMilanka Ringwald bond_management_delete_bonding_information_le(connection, false, true); 221b3d26436SMilanka Ringwald break; 222b3d26436SMilanka Ringwald default: 223b3d26436SMilanka Ringwald return BOND_MANAGEMENT_CONTROL_POINT_OPCODE_NOT_SUPPORTED; 224b3d26436SMilanka Ringwald } 225b3d26436SMilanka Ringwald 226b3d26436SMilanka Ringwald return 0; 227b3d26436SMilanka Ringwald } 228b3d26436SMilanka Ringwald return 0; 229b3d26436SMilanka Ringwald } 230b3d26436SMilanka Ringwald 231b3d26436SMilanka Ringwald // buffer for authorisation conde 232b3d26436SMilanka Ringwald void bond_management_service_server_init(uint32_t supported_features){ 233b3d26436SMilanka Ringwald // get service handle range 234b3d26436SMilanka Ringwald uint16_t start_handle = 0; 235b3d26436SMilanka Ringwald uint16_t end_handle = 0xffff; 236b3d26436SMilanka Ringwald int service_found = gatt_server_get_handle_range_for_service_with_uuid16(ORG_BLUETOOTH_SERVICE_BOND_MANAGEMENT, &start_handle, &end_handle); 237b3d26436SMilanka Ringwald btstack_assert(service_found != 0); 238b3d26436SMilanka Ringwald UNUSED(service_found); 239b3d26436SMilanka Ringwald 240b3d26436SMilanka Ringwald bm_control_point_value_handle = gatt_server_get_value_handle_for_characteristic_with_uuid16(start_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_BOND_MANAGEMENT_CONTROL_POINT); 241b3d26436SMilanka Ringwald bm_supported_features_value_handle = gatt_server_get_value_handle_for_characteristic_with_uuid16(start_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_BOND_MANAGEMENT_FEATURE); 242b3d26436SMilanka Ringwald bm_supported_features = supported_features; 243b3d26436SMilanka Ringwald 244b3d26436SMilanka Ringwald log_info("Control Point value handle 0x%02x", bm_control_point_value_handle); 245b3d26436SMilanka Ringwald log_info("Feature value handle 0x%02x", bm_supported_features_value_handle); 246b3d26436SMilanka Ringwald // register service with ATT Server 247b3d26436SMilanka Ringwald bond_management_service.start_handle = start_handle; 248b3d26436SMilanka Ringwald bond_management_service.end_handle = end_handle; 249b3d26436SMilanka Ringwald bond_management_service.read_callback = &bond_management_service_read_callback; 250b3d26436SMilanka Ringwald bond_management_service.write_callback = &bond_management_service_write_callback; 251b3d26436SMilanka Ringwald 252b3d26436SMilanka Ringwald att_server_register_service_handler(&bond_management_service); 253b3d26436SMilanka Ringwald } 254b3d26436SMilanka Ringwald 255b3d26436SMilanka Ringwald void bond_management_service_server_set_authorisation_string(const char * authorisation_string){ 256b3d26436SMilanka Ringwald bm_authorization_string = authorisation_string; 257b3d26436SMilanka Ringwald } 258