1 /******************************************************************************
2 *
3 * Copyright (C) 2009-2012 Broadcom Corporation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 /******************************************************************************
20 *
21 * this file contains GATT database building and query functions
22 *
23 ******************************************************************************/
24
25 #include "bt_target.h"
26
27 #include "bt_trace.h"
28 #include "bt_utils.h"
29
30 #include <stdio.h>
31 #include <string.h>
32 #include "btm_int.h"
33 #include "gatt_int.h"
34 #include "l2c_api.h"
35 #include "osi/include/osi.h"
36
37 /*******************************************************************************
38 * L O C A L F U N C T I O N P R O T O T Y P E S *
39 ******************************************************************************/
40 static tGATT_ATTR& allocate_attr_in_db(tGATT_SVC_DB& db, const tBT_UUID& uuid,
41 tGATT_PERM perm);
42 static tGATT_STATUS gatts_send_app_read_request(
43 tGATT_TCB* p_tcb, uint8_t op_code, uint16_t handle, uint16_t offset,
44 uint32_t trans_id, bt_gatt_db_attribute_type_t gatt_type);
45
46 /**
47 * Initialize a memory space to be a service database.
48 */
gatts_init_service_db(tGATT_SVC_DB & db,tBT_UUID * p_service,bool is_pri,uint16_t s_hdl,uint16_t num_handle)49 void gatts_init_service_db(tGATT_SVC_DB& db, tBT_UUID* p_service, bool is_pri,
50 uint16_t s_hdl, uint16_t num_handle) {
51 db.attr_list.reserve(num_handle);
52
53 GATT_TRACE_DEBUG("%s: s_hdl= %d num_handle= %d", __func__, s_hdl, num_handle);
54
55 /* update service database information */
56 db.next_handle = s_hdl;
57 db.end_handle = s_hdl + num_handle;
58
59 /* add service declration record */
60 tBT_UUID uuid = {LEN_UUID_16, {0}};
61 uuid.uu.uuid16 = is_pri ? GATT_UUID_PRI_SERVICE : GATT_UUID_SEC_SERVICE;
62 tGATT_ATTR& attr = allocate_attr_in_db(db, uuid, GATT_PERM_READ);
63 attr.p_value.reset((tGATT_ATTR_VALUE*)(new tBT_UUID));
64 memcpy(&attr.p_value->uuid, p_service, sizeof(tBT_UUID));
65 }
66
gatts_get_service_uuid(tGATT_SVC_DB * p_db)67 tBT_UUID* gatts_get_service_uuid(tGATT_SVC_DB* p_db) {
68 if (!p_db || p_db->attr_list.empty()) {
69 GATT_TRACE_ERROR("service DB empty");
70 return NULL;
71 } else {
72 return &p_db->attr_list[0].p_value->uuid;
73 }
74 }
75
76 /** Check attribute readability. Returns status of operation. */
gatts_check_attr_readability(const tGATT_ATTR & attr,UNUSED_ATTR uint16_t offset,bool read_long,tGATT_SEC_FLAG sec_flag,uint8_t key_size)77 static tGATT_STATUS gatts_check_attr_readability(const tGATT_ATTR& attr,
78 UNUSED_ATTR uint16_t offset,
79 bool read_long,
80 tGATT_SEC_FLAG sec_flag,
81 uint8_t key_size) {
82 uint16_t min_key_size;
83 tGATT_PERM perm = attr.permission;
84
85 min_key_size = (((perm & GATT_ENCRYPT_KEY_SIZE_MASK) >> 12));
86 if (min_key_size != 0) {
87 min_key_size += 6;
88 }
89
90 if (!(perm & GATT_READ_ALLOWED)) {
91 GATT_TRACE_ERROR("%s: GATT_READ_NOT_PERMIT", __func__);
92 return GATT_READ_NOT_PERMIT;
93 }
94
95 if ((perm & GATT_READ_AUTH_REQUIRED) &&
96 !(sec_flag & GATT_SEC_FLAG_LKEY_UNAUTHED) &&
97 !(sec_flag & BTM_SEC_FLAG_ENCRYPTED)) {
98 GATT_TRACE_ERROR("%s: GATT_INSUF_AUTHENTICATION", __func__);
99 return GATT_INSUF_AUTHENTICATION;
100 }
101
102 if ((perm & GATT_READ_MITM_REQUIRED) &&
103 !(sec_flag & GATT_SEC_FLAG_LKEY_AUTHED)) {
104 GATT_TRACE_ERROR("%s: GATT_INSUF_AUTHENTICATION: MITM Required", __func__);
105 return GATT_INSUF_AUTHENTICATION;
106 }
107
108 if ((perm & GATT_READ_ENCRYPTED_REQUIRED) &&
109 !(sec_flag & GATT_SEC_FLAG_ENCRYPTED)) {
110 GATT_TRACE_ERROR("%s: GATT_INSUF_ENCRYPTION", __func__);
111 return GATT_INSUF_ENCRYPTION;
112 }
113
114 if ((perm & GATT_READ_ENCRYPTED_REQUIRED) &&
115 (sec_flag & GATT_SEC_FLAG_ENCRYPTED) && (key_size < min_key_size)) {
116 GATT_TRACE_ERROR("%s: GATT_INSUF_KEY_SIZE", __func__);
117 return GATT_INSUF_KEY_SIZE;
118 }
119
120 if (read_long && attr.uuid.len == LEN_UUID_16) {
121 switch (attr.uuid.uu.uuid16) {
122 case GATT_UUID_PRI_SERVICE:
123 case GATT_UUID_SEC_SERVICE:
124 case GATT_UUID_CHAR_DECLARE:
125 case GATT_UUID_INCLUDE_SERVICE:
126 case GATT_UUID_CHAR_EXT_PROP:
127 case GATT_UUID_CHAR_CLIENT_CONFIG:
128 case GATT_UUID_CHAR_SRVR_CONFIG:
129 case GATT_UUID_CHAR_PRESENT_FORMAT:
130 GATT_TRACE_ERROR("%s: GATT_NOT_LONG", __func__);
131 return GATT_NOT_LONG;
132
133 default:
134 break;
135 }
136 }
137
138 return GATT_SUCCESS;
139 }
140
141 /*******************************************************************************
142 *
143 * Function read_attr_value
144 *
145 * Description Utility function to read an attribute value.
146 *
147 * Parameter p_attr: pointer to the attribute to read.
148 * offset: read offset.
149 * p_value: output parameter to carry out the attribute value.
150 * p_len: output parameter to carry out the attribute length.
151 * read_long: this is a read blob request.
152 * mtu: MTU
153 * sec_flag: current link security status.
154 * key_size: encryption key size.
155 *
156 * Returns status of operation.
157 *
158 ******************************************************************************/
read_attr_value(tGATT_ATTR & attr16,uint16_t offset,uint8_t ** p_data,bool read_long,uint16_t mtu,uint16_t * p_len,tGATT_SEC_FLAG sec_flag,uint8_t key_size)159 static tGATT_STATUS read_attr_value(tGATT_ATTR& attr16, uint16_t offset,
160 uint8_t** p_data, bool read_long,
161 uint16_t mtu, uint16_t* p_len,
162 tGATT_SEC_FLAG sec_flag, uint8_t key_size) {
163 uint16_t len = 0, uuid16 = 0;
164 uint8_t* p = *p_data;
165
166 GATT_TRACE_DEBUG(
167 "%s: uuid=0x%04x perm=0x%02x sec_flag=0x%x offset=%d read_long=%d",
168 __func__, attr16.uuid, attr16.permission, sec_flag, offset, read_long);
169
170 tGATT_STATUS status = gatts_check_attr_readability(attr16, offset, read_long,
171 sec_flag, key_size);
172
173 if (status != GATT_SUCCESS) return status;
174
175 if (attr16.uuid.len == LEN_UUID_16) uuid16 = attr16.uuid.uu.uuid16;
176
177 status = GATT_NO_RESOURCES;
178
179 if (uuid16 == GATT_UUID_PRI_SERVICE || uuid16 == GATT_UUID_SEC_SERVICE) {
180 len = attr16.p_value->uuid.len;
181 if (mtu >= attr16.p_value->uuid.len) {
182 gatt_build_uuid_to_stream(&p, attr16.p_value->uuid);
183 status = GATT_SUCCESS;
184 }
185 } else if (uuid16 == GATT_UUID_CHAR_DECLARE) {
186 tGATT_ATTR* val_attr = &attr16 + 1;
187 len = (val_attr->uuid.len == LEN_UUID_16) ? 5 : 19;
188
189 if (mtu >= len) {
190 UINT8_TO_STREAM(p, attr16.p_value->char_decl.property);
191 UINT16_TO_STREAM(p, attr16.p_value->char_decl.char_val_handle);
192
193 if (val_attr->uuid.len == LEN_UUID_16) {
194 UINT16_TO_STREAM(p, val_attr->uuid.uu.uuid16);
195 }
196 /* convert a 32bits UUID to 128 bits */
197 else if (val_attr->uuid.len == LEN_UUID_32) {
198 gatt_convert_uuid32_to_uuid128(p, val_attr->uuid.uu.uuid32);
199 p += LEN_UUID_128;
200 } else {
201 ARRAY_TO_STREAM(p, val_attr->uuid.uu.uuid128, LEN_UUID_128);
202 }
203 status = GATT_SUCCESS;
204 }
205
206 } else if (uuid16 == GATT_UUID_INCLUDE_SERVICE) {
207 if (attr16.p_value->incl_handle.service_type.len == LEN_UUID_16)
208 len = 6;
209 else
210 len = 4;
211
212 if (mtu >= len) {
213 UINT16_TO_STREAM(p, attr16.p_value->incl_handle.s_handle);
214 UINT16_TO_STREAM(p, attr16.p_value->incl_handle.e_handle);
215
216 if (attr16.p_value->incl_handle.service_type.len == LEN_UUID_16) {
217 UINT16_TO_STREAM(p, attr16.p_value->incl_handle.service_type.uu.uuid16);
218 }
219 status = GATT_SUCCESS;
220 }
221 } else /* characteristic description or characteristic value */
222 {
223 status = GATT_PENDING;
224 }
225
226 *p_len = len;
227 *p_data = p;
228 return status;
229 }
230
231 /*******************************************************************************
232 *
233 * Function gatts_db_read_attr_value_by_type
234 *
235 * Description Query attribute value by attribute type.
236 *
237 * Parameter p_db: pointer to the attribute database.
238 * p_rsp: Read By type response data.
239 * s_handle: starting handle of the range we are looking for.
240 * e_handle: ending handle of the range we are looking for.
241 * type: Attribute type.
242 * mtu: MTU.
243 * sec_flag: current link security status.
244 * key_size: encryption key size.
245 *
246 * Returns Status of the operation.
247 *
248 ******************************************************************************/
gatts_db_read_attr_value_by_type(tGATT_TCB * p_tcb,tGATT_SVC_DB * p_db,uint8_t op_code,BT_HDR * p_rsp,uint16_t s_handle,uint16_t e_handle,tBT_UUID type,uint16_t * p_len,tGATT_SEC_FLAG sec_flag,uint8_t key_size,uint32_t trans_id,uint16_t * p_cur_handle)249 tGATT_STATUS gatts_db_read_attr_value_by_type(
250 tGATT_TCB* p_tcb, tGATT_SVC_DB* p_db, uint8_t op_code, BT_HDR* p_rsp,
251 uint16_t s_handle, uint16_t e_handle, tBT_UUID type, uint16_t* p_len,
252 tGATT_SEC_FLAG sec_flag, uint8_t key_size, uint32_t trans_id,
253 uint16_t* p_cur_handle) {
254 tGATT_STATUS status = GATT_NOT_FOUND;
255 uint16_t len = 0;
256 uint8_t* p = (uint8_t*)(p_rsp + 1) + p_rsp->len + L2CAP_MIN_OFFSET;
257
258 if (p_db) {
259 for (tGATT_ATTR& attr : p_db->attr_list) {
260 tBT_UUID attr_uuid = attr.uuid;
261
262 if (attr.handle >= s_handle && gatt_uuid_compare(type, attr_uuid)) {
263 if (*p_len <= 2) {
264 status = GATT_NO_RESOURCES;
265 break;
266 }
267
268 UINT16_TO_STREAM(p, attr.handle);
269
270 status = read_attr_value(attr, 0, &p, false, (uint16_t)(*p_len - 2),
271 &len, sec_flag, key_size);
272
273 if (status == GATT_PENDING) {
274 status = gatts_send_app_read_request(p_tcb, op_code, attr.handle, 0,
275 trans_id, attr.gatt_type);
276
277 /* one callback at a time */
278 break;
279 } else if (status == GATT_SUCCESS) {
280 if (p_rsp->offset == 0) p_rsp->offset = len + 2;
281
282 if (p_rsp->offset == len + 2) {
283 p_rsp->len += (len + 2);
284 *p_len -= (len + 2);
285 } else {
286 GATT_TRACE_ERROR("format mismatch");
287 status = GATT_NO_RESOURCES;
288 break;
289 }
290 } else {
291 *p_cur_handle = attr.handle;
292 break;
293 }
294 }
295 }
296 }
297
298 #if (BLE_DELAY_REQUEST_ENC == TRUE)
299 uint8_t flag = 0;
300 if (BTM_GetSecurityFlags(p_tcb->peer_bda, &flag)) {
301 if ((p_tcb->att_lcid == L2CAP_ATT_CID) && (status == GATT_PENDING) &&
302 (type.uu.uuid16 == GATT_UUID_GAP_DEVICE_NAME)) {
303 if ((flag & (BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_FLAG_ENCRYPTED)) ==
304 BTM_SEC_LINK_KEY_KNOWN) {
305 tACL_CONN* p = btm_bda_to_acl(p_tcb->peer_bda, BT_TRANSPORT_LE);
306 if ((p != NULL) && (p->link_role == BTM_ROLE_MASTER))
307 btm_ble_set_encryption(p_tcb->peer_bda, BTM_BLE_SEC_ENCRYPT,
308 p->link_role);
309 }
310 }
311 }
312 #endif
313 return status;
314 }
315
316 /**
317 * This function adds an included service into a database.
318 *
319 * Parameter db: database pointer.
320 * inc_srvc_type: included service type.
321 *
322 * Returns Status of the operation.
323 *
324 */
gatts_add_included_service(tGATT_SVC_DB & db,uint16_t s_handle,uint16_t e_handle,tBT_UUID service)325 uint16_t gatts_add_included_service(tGATT_SVC_DB& db, uint16_t s_handle,
326 uint16_t e_handle, tBT_UUID service) {
327 tBT_UUID uuid = {LEN_UUID_16, {GATT_UUID_INCLUDE_SERVICE}};
328
329 GATT_TRACE_DEBUG("%s: s_hdl = 0x%04x e_hdl = 0x%04x uuid = 0x%04x", __func__,
330 s_handle, e_handle, service.uu.uuid16);
331
332 if (service.len == 0 || s_handle == 0 || e_handle == 0) {
333 GATT_TRACE_ERROR("%s: Illegal Params.", __func__);
334 return 0;
335 }
336
337 tGATT_ATTR& attr = allocate_attr_in_db(db, uuid, GATT_PERM_READ);
338
339 attr.p_value.reset((tGATT_ATTR_VALUE*)(new tGATT_INCL_SRVC));
340 attr.p_value->incl_handle.s_handle = s_handle;
341 attr.p_value->incl_handle.e_handle = e_handle;
342 memcpy(&attr.p_value->incl_handle.service_type, &service, sizeof(tBT_UUID));
343
344 return attr.handle;
345 }
346
347 /*******************************************************************************
348 *
349 * Function gatts_add_characteristic
350 *
351 * Description This function add a characteristics and its descriptor into
352 * a servce identified by the service database pointer.
353 *
354 * Parameter db: database.
355 * perm: permission (authentication and key size requirements)
356 * property: property of the characteristic.
357 * p_char: characteristic value information.
358 *
359 * Returns Status of te operation.
360 *
361 ******************************************************************************/
gatts_add_characteristic(tGATT_SVC_DB & db,tGATT_PERM perm,tGATT_CHAR_PROP property,tBT_UUID & char_uuid)362 uint16_t gatts_add_characteristic(tGATT_SVC_DB& db, tGATT_PERM perm,
363 tGATT_CHAR_PROP property,
364 tBT_UUID& char_uuid) {
365 tBT_UUID uuid = {LEN_UUID_16, {GATT_UUID_CHAR_DECLARE}};
366
367 GATT_TRACE_DEBUG("%s: perm=0x%0x property=0x%0x", __func__, perm, property);
368
369 tGATT_ATTR& char_decl = allocate_attr_in_db(db, uuid, GATT_PERM_READ);
370 tGATT_ATTR& char_val = allocate_attr_in_db(db, char_uuid, perm);
371
372 char_decl.p_value.reset((tGATT_ATTR_VALUE*)(new tGATT_CHAR_DECL));
373 char_decl.p_value->char_decl.property = property;
374 char_decl.p_value->char_decl.char_val_handle = char_val.handle;
375 char_val.gatt_type = BTGATT_DB_CHARACTERISTIC;
376 return char_val.handle;
377 }
378
379 /*******************************************************************************
380 *
381 * Function gatt_convertchar_descr_type
382 *
383 * Description Convert a char descript UUID into descriptor type.
384 *
385 * Returns descriptor type.
386 *
387 ******************************************************************************/
gatt_convertchar_descr_type(tBT_UUID * p_descr_uuid)388 uint8_t gatt_convertchar_descr_type(tBT_UUID* p_descr_uuid) {
389 tBT_UUID std_descr = {LEN_UUID_16, {GATT_UUID_CHAR_EXT_PROP}};
390
391 if (gatt_uuid_compare(std_descr, *p_descr_uuid))
392 return GATT_DESCR_EXT_DSCPTOR;
393
394 std_descr.uu.uuid16++;
395 if (gatt_uuid_compare(std_descr, *p_descr_uuid))
396 return GATT_DESCR_USER_DSCPTOR;
397
398 std_descr.uu.uuid16++;
399 if (gatt_uuid_compare(std_descr, *p_descr_uuid)) return GATT_DESCR_CLT_CONFIG;
400
401 std_descr.uu.uuid16++;
402 if (gatt_uuid_compare(std_descr, *p_descr_uuid)) return GATT_DESCR_SVR_CONFIG;
403
404 std_descr.uu.uuid16++;
405 if (gatt_uuid_compare(std_descr, *p_descr_uuid))
406 return GATT_DESCR_PRES_FORMAT;
407
408 std_descr.uu.uuid16++;
409 if (gatt_uuid_compare(std_descr, *p_descr_uuid))
410 return GATT_DESCR_AGGR_FORMAT;
411
412 std_descr.uu.uuid16++;
413 if (gatt_uuid_compare(std_descr, *p_descr_uuid))
414 return GATT_DESCR_VALID_RANGE;
415
416 return GATT_DESCR_UNKNOWN;
417 }
418
419 /*******************************************************************************
420 *
421 * Function gatts_add_char_descr
422 *
423 * Description This function add a characteristics descriptor.
424 *
425 * Parameter p_db: database pointer.
426 * perm: characteristic descriptor permission type.
427 * char_dscp_tpye: the characteristic descriptor masks.
428 * p_dscp_params: characteristic descriptors values.
429 *
430 * Returns Status of the operation.
431 *
432 ******************************************************************************/
gatts_add_char_descr(tGATT_SVC_DB & db,tGATT_PERM perm,tBT_UUID & descr_uuid)433 uint16_t gatts_add_char_descr(tGATT_SVC_DB& db, tGATT_PERM perm,
434 tBT_UUID& descr_uuid) {
435 GATT_TRACE_DEBUG("gatts_add_char_descr uuid=0x%04x", descr_uuid.uu.uuid16);
436
437 /* Add characteristic descriptors */
438 tGATT_ATTR& char_dscptr = allocate_attr_in_db(db, descr_uuid, perm);
439 char_dscptr.gatt_type = BTGATT_DB_DESCRIPTOR;
440 return char_dscptr.handle;
441 }
442
443 /******************************************************************************/
444 /* Service Attribute Database Query Utility Functions */
445 /******************************************************************************/
find_attr_by_handle(tGATT_SVC_DB * p_db,uint16_t handle)446 tGATT_ATTR* find_attr_by_handle(tGATT_SVC_DB* p_db, uint16_t handle) {
447 if (!p_db) return nullptr;
448
449 for (auto& attr : p_db->attr_list) {
450 if (attr.handle == handle) return &attr;
451 if (attr.handle > handle) return nullptr;
452 }
453
454 return nullptr;
455 }
456
457 /*******************************************************************************
458 *
459 * Function gatts_read_attr_value_by_handle
460 *
461 * Description Query attribute value by attribute handle.
462 *
463 * Parameter p_db: pointer to the attribute database.
464 * handle: Attribute handle to read.
465 * offset: Read offset.
466 * p_value: output parameter to carry out the attribute value.
467 * p_len: output parameter as attribute length read.
468 * read_long: this is a read blob request.
469 * mtu: MTU.
470 * sec_flag: current link security status.
471 * key_size: encryption key size
472 *
473 * Returns Status of operation.
474 *
475 ******************************************************************************/
gatts_read_attr_value_by_handle(tGATT_TCB * p_tcb,tGATT_SVC_DB * p_db,uint8_t op_code,uint16_t handle,uint16_t offset,uint8_t * p_value,uint16_t * p_len,uint16_t mtu,tGATT_SEC_FLAG sec_flag,uint8_t key_size,uint32_t trans_id)476 tGATT_STATUS gatts_read_attr_value_by_handle(
477 tGATT_TCB* p_tcb, tGATT_SVC_DB* p_db, uint8_t op_code, uint16_t handle,
478 uint16_t offset, uint8_t* p_value, uint16_t* p_len, uint16_t mtu,
479 tGATT_SEC_FLAG sec_flag, uint8_t key_size, uint32_t trans_id) {
480 tGATT_ATTR* p_attr = find_attr_by_handle(p_db, handle);
481 if (!p_attr) return GATT_NOT_FOUND;
482
483 uint8_t* pp = p_value;
484 tGATT_STATUS status = read_attr_value(*p_attr, offset, &pp,
485 (bool)(op_code == GATT_REQ_READ_BLOB),
486 mtu, p_len, sec_flag, key_size);
487
488 if (status == GATT_PENDING) {
489 status = gatts_send_app_read_request(p_tcb, op_code, p_attr->handle, offset,
490 trans_id, p_attr->gatt_type);
491 }
492 return status;
493 }
494
495 /*******************************************************************************
496 *
497 * Function gatts_read_attr_perm_check
498 *
499 * Description Check attribute readability.
500 *
501 * Parameter p_db: pointer to the attribute database.
502 * handle: Attribute handle to read.
503 * offset: Read offset.
504 * p_value: output parameter to carry out the attribute value.
505 * p_len: output parameter as attribute length read.
506 * read_long: this is a read blob request.
507 * mtu: MTU.
508 * sec_flag: current link security status.
509 * key_size: encryption key size
510 *
511 * Returns Status of operation.
512 *
513 ******************************************************************************/
gatts_read_attr_perm_check(tGATT_SVC_DB * p_db,bool is_long,uint16_t handle,tGATT_SEC_FLAG sec_flag,uint8_t key_size)514 tGATT_STATUS gatts_read_attr_perm_check(tGATT_SVC_DB* p_db, bool is_long,
515 uint16_t handle,
516 tGATT_SEC_FLAG sec_flag,
517 uint8_t key_size) {
518 tGATT_ATTR* p_attr = find_attr_by_handle(p_db, handle);
519 if (!p_attr) return GATT_NOT_FOUND;
520
521 return gatts_check_attr_readability(*p_attr, 0, is_long, sec_flag, key_size);
522 }
523
524 /*******************************************************************************
525 *
526 * Function gatts_write_attr_perm_check
527 *
528 * Description Write attribute value into database.
529 *
530 * Parameter p_db: pointer to the attribute database.
531 * op_code:op code of this write.
532 * handle: handle of the attribute to write.
533 * offset: Write offset if write op code is write blob.
534 * p_data: Attribute value to write.
535 * len: attribute data length.
536 * sec_flag: current link security status.
537 * key_size: encryption key size
538 *
539 * Returns Status of the operation.
540 *
541 ******************************************************************************/
gatts_write_attr_perm_check(tGATT_SVC_DB * p_db,uint8_t op_code,uint16_t handle,uint16_t offset,uint8_t * p_data,uint16_t len,tGATT_SEC_FLAG sec_flag,uint8_t key_size)542 tGATT_STATUS gatts_write_attr_perm_check(tGATT_SVC_DB* p_db, uint8_t op_code,
543 uint16_t handle, uint16_t offset,
544 uint8_t* p_data, uint16_t len,
545 tGATT_SEC_FLAG sec_flag,
546 uint8_t key_size) {
547 GATT_TRACE_DEBUG(
548 "%s: op_code=0x%0x handle=0x%04x offset=%d len=%d sec_flag=0x%0x "
549 "key_size=%d",
550 __func__, op_code, handle, offset, len, sec_flag, key_size);
551
552 tGATT_ATTR* p_attr = find_attr_by_handle(p_db, handle);
553 if (!p_attr) return GATT_NOT_FOUND;
554
555 tGATT_PERM perm = p_attr->permission;
556 uint16_t min_key_size = (((perm & GATT_ENCRYPT_KEY_SIZE_MASK) >> 12));
557 if (min_key_size != 0) {
558 min_key_size += 6;
559 }
560 GATT_TRACE_DEBUG("%s: p_attr->permission =0x%04x min_key_size==0x%04x",
561 __func__, p_attr->permission, min_key_size);
562
563 if ((op_code == GATT_CMD_WRITE || op_code == GATT_REQ_WRITE) &&
564 (perm & GATT_WRITE_SIGNED_PERM)) {
565 /* use the rules for the mixed security see section 10.2.3*/
566 /* use security mode 1 level 2 when the following condition follows */
567 /* LE security mode 2 level 1 and LE security mode 1 level 2 */
568 if ((perm & GATT_PERM_WRITE_SIGNED) && (perm & GATT_PERM_WRITE_ENCRYPTED)) {
569 perm = GATT_PERM_WRITE_ENCRYPTED;
570 }
571 /* use security mode 1 level 3 when the following condition follows */
572 /* LE security mode 2 level 2 and security mode 1 and LE */
573 else if (((perm & GATT_PERM_WRITE_SIGNED_MITM) &&
574 (perm & GATT_PERM_WRITE_ENCRYPTED)) ||
575 /* LE security mode 2 and security mode 1 level 3 */
576 ((perm & GATT_WRITE_SIGNED_PERM) &&
577 (perm & GATT_PERM_WRITE_ENC_MITM))) {
578 perm = GATT_PERM_WRITE_ENC_MITM;
579 }
580 }
581
582 tGATT_STATUS status = GATT_NOT_FOUND;
583 if ((op_code == GATT_SIGN_CMD_WRITE) && !(perm & GATT_WRITE_SIGNED_PERM)) {
584 status = GATT_WRITE_NOT_PERMIT;
585 GATT_TRACE_DEBUG("%s: sign cmd write not allowed", __func__);
586 }
587 if ((op_code == GATT_SIGN_CMD_WRITE) &&
588 (sec_flag & GATT_SEC_FLAG_ENCRYPTED)) {
589 status = GATT_INVALID_PDU;
590 GATT_TRACE_ERROR("%s: Error!! sign cmd write sent on a encypted link",
591 __func__);
592 } else if (!(perm & GATT_WRITE_ALLOWED)) {
593 status = GATT_WRITE_NOT_PERMIT;
594 GATT_TRACE_ERROR("%s: GATT_WRITE_NOT_PERMIT", __func__);
595 }
596 /* require authentication, but not been authenticated */
597 else if ((perm & GATT_WRITE_AUTH_REQUIRED) &&
598 !(sec_flag & GATT_SEC_FLAG_LKEY_UNAUTHED)) {
599 status = GATT_INSUF_AUTHENTICATION;
600 GATT_TRACE_ERROR("%s: GATT_INSUF_AUTHENTICATION", __func__);
601 } else if ((perm & GATT_WRITE_MITM_REQUIRED) &&
602 !(sec_flag & GATT_SEC_FLAG_LKEY_AUTHED)) {
603 status = GATT_INSUF_AUTHENTICATION;
604 GATT_TRACE_ERROR("%s: GATT_INSUF_AUTHENTICATION: MITM required", __func__);
605 } else if ((perm & GATT_WRITE_ENCRYPTED_PERM) &&
606 !(sec_flag & GATT_SEC_FLAG_ENCRYPTED)) {
607 status = GATT_INSUF_ENCRYPTION;
608 GATT_TRACE_ERROR("%s: GATT_INSUF_ENCRYPTION", __func__);
609 } else if ((perm & GATT_WRITE_ENCRYPTED_PERM) &&
610 (sec_flag & GATT_SEC_FLAG_ENCRYPTED) &&
611 (key_size < min_key_size)) {
612 status = GATT_INSUF_KEY_SIZE;
613 GATT_TRACE_ERROR("%s: GATT_INSUF_KEY_SIZE", __func__);
614 }
615 /* LE security mode 2 attribute */
616 else if (perm & GATT_WRITE_SIGNED_PERM && op_code != GATT_SIGN_CMD_WRITE &&
617 !(sec_flag & GATT_SEC_FLAG_ENCRYPTED) &&
618 (perm & GATT_WRITE_ALLOWED) == 0) {
619 status = GATT_INSUF_AUTHENTICATION;
620 GATT_TRACE_ERROR(
621 "%s: GATT_INSUF_AUTHENTICATION: LE security mode 2 required", __func__);
622 } else /* writable: must be char value declaration or char descritpors
623 */
624 {
625 uint16_t max_size = 0;
626
627 if (p_attr->uuid.len == LEN_UUID_16) {
628 switch (p_attr->uuid.uu.uuid16) {
629 case GATT_UUID_CHAR_PRESENT_FORMAT: /* should be readable only */
630 case GATT_UUID_CHAR_EXT_PROP: /* should be readable only */
631 case GATT_UUID_CHAR_AGG_FORMAT: /* should be readable only */
632 case GATT_UUID_CHAR_VALID_RANGE:
633 status = GATT_WRITE_NOT_PERMIT;
634 break;
635
636 case GATT_UUID_CHAR_CLIENT_CONFIG:
637 /* fall through */
638 case GATT_UUID_CHAR_SRVR_CONFIG:
639 max_size = 2;
640 /* fall through */
641 case GATT_UUID_CHAR_DESCRIPTION:
642 default: /* any other must be character value declaration */
643 status = GATT_SUCCESS;
644 break;
645 }
646 } else if (p_attr->uuid.len == LEN_UUID_128 ||
647 p_attr->uuid.len == LEN_UUID_32) {
648 status = GATT_SUCCESS;
649 } else {
650 status = GATT_INVALID_PDU;
651 }
652
653 if (p_data == NULL && len > 0) {
654 status = GATT_INVALID_PDU;
655 }
656 /* these attribute does not allow write blob */
657 else if ((p_attr->uuid.len == LEN_UUID_16) &&
658 (p_attr->uuid.uu.uuid16 == GATT_UUID_CHAR_CLIENT_CONFIG ||
659 p_attr->uuid.uu.uuid16 == GATT_UUID_CHAR_SRVR_CONFIG)) {
660 if (op_code == GATT_REQ_PREPARE_WRITE &&
661 offset != 0) /* does not allow write blob */
662 {
663 status = GATT_NOT_LONG;
664 GATT_TRACE_ERROR("%s: GATT_NOT_LONG", __func__);
665 } else if (len != max_size) /* data does not match the required format */
666 {
667 status = GATT_INVALID_ATTR_LEN;
668 GATT_TRACE_ERROR("%s: GATT_INVALID_PDU", __func__);
669 } else {
670 status = GATT_SUCCESS;
671 }
672 }
673 }
674
675 return status;
676 }
677
uuid_to_str(const tBT_UUID bt_uuid,char * str_buf,size_t buf_len)678 static void uuid_to_str(const tBT_UUID bt_uuid, char* str_buf, size_t buf_len) {
679 if (bt_uuid.len == LEN_UUID_16) {
680 snprintf(str_buf, buf_len, "0x%04x", bt_uuid.uu.uuid16);
681 } else if (bt_uuid.len == LEN_UUID_32) {
682 snprintf(str_buf, buf_len, "0x%08x", bt_uuid.uu.uuid32);
683 } else if (bt_uuid.len == LEN_UUID_128) {
684 int x = snprintf(str_buf, buf_len, "%02x%02x%02x%02x-%02x%02x-%02x%02x-",
685 bt_uuid.uu.uuid128[15], bt_uuid.uu.uuid128[14],
686 bt_uuid.uu.uuid128[13], bt_uuid.uu.uuid128[12],
687 bt_uuid.uu.uuid128[11], bt_uuid.uu.uuid128[10],
688 bt_uuid.uu.uuid128[9], bt_uuid.uu.uuid128[8]);
689 snprintf(&str_buf[x], buf_len - x, "%02x%02x-%02x%02x%02x%02x%02x%02x",
690 bt_uuid.uu.uuid128[7], bt_uuid.uu.uuid128[6],
691 bt_uuid.uu.uuid128[5], bt_uuid.uu.uuid128[4],
692 bt_uuid.uu.uuid128[3], bt_uuid.uu.uuid128[2],
693 bt_uuid.uu.uuid128[1], bt_uuid.uu.uuid128[0]);
694 } else
695 snprintf(str_buf, buf_len, "Unknown (len=%d)", bt_uuid.len);
696 }
697
698 /**
699 * Description Allocate a memory space for a new attribute, and link this
700 * attribute into the database attribute list.
701 *
702 *
703 * Parameter p_db : database pointer.
704 * uuid: attribute UUID
705 *
706 * Returns pointer to the newly allocated attribute.
707 *
708 */
allocate_attr_in_db(tGATT_SVC_DB & db,const tBT_UUID & uuid,tGATT_PERM perm)709 static tGATT_ATTR& allocate_attr_in_db(tGATT_SVC_DB& db, const tBT_UUID& uuid,
710 tGATT_PERM perm) {
711 if (db.next_handle >= db.end_handle) {
712 LOG(FATAL) << __func__
713 << " wrong number of handles! handle_max = " << +db.end_handle
714 << ", next_handle = " << +db.next_handle;
715 }
716
717 db.attr_list.emplace_back();
718 tGATT_ATTR& attr = db.attr_list.back();
719 attr.handle = db.next_handle++;
720 attr.uuid = uuid;
721 attr.permission = perm;
722
723 char uuid_str[37];
724 uuid_to_str(attr.uuid, uuid_str, sizeof(uuid_str));
725
726 return attr;
727 }
728
729 /*******************************************************************************
730 *
731 * Function gatts_send_app_read_request
732 *
733 * Description Send application read request callback
734 *
735 * Returns status of operation.
736 *
737 ******************************************************************************/
gatts_send_app_read_request(tGATT_TCB * p_tcb,uint8_t op_code,uint16_t handle,uint16_t offset,uint32_t trans_id,bt_gatt_db_attribute_type_t gatt_type)738 static tGATT_STATUS gatts_send_app_read_request(
739 tGATT_TCB* p_tcb, uint8_t op_code, uint16_t handle, uint16_t offset,
740 uint32_t trans_id, bt_gatt_db_attribute_type_t gatt_type) {
741 tGATT_SRV_LIST_ELEM& el = *gatt_sr_find_i_rcb_by_handle(handle);
742 uint16_t conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, el.gatt_if);
743
744 if (trans_id == 0) {
745 trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, handle);
746 gatt_sr_update_cback_cnt(p_tcb, el.gatt_if, true, true);
747 }
748
749 if (trans_id != 0) {
750 tGATTS_DATA sr_data;
751 memset(&sr_data, 0, sizeof(tGATTS_DATA));
752
753 sr_data.read_req.handle = handle;
754 sr_data.read_req.is_long = (bool)(op_code == GATT_REQ_READ_BLOB);
755 sr_data.read_req.offset = offset;
756
757 uint8_t opcode;
758 if (gatt_type == BTGATT_DB_DESCRIPTOR) {
759 opcode = GATTS_REQ_TYPE_READ_DESCRIPTOR;
760 } else if (gatt_type == BTGATT_DB_CHARACTERISTIC) {
761 opcode = GATTS_REQ_TYPE_READ_CHARACTERISTIC;
762 } else {
763 GATT_TRACE_ERROR(
764 "%s: Attempt to read attribute that's not tied with"
765 " characteristic or descriptor value.",
766 __func__);
767 return GATT_ERROR;
768 }
769
770 gatt_sr_send_req_callback(conn_id, trans_id, opcode, &sr_data);
771 return (tGATT_STATUS)GATT_PENDING;
772 } else
773 return (tGATT_STATUS)GATT_BUSY; /* max pending command, application error */
774 }
775