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