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