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