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