/******************************************************************************* ** ** Function gatt_proc_srv_chg ** ** Description This function is process the service changed request ** ** Returns void ** *******************************************************************************/ void gatt_proc_srv_chg (void) { UINT8 start_idx, found_idx; BD_ADDR bda; BOOLEAN srv_chg_ind_pending=FALSE; tGATT_TCB *p_tcb; GATT_TRACE_DEBUG0 ("gatt_proc_srv_chg"); if (gatt_cb.cb_info.p_srv_chg_callback && gatt_cb.handle_of_h_r) { gatt_set_srv_chg(); start_idx =0; while (gatt_find_the_connected_bda(start_idx, bda, &found_idx)) { p_tcb = &gatt_cb.tcb[found_idx];; srv_chg_ind_pending = gatt_is_srv_chg_ind_pending(p_tcb); if (!srv_chg_ind_pending) { gatt_send_srv_chg_ind(bda); } else { GATT_TRACE_DEBUG0 ("discard srv chg - already has one in the queue"); } start_idx = ++found_idx; } } }
/******************************************************************************* ** ** Function gatt_le_data_ind ** ** Description This function is called when data is received from L2CAP. ** if we are the originator of the connection, we are the ATT ** client, and the received message is queued up for the client. ** ** If we are the destination of the connection, we are the ATT ** server, so the message is passed to the server processing ** function. ** ** Returns void ** *******************************************************************************/ void gatt_data_process (tGATT_TCB *p_tcb, BT_HDR *p_buf) { GATT_TRACE_DEBUG0("gatt_data_process"); UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset; UINT8 op_code, pseudo_op_code; UINT16 msg_len; if (p_buf->len > 0) { msg_len = p_buf->len - 1; STREAM_TO_UINT8(op_code, p); GATT_TRACE_DEBUG1("op_code = %d", op_code); /* remove the two MSBs associated with sign write and write cmd */ pseudo_op_code = op_code & (~GATT_WRITE_CMD_MASK); if (pseudo_op_code < GATT_OP_CODE_MAX) { if (op_code == GATT_SIGN_CMD_WRITE) { GATT_TRACE_DEBUG0("op_code == GATT_SIGN_CMD_WRITE"); gatt_verify_signature(p_tcb, p_buf); return; } else { /* message from client */ if ((op_code % 2) == 0) { GATT_TRACE_DEBUG0("gatt_server_handle_client_req"); gatt_server_handle_client_req (p_tcb, op_code, msg_len, p); } else { GATT_TRACE_DEBUG0("gatt_client_handle_server_rsp"); gatt_client_handle_server_rsp (p_tcb, op_code, msg_len, p); } } } else { GATT_TRACE_ERROR1 ("ATT - Rcvd L2CAP data, unknown cmd: 0x%x", op_code); } } else { GATT_TRACE_ERROR0 ("invalid data length, ignore"); } GKI_freebuf (p_buf); }
/******************************************************************************* ** ** Function gatt_process_find_type_value_rsp ** ** Description This function is called to handle find by type value response. ** ** ** Returns void ** *******************************************************************************/ void gatt_process_find_type_value_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT16 len, UINT8 *p_data) { tGATT_DISC_RES result; UINT8 *p = p_data; GATT_TRACE_DEBUG0("gatt_process_find_type_value_rsp "); /* unexpected response */ if (p_clcb->operation != GATTC_OPTYPE_DISCOVERY || p_clcb->op_subtype != GATT_DISC_SRVC_BY_UUID) return; memset (&result, 0, sizeof(tGATT_DISC_RES)); result.type.len = 2; result.type.uu.uuid16 = GATT_UUID_PRI_SERVICE; /* returns a series of handle ranges */ while (len >= 4) { STREAM_TO_UINT16 (result.handle, p); STREAM_TO_UINT16 (result.value.group_value.e_handle, p); memcpy (&result.value.group_value.service_type, &p_clcb->uuid, sizeof(tBT_UUID)); len -= 4; if (p_clcb->p_reg->app_cb.p_disc_res_cb) (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &result); } /* last handle + 1 */ p_clcb->s_handle = (result.value.group_value.e_handle == 0) ? 0 : (result.value.group_value.e_handle + 1); /* initiate another request */ gatt_act_discovery(p_clcb) ; }
/******************************************************************************* ** ** Function gatt_check_write_long_terminate ** ** Description To terminate write long or not. ** ** Returns TRUE: write long is terminated; FALSE keep sending. ** *******************************************************************************/ BOOLEAN gatt_check_write_long_terminate(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, tGATT_VALUE *p_rsp_value) { tGATT_VALUE *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf; BOOLEAN exec = FALSE; tGATT_EXEC_FLAG flag = GATT_PREP_WRITE_EXEC; GATT_TRACE_DEBUG0("gatt_check_write_long_terminate "); /* check the first write response status */ if (p_rsp_value != NULL) { if (p_rsp_value->handle != p_attr->handle || p_rsp_value->len != p_clcb->counter || memcmp(p_rsp_value->value, p_attr->value + p_attr->offset, p_rsp_value->len)) { /* data does not match */ p_clcb->status = GATT_ERROR; flag = GATT_PREP_WRITE_CANCEL; exec = TRUE; } else /* response checking is good */ { p_clcb->status = GATT_SUCCESS; /* update write offset and check if end of attribute value */ if ((p_attr->offset += p_rsp_value->len) >= p_attr->len) exec = TRUE; } } if (exec) { gatt_send_queue_write_cancel (p_tcb, p_clcb, flag); return TRUE; } return FALSE; }
/******************************************************************************* ** ** Function gatt_update_app_use_link_flag ** ** Description Update the application use link flag and optional to check the acl link ** if the link is up then set the idle time out accordingly ** ** Returns void. ** *******************************************************************************/ void gatt_update_app_use_link_flag (tGATT_IF gatt_if, tGATT_TCB *p_tcb, BOOLEAN is_add, BOOLEAN check_acl_link) { GATT_TRACE_DEBUG2("gatt_update_app_use_link_flag is_add=%d chk_link=%d", is_add, check_acl_link); gatt_update_app_hold_link_status(gatt_if, p_tcb, is_add); if (check_acl_link && p_tcb && (BTM_GetHCIConnHandle(p_tcb->peer_bda) != GATT_INVALID_ACL_HANDLE)) { if (is_add) { GATT_TRACE_DEBUG0("GATT disables link idle timer"); /* acl link is connected disable the idle timeout */ GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_NO_IDLE_TIMEOUT); } else { if (!gatt_num_apps_hold_link(p_tcb)) { /* acl link is connected but no application needs to use the link so set the timeout value to GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP seconds */ GATT_TRACE_DEBUG1("GATT starts link idle timer =%d sec", GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP); GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP); } } } }
/******************************************************************************* ** ** Function gatt_proc_disc_error_rsp ** ** Description This function process the read by type response and send another ** request if needed. ** ** Returns void. ** *******************************************************************************/ void gatt_proc_disc_error_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 opcode, UINT16 handle, UINT8 reason) { tGATT_STATUS status = (tGATT_STATUS) reason; GATT_TRACE_DEBUG2("gatt_proc_disc_error_rsp reason: %02x cmd_code %04x", reason, opcode); switch (opcode) { case GATT_REQ_READ_BY_GRP_TYPE: case GATT_REQ_FIND_TYPE_VALUE: case GATT_REQ_READ_BY_TYPE: case GATT_REQ_FIND_INFO: if (reason == GATT_NOT_FOUND) { status = GATT_SUCCESS; GATT_TRACE_DEBUG0("Discovery completed"); } break; default: GATT_TRACE_ERROR1("Incorrect discovery opcode %04x", opcode); break; } gatt_end_operation(p_clcb, status, NULL); }
/******************************************************************************* ** ** Function gatt_send_srv_chg_ind ** ** Description This function is called to send a service chnaged indication to ** the specified bd address ** ** Returns void ** *******************************************************************************/ void gatt_send_srv_chg_ind (BD_ADDR peer_bda) { UINT8 handle_range[GATT_SIZE_OF_SRV_CHG_HNDL_RANGE]; UINT8 *p = handle_range; UINT16 conn_id; GATT_TRACE_DEBUG0("gatt_send_srv_chg_ind"); if (gatt_cb.handle_of_h_r) { if ((conn_id = gatt_profile_find_conn_id_by_bd_addr(peer_bda)) != GATT_INVALID_CONN_ID) { UINT16_TO_STREAM (p, 1); UINT16_TO_STREAM (p, 0xFFFF); GATTS_HandleValueIndication (conn_id, gatt_cb.handle_of_h_r, GATT_SIZE_OF_SRV_CHG_HNDL_RANGE, handle_range); } else { GATT_TRACE_ERROR2("Unable to find conn_id for %08x%04x ", (peer_bda[0]<<24)+(peer_bda[1]<<16)+(peer_bda[2]<<8)+peer_bda[3], (peer_bda[4]<<8)+peer_bda[5] ); } } }
/******************************************************************************* ** ** 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_send_queue_write_cancel ** ** Description send queue write cancel ** ** Returns void. ** *******************************************************************************/ void gatt_send_queue_write_cancel (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, tGATT_EXEC_FLAG flag) { UINT8 rt ; GATT_TRACE_DEBUG0("gatt_send_queue_write_cancel "); rt = attp_send_cl_msg(p_tcb, p_clcb->clcb_idx, GATT_REQ_EXEC_WRITE, (tGATT_CL_MSG *)&flag); if (rt != GATT_SUCCESS) { gatt_end_operation(p_clcb, rt, NULL); } }
/******************************************************************************* ** ** Function gatt_init_srv_chg ** ** Description This function is used to initialize the service changed ** attribute value ** ** Returns void ** *******************************************************************************/ void gatt_init_srv_chg (void) { tGATTS_SRV_CHG_REQ req; tGATTS_SRV_CHG_RSP rsp; BOOLEAN status; UINT8 num_clients,i; tGATTS_SRV_CHG srv_chg_clt; GATT_TRACE_DEBUG0("gatt_init_srv_chg"); if (gatt_cb.cb_info.p_srv_chg_callback) { status = (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_READ_NUM_CLENTS, NULL, &rsp); if (status && rsp.num_clients) { GATT_TRACE_DEBUG1("gatt_init_srv_chg num_srv_chg_clt_clients=%d", rsp.num_clients); num_clients = rsp.num_clients; i = 1; /* use one based index */ while ((i <= num_clients) && status) { req.client_read_index = i; if ((status = (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_READ_CLENT, &req, &rsp))) { memcpy(&srv_chg_clt, &rsp.srv_chg ,sizeof(tGATTS_SRV_CHG)); if (gatt_add_srv_chg_clt(&srv_chg_clt) == NULL) { GATT_TRACE_ERROR0("Unable to add a service change client"); status = FALSE; } } i++; } } } else { GATT_TRACE_DEBUG0("gatt_init_srv_chg callback not registered yet"); } }
/******************************************************************************* ** ** Function gatt_disconnect ** ** Description This function is called to disconnect to an ATT device. ** ** Parameter rem_bda: remote device address to disconnect from. ** ** Returns TRUE: if connection found and to be disconnected; otherwise ** return FALSE. ** *******************************************************************************/ BOOLEAN gatt_disconnect (BD_ADDR rem_bda) { tGATT_TCB *p_tcb = gatt_find_tcb_by_addr(rem_bda); BOOLEAN ret = FALSE; tGATT_CH_STATE ch_state; GATT_TRACE_DEBUG0 ("gatt_disconnect "); if (p_tcb != NULL) { ret = TRUE; if ( (ch_state = gatt_get_ch_state(p_tcb)) != GATT_CH_CLOSING ) { if (p_tcb->att_lcid == L2CAP_ATT_CID) { if (ch_state == GATT_CH_OPEN) { /* only LCB exist between remote device and local */ ret = L2CA_RemoveFixedChnl (L2CAP_ATT_CID, rem_bda); } else { gatt_set_ch_state(p_tcb, GATT_CH_CLOSING); ret = L2CA_CancelBleConnectReq (rem_bda); } } else { ret = L2CA_DisconnectReq(p_tcb->att_lcid); } } else { GATT_TRACE_DEBUG0 ("gatt_disconnect already in closing state"); } } return ret; }
/******************************************************************************* ** ** Function gatt_chk_srv_chg ** ** Description Check sending service chnaged Indication is required or not ** if required then send the Indication ** ** Returns void ** *******************************************************************************/ void gatt_chk_srv_chg(tGATTS_SRV_CHG *p_srv_chg_clt) { GATT_TRACE_DEBUG1("gatt_chk_srv_chg srv_changed=%d", p_srv_chg_clt->srv_changed ); if (p_srv_chg_clt->srv_changed) { gatt_send_srv_chg_ind(p_srv_chg_clt->bda); } else { GATT_TRACE_DEBUG0("No need to send srv chg "); } }
/******************************************************************************* ** ** Function gatt_init ** ** Description This function is enable the GATT profile on the device. ** It clears out the control blocks, and registers with L2CAP. ** ** Returns void ** *******************************************************************************/ void gatt_init (void) { tL2CAP_FIXED_CHNL_REG fixed_reg; GATT_TRACE_DEBUG0("gatt_init()"); memset (&gatt_cb, 0, sizeof(tGATT_CB)); #if defined(GATT_INITIAL_TRACE_LEVEL) gatt_cb.trace_level = GATT_INITIAL_TRACE_LEVEL; #else gatt_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */ #endif gatt_cb.def_mtu_size = GATT_DEF_BLE_MTU_SIZE; GKI_init_q (&gatt_cb.sign_op_queue); /* First, register fixed L2CAP channel for ATT over BLE */ fixed_reg.fixed_chnl_opts.mode = L2CAP_FCR_BASIC_MODE; fixed_reg.fixed_chnl_opts.max_transmit = 0xFF; fixed_reg.fixed_chnl_opts.rtrans_tout = 2000; fixed_reg.fixed_chnl_opts.mon_tout = 12000; fixed_reg.fixed_chnl_opts.mps = 670; fixed_reg.fixed_chnl_opts.tx_win_sz = 1; fixed_reg.pL2CA_FixedConn_Cb = gatt_le_connect_cback; fixed_reg.pL2CA_FixedData_Cb = gatt_le_data_ind; fixed_reg.default_idle_tout = 0xffff; /* 0xffff default idle timeout */ L2CA_RegisterFixedChannel (L2CAP_ATT_CID, &fixed_reg); /* Now, register with L2CAP for ATT PSM over BR/EDR */ if (!L2CA_Register (BT_PSM_ATT, (tL2CAP_APPL_INFO *) &dyn_info)) { GATT_TRACE_ERROR0 ("ATT Dynamic Registration failed"); } BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_ATT, BTM_SEC_NONE, BT_PSM_ATT, 0, 0); BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_ATT, BTM_SEC_NONE, BT_PSM_ATT, 0, 0); gatt_cb.hdl_cfg.gatt_start_hdl = GATT_GATT_START_HANDLE; gatt_cb.hdl_cfg.gap_start_hdl = GATT_GAP_START_HANDLE; gatt_cb.hdl_cfg.app_start_hdl = GATT_APP_START_HANDLE; gatt_profile_db_init(); }
/******************************************************************************* ** ** 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_process_error_rsp ** ** Description This function is called to handle the error response ** ** ** Returns void ** *******************************************************************************/ void gatt_process_error_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code, UINT16 len, UINT8 *p_data) { UINT8 opcode, reason, * p= p_data; UINT16 handle; tGATT_VALUE *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf; GATT_TRACE_DEBUG0("gatt_process_error_rsp "); STREAM_TO_UINT8(opcode, p); STREAM_TO_UINT16(handle, p); STREAM_TO_UINT8(reason, p); if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY) { gatt_proc_disc_error_rsp(p_tcb, p_clcb, opcode, handle, reason); } else { if ( (p_clcb->operation == GATTC_OPTYPE_WRITE) && (p_clcb->op_subtype == GATT_WRITE) && (opcode == GATT_REQ_PREPARE_WRITE) && (p_attr) && (handle == p_attr->handle) ) { p_clcb->status = reason; gatt_send_queue_write_cancel(p_tcb, p_clcb, GATT_PREP_WRITE_CANCEL); } else if ((p_clcb->operation == GATTC_OPTYPE_READ) && ((p_clcb->op_subtype == GATT_READ_CHAR_VALUE_HDL) || (p_clcb->op_subtype == GATT_READ_BY_HANDLE)) && (opcode == GATT_REQ_READ_BLOB) && p_clcb->first_read_blob_after_read && (reason == GATT_NOT_LONG)) { gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p_clcb->p_attr_buf); } else gatt_end_operation(p_clcb, reason, NULL); } }
/******************************************************************************* ** ** Function gatt_le_data_ind ** ** Description This function is called when data is received from L2CAP. ** if we are the originator of the connection, we are the ATT ** client, and the received message is queued up for the client. ** ** If we are the destination of the connection, we are the ATT ** server, so the message is passed to the server processing ** function. ** ** Returns void ** *******************************************************************************/ static void gatt_le_data_ind (BD_ADDR bd_addr, BT_HDR *p_buf) { GATT_TRACE_DEBUG0("gatt_le_data_ind"); tGATT_TCB *p_tcb; /* Find CCB based on bd addr */ if ((p_tcb = gatt_find_tcb_by_addr (bd_addr)) != NULL && gatt_get_ch_state(p_tcb) >= GATT_CH_OPEN) { gatt_data_process(p_tcb, p_buf); } else { GKI_freebuf (p_buf); if (p_tcb != NULL) { GATT_TRACE_WARNING1 ("ATT - Ignored L2CAP data while in state: %d", gatt_get_ch_state(p_tcb)); } } }
/******************************************************************************* ** ** Function gatt_process_notification ** ** Description This function is called to handle the handle value indication ** or handle value notification. ** ** ** Returns void ** *******************************************************************************/ void gatt_process_notification(tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, UINT8 *p_data) { tGATT_VALUE value = {0}; tGATT_REG *p_reg; UINT16 conn_id; tGATT_STATUS encrypt_status; UINT8 *p= p_data, i, event = (op_code == GATT_HANDLE_VALUE_NOTIF) ? GATTC_OPTYPE_NOTIFICATION : GATTC_OPTYPE_INDICATION; GATT_TRACE_DEBUG0("gatt_process_notification "); STREAM_TO_UINT16 (value.handle, p); value.len = len - 2; memcpy (value.value, p, value.len); if (!GATT_HANDLE_IS_VALID(value.handle)) { /* illegal handle, send ack now */ if (op_code == GATT_HANDLE_VALUE_IND) attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL); return; } if (event == GATTC_OPTYPE_INDICATION) { if (p_tcb->ind_count) { /* this is an error case that receiving an indication but we still has an indication not being acked yet. For now, just log the error reset the counter. Later we need to disconnect the link unconditionally. */ GATT_TRACE_ERROR1("gatt_process_notification rcv Ind. but ind_count=%d (will reset ind_count)", p_tcb->ind_count); } p_tcb->ind_count = 0; } /* should notify all registered client with the handle value notificaion/indication Note: need to do the indication count and start timer first then do callback */ for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) { if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb && (event == GATTC_OPTYPE_INDICATION)) p_tcb->ind_count++; } if (event == GATTC_OPTYPE_INDICATION) { /* start a timer for app confirmation */ if (p_tcb->ind_count > 0) gatt_start_ind_ack_timer(p_tcb); else /* no app to indicate, or invalid handle */ attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL); } encrypt_status = gatt_get_link_encrypt_status(p_tcb); for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) { if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb) { conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if); (*p_reg->app_cb.p_cmpl_cb) (conn_id, event, encrypt_status, (tGATT_CL_COMPLETE *)&value); } } }
/******************************************************************************* ** ** 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"); } }