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 #if BLE_INCLUDED == TRUE 28 29 #include "bt_trace.h" 30 #include "bt_utils.h" 31 32 #include <stdio.h> 33 #include <string.h> 34 #include "gatt_int.h" 35 #include "l2c_api.h" 36 #include "btm_int.h" 37 38 /******************************************************************************** 39 ** L O C A L F U N C T I O N P R O T O T Y P E S * 40 *********************************************************************************/ 41 static BOOLEAN allocate_svc_db_buf(tGATT_SVC_DB *p_db); 42 static void *allocate_attr_in_db(tGATT_SVC_DB *p_db, tBT_UUID *p_uuid, tGATT_PERM perm); 43 static BOOLEAN deallocate_attr_in_db(tGATT_SVC_DB *p_db, void *p_attr); 44 static BOOLEAN copy_extra_byte_in_db(tGATT_SVC_DB *p_db, void **p_dst, UINT16 len); 45 46 static BOOLEAN gatts_db_add_service_declaration(tGATT_SVC_DB *p_db, tBT_UUID *p_service, BOOLEAN is_pri); 47 static tGATT_STATUS gatts_send_app_read_request(tGATT_TCB *p_tcb, UINT8 op_code, 48 UINT16 handle, UINT16 offset, UINT32 trans_id); 49 50 /******************************************************************************* 51 ** 52 ** Function gatts_init_service_db 53 ** 54 ** Description This function initialize a memory space to be a service database. 55 ** 56 ** Parameter p_db: database pointer. 57 ** len: size of the memory space. 58 ** 59 ** Returns Status of te operation. 60 ** 61 *******************************************************************************/ 62 BOOLEAN gatts_init_service_db (tGATT_SVC_DB *p_db, tBT_UUID *p_service, BOOLEAN is_pri, 63 UINT16 s_hdl, UINT16 num_handle) 64 { 65 GKI_init_q(&p_db->svc_buffer); 66 67 if (!allocate_svc_db_buf(p_db)) 68 { 69 GATT_TRACE_ERROR("gatts_init_service_db failed, no resources"); 70 return FALSE; 71 } 72 73 GATT_TRACE_DEBUG("gatts_init_service_db"); 74 GATT_TRACE_DEBUG("s_hdl = %d num_handle = %d", s_hdl, num_handle ); 75 76 /* update service database information */ 77 p_db->next_handle = s_hdl; 78 p_db->end_handle = s_hdl + num_handle; 79 80 return gatts_db_add_service_declaration(p_db, p_service, is_pri); 81 } 82 83 /******************************************************************************* 84 ** 85 ** Function gatts_init_service_db 86 ** 87 ** Description This function initialize a memory space to be a service database. 88 ** 89 ** Parameter p_db: database pointer. 90 ** len: size of the memory space. 91 ** 92 ** Returns Status of te operation. 93 ** 94 *******************************************************************************/ 95 tBT_UUID * gatts_get_service_uuid (tGATT_SVC_DB *p_db) 96 { 97 if (!p_db || !p_db->p_attr_list) 98 { 99 GATT_TRACE_ERROR("service DB empty"); 100 101 return NULL; 102 } 103 else 104 { 105 return &((tGATT_ATTR16 *)p_db->p_attr_list)->p_value->uuid; 106 } 107 } 108 109 /******************************************************************************* 110 ** 111 ** Function gatts_check_attr_readability 112 ** 113 ** Description check attribute readability 114 ** 115 ** Returns status of operation. 116 ** 117 *******************************************************************************/ 118 static tGATT_STATUS gatts_check_attr_readability(tGATT_ATTR16 *p_attr, 119 UINT16 offset, 120 BOOLEAN read_long, 121 tGATT_SEC_FLAG sec_flag, 122 UINT8 key_size) 123 { 124 UINT16 min_key_size; 125 tGATT_PERM perm = p_attr->permission; 126 127 UNUSED(offset); 128 min_key_size = (((perm & GATT_ENCRYPT_KEY_SIZE_MASK) >> 12)); 129 if (min_key_size != 0 ) 130 { 131 min_key_size +=6; 132 } 133 134 if (!(perm & GATT_READ_ALLOWED)) 135 { 136 GATT_TRACE_ERROR( "GATT_READ_NOT_PERMIT"); 137 return GATT_READ_NOT_PERMIT; 138 } 139 140 if ((perm & GATT_READ_AUTH_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_LKEY_UNAUTHED) && 141 !(sec_flag & BTM_SEC_FLAG_ENCRYPTED)) 142 { 143 GATT_TRACE_ERROR( "GATT_INSUF_AUTHENTICATION"); 144 return GATT_INSUF_AUTHENTICATION; 145 } 146 147 if ((perm & GATT_READ_MITM_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_LKEY_AUTHED)) 148 { 149 GATT_TRACE_ERROR( "GATT_INSUF_AUTHENTICATION: MITM Required"); 150 return GATT_INSUF_AUTHENTICATION; 151 } 152 153 if ((perm & GATT_READ_ENCRYPTED_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_ENCRYPTED)) 154 { 155 GATT_TRACE_ERROR( "GATT_INSUF_ENCRYPTION"); 156 return GATT_INSUF_ENCRYPTION; 157 } 158 159 if ( (perm & GATT_READ_ENCRYPTED_REQUIRED) && (sec_flag & GATT_SEC_FLAG_ENCRYPTED) && (key_size < min_key_size)) 160 { 161 GATT_TRACE_ERROR( "GATT_INSUF_KEY_SIZE"); 162 return GATT_INSUF_KEY_SIZE; 163 } 164 165 166 if (read_long) 167 { 168 switch (p_attr->uuid) 169 { 170 case GATT_UUID_PRI_SERVICE: 171 case GATT_UUID_SEC_SERVICE: 172 case GATT_UUID_CHAR_DECLARE: 173 case GATT_UUID_INCLUDE_SERVICE: 174 case GATT_UUID_CHAR_EXT_PROP: 175 case GATT_UUID_CHAR_CLIENT_CONFIG: 176 case GATT_UUID_CHAR_SRVR_CONFIG: 177 case GATT_UUID_CHAR_PRESENT_FORMAT: 178 GATT_TRACE_ERROR("GATT_NOT_LONG"); 179 return GATT_NOT_LONG; 180 181 default: 182 break; 183 } 184 } 185 186 return GATT_SUCCESS; 187 } 188 189 /******************************************************************************* 190 ** 191 ** Function read_attr_value 192 ** 193 ** Description Utility function to read an attribute value. 194 ** 195 ** Parameter p_attr: pointer to the attribute to read. 196 ** offset: read offset. 197 ** p_value: output parameter to carry out the attribute value. 198 ** p_len: output parameter to carry out the attribute length. 199 ** read_long: this is a read blob request. 200 ** mtu: MTU 201 ** sec_flag: current link security status. 202 ** key_size: encryption key size. 203 ** 204 ** Returns status of operation. 205 ** 206 *******************************************************************************/ 207 static tGATT_STATUS read_attr_value (void *p_attr, 208 UINT16 offset, 209 UINT8 **p_data, 210 BOOLEAN read_long, 211 UINT16 mtu, 212 UINT16 *p_len, 213 tGATT_SEC_FLAG sec_flag, 214 UINT8 key_size) 215 { 216 UINT16 len = 0, uuid16 = 0; 217 UINT8 *p = *p_data; 218 tGATT_STATUS status; 219 tGATT_ATTR16 *p_attr16 = (tGATT_ATTR16 *)p_attr; 220 221 GATT_TRACE_DEBUG("read_attr_value uuid=0x%04x perm=0x%0x sec_flag=0x%x offset=%d read_long=%d", 222 p_attr16->uuid, 223 p_attr16->permission, 224 sec_flag, 225 offset, 226 read_long); 227 228 status = gatts_check_attr_readability((tGATT_ATTR16 *)p_attr, offset, read_long, sec_flag, key_size); 229 230 if (status != GATT_SUCCESS) 231 return status; 232 233 if (p_attr16->uuid_type == GATT_ATTR_UUID_TYPE_16) 234 uuid16 = p_attr16->uuid; 235 236 status = GATT_NO_RESOURCES; 237 238 if (uuid16 == GATT_UUID_PRI_SERVICE || uuid16 == GATT_UUID_SEC_SERVICE) 239 { 240 len = p_attr16->p_value->uuid.len; 241 if (mtu >= p_attr16->p_value->uuid.len) 242 { 243 gatt_build_uuid_to_stream(&p, p_attr16->p_value->uuid); 244 status = GATT_SUCCESS; 245 } 246 } 247 else if (uuid16 == GATT_UUID_CHAR_DECLARE) 248 { 249 len = (((tGATT_ATTR16 *)(p_attr16->p_next))->uuid_type == GATT_ATTR_UUID_TYPE_16) ? 5 :19; 250 251 if (mtu >= len) 252 { 253 UINT8_TO_STREAM(p, p_attr16->p_value->char_decl.property); 254 UINT16_TO_STREAM(p, p_attr16->p_value->char_decl.char_val_handle); 255 256 if (((tGATT_ATTR16 *)(p_attr16->p_next))->uuid_type == GATT_ATTR_UUID_TYPE_16) 257 { 258 UINT16_TO_STREAM(p, ((tGATT_ATTR16 *)(p_attr16->p_next))->uuid); 259 } 260 /* convert a 32bits UUID to 128 bits */ 261 else if (((tGATT_ATTR32 *)(p_attr16->p_next))->uuid_type == GATT_ATTR_UUID_TYPE_32) 262 { 263 gatt_convert_uuid32_to_uuid128 (p, ((tGATT_ATTR32 *)(p_attr16->p_next))->uuid); 264 p += LEN_UUID_128; 265 } 266 else 267 { 268 ARRAY_TO_STREAM (p, ((tGATT_ATTR128 *)(p_attr16->p_next))->uuid, LEN_UUID_128); 269 } 270 status = GATT_SUCCESS; 271 } 272 273 } 274 else if (uuid16 == GATT_UUID_INCLUDE_SERVICE) 275 { 276 if (p_attr16->p_value->incl_handle.service_type.len == LEN_UUID_16) 277 len = 6; 278 else 279 len = 4; 280 281 if (mtu >= len) 282 { 283 UINT16_TO_STREAM(p, p_attr16->p_value->incl_handle.s_handle); 284 UINT16_TO_STREAM(p, p_attr16->p_value->incl_handle.e_handle); 285 286 if (p_attr16->p_value->incl_handle.service_type.len == LEN_UUID_16) 287 { 288 UINT16_TO_STREAM(p, p_attr16->p_value->incl_handle.service_type.uu.uuid16); 289 } 290 status = GATT_SUCCESS; 291 } 292 } 293 else /* characteristic description or characteristic value */ 294 { 295 status = GATT_PENDING; 296 } 297 298 *p_len = len; 299 *p_data = p; 300 return status; 301 } 302 303 /******************************************************************************* 304 ** 305 ** Function gatts_db_read_attr_value_by_type 306 ** 307 ** Description Query attribute value by attribute type. 308 ** 309 ** Parameter p_db: pointer to the attribute database. 310 ** p_rsp: Read By type response data. 311 ** s_handle: starting handle of the range we are looking for. 312 ** e_handle: ending handle of the range we are looking for. 313 ** type: Attribute type. 314 ** mtu: MTU. 315 ** sec_flag: current link security status. 316 ** key_size: encryption key size. 317 ** 318 ** Returns Status of the operation. 319 ** 320 *******************************************************************************/ 321 tGATT_STATUS gatts_db_read_attr_value_by_type (tGATT_TCB *p_tcb, 322 tGATT_SVC_DB *p_db, 323 UINT8 op_code, 324 BT_HDR *p_rsp, 325 UINT16 s_handle, 326 UINT16 e_handle, 327 tBT_UUID type, 328 UINT16 *p_len, 329 tGATT_SEC_FLAG sec_flag, 330 UINT8 key_size, 331 UINT32 trans_id, 332 UINT16 *p_cur_handle) 333 { 334 tGATT_STATUS status = GATT_NOT_FOUND; 335 tGATT_ATTR16 *p_attr; 336 UINT16 len = 0; 337 UINT8 *p = (UINT8 *)(p_rsp + 1) + p_rsp->len + L2CAP_MIN_OFFSET; 338 tBT_UUID attr_uuid; 339 #if (defined(BLE_DELAY_REQUEST_ENC) && (BLE_DELAY_REQUEST_ENC == TRUE)) 340 UINT8 flag; 341 #endif 342 343 if (p_db && p_db->p_attr_list) 344 { 345 p_attr = (tGATT_ATTR16 *)p_db->p_attr_list; 346 347 while (p_attr && p_attr->handle <= e_handle) 348 { 349 if (p_attr->uuid_type == GATT_ATTR_UUID_TYPE_16) 350 { 351 attr_uuid.len = LEN_UUID_16; 352 attr_uuid.uu.uuid16 = p_attr->uuid; 353 } 354 else if (p_attr->uuid_type == GATT_ATTR_UUID_TYPE_32) 355 { 356 attr_uuid.len = LEN_UUID_32; 357 attr_uuid.uu.uuid32 = ((tGATT_ATTR32 *)p_attr)->uuid; 358 } 359 else 360 { 361 attr_uuid.len = LEN_UUID_128; 362 memcpy(attr_uuid.uu.uuid128, ((tGATT_ATTR128 *)p_attr)->uuid, LEN_UUID_128); 363 } 364 365 if (p_attr->handle >= s_handle && gatt_uuid_compare(type, attr_uuid)) 366 { 367 if (*p_len <= 2) 368 { 369 status = GATT_NO_RESOURCES; 370 break; 371 } 372 373 UINT16_TO_STREAM (p, p_attr->handle); 374 375 status = read_attr_value ((void *)p_attr, 0, &p, FALSE, (UINT16)(*p_len -2), &len, sec_flag, key_size); 376 377 if (status == GATT_PENDING) 378 { 379 status = gatts_send_app_read_request(p_tcb, op_code, p_attr->handle, 0, trans_id); 380 381 /* one callback at a time */ 382 break; 383 } 384 else if (status == GATT_SUCCESS) 385 { 386 if (p_rsp->offset == 0) 387 p_rsp->offset = len + 2; 388 389 if (p_rsp->offset == len + 2) 390 { 391 p_rsp->len += (len + 2); 392 *p_len -= (len + 2); 393 } 394 else 395 { 396 GATT_TRACE_ERROR("format mismatch"); 397 status = GATT_NO_RESOURCES; 398 break; 399 } 400 } 401 else 402 { 403 *p_cur_handle = p_attr->handle; 404 break; 405 } 406 } 407 p_attr = (tGATT_ATTR16 *)p_attr->p_next; 408 } 409 } 410 411 #if (defined(BLE_DELAY_REQUEST_ENC) && (BLE_DELAY_REQUEST_ENC == TRUE)) 412 if (BTM_GetSecurityFlags(p_tcb->peer_bda, &flag)) 413 { 414 if ((p_tcb->att_lcid == L2CAP_ATT_CID) && (status == GATT_PENDING) && 415 (type.uu.uuid16 == GATT_UUID_GAP_DEVICE_NAME)) 416 { 417 if ((flag & (BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_FLAG_ENCRYPTED)) == 418 BTM_SEC_LINK_KEY_KNOWN) 419 { 420 tACL_CONN *p; 421 p = btm_bda_to_acl(p_tcb->peer_bda, BT_TRANSPORT_LE); 422 if ((p != NULL) && (p->link_role == BTM_ROLE_MASTER)) 423 { 424 tBTM_BLE_SEC_ACT sec_act = BTM_BLE_SEC_ENCRYPT; 425 btm_ble_set_encryption(p_tcb->peer_bda, &sec_act, p->link_role); 426 } 427 } 428 } 429 } 430 #endif 431 return status; 432 } 433 434 /******************************************************************************* 435 ** 436 ** Function gatts_add_included_service 437 ** 438 ** Description This function adds an included service into a database. 439 ** 440 ** Parameter p_db: database pointer. 441 ** inc_srvc_type: included service type. 442 ** 443 ** Returns Status of the operation. 444 ** 445 *******************************************************************************/ 446 UINT16 gatts_add_included_service (tGATT_SVC_DB *p_db, UINT16 s_handle, UINT16 e_handle, 447 tBT_UUID service) 448 { 449 tGATT_ATTR16 *p_attr; 450 tBT_UUID uuid = {LEN_UUID_16, {GATT_UUID_INCLUDE_SERVICE}}; 451 452 GATT_TRACE_DEBUG("gatts_add_included_service: s_hdl = 0x%04x e_hdl = 0x%04x uuid = 0x%04x", 453 s_handle, e_handle, service.uu.uuid16); 454 455 if (service.len == 0 || s_handle == 0 || e_handle == 0) 456 { 457 GATT_TRACE_ERROR("gatts_add_included_service Illegal Params."); 458 return 0; 459 } 460 461 if ((p_attr = (tGATT_ATTR16 *) allocate_attr_in_db(p_db, &uuid, GATT_PERM_READ)) != NULL) 462 { 463 if (copy_extra_byte_in_db(p_db, (void **)&p_attr->p_value, sizeof(tGATT_INCL_SRVC))) 464 { 465 p_attr->p_value->incl_handle.s_handle = s_handle; 466 p_attr->p_value->incl_handle.e_handle = e_handle; 467 memcpy(&p_attr->p_value->incl_handle.service_type, &service, sizeof(tBT_UUID)); 468 469 return p_attr->handle; 470 } 471 else 472 { 473 deallocate_attr_in_db(p_db, p_attr); 474 } 475 } 476 477 return 0; 478 } 479 480 /******************************************************************************* 481 ** 482 ** Function gatts_add_characteristic 483 ** 484 ** Description This function add a characteristics and its descriptor into 485 ** a servce identified by the service database pointer. 486 ** 487 ** Parameter p_db: database pointer. 488 ** perm: permission (authentication and key size requirements) 489 ** property: property of the characteristic. 490 ** p_char: characteristic value information. 491 ** 492 ** Returns Status of te operation. 493 ** 494 *******************************************************************************/ 495 UINT16 gatts_add_characteristic (tGATT_SVC_DB *p_db, tGATT_PERM perm, 496 tGATT_CHAR_PROP property, 497 tBT_UUID * p_char_uuid) 498 { 499 tGATT_ATTR16 *p_char_decl, *p_char_val; 500 tBT_UUID uuid = {LEN_UUID_16, {GATT_UUID_CHAR_DECLARE}}; 501 502 GATT_TRACE_DEBUG("gatts_add_characteristic perm=0x%0x property=0x%0x", perm, property); 503 504 if ((p_char_decl = (tGATT_ATTR16 *)allocate_attr_in_db(p_db, &uuid, GATT_PERM_READ)) != NULL) 505 { 506 if (!copy_extra_byte_in_db(p_db, (void **)&p_char_decl->p_value, sizeof(tGATT_CHAR_DECL))) 507 { 508 deallocate_attr_in_db(p_db, p_char_decl); 509 return 0; 510 } 511 512 p_char_val = (tGATT_ATTR16 *)allocate_attr_in_db(p_db, p_char_uuid, perm); 513 514 if (p_char_val == NULL) 515 { 516 deallocate_attr_in_db(p_db, p_char_decl); 517 return 0; 518 } 519 520 p_char_decl->p_value->char_decl.property = property; 521 p_char_decl->p_value->char_decl.char_val_handle = p_char_val->handle; 522 523 p_char_val->p_value = NULL; 524 525 return p_char_val->handle; 526 } 527 528 return 0; 529 } 530 531 /******************************************************************************* 532 ** 533 ** Function gatt_convertchar_descr_type 534 ** 535 ** Description This function convert a char descript UUID into descriptor type. 536 ** 537 ** Returns descriptor type. 538 ** 539 *******************************************************************************/ 540 UINT8 gatt_convertchar_descr_type(tBT_UUID *p_descr_uuid) 541 { 542 tBT_UUID std_descr = {LEN_UUID_16, {GATT_UUID_CHAR_EXT_PROP}}; 543 544 if (gatt_uuid_compare(std_descr, * p_descr_uuid)) 545 return GATT_DESCR_EXT_DSCPTOR; 546 547 std_descr.uu.uuid16 ++; 548 if (gatt_uuid_compare(std_descr, * p_descr_uuid)) 549 return GATT_DESCR_USER_DSCPTOR; 550 551 std_descr.uu.uuid16 ++; 552 if (gatt_uuid_compare(std_descr, * p_descr_uuid)) 553 return GATT_DESCR_CLT_CONFIG; 554 555 std_descr.uu.uuid16 ++; 556 if (gatt_uuid_compare(std_descr, * p_descr_uuid)) 557 return GATT_DESCR_SVR_CONFIG; 558 559 std_descr.uu.uuid16 ++; 560 if (gatt_uuid_compare(std_descr, * p_descr_uuid)) 561 return GATT_DESCR_PRES_FORMAT; 562 563 std_descr.uu.uuid16 ++; 564 if (gatt_uuid_compare(std_descr, * p_descr_uuid)) 565 return GATT_DESCR_AGGR_FORMAT; 566 567 std_descr.uu.uuid16 ++; 568 if (gatt_uuid_compare(std_descr, * p_descr_uuid)) 569 return GATT_DESCR_VALID_RANGE; 570 571 572 return GATT_DESCR_UNKNOWN; 573 } 574 575 /******************************************************************************* 576 ** 577 ** Function gatts_add_char_descr 578 ** 579 ** Description This function add a characteristics descriptor. 580 ** 581 ** Parameter p_db: database pointer. 582 ** perm: characteristic descriptor permission type. 583 ** char_dscp_tpye: the characteristic descriptor masks. 584 ** p_dscp_params: characteristic descriptors values. 585 ** 586 ** Returns Status of the operation. 587 ** 588 *******************************************************************************/ 589 UINT16 gatts_add_char_descr (tGATT_SVC_DB *p_db, tGATT_PERM perm, 590 tBT_UUID * p_descr_uuid) 591 { 592 tGATT_ATTR16 *p_char_dscptr; 593 594 GATT_TRACE_DEBUG("gatts_add_char_descr uuid=0x%04x", p_descr_uuid->uu.uuid16); 595 596 /* Add characteristic descriptors */ 597 if ((p_char_dscptr = (tGATT_ATTR16 *)allocate_attr_in_db(p_db, 598 p_descr_uuid, 599 perm)) 600 == NULL) 601 { 602 GATT_TRACE_DEBUG("gatts_add_char_descr Fail for adding char descriptors."); 603 return 0; 604 } 605 else 606 { 607 return p_char_dscptr->handle; 608 } 609 } 610 611 /*******************************************************************************/ 612 /* Service Attribute Database Query Utility Functions */ 613 /*******************************************************************************/ 614 /******************************************************************************* 615 ** 616 ** Function gatts_read_attr_value_by_handle 617 ** 618 ** Description Query attribute value by attribute handle. 619 ** 620 ** Parameter p_db: pointer to the attribute database. 621 ** handle: Attribute handle to read. 622 ** offset: Read offset. 623 ** p_value: output parameter to carry out the attribute value. 624 ** p_len: output parameter as attribute length read. 625 ** read_long: this is a read blob request. 626 ** mtu: MTU. 627 ** sec_flag: current link security status. 628 ** key_size: encryption key size 629 ** 630 ** Returns Status of operation. 631 ** 632 *******************************************************************************/ 633 tGATT_STATUS gatts_read_attr_value_by_handle(tGATT_TCB *p_tcb, 634 tGATT_SVC_DB *p_db, 635 UINT8 op_code, 636 UINT16 handle, UINT16 offset, 637 UINT8 *p_value, UINT16 *p_len, 638 UINT16 mtu, 639 tGATT_SEC_FLAG sec_flag, 640 UINT8 key_size, 641 UINT32 trans_id) 642 { 643 tGATT_STATUS status = GATT_NOT_FOUND; 644 tGATT_ATTR16 *p_attr; 645 UINT8 *pp = p_value; 646 647 if (p_db && p_db->p_attr_list) 648 { 649 p_attr = (tGATT_ATTR16 *)p_db->p_attr_list; 650 651 while (p_attr && handle >= p_attr->handle) 652 { 653 if (p_attr->handle == handle) 654 { 655 status = read_attr_value (p_attr, offset, &pp, 656 (BOOLEAN)(op_code == GATT_REQ_READ_BLOB), 657 mtu, p_len, sec_flag, key_size); 658 659 if (status == GATT_PENDING) 660 { 661 status = gatts_send_app_read_request(p_tcb, op_code, p_attr->handle, offset, trans_id); 662 } 663 break; 664 } 665 p_attr = (tGATT_ATTR16 *)p_attr->p_next; 666 } 667 } 668 669 return status; 670 } 671 672 /******************************************************************************* 673 ** 674 ** Function gatts_read_attr_perm_check 675 ** 676 ** Description Check attribute readability. 677 ** 678 ** Parameter p_db: pointer to the attribute database. 679 ** handle: Attribute handle to read. 680 ** offset: Read offset. 681 ** p_value: output parameter to carry out the attribute value. 682 ** p_len: output parameter as attribute length read. 683 ** read_long: this is a read blob request. 684 ** mtu: MTU. 685 ** sec_flag: current link security status. 686 ** key_size: encryption key size 687 ** 688 ** Returns Status of operation. 689 ** 690 *******************************************************************************/ 691 tGATT_STATUS gatts_read_attr_perm_check(tGATT_SVC_DB *p_db, 692 BOOLEAN is_long, 693 UINT16 handle, 694 tGATT_SEC_FLAG sec_flag, 695 UINT8 key_size) 696 { 697 tGATT_STATUS status = GATT_NOT_FOUND; 698 tGATT_ATTR16 *p_attr; 699 700 if (p_db && p_db->p_attr_list) 701 { 702 p_attr = (tGATT_ATTR16 *)p_db->p_attr_list; 703 704 while (p_attr && handle >= p_attr->handle) 705 { 706 if (p_attr->handle == handle) 707 { 708 status = gatts_check_attr_readability (p_attr, 0, 709 is_long, 710 sec_flag, key_size); 711 break; 712 } 713 p_attr = (tGATT_ATTR16 *) p_attr->p_next; 714 } 715 } 716 717 return status; 718 } 719 /******************************************************************************* 720 ** 721 ** Function gatts_write_attr_perm_check 722 ** 723 ** Description Write attribute value into database. 724 ** 725 ** Parameter p_db: pointer to the attribute database. 726 ** op_code:op code of this write. 727 ** handle: handle of the attribute to write. 728 ** offset: Write offset if write op code is write blob. 729 ** p_data: Attribute value to write. 730 ** len: attribute data length. 731 ** sec_flag: current link security status. 732 ** key_size: encryption key size 733 ** 734 ** Returns Status of the operation. 735 ** 736 *******************************************************************************/ 737 tGATT_STATUS gatts_write_attr_perm_check (tGATT_SVC_DB *p_db, UINT8 op_code, 738 UINT16 handle, UINT16 offset, UINT8 *p_data, 739 UINT16 len, tGATT_SEC_FLAG sec_flag, UINT8 key_size) 740 { 741 tGATT_STATUS status = GATT_NOT_FOUND; 742 tGATT_ATTR16 *p_attr; 743 UINT16 max_size = 0; 744 tGATT_PERM perm; 745 UINT16 min_key_size; 746 747 GATT_TRACE_DEBUG( "gatts_write_attr_perm_check op_code=0x%0x handle=0x%04x offset=%d len=%d sec_flag=0x%0x key_size=%d", 748 op_code, handle, offset, len, sec_flag, key_size); 749 750 if (p_db != NULL) 751 { 752 p_attr = (tGATT_ATTR16 *) p_db->p_attr_list; 753 754 while (p_attr != NULL) 755 { 756 if (p_attr->handle == handle) 757 { 758 perm = p_attr->permission; 759 min_key_size = (((perm & GATT_ENCRYPT_KEY_SIZE_MASK) >> 12)); 760 if (min_key_size != 0 ) 761 { 762 min_key_size +=6; 763 } 764 GATT_TRACE_DEBUG( "gatts_write_attr_perm_check p_attr->permission =0x%04x min_key_size==0x%04x", 765 p_attr->permission, 766 min_key_size); 767 768 if ((op_code == GATT_CMD_WRITE || op_code == GATT_REQ_WRITE) 769 && (perm & GATT_WRITE_SIGNED_PERM)) 770 { 771 /* use the rules for the mixed security see section 10.2.3*/ 772 /* use security mode 1 level 2 when the following condition follows */ 773 /* LE security mode 2 level 1 and LE security mode 1 level 2 */ 774 if ((perm & GATT_PERM_WRITE_SIGNED) && (perm & GATT_PERM_WRITE_ENCRYPTED)) 775 { 776 perm = GATT_PERM_WRITE_ENCRYPTED; 777 } 778 /* use security mode 1 level 3 when the following condition follows */ 779 /* LE security mode 2 level 2 and security mode 1 and LE */ 780 else if (((perm & GATT_PERM_WRITE_SIGNED_MITM) && (perm & GATT_PERM_WRITE_ENCRYPTED)) || 781 /* LE security mode 2 and security mode 1 level 3 */ 782 ((perm & GATT_WRITE_SIGNED_PERM) && (perm & GATT_PERM_WRITE_ENC_MITM))) 783 { 784 perm = GATT_PERM_WRITE_ENC_MITM; 785 } 786 } 787 788 if ((op_code == GATT_SIGN_CMD_WRITE) && !(perm & GATT_WRITE_SIGNED_PERM)) 789 { 790 status = GATT_WRITE_NOT_PERMIT; 791 GATT_TRACE_DEBUG( "gatts_write_attr_perm_check - sign cmd write not allowed"); 792 } 793 if ((op_code == GATT_SIGN_CMD_WRITE) && (sec_flag & GATT_SEC_FLAG_ENCRYPTED)) 794 { 795 status = GATT_INVALID_PDU; 796 GATT_TRACE_ERROR( "gatts_write_attr_perm_check - Error!! sign cmd write sent on a encypted link"); 797 } 798 else if (!(perm & GATT_WRITE_ALLOWED)) 799 { 800 status = GATT_WRITE_NOT_PERMIT; 801 GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_WRITE_NOT_PERMIT"); 802 } 803 /* require authentication, but not been authenticated */ 804 else if ((perm & GATT_WRITE_AUTH_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_LKEY_UNAUTHED)) 805 { 806 status = GATT_INSUF_AUTHENTICATION; 807 GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_INSUF_AUTHENTICATION"); 808 } 809 else if ((perm & GATT_WRITE_MITM_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_LKEY_AUTHED)) 810 { 811 status = GATT_INSUF_AUTHENTICATION; 812 GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_INSUF_AUTHENTICATION: MITM required"); 813 } 814 else if ((perm & GATT_WRITE_ENCRYPTED_PERM ) && !(sec_flag & GATT_SEC_FLAG_ENCRYPTED)) 815 { 816 status = GATT_INSUF_ENCRYPTION; 817 GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_INSUF_ENCRYPTION"); 818 } 819 else if ((perm & GATT_WRITE_ENCRYPTED_PERM ) && (sec_flag & GATT_SEC_FLAG_ENCRYPTED) && (key_size < min_key_size)) 820 { 821 status = GATT_INSUF_KEY_SIZE; 822 GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_INSUF_KEY_SIZE"); 823 } 824 /* LE security mode 2 attribute */ 825 else if (perm & GATT_WRITE_SIGNED_PERM && op_code != GATT_SIGN_CMD_WRITE && !(sec_flag & GATT_SEC_FLAG_ENCRYPTED) 826 && (perm & GATT_WRITE_ALLOWED) == 0) 827 { 828 status = GATT_INSUF_AUTHENTICATION; 829 GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_INSUF_AUTHENTICATION: LE security mode 2 required"); 830 } 831 else /* writable: must be char value declaration or char descritpors */ 832 { 833 if(p_attr->uuid_type == GATT_ATTR_UUID_TYPE_16) 834 { 835 switch (p_attr->uuid) 836 { 837 case GATT_UUID_CHAR_PRESENT_FORMAT:/* should be readable only */ 838 case GATT_UUID_CHAR_EXT_PROP:/* should be readable only */ 839 case GATT_UUID_CHAR_AGG_FORMAT: /* should be readable only */ 840 case GATT_UUID_CHAR_VALID_RANGE: 841 status = GATT_WRITE_NOT_PERMIT; 842 break; 843 844 case GATT_UUID_CHAR_CLIENT_CONFIG: 845 /* coverity[MISSING_BREAK] */ 846 /* intnended fall through, ignored */ 847 /* fall through */ 848 case GATT_UUID_CHAR_SRVR_CONFIG: 849 max_size = 2; 850 case GATT_UUID_CHAR_DESCRIPTION: 851 default: /* any other must be character value declaration */ 852 status = GATT_SUCCESS; 853 break; 854 } 855 } 856 else if (p_attr->uuid_type == GATT_ATTR_UUID_TYPE_128 || 857 p_attr->uuid_type == GATT_ATTR_UUID_TYPE_32) 858 { 859 status = GATT_SUCCESS; 860 } 861 else 862 { 863 status = GATT_INVALID_PDU; 864 } 865 866 if (p_data == NULL && len > 0) 867 { 868 status = GATT_INVALID_PDU; 869 } 870 /* these attribute does not allow write blob */ 871 // btla-specific ++ 872 else if ( (p_attr->uuid_type == GATT_ATTR_UUID_TYPE_16) && 873 (p_attr->uuid == GATT_UUID_CHAR_CLIENT_CONFIG || 874 p_attr->uuid == GATT_UUID_CHAR_SRVR_CONFIG) ) 875 // btla-specific -- 876 { 877 if (op_code == GATT_REQ_PREPARE_WRITE && offset != 0) /* does not allow write blob */ 878 { 879 status = GATT_NOT_LONG; 880 GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_NOT_LONG"); 881 } 882 else if (len != max_size) /* data does not match the required format */ 883 { 884 status = GATT_INVALID_ATTR_LEN; 885 GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_INVALID_PDU"); 886 } 887 else 888 { 889 status = GATT_SUCCESS; 890 } 891 } 892 } 893 break; 894 } 895 else 896 p_attr = (tGATT_ATTR16 *)p_attr->p_next; 897 } 898 } 899 900 return status; 901 } 902 903 /******************************************************************************* 904 ** 905 ** Function allocate_attr_in_db 906 ** 907 ** Description Allocate a memory space for a new attribute, and link this 908 ** attribute into the database attribute list. 909 ** 910 ** 911 ** Parameter p_db : database pointer. 912 ** p_uuid: pointer to attribute UUID 913 ** service : type of attribute to be added. 914 ** 915 ** Returns pointer to the newly allocated attribute. 916 ** 917 *******************************************************************************/ 918 static void *allocate_attr_in_db(tGATT_SVC_DB *p_db, tBT_UUID *p_uuid, tGATT_PERM perm) 919 { 920 tGATT_ATTR16 *p_attr16 = NULL, *p_last; 921 tGATT_ATTR32 *p_attr32 = NULL; 922 tGATT_ATTR128 *p_attr128 = NULL; 923 UINT16 len = sizeof(tGATT_ATTR128); 924 925 if (p_uuid == NULL) 926 { 927 GATT_TRACE_ERROR("illegal UUID"); 928 return NULL; 929 } 930 931 if (p_uuid->len == LEN_UUID_16) 932 len = sizeof(tGATT_ATTR16); 933 else if (p_uuid->len == LEN_UUID_32) 934 len = sizeof(tGATT_ATTR32); 935 936 GATT_TRACE_DEBUG("allocate attr %d bytes ",len); 937 938 if (p_db->end_handle <= p_db->next_handle) 939 { 940 GATT_TRACE_DEBUG("handle space full. handle_max = %d next_handle = %d", 941 p_db->end_handle, p_db->next_handle); 942 return NULL; 943 } 944 945 if (p_db->mem_free < len) 946 { 947 if (!allocate_svc_db_buf(p_db)) 948 { 949 GATT_TRACE_ERROR("allocate_attr_in_db failed, no resources"); 950 return NULL; 951 } 952 } 953 memset(p_db->p_free_mem, 0, len); 954 p_attr16 = (tGATT_ATTR16 *) p_db->p_free_mem; 955 956 if (p_uuid->len == LEN_UUID_16 && p_uuid->uu.uuid16 != GATT_ILLEGAL_UUID) 957 { 958 p_attr16->uuid_type = GATT_ATTR_UUID_TYPE_16; 959 p_attr16->uuid = p_uuid->uu.uuid16; 960 } 961 else if (p_uuid->len == LEN_UUID_32) 962 { 963 p_attr32 = (tGATT_ATTR32 *) p_db->p_free_mem; 964 p_attr32->uuid_type = GATT_ATTR_UUID_TYPE_32; 965 p_attr32->uuid = p_uuid->uu.uuid32; 966 } 967 else if (p_uuid->len == LEN_UUID_128) 968 { 969 p_attr128 = (tGATT_ATTR128 *) p_db->p_free_mem; 970 p_attr128->uuid_type = GATT_ATTR_UUID_TYPE_128; 971 memcpy(p_attr128->uuid, p_uuid->uu.uuid128, LEN_UUID_128); 972 } 973 974 p_db->p_free_mem += len; 975 p_db->mem_free -= len; 976 977 p_attr16->handle = p_db->next_handle++; 978 p_attr16->permission = perm; 979 p_attr16->p_next = NULL; 980 981 /* link the attribute record into the end of DB */ 982 if (p_db->p_attr_list == NULL) 983 p_db->p_attr_list = p_attr16; 984 else 985 { 986 p_last = (tGATT_ATTR16 *)p_db->p_attr_list; 987 988 while (p_last != NULL && p_last->p_next != NULL) 989 p_last = (tGATT_ATTR16 *)p_last->p_next; 990 991 p_last->p_next = p_attr16; 992 } 993 994 if (p_attr16->uuid_type == GATT_ATTR_UUID_TYPE_16) 995 { 996 GATT_TRACE_DEBUG("=====> handle = [0x%04x] uuid16 = [0x%04x] perm=0x%02x ", 997 p_attr16->handle, p_attr16->uuid, p_attr16->permission); 998 } 999 else if (p_attr16->uuid_type == GATT_ATTR_UUID_TYPE_32) 1000 { 1001 GATT_TRACE_DEBUG("=====> handle = [0x%04x] uuid32 = [0x%08x] perm=0x%02x ", 1002 p_attr32->handle, p_attr32->uuid, p_attr32->permission); 1003 } 1004 else 1005 { 1006 GATT_TRACE_DEBUG("=====> handle = [0x%04x] uuid128 = [0x%02x:0x%02x] perm=0x%02x ", 1007 p_attr128->handle, p_attr128->uuid[0],p_attr128->uuid[1], 1008 p_attr128->permission); 1009 } 1010 return(void *)p_attr16; 1011 } 1012 1013 /******************************************************************************* 1014 ** 1015 ** Function deallocate_attr_in_db 1016 ** 1017 ** Description Free an attribute within the database. 1018 ** 1019 ** Parameter p_db: database pointer. 1020 ** p_attr: pointer to the attribute record to be freed. 1021 ** 1022 ** Returns BOOLEAN: success 1023 ** 1024 *******************************************************************************/ 1025 static BOOLEAN deallocate_attr_in_db(tGATT_SVC_DB *p_db, void *p_attr) 1026 { 1027 tGATT_ATTR16 *p_cur, *p_next; 1028 BOOLEAN found = FALSE; 1029 1030 if (p_db->p_attr_list == NULL) 1031 return found; 1032 1033 p_cur = (tGATT_ATTR16 *) p_db->p_attr_list; 1034 p_next = (tGATT_ATTR16 *) p_cur->p_next; 1035 1036 for (; p_cur != NULL && p_next != NULL; 1037 p_cur = p_next, p_next = (tGATT_ATTR16 *)p_next->p_next) 1038 { 1039 if (p_next == p_attr) 1040 { 1041 p_cur->p_next = p_next->p_next; 1042 found = TRUE; 1043 } 1044 } 1045 if (p_cur == p_attr && p_cur == p_db->p_attr_list) 1046 { 1047 p_db->p_attr_list = p_cur->p_next; 1048 found = TRUE; 1049 } 1050 /* else attr not found */ 1051 if ( found) 1052 p_db->next_handle --; 1053 1054 return found; 1055 } 1056 1057 /******************************************************************************* 1058 ** 1059 ** Function copy_extra_byte_in_db 1060 ** 1061 ** Description Utility function to allocate extra bytes memory in DB and copy 1062 ** the value from a source place. 1063 ** 1064 ** 1065 ** Parameter p_db: database pointer. 1066 ** p_dst: destination data pointer. 1067 ** p_src: source data pointer. 1068 ** len: data length to be copied. 1069 ** 1070 ** Returns None. 1071 ** 1072 *******************************************************************************/ 1073 static BOOLEAN copy_extra_byte_in_db(tGATT_SVC_DB *p_db, void **p_dst, UINT16 len) 1074 { 1075 UINT8 *p = (UINT8 *)*p_dst; 1076 1077 if (p_db->mem_free < len) 1078 { 1079 if (!allocate_svc_db_buf(p_db)) 1080 { 1081 GATT_TRACE_ERROR("copy_extra_byte_in_db failed, no resources"); 1082 return FALSE; 1083 } 1084 } 1085 1086 p = p_db->p_free_mem; 1087 p_db->p_free_mem += len; 1088 p_db->mem_free -= len; 1089 memset((void *)p, 0, len); 1090 *p_dst = (void *)p; 1091 1092 return TRUE; 1093 } 1094 1095 /******************************************************************************* 1096 ** 1097 ** Function allocate_svc_db_buf 1098 ** 1099 ** Description Utility function to allocate extra buffer for service database. 1100 ** 1101 ** Returns TRUE if allocation succeed, otherwise FALSE. 1102 ** 1103 *******************************************************************************/ 1104 static BOOLEAN allocate_svc_db_buf(tGATT_SVC_DB *p_db) 1105 { 1106 BT_HDR *p_buf; 1107 1108 GATT_TRACE_DEBUG("allocate_svc_db_buf allocating extra buffer"); 1109 1110 if ((p_buf = (BT_HDR *)GKI_getpoolbuf(GATT_DB_POOL_ID)) == NULL) 1111 { 1112 GATT_TRACE_ERROR("allocate_svc_db_buf failed, no resources"); 1113 return FALSE; 1114 } 1115 1116 memset(p_buf, 0, GKI_get_buf_size(p_buf)); 1117 p_db->p_free_mem = (UINT8 *) p_buf; 1118 p_db->mem_free = GKI_get_buf_size(p_buf); 1119 1120 GKI_enqueue(&p_db->svc_buffer, p_buf); 1121 1122 return TRUE; 1123 1124 } 1125 1126 /******************************************************************************* 1127 ** 1128 ** Function gatts_send_app_read_request 1129 ** 1130 ** Description Send application read request callback 1131 ** 1132 ** Returns status of operation. 1133 ** 1134 *******************************************************************************/ 1135 static tGATT_STATUS gatts_send_app_read_request(tGATT_TCB *p_tcb, UINT8 op_code, 1136 UINT16 handle, UINT16 offset, UINT32 trans_id) 1137 { 1138 tGATTS_DATA sr_data; 1139 UINT8 i_rcb; 1140 tGATT_SR_REG *p_sreg; 1141 UINT16 conn_id; 1142 1143 i_rcb = gatt_sr_find_i_rcb_by_handle(handle); 1144 p_sreg = &gatt_cb.sr_reg[i_rcb]; 1145 conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_sreg->gatt_if); 1146 1147 if (trans_id == 0) 1148 { 1149 trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, handle); 1150 gatt_sr_update_cback_cnt(p_tcb, p_sreg->gatt_if, TRUE, TRUE); 1151 } 1152 1153 if (trans_id != 0 ) 1154 { 1155 memset(&sr_data, 0, sizeof(tGATTS_DATA)); 1156 1157 sr_data.read_req.handle = handle; 1158 sr_data.read_req.is_long = (BOOLEAN)(op_code == GATT_REQ_READ_BLOB); 1159 sr_data.read_req.offset = offset; 1160 1161 gatt_sr_send_req_callback(conn_id, 1162 trans_id, GATTS_REQ_TYPE_READ, &sr_data); 1163 return(tGATT_STATUS) GATT_PENDING; 1164 } 1165 else 1166 return(tGATT_STATUS) GATT_BUSY; /* max pending command, application error */ 1167 1168 } 1169 1170 /******************************************************************************* 1171 ** 1172 ** Function gatts_db_add_service_declaration 1173 ** 1174 ** Description Update a service database service declaration record. 1175 ** 1176 ** Parameter p_db: database pointer. 1177 ** service: UUID of the service. 1178 ** 1179 ** Returns void 1180 ** 1181 *******************************************************************************/ 1182 static BOOLEAN gatts_db_add_service_declaration(tGATT_SVC_DB *p_db, tBT_UUID *p_service, BOOLEAN is_pri) 1183 { 1184 tGATT_ATTR16 *p_attr; 1185 tBT_UUID uuid = {LEN_UUID_16, {0}}; 1186 BOOLEAN rt = FALSE; 1187 1188 GATT_TRACE_DEBUG( "add_service_declaration"); 1189 1190 if (is_pri) 1191 uuid.uu.uuid16 = GATT_UUID_PRI_SERVICE; 1192 else 1193 uuid.uu.uuid16 = GATT_UUID_SEC_SERVICE; 1194 1195 /* add service declration record */ 1196 if ((p_attr = (tGATT_ATTR16 *)(allocate_attr_in_db(p_db, &uuid, GATT_PERM_READ))) != NULL) 1197 { 1198 if (copy_extra_byte_in_db (p_db, (void **)&p_attr->p_value, sizeof(tBT_UUID))) 1199 { 1200 if (p_service->len == LEN_UUID_16) 1201 { 1202 p_attr->p_value->uuid.len = LEN_UUID_16; 1203 p_attr->p_value->uuid.uu.uuid16 = p_service->uu.uuid16; 1204 } 1205 else if (p_service->len == LEN_UUID_32) 1206 { 1207 p_attr->p_value->uuid.len = LEN_UUID_128; 1208 gatt_convert_uuid32_to_uuid128(p_attr->p_value->uuid.uu.uuid128, p_service->uu.uuid32); 1209 } 1210 else 1211 { 1212 p_attr->p_value->uuid.len = LEN_UUID_128; 1213 memcpy(p_attr->p_value->uuid.uu.uuid128, p_service->uu.uuid128, LEN_UUID_128); 1214 } 1215 rt = TRUE; 1216 } 1217 1218 } 1219 return rt; 1220 } 1221 1222 #endif /* BLE_INCLUDED */ 1223