Home | History | Annotate | Download | only in gatt
      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*)&notif);
    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