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*********************************************************************************/ 41static BOOLEAN allocate_svc_db_buf(tGATT_SVC_DB *p_db); 42static void *allocate_attr_in_db(tGATT_SVC_DB *p_db, tBT_UUID *p_uuid, tGATT_PERM perm); 43static BOOLEAN deallocate_attr_in_db(tGATT_SVC_DB *p_db, void *p_attr); 44static BOOLEAN copy_extra_byte_in_db(tGATT_SVC_DB *p_db, void **p_dst, UINT16 len); 45 46static BOOLEAN gatts_db_add_service_declaration(tGATT_SVC_DB *p_db, tBT_UUID *p_service, BOOLEAN is_pri); 47static 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*******************************************************************************/ 62BOOLEAN 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 p_db->svc_buffer = fixed_queue_new(SIZE_MAX); 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*******************************************************************************/ 95tBT_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*******************************************************************************/ 118static 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*******************************************************************************/ 207static 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*******************************************************************************/ 321tGATT_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 340 if (p_db && p_db->p_attr_list) 341 { 342 p_attr = (tGATT_ATTR16 *)p_db->p_attr_list; 343 344 while (p_attr && p_attr->handle <= e_handle) 345 { 346 if (p_attr->uuid_type == GATT_ATTR_UUID_TYPE_16) 347 { 348 attr_uuid.len = LEN_UUID_16; 349 attr_uuid.uu.uuid16 = p_attr->uuid; 350 } 351 else if (p_attr->uuid_type == GATT_ATTR_UUID_TYPE_32) 352 { 353 attr_uuid.len = LEN_UUID_32; 354 attr_uuid.uu.uuid32 = ((tGATT_ATTR32 *)p_attr)->uuid; 355 } 356 else 357 { 358 attr_uuid.len = LEN_UUID_128; 359 memcpy(attr_uuid.uu.uuid128, ((tGATT_ATTR128 *)p_attr)->uuid, LEN_UUID_128); 360 } 361 362 if (p_attr->handle >= s_handle && gatt_uuid_compare(type, attr_uuid)) 363 { 364 if (*p_len <= 2) 365 { 366 status = GATT_NO_RESOURCES; 367 break; 368 } 369 370 UINT16_TO_STREAM (p, p_attr->handle); 371 372 status = read_attr_value ((void *)p_attr, 0, &p, FALSE, (UINT16)(*p_len -2), &len, sec_flag, key_size); 373 374 if (status == GATT_PENDING) 375 { 376 status = gatts_send_app_read_request(p_tcb, op_code, p_attr->handle, 0, trans_id); 377 378 /* one callback at a time */ 379 break; 380 } 381 else if (status == GATT_SUCCESS) 382 { 383 if (p_rsp->offset == 0) 384 p_rsp->offset = len + 2; 385 386 if (p_rsp->offset == len + 2) 387 { 388 p_rsp->len += (len + 2); 389 *p_len -= (len + 2); 390 } 391 else 392 { 393 GATT_TRACE_ERROR("format mismatch"); 394 status = GATT_NO_RESOURCES; 395 break; 396 } 397 } 398 else 399 { 400 *p_cur_handle = p_attr->handle; 401 break; 402 } 403 } 404 p_attr = (tGATT_ATTR16 *)p_attr->p_next; 405 } 406 } 407 408#if (defined(BLE_DELAY_REQUEST_ENC) && (BLE_DELAY_REQUEST_ENC == TRUE)) 409 UINT8 flag = 0; 410 if (BTM_GetSecurityFlags(p_tcb->peer_bda, &flag)) 411 { 412 if ((p_tcb->att_lcid == L2CAP_ATT_CID) && (status == GATT_PENDING) && 413 (type.uu.uuid16 == GATT_UUID_GAP_DEVICE_NAME)) 414 { 415 if ((flag & (BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_FLAG_ENCRYPTED)) == 416 BTM_SEC_LINK_KEY_KNOWN) 417 { 418 tACL_CONN *p = btm_bda_to_acl(p_tcb->peer_bda, BT_TRANSPORT_LE); 419 if ((p != NULL) && (p->link_role == BTM_ROLE_MASTER)) 420 btm_ble_set_encryption(p_tcb->peer_bda, BTM_BLE_SEC_ENCRYPT, p->link_role); 421 } 422 } 423 } 424#endif 425 return status; 426} 427 428/******************************************************************************* 429** 430** Function gatts_add_included_service 431** 432** Description This function adds an included service into a database. 433** 434** Parameter p_db: database pointer. 435** inc_srvc_type: included service type. 436** 437** Returns Status of the operation. 438** 439*******************************************************************************/ 440UINT16 gatts_add_included_service (tGATT_SVC_DB *p_db, UINT16 s_handle, UINT16 e_handle, 441 tBT_UUID service) 442{ 443 tGATT_ATTR16 *p_attr; 444 tBT_UUID uuid = {LEN_UUID_16, {GATT_UUID_INCLUDE_SERVICE}}; 445 446 GATT_TRACE_DEBUG("gatts_add_included_service: s_hdl = 0x%04x e_hdl = 0x%04x uuid = 0x%04x", 447 s_handle, e_handle, service.uu.uuid16); 448 449 if (service.len == 0 || s_handle == 0 || e_handle == 0) 450 { 451 GATT_TRACE_ERROR("gatts_add_included_service Illegal Params."); 452 return 0; 453 } 454 455 if ((p_attr = (tGATT_ATTR16 *) allocate_attr_in_db(p_db, &uuid, GATT_PERM_READ)) != NULL) 456 { 457 if (copy_extra_byte_in_db(p_db, (void **)&p_attr->p_value, sizeof(tGATT_INCL_SRVC))) 458 { 459 p_attr->p_value->incl_handle.s_handle = s_handle; 460 p_attr->p_value->incl_handle.e_handle = e_handle; 461 memcpy(&p_attr->p_value->incl_handle.service_type, &service, sizeof(tBT_UUID)); 462 463 return p_attr->handle; 464 } 465 else 466 { 467 deallocate_attr_in_db(p_db, p_attr); 468 } 469 } 470 471 return 0; 472} 473 474/******************************************************************************* 475** 476** Function gatts_add_characteristic 477** 478** Description This function add a characteristics and its descriptor into 479** a servce identified by the service database pointer. 480** 481** Parameter p_db: database pointer. 482** perm: permission (authentication and key size requirements) 483** property: property of the characteristic. 484** p_char: characteristic value information. 485** 486** Returns Status of te operation. 487** 488*******************************************************************************/ 489UINT16 gatts_add_characteristic (tGATT_SVC_DB *p_db, tGATT_PERM perm, 490 tGATT_CHAR_PROP property, 491 tBT_UUID * p_char_uuid) 492{ 493 tGATT_ATTR16 *p_char_decl, *p_char_val; 494 tBT_UUID uuid = {LEN_UUID_16, {GATT_UUID_CHAR_DECLARE}}; 495 496 GATT_TRACE_DEBUG("gatts_add_characteristic perm=0x%0x property=0x%0x", perm, property); 497 498 if ((p_char_decl = (tGATT_ATTR16 *)allocate_attr_in_db(p_db, &uuid, GATT_PERM_READ)) != NULL) 499 { 500 if (!copy_extra_byte_in_db(p_db, (void **)&p_char_decl->p_value, sizeof(tGATT_CHAR_DECL))) 501 { 502 deallocate_attr_in_db(p_db, p_char_decl); 503 return 0; 504 } 505 506 p_char_val = (tGATT_ATTR16 *)allocate_attr_in_db(p_db, p_char_uuid, perm); 507 508 if (p_char_val == NULL) 509 { 510 deallocate_attr_in_db(p_db, p_char_decl); 511 return 0; 512 } 513 514 p_char_decl->p_value->char_decl.property = property; 515 p_char_decl->p_value->char_decl.char_val_handle = p_char_val->handle; 516 517 p_char_val->p_value = NULL; 518 519 return p_char_val->handle; 520 } 521 522 return 0; 523} 524 525/******************************************************************************* 526** 527** Function gatt_convertchar_descr_type 528** 529** Description This function convert a char descript UUID into descriptor type. 530** 531** Returns descriptor type. 532** 533*******************************************************************************/ 534UINT8 gatt_convertchar_descr_type(tBT_UUID *p_descr_uuid) 535{ 536 tBT_UUID std_descr = {LEN_UUID_16, {GATT_UUID_CHAR_EXT_PROP}}; 537 538 if (gatt_uuid_compare(std_descr, * p_descr_uuid)) 539 return GATT_DESCR_EXT_DSCPTOR; 540 541 std_descr.uu.uuid16 ++; 542 if (gatt_uuid_compare(std_descr, * p_descr_uuid)) 543 return GATT_DESCR_USER_DSCPTOR; 544 545 std_descr.uu.uuid16 ++; 546 if (gatt_uuid_compare(std_descr, * p_descr_uuid)) 547 return GATT_DESCR_CLT_CONFIG; 548 549 std_descr.uu.uuid16 ++; 550 if (gatt_uuid_compare(std_descr, * p_descr_uuid)) 551 return GATT_DESCR_SVR_CONFIG; 552 553 std_descr.uu.uuid16 ++; 554 if (gatt_uuid_compare(std_descr, * p_descr_uuid)) 555 return GATT_DESCR_PRES_FORMAT; 556 557 std_descr.uu.uuid16 ++; 558 if (gatt_uuid_compare(std_descr, * p_descr_uuid)) 559 return GATT_DESCR_AGGR_FORMAT; 560 561 std_descr.uu.uuid16 ++; 562 if (gatt_uuid_compare(std_descr, * p_descr_uuid)) 563 return GATT_DESCR_VALID_RANGE; 564 565 566 return GATT_DESCR_UNKNOWN; 567} 568 569/******************************************************************************* 570** 571** Function gatts_add_char_descr 572** 573** Description This function add a characteristics descriptor. 574** 575** Parameter p_db: database pointer. 576** perm: characteristic descriptor permission type. 577** char_dscp_tpye: the characteristic descriptor masks. 578** p_dscp_params: characteristic descriptors values. 579** 580** Returns Status of the operation. 581** 582*******************************************************************************/ 583UINT16 gatts_add_char_descr (tGATT_SVC_DB *p_db, tGATT_PERM perm, 584 tBT_UUID * p_descr_uuid) 585{ 586 tGATT_ATTR16 *p_char_dscptr; 587 588 GATT_TRACE_DEBUG("gatts_add_char_descr uuid=0x%04x", p_descr_uuid->uu.uuid16); 589 590 /* Add characteristic descriptors */ 591 if ((p_char_dscptr = (tGATT_ATTR16 *)allocate_attr_in_db(p_db, 592 p_descr_uuid, 593 perm)) 594 == NULL) 595 { 596 GATT_TRACE_DEBUG("gatts_add_char_descr Fail for adding char descriptors."); 597 return 0; 598 } 599 else 600 { 601 return p_char_dscptr->handle; 602 } 603} 604 605/*******************************************************************************/ 606/* Service Attribute Database Query Utility Functions */ 607/*******************************************************************************/ 608/******************************************************************************* 609** 610** Function gatts_read_attr_value_by_handle 611** 612** Description Query attribute value by attribute handle. 613** 614** Parameter p_db: pointer to the attribute database. 615** handle: Attribute handle to read. 616** offset: Read offset. 617** p_value: output parameter to carry out the attribute value. 618** p_len: output parameter as attribute length read. 619** read_long: this is a read blob request. 620** mtu: MTU. 621** sec_flag: current link security status. 622** key_size: encryption key size 623** 624** Returns Status of operation. 625** 626*******************************************************************************/ 627tGATT_STATUS gatts_read_attr_value_by_handle(tGATT_TCB *p_tcb, 628 tGATT_SVC_DB *p_db, 629 UINT8 op_code, 630 UINT16 handle, UINT16 offset, 631 UINT8 *p_value, UINT16 *p_len, 632 UINT16 mtu, 633 tGATT_SEC_FLAG sec_flag, 634 UINT8 key_size, 635 UINT32 trans_id) 636{ 637 tGATT_STATUS status = GATT_NOT_FOUND; 638 tGATT_ATTR16 *p_attr; 639 UINT8 *pp = p_value; 640 641 if (p_db && p_db->p_attr_list) 642 { 643 p_attr = (tGATT_ATTR16 *)p_db->p_attr_list; 644 645 while (p_attr && handle >= p_attr->handle) 646 { 647 if (p_attr->handle == handle) 648 { 649 status = read_attr_value (p_attr, offset, &pp, 650 (BOOLEAN)(op_code == GATT_REQ_READ_BLOB), 651 mtu, p_len, sec_flag, key_size); 652 653 if (status == GATT_PENDING) 654 { 655 status = gatts_send_app_read_request(p_tcb, op_code, p_attr->handle, offset, trans_id); 656 } 657 break; 658 } 659 p_attr = (tGATT_ATTR16 *)p_attr->p_next; 660 } 661 } 662 663 return status; 664} 665 666/******************************************************************************* 667** 668** Function gatts_read_attr_perm_check 669** 670** Description Check attribute readability. 671** 672** Parameter p_db: pointer to the attribute database. 673** handle: Attribute handle to read. 674** offset: Read offset. 675** p_value: output parameter to carry out the attribute value. 676** p_len: output parameter as attribute length read. 677** read_long: this is a read blob request. 678** mtu: MTU. 679** sec_flag: current link security status. 680** key_size: encryption key size 681** 682** Returns Status of operation. 683** 684*******************************************************************************/ 685tGATT_STATUS gatts_read_attr_perm_check(tGATT_SVC_DB *p_db, 686 BOOLEAN is_long, 687 UINT16 handle, 688 tGATT_SEC_FLAG sec_flag, 689 UINT8 key_size) 690{ 691 tGATT_STATUS status = GATT_NOT_FOUND; 692 tGATT_ATTR16 *p_attr; 693 694 if (p_db && p_db->p_attr_list) 695 { 696 p_attr = (tGATT_ATTR16 *)p_db->p_attr_list; 697 698 while (p_attr && handle >= p_attr->handle) 699 { 700 if (p_attr->handle == handle) 701 { 702 status = gatts_check_attr_readability (p_attr, 0, 703 is_long, 704 sec_flag, key_size); 705 break; 706 } 707 p_attr = (tGATT_ATTR16 *) p_attr->p_next; 708 } 709 } 710 711 return status; 712} 713/******************************************************************************* 714** 715** Function gatts_write_attr_perm_check 716** 717** Description Write attribute value into database. 718** 719** Parameter p_db: pointer to the attribute database. 720** op_code:op code of this write. 721** handle: handle of the attribute to write. 722** offset: Write offset if write op code is write blob. 723** p_data: Attribute value to write. 724** len: attribute data length. 725** sec_flag: current link security status. 726** key_size: encryption key size 727** 728** Returns Status of the operation. 729** 730*******************************************************************************/ 731tGATT_STATUS gatts_write_attr_perm_check (tGATT_SVC_DB *p_db, UINT8 op_code, 732 UINT16 handle, UINT16 offset, UINT8 *p_data, 733 UINT16 len, tGATT_SEC_FLAG sec_flag, UINT8 key_size) 734{ 735 tGATT_STATUS status = GATT_NOT_FOUND; 736 tGATT_ATTR16 *p_attr; 737 UINT16 max_size = 0; 738 tGATT_PERM perm; 739 UINT16 min_key_size; 740 741 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", 742 op_code, handle, offset, len, sec_flag, key_size); 743 744 if (p_db != NULL) 745 { 746 p_attr = (tGATT_ATTR16 *) p_db->p_attr_list; 747 748 while (p_attr != NULL) 749 { 750 if (p_attr->handle == handle) 751 { 752 perm = p_attr->permission; 753 min_key_size = (((perm & GATT_ENCRYPT_KEY_SIZE_MASK) >> 12)); 754 if (min_key_size != 0 ) 755 { 756 min_key_size +=6; 757 } 758 GATT_TRACE_DEBUG( "gatts_write_attr_perm_check p_attr->permission =0x%04x min_key_size==0x%04x", 759 p_attr->permission, 760 min_key_size); 761 762 if ((op_code == GATT_CMD_WRITE || op_code == GATT_REQ_WRITE) 763 && (perm & GATT_WRITE_SIGNED_PERM)) 764 { 765 /* use the rules for the mixed security see section 10.2.3*/ 766 /* use security mode 1 level 2 when the following condition follows */ 767 /* LE security mode 2 level 1 and LE security mode 1 level 2 */ 768 if ((perm & GATT_PERM_WRITE_SIGNED) && (perm & GATT_PERM_WRITE_ENCRYPTED)) 769 { 770 perm = GATT_PERM_WRITE_ENCRYPTED; 771 } 772 /* use security mode 1 level 3 when the following condition follows */ 773 /* LE security mode 2 level 2 and security mode 1 and LE */ 774 else if (((perm & GATT_PERM_WRITE_SIGNED_MITM) && (perm & GATT_PERM_WRITE_ENCRYPTED)) || 775 /* LE security mode 2 and security mode 1 level 3 */ 776 ((perm & GATT_WRITE_SIGNED_PERM) && (perm & GATT_PERM_WRITE_ENC_MITM))) 777 { 778 perm = GATT_PERM_WRITE_ENC_MITM; 779 } 780 } 781 782 if ((op_code == GATT_SIGN_CMD_WRITE) && !(perm & GATT_WRITE_SIGNED_PERM)) 783 { 784 status = GATT_WRITE_NOT_PERMIT; 785 GATT_TRACE_DEBUG( "gatts_write_attr_perm_check - sign cmd write not allowed"); 786 } 787 if ((op_code == GATT_SIGN_CMD_WRITE) && (sec_flag & GATT_SEC_FLAG_ENCRYPTED)) 788 { 789 status = GATT_INVALID_PDU; 790 GATT_TRACE_ERROR( "gatts_write_attr_perm_check - Error!! sign cmd write sent on a encypted link"); 791 } 792 else if (!(perm & GATT_WRITE_ALLOWED)) 793 { 794 status = GATT_WRITE_NOT_PERMIT; 795 GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_WRITE_NOT_PERMIT"); 796 } 797 /* require authentication, but not been authenticated */ 798 else if ((perm & GATT_WRITE_AUTH_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_LKEY_UNAUTHED)) 799 { 800 status = GATT_INSUF_AUTHENTICATION; 801 GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_INSUF_AUTHENTICATION"); 802 } 803 else if ((perm & GATT_WRITE_MITM_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_LKEY_AUTHED)) 804 { 805 status = GATT_INSUF_AUTHENTICATION; 806 GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_INSUF_AUTHENTICATION: MITM required"); 807 } 808 else if ((perm & GATT_WRITE_ENCRYPTED_PERM ) && !(sec_flag & GATT_SEC_FLAG_ENCRYPTED)) 809 { 810 status = GATT_INSUF_ENCRYPTION; 811 GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_INSUF_ENCRYPTION"); 812 } 813 else if ((perm & GATT_WRITE_ENCRYPTED_PERM ) && (sec_flag & GATT_SEC_FLAG_ENCRYPTED) && (key_size < min_key_size)) 814 { 815 status = GATT_INSUF_KEY_SIZE; 816 GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_INSUF_KEY_SIZE"); 817 } 818 /* LE security mode 2 attribute */ 819 else if (perm & GATT_WRITE_SIGNED_PERM && op_code != GATT_SIGN_CMD_WRITE && !(sec_flag & GATT_SEC_FLAG_ENCRYPTED) 820 && (perm & GATT_WRITE_ALLOWED) == 0) 821 { 822 status = GATT_INSUF_AUTHENTICATION; 823 GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_INSUF_AUTHENTICATION: LE security mode 2 required"); 824 } 825 else /* writable: must be char value declaration or char descritpors */ 826 { 827 if(p_attr->uuid_type == GATT_ATTR_UUID_TYPE_16) 828 { 829 switch (p_attr->uuid) 830 { 831 case GATT_UUID_CHAR_PRESENT_FORMAT:/* should be readable only */ 832 case GATT_UUID_CHAR_EXT_PROP:/* should be readable only */ 833 case GATT_UUID_CHAR_AGG_FORMAT: /* should be readable only */ 834 case GATT_UUID_CHAR_VALID_RANGE: 835 status = GATT_WRITE_NOT_PERMIT; 836 break; 837 838 case GATT_UUID_CHAR_CLIENT_CONFIG: 839/* coverity[MISSING_BREAK] */ 840/* intnended fall through, ignored */ 841 /* fall through */ 842 case GATT_UUID_CHAR_SRVR_CONFIG: 843 max_size = 2; 844 case GATT_UUID_CHAR_DESCRIPTION: 845 default: /* any other must be character value declaration */ 846 status = GATT_SUCCESS; 847 break; 848 } 849 } 850 else if (p_attr->uuid_type == GATT_ATTR_UUID_TYPE_128 || 851 p_attr->uuid_type == GATT_ATTR_UUID_TYPE_32) 852 { 853 status = GATT_SUCCESS; 854 } 855 else 856 { 857 status = GATT_INVALID_PDU; 858 } 859 860 if (p_data == NULL && len > 0) 861 { 862 status = GATT_INVALID_PDU; 863 } 864 /* these attribute does not allow write blob */ 865 else if ( (p_attr->uuid_type == GATT_ATTR_UUID_TYPE_16) && 866 (p_attr->uuid == GATT_UUID_CHAR_CLIENT_CONFIG || 867 p_attr->uuid == GATT_UUID_CHAR_SRVR_CONFIG) ) 868 { 869 if (op_code == GATT_REQ_PREPARE_WRITE && offset != 0) /* does not allow write blob */ 870 { 871 status = GATT_NOT_LONG; 872 GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_NOT_LONG"); 873 } 874 else if (len != max_size) /* data does not match the required format */ 875 { 876 status = GATT_INVALID_ATTR_LEN; 877 GATT_TRACE_ERROR( "gatts_write_attr_perm_check - GATT_INVALID_PDU"); 878 } 879 else 880 { 881 status = GATT_SUCCESS; 882 } 883 } 884 } 885 break; 886 } 887 else 888 p_attr = (tGATT_ATTR16 *)p_attr->p_next; 889 } 890 } 891 892 return status; 893} 894 895/******************************************************************************* 896** 897** Function allocate_attr_in_db 898** 899** Description Allocate a memory space for a new attribute, and link this 900** attribute into the database attribute list. 901** 902** 903** Parameter p_db : database pointer. 904** p_uuid: pointer to attribute UUID 905** service : type of attribute to be added. 906** 907** Returns pointer to the newly allocated attribute. 908** 909*******************************************************************************/ 910static void *allocate_attr_in_db(tGATT_SVC_DB *p_db, tBT_UUID *p_uuid, tGATT_PERM perm) 911{ 912 tGATT_ATTR16 *p_attr16 = NULL, *p_last; 913 tGATT_ATTR32 *p_attr32 = NULL; 914 tGATT_ATTR128 *p_attr128 = NULL; 915 UINT16 len = sizeof(tGATT_ATTR128); 916 917 if (p_uuid == NULL) 918 { 919 GATT_TRACE_ERROR("illegal UUID"); 920 return NULL; 921 } 922 923 if (p_uuid->len == LEN_UUID_16) 924 len = sizeof(tGATT_ATTR16); 925 else if (p_uuid->len == LEN_UUID_32) 926 len = sizeof(tGATT_ATTR32); 927 928 GATT_TRACE_DEBUG("allocate attr %d bytes ",len); 929 930 if (p_db->end_handle <= p_db->next_handle) 931 { 932 GATT_TRACE_DEBUG("handle space full. handle_max = %d next_handle = %d", 933 p_db->end_handle, p_db->next_handle); 934 return NULL; 935 } 936 937 if (p_db->mem_free < len) 938 { 939 if (!allocate_svc_db_buf(p_db)) 940 { 941 GATT_TRACE_ERROR("allocate_attr_in_db failed, no resources"); 942 return NULL; 943 } 944 } 945 memset(p_db->p_free_mem, 0, len); 946 p_attr16 = (tGATT_ATTR16 *) p_db->p_free_mem; 947 948 if (p_uuid->len == LEN_UUID_16 && p_uuid->uu.uuid16 != GATT_ILLEGAL_UUID) 949 { 950 p_attr16->uuid_type = GATT_ATTR_UUID_TYPE_16; 951 p_attr16->uuid = p_uuid->uu.uuid16; 952 } 953 else if (p_uuid->len == LEN_UUID_32) 954 { 955 p_attr32 = (tGATT_ATTR32 *) p_db->p_free_mem; 956 p_attr32->uuid_type = GATT_ATTR_UUID_TYPE_32; 957 p_attr32->uuid = p_uuid->uu.uuid32; 958 } 959 else if (p_uuid->len == LEN_UUID_128) 960 { 961 p_attr128 = (tGATT_ATTR128 *) p_db->p_free_mem; 962 p_attr128->uuid_type = GATT_ATTR_UUID_TYPE_128; 963 memcpy(p_attr128->uuid, p_uuid->uu.uuid128, LEN_UUID_128); 964 } 965 966 p_db->p_free_mem += len; 967 p_db->mem_free -= len; 968 969 p_attr16->handle = p_db->next_handle++; 970 p_attr16->permission = perm; 971 p_attr16->p_next = NULL; 972 973 /* link the attribute record into the end of DB */ 974 if (p_db->p_attr_list == NULL) 975 p_db->p_attr_list = p_attr16; 976 else 977 { 978 p_last = (tGATT_ATTR16 *)p_db->p_attr_list; 979 980 while (p_last != NULL && p_last->p_next != NULL) 981 p_last = (tGATT_ATTR16 *)p_last->p_next; 982 983 p_last->p_next = p_attr16; 984 } 985 986 if (p_attr16->uuid_type == GATT_ATTR_UUID_TYPE_16) 987 { 988 GATT_TRACE_DEBUG("=====> handle = [0x%04x] uuid16 = [0x%04x] perm=0x%02x ", 989 p_attr16->handle, p_attr16->uuid, p_attr16->permission); 990 } 991 else if (p_attr16->uuid_type == GATT_ATTR_UUID_TYPE_32) 992 { 993 GATT_TRACE_DEBUG("=====> handle = [0x%04x] uuid32 = [0x%08x] perm=0x%02x ", 994 p_attr32->handle, p_attr32->uuid, p_attr32->permission); 995 } 996 else 997 { 998 GATT_TRACE_DEBUG("=====> handle = [0x%04x] uuid128 = [0x%02x:0x%02x] perm=0x%02x ", 999 p_attr128->handle, p_attr128->uuid[0],p_attr128->uuid[1], 1000 p_attr128->permission); 1001 } 1002 return(void *)p_attr16; 1003} 1004 1005/******************************************************************************* 1006** 1007** Function deallocate_attr_in_db 1008** 1009** Description Free an attribute within the database. 1010** 1011** Parameter p_db: database pointer. 1012** p_attr: pointer to the attribute record to be freed. 1013** 1014** Returns BOOLEAN: success 1015** 1016*******************************************************************************/ 1017static BOOLEAN deallocate_attr_in_db(tGATT_SVC_DB *p_db, void *p_attr) 1018{ 1019 tGATT_ATTR16 *p_cur, *p_next; 1020 BOOLEAN found = FALSE; 1021 1022 if (p_db->p_attr_list == NULL) 1023 return found; 1024 1025 p_cur = (tGATT_ATTR16 *) p_db->p_attr_list; 1026 p_next = (tGATT_ATTR16 *) p_cur->p_next; 1027 1028 for (; p_cur != NULL && p_next != NULL; 1029 p_cur = p_next, p_next = (tGATT_ATTR16 *)p_next->p_next) 1030 { 1031 if (p_next == p_attr) 1032 { 1033 p_cur->p_next = p_next->p_next; 1034 found = TRUE; 1035 } 1036 } 1037 if (p_cur == p_attr && p_cur == p_db->p_attr_list) 1038 { 1039 p_db->p_attr_list = p_cur->p_next; 1040 found = TRUE; 1041 } 1042 /* else attr not found */ 1043 if ( found) 1044 p_db->next_handle --; 1045 1046 return found; 1047} 1048 1049/******************************************************************************* 1050** 1051** Function copy_extra_byte_in_db 1052** 1053** Description Utility function to allocate extra bytes memory in DB and copy 1054** the value from a source place. 1055** 1056** 1057** Parameter p_db: database pointer. 1058** p_dst: destination data pointer. 1059** p_src: source data pointer. 1060** len: data length to be copied. 1061** 1062** Returns None. 1063** 1064*******************************************************************************/ 1065static BOOLEAN copy_extra_byte_in_db(tGATT_SVC_DB *p_db, void **p_dst, UINT16 len) 1066{ 1067 UINT8 *p = (UINT8 *)*p_dst; 1068 1069 if (p_db->mem_free < len) 1070 { 1071 if (!allocate_svc_db_buf(p_db)) 1072 { 1073 GATT_TRACE_ERROR("copy_extra_byte_in_db failed, no resources"); 1074 return FALSE; 1075 } 1076 } 1077 1078 p = p_db->p_free_mem; 1079 p_db->p_free_mem += len; 1080 p_db->mem_free -= len; 1081 memset((void *)p, 0, len); 1082 *p_dst = (void *)p; 1083 1084 return TRUE; 1085} 1086 1087/******************************************************************************* 1088** 1089** Function allocate_svc_db_buf 1090** 1091** Description Utility function to allocate extra buffer for service database. 1092** 1093** Returns TRUE if allocation succeed, otherwise FALSE. 1094** 1095*******************************************************************************/ 1096static BOOLEAN allocate_svc_db_buf(tGATT_SVC_DB *p_db) 1097{ 1098 BT_HDR *p_buf = (BT_HDR *)osi_calloc(GATT_DB_BUF_SIZE); 1099 1100 GATT_TRACE_DEBUG("%s allocating extra buffer", __func__); 1101 1102 p_db->p_free_mem = (UINT8 *) p_buf; 1103 p_db->mem_free = GATT_DB_BUF_SIZE; 1104 1105 fixed_queue_enqueue(p_db->svc_buffer, p_buf); 1106 1107 return TRUE; 1108 1109} 1110 1111/******************************************************************************* 1112** 1113** Function gatts_send_app_read_request 1114** 1115** Description Send application read request callback 1116** 1117** Returns status of operation. 1118** 1119*******************************************************************************/ 1120static tGATT_STATUS gatts_send_app_read_request(tGATT_TCB *p_tcb, UINT8 op_code, 1121 UINT16 handle, UINT16 offset, UINT32 trans_id) 1122{ 1123 tGATTS_DATA sr_data; 1124 UINT8 i_rcb; 1125 tGATT_SR_REG *p_sreg; 1126 UINT16 conn_id; 1127 1128 i_rcb = gatt_sr_find_i_rcb_by_handle(handle); 1129 p_sreg = &gatt_cb.sr_reg[i_rcb]; 1130 conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_sreg->gatt_if); 1131 1132 if (trans_id == 0) 1133 { 1134 trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, handle); 1135 gatt_sr_update_cback_cnt(p_tcb, p_sreg->gatt_if, TRUE, TRUE); 1136 } 1137 1138 if (trans_id != 0 ) 1139 { 1140 memset(&sr_data, 0, sizeof(tGATTS_DATA)); 1141 1142 sr_data.read_req.handle = handle; 1143 sr_data.read_req.is_long = (BOOLEAN)(op_code == GATT_REQ_READ_BLOB); 1144 sr_data.read_req.offset = offset; 1145 1146 gatt_sr_send_req_callback(conn_id, 1147 trans_id, GATTS_REQ_TYPE_READ, &sr_data); 1148 return(tGATT_STATUS) GATT_PENDING; 1149 } 1150 else 1151 return(tGATT_STATUS) GATT_BUSY; /* max pending command, application error */ 1152 1153} 1154 1155/******************************************************************************* 1156** 1157** Function gatts_db_add_service_declaration 1158** 1159** Description Update a service database service declaration record. 1160** 1161** Parameter p_db: database pointer. 1162** service: UUID of the service. 1163** 1164** Returns void 1165** 1166*******************************************************************************/ 1167static BOOLEAN gatts_db_add_service_declaration(tGATT_SVC_DB *p_db, tBT_UUID *p_service, BOOLEAN is_pri) 1168{ 1169 tGATT_ATTR16 *p_attr; 1170 tBT_UUID uuid = {LEN_UUID_16, {0}}; 1171 BOOLEAN rt = FALSE; 1172 1173 GATT_TRACE_DEBUG( "add_service_declaration"); 1174 1175 if (is_pri) 1176 uuid.uu.uuid16 = GATT_UUID_PRI_SERVICE; 1177 else 1178 uuid.uu.uuid16 = GATT_UUID_SEC_SERVICE; 1179 1180 /* add service declration record */ 1181 if ((p_attr = (tGATT_ATTR16 *)(allocate_attr_in_db(p_db, &uuid, GATT_PERM_READ))) != NULL) 1182 { 1183 if (copy_extra_byte_in_db (p_db, (void **)&p_attr->p_value, sizeof(tBT_UUID))) 1184 { 1185 if (p_service->len == LEN_UUID_16) 1186 { 1187 p_attr->p_value->uuid.len = LEN_UUID_16; 1188 p_attr->p_value->uuid.uu.uuid16 = p_service->uu.uuid16; 1189 } 1190 else if (p_service->len == LEN_UUID_32) 1191 { 1192 p_attr->p_value->uuid.len = LEN_UUID_128; 1193 gatt_convert_uuid32_to_uuid128(p_attr->p_value->uuid.uu.uuid128, p_service->uu.uuid32); 1194 } 1195 else 1196 { 1197 p_attr->p_value->uuid.len = LEN_UUID_128; 1198 memcpy(p_attr->p_value->uuid.uu.uuid128, p_service->uu.uuid128, LEN_UUID_128); 1199 } 1200 rt = TRUE; 1201 } 1202 1203 } 1204 return rt; 1205} 1206 1207#endif /* BLE_INCLUDED */ 1208