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