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
bond_management_delete_bonding_information_classic(hci_connection_t * connection,bool delete_own_bonding,bool delete_all_bonding_but_active)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
bond_management_delete_bonding_information_le(hci_connection_t * connection,bool delete_own_bonding,bool delete_all_bonding_but_active)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
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)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
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 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
bond_management_service_server_init(uint32_t supported_features)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
bond_management_service_server_set_authorisation_string(const char * authorisation_string)286 void bond_management_service_server_set_authorisation_string(const char * authorisation_string){
287 bm_authorization_string = authorisation_string;
288 }
289