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