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