blob: d5e017b55d085a08918886faadb8395c6dc2c490 [file] [log] [blame]
The Android Open Source Project5738f832012-12-12 16:00:35 -08001/******************************************************************************
2 *
3 * Copyright (C) 2008-2012 Broadcom Corporation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19/******************************************************************************
20 *
21 * this file contains the main ATT functions
22 *
23 ******************************************************************************/
24
25#include "bt_target.h"
26
27#if BLE_INCLUDED == TRUE
28
29#include "gki.h"
30#include "gatt_int.h"
31#include "l2c_api.h"
32#include "btm_int.h"
33#include "btm_ble_int.h"
Mike J. Chen5cd8bff2014-01-31 18:16:59 -080034#include "bt_utils.h"
The Android Open Source Project5738f832012-12-12 16:00:35 -080035
36/* Configuration flags. */
37#define GATT_L2C_CFG_IND_DONE (1<<0)
38#define GATT_L2C_CFG_CFM_DONE (1<<1)
39
Andre Eisenbach6975b4d2013-08-05 16:55:38 -070040/* minimum GATT MTU size over BR/EDR link
41*/
42#define GATT_MIN_BR_MTU_SIZE 48
43
The Android Open Source Project5738f832012-12-12 16:00:35 -080044/********************************************************************************/
45/* L O C A L F U N C T I O N P R O T O T Y P E S */
46/********************************************************************************/
47static void gatt_le_connect_cback (BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason);
48static void gatt_le_data_ind (BD_ADDR bd_addr, BT_HDR *p_buf);
49
50static void gatt_l2cif_connect_ind_cback (BD_ADDR bd_addr, UINT16 l2cap_cid, UINT16 psm, UINT8 l2cap_id);
51static void gatt_l2cif_connect_cfm_cback (UINT16 l2cap_cid, UINT16 result);
52static void gatt_l2cif_config_ind_cback (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
53static void gatt_l2cif_config_cfm_cback (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
54static void gatt_l2cif_disconnect_ind_cback (UINT16 l2cap_cid, BOOLEAN ack_needed);
55static void gatt_l2cif_disconnect_cfm_cback (UINT16 l2cap_cid, UINT16 result);
56static void gatt_l2cif_data_ind_cback (UINT16 l2cap_cid, BT_HDR *p_msg);
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -080057static void gatt_send_conn_cback (tGATT_TCB *p_tcb);
The Android Open Source Project5738f832012-12-12 16:00:35 -080058
59static const tL2CAP_APPL_INFO dyn_info =
60{
61 gatt_l2cif_connect_ind_cback,
62 gatt_l2cif_connect_cfm_cback,
63 NULL,
64 gatt_l2cif_config_ind_cback,
65 gatt_l2cif_config_cfm_cback,
66 gatt_l2cif_disconnect_ind_cback,
67 gatt_l2cif_disconnect_cfm_cback,
68 NULL,
69 gatt_l2cif_data_ind_cback,
Mike J. Chen41eee7b2014-01-31 13:28:58 -080070 NULL,
The Android Open Source Project5738f832012-12-12 16:00:35 -080071 NULL
72} ;
73
74#if GATT_DYNAMIC_MEMORY == FALSE
75tGATT_CB gatt_cb;
76#endif
77
78/*******************************************************************************
79**
80** Function gatt_init
81**
82** Description This function is enable the GATT profile on the device.
83** It clears out the control blocks, and registers with L2CAP.
84**
85** Returns void
86**
87*******************************************************************************/
88void gatt_init (void)
89{
90 tL2CAP_FIXED_CHNL_REG fixed_reg;
91
92 GATT_TRACE_DEBUG0("gatt_init()");
93
94 memset (&gatt_cb, 0, sizeof(tGATT_CB));
95
96#if defined(GATT_INITIAL_TRACE_LEVEL)
97 gatt_cb.trace_level = GATT_INITIAL_TRACE_LEVEL;
98#else
99 gatt_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
100#endif
101 gatt_cb.def_mtu_size = GATT_DEF_BLE_MTU_SIZE;
102 GKI_init_q (&gatt_cb.sign_op_queue);
103 /* First, register fixed L2CAP channel for ATT over BLE */
104 fixed_reg.fixed_chnl_opts.mode = L2CAP_FCR_BASIC_MODE;
105 fixed_reg.fixed_chnl_opts.max_transmit = 0xFF;
106 fixed_reg.fixed_chnl_opts.rtrans_tout = 2000;
107 fixed_reg.fixed_chnl_opts.mon_tout = 12000;
108 fixed_reg.fixed_chnl_opts.mps = 670;
109 fixed_reg.fixed_chnl_opts.tx_win_sz = 1;
110
111 fixed_reg.pL2CA_FixedConn_Cb = gatt_le_connect_cback;
112 fixed_reg.pL2CA_FixedData_Cb = gatt_le_data_ind;
113 fixed_reg.default_idle_tout = 0xffff; /* 0xffff default idle timeout */
114
115 L2CA_RegisterFixedChannel (L2CAP_ATT_CID, &fixed_reg);
116
117 /* Now, register with L2CAP for ATT PSM over BR/EDR */
118 if (!L2CA_Register (BT_PSM_ATT, (tL2CAP_APPL_INFO *) &dyn_info))
119 {
120 GATT_TRACE_ERROR0 ("ATT Dynamic Registration failed");
121 }
122
123 BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_ATT, BTM_SEC_NONE, BT_PSM_ATT, 0, 0);
124 BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_ATT, BTM_SEC_NONE, BT_PSM_ATT, 0, 0);
125
126 gatt_cb.hdl_cfg.gatt_start_hdl = GATT_GATT_START_HANDLE;
127 gatt_cb.hdl_cfg.gap_start_hdl = GATT_GAP_START_HANDLE;
128 gatt_cb.hdl_cfg.app_start_hdl = GATT_APP_START_HANDLE;
129 gatt_profile_db_init();
130
131}
132
133
134
135/*******************************************************************************
136**
137** Function gatt_connect
138**
139** Description This function is called to initiate a connection to a peer device.
140**
141** Parameter rem_bda: remote device address to connect to.
142**
143** Returns TRUE if connection is started, otherwise return FALSE.
144**
145*******************************************************************************/
146BOOLEAN gatt_connect (BD_ADDR rem_bda, tGATT_TCB *p_tcb)
147{
Andre Eisenbach6975b4d2013-08-05 16:55:38 -0700148 BOOLEAN gatt_ret = FALSE;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800149
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800150 if (gatt_get_ch_state(p_tcb) != GATT_CH_OPEN)
151 gatt_set_ch_state(p_tcb, GATT_CH_CONN);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800152
Andre Eisenbach6975b4d2013-08-05 16:55:38 -0700153 /* select the physical link for GATT connection */
154 if (BTM_UseLeLink(rem_bda))
The Android Open Source Project5738f832012-12-12 16:00:35 -0800155 {
156 p_tcb->att_lcid = L2CAP_ATT_CID;
157 gatt_ret = L2CA_ConnectFixedChnl (L2CAP_ATT_CID, rem_bda);
158 }
159 else
160 {
Andre Eisenbach6975b4d2013-08-05 16:55:38 -0700161 if ((p_tcb->att_lcid = L2CA_ConnectReq(BT_PSM_ATT, rem_bda)) != 0)
162 gatt_ret = TRUE;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800163 }
164
165 return gatt_ret;
166}
167
168/*******************************************************************************
169**
170** Function gatt_disconnect
171**
172** Description This function is called to disconnect to an ATT device.
173**
174** Parameter rem_bda: remote device address to disconnect from.
175**
176** Returns TRUE: if connection found and to be disconnected; otherwise
177** return FALSE.
178**
179*******************************************************************************/
180BOOLEAN gatt_disconnect (BD_ADDR rem_bda)
181{
182 tGATT_TCB *p_tcb = gatt_find_tcb_by_addr(rem_bda);
183 BOOLEAN ret = FALSE;
184 tGATT_CH_STATE ch_state;
185 GATT_TRACE_DEBUG0 ("gatt_disconnect ");
186
187 if (p_tcb != NULL)
188 {
189 ret = TRUE;
190 if ( (ch_state = gatt_get_ch_state(p_tcb)) != GATT_CH_CLOSING )
191 {
192 if (p_tcb->att_lcid == L2CAP_ATT_CID)
193 {
194 if (ch_state == GATT_CH_OPEN)
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800195 {
The Android Open Source Project5738f832012-12-12 16:00:35 -0800196 /* only LCB exist between remote device and local */
197 ret = L2CA_RemoveFixedChnl (L2CAP_ATT_CID, rem_bda);
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800198 }
The Android Open Source Project5738f832012-12-12 16:00:35 -0800199 else
200 {
201 gatt_set_ch_state(p_tcb, GATT_CH_CLOSING);
202 ret = L2CA_CancelBleConnectReq (rem_bda);
203 }
204 }
205 else
206 {
207 ret = L2CA_DisconnectReq(p_tcb->att_lcid);
208 }
209 }
210 else
211 {
212 GATT_TRACE_DEBUG0 ("gatt_disconnect already in closing state");
213 }
214 }
215
216 return ret;
217}
218
219/*******************************************************************************
220**
221** Function gatt_update_app_hold_link_status
222**
223** Description Update the application use link status
224**
225** Returns void.
226**
227*******************************************************************************/
228void gatt_update_app_hold_link_status (tGATT_IF gatt_if, tGATT_TCB *p_tcb, BOOLEAN is_add)
229{
230 UINT8 i;
231 BOOLEAN found=FALSE;
232
233 if (p_tcb == NULL)
234 {
235 GATT_TRACE_ERROR0("gatt_update_app_hold_link_status p_tcb=NULL");
236 return;
237 }
238
239
240 for (i=0; i<GATT_MAX_APPS; i++)
241 {
242 if (p_tcb->app_hold_link[i] == gatt_if)
243 {
244 found = TRUE;
245 if (!is_add)
246 {
247 p_tcb->app_hold_link[i] = 0;
248 break;
249 }
250 }
251 }
252
253 if (!found && is_add)
254 {
255 for (i=0; i<GATT_MAX_APPS; i++)
256 {
257 if (p_tcb->app_hold_link[i] == 0)
258 {
259 p_tcb->app_hold_link[i] = gatt_if;
260 found = TRUE;
261 break;
262 }
263 }
264 }
265
266 GATT_TRACE_DEBUG4("gatt_update_app_hold_link_status found=%d[1-found] idx=%d gatt_if=%d is_add=%d", found, i, gatt_if, is_add);
267
268}
269
270/*******************************************************************************
271**
272** Function gatt_update_app_use_link_flag
273**
274** Description Update the application use link flag and optional to check the acl link
275** if the link is up then set the idle time out accordingly
276**
277** Returns void.
278**
279*******************************************************************************/
280void gatt_update_app_use_link_flag (tGATT_IF gatt_if, tGATT_TCB *p_tcb, BOOLEAN is_add, BOOLEAN check_acl_link)
281{
282 GATT_TRACE_DEBUG2("gatt_update_app_use_link_flag is_add=%d chk_link=%d",
283 is_add, check_acl_link);
284
285 gatt_update_app_hold_link_status(gatt_if, p_tcb, is_add);
286
287 if (check_acl_link &&
288 p_tcb &&
289 (BTM_GetHCIConnHandle(p_tcb->peer_bda) != GATT_INVALID_ACL_HANDLE))
290 {
291 if (is_add)
292 {
293 GATT_TRACE_DEBUG0("GATT disables link idle timer");
294 /* acl link is connected disable the idle timeout */
295 GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_NO_IDLE_TIMEOUT);
296 }
297 else
298 {
299 if (!gatt_num_apps_hold_link(p_tcb))
300 {
301 /* acl link is connected but no application needs to use the link
302 so set the timeout value to GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP seconds */
303 GATT_TRACE_DEBUG1("GATT starts link idle timer =%d sec", GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP);
304 GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP);
305 }
306
307 }
308 }
309}
310
311/*******************************************************************************
312**
313** Function gatt_act_connect
314**
315** Description GATT connection initiation.
316**
317** Returns void.
318**
319*******************************************************************************/
320BOOLEAN gatt_act_connect (tGATT_REG *p_reg, BD_ADDR bd_addr)
321{
322 BOOLEAN ret = FALSE;
323 tGATT_TCB *p_tcb;
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800324 UINT8 st;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800325
326 GATT_TRACE_DEBUG0("gatt_act_connect");
327
328 if ((p_tcb = gatt_find_tcb_by_addr(bd_addr)) != NULL)
329 {
330 ret = TRUE;
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800331 st = gatt_get_ch_state(p_tcb);
332
333 /* before link down, another app try to open a GATT connection */
Andre Eisenbach6975b4d2013-08-05 16:55:38 -0700334 if(st == GATT_CH_OPEN && gatt_num_apps_hold_link(p_tcb) == 0 &&
335 /* only connection on fix channel when the l2cap channel is already open */
336 p_tcb->att_lcid == L2CAP_ATT_CID )
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800337 {
338 if (!gatt_connect(bd_addr, p_tcb))
339 ret = FALSE;
340 }
341 else if(st == GATT_CH_CLOSING)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800342 {
343 /* need to complete the closing first */
344 ret = FALSE;
345 }
346 }
347 else
348 {
349 if ((p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr)) != NULL)
350 {
351 if (!gatt_connect(bd_addr, p_tcb))
352 {
353 GATT_TRACE_ERROR0("gatt_connect failed");
354 memset(p_tcb, 0, sizeof(tGATT_TCB));
355 }
356 else
357 ret = TRUE;
358 }
359 else
360 {
361 ret = 0;
362 GATT_TRACE_ERROR1("Max TCB for gatt_if [%d] reached.", p_reg->gatt_if);
363 }
364 }
365
366 if (ret)
367 {
368 gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, TRUE, FALSE);
369 }
370
371 return ret;
372}
373
374/*******************************************************************************
375**
376** Function gatt_le_connect_cback
377**
378** Description This callback function is called by L2CAP to indicate that
379** the ATT fixed channel for LE is
380** connected (conn = TRUE)/disconnected (conn = FALSE).
381**
382*******************************************************************************/
383static void gatt_le_connect_cback (BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason)
384{
385
386 tGATT_TCB *p_tcb = gatt_find_tcb_by_addr(bd_addr);
387
388 BOOLEAN check_srv_chg = FALSE;
389 tGATTS_SRV_CHG *p_srv_chg_clt=NULL;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800390
391 GATT_TRACE_DEBUG3 ("GATT ATT protocol channel with BDA: %08x%04x is %s",
392 (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3],
393 (bd_addr[4]<<8)+bd_addr[5], (connected) ? "connected" : "disconnected");
394
395
396 if ((p_srv_chg_clt = gatt_is_bda_in_the_srv_chg_clt_list(bd_addr)) != NULL)
397 {
398 check_srv_chg = TRUE;
399 }
400 else
401 {
402 if (btm_sec_is_a_bonded_dev(bd_addr))
403 gatt_add_a_bonded_dev_for_srv_chg(bd_addr);
404 }
405
406 if (connected)
407 {
408 GATT_TRACE_DEBUG1("connected is TRUE reason=%d",reason );
409 /* BR/EDR lik, ignore this callback */
410 if (reason == 0)
411 return;
412
413 /* do we have a channel initiating a connection? */
414 if (p_tcb)
415 {
416 if (check_srv_chg)
417 gatt_chk_srv_chg (p_srv_chg_clt);
418 /* we are initiating connection */
419 if ( gatt_get_ch_state(p_tcb) == GATT_CH_CONN)
420 {
421 /* send callback */
422 gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
423 p_tcb->payload_size = GATT_DEF_BLE_MTU_SIZE;
424
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800425 gatt_send_conn_cback(p_tcb);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800426 }
The Android Open Source Project5738f832012-12-12 16:00:35 -0800427 }
428 /* this is incoming connection or background connection callback */
429 else
430 {
431 if ((p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr)) != NULL)
432 {
433 p_tcb->att_lcid = L2CAP_ATT_CID;
434
435 gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
436
437 p_tcb->payload_size = GATT_DEF_BLE_MTU_SIZE;
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800438
439 gatt_send_conn_cback (p_tcb);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800440 if (check_srv_chg)
441 {
442 gatt_chk_srv_chg (p_srv_chg_clt);
443 }
444 }
445 else
446 {
447 GATT_TRACE_ERROR0("CCB max out, no rsources");
448 }
449 }
450 }
451 else
452 {
453 gatt_cleanup_upon_disc(bd_addr, reason);
454 GATT_TRACE_DEBUG0 ("ATT disconnected");
455 }
456}
457
458/*******************************************************************************
459**
460** Function gatt_le_data_ind
461**
462** Description This function is called when data is received from L2CAP.
463** if we are the originator of the connection, we are the ATT
464** client, and the received message is queued up for the client.
465**
466** If we are the destination of the connection, we are the ATT
467** server, so the message is passed to the server processing
468** function.
469**
470** Returns void
471**
472*******************************************************************************/
473static void gatt_le_data_ind (BD_ADDR bd_addr, BT_HDR *p_buf)
474{
475 tGATT_TCB *p_tcb;
476
477 /* Find CCB based on bd addr */
478 if ((p_tcb = gatt_find_tcb_by_addr (bd_addr)) != NULL &&
479 gatt_get_ch_state(p_tcb) >= GATT_CH_OPEN)
480 {
481 gatt_data_process(p_tcb, p_buf);
482 }
483 else
484 {
485 GKI_freebuf (p_buf);
486
487 if (p_tcb != NULL)
488 {
489 GATT_TRACE_WARNING1 ("ATT - Ignored L2CAP data while in state: %d",
490 gatt_get_ch_state(p_tcb));
491 }
492 }
493}
494
495/*******************************************************************************
496**
497** Function gatt_l2cif_connect_ind
498**
499** Description This function handles an inbound connection indication
500** from L2CAP. This is the case where we are acting as a
501** server.
502**
503** Returns void
504**
505*******************************************************************************/
506static void gatt_l2cif_connect_ind_cback (BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
507{
508 /* do we already have a control channel for this peer? */
509 UINT8 result = L2CAP_CONN_OK;
510 tL2CAP_CFG_INFO cfg;
511 tGATT_TCB *p_tcb = gatt_find_tcb_by_addr(bd_addr);
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800512 UNUSED(psm);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800513
514 GATT_TRACE_ERROR1("Connection indication cid = %d", lcid);
515 /* new connection ? */
516 if (p_tcb == NULL)
517 {
518 /* allocate tcb */
519 if ((p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr)) == NULL)
520 {
521 /* no tcb available, reject L2CAP connection */
522 result = L2CAP_CONN_NO_RESOURCES;
523 }
524 else
525 p_tcb->att_lcid = lcid;
526
527 }
528 else /* existing connection , reject it */
529 {
530 result = L2CAP_CONN_NO_RESOURCES;
531 }
532
533 /* Send L2CAP connect rsp */
534 L2CA_ConnectRsp(bd_addr, id, lcid, result, 0);
535
536 /* if result ok, proceed with connection */
537 if (result == L2CAP_CONN_OK)
538 {
539 /* transition to configuration state */
540 gatt_set_ch_state(p_tcb, GATT_CH_CFG);
541
542 /* Send L2CAP config req */
543 memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
544 cfg.mtu_present = TRUE;
545 cfg.mtu = GATT_MAX_MTU_SIZE;
546
547 L2CA_ConfigReq(lcid, &cfg);
548 }
549}
550
551/*******************************************************************************
552**
553** Function gatt_l2c_connect_cfm_cback
554**
555** Description This is the L2CAP connect confirm callback function.
556**
557**
558** Returns void
559**
560*******************************************************************************/
561void gatt_l2cif_connect_cfm_cback(UINT16 lcid, UINT16 result)
562{
563 tGATT_TCB *p_tcb;
564 tL2CAP_CFG_INFO cfg;
565
566 /* look up clcb for this channel */
567 if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL)
568 {
569 GATT_TRACE_DEBUG3("gatt_l2c_connect_cfm_cback result: %d ch_state: %d, lcid:0x%x", result, gatt_get_ch_state(p_tcb), p_tcb->att_lcid);
570
571 /* if in correct state */
572 if (gatt_get_ch_state(p_tcb) == GATT_CH_CONN)
573 {
574 /* if result successful */
575 if (result == L2CAP_CONN_OK)
576 {
577 /* set channel state */
578 gatt_set_ch_state(p_tcb, GATT_CH_CFG);
579
580 /* Send L2CAP config req */
581 memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
582 cfg.mtu_present = TRUE;
583 cfg.mtu = GATT_MAX_MTU_SIZE;
584 L2CA_ConfigReq(lcid, &cfg);
585 }
586 /* else initiating connection failure */
587 else
588 {
Andre Eisenbach6975b4d2013-08-05 16:55:38 -0700589 gatt_cleanup_upon_disc(p_tcb->peer_bda, GATT_CONN_L2C_FAILURE);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800590 }
591 }
592 else /* wrong state, disconnect it */
593 {
594 if (result == L2CAP_CONN_OK)
595 {
596 /* just in case the peer also accepts our connection - Send L2CAP disconnect req */
597 L2CA_DisconnectReq(lcid);
598 }
599 }
600 }
601}
602
603/*******************************************************************************
604**
605** Function gatt_l2cif_config_cfm_cback
606**
607** Description This is the L2CAP config confirm callback function.
608**
609**
610** Returns void
611**
612*******************************************************************************/
613void gatt_l2cif_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
614{
615 tGATT_TCB *p_tcb;
616 tGATTS_SRV_CHG *p_srv_chg_clt=NULL;
617
618 /* look up clcb for this channel */
619 if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL)
620 {
621 /* if in correct state */
622 if ( gatt_get_ch_state(p_tcb) == GATT_CH_CFG)
623 {
624 /* if result successful */
625 if (p_cfg->result == L2CAP_CFG_OK)
626 {
627 /* update flags */
628 p_tcb->ch_flags |= GATT_L2C_CFG_CFM_DONE;
629
630 /* if configuration complete */
631 if (p_tcb->ch_flags & GATT_L2C_CFG_IND_DONE)
632 {
633 gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
634
635 if ((p_srv_chg_clt = gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda)) != NULL)
636 {
637 gatt_chk_srv_chg(p_srv_chg_clt);
638 }
639 else
640 {
Andre Eisenbach6975b4d2013-08-05 16:55:38 -0700641 if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda))
The Android Open Source Project5738f832012-12-12 16:00:35 -0800642 gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
643 }
644
645 /* send callback */
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800646 gatt_send_conn_cback(p_tcb);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800647 }
648 }
649 /* else failure */
650 else
651 {
652 /* Send L2CAP disconnect req */
653 L2CA_DisconnectReq(lcid);
654 }
655 }
656 }
657}
658
659/*******************************************************************************
660**
661** Function gatt_l2cif_config_ind_cback
662**
663** Description This is the L2CAP config indication callback function.
664**
665**
666** Returns void
667**
668*******************************************************************************/
669void gatt_l2cif_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
670{
671 tGATT_TCB *p_tcb;
672 tGATTS_SRV_CHG *p_srv_chg_clt=NULL;
673 /* look up clcb for this channel */
674 if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL)
675 {
676 /* GATT uses the smaller of our MTU and peer's MTU */
Andre Eisenbach6975b4d2013-08-05 16:55:38 -0700677 if ( p_cfg->mtu_present &&
678 (p_cfg->mtu >= GATT_MIN_BR_MTU_SIZE && p_cfg->mtu < L2CAP_DEFAULT_MTU))
The Android Open Source Project5738f832012-12-12 16:00:35 -0800679 p_tcb->payload_size = p_cfg->mtu;
680 else
681 p_tcb->payload_size = L2CAP_DEFAULT_MTU;
682
683 /* send L2CAP configure response */
684 memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
685 p_cfg->result = L2CAP_CFG_OK;
686 L2CA_ConfigRsp(lcid, p_cfg);
687
688 /* if first config ind */
689 if ((p_tcb->ch_flags & GATT_L2C_CFG_IND_DONE) == 0)
690 {
691 /* update flags */
692 p_tcb->ch_flags |= GATT_L2C_CFG_IND_DONE;
693
694 /* if configuration complete */
695 if (p_tcb->ch_flags & GATT_L2C_CFG_CFM_DONE)
696 {
697 gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
698 if ((p_srv_chg_clt = gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda)) != NULL)
699 {
700 gatt_chk_srv_chg(p_srv_chg_clt);
701 }
702 else
703 {
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800704 if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda) &&
705 btm_sec_is_le_capable_dev(p_tcb->peer_bda))
706 {
The Android Open Source Project5738f832012-12-12 16:00:35 -0800707 gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800708 }
The Android Open Source Project5738f832012-12-12 16:00:35 -0800709 }
710
711 /* send callback */
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800712 gatt_send_conn_cback(p_tcb);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800713 }
714 }
715 }
716}
717
718/*******************************************************************************
719**
720** Function gatt_l2cif_disconnect_ind_cback
721**
722** Description This is the L2CAP disconnect indication callback function.
723**
724**
725** Returns void
726**
727*******************************************************************************/
728void gatt_l2cif_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
729{
730 tGATT_TCB *p_tcb;
731 UINT16 reason;
732
733 /* look up clcb for this channel */
734 if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL)
735 {
736 if (ack_needed)
737 {
738 /* send L2CAP disconnect response */
739 L2CA_DisconnectRsp(lcid);
740 }
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800741
Andre Eisenbach0d3786e2013-07-22 17:42:18 -0700742 if (gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda) == NULL)
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800743 {
Andre Eisenbach0d3786e2013-07-22 17:42:18 -0700744 if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda) &&
745 btm_sec_is_le_capable_dev(p_tcb->peer_bda))
746 gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800747 }
748
The Android Open Source Project5738f832012-12-12 16:00:35 -0800749 /* if ACL link is still up, no reason is logged, l2cap is disconnect from peer */
750 if ((reason = L2CA_GetDisconnectReason(p_tcb->peer_bda)) == 0)
751 reason = GATT_CONN_TERMINATE_PEER_USER;
752
753 /* send disconnect callback */
754 gatt_cleanup_upon_disc(p_tcb->peer_bda, reason);
755 }
756}
757
758/*******************************************************************************
759**
760** Function gatt_l2cif_disconnect_cfm_cback
761**
762** Description This is the L2CAP disconnect confirm callback function.
763**
764**
765** Returns void
766**
767*******************************************************************************/
768void gatt_l2cif_disconnect_cfm_cback(UINT16 lcid, UINT16 result)
769{
770 tGATT_TCB *p_tcb;
771 UINT16 reason;
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800772 UNUSED(result);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800773
774 /* look up clcb for this channel */
775 if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL)
776 {
Andre Eisenbach0d3786e2013-07-22 17:42:18 -0700777 /* If the device is not in the service changed client list, add it... */
778 if (gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda) == NULL)
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800779 {
Andre Eisenbach0d3786e2013-07-22 17:42:18 -0700780 if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda) &&
781 btm_sec_is_le_capable_dev(p_tcb->peer_bda))
782 gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800783 }
784
The Android Open Source Project5738f832012-12-12 16:00:35 -0800785 /* send disconnect callback */
786 /* if ACL link is still up, no reason is logged, l2cap is disconnect from peer */
787 if ((reason = L2CA_GetDisconnectReason(p_tcb->peer_bda)) == 0)
788 reason = GATT_CONN_TERMINATE_LOCAL_HOST;
789
790 gatt_cleanup_upon_disc(p_tcb->peer_bda, reason);
791 }
792}
793
794/*******************************************************************************
795**
796** Function gatt_l2cif_data_ind_cback
797**
798** Description This is the L2CAP data indication callback function.
799**
800**
801** Returns void
802**
803*******************************************************************************/
804void gatt_l2cif_data_ind_cback(UINT16 lcid, BT_HDR *p_buf)
805{
806 tGATT_TCB *p_tcb;
807
808 /* look up clcb for this channel */
809 if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL &&
810 gatt_get_ch_state(p_tcb) == GATT_CH_OPEN)
811 {
812 /* process the data */
813 gatt_data_process(p_tcb, p_buf);
814 }
815 else /* prevent buffer leak */
816 GKI_freebuf(p_buf);
817}
818
819/*******************************************************************************
820**
821** Function gatt_send_conn_cback
822**
823** Description Callback used to notify layer above about a connection.
824**
825**
826** Returns void
827**
828*******************************************************************************/
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800829static void gatt_send_conn_cback(tGATT_TCB *p_tcb)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800830{
831 UINT8 i;
832 tGATT_REG *p_reg;
833 tGATT_BG_CONN_DEV *p_bg_dev=NULL;
834 UINT16 conn_id;
835
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800836 p_bg_dev = gatt_find_bg_dev(p_tcb->peer_bda);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800837
838 /* notifying all applications for the connection up event */
839 for (i = 0, p_reg = gatt_cb.cl_rcb ; i < GATT_MAX_APPS; i++, p_reg++)
840 {
841 if (p_reg->in_use)
842 {
843 if (p_bg_dev && gatt_is_bg_dev_for_app(p_bg_dev, p_reg->gatt_if))
844 gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, TRUE, TRUE);
845
846 if (p_reg->app_cb.p_conn_cb)
847 {
848 conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if);
849 (*p_reg->app_cb.p_conn_cb)(p_reg->gatt_if, p_tcb->peer_bda, conn_id, TRUE, 0);
850 }
851 }
852 }
853
854
855 if (gatt_num_apps_hold_link(p_tcb))
856 {
857 /* disable idle timeout if one or more clients are holding the link disable the idle timer */
858 GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_NO_IDLE_TIMEOUT);
859 }
860}
861
862/*******************************************************************************
863**
864** Function gatt_le_data_ind
865**
866** Description This function is called when data is received from L2CAP.
867** if we are the originator of the connection, we are the ATT
868** client, and the received message is queued up for the client.
869**
870** If we are the destination of the connection, we are the ATT
871** server, so the message is passed to the server processing
872** function.
873**
874** Returns void
875**
876*******************************************************************************/
877void gatt_data_process (tGATT_TCB *p_tcb, BT_HDR *p_buf)
878{
879 UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset;
880 UINT8 op_code, pseudo_op_code;
881 UINT16 msg_len;
882
883
884 if (p_buf->len > 0)
885 {
886 msg_len = p_buf->len - 1;
887 STREAM_TO_UINT8(op_code, p);
888
889 /* remove the two MSBs associated with sign write and write cmd */
890 pseudo_op_code = op_code & (~GATT_WRITE_CMD_MASK);
891
892 if (pseudo_op_code < GATT_OP_CODE_MAX)
893 {
894 if (op_code == GATT_SIGN_CMD_WRITE)
895 {
896 gatt_verify_signature(p_tcb, p_buf);
897 return;
898 }
899 else
900 {
901 /* message from client */
902 if ((op_code % 2) == 0)
903 gatt_server_handle_client_req (p_tcb, op_code, msg_len, p);
904 else
905 gatt_client_handle_server_rsp (p_tcb, op_code, msg_len, p);
906 }
907 }
908 else
909 {
910 GATT_TRACE_ERROR1 ("ATT - Rcvd L2CAP data, unknown cmd: 0x%x", op_code);
911 }
912 }
913 else
914 {
915 GATT_TRACE_ERROR0 ("invalid data length, ignore");
916 }
917
918 GKI_freebuf (p_buf);
919}
920
921/*******************************************************************************
922**
923** Function gatt_add_a_bonded_dev_for_srv_chg
924**
925** Description Add a bonded dev to the service changed client list
926**
927** Returns void
928**
929*******************************************************************************/
930void gatt_add_a_bonded_dev_for_srv_chg (BD_ADDR bda)
931{
932 tGATTS_SRV_CHG *p_buf;
933 tGATTS_SRV_CHG_REQ req;
934 tGATTS_SRV_CHG srv_chg_clt;
935
936 memcpy(srv_chg_clt.bda, bda, BD_ADDR_LEN);
937 srv_chg_clt.srv_changed = FALSE;
938 if ((p_buf = gatt_add_srv_chg_clt(&srv_chg_clt)) != NULL)
939 {
940 memcpy(req.srv_chg.bda, bda, BD_ADDR_LEN);
941 req.srv_chg.srv_changed = FALSE;
942 if (gatt_cb.cb_info.p_srv_chg_callback)
943 (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_ADD_CLIENT, &req, NULL);
944 }
945
946}
947
948/*******************************************************************************
949**
950** Function gatt_send_srv_chg_ind
951**
952** Description This function is called to send a service chnaged indication to
953** the specified bd address
954**
955** Returns void
956**
957*******************************************************************************/
958void gatt_send_srv_chg_ind (BD_ADDR peer_bda)
959{
960 UINT8 handle_range[GATT_SIZE_OF_SRV_CHG_HNDL_RANGE];
961 UINT8 *p = handle_range;
962 UINT16 conn_id;
963
964 GATT_TRACE_DEBUG0("gatt_send_srv_chg_ind");
965
966 if (gatt_cb.handle_of_h_r)
967 {
968 if ((conn_id = gatt_profile_find_conn_id_by_bd_addr(peer_bda)) != GATT_INVALID_CONN_ID)
969 {
970 UINT16_TO_STREAM (p, 1);
971 UINT16_TO_STREAM (p, 0xFFFF);
972 GATTS_HandleValueIndication (conn_id,
973 gatt_cb.handle_of_h_r,
974 GATT_SIZE_OF_SRV_CHG_HNDL_RANGE,
975 handle_range);
976 }
977 else
978 {
979 GATT_TRACE_ERROR2("Unable to find conn_id for %08x%04x ",
980 (peer_bda[0]<<24)+(peer_bda[1]<<16)+(peer_bda[2]<<8)+peer_bda[3],
981 (peer_bda[4]<<8)+peer_bda[5] );
982 }
983 }
984}
985
986/*******************************************************************************
987**
988** Function gatt_chk_srv_chg
989**
990** Description Check sending service chnaged Indication is required or not
991** if required then send the Indication
992**
993** Returns void
994**
995*******************************************************************************/
996void gatt_chk_srv_chg(tGATTS_SRV_CHG *p_srv_chg_clt)
997{
998 GATT_TRACE_DEBUG1("gatt_chk_srv_chg srv_changed=%d", p_srv_chg_clt->srv_changed );
999
1000 if (p_srv_chg_clt->srv_changed)
1001 {
1002 gatt_send_srv_chg_ind(p_srv_chg_clt->bda);
1003 }
The Android Open Source Project5738f832012-12-12 16:00:35 -08001004}
1005
1006/*******************************************************************************
1007**
1008** Function gatt_init_srv_chg
1009**
1010** Description This function is used to initialize the service changed
1011** attribute value
1012**
1013** Returns void
1014**
1015*******************************************************************************/
1016void gatt_init_srv_chg (void)
1017{
1018 tGATTS_SRV_CHG_REQ req;
1019 tGATTS_SRV_CHG_RSP rsp;
1020 BOOLEAN status;
1021 UINT8 num_clients,i;
1022 tGATTS_SRV_CHG srv_chg_clt;
1023
1024 GATT_TRACE_DEBUG0("gatt_init_srv_chg");
1025 if (gatt_cb.cb_info.p_srv_chg_callback)
1026 {
1027 status = (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_READ_NUM_CLENTS, NULL, &rsp);
1028
1029 if (status && rsp.num_clients)
1030 {
1031 GATT_TRACE_DEBUG1("gatt_init_srv_chg num_srv_chg_clt_clients=%d", rsp.num_clients);
1032 num_clients = rsp.num_clients;
1033 i = 1; /* use one based index */
1034 while ((i <= num_clients) && status)
1035 {
1036 req.client_read_index = i;
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -08001037 if ((status = (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_READ_CLENT, &req, &rsp)) == TRUE)
The Android Open Source Project5738f832012-12-12 16:00:35 -08001038 {
1039 memcpy(&srv_chg_clt, &rsp.srv_chg ,sizeof(tGATTS_SRV_CHG));
1040 if (gatt_add_srv_chg_clt(&srv_chg_clt) == NULL)
1041 {
1042 GATT_TRACE_ERROR0("Unable to add a service change client");
1043 status = FALSE;
1044 }
1045 }
1046 i++;
1047 }
1048 }
1049 }
1050 else
1051 {
1052 GATT_TRACE_DEBUG0("gatt_init_srv_chg callback not registered yet");
1053 }
1054}
1055
1056/*******************************************************************************
1057**
1058** Function gatt_proc_srv_chg
1059**
1060** Description This function is process the service changed request
1061**
1062** Returns void
1063**
1064*******************************************************************************/
1065void gatt_proc_srv_chg (void)
1066{
1067 UINT8 start_idx, found_idx;
1068 BD_ADDR bda;
1069 BOOLEAN srv_chg_ind_pending=FALSE;
1070 tGATT_TCB *p_tcb;
1071
1072 GATT_TRACE_DEBUG0 ("gatt_proc_srv_chg");
1073
1074 if (gatt_cb.cb_info.p_srv_chg_callback && gatt_cb.handle_of_h_r)
1075 {
1076 gatt_set_srv_chg();
1077 start_idx =0;
1078 while (gatt_find_the_connected_bda(start_idx, bda, &found_idx))
1079 {
1080 p_tcb = &gatt_cb.tcb[found_idx];;
1081 srv_chg_ind_pending = gatt_is_srv_chg_ind_pending(p_tcb);
1082
1083 if (!srv_chg_ind_pending)
1084 {
1085 gatt_send_srv_chg_ind(bda);
1086 }
1087 else
1088 {
1089 GATT_TRACE_DEBUG0 ("discard srv chg - already has one in the queue");
1090 }
1091 start_idx = ++found_idx;
1092 }
1093 }
1094}
1095
1096/*******************************************************************************
1097**
1098** Function gatt_set_ch_state
1099**
1100** Description This function set the ch_state in tcb
1101**
1102** Returns none
1103**
1104*******************************************************************************/
1105void gatt_set_ch_state(tGATT_TCB *p_tcb, tGATT_CH_STATE ch_state)
1106{
1107 if (p_tcb)
1108 {
1109 GATT_TRACE_DEBUG2 ("gatt_set_ch_state: old=%d new=%d", p_tcb->ch_state, ch_state);
1110 p_tcb->ch_state = ch_state;
1111 }
1112}
1113
1114/*******************************************************************************
1115**
1116** Function gatt_get_ch_state
1117**
1118** Description This function get the ch_state in tcb
1119**
1120** Returns none
1121**
1122*******************************************************************************/
1123tGATT_CH_STATE gatt_get_ch_state(tGATT_TCB *p_tcb)
1124{
1125 tGATT_CH_STATE ch_state = GATT_CH_CLOSE;
1126 if (p_tcb)
1127 {
1128 GATT_TRACE_DEBUG1 ("gatt_get_ch_state: ch_state=%d", p_tcb->ch_state);
1129 ch_state = p_tcb->ch_state;
1130 }
1131 return ch_state;
1132}
1133
1134#endif /* BLE_INCLUDED */