Home | History | Annotate | Download | only in gatt
      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