Home | History | Annotate | Download | only in gatt
      1 /******************************************************************************
      2  *
      3  *  Copyright (C) 2008-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 the main ATT functions
     22  *
     23  ******************************************************************************/
     24 
     25 #include "bt_target.h"
     26 
     27 #if BLE_INCLUDED == TRUE
     28 
     29 #include "bt_common.h"
     30 #include "gatt_int.h"
     31 #include "l2c_api.h"
     32 #include "btm_int.h"
     33 #include "btm_ble_int.h"
     34 #include "bt_utils.h"
     35 
     36 /* Configuration flags. */
     37 #define GATT_L2C_CFG_IND_DONE   (1<<0)
     38 #define GATT_L2C_CFG_CFM_DONE   (1<<1)
     39 
     40 /* minimum GATT MTU size over BR/EDR link
     41 */
     42 #define GATT_MIN_BR_MTU_SIZE       48
     43 
     44 /********************************************************************************/
     45 /*              L O C A L    F U N C T I O N     P R O T O T Y P E S            */
     46 /********************************************************************************/
     47 static void gatt_le_connect_cback (UINT16 chan, BD_ADDR bd_addr, BOOLEAN connected,
     48         UINT16 reason, tBT_TRANSPORT transport);
     49 static void gatt_le_data_ind (UINT16 chan, BD_ADDR bd_addr, BT_HDR *p_buf);
     50 static void gatt_le_cong_cback(BD_ADDR remote_bda, BOOLEAN congest);
     51 
     52 static void gatt_l2cif_connect_ind_cback (BD_ADDR  bd_addr, UINT16 l2cap_cid,
     53         UINT16 psm, UINT8 l2cap_id);
     54 static void gatt_l2cif_connect_cfm_cback (UINT16 l2cap_cid, UINT16 result);
     55 static void gatt_l2cif_config_ind_cback (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
     56 static void gatt_l2cif_config_cfm_cback (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
     57 static void gatt_l2cif_disconnect_ind_cback (UINT16 l2cap_cid, BOOLEAN ack_needed);
     58 static void gatt_l2cif_disconnect_cfm_cback (UINT16 l2cap_cid, UINT16 result);
     59 static void gatt_l2cif_data_ind_cback (UINT16 l2cap_cid, BT_HDR *p_msg);
     60 static void gatt_send_conn_cback (tGATT_TCB *p_tcb);
     61 static void gatt_l2cif_congest_cback (UINT16 cid, BOOLEAN congested);
     62 
     63 static const tL2CAP_APPL_INFO dyn_info =
     64 {
     65     gatt_l2cif_connect_ind_cback,
     66     gatt_l2cif_connect_cfm_cback,
     67     NULL,
     68     gatt_l2cif_config_ind_cback,
     69     gatt_l2cif_config_cfm_cback,
     70     gatt_l2cif_disconnect_ind_cback,
     71     gatt_l2cif_disconnect_cfm_cback,
     72     NULL,
     73     gatt_l2cif_data_ind_cback,
     74     gatt_l2cif_congest_cback,
     75     NULL
     76 } ;
     77 
     78 #if GATT_DYNAMIC_MEMORY == FALSE
     79 tGATT_CB  gatt_cb;
     80 #endif
     81 
     82 /*******************************************************************************
     83 **
     84 ** Function         gatt_init
     85 **
     86 ** Description      This function is enable the GATT profile on the device.
     87 **                  It clears out the control blocks, and registers with L2CAP.
     88 **
     89 ** Returns          void
     90 **
     91 *******************************************************************************/
     92 void gatt_init (void)
     93 {
     94     tL2CAP_FIXED_CHNL_REG  fixed_reg;
     95 
     96     GATT_TRACE_DEBUG("gatt_init()");
     97 
     98     memset (&gatt_cb, 0, sizeof(tGATT_CB));
     99     memset (&fixed_reg, 0, sizeof(tL2CAP_FIXED_CHNL_REG));
    100 
    101 #if defined(GATT_INITIAL_TRACE_LEVEL)
    102     gatt_cb.trace_level = GATT_INITIAL_TRACE_LEVEL;
    103 #else
    104     gatt_cb.trace_level = BT_TRACE_LEVEL_NONE;    /* No traces */
    105 #endif
    106     gatt_cb.def_mtu_size = GATT_DEF_BLE_MTU_SIZE;
    107     gatt_cb.sign_op_queue = fixed_queue_new(SIZE_MAX);
    108     gatt_cb.srv_chg_clt_q = fixed_queue_new(SIZE_MAX);
    109     gatt_cb.pending_new_srv_start_q = fixed_queue_new(SIZE_MAX);
    110     /* First, register fixed L2CAP channel for ATT over BLE */
    111     fixed_reg.fixed_chnl_opts.mode         = L2CAP_FCR_BASIC_MODE;
    112     fixed_reg.fixed_chnl_opts.max_transmit = 0xFF;
    113     fixed_reg.fixed_chnl_opts.rtrans_tout  = 2000;
    114     fixed_reg.fixed_chnl_opts.mon_tout     = 12000;
    115     fixed_reg.fixed_chnl_opts.mps          = 670;
    116     fixed_reg.fixed_chnl_opts.tx_win_sz    = 1;
    117 
    118     fixed_reg.pL2CA_FixedConn_Cb = gatt_le_connect_cback;
    119     fixed_reg.pL2CA_FixedData_Cb = gatt_le_data_ind;
    120     fixed_reg.pL2CA_FixedCong_Cb = gatt_le_cong_cback;      /* congestion callback */
    121     fixed_reg.default_idle_tout  = 0xffff;                  /* 0xffff default idle timeout */
    122 
    123     L2CA_RegisterFixedChannel (L2CAP_ATT_CID, &fixed_reg);
    124 
    125     /* Now, register with L2CAP for ATT PSM over BR/EDR */
    126     if (!L2CA_Register (BT_PSM_ATT, (tL2CAP_APPL_INFO *) &dyn_info))
    127     {
    128         GATT_TRACE_ERROR ("ATT Dynamic Registration failed");
    129     }
    130 
    131     BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_ATT, BTM_SEC_NONE, BT_PSM_ATT, 0, 0);
    132     BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_ATT, BTM_SEC_NONE, BT_PSM_ATT, 0, 0);
    133 
    134     gatt_cb.hdl_cfg.gatt_start_hdl = GATT_GATT_START_HANDLE;
    135     gatt_cb.hdl_cfg.gap_start_hdl  = GATT_GAP_START_HANDLE;
    136     gatt_cb.hdl_cfg.app_start_hdl  = GATT_APP_START_HANDLE;
    137     gatt_profile_db_init();
    138 
    139 }
    140 
    141 
    142 /*******************************************************************************
    143 **
    144 ** Function         gatt_free
    145 **
    146 ** Description      This function frees resources used by the GATT profile.
    147 **
    148 ** Returns          void
    149 **
    150 *******************************************************************************/
    151 void gatt_free(void)
    152 {
    153     int i;
    154     GATT_TRACE_DEBUG("gatt_free()");
    155 
    156     fixed_queue_free(gatt_cb.sign_op_queue, NULL);
    157     gatt_cb.sign_op_queue = NULL;
    158     fixed_queue_free(gatt_cb.srv_chg_clt_q, NULL);
    159     gatt_cb.srv_chg_clt_q = NULL;
    160     fixed_queue_free(gatt_cb.pending_new_srv_start_q, NULL);
    161     gatt_cb.pending_new_srv_start_q = NULL;
    162     for (i = 0; i < GATT_MAX_PHY_CHANNEL; i++)
    163     {
    164         fixed_queue_free(gatt_cb.tcb[i].pending_enc_clcb, NULL);
    165         gatt_cb.tcb[i].pending_enc_clcb = NULL;
    166 
    167         fixed_queue_free(gatt_cb.tcb[i].pending_ind_q, NULL);
    168         gatt_cb.tcb[i].pending_ind_q = NULL;
    169 
    170         alarm_free(gatt_cb.tcb[i].conf_timer);
    171         gatt_cb.tcb[i].conf_timer = NULL;
    172 
    173         alarm_free(gatt_cb.tcb[i].ind_ack_timer);
    174         gatt_cb.tcb[i].ind_ack_timer = NULL;
    175 
    176         fixed_queue_free(gatt_cb.tcb[i].sr_cmd.multi_rsp_q, NULL);
    177         gatt_cb.tcb[i].sr_cmd.multi_rsp_q = NULL;
    178     }
    179     for (i = 0; i < GATT_MAX_SR_PROFILES; i++)
    180     {
    181         gatt_free_hdl_buffer(&gatt_cb.hdl_list[i]);
    182     }
    183 }
    184 
    185 /*******************************************************************************
    186 **
    187 ** Function         gatt_connect
    188 **
    189 ** Description      This function is called to initiate a connection to a peer device.
    190 **
    191 ** Parameter        rem_bda: remote device address to connect to.
    192 **
    193 ** Returns          TRUE if connection is started, otherwise return FALSE.
    194 **
    195 *******************************************************************************/
    196 BOOLEAN gatt_connect (BD_ADDR rem_bda, tGATT_TCB *p_tcb, tBT_TRANSPORT transport)
    197 {
    198     BOOLEAN             gatt_ret = FALSE;
    199 
    200     if (gatt_get_ch_state(p_tcb) != GATT_CH_OPEN)
    201         gatt_set_ch_state(p_tcb, GATT_CH_CONN);
    202 
    203     if (transport == BT_TRANSPORT_LE)
    204     {
    205         p_tcb->att_lcid = L2CAP_ATT_CID;
    206         gatt_ret = L2CA_ConnectFixedChnl (L2CAP_ATT_CID, rem_bda);
    207     }
    208     else
    209     {
    210         if ((p_tcb->att_lcid = L2CA_ConnectReq(BT_PSM_ATT, rem_bda)) != 0)
    211             gatt_ret = TRUE;
    212     }
    213 
    214     return gatt_ret;
    215 }
    216 
    217 /*******************************************************************************
    218 **
    219 ** Function         gatt_disconnect
    220 **
    221 ** Description      This function is called to disconnect to an ATT device.
    222 **
    223 ** Parameter        p_tcb: pointer to the TCB to disconnect.
    224 **
    225 ** Returns          TRUE: if connection found and to be disconnected; otherwise
    226 **                  return FALSE.
    227 **
    228 *******************************************************************************/
    229 BOOLEAN gatt_disconnect (tGATT_TCB *p_tcb)
    230 {
    231     BOOLEAN             ret = FALSE;
    232     tGATT_CH_STATE      ch_state;
    233 
    234     GATT_TRACE_EVENT ("%s", __func__);
    235 
    236     if (p_tcb != NULL)
    237     {
    238         ret = TRUE;
    239         if ( (ch_state = gatt_get_ch_state(p_tcb)) != GATT_CH_CLOSING )
    240         {
    241             if (p_tcb->att_lcid == L2CAP_ATT_CID)
    242             {
    243                 if (ch_state == GATT_CH_OPEN)
    244                 {
    245                     /* only LCB exist between remote device and local */
    246                     ret = L2CA_RemoveFixedChnl (L2CAP_ATT_CID, p_tcb->peer_bda);
    247                 }
    248                 else
    249                 {
    250                     gatt_set_ch_state(p_tcb, GATT_CH_CLOSING);
    251                     ret = L2CA_CancelBleConnectReq (p_tcb->peer_bda);
    252                 }
    253             }
    254             else
    255             {
    256                 if ((ch_state == GATT_CH_OPEN) || (ch_state == GATT_CH_CFG))
    257                     ret = L2CA_DisconnectReq(p_tcb->att_lcid);
    258                 else
    259                     GATT_TRACE_DEBUG ("%s gatt_disconnect channel not opened", __func__);
    260             }
    261         }
    262         else
    263         {
    264             GATT_TRACE_DEBUG ("%s already in closing state", __func__);
    265         }
    266     }
    267 
    268     return ret;
    269 }
    270 
    271 /*******************************************************************************
    272 **
    273 ** Function         gatt_update_app_hold_link_status
    274 **
    275 ** Description      Update the application use link status
    276 **
    277 ** Returns          true if any modifications are made, false otherwise.
    278 **
    279 *******************************************************************************/
    280 BOOLEAN gatt_update_app_hold_link_status(tGATT_IF gatt_if, tGATT_TCB *p_tcb, BOOLEAN is_add)
    281 {
    282     for (int i=0; i<GATT_MAX_APPS; i++) {
    283         if (p_tcb->app_hold_link[i] == 0 && is_add) {
    284             p_tcb->app_hold_link[i] = gatt_if;
    285             GATT_TRACE_DEBUG("%s: added gatt_if=%d idx=%d ", __func__, gatt_if, i);
    286             return TRUE;
    287         } else if (p_tcb->app_hold_link[i] == gatt_if && !is_add) {
    288             p_tcb->app_hold_link[i] = 0;
    289             GATT_TRACE_DEBUG("%s: removed gatt_if=%d idx=%d", __func__, gatt_if, i);
    290             return TRUE;
    291         }
    292     }
    293 
    294     GATT_TRACE_DEBUG("%s: gatt_if=%d not found; is_add=%d", __func__, gatt_if, is_add);
    295     return FALSE;
    296 }
    297 
    298 /*******************************************************************************
    299 **
    300 ** Function         gatt_update_app_use_link_flag
    301 **
    302 ** Description      Update the application use link flag and optional to check the acl link
    303 **                  if the link is up then set the idle time out accordingly
    304 **
    305 ** Returns          void.
    306 **
    307 *******************************************************************************/
    308 void gatt_update_app_use_link_flag(tGATT_IF gatt_if, tGATT_TCB *p_tcb, BOOLEAN is_add,
    309                                    BOOLEAN check_acl_link)
    310 {
    311     GATT_TRACE_DEBUG("%s: is_add=%d chk_link=%d", __func__, is_add, check_acl_link);
    312 
    313     if (!p_tcb)
    314         return;
    315 
    316     // If we make no modification, i.e. kill app that was never connected to a device,
    317     // skip updating the device state.
    318     if (!gatt_update_app_hold_link_status(gatt_if, p_tcb, is_add))
    319         return;
    320 
    321     if (!check_acl_link ||
    322             p_tcb->att_lcid != L2CAP_ATT_CID || /* only update link idle timer for fixed channel */
    323             (BTM_GetHCIConnHandle(p_tcb->peer_bda, p_tcb->transport) == GATT_INVALID_ACL_HANDLE)) {
    324         return;
    325     }
    326 
    327     if (is_add) {
    328         GATT_TRACE_DEBUG("%s: disable link idle timer", __func__);
    329         /* acl link is connected disable the idle timeout */
    330         GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_NO_IDLE_TIMEOUT, p_tcb->transport);
    331     } else {
    332         if (!gatt_num_apps_hold_link(p_tcb)) {
    333             /* acl link is connected but no application needs to use the link
    334                so set the timeout value to GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP seconds */
    335             GATT_TRACE_DEBUG("%s: start link idle timer =%d sec", __func__,
    336                              GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP);
    337             GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP,
    338                                 p_tcb->transport);
    339         }
    340     }
    341 }
    342 
    343 /*******************************************************************************
    344 **
    345 ** Function         gatt_act_connect
    346 **
    347 ** Description      GATT connection initiation.
    348 **
    349 ** Returns          void.
    350 **
    351 *******************************************************************************/
    352 BOOLEAN gatt_act_connect (tGATT_REG *p_reg, BD_ADDR bd_addr,
    353                           tBT_TRANSPORT transport, BOOLEAN opportunistic)
    354 {
    355     BOOLEAN     ret = FALSE;
    356     tGATT_TCB   *p_tcb;
    357     UINT8       st;
    358 
    359     if ((p_tcb = gatt_find_tcb_by_addr(bd_addr, transport)) != NULL)
    360     {
    361         ret = TRUE;
    362         st = gatt_get_ch_state(p_tcb);
    363 
    364         /* before link down, another app try to open a GATT connection */
    365         if(st == GATT_CH_OPEN &&  gatt_num_apps_hold_link(p_tcb) == 0 &&
    366             transport == BT_TRANSPORT_LE )
    367         {
    368             if (!gatt_connect(bd_addr,  p_tcb, transport))
    369                 ret = FALSE;
    370         }
    371         else if(st == GATT_CH_CLOSING)
    372         {
    373             /* need to complete the closing first */
    374             ret = FALSE;
    375         }
    376     }
    377     else
    378     {
    379         if ((p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr, transport)) != NULL)
    380         {
    381             if (!gatt_connect(bd_addr,  p_tcb, transport))
    382             {
    383                 GATT_TRACE_ERROR("gatt_connect failed");
    384                 fixed_queue_free(p_tcb->pending_enc_clcb, NULL);
    385                 fixed_queue_free(p_tcb->pending_ind_q, NULL);
    386                 memset(p_tcb, 0, sizeof(tGATT_TCB));
    387             }
    388             else
    389                 ret = TRUE;
    390         }
    391         else
    392         {
    393             ret = 0;
    394             GATT_TRACE_ERROR("Max TCB for gatt_if [%d] reached.", p_reg->gatt_if);
    395         }
    396     }
    397 
    398     if (ret)
    399     {
    400         if (!opportunistic)
    401             gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, TRUE, FALSE);
    402         else
    403             GATT_TRACE_DEBUG("%s: connection is opportunistic, not updating app usage",
    404                             __func__);
    405     }
    406 
    407     return ret;
    408 }
    409 
    410 /*******************************************************************************
    411 **
    412 ** Function         gatt_le_connect_cback
    413 **
    414 ** Description      This callback function is called by L2CAP to indicate that
    415 **                  the ATT fixed channel for LE is
    416 **                      connected (conn = TRUE)/disconnected (conn = FALSE).
    417 **
    418 *******************************************************************************/
    419 static void gatt_le_connect_cback (UINT16 chan, BD_ADDR bd_addr, BOOLEAN connected,
    420                                    UINT16 reason, tBT_TRANSPORT transport)
    421 {
    422 
    423     tGATT_TCB       *p_tcb = gatt_find_tcb_by_addr(bd_addr, transport);
    424     BOOLEAN                 check_srv_chg = FALSE;
    425     tGATTS_SRV_CHG          *p_srv_chg_clt=NULL;
    426 
    427     /* ignore all fixed channel connect/disconnect on BR/EDR link for GATT */
    428     if (transport == BT_TRANSPORT_BR_EDR)
    429         return;
    430 
    431     GATT_TRACE_DEBUG ("GATT   ATT protocol channel with BDA: %08x%04x is %s",
    432                        (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3],
    433                        (bd_addr[4]<<8)+bd_addr[5], (connected) ? "connected" : "disconnected");
    434 
    435     if ((p_srv_chg_clt = gatt_is_bda_in_the_srv_chg_clt_list(bd_addr)) != NULL)
    436     {
    437         check_srv_chg = TRUE;
    438     }
    439     else
    440     {
    441         if (btm_sec_is_a_bonded_dev(bd_addr))
    442             gatt_add_a_bonded_dev_for_srv_chg(bd_addr);
    443     }
    444 
    445     if (connected)
    446     {
    447         /* do we have a channel initiating a connection? */
    448         if (p_tcb)
    449         {
    450             /* we are initiating connection */
    451             if ( gatt_get_ch_state(p_tcb) == GATT_CH_CONN)
    452             {
    453                 /* send callback */
    454                 gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
    455                 p_tcb->payload_size = GATT_DEF_BLE_MTU_SIZE;
    456 
    457                 gatt_send_conn_cback(p_tcb);
    458             }
    459             if (check_srv_chg)
    460                 gatt_chk_srv_chg (p_srv_chg_clt);
    461         }
    462         /* this is incoming connection or background connection callback */
    463 
    464         else
    465         {
    466             if ((p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr, BT_TRANSPORT_LE)) != NULL)
    467             {
    468                 p_tcb->att_lcid = L2CAP_ATT_CID;
    469 
    470                 gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
    471 
    472                 p_tcb->payload_size = GATT_DEF_BLE_MTU_SIZE;
    473 
    474                 gatt_send_conn_cback (p_tcb);
    475                 if (check_srv_chg)
    476                 {
    477                     gatt_chk_srv_chg (p_srv_chg_clt);
    478                 }
    479             }
    480             else
    481             {
    482                 GATT_TRACE_ERROR("CCB max out, no rsources");
    483             }
    484         }
    485     }
    486     else
    487     {
    488         gatt_cleanup_upon_disc(bd_addr, reason, transport);
    489         GATT_TRACE_DEBUG ("ATT disconnected");
    490     }
    491 }
    492 
    493 /*******************************************************************************
    494 **
    495 ** Function         gatt_channel_congestion
    496 **
    497 ** Description      This function is called to process the congestion callback
    498 **                  from lcb
    499 **
    500 ** Returns          void
    501 **
    502 *******************************************************************************/
    503 static void gatt_channel_congestion(tGATT_TCB *p_tcb, BOOLEAN congested)
    504 {
    505     UINT8 i = 0;
    506     tGATT_REG *p_reg=NULL;
    507     UINT16 conn_id;
    508 
    509     /* if uncongested, check to see if there is any more pending data */
    510     if (p_tcb != NULL && congested == FALSE)
    511     {
    512         gatt_cl_send_next_cmd_inq(p_tcb);
    513     }
    514     /* notifying all applications for the connection up event */
    515     for (i = 0, p_reg = gatt_cb.cl_rcb ; i < GATT_MAX_APPS; i++, p_reg++)
    516     {
    517         if (p_reg->in_use)
    518         {
    519             if (p_reg->app_cb.p_congestion_cb)
    520             {
    521                 conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if);
    522                 (*p_reg->app_cb.p_congestion_cb)(conn_id, congested);
    523             }
    524         }
    525     }
    526 }
    527 
    528 /*******************************************************************************
    529 **
    530 ** Function         gatt_le_cong_cback
    531 **
    532 ** Description      This function is called when GATT fixed channel is congested
    533 **                  or uncongested.
    534 **
    535 ** Returns          void
    536 **
    537 *******************************************************************************/
    538 static void gatt_le_cong_cback(BD_ADDR remote_bda, BOOLEAN congested)
    539 {
    540     tGATT_TCB *p_tcb = gatt_find_tcb_by_addr(remote_bda, BT_TRANSPORT_LE);
    541 
    542     /* if uncongested, check to see if there is any more pending data */
    543     if (p_tcb != NULL)
    544     {
    545         gatt_channel_congestion(p_tcb, congested);
    546     }
    547 }
    548 
    549 /*******************************************************************************
    550 **
    551 ** Function         gatt_le_data_ind
    552 **
    553 ** Description      This function is called when data is received from L2CAP.
    554 **                  if we are the originator of the connection, we are the ATT
    555 **                  client, and the received message is queued up for the client.
    556 **
    557 **                  If we are the destination of the connection, we are the ATT
    558 **                  server, so the message is passed to the server processing
    559 **                  function.
    560 **
    561 ** Returns          void
    562 **
    563 *******************************************************************************/
    564 static void gatt_le_data_ind (UINT16 chan, BD_ADDR bd_addr, BT_HDR *p_buf)
    565 {
    566     tGATT_TCB    *p_tcb;
    567 
    568     /* Find CCB based on bd addr */
    569     if ((p_tcb = gatt_find_tcb_by_addr (bd_addr, BT_TRANSPORT_LE)) != NULL &&
    570         gatt_get_ch_state(p_tcb) >= GATT_CH_OPEN)
    571     {
    572         gatt_data_process(p_tcb, p_buf);
    573     }
    574     else
    575     {
    576         osi_free(p_buf);
    577 
    578         if (p_tcb != NULL)
    579         {
    580             GATT_TRACE_WARNING ("ATT - Ignored L2CAP data while in state: %d",
    581                                  gatt_get_ch_state(p_tcb));
    582         }
    583     }
    584 }
    585 
    586 /*******************************************************************************
    587 **
    588 ** Function         gatt_l2cif_connect_ind
    589 **
    590 ** Description      This function handles an inbound connection indication
    591 **                  from L2CAP. This is the case where we are acting as a
    592 **                  server.
    593 **
    594 ** Returns          void
    595 **
    596 *******************************************************************************/
    597 static void gatt_l2cif_connect_ind_cback (BD_ADDR  bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
    598 {
    599     /* do we already have a control channel for this peer? */
    600     UINT8       result = L2CAP_CONN_OK;
    601     tL2CAP_CFG_INFO cfg;
    602     tGATT_TCB       *p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_BR_EDR);
    603     UNUSED(psm);
    604 
    605     GATT_TRACE_ERROR("Connection indication cid = %d", lcid);
    606     /* new connection ? */
    607     if (p_tcb == NULL)
    608     {
    609         /* allocate tcb */
    610         if ((p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr, BT_TRANSPORT_BR_EDR)) == NULL)
    611         {
    612             /* no tcb available, reject L2CAP connection */
    613             result = L2CAP_CONN_NO_RESOURCES;
    614         }
    615         else
    616             p_tcb->att_lcid = lcid;
    617 
    618     }
    619     else /* existing connection , reject it */
    620     {
    621         result = L2CAP_CONN_NO_RESOURCES;
    622     }
    623 
    624     /* Send L2CAP connect rsp */
    625     L2CA_ConnectRsp(bd_addr, id, lcid, result, 0);
    626 
    627     /* if result ok, proceed with connection */
    628     if (result == L2CAP_CONN_OK)
    629     {
    630         /* transition to configuration state */
    631         gatt_set_ch_state(p_tcb, GATT_CH_CFG);
    632 
    633         /* Send L2CAP config req */
    634         memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
    635         cfg.mtu_present = TRUE;
    636         cfg.mtu = GATT_MAX_MTU_SIZE;
    637 
    638         L2CA_ConfigReq(lcid, &cfg);
    639     }
    640 }
    641 
    642 /*******************************************************************************
    643 **
    644 ** Function         gatt_l2c_connect_cfm_cback
    645 **
    646 ** Description      This is the L2CAP connect confirm callback function.
    647 **
    648 **
    649 ** Returns          void
    650 **
    651 *******************************************************************************/
    652 static void gatt_l2cif_connect_cfm_cback(UINT16 lcid, UINT16 result)
    653 {
    654     tGATT_TCB       *p_tcb;
    655     tL2CAP_CFG_INFO cfg;
    656 
    657     /* look up clcb for this channel */
    658     if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL)
    659     {
    660         GATT_TRACE_DEBUG("gatt_l2c_connect_cfm_cback result: %d ch_state: %d, lcid:0x%x", result, gatt_get_ch_state(p_tcb), p_tcb->att_lcid);
    661 
    662         /* if in correct state */
    663         if (gatt_get_ch_state(p_tcb) == GATT_CH_CONN)
    664         {
    665             /* if result successful */
    666             if (result == L2CAP_CONN_OK)
    667             {
    668                 /* set channel state */
    669                 gatt_set_ch_state(p_tcb, GATT_CH_CFG);
    670 
    671                 /* Send L2CAP config req */
    672                 memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
    673                 cfg.mtu_present = TRUE;
    674                 cfg.mtu = GATT_MAX_MTU_SIZE;
    675                 L2CA_ConfigReq(lcid, &cfg);
    676             }
    677             /* else initiating connection failure */
    678             else
    679             {
    680                 gatt_cleanup_upon_disc(p_tcb->peer_bda, result, GATT_TRANSPORT_BR_EDR);
    681             }
    682         }
    683         else /* wrong state, disconnect it */
    684         {
    685             if (result == L2CAP_CONN_OK)
    686             {
    687                 /* just in case the peer also accepts our connection - Send L2CAP disconnect req */
    688                 L2CA_DisconnectReq(lcid);
    689             }
    690         }
    691     }
    692 }
    693 
    694 /*******************************************************************************
    695 **
    696 ** Function         gatt_l2cif_config_cfm_cback
    697 **
    698 ** Description      This is the L2CAP config confirm callback function.
    699 **
    700 **
    701 ** Returns          void
    702 **
    703 *******************************************************************************/
    704 void gatt_l2cif_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
    705 {
    706     tGATT_TCB       *p_tcb;
    707     tGATTS_SRV_CHG  *p_srv_chg_clt=NULL;
    708 
    709     /* look up clcb for this channel */
    710     if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL)
    711     {
    712         /* if in correct state */
    713         if ( gatt_get_ch_state(p_tcb) == GATT_CH_CFG)
    714         {
    715             /* if result successful */
    716             if (p_cfg->result == L2CAP_CFG_OK)
    717             {
    718                 /* update flags */
    719                 p_tcb->ch_flags |= GATT_L2C_CFG_CFM_DONE;
    720 
    721                 /* if configuration complete */
    722                 if (p_tcb->ch_flags & GATT_L2C_CFG_IND_DONE)
    723                 {
    724                     gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
    725 
    726                     if ((p_srv_chg_clt = gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda)) != NULL)
    727                     {
    728                         gatt_chk_srv_chg(p_srv_chg_clt);
    729                     }
    730                     else
    731                     {
    732                         if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda))
    733                             gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
    734                     }
    735 
    736                     /* send callback */
    737                     gatt_send_conn_cback(p_tcb);
    738                 }
    739             }
    740             /* else failure */
    741             else
    742             {
    743                 /* Send L2CAP disconnect req */
    744                 L2CA_DisconnectReq(lcid);
    745             }
    746         }
    747     }
    748 }
    749 
    750 /*******************************************************************************
    751 **
    752 ** Function         gatt_l2cif_config_ind_cback
    753 **
    754 ** Description      This is the L2CAP config indication callback function.
    755 **
    756 **
    757 ** Returns          void
    758 **
    759 *******************************************************************************/
    760 void gatt_l2cif_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
    761 {
    762     tGATT_TCB       *p_tcb;
    763     tGATTS_SRV_CHG  *p_srv_chg_clt=NULL;
    764     /* look up clcb for this channel */
    765     if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL)
    766     {
    767         /* GATT uses the smaller of our MTU and peer's MTU  */
    768         if ( p_cfg->mtu_present &&
    769              (p_cfg->mtu >= GATT_MIN_BR_MTU_SIZE && p_cfg->mtu < L2CAP_DEFAULT_MTU))
    770             p_tcb->payload_size = p_cfg->mtu;
    771         else
    772             p_tcb->payload_size = L2CAP_DEFAULT_MTU;
    773 
    774         /* send L2CAP configure response */
    775         memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
    776         p_cfg->result = L2CAP_CFG_OK;
    777         L2CA_ConfigRsp(lcid, p_cfg);
    778 
    779         /* if first config ind */
    780         if ((p_tcb->ch_flags & GATT_L2C_CFG_IND_DONE) == 0)
    781         {
    782             /* update flags */
    783             p_tcb->ch_flags |= GATT_L2C_CFG_IND_DONE;
    784 
    785             /* if configuration complete */
    786             if (p_tcb->ch_flags & GATT_L2C_CFG_CFM_DONE)
    787             {
    788                 gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
    789                 if ((p_srv_chg_clt = gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda)) != NULL)
    790                 {
    791                     gatt_chk_srv_chg(p_srv_chg_clt);
    792                 }
    793                 else
    794                 {
    795                     if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda))
    796                         gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
    797                 }
    798 
    799                 /* send callback */
    800                 gatt_send_conn_cback(p_tcb);
    801             }
    802         }
    803     }
    804 }
    805 
    806 /*******************************************************************************
    807 **
    808 ** Function         gatt_l2cif_disconnect_ind_cback
    809 **
    810 ** Description      This is the L2CAP disconnect indication callback function.
    811 **
    812 **
    813 ** Returns          void
    814 **
    815 *******************************************************************************/
    816 void gatt_l2cif_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
    817 {
    818     tGATT_TCB       *p_tcb;
    819     UINT16          reason;
    820 
    821     /* look up clcb for this channel */
    822     if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL)
    823     {
    824         if (ack_needed)
    825         {
    826             /* send L2CAP disconnect response */
    827             L2CA_DisconnectRsp(lcid);
    828         }
    829         if (gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda) == NULL)
    830         {
    831             if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda))
    832                 gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
    833         }
    834         /* if ACL link is still up, no reason is logged, l2cap is disconnect from peer */
    835         if ((reason = L2CA_GetDisconnectReason(p_tcb->peer_bda, p_tcb->transport)) == 0)
    836             reason = GATT_CONN_TERMINATE_PEER_USER;
    837 
    838         /* send disconnect callback */
    839         gatt_cleanup_upon_disc(p_tcb->peer_bda, reason, GATT_TRANSPORT_BR_EDR);
    840     }
    841 }
    842 
    843 /*******************************************************************************
    844 **
    845 ** Function         gatt_l2cif_disconnect_cfm_cback
    846 **
    847 ** Description      This is the L2CAP disconnect confirm callback function.
    848 **
    849 **
    850 ** Returns          void
    851 **
    852 *******************************************************************************/
    853 static void gatt_l2cif_disconnect_cfm_cback(UINT16 lcid, UINT16 result)
    854 {
    855     tGATT_TCB       *p_tcb;
    856     UINT16          reason;
    857     UNUSED(result);
    858 
    859     /* look up clcb for this channel */
    860     if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL)
    861     {
    862         /* If the device is not in the service changed client list, add it... */
    863         if (gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda) == NULL)
    864         {
    865             if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda))
    866                 gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
    867         }
    868 
    869         /* send disconnect callback */
    870         /* if ACL link is still up, no reason is logged, l2cap is disconnect from peer */
    871         if ((reason = L2CA_GetDisconnectReason(p_tcb->peer_bda, p_tcb->transport)) == 0)
    872             reason = GATT_CONN_TERMINATE_LOCAL_HOST;
    873 
    874         gatt_cleanup_upon_disc(p_tcb->peer_bda, reason, GATT_TRANSPORT_BR_EDR);
    875     }
    876 }
    877 
    878 /*******************************************************************************
    879 **
    880 ** Function         gatt_l2cif_data_ind_cback
    881 **
    882 ** Description      This is the L2CAP data indication callback function.
    883 **
    884 **
    885 ** Returns          void
    886 **
    887 *******************************************************************************/
    888 static void gatt_l2cif_data_ind_cback(UINT16 lcid, BT_HDR *p_buf)
    889 {
    890     tGATT_TCB       *p_tcb;
    891 
    892     /* look up clcb for this channel */
    893     if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL &&
    894         gatt_get_ch_state(p_tcb) == GATT_CH_OPEN)
    895     {
    896         /* process the data */
    897         gatt_data_process(p_tcb, p_buf);
    898     }
    899     else /* prevent buffer leak */
    900         osi_free(p_buf);
    901 }
    902 
    903 /*******************************************************************************
    904 **
    905 ** Function         gatt_l2cif_congest_cback
    906 **
    907 ** Description      L2CAP congestion callback
    908 **
    909 ** Returns          void
    910 **
    911 *******************************************************************************/
    912 static void gatt_l2cif_congest_cback (UINT16 lcid, BOOLEAN congested)
    913 {
    914     tGATT_TCB *p_tcb = gatt_find_tcb_by_cid(lcid);
    915 
    916     if (p_tcb != NULL)
    917     {
    918         gatt_channel_congestion(p_tcb, congested);
    919     }
    920 }
    921 
    922 /*******************************************************************************
    923 **
    924 ** Function         gatt_send_conn_cback
    925 **
    926 ** Description      Callback used to notify layer above about a connection.
    927 **
    928 **
    929 ** Returns          void
    930 **
    931 *******************************************************************************/
    932 static void gatt_send_conn_cback(tGATT_TCB *p_tcb)
    933 {
    934     UINT8               i;
    935     tGATT_REG           *p_reg;
    936     tGATT_BG_CONN_DEV   *p_bg_dev=NULL;
    937     UINT16              conn_id;
    938 
    939     p_bg_dev = gatt_find_bg_dev(p_tcb->peer_bda);
    940 
    941     /* notifying all applications for the connection up event */
    942     for (i = 0,  p_reg = gatt_cb.cl_rcb ; i < GATT_MAX_APPS; i++, p_reg++)
    943     {
    944         if (p_reg->in_use)
    945         {
    946             if (p_bg_dev && gatt_is_bg_dev_for_app(p_bg_dev, p_reg->gatt_if))
    947                 gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, TRUE, TRUE);
    948 
    949             if (p_reg->app_cb.p_conn_cb)
    950             {
    951                 conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if);
    952                 (*p_reg->app_cb.p_conn_cb)(p_reg->gatt_if, p_tcb->peer_bda, conn_id,
    953                                           TRUE, 0, p_tcb->transport);
    954             }
    955         }
    956     }
    957 
    958 
    959     if (gatt_num_apps_hold_link(p_tcb) &&  p_tcb->att_lcid == L2CAP_ATT_CID )
    960     {
    961         /* disable idle timeout if one or more clients are holding the link disable the idle timer */
    962         GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_NO_IDLE_TIMEOUT, p_tcb->transport);
    963     }
    964 }
    965 
    966 /*******************************************************************************
    967 **
    968 ** Function         gatt_le_data_ind
    969 **
    970 ** Description      This function is called when data is received from L2CAP.
    971 **                  if we are the originator of the connection, we are the ATT
    972 **                  client, and the received message is queued up for the client.
    973 **
    974 **                  If we are the destination of the connection, we are the ATT
    975 **                  server, so the message is passed to the server processing
    976 **                  function.
    977 **
    978 ** Returns          void
    979 **
    980 *******************************************************************************/
    981 void gatt_data_process (tGATT_TCB *p_tcb, BT_HDR *p_buf)
    982 {
    983     UINT8   *p = (UINT8 *)(p_buf + 1) + p_buf->offset;
    984     UINT8   op_code, pseudo_op_code;
    985     UINT16  msg_len;
    986 
    987 
    988     if (p_buf->len > 0)
    989     {
    990         msg_len = p_buf->len - 1;
    991         STREAM_TO_UINT8(op_code, p);
    992 
    993         /* remove the two MSBs associated with sign write and write cmd */
    994         pseudo_op_code = op_code & (~GATT_WRITE_CMD_MASK);
    995 
    996         if (pseudo_op_code < GATT_OP_CODE_MAX)
    997         {
    998             if (op_code == GATT_SIGN_CMD_WRITE)
    999             {
   1000                 gatt_verify_signature(p_tcb, p_buf);
   1001             }
   1002             else
   1003             {
   1004                 /* message from client */
   1005                 if ((op_code % 2) == 0)
   1006                     gatt_server_handle_client_req (p_tcb, op_code, msg_len, p);
   1007                 else
   1008                     gatt_client_handle_server_rsp (p_tcb, op_code, msg_len, p);
   1009             }
   1010         }
   1011         else
   1012         {
   1013             GATT_TRACE_ERROR ("ATT - Rcvd L2CAP data, unknown cmd: 0x%x", op_code);
   1014         }
   1015     }
   1016     else
   1017     {
   1018         GATT_TRACE_ERROR ("invalid data length, ignore");
   1019     }
   1020 
   1021     osi_free(p_buf);
   1022 }
   1023 
   1024 /*******************************************************************************
   1025 **
   1026 ** Function         gatt_add_a_bonded_dev_for_srv_chg
   1027 **
   1028 ** Description      Add a bonded dev to the service changed client list
   1029 **
   1030 ** Returns          void
   1031 **
   1032 *******************************************************************************/
   1033 void gatt_add_a_bonded_dev_for_srv_chg (BD_ADDR bda)
   1034 {
   1035     tGATTS_SRV_CHG_REQ req;
   1036     tGATTS_SRV_CHG srv_chg_clt;
   1037 
   1038     memcpy(srv_chg_clt.bda, bda, BD_ADDR_LEN);
   1039     srv_chg_clt.srv_changed = FALSE;
   1040     if (gatt_add_srv_chg_clt(&srv_chg_clt) != NULL)
   1041     {
   1042         memcpy(req.srv_chg.bda, bda, BD_ADDR_LEN);
   1043         req.srv_chg.srv_changed = FALSE;
   1044         if (gatt_cb.cb_info.p_srv_chg_callback)
   1045             (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_ADD_CLIENT, &req, NULL);
   1046     }
   1047 }
   1048 
   1049 /*******************************************************************************
   1050 **
   1051 ** Function         gatt_send_srv_chg_ind
   1052 **
   1053 ** Description      This function is called to send a service chnaged indication to
   1054 **                  the specified bd address
   1055 **
   1056 ** Returns          void
   1057 **
   1058 *******************************************************************************/
   1059 void gatt_send_srv_chg_ind (BD_ADDR peer_bda)
   1060 {
   1061     UINT8   handle_range[GATT_SIZE_OF_SRV_CHG_HNDL_RANGE];
   1062     UINT8   *p = handle_range;
   1063     UINT16  conn_id;
   1064 
   1065     GATT_TRACE_DEBUG("gatt_send_srv_chg_ind");
   1066 
   1067     if (gatt_cb.handle_of_h_r)
   1068     {
   1069         if ((conn_id = gatt_profile_find_conn_id_by_bd_addr(peer_bda)) != GATT_INVALID_CONN_ID)
   1070         {
   1071             UINT16_TO_STREAM (p, 1);
   1072             UINT16_TO_STREAM (p, 0xFFFF);
   1073             GATTS_HandleValueIndication (conn_id,
   1074                                          gatt_cb.handle_of_h_r,
   1075                                          GATT_SIZE_OF_SRV_CHG_HNDL_RANGE,
   1076                                          handle_range);
   1077         }
   1078         else
   1079         {
   1080             GATT_TRACE_ERROR("Unable to find conn_id for  %08x%04x ",
   1081                               (peer_bda[0]<<24)+(peer_bda[1]<<16)+(peer_bda[2]<<8)+peer_bda[3],
   1082                               (peer_bda[4]<<8)+peer_bda[5] );
   1083         }
   1084     }
   1085 }
   1086 
   1087 /*******************************************************************************
   1088 **
   1089 ** Function         gatt_chk_srv_chg
   1090 **
   1091 ** Description      Check sending service chnaged Indication is required or not
   1092 **                  if required then send the Indication
   1093 **
   1094 ** Returns          void
   1095 **
   1096 *******************************************************************************/
   1097 void gatt_chk_srv_chg(tGATTS_SRV_CHG *p_srv_chg_clt)
   1098 {
   1099     GATT_TRACE_DEBUG("gatt_chk_srv_chg srv_changed=%d", p_srv_chg_clt->srv_changed );
   1100 
   1101     if (p_srv_chg_clt->srv_changed)
   1102     {
   1103         gatt_send_srv_chg_ind(p_srv_chg_clt->bda);
   1104     }
   1105 }
   1106 
   1107 /*******************************************************************************
   1108 **
   1109 ** Function         gatt_init_srv_chg
   1110 **
   1111 ** Description      This function is used to initialize the service changed
   1112 **                  attribute value
   1113 **
   1114 ** Returns          void
   1115 **
   1116 *******************************************************************************/
   1117 void gatt_init_srv_chg (void)
   1118 {
   1119     tGATTS_SRV_CHG_REQ req;
   1120     tGATTS_SRV_CHG_RSP rsp;
   1121     BOOLEAN status;
   1122     UINT8 num_clients,i;
   1123     tGATTS_SRV_CHG  srv_chg_clt;
   1124 
   1125     GATT_TRACE_DEBUG("gatt_init_srv_chg");
   1126     if (gatt_cb.cb_info.p_srv_chg_callback)
   1127     {
   1128         status = (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_READ_NUM_CLENTS, NULL, &rsp);
   1129 
   1130         if (status && rsp.num_clients)
   1131         {
   1132             GATT_TRACE_DEBUG("gatt_init_srv_chg num_srv_chg_clt_clients=%d", rsp.num_clients);
   1133             num_clients = rsp.num_clients;
   1134             i = 1; /* use one based index */
   1135             while ((i <= num_clients) && status)
   1136             {
   1137                 req.client_read_index = i;
   1138                 if ((status = (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_READ_CLENT, &req, &rsp)) == TRUE)
   1139                 {
   1140                     memcpy(&srv_chg_clt, &rsp.srv_chg ,sizeof(tGATTS_SRV_CHG));
   1141                     if (gatt_add_srv_chg_clt(&srv_chg_clt) == NULL)
   1142                     {
   1143                         GATT_TRACE_ERROR("Unable to add a service change client");
   1144                         status = FALSE;
   1145                     }
   1146                 }
   1147                 i++;
   1148             }
   1149         }
   1150     }
   1151     else
   1152     {
   1153         GATT_TRACE_DEBUG("gatt_init_srv_chg callback not registered yet");
   1154     }
   1155 }
   1156 
   1157 /*******************************************************************************
   1158 **
   1159 ** Function         gatt_proc_srv_chg
   1160 **
   1161 ** Description      This function is process the service changed request
   1162 **
   1163 ** Returns          void
   1164 **
   1165 *******************************************************************************/
   1166 void gatt_proc_srv_chg (void)
   1167 {
   1168     UINT8               start_idx, found_idx;
   1169     BD_ADDR             bda;
   1170     BOOLEAN             srv_chg_ind_pending=FALSE;
   1171     tGATT_TCB           *p_tcb;
   1172     tBT_TRANSPORT      transport;
   1173 
   1174     GATT_TRACE_DEBUG ("gatt_proc_srv_chg");
   1175 
   1176     if (gatt_cb.cb_info.p_srv_chg_callback && gatt_cb.handle_of_h_r)
   1177     {
   1178         gatt_set_srv_chg();
   1179         start_idx =0;
   1180         while (gatt_find_the_connected_bda(start_idx, bda, &found_idx, &transport))
   1181         {
   1182             p_tcb = &gatt_cb.tcb[found_idx];;
   1183             srv_chg_ind_pending  = gatt_is_srv_chg_ind_pending(p_tcb);
   1184 
   1185             if (!srv_chg_ind_pending)
   1186             {
   1187                 gatt_send_srv_chg_ind(bda);
   1188             }
   1189             else
   1190             {
   1191                 GATT_TRACE_DEBUG ("discard srv chg - already has one in the queue");
   1192             }
   1193             start_idx = ++found_idx;
   1194         }
   1195     }
   1196 }
   1197 
   1198 /*******************************************************************************
   1199 **
   1200 ** Function         gatt_set_ch_state
   1201 **
   1202 ** Description      This function set the ch_state in tcb
   1203 **
   1204 ** Returns          none
   1205 **
   1206 *******************************************************************************/
   1207 void gatt_set_ch_state(tGATT_TCB *p_tcb, tGATT_CH_STATE ch_state)
   1208 {
   1209     if (p_tcb)
   1210     {
   1211         GATT_TRACE_DEBUG ("gatt_set_ch_state: old=%d new=%d", p_tcb->ch_state, ch_state);
   1212         p_tcb->ch_state = ch_state;
   1213     }
   1214 }
   1215 
   1216 /*******************************************************************************
   1217 **
   1218 ** Function         gatt_get_ch_state
   1219 **
   1220 ** Description      This function get the ch_state in tcb
   1221 **
   1222 ** Returns          none
   1223 **
   1224 *******************************************************************************/
   1225 tGATT_CH_STATE gatt_get_ch_state(tGATT_TCB *p_tcb)
   1226 {
   1227     tGATT_CH_STATE ch_state = GATT_CH_CLOSE;
   1228     if (p_tcb)
   1229     {
   1230         GATT_TRACE_DEBUG ("gatt_get_ch_state: ch_state=%d", p_tcb->ch_state);
   1231         ch_state = p_tcb->ch_state;
   1232     }
   1233     return ch_state;
   1234 }
   1235 
   1236 #endif /* BLE_INCLUDED */
   1237