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