/******************************************************************************* ** ** Function gatt_act_connect ** ** Description GATT connection initiation. ** ** Returns void. ** *******************************************************************************/ BOOLEAN gatt_act_connect (tGATT_REG *p_reg, BD_ADDR bd_addr) { BOOLEAN ret = FALSE; tGATT_TCB *p_tcb; UINT8 st; GATT_TRACE_DEBUG0("gatt_act_connect"); if ((p_tcb = gatt_find_tcb_by_addr(bd_addr)) != NULL) { ret = TRUE; st = gatt_get_ch_state(p_tcb); /* before link down, another app try to open a GATT connection */ if(st == GATT_CH_OPEN && gatt_num_apps_hold_link(p_tcb) == 0 && /* only connection on fix channel when the l2cap channel is already open */ p_tcb->att_lcid == L2CAP_ATT_CID ) { if (!gatt_connect(bd_addr, p_tcb)) ret = FALSE; } else if(st == GATT_CH_CLOSING) { /* need to complete the closing first */ ret = FALSE; } } else { if ((p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr)) != NULL) { if (!gatt_connect(bd_addr, p_tcb)) { GATT_TRACE_ERROR0("gatt_connect failed"); memset(p_tcb, 0, sizeof(tGATT_TCB)); } else ret = TRUE; } else { ret = 0; GATT_TRACE_ERROR1("Max TCB for gatt_if [%d] reached.", p_reg->gatt_if); } } if (ret) { gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, TRUE, FALSE); } return ret; }
/******************************************************************************* ** ** Function gatt_act_connect ** ** Description GATT connection initiation. ** ** Returns void. ** *******************************************************************************/ BOOLEAN gatt_act_connect (tGATT_REG *p_reg, BD_ADDR bd_addr, tBT_TRANSPORT transport) { BOOLEAN ret = FALSE; tGATT_TCB *p_tcb; UINT8 st; if ((p_tcb = gatt_find_tcb_by_addr(bd_addr, transport)) != NULL) { ret = TRUE; st = gatt_get_ch_state(p_tcb); /* before link down, another app try to open a GATT connection */ if(st == GATT_CH_OPEN && gatt_num_apps_hold_link(p_tcb) == 0 && transport == BT_TRANSPORT_LE ) { if (!gatt_connect(bd_addr, p_tcb, transport)) ret = FALSE; } else if(st == GATT_CH_CLOSING) { /* need to complete the closing first */ ret = FALSE; } } else { if ((p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr, transport)) != NULL) { if (!gatt_connect(bd_addr, p_tcb, transport)) { GATT_TRACE_ERROR("gatt_connect failed"); memset(p_tcb, 0, sizeof(tGATT_TCB)); } else ret = TRUE; } else { ret = 0; GATT_TRACE_ERROR("Max TCB for gatt_if [%d] reached.", p_reg->gatt_if); } } if (ret) { gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, TRUE, FALSE); } return ret; }
/******************************************************************************* ** ** Function gatt_l2cif_connect_ind ** ** Description This function handles an inbound connection indication ** from L2CAP. This is the case where we are acting as a ** server. ** ** Returns void ** *******************************************************************************/ static void gatt_l2cif_connect_ind_cback (BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id) { /* do we already have a control channel for this peer? */ UINT8 result = L2CAP_CONN_OK; tL2CAP_CFG_INFO cfg; tGATT_TCB *p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_BR_EDR); UNUSED(psm); GATT_TRACE_ERROR("Connection indication cid = %d", lcid); /* new connection ? */ if (p_tcb == NULL) { /* allocate tcb */ if ((p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr, BT_TRANSPORT_BR_EDR)) == NULL) { /* no tcb available, reject L2CAP connection */ result = L2CAP_CONN_NO_RESOURCES; } else p_tcb->att_lcid = lcid; } else /* existing connection , reject it */ { result = L2CAP_CONN_NO_RESOURCES; } /* Send L2CAP connect rsp */ L2CA_ConnectRsp(bd_addr, id, lcid, result, 0); /* if result ok, proceed with connection */ if (result == L2CAP_CONN_OK) { /* transition to configuration state */ gatt_set_ch_state(p_tcb, GATT_CH_CFG); /* Send L2CAP config req */ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO)); cfg.mtu_present = TRUE; cfg.mtu = GATT_MAX_MTU_SIZE; L2CA_ConfigReq(lcid, &cfg); } }
/******************************************************************************* ** ** Function gatt_act_connect ** ** Description GATT connection initiation. ** ** Returns void. ** *******************************************************************************/ BOOLEAN gatt_act_connect (tGATT_REG *p_reg, BD_ADDR bd_addr) { BOOLEAN ret = FALSE; tGATT_TCB *p_tcb; GATT_TRACE_DEBUG0("gatt_act_connect"); if ((p_tcb = gatt_find_tcb_by_addr(bd_addr)) != NULL) { ret = TRUE; if(gatt_get_ch_state(p_tcb) == GATT_CH_CLOSING ) { /* need to complete the closing first */ ret = FALSE; } } else { if ((p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr)) != NULL) { if (!gatt_connect(bd_addr, p_tcb)) { GATT_TRACE_ERROR0("gatt_connect failed"); memset(p_tcb, 0, sizeof(tGATT_TCB)); } else ret = TRUE; } else { ret = 0; GATT_TRACE_ERROR1("Max TCB for gatt_if [%d] reached.", p_reg->gatt_if); } } if (ret) { gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, TRUE, FALSE); } return ret; }
/******************************************************************************* ** ** Function gatt_le_connect_cback ** ** Description This callback function is called by L2CAP to indicate that ** the ATT fixed channel for LE is ** connected (conn = TRUE)/disconnected (conn = FALSE). ** *******************************************************************************/ static void gatt_le_connect_cback (BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason, tBT_TRANSPORT transport) { tGATT_TCB *p_tcb = gatt_find_tcb_by_addr(bd_addr, transport); BOOLEAN check_srv_chg = FALSE; tGATTS_SRV_CHG *p_srv_chg_clt=NULL; /* ignore all fixed channel connect/disconnect on BR/EDR link for GATT */ if (transport == BT_TRANSPORT_BR_EDR) return; GATT_TRACE_DEBUG ("GATT ATT protocol channel with BDA: %08x%04x is %s", (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3], (bd_addr[4]<<8)+bd_addr[5], (connected) ? "connected" : "disconnected"); if ((p_srv_chg_clt = gatt_is_bda_in_the_srv_chg_clt_list(bd_addr)) != NULL) { check_srv_chg = TRUE; } else { if (btm_sec_is_a_bonded_dev(bd_addr)) gatt_add_a_bonded_dev_for_srv_chg(bd_addr); } if (connected) { /* do we have a channel initiating a connection? */ if (p_tcb) { /* we are initiating connection */ if ( gatt_get_ch_state(p_tcb) == GATT_CH_CONN) { /* send callback */ gatt_set_ch_state(p_tcb, GATT_CH_OPEN); p_tcb->payload_size = GATT_DEF_BLE_MTU_SIZE; gatt_send_conn_cback(p_tcb); } if (check_srv_chg) gatt_chk_srv_chg (p_srv_chg_clt); } /* this is incoming connection or background connection callback */ else { if ((p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr, BT_TRANSPORT_LE)) != NULL) { p_tcb->att_lcid = L2CAP_ATT_CID; gatt_set_ch_state(p_tcb, GATT_CH_OPEN); p_tcb->payload_size = GATT_DEF_BLE_MTU_SIZE; gatt_send_conn_cback (p_tcb); if (check_srv_chg) { gatt_chk_srv_chg (p_srv_chg_clt); } } else { GATT_TRACE_ERROR("CCB max out, no rsources"); } } } else { gatt_cleanup_upon_disc(bd_addr, reason, transport); GATT_TRACE_DEBUG ("ATT disconnected"); } }
/******************************************************************************* ** ** Function gatt_le_connect_cback ** ** Description This callback function is called by L2CAP to indicate that ** the ATT fixed channel for LE is ** connected (conn = TRUE)/disconnected (conn = FALSE). ** *******************************************************************************/ static void gatt_le_connect_cback (BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason) { tGATT_TCB *p_tcb = gatt_find_tcb_by_addr(bd_addr); BOOLEAN check_srv_chg = FALSE; tGATTS_SRV_CHG *p_srv_chg_clt=NULL; BOOLEAN is_bg_conn = FALSE; GATT_TRACE_DEBUG3 ("GATT ATT protocol channel with BDA: %08x%04x is %s", (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3], (bd_addr[4]<<8)+bd_addr[5], (connected) ? "connected" : "disconnected"); if ((p_srv_chg_clt = gatt_is_bda_in_the_srv_chg_clt_list(bd_addr)) != NULL) { check_srv_chg = TRUE; } else { if (btm_sec_is_a_bonded_dev(bd_addr)) gatt_add_a_bonded_dev_for_srv_chg(bd_addr); } if (connected) { GATT_TRACE_DEBUG1("connected is TRUE reason=%d",reason ); /* BR/EDR lik, ignore this callback */ if (reason == 0) return; /* do we have a channel initiating a connection? */ if (p_tcb) { if (check_srv_chg) gatt_chk_srv_chg (p_srv_chg_clt); /* we are initiating connection */ if ( gatt_get_ch_state(p_tcb) == GATT_CH_CONN) { /* send callback */ gatt_set_ch_state(p_tcb, GATT_CH_OPEN); p_tcb->payload_size = GATT_DEF_BLE_MTU_SIZE; gatt_send_conn_cback(FALSE, p_tcb); } else /* there was an exisiting link, ignore the callback */ { GATT_TRACE_ERROR0("connection already up, ignore it"); return; } } /* this is incoming connection or background connection callback */ else { if ((p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr)) != NULL) { p_tcb->att_lcid = L2CAP_ATT_CID; gatt_set_ch_state(p_tcb, GATT_CH_OPEN); p_tcb->payload_size = GATT_DEF_BLE_MTU_SIZE; if (L2CA_GetBleConnRole(p_tcb->peer_bda)== HCI_ROLE_MASTER) { is_bg_conn = TRUE; } gatt_send_conn_cback (is_bg_conn, p_tcb); if (check_srv_chg) { gatt_chk_srv_chg (p_srv_chg_clt); } } else { GATT_TRACE_ERROR0("CCB max out, no rsources"); } } } else { gatt_cleanup_upon_disc(bd_addr, reason); GATT_TRACE_DEBUG0 ("ATT disconnected"); } }