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