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          void.
    278 **
    279 *******************************************************************************/
    280 void gatt_update_app_hold_link_status (tGATT_IF gatt_if, tGATT_TCB *p_tcb, BOOLEAN is_add)
    281 {
    282     UINT8 i;
    283     BOOLEAN found=FALSE;
    284 
    285     if (p_tcb == NULL)
    286     {
    287         GATT_TRACE_ERROR("gatt_update_app_hold_link_status p_tcb=NULL");
    288         return;
    289     }
    290 
    291 
    292     for (i=0; i<GATT_MAX_APPS; i++)
    293     {
    294         if (p_tcb->app_hold_link[i] ==  gatt_if)
    295         {
    296             found = TRUE;
    297             if (!is_add)
    298             {
    299                 p_tcb->app_hold_link[i] = 0;
    300                 break;
    301             }
    302         }
    303     }
    304 
    305     if (!found && is_add)
    306     {
    307         for (i=0; i<GATT_MAX_APPS; i++)
    308         {
    309             if (p_tcb->app_hold_link[i] ==  0)
    310             {
    311                 p_tcb->app_hold_link[i] = gatt_if;
    312                 found = TRUE;
    313                 break;
    314             }
    315         }
    316     }
    317 
    318     GATT_TRACE_DEBUG("gatt_update_app_hold_link_status found=%d[1-found] idx=%d gatt_if=%d is_add=%d", found, i, gatt_if, is_add);
    319 
    320 }
    321 
    322 /*******************************************************************************
    323 **
    324 ** Function         gatt_update_app_use_link_flag
    325 **
    326 ** Description      Update the application use link flag and optional to check the acl link
    327 **                  if the link is up then set the idle time out accordingly
    328 **
    329 ** Returns          void.
    330 **
    331 *******************************************************************************/
    332 void gatt_update_app_use_link_flag (tGATT_IF gatt_if, tGATT_TCB *p_tcb, BOOLEAN is_add, BOOLEAN check_acl_link)
    333 {
    334     GATT_TRACE_DEBUG("gatt_update_app_use_link_flag  is_add=%d chk_link=%d",
    335                       is_add, check_acl_link);
    336 
    337     gatt_update_app_hold_link_status(gatt_if, p_tcb, is_add);
    338 
    339     if (check_acl_link &&
    340         p_tcb &&
    341          p_tcb->att_lcid == L2CAP_ATT_CID && /* only update link idle timer for fixed channel */
    342         (BTM_GetHCIConnHandle(p_tcb->peer_bda, p_tcb->transport) != GATT_INVALID_ACL_HANDLE))
    343     {
    344         if (is_add)
    345         {
    346             GATT_TRACE_DEBUG("GATT disables link idle timer");
    347             /* acl link is connected disable the idle timeout */
    348             GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_NO_IDLE_TIMEOUT, p_tcb->transport);
    349         }
    350         else
    351         {
    352             if (!gatt_num_apps_hold_link(p_tcb))
    353             {
    354                 /* acl link is connected but no application needs to use the link
    355                    so set the timeout value to GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP seconds */
    356                 GATT_TRACE_DEBUG("GATT starts link idle timer =%d sec", GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP);
    357                 GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP, p_tcb->transport);
    358             }
    359 
    360         }
    361     }
    362 }
    363 
    364 /*******************************************************************************
    365 **
    366 ** Function         gatt_act_connect
    367 **
    368 ** Description      GATT connection initiation.
    369 **
    370 ** Returns          void.
    371 **
    372 *******************************************************************************/
    373 BOOLEAN gatt_act_connect (tGATT_REG *p_reg, BD_ADDR bd_addr, tBT_TRANSPORT transport)
    374 {
    375     BOOLEAN     ret = FALSE;
    376     tGATT_TCB   *p_tcb;
    377     UINT8       st;
    378 
    379     if ((p_tcb = gatt_find_tcb_by_addr(bd_addr, transport)) != NULL)
    380     {
    381         ret = TRUE;
    382         st = gatt_get_ch_state(p_tcb);
    383 
    384         /* before link down, another app try to open a GATT connection */
    385         if(st == GATT_CH_OPEN &&  gatt_num_apps_hold_link(p_tcb) == 0 &&
    386             transport == BT_TRANSPORT_LE )
    387         {
    388             if (!gatt_connect(bd_addr,  p_tcb, transport))
    389                 ret = FALSE;
    390         }
    391         else if(st == GATT_CH_CLOSING)
    392         {
    393             /* need to complete the closing first */
    394             ret = FALSE;
    395         }
    396     }
    397     else
    398     {
    399         if ((p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr, transport)) != NULL)
    400         {
    401             if (!gatt_connect(bd_addr,  p_tcb, transport))
    402             {
    403                 GATT_TRACE_ERROR("gatt_connect failed");
    404                 fixed_queue_free(p_tcb->pending_enc_clcb, NULL);
    405                 fixed_queue_free(p_tcb->pending_ind_q, NULL);
    406                 fixed_queue_free(p_tcb->sr_cmd.multi_rsp_q, NULL);
    407                 memset(p_tcb, 0, sizeof(tGATT_TCB));
    408             }
    409             else
    410                 ret = TRUE;
    411         }
    412         else
    413         {
    414             ret = 0;
    415             GATT_TRACE_ERROR("Max TCB for gatt_if [%d] reached.", p_reg->gatt_if);
    416         }
    417     }
    418 
    419     if (ret)
    420     {
    421         gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, TRUE, FALSE);
    422     }
    423 
    424     return ret;
    425 }
    426 
    427 /*******************************************************************************
    428 **
    429 ** Function         gatt_le_connect_cback
    430 **
    431 ** Description      This callback function is called by L2CAP to indicate that
    432 **                  the ATT fixed channel for LE is
    433 **                      connected (conn = TRUE)/disconnected (conn = FALSE).
    434 **
    435 *******************************************************************************/
    436 static void gatt_le_connect_cback (UINT16 chan, BD_ADDR bd_addr, BOOLEAN connected,
    437                                    UINT16 reason, tBT_TRANSPORT transport)
    438 {
    439 
    440     tGATT_TCB       *p_tcb = gatt_find_tcb_by_addr(bd_addr, transport);
    441     BOOLEAN                 check_srv_chg = FALSE;
    442     tGATTS_SRV_CHG          *p_srv_chg_clt=NULL;
    443 
    444     /* ignore all fixed channel connect/disconnect on BR/EDR link for GATT */
    445     if (transport == BT_TRANSPORT_BR_EDR)
    446         return;
    447 
    448     GATT_TRACE_DEBUG ("GATT   ATT protocol channel with BDA: %08x%04x is %s",
    449                        (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3],
    450                        (bd_addr[4]<<8)+bd_addr[5], (connected) ? "connected" : "disconnected");
    451 
    452     if ((p_srv_chg_clt = gatt_is_bda_in_the_srv_chg_clt_list(bd_addr)) != NULL)
    453     {
    454         check_srv_chg = TRUE;
    455     }
    456     else
    457     {
    458         if (btm_sec_is_a_bonded_dev(bd_addr))
    459             gatt_add_a_bonded_dev_for_srv_chg(bd_addr);
    460     }
    461 
    462     if (connected)
    463     {
    464         /* do we have a channel initiating a connection? */
    465         if (p_tcb)
    466         {
    467             /* we are initiating connection */
    468             if ( gatt_get_ch_state(p_tcb) == GATT_CH_CONN)
    469             {
    470                 /* send callback */
    471                 gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
    472                 p_tcb->payload_size = GATT_DEF_BLE_MTU_SIZE;
    473 
    474                 gatt_send_conn_cback(p_tcb);
    475             }
    476             if (check_srv_chg)
    477                 gatt_chk_srv_chg (p_srv_chg_clt);
    478         }
    479         /* this is incoming connection or background connection callback */
    480 
    481         else
    482         {
    483             if ((p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr, BT_TRANSPORT_LE)) != NULL)
    484             {
    485                 p_tcb->att_lcid = L2CAP_ATT_CID;
    486 
    487                 gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
    488 
    489                 p_tcb->payload_size = GATT_DEF_BLE_MTU_SIZE;
    490 
    491                 gatt_send_conn_cback (p_tcb);
    492                 if (check_srv_chg)
    493                 {
    494                     gatt_chk_srv_chg (p_srv_chg_clt);
    495                 }
    496             }
    497             else
    498             {
    499                 GATT_TRACE_ERROR("CCB max out, no rsources");
    500             }
    501         }
    502     }
    503     else
    504     {
    505         gatt_cleanup_upon_disc(bd_addr, reason, transport);
    506         GATT_TRACE_DEBUG ("ATT disconnected");
    507     }
    508 }
    509 
    510 /*******************************************************************************
    511 **
    512 ** Function         gatt_channel_congestion
    513 **
    514 ** Description      This function is called to process the congestion callback
    515 **                  from lcb
    516 **
    517 ** Returns          void
    518 **
    519 *******************************************************************************/
    520 static void gatt_channel_congestion(tGATT_TCB *p_tcb, BOOLEAN congested)
    521 {
    522     UINT8 i = 0;
    523     tGATT_REG *p_reg=NULL;
    524     UINT16 conn_id;
    525 
    526     /* if uncongested, check to see if there is any more pending data */
    527     if (p_tcb != NULL && congested == FALSE)
    528     {
    529         gatt_cl_send_next_cmd_inq(p_tcb);
    530     }
    531     /* notifying all applications for the connection up event */
    532     for (i = 0, p_reg = gatt_cb.cl_rcb ; i < GATT_MAX_APPS; i++, p_reg++)
    533     {
    534         if (p_reg->in_use)
    535         {
    536             if (p_reg->app_cb.p_congestion_cb)
    537             {
    538                 conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if);
    539                 (*p_reg->app_cb.p_congestion_cb)(conn_id, congested);
    540             }
    541         }
    542     }
    543 }
    544 
    545 /*******************************************************************************
    546 **
    547 ** Function         gatt_le_cong_cback
    548 **
    549 ** Description      This function is called when GATT fixed channel is congested
    550 **                  or uncongested.
    551 **
    552 ** Returns          void
    553 **
    554 *******************************************************************************/
    555 static void gatt_le_cong_cback(BD_ADDR remote_bda, BOOLEAN congested)
    556 {
    557     tGATT_TCB *p_tcb = gatt_find_tcb_by_addr(remote_bda, BT_TRANSPORT_LE);
    558 
    559     /* if uncongested, check to see if there is any more pending data */
    560     if (p_tcb != NULL)
    561     {
    562         gatt_channel_congestion(p_tcb, congested);
    563     }
    564 }
    565 
    566 /*******************************************************************************
    567 **
    568 ** Function         gatt_le_data_ind
    569 **
    570 ** Description      This function is called when data is received from L2CAP.
    571 **                  if we are the originator of the connection, we are the ATT
    572 **                  client, and the received message is queued up for the client.
    573 **
    574 **                  If we are the destination of the connection, we are the ATT
    575 **                  server, so the message is passed to the server processing
    576 **                  function.
    577 **
    578 ** Returns          void
    579 **
    580 *******************************************************************************/
    581 static void gatt_le_data_ind (UINT16 chan, BD_ADDR bd_addr, BT_HDR *p_buf)
    582 {
    583     tGATT_TCB    *p_tcb;
    584 
    585     /* Find CCB based on bd addr */
    586     if ((p_tcb = gatt_find_tcb_by_addr (bd_addr, BT_TRANSPORT_LE)) != NULL &&
    587         gatt_get_ch_state(p_tcb) >= GATT_CH_OPEN)
    588     {
    589         gatt_data_process(p_tcb, p_buf);
    590     }
    591     else
    592     {
    593         osi_free(p_buf);
    594 
    595         if (p_tcb != NULL)
    596         {
    597             GATT_TRACE_WARNING ("ATT - Ignored L2CAP data while in state: %d",
    598                                  gatt_get_ch_state(p_tcb));
    599         }
    600     }
    601 }
    602 
    603 /*******************************************************************************
    604 **
    605 ** Function         gatt_l2cif_connect_ind
    606 **
    607 ** Description      This function handles an inbound connection indication
    608 **                  from L2CAP. This is the case where we are acting as a
    609 **                  server.
    610 **
    611 ** Returns          void
    612 **
    613 *******************************************************************************/
    614 static void gatt_l2cif_connect_ind_cback (BD_ADDR  bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
    615 {
    616     /* do we already have a control channel for this peer? */
    617     UINT8       result = L2CAP_CONN_OK;
    618     tL2CAP_CFG_INFO cfg;
    619     tGATT_TCB       *p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_BR_EDR);
    620     UNUSED(psm);
    621 
    622     GATT_TRACE_ERROR("Connection indication cid = %d", lcid);
    623     /* new connection ? */
    624     if (p_tcb == NULL)
    625     {
    626         /* allocate tcb */
    627         if ((p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr, BT_TRANSPORT_BR_EDR)) == NULL)
    628         {
    629             /* no tcb available, reject L2CAP connection */
    630             result = L2CAP_CONN_NO_RESOURCES;
    631         }
    632         else
    633             p_tcb->att_lcid = lcid;
    634 
    635     }
    636     else /* existing connection , reject it */
    637     {
    638         result = L2CAP_CONN_NO_RESOURCES;
    639     }
    640 
    641     /* Send L2CAP connect rsp */
    642     L2CA_ConnectRsp(bd_addr, id, lcid, result, 0);
    643 
    644     /* if result ok, proceed with connection */
    645     if (result == L2CAP_CONN_OK)
    646     {
    647         /* transition to configuration state */
    648         gatt_set_ch_state(p_tcb, GATT_CH_CFG);
    649 
    650         /* Send L2CAP config req */
    651         memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
    652         cfg.mtu_present = TRUE;
    653         cfg.mtu = GATT_MAX_MTU_SIZE;
    654 
    655         L2CA_ConfigReq(lcid, &cfg);
    656     }
    657 }
    658 
    659 /*******************************************************************************
    660 **
    661 ** Function         gatt_l2c_connect_cfm_cback
    662 **
    663 ** Description      This is the L2CAP connect confirm callback function.
    664 **
    665 **
    666 ** Returns          void
    667 **
    668 *******************************************************************************/
    669 static void gatt_l2cif_connect_cfm_cback(UINT16 lcid, UINT16 result)
    670 {
    671     tGATT_TCB       *p_tcb;
    672     tL2CAP_CFG_INFO cfg;
    673 
    674     /* look up clcb for this channel */
    675     if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL)
    676     {
    677         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);
    678 
    679         /* if in correct state */
    680         if (gatt_get_ch_state(p_tcb) == GATT_CH_CONN)
    681         {
    682             /* if result successful */
    683             if (result == L2CAP_CONN_OK)
    684             {
    685                 /* set channel state */
    686                 gatt_set_ch_state(p_tcb, GATT_CH_CFG);
    687 
    688                 /* Send L2CAP config req */
    689                 memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
    690                 cfg.mtu_present = TRUE;
    691                 cfg.mtu = GATT_MAX_MTU_SIZE;
    692                 L2CA_ConfigReq(lcid, &cfg);
    693             }
    694             /* else initiating connection failure */
    695             else
    696             {
    697                 gatt_cleanup_upon_disc(p_tcb->peer_bda, result, GATT_TRANSPORT_BR_EDR);
    698             }
    699         }
    700         else /* wrong state, disconnect it */
    701         {
    702             if (result == L2CAP_CONN_OK)
    703             {
    704                 /* just in case the peer also accepts our connection - Send L2CAP disconnect req */
    705                 L2CA_DisconnectReq(lcid);
    706             }
    707         }
    708     }
    709 }
    710 
    711 /*******************************************************************************
    712 **
    713 ** Function         gatt_l2cif_config_cfm_cback
    714 **
    715 ** Description      This is the L2CAP config confirm callback function.
    716 **
    717 **
    718 ** Returns          void
    719 **
    720 *******************************************************************************/
    721 void gatt_l2cif_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
    722 {
    723     tGATT_TCB       *p_tcb;
    724     tGATTS_SRV_CHG  *p_srv_chg_clt=NULL;
    725 
    726     /* look up clcb for this channel */
    727     if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL)
    728     {
    729         /* if in correct state */
    730         if ( gatt_get_ch_state(p_tcb) == GATT_CH_CFG)
    731         {
    732             /* if result successful */
    733             if (p_cfg->result == L2CAP_CFG_OK)
    734             {
    735                 /* update flags */
    736                 p_tcb->ch_flags |= GATT_L2C_CFG_CFM_DONE;
    737 
    738                 /* if configuration complete */
    739                 if (p_tcb->ch_flags & GATT_L2C_CFG_IND_DONE)
    740                 {
    741                     gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
    742 
    743                     if ((p_srv_chg_clt = gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda)) != NULL)
    744                     {
    745                         gatt_chk_srv_chg(p_srv_chg_clt);
    746                     }
    747                     else
    748                     {
    749                         if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda))
    750                             gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
    751                     }
    752 
    753                     /* send callback */
    754                     gatt_send_conn_cback(p_tcb);
    755                 }
    756             }
    757             /* else failure */
    758             else
    759             {
    760                 /* Send L2CAP disconnect req */
    761                 L2CA_DisconnectReq(lcid);
    762             }
    763         }
    764     }
    765 }
    766 
    767 /*******************************************************************************
    768 **
    769 ** Function         gatt_l2cif_config_ind_cback
    770 **
    771 ** Description      This is the L2CAP config indication callback function.
    772 **
    773 **
    774 ** Returns          void
    775 **
    776 *******************************************************************************/
    777 void gatt_l2cif_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
    778 {
    779     tGATT_TCB       *p_tcb;
    780     tGATTS_SRV_CHG  *p_srv_chg_clt=NULL;
    781     /* look up clcb for this channel */
    782     if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL)
    783     {
    784         /* GATT uses the smaller of our MTU and peer's MTU  */
    785         if ( p_cfg->mtu_present &&
    786              (p_cfg->mtu >= GATT_MIN_BR_MTU_SIZE && p_cfg->mtu < L2CAP_DEFAULT_MTU))
    787             p_tcb->payload_size = p_cfg->mtu;
    788         else
    789             p_tcb->payload_size = L2CAP_DEFAULT_MTU;
    790 
    791         /* send L2CAP configure response */
    792         memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
    793         p_cfg->result = L2CAP_CFG_OK;
    794         L2CA_ConfigRsp(lcid, p_cfg);
    795 
    796         /* if first config ind */
    797         if ((p_tcb->ch_flags & GATT_L2C_CFG_IND_DONE) == 0)
    798         {
    799             /* update flags */
    800             p_tcb->ch_flags |= GATT_L2C_CFG_IND_DONE;
    801 
    802             /* if configuration complete */
    803             if (p_tcb->ch_flags & GATT_L2C_CFG_CFM_DONE)
    804             {
    805                 gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
    806                 if ((p_srv_chg_clt = gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda)) != NULL)
    807                 {
    808                     gatt_chk_srv_chg(p_srv_chg_clt);
    809                 }
    810                 else
    811                 {
    812                     if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda))
    813                         gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
    814                 }
    815 
    816                 /* send callback */
    817                 gatt_send_conn_cback(p_tcb);
    818             }
    819         }
    820     }
    821 }
    822 
    823 /*******************************************************************************
    824 **
    825 ** Function         gatt_l2cif_disconnect_ind_cback
    826 **
    827 ** Description      This is the L2CAP disconnect indication callback function.
    828 **
    829 **
    830 ** Returns          void
    831 **
    832 *******************************************************************************/
    833 void gatt_l2cif_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
    834 {
    835     tGATT_TCB       *p_tcb;
    836     UINT16          reason;
    837 
    838     /* look up clcb for this channel */
    839     if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL)
    840     {
    841         if (ack_needed)
    842         {
    843             /* send L2CAP disconnect response */
    844             L2CA_DisconnectRsp(lcid);
    845         }
    846         if (gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda) == NULL)
    847         {
    848             if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda))
    849                 gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
    850         }
    851         /* if ACL link is still up, no reason is logged, l2cap is disconnect from peer */
    852         if ((reason = L2CA_GetDisconnectReason(p_tcb->peer_bda, p_tcb->transport)) == 0)
    853             reason = GATT_CONN_TERMINATE_PEER_USER;
    854 
    855         /* send disconnect callback */
    856         gatt_cleanup_upon_disc(p_tcb->peer_bda, reason, GATT_TRANSPORT_BR_EDR);
    857     }
    858 }
    859 
    860 /*******************************************************************************
    861 **
    862 ** Function         gatt_l2cif_disconnect_cfm_cback
    863 **
    864 ** Description      This is the L2CAP disconnect confirm callback function.
    865 **
    866 **
    867 ** Returns          void
    868 **
    869 *******************************************************************************/
    870 static void gatt_l2cif_disconnect_cfm_cback(UINT16 lcid, UINT16 result)
    871 {
    872     tGATT_TCB       *p_tcb;
    873     UINT16          reason;
    874     UNUSED(result);
    875 
    876     /* look up clcb for this channel */
    877     if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL)
    878     {
    879         /* If the device is not in the service changed client list, add it... */
    880         if (gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda) == NULL)
    881         {
    882             if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda))
    883                 gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
    884         }
    885 
    886         /* send disconnect callback */
    887         /* if ACL link is still up, no reason is logged, l2cap is disconnect from peer */
    888         if ((reason = L2CA_GetDisconnectReason(p_tcb->peer_bda, p_tcb->transport)) == 0)
    889             reason = GATT_CONN_TERMINATE_LOCAL_HOST;
    890 
    891         gatt_cleanup_upon_disc(p_tcb->peer_bda, reason, GATT_TRANSPORT_BR_EDR);
    892     }
    893 }
    894 
    895 /*******************************************************************************
    896 **
    897 ** Function         gatt_l2cif_data_ind_cback
    898 **
    899 ** Description      This is the L2CAP data indication callback function.
    900 **
    901 **
    902 ** Returns          void
    903 **
    904 *******************************************************************************/
    905 static void gatt_l2cif_data_ind_cback(UINT16 lcid, BT_HDR *p_buf)
    906 {
    907     tGATT_TCB       *p_tcb;
    908 
    909     /* look up clcb for this channel */
    910     if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL &&
    911         gatt_get_ch_state(p_tcb) == GATT_CH_OPEN)
    912     {
    913         /* process the data */
    914         gatt_data_process(p_tcb, p_buf);
    915     }
    916     else /* prevent buffer leak */
    917         osi_free(p_buf);
    918 }
    919 
    920 /*******************************************************************************
    921 **
    922 ** Function         gatt_l2cif_congest_cback
    923 **
    924 ** Description      L2CAP congestion callback
    925 **
    926 ** Returns          void
    927 **
    928 *******************************************************************************/
    929 static void gatt_l2cif_congest_cback (UINT16 lcid, BOOLEAN congested)
    930 {
    931     tGATT_TCB *p_tcb = gatt_find_tcb_by_cid(lcid);
    932 
    933     if (p_tcb != NULL)
    934     {
    935         gatt_channel_congestion(p_tcb, congested);
    936     }
    937 }
    938 
    939 /*******************************************************************************
    940 **
    941 ** Function         gatt_send_conn_cback
    942 **
    943 ** Description      Callback used to notify layer above about a connection.
    944 **
    945 **
    946 ** Returns          void
    947 **
    948 *******************************************************************************/
    949 static void gatt_send_conn_cback(tGATT_TCB *p_tcb)
    950 {
    951     UINT8               i;
    952     tGATT_REG           *p_reg;
    953     tGATT_BG_CONN_DEV   *p_bg_dev=NULL;
    954     UINT16              conn_id;
    955 
    956     p_bg_dev = gatt_find_bg_dev(p_tcb->peer_bda);
    957 
    958     /* notifying all applications for the connection up event */
    959     for (i = 0,  p_reg = gatt_cb.cl_rcb ; i < GATT_MAX_APPS; i++, p_reg++)
    960     {
    961         if (p_reg->in_use)
    962         {
    963             if (p_bg_dev && gatt_is_bg_dev_for_app(p_bg_dev, p_reg->gatt_if))
    964                 gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, TRUE, TRUE);
    965 
    966             if (p_reg->app_cb.p_conn_cb)
    967             {
    968                 conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if);
    969                 (*p_reg->app_cb.p_conn_cb)(p_reg->gatt_if, p_tcb->peer_bda, conn_id,
    970                                           TRUE, 0, p_tcb->transport);
    971             }
    972         }
    973     }
    974 
    975 
    976     if (gatt_num_apps_hold_link(p_tcb) &&  p_tcb->att_lcid == L2CAP_ATT_CID )
    977     {
    978         /* disable idle timeout if one or more clients are holding the link disable the idle timer */
    979         GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_NO_IDLE_TIMEOUT, p_tcb->transport);
    980     }
    981 }
    982 
    983 /*******************************************************************************
    984 **
    985 ** Function         gatt_le_data_ind
    986 **
    987 ** Description      This function is called when data is received from L2CAP.
    988 **                  if we are the originator of the connection, we are the ATT
    989 **                  client, and the received message is queued up for the client.
    990 **
    991 **                  If we are the destination of the connection, we are the ATT
    992 **                  server, so the message is passed to the server processing
    993 **                  function.
    994 **
    995 ** Returns          void
    996 **
    997 *******************************************************************************/
    998 void gatt_data_process (tGATT_TCB *p_tcb, BT_HDR *p_buf)
    999 {
   1000     UINT8   *p = (UINT8 *)(p_buf + 1) + p_buf->offset;
   1001     UINT8   op_code, pseudo_op_code;
   1002     UINT16  msg_len;
   1003 
   1004 
   1005     if (p_buf->len > 0)
   1006     {
   1007         msg_len = p_buf->len - 1;
   1008         STREAM_TO_UINT8(op_code, p);
   1009 
   1010         /* remove the two MSBs associated with sign write and write cmd */
   1011         pseudo_op_code = op_code & (~GATT_WRITE_CMD_MASK);
   1012 
   1013         if (pseudo_op_code < GATT_OP_CODE_MAX)
   1014         {
   1015             if (op_code == GATT_SIGN_CMD_WRITE)
   1016             {
   1017                 gatt_verify_signature(p_tcb, p_buf);
   1018             }
   1019             else
   1020             {
   1021                 /* message from client */
   1022                 if ((op_code % 2) == 0)
   1023                     gatt_server_handle_client_req (p_tcb, op_code, msg_len, p);
   1024                 else
   1025                     gatt_client_handle_server_rsp (p_tcb, op_code, msg_len, p);
   1026             }
   1027         }
   1028         else
   1029         {
   1030             GATT_TRACE_ERROR ("ATT - Rcvd L2CAP data, unknown cmd: 0x%x", op_code);
   1031         }
   1032     }
   1033     else
   1034     {
   1035         GATT_TRACE_ERROR ("invalid data length, ignore");
   1036     }
   1037 
   1038     osi_free(p_buf);
   1039 }
   1040 
   1041 /*******************************************************************************
   1042 **
   1043 ** Function         gatt_add_a_bonded_dev_for_srv_chg
   1044 **
   1045 ** Description      Add a bonded dev to the service changed client list
   1046 **
   1047 ** Returns          void
   1048 **
   1049 *******************************************************************************/
   1050 void gatt_add_a_bonded_dev_for_srv_chg (BD_ADDR bda)
   1051 {
   1052     tGATTS_SRV_CHG_REQ req;
   1053     tGATTS_SRV_CHG srv_chg_clt;
   1054 
   1055     memcpy(srv_chg_clt.bda, bda, BD_ADDR_LEN);
   1056     srv_chg_clt.srv_changed = FALSE;
   1057     if (gatt_add_srv_chg_clt(&srv_chg_clt) != NULL)
   1058     {
   1059         memcpy(req.srv_chg.bda, bda, BD_ADDR_LEN);
   1060         req.srv_chg.srv_changed = FALSE;
   1061         if (gatt_cb.cb_info.p_srv_chg_callback)
   1062             (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_ADD_CLIENT, &req, NULL);
   1063     }
   1064 }
   1065 
   1066 /*******************************************************************************
   1067 **
   1068 ** Function         gatt_send_srv_chg_ind
   1069 **
   1070 ** Description      This function is called to send a service chnaged indication to
   1071 **                  the specified bd address
   1072 **
   1073 ** Returns          void
   1074 **
   1075 *******************************************************************************/
   1076 void gatt_send_srv_chg_ind (BD_ADDR peer_bda)
   1077 {
   1078     UINT8   handle_range[GATT_SIZE_OF_SRV_CHG_HNDL_RANGE];
   1079     UINT8   *p = handle_range;
   1080     UINT16  conn_id;
   1081 
   1082     GATT_TRACE_DEBUG("gatt_send_srv_chg_ind");
   1083 
   1084     if (gatt_cb.handle_of_h_r)
   1085     {
   1086         if ((conn_id = gatt_profile_find_conn_id_by_bd_addr(peer_bda)) != GATT_INVALID_CONN_ID)
   1087         {
   1088             UINT16_TO_STREAM (p, 1);
   1089             UINT16_TO_STREAM (p, 0xFFFF);
   1090             GATTS_HandleValueIndication (conn_id,
   1091                                          gatt_cb.handle_of_h_r,
   1092                                          GATT_SIZE_OF_SRV_CHG_HNDL_RANGE,
   1093                                          handle_range);
   1094         }
   1095         else
   1096         {
   1097             GATT_TRACE_ERROR("Unable to find conn_id for  %08x%04x ",
   1098                               (peer_bda[0]<<24)+(peer_bda[1]<<16)+(peer_bda[2]<<8)+peer_bda[3],
   1099                               (peer_bda[4]<<8)+peer_bda[5] );
   1100         }
   1101     }
   1102 }
   1103 
   1104 /*******************************************************************************
   1105 **
   1106 ** Function         gatt_chk_srv_chg
   1107 **
   1108 ** Description      Check sending service chnaged Indication is required or not
   1109 **                  if required then send the Indication
   1110 **
   1111 ** Returns          void
   1112 **
   1113 *******************************************************************************/
   1114 void gatt_chk_srv_chg(tGATTS_SRV_CHG *p_srv_chg_clt)
   1115 {
   1116     GATT_TRACE_DEBUG("gatt_chk_srv_chg srv_changed=%d", p_srv_chg_clt->srv_changed );
   1117 
   1118     if (p_srv_chg_clt->srv_changed)
   1119     {
   1120         gatt_send_srv_chg_ind(p_srv_chg_clt->bda);
   1121     }
   1122 }
   1123 
   1124 /*******************************************************************************
   1125 **
   1126 ** Function         gatt_init_srv_chg
   1127 **
   1128 ** Description      This function is used to initialize the service changed
   1129 **                  attribute value
   1130 **
   1131 ** Returns          void
   1132 **
   1133 *******************************************************************************/
   1134 void gatt_init_srv_chg (void)
   1135 {
   1136     tGATTS_SRV_CHG_REQ req;
   1137     tGATTS_SRV_CHG_RSP rsp;
   1138     BOOLEAN status;
   1139     UINT8 num_clients,i;
   1140     tGATTS_SRV_CHG  srv_chg_clt;
   1141 
   1142     GATT_TRACE_DEBUG("gatt_init_srv_chg");
   1143     if (gatt_cb.cb_info.p_srv_chg_callback)
   1144     {
   1145         status = (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_READ_NUM_CLENTS, NULL, &rsp);
   1146 
   1147         if (status && rsp.num_clients)
   1148         {
   1149             GATT_TRACE_DEBUG("gatt_init_srv_chg num_srv_chg_clt_clients=%d", rsp.num_clients);
   1150             num_clients = rsp.num_clients;
   1151             i = 1; /* use one based index */
   1152             while ((i <= num_clients) && status)
   1153             {
   1154                 req.client_read_index = i;
   1155                 if ((status = (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_READ_CLENT, &req, &rsp)) == TRUE)
   1156                 {
   1157                     memcpy(&srv_chg_clt, &rsp.srv_chg ,sizeof(tGATTS_SRV_CHG));
   1158                     if (gatt_add_srv_chg_clt(&srv_chg_clt) == NULL)
   1159                     {
   1160                         GATT_TRACE_ERROR("Unable to add a service change client");
   1161                         status = FALSE;
   1162                     }
   1163                 }
   1164                 i++;
   1165             }
   1166         }
   1167     }
   1168     else
   1169     {
   1170         GATT_TRACE_DEBUG("gatt_init_srv_chg callback not registered yet");
   1171     }
   1172 }
   1173 
   1174 /*******************************************************************************
   1175 **
   1176 ** Function         gatt_proc_srv_chg
   1177 **
   1178 ** Description      This function is process the service changed request
   1179 **
   1180 ** Returns          void
   1181 **
   1182 *******************************************************************************/
   1183 void gatt_proc_srv_chg (void)
   1184 {
   1185     UINT8               start_idx, found_idx;
   1186     BD_ADDR             bda;
   1187     BOOLEAN             srv_chg_ind_pending=FALSE;
   1188     tGATT_TCB           *p_tcb;
   1189     tBT_TRANSPORT      transport;
   1190 
   1191     GATT_TRACE_DEBUG ("gatt_proc_srv_chg");
   1192 
   1193     if (gatt_cb.cb_info.p_srv_chg_callback && gatt_cb.handle_of_h_r)
   1194     {
   1195         gatt_set_srv_chg();
   1196         start_idx =0;
   1197         while (gatt_find_the_connected_bda(start_idx, bda, &found_idx, &transport))
   1198         {
   1199             p_tcb = &gatt_cb.tcb[found_idx];;
   1200             srv_chg_ind_pending  = gatt_is_srv_chg_ind_pending(p_tcb);
   1201 
   1202             if (!srv_chg_ind_pending)
   1203             {
   1204                 gatt_send_srv_chg_ind(bda);
   1205             }
   1206             else
   1207             {
   1208                 GATT_TRACE_DEBUG ("discard srv chg - already has one in the queue");
   1209             }
   1210             start_idx = ++found_idx;
   1211         }
   1212     }
   1213 }
   1214 
   1215 /*******************************************************************************
   1216 **
   1217 ** Function         gatt_set_ch_state
   1218 **
   1219 ** Description      This function set the ch_state in tcb
   1220 **
   1221 ** Returns          none
   1222 **
   1223 *******************************************************************************/
   1224 void gatt_set_ch_state(tGATT_TCB *p_tcb, tGATT_CH_STATE ch_state)
   1225 {
   1226     if (p_tcb)
   1227     {
   1228         GATT_TRACE_DEBUG ("gatt_set_ch_state: old=%d new=%d", p_tcb->ch_state, ch_state);
   1229         p_tcb->ch_state = ch_state;
   1230     }
   1231 }
   1232 
   1233 /*******************************************************************************
   1234 **
   1235 ** Function         gatt_get_ch_state
   1236 **
   1237 ** Description      This function get the ch_state in tcb
   1238 **
   1239 ** Returns          none
   1240 **
   1241 *******************************************************************************/
   1242 tGATT_CH_STATE gatt_get_ch_state(tGATT_TCB *p_tcb)
   1243 {
   1244     tGATT_CH_STATE ch_state = GATT_CH_CLOSE;
   1245     if (p_tcb)
   1246     {
   1247         GATT_TRACE_DEBUG ("gatt_get_ch_state: ch_state=%d", p_tcb->ch_state);
   1248         ch_state = p_tcb->ch_state;
   1249     }
   1250     return ch_state;
   1251 }
   1252 
   1253 #endif /* BLE_INCLUDED */
   1254