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