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" 430317c1b4SMilanka 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 72*82fa8541SMilanka Ringwald log_info("BMS Classic: delete bonding %s - own %d, other %d", bd_addr_to_str(connection->address), delete_own_bonding?1:0, delete_all_bonding_but_active?1:0); 73*82fa8541SMilanka Ringwald 74b3d26436SMilanka Ringwald int ok = gap_link_key_iterator_init(&it); 75b3d26436SMilanka Ringwald if (!ok) { 76*82fa8541SMilanka Ringwald log_error("BMS: could not initialize iterator"); 77b3d26436SMilanka Ringwald return; 78b3d26436SMilanka Ringwald } 79b3d26436SMilanka Ringwald 80b3d26436SMilanka Ringwald while (gap_link_key_iterator_get_next(&it, entry_address, link_key, &type)){ 81b3d26436SMilanka Ringwald if (memcmp(connection->address, entry_address, 6) == 0){ 82b3d26436SMilanka Ringwald if (delete_own_bonding){ 83b3d26436SMilanka Ringwald gap_drop_link_key_for_bd_addr(entry_address); 84b3d26436SMilanka Ringwald } 85b3d26436SMilanka Ringwald } else { 86b3d26436SMilanka Ringwald if (delete_all_bonding_but_active){ 87b3d26436SMilanka Ringwald gap_drop_link_key_for_bd_addr(entry_address); 88b3d26436SMilanka Ringwald } 89b3d26436SMilanka Ringwald } 90b3d26436SMilanka Ringwald } 91b3d26436SMilanka Ringwald gap_link_key_iterator_done(&it); 92b3d26436SMilanka Ringwald 93b3d26436SMilanka Ringwald } 94b3d26436SMilanka Ringwald #endif 95b3d26436SMilanka Ringwald 96b3d26436SMilanka Ringwald static void bond_management_delete_bonding_information_le(hci_connection_t * connection, bool delete_own_bonding, bool delete_all_bonding_but_active){ 97b3d26436SMilanka Ringwald bd_addr_t entry_address; 98b3d26436SMilanka Ringwald bd_addr_type_t device_address_type = connection->address_type; 99b3d26436SMilanka Ringwald 100*82fa8541SMilanka Ringwald log_info("BMS LE: delete bonding %s - own %d, other %d", bd_addr_to_str(connection->address), delete_own_bonding?1:0, delete_all_bonding_but_active?1:0); 101*82fa8541SMilanka Ringwald 102b3d26436SMilanka Ringwald uint16_t i; 103b3d26436SMilanka Ringwald for (i=0; i < le_device_db_max_count(); i++){ 104b3d26436SMilanka Ringwald int entry_address_type = (int) BD_ADDR_TYPE_UNKNOWN; 105b3d26436SMilanka Ringwald le_device_db_info(i, &entry_address_type, entry_address, NULL); 106b3d26436SMilanka Ringwald // skip unused entries 107*82fa8541SMilanka Ringwald 108b3d26436SMilanka Ringwald if (entry_address_type == (int) BD_ADDR_TYPE_UNKNOWN) continue; 109b3d26436SMilanka Ringwald 110b3d26436SMilanka Ringwald if ((entry_address_type == (int) device_address_type) && (memcmp(entry_address, connection->address, 6) == 0)){ 111b3d26436SMilanka Ringwald if (delete_own_bonding){ 1120317c1b4SMilanka Ringwald gap_delete_bonding((bd_addr_type_t)entry_address_type, entry_address); 113b3d26436SMilanka Ringwald } 114b3d26436SMilanka Ringwald } else { 115b3d26436SMilanka Ringwald if (delete_all_bonding_but_active){ 1160317c1b4SMilanka Ringwald gap_delete_bonding((bd_addr_type_t)entry_address_type, entry_address); 117b3d26436SMilanka Ringwald } 118b3d26436SMilanka Ringwald } 119b3d26436SMilanka Ringwald } 120b3d26436SMilanka Ringwald } 121b3d26436SMilanka Ringwald 122b3d26436SMilanka 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){ 123b3d26436SMilanka Ringwald UNUSED(con_handle); 124b3d26436SMilanka Ringwald UNUSED(attribute_handle); 125b3d26436SMilanka Ringwald UNUSED(offset); 126b3d26436SMilanka Ringwald UNUSED(buffer_size); 127b3d26436SMilanka Ringwald 128b3d26436SMilanka Ringwald if (attribute_handle == bm_supported_features_value_handle){ 129*82fa8541SMilanka Ringwald 130*82fa8541SMilanka Ringwald #if 0 131*82fa8541SMilanka Ringwald 132*82fa8541SMilanka Ringwald // According to BMS Spec, 3.2.1 Bond Management Feature Characteristic Behavior, only relevant bits should be sent 133b3d26436SMilanka Ringwald uint16_t relevant_octets = 0; 134b3d26436SMilanka Ringwald 135b3d26436SMilanka Ringwald // The server shall only include the number of octets needed for returning the highest set feature bit 136b3d26436SMilanka Ringwald if (bm_supported_features > 0xFFFF){ 137b3d26436SMilanka Ringwald relevant_octets = 3; 138b3d26436SMilanka Ringwald } else if (bm_supported_features > 0xFF) { 139b3d26436SMilanka Ringwald relevant_octets = 2; 140b3d26436SMilanka Ringwald } else if (bm_supported_features > 0x00){ 141b3d26436SMilanka Ringwald relevant_octets = 1; 142b3d26436SMilanka Ringwald } 143*82fa8541SMilanka Ringwald #else 144*82fa8541SMilanka Ringwald // however PTS 8.0.3 expects 3 bytes 145*82fa8541SMilanka Ringwald uint16_t relevant_octets = 3; 146*82fa8541SMilanka Ringwald #endif 147b3d26436SMilanka Ringwald 148b3d26436SMilanka Ringwald uint8_t feature_buffer[3]; 149b3d26436SMilanka Ringwald if (buffer != NULL){ 150b3d26436SMilanka Ringwald little_endian_store_24(feature_buffer, 0, bm_supported_features); 151b3d26436SMilanka Ringwald (void) memcpy(buffer, feature_buffer, relevant_octets); 152b3d26436SMilanka Ringwald } 153b3d26436SMilanka Ringwald return relevant_octets; 154b3d26436SMilanka Ringwald } 155b3d26436SMilanka Ringwald 156b3d26436SMilanka Ringwald return 0; 157b3d26436SMilanka Ringwald } 158b3d26436SMilanka Ringwald 159*82fa8541SMilanka Ringwald #include <stdio.h> 160*82fa8541SMilanka Ringwald 161b3d26436SMilanka 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){ 162b3d26436SMilanka Ringwald UNUSED(transaction_mode); 163b3d26436SMilanka Ringwald UNUSED(offset); 164b3d26436SMilanka Ringwald UNUSED(buffer_size); 165b3d26436SMilanka Ringwald 166*82fa8541SMilanka Ringwald if (transaction_mode != ATT_TRANSACTION_MODE_NONE){ 167*82fa8541SMilanka Ringwald return 0; 168*82fa8541SMilanka Ringwald } 169*82fa8541SMilanka Ringwald 170b3d26436SMilanka Ringwald hci_connection_t * connection = hci_connection_for_handle(con_handle); 171b3d26436SMilanka Ringwald btstack_assert(connection != NULL); 172b3d26436SMilanka Ringwald 173b3d26436SMilanka Ringwald if (attribute_handle == bm_control_point_value_handle){ 174b3d26436SMilanka Ringwald if (buffer_size == 0){ 175b3d26436SMilanka Ringwald return BOND_MANAGEMENT_CONTROL_POINT_OPCODE_NOT_SUPPORTED; 176b3d26436SMilanka Ringwald } 177b3d26436SMilanka Ringwald 178*82fa8541SMilanka Ringwald uint8_t remote_cmd = buffer[0]; 179b3d26436SMilanka Ringwald // check if command/auth is supported 180*82fa8541SMilanka Ringwald if (remote_cmd > BOND_MANAGEMENT_CMD_DELETE_ALL_BUT_ACTIVE_BOND_LE) { 181b3d26436SMilanka Ringwald return BOND_MANAGEMENT_CONTROL_POINT_OPCODE_NOT_SUPPORTED; 182b3d26436SMilanka Ringwald } 183b3d26436SMilanka Ringwald uint16_t authorisation_code_size = buffer_size - 1; 184b3d26436SMilanka Ringwald if (authorisation_code_size > 511){ 185b3d26436SMilanka Ringwald return BOND_MANAGEMENT_OPERATION_FAILED; 186b3d26436SMilanka Ringwald } 187b3d26436SMilanka Ringwald 188*82fa8541SMilanka Ringwald uint32_t requested_feature_mask_without_auth = 1UL << (2*(remote_cmd-1)); 189*82fa8541SMilanka Ringwald uint32_t requested_feature_mask_with_auth = 1UL << (2*(remote_cmd-1) + 1); 190*82fa8541SMilanka Ringwald bool locally_supported_with_auth = (bm_supported_features & requested_feature_mask_with_auth) != 0; 191*82fa8541SMilanka Ringwald bool locally_supported_without_auth = (bm_supported_features & requested_feature_mask_without_auth) != 0; 1920317c1b4SMilanka Ringwald 193*82fa8541SMilanka Ringwald bool remote_auth_provided = authorisation_code_size > 0; 194b3d26436SMilanka Ringwald 195*82fa8541SMilanka Ringwald // log_info("cmd 0x%02X, features 0x%03X, auth_provided %d, LA %d, LW %d", remote_cmd, bm_supported_features, remote_auth_provided?1:0, locally_supported_with_auth?1:0, locally_supported_without_auth?1:0); 196*82fa8541SMilanka Ringwald if (remote_auth_provided){ 197*82fa8541SMilanka Ringwald if (locally_supported_with_auth){ 1980317c1b4SMilanka Ringwald if (!bm_authorization_string){ 1990317c1b4SMilanka Ringwald return ATT_ERROR_INSUFFICIENT_AUTHORIZATION; 2000317c1b4SMilanka Ringwald } 201b3d26436SMilanka Ringwald if (strlen(bm_authorization_string) != authorisation_code_size){ 2020317c1b4SMilanka Ringwald return ATT_ERROR_INSUFFICIENT_AUTHORIZATION; 203b3d26436SMilanka Ringwald } 204b3d26436SMilanka Ringwald if (memcmp(bm_authorization_string, (const char *)&buffer[1], authorisation_code_size) != 0){ 2050317c1b4SMilanka Ringwald return ATT_ERROR_INSUFFICIENT_AUTHORIZATION; 206b3d26436SMilanka Ringwald } 207*82fa8541SMilanka Ringwald } else { 208*82fa8541SMilanka Ringwald return BOND_MANAGEMENT_CONTROL_POINT_OPCODE_NOT_SUPPORTED; 209*82fa8541SMilanka Ringwald } 210*82fa8541SMilanka Ringwald } else { 211*82fa8541SMilanka Ringwald if (!locally_supported_without_auth){ 212*82fa8541SMilanka Ringwald if (locally_supported_with_auth){ 213*82fa8541SMilanka Ringwald return ATT_ERROR_INSUFFICIENT_AUTHORIZATION; 214*82fa8541SMilanka Ringwald } else { 215*82fa8541SMilanka Ringwald return BOND_MANAGEMENT_CONTROL_POINT_OPCODE_NOT_SUPPORTED; 216*82fa8541SMilanka Ringwald } 217*82fa8541SMilanka Ringwald } 218b3d26436SMilanka Ringwald } 219b3d26436SMilanka Ringwald 220*82fa8541SMilanka Ringwald switch (remote_cmd){ 221b3d26436SMilanka Ringwald #ifdef ENABLE_CLASSIC 222b3d26436SMilanka Ringwald case BOND_MANAGEMENT_CMD_DELETE_ACTIVE_BOND_CLASSIC_AND_LE: 223b3d26436SMilanka Ringwald bond_management_delete_bonding_information_classic(connection, true, false); 224b3d26436SMilanka Ringwald bond_management_delete_bonding_information_le(connection, true, false); 225b3d26436SMilanka Ringwald break; 226b3d26436SMilanka Ringwald case BOND_MANAGEMENT_CMD_DELETE_ACTIVE_BOND_CLASSIC: 227b3d26436SMilanka Ringwald bond_management_delete_bonding_information_classic(connection, true, false); 228b3d26436SMilanka Ringwald break; 229b3d26436SMilanka Ringwald case BOND_MANAGEMENT_CMD_DELETE_ALL_BONDS_CLASSIC_AND_LE: 230b3d26436SMilanka Ringwald bond_management_delete_bonding_information_classic(connection, true, true); 231b3d26436SMilanka Ringwald bond_management_delete_bonding_information_le(connection, true, true); 232b3d26436SMilanka Ringwald break; 233b3d26436SMilanka Ringwald case BOND_MANAGEMENT_CMD_DELETE_ALL_BONDS_CLASSIC: 234b3d26436SMilanka Ringwald bond_management_delete_bonding_information_classic(connection, true, true); 235b3d26436SMilanka Ringwald break; 236b3d26436SMilanka Ringwald case BOND_MANAGEMENT_CMD_DELETE_ALL_BUT_ACTIVE_BOND_CLASSIC_AND_LE: 237b3d26436SMilanka Ringwald bond_management_delete_bonding_information_classic(connection, false, true); 238b3d26436SMilanka Ringwald bond_management_delete_bonding_information_le(connection, false, true); 239b3d26436SMilanka Ringwald break; 240b3d26436SMilanka Ringwald case BOND_MANAGEMENT_CMD_DELETE_ALL_BUT_ACTIVE_BOND_CLASSIC: 241b3d26436SMilanka Ringwald bond_management_delete_bonding_information_classic(connection, false, true); 242b3d26436SMilanka Ringwald break; 243b3d26436SMilanka Ringwald #endif 244b3d26436SMilanka Ringwald case BOND_MANAGEMENT_CMD_DELETE_ACTIVE_BOND_LE: 245b3d26436SMilanka Ringwald bond_management_delete_bonding_information_le(connection, true, false); 246b3d26436SMilanka Ringwald break; 247b3d26436SMilanka Ringwald case BOND_MANAGEMENT_CMD_DELETE_ALL_BONDS_LE: 248b3d26436SMilanka Ringwald bond_management_delete_bonding_information_le(connection, true, true); 249b3d26436SMilanka Ringwald break; 250b3d26436SMilanka Ringwald case BOND_MANAGEMENT_CMD_DELETE_ALL_BUT_ACTIVE_BOND_LE: 251b3d26436SMilanka Ringwald bond_management_delete_bonding_information_le(connection, false, true); 252b3d26436SMilanka Ringwald break; 253b3d26436SMilanka Ringwald default: 254b3d26436SMilanka Ringwald return BOND_MANAGEMENT_CONTROL_POINT_OPCODE_NOT_SUPPORTED; 255b3d26436SMilanka Ringwald } 256b3d26436SMilanka Ringwald 257b3d26436SMilanka Ringwald return 0; 258b3d26436SMilanka Ringwald } 259b3d26436SMilanka Ringwald return 0; 260b3d26436SMilanka Ringwald } 261b3d26436SMilanka Ringwald 262b3d26436SMilanka Ringwald // buffer for authorisation conde 263b3d26436SMilanka Ringwald void bond_management_service_server_init(uint32_t supported_features){ 264b3d26436SMilanka Ringwald // get service handle range 265b3d26436SMilanka Ringwald uint16_t start_handle = 0; 266b3d26436SMilanka Ringwald uint16_t end_handle = 0xffff; 267b3d26436SMilanka Ringwald int service_found = gatt_server_get_handle_range_for_service_with_uuid16(ORG_BLUETOOTH_SERVICE_BOND_MANAGEMENT, &start_handle, &end_handle); 268b3d26436SMilanka Ringwald btstack_assert(service_found != 0); 269b3d26436SMilanka Ringwald UNUSED(service_found); 270b3d26436SMilanka Ringwald 271b3d26436SMilanka 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); 272b3d26436SMilanka 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); 273b3d26436SMilanka Ringwald bm_supported_features = supported_features; 274b3d26436SMilanka Ringwald 275b3d26436SMilanka Ringwald log_info("Control Point value handle 0x%02x", bm_control_point_value_handle); 276b3d26436SMilanka Ringwald log_info("Feature value handle 0x%02x", bm_supported_features_value_handle); 277b3d26436SMilanka Ringwald // register service with ATT Server 278b3d26436SMilanka Ringwald bond_management_service.start_handle = start_handle; 279b3d26436SMilanka Ringwald bond_management_service.end_handle = end_handle; 280b3d26436SMilanka Ringwald bond_management_service.read_callback = &bond_management_service_read_callback; 281b3d26436SMilanka Ringwald bond_management_service.write_callback = &bond_management_service_write_callback; 282b3d26436SMilanka Ringwald 283b3d26436SMilanka Ringwald att_server_register_service_handler(&bond_management_service); 284b3d26436SMilanka Ringwald } 285b3d26436SMilanka Ringwald 286b3d26436SMilanka Ringwald void bond_management_service_server_set_authorisation_string(const char * authorisation_string){ 287b3d26436SMilanka Ringwald bm_authorization_string = authorisation_string; 288b3d26436SMilanka Ringwald } 289