1 /****************************************************************************** 2 * 3 * Copyright 1999-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 interface functions 22 * 23 ******************************************************************************/ 24 #include "bt_target.h" 25 26 #include <base/strings/string_number_conversions.h> 27 #include <base/strings/stringprintf.h> 28 #include <stdio.h> 29 #include <string.h> 30 #include "bt_common.h" 31 #include "btm_int.h" 32 #include "device/include/controller.h" 33 #include "gatt_api.h" 34 #include "gatt_int.h" 35 #include "l2c_api.h" 36 37 using base::StringPrintf; 38 using bluetooth::Uuid; 39 40 /** 41 * Add an service handle range to the list in decending order of the start 42 * handle. Return reference to the newly added element. 43 **/ 44 tGATT_HDL_LIST_ELEM& gatt_add_an_item_to_list(uint16_t s_handle) { 45 auto lst_ptr = gatt_cb.hdl_list_info; 46 auto it = lst_ptr->begin(); 47 for (; it != lst_ptr->end(); it++) { 48 if (s_handle > it->asgn_range.s_handle) break; 49 } 50 51 auto rit = lst_ptr->emplace(it); 52 return *rit; 53 } 54 55 /***************************************************************************** 56 * 57 * GATT SERVER API 58 * 59 *****************************************************************************/ 60 /******************************************************************************* 61 * 62 * Function GATTS_AddHandleRange 63 * 64 * Description This function add the allocated handles range for the 65 * specified application UUID, service UUID and service 66 * instance 67 * 68 * Parameter p_hndl_range: pointer to allocated handles information 69 * 70 **/ 71 72 void GATTS_AddHandleRange(tGATTS_HNDL_RANGE* p_hndl_range) { 73 gatt_add_an_item_to_list(p_hndl_range->s_handle); 74 } 75 76 /******************************************************************************* 77 * 78 * Function GATTS_NVRegister 79 * 80 * Description Application manager calls this function to register for 81 * NV save callback function. There can be one and only one 82 * NV save callback function. 83 * 84 * Parameter p_cb_info : callback informaiton 85 * 86 * Returns true if registered OK, else false 87 * 88 ******************************************************************************/ 89 bool GATTS_NVRegister(tGATT_APPL_INFO* p_cb_info) { 90 bool status = false; 91 if (p_cb_info) { 92 gatt_cb.cb_info = *p_cb_info; 93 status = true; 94 gatt_init_srv_chg(); 95 } 96 97 return status; 98 } 99 100 static uint16_t compute_service_size(btgatt_db_element_t* service, int count) { 101 int db_size = 0; 102 btgatt_db_element_t* el = service; 103 104 for (int i = 0; i < count; i++, el++) 105 if (el->type == BTGATT_DB_PRIMARY_SERVICE || 106 el->type == BTGATT_DB_SECONDARY_SERVICE || 107 el->type == BTGATT_DB_DESCRIPTOR || 108 el->type == BTGATT_DB_INCLUDED_SERVICE) 109 db_size += 1; 110 else if (el->type == BTGATT_DB_CHARACTERISTIC) 111 db_size += 2; 112 else 113 LOG(ERROR) << __func__ << ": Unknown element type: " << el->type; 114 115 return db_size; 116 } 117 118 static bool is_gatt_attr_type(const Uuid& uuid) { 119 if (uuid == Uuid::From16Bit(GATT_UUID_PRI_SERVICE) || 120 uuid == Uuid::From16Bit(GATT_UUID_SEC_SERVICE) || 121 uuid == Uuid::From16Bit(GATT_UUID_INCLUDE_SERVICE) || 122 uuid == Uuid::From16Bit(GATT_UUID_CHAR_DECLARE)) { 123 return true; 124 } 125 return false; 126 } 127 128 /** Update the the last service info for the service list info */ 129 static void gatt_update_last_srv_info() { 130 gatt_cb.last_service_handle = 0; 131 132 for (tGATT_SRV_LIST_ELEM& el : *gatt_cb.srv_list_info) { 133 gatt_cb.last_service_handle = el.s_hdl; 134 } 135 } 136 137 /******************************************************************************* 138 * 139 * Function GATTS_AddService 140 * 141 * Description This function is called to add GATT service. 142 * 143 * Parameter gatt_if : application if 144 * service : pseudo-representation of service and it's content 145 * count : size of service 146 * 147 * Returns on success GATT_SERVICE_STARTED is returned, and 148 * attribute_handle field inside service elements are filled. 149 * on error error status is returned. 150 * 151 ******************************************************************************/ 152 uint16_t GATTS_AddService(tGATT_IF gatt_if, btgatt_db_element_t* service, 153 int count) { 154 uint16_t s_hdl = 0; 155 bool save_hdl = false; 156 tGATT_REG* p_reg = gatt_get_regcb(gatt_if); 157 158 bool is_pri = (service->type == BTGATT_DB_PRIMARY_SERVICE) ? true : false; 159 Uuid svc_uuid = service->uuid; 160 161 LOG(INFO) << __func__; 162 163 if (!p_reg) { 164 LOG(ERROR) << "Inavlid gatt_if=" << +gatt_if; 165 return GATT_INTERNAL_ERROR; 166 } 167 168 uint16_t num_handles = compute_service_size(service, count); 169 170 if (svc_uuid == Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER)) { 171 s_hdl = gatt_cb.hdl_cfg.gatt_start_hdl; 172 } else if (svc_uuid == Uuid::From16Bit(UUID_SERVCLASS_GAP_SERVER)) { 173 s_hdl = gatt_cb.hdl_cfg.gap_start_hdl; 174 } else { 175 if (!gatt_cb.hdl_list_info->empty()) { 176 s_hdl = gatt_cb.hdl_list_info->front().asgn_range.e_handle + 1; 177 } 178 179 if (s_hdl < gatt_cb.hdl_cfg.app_start_hdl) 180 s_hdl = gatt_cb.hdl_cfg.app_start_hdl; 181 182 save_hdl = true; 183 } 184 185 /* check for space */ 186 if (num_handles > (0xFFFF - s_hdl + 1)) { 187 LOG(ERROR) << StringPrintf( 188 "GATTS_ReserveHandles: no handles, s_hdl: %u needed: %u", s_hdl, 189 num_handles); 190 return GATT_INTERNAL_ERROR; 191 } 192 193 tGATT_HDL_LIST_ELEM& list = gatt_add_an_item_to_list(s_hdl); 194 list.asgn_range.app_uuid128 = p_reg->app_uuid128; 195 list.asgn_range.svc_uuid = svc_uuid; 196 list.asgn_range.s_handle = s_hdl; 197 list.asgn_range.e_handle = s_hdl + num_handles - 1; 198 list.asgn_range.is_primary = is_pri; 199 200 if (save_hdl) { 201 if (gatt_cb.cb_info.p_nv_save_callback) 202 (*gatt_cb.cb_info.p_nv_save_callback)(true, &list.asgn_range); 203 } 204 205 gatts_init_service_db(list.svc_db, svc_uuid, is_pri, s_hdl, num_handles); 206 207 VLOG(1) << StringPrintf( 208 "%s: handles needed:%u s_hdl=%u e_hdl=%u %s is_primary=%d", __func__, 209 num_handles, list.asgn_range.s_handle, list.asgn_range.e_handle, 210 list.asgn_range.svc_uuid.ToString().c_str(), list.asgn_range.is_primary); 211 212 service->attribute_handle = s_hdl; 213 214 btgatt_db_element_t* el = service + 1; 215 for (int i = 0; i < count - 1; i++, el++) { 216 const Uuid& uuid = el->uuid; 217 218 if (el->type == BTGATT_DB_CHARACTERISTIC) { 219 /* data validity checking */ 220 if (((el->properties & GATT_CHAR_PROP_BIT_AUTH) && 221 !(el->permissions & GATT_WRITE_SIGNED_PERM)) || 222 ((el->permissions & GATT_WRITE_SIGNED_PERM) && 223 !(el->properties & GATT_CHAR_PROP_BIT_AUTH))) { 224 VLOG(1) << StringPrintf( 225 "Invalid configuration property=0x%02x perm=0x%04x ", 226 el->properties, el->permissions); 227 return GATT_INTERNAL_ERROR; 228 } 229 230 if (is_gatt_attr_type(uuid)) { 231 LOG(ERROR) << StringPrintf( 232 "%s: attept to add characteristic with UUID equal to GATT " 233 "Attribute Type %s ", 234 __func__, uuid.ToString().c_str()); 235 return GATT_INTERNAL_ERROR; 236 } 237 238 el->attribute_handle = gatts_add_characteristic( 239 list.svc_db, el->permissions, el->properties, uuid); 240 } else if (el->type == BTGATT_DB_DESCRIPTOR) { 241 if (is_gatt_attr_type(uuid)) { 242 LOG(ERROR) << StringPrintf( 243 "%s: attept to add descriptor with UUID equal to GATT " 244 "Attribute Type %s", 245 __func__, uuid.ToString().c_str()); 246 return GATT_INTERNAL_ERROR; 247 } 248 249 el->attribute_handle = 250 gatts_add_char_descr(list.svc_db, el->permissions, uuid); 251 } else if (el->type == BTGATT_DB_INCLUDED_SERVICE) { 252 tGATT_HDL_LIST_ELEM* p_incl_decl; 253 p_incl_decl = gatt_find_hdl_buffer_by_handle(el->attribute_handle); 254 if (p_incl_decl == nullptr) { 255 VLOG(1) << "Included Service not created"; 256 return GATT_INTERNAL_ERROR; 257 } 258 259 el->attribute_handle = gatts_add_included_service( 260 list.svc_db, p_incl_decl->asgn_range.s_handle, 261 p_incl_decl->asgn_range.e_handle, p_incl_decl->asgn_range.svc_uuid); 262 } 263 } 264 265 LOG(INFO) << __func__ << ": service parsed correctly, now starting"; 266 267 /*this is a new application service start */ 268 269 // find a place for this service in the list 270 auto lst_ptr = gatt_cb.srv_list_info; 271 auto it = lst_ptr->begin(); 272 for (; it != lst_ptr->end(); it++) { 273 if (list.asgn_range.s_handle < it->s_hdl) break; 274 } 275 auto rit = lst_ptr->emplace(it); 276 277 tGATT_SRV_LIST_ELEM& elem = *rit; 278 elem.gatt_if = gatt_if; 279 elem.s_hdl = list.asgn_range.s_handle; 280 elem.e_hdl = list.asgn_range.e_handle; 281 elem.p_db = &list.svc_db; 282 elem.is_primary = list.asgn_range.is_primary; 283 284 elem.app_uuid = list.asgn_range.app_uuid128; 285 elem.type = list.asgn_range.is_primary ? GATT_UUID_PRI_SERVICE 286 : GATT_UUID_SEC_SERVICE; 287 288 if (elem.type == GATT_UUID_PRI_SERVICE) { 289 Uuid* p_uuid = gatts_get_service_uuid(elem.p_db); 290 elem.sdp_handle = gatt_add_sdp_record(*p_uuid, elem.s_hdl, elem.e_hdl); 291 } else { 292 elem.sdp_handle = 0; 293 } 294 295 gatt_update_last_srv_info(); 296 297 VLOG(1) << StringPrintf( 298 "%s: allocated el: s_hdl=%d e_hdl=%d type=0x%x sdp_hdl=0x%x", __func__, 299 elem.s_hdl, elem.e_hdl, elem.type, elem.sdp_handle); 300 301 gatt_proc_srv_chg(); 302 303 return GATT_SERVICE_STARTED; 304 } 305 306 bool is_active_service(const Uuid& app_uuid128, Uuid* p_svc_uuid, 307 uint16_t start_handle) { 308 for (auto& info : *gatt_cb.srv_list_info) { 309 Uuid* p_this_uuid = gatts_get_service_uuid(info.p_db); 310 311 if (p_this_uuid && app_uuid128 == info.app_uuid && 312 *p_svc_uuid == *p_this_uuid && (start_handle == info.s_hdl)) { 313 LOG(ERROR) << "Active Service Found: " << *p_svc_uuid; 314 return true; 315 } 316 } 317 return false; 318 } 319 320 /******************************************************************************* 321 * 322 * Function GATTS_DeleteService 323 * 324 * Description This function is called to delete a service. 325 * 326 * Parameter gatt_if : application interface 327 * p_svc_uuid : service UUID 328 * start_handle : start handle of the service 329 * 330 * Returns true if the operation succeeded, false if the handle block 331 * was not found. 332 * 333 ******************************************************************************/ 334 bool GATTS_DeleteService(tGATT_IF gatt_if, Uuid* p_svc_uuid, 335 uint16_t svc_inst) { 336 VLOG(1) << __func__; 337 338 tGATT_REG* p_reg = gatt_get_regcb(gatt_if); 339 if (p_reg == NULL) { 340 LOG(ERROR) << "Applicaiton not foud"; 341 return false; 342 } 343 344 auto it = 345 gatt_find_hdl_buffer_by_app_id(p_reg->app_uuid128, p_svc_uuid, svc_inst); 346 if (it == gatt_cb.hdl_list_info->end()) { 347 LOG(ERROR) << "No Service found"; 348 return false; 349 } 350 351 gatt_proc_srv_chg(); 352 353 if (is_active_service(p_reg->app_uuid128, p_svc_uuid, svc_inst)) { 354 GATTS_StopService(it->asgn_range.s_handle); 355 } 356 357 VLOG(1) << StringPrintf("released handles s_hdl=%u e_hdl=%u", 358 it->asgn_range.s_handle, it->asgn_range.e_handle); 359 360 if ((it->asgn_range.s_handle >= gatt_cb.hdl_cfg.app_start_hdl) && 361 gatt_cb.cb_info.p_nv_save_callback) 362 (*gatt_cb.cb_info.p_nv_save_callback)(false, &it->asgn_range); 363 364 gatt_cb.hdl_list_info->erase(it); 365 return true; 366 } 367 368 /******************************************************************************* 369 * 370 * Function GATTS_StopService 371 * 372 * Description This function is called to stop a service 373 * 374 * Parameter service_handle : this is the start handle of a service 375 * 376 * Returns None. 377 * 378 ******************************************************************************/ 379 void GATTS_StopService(uint16_t service_handle) { 380 LOG(INFO) << __func__ << ": 0x" << std::hex << +service_handle; 381 382 auto it = gatt_sr_find_i_rcb_by_handle(service_handle); 383 if (it == gatt_cb.srv_list_info->end()) { 384 LOG(ERROR) << StringPrintf("%s: service_handle: %u is not in use", __func__, 385 service_handle); 386 } 387 388 if (it->sdp_handle) { 389 SDP_DeleteRecord(it->sdp_handle); 390 } 391 392 gatt_cb.srv_list_info->erase(it); 393 gatt_update_last_srv_info(); 394 } 395 /******************************************************************************* 396 * 397 * Function GATTs_HandleValueIndication 398 * 399 * Description This function sends a handle value indication to a client. 400 * 401 * Parameter conn_id: connection identifier. 402 * attr_handle: Attribute handle of this handle value 403 * indication. 404 * val_len: Length of the indicated attribute value. 405 * p_val: Pointer to the indicated attribute value data. 406 * 407 * Returns GATT_SUCCESS if sucessfully sent or queued; otherwise error 408 * code. 409 * 410 ******************************************************************************/ 411 tGATT_STATUS GATTS_HandleValueIndication(uint16_t conn_id, uint16_t attr_handle, 412 uint16_t val_len, uint8_t* p_val) { 413 tGATT_STATUS cmd_status = GATT_NO_RESOURCES; 414 415 tGATT_VALUE indication; 416 BT_HDR* p_msg; 417 tGATT_VALUE* p_buf; 418 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id); 419 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id); 420 tGATT_REG* p_reg = gatt_get_regcb(gatt_if); 421 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx); 422 423 VLOG(1) << __func__; 424 if ((p_reg == NULL) || (p_tcb == NULL)) { 425 LOG(ERROR) << __func__ << ": Unknown conn_id: " << +conn_id; 426 return (tGATT_STATUS)GATT_INVALID_CONN_ID; 427 } 428 429 if (!GATT_HANDLE_IS_VALID(attr_handle)) return GATT_ILLEGAL_PARAMETER; 430 431 indication.conn_id = conn_id; 432 indication.handle = attr_handle; 433 indication.len = val_len; 434 memcpy(indication.value, p_val, val_len); 435 indication.auth_req = GATT_AUTH_REQ_NONE; 436 437 if (GATT_HANDLE_IS_VALID(p_tcb->indicate_handle)) { 438 VLOG(1) << "Add a pending indication"; 439 p_buf = gatt_add_pending_ind(p_tcb, &indication); 440 if (p_buf != NULL) { 441 cmd_status = GATT_SUCCESS; 442 } else { 443 cmd_status = GATT_NO_RESOURCES; 444 } 445 } else { 446 tGATT_SR_MSG gatt_sr_msg; 447 gatt_sr_msg.attr_value = indication; 448 p_msg = attp_build_sr_msg(*p_tcb, GATT_HANDLE_VALUE_IND, &gatt_sr_msg); 449 if (p_msg != NULL) { 450 cmd_status = attp_send_sr_msg(*p_tcb, p_msg); 451 452 if (cmd_status == GATT_SUCCESS || cmd_status == GATT_CONGESTED) { 453 p_tcb->indicate_handle = indication.handle; 454 gatt_start_conf_timer(p_tcb); 455 } 456 } 457 } 458 return cmd_status; 459 } 460 461 /******************************************************************************* 462 * 463 * Function GATTS_HandleValueNotification 464 * 465 * Description This function sends a handle value notification to a client. 466 * 467 * Parameter conn_id: connection identifier. 468 * attr_handle: Attribute handle of this handle value 469 * indication. 470 * val_len: Length of the indicated attribute value. 471 * p_val: Pointer to the indicated attribute value data. 472 * 473 * Returns GATT_SUCCESS if sucessfully sent; otherwise error code. 474 * 475 ******************************************************************************/ 476 tGATT_STATUS GATTS_HandleValueNotification(uint16_t conn_id, 477 uint16_t attr_handle, 478 uint16_t val_len, uint8_t* p_val) { 479 tGATT_VALUE notif; 480 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id); 481 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id); 482 tGATT_REG* p_reg = gatt_get_regcb(gatt_if); 483 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx); 484 485 VLOG(1) << __func__; 486 487 if ((p_reg == NULL) || (p_tcb == NULL)) { 488 LOG(ERROR) << __func__ << "Unknown conn_id: " << conn_id; 489 return (tGATT_STATUS)GATT_INVALID_CONN_ID; 490 } 491 492 if (!GATT_HANDLE_IS_VALID(attr_handle)) { 493 return GATT_ILLEGAL_PARAMETER; 494 } 495 496 notif.handle = attr_handle; 497 notif.len = val_len; 498 memcpy(notif.value, p_val, val_len); 499 notif.auth_req = GATT_AUTH_REQ_NONE; 500 501 tGATT_STATUS cmd_sent; 502 tGATT_SR_MSG gatt_sr_msg; 503 gatt_sr_msg.attr_value = notif; 504 BT_HDR* p_buf = 505 attp_build_sr_msg(*p_tcb, GATT_HANDLE_VALUE_NOTIF, &gatt_sr_msg); 506 if (p_buf != NULL) { 507 cmd_sent = attp_send_sr_msg(*p_tcb, p_buf); 508 } else 509 cmd_sent = GATT_NO_RESOURCES; 510 return cmd_sent; 511 } 512 513 /******************************************************************************* 514 * 515 * Function GATTS_SendRsp 516 * 517 * Description This function sends the server response to client. 518 * 519 * Parameter conn_id: connection identifier. 520 * trans_id: transaction id 521 * status: response status 522 * p_msg: pointer to message parameters structure. 523 * 524 * Returns GATT_SUCCESS if sucessfully sent; otherwise error code. 525 * 526 ******************************************************************************/ 527 tGATT_STATUS GATTS_SendRsp(uint16_t conn_id, uint32_t trans_id, 528 tGATT_STATUS status, tGATTS_RSP* p_msg) { 529 tGATT_STATUS cmd_sent = GATT_ILLEGAL_PARAMETER; 530 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id); 531 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id); 532 tGATT_REG* p_reg = gatt_get_regcb(gatt_if); 533 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx); 534 535 VLOG(1) << __func__ 536 << StringPrintf(": conn_id: %u trans_id: %u Status: 0x%04x", 537 conn_id, trans_id, status); 538 539 if ((p_reg == NULL) || (p_tcb == NULL)) { 540 LOG(ERROR) << StringPrintf("Unknown conn_id: %u ", conn_id); 541 return (tGATT_STATUS)GATT_INVALID_CONN_ID; 542 } 543 544 if (p_tcb->sr_cmd.trans_id != trans_id) { 545 LOG(ERROR) << StringPrintf("conn_id: %u waiting for op_code = %02x", 546 conn_id, p_tcb->sr_cmd.op_code); 547 548 return (GATT_WRONG_STATE); 549 } 550 /* Process App response */ 551 cmd_sent = gatt_sr_process_app_rsp(*p_tcb, gatt_if, trans_id, 552 p_tcb->sr_cmd.op_code, status, p_msg); 553 554 return cmd_sent; 555 } 556 557 /******************************************************************************/ 558 /* GATT Profile Srvr Functions */ 559 /******************************************************************************/ 560 561 /******************************************************************************/ 562 /* */ 563 /* GATT CLIENT APIs */ 564 /* */ 565 /******************************************************************************/ 566 567 /******************************************************************************* 568 * 569 * Function GATTC_ConfigureMTU 570 * 571 * Description This function is called to configure the ATT MTU size. 572 * 573 * Parameters conn_id: connection identifier. 574 * mtu - attribute MTU size.. 575 * 576 * Returns GATT_SUCCESS if command started successfully. 577 * 578 ******************************************************************************/ 579 tGATT_STATUS GATTC_ConfigureMTU(uint16_t conn_id, uint16_t mtu) { 580 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id); 581 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id); 582 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx); 583 tGATT_REG* p_reg = gatt_get_regcb(gatt_if); 584 585 VLOG(1) << __func__ << StringPrintf("conn_id=%d mtu=%d", conn_id, mtu); 586 587 if ((p_tcb == NULL) || (p_reg == NULL) || (mtu < GATT_DEF_BLE_MTU_SIZE) || 588 (mtu > GATT_MAX_MTU_SIZE)) { 589 return GATT_ILLEGAL_PARAMETER; 590 } 591 592 /* Validate that the link is BLE, not BR/EDR */ 593 if (p_tcb->transport != BT_TRANSPORT_LE) { 594 return GATT_ERROR; 595 } 596 597 if (gatt_is_clcb_allocated(conn_id)) { 598 LOG(ERROR) << "GATT_BUSY conn_id = " << +conn_id; 599 return GATT_BUSY; 600 } 601 602 tGATT_CLCB* p_clcb = gatt_clcb_alloc(conn_id); 603 if (!p_clcb) return GATT_NO_RESOURCES; 604 605 p_clcb->p_tcb->payload_size = mtu; 606 p_clcb->operation = GATTC_OPTYPE_CONFIG; 607 tGATT_CL_MSG gatt_cl_msg; 608 gatt_cl_msg.mtu = mtu; 609 return attp_send_cl_msg(*p_clcb->p_tcb, p_clcb, GATT_REQ_MTU, &gatt_cl_msg); 610 } 611 612 /******************************************************************************* 613 * 614 * Function GATTC_Discover 615 * 616 * Description This function is called to do a discovery procedure on ATT 617 * server. 618 * 619 * Parameters conn_id: connection identifier. 620 * disc_type:discovery type. 621 * p_param: parameters of discovery requirement. 622 * 623 * Returns GATT_SUCCESS if command received/sent successfully. 624 * 625 ******************************************************************************/ 626 tGATT_STATUS GATTC_Discover(uint16_t conn_id, tGATT_DISC_TYPE disc_type, 627 tGATT_DISC_PARAM* p_param) { 628 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id); 629 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id); 630 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx); 631 tGATT_REG* p_reg = gatt_get_regcb(gatt_if); 632 633 LOG(INFO) << __func__ 634 << StringPrintf(" conn_id=%d disc_type=%d", conn_id, disc_type); 635 636 if ((p_tcb == NULL) || (p_reg == NULL) || (p_param == NULL) || 637 (disc_type >= GATT_DISC_MAX)) { 638 LOG(ERROR) << StringPrintf("Illegal param: disc_type %d conn_id = %d", 639 disc_type, conn_id); 640 return GATT_ILLEGAL_PARAMETER; 641 } 642 643 if (!GATT_HANDLE_IS_VALID(p_param->s_handle) || 644 !GATT_HANDLE_IS_VALID(p_param->e_handle) || 645 /* search by type does not have a valid UUID param */ 646 (disc_type == GATT_DISC_SRVC_BY_UUID && p_param->service.IsEmpty())) { 647 return GATT_ILLEGAL_PARAMETER; 648 } 649 650 if (gatt_is_clcb_allocated(conn_id)) { 651 LOG(ERROR) << __func__ << "GATT_BUSY conn_id = " << +conn_id; 652 return GATT_BUSY; 653 } 654 655 tGATT_CLCB* p_clcb = gatt_clcb_alloc(conn_id); 656 if (!p_clcb) return GATT_NO_RESOURCES; 657 658 p_clcb->operation = GATTC_OPTYPE_DISCOVERY; 659 p_clcb->op_subtype = disc_type; 660 p_clcb->s_handle = p_param->s_handle; 661 p_clcb->e_handle = p_param->e_handle; 662 p_clcb->uuid = p_param->service; 663 664 gatt_act_discovery(p_clcb); 665 return GATT_SUCCESS; 666 } 667 668 /******************************************************************************* 669 * 670 * Function GATTC_Read 671 * 672 * Description This function is called to read the value of an attribute 673 * from the server. 674 * 675 * Parameters conn_id: connection identifier. 676 * type - attribute read type. 677 * p_read - read operation parameters. 678 * 679 * Returns GATT_SUCCESS if command started successfully. 680 * 681 ******************************************************************************/ 682 tGATT_STATUS GATTC_Read(uint16_t conn_id, tGATT_READ_TYPE type, 683 tGATT_READ_PARAM* p_read) { 684 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id); 685 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id); 686 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx); 687 tGATT_REG* p_reg = gatt_get_regcb(gatt_if); 688 689 VLOG(1) << __func__ << StringPrintf(" conn_id=%d type=%d", conn_id, type); 690 691 if ((p_tcb == NULL) || (p_reg == NULL) || (p_read == NULL) || 692 ((type >= GATT_READ_MAX) || (type == 0))) { 693 LOG(ERROR) << StringPrintf(" Illegal param: conn_id %d, type 0%d,", conn_id, 694 type); 695 return GATT_ILLEGAL_PARAMETER; 696 } 697 698 if (gatt_is_clcb_allocated(conn_id)) { 699 LOG(ERROR) << StringPrintf(" GATT_BUSY conn_id = %d", conn_id); 700 return GATT_BUSY; 701 } 702 703 tGATT_CLCB* p_clcb = gatt_clcb_alloc(conn_id); 704 if (!p_clcb) return GATT_NO_RESOURCES; 705 706 p_clcb->operation = GATTC_OPTYPE_READ; 707 p_clcb->op_subtype = type; 708 p_clcb->auth_req = p_read->by_handle.auth_req; 709 p_clcb->counter = 0; 710 711 switch (type) { 712 case GATT_READ_BY_TYPE: 713 case GATT_READ_CHAR_VALUE: 714 p_clcb->s_handle = p_read->service.s_handle; 715 p_clcb->e_handle = p_read->service.e_handle; 716 p_clcb->uuid = p_read->service.uuid; 717 break; 718 case GATT_READ_MULTIPLE: { 719 p_clcb->s_handle = 0; 720 /* copy multiple handles in CB */ 721 tGATT_READ_MULTI* p_read_multi = 722 (tGATT_READ_MULTI*)osi_malloc(sizeof(tGATT_READ_MULTI)); 723 p_clcb->p_attr_buf = (uint8_t*)p_read_multi; 724 memcpy(p_read_multi, &p_read->read_multiple, sizeof(tGATT_READ_MULTI)); 725 break; 726 } 727 case GATT_READ_BY_HANDLE: 728 case GATT_READ_PARTIAL: 729 p_clcb->uuid = Uuid::kEmpty; 730 p_clcb->s_handle = p_read->by_handle.handle; 731 732 if (type == GATT_READ_PARTIAL) { 733 p_clcb->counter = p_read->partial.offset; 734 } 735 736 break; 737 default: 738 break; 739 } 740 741 /* start security check */ 742 gatt_security_check_start(p_clcb); 743 return GATT_SUCCESS; 744 } 745 746 /******************************************************************************* 747 * 748 * Function GATTC_Write 749 * 750 * Description This function is called to write the value of an attribute 751 * to the server. 752 * 753 * Parameters conn_id: connection identifier. 754 * type - attribute write type. 755 * p_write - write operation parameters. 756 * 757 * Returns GATT_SUCCESS if command started successfully. 758 * 759 ******************************************************************************/ 760 tGATT_STATUS GATTC_Write(uint16_t conn_id, tGATT_WRITE_TYPE type, 761 tGATT_VALUE* p_write) { 762 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id); 763 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id); 764 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx); 765 tGATT_REG* p_reg = gatt_get_regcb(gatt_if); 766 767 if ((p_tcb == NULL) || (p_reg == NULL) || (p_write == NULL) || 768 ((type != GATT_WRITE) && (type != GATT_WRITE_PREPARE) && 769 (type != GATT_WRITE_NO_RSP))) { 770 LOG(ERROR) << __func__ 771 << StringPrintf(" Illegal param: conn_id %d, type 0%d,", conn_id, 772 type); 773 return GATT_ILLEGAL_PARAMETER; 774 } 775 776 if (gatt_is_clcb_allocated(conn_id)) { 777 LOG(ERROR) << StringPrintf("GATT_BUSY conn_id = %d", conn_id); 778 return GATT_BUSY; 779 } 780 781 tGATT_CLCB* p_clcb = gatt_clcb_alloc(conn_id); 782 if (!p_clcb) return GATT_NO_RESOURCES; 783 784 p_clcb->operation = GATTC_OPTYPE_WRITE; 785 p_clcb->op_subtype = type; 786 p_clcb->auth_req = p_write->auth_req; 787 788 p_clcb->p_attr_buf = (uint8_t*)osi_malloc(sizeof(tGATT_VALUE)); 789 memcpy(p_clcb->p_attr_buf, (void*)p_write, sizeof(tGATT_VALUE)); 790 791 tGATT_VALUE* p = (tGATT_VALUE*)p_clcb->p_attr_buf; 792 if (type == GATT_WRITE_PREPARE) { 793 p_clcb->start_offset = p_write->offset; 794 p->offset = 0; 795 } 796 797 gatt_security_check_start(p_clcb); 798 return GATT_SUCCESS; 799 } 800 801 /******************************************************************************* 802 * 803 * Function GATTC_ExecuteWrite 804 * 805 * Description This function is called to send an Execute write request to 806 * the server. 807 * 808 * Parameters conn_id: connection identifier. 809 * is_execute - to execute or cancel the prepared write 810 * request(s) 811 * 812 * Returns GATT_SUCCESS if command started successfully. 813 * 814 ******************************************************************************/ 815 tGATT_STATUS GATTC_ExecuteWrite(uint16_t conn_id, bool is_execute) { 816 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id); 817 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id); 818 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx); 819 tGATT_REG* p_reg = gatt_get_regcb(gatt_if); 820 821 VLOG(1) << __func__ 822 << StringPrintf(": conn_id=%d is_execute=%d", conn_id, is_execute); 823 824 if ((p_tcb == NULL) || (p_reg == NULL)) { 825 LOG(ERROR) << StringPrintf(" Illegal param: conn_id %d", conn_id); 826 return GATT_ILLEGAL_PARAMETER; 827 } 828 829 if (gatt_is_clcb_allocated(conn_id)) { 830 LOG(ERROR) << StringPrintf(" GATT_BUSY conn_id = %d", conn_id); 831 return GATT_BUSY; 832 } 833 834 tGATT_CLCB* p_clcb = gatt_clcb_alloc(conn_id); 835 if (!p_clcb) return GATT_NO_RESOURCES; 836 837 p_clcb->operation = GATTC_OPTYPE_EXE_WRITE; 838 tGATT_EXEC_FLAG flag = 839 is_execute ? GATT_PREP_WRITE_EXEC : GATT_PREP_WRITE_CANCEL; 840 gatt_send_queue_write_cancel(*p_clcb->p_tcb, p_clcb, flag); 841 return GATT_SUCCESS; 842 } 843 844 /******************************************************************************* 845 * 846 * Function GATTC_SendHandleValueConfirm 847 * 848 * Description This function is called to send a handle value confirmation 849 * as response to a handle value notification from server. 850 * 851 * Parameters conn_id: connection identifier. 852 * handle: the handle of the attribute confirmation. 853 * 854 * Returns GATT_SUCCESS if command started successfully. 855 * 856 ******************************************************************************/ 857 tGATT_STATUS GATTC_SendHandleValueConfirm(uint16_t conn_id, uint16_t handle) { 858 VLOG(1) << __func__ 859 << StringPrintf(" conn_id=%d handle=0x%x", conn_id, handle); 860 861 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(GATT_GET_TCB_IDX(conn_id)); 862 if (!p_tcb) { 863 LOG(ERROR) << StringPrintf(" Unknown conn_id: %u", conn_id); 864 return GATT_ILLEGAL_PARAMETER; 865 } 866 867 if (p_tcb->ind_count == 0) { 868 VLOG(1) << " conn_id: " << +conn_id 869 << " ignored not waiting for indicaiton ack"; 870 return GATT_SUCCESS; 871 } 872 873 alarm_cancel(p_tcb->ind_ack_timer); 874 875 VLOG(1) << "notif_count= " << p_tcb->ind_count; 876 /* send confirmation now */ 877 tGATT_CL_MSG gatt_cl_msg; 878 gatt_cl_msg.handle = handle; 879 tGATT_STATUS ret = 880 attp_send_cl_msg(*p_tcb, nullptr, GATT_HANDLE_VALUE_CONF, &gatt_cl_msg); 881 882 p_tcb->ind_count = 0; 883 884 return ret; 885 } 886 887 /******************************************************************************/ 888 /* */ 889 /* GATT APIs */ 890 /* */ 891 /******************************************************************************/ 892 /******************************************************************************* 893 * 894 * Function GATT_SetIdleTimeout 895 * 896 * Description This function (common to both client and server) sets the 897 * idle timeout for a tansport connection 898 * 899 * Parameter bd_addr: target device bd address. 900 * idle_tout: timeout value in seconds. 901 * 902 * Returns void 903 * 904 ******************************************************************************/ 905 void GATT_SetIdleTimeout(const RawAddress& bd_addr, uint16_t idle_tout, 906 tBT_TRANSPORT transport) { 907 tGATT_TCB* p_tcb; 908 bool status = false; 909 910 p_tcb = gatt_find_tcb_by_addr(bd_addr, transport); 911 if (p_tcb != NULL) { 912 if (p_tcb->att_lcid == L2CAP_ATT_CID) { 913 status = L2CA_SetFixedChannelTout(bd_addr, L2CAP_ATT_CID, idle_tout); 914 915 if (idle_tout == GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP) 916 L2CA_SetIdleTimeoutByBdAddr(p_tcb->peer_bda, 917 GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP, 918 BT_TRANSPORT_LE); 919 } else { 920 status = L2CA_SetIdleTimeout(p_tcb->att_lcid, idle_tout, false); 921 } 922 } 923 924 VLOG(1) << __func__ 925 << StringPrintf(" idle_tout=%d status=%d(1-OK 0-not performed)", 926 idle_tout, status); 927 } 928 929 /******************************************************************************* 930 * 931 * Function GATT_Register 932 * 933 * Description This function is called to register an application 934 * with GATT 935 * 936 * Parameter p_app_uuid128: Application UUID 937 * p_cb_info: callback functions. 938 * 939 * Returns 0 for error, otherwise the index of the client registered 940 * with GATT 941 * 942 ******************************************************************************/ 943 tGATT_IF GATT_Register(const Uuid& app_uuid128, tGATT_CBACK* p_cb_info) { 944 tGATT_REG* p_reg; 945 uint8_t i_gatt_if = 0; 946 tGATT_IF gatt_if = 0; 947 948 LOG(INFO) << __func__ << " " << app_uuid128; 949 950 for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; 951 i_gatt_if++, p_reg++) { 952 if (p_reg->in_use && p_reg->app_uuid128 == app_uuid128) { 953 LOG(ERROR) << "application already registered."; 954 return 0; 955 } 956 } 957 958 for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; 959 i_gatt_if++, p_reg++) { 960 if (!p_reg->in_use) { 961 memset(p_reg, 0, sizeof(tGATT_REG)); 962 i_gatt_if++; /* one based number */ 963 p_reg->app_uuid128 = app_uuid128; 964 gatt_if = p_reg->gatt_if = (tGATT_IF)i_gatt_if; 965 p_reg->app_cb = *p_cb_info; 966 p_reg->in_use = true; 967 968 LOG(INFO) << "allocated gatt_if=" << +gatt_if; 969 return gatt_if; 970 } 971 } 972 973 LOG(ERROR) << "can't Register GATT client, MAX client reached: " 974 << GATT_MAX_APPS; 975 return 0; 976 } 977 978 /******************************************************************************* 979 * 980 * Function GATT_Deregister 981 * 982 * Description This function deregistered the application from GATT. 983 * 984 * Parameters gatt_if: applicaiton interface. 985 * 986 * Returns None. 987 * 988 ******************************************************************************/ 989 void GATT_Deregister(tGATT_IF gatt_if) { 990 VLOG(1) << __func__ << " gatt_if=" << +gatt_if; 991 992 tGATT_REG* p_reg = gatt_get_regcb(gatt_if); 993 /* Index 0 is GAP and is never deregistered */ 994 if ((gatt_if == 0) || (p_reg == NULL)) { 995 LOG(ERROR) << "invalid gatt_if: " << +gatt_if; 996 return; 997 } 998 999 /* stop all services */ 1000 /* todo an applcaiton can not be deregistered if its services is also used by 1001 other application 1002 deregisteration need to bed performed in an orderly fashion 1003 no check for now */ 1004 for (auto it = gatt_cb.srv_list_info->begin(); it != gatt_cb.srv_list_info->end(); ) { 1005 if (it->gatt_if == gatt_if) { 1006 GATTS_StopService(it++->s_hdl); 1007 } else { 1008 ++it; 1009 } 1010 } 1011 1012 /* free all services db buffers if owned by this application */ 1013 gatt_free_srvc_db_buffer_app_id(p_reg->app_uuid128); 1014 1015 /* When an application deregisters, check remove the link associated with the 1016 * app */ 1017 tGATT_TCB* p_tcb; 1018 int i, j; 1019 for (i = 0, p_tcb = gatt_cb.tcb; i < GATT_MAX_PHY_CHANNEL; i++, p_tcb++) { 1020 if (p_tcb->in_use) { 1021 if (gatt_get_ch_state(p_tcb) != GATT_CH_CLOSE) { 1022 gatt_update_app_use_link_flag(gatt_if, p_tcb, false, true); 1023 } 1024 1025 tGATT_CLCB* p_clcb; 1026 for (j = 0, p_clcb = &gatt_cb.clcb[j]; j < GATT_CL_MAX_LCB; 1027 j++, p_clcb++) { 1028 if (p_clcb->in_use && (p_clcb->p_reg->gatt_if == gatt_if) && 1029 (p_clcb->p_tcb->tcb_idx == p_tcb->tcb_idx)) { 1030 alarm_cancel(p_clcb->gatt_rsp_timer_ent); 1031 gatt_clcb_dealloc(p_clcb); 1032 break; 1033 } 1034 } 1035 } 1036 } 1037 1038 gatt_deregister_bgdev_list(gatt_if); 1039 1040 memset(p_reg, 0, sizeof(tGATT_REG)); 1041 } 1042 1043 /******************************************************************************* 1044 * 1045 * Function GATT_StartIf 1046 * 1047 * Description This function is called after registration to start 1048 * receiving callbacks for registered interface. Function may 1049 * call back with connection status and queued notifications 1050 * 1051 * Parameter gatt_if: applicaiton interface. 1052 * 1053 * Returns None. 1054 * 1055 ******************************************************************************/ 1056 void GATT_StartIf(tGATT_IF gatt_if) { 1057 tGATT_REG* p_reg; 1058 tGATT_TCB* p_tcb; 1059 RawAddress bda; 1060 uint8_t start_idx, found_idx; 1061 uint16_t conn_id; 1062 tGATT_TRANSPORT transport; 1063 1064 VLOG(1) << __func__ << " gatt_if=" << gatt_if; 1065 p_reg = gatt_get_regcb(gatt_if); 1066 if (p_reg != NULL) { 1067 start_idx = 0; 1068 while ( 1069 gatt_find_the_connected_bda(start_idx, bda, &found_idx, &transport)) { 1070 p_tcb = gatt_find_tcb_by_addr(bda, transport); 1071 if (p_reg->app_cb.p_conn_cb && p_tcb) { 1072 conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if); 1073 (*p_reg->app_cb.p_conn_cb)(gatt_if, bda, conn_id, true, 0, transport); 1074 } 1075 start_idx = ++found_idx; 1076 } 1077 } 1078 } 1079 1080 /******************************************************************************* 1081 * 1082 * Function GATT_Connect 1083 * 1084 * Description This function initiate a connecttion to a remote device on 1085 * GATT channel. 1086 * 1087 * Parameters gatt_if: applicaiton interface 1088 * bd_addr: peer device address. 1089 * is_direct: is a direct conenection or a background auto 1090 * connection 1091 * 1092 * Returns true if connection started; false if connection start 1093 * failure. 1094 * 1095 ******************************************************************************/ 1096 bool GATT_Connect(tGATT_IF gatt_if, const RawAddress& bd_addr, bool is_direct, 1097 tBT_TRANSPORT transport, bool opportunistic) { 1098 uint8_t phy = controller_get_interface()->get_le_all_initiating_phys(); 1099 return GATT_Connect(gatt_if, bd_addr, is_direct, transport, opportunistic, 1100 phy); 1101 } 1102 1103 bool GATT_Connect(tGATT_IF gatt_if, const RawAddress& bd_addr, bool is_direct, 1104 tBT_TRANSPORT transport, bool opportunistic, 1105 uint8_t initiating_phys) { 1106 tGATT_REG* p_reg; 1107 bool status = false; 1108 1109 LOG(INFO) << __func__ << "gatt_if=" << +gatt_if << " " << bd_addr; 1110 1111 /* Make sure app is registered */ 1112 p_reg = gatt_get_regcb(gatt_if); 1113 if (p_reg == NULL) { 1114 LOG(ERROR) << "gatt_if = " << gatt_if << " is not registered"; 1115 return (false); 1116 } 1117 1118 if (is_direct) 1119 status = gatt_act_connect(p_reg, bd_addr, transport, opportunistic, 1120 initiating_phys); 1121 else { 1122 if (transport == BT_TRANSPORT_LE) 1123 status = gatt_update_auto_connect_dev(gatt_if, true, bd_addr); 1124 else { 1125 LOG(ERROR) << "Unsupported transport for background connection"; 1126 } 1127 } 1128 1129 return status; 1130 } 1131 1132 /******************************************************************************* 1133 * 1134 * Function GATT_CancelConnect 1135 * 1136 * Description This function terminate the connection initaition to a 1137 * remote device on GATT channel. 1138 * 1139 * Parameters gatt_if: client interface. If 0 used as unconditionally 1140 * disconnect, typically used for direct connection 1141 * cancellation. 1142 * bd_addr: peer device address. 1143 * 1144 * Returns true if the connection started; false otherwise. 1145 * 1146 ******************************************************************************/ 1147 bool GATT_CancelConnect(tGATT_IF gatt_if, const RawAddress& bd_addr, 1148 bool is_direct) { 1149 LOG(INFO) << __func__ << ": gatt_if=" << +gatt_if; 1150 1151 if (gatt_if && !gatt_get_regcb(gatt_if)) { 1152 LOG(ERROR) << "gatt_if =" << +gatt_if << " is not registered"; 1153 return false; 1154 } 1155 1156 if (is_direct) { 1157 if (gatt_if) { 1158 return gatt_cancel_open(gatt_if, bd_addr); 1159 } 1160 1161 VLOG(1) << " unconditional"; 1162 /* only LE connection can be cancelled */ 1163 tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE); 1164 if (!p_tcb || p_tcb->app_hold_link.empty()) { 1165 LOG(ERROR) << __func__ << " no app found"; 1166 return false; 1167 } 1168 1169 for (auto it = p_tcb->app_hold_link.begin(); 1170 it != p_tcb->app_hold_link.end();) { 1171 auto next = std::next(it); 1172 // gatt_cancel_open modifies the app_hold_link. 1173 if (!gatt_cancel_open(*it, bd_addr)) return false; 1174 1175 it = next; 1176 } 1177 1178 return true; 1179 } 1180 // is not direct 1181 1182 if (gatt_if) return gatt_remove_bg_dev_for_app(gatt_if, bd_addr); 1183 1184 if (!gatt_clear_bg_dev_for_addr(bd_addr)) { 1185 LOG(ERROR) 1186 << __func__ 1187 << ": no app associated with the bg device for unconditional removal"; 1188 return false; 1189 } 1190 1191 return true; 1192 } 1193 1194 /******************************************************************************* 1195 * 1196 * Function GATT_Disconnect 1197 * 1198 * Description This function disconnects the GATT channel for this 1199 * registered application. 1200 * 1201 * Parameters conn_id: connection identifier. 1202 * 1203 * Returns GATT_SUCCESS if disconnected. 1204 * 1205 ******************************************************************************/ 1206 tGATT_STATUS GATT_Disconnect(uint16_t conn_id) { 1207 tGATT_STATUS ret = GATT_ILLEGAL_PARAMETER; 1208 tGATT_TCB* p_tcb = NULL; 1209 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id); 1210 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id); 1211 1212 LOG(INFO) << __func__ << " conn_id=" << +conn_id; 1213 1214 p_tcb = gatt_get_tcb_by_idx(tcb_idx); 1215 1216 if (p_tcb) { 1217 gatt_update_app_use_link_flag(gatt_if, p_tcb, false, true); 1218 ret = GATT_SUCCESS; 1219 } 1220 return ret; 1221 } 1222 1223 /******************************************************************************* 1224 * 1225 * Function GATT_GetConnectionInfor 1226 * 1227 * Description This function uses conn_id to find its associated BD address 1228 * and application interface 1229 * 1230 * Parameters conn_id: connection id (input) 1231 * p_gatt_if: applicaiton interface (output) 1232 * bd_addr: peer device address. (output) 1233 * 1234 * Returns true the ligical link information is found for conn_id 1235 * 1236 ******************************************************************************/ 1237 bool GATT_GetConnectionInfor(uint16_t conn_id, tGATT_IF* p_gatt_if, 1238 RawAddress& bd_addr, tBT_TRANSPORT* p_transport) { 1239 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id); 1240 tGATT_REG* p_reg = gatt_get_regcb(gatt_if); 1241 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id); 1242 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx); 1243 bool status = false; 1244 1245 VLOG(1) << __func__ << " conn_id=" << +conn_id; 1246 1247 if (p_tcb && p_reg) { 1248 bd_addr = p_tcb->peer_bda; 1249 *p_gatt_if = gatt_if; 1250 *p_transport = p_tcb->transport; 1251 status = true; 1252 } 1253 return status; 1254 } 1255 1256 /******************************************************************************* 1257 * 1258 * Function GATT_GetConnIdIfConnected 1259 * 1260 * Description This function find the conn_id if the logical link for BD 1261 * address and applciation interface is connected 1262 * 1263 * Parameters gatt_if: applicaiton interface (input) 1264 * bd_addr: peer device address. (input) 1265 * p_conn_id: connection id (output) 1266 * transport: transport option 1267 * 1268 * Returns true the logical link is connected 1269 * 1270 ******************************************************************************/ 1271 bool GATT_GetConnIdIfConnected(tGATT_IF gatt_if, const RawAddress& bd_addr, 1272 uint16_t* p_conn_id, tBT_TRANSPORT transport) { 1273 tGATT_REG* p_reg = gatt_get_regcb(gatt_if); 1274 tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, transport); 1275 bool status = false; 1276 1277 if (p_reg && p_tcb && (gatt_get_ch_state(p_tcb) == GATT_CH_OPEN)) { 1278 *p_conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if); 1279 status = true; 1280 } 1281 1282 VLOG(1) << __func__ << " status= " << +status; 1283 return status; 1284 } 1285