diff options
author | Ganesh Ganapathi Batta <ganeshg@broadcom.com> | 2013-02-05 15:22:31 -0800 |
---|---|---|
committer | Matthew Xie <mattx@google.com> | 2013-02-27 18:15:49 -0800 |
commit | ead3cde4bac0c3e32cd31f149093f004eef8ceeb (patch) | |
tree | f45b52e375e1a80e807dbbc864bb1da603965b0d | |
parent | e17bf003d4eefdc8525e55894210e9ee494972b8 (diff) | |
download | android_system_bt-ead3cde4bac0c3e32cd31f149093f004eef8ceeb.tar.gz android_system_bt-ead3cde4bac0c3e32cd31f149093f004eef8ceeb.tar.bz2 android_system_bt-ead3cde4bac0c3e32cd31f149093f004eef8ceeb.zip |
Initial version of BLE support for Bluedroid
Change-Id: I9825a5cef9be2559c34c2a529b211b7d471147cf
149 files changed, 15391 insertions, 2549 deletions
diff --git a/bta/av/bta_av_aact.c b/bta/av/bta_av_aact.c index 741a5a075..6a407e041 100644 --- a/bta/av/bta_av_aact.c +++ b/bta/av/bta_av_aact.c @@ -394,6 +394,16 @@ void bta_av_proc_stream_evt(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CT /* copy config params to event message buffer */ switch (event) { + case AVDT_RECONFIG_CFM_EVT: + APPL_TRACE_DEBUG4("reconfig cfm event codec info = 0x%06x-%06x-%06x-%02x", + (p_msg->msg.reconfig_cfm.p_cfg->codec_info[0]<<16)+(p_msg->msg.reconfig_cfm.p_cfg->codec_info[1]<<8)+p_msg->msg.reconfig_cfm.p_cfg->codec_info[2], + (p_msg->msg.reconfig_cfm.p_cfg->codec_info[3]<<16)+(p_msg->msg.reconfig_cfm.p_cfg->codec_info[4]<<8)+p_msg->msg.reconfig_cfm.p_cfg->codec_info[5], + (p_msg->msg.reconfig_cfm.p_cfg->codec_info[6]<<16)+(p_msg->msg.reconfig_cfm.p_cfg->codec_info[7]<<8)+p_msg->msg.reconfig_cfm.p_cfg->codec_info[8], + p_msg->msg.reconfig_cfm.p_cfg->codec_info[9]); + break; + + + case AVDT_CONFIG_IND_EVT: /* We might have 2 SEP signallings(A2DP + VDP) with one peer device on one L2CAP. * If we already have a signalling connection with the bd_addr and the streaming @@ -461,17 +471,16 @@ void bta_av_proc_stream_evt(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CT if (event == AVDT_SUSPEND_CFM_EVT) p_msg->initiator = TRUE; - APPL_TRACE_EVENT1("hndl:x%x", p_scb->hndl); + APPL_TRACE_VERBOSE1("hndl:x%x", p_scb->hndl); p_msg->hdr.layer_specific = p_scb->hndl; p_msg->handle = handle; p_msg->avdt_event = event; bta_sys_sendmsg(p_msg); } -/* coverity[var_deref_model]: Variable "p_data" tracked as NULL was passed to function "bta_av_conn_cback" that dereferences it. - * false-positive: bta_av_conn_cback only processes AVDT_CONNECT_IND_EVT and AVDT_DISCONNECT_IND_EVT event - * these 2 events always have associated p_data - */ +/* coverity[var_deref_model] */ +/* false-positive: bta_av_conn_cback only processes AVDT_CONNECT_IND_EVT and AVDT_DISCONNECT_IND_EVT event + * these 2 events always have associated p_data */ bta_av_conn_cback(handle, bd_addr, event, p_data); } @@ -486,7 +495,7 @@ void bta_av_proc_stream_evt(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CT *******************************************************************************/ static void bta_av_stream0_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data) { - APPL_TRACE_EVENT2("bta_av_stream0_cback avdt_handle: %d event=0x%x", handle, event); + APPL_TRACE_VERBOSE2("bta_av_stream0_cback avdt_handle: %d event=0x%x", handle, event); bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 0); } @@ -1570,11 +1579,48 @@ void bta_av_cco_close (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) *******************************************************************************/ void bta_av_open_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) { + + BOOLEAN is_av_opened = FALSE; + tBTA_AV_SCB * p_opened_scb = NULL; + UINT8 idx; + tBTA_AV_OPEN open; + + APPL_TRACE_DEBUG0("bta_av_open_failed"); p_scb->open_status = BTA_AV_FAIL_STREAM; bta_av_cco_close(p_scb, p_data); - AVDT_DisconnectReq(p_scb->peer_addr, bta_av_dt_cback[p_scb->hdi]); + + /* check whether there is already an opened audio or video connection with the same device */ + for (idx = 0; (idx < BTA_AV_NUM_STRS) && (is_av_opened == FALSE); idx++ ) + { + p_opened_scb = bta_av_cb.p_scb[idx]; + if (p_opened_scb && (p_opened_scb->state == BTA_AV_OPEN_SST) && (!bdcmp(p_opened_scb->peer_addr,p_scb->peer_addr )) ) + is_av_opened = TRUE; + + } + + /* if there is already an active AV connnection with the same bd_addr, + don't send disconnect req, just report the open event with BTA_AV_FAIL_GET_CAP status */ + if (is_av_opened == TRUE) + { + bdcpy(open.bd_addr, p_scb->peer_addr); + open.chnl = p_scb->chnl; + open.hndl = p_scb->hndl; + open.status = BTA_AV_FAIL_GET_CAP; + open.starting = bta_av_chk_start(p_scb); + open.edr = 0; + /* set the state back to initial state */ + bta_av_set_scb_sst_init(p_scb); + + (*bta_av_cb.p_cback)(BTA_AV_OPEN_EVT, (tBTA_AV *) &open); + + } + else + { + AVDT_DisconnectReq(p_scb->peer_addr, bta_av_dt_cback[p_scb->hdi]); + } } + /******************************************************************************* ** ** Function bta_av_getcap_results @@ -1798,7 +1844,8 @@ void bta_av_str_stopped (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) AVDT_SuspendReq(&p_scb->avdt_handle, 1); } - if(sus_evt) + /* send SUSPEND_EVT event only if not in reconfiguring state and sus_evt is TRUE*/ + if ((sus_evt)&&(p_scb->state != BTA_AV_RCFG_SST)) { suspend_rsp.status = BTA_AV_SUCCESS; suspend_rsp.initiator = TRUE; @@ -1811,7 +1858,11 @@ void bta_av_str_stopped (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) suspend_rsp.initiator = TRUE; APPL_TRACE_EVENT1("bta_av_str_stopped status %d", suspend_rsp.status); - (*bta_av_cb.p_cback)(BTA_AV_STOP_EVT, (tBTA_AV *) &suspend_rsp); + /* send STOP_EVT event only if not in reconfiguring state */ + if (p_scb->state != BTA_AV_RCFG_SST) + { + (*bta_av_cb.p_cback)(BTA_AV_STOP_EVT, (tBTA_AV *) &suspend_rsp); + } } } @@ -1916,6 +1967,7 @@ void bta_av_data_path (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) UINT32 timestamp; BOOLEAN new_buf = FALSE; UINT8 m_pt = 0x60 | p_scb->codec_type; + tAVDT_DATA_OPT_MASK opt; if (!p_scb->cong) { @@ -1958,7 +2010,15 @@ void bta_av_data_path (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) /* APPL_TRACE_ERROR1("qw: %d", p_scb->l2c_bufs); */ - AVDT_WriteReq(p_scb->avdt_handle, p_buf, timestamp, m_pt); + + /* opt is a bit mask, it could have several options set */ + opt = AVDT_DATA_OPT_NONE; + if (p_scb->no_rtp_hdr) + { + opt |= AVDT_DATA_OPT_NO_RTP; + } + + AVDT_WriteReqOpt(p_scb->avdt_handle, p_buf, timestamp, m_pt, opt); p_scb->cong = TRUE; } else @@ -2008,6 +2068,8 @@ void bta_av_start_ok (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) UINT16 flush_to; UINT8 new_role = p_scb->role; BT_HDR hdr; + UINT8 policy = HCI_ENABLE_SNIFF_MODE; + UINT8 cur_role; APPL_TRACE_DEBUG2("bta_av_start_ok wait:x%x, role:x%x", p_scb->wait, p_scb->role); @@ -2111,11 +2173,27 @@ void bta_av_start_ok (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) } { + /* If sink starts stream, disable sniff mode here */ + if (!initiator) + { + /* If souce is the master role, disable role switch during streaming. + * Otherwise allow role switch, if source is slave. + * Because it would not hurt source, if the peer device wants source to be master */ + if ((BTM_GetRole (p_scb->peer_addr, &cur_role) == BTM_SUCCESS) && + (cur_role == BTM_ROLE_MASTER) ) + { + policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH; + } + + bta_sys_clear_policy(BTA_ID_AV, policy, p_scb->peer_addr); + } + p_scb->role = new_role; p_scb->role &= ~BTA_AV_ROLE_AD_ACP; p_scb->role &= ~BTA_AV_ROLE_SUSPEND_OPT; - p_scb->p_cos->start(p_scb->hndl, p_scb->codec_type); + p_scb->no_rtp_hdr = FALSE; + p_scb->p_cos->start(p_scb->hndl, p_scb->codec_type, p_scb->cfg.codec_info, &p_scb->no_rtp_hdr); p_scb->co_started = TRUE; APPL_TRACE_DEBUG3("bta_av_start_ok suspending: %d, role:x%x, init %d", @@ -2269,9 +2347,13 @@ void bta_av_suspend_cfm (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) bta_av_cb.audio_open_cnt, err_code); suspend_rsp.status = BTA_AV_SUCCESS; - if(err_code) + if (err_code) { - p_scb->suspend_sup = FALSE; + /* Disable suspend feature only with explicit rejection(not with timeout) */ + if (err_code != AVDT_ERR_TIMEOUT) + { + p_scb->suspend_sup = FALSE; + } suspend_rsp.status = BTA_AV_FAIL; APPL_TRACE_ERROR0 ("bta_av_suspend_cfm: suspend failed, closing connection"); @@ -2285,7 +2367,7 @@ void bta_av_suspend_cfm (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) p_scb->started = FALSE; } - if(p_scb->role & BTA_AV_ROLE_SUSPEND) + if (p_scb->role & BTA_AV_ROLE_SUSPEND) { p_scb->role &= ~BTA_AV_ROLE_SUSPEND; p_scb->cong = FALSE; @@ -2460,9 +2542,9 @@ void bta_av_suspend_cont (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) p_scb->started = FALSE; p_scb->cong = FALSE; - if(err_code) + if (err_code) { - if(AVDT_ERR_CONNECT == err_code) + if (AVDT_ERR_CONNECT == err_code) { /* report failure */ evt.status = BTA_AV_FAIL; @@ -2472,8 +2554,11 @@ void bta_av_suspend_cont (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) else { APPL_TRACE_ERROR0("suspend rejected, try close"); - p_scb->suspend_sup = FALSE; - + /* Disable suspend feature only with explicit rejection(not with timeout) */ + if (err_code != AVDT_ERR_TIMEOUT) + { + p_scb->suspend_sup = FALSE; + } /* drop the buffers queued in L2CAP */ L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL); @@ -2507,10 +2592,14 @@ void bta_av_rcfg_cfm (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) /* APPL_TRACE_DEBUG0("bta_av_rcfg_cfm"); */ - if(err_code) + if (err_code) { APPL_TRACE_ERROR0("reconfig rejected, try close"); - p_scb->recfg_sup = FALSE; + /* Disable reconfiguration feature only with explicit rejection(not with timeout) */ + if (err_code != AVDT_ERR_TIMEOUT) + { + p_scb->recfg_sup = FALSE; + } /* started flag is FALSE when reconfigure command is sent */ /* drop the buffers queued in L2CAP */ L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL); @@ -2518,6 +2607,8 @@ void bta_av_rcfg_cfm (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) } else { + /* update the codec info after rcfg cfm */ + memcpy(p_scb->cfg.codec_info,p_data->str_msg.msg.reconfig_cfm.p_cfg->codec_info,AVDT_CODEC_SIZE); /* take the SSM back to OPEN state */ bta_av_ssm_execute(p_scb, BTA_AV_STR_OPEN_OK_EVT, NULL); } diff --git a/bta/av/bta_av_act.c b/bta/av/bta_av_act.c index a47921af3..edf8b7fd3 100644 --- a/bta/av/bta_av_act.c +++ b/bta/av/bta_av_act.c @@ -363,7 +363,7 @@ UINT8 bta_av_rc_create(tBTA_AV_CB *p_cb, UINT8 role, UINT8 shdl, UINT8 lidx) ** Returns BTA_AV_RSP_ACCEPT or BTA_AV_RSP_NOT_IMPL. ** *******************************************************************************/ -static tBTA_AV_CODE bta_av_group_navi_supported(UINT8 len, UINT8 *p_data) +static tBTA_AV_CODE bta_av_group_navi_supported(UINT8 len, UINT8 *p_data, BOOLEAN is_inquiry) { tBTA_AV_CODE ret=BTA_AV_RSP_NOT_IMPL; UINT8 *p_ptr = p_data; @@ -377,10 +377,18 @@ static tBTA_AV_CODE bta_av_group_navi_supported(UINT8 len, UINT8 *p_data) if (u32 == AVRC_CO_METADATA) { - if (u16 <= AVRC_PDU_PREV_GROUP) - ret = BTA_AV_RSP_ACCEPT; + if (is_inquiry) + { + if (u16 <= AVRC_PDU_PREV_GROUP) + ret = BTA_AV_RSP_IMPL_STBL; + } else - ret = BTA_AV_RSP_REJ; + { + if (u16 <= AVRC_PDU_PREV_GROUP) + ret = BTA_AV_RSP_ACCEPT; + else + ret = BTA_AV_RSP_REJ; + } } } @@ -396,23 +404,34 @@ static tBTA_AV_CODE bta_av_group_navi_supported(UINT8 len, UINT8 *p_data) ** Returns BTA_AV_RSP_ACCEPT of supported, BTA_AV_RSP_NOT_IMPL if not. ** *******************************************************************************/ -static tBTA_AV_CODE bta_av_op_supported(tBTA_AV_RC rc_id) +static tBTA_AV_CODE bta_av_op_supported(tBTA_AV_RC rc_id, BOOLEAN is_inquiry) { tBTA_AV_CODE ret_code = BTA_AV_RSP_NOT_IMPL; if (p_bta_av_rc_id) { - if (p_bta_av_rc_id[rc_id >> 4] & (1 << (rc_id & 0x0F))) + if (is_inquiry) { - ret_code = BTA_AV_RSP_ACCEPT; + if (p_bta_av_rc_id[rc_id >> 4] & (1 << (rc_id & 0x0F))) + { + ret_code = BTA_AV_RSP_IMPL_STBL; + } } - else if ((p_bta_av_cfg->rc_pass_rsp == BTA_AV_RSP_INTERIM) && p_bta_av_rc_id_ac) + else { - if (p_bta_av_rc_id_ac[rc_id >> 4] & (1 << (rc_id & 0x0F))) + if (p_bta_av_rc_id[rc_id >> 4] & (1 << (rc_id & 0x0F))) + { + ret_code = BTA_AV_RSP_ACCEPT; + } + else if ((p_bta_av_cfg->rc_pass_rsp == BTA_AV_RSP_INTERIM) && p_bta_av_rc_id_ac) { - ret_code = BTA_AV_RSP_INTERIM; + if (p_bta_av_rc_id_ac[rc_id >> 4] & (1 << (rc_id & 0x0F))) + { + ret_code = BTA_AV_RSP_INTERIM; + } } } + } return ret_code; } @@ -824,11 +843,15 @@ void bta_av_rc_msg(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data) tBTA_AV av; BT_HDR *p_pkt = NULL; tAVRC_MSG_VENDOR *p_vendor = &p_data->rc_msg.msg.vendor; + BOOLEAN is_inquiry = ((p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_SPEC_INQ) || p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_GEN_INQ); if (p_data->rc_msg.opcode == AVRC_OP_PASS_THRU) { /* if this is a pass thru command */ - if (p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_CTRL) + if ((p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_CTRL) || + (p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_SPEC_INQ) || + (p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_GEN_INQ) + ) { /* check if operation is supported */ if (p_data->rc_msg.msg.pass.op_id == AVRC_ID_VENDOR) @@ -837,9 +860,11 @@ void bta_av_rc_msg(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data) } else { - p_data->rc_msg.msg.hdr.ctype = bta_av_op_supported(p_data->rc_msg.msg.pass.op_id); + p_data->rc_msg.msg.hdr.ctype = bta_av_op_supported(p_data->rc_msg.msg.pass.op_id, is_inquiry); } + APPL_TRACE_DEBUG1("ctype %d",p_data->rc_msg.msg.hdr.ctype) + /* send response */ if (p_data->rc_msg.msg.hdr.ctype != BTA_AV_RSP_INTERIM) AVRC_PassRsp(p_data->rc_msg.handle, p_data->rc_msg.label, &p_data->rc_msg.msg.pass); @@ -1335,17 +1360,10 @@ void bta_av_sig_chg(tBTA_AV_DATA *p_data) { mask = 1 << xx; APPL_TRACE_DEBUG1("conn_lcb: 0x%x", p_cb->conn_lcb); - if(!(mask & p_cb->conn_lcb)) - { - if (!p_cb->p_scb[xx]) - { - /* We do not have scb for this avdt connection. */ - /* Silently close the connection. */ - APPL_TRACE_ERROR0("av scb not available for avdt connection"); - AVDT_DisconnectReq (p_data->str_msg.bd_addr, NULL); - return; - } + /* look for a p_lcb with its p_scb registered */ + if((!(mask & p_cb->conn_lcb)) && (p_cb->p_scb[xx] != NULL)) + { p_lcb = &p_cb->lcb[xx]; p_lcb->lidx = xx + 1; bdcpy(p_lcb->addr, p_data->str_msg.bd_addr); @@ -1382,6 +1400,16 @@ void bta_av_sig_chg(tBTA_AV_DATA *p_data) break; } } + + /* check if we found something */ + if (xx == BTA_AV_NUM_LINKS) + { + /* We do not have scb for this avdt connection. */ + /* Silently close the connection. */ + APPL_TRACE_ERROR0("av scb not available for avdt connection"); + AVDT_DisconnectReq (p_data->str_msg.bd_addr, NULL); + return; + } } } #if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) @@ -1516,9 +1544,10 @@ static void bta_av_acp_sig_timer_cback (TIMER_LIST_ENT *p_tle) ** ** Function bta_av_check_peer_features ** -** Description checks +** Description check supported features on the peer device from the SDP record +** and return the feature mask ** -** Returns void +** Returns tBTA_AV_FEAT peer device feature mask ** *******************************************************************************/ tBTA_AV_FEAT bta_av_check_peer_features (UINT16 service_uuid) @@ -1624,13 +1653,9 @@ void bta_av_rc_disc_done(tBTA_AV_DATA *p_data) } APPL_TRACE_DEBUG1("rc_handle %d", rc_handle); + /* check peer version and whether support CT and TG role */ peer_features = bta_av_check_peer_features (UUID_SERVCLASS_AV_REMOTE_CONTROL); - if ((p_cb->features & BTA_AV_FEAT_ADV_CTRL) && ((peer_features&BTA_AV_FEAT_ADV_CTRL) == 0)) - { - /* if we support advance control and peer does not, check their support on TG role - * some implementation uses 1.3 on CT ans 1.4 on TG */ - peer_features |= bta_av_check_peer_features (UUID_SERVCLASS_AV_REM_CTRL_TARGET); - } + peer_features |= bta_av_check_peer_features (UUID_SERVCLASS_AV_REM_CTRL_TARGET); p_cb->disc = 0; utl_freebuf((void **) &p_cb->p_disc_db); diff --git a/bta/av/bta_av_cfg.c b/bta/av/bta_av_cfg.c index 793c77259..f589a8870 100644 --- a/bta/av/bta_av_cfg.c +++ b/bta/av/bta_av_cfg.c @@ -78,39 +78,6 @@ const UINT8 bta_av_meta_caps_evt_ids[] = { #define BTA_AV_NUM_RC_EVT_IDS (sizeof(bta_av_meta_caps_evt_ids) / sizeof(bta_av_meta_caps_evt_ids[0])) #endif /* BTA_AV_NUM_RC_EVT_IDS */ - -#else /* !ANDROID_APP_INCLUDED */ - -/* Note: if AVRC_SUPF_TG_GROUP_NAVI is set, bta_av_cfg.avrc_group should be TRUE */ -#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT1) - -const UINT16 bta_av_audio_flush_to[] = { - 120, /* 1 stream */ - 100, /* 2 streams */ - 80, /* 3 streams */ - 60, /* 4 streams */ - 40 /* 5 streams */ -}; /* AVDTP audio transport channel flush timeout */ - - -/* - * If the number of event IDs is changed in this array, BTA_AV_ NUM_RC_EVT_IDS also needs to be changed. - */ -const UINT8 bta_av_meta_caps_evt_ids[] = { - AVRC_EVT_PLAY_STATUS_CHANGE, - AVRC_EVT_TRACK_CHANGE, - AVRC_EVT_TRACK_REACHED_END, - AVRC_EVT_TRACK_REACHED_START, - AVRC_EVT_PLAY_POS_CHANGED, - AVRC_EVT_BATTERY_STATUS_CHANGE, - AVRC_EVT_SYSTEM_STATUS_CHANGE, - AVRC_EVT_APP_SETTING_CHANGE, -}; - -#ifndef BTA_AV_NUM_RC_EVT_IDS -#define BTA_AV_NUM_RC_EVT_IDS 8 -#endif - #endif /* ANDROID_APP_INCLUDED */ /* the MTU for the AVRCP browsing channel */ diff --git a/bta/av/bta_av_int.h b/bta/av/bta_av_int.h index 9ce7b2a89..cd22bcb2d 100644 --- a/bta/av/bta_av_int.h +++ b/bta/av/bta_av_int.h @@ -170,7 +170,7 @@ typedef void (*tBTA_AV_CO_OPEN) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, UINT8 *p_codec_info, UINT16 mtu); typedef void (*tBTA_AV_CO_CLOSE) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, UINT16 mtu); -typedef void (*tBTA_AV_CO_START) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type); +typedef void (*tBTA_AV_CO_START) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type,UINT8 *p_codec_info, BOOLEAN *p_no_rtp_hdr); typedef void (*tBTA_AV_CO_STOP) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type); typedef void * (*tBTA_AV_CO_DATAPATH) (tBTA_AV_CODEC codec_type, UINT32 *p_len, UINT32 *p_timestamp); @@ -504,6 +504,7 @@ typedef struct tBTA_AV_API_OPEN open_api; /* Saved OPEN api message */ UINT8 wait; /* set 0x1, when getting Caps as ACP, set 0x2, when started */ UINT8 q_tag; /* identify the associated q_info union member */ + BOOLEAN no_rtp_hdr; /* TRUE if add no RTP header*/ } tBTA_AV_SCB; #define BTA_AV_RC_ROLE_MASK 0x10 diff --git a/bta/av/bta_av_main.c b/bta/av/bta_av_main.c index 085362dd4..749756d61 100644 --- a/bta/av/bta_av_main.c +++ b/bta/av/bta_av_main.c @@ -1191,9 +1191,9 @@ BOOLEAN bta_av_hdl_event(BT_HDR *p_msg) if(event >= first_event) { #if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE) - APPL_TRACE_EVENT2("AV nsm event=0x%x(%s)", event, bta_av_evt_code(event)); + APPL_TRACE_VERBOSE2("AV nsm event=0x%x(%s)", event, bta_av_evt_code(event)); #else - APPL_TRACE_EVENT1("AV nsm event=0x%x", event); + APPL_TRACE_VERBOSE1("AV nsm event=0x%x", event); #endif /* non state machine events */ (*bta_av_nsm_act[event - BTA_AV_FIRST_NSM_EVT]) ((tBTA_AV_DATA *) p_msg); @@ -1201,16 +1201,16 @@ BOOLEAN bta_av_hdl_event(BT_HDR *p_msg) else if (event >= BTA_AV_FIRST_SM_EVT && event <= BTA_AV_LAST_SM_EVT) { #if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE) - APPL_TRACE_EVENT2("AV sm event=0x%x(%s)", event, bta_av_evt_code(event)); + APPL_TRACE_VERBOSE2("AV sm event=0x%x(%s)", event, bta_av_evt_code(event)); #else - APPL_TRACE_EVENT1("AV sm event=0x%x", event); + APPL_TRACE_VERBOSE1("AV sm event=0x%x", event); #endif /* state machine events */ bta_av_sm_execute(&bta_av_cb, p_msg->event, (tBTA_AV_DATA *) p_msg); } else { - APPL_TRACE_EVENT1("handle=0x%x", p_msg->layer_specific); + APPL_TRACE_VERBOSE1("handle=0x%x", p_msg->layer_specific); /* stream state machine events */ bta_av_ssm_execute( bta_av_hndl_to_scb(p_msg->layer_specific), p_msg->event, (tBTA_AV_DATA *) p_msg); diff --git a/bta/av/bta_av_ssm.c b/bta/av/bta_av_ssm.c index a35a4b02a..407146efd 100644 --- a/bta/av/bta_av_ssm.c +++ b/bta/av/bta_av_ssm.c @@ -436,10 +436,10 @@ void bta_av_ssm_execute(tBTA_AV_SCB *p_scb, UINT16 event, tBTA_AV_DATA *p_data) } #if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE) - APPL_TRACE_EVENT5("AV Sevent(0x%x)=0x%x(%s) state=%d(%s)", + APPL_TRACE_VERBOSE5("AV Sevent(0x%x)=0x%x(%s) state=%d(%s)", p_scb->hndl, event, bta_av_evt_code(event), p_scb->state, bta_av_sst_code(p_scb->state)); #else - APPL_TRACE_EVENT2("AV Sevent=0x%x state=%d", event, p_scb->state); + APPL_TRACE_VERBOSE2("AV Sevent=0x%x state=%d", event, p_scb->state); #endif /* look up the state table for the current state */ diff --git a/bta/dm/bta_dm_act.c b/bta/dm/bta_dm_act.c index 29b4ec279..0ade1cca6 100644 --- a/bta/dm/bta_dm_act.c +++ b/bta/dm/bta_dm_act.c @@ -92,7 +92,10 @@ static void bta_dm_sys_hw_cback( tBTA_SYS_HW_EVT status ); static BOOLEAN bta_dm_dev_blacklisted_for_switch (BD_ADDR remote_bd_addr); static void bta_dm_delay_role_switch_cback (TIMER_LIST_ENT *p_tle); +static void bta_dm_remove_sec_dev_entry(BD_ADDR remote_bd_addr); + +static void bta_dm_disable_search_and_disc(void); #if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) #if ((defined SMP_INCLUDED) && (SMP_INCLUDED == TRUE)) static UINT8 bta_dm_ble_smp_cback (tBTM_LE_EVT event, BD_ADDR bda, tBTM_LE_EVT_DATA *p_data); @@ -103,8 +106,13 @@ static void btm_dm_start_gatt_discovery ( BD_ADDR bd_addr); static void bta_dm_cancel_gatt_discovery(BD_ADDR bd_addr); static void bta_dm_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC *p_data); #endif -#endif +static void bta_dm_observe_results_cb (tBTM_INQ_RESULTS *p_inq, UINT8 *p_eir); +static void bta_dm_observe_cmpl_cb (void * p_result); +#ifndef BTA_DM_BLE_ADV_CHNL_MAP +#define BTA_DM_BLE_ADV_CHNL_MAP (BTM_BLE_ADV_CHNL_37|BTM_BLE_ADV_CHNL_38|BTM_BLE_ADV_CHNL_39) +#endif +#endif extern void sdpu_uuid16_to_uuid128(UINT16 uuid16, UINT8* p_uuid128); const UINT16 bta_service_id_to_uuid_lkup_tbl [BTA_MAX_SERVICE_ID] = @@ -454,10 +462,9 @@ void bta_dm_disable (tBTA_DM_MSG *p_data) BTM_SetConnectability(BTM_NON_CONNECTABLE, 0, 0); bta_dm_disable_pm(); - + bta_dm_disable_search_and_disc(); bta_dm_cb.disabling = TRUE; - bta_dm_search_cancel(NULL); if(BTM_GetNumAclLinks()==0) { @@ -750,6 +757,58 @@ void bta_dm_add_device (tBTA_DM_MSG *p_data) /******************************************************************************* ** +** Function bta_dm_close_acl +** +** Description This function forces to close the connection to a remote device +** and optionaly remove the device from security database if +** required. +**** +*******************************************************************************/ +void bta_dm_close_acl(tBTA_DM_MSG *p_data) +{ + tBTA_DM_API_REMOVE_ACL *p_remove_acl = &p_data->remove_acl; + UINT8 index; + + APPL_TRACE_DEBUG0("bta_dm_close_acl"); + + if (BTM_IsAclConnectionUp(p_remove_acl->bd_addr)) + { + for (index = 0; index < bta_dm_cb.device_list.count; index ++) + { + if (!bdcmp( bta_dm_cb.device_list.peer_device[index].peer_bdaddr, p_remove_acl->bd_addr)) + break; + } + if (index != bta_dm_cb.device_list.count) + { + if (p_remove_acl->remove_dev) + bta_dm_cb.device_list.peer_device[index].remove_dev_pending = TRUE; + } + else + { + APPL_TRACE_ERROR0("unknown device, remove ACL failed"); + } + /* Disconnect the ACL link */ + btm_remove_acl(p_remove_acl->bd_addr); + } + /* if to remove the device from security database ? do it now */ + else if (p_remove_acl->remove_dev) + { + if (!BTM_SecDeleteDevice(p_remove_acl->bd_addr)) + { + APPL_TRACE_ERROR0("delete device from security database failed."); + } +#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE) + /* need to remove all pending background connection if any */ + BTA_GATTC_CancelOpen(0, p_remove_acl->bd_addr, FALSE); + /* remove all cached GATT information */ + BTA_GATTC_Refresh(p_remove_acl->bd_addr); +#endif + } + /* otherwise, no action needed */ + +} +/******************************************************************************* +** ** Function bta_dm_bond ** ** Description Bonds with peer device @@ -784,8 +843,14 @@ void bta_dm_bond (tBTA_DM_MSG *p_data) */ sec_event.auth_cmpl.fail_reason = HCI_ERR_ILLEGAL_COMMAND; if (status == BTM_SUCCESS) + { sec_event.auth_cmpl.success = TRUE; - + } + else + { + /* delete this device entry from Sec Dev DB */ + bta_dm_remove_sec_dev_entry(p_data->bond.bd_addr); + } bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event); } @@ -1148,11 +1213,6 @@ void bta_dm_search_start (tBTA_DM_MSG *p_data) // bta_dm_search_cb.p_srvc_uuid = (tBT_UUID *)GKI_getbuf(len); memcpy(bta_dm_search_cb.p_srvc_uuid, p_data->search.p_uuid, len); } - - if (p_data->search.inq_params.mode & BTM_LIMITED_INQUIRY) - p_data->search.inq_params.mode |= BTM_BLE_LIMITED_INQUIRY; - else - p_data->search.inq_params.mode |= BTM_BLE_GENERAL_INQUIRY; #endif result.status = BTM_StartInquiry( (tBTM_INQ_PARMS*)&p_data->search.inq_params, bta_dm_inq_results_cb, @@ -1200,7 +1260,7 @@ void bta_dm_search_cancel (tBTA_DM_MSG *p_data) { BTM_CancelRemoteDeviceName(); } -#if ((BLE_INCLUDED == TRUE) && (defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)) +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE if (bta_dm_search_cb.gatt_disc_active) { bta_dm_cancel_gatt_discovery(bta_dm_search_cb.peer_bdaddr); @@ -1311,6 +1371,65 @@ static void bta_dm_di_disc_callback(UINT16 result) /******************************************************************************* ** +** Function bta_dm_disable_search_and_disc +** +** Description Cancels an ongoing search or discovery for devices in case of +** a Bluetooth disable +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_disable_search_and_disc (void) +{ + tBTA_DM_DI_DISC_CMPL di_disc; + tBTA_DM_MSG * p_msg; + + if(BTM_IsInquiryActive()||(bta_dm_search_cb.state != BTA_DM_SEARCH_IDLE)) + { + BTM_CancelInquiry(); + bta_dm_search_cancel_notify(NULL); + + if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT; + p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT; + bta_sys_sendmsg(p_msg); + + } + } + /* If no Service Search going on then issue cancel remote name in case it is active */ + else if (!bta_dm_search_cb.name_discover_done) + { + BTM_CancelRemoteDeviceName(); + + if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT; + p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT; + bta_sys_sendmsg(p_msg); + } + } + else if(bta_dm_di_cb.p_di_db != NULL) + { + memset(&di_disc, 0, sizeof(tBTA_DM_DI_DISC_CMPL)); + bdcpy(di_disc.bd_addr, bta_dm_search_cb.peer_bdaddr); + di_disc.result = BTA_FAILURE; + + bta_dm_di_cb.p_di_db = NULL; + bta_dm_search_cb.p_search_cback(BTA_DM_DI_DISC_CMPL_EVT, NULL); + } + +#if (BLE_INCLUDED == TRUE) && (BTA_GATT_INCLUDED == TRUE) + if (bta_dm_search_cb.gatt_disc_active) + { + bta_dm_cancel_gatt_discovery(bta_dm_search_cb.peer_bdaddr); + } +#endif +} + +/******************************************************************************* +** ** Function bta_dm_di_disc ** ** Description This function queries a remote device for DI information. @@ -1561,7 +1680,8 @@ void bta_dm_sdp_result (tBTA_DM_MSG *p_data) { /* send result back to app now, one by one */ bdcpy (result.disc_ble_res.bd_addr, bta_dm_search_cb.peer_bdaddr); - BCM_STRNCPY_S((char*)result.disc_ble_res.bd_name, sizeof(BD_NAME), bta_dm_get_remname(), (BD_NAME_LEN-1)); + BCM_STRNCPY_S((char*)result.disc_ble_res.bd_name, sizeof(BD_NAME), bta_dm_get_remname(), (BD_NAME_LEN)); + result.disc_ble_res.bd_name[BD_NAME_LEN] = 0; result.disc_ble_res.service.len = service_uuid.len; result.disc_ble_res.service.uu.uuid16 = service_uuid.uu.uuid16; @@ -2022,7 +2142,7 @@ void bta_dm_search_cancel_notify (tBTA_DM_MSG *p_data) { BTM_CancelRemoteDeviceName(); } -#if ((BLE_INCLUDED == TRUE) && (defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)) +#if (BLE_INCLUDED == TRUE) && (BTA_GATT_INCLUDED == TRUE) if (bta_dm_search_cb.gatt_disc_active) { bta_dm_cancel_gatt_discovery(bta_dm_search_cb.peer_bdaddr); @@ -2535,22 +2655,25 @@ static void bta_dm_remname_cback (tBTM_REMOTE_DEV_NAME *p_remote_name) { tBTA_DM_REM_NAME * p_msg; - APPL_TRACE_DEBUG1("bta_dm_remname_cback name=<%s>", p_remote_name->remote_bd_name); + APPL_TRACE_DEBUG2("bta_dm_remname_cback len = %d name=<%s>", p_remote_name->length, + p_remote_name->remote_bd_name); /* remote name discovery is done but it could be failed */ bta_dm_search_cb.name_discover_done = TRUE; - BCM_STRNCPY_S((char*)bta_dm_search_cb.peer_name, sizeof(BD_NAME), (char*)p_remote_name->remote_bd_name, (BD_NAME_LEN-1)); - bta_dm_search_cb.peer_name[BD_NAME_LEN-1]=0; + BCM_STRNCPY_S((char*)bta_dm_search_cb.peer_name, sizeof(BD_NAME), (char*)p_remote_name->remote_bd_name, (BD_NAME_LEN)); + bta_dm_search_cb.peer_name[BD_NAME_LEN]=0; BTM_SecDeleteRmtNameNotifyCallback(&bta_dm_service_search_remname_cback); - +#if BLE_INCLUDED == TRUE + GAP_BleReadPeerPrefConnParams (bta_dm_search_cb.peer_bdaddr); +#endif if ((p_msg = (tBTA_DM_REM_NAME *) GKI_getbuf(sizeof(tBTA_DM_REM_NAME))) != NULL) { bdcpy (p_msg->result.disc_res.bd_addr, bta_dm_search_cb.peer_bdaddr); - BCM_STRNCPY_S((char*)p_msg->result.disc_res.bd_name, sizeof(BD_NAME), (char*)p_remote_name->remote_bd_name, (BD_NAME_LEN-1)); + BCM_STRNCPY_S((char*)p_msg->result.disc_res.bd_name, sizeof(BD_NAME), (char*)p_remote_name->remote_bd_name, (BD_NAME_LEN)); /* make sure the string is null terminated */ - p_msg->result.disc_res.bd_name[BD_NAME_LEN-1] = 0; + p_msg->result.disc_res.bd_name[BD_NAME_LEN] = 0; p_msg->hdr.event = BTA_DM_REMT_NAME_EVT; bta_sys_sendmsg(p_msg); @@ -2825,6 +2948,8 @@ static UINT8 bta_dm_authentication_complete_cback(BD_ADDR bd_addr, DEV_CLASS dev { bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event); } + /* delete this device entry from Sec Dev DB */ + bta_dm_remove_sec_dev_entry(bd_addr); } return BTM_SUCCESS; @@ -3074,6 +3199,7 @@ static void bta_dm_bl_change_cback (tBTM_BL_EVENT_DATA *p_data) break; case BTM_BL_UPDATE_EVT: p_msg->busy_level = p_data->update.busy_level; + p_msg->busy_level_flags = p_data->update.busy_level_flags; break; case BTM_BL_ROLE_CHG_EVT: p_msg->new_role = p_data->role_chg.new_role; @@ -3219,6 +3345,7 @@ void bta_dm_acl_change(tBTA_DM_MSG *p_data) if( bta_dm_cb.p_sec_cback ) { conn.busy_level.level = p_data->acl_change.busy_level; + conn.busy_level.level_flags = p_data->acl_change.busy_level_flags; bta_dm_cb.p_sec_cback(BTA_DM_BUSY_LEVEL_EVT, &conn); } return; @@ -3319,6 +3446,8 @@ void bta_dm_acl_change(tBTA_DM_MSG *p_data) issue_unpair_cb = TRUE; } + conn.link_down.is_removed = bta_dm_cb.device_list.peer_device[i].remove_dev_pending; + for(; i<bta_dm_cb.device_list.count ; i++) { memcpy(&bta_dm_cb.device_list.peer_device[i], &bta_dm_cb.device_list.peer_device[i+1], sizeof(bta_dm_cb.device_list.peer_device[i])); @@ -3351,6 +3480,16 @@ void bta_dm_acl_change(tBTA_DM_MSG *p_data) bta_sys_start_timer(&bta_dm_cb.disable_timer, 0, 1000); } } + if (conn.link_down.is_removed) + { + BTM_SecDeleteDevice(p_bda); +#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE) + /* need to remove all pending background connection */ + BTA_GATTC_CancelOpen(0, p_bda, FALSE); + /* remove all cached GATT information */ + BTA_GATTC_Refresh(p_bda); +#endif + } bdcpy(conn.link_down.bd_addr, p_bda); conn.link_down.status = (UINT8) btm_get_acl_disc_reason_code(); @@ -3379,6 +3518,9 @@ static void bta_dm_disable_conn_down_timer_cback (TIMER_LIST_ENT *p_tle) { tBTA_SYS_HW_MSG *sys_enable_event; + /* disable the power managment module */ + bta_dm_disable_pm(); + /* register our callback to SYS HW manager */ bta_sys_hw_register( BTA_SYS_HW_BLUETOOTH, bta_dm_sys_hw_cback ); @@ -3573,6 +3715,44 @@ static void bta_dm_delay_role_switch_cback(TIMER_LIST_ENT *p_tle) /******************************************************************************* ** +** Function bta_dm_remove_sec_dev_entry +** +** Description Removes device entry from Security device DB if ACL connection with +** remtoe device does not exist, else schedule for dev entry removal upon + ACL close +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_remove_sec_dev_entry(BD_ADDR remote_bd_addr) +{ + UINT16 index = 0; + if (BTM_IsAclConnectionUp(remote_bd_addr)) + { + APPL_TRACE_DEBUG1("%s ACL is not down. Schedule for Dev Removal when ACL closes", + __FUNCTION__); + for (index = 0; index < bta_dm_cb.device_list.count; index ++) + { + if (!bdcmp( bta_dm_cb.device_list.peer_device[index].peer_bdaddr, remote_bd_addr)) + break; + } + if (index != bta_dm_cb.device_list.count) + { + bta_dm_cb.device_list.peer_device[index].remove_dev_pending = TRUE; + } + else + { + APPL_TRACE_ERROR1(" %s Device does not exist in DB", __FUNCTION__); + } + } + else + { + BTM_SecDeleteDevice (remote_bd_addr); + } +} + +/******************************************************************************* +** ** Function bta_dm_adjust_roles ** ** Description Adjust roles @@ -3668,7 +3848,7 @@ static void bta_dm_adjust_roles(BOOLEAN delay_role_switch) *******************************************************************************/ static char *bta_dm_get_remname(void) { - char *p_name = bta_dm_search_cb.peer_name; + char *p_name = (char *)bta_dm_search_cb.peer_name; char *p_temp; /* If the name isn't already stored, try retrieving from BTM */ @@ -4048,16 +4228,6 @@ static void bta_dm_set_eir (char *local_name) free_eir_length -= p_bta_dm_eir_cfg->bta_dm_eir_flag_len + 2; } - /* if Inquiry Tx Resp Power compiled */ - if((p_bta_dm_eir_cfg->bta_dm_eir_inq_tx_power) && - (free_eir_length >= 3)) - { - UINT8_TO_STREAM(p, 2); /* Length field */ - UINT8_TO_STREAM(p, BTM_EIR_TX_POWER_LEVEL_TYPE); - UINT8_TO_STREAM(p, *(p_bta_dm_eir_cfg->bta_dm_eir_inq_tx_power)); - free_eir_length -= 3; - } - /* if Manufacturer Specific are provided in configuration */ if(( p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len > 0 ) &&( p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec ) @@ -4078,6 +4248,16 @@ static void bta_dm_set_eir (char *local_name) p_length = NULL; } + /* if Inquiry Tx Resp Power compiled */ + if ((p_bta_dm_eir_cfg->bta_dm_eir_inq_tx_power) && + (free_eir_length >= 3)) + { + UINT8_TO_STREAM(p, 2); /* Length field */ + UINT8_TO_STREAM(p, BTM_EIR_TX_POWER_LEVEL_TYPE); + UINT8_TO_STREAM(p, *(p_bta_dm_eir_cfg->bta_dm_eir_inq_tx_power)); + free_eir_length -= 3; + } + if( free_eir_length ) UINT8_TO_STREAM(p, 0); /* terminator of significant part */ @@ -4352,6 +4532,74 @@ void bta_dm_set_afh_channel_assesment (tBTA_DM_MSG * p_data) } #if (BLE_INCLUDED == TRUE) +/******************************************************************************* +** +** Function bta_dm_observe_results_cb +** +** Description Callback for BLE Observe result +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_observe_results_cb (tBTM_INQ_RESULTS *p_inq, UINT8 *p_eir) +{ +; + tBTA_DM_SEARCH result; + tBTM_INQ_INFO *p_inq_info; + UINT16 service_class; + APPL_TRACE_DEBUG0("bta_dm_observe_results_cb") + + bdcpy(result.inq_res.bd_addr, p_inq->remote_bd_addr); + result.inq_res.rssi = p_inq->rssi; + result.inq_res.ble_addr_type = p_inq->ble_addr_type; + result.inq_res.inq_result_type = p_inq->inq_result_type; + result.inq_res.device_type = p_inq->device_type; + + /* application will parse EIR to find out remote device name */ + result.inq_res.p_eir = p_eir; + + if((p_inq_info = BTM_InqDbRead(p_inq->remote_bd_addr)) != NULL) + { + /* initialize remt_name_not_required to FALSE so that we get the name by default */ + result.inq_res.remt_name_not_required = FALSE; + } + + if(bta_dm_search_cb.p_scan_cback) + bta_dm_search_cb.p_scan_cback(BTA_DM_INQ_RES_EVT, &result); + + if(p_inq_info) + { + /* application indicates if it knows the remote name, inside the callback + copy that to the inquiry data base*/ + if(result.inq_res.remt_name_not_required) + p_inq_info->appl_knows_rem_name = TRUE; + } +} + +/******************************************************************************* +** +** Function bta_dm_observe_cmpl_cb +** +** Description Callback for BLE Observe complete +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_observe_cmpl_cb (void * p_result) +{ + tBTA_DM_SEARCH data; + + APPL_TRACE_DEBUG0("bta_dm_observe_cmpl_cb"); + + data.inq_cmpl.num_resps = ((tBTM_INQUIRY_CMPL *)p_result)->num_resp; + if (bta_dm_search_cb.p_scan_cback) + { + bta_dm_search_cb.p_scan_cback(BTA_DM_INQ_CMPL_EVT, &data); + } +} + #if (SMP_INCLUDED == TRUE) /******************************************************************************* ** @@ -4367,6 +4615,9 @@ static UINT8 bta_dm_ble_smp_cback (tBTM_LE_EVT event, BD_ADDR bda, tBTM_LE_EVT_D { tBTM_STATUS status = BTM_SUCCESS; tBTA_DM_SEC sec_event; + UINT8 i; + + APPL_TRACE_DEBUG0("bta_dm_ble_smp_cback"); if (!bta_dm_cb.p_sec_cback) return BTM_NOT_AUTHORIZED; @@ -4394,13 +4645,15 @@ static UINT8 bta_dm_ble_smp_cback (tBTM_LE_EVT event, BD_ADDR bda, tBTM_LE_EVT_D case BTM_LE_SEC_REQUEST_EVT: bdcpy(sec_event.ble_req.bd_addr, bda); - BCM_STRNCPY_S((char*)sec_event.ble_req.bd_name, sizeof(BD_NAME), bta_dm_get_remname(), (BD_NAME_LEN-1)); + BCM_STRNCPY_S((char*)sec_event.ble_req.bd_name, sizeof(BD_NAME), bta_dm_get_remname(), (BD_NAME_LEN)); + sec_event.ble_req.bd_name[BD_NAME_LEN] = 0; bta_dm_cb.p_sec_cback(BTA_DM_BLE_SEC_REQ_EVT, &sec_event); break; case BTM_LE_KEY_NOTIF_EVT: bdcpy(sec_event.key_notif.bd_addr, bda); - BCM_STRNCPY_S((char*)sec_event.key_notif.bd_name, sizeof(BD_NAME), bta_dm_get_remname(), (BD_NAME_LEN-1)); + BCM_STRNCPY_S((char*)sec_event.key_notif.bd_name, sizeof(BD_NAME), bta_dm_get_remname(), (BD_NAME_LEN)); + sec_event.ble_req.bd_name[BD_NAME_LEN] = 0; sec_event.key_notif.passkey = p_data->key_notif; bta_dm_cb.p_sec_cback(BTA_DM_BLE_PASSKEY_NOTIF_EVT, &sec_event); break; @@ -4418,17 +4671,41 @@ static UINT8 bta_dm_ble_smp_cback (tBTM_LE_EVT event, BD_ADDR bda, tBTM_LE_EVT_D case BTM_LE_KEY_EVT: bdcpy(sec_event.ble_key.bd_addr, bda); sec_event.ble_key.key_type = p_data->key.key_type; - memcpy(&sec_event.ble_key.key_value, p_data->key.p_key_value, sizeof(tBTM_LE_KEY_VALUE)); + + if (p_data->key.key_type == BTM_LE_KEY_PID) + { + for (i=0; i<BT_OCTET16_LEN; i++ ) + { + sec_event.ble_key.key_value.pid_key.irk[i] = p_data->key.p_key_value->pid_key.irk[i]; + } + sec_event.ble_key.key_value.pid_key.addr_type = p_data->key.p_key_value->pid_key.addr_type; + memcpy( &(sec_event.ble_key.key_value.pid_key.static_addr), + &(p_data->key.p_key_value->pid_key.static_addr), + sizeof (BD_ADDR)); + } + else + { + memcpy(&sec_event.ble_key.key_value, p_data->key.p_key_value, sizeof(tBTM_LE_KEY_VALUE)); + } + // memcpy(&sec_event.ble_key.key_value, p_data->key.p_key_value, sizeof(tBTM_LE_KEY_VALUE)); todo will crash bta_dm_cb.p_sec_cback(BTA_DM_BLE_KEY_EVT, &sec_event); break; case BTM_LE_COMPLT_EVT: bdcpy(sec_event.auth_cmpl.bd_addr, bda); + BCM_STRNCPY_S((char*)sec_event.auth_cmpl.bd_name, sizeof(BD_NAME), bta_dm_get_remname(), (BD_NAME_LEN)); + if (p_data->complt.reason != 0) + { sec_event.auth_cmpl.fail_reason = BTA_DM_AUTH_CONVERT_SMP_CODE(((UINT8)p_data->complt.reason)); + /* delete this device entry from Sec Dev DB */ + bta_dm_remove_sec_dev_entry (bda); + } else + { sec_event.auth_cmpl.success = TRUE; - + } + sec_event.auth_cmpl.privacy_enabled = p_data->complt.privacy_supported; if (bta_dm_cb.p_sec_cback) { //bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event); @@ -4618,6 +4895,43 @@ void bta_dm_ble_set_scan_params (tBTA_DM_MSG *p_data) p_data->ble_set_scan_params.scan_window); } + +/******************************************************************************* +** +** Function bta_dm_ble_observe +** +** Description This function set the preferred connection scan parameters. +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_ble_observe (tBTA_DM_MSG *p_data) +{ + + tBTM_STATUS status; + if (p_data->ble_observe.start) + { + /*Save the callback to be called when a scan results are available */ + bta_dm_search_cb.p_scan_cback = p_data->ble_observe.p_cback; + if ((status = BTM_BleObserve(TRUE, p_data->ble_observe.duration, + bta_dm_observe_results_cb, bta_dm_observe_cmpl_cb))!= BTM_SUCCESS) + { + tBTA_DM_SEARCH data; + APPL_TRACE_WARNING2(" %s BTM_BleObserve failed. status %d",__FUNCTION__,status); + data.inq_cmpl.num_resps = 0; + if (bta_dm_search_cb.p_scan_cback) + { + bta_dm_search_cb.p_scan_cback(BTA_DM_INQ_CMPL_EVT, &data); + } + } + } + else + { + bta_dm_search_cb.p_scan_cback = NULL; + BTM_BleObserve(FALSE, 0, NULL,NULL ); + } +} + #if ((defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)) /******************************************************************************* @@ -4682,6 +4996,7 @@ static void bta_dm_gatt_disc_result(tBTA_GATT_ID service_id) /* send result back to app now, one by one */ bdcpy (result.disc_ble_res.bd_addr, bta_dm_search_cb.peer_bdaddr); BCM_STRNCPY_S((char*)result.disc_ble_res.bd_name, sizeof(BD_NAME), bta_dm_get_remname(), (BD_NAME_LEN-1)); + result.disc_ble_res.bd_name[BD_NAME_LEN] = 0; memcpy(&result.disc_ble_res.service, &service_id.uuid, sizeof(tBT_UUID)); bta_dm_search_cb.p_search_cback(BTA_DM_DISC_BLE_RES_EVT, &result); @@ -4719,6 +5034,8 @@ static void bta_dm_gatt_disc_complete(UINT16 conn_id, tBTA_GATT_STATUS status) p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT; p_msg->disc_result.result.disc_res.result = (status == BTA_GATT_OK) ? BTA_SUCCESS :BTA_FAILURE; p_msg->disc_result.result.disc_res.services = bta_dm_search_cb.services_found; + p_msg->disc_result.result.disc_res.num_uuids = 0; + p_msg->disc_result.result.disc_res.p_uuid_list = NULL; bdcpy (p_msg->disc_result.result.disc_res.bd_addr, bta_dm_search_cb.peer_bdaddr); BCM_STRNCPY_S((char*)p_msg->disc_result.result.disc_res.bd_name, sizeof(BD_NAME), bta_dm_get_remname(), (BD_NAME_LEN-1)); @@ -4882,5 +5199,4 @@ static void bta_dm_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC *p_data) } #endif /* BTA_GATT_INCLUDED */ - #endif /* BLE_INCLUDED */ diff --git a/bta/dm/bta_dm_api.c b/bta/dm/bta_dm_api.c index 06e3b936c..aedbe8106 100644 --- a/bta/dm/bta_dm_api.c +++ b/bta/dm/bta_dm_api.c @@ -1572,6 +1572,42 @@ void BTA_DmSearchExt(tBTA_DM_INQ *p_dm_inq, tBTA_SERVICE_MASK_EXT *p_services, t #endif } +/******************************************************************************* +** +** Function BTA_DmBleEnableRemotePrivacy +** +** Description Enable/disable privacy on a remote device +** +** Parameters: bd_addr - BD address of the peer +** privacy_enable - enable/disabe privacy on remote device. +** +** Returns void +** +*******************************************************************************/ +void BTA_DmBleEnableRemotePrivacy(BD_ADDR bd_addr, BOOLEAN privacy_enable) +{ +#if BLE_INCLUDED == TRUE +#endif +} + + +/******************************************************************************* +** +** Function BTA_DmBleConfigLocalPrivacy +** +** Description Enable/disable privacy on the local device +** +** Parameters: privacy_enable - enable/disabe privacy on remote device. +** +** Returns void +** +*******************************************************************************/ +void BTA_DmBleConfigLocalPrivacy(BOOLEAN privacy_enable) +{ +#if BLE_INCLUDED == TRUE +#endif +} + /******************************************************************************* ** @@ -1614,3 +1650,74 @@ void BTA_DmSetEncryption(BD_ADDR bd_addr, tBTA_DM_ENCRYPT_CBACK *p_callback, } } +/******************************************************************************* +** +** Function BTA_DmCloseACL +** +** Description This function force to close an ACL connection and remove the +** device from the security database list of known devices. +** +** Parameters: bd_addr - Address of the peer device +** remove_dev - remove device or not after link down +** +** Returns void +** +*******************************************************************************/ +void BTA_DmCloseACL(BD_ADDR bd_addr, BOOLEAN remove_dev) +{ + tBTA_DM_API_REMOVE_ACL *p_msg; + + APPL_TRACE_API0("BTA_DmCloseACL"); + + if ((p_msg = (tBTA_DM_API_REMOVE_ACL *) GKI_getbuf(sizeof(tBTA_DM_API_REMOVE_ACL))) != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_API_REMOVE_ACL)); + + p_msg->hdr.event = BTA_DM_API_REMOVE_ACL_EVT; + + memcpy(p_msg->bd_addr, bd_addr, BD_ADDR_LEN); + p_msg->remove_dev = remove_dev; + + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_DmBleObserve +** +** Description This procedure keep the device listening for advertising +** events from a broadcast device. +** +** Parameters start: start or stop observe. +** +** Returns void + +** +** Returns void. +** +*******************************************************************************/ +BTA_API extern void BTA_DmBleObserve(BOOLEAN start, UINT8 duration, + tBTA_DM_SEARCH_CBACK *p_results_cb) +{ +#if BLE_INCLUDED == TRUE + + tBTA_DM_API_BLE_OBSERVE *p_msg; + + APPL_TRACE_API1("BTA_DmBleObserve:start = %d ", start); + + if ((p_msg = (tBTA_DM_API_BLE_OBSERVE *) GKI_getbuf(sizeof(tBTA_DM_API_BLE_OBSERVE))) != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_API_BLE_OBSERVE)); + + p_msg->hdr.event = BTA_DM_API_BLE_OBSERVE_EVT; + p_msg->start = start; + p_msg->duration = duration; + p_msg->p_cback = p_results_cb; + + bta_sys_sendmsg(p_msg); + } +#endif +} + + diff --git a/bta/dm/bta_dm_cfg.c b/bta/dm/bta_dm_cfg.c index 5e2690955..a7c3cc4ec 100644 --- a/bta/dm/bta_dm_cfg.c +++ b/bta/dm/bta_dm_cfg.c @@ -240,14 +240,14 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = (BTA_DM_PM_SSR1), /* the SSR entry */ #endif { - {{BTA_DM_PM_SNIFF2, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ + {{BTA_DM_PM_SNIFF2, 30000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close, used for HH suspend */ - {{BTA_DM_PM_SNIFF2, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ - {{BTA_DM_PM_SNIFF2, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ + {{BTA_DM_PM_SNIFF2, 30000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_SNIFF2, 30000}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ } }, @@ -358,7 +358,9 @@ tBTA_DM_SSR_SPEC bta_dm_ssr_spec[] = { /*max_lat, min_rmt_to, min_loc_to*/ {0, 0, 0}, /* BTA_DM_PM_SSR0 - do not use SSR */ - {1600, 2, 2}, /* BTA_DM_PM_SSR1 - HH */ + {0, 0, 2}, /* BTA_DM_PM_SSR1 - HH, can NOT share entry with any other profile, + seting default max latency and min remote timeout as 0, + and always read individual device preference from HH module */ {1200, 2, 2}, /* BTA_DM_PM_SSR2 - others (as long as sniff is allowed)*/ {360, 160, 2} /* BTA_DM_PM_SSR3 - HD */ }; diff --git a/bta/dm/bta_dm_int.h b/bta/dm/bta_dm_int.h index 35b369d23..245c8712d 100644 --- a/bta/dm/bta_dm_int.h +++ b/bta/dm/bta_dm_int.h @@ -60,6 +60,7 @@ enum BTA_DM_API_TX_INQPWR_EVT, BTA_DM_ACL_CHANGE_EVT, BTA_DM_API_ADD_DEVICE_EVT, + BTA_DM_API_REMOVE_ACL_EVT, /* security API events */ BTA_DM_API_BOND_EVT, @@ -77,6 +78,7 @@ enum BTA_DM_API_SET_ENCRYPTION_EVT, + #if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE) BTA_DM_API_PASKY_CANCEL_EVT, #endif @@ -96,6 +98,7 @@ enum BTA_DM_API_BLE_SET_BG_CONN_TYPE, BTA_DM_API_BLE_CONN_PARAM_EVT, BTA_DM_API_BLE_SCAN_PARAM_EVT, + BTA_DM_API_BLE_OBSERVE_EVT, #endif #if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&( BTA_EIR_CANNED_UUID_LIST != TRUE )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) @@ -140,7 +143,7 @@ typedef struct typedef struct { BT_HDR hdr; - char name[BD_NAME_LEN]; + BD_NAME name; /* max 248 bytes name, plus must be Null terminated */ } tBTA_DM_API_SET_NAME; /* data type for BTA_DM_API_SET_VISIBILITY_EVT */ @@ -353,6 +356,7 @@ typedef struct BT_HDR hdr; tBTM_BL_EVENT event; UINT8 busy_level; + UINT8 busy_level_flags; BOOLEAN is_new; UINT8 new_role; BD_ADDR bd_addr; @@ -475,6 +479,20 @@ typedef struct }tBTA_DM_API_BLE_CONN_PARAMS; +typedef struct +{ + BT_HDR hdr; + BD_ADDR peer_bda; + BOOLEAN privacy_enable; + +}tBTA_DM_API_ENABLE_PRIVACY; + +typedef struct +{ + BT_HDR hdr; + BOOLEAN privacy_enable; +}tBTA_DM_API_LOCAL_PRIVACY; + /* set scan parameter for BLE connections */ typedef struct { @@ -483,7 +501,14 @@ typedef struct UINT16 scan_window; }tBTA_DM_API_BLE_SCAN_PARAMS; -#endif +/* Data type for start/stop observe */ +typedef struct +{ + BT_HDR hdr; + BOOLEAN start; + UINT16 duration; + tBTA_DM_SEARCH_CBACK * p_cback; +}tBTA_DM_API_BLE_OBSERVE; typedef struct { @@ -491,6 +516,25 @@ typedef struct BOOLEAN enable_or_disable; }tBTA_DM_API_SET_AFH_CHANNEL_ASSESSMENT; + +/* set adv parameter for BLE advertising */ +typedef struct +{ + BT_HDR hdr; + UINT16 adv_int_min; + UINT16 adv_int_max; + tBLE_BD_ADDR *p_dir_bda; +}tBTA_DM_API_BLE_ADV_PARAMS; + +typedef struct +{ + BT_HDR hdr; + UINT16 data_mask; + tBTA_BLE_ADV_DATA *p_adv_cfg; +}tBTA_DM_API_SET_ADV_CONFIG; + +#endif + #if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&( BTA_EIR_CANNED_UUID_LIST != TRUE )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) /* data type for BTA_DM_API_UPDATE_EIR_UUID_EVT */ typedef struct @@ -510,6 +554,14 @@ typedef struct }tBTA_DM_API_SET_EIR_CONFIG; #endif +/* data type for BTA_DM_API_REMOVE_ACL_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + BOOLEAN remove_dev; +}tBTA_DM_API_REMOVE_ACL; + /* union of all data types */ typedef union { @@ -580,6 +632,11 @@ typedef union tBTA_DM_API_BLE_SET_BG_CONN_TYPE ble_set_bd_conn_type; tBTA_DM_API_BLE_CONN_PARAMS ble_set_conn_params; tBTA_DM_API_BLE_SCAN_PARAMS ble_set_scan_params; + tBTA_DM_API_BLE_OBSERVE ble_observe; + tBTA_DM_API_ENABLE_PRIVACY ble_remote_privacy; + tBTA_DM_API_LOCAL_PRIVACY ble_local_privacy; + tBTA_DM_API_BLE_ADV_PARAMS ble_set_adv_params; + tBTA_DM_API_SET_ADV_CONFIG ble_set_adv_data; #endif tBTA_DM_API_SET_AFH_CHANNEL_ASSESSMENT set_afh_channel_assessment; @@ -590,6 +647,7 @@ typedef union #if (BTM_EIR_SERVER_INCLUDED == TRUE) tBTA_DM_API_SET_EIR_CONFIG set_eir_cfg; #endif + tBTA_DM_API_REMOVE_ACL remove_acl; } tBTA_DM_MSG; @@ -623,6 +681,7 @@ typedef struct #endif tBTA_DM_PM_ACTTION pm_mode_attempted; tBTA_DM_PM_ACTTION pm_mode_failed; + BOOLEAN remove_dev_pending; } tBTA_DM_PEER_DEVICE; @@ -738,7 +797,7 @@ typedef struct UINT16 state; BD_ADDR peer_bdaddr; BOOLEAN name_discover_done; - char peer_name[BD_NAME_LEN]; + BD_NAME peer_name; TIMER_LIST_ENT search_timer; UINT8 service_index; tBTA_DM_MSG * p_search_queue; /* search or discover commands during search cancel stored here */ @@ -749,6 +808,7 @@ typedef struct BOOLEAN sdp_search; #if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) + tBTA_DM_SEARCH_CBACK * p_scan_cback; #if ((defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)) tBTA_GATTC_IF client_if; UINT8 num_uuid; @@ -917,6 +977,7 @@ extern void bta_dm_tx_inqpower(tBTA_DM_MSG *p_data); extern void bta_dm_acl_change(tBTA_DM_MSG *p_data); extern void bta_dm_add_device (tBTA_DM_MSG *p_data); extern void bta_dm_remove_device (tBTA_DM_MSG *p_data); +extern void bta_dm_close_acl(tBTA_DM_MSG *p_data); extern void bta_dm_pm_btm_status(tBTA_DM_MSG *p_data); @@ -931,6 +992,7 @@ extern void bta_dm_security_grant (tBTA_DM_MSG *p_data); extern void bta_dm_ble_set_bg_conn_type (tBTA_DM_MSG *p_data); extern void bta_dm_ble_set_conn_params (tBTA_DM_MSG *p_data); extern void bta_dm_ble_set_scan_params (tBTA_DM_MSG *p_data); +extern void bta_dm_ble_observe (tBTA_DM_MSG *p_data); #endif extern void bta_dm_set_encryption(tBTA_DM_MSG *p_data); extern void bta_dm_confirm(tBTA_DM_MSG *p_data); diff --git a/bta/dm/bta_dm_main.c b/bta/dm/bta_dm_main.c index a2fec0474..dc94c6c4c 100644 --- a/bta/dm/bta_dm_main.c +++ b/bta/dm/bta_dm_main.c @@ -58,6 +58,7 @@ const tBTA_DM_ACTION bta_dm_action[] = bta_dm_tx_inqpower, /* 7 BTA_DM_API_SIG_STRENGTH_EVT */ bta_dm_acl_change, /* 8 BTA_DM_ACL_CHANGE_EVT */ bta_dm_add_device, /* 9 BTA_DM_API_ADD_DEVICE_EVT */ + bta_dm_close_acl, /* 10 BTA_DM_API_ADD_DEVICE_EVT */ /* security API events */ bta_dm_bond, /* 10 BTA_DM_API_BOND_EVT */ @@ -94,6 +95,7 @@ const tBTA_DM_ACTION bta_dm_action[] = bta_dm_ble_set_bg_conn_type, bta_dm_ble_set_conn_params, /* BTA_DM_API_BLE_CONN_PARAM_EVT */ bta_dm_ble_set_scan_params, /* BTA_DM_API_BLE_SCAN_PARAM_EVT */ + bta_dm_ble_observe, #endif #if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&( BTA_EIR_CANNED_UUID_LIST != TRUE )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) @@ -211,8 +213,8 @@ const UINT8 bta_dm_search_search_cancelling_st_table[][BTA_DM_SEARCH_NUM_COLS] = /* INQUIRY_CMPL */ {BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE}, /* REMT_NAME_EVT */ {BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL, BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IDLE}, /* SDP_RESULT_EVT */ {BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL, BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IDLE}, -/* SEARCH_CMPL_EVT */ {BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE}, -/* DISCV_RES_EVT */ {BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE}, +/* SEARCH_CMPL_EVT */ {BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL, BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IDLE}, +/* DISCV_RES_EVT */ {BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL, BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IDLE}, /* API_DI_DISCOVER_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_CANCELLING} diff --git a/bta/dm/bta_dm_pm.c b/bta/dm/bta_dm_pm.c index 8a993de22..cb5da6faf 100644 --- a/bta/dm/bta_dm_pm.c +++ b/bta/dm/bta_dm_pm.c @@ -42,9 +42,14 @@ static BOOLEAN bta_dm_pm_sniff(tBTA_DM_PEER_DEVICE *p_peer_dev, UINT8 index); static BOOLEAN bta_dm_pm_is_sco_active (); static void bta_dm_pm_hid_check(BOOLEAN bScoActive); static void bta_dm_pm_set_sniff_policy(tBTA_DM_PEER_DEVICE *p_dev, BOOLEAN bDisable); + #if (BTM_SSR_INCLUDED == TRUE) +#if (defined BTA_HH_INCLUDED && BTA_HH_INCLUDED == TRUE) +#include "../hh/bta_hh_int.h" +/* BTA_DM_PM_SSR1 will be dedicated for HH SSR setting entry, no other profile can use it */ +#define BTA_DM_PM_SSR_HH BTA_DM_PM_SSR1 +#endif static void bta_dm_pm_ssr(BD_ADDR peer_addr); -static void bta_dm_ssr_cfg_cback(UINT8 id, UINT8 app_id, UINT16 max_lat, UINT16 min_rmt_to); #endif tBTA_DM_CONNECTED_SRVCS bta_dm_conn_srvcs; @@ -70,9 +75,6 @@ void bta_dm_init_pm(void) { bta_sys_pm_register((tBTA_SYS_CONN_CBACK*)bta_dm_pm_cback); -#if (BTM_SSR_INCLUDED == TRUE) - bta_sys_ssr_cfg_register((tBTA_SYS_SSR_CFG_CBACK*)bta_dm_ssr_cfg_cback); -#endif BTM_PmRegister((BTM_PM_REG_SET | BTM_PM_REG_NOTIF), &bta_dm_cb.pm_id, bta_dm_pm_btm_cback); } @@ -165,13 +167,16 @@ static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, btm_status = BTM_ReadLocalVersion (&vers); p_dev = bta_dm_find_peer_device(peer_addr); - /* Disable/Enable sniff policy on the SCO link if sco Up/Down. Will be removed in 2.2*/ - if ((btm_status == BTM_SUCCESS) && - (vers.manufacturer == LMP_COMPID_BROADCOM) && - (vers.hci_version < HCI_PROTO_VERSION_2_0) && + /* Disable/Enable sniff policy on the SCO link if sco Up/Down. Will be removed in 2.2*/ + if ((p_dev) && ((status == BTA_SYS_SCO_OPEN) || (status == BTA_SYS_SCO_CLOSE)) ) + { + if ((btm_status == BTM_SUCCESS) && + (vers.manufacturer == LMP_COMPID_BROADCOM) && + (vers.hci_version < HCI_PROTO_VERSION_2_0)) { - bta_dm_pm_set_sniff_policy(p_dev, (status == BTA_SYS_SCO_OPEN)); + bta_dm_pm_set_sniff_policy(p_dev, (status == BTA_SYS_SCO_OPEN)); + } } /* find if there is an power mode entry for the service */ @@ -272,7 +277,11 @@ static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, } #if (BTM_SSR_INCLUDED == TRUE) - if(p_bta_dm_ssr_spec[index].max_lat) + if(p_bta_dm_ssr_spec[index].max_lat +#if (defined BTA_HH_INCLUDED && BTA_HH_INCLUDED == TRUE) + || index == BTA_DM_PM_SSR_HH +#endif + ) { bta_dm_pm_ssr(peer_addr); } @@ -559,7 +568,6 @@ static BOOLEAN bta_dm_pm_sniff(tBTA_DM_PEER_DEVICE *p_peer_dev, UINT8 index) return TRUE; } - /******************************************************************************* ** ** Function bta_dm_pm_ssr @@ -599,6 +607,14 @@ static void bta_dm_pm_ssr(BD_ADDR peer_addr) p_spec_cur = &p_bta_dm_ssr_spec[p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr]; p_spec = &p_bta_dm_ssr_spec[ssr]; +#if (defined BTA_HH_INCLUDED && BTA_HH_INCLUDED == TRUE) + /* HH has the per connection SSR preference, already read the SSR params from BTA HH */ + if (p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr == BTA_DM_PM_SSR_HH) + { + if (bta_hh_read_ssr_param(peer_addr, &p_spec_cur->max_lat, &p_spec_cur->min_rmt_to) == BTA_HH_ERR) + continue; + } +#endif if (p_spec_cur->max_lat < p_spec->max_lat || (ssr == BTA_DM_PM_SSR0 && p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr != BTA_DM_PM_SSR0)) { @@ -617,44 +633,6 @@ static void bta_dm_pm_ssr(BD_ADDR peer_addr) p_spec->min_rmt_to, p_spec->min_loc_to); } } -/******************************************************************************* -** -** Function bta_dm_ssr_cfg_cback -** -** Description Conn change callback from sys for low power management -** -** -** Returns void -** -*******************************************************************************/ -static void bta_dm_ssr_cfg_cback(UINT8 id, UINT8 app_id, - UINT16 max_lat, UINT16 min_rmt_to) -{ - tBTA_DM_SSR_SPEC *p_spec; - UINT8 i, index; - /* find if there is an power mode entry for the service */ - for(i=1; i<=p_bta_dm_pm_cfg[0].app_id; i++) - { - - if((p_bta_dm_pm_cfg[i].id == id) - && ((p_bta_dm_pm_cfg[i].app_id == BTA_ALL_APP_ID ) || (p_bta_dm_pm_cfg[i].app_id == app_id ))) - break; - - } - /* if no entries are there for the app_id and subystem in p_bta_dm_pm_spec*/ - if(i> p_bta_dm_pm_cfg[0].app_id) - return; - - index = p_bta_dm_pm_spec[p_bta_dm_pm_cfg[i].spec_idx].ssr; - - APPL_TRACE_DEBUG2("SSR parameter changed to: max_latency: %d min_tout: %d", max_lat, min_rmt_to); - - p_spec = &p_bta_dm_ssr_spec[index]; - p_spec->max_lat = max_lat; - p_spec->min_rmt_to = min_rmt_to; -} - - #endif /******************************************************************************* ** diff --git a/bta/gatt/bta_gattc_act.c b/bta/gatt/bta_gattc_act.c index 5cacf03ef..25260f998 100644 --- a/bta/gatt/bta_gattc_act.c +++ b/bta/gatt/bta_gattc_act.c @@ -146,7 +146,6 @@ void bta_gattc_register(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data) (*p_data->api_reg.p_cback)(BTA_GATTC_REG_EVT, (tBTA_GATTC *)&cb_data); } } - /******************************************************************************* ** ** Function bta_gattc_start_if @@ -167,8 +166,6 @@ void bta_gattc_start_if(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_msg) APPL_TRACE_ERROR1("Unable to start app.: Unknown interface =%d",p_msg->int_start_if.client_if ); } } - - /******************************************************************************* ** ** Function bta_gattc_deregister_cmpl @@ -225,7 +222,6 @@ void bta_gattc_deregister_cmpl(tBTA_GATTC_RCB *p_clreg, tBTA_GATTC_IF client_if) } } - /******************************************************************************* ** ** Function bta_gattc_deregister @@ -263,8 +259,6 @@ void bta_gattc_int_deregister(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data) APPL_TRACE_ERROR1("bta_gattc_int_deregister Deregister Failed, unknown client_if: %d", p_data->int_dereg.client_if); } } - - /******************************************************************************* ** ** Function bta_gattc_deregister @@ -364,7 +358,7 @@ void bta_gattc_process_api_open_cancel (tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p UINT16 event = ((BT_HDR *)p_msg)->event; tBTA_GATTC_CLCB *p_clcb = NULL; tBTA_GATTC_RCB *p_clreg; - tBTA_GATT_STATUS status = BTA_GATT_ERROR; + tBTA_GATTC cb_data; if (p_msg->api_cancel_conn.is_direct) { @@ -381,7 +375,8 @@ void bta_gattc_process_api_open_cancel (tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p if (p_clreg && p_clreg->p_cback) { - (*p_clreg->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, (tBTA_GATTC *)&status); + cb_data.status = BTA_GATT_ERROR; + (*p_clreg->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data); } } } @@ -391,7 +386,6 @@ void bta_gattc_process_api_open_cancel (tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p } } - /******************************************************************************* ** ** Function bta_gattc_cancel_open_error @@ -403,10 +397,11 @@ void bta_gattc_process_api_open_cancel (tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p *******************************************************************************/ void bta_gattc_cancel_open_error(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) { - tBTA_GATT_STATUS status=BTA_GATT_ERROR; + tBTA_GATTC cb_data; + cb_data.status=BTA_GATT_ERROR; - if ( p_clcb->p_rcb->p_cback ) - (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, (tBTA_GATTC *)&status); + if ( p_clcb && p_clcb->p_rcb && p_clcb->p_rcb->p_cback ) + (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data); } /******************************************************************************* @@ -493,7 +488,7 @@ void bta_gattc_init_bk_conn(tBTA_GATTC_API_OPEN *p_data, tBTA_GATTC_RCB *p_clreg tBTA_GATTC_CLCB *p_clcb; tBTA_GATTC_DATA gattc_data; - if (bta_gattc_mark_bg_conn(p_data->client_if, p_data->remote_bda, TRUE)) + if (bta_gattc_mark_bg_conn(p_data->client_if, p_data->remote_bda, TRUE, FALSE)) { /* alwaya call open to hold a connection */ if (!GATT_Connect(p_data->client_if, p_data->remote_bda, FALSE)) @@ -540,14 +535,15 @@ void bta_gattc_init_bk_conn(tBTA_GATTC_API_OPEN *p_data, tBTA_GATTC_RCB *p_clreg void bta_gattc_cancel_bk_conn(tBTA_GATTC_API_CANCEL_OPEN *p_data) { tBTA_GATTC_RCB *p_clreg; - tBTA_GATT_STATUS status = BTA_GATT_ERROR; + tBTA_GATTC cb_data; + cb_data.status = BTA_GATT_ERROR; /* remove the device from the bg connection mask */ - if (bta_gattc_mark_bg_conn(p_data->client_if, p_data->remote_bda, FALSE)) + if (bta_gattc_mark_bg_conn(p_data->client_if, p_data->remote_bda, FALSE, FALSE)) { if (GATT_CancelConnect(p_data->client_if, p_data->remote_bda, FALSE)) { - status = BTA_GATT_OK; + cb_data.status = BTA_GATT_OK; } else { @@ -558,7 +554,7 @@ void bta_gattc_cancel_bk_conn(tBTA_GATTC_API_CANCEL_OPEN *p_data) if (p_clreg && p_clreg->p_cback) { - (*p_clreg->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, (tBTA_GATTC *)&status); + (*p_clreg->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data); } } @@ -573,16 +569,16 @@ void bta_gattc_cancel_bk_conn(tBTA_GATTC_API_CANCEL_OPEN *p_data) *******************************************************************************/ void bta_gattc_cancel_open_ok(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) { - tBTA_GATT_STATUS status = BTA_GATT_OK; + tBTA_GATTC cb_data; if ( p_clcb->p_rcb->p_cback ) { - (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, (tBTA_GATTC *)&status); + cb_data.status = BTA_GATT_OK; + (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data); } bta_gattc_clcb_dealloc(p_clcb); } - /******************************************************************************* ** ** Function bta_gattc_cancel_open @@ -594,7 +590,7 @@ void bta_gattc_cancel_open_ok(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) *******************************************************************************/ void bta_gattc_cancel_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) { - tBTA_GATT_STATUS status=BTA_GATT_ERROR; + tBTA_GATTC cb_data; if (GATT_CancelConnect(p_clcb->p_rcb->client_if, p_data->api_cancel_conn.remote_bda, TRUE)) { @@ -604,7 +600,8 @@ void bta_gattc_cancel_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) { if ( p_clcb->p_rcb->p_cback ) { - (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, (tBTA_GATTC *)&status); + cb_data.status = BTA_GATT_ERROR; + (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data); } } } @@ -631,7 +628,8 @@ void bta_gattc_conn(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) GATT_GetConnectionInfor(p_data->hdr.layer_specific, &gatt_if, p_clcb->bda); /* start database cache if needed */ - if (p_clcb->p_srcb->p_srvc_cache == NULL) + if (p_clcb->p_srcb->p_srvc_cache == NULL || + p_clcb->p_srcb->state != BTA_GATTC_SERV_IDLE) { if (p_clcb->p_srcb->state == BTA_GATTC_SERV_IDLE) { @@ -662,7 +660,6 @@ void bta_gattc_conn(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) } } } - /******************************************************************************* ** ** Function bta_gattc_close_fail @@ -717,26 +714,16 @@ void bta_gattc_close(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) if (p_clcb->status == BTA_GATT_OK) { - /* if the srcb is no longer needed, reset the state */ - if ( -- p_clcb->p_srcb->num_clcb == 0) - { - APPL_TRACE_DEBUG0("Update srcb connection status"); - p_clcb->p_srcb->connected = FALSE; - p_clcb->p_srcb->state = BTA_GATTC_SERV_IDLE; - } - bta_gattc_clcb_dealloc(p_clcb); } ( * p_cback)(BTA_GATTC_CLOSE_EVT, (tBTA_GATTC *)&cb_data); - if (-- p_clreg->num_clcb == 0 && p_clreg->dereg_pending) + if (p_clreg->num_clcb == 0 && p_clreg->dereg_pending) { bta_gattc_deregister_cmpl(p_clreg, p_clreg->client_if); } - } - /******************************************************************************* ** ** Function bta_gattc_reset_discover_st @@ -746,7 +733,7 @@ void bta_gattc_close(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) ** Returns None. ** *******************************************************************************/ -void bta_gattc_reset_discover_st(tBTA_GATTC_SERV *p_srcb) +void bta_gattc_reset_discover_st(tBTA_GATTC_SERV *p_srcb, tBTA_GATT_STATUS status) { tBTA_GATTC_CB *p_cb = &bta_gattc_cb; UINT8 i; @@ -755,12 +742,29 @@ void bta_gattc_reset_discover_st(tBTA_GATTC_SERV *p_srcb) { if (p_cb->clcb[i].p_srcb == p_srcb) { + p_cb->clcb[i].status = status; bta_gattc_sm_execute(&p_cb->clcb[i], BTA_GATTC_DISCOVER_CMPL_EVT, NULL); } } } /******************************************************************************* ** +** Function bta_gattc_disc_close +** +** Description close a GATTC connection while in discovery state. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_disc_close(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + APPL_TRACE_DEBUG1("Discovery cancel conn_id=%d",p_clcb->bta_conn_id); + + bta_gattc_reset_discover_st(p_clcb->p_srcb, BTA_GATT_ERROR); + bta_gattc_sm_execute(p_clcb, BTA_GATTC_API_CLOSE_EVT, p_data); +} +/******************************************************************************* +** ** Function bta_gattc_set_discover_st ** ** Description when a SRCB start discovery, tell all related clcb and set @@ -781,12 +785,29 @@ void bta_gattc_set_discover_st(tBTA_GATTC_SERV *p_srcb) { if (p_cb->clcb[i].p_srcb == p_srcb) { + p_cb->clcb[i].status = BTA_GATT_OK; p_cb->clcb[i].state = BTA_GATTC_DISCOVER_ST; } } } /******************************************************************************* ** +** Function bta_gattc_restart_discover +** +** Description process service change in discovery state, mark up the auto +** update flag and set status to be discovery cancel for current +** discovery. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_restart_discover(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + p_clcb->status = BTA_GATT_CANCEL; + p_clcb->auto_update = BTA_GATTC_DISC_WAITING; +} +/******************************************************************************* +** ** Function bta_gattc_start_discover ** ** Description Start a discovery on server. @@ -796,16 +817,14 @@ void bta_gattc_set_discover_st(tBTA_GATTC_SERV *p_srcb) *******************************************************************************/ void bta_gattc_start_discover(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) { - /* pending operation, wait until it finishes */ - APPL_TRACE_DEBUG1("bta_gattc_start_discover conn_id=%d",p_clcb->bta_conn_id); - if (p_clcb->p_q_cmd != NULL && p_clcb->auto_update == BTA_GATTC_NO_SCHEDULE && - p_clcb->p_srcb->state == BTA_GATTC_SERV_IDLE) - { - p_clcb->auto_update = BTA_GATTC_DISC_WAITING; - p_clcb->state = BTA_GATTC_CONN_ST; /* set clcb state */ - } - else /* no pending operation, start discovery right away */ + APPL_TRACE_DEBUG2("bta_gattc_start_discover conn_id=%d p_clcb->p_srcb->state = %d ", + p_clcb->bta_conn_id, p_clcb->p_srcb->state); + + if (((p_clcb->p_q_cmd == NULL || p_clcb->auto_update == BTA_GATTC_REQ_WAITING) && + p_clcb->p_srcb->state == BTA_GATTC_SERV_IDLE) || + p_clcb->p_srcb->state == BTA_GATTC_SERV_DISC) + /* no pending operation, start discovery right away */ { p_clcb->auto_update = BTA_GATTC_NO_SCHEDULE; @@ -814,15 +833,19 @@ void bta_gattc_start_discover(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) /* clear the service change mask */ p_clcb->p_srcb->srvc_hdl_chg = FALSE; p_clcb->p_srcb->update_count = 0; + p_clcb->p_srcb->state = BTA_GATTC_SERV_DISC_ACT; /* set all srcb related clcb into discovery ST */ bta_gattc_set_discover_st(p_clcb->p_srcb); - if ( bta_gattc_init_cache(p_clcb->p_srcb) || - bta_gattc_discover_pri_service(p_clcb->bta_conn_id, p_clcb->p_srcb, GATT_DISC_SRVC_ALL) != BTA_GATT_OK) + if ((p_clcb->status = bta_gattc_init_cache(p_clcb->p_srcb)) == BTA_GATT_OK) + { + p_clcb->status = bta_gattc_discover_pri_service(p_clcb->bta_conn_id, p_clcb->p_srcb, GATT_DISC_SRVC_ALL); + } + if (p_clcb->status != BTA_GATT_OK) { APPL_TRACE_ERROR0("discovery on server failed"); - bta_gattc_reset_discover_st(p_clcb->p_srcb); + bta_gattc_reset_discover_st(p_clcb->p_srcb, p_clcb->status); } } else @@ -830,6 +853,15 @@ void bta_gattc_start_discover(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) APPL_TRACE_ERROR0("unknown device, can not start discovery"); } } + /* pending operation, wait until it finishes */ + else + { + p_clcb->auto_update = BTA_GATTC_DISC_WAITING; + + if (p_clcb->p_srcb->state == BTA_GATTC_SERV_IDLE) + p_clcb->state = BTA_GATTC_CONN_ST; /* set clcb state */ + } + } /******************************************************************************* ** @@ -850,11 +882,31 @@ void bta_gattc_disc_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) #endif p_clcb->p_srcb->state = BTA_GATTC_SERV_IDLE; + if (p_clcb->status != GATT_SUCCESS) + { + /* clean up cache */ + if(p_clcb->p_srcb && p_clcb->p_srcb->p_srvc_cache) + { + while (p_clcb->p_srcb->cache_buffer.p_first) + { + GKI_freebuf (GKI_dequeue (&p_clcb->p_srcb->cache_buffer)); + } + p_clcb->p_srcb->p_srvc_cache = NULL; + } + + /* used to reset cache in application */ + bta_gattc_co_cache_reset(p_clcb->p_srcb->server_bda); + } /* release pending attribute list buffer */ utl_freebuf((void **)&p_clcb->p_srcb->p_srvc_list); + if (p_clcb->auto_update == BTA_GATTC_DISC_WAITING) + { + /* start discovery again */ + bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL); + } /* get any queued command to proceed */ - if (p_q_cmd != NULL) + else if (p_q_cmd != NULL) { p_clcb->p_q_cmd = NULL; @@ -1063,7 +1115,6 @@ void bta_gattc_execute(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) } } } - /******************************************************************************* ** ** Function bta_gattc_confirm @@ -1220,8 +1271,6 @@ void bta_gattc_exec_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data) ( *p_clcb->p_rcb->p_cback)(BTA_GATTC_EXEC_EVT, &cb_data); } - - /******************************************************************************* ** ** Function bta_gattc_op_cmpl @@ -1384,6 +1433,7 @@ void bta_gattc_ci_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) } else { + p_clcb->p_srcb->state = BTA_GATTC_SERV_DISC; /* cache open failure, start discovery */ bta_gattc_start_discover(p_clcb, NULL); } @@ -1401,7 +1451,7 @@ void bta_gattc_ci_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) { p_clcb->p_srcb->attr_index = 0; bta_gattc_co_cache_close(p_clcb->p_srcb->server_bda, p_clcb->bta_conn_id); - bta_gattc_reset_discover_st(p_clcb->p_srcb); + bta_gattc_reset_discover_st(p_clcb->p_srcb, p_clcb->status); } } @@ -1431,7 +1481,7 @@ void bta_gattc_ci_load(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) if (p_data->ci_load.status == BTA_GATT_OK) { p_clcb->p_srcb->attr_index = 0; - bta_gattc_reset_discover_st(p_clcb->p_srcb); + bta_gattc_reset_discover_st(p_clcb->p_srcb, BTA_GATT_OK); } else /* load more */ @@ -1446,6 +1496,7 @@ void bta_gattc_ci_load(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) } else { + p_clcb->p_srcb->state = BTA_GATTC_SERV_DISC; p_clcb->p_srcb->attr_index = 0; /* cache open failure, start discovery */ bta_gattc_start_discover(p_clcb, NULL); @@ -1469,10 +1520,9 @@ void bta_gattc_ci_save(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) { p_clcb->p_srcb->attr_index = 0; bta_gattc_co_cache_close(p_clcb->p_srcb->server_bda, 0); - bta_gattc_reset_discover_st(p_clcb->p_srcb); + bta_gattc_reset_discover_st(p_clcb->p_srcb, p_clcb->status); } } - /******************************************************************************* ** ** Function bta_gattc_fail @@ -1504,20 +1554,28 @@ static void bta_gattc_conn_cback(tGATT_IF gattc_if, BD_ADDR bda, UINT16 conn_id, { BT_HDR *p_buf; tBTA_GATTC_CLCB *p_clcb = NULL; - +#if BLE_INCLUDED == TRUE + UINT8 role ; +#endif APPL_TRACE_DEBUG4("bta_gattc_conn_cback: cif = %d connected = %d conn_id = %d reaosn = 0x%04x", gattc_if, connected, conn_id, reason); if (connected) { +#if BLE_INCLUDED == TRUE + role = L2CA_GetBleConnRole(bda); + + if (role == HCI_ROLE_SLAVE) + bta_gattc_conn_find_alloc(bda); +#endif + /* outgoing connection : locate a logic channel */ if ((p_clcb = bta_gattc_find_clcb_by_cif(gattc_if, bda)) == NULL) { - #if BLE_INCLUDED == TRUE - /* for a background connection */ - if (L2CA_GetBleConnRole(bda)== HCI_ROLE_MASTER && - bta_gattc_check_bg_conn(gattc_if, bda)) + /* for a background connection or listening connection */ + if (/* L2CA_GetBleConnRole(bda)== HCI_ROLE_MASTER && */ + bta_gattc_check_bg_conn(gattc_if, bda, role)) { /* allocate a new channel */ p_clcb = bta_gattc_clcb_alloc(gattc_if, bda); @@ -1539,10 +1597,13 @@ static void bta_gattc_conn_cback(tGATT_IF gattc_if, BD_ADDR bda, UINT16 conn_id, } else { +#if BLE_INCLUDED == TRUE + bta_gattc_conn_dealloc(bda); +#endif /* connection attempt timeout, send connection callback event */ if (reason == GATT_CONN_CANCEL ) { - p_clcb = bta_gattc_clcb_alloc(gattc_if, bda); + p_clcb = bta_gattc_find_alloc_clcb(gattc_if, bda); p_clcb->bta_conn_id = conn_id; } if ((p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id)) != NULL) @@ -1564,6 +1625,55 @@ static void bta_gattc_conn_cback(tGATT_IF gattc_if, BD_ADDR bda, UINT16 conn_id, } /******************************************************************************* ** +** Function bta_gattc_process_api_refresh +** +** Description process refresh API to delete cache and start a new discovery +** if currently connected. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_process_api_refresh(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p_msg) +{ + tBTA_GATTC_SERV *p_srvc_cb = bta_gattc_find_srvr_cache(p_msg->api_conn.remote_bda); + tBTA_GATTC_CLCB *p_clcb = &bta_gattc_cb.clcb[0]; + BOOLEAN found = FALSE; + UINT8 i; + + if (p_srvc_cb != NULL) + { + /* try to find a CLCB */ + if (p_srvc_cb->connected && p_srvc_cb->num_clcb != 0) + { + for (i = 0; i < BTA_GATTC_CLCB_MAX; i ++, p_clcb ++) + { + if (p_clcb->in_use && p_clcb->p_srcb == p_srvc_cb) + { + found = TRUE; + break; + } + } + if (found) + { + bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL); + return; + } + } + /* in all other cases, mark it and delete the cache */ + if (p_srvc_cb->p_srvc_cache != NULL) + { + while (p_srvc_cb->cache_buffer.p_first) + GKI_freebuf (GKI_dequeue (&p_srvc_cb->cache_buffer)); + + p_srvc_cb->p_srvc_cache = NULL; + } + } + /* used to reset cache in application */ + bta_gattc_co_cache_reset(p_msg->api_conn.remote_bda); + +} +/******************************************************************************* +** ** Function bta_gattc_process_srvc_chg_ind ** ** Description process service change indication. @@ -1624,7 +1734,6 @@ BOOLEAN bta_gattc_process_srvc_chg_ind(UINT16 conn_id, /* notify applicationf or service change */ if (p_clrcb->p_cback != NULL) { - APPL_TRACE_ERROR0("bta_gattc_process_srvc_chg_ind 2"); (* p_clrcb->p_cback)(BTA_GATTC_SRVC_CHG_EVT, (tBTA_GATTC *)p_srcb->server_bda); } @@ -1746,7 +1855,6 @@ void bta_gattc_process_indicate(UINT16 conn_id, tGATTC_OPTYPE op, tGATT_CL_COMPL APPL_TRACE_ERROR1("Indi/Notif for Unknown handle[0x%04x], can not find in local cache.", handle); } } - /******************************************************************************* ** ** Function bta_gattc_cmpl_cback @@ -1799,4 +1907,45 @@ static void bta_gattc_cmpl_cback(UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS return; } +#if BLE_INCLUDED == TRUE +/******************************************************************************* +** +** Function bta_gattc_init_clcb_conn +** +** Description Initaite a BTA CLCB connection +** +** Returns void +** +********************************************************************************/ +void bta_gattc_init_clcb_conn(UINT8 cif, BD_ADDR remote_bda) +{ + tBTA_GATTC_CLCB *p_clcb = NULL; + tBTA_GATTC_DATA gattc_data; + UINT16 conn_id; + + /* should always get the connection ID */ + if (GATT_GetConnIdIfConnected(cif, remote_bda,&conn_id) == FALSE) + { + APPL_TRACE_ERROR0("bta_gattc_init_clcb_conn ERROR: not a connected device"); + return; + } + + /* initaite a new connection here */ + if ((p_clcb = bta_gattc_clcb_alloc(cif, remote_bda)) != NULL) + { + gattc_data.hdr.layer_specific = p_clcb->bta_conn_id = conn_id; + + gattc_data.api_conn.client_if = cif; + memcpy(gattc_data.api_conn.remote_bda, remote_bda, BD_ADDR_LEN); + gattc_data.api_conn.is_direct = TRUE; + + bta_gattc_sm_execute(p_clcb, BTA_GATTC_API_OPEN_EVT, &gattc_data); + } + else + { + APPL_TRACE_ERROR0("No resources"); + } +} + +#endif /* #if BLE_INCLUDED == TRUE */ #endif /* BTA_GATT_INCLUDED */ diff --git a/bta/gatt/bta_gattc_api.c b/bta/gatt/bta_gattc_api.c index 1cace7d6a..59a9544d4 100644 --- a/bta/gatt/bta_gattc_api.c +++ b/bta/gatt/bta_gattc_api.c @@ -32,6 +32,14 @@ #include "bta_gatt_api.h" #include "bta_gattc_int.h" + +/***************************************************************************** +** Externs +*****************************************************************************/ +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_GATTC_CB bta_gattc_cb; +#endif + /***************************************************************************** ** Constants *****************************************************************************/ @@ -44,6 +52,22 @@ static const tBTA_SYS_REG bta_gatt_reg = /******************************************************************************* ** +** Function BTA_GATTC_Init +** +** Description This function is called to initalize GATTC module +** +** Parameters None +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_Init() +{ + memset(&bta_gattc_cb, 0, sizeof(tBTA_GATTC_CB)); +} + +/******************************************************************************* +** ** Function BTA_GATTC_AppRegister ** ** Description This function is called to register application callbacks @@ -232,7 +256,7 @@ void BTA_GATTC_ServiceSearchRequest (UINT16 conn_id, tBT_UUID *p_srvc_uuid) ** ** Function BTA_GATTC_GetFirstChar ** -** Description This function is called to find the first charatceristic of the +** Description This function is called to find the first characteristic of the ** service on the given server. ** ** Parameters conn_id: connection ID which identify the server. @@ -270,7 +294,7 @@ tBTA_GATT_STATUS BTA_GATTC_GetFirstChar (UINT16 conn_id, tBTA_GATT_SRVC_ID *p_s ** ** Function BTA_GATTC_GetNextChar ** -** Description This function is called to find the next charatceristic of the +** Description This function is called to find the next characteristic of the ** service on the given server. ** ** Parameters conn_id: connection ID which identify the server. @@ -314,8 +338,8 @@ tBTA_GATT_STATUS BTA_GATTC_GetNextChar (UINT16 conn_id, ** ** Function BTA_GATTC_GetFirstCharDescr ** -** Description This function is called to find the first charatceristic descriptor of the -** charatceristic on the given server. +** Description This function is called to find the first characteristic descriptor of the +** characteristic on the given server. ** ** Parameters conn_id: connection ID which identify the server. ** p_char_id: the characteristic ID of which the descriptor is belonged to. @@ -358,8 +382,8 @@ tBTA_GATT_STATUS BTA_GATTC_GetFirstCharDescr (UINT16 conn_id, tBTA_GATTC_CHAR_I ** ** Function BTA_GATTC_GetNextCharDescr ** -** Description This function is called to find the next charatceristic of the -** service on the given server. +** Description This function is called to find the next characteristic descriptor +** of the characterisctic. ** ** Parameters conn_id: connection ID which identify the server. ** p_start_descr_id: start the characteristic search from the next record @@ -667,7 +691,10 @@ void BTA_GATTC_WriteCharDescr (UINT16 conn_id, tBTA_GATT_AUTH_REQ auth_req) { tBTA_GATTC_API_WRITE *p_buf; - UINT16 len = sizeof(tBTA_GATTC_API_WRITE) + p_data->len; + UINT16 len = sizeof(tBTA_GATTC_API_WRITE); + + if (p_data != NULL) + len += p_data->len; if ((p_buf = (tBTA_GATTC_API_WRITE *) GKI_getbuf(len)) != NULL) { @@ -789,7 +816,7 @@ void BTA_GATTC_SendIndConfirm (UINT16 conn_id, tBTA_GATTC_CHAR_ID *p_char_id) tBTA_GATTC_API_CONFIRM *p_buf; APPL_TRACE_API3("BTA_GATTC_SendIndConfirm conn_id=%d service uuid1=0x%x char uuid=0x%x", - conn_id, p_char_id->srvc_id.id.uuid.uu.uuid16, p_char_id->char_id.uuid.uu.uuid16); //toto + conn_id, p_char_id->srvc_id.id.uuid.uu.uuid16, p_char_id->char_id.uuid.uu.uuid16); if ((p_buf = (tBTA_GATTC_API_CONFIRM *) GKI_getbuf(sizeof(tBTA_GATTC_API_CONFIRM))) != NULL) { @@ -841,22 +868,39 @@ tBTA_GATT_STATUS BTA_GATTC_RegisterForNotifications (tBTA_GATTC_IF client_if, { for (i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i ++) { - if (!p_clreg->notif_reg[i].in_use) + if ( p_clreg->notif_reg[i].in_use && + !memcmp(p_clreg->notif_reg[i].remote_bda, bda, BD_ADDR_LEN) && + bta_gattc_charid_compare(&p_clreg->notif_reg[i].char_id, p_char_id)) { - memset(&p_clreg->notif_reg, 0, sizeof(tBTA_GATTC_NOTIF_REG)); - - p_clreg->notif_reg[i].in_use = TRUE; - memcpy(p_clreg->notif_reg[i].remote_bda, bda, BD_ADDR_LEN); - memcpy(&p_clreg->notif_reg[i].char_id, p_char_id, sizeof(tBTA_GATTC_CHAR_ID)); - + APPL_TRACE_WARNING0("notification already registered"); status = BTA_GATT_OK; break; } } - if (i == BTA_GATTC_NOTIF_REG_MAX) + if (status != BTA_GATT_OK) { - status = BTA_GATT_NO_RESOURCES; - APPL_TRACE_ERROR0("Max Notification Reached, registration failed."); + for (i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i ++) + { + if (!p_clreg->notif_reg[i].in_use) + { + memset((void *)&p_clreg->notif_reg[i], 0, sizeof(tBTA_GATTC_NOTIF_REG)); + + p_clreg->notif_reg[i].in_use = TRUE; + memcpy(p_clreg->notif_reg[i].remote_bda, bda, BD_ADDR_LEN); + + p_clreg->notif_reg[i].char_id.srvc_id.is_primary = p_char_id->srvc_id.is_primary; + bta_gattc_cpygattid(&p_clreg->notif_reg[i].char_id.srvc_id.id, &p_char_id->srvc_id.id); + bta_gattc_cpygattid(&p_clreg->notif_reg[i].char_id.char_id, &p_char_id->char_id); + + status = BTA_GATT_OK; + break; + } + } + if (i == BTA_GATTC_NOTIF_REG_MAX) + { + status = BTA_GATT_NO_RESOURCES; + APPL_TRACE_ERROR0("Max Notification Reached, registration failed."); + } } } else @@ -905,10 +949,9 @@ tBTA_GATT_STATUS BTA_GATTC_DeregisterForNotifications (tBTA_GATTC_IF client_if, { if (p_clreg->notif_reg[i].in_use && !memcmp(p_clreg->notif_reg[i].remote_bda, bda, BD_ADDR_LEN) && - !memcmp(&p_clreg->notif_reg[i].char_id, p_char_id, sizeof(tBTA_GATTC_CHAR_ID))) + bta_gattc_charid_compare(&p_clreg->notif_reg[i].char_id, p_char_id)) { APPL_TRACE_DEBUG0("Deregistered."); - memset(&p_clreg->notif_reg[i], 0, sizeof(tBTA_GATTC_NOTIF_REG)); status = BTA_GATT_OK; break; @@ -931,4 +974,31 @@ tBTA_GATT_STATUS BTA_GATTC_DeregisterForNotifications (tBTA_GATTC_IF client_if, return status; } +/******************************************************************************* +** +** Function BTA_GATTC_Refresh +** +** Description Refresh the server cache of the remote device +** +** Parameters remote_bda: remote device BD address. +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTC_Refresh(BD_ADDR remote_bda) +{ + tBTA_GATTC_API_OPEN *p_buf; + + if ((p_buf = (tBTA_GATTC_API_OPEN *) GKI_getbuf(sizeof(tBTA_GATTC_API_OPEN))) != NULL) + { + p_buf->hdr.event = BTA_GATTC_API_REFRESH_EVT; + + memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN); + + + bta_sys_sendmsg(p_buf); + } + return; +} #endif /* BTA_GATT_INCLUDED */ + diff --git a/bta/gatt/bta_gattc_cache.c b/bta/gatt/bta_gattc_cache.c index 3774df4a6..7b87afe99 100644 --- a/bta/gatt/bta_gattc_cache.c +++ b/bta/gatt/bta_gattc_cache.c @@ -303,10 +303,6 @@ static tBTA_GATT_STATUS bta_gattc_add_srvc_to_cache(tBTA_GATTC_SERV *p_srvc_cb, p_srvc_cb->free_byte -= sizeof(tBTA_GATTC_CACHE); -#if 0 -//#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) - bta_gattc_display_cache_server(p_srvc_cb->p_srvc_cache); -#endif return status; } /******************************************************************************* @@ -335,6 +331,12 @@ static tBTA_GATT_STATUS bta_gattc_add_attr_to_cache(tBTA_GATTC_SERV *p_srvc_cb, APPL_TRACE_DEBUG2("free byte = %d, req %d bytes.", p_srvc_cb->free_byte, len); #endif + if (p_srvc_cb->p_cur_srvc == NULL) + { + APPL_TRACE_ERROR0("Illegal action to add char/descr/incl srvc before adding a service!"); + return GATT_WRONG_STATE; + } + if (p_srvc_cb->free_byte < len) { if (bta_gattc_alloc_cache_buf(p_srvc_cb) == NULL) @@ -381,10 +383,6 @@ static tBTA_GATT_STATUS bta_gattc_add_attr_to_cache(tBTA_GATTC_SERV *p_srvc_cb, p_srvc_cb->p_cur_srvc->p_last_attr = p_attr; -#if 0 -//#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) - bta_gattc_display_cache_server(p_srvc_cb->p_srvc_cache); -#endif return status; } @@ -578,7 +576,6 @@ static void bta_gattc_explore_srvc(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb) p_clcb->p_srcb->state = BTA_GATTC_SERV_SAVE; bta_gattc_co_cache_open(p_srvc_cb->server_bda, BTA_GATTC_CI_CACHE_OPEN_EVT, conn_id, TRUE); - //bta_gattc_sm_execute(p_clcb, BTA_GATTC_DISCOVER_CMPL_EVT, NULL); } /******************************************************************************* ** @@ -935,8 +932,8 @@ void bta_gattc_disc_res_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_ case GATT_DISC_SRVC_BY_UUID: bta_gattc_add_srvc_to_list(p_srvc_cb, p_data->handle, - p_data->value.handle, - p_data->type, + p_data->value.group_value.e_handle, + p_data->value.group_value.service_type, TRUE); break; @@ -980,7 +977,14 @@ void bta_gattc_disc_res_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_ void bta_gattc_disc_cmpl_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_STATUS status) { tBTA_GATTC_SERV * p_srvc_cb; + tBTA_GATTC_CLCB *p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id); + if ( p_clcb && (status != GATT_SUCCESS || p_clcb->status != GATT_SUCCESS) ) + { + p_clcb->status = status; + bta_gattc_sm_execute(p_clcb, BTA_GATTC_DISCOVER_CMPL_EVT, NULL); + return; + } p_srvc_cb = bta_gattc_find_scb_by_cid(conn_id); if (p_srvc_cb != NULL) @@ -988,6 +992,7 @@ void bta_gattc_disc_cmpl_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT switch (disc_type) { case GATT_DISC_SRVC_ALL: + case GATT_DISC_SRVC_BY_UUID: #if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) bta_gattc_display_explore_record(p_srvc_cb->p_srvc_list, p_srvc_cb->next_avail_idx); #endif @@ -1031,7 +1036,7 @@ UINT16 bta_gattc_id2handle(tBTA_GATTC_SERV *p_srcb, tBTA_GATT_SRVC_ID *p_service tBT_UUID attr_uuid; BOOLEAN char_map = FALSE, done = FALSE; - while (p_cache && !done) + while (p_service_id && p_cache && !done) { #if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) APPL_TRACE_DEBUG3("Service: handle[%d] uuid[0x%04x] inst[%d]", @@ -1040,9 +1045,7 @@ UINT16 bta_gattc_id2handle(tBTA_GATTC_SERV *p_srcb, tBTA_GATT_SRVC_ID *p_service #endif p_attr = p_cache->p_attr; - if (bta_gattc_uuid_compare(p_service_id->id.uuid, p_cache->service_uuid.id.uuid, TRUE) && - p_service_id->id.inst_id == p_cache->service_uuid.id.inst_id && - p_cache->service_uuid.is_primary == p_service_id->is_primary) + if (bta_gattc_srvcid_compare(p_service_id, &p_cache->service_uuid)) { for (j = 0; p_attr; j ++) { @@ -1210,12 +1213,12 @@ void bta_gattc_search_service(tBTA_GATTC_CLCB *p_clcb, tBT_UUID uuid) { if (bta_gattc_uuid_compare(uuid, p_cache->service_uuid.id.uuid, FALSE)) { -//#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) APPL_TRACE_DEBUG3("found service [0x%04x], inst[%d] handle [%d]", p_cache->service_uuid.id.uuid.uu.uuid16, p_cache->service_uuid.id.inst_id, p_cache->s_handle); -//#endif +#endif if (p_clcb->p_rcb->p_cback) { memset(&cb_data, 0, sizeof(tBTA_GATTC)); @@ -1224,7 +1227,6 @@ void bta_gattc_search_service(tBTA_GATTC_CLCB *p_clcb, tBT_UUID uuid) memcpy(&cb_data.srvc_res.service_uuid, &p_cache->service_uuid ,sizeof(tBTA_GATT_SRVC_ID)); (* p_clcb->p_rcb->p_cback)(BTA_GATTC_SEARCH_RES_EVT, &cb_data); - //todo (tBTA_GATTC *)&p_cache->service_uuid); } } p_cache = p_cache->p_next; @@ -1260,11 +1262,9 @@ static tBTA_GATT_STATUS bta_gattc_find_record(tBTA_GATTC_SERV *p_srcb, if (p_uuid_cond) memcpy(&uuid_cond, p_uuid_cond, sizeof(tBT_UUID)); - for (i = 0; p_cache <= p_srcb->p_cur_srvc && p_cache && status != BTA_GATT_OK; i ++) + for (i = 0; p_cache && status != BTA_GATT_OK; i ++) { - if (bta_gattc_uuid_compare(p_service_id->id.uuid, p_cache->service_uuid.id.uuid, FALSE) && - p_service_id->id.inst_id == p_cache->service_uuid.id.inst_id && - p_service_id->is_primary == p_cache->service_uuid.is_primary) + if (bta_gattc_srvcid_compare(p_service_id, &p_cache->service_uuid)) { #if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) APPL_TRACE_DEBUG2("found matching service [0x%04x], inst[%d]", @@ -1399,8 +1399,6 @@ tBTA_GATT_STATUS bta_gattc_query_cache(UINT16 conn_id, /* lock other GKI task */ GKI_sched_lock(); - APPL_TRACE_DEBUG0("bta_gattc_query_cache"); - if (p_clcb != NULL ) { if (p_clcb->state == BTA_GATTC_CONN_ST) diff --git a/bta/gatt/bta_gattc_int.h b/bta/gatt/bta_gattc_int.h index 407e5d878..118b906a9 100644 --- a/bta/gatt/bta_gattc_int.h +++ b/bta/gatt/bta_gattc_int.h @@ -51,6 +51,7 @@ enum BTA_GATTC_API_SEARCH_EVT, BTA_GATTC_API_CONFIRM_EVT, BTA_GATTC_API_READ_MULTI_EVT, + BTA_GATTC_API_REFRESH_EVT, BTA_GATTC_INT_CONN_EVT, BTA_GATTC_INT_DISCOVER_EVT, @@ -74,14 +75,16 @@ typedef UINT16 tBTA_GATTC_INT_EVT; /* max client application GATTC can support */ #ifndef BTA_GATTC_CL_MAX -#define BTA_GATTC_CL_MAX 4 +#define BTA_GATTC_CL_MAX 10 #endif /* max known devices GATTC can support */ #ifndef BTA_GATTC_KNOWN_SR_MAX -#define BTA_GATTC_KNOWN_SR_MAX 4 +#define BTA_GATTC_KNOWN_SR_MAX 10 #endif +#define BTA_GATTC_CONN_MAX GATT_MAX_PHY_CHANNEL + #ifndef BTA_GATTC_CLCB_MAX #define BTA_GATTC_CLCB_MAX GATT_CL_MAX_LCB #endif @@ -268,6 +271,8 @@ typedef struct #define BTA_GATTC_SERV_IDLE 0 #define BTA_GATTC_SERV_LOAD 1 #define BTA_GATTC_SERV_SAVE 2 +#define BTA_GATTC_SERV_DISC 3 +#define BTA_GATTC_SERV_DISC_ACT 4 UINT8 state; @@ -348,11 +353,19 @@ typedef struct BOOLEAN in_use; BD_ADDR remote_bda; tBTA_GATTC_CIF_MASK cif_mask; + tBTA_GATTC_CIF_MASK cif_adv_mask; }tBTA_GATTC_BG_TCK; typedef struct { + BOOLEAN in_use; + BD_ADDR remote_bda; +}tBTA_GATTC_CONN; + +typedef struct +{ + tBTA_GATTC_CONN conn_track[BTA_GATTC_CONN_MAX]; tBTA_GATTC_BG_TCK bg_track[BTA_GATTC_KNOWN_SR_MAX]; tBTA_GATTC_RCB cl_rcb[BTA_GATTC_CL_MAX]; @@ -402,6 +415,7 @@ extern void bta_gattc_conn(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); extern void bta_gattc_close(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); extern void bta_gattc_close_fail(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_disc_close(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); extern void bta_gattc_start_discover(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); extern void bta_gattc_disc_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); @@ -420,13 +434,15 @@ extern void bta_gattc_ci_close(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) extern void bta_gattc_ci_save(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); extern void bta_gattc_cache_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); extern void bta_gattc_ignore_op_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_restart_discover(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA * p_msg); extern void bta_gattc_init_bk_conn(tBTA_GATTC_API_OPEN *p_data, tBTA_GATTC_RCB *p_clreg); extern void bta_gattc_cancel_bk_conn(tBTA_GATTC_API_CANCEL_OPEN *p_data); extern void bta_gattc_send_open_cback( tBTA_GATTC_RCB *p_clreg, tBTA_GATT_STATUS status, BD_ADDR remote_bda, UINT16 conn_id); +extern void bta_gattc_process_api_refresh(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p_msg); /* utility functions */ -extern tBTA_GATTC_CLCB * bta_gattc_find_clcb_by_cif (UINT8 client_if, BD_ADDR remote_bda); //todo +extern tBTA_GATTC_CLCB * bta_gattc_find_clcb_by_cif (UINT8 client_if, BD_ADDR remote_bda); extern tBTA_GATTC_CLCB * bta_gattc_find_clcb_by_conn_id (UINT16 conn_id); extern tBTA_GATTC_CLCB * bta_gattc_clcb_alloc(tBTA_GATTC_IF client_if, BD_ADDR remote_bda); extern void bta_gattc_clcb_dealloc(tBTA_GATTC_CLCB *p_clcb); @@ -443,10 +459,14 @@ extern BOOLEAN bta_gattc_uuid_compare (tBT_UUID src, tBT_UUID tar, BOOLEAN is_pr extern void bta_gattc_pack_attr_uuid(tBTA_GATTC_CACHE_ATTR *p_attr, tBT_UUID *p_uuid); extern BOOLEAN bta_gattc_check_notif_registry(tBTA_GATTC_RCB *p_clreg, tBTA_GATTC_SERV *p_srcb, tBTA_GATTC_NOTIFY *p_notify); extern tBTA_GATT_STATUS bta_gattc_pack_read_cb_data(tBTA_GATTC_SERV *p_srcb, tBT_UUID descr_uuid, tGATT_VALUE *p_attr, tBTA_GATT_READ_VAL *p_value); -extern BOOLEAN bta_gattc_mark_bg_conn (tBTA_GATTC_IF client_if, BD_ADDR remote_bda, BOOLEAN add); -extern BOOLEAN bta_gattc_check_bg_conn (tBTA_GATTC_IF client_if, BD_ADDR remote_bda); +extern BOOLEAN bta_gattc_mark_bg_conn (tBTA_GATTC_IF client_if, BD_ADDR_PTR remote_bda, BOOLEAN add, BOOLEAN is_listen); +extern BOOLEAN bta_gattc_check_bg_conn (tBTA_GATTC_IF client_if, BD_ADDR remote_bda, UINT8 role); extern UINT8 bta_gattc_num_reg_app(void); extern void bta_gattc_clear_notif_registration(UINT16 conn_id); +extern tBTA_GATTC_SERV * bta_gattc_find_srvr_cache(BD_ADDR bda); +extern BOOLEAN bta_gattc_charid_compare(tBTA_GATTC_CHAR_ID *p_src, tBTA_GATTC_CHAR_ID *p_tar); +extern BOOLEAN bta_gattc_srvcid_compare(tBTA_GATT_SRVC_ID *p_src, tBTA_GATT_SRVC_ID *p_tar); +extern void bta_gattc_cpygattid(tBTA_GATT_ID *p_des, tBTA_GATT_ID *p_src); /* discovery functions */ extern void bta_gattc_disc_res_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_DISC_RES *p_data); @@ -461,4 +481,10 @@ extern tBTA_GATT_STATUS bta_gattc_init_cache(tBTA_GATTC_SERV *p_srvc_cb); extern void bta_gattc_rebuild_cache(tBTA_GATTC_SERV *p_srcv, UINT16 num_attr, tBTA_GATTC_NV_ATTR *p_attr, UINT16 attr_index); extern BOOLEAN bta_gattc_cache_save(tBTA_GATTC_SERV *p_srvc_cb, UINT16 conn_id); + +extern tBTA_GATTC_CONN * bta_gattc_conn_alloc(BD_ADDR remote_bda); +extern tBTA_GATTC_CONN * bta_gattc_conn_find(BD_ADDR remote_bda); +extern tBTA_GATTC_CONN * bta_gattc_conn_find_alloc(BD_ADDR remote_bda); +extern BOOLEAN bta_gattc_conn_dealloc(BD_ADDR remote_bda); + #endif /* BTA_GATTC_INT_H */ diff --git a/bta/gatt/bta_gattc_main.c b/bta/gatt/bta_gattc_main.c index a1fb536d6..01a0224ce 100644 --- a/bta/gatt/bta_gattc_main.c +++ b/bta/gatt/bta_gattc_main.c @@ -42,7 +42,6 @@ enum { BTA_GATTC_OPEN, BTA_GATTC_OPEN_FAIL, - //BTA_GATTC_OPEN_FAIL_IN_CONN, //<--- need to remove this? BTA_GATTC_OPEN_ERROR, BTA_GATTC_CANCEL_OPEN, BTA_GATTC_CANCEL_OPEN_OK, @@ -68,6 +67,8 @@ enum BTA_GATTC_CI_SAVE, BTA_GATTC_CACHE_OPEN, BTA_GATTC_IGNORE_OP_CMPL, + BTA_GATTC_DISC_CLOSE, + BTA_GATTC_RESTART_DISCOVER, BTA_GATTC_IGNORE }; @@ -79,7 +80,6 @@ const tBTA_GATTC_ACTION bta_gattc_action[] = { bta_gattc_open, bta_gattc_open_fail, - //bta_gattc_open_fail_in_conn, //<--- need to remove this? bta_gattc_open_error, bta_gattc_cancel_open, bta_gattc_cancel_open_ok, @@ -104,7 +104,9 @@ const tBTA_GATTC_ACTION bta_gattc_action[] = bta_gattc_ci_load, bta_gattc_ci_save, bta_gattc_cache_open, - bta_gattc_ignore_op_cmpl + bta_gattc_ignore_op_cmpl, + bta_gattc_disc_close, + bta_gattc_restart_discover }; @@ -131,6 +133,8 @@ static const UINT8 bta_gattc_st_idle[][BTA_GATTC_NUM_COLS] = /* BTA_GATTC_API_SEARCH_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST}, /* BTA_GATTC_API_CONFIRM_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST}, /* BTA_GATTC_API_READ_MULTI_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_API_REFRESH_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, + /* BTA_GATTC_INT_CONN_EVT */ {BTA_GATTC_CONN, BTA_GATTC_CONN_ST}, /* BTA_GATTC_INT_DISCOVER_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, /* BTA_GATTC_DISCOVER_CMPL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, @@ -163,6 +167,7 @@ static const UINT8 bta_gattc_st_w4_conn[][BTA_GATTC_NUM_COLS] = /* BTA_GATTC_API_SEARCH_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_W4_CONN_ST}, /* BTA_GATTC_API_CONFIRM_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_W4_CONN_ST}, /* BTA_GATTC_API_READ_MULTI_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_API_REFRESH_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST}, /* BTA_GATTC_INT_CONN_EVT */ {BTA_GATTC_CONN, BTA_GATTC_CONN_ST}, /* BTA_GATTC_INT_DISCOVER_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST}, @@ -190,11 +195,13 @@ static const UINT8 bta_gattc_st_connected[][BTA_GATTC_NUM_COLS] = /* BTA_GATTC_API_WRITE_EVT */ {BTA_GATTC_WRITE, BTA_GATTC_CONN_ST}, /* BTA_GATTC_API_EXEC_EVT */ {BTA_GATTC_EXEC, BTA_GATTC_CONN_ST}, -/* BTA_GATTC_API_CLOSE_EVT */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST}, //BTA_GATTC_CLOSING_ST +/* BTA_GATTC_API_CLOSE_EVT */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST}, /* BTA_GATTC_API_SEARCH_EVT */ {BTA_GATTC_SEARCH, BTA_GATTC_CONN_ST}, /* BTA_GATTC_API_CONFIRM_EVT */ {BTA_GATTC_CONFIRM, BTA_GATTC_CONN_ST}, /* BTA_GATTC_API_READ_MULTI_EVT */ {BTA_GATTC_READ_MULTI, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_API_REFRESH_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST}, + /* BTA_GATTC_INT_CONN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST}, /* BTA_GATTC_INT_DISCOVER_EVT */ {BTA_GATTC_START_DISCOVER, BTA_GATTC_DISCOVER_ST}, /* BTA_GATTC_DISCOVER_CMPL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST}, @@ -222,13 +229,15 @@ static const UINT8 bta_gattc_st_discover[][BTA_GATTC_NUM_COLS] = /* BTA_GATTC_API_WRITE_EVT */ {BTA_GATTC_Q_CMD, BTA_GATTC_DISCOVER_ST}, /* BTA_GATTC_API_EXEC_EVT */ {BTA_GATTC_Q_CMD, BTA_GATTC_DISCOVER_ST}, -/* BTA_GATTC_API_CLOSE_EVT */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST }, //BTA_GATTC_CLOSING_ST +/* BTA_GATTC_API_CLOSE_EVT */ {BTA_GATTC_DISC_CLOSE, BTA_GATTC_DISCOVER_ST}, /* BTA_GATTC_API_SEARCH_EVT */ {BTA_GATTC_Q_CMD, BTA_GATTC_DISCOVER_ST}, /* BTA_GATTC_API_CONFIRM_EVT */ {BTA_GATTC_CONFIRM, BTA_GATTC_DISCOVER_ST}, /* BTA_GATTC_API_READ_MULTI_EVT */ {BTA_GATTC_Q_CMD, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_API_REFRESH_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_DISCOVER_ST}, + /* BTA_GATTC_INT_CONN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_DISCOVER_ST}, -/* BTA_GATTC_INT_DISCOVER_EVT */ {BTA_GATTC_START_DISCOVER, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_INT_DISCOVER_EVT */ {BTA_GATTC_RESTART_DISCOVER, BTA_GATTC_DISCOVER_ST}, /* BTA_GATTC_DISCOVER_CMPL_EVT */ {BTA_GATTC_DISC_CMPL, BTA_GATTC_CONN_ST}, /* BTA_GATTC_OP_CMPL_EVT */ {BTA_GATTC_IGNORE_OP_CMPL, BTA_GATTC_DISCOVER_ST}, /* BTA_GATTC_INT_DISCONN_EVT */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST}, @@ -367,6 +376,10 @@ BOOLEAN bta_gattc_hdl_event(BT_HDR *p_msg) bta_gattc_process_api_open_cancel(p_cb, (tBTA_GATTC_DATA *) p_msg); break; + case BTA_GATTC_API_REFRESH_EVT: + bta_gattc_process_api_refresh(p_cb, (tBTA_GATTC_DATA *) p_msg); + break; + default: if ((p_clcb = bta_gattc_find_clcb_by_conn_id(p_msg->layer_specific)) != NULL) @@ -450,7 +463,8 @@ static char *gattc_evt_code(tBTA_GATTC_INT_EVT evt_code) return "BTA_GATTC_API_REG_EVT"; case BTA_GATTC_API_DEREG_EVT: return "BTA_GATTC_API_DEREG_EVT"; - + case BTA_GATTC_API_REFRESH_EVT: + return "BTA_GATTC_API_REFRESH_EVT"; default: return "unknown GATTC event code"; } diff --git a/bta/gatt/bta_gattc_utils.c b/bta/gatt/bta_gattc_utils.c index a36e26cd2..4749f21e5 100644 --- a/bta/gatt/bta_gattc_utils.c +++ b/bta/gatt/bta_gattc_utils.c @@ -221,6 +221,7 @@ tBTA_GATTC_CLCB * bta_gattc_clcb_alloc(tBTA_GATTC_IF client_if, BD_ADDR remote_b #endif p_clcb = &bta_gattc_cb.clcb[i_clcb]; p_clcb->in_use = TRUE; + p_clcb->status = BTA_GATT_OK; bdcpy(p_clcb->bda, remote_bda); p_clcb->p_rcb = bta_gattc_cl_get_regcb(client_if); @@ -275,18 +276,23 @@ tBTA_GATTC_CLCB *bta_gattc_find_alloc_clcb(tBTA_GATTC_IF client_if, BD_ADDR remo *******************************************************************************/ void bta_gattc_clcb_dealloc(tBTA_GATTC_CLCB *p_clcb) { + tBTA_GATTC_SERV *p_srcb = p_clcb->p_srcb; if (p_clcb) { - if (p_clcb->p_srcb->num_clcb) - p_clcb->p_srcb->num_clcb --; + if (p_srcb->num_clcb) + p_srcb->num_clcb --; if (p_clcb->p_rcb->num_clcb) p_clcb->p_rcb->num_clcb --; + if ( p_srcb->num_clcb == 0) + { + p_srcb->connected = FALSE; + p_srcb->state = BTA_GATTC_SERV_IDLE; + } utl_freebuf((void **)&p_clcb->p_q_cmd); - APPL_TRACE_ERROR2("bta_gattc_clcb_dealloc in_use=%d conn_id=%d",p_clcb->in_use, p_clcb->bta_conn_id); memset(p_clcb, 0, sizeof(tBTA_GATTC_CLCB)); } else @@ -299,7 +305,7 @@ void bta_gattc_clcb_dealloc(tBTA_GATTC_CLCB *p_clcb) ** ** Function bta_gattc_find_srcb ** -** Description find server cache by remote bd address +** Description find server cache by remote bd address currently in use ** ** Returns pointer to the server cache. ** @@ -316,6 +322,28 @@ tBTA_GATTC_SERV * bta_gattc_find_srcb(BD_ADDR bda) } return NULL; } + +/******************************************************************************* +** +** Function bta_gattc_find_srvr_cache +** +** Description find server cache by remote bd address +** +** Returns pointer to the server cache. +** +*******************************************************************************/ +tBTA_GATTC_SERV * bta_gattc_find_srvr_cache(BD_ADDR bda) +{ + tBTA_GATTC_SERV *p_srcb = &bta_gattc_cb.known_server[0]; + UINT8 i; + + for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i ++, p_srcb ++) + { + if (bdcmp(p_srcb->server_bda, bda) == 0) + return p_srcb; + } + return NULL; +} /******************************************************************************* ** ** Function bta_gattc_find_scb_by_cid @@ -441,6 +469,85 @@ void bta_gattc_pack_attr_uuid(tBTA_GATTC_CACHE_ATTR *p_attr, tBT_UUID *p_uuid) } /******************************************************************************* ** +** Function bta_gattc_cpygattid +** +** Description copy two tBTA_GATT_ID value +** +** Returns +** +*******************************************************************************/ +void bta_gattc_cpygattid(tBTA_GATT_ID *p_des, tBTA_GATT_ID *p_src) +{ + memset ((void *)p_des, 0, sizeof(tBTA_GATT_ID)); + + p_des->inst_id = p_src->inst_id; + + p_des->uuid.len = p_src->uuid.len; + + if (p_des->uuid.len == LEN_UUID_16) + { + p_des->uuid.uu.uuid16 = p_src->uuid.uu.uuid16; + } + else if (p_des->uuid.len == LEN_UUID_128) + { + memcpy(p_des->uuid.uu.uuid128, p_src->uuid.uu.uuid128, LEN_UUID_128); + } +} +/******************************************************************************* +** +** Function bta_gattc_gattid_compare +** +** Description compare two tBTA_GATT_ID type of pointer +** +** Returns +** +*******************************************************************************/ +BOOLEAN bta_gattc_gattid_compare(tBTA_GATT_ID *p_src, tBTA_GATT_ID *p_tar) +{ + if (p_src->inst_id == p_tar->inst_id && + bta_gattc_uuid_compare (p_src->uuid, p_tar->uuid, TRUE )) + return TRUE; + else + return FALSE; + +} +/******************************************************************************* +** +** Function bta_gattc_srvcid_compare +** +** Description compare two tBTA_GATT_SRVC_ID type of pointer +** +** Returns +** +*******************************************************************************/ +BOOLEAN bta_gattc_srvcid_compare(tBTA_GATT_SRVC_ID *p_src, tBTA_GATT_SRVC_ID *p_tar) +{ + if (p_src->is_primary == p_tar->is_primary && + bta_gattc_gattid_compare (&p_src->id, &p_tar->id)) + return TRUE; + else + return FALSE; +} +/******************************************************************************* +** +** Function bta_gattc_charid_compare +** +** Description compare two tBTA_GATTC_CHAR_ID type of pointer +** +** Returns +** +*******************************************************************************/ +BOOLEAN bta_gattc_charid_compare(tBTA_GATTC_CHAR_ID *p_src, tBTA_GATTC_CHAR_ID *p_tar) +{ + if (bta_gattc_gattid_compare (&p_src->char_id, &p_tar->char_id) && + bta_gattc_srvcid_compare (&p_src->srvc_id, &p_tar->srvc_id)) + return TRUE; + else + return FALSE; +} + +/******************************************************************************* +** ** Function bta_gattc_check_notif_registry ** ** Description check if the service notificaition has been registered. @@ -457,12 +564,7 @@ BOOLEAN bta_gattc_check_notif_registry(tBTA_GATTC_RCB *p_clreg, tBTA_GATTC_SERV { if (p_clreg->notif_reg[i].in_use && bdcmp(p_clreg->notif_reg[i].remote_bda, p_srcb->server_bda) == 0 && - (bta_gattc_uuid_compare(p_clreg->notif_reg[i].char_id.srvc_id.id.uuid, p_notify->char_id.srvc_id.id.uuid, FALSE) && - p_clreg->notif_reg[i].char_id.srvc_id.id.inst_id == p_notify->char_id.srvc_id.id.inst_id && - p_clreg->notif_reg[i].char_id.srvc_id.is_primary == p_notify->char_id.srvc_id.is_primary && - bta_gattc_uuid_compare(p_clreg->notif_reg[i].char_id.char_id.uuid, p_notify->char_id.char_id.uuid, FALSE) && - p_clreg->notif_reg[i].char_id.char_id.inst_id == p_notify->char_id.char_id.inst_id) - ) + bta_gattc_charid_compare (&p_clreg->notif_reg[i].char_id, &p_notify->char_id)) { APPL_TRACE_DEBUG0("Notification registered!"); return TRUE; @@ -562,22 +664,36 @@ tBTA_GATT_STATUS bta_gattc_pack_read_cb_data(tBTA_GATTC_SERV *p_srcb, tBT_UUID d ** Returns TRUE if success; FALSE otherwise. ** *******************************************************************************/ -BOOLEAN bta_gattc_mark_bg_conn (tBTA_GATTC_IF client_if, BD_ADDR remote_bda, BOOLEAN add) +BOOLEAN bta_gattc_mark_bg_conn (tBTA_GATTC_IF client_if, BD_ADDR_PTR remote_bda_ptr, + BOOLEAN add, BOOLEAN is_listen) { tBTA_GATTC_BG_TCK *p_bg_tck = &bta_gattc_cb.bg_track[0]; UINT8 i = 0; + tBTA_GATTC_CIF_MASK *p_cif_mask; for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i ++, p_bg_tck ++) { if (p_bg_tck->in_use && - bdcmp(p_bg_tck->remote_bda, remote_bda) == 0) + ((remote_bda_ptr != NULL && bdcmp(p_bg_tck->remote_bda, remote_bda_ptr) == 0) || + (remote_bda_ptr == NULL && bdcmp(p_bg_tck->remote_bda, bd_addr_null) == 0))) { + p_cif_mask = is_listen ? &p_bg_tck->cif_adv_mask : &p_bg_tck->cif_mask; + if (add) /* mask on the cif bit */ - p_bg_tck->cif_mask |= (1 <<(client_if - 1)); + *p_cif_mask |= (1 <<(client_if - 1)); else - p_bg_tck->cif_mask &= (~(1 <<(client_if - 1))); - + { + if (client_if != 0) + *p_cif_mask &= (~(1 <<(client_if - 1))); + else + *p_cif_mask = 0; + } + /* no BG connection for this device, make it available */ + if (p_bg_tck->cif_mask == 0 && p_bg_tck->cif_adv_mask == 0) + { + memset(p_bg_tck, 0, sizeof(tBTA_GATTC_BG_TCK)); + } return TRUE; } } @@ -594,8 +710,14 @@ BOOLEAN bta_gattc_mark_bg_conn (tBTA_GATTC_IF client_if, BD_ADDR remote_bda, BO if (!p_bg_tck->in_use) { p_bg_tck->in_use = TRUE; - bdcpy(p_bg_tck->remote_bda, remote_bda); - p_bg_tck->cif_mask = (1 <<(client_if - 1)); + if (remote_bda_ptr) + bdcpy(p_bg_tck->remote_bda, remote_bda_ptr); + else + bdcpy(p_bg_tck->remote_bda, bd_addr_null); + + p_cif_mask = is_listen ? &p_bg_tck->cif_adv_mask : &p_bg_tck->cif_mask; + + *p_cif_mask = (1 <<(client_if - 1)); return TRUE; } } @@ -612,20 +734,25 @@ BOOLEAN bta_gattc_mark_bg_conn (tBTA_GATTC_IF client_if, BD_ADDR remote_bda, BO ** Returns TRUE if success; FALSE otherwise. ** *******************************************************************************/ -BOOLEAN bta_gattc_check_bg_conn (tBTA_GATTC_IF client_if, BD_ADDR remote_bda) +BOOLEAN bta_gattc_check_bg_conn (tBTA_GATTC_IF client_if, BD_ADDR remote_bda, UINT8 role) { tBTA_GATTC_BG_TCK *p_bg_tck = &bta_gattc_cb.bg_track[0]; UINT8 i = 0; BOOLEAN is_bg_conn = FALSE; - for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i ++, p_bg_tck ++) + for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX && !is_bg_conn; i ++, p_bg_tck ++) { if (p_bg_tck->in_use && - bdcmp(p_bg_tck->remote_bda, remote_bda) == 0) + (bdcmp(p_bg_tck->remote_bda, remote_bda) == 0 || + bdcmp(p_bg_tck->remote_bda, bd_addr_null) == 0)) { - if ((p_bg_tck->cif_mask &(1 <<(client_if - 1))) != 0) + if (((p_bg_tck->cif_mask &(1 <<(client_if - 1))) != 0) && + role == HCI_ROLE_MASTER) + is_bg_conn = TRUE; + + if (((p_bg_tck->cif_adv_mask &(1 <<(client_if - 1))) != 0) && + role == HCI_ROLE_SLAVE) is_bg_conn = TRUE; - break; } } return is_bg_conn; @@ -656,9 +783,103 @@ void bta_gattc_send_open_cback( tBTA_GATTC_RCB *p_clreg, tBTA_GATT_STATUS status (*p_clreg->p_cback)(BTA_GATTC_OPEN_EVT, &cb_data); } } +/******************************************************************************* +** +** Function bta_gattc_conn_alloc +** +** Description allocate connection tracking spot +** +** Returns pointer to the clcb +** +*******************************************************************************/ +tBTA_GATTC_CONN * bta_gattc_conn_alloc(BD_ADDR remote_bda) +{ + UINT8 i_conn = 0; + tBTA_GATTC_CONN *p_conn = &bta_gattc_cb.conn_track[0]; + + for (i_conn = 0; i_conn < BTA_GATTC_CONN_MAX; i_conn++, p_conn ++) + { + if (!p_conn->in_use) + { +#if BTA_GATT_DEBUG == TRUE + APPL_TRACE_DEBUG1("bta_gattc_conn_alloc: found conn_track[%d] available",i_conn); +#endif + p_conn->in_use = TRUE; + bdcpy(p_conn->remote_bda, remote_bda); + return p_conn; + } + } + return NULL; +} + +/******************************************************************************* +** +** Function bta_gattc_conn_find +** +** Description allocate connection tracking spot +** +** Returns pointer to the clcb +** +*******************************************************************************/ +tBTA_GATTC_CONN * bta_gattc_conn_find(BD_ADDR remote_bda) +{ + UINT8 i_conn = 0; + tBTA_GATTC_CONN *p_conn = &bta_gattc_cb.conn_track[0]; + + for (i_conn = 0; i_conn < BTA_GATTC_CONN_MAX; i_conn++, p_conn ++) + { + if (p_conn->in_use && bdcmp(remote_bda, p_conn->remote_bda) == 0) + { +#if BTA_GATT_DEBUG == TRUE + APPL_TRACE_DEBUG1("bta_gattc_conn_find: found conn_track[%d] matched",i_conn); +#endif + return p_conn; + } + } + return NULL; +} +/******************************************************************************* +** +** Function bta_gattc_conn_find_alloc +** +** Description find or allocate connection tracking spot +** +** Returns pointer to the clcb +** +*******************************************************************************/ +tBTA_GATTC_CONN * bta_gattc_conn_find_alloc(BD_ADDR remote_bda) +{ + tBTA_GATTC_CONN *p_conn = bta_gattc_conn_find (remote_bda); + + if (p_conn == NULL) + { + p_conn = bta_gattc_conn_alloc(remote_bda); + } + return p_conn; +} +/******************************************************************************* +** +** Function bta_gattc_conn_dealloc +** +** Description de-allocate connection tracking spot +** +** Returns pointer to the clcb +** +*******************************************************************************/ +BOOLEAN bta_gattc_conn_dealloc(BD_ADDR remote_bda) +{ + tBTA_GATTC_CONN *p_conn = bta_gattc_conn_find (remote_bda); + if (p_conn != NULL) + { + p_conn->in_use = FALSE; + memset(p_conn->remote_bda, 0, BD_ADDR_LEN); + return TRUE; + } + return FALSE; +} #endif /* BTA_GATT_INCLUDED */ diff --git a/bta/gatt/bta_gatts_act.c b/bta/gatt/bta_gatts_act.c index 1b475985c..5504df0b6 100644 --- a/bta/gatt/bta_gatts_act.c +++ b/bta/gatt/bta_gatts_act.c @@ -292,7 +292,6 @@ void bta_gatts_create_srvc(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg) tBTA_GATTS cb_data; UINT8 srvc_idx; UINT16 service_id = 0; - //tBTA_GATTS_HNDL_RANGE handle_range; cb_data.create.status = BTA_GATT_ERROR; @@ -714,7 +713,6 @@ void bta_gatts_close (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg) } - /******************************************************************************* ** ** Function bta_gatts_request_cback diff --git a/bta/gatt/bta_gatts_api.c b/bta/gatt/bta_gatts_api.c index 65df0a6b9..d30878e61 100644 --- a/bta/gatt/bta_gatts_api.c +++ b/bta/gatt/bta_gatts_api.c @@ -33,6 +33,13 @@ #include "bta_gatts_int.h" /***************************************************************************** +** Externs +*****************************************************************************/ +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_GATTS_CB bta_gatts_cb; +#endif + +/***************************************************************************** ** Constants *****************************************************************************/ @@ -44,6 +51,22 @@ static const tBTA_SYS_REG bta_gatts_reg = /******************************************************************************* ** +** Function BTA_GATTS_Init +** +** Description This function is called to initalize GATTS module +** +** Parameters None +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTS_Init() +{ + memset(&bta_gatts_cb, 0, sizeof(tBTA_GATTS_CB)); +} + +/******************************************************************************* +** ** Function BTA_GATTS_AppRegister ** ** Description This function is called to register application callbacks diff --git a/bta/gatt/bta_gatts_int.h b/bta/gatt/bta_gatts_int.h index 4810c058e..9f0ec7e2f 100644 --- a/bta/gatt/bta_gatts_int.h +++ b/bta/gatt/bta_gatts_int.h @@ -28,7 +28,6 @@ #include "bta_sys.h" #include "bta_gatt_api.h" #include "gatt_api.h" -//#include "bta_gatts_co.h" #include "gki.h" @@ -52,7 +51,8 @@ enum BTA_GATTS_API_RSP_EVT, BTA_GATTS_API_OPEN_EVT, BTA_GATTS_API_CANCEL_OPEN_EVT, - BTA_GATTS_API_CLOSE_EVT + BTA_GATTS_API_CLOSE_EVT, + BTA_GATTS_API_LISTEN_EVT }; typedef UINT16 tBTA_GATTS_INT_EVT; @@ -116,7 +116,6 @@ typedef struct typedef struct { BT_HDR hdr; - //todo BD_ADDR bd_addr; UINT16 attr_id; UINT16 len; BOOLEAN need_confirm; @@ -148,6 +147,14 @@ typedef struct typedef tBTA_GATTS_API_OPEN tBTA_GATTS_API_CANCEL_OPEN; +typedef struct +{ + BT_HDR hdr; + BD_ADDR_PTR remote_bda; + tBTA_GATTS_IF server_if; + BOOLEAN start; +} tBTA_GATTS_API_LISTEN; + typedef union { BT_HDR hdr; @@ -164,6 +171,8 @@ typedef union tBTA_GATTS_API_CANCEL_OPEN api_cancel_open; tBTA_GATTS_INT_START_IF int_start_if; + /* if peripheral role is supported */ + tBTA_GATTS_API_LISTEN api_listen; } tBTA_GATTS_DATA; /* application registration control block */ @@ -172,7 +181,7 @@ typedef struct BOOLEAN in_use; tBT_UUID app_uuid; tBTA_GATTS_CBACK *p_cback; - tBTA_GATTS_IF gatt_if; //todo cahneg to server_if + tBTA_GATTS_IF gatt_if; }tBTA_GATTS_RCB; /* service registration control block */ @@ -233,6 +242,7 @@ extern void bta_gatts_indicate_handle (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_ extern void bta_gatts_open (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg); extern void bta_gatts_cancel_open (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg); extern void bta_gatts_close (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg); +extern void bta_gatts_listen(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg); extern BOOLEAN bta_gatts_uuid_compare(tBT_UUID tar, tBT_UUID src); extern tBTA_GATTS_RCB *bta_gatts_find_app_rcb_by_app_if(tBTA_GATTS_IF server_if); diff --git a/bta/hh/bta_hh_act.c b/bta/hh/bta_hh_act.c index de080965b..f2b91e005 100644 --- a/bta/hh/bta_hh_act.c +++ b/bta/hh/bta_hh_act.c @@ -84,18 +84,20 @@ void bta_hh_api_enable(tBTA_HH_DATA *p_data) status = BTA_HH_OK; /* initialize device CB */ - for (xx = 0; xx < BTA_HH_MAX_KNOWN; xx ++) + for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx ++) { bta_hh_cb.kdev[xx].state = BTA_HH_IDLE_ST; bta_hh_cb.kdev[xx].hid_handle = BTA_HH_INVALID_HANDLE; bta_hh_cb.kdev[xx].index = xx; - /* initialize control block map */ - bta_hh_cb.cb_index[xx] = BTA_HH_MAX_KNOWN; } + + /* initialize control block map */ + for (xx = 0; xx < BTA_HH_MAX_KNOWN; xx ++) + bta_hh_cb.cb_index[xx] = BTA_HH_IDX_INVALID; } - /* signal BTA call back event */ - (* bta_hh_cb.p_cback)(BTA_HH_ENABLE_EVT, (tBTA_HH *)&status); + /* signal BTA call back event */ + (* bta_hh_cb.p_cback)(BTA_HH_ENABLE_EVT, (tBTA_HH *)&status); } /******************************************************************************* ** @@ -124,7 +126,7 @@ void bta_hh_api_disable(void) { bta_hh_cb.w4_disable = TRUE; - for(xx = 0; xx < BTA_HH_MAX_KNOWN; xx ++) + for(xx = 0; xx < BTA_HH_MAX_DEVICE; xx ++) { /* send API_CLOSE event to every connected device */ if ( bta_hh_cb.kdev[xx].state == BTA_HH_CONN_ST ) @@ -152,24 +154,15 @@ void bta_hh_api_disable(void) *******************************************************************************/ void bta_hh_disc_cmpl(void) { - UINT8 xx; tBTA_HH_STATUS status = BTA_HH_OK; /* Deregister with lower layer */ if (HID_HostDeregister()!= HID_SUCCESS) status = BTA_HH_ERR; - /* free buffer in CB holding report descriptors */ - for(xx = 0; xx < BTA_HH_MAX_KNOWN; xx ++) - { - utl_freebuf((void **)&bta_hh_cb.kdev[xx].dscp_info.descriptor.dsc_list); - } - utl_freebuf((void **)&bta_hh_cb.p_disc_db); - - (* bta_hh_cb.p_cback)(BTA_HH_DISABLE_EVT, (tBTA_HH *)&status); - /* all connections are down, no waiting for diconnect */ - memset(&bta_hh_cb, 0, sizeof(tBTA_HH_CB)); + bta_hh_cleanup_disable(status); } + /******************************************************************************* ** ** Function bta_hh_sdp_cback @@ -186,7 +179,8 @@ static void bta_hh_sdp_cback(UINT16 result, UINT16 attr_mask, UINT8 hdl; tBTA_HH_STATUS status = BTA_HH_ERR_SDP; - if (result == SDP_SUCCESS) + /* make sure sdp succeeded and hh has not been disabled */ + if ((result == SDP_SUCCESS) && (p_cb != NULL)) { /* security is required for the connection, add attr_mask bit*/ if (p_cb->sec_mask) @@ -269,20 +263,20 @@ static void bta_hh_di_sdp_cback(UINT16 result) * set to 0xffff and we will allow the connection to go through. Spec mandates that DI * record be set, but many HID devices do not set this. So for IOP purposes, we allow the * connection to go through and update the DI record to invalid DI entry.*/ - if ((result == SDP_SUCCESS) || (result == SDP_NO_RECS_MATCH)) + if (((result == SDP_SUCCESS) || (result == SDP_NO_RECS_MATCH)) && (p_cb != NULL)) { if(result == SDP_SUCCESS && SDP_GetNumDiRecords(bta_hh_cb.p_disc_db) != 0) { /* always update information with primary DI record */ if (SDP_GetDiRecord(1, &di_rec, bta_hh_cb.p_disc_db) == SDP_SUCCESS) { - bta_hh_update_di_info(p_cb, di_rec.rec.vendor, di_rec.rec.product, di_rec.rec.version); + bta_hh_update_di_info(p_cb, di_rec.rec.vendor, di_rec.rec.product, di_rec.rec.version, 0); } } else /* no DI recrod available */ { - bta_hh_update_di_info(p_cb, BTA_HH_VENDOR_ID_INVALID, 0, 0); + bta_hh_update_di_info(p_cb, BTA_HH_VENDOR_ID_INVALID, 0, 0, 0); } if ((ret = HID_HostGetSDPRecord(p_cb->addr, @@ -332,6 +326,7 @@ void bta_hh_start_sdp(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) p_cb->sec_mask = p_data->api_conn.sec_mask; p_cb->mode = p_data->api_conn.mode; + bta_hh_cb.p_cur = p_cb; /* if previously virtually cabled device, skip SDP */ if (p_cb->app_id) @@ -355,9 +350,7 @@ void bta_hh_start_sdp(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) bta_hh_cb.cb_index[hdl] = p_cb->index; } else - { - status = BTA_HH_ERR_SDP; - } + status = BTA_HH_ERR_NO_RES; } bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA *)&status); @@ -531,12 +524,7 @@ void bta_hh_open_cmpl_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) /* initialize device driver */ bta_hh_co_open(p_cb->hid_handle, p_cb->sub_class, - p_cb->attr_mask, p_cb->app_id); - - /* update SSR settings */ - bta_sys_chg_ssr_config(BTA_ID_HH ,p_cb->app_id, p_cb->dscp_info.ssr_max_latency, p_cb->dscp_info.ssr_min_tout); - /* inform role manager */ - bta_sys_conn_open( BTA_ID_HH ,p_cb->app_id, p_cb->addr); + p_cb->attr_mask, p_cb->app_id); /* set protocol mode when not default report mode */ if (p_cb->mode != BTA_HH_PROTO_RPT_MODE) @@ -895,7 +883,8 @@ void bta_hh_maint_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) bta_hh_update_di_info(p_cb, p_dev_info->dscp_info.vendor_id, p_dev_info->dscp_info.product_id, - p_dev_info->dscp_info.version); + p_dev_info->dscp_info.version, + 0); /* add to BTA device list */ bta_hh_add_device_to_list(p_cb, dev_handle, @@ -917,13 +906,12 @@ void bta_hh_maint_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) #if BTA_HH_DEBUG bta_hh_trace_dev_db(); #endif - break; + break; case BTA_HH_RMV_DEV_EVT: /* remove device */ dev_info.handle = (UINT8)p_dev_info->hdr.layer_specific; - bdcpy(dev_info.bda, p_cb->addr); - if (p_cb->state != BTA_HH_CONN_ST ) + { if(HID_HostRemoveDev( dev_info.handle ) == HID_SUCCESS) { @@ -1087,7 +1075,7 @@ static void bta_hh_cback (UINT8 dev_handle, UINT8 event, UINT32 data, utl_freebuf((void **)&pdata); break; case HID_HDEV_EVT_VC_UNPLUG: - for (xx = 0; xx < BTA_HH_MAX_KNOWN; xx++) + for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) { if (bta_hh_cb.kdev[xx].hid_handle == dev_handle) { diff --git a/bta/hh/bta_hh_api.c b/bta/hh/bta_hh_api.c index 300fc6fc2..2a7965e92 100644 --- a/bta/hh/bta_hh_api.c +++ b/bta/hh/bta_hh_api.c @@ -57,7 +57,7 @@ static const tBTA_SYS_REG bta_hh_reg = ** Returns void ** *******************************************************************************/ -void BTA_HhEnable(tBTA_SEC sec_mask, BOOLEAN ucd_enabled, tBTA_HH_CBACK *p_cback) +void BTA_HhEnable(tBTA_SEC sec_mask, tBTA_HH_CBACK *p_cback) { tBTA_HH_API_ENABLE *p_buf; @@ -291,12 +291,21 @@ void BTA_HhSendCtrl(UINT8 dev_handle, tBTA_HH_TRANS_CTRL_TYPE c_type) ** ** Description This function send DATA transaction to HID device. ** +** Parameter dev_handle: device handle +** dev_bda: remote device address +** p_data: data to be sent in the DATA transaction; or +** the data to be write into the Output Report of a LE HID +** device. The report is identified the report ID which is +** the value of the byte (UINT8 *)(p_buf + 1) + p_buf->offset. +** p_data->layer_specific needs to be set to the report type, +** it can be OUTPUT report, or FEATURE report. +** ** Returns void ** *******************************************************************************/ void BTA_HhSendData(UINT8 dev_handle, BD_ADDR dev_bda, BT_HDR *p_data) { - bta_hh_snd_write_dev(dev_handle, HID_TRANS_DATA, BTA_HH_RPTT_OUTPUT, 0, 0, p_data); + bta_hh_snd_write_dev(dev_handle, HID_TRANS_DATA, (UINT8)p_data->layer_specific, 0, 0, p_data); } /******************************************************************************* diff --git a/bta/hh/bta_hh_cfg.c b/bta/hh/bta_hh_cfg.c index 5b7335abf..e3ffefe9b 100644 --- a/bta/hh/bta_hh_cfg.c +++ b/bta/hh/bta_hh_cfg.c @@ -34,13 +34,6 @@ #define BTA_HH_DISC_BUF_SIZE GKI_MAX_BUF_SIZE #endif -/* application ID(none-zero) for each type of device */ -#define BTA_HH_APP_ID_MI 1 -#define BTA_HH_APP_ID_KB 2 -#define BTA_HH_APP_ID_RMC 3 -#define BTA_HH_APP_ID_3DSG 4 -#define BTA_HH_APP_ID_JOY 5 -#define BTA_HH_APP_ID_GPAD 6 /* The type of devices supported by BTA HH and corresponding application ID */ diff --git a/bta/hh/bta_hh_int.h b/bta/hh/bta_hh_int.h index f3a8e54d3..7630a3ad3 100644 --- a/bta/hh/bta_hh_int.h +++ b/bta/hh/bta_hh_int.h @@ -174,7 +174,7 @@ typedef struct suppose BTA will connect to only one keyboard at the same time */ - tBTA_HH_DEV_CB kdev[BTA_HH_MAX_KNOWN]; /* device control block */ + tBTA_HH_DEV_CB kdev[BTA_HH_MAX_DEVICE]; /* device control block */ tBTA_HH_DEV_CB* p_cur; /* current device control block idx, used in sdp */ UINT8 cb_index[BTA_HH_MAX_KNOWN]; /* maintain a CB index @@ -232,13 +232,17 @@ extern void bta_hh_add_device_to_list(tBTA_HH_DEV_CB *p_cb, UINT8 handle, tHID_DEV_DSCP_INFO *p_dscp_info, UINT8 sub_class, UINT16 max_latency, UINT16 min_tout, UINT8 app_id); extern void bta_hh_update_di_info(tBTA_HH_DEV_CB *p_cb, UINT16 vendor_id, UINT16 product_id, - UINT16 version); + UINT16 version, UINT8 flag); +extern void bta_hh_cleanup_disable(tBTA_HH_STATUS status); + +extern UINT8 bta_hh_dev_handle_to_cb_idx(UINT8 dev_handle); /* action functions used outside state machine */ extern void bta_hh_api_enable(tBTA_HH_DATA *p_data); extern void bta_hh_api_disable(void); extern void bta_hh_disc_cmpl(void); +extern tBTA_HH_STATUS bta_hh_read_ssr_param(BD_ADDR bd_addr, UINT16 *p_max_ssr_lat, UINT16 *p_min_ssr_tout); #if BTA_HH_DEBUG extern void bta_hh_trace_dev_db(void); diff --git a/bta/hh/bta_hh_main.c b/bta/hh/bta_hh_main.c index a1d0ad27a..1c034698d 100644 --- a/bta/hh/bta_hh_main.c +++ b/bta/hh/bta_hh_main.c @@ -96,8 +96,7 @@ const UINT8 bta_hh_st_idle[][BTA_HH_NUM_COLS] = /* BTA_HH_API_WRITE_DEV_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST }, /* BTA_HH_API_GET_DSCP_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST }, /* BTA_HH_API_MAINT_DEV_EVT */ {BTA_HH_MAINT_DEV_ACT, BTA_HH_IDLE_ST }, -/* BTA_HH_OPEN_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST } - +/* BTA_HH_OPEN_CMPL_EVT */ {BTA_HH_OPEN_CMPL_ACT, BTA_HH_CONN_ST } }; @@ -115,7 +114,7 @@ const UINT8 bta_hh_st_w4_conn[][BTA_HH_NUM_COLS] = /* BTA_HH_API_WRITE_DEV_EVT */ {BTA_HH_IGNORE , BTA_HH_W4_CONN_ST }, /* BTA_HH_API_GET_DSCP_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST }, /* BTA_HH_API_MAINT_DEV_EVT */ {BTA_HH_MAINT_DEV_ACT, BTA_HH_IDLE_ST }, -/* BTA_HH_OPEN_CMPL_EVT */ {BTA_HH_OPEN_CMPL_ACT, BTA_HH_CONN_ST } +/* BTA_HH_OPEN_CMPL_EVT */ {BTA_HH_OPEN_CMPL_ACT, BTA_HH_CONN_ST } }; @@ -233,6 +232,14 @@ void bta_hh_sm_execute(tBTA_HH_DEV_CB *p_cb, UINT16 event, tBTA_HH_DATA * p_data cback_data.hs_data.status = BTA_HH_ERR_HDL; /* hs_data.rsp_data will be all zero, which is not valid value */ } + else if (p_data->api_sndcmd.t_type == HID_TRANS_CONTROL && + p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG) + { + cback_data.status = BTA_HH_ERR_HDL; + cback_event = BTA_HH_VC_UNPLUG_EVT; + } + else + cback_event = 0; break; case BTA_HH_API_CLOSE_EVT: @@ -297,7 +304,7 @@ void bta_hh_sm_execute(tBTA_HH_DEV_CB *p_cb, UINT16 event, tBTA_HH_DATA * p_data *******************************************************************************/ BOOLEAN bta_hh_hdl_event(BT_HDR *p_msg) { - UINT8 index = BTA_HH_MAX_KNOWN; + UINT8 index = BTA_HH_IDX_INVALID; tBTA_HH_DEV_CB *p_cb = NULL; switch (p_msg->event) @@ -330,24 +337,24 @@ BOOLEAN bta_hh_hdl_event(BT_HDR *p_msg) } else /* else remove device by handle */ { - index = bta_hh_cb.cb_index[p_msg->layer_specific]; + index = bta_hh_dev_handle_to_cb_idx((UINT8)p_msg->layer_specific); // btla-specific ++ /* If BT disable is done while the HID device is connected and Link_Key uses unauthenticated combination * then we can get into a situation where remove_bonding is called with the index set to 0 (without getting * cleaned up). Only when VIRTUAL_UNPLUG is called do we cleanup the index and make it MAX_KNOWN. * So if REMOVE_DEVICE is called and in_use is FALSE then we should treat this as a NULL p_cb. Hence we - * force the index to be MAX_KNOWN + * force the index to be IDX_INVALID */ if (bta_hh_cb.kdev[index].in_use == FALSE) { - index = BTA_HH_MAX_KNOWN; + index = BTA_HH_IDX_INVALID; } // btla-specific -- } } - else if (p_msg->layer_specific < BTA_HH_MAX_KNOWN ) - index = bta_hh_cb.cb_index[p_msg->layer_specific]; + else + index = bta_hh_dev_handle_to_cb_idx((UINT8)p_msg->layer_specific); - if (index != BTA_HH_MAX_KNOWN) + if (index != BTA_HH_IDX_INVALID) p_cb = &bta_hh_cb.kdev[index]; #if BTA_HH_DEBUG diff --git a/bta/hh/bta_hh_utils.c b/bta/hh/bta_hh_utils.c index 43492824d..bea0f2b81 100644 --- a/bta/hh/bta_hh_utils.c +++ b/bta/hh/bta_hh_utils.c @@ -23,6 +23,10 @@ #include "bta_hh_int.h" +/* if SSR max latency is not defined by remote device, set the default value + as half of the link supervision timeout */ +#define BTA_HH_GET_DEF_SSR_MAX_LAT(x) ((x)>> 1) + /***************************************************************************** ** Constants *****************************************************************************/ @@ -61,7 +65,7 @@ UINT8 bta_hh_find_cb(BD_ADDR bda) UINT8 xx; /* See how many active devices there are. */ - for (xx = 0; xx < BTA_HH_MAX_KNOWN; xx++) + for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) { /* check if any active/known devices is a match */ if ((!bdcmp (bda, bta_hh_cb.kdev[xx].addr) && @@ -83,7 +87,7 @@ UINT8 bta_hh_find_cb(BD_ADDR bda) } /* if no active device match, find a spot for it */ - for (xx = 0; xx < BTA_HH_MAX_KNOWN; xx++) + for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) { if (!bta_hh_cb.kdev[xx].in_use) { @@ -91,12 +95,15 @@ UINT8 bta_hh_find_cb(BD_ADDR bda) break; } } - /* If device list full, report BTA_HH_MAX_KNOWN */ + /* If device list full, report BTA_HH_IDX_INVALID */ #if BTA_HH_DEBUG APPL_TRACE_DEBUG2("bta_hh_find_cb:: index = %d while max = %d", - xx, BTA_HH_MAX_KNOWN); + xx, BTA_HH_MAX_DEVICE); #endif + if (xx == BTA_HH_MAX_DEVICE) + xx = BTA_HH_IDX_INVALID; + return xx; } @@ -115,7 +122,9 @@ void bta_hh_clean_up_kdev(tBTA_HH_DEV_CB *p_cb) UINT8 index; if (p_cb->hid_handle != BTA_HH_INVALID_HANDLE ) - bta_hh_cb.cb_index[p_cb->hid_handle] = BTA_HH_MAX_KNOWN; + { + bta_hh_cb.cb_index[p_cb->hid_handle] = BTA_HH_IDX_INVALID; + } /* reset device control block */ index = p_cb->index; /* Preserve index for this control block */ @@ -140,7 +149,7 @@ void bta_hh_clean_up_kdev(tBTA_HH_DEV_CB *p_cb) ** *******************************************************************************/ void bta_hh_update_di_info(tBTA_HH_DEV_CB *p_cb, UINT16 vendor_id, UINT16 product_id, - UINT16 version) + UINT16 version, UINT8 flag) { #if BTA_HH_DEBUG APPL_TRACE_DEBUG3("vendor_id = 0x%2x product_id = 0x%2x version = 0x%2x", @@ -178,15 +187,8 @@ void bta_hh_add_device_to_list(tBTA_HH_DEV_CB *p_cb, UINT8 handle, p_cb->sub_class = sub_class; p_cb->app_id = app_id; - if (ssr_max_latency == HID_SSR_PARAM_INVALID) - p_cb->dscp_info.ssr_max_latency = BTA_HH_SSR_MAX_LATENCY_DEF; - else - p_cb->dscp_info.ssr_max_latency = ssr_max_latency; - - if (ssr_min_tout == HID_SSR_PARAM_INVALID) - p_cb->dscp_info.ssr_min_tout = BTA_HH_SSR_MIN_TOUT_DEF; - else - p_cb->dscp_info.ssr_min_tout = ssr_min_tout; + p_cb->dscp_info.ssr_max_latency = ssr_max_latency; + p_cb->dscp_info.ssr_min_tout = ssr_min_tout; /* store report descriptor info */ if ( p_dscp_info) @@ -386,6 +388,108 @@ void bta_hh_parse_mice_rpt(tBTA_HH_BOOT_RPT *p_mice_data, UINT8 *p_report, } +/******************************************************************************* +** +** Function bta_hh_read_ssr_param +** +** Description Read the SSR Parameter for the remote device +** +** Returns tBTA_HH_STATUS operation status +** +*******************************************************************************/ +tBTA_HH_STATUS bta_hh_read_ssr_param(BD_ADDR bd_addr, UINT16 *p_max_ssr_lat, UINT16 *p_min_ssr_tout) +{ + tBTA_HH_STATUS status = BTA_HH_ERR; + tBTA_HH_CB *p_cb = &bta_hh_cb; + UINT8 i; + UINT16 ssr_max_latency; + /* lock other GKI task */ + GKI_sched_lock(); + for (i = 0; i < BTA_HH_MAX_KNOWN; i ++) + { + if (memcmp(p_cb->kdev[i].addr, bd_addr, BD_ADDR_LEN) == 0) + { + + /* if remote device does not have HIDSSRHostMaxLatency attribute in SDP, + set SSR max latency default value here. */ + if (p_cb->kdev[i].dscp_info.ssr_max_latency == HID_SSR_PARAM_INVALID) + { + /* The default is calculated as half of link supervision timeout.*/ + + BTM_GetLinkSuperTout(p_cb->kdev[i].addr, &ssr_max_latency) ; + ssr_max_latency = BTA_HH_GET_DEF_SSR_MAX_LAT(ssr_max_latency); + + /* per 1.1 spec, if the newly calculated max latency is greater than + BTA_HH_SSR_MAX_LATENCY_DEF which is 500ms, use BTA_HH_SSR_MAX_LATENCY_DEF */ + if (ssr_max_latency > BTA_HH_SSR_MAX_LATENCY_DEF) + ssr_max_latency = BTA_HH_SSR_MAX_LATENCY_DEF; + + * p_max_ssr_lat = ssr_max_latency; + } + else + * p_max_ssr_lat = p_cb->kdev[i].dscp_info.ssr_max_latency; + + if (p_cb->kdev[i].dscp_info.ssr_min_tout == HID_SSR_PARAM_INVALID) + * p_min_ssr_tout = BTA_HH_SSR_MIN_TOUT_DEF; + else + * p_min_ssr_tout = p_cb->kdev[i].dscp_info.ssr_min_tout; + + status = BTA_HH_OK; + + break; + } + } + GKI_sched_unlock(); + + return status; +} + +/******************************************************************************* +** +** Function bta_hh_cleanup_disable +** +** Description when disable finished, cleanup control block and send callback +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_cleanup_disable(tBTA_HH_STATUS status) +{ + UINT8 xx; + /* free buffer in CB holding report descriptors */ + for(xx = 0; xx < BTA_HH_MAX_DEVICE; xx ++) + { + utl_freebuf((void **)&bta_hh_cb.kdev[xx].dscp_info.descriptor.dsc_list); + } + utl_freebuf((void **)&bta_hh_cb.p_disc_db); + + (* bta_hh_cb.p_cback)(BTA_HH_DISABLE_EVT, (tBTA_HH *)&status); + /* all connections are down, no waiting for diconnect */ + memset(&bta_hh_cb, 0, sizeof(tBTA_HH_CB)); +} + +/******************************************************************************* +** +** Function bta_hh_dev_handle_to_cb_idx +** +** Description convert a HID device handle to the device control block index. +** +** +** Returns UINT8: index of the device control block. +** +*******************************************************************************/ +UINT8 bta_hh_dev_handle_to_cb_idx(UINT8 dev_handle) +{ + UINT8 index = BTA_HH_IDX_INVALID; + + /* regular HID device checking */ + if (dev_handle < BTA_HH_MAX_KNOWN ) + index = bta_hh_cb.cb_index[dev_handle]; + + return index; + +} #if BTA_HH_DEBUG /******************************************************************************* ** @@ -402,7 +506,7 @@ void bta_hh_trace_dev_db(void) APPL_TRACE_DEBUG0("bta_hh_trace_dev_db:: Device DB list********************"); - for (xx = 0; xx < BTA_HH_MAX_KNOWN; xx++) + for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) { APPL_TRACE_DEBUG3("kdev[%d] in_use[%d] handle[%d] ",xx, bta_hh_cb.kdev[xx].in_use, bta_hh_cb.kdev[xx].hid_handle); diff --git a/bta/hl/bta_hl_act.c b/bta/hl/bta_hl_act.c index 0f46e5ebd..ab1222229 100644 --- a/bta/hl/bta_hl_act.c +++ b/bta/hl/bta_hl_act.c @@ -59,7 +59,8 @@ static void bta_hl_sdp_cback5(UINT16 status); static void bta_hl_sdp_cback6(UINT16 status); -static tSDP_DISC_CMPL_CB * const bta_hl_sdp_cback_arr[] = { +static tSDP_DISC_CMPL_CB * const bta_hl_sdp_cback_arr[] = +{ bta_hl_sdp_cback0, bta_hl_sdp_cback1, bta_hl_sdp_cback2, @@ -544,7 +545,7 @@ void bta_hl_dch_close_cmpl(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); tBTA_HL evt_data; - tBTA_HL_EVT event; + tBTA_HL_EVT event = 0; BOOLEAN send_evt=TRUE; tBTA_HL_STATUS status; @@ -880,7 +881,7 @@ void bta_hl_dch_mca_open_ind(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, tMCA_DL_OPEN *p_open_ind = &p_data->mca_evt.mca_data.open_ind; tBTA_HL evt_data; tBTA_HL_EVT event; - UINT8 old_dch_oper; + UINT8 old_dch_oper = BTA_HL_DCH_OP_NONE; BOOLEAN send_event = FALSE; @@ -987,8 +988,8 @@ void bta_hl_dch_mca_open_cfm(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, tMCA_DL_OPEN *p_open_cfm = &p_data->mca_evt.mca_data.open_cfm; tBTA_HL evt_data; tBTA_HL_EVT event; - UINT8 old_dch_oper; - tBTA_HL_DCH_MODE dch_mode; + UINT8 old_dch_oper = BTA_HL_DCH_OP_NONE; + tBTA_HL_DCH_MODE dch_mode = BTA_HL_DCH_MODE_STREAMING; BOOLEAN send_event = FALSE; @@ -1006,10 +1007,6 @@ void bta_hl_dch_mca_open_cfm(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, { dch_mode = BTA_HL_DCH_MODE_RELIABLE; } - else - { - dch_mode = BTA_HL_DCH_MODE_STREAMING; - } if (p_dcb->local_mdep_id != BTA_HL_ECHO_TEST_MDEP_ID) { @@ -1034,6 +1031,11 @@ void bta_hl_dch_mca_open_cfm(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, old_dch_oper = p_dcb->dch_oper; p_dcb->dch_oper = BTA_HL_DCH_OP_NONE; } + else + { + APPL_TRACE_ERROR1("Error dch oper =%d", p_dcb->dch_oper); + return; + } switch (old_dch_oper) { @@ -2209,7 +2211,6 @@ tBTA_HL_STATUS bta_hl_init_sdp(tBTA_HL_SDP_OPER sdp_oper, UINT8 app_idx, UINT8 m uuid_list.len = LEN_UUID_16; uuid_list.uu.uuid16 = UUID_SERVCLASS_HDP_PROFILE; - SDP_InitDiscoveryDb(p_cb->p_db, BTA_HL_DISC_SIZE, 1, &uuid_list, num_attrs, attr_list); if (!SDP_ServiceSearchAttributeRequest(p_cb->bd_addr, p_cb->p_db, p_cb->sdp_cback)) @@ -2324,22 +2325,30 @@ void bta_hl_cch_mca_open(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data) *******************************************************************************/ void bta_hl_cch_mca_close(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data) { - tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); #if BTA_HL_DEBUG == TRUE - APPL_TRACE_DEBUG0("bta_hl_cch_mca_close"); + APPL_TRACE_DEBUG1("bta_hl_cch_mca_close mcl_handle=%d", p_mcb->mcl_handle); #endif if (p_mcb->sdp_oper != BTA_HL_SDP_OP_CCH_INIT) { - if ( MCA_DisconnectReq((tMCA_HANDLE) p_acb->app_handle) != MCA_SUCCESS) + if(p_mcb->mcl_handle) { - bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_CLOSE_CMPL_EVT, p_data); + if ( MCA_DisconnectReq((tMCA_HANDLE) p_mcb->mcl_handle) != MCA_SUCCESS) + { + bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_CLOSE_CMPL_EVT, p_data); + } + } + else + { + p_mcb->close_pending = TRUE; + APPL_TRACE_DEBUG0("No valid mcl_handle to stop the CCH setup now so wait until CCH is up then close it" ); } } else { p_mcb->close_pending = TRUE; + APPL_TRACE_DEBUG0("can not stop the CCH setup becasue SDP is in progress so wait until it is done" ); } } @@ -2365,6 +2374,12 @@ void bta_hl_cch_close_cmpl(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data) #endif bta_sys_conn_close(BTA_ID_HL, p_acb->app_id, p_mcb->bd_addr); + if (p_mcb->cch_oper == BTA_HL_CCH_OP_LOCAL_CLOSE && p_mcb->force_close_local_cch_opening) + { + p_mcb->cch_oper = BTA_HL_CCH_OP_LOCAL_OPEN; + APPL_TRACE_DEBUG0("change cch_oper from BTA_HL_CCH_OP_LOCAL_CLOSE to BTA_HL_CCH_OP_LOCAL_OPEN"); + } + switch (p_mcb->cch_oper) { case BTA_HL_CCH_OP_LOCAL_OPEN: @@ -2445,6 +2460,28 @@ void bta_hl_cch_mca_disconnect(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_da /******************************************************************************* ** +** Function bta_hl_cch_mca_disc_open +** +** Description Action routine for disconnect the just opened Control channel +** +** Returns void +** +*******************************************************************************/ +void bta_hl_cch_mca_disc_open(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data) +{ + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG2("bta_hl_cch_mca_disc_open mcl_handle=0x%x close_pending=%d", p_data->mca_evt.mcl_handle, p_mcb->close_pending ); +#endif + + p_mcb->close_pending = FALSE; + p_mcb->mcl_handle = p_data->mca_evt.mcl_handle; + bta_hl_cch_mca_close(app_idx, mcl_idx, p_data); +} + +/******************************************************************************* +** ** Function bta_hl_cch_mca_rsp_tout ** ** Description Action routine for processing the MCAP response timeout @@ -2464,6 +2501,7 @@ void bta_hl_cch_mca_rsp_tout(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data bta_hl_check_cch_close(app_idx,mcl_idx,p_data,TRUE); } + /******************************************************************************* ** ** Function bta_hl_cch_mca_connect @@ -2482,7 +2520,7 @@ void bta_hl_cch_mca_connect(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data) BOOLEAN send_event=TRUE; #if BTA_HL_DEBUG == TRUE - APPL_TRACE_DEBUG0("bta_hl_cch_mca_connect"); + APPL_TRACE_DEBUG1("bta_hl_cch_mca_connect mcl_handle=%d ", p_data->mca_evt.mcl_handle); #endif p_mcb->mcl_handle = p_data->mca_evt.mcl_handle; @@ -2596,7 +2634,7 @@ void bta_hl_mcap_ctrl_cback (tMCA_HANDLE handle, tMCA_CL mcl, UINT8 event, break; } - if ((p_msg = (tBTA_HL_MCA_EVT *)GKI_getbuf(sizeof(tBTA_HL_MCA_EVT))) != NULL) + if (send_event && ((p_msg = (tBTA_HL_MCA_EVT *)GKI_getbuf(sizeof(tBTA_HL_MCA_EVT))) != NULL)) { p_msg->hdr.event = mca_event; p_msg->app_handle = (tBTA_HL_APP_HANDLE) handle; @@ -2606,7 +2644,6 @@ void bta_hl_mcap_ctrl_cback (tMCA_HANDLE handle, tMCA_CL mcl, UINT8 event, } } - /******************************************************************************* ** ** Function bta_hl_mcap_data_cback diff --git a/bta/hl/bta_hl_int.h b/bta/hl/bta_hl_int.h index 648eb2cff..30a3f94ae 100644 --- a/bta/hl/bta_hl_int.h +++ b/bta/hl/bta_hl_int.h @@ -485,6 +485,7 @@ typedef struct UINT8 sdp_mdl_idx; tBTA_HL_SDP sdp; UINT8 cch_oper; + UINT8 force_close_local_cch_opening; BOOLEAN intentional_close; BOOLEAN rsp_tout; UINT8 timer_oper; @@ -667,6 +668,7 @@ extern "C" extern void bta_hl_cch_mca_close(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data); extern void bta_hl_cch_close_cmpl(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data); extern void bta_hl_cch_mca_disconnect(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data); + extern void bta_hl_cch_mca_disc_open(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data); extern void bta_hl_cch_mca_rsp_tout(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data); extern void bta_hl_cch_mca_connect(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data); diff --git a/bta/hl/bta_hl_main.c b/bta/hl/bta_hl_main.c index afac4c371..cbc83ef21 100644 --- a/bta/hl/bta_hl_main.c +++ b/bta/hl/bta_hl_main.c @@ -300,6 +300,7 @@ enum BTA_HL_CCH_MCA_CONNECT, BTA_HL_CCH_MCA_DISCONNECT, BTA_HL_CCH_MCA_RSP_TOUT, + BTA_HL_CCH_MCA_DISC_OPEN, BTA_HL_CCH_IGNORE }; @@ -315,7 +316,8 @@ const tBTA_HL_CCH_ACTION bta_hl_cch_action[] = bta_hl_cch_close_cmpl, bta_hl_cch_mca_connect, bta_hl_cch_mca_disconnect, - bta_hl_cch_mca_rsp_tout + bta_hl_cch_mca_rsp_tout, + bta_hl_cch_mca_disc_open }; @@ -374,7 +376,7 @@ static const UINT8 bta_hl_cch_st_closing[][BTA_HL_CCH_NUM_COLS] = /* BTA_HL_CCH_OPEN_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_CLOSING_ST}, /* BTA_HL_CCH_SDP_OK_EVT */ {BTA_HL_CCH_CLOSE_CMPL, BTA_HL_CCH_IDLE_ST}, /* BTA_HL_CCH_SDP_FAIL_EVT */ {BTA_HL_CCH_CLOSE_CMPL, BTA_HL_CCH_IDLE_ST}, -/* BTA_HL_MCA_CONNECT_IND_EVT */ {BTA_HL_CCH_MCA_CONNECT, BTA_HL_CCH_OPEN_ST}, +/* BTA_HL_MCA_CONNECT_IND_EVT */ {BTA_HL_CCH_MCA_DISC_OPEN, BTA_HL_CCH_CLOSING_ST}, /* BTA_HL_MCA_DISCONNECT_IND_EVT */ {BTA_HL_CCH_MCA_DISCONNECT, BTA_HL_CCH_CLOSING_ST}, /* BTA_HL_CCH_CLOSE_EVT */ {BTA_HL_CCH_MCA_CLOSE, BTA_HL_CCH_CLOSING_ST}, /* BTA_HL_CCH_CLOSE_CMPL_EVT */ {BTA_HL_CCH_CLOSE_CMPL, BTA_HL_CCH_IDLE_ST}, @@ -601,9 +603,10 @@ static void bta_hl_api_register(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) { tBTA_HL evt_data; UINT8 app_idx; - tBTA_HL_APP_CB *p_acb; + tBTA_HL_APP_CB *p_acb = NULL; tBTA_HL_STATUS status = BTA_HL_STATUS_FAIL; + if (p_cb->enable) { if (!bta_hl_is_a_duplicate_id(p_data->api_reg.app_id)) @@ -641,7 +644,8 @@ static void bta_hl_api_register(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) if ((status != BTA_HL_STATUS_DUPLICATE_APP_ID) && (status != BTA_HL_STATUS_NO_RESOURCE)) { - memset(p_acb, 0, sizeof(tBTA_HL_APP_CB)); + if (p_acb) + memset(p_acb, 0, sizeof(tBTA_HL_APP_CB)); } } #if BTA_HL_DEBUG == TRUE @@ -651,9 +655,11 @@ static void bta_hl_api_register(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) } #endif + memset(&evt_data, 0, sizeof(tBTA_HL)); evt_data.reg_cfm.status = status; evt_data.reg_cfm.app_id = p_data->api_reg.app_id; - evt_data.reg_cfm.app_handle = p_acb->app_handle; + if (status == BTA_HL_STATUS_OK) + evt_data.reg_cfm.app_handle = p_acb->app_handle; if (p_data->api_reg.p_cback) { p_data->api_reg.p_cback(BTA_HL_REGISTER_CFM_EVT, (tBTA_HL *) &evt_data); @@ -697,7 +703,7 @@ static void bta_hl_api_deregister(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) } else { - APPL_TRACE_ERROR1("Inavlide app_handle=%d", p_data->api_dereg.app_handle); + APPL_TRACE_ERROR1("Invalid app_handle=%d", p_data->api_dereg.app_handle); } } @@ -760,12 +766,20 @@ static void bta_hl_api_cch_open(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) break; case BTA_HL_STATUS_NO_RESOURCE: case BTA_HL_STATUS_FAIL: - bta_hl_build_cch_open_cfm(&evt_data, p_data->api_cch_open.app_handle, - 0, - p_data->api_cch_open.bd_addr, - status); + p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); - p_acb->p_cback(BTA_HL_CCH_OPEN_CFM_EVT,(tBTA_HL *) &evt_data ); + if (p_acb->p_cback) + { + bta_hl_build_cch_open_cfm(&evt_data, p_data->api_cch_open.app_handle, + 0, + p_data->api_cch_open.bd_addr, + status); + p_acb->p_cback(BTA_HL_CCH_OPEN_CFM_EVT,(tBTA_HL *) &evt_data ); + } + else + { + APPL_TRACE_ERROR0("bta_hl_api_cch_open Null Callback"); + } break; default: APPL_TRACE_ERROR1("status code=%d", status); @@ -811,13 +825,20 @@ static void bta_hl_api_cch_close(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) bta_hl_check_cch_close(app_idx, mcl_idx, p_data, TRUE); break; - case BTA_HL_STATUS_FAIL: + case BTA_HL_STATUS_INVALID_MCL_HANDLE: p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); - bta_hl_build_cch_close_cfm(&evt_data, + if (p_acb->p_cback) + { + bta_hl_build_cch_close_cfm(&evt_data, p_acb->app_handle, p_data->api_cch_close.mcl_handle, status); - p_acb->p_cback(BTA_HL_CCH_CLOSE_CFM_EVT,(tBTA_HL *) &evt_data ); + p_acb->p_cback(BTA_HL_CCH_CLOSE_CFM_EVT,(tBTA_HL *) &evt_data ); + } + else + { + APPL_TRACE_ERROR0("bta_hl_api_cch_close Null Callback"); + } break; default: @@ -958,12 +979,20 @@ static void bta_hl_api_dch_open(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) case BTA_HL_STATUS_INVALID_LOCAL_MDEP_ID: case BTA_HL_STATUS_INVALID_CTRL_PSM: p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); - bta_hl_build_dch_open_cfm(&evt_data, - p_acb->app_handle, - p_data->api_dch_open.mcl_handle, - BTA_HL_INVALID_MDL_HANDLE, - 0,0,0,0,0, status); - p_acb->p_cback(BTA_HL_DCH_OPEN_CFM_EVT,(tBTA_HL *) &evt_data ); + if (p_acb->p_cback) + { + bta_hl_build_dch_open_cfm(&evt_data, + p_acb->app_handle, + p_data->api_dch_open.mcl_handle, + BTA_HL_INVALID_MDL_HANDLE, + 0,0,0,0,0, status); + p_acb->p_cback(BTA_HL_DCH_OPEN_CFM_EVT,(tBTA_HL *) &evt_data ); + } + else + { + APPL_TRACE_ERROR0("bta_hl_api_dch_open Null Callback"); + } + break; default: APPL_TRACE_ERROR1("Status code=%d", status); @@ -1018,14 +1047,21 @@ static void bta_hl_api_dch_close(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) break; case BTA_HL_STATUS_FAIL: p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); - p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); - bta_hl_build_dch_close_cfm(&evt_data, - p_acb->app_handle, - p_mcb->mcl_handle, - p_data->api_dch_close.mdl_handle, - status); + if (p_acb->p_cback) + { + p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + bta_hl_build_dch_close_cfm(&evt_data, + p_acb->app_handle, + p_mcb->mcl_handle, + p_data->api_dch_close.mdl_handle, + status); - p_acb->p_cback(BTA_HL_DCH_CLOSE_CFM_EVT,(tBTA_HL *) &evt_data ); + p_acb->p_cback(BTA_HL_DCH_CLOSE_CFM_EVT,(tBTA_HL *) &evt_data ); + } + else + { + APPL_TRACE_ERROR0("bta_hl_api_dch_close Null Callback"); + } break; default: APPL_TRACE_ERROR1("Status code=%d", status); @@ -1053,8 +1089,9 @@ static void bta_hl_api_dch_reconnect(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) tBTA_HL_MDL_CB *p_dcb; UINT8 mdep_cfg_idx; UINT8 mdl_cfg_idx; + tBTA_HL_MDEP_CFG *p_mdep_cfg; - if (bta_hl_find_mcl_idx_using_handle(p_data->api_dch_open.mcl_handle, &app_idx, &mcl_idx)) + if (bta_hl_find_mcl_idx_using_handle(p_data->api_dch_reconnect.mcl_handle, &app_idx, &mcl_idx)) { p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); @@ -1085,6 +1122,20 @@ static void bta_hl_api_dch_reconnect(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) p_dcb->mdl_cfg_idx_included = TRUE; p_dcb->mdl_cfg_idx = mdl_cfg_idx; p_dcb->dch_mode = p_acb->mdl_cfg[mdl_cfg_idx].dch_mode; + + p_mdep_cfg = BTA_HL_GET_MDEP_CFG_PTR(app_idx, mdep_cfg_idx); + + if (p_mdep_cfg->mdep_role == BTA_HL_MDEP_ROLE_SINK) + { + p_dcb->peer_mdep_role = BTA_HL_MDEP_ROLE_SOURCE; + APPL_TRACE_DEBUG0("peer mdep role = SOURCE "); + } + else + { + p_dcb->peer_mdep_role = BTA_HL_MDEP_ROLE_SINK; + APPL_TRACE_DEBUG0("peer mdep role = SINK "); + } + bta_hl_find_rxtx_apdu_size(app_idx, mdep_cfg_idx, &p_dcb->max_rx_apdu_size, &p_dcb->max_tx_apdu_size); @@ -1139,12 +1190,19 @@ static void bta_hl_api_dch_reconnect(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) case BTA_HL_STATUS_NO_CCH: case BTA_HL_STATUS_NO_RESOURCE: p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); - bta_hl_build_dch_open_cfm(&evt_data, - p_acb->app_handle, - p_data->api_dch_reconnect.mcl_handle, - BTA_HL_INVALID_MDL_HANDLE, - 0,p_data->api_dch_reconnect.mdl_id,0,0,0, status); - p_acb->p_cback(BTA_HL_DCH_RECONNECT_CFM_EVT,(tBTA_HL *) &evt_data ); + if (p_acb->p_cback) + { + bta_hl_build_dch_open_cfm(&evt_data, + p_acb->app_handle, + p_data->api_dch_reconnect.mcl_handle, + BTA_HL_INVALID_MDL_HANDLE, + 0,p_data->api_dch_reconnect.mdl_id,0,0,0, status); + p_acb->p_cback(BTA_HL_DCH_RECONNECT_CFM_EVT,(tBTA_HL *) &evt_data ); + } + else + { + APPL_TRACE_ERROR0("bta_hl_api_dch_reconnect Null Callback"); + } break; default: APPL_TRACE_ERROR1("Status code=%d", status); @@ -1260,15 +1318,22 @@ static void bta_hl_api_dch_echo_test(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_SDP_INIT_EVT, p_data); } break; - case BTA_HL_STATUS_NO_CCH: case BTA_HL_STATUS_ECHO_TEST_BUSY: case BTA_HL_STATUS_NO_RESOURCE: case BTA_HL_STATUS_INVALID_DCH_CFG: - bta_hl_build_echo_test_cfm(&evt_data, - p_acb->app_handle, - p_mcb->mcl_handle, - status); - p_acb->p_cback(BTA_HL_DCH_ECHO_TEST_CFM_EVT,(tBTA_HL *) &evt_data ); + p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + if (p_acb->p_cback) + { + bta_hl_build_echo_test_cfm(&evt_data, + p_acb->app_handle, + p_mcb->mcl_handle, + status); + p_acb->p_cback(BTA_HL_DCH_ECHO_TEST_CFM_EVT,(tBTA_HL *) &evt_data ); + } + else + { + APPL_TRACE_ERROR0("bta_hl_api_dch_echo_test Null Callback"); + } break; default: @@ -1350,13 +1415,20 @@ static void bta_hl_api_sdp_query(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) case BTA_HL_STATUS_NO_RESOURCE: case BTA_HL_STATUS_FAIL: case BTA_HL_STATUS_SDP_NO_RESOURCE: - bta_hl_build_sdp_query_cfm(&evt_data, - p_data->api_sdp_query.app_handle, - p_data->api_sdp_query.bd_addr, - NULL, - status); p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); - p_acb->p_cback(BTA_HL_SDP_QUERY_CFM_EVT,(tBTA_HL *) &evt_data ); + if (p_acb->p_cback) + { + bta_hl_build_sdp_query_cfm(&evt_data, + p_data->api_sdp_query.app_handle, + p_data->api_sdp_query.bd_addr, + NULL, + status); + p_acb->p_cback(BTA_HL_SDP_QUERY_CFM_EVT,(tBTA_HL *) &evt_data ); + } + else + { + APPL_TRACE_ERROR0("bta_hl_api_sdp_query Null Callback"); + } break; case BTA_HL_STATUS_OK: break; @@ -1515,15 +1587,20 @@ static void bta_hl_api_delete_mdl(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) case BTA_HL_STATUS_NO_MDL_ID_FOUND: case BTA_HL_STATUS_INVALID_MDL_ID: p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); - bta_hl_build_delete_mdl_cfm(&evt_data, - p_acb->app_handle, - p_data->api_delete_mdl.mcl_handle, - p_data->api_delete_mdl.mdl_id, - status); - - p_acb->p_cback(BTA_HL_DELETE_MDL_CFM_EVT,(tBTA_HL *) &evt_data ); + if (p_acb->p_cback) + { + bta_hl_build_delete_mdl_cfm(&evt_data, + p_acb->app_handle, + p_data->api_delete_mdl.mcl_handle, + p_data->api_delete_mdl.mdl_id, + status); + p_acb->p_cback(BTA_HL_DELETE_MDL_CFM_EVT,(tBTA_HL *) &evt_data ); + } + else + { + APPL_TRACE_ERROR0("bta_hl_api_delete_mdl Null Callback"); + } break; - case BTA_HL_STATUS_INVALID_APP_HANDLE: default: APPL_TRACE_ERROR1("status code =%d", status); break; @@ -1591,13 +1668,21 @@ static void bta_hl_mca_delete_mdl_cfm(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) if (send_cfm_evt) { p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); - bta_hl_build_delete_mdl_cfm(&evt_data, - p_acb->app_handle, - p_mcb->mcl_handle, - p_delete_cfm->mdl_id, - status); + if (p_acb->p_cback) + { + bta_hl_build_delete_mdl_cfm(&evt_data, + p_acb->app_handle, + p_mcb->mcl_handle, + p_delete_cfm->mdl_id, + status); + + p_acb->p_cback(BTA_HL_DELETE_MDL_CFM_EVT,(tBTA_HL *) &evt_data ); + } + else + { + APPL_TRACE_ERROR0("bta_hl_mca_delete_mdl_cfm Null Callback"); - p_acb->p_cback(BTA_HL_DELETE_MDL_CFM_EVT,(tBTA_HL *) &evt_data ); + } } } @@ -1647,10 +1732,17 @@ static void bta_hl_mca_delete_mdl_ind(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) if (send_ind_evt) { p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); - evt_data.delete_mdl_ind.mcl_handle = p_mcb->mcl_handle; - evt_data.delete_mdl_ind.app_handle = p_acb->app_handle; - evt_data.delete_mdl_ind.mdl_id = p_delete_ind->mdl_id; - p_acb->p_cback(BTA_HL_DELETE_MDL_IND_EVT,(tBTA_HL *) &evt_data ); + if (p_acb->p_cback) + { + evt_data.delete_mdl_ind.mcl_handle = p_mcb->mcl_handle; + evt_data.delete_mdl_ind.app_handle = p_acb->app_handle; + evt_data.delete_mdl_ind.mdl_id = p_delete_ind->mdl_id; + p_acb->p_cback(BTA_HL_DELETE_MDL_IND_EVT,(tBTA_HL *) &evt_data ); + } + else + { + APPL_TRACE_ERROR0("bta_hl_mca_delete_mdl_ind Null Callback"); + } } } @@ -1718,16 +1810,24 @@ static void bta_hl_api_dch_abort(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) case BTA_HL_STATUS_NO_MDL_ID_FOUND: case BTA_HL_STATUS_FAIL: - p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); - bta_hl_build_abort_cfm(&evt_data, - p_acb->app_handle, - p_mcb->mcl_handle, - BTA_HL_STATUS_FAIL); - p_acb->p_cback(BTA_HL_DCH_ABORT_CFM_EVT,(tBTA_HL *) &evt_data ); + if (p_acb->p_cback) + { + p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + bta_hl_build_abort_cfm(&evt_data, + + + + p_acb->app_handle, + p_mcb->mcl_handle, + BTA_HL_STATUS_FAIL); + p_acb->p_cback(BTA_HL_DCH_ABORT_CFM_EVT,(tBTA_HL *) &evt_data); + } + else + { + APPL_TRACE_ERROR0("bta_hl_api_dch_abort Null Callback"); + } break; - case BTA_HL_STATUS_INVALID_BD_ADDR: - case BTA_HL_STATUS_INVALID_APP_HANDLE: default: APPL_TRACE_ERROR1("Status code=%d", status); break; diff --git a/bta/hl/bta_hl_sdp.c b/bta/hl/bta_hl_sdp.c index 15620e8d4..45af7be48 100644 --- a/bta/hl/bta_hl_sdp.c +++ b/bta/hl/bta_hl_sdp.c @@ -310,7 +310,7 @@ tBTA_HL_STATUS bta_hl_sdp_register (UINT8 app_idx) } cnt++; - if (cnt>BTA_HL_NUM_SUP_FEATURE_ELEMS) + if (cnt==BTA_HL_NUM_SUP_FEATURE_ELEMS) { result = FALSE; break; diff --git a/bta/hl/bta_hl_utils.c b/bta/hl/bta_hl_utils.c index 7f94a9cf9..5fab7fd03 100644 --- a/bta/hl/bta_hl_utils.c +++ b/bta/hl/bta_hl_utils.c @@ -520,7 +520,7 @@ BOOLEAN bta_hl_find_cch_cb_indexes(tBTA_HL_DATA *p_msg, { BOOLEAN found = FALSE; tBTA_HL_MCL_CB *p_mcb; - UINT8 app_idx, mcl_idx; + UINT8 app_idx = 0, mcl_idx = 0; switch (p_msg->hdr.event) { @@ -567,7 +567,7 @@ BOOLEAN bta_hl_find_cch_cb_indexes(tBTA_HL_DATA *p_msg, if (found) { p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); - if (p_mcb->cch_oper != BTA_HL_CCH_OP_LOCAL_CLOSE) + if ((p_mcb->cch_oper != BTA_HL_CCH_OP_LOCAL_CLOSE) && (p_mcb->cch_oper != BTA_HL_CCH_OP_LOCAL_OPEN) ) { p_mcb->cch_oper = BTA_HL_CCH_OP_REMOTE_CLOSE; } @@ -584,7 +584,7 @@ BOOLEAN bta_hl_find_cch_cb_indexes(tBTA_HL_DATA *p_msg, if (found) { p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); - if (p_mcb->cch_oper != BTA_HL_CCH_OP_REMOTE_CLOSE) + if ((p_mcb->cch_oper != BTA_HL_CCH_OP_REMOTE_CLOSE) && (p_mcb->cch_oper != BTA_HL_CCH_OP_LOCAL_OPEN)) { p_mcb->cch_oper = BTA_HL_CCH_OP_LOCAL_CLOSE; } @@ -629,7 +629,7 @@ BOOLEAN bta_hl_find_dch_cb_indexes(tBTA_HL_DATA *p_msg, { BOOLEAN found = FALSE; tBTA_HL_MCL_CB *p_mcb; - UINT8 app_idx, mcl_idx, mdl_idx; + UINT8 app_idx = 0, mcl_idx = 0, mdl_idx = 0; switch (p_msg->hdr.event) { @@ -1124,7 +1124,7 @@ BOOLEAN bta_hl_find_mcl_idx_using_handle( tBTA_HL_MCL_HANDLE mcl_handle, { tBTA_HL_APP_CB *p_acb; BOOLEAN found=FALSE; - UINT8 i,j; + UINT8 i = 0,j = 0; for (i=0; i<BTA_HL_NUM_APPS; i++) { @@ -1959,7 +1959,7 @@ BOOLEAN bta_hl_validate_reconnect_params(UINT8 app_idx, UINT8 mcl_idx, BOOLEAN local_mdep_id_found =FALSE; BOOLEAN mdl_cfg_found =FALSE; BOOLEAN status=FALSE; - UINT8 i, in_use_mdl_idx; + UINT8 i, in_use_mdl_idx = 0; #if BTA_HL_DEBUG == TRUE APPL_TRACE_DEBUG1("bta_hl_validate_reconnect_params mdl_id=%d", p_reconnect->mdl_id); @@ -2358,7 +2358,7 @@ void bta_hl_save_mdl_cfg(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx ) tBTA_HL_MDL_CFG mdl_cfg; tBTA_HL_MDEP *p_mdep_cfg; tBTA_HL_L2CAP_CFG_INFO l2cap_cfg; - UINT8 time_val; + UINT8 time_val = 0; mdl_id = p_dcb->mdl_id; if (!bta_hl_find_mdl_cfg_idx(app_idx, mcl_idx, mdl_id, &mdl_cfg_idx)) { @@ -2581,12 +2581,14 @@ BOOLEAN bta_hl_validate_chan_cfg(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx) tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); BOOLEAN success = FALSE; - UINT8 mdl_cfg_idx; + UINT8 mdl_cfg_idx = 0; tBTA_HL_L2CAP_CFG_INFO l2cap_cfg; + BOOLEAN get_l2cap_result, get_mdl_result; + get_l2cap_result = bta_hl_get_l2cap_cfg(p_dcb->mdl_handle, &l2cap_cfg); + get_mdl_result = bta_hl_find_mdl_cfg_idx(app_idx, mcl_idx, p_dcb->mdl_id, &mdl_cfg_idx); - if (bta_hl_get_l2cap_cfg(p_dcb->mdl_handle, &l2cap_cfg) && - bta_hl_find_mdl_cfg_idx(app_idx, mcl_idx, p_dcb->mdl_id, &mdl_cfg_idx)) + if (get_l2cap_result && get_mdl_result) { if ((p_acb->mdl_cfg[mdl_cfg_idx].mtu <= l2cap_cfg.mtu) && (p_acb->mdl_cfg[mdl_cfg_idx].fcs == l2cap_cfg.fcs) && @@ -2632,7 +2634,7 @@ BOOLEAN bta_hl_is_cong_on(UINT8 app_id, BD_ADDR bd_addr, tBTA_HL_MDL_ID mdl_id) { tBTA_HL_MDL_CB *p_dcb; - UINT8 app_idx, mcl_idx, mdl_idx; + UINT8 app_idx = 0, mcl_idx, mdl_idx; BOOLEAN cong_status = TRUE; if (bta_hl_find_app_idx(app_id, &app_idx)) @@ -2766,7 +2768,10 @@ void bta_hl_check_deregistration(UINT8 app_idx, tBTA_HL_DATA *p_data ) p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); if (p_mcb->cch_oper != BTA_HL_CCH_OP_LOCAL_CLOSE) { + if (p_mcb->cch_state == BTA_HL_CCH_OPENING_ST) + p_mcb->force_close_local_cch_opening = TRUE; p_mcb->cch_oper = BTA_HL_CCH_OP_LOCAL_CLOSE; + APPL_TRACE_DEBUG1("p_mcb->force_close_local_cch_opening=%d", p_mcb->force_close_local_cch_opening ); bta_hl_check_cch_close(app_idx,mcl_idx,p_data, TRUE); } } diff --git a/bta/include/bta_api.h b/bta/include/bta_api.h index 81dff39cc..042e48755 100644 --- a/bta/include/bta_api.h +++ b/bta/include/bta_api.h @@ -182,14 +182,20 @@ typedef UINT8 tBTA_SEC; #define BTA_DM_NON_DISC BTM_NON_DISCOVERABLE /* Device is not discoverable. */ #define BTA_DM_GENERAL_DISC BTM_GENERAL_DISCOVERABLE /* General discoverable. */ #define BTA_DM_LIMITED_DISC BTM_LIMITED_DISCOVERABLE /* Limited discoverable. */ - -// btla-specific ++ -typedef UINT16 tBTA_DM_DISC; -// btla-specific -- +#if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) +#define BTA_DM_BLE_NON_DISCOVERABLE BTM_BLE_NON_DISCOVERABLE /* Device is not LE discoverable */ +#define BTA_DM_BLE_GENERAL_DISCOVERABLE BTM_BLE_GENERAL_DISCOVERABLE /* Device is LE General discoverable */ +#define BTA_DM_BLE_LIMITED_DISCOVERABLE BTM_BLE_LIMITED_DISCOVERABLE /* Device is LE Limited discoverable */ +#endif +typedef UINT16 tBTA_DM_DISC; /* this discoverability mode is a bit mask among BR mode and LE mode */ /* Connectable Modes */ #define BTA_DM_NON_CONN BTM_NON_CONNECTABLE /* Device is not connectable. */ #define BTA_DM_CONN BTM_CONNECTABLE /* Device is connectable. */ +#if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) +#define BTA_DM_BLE_NON_CONNECTABLE BTM_BLE_NON_CONNECTABLE /* Device is LE non-connectable. */ +#define BTA_DM_BLE_CONNECTABLE BTM_BLE_CONNECTABLE /* Device is LE connectable. */ +#endif // btla-specific ++ typedef UINT16 tBTA_DM_CONN; @@ -204,6 +210,7 @@ typedef UINT16 tBTA_DM_CONN; #define BTA_DM_CONN_PAIRED 1 /* Inquiry Modes */ +#define BTA_DM_INQUIRY_NONE BTM_INQUIRY_NONE /*No BR inquiry. */ #define BTA_DM_GENERAL_INQUIRY BTM_GENERAL_INQUIRY /* Perform general inquiry. */ #define BTA_DM_LIMITED_INQUIRY BTM_LIMITED_INQUIRY /* Perform limited inquiry. */ @@ -291,6 +298,8 @@ typedef struct UINT8 *bta_dm_eir_flags; /* flags for EIR */ UINT8 bta_dm_eir_manufac_spec_len; /* length of manufacturer specific in bytes */ UINT8 *bta_dm_eir_manufac_spec; /* manufacturer specific */ + UINT8 bta_dm_eir_additional_len; /* length of additional data in bytes */ + UINT8 *bta_dm_eir_additional; /* additional data */ } tBTA_DM_EIR_CONF; #if BLE_INCLUDED == TRUE @@ -302,16 +311,22 @@ typedef struct #define BTA_BLE_ADV_FLAG_MASK BTM_BLE_ADV_FLAG_MASK #define BTA_BLE_LIMIT_DISC_MASK BTM_BLE_LIMIT_DISC_MASK -#define BTA_BLE_AD_BIT_DEV_NAME BTM_BLE_AD_BIT_DEV_NAME -#define BTA_BLE_AD_BIT_FLAGS BTM_BLE_AD_BIT_FLAGS -#define BTA_BLE_AD_BIT_MANU BTM_BLE_AD_BIT_MANU -#define BTA_BLE_AD_BIT_TX_PWR BTM_BLE_AD_BIT_TX_PWR -#define BTA_BLE_AD_BIT_ATTR BTM_BLE_AD_BIT_ATTR -#define BTA_BLE_AD_BIT_INT_RANGE BTM_BLE_AD_BIT_INT_RANGE -#define BTA_BLE_AD_BIT_SERVICE BTM_BLE_AD_BIT_SERVICE -#define BTA_BLE_AD_BIT_SERVICE_SOL BTM_BLE_AD_BIT_SERVICE_SOL -#define BTA_BLE_AD_BIT_SERVICE_DATA BTM_BLE_AD_BIT_SERVICE_DATA -#define BTA_BLE_AD_BIT_SIGN_DATA BTM_BLE_AD_BIT_SIGN_DATA +/* ADV data bit mask */ +#define BTA_BLE_AD_BIT_DEV_NAME BTM_BLE_AD_BIT_DEV_NAME +#define BTA_BLE_AD_BIT_FLAGS BTM_BLE_AD_BIT_FLAGS +#define BTA_BLE_AD_BIT_MANU BTM_BLE_AD_BIT_MANU +#define BTA_BLE_AD_BIT_TX_PWR BTM_BLE_AD_BIT_TX_PWR +#define BTA_BLE_AD_BIT_INT_RANGE BTM_BLE_AD_BIT_INT_RANGE +#define BTA_BLE_AD_BIT_SERVICE BTM_BLE_AD_BIT_SERVICE +#define BTA_BLE_AD_BIT_APPEARANCE BTM_BLE_AD_BIT_APPEARANCE +#define BTA_BLE_AD_BIT_PROPRIETARY BTM_BLE_AD_BIT_PROPRIETARY +#define BTA_DM_BLE_AD_BIT_SERVICE_SOL BTM_BLE_AD_BIT_SERVICE_SOL +#define BTA_DM_BLE_AD_BIT_SERVICE_DATA BTM_BLE_AD_BIT_SERVICE_DATA +#define BTA_DM_BLE_AD_BIT_SIGN_DATA BTM_BLE_AD_BIT_SIGN_DATA +#define BTA_DM_BLE_AD_BIT_SERVICE_128SOL BTM_BLE_AD_BIT_SERVICE_128SOL +#define BTA_DM_BLE_AD_BIT_PUBLIC_ADDR BTM_BLE_AD_BIT_PUBLIC_ADDR +#define BTA_DM_BLE_AD_BIT_RANDOM_ADDR BTM_BLE_AD_BIT_RANDOM_ADDR + typedef UINT16 tBTA_BLE_AD_MASK; /* slave preferred connection interval range */ @@ -330,36 +345,36 @@ typedef struct UINT16 *p_uuid; }tBTA_BLE_SERVICE; -/* attribute data */ + typedef struct { - UINT16 uuid; - UINT16 data_len; - UINT8 *p_data; -}tBTA_BLE_ATTR; - -#define BTA_BLE_NUM_AD_ATTR_MAX BTM_BLE_NUM_AD_ATTR_MAX + UINT8 len; + UINT8 *p_val; +}tBTA_BLE_MANU; -/* attribute list contained in adv data */ typedef struct { - UINT8 num_attr; - tBTA_BLE_ATTR attr_list[BTA_BLE_NUM_AD_ATTR_MAX]; -}tBTA_BLE_ATTR_DATA; + UINT8 adv_type; + UINT8 len; + UINT8 *p_val; /* number of len byte */ +}tBTA_BLE_PROP_ELEM; +/* vendor proprietary adv type */ typedef struct { - UINT8 len; - UINT8 *p_val; -}tBTA_BLE_MANU; + UINT8 num_elem; + tBTA_BLE_PROP_ELEM *p_elem; +}tBTA_BLE_PROPRIETARY; typedef struct { - tBTA_BLE_MANU manu; /* manufactuer data */ - tBTA_BLE_INT_RANGE int_range; /* slave prefered conn interval range */ - tBTA_BLE_SERVICE services; /* services */ - tBTA_BLE_ATTR_DATA attr; /* attribute data */ - UINT8 flag; + tBTA_BLE_MANU manu; /* manufactuer data */ + tBTA_BLE_INT_RANGE int_range; /* slave prefered conn interval range */ + tBTA_BLE_SERVICE services; /* services */ + UINT16 appearance; /* appearance data */ + UINT8 flag; + tBTA_BLE_PROPRIETARY *p_proprietary; + }tBTA_BLE_ADV_DATA; /* These are the fields returned in each device adv packet. It @@ -373,11 +388,84 @@ typedef struct UINT8 tx_power_level; UINT8 remote_name_len; UINT8 *p_remote_name; - tBTA_BLE_ATTR_DATA attr_data; tBTA_BLE_SERVICE service; } tBTA_BLE_INQ_DATA; #endif +/* BLE customer specific feature function type definitions */ +/* data type used on customer specific feature for RSSI monitoring */ +#define BTA_BLE_RSSI_ALERT_HI 0 +#define BTA_BLE_RSSI_ALERT_RANGE 1 +#define BTA_BLE_RSSI_ALERT_LO 2 +typedef UINT8 tBTA_DM_BLE_RSSI_ALERT_TYPE; + +#define BTA_BLE_RSSI_ALERT_NONE BTM_BLE_RSSI_ALERT_NONE /* (0) */ +#define BTA_BLE_RSSI_ALERT_HI_BIT BTM_BLE_RSSI_ALERT_HI_BIT /* (1) */ +#define BTA_BLE_RSSI_ALERT_RANGE_BIT BTM_BLE_RSSI_ALERT_RANGE_BIT /* (1 << 1) */ +#define BTA_BLE_RSSI_ALERT_LO_BIT BTM_BLE_RSSI_ALERT_LO_BIT /* (1 << 2) */ +typedef UINT8 tBTA_DM_BLE_RSSI_ALERT_MASK; + + +typedef void (tBTA_DM_BLE_RSSI_CBACK) (BD_ADDR bd_addr, tBTA_DM_BLE_RSSI_ALERT_TYPE alert_type, INT8 rssi); + +/* max number of filter spot for different filter type */ +#define BTA_DM_BLE_MAX_UUID_FILTER BTM_BLE_MAX_UUID_FILTER /* 8 */ +#define BTA_DM_BLE_MAX_ADDR_FILTER BTM_BLE_MAX_ADDR_FILTER /* 8 */ +#define BTA_DM_BLE_PF_STR_COND_MAX BTM_BLE_PF_STR_COND_MAX /* 4 apply to manu data , or local name */ +#define BTA_DM_BLE_PF_STR_LEN_MAX BTM_BLE_PF_STR_LEN_MAX /* match for first 20 bytes */ + +#define BTA_DM_BLE_PF_LOGIC_OR 0 +#define BTA_DM_BLE_PF_LOGIC_AND 1 +typedef UINT8 tBTA_DM_BLE_PF_LOGIC_TYPE; + +enum +{ + BTA_DM_BLE_SCAN_COND_ADD, + BTA_DM_BLE_SCAN_COND_DELETE, + BTA_DM_BLE_SCAN_COND_CLEAR = 2 +}; +typedef UINT8 tBTA_DM_BLE_SCAN_COND_OP; + +/* filter selection bit index */ +#define BTA_DM_BLE_PF_ADDR_FILTER BTM_BLE_PF_ADDR_FILTER +#define BTA_DM_BLE_PF_SRVC_UUID BTM_BLE_PF_SRVC_UUID +#define BTA_DM_BLE_PF_SRVC_SOL_UUID BTM_BLE_PF_SRVC_SOL_UUID +#define BTA_DM_BLE_PF_LOCAL_NAME BTM_BLE_PF_LOCAL_NAME +#define BTA_DM_BLE_PF_MANU_DATA BTM_BLE_PF_MANU_DATA +#define BTA_DM_BLE_PF_SRVC_DATA BTM_BLE_PF_SRVC_DATA +#define BTA_DM_BLE_PF_TYPE_MAX BTM_BLE_PF_TYPE_MAX +typedef UINT8 tBTA_DM_BLE_PF_COND_TYPE; + +typedef struct +{ + tBLE_BD_ADDR *p_target_addr; /* target address, if NULL, generic UUID filter */ + tBT_UUID uuid; /* UUID condition */ + tBTA_DM_BLE_PF_LOGIC_TYPE cond_logic; /* AND/OR */ +}tBTA_DM_BLE_PF_UUID_COND; + +typedef struct +{ + UINT8 data_len; /* <= 20 bytes */ + UINT8 *p_data; +}tBTA_DM_BLE_PF_LOCAL_NAME_COND; + +typedef struct +{ + UINT16 company_id; /* company ID */ + UINT8 data_len; /* <= 20 bytes */ + UINT8 *p_pattern; +}tBTA_DM_BLE_PF_MANU_COND; + +typedef union +{ + tBLE_BD_ADDR target_addr; + tBTA_DM_BLE_PF_LOCAL_NAME_COND local_name; /* lcoal name filtering */ + tBTA_DM_BLE_PF_MANU_COND manu_data; /* manufactuer data filtering */ + tBTA_DM_BLE_PF_UUID_COND srvc_uuid; /* service UUID filtering */ + tBTA_DM_BLE_PF_UUID_COND solicitate_uuid; /* solicitated service UUID filtering */ +}tBTA_DM_BLE_PF_COND_PARAM; + + typedef INT8 tBTA_DM_RSSI_VALUE; typedef UINT8 tBTA_DM_LINK_QUALITY_VALUE; @@ -430,8 +518,8 @@ typedef struct typedef struct { BD_ADDR bd_addr; /* BD address peer device. */ - BD_NAME bd_name; /* Name of peer device. */ DEV_CLASS dev_class; /* Class of Device */ + BD_NAME bd_name; /* Name of peer device. */ } tBTA_DM_PIN_REQ; /* BLE related definition */ @@ -481,12 +569,13 @@ typedef tBTM_LE_PENC_KEYS tBTA_LE_PENC_KEYS ; typedef tBTM_LE_PCSRK_KEYS tBTA_LE_PCSRK_KEYS; typedef tBTM_LE_LENC_KEYS tBTA_LE_LENC_KEYS ; typedef tBTM_LE_LCSRK_KEYS tBTA_LE_LCSRK_KEYS ; +typedef tBTM_LE_PID_KEYS tBTA_LE_PID_KEYS ; typedef union { tBTA_LE_PENC_KEYS penc_key; /* received peer encryption key */ tBTA_LE_PCSRK_KEYS psrk_key; /* received peer device SRK */ - BT_OCTET16 pid_key; /* peer device ID key */ + tBTA_LE_PID_KEYS pid_key; /* peer device ID key */ tBTA_LE_LENC_KEYS lenc_key; /* local encryption reproduction keys LTK = = d1(ER,DIV,0)*/ tBTA_LE_LCSRK_KEYS lcsrk_key; /* local device CSRK = d1(ER,DIV,1)*/ }tBTA_LE_KEY_VALUE; @@ -538,6 +627,9 @@ typedef struct LINK_KEY key; /* Link key associated with peer device. */ UINT8 key_type; /* The type of Link Key */ BOOLEAN success; /* TRUE of authentication succeeded, FALSE if failed. */ +#if BLE_INCLUDED == TRUE + BOOLEAN privacy_enabled; /* used for BLE device only */ +#endif UINT8 fail_reason; /* The HCI reason/error code for when success=FALSE */ } tBTA_DM_AUTH_CMPL; @@ -565,6 +657,7 @@ typedef struct { BD_ADDR bd_addr; /* BD address peer device. */ UINT8 status; /* connection open/closed */ + BOOLEAN is_removed; /* TRUE if device is removed when link is down */ } tBTA_DM_LINK_DOWN; /* Structure associated with BTA_DM_ROLE_CHG_EVT */ @@ -589,6 +682,7 @@ typedef struct { UINT8 level; /* when paging or inquiring, level is 10. Otherwise, the number of ACL links */ + UINT8 level_flags; /* indicates individual flags */ } tBTA_DM_BUSY_LEVEL; #define BTA_IO_CAP_OUT BTM_IO_CAP_OUT /* DisplayOnly */ @@ -630,6 +724,7 @@ typedef tBTM_OOB_DATA tBTA_OOB_DATA; /* Structure associated with BTA_DM_SP_CFM_REQ_EVT */ typedef struct { + /* Note: First 3 data members must be, bd_addr, dev_class, and bd_name in order */ BD_ADDR bd_addr; /* peer address */ DEV_CLASS dev_class; /* peer CoD */ BD_NAME bd_name; /* peer device name */ @@ -661,6 +756,7 @@ typedef struct /* Structure associated with BTA_DM_SP_KEY_NOTIF_EVT */ typedef struct { + /* Note: First 3 data members must be, bd_addr, dev_class, and bd_name in order */ BD_ADDR bd_addr; /* peer address */ DEV_CLASS dev_class; /* peer CoD */ BD_NAME bd_name; /* peer device name */ @@ -670,6 +766,7 @@ typedef struct /* Structure associated with BTA_DM_SP_RMT_OOB_EVT */ typedef struct { + /* Note: First 3 data members must be, bd_addr, dev_class, and bd_name in order */ BD_ADDR bd_addr; /* peer address */ DEV_CLASS dev_class; /* peer CoD */ BD_NAME bd_name; /* peer device name */ @@ -845,7 +942,8 @@ typedef UINT8 tBTA_DM_PM_ACTTION; /* index to bta_dm_ssr_spec */ #define BTA_DM_PM_SSR0 0 -#define BTA_DM_PM_SSR1 1 +#define BTA_DM_PM_SSR1 1 /* BTA_DM_PM_SSR1 will be dedicated for + HH SSR setting entry, no other profile can use it */ #define BTA_DM_PM_SSR2 2 #define BTA_DM_PM_SSR3 3 #define BTA_DM_PM_SSR4 4 @@ -1458,6 +1556,22 @@ BTA_API extern tBTA_STATUS BTA_DmGetDiRecord( UINT8 get_record_index, tBTA_DI_GE /******************************************************************************* ** +** +** Function BTA_DmCloseACL +** +** Description This function force to close an ACL connection and remove the +** device from the security database list of known devices. +** +** Parameters: bd_addr - Address of the peer device +** remove_dev - remove device or not after link down +** +** Returns void. +** +*******************************************************************************/ +BTA_API extern void BTA_DmCloseACL(BD_ADDR bd_addr, BOOLEAN remove_dev); + +/******************************************************************************* +** ** Function BTA_SysFeatures ** ** Description This function is called to set system features. @@ -1707,6 +1821,25 @@ BTA_API extern void BTA_DmDiscoverExt(BD_ADDR bd_addr, tBTA_SERVICE_MASK_EXT *p_ BTA_API extern void BTA_DmSetEncryption(BD_ADDR bd_addr, tBTA_DM_ENCRYPT_CBACK *p_callback, tBTA_DM_BLE_SEC_ACT sec_act); + +/******************************************************************************* +** +** Function BTA_DmBleObserve +** +** Description This procedure keep the device listening for advertising +** events from a broadcast device. +** +** Parameters start: start or stop observe. +** duration : Duration of the scan. Continuous scan if 0 is passed +** p_results_cb: Callback to be called with scan results +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmBleObserve(BOOLEAN start, UINT8 duration, + tBTA_DM_SEARCH_CBACK *p_results_cb); + + #endif // btla-specific ++ @@ -1721,6 +1854,47 @@ BTA_API extern void BTA_DmSetEncryption(BD_ADDR bd_addr, tBTA_DM_ENCRYPT_CBACK * *******************************************************************************/ BTA_API extern void BTA_DmSetAfhChannelAssessment (BOOLEAN enable_or_disable); // btla-specific -- +/******************************************************************************* +** +** Function BTA_DmBleConfigLocalPrivacy +** +** Description Enable/disable privacy on the local device +** +** Parameters: privacy_enable - enable/disabe privacy on remote device. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmBleConfigLocalPrivacy(BOOLEAN privacy_enable); + +/******************************************************************************* +** +** Function BTA_DmBleEnableRemotePrivacy +** +** Description Enable/disable privacy on a remote device +** +** Parameters: bd_addr - BD address of the peer +** privacy_enable - enable/disabe privacy on remote device. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmBleEnableRemotePrivacy(BD_ADDR bd_addr, BOOLEAN privacy_enable); + + +/******************************************************************************* +** +** Function BTA_DmBleSetAdvConfig +** +** Description This function is called to override the BTA default ADV parameters. +** +** Parameters Pointer to User defined ADV data structure +** +** Returns None +** +*******************************************************************************/ +BTA_API extern void BTA_DmBleSetAdvConfig (tBTA_BLE_AD_MASK data_mask, + tBTA_BLE_ADV_DATA *p_adv_cfg); #ifdef __cplusplus } diff --git a/bta/include/bta_av_api.h b/bta/include/bta_av_api.h index eb7727945..1ea570c64 100644 --- a/bta/include/bta_av_api.h +++ b/bta/include/bta_av_api.h @@ -47,6 +47,7 @@ #define BTA_AV_FAIL_STREAM 3 /* stream connection failed */ #define BTA_AV_FAIL_RESOURCES 4 /* no resources */ #define BTA_AV_FAIL_ROLE 5 /* failed due to role management related issues */ +#define BTA_AV_FAIL_GET_CAP 6 /* get capability failed due to no SEP availale on the peer */ typedef UINT8 tBTA_AV_STATUS; @@ -492,6 +493,8 @@ typedef struct const UINT8 *p_meta_evt_ids;/* the the metadata Get Capabilities response for event id */ const tBTA_AV_ACT *p_act_tbl;/* the action function table for VDP stream */ tBTA_AV_REG *p_reg; /* action function to register VDP */ + char avrc_controller_name[BTA_SERVICE_NAME_LEN]; /* Default AVRCP controller name */ + char avrc_target_name[BTA_SERVICE_NAME_LEN]; /* Default AVRCP target name*/ } tBTA_AV_CFG; #ifdef __cplusplus diff --git a/bta/include/bta_gatt_api.h b/bta/include/bta_gatt_api.h index 0404847e6..78bdf134a 100644 --- a/bta/include/bta_gatt_api.h +++ b/bta/include/bta_gatt_api.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright (C) 2003-2012 Broadcom Corporation + * Copyright (C) 2003-2013 Broadcom Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ * This is the public interface file for BTA GATT. * ******************************************************************************/ + #ifndef BTA_GATT_API_H #define BTA_GATT_API_H @@ -53,7 +54,7 @@ typedef struct { tBT_UUID uuid; /* uuid of the attribute */ UINT8 inst_id; /* instance ID */ -} tBTA_GATT_ID; +} __attribute__((packed)) tBTA_GATT_ID; /* Success code and error codes */ #define BTA_GATT_OK GATT_SUCCESS @@ -90,6 +91,7 @@ typedef struct #define BTA_GATT_INVALID_CFG GATT_INVALID_CFG /* 0x008b */ #define BTA_GATT_DUP_REG 0x008c #define BTA_GATT_ALREADY_OPEN 0x008d /* 0x008d */ +#define BTA_GATT_CANCEL 0x008e /* 0x008e */ typedef UINT8 tBTA_GATT_STATUS; #define BTA_GATT_INVALID_CONN_ID GATT_INVALID_CONN_ID @@ -110,8 +112,9 @@ typedef UINT8 tBTA_GATT_STATUS; #define BTA_GATTC_PREP_WRITE_EVT 11 /* GATT prepare write event */ #define BTA_GATTC_EXEC_EVT 12 /* execute write complete event */ #define BTA_GATTC_ACL_EVT 13 /* ACL up event */ -#define BTA_GATTC_CANCEL_OPEN_EVT 14 /* cancel open event */ +#define BTA_GATTC_CANCEL_OPEN_EVT 14 /* cancel open event */ #define BTA_GATTC_SRVC_CHG_EVT 15 /* service change event */ + typedef UINT8 tBTA_GATTC_EVT; typedef tGATT_IF tBTA_GATTC_IF; @@ -562,6 +565,19 @@ extern "C" /******************************************************************************* ** +** Function BTA_GATTC_Init +** +** Description This function is called to initalize GATTC module +** +** Parameters None +** +** Returns None +** +*******************************************************************************/ +BTA_API extern void BTA_GATTC_Init(); + +/******************************************************************************* +** ** Function BTA_GATTC_AppRegister ** ** Description This function is called to register application callbacks @@ -968,11 +984,37 @@ BTA_API extern void BTA_GATTC_ReadMultiple(UINT16 conn_id, tBTA_GATTC_MULTI *p_r tBTA_GATT_AUTH_REQ auth_req); +/******************************************************************************* +** +** Function BTA_GATTC_Refresh +** +** Description Refresh the server cache of the remote device +** +** Parameters remote_bda: remote device BD address. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_GATTC_Refresh(BD_ADDR remote_bda); /******************************************************************************* ** BTA GATT Server API ********************************************************************************/ + +/******************************************************************************* +** +** Function BTA_GATTS_Init +** +** Description This function is called to initalize GATTS module +** +** Parameters None +** +** Returns None +** +*******************************************************************************/ + BTA_API extern void BTA_GATTS_Init(); + /******************************************************************************* ** ** Function BTA_GATTS_AppRegister @@ -1208,6 +1250,24 @@ BTA_API extern void BTA_GATTC_ReadMultiple(UINT16 conn_id, tBTA_GATTC_MULTI *p_r *******************************************************************************/ BTA_API extern void BTA_GATTS_Close(UINT16 conn_id); +/******************************************************************************* +** +** Function BTA_GATTS_Listen +** +** Description Start advertisement to listen for connection request for a +** GATT server +** +** Parameters server_if: server interface. +** start: to start or stop listening for connection +** remote_bda: remote device BD address, if listen to all device +** use NULL. +** +** Returns void +** +*******************************************************************************/ + BTA_API extern void BTA_GATTS_Listen(tBTA_GATTS_IF server_if, BOOLEAN start, + BD_ADDR_PTR target_bda); + #ifdef __cplusplus diff --git a/bta/include/bta_gattc_co.h b/bta/include/bta_gattc_co.h index d2392b82a..fa882ecdb 100644 --- a/bta/include/bta_gattc_co.h +++ b/bta/include/bta_gattc_co.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright (C) 2010-2012 Broadcom Corporation + * Copyright (C) 2009-2013 Broadcom Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -97,5 +97,19 @@ BTA_API extern void bta_gattc_co_cache_save(BD_ADDR server_bda, UINT16 evt, BTA_API extern void bta_gattc_co_cache_load(BD_ADDR server_bda, UINT16 evt, UINT16 start_index, UINT16 conn_id); +/******************************************************************************* +** +** Function bta_gattc_co_cache_reset +** +** Description This callout function is executed by GATTC to reset cache in +** application +** +** Parameter server_bda: server bd address of this cache belongs to +** +** Returns void. +** +*******************************************************************************/ +BTA_API extern void bta_gattc_co_cache_reset(BD_ADDR server_bda); + #endif /* BTA_GATT_CO_H */ diff --git a/bta/include/bta_hh_api.h b/bta/include/bta_hh_api.h index f613d30ae..2cd29f406 100644 --- a/bta/include/bta_hh_api.h +++ b/bta/include/bta_hh_api.h @@ -29,7 +29,7 @@ #endif #ifndef BTA_HH_SSR_MAX_LATENCY_DEF -#define BTA_HH_SSR_MAX_LATENCY_DEF 1600 +#define BTA_HH_SSR_MAX_LATENCY_DEF 800 /* 500 ms*/ #endif #ifndef BTA_HH_SSR_MIN_TOUT_DEF @@ -51,15 +51,28 @@ #define BTA_HH_ADD_DEV_EVT 11 /* Add Device callback */ #define BTA_HH_RMV_DEV_EVT 12 /* remove device finished */ #define BTA_HH_VC_UNPLUG_EVT 13 /* virtually unplugged */ -#define BTA_HH_UPDATE_UCD_EVT 14 -#define BTA_HH_API_ERR_EVT 15 /* API error is caught */ +#define BTA_HH_DATA_EVT 15 +#define BTA_HH_API_ERR_EVT 16 /* API error is caught */ typedef UINT16 tBTA_HH_EVT; +/* application ID(none-zero) for each type of device */ +#define BTA_HH_APP_ID_MI 1 +#define BTA_HH_APP_ID_KB 2 +#define BTA_HH_APP_ID_RMC 3 +#define BTA_HH_APP_ID_3DSG 4 +#define BTA_HH_APP_ID_JOY 5 +#define BTA_HH_APP_ID_GPAD 6 +#define BTA_HH_APP_ID_LE 0xff + /* defined the minimum offset */ #define BTA_HH_MIN_OFFSET L2CAP_MIN_OFFSET+1 +/* HID_HOST_MAX_DEVICES can not exceed 15 for th design of BTA HH */ +#define BTA_HH_IDX_INVALID 0xff #define BTA_HH_MAX_KNOWN HID_HOST_MAX_DEVICES +#define BTA_HH_MAX_DEVICE HID_HOST_MAX_DEVICES + /* invalid device handle */ #define BTA_HH_INVALID_HANDLE 0xff @@ -107,7 +120,8 @@ enum BTA_HH_ERR_TOD_UNSPT, /* type of device not supported */ BTA_HH_ERR_NO_RES, /* out of system resources */ BTA_HH_ERR_AUTH_FAILED, /* authentication fail */ - BTA_HH_ERR_HDL + BTA_HH_ERR_HDL, + BTA_HH_ERR_SEC }; typedef UINT8 tBTA_HH_STATUS; @@ -162,6 +176,8 @@ typedef UINT8 tBTA_HH_TRANS_CTRL_TYPE; typedef tHID_DEV_DSCP_INFO tBTA_HH_DEV_DESCR; +#define BTA_HH_SSR_PARAM_INVALID HID_SSR_PARAM_INVALID + /* id DI is not existing in remote device, vendor_id in tBTA_HH_DEV_DSCP_INFO will be set to 0xffff */ #define BTA_HH_VENDOR_ID_INVALID 0xffff @@ -172,8 +188,8 @@ typedef struct UINT16 vendor_id; /* vendor ID */ UINT16 product_id; /* product ID */ UINT16 version; /* version */ - UINT16 ssr_max_latency; /* SSR max latency */ - UINT16 ssr_min_tout; /* SSR min timeout */ + UINT16 ssr_max_latency; /* SSR max latency, BTA_HH_SSR_PARAM_INVALID if unknown */ + UINT16 ssr_min_tout; /* SSR min timeout, BTA_HH_SSR_PARAM_INVALID if unknown */ UINT8 ctry_code; /*Country Code.*/ tBTA_HH_DEV_DESCR descriptor; }tBTA_HH_DEV_DSCP_INFO; @@ -291,7 +307,7 @@ extern "C" ** Returns void ** *******************************************************************************/ -BTA_API extern void BTA_HhEnable(tBTA_SEC sec_mask, BOOLEAN ucd_enabled, tBTA_HH_CBACK *p_cback); +BTA_API extern void BTA_HhEnable(tBTA_SEC sec_mask, tBTA_HH_CBACK *p_cback); /******************************************************************************* ** @@ -375,6 +391,28 @@ BTA_API extern void BTA_HhGetReport(UINT8 dev_handle, tBTA_HH_RPT_TYPE r_type, UINT8 rpt_id, UINT16 buf_size); /******************************************************************************* ** +** Function BTA_HhSetIdle +** +** Description send SET_IDLE to device. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_HhSetIdle(UINT8 dev_handle, UINT16 idle_rate); + +/******************************************************************************* +** +** Function BTA_HhGetIdle +** +** Description Send a GET_IDLE to HID device. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_HhGetIdle(UINT8 dev_handle); + +/******************************************************************************* +** ** Function BTA_HhSendCtrl ** ** Description Send HID_CONTROL request to a HID device. @@ -455,6 +493,7 @@ BTA_API extern void BTA_HhAddDev(BD_ADDR bda, tBTA_HH_ATTR_MASK attr_mask, ** *******************************************************************************/ BTA_API extern void BTA_HhRemoveDev(UINT8 dev_handle ); + /******************************************************************************* ** ** Parsing Utility Functions @@ -472,6 +511,11 @@ BTA_API extern void BTA_HhRemoveDev(UINT8 dev_handle ); BTA_API extern void BTA_HhParseBootRpt(tBTA_HH_BOOT_RPT *p_data, UINT8 *p_report, UINT16 report_len); +/* test commands */ +BTA_API extern void bta_hh_le_hid_read_rpt_clt_cfg(BD_ADDR bd_addr, UINT8 rpt_id); + + + #ifdef __cplusplus } #endif diff --git a/btif/co/bta_dm_co.c b/btif/co/bta_dm_co.c index 611af2dbf..a310a008d 100644 --- a/btif/co/bta_dm_co.c +++ b/btif/co/bta_dm_co.c @@ -25,6 +25,12 @@ #if (BTM_OOB_INCLUDED == TRUE) #include "btif_dm.h" #endif +#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE) +#include "bte_appl.h" +#endif + +tBTE_APPL_CFG bte_appl_cfg = { 0x5, 0x4, 0x7, 0x7, 0x10 }; + /******************************************************************************* ** ** Function bta_dm_co_get_compress_memory @@ -352,9 +358,10 @@ void bta_dm_co_le_io_key_req(BD_ADDR bd_addr, UINT8 *p_max_key_size, void bta_dm_co_ble_load_local_keys(tBTA_DM_BLE_LOCAL_KEY_MASK *p_key_mask, BT_OCTET16 er, tBTA_BLE_LOCAL_ID_KEYS *p_id_keys) { - BTIF_TRACE_ERROR0("##################################"); - BTIF_TRACE_ERROR0("bta_dm_co_ble_load_local_keys: TBD Load local keys if any are persisted"); - BTIF_TRACE_ERROR0("##################################"); + BTIF_TRACE_DEBUG0("##################################"); + BTIF_TRACE_DEBUG0("bta_dm_co_ble_load_local_keys: Load local keys if any are persisted"); + BTIF_TRACE_DEBUG0("##################################"); + btif_dm_get_ble_local_keys( p_key_mask, er, p_id_keys); } /******************************************************************************* @@ -387,14 +394,10 @@ void bta_dm_co_ble_io_req(BD_ADDR bd_addr, tBTA_IO_CAP *p_io_cap, * If the answer can not be obtained right away, * set *p_oob_data to BTA_OOB_UNKNOWN and call bta_dm_ci_io_req() when the answer is available */ + *p_oob_data = FALSE; + /* *p_auth_req by default is FALSE for devices with NoInputNoOutput; TRUE for other devices. */ - BTIF_TRACE_ERROR2("bta_dm_co_ble_io_req. p_auth_req=%d ble_authereq=%d", *p_auth_req, bte_appl_cfg.ble_auth_req); - BTIF_TRACE_ERROR2("bta_dm_co_ble_io_req. p_io_cap=%d ble_io_cap=%d", *p_io_cap, bte_appl_cfg.ble_io_cap); - BTIF_TRACE_ERROR2("bta_dm_co_ble_io_req. p_init_key=%d ble_init_key=%d", *p_init_key, bte_appl_cfg.ble_init_key); - BTIF_TRACE_ERROR2("bta_dm_co_ble_io_req. p_resp_key=%d ble_resp_key=%d", *p_resp_key, bte_appl_cfg.ble_resp_key ); - BTIF_TRACE_ERROR2("bta_dm_co_ble_io_req. p_max_key_size=%d ble_max_key_size=%d", *p_max_key_size, bte_appl_cfg.ble_max_key_size ); - *p_oob_data = FALSE; if (bte_appl_cfg.ble_auth_req) *p_auth_req = bte_appl_cfg.ble_auth_req | (bte_appl_cfg.ble_auth_req & 0x04) | ((*p_auth_req) & 0x04); @@ -407,9 +410,8 @@ void bta_dm_co_ble_io_req(BD_ADDR bd_addr, tBTA_IO_CAP *p_io_cap, if (bte_appl_cfg.ble_resp_key<=7) *p_resp_key = bte_appl_cfg.ble_resp_key; - if (bte_appl_cfg.ble_max_key_size<=16) + if (bte_appl_cfg.ble_max_key_size > 7 && bte_appl_cfg.ble_max_key_size <= 16) *p_max_key_size = bte_appl_cfg.ble_max_key_size; - } diff --git a/btif/co/bta_gattc_co.c b/btif/co/bta_gattc_co.c new file mode 100644 index 000000000..1a71d69f5 --- /dev/null +++ b/btif/co/bta_gattc_co.c @@ -0,0 +1,139 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2013 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + + +#include "gki.h" +#include "bta_gattc_co.h" +#include "bta_gattc_ci.h" + +#if( defined BLE_INCLUDED ) && (BLE_INCLUDED == TRUE) +#if( defined BTA_GATT_INCLUDED ) && (BTA_GATT_INCLUDED == TRUE) + + +/***************************************************************************** +** Function Declarations +*****************************************************************************/ + +/******************************************************************************* +** +** Function bta_gattc_co_cache_open +** +** Description This callout function is executed by GATTC when a GATT server +** cache is ready to be sent. +** +** Parameter server_bda: server bd address of this cache belongs to +** evt: call in event to be passed in when cache open is done. +** conn_id: connection ID of this cache operation attach to. +** to_save: open cache to save or to load. +** +** Returns void. +** +*******************************************************************************/ +void bta_gattc_co_cache_open(BD_ADDR server_bda, UINT16 evt, UINT16 conn_id, BOOLEAN to_save) +{ + tBTA_GATT_STATUS status = BTA_GATT_OK; + + /* open NV cache and send call in */ + bta_gattc_ci_cache_open(server_bda, evt, status, conn_id); +} + +/******************************************************************************* +** +** Function bta_gattc_co_cache_load +** +** Description This callout function is executed by GATT when server cache +** is required to load. +** +** Parameter server_bda: server bd address of this cache belongs to +** evt: call in event to be passed in when cache save is done. +** num_attr: number of attribute to be save. +** attr_index: starting attribute index of the save operation. +** conn_id: connection ID of this cache operation attach to. +** Returns +** +*******************************************************************************/ +void bta_gattc_co_cache_load(BD_ADDR server_bda, UINT16 evt, UINT16 start_index, UINT16 conn_id) +{ + UINT16 num_attr = 0; + tBTA_GATTC_NV_ATTR attr[BTA_GATTC_NV_LOAD_MAX]; + tBTA_GATT_STATUS status = BTA_GATT_MORE; + + bta_gattc_ci_cache_load(server_bda, evt, num_attr, attr, status, conn_id); +} +/******************************************************************************* +** +** Function bta_gattc_co_cache_save +** +** Description This callout function is executed by GATT when a server cache +** is available to save. +** +** Parameter server_bda: server bd address of this cache belongs to +** evt: call in event to be passed in when cache save is done. +** num_attr: number of attribute to be save. +** p_attr: pointer to the list of attributes to save. +** attr_index: starting attribute index of the save operation. +** conn_id: connection ID of this cache operation attach to. +** Returns +** +*******************************************************************************/ +void bta_gattc_co_cache_save (BD_ADDR server_bda, UINT16 evt, UINT16 num_attr, + tBTA_GATTC_NV_ATTR *p_attr_list, UINT16 attr_index, UINT16 conn_id) +{ + tBTA_GATT_STATUS status = BTA_GATT_OK; + + bta_gattc_ci_cache_save(server_bda, evt, status, conn_id); +} + +/******************************************************************************* +** +** Function bta_gattc_co_cache_close +** +** Description This callout function is executed by GATTC when a GATT server +** cache is written completely. +** +** Parameter server_bda: server bd address of this cache belongs to +** conn_id: connection ID of this cache operation attach to. +** +** Returns void. +** +*******************************************************************************/ +void bta_gattc_co_cache_close(BD_ADDR server_bda, UINT16 conn_id) +{ + /* close NV when server cache is done saving or loading, + does not need to do anything for now on Insight */ +} + +/******************************************************************************* +** +** Function bta_gattc_co_cache_reset +** +** Description This callout function is executed by GATTC to reset cache in +** application +** +** Parameter server_bda: server bd address of this cache belongs to +** +** Returns void. +** +*******************************************************************************/ +void bta_gattc_co_cache_reset(BD_ADDR server_bda) +{ +} + +#endif +#endif + diff --git a/btif/co/bta_gatts_co.c b/btif/co/bta_gatts_co.c new file mode 100644 index 000000000..725d14595 --- /dev/null +++ b/btif/co/bta_gatts_co.c @@ -0,0 +1,243 @@ +/***************************************************************************** +** +** Name: bta_gattc_co.c +** +** Description: This file contains the GATT client call-out +** function implementation for Insight. +** +** Copyright (c) 2010, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ + +#include "bta_api.h" + +#if( defined BLE_INCLUDED ) && (BLE_INCLUDED == TRUE) +#if( defined BTA_GATT_INCLUDED ) && (BTA_GATT_INCLUDED == TRUE) + +#include <stdlib.h> +#include "gki.h" +#include "bd.h" +#include "bta_gatts_co.h" + +/***************************************************************************** +** Local type definitions +*****************************************************************************/ + +#define BTIF_GATTS_MAX_SRV_CHG_CLT_SIZE 50 + +typedef struct +{ + BOOLEAN enable; + UINT8 num_clients; + tBTA_GATTS_SRV_CHG srv_chg[BTIF_GATTS_MAX_SRV_CHG_CLT_SIZE]; +} __attribute__((packed)) btif_gatts_srv_chg_cb_t; + +/***************************************************************************** +** Static variables +*****************************************************************************/ + +static btif_gatts_srv_chg_cb_t btif_gatts_srv_chg_cb; + +/***************************************************************************** +** Static functions +*****************************************************************************/ + +static void btif_gatts_check_init(void) +{ + btif_gatts_srv_chg_cb_t *p_cb= &btif_gatts_srv_chg_cb; + + if (!p_cb->enable) + { + memset(p_cb, 0, sizeof(btif_gatts_srv_chg_cb_t)); + p_cb->enable = TRUE; + } +} + +static BOOLEAN btif_gatts_srv_chg(tBTA_GATTS_SRV_CHG_CMD cmd, + tBTA_GATTS_SRV_CHG_REQ *p_req, + tBTA_GATTS_SRV_CHG_RSP *p_rsp) +{ + BOOLEAN status = TRUE; + BOOLEAN found = FALSE; + UINT8 i, j, idx, last_idx; + btif_gatts_srv_chg_cb_t *p_cb = &btif_gatts_srv_chg_cb; + + btif_gatts_check_init(); + + switch (cmd) + { + case BTA_GATTS_SRV_CHG_CMD_ADD_CLIENT: + + if (p_cb->num_clients < BTIF_GATTS_MAX_SRV_CHG_CLT_SIZE) + { + memcpy(&p_cb->srv_chg[p_cb->num_clients], &p_req->srv_chg, sizeof(tBTA_GATTS_SRV_CHG)); + p_cb->num_clients++; + } else { + status = FALSE; + } + break; + + case BTA_GATTS_SRV_CHG_CMD_UPDATE_CLIENT: + + for (i=0; i != p_cb->num_clients; ++i) + { + if (!memcmp(p_cb->srv_chg[i].bda, p_req->srv_chg.bda, sizeof(BD_ADDR))) + { + found = TRUE; + memcpy(&p_cb->srv_chg[i], &p_req->srv_chg, sizeof(tBTA_GATTS_SRV_CHG)); + break; + } + } + + if (!found) + status = FALSE; + break; + + case BTA_GATTS_SRV_CHG_CMD_REMOVE_CLIENT: + + for (i=0; i != p_cb->num_clients; ++i) + { + if (!memcmp(p_cb->srv_chg[i].bda, p_req->srv_chg.bda, sizeof(BD_ADDR))) + { + found = TRUE; + last_idx = p_cb->num_clients - 1; + + if (i != last_idx ) + { + /* Update the array so there is no gap */ + for (j=i; j != last_idx; ++j ) + { + memcpy(&p_cb->srv_chg[j], &p_cb->srv_chg[j+1], sizeof(tBTA_GATTS_SRV_CHG)); + } + + } + + /* Reset the last client and update num_clients */ + memset(&p_cb->srv_chg[last_idx], 0, sizeof(tBTA_GATTS_SRV_CHG)); + p_cb->num_clients--; + break; + } + } + + if (!found) + status = FALSE; + break; + + case BTA_GATTS_SRV_CHG_CMD_READ_NUM_CLENTS: + p_rsp->num_clients = p_cb->num_clients; + break; + + case BTA_GATTS_SRV_CHG_CMD_READ_CLENT: + idx = p_req->client_read_index - 1; + + if (idx < p_cb->num_clients ) + memcpy(&p_rsp->srv_chg, &p_cb->srv_chg[idx], sizeof(tBTA_GATTS_SRV_CHG)); + else + status = FALSE; + break; + + default: + status = FALSE; + break; + } + + return status; +} + +/***************************************************************************** +** Externally called functions +*****************************************************************************/ + +void btif_gatts_add_bonded_dev_from_nv(BD_ADDR bda) +{ + btif_gatts_srv_chg_cb_t *p_cb= &btif_gatts_srv_chg_cb; + BOOLEAN found = FALSE; + UINT8 i; + + btif_gatts_check_init(); + + for (i=0; i != p_cb->num_clients; ++i) + { + if (!memcmp(p_cb->srv_chg[i].bda, bda, sizeof(BD_ADDR))) + { + found = TRUE; + break; + } + } + + if (!found) + { + if (p_cb->num_clients < BTIF_GATTS_MAX_SRV_CHG_CLT_SIZE) + { + bdcpy(p_cb->srv_chg[p_cb->num_clients].bda, bda); + p_cb->srv_chg[p_cb->num_clients].srv_changed = FALSE; + p_cb->num_clients++; + } + } +} + +/***************************************************************************** +** Call-out functions +*****************************************************************************/ + +/******************************************************************************* +** +** Function bta_gatts_co_update_handle_range +** +** Description This callout function is executed by GATTS when a GATT server +** handle range ios to be added or removed. +** +** Parameter is_add: true is to add a handle range; otherwise is to delete. +** p_hndl_range: handle range. +** +** Returns void. +** +*******************************************************************************/ +void bta_gatts_co_update_handle_range(BOOLEAN is_add, tBTA_GATTS_HNDL_RANGE *p_hndl_range) +{ +} + +/******************************************************************************* +** +** Function bta_gatts_co_srv_chg +** +** Description This call-out is to read/write/remove service change related +** informaiton. The request consists of the cmd and p_req and the +** response is returned in p_rsp +** +** Parameter cmd - request command +** p_req - request paramters +** p_rsp - response data for the request +** +** Returns TRUE - if the request is processed successfully and +** the response is returned in p_rsp. +** FASLE - if the request can not be processed +** +*******************************************************************************/ +BOOLEAN bta_gatts_co_srv_chg(tBTA_GATTS_SRV_CHG_CMD cmd, + tBTA_GATTS_SRV_CHG_REQ *p_req, + tBTA_GATTS_SRV_CHG_RSP *p_rsp) +{ + return FALSE; +} + +/******************************************************************************* +** +** Function bta_gatts_co_load_handle_range +** +** Description This callout function is executed by GATTS when a GATT server +** handle range is requested to be loaded from NV. +** +** Parameter +** +** Returns void. +** +*******************************************************************************/ +BOOLEAN bta_gatts_co_load_handle_range(UINT8 index, + tBTA_GATTS_HNDL_RANGE *p_handle_range) +{ + return FALSE; +} +#endif +#endif diff --git a/btif/co/bta_hh_co.c b/btif/co/bta_hh_co.c index b4ea4c223..e7f9be211 100644 --- a/btif/co/bta_hh_co.c +++ b/btif/co/bta_hh_co.c @@ -61,7 +61,10 @@ static int uhid_event(btif_hh_device_t *p_dev) ssize_t ret; memset(&ev, 0, sizeof(ev)); if(!p_dev) + { APPL_TRACE_ERROR1("%s: Device not found",__FUNCTION__) + return -1; + } ret = read(p_dev->fd, &ev, sizeof(ev)); if (ret == 0) { APPL_TRACE_ERROR2("%s: Read HUP on uhid-cdev %s", __FUNCTION__, @@ -91,7 +94,6 @@ static int uhid_event(btif_hh_device_t *p_dev) APPL_TRACE_DEBUG0("UHID_CLOSE from uhid-dev\n"); break; case UHID_OUTPUT: - APPL_TRACE_DEBUG0("UHID_OUTPUT from uhid-dev\n"); APPL_TRACE_DEBUG2("UHID_OUTPUT: Report type = %d, report_size = %d" ,ev.u.output.rtype, ev.u.output.size); //Send SET_REPORT with feature report if the report type in output event is FEATURE @@ -331,8 +333,9 @@ void bta_hh_co_close(UINT8 dev_handle, UINT8 app_id) p_dev = &btif_hh_cb.devices[i]; if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN && p_dev->dev_handle == dev_handle) { APPL_TRACE_WARNING3("%s: Found an existing device with the same handle " - "dev_status = %d, dev_handle =%d",__FUNCTION__, - p_dev->dev_status,p_dev->dev_handle); + "dev_status = %d, dev_handle =%d" + ,__FUNCTION__,p_dev->dev_status + ,p_dev->dev_handle); btif_hh_close_poll_thread(p_dev); break; } diff --git a/btif/include/btif_api.h b/btif/include/btif_api.h index c787becb7..19af505ac 100644 --- a/btif/include/btif_api.h +++ b/btif/include/btif_api.h @@ -325,4 +325,14 @@ bt_status_t btif_dut_mode_configure(uint8_t enable); *******************************************************************************/ bt_status_t btif_dut_mode_send(uint16_t opcode, uint8_t *buf, uint8_t len); +/******************************************************************************* +** +** Function btif_le_test_mode +** +** Description Sends a HCI BLE Test command to the Controller +** +** Returns BT_STATUS_SUCCESS on success +** +*******************************************************************************/ +bt_status_t btif_le_test_mode(uint16_t opcode, uint8_t *buf, uint8_t len); #endif /* BTIF_API_H */ diff --git a/btif/include/btif_common.h b/btif/include/btif_common.h index 6bf885fde..f11b6294d 100644 --- a/btif/include/btif_common.h +++ b/btif/include/btif_common.h @@ -107,6 +107,9 @@ enum BTIF_DM_CB_REMOVE_BOND, /*Remove bond */ BTIF_DM_CB_HID_REMOTE_NAME, /* Remote name callback for HID device */ BTIF_DM_CB_BOND_STATE_BONDING, + BTIF_DM_CB_LE_TX_TEST, /* BLE Tx Test command complete callback */ + BTIF_DM_CB_LE_RX_TEST, /* BLE Rx Test command complete callback */ + BTIF_DM_CB_LE_TEST_END, /* BLE Test mode end callback */ BTIF_HFP_CB_START = BTIF_SIG_CB_START(BTIF_HFP), BTIF_HFP_CB_AUDIO_CONNECTING, /* HF AUDIO connect has been sent to BTA successfully */ diff --git a/btif/include/btif_dm.h b/btif/include/btif_dm.h index 2d73c45fb..ed03e3419 100644 --- a/btif/include/btif_dm.h +++ b/btif/include/btif_dm.h @@ -19,7 +19,8 @@ #ifndef BTIF_DM_H #define BTIF_DM_H -/******************************************************************************* +#include "bta_api.h" +/************************************************************************************ ** Functions ********************************************************************************/ @@ -45,5 +46,75 @@ void btif_dm_proc_loc_oob(BOOLEAN valid, BT_OCTET16 c, BT_OCTET16 r); BOOLEAN btif_dm_proc_rmt_oob(BD_ADDR bd_addr, BT_OCTET16 p_c, BT_OCTET16 p_r); #endif /* BTIF_DM_OOB_TEST */ #endif /* BTM_OOB_INCLUDED */ +#if (BLE_INCLUDED == TRUE) + +typedef struct +{ + UINT8 ltk[BT_OCTET16_LEN]; + UINT8 rand[BT_OCTET8_LEN]; + UINT16 ediv; + UINT8 sec_level; + UINT8 key_size; +}btif_dm_ble_penc_keys_t; + +typedef struct +{ + UINT32 counter; + UINT8 csrk[BT_OCTET16_LEN]; + UINT8 sec_level; +}btif_dm_ble_pcsrk_keys_t; + +typedef struct +{ + UINT16 div; + UINT8 key_size; + UINT8 sec_level; +}btif_dm_ble_lenc_keys_t; + +typedef struct +{ + UINT32 counter; + UINT16 div; + UINT8 sec_level; + +}btif_dm_ble_lcsrk_keys_t; + +typedef struct +{ + BOOLEAN is_penc_key_rcvd; + btif_dm_ble_penc_keys_t penc_key; /* received peer encryption key */ + BOOLEAN is_pcsrk_key_rcvd; + btif_dm_ble_pcsrk_keys_t pcsrk_key; /* received peer device SRK */ + BOOLEAN is_pid_key_rcvd; + UINT8 pid_key[BT_OCTET16_LEN]; /* peer device ID key */ + BOOLEAN is_lenc_key_rcvd; + btif_dm_ble_lenc_keys_t lenc_key; /* local encryption reproduction keys LTK = = d1(ER,DIV,0)*/ + BOOLEAN is_lcsrk_key_rcvd; + btif_dm_ble_lcsrk_keys_t lcsrk_key; /* local device CSRK = d1(ER,DIV,1)*/ +} btif_dm_ble_cb_t; + +#define BTIF_DM_LE_KEY_PENC BTA_LE_KEY_PENC +#define BTIF_DM_LE_KEY_PID BTA_LE_KEY_PID +#define BTIF_DM_LE_KEY_PCSRK BTA_LE_KEY_PCSRK +#define BTIF_DM_LE_KEY_LENC BTA_LE_KEY_LENC +#define BTIF_DM_LE_KEY_LID BTA_LE_KEY_LID +#define BTIF_DM_LE_KEY_LCSRK BTA_LE_KEY_LCSRK + +#define BTIF_DM_LE_LOCAL_KEY_IR (1<<0) +#define BTIF_DM_LE_LOCAL_KEY_IRK (1<<1) +#define BTIF_DM_LE_LOCAL_KEY_DHK (1<<2) +#define BTIF_DM_LE_LOCAL_KEY_ER (1<<3) + +void btif_dm_load_ble_local_keys(void); +void btif_dm_get_ble_local_keys(tBTA_DM_BLE_LOCAL_KEY_MASK *p_key_mask, BT_OCTET16 er, + tBTA_BLE_LOCAL_ID_KEYS *p_id_keys); +void btif_dm_save_ble_bonding_keys(void); +void btif_dm_remove_ble_bonding_keys(void); +void btif_dm_ble_sec_req_evt(tBTA_DM_BLE_SEC_REQ *p_ble_req); + +void btif_dm_update_ble_remote_properties( BD_ADDR bd_addr, BD_NAME bd_name, + tBT_DEVICE_TYPE dev_type); + +#endif /* BLE_INCLUDED */ #endif diff --git a/btif/include/btif_gatt.h b/btif/include/btif_gatt.h new file mode 100644 index 000000000..e71ba1ee3 --- /dev/null +++ b/btif/include/btif_gatt.h @@ -0,0 +1,34 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2013 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + + +/***************************************************************************** +** +** Name: btif_gatt.h +** +** Description: +** +******************************************************************************/ + +#ifndef BTIF_GATT_H +#define BTIF_GATT_H + + + +#endif + diff --git a/btif/include/btif_gatt_util.h b/btif/include/btif_gatt_util.h new file mode 100644 index 000000000..37fe5011a --- /dev/null +++ b/btif/include/btif_gatt_util.h @@ -0,0 +1,39 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2013 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + + +#ifndef BTIF_GATT_UTIL_H +#define BTIF_GATT_UTIL_H + +void btif_to_bta_uuid(tBT_UUID *p_dest, bt_uuid_t *p_src); +void btif_to_bta_char_id(tBTA_GATT_ID *p_dest, btgatt_char_id_t *p_src); +void btif_to_bta_srvc_id(tBTA_GATT_SRVC_ID *p_dest, btgatt_srvc_id_t *p_src); +void btif_to_bta_response(tBTA_GATTS_RSP *p_dest, btgatt_response_t* p_src); + +void bta_to_btif_uuid(bt_uuid_t *p_dest, tBT_UUID *p_src); +void bta_to_btif_srvc_id(btgatt_srvc_id_t *p_dest, tBTA_GATT_SRVC_ID *p_src); +void bta_to_btif_char_id(btgatt_char_id_t *p_dest, tBTA_GATT_ID *p_src); + +uint16_t set_read_value(btgatt_read_params_t *p_dest, tBTA_GATTC_READ *p_src); + +void btif_gatt_check_encrypted_link(BD_ADDR bd_addr); +void btif_gatt_remove_encrypted_link(BD_ADDR bd_addr); + + +#endif + diff --git a/btif/include/btif_hh.h b/btif/include/btif_hh.h index 25063eb24..c77d59707 100644 --- a/btif/include/btif_hh.h +++ b/btif/include/btif_hh.h @@ -96,6 +96,7 @@ extern btif_hh_cb_t btif_hh_cb; extern btif_hh_device_t *btif_hh_find_connected_dev_by_handle(UINT8 handle); extern void btif_hh_remove_device(bt_bdaddr_t bd_addr); +BOOLEAN btif_hh_add_added_dev(bt_bdaddr_t bda, tBTA_HH_ATTR_MASK attr_mask); extern bt_status_t btif_hh_virtual_unplug(bt_bdaddr_t *bd_addr); extern void btif_hh_disconnect(bt_bdaddr_t *bd_addr); extern void btif_hh_setreport(btif_hh_device_t *p_dev, bthh_report_type_t r_type, diff --git a/btif/include/btif_storage.h b/btif/include/btif_storage.h index 87dec3bb0..41507fbf8 100644 --- a/btif/include/btif_storage.h +++ b/btif/include/btif_storage.h @@ -105,7 +105,7 @@ bt_status_t btif_storage_set_remote_device_property(bt_bdaddr_t *remote_bd_addr, ** BT_STATUS_FAIL otherwise ** *******************************************************************************/ -bt_status_t btif_storage_add_remote_device(bt_bdaddr_t *remote_bdaddr, +bt_status_t btif_storage_add_remote_device(bt_bdaddr_t *remote_bd_addr, uint32_t num_properties, bt_property_t *properties); @@ -231,19 +231,19 @@ bt_status_t btif_storage_write_hl_mdl_data(UINT8 app_idx, char *value, int value ** BT_STATUS_FAIL otherwise ** *******************************************************************************/ + bt_status_t btif_storage_add_hid_device_info(bt_bdaddr_t *remote_bd_addr, UINT16 attr_mask, UINT8 sub_class, UINT8 app_id, UINT16 vendor_id, UINT16 product_id, UINT16 version, - UINT8 ctry_code, UINT16 dl_len, - UINT8 *dsc_list); + UINT8 ctry_code, UINT16 dl_len, UINT8 *dsc_list); /******************************************************************************* ** ** Function btif_storage_load_bonded_hid_info ** -** Description BTIF storage API - Loads hid info for all the bonded devices -** from NVRAM and adds those devices to the BTA_HH. +** Description BTIF storage API - Loads hid info for all the bonded devices from NVRAM +** and adds those devices to the BTA_HH. ** ** Returns BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise ** @@ -284,7 +284,8 @@ bt_status_t btif_storage_load_autopair_device_list(); ** FALSE otherwise ** *******************************************************************************/ -BOOLEAN btif_storage_is_device_autopair_blacklisted(bt_bdaddr_t *remote_dev_addr); + +BOOLEAN btif_storage_is_device_autopair_blacklisted(bt_bdaddr_t *remote_bd_addr); /******************************************************************************* ** @@ -296,7 +297,8 @@ BOOLEAN btif_storage_is_device_autopair_blacklisted(bt_bdaddr_t *remote_dev_add ** BT_STATUS_FAIL otherwise ** *******************************************************************************/ -bt_status_t btif_storage_add_device_to_autopair_blacklist(bt_bdaddr_t *remote_dev_addr); + +bt_status_t btif_storage_add_device_to_autopair_blacklist(bt_bdaddr_t *remote_bd_addr); /******************************************************************************* ** @@ -308,6 +310,45 @@ bt_status_t btif_storage_add_device_to_autopair_blacklist(bt_bdaddr_t *remote_de ** FALSE otherwise ** *******************************************************************************/ -BOOLEAN btif_storage_is_fixed_pin_zeros_keyboard(bt_bdaddr_t *remote_dev_addr); +BOOLEAN btif_storage_is_fixed_pin_zeros_keyboard(bt_bdaddr_t *remote_bd_addr); + +#if (BLE_INCLUDED == TRUE) +bt_status_t btif_storage_add_ble_bonding_key( bt_bdaddr_t *remote_bd_addr, + char *key, + uint8_t key_type, + uint8_t key_length); +bt_status_t btif_storage_get_ble_bonding_key(bt_bdaddr_t *remote_bd_addr, + UINT8 key_type, + char *key_value, + int key_length); + +bt_status_t btif_storage_add_ble_local_key(char *key, + uint8_t key_type, + uint8_t key_length); +bt_status_t btif_storage_remove_ble_bonding_keys(bt_bdaddr_t *remote_bd_addr); +bt_status_t btif_storage_remove_ble_local_keys(void); +bt_status_t btif_storage_get_ble_local_key(UINT8 key_type, + char *key_value, + int key_len); + +bt_status_t btif_storage_get_remote_addr_type(bt_bdaddr_t *remote_bd_addr, + int *addr_type); + +bt_status_t btif_storage_set_remote_addr_type(bt_bdaddr_t *remote_bd_addr, + UINT8 addr_type); + +#endif +/******************************************************************************* +** +** Function btif_storage_get_remote_version +** +** Description Fetch remote version info on cached remote device +** +** Returns BT_STATUS_SUCCESS if found +** BT_STATUS_FAIL otherwise +** +*******************************************************************************/ +bt_status_t btif_storage_get_remote_version(const bt_bdaddr_t *remote_bd_addr, + bt_remote_version_t *p_ver); #endif /* BTIF_STORAGE_H */ diff --git a/btif/include/btif_util.h b/btif/include/btif_util.h index 09dae6e33..ddb469966 100644 --- a/btif/include/btif_util.h +++ b/btif/include/btif_util.h @@ -22,6 +22,7 @@ #include <hardware/bluetooth.h> #include <hardware/bt_hf.h> #include <utils/Log.h> +#include <sys/time.h> #include "data_types.h" #include "bt_types.h" @@ -60,7 +61,7 @@ const char* dump_av_conn_state(UINT16 event); const char* dump_av_audio_state(UINT16 event); int str2bd(char *str, bt_bdaddr_t *addr); -char *bd2str(bt_bdaddr_t *addr, bdstr_t *bdstr); +char *bd2str(const bt_bdaddr_t *addr, bdstr_t *bdstr); UINT32 devclass2uint(DEV_CLASS dev_class); void uint2devclass(UINT32 dev, DEV_CLASS dev_class); diff --git a/btif/include/uinput.h b/btif/include/uinput.h index 5925703a7..9a25e4b45 100644 --- a/btif/include/uinput.h +++ b/btif/include/uinput.h @@ -262,6 +262,7 @@ extern "C" { #define KEY_SUSPEND 205 #define KEY_CLOSE 206 #define KEY_PLAY 207 +#define KEY_FAST_FORWARD 208 #define KEY_UNKNOWN 220 diff --git a/btif/src/bluetooth.c b/btif/src/bluetooth.c index 20d6a0702..ffeaaaf90 100644 --- a/btif/src/bluetooth.c +++ b/btif/src/bluetooth.c @@ -35,6 +35,7 @@ #include <hardware/bt_hh.h> #include <hardware/bt_hl.h> #include <hardware/bt_pan.h> +#include <hardware/bt_gatt.h> #define LOG_NDDEBUG 0 #define LOG_TAG "bluedroid" @@ -80,6 +81,8 @@ extern bthh_interface_t *btif_hh_get_interface(); extern bthl_interface_t *btif_hl_get_interface(); /*pan*/ extern btpan_interface_t *btif_pan_get_interface(); +/* gatt */ +extern btgatt_interface_t *btif_gatt_get_interface(); /************************************************************************************ ** Functions @@ -319,6 +322,8 @@ static const void* get_profile_interface (const char *profile_id) if (is_profile(profile_id, BT_PROFILE_HEALTH_ID)) return btif_hl_get_interface(); + if (is_profile(profile_id, BT_PROFILE_GATT_ID)) + return btif_gatt_get_interface(); return NULL; } @@ -343,8 +348,20 @@ int dut_mode_send(uint16_t opcode, uint8_t* buf, uint8_t len) return btif_dut_mode_send(opcode, buf, len); } +int le_test_mode(uint16_t opcode, uint8_t* buf, uint8_t len) +{ + ALOGI("le_test_mode"); + + /* sanity check */ + if (interface_ready() == FALSE) + return BT_STATUS_NOT_READY; + + return btif_le_test_mode(opcode, buf, len); +} + + static const bt_interface_t bluetoothInterface = { - sizeof(bt_interface_t), + sizeof(bluetoothInterface), init, enable, disable, @@ -366,7 +383,8 @@ static const bt_interface_t bluetoothInterface = { ssp_reply, get_profile_interface, dut_mode_configure, - dut_mode_send + dut_mode_send, + le_test_mode }; const bt_interface_t* bluetooth__get_bluetooth_interface () diff --git a/btif/src/btif_core.c b/btif/src/btif_core.c index 62339a907..ca39cc8f7 100755..100644 --- a/btif/src/btif_core.c +++ b/btif/src/btif_core.c @@ -290,6 +290,9 @@ static void btif_task(UINT32 params) if (event == BT_EVT_TRIGGER_STACK_INIT) { BTIF_TRACE_DEBUG0("btif_task: received trigger stack init event"); + #if (BLE_INCLUDED == TRUE) + btif_dm_load_ble_local_keys(); + #endif BTA_EnableBluetooth(bte_dm_evt); } @@ -830,6 +833,7 @@ bt_status_t btif_dut_mode_send(uint16_t opcode, uint8_t *buf, uint8_t len) BTM_VendorSpecificCommand(opcode, len, buf, btif_dut_mode_cback); return BT_STATUS_SUCCESS; } + /***************************************************************************** ** ** btif api adapter property functions diff --git a/btif/src/btif_dm.c b/btif/src/btif_dm.c index cb0971944..767cd0faa 100644 --- a/btif/src/btif_dm.c +++ b/btif/src/btif_dm.c @@ -38,10 +38,12 @@ #include "bta_api.h" #include "btif_api.h" #include "btif_util.h" +#include "btif_dm.h" #include "btif_storage.h" #include "btif_hh.h" #include "btif_config.h" +#include "bta_gatt_api.h" /****************************************************************************** ** Constants & Macros ******************************************************************************/ @@ -61,7 +63,10 @@ #define BTIF_DM_DEFAULT_INQ_MAX_RESULTS 0 #define BTIF_DM_DEFAULT_INQ_MAX_DURATION 10 -typedef struct { + + +typedef struct +{ bt_bond_state_t state; BD_ADDR bd_addr; UINT8 is_temp; @@ -70,9 +75,31 @@ typedef struct { UINT8 autopair_attempts; UINT8 is_local_initiated; UINT8 bonded_pending_sdp; +#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) + BOOLEAN is_le_only; + btif_dm_ble_cb_t ble; +#endif } btif_dm_pairing_cb_t; -typedef struct { + +typedef struct +{ + UINT8 ir[BT_OCTET16_LEN]; + UINT8 irk[BT_OCTET16_LEN]; + UINT8 dhk[BT_OCTET16_LEN]; +}btif_dm_local_key_id_t; + +typedef struct +{ + BOOLEAN is_er_rcvd; + UINT8 er[BT_OCTET16_LEN]; + BOOLEAN is_id_keys_rcvd; + btif_dm_local_key_id_t id_keys; /* ID kyes */ + +}btif_dm_local_key_cb_t; + +typedef struct +{ BD_ADDR bd_addr; BD_NAME bd_name; } btif_dm_remote_name_t; @@ -98,7 +125,12 @@ static void btif_dm_cb_create_bond(bt_bdaddr_t *bd_addr); static void btif_dm_cb_hid_remote_name(tBTM_REMOTE_DEV_NAME *p_remote_name); static void btif_update_remote_properties(BD_ADDR bd_addr, BD_NAME bd_name, DEV_CLASS dev_class, tBT_DEVICE_TYPE dev_type); - +#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) +static btif_dm_local_key_cb_t ble_local_key_cb; +static void btif_dm_ble_key_notif_evt(tBTA_DM_SP_KEY_NOTIF *p_ssp_key_notif); +static void btif_dm_ble_auth_cmpl_evt (tBTA_DM_AUTH_CMPL *p_auth_cmpl); +static void btif_dm_ble_passkey_req_evt(tBTA_DM_PIN_REQ *p_pin_req); +#endif /****************************************************************************** ** Externs ******************************************************************************/ @@ -283,6 +315,40 @@ static void bond_state_changed(bt_status_t status, bt_bdaddr_t *bd_addr, bt_bond } +/* store remote version in bt config to always have access + to it post pairing*/ +static void btif_update_remote_version_property(bt_bdaddr_t *p_bd) +{ + bt_property_t property; + UINT8 lmp_ver = 0; + UINT16 lmp_subver = 0; + UINT16 mfct_set = 0; + tBTM_STATUS btm_status; + bt_remote_version_t info; + bt_status_t status; + bdstr_t bdstr; + + btm_status = BTM_ReadRemoteVersion(*(BD_ADDR*)p_bd, &lmp_ver, + &mfct_set, &lmp_subver); + + ALOGD("remote version info [%s]: %x, %x, %x", bd2str(p_bd, &bdstr), + lmp_ver, mfct_set, lmp_subver); + + if (btm_status == BTM_SUCCESS) + { + /* always update cache to ensure we have availability whenever BTM API + is not populated */ + info.manufacturer = mfct_set; + info.sub_ver = lmp_subver; + info.version = lmp_ver; + BTIF_STORAGE_FILL_PROPERTY(&property, + BT_PROPERTY_REMOTE_VERSION_INFO, sizeof(bt_remote_version_t), + &info); + status = btif_storage_set_remote_device_property(p_bd, &property); + ASSERTC(status == BT_STATUS_SUCCESS, "failed to save remote version", status); + } +} + static void btif_update_remote_properties(BD_ADDR bd_addr, BD_NAME bd_name, DEV_CLASS dev_class, tBT_DEVICE_TYPE device_type) @@ -379,12 +445,13 @@ static void btif_dm_cb_hid_remote_name(tBTM_REMOTE_DEV_NAME *p_remote_name) int remove_hid_bond(bt_bdaddr_t *bd_addr) { - /* For HID device, inorder to avoid the HID device from re-connecting again after unpairing, - * we need to do virtual unplug - */ - bdstr_t bdstr; - BTIF_TRACE_DEBUG2("%s---Removing HID bond--%s", __FUNCTION__,bd2str((bt_bdaddr_t *)bd_addr, &bdstr)); - return btif_hh_virtual_unplug(bd_addr); + /* For HID device, inorder to avoid the HID device from re-connecting again after unpairing, + * we need to do virtual unplug + */ + bdstr_t bdstr; + BTIF_TRACE_DEBUG2("%s---Removing HID bond--%s", __FUNCTION__,bd2str((bt_bdaddr_t *)bd_addr, &bdstr)); + return btif_hh_virtual_unplug(bd_addr); + } /******************************************************************************* ** @@ -398,18 +465,34 @@ int remove_hid_bond(bt_bdaddr_t *bd_addr) *******************************************************************************/ static void btif_dm_cb_create_bond(bt_bdaddr_t *bd_addr) { + BOOLEAN is_hid = check_cod(bd_addr, COD_HID_POINTING); + + bond_state_changed(BT_STATUS_SUCCESS, bd_addr, BT_BOND_STATE_BONDING); - if (check_cod(bd_addr, COD_HID_POINTING)){ + + if (is_hid){ + int status; status = btif_hh_connect(bd_addr); if(status != BT_STATUS_SUCCESS) bond_state_changed(status, bd_addr, BT_BOND_STATE_NONE); } else + { + int device_type; + int addr_type; + bdstr_t bdstr; + bd2str(bd_addr, &bdstr); + if(btif_config_get_int("Remote", (char const *)&bdstr,"DevType", &device_type) && + (btif_storage_get_remote_addr_type(bd_addr, &addr_type) == BT_STATUS_SUCCESS) && + (device_type == BT_DEVICE_TYPE_BLE)) + { + BTA_DmAddBleDevice(bd_addr->address, addr_type, BT_DEVICE_TYPE_BLE); + } BTA_DmBond ((UINT8 *)bd_addr->address); - - /* Track originator of bond creation */ - pairing_cb.is_local_initiated = TRUE; + } + /* Track originator of bond creation */ + pairing_cb.is_local_initiated = TRUE; } @@ -629,7 +712,8 @@ static void btif_dm_ssp_cfm_req_evt(tBTA_DM_SP_CFM_REQ *p_ssp_cfm_req) /* if just_works and bonding bit is not set treat this as temporary */ if (p_ssp_cfm_req->just_works && !(p_ssp_cfm_req->loc_auth_req & BTM_AUTH_BONDS) && - !(p_ssp_cfm_req->rmt_auth_req & BTM_AUTH_BONDS)) + !(p_ssp_cfm_req->rmt_auth_req & BTM_AUTH_BONDS) && + !(check_cod((bt_bdaddr_t*)&p_ssp_cfm_req->bd_addr, COD_HID_POINTING))) pairing_cb.is_temp = TRUE; else pairing_cb.is_temp = FALSE; @@ -1214,23 +1298,22 @@ static void btif_dm_upstreams_evt(UINT16 event, char* p_param) case BTA_DM_BUSY_LEVEL_EVT: { - UINT8 busy_level; - busy_level = p_data->busy_level.level; - if (busy_level & BTM_BL_INQUIRY_PAGING_MASK) + + if (p_data->busy_level.level_flags & BTM_BL_INQUIRY_PAGING_MASK) { - if (busy_level == BTM_BL_INQUIRY_STARTED) + if (p_data->busy_level.level_flags == BTM_BL_INQUIRY_STARTED) { HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb, BT_DISCOVERY_STARTED); btif_dm_inquiry_in_progress = TRUE; } - else if (busy_level == BTM_BL_INQUIRY_CANCELLED) + else if (p_data->busy_level.level_flags == BTM_BL_INQUIRY_CANCELLED) { HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb, BT_DISCOVERY_STOPPED); btif_dm_inquiry_in_progress = FALSE; } - else if (busy_level == BTM_BL_INQUIRY_COMPLETE) + else if (p_data->busy_level.level_flags == BTM_BL_INQUIRY_COMPLETE) { btif_dm_inquiry_in_progress = FALSE; } @@ -1240,6 +1323,9 @@ static void btif_dm_upstreams_evt(UINT16 event, char* p_param) case BTA_DM_LINK_UP_EVT: bdcpy(bd_addr.address, p_data->link_up.bd_addr); BTIF_TRACE_DEBUG0("BTA_DM_LINK_UP_EVT. Sending BT_ACL_STATE_CONNECTED"); + + btif_update_remote_version_property(&bd_addr); + HAL_CBACK(bt_hal_cbacks, acl_state_changed_cb, BT_STATUS_SUCCESS, &bd_addr, BT_ACL_STATE_CONNECTED); break; @@ -1265,19 +1351,158 @@ static void btif_dm_upstreams_evt(UINT16 event, char* p_param) kill(getpid(), SIGKILL); break; - case BTA_DM_AUTHORIZE_EVT: - case BTA_DM_SIG_STRENGTH_EVT: - case BTA_DM_SP_RMT_OOB_EVT: - case BTA_DM_SP_KEYPRESS_EVT: - case BTA_DM_ROLE_CHG_EVT: +#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) case BTA_DM_BLE_KEY_EVT: + BTIF_TRACE_DEBUG1("BTA_DM_BLE_KEY_EVT key_type=0x%02x ", p_data->ble_key.key_type); + + /* If this pairing is by-product of local initiated GATT client Read or Write, + BTA would not have sent BTA_DM_BLE_SEC_REQ_EVT event and Bond state would not + have setup properly. Setup pairing_cb and notify App about Bonding state now*/ + if (pairing_cb.state != BT_BOND_STATE_BONDING) + { + BTIF_TRACE_DEBUG0("Bond state not sent to App so far.Notify the app now"); + bond_state_changed(BT_STATUS_SUCCESS, (bt_bdaddr_t*)p_data->ble_key.bd_addr, + BT_BOND_STATE_BONDING); + } + else if (memcmp (pairing_cb.bd_addr, p_data->ble_key.bd_addr, BD_ADDR_LEN)!=0) + { + BTIF_TRACE_ERROR1("BD mismatch discard BLE key_type=%d ",p_data->ble_key.key_type); + break; + } + + switch (p_data->ble_key.key_type) + { + case BTA_LE_KEY_PENC: + BTIF_TRACE_DEBUG0("Rcv BTA_LE_KEY_PENC"); + pairing_cb.ble.is_penc_key_rcvd = TRUE; + memcpy(pairing_cb.ble.penc_key.ltk,p_data->ble_key.key_value.penc_key.ltk, 16); + memcpy(pairing_cb.ble.penc_key.rand, p_data->ble_key.key_value.penc_key.rand,8); + pairing_cb.ble.penc_key.ediv = p_data->ble_key.key_value.penc_key.ediv; + pairing_cb.ble.penc_key.sec_level = p_data->ble_key.key_value.penc_key.sec_level; + + for (i=0; i<16; i++) + { + BTIF_TRACE_DEBUG2("pairing_cb.ble.penc_key.ltk[%d]=0x%02x",i,pairing_cb.ble.penc_key.ltk[i]); + } + for (i=0; i<8; i++) + { + BTIF_TRACE_DEBUG2("pairing_cb.ble.penc_key.rand[%d]=0x%02x",i,pairing_cb.ble.penc_key.rand[i]); + } + BTIF_TRACE_DEBUG1("pairing_cb.ble.penc_key.ediv=0x%04x",pairing_cb.ble.penc_key.ediv); + BTIF_TRACE_DEBUG1("pairing_cb.ble.penc_key.sec_level=0x%02x",pairing_cb.ble.penc_key.sec_level); + BTIF_TRACE_DEBUG1("pairing_cb.ble.penc_key.key_size=0x%02x",pairing_cb.ble.penc_key.key_size); + break; + + case BTA_LE_KEY_PID: + BTIF_TRACE_DEBUG0("Rcv BTA_LE_KEY_PID"); + pairing_cb.ble.is_pid_key_rcvd = TRUE; + memcpy(pairing_cb.ble.pid_key, p_data->ble_key.key_value.pid_key.irk, 16); + for (i=0; i<16; i++) + { + BTIF_TRACE_DEBUG2("pairing_cb.ble.pid_key[%d]=0x%02x",i,pairing_cb.ble.pid_key[i]); + } + break; + + case BTA_LE_KEY_PCSRK: + BTIF_TRACE_DEBUG0("Rcv BTA_LE_KEY_PCSRK"); + pairing_cb.ble.is_pcsrk_key_rcvd = TRUE; + pairing_cb.ble.pcsrk_key.counter = p_data->ble_key.key_value.pcsrk_key.counter; + pairing_cb.ble.pcsrk_key.sec_level = p_data->ble_key.key_value.pcsrk_key.sec_level; + memcpy(pairing_cb.ble.pcsrk_key.csrk,p_data->ble_key.key_value.pcsrk_key.csrk,16); + + for (i=0; i<16; i++) + { + BTIF_TRACE_DEBUG2("pairing_cb.ble.pcsrk_key.csrk[%d]=0x%02x",i,pairing_cb.ble.pcsrk_key.csrk[i]); + } + BTIF_TRACE_DEBUG1("pairing_cb.ble.pcsrk_key.counter=0x%08x",pairing_cb.ble.pcsrk_key.counter); + BTIF_TRACE_DEBUG1("pairing_cb.ble.pcsrk_key.sec_level=0x%02x",pairing_cb.ble.pcsrk_key.sec_level); + break; + + case BTA_LE_KEY_LENC: + BTIF_TRACE_DEBUG0("Rcv BTA_LE_KEY_LENC"); + pairing_cb.ble.is_lenc_key_rcvd = TRUE; + pairing_cb.ble.lenc_key.div = p_data->ble_key.key_value.lenc_key.div; + pairing_cb.ble.lenc_key.key_size = p_data->ble_key.key_value.lenc_key.key_size; + pairing_cb.ble.lenc_key.sec_level = p_data->ble_key.key_value.lenc_key.sec_level; + + BTIF_TRACE_DEBUG1("pairing_cb.ble.lenc_key.div=0x%04x",pairing_cb.ble.lenc_key.div); + BTIF_TRACE_DEBUG1("pairing_cb.ble.lenc_key.key_size=0x%02x",pairing_cb.ble.lenc_key.key_size); + BTIF_TRACE_DEBUG1("pairing_cb.ble.lenc_key.sec_level=0x%02x",pairing_cb.ble.lenc_key.sec_level); + break; + + + + case BTA_LE_KEY_LCSRK: + BTIF_TRACE_DEBUG0("Rcv BTA_LE_KEY_LCSRK"); + pairing_cb.ble.is_lcsrk_key_rcvd = TRUE; + pairing_cb.ble.lcsrk_key.counter = p_data->ble_key.key_value.lcsrk_key.counter; + pairing_cb.ble.lcsrk_key.div = p_data->ble_key.key_value.lcsrk_key.div; + pairing_cb.ble.lcsrk_key.sec_level = p_data->ble_key.key_value.lcsrk_key.sec_level; + + BTIF_TRACE_DEBUG1("pairing_cb.ble.lcsrk_key.div=0x%04x",pairing_cb.ble.lcsrk_key.div); + BTIF_TRACE_DEBUG1("pairing_cb.ble.lcsrk_key.counter=0x%08x",pairing_cb.ble.lcsrk_key.counter); + BTIF_TRACE_DEBUG1("pairing_cb.ble.lcsrk_key.sec_level=0x%02x",pairing_cb.ble.lcsrk_key.sec_level); + + break; + + default: + BTIF_TRACE_ERROR1("unknown BLE key type (0x%02x)", p_data->ble_key.key_type); + break; + } + + break; case BTA_DM_BLE_SEC_REQ_EVT: + BTIF_TRACE_DEBUG0("BTA_DM_BLE_SEC_REQ_EVT. "); + btif_dm_ble_sec_req_evt(&p_data->ble_req); + break; case BTA_DM_BLE_PASSKEY_NOTIF_EVT: + BTIF_TRACE_DEBUG0("BTA_DM_BLE_PASSKEY_NOTIF_EVT. "); + btif_dm_ble_key_notif_evt(&p_data->key_notif); + break; case BTA_DM_BLE_PASSKEY_REQ_EVT: + BTIF_TRACE_DEBUG0("BTA_DM_BLE_PASSKEY_REQ_EVT. "); + btif_dm_ble_passkey_req_evt(&p_data->pin_req); + break; case BTA_DM_BLE_OOB_REQ_EVT: + BTIF_TRACE_DEBUG0("BTA_DM_BLE_OOB_REQ_EVT. "); + break; case BTA_DM_BLE_LOCAL_IR_EVT: + BTIF_TRACE_DEBUG0("BTA_DM_BLE_LOCAL_IR_EVT. "); + ble_local_key_cb.is_id_keys_rcvd = TRUE; + memcpy(&ble_local_key_cb.id_keys.irk[0], &p_data->ble_id_keys.irk[0], sizeof(BT_OCTET16)); + memcpy(&ble_local_key_cb.id_keys.ir[0], &p_data->ble_id_keys.ir[0], sizeof(BT_OCTET16)); + memcpy(&ble_local_key_cb.id_keys.dhk[0], &p_data->ble_id_keys.dhk[0], sizeof(BT_OCTET16)); + btif_storage_add_ble_local_key( (char *)&ble_local_key_cb.id_keys.irk[0], + BTIF_DM_LE_LOCAL_KEY_IR, + BT_OCTET16_LEN); + btif_storage_add_ble_local_key( (char *)&ble_local_key_cb.id_keys.ir[0], + BTIF_DM_LE_LOCAL_KEY_IRK, + BT_OCTET16_LEN); + btif_storage_add_ble_local_key( (char *)&ble_local_key_cb.id_keys.dhk[0], + BTIF_DM_LE_LOCAL_KEY_DHK, + BT_OCTET16_LEN); + break; case BTA_DM_BLE_LOCAL_ER_EVT: + BTIF_TRACE_DEBUG0("BTA_DM_BLE_LOCAL_ER_EVT. "); + ble_local_key_cb.is_er_rcvd = TRUE; + memcpy(&ble_local_key_cb.er[0], &p_data->ble_er[0], sizeof(BT_OCTET16)); + btif_storage_add_ble_local_key( (char *)&ble_local_key_cb.er[0], + BTIF_DM_LE_LOCAL_KEY_ER, + BT_OCTET16_LEN); + break; + case BTA_DM_BLE_AUTH_CMPL_EVT: + BTIF_TRACE_DEBUG0("BTA_DM_BLE_KEY_EVT. "); + btif_dm_ble_auth_cmpl_evt(&p_data->auth_cmpl); + break; +#endif + + case BTA_DM_AUTHORIZE_EVT: + case BTA_DM_SIG_STRENGTH_EVT: + case BTA_DM_SP_RMT_OOB_EVT: + case BTA_DM_SP_KEYPRESS_EVT: + case BTA_DM_ROLE_CHG_EVT: + default: BTIF_TRACE_WARNING1( "btif_dm_cback : unhandled event (%d)", event ); break; @@ -1328,6 +1553,26 @@ static void btif_dm_generic_evt(UINT16 event, char* p_param) bond_state_changed(BT_STATUS_SUCCESS, (bt_bdaddr_t *)p_param, BT_BOND_STATE_BONDING); } break; + case BTIF_DM_CB_LE_TX_TEST: + case BTIF_DM_CB_LE_RX_TEST: + { + uint8_t status; + STREAM_TO_UINT8(status, p_param); + HAL_CBACK(bt_hal_cbacks, le_test_mode_cb, + (status == 0) ? BT_STATUS_SUCCESS : BT_STATUS_FAIL, 0); + } + break; + case BTIF_DM_CB_LE_TEST_END: + { + uint8_t status; + uint16_t count = 0; + STREAM_TO_UINT8(status, p_param); + if (status == 0) + STREAM_TO_UINT16(count, p_param); + HAL_CBACK(bt_hal_cbacks, le_test_mode_cb, + (status == 0) ? BT_STATUS_SUCCESS : BT_STATUS_FAIL, count); + } + break; default: { BTIF_TRACE_WARNING2("%s : Unknown event 0x%x", __FUNCTION__, event); @@ -1469,7 +1714,7 @@ bt_status_t btif_dm_start_discovery(void) /* TODO: Do we need to handle multiple inquiries at the same time? */ /* Set inquiry params and call API */ -#if (BLE_INCLUDED == TRUE) +#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) inq_params.mode = BTA_DM_GENERAL_INQUIRY|BTA_BLE_GENERAL_INQUIRY; #else inq_params.mode = BTA_DM_GENERAL_INQUIRY; @@ -1551,6 +1796,33 @@ bt_status_t btif_dm_cancel_bond(const bt_bdaddr_t *bd_addr) */ if (pairing_cb.state == BT_BOND_STATE_BONDING) { + +#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) + + if (pairing_cb.is_ssp) + { + if (pairing_cb.is_le_only) + { + BTA_DmBleSecurityGrant((UINT8 *)bd_addr->address,BTA_DM_SEC_PAIR_NOT_SPT); + } + else + BTA_DmConfirm( (UINT8 *)bd_addr->address, FALSE); + } + else + { + if (pairing_cb.is_le_only) + { + BTA_DmBondCancel ((UINT8 *)bd_addr->address); + } + else + { + BTA_DmPinReply( (UINT8 *)bd_addr->address, FALSE, 0, NULL); + } + /* Cancel bonding, in case it is in ACL connection setup state */ + BTA_DmBondCancel ((UINT8 *)bd_addr->address); + } + +#else if (pairing_cb.is_ssp) { BTA_DmConfirm( (UINT8 *)bd_addr->address, FALSE); @@ -1562,6 +1834,7 @@ bt_status_t btif_dm_cancel_bond(const bt_bdaddr_t *bd_addr) /* Cancel bonding, in case it is in ACL connection setup state */ BTA_DmBondCancel ((UINT8 *)bd_addr->address); btif_storage_remove_bonded_device((bt_bdaddr_t *)bd_addr); +#endif } return BT_STATUS_SUCCESS; @@ -1602,12 +1875,35 @@ bt_status_t btif_dm_pin_reply( const bt_bdaddr_t *bd_addr, uint8_t accept, uint8_t pin_len, bt_pin_code_t *pin_code) { BTIF_TRACE_EVENT2("%s: accept=%d", __FUNCTION__, accept); +#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) + + if (pairing_cb.is_le_only) + { + int i; + UINT32 passkey = 0; + int multi[] = {100000, 10000, 1000, 100, 10,1}; + BD_ADDR remote_bd_addr; + bdcpy(remote_bd_addr, bd_addr->address); + for (i = 0; i < 6; i++) + { + passkey += (multi[i] * (pin_code->pin[i] - '0')); + } + BTIF_TRACE_DEBUG1("btif_dm_pin_reply: passkey: %d", passkey); + BTA_DmBlePasskeyReply(remote_bd_addr, accept, passkey); + } + else + { + BTA_DmPinReply( (UINT8 *)bd_addr->address, accept, pin_len, pin_code->pin); + if (accept) + pairing_cb.pin_code_len = pin_len; + } +#else BTA_DmPinReply( (UINT8 *)bd_addr->address, accept, pin_len, pin_code->pin); if (accept) pairing_cb.pin_code_len = pin_len; - +#endif return BT_STATUS_SUCCESS; } @@ -1635,8 +1931,20 @@ bt_status_t btif_dm_ssp_reply(const bt_bdaddr_t *bd_addr, } /* BT_SSP_VARIANT_CONSENT & BT_SSP_VARIANT_PASSKEY_CONFIRMATION supported */ BTIF_TRACE_EVENT2("%s: accept=%d", __FUNCTION__, accept); - BTA_DmConfirm( (UINT8 *)bd_addr->address, accept); +#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) + if (pairing_cb.is_le_only) + { + if (accept) + BTA_DmBleSecurityGrant((UINT8 *)bd_addr->address,BTA_DM_SEC_GRANTED); + else + BTA_DmBleSecurityGrant((UINT8 *)bd_addr->address,BTA_DM_SEC_PAIR_NOT_SPT); + } + else + BTA_DmConfirm( (UINT8 *)bd_addr->address, accept); +#else + BTA_DmConfirm( (UINT8 *)bd_addr->address, accept); +#endif return BT_STATUS_SUCCESS; } @@ -1888,6 +2196,314 @@ BOOLEAN btif_dm_proc_rmt_oob(BD_ADDR bd_addr, BT_OCTET16 p_c, BT_OCTET16 p_r) return result; } #endif /* BTIF_DM_OOB_TEST */ +#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) + +static void btif_dm_ble_key_notif_evt(tBTA_DM_SP_KEY_NOTIF *p_ssp_key_notif) +{ + bt_bdaddr_t bd_addr; + bt_bdname_t bd_name; + UINT32 cod; + + BTIF_TRACE_DEBUG1("%s", __FUNCTION__); + + /* Remote name update */ + btif_update_remote_properties(p_ssp_key_notif->bd_addr , p_ssp_key_notif->bd_name, + NULL, BT_DEVICE_TYPE_BLE); + bdcpy(bd_addr.address, p_ssp_key_notif->bd_addr); + memcpy(bd_name.name, p_ssp_key_notif->bd_name, BD_NAME_LEN); + + bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING); + pairing_cb.is_ssp = FALSE; + cod = COD_UNCLASSIFIED; + + HAL_CBACK(bt_hal_cbacks, ssp_request_cb, &bd_addr, &bd_name, + cod, BT_SSP_VARIANT_PASSKEY_NOTIFICATION, + p_ssp_key_notif->passkey); +} + +/******************************************************************************* +** +** Function btif_dm_ble_auth_cmpl_evt +** +** Description Executes authentication complete event in btif context +** +** Returns void +** +*******************************************************************************/ +static void btif_dm_ble_auth_cmpl_evt (tBTA_DM_AUTH_CMPL *p_auth_cmpl) +{ + /* Save link key, if not temporary */ + bt_bdaddr_t bd_addr; + bt_status_t status = BT_STATUS_FAIL; + bt_bond_state_t state = BT_BOND_STATE_NONE; + + bdcpy(bd_addr.address, p_auth_cmpl->bd_addr); + if ( (p_auth_cmpl->success == TRUE) && (p_auth_cmpl->key_present) ) + { + /* store keys */ + } + if (p_auth_cmpl->success) + { + status = BT_STATUS_SUCCESS; + state = BT_BOND_STATE_BONDED; + + btif_dm_save_ble_bonding_keys(); + BTA_GATTC_Refresh(bd_addr.address); + btif_dm_get_remote_services(&bd_addr); + } + else + { + /*Map the HCI fail reason to bt status */ + switch (p_auth_cmpl->fail_reason) + { + + btif_dm_remove_ble_bonding_keys(); + default: + status = BT_STATUS_FAIL; + break; + } + } + bond_state_changed(status, &bd_addr, state); +} + + + +void btif_dm_load_ble_local_keys(void) +{ + bt_status_t bt_status; + + memset(&ble_local_key_cb, 0, sizeof(btif_dm_local_key_cb_t)); + + if (btif_storage_get_ble_local_key(BTIF_DM_LE_LOCAL_KEY_ER,(char*)&ble_local_key_cb.er[0], + BT_OCTET16_LEN)== BT_STATUS_SUCCESS) + { + ble_local_key_cb.is_er_rcvd = TRUE; + BTIF_TRACE_DEBUG1("%s BLE ER key loaded",__FUNCTION__ ); + } + + if ((btif_storage_get_ble_local_key(BTIF_DM_LE_LOCAL_KEY_IR,(char*)&ble_local_key_cb.id_keys.ir[0], + BT_OCTET16_LEN)== BT_STATUS_SUCCESS )&& + (btif_storage_get_ble_local_key(BTIF_DM_LE_LOCAL_KEY_IRK, (char*)&ble_local_key_cb.id_keys.irk[0], + BT_OCTET16_LEN)== BT_STATUS_SUCCESS)&& + (btif_storage_get_ble_local_key(BTIF_DM_LE_LOCAL_KEY_DHK,(char*)&ble_local_key_cb.id_keys.dhk[0], + BT_OCTET16_LEN)== BT_STATUS_SUCCESS)) + { + ble_local_key_cb.is_id_keys_rcvd = TRUE; + BTIF_TRACE_DEBUG1("%s BLE ID keys loaded",__FUNCTION__ ); + } + +} +void btif_dm_get_ble_local_keys(tBTA_DM_BLE_LOCAL_KEY_MASK *p_key_mask, BT_OCTET16 er, + tBTA_BLE_LOCAL_ID_KEYS *p_id_keys) +{ + if (ble_local_key_cb.is_er_rcvd ) + { + memcpy(&er[0], &ble_local_key_cb.er[0], sizeof(BT_OCTET16)); + *p_key_mask |= BTA_BLE_LOCAL_KEY_TYPE_ER; + } + + if (ble_local_key_cb.is_id_keys_rcvd) + { + memcpy(&p_id_keys->ir[0], &ble_local_key_cb.id_keys.ir[0], sizeof(BT_OCTET16)); + memcpy(&p_id_keys->irk[0], &ble_local_key_cb.id_keys.irk[0], sizeof(BT_OCTET16)); + memcpy(&p_id_keys->dhk[0], &ble_local_key_cb.id_keys.dhk[0], sizeof(BT_OCTET16)); + *p_key_mask |= BTA_BLE_LOCAL_KEY_TYPE_ID; + } + BTIF_TRACE_DEBUG2("%s *p_key_mask=0x%02x",__FUNCTION__, *p_key_mask); +} + +void btif_dm_save_ble_bonding_keys(void) +{ + + bt_bdaddr_t bd_addr; + + BTIF_TRACE_DEBUG1("%s",__FUNCTION__ ); + + bdcpy(bd_addr.address, pairing_cb.bd_addr); + + if (pairing_cb.ble.is_penc_key_rcvd) + { + btif_storage_add_ble_bonding_key(&bd_addr, + (char *) &pairing_cb.ble.penc_key, + BTIF_DM_LE_KEY_PENC, + sizeof(btif_dm_ble_penc_keys_t)); + } + + if (pairing_cb.ble.is_pid_key_rcvd) + { + btif_storage_add_ble_bonding_key(&bd_addr, + (char *) &pairing_cb.ble.pid_key[0], + BTIF_DM_LE_KEY_PID, + BT_OCTET16_LEN); + } + + + if (pairing_cb.ble.is_pcsrk_key_rcvd) + { + btif_storage_add_ble_bonding_key(&bd_addr, + (char *) &pairing_cb.ble.pcsrk_key, + BTIF_DM_LE_KEY_PCSRK, + sizeof(btif_dm_ble_pcsrk_keys_t)); + } + + + if (pairing_cb.ble.is_lenc_key_rcvd) + { + btif_storage_add_ble_bonding_key(&bd_addr, + (char *) &pairing_cb.ble.lenc_key, + BTIF_DM_LE_KEY_LENC, + sizeof(btif_dm_ble_lenc_keys_t)); + } + + if (pairing_cb.ble.is_lcsrk_key_rcvd) + { + btif_storage_add_ble_bonding_key(&bd_addr, + (char *) &pairing_cb.ble.lcsrk_key, + BTIF_DM_LE_KEY_LCSRK, + sizeof(btif_dm_ble_lcsrk_keys_t)); + } + +} + + +void btif_dm_remove_ble_bonding_keys(void) +{ + bt_bdaddr_t bd_addr; + + BTIF_TRACE_DEBUG1("%s",__FUNCTION__ ); + + bdcpy(bd_addr.address, pairing_cb.bd_addr); + btif_storage_remove_ble_bonding_keys(&bd_addr); +} + + +/******************************************************************************* +** +** Function btif_dm_ble_sec_req_evt +** +** Description Eprocess security request event in btif context +** +** Returns void +** +*******************************************************************************/ +void btif_dm_ble_sec_req_evt(tBTA_DM_BLE_SEC_REQ *p_ble_req) +{ + bt_bdaddr_t bd_addr; + bt_bdname_t bd_name; + UINT32 cod; + BTIF_TRACE_DEBUG1("%s", __FUNCTION__); + + if (pairing_cb.state == BT_BOND_STATE_BONDING) + { + BTIF_TRACE_DEBUG1("%s Discard security request", __FUNCTION__); + return; + } + + /* Remote name update */ + btif_update_remote_properties(p_ble_req->bd_addr,p_ble_req->bd_name,NULL,BT_DEVICE_TYPE_BLE); + + bdcpy(bd_addr.address, p_ble_req->bd_addr); + memcpy(bd_name.name, p_ble_req->bd_name, BD_NAME_LEN); + + bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING); + + pairing_cb.is_temp = FALSE; + pairing_cb.is_le_only = TRUE; + pairing_cb.is_ssp = TRUE; + + cod = COD_UNCLASSIFIED; + + HAL_CBACK(bt_hal_cbacks, ssp_request_cb, &bd_addr, &bd_name, cod, + BT_SSP_VARIANT_CONSENT, 0); +} + + + +/******************************************************************************* +** +** Function btif_dm_ble_passkey_req_evt +** +** Description Executes pin request event in btif context +** +** Returns void +** +*******************************************************************************/ +static void btif_dm_ble_passkey_req_evt(tBTA_DM_PIN_REQ *p_pin_req) +{ + bt_bdaddr_t bd_addr; + bt_bdname_t bd_name; + UINT32 cod; + + /* Remote name update */ + btif_update_remote_properties(p_pin_req->bd_addr,p_pin_req->bd_name,NULL,BT_DEVICE_TYPE_BLE); + + bdcpy(bd_addr.address, p_pin_req->bd_addr); + memcpy(bd_name.name, p_pin_req->bd_name, BD_NAME_LEN); + + bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING); + pairing_cb.is_le_only = TRUE; + + cod = COD_UNCLASSIFIED; + + HAL_CBACK(bt_hal_cbacks, pin_request_cb, + &bd_addr, &bd_name, cod); +} + + +void btif_dm_update_ble_remote_properties( BD_ADDR bd_addr, BD_NAME bd_name, + tBT_DEVICE_TYPE dev_type) +{ + btif_update_remote_properties(bd_addr,bd_name,NULL,dev_type); +} + +static void btif_dm_ble_tx_test_cback(void *p) +{ + btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_LE_TX_TEST, + (char *)p, 1, NULL); +} + +static void btif_dm_ble_rx_test_cback(void *p) +{ + btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_LE_RX_TEST, + (char *)p, 1, NULL); +} + +static void btif_dm_ble_test_end_cback(void *p) +{ + btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_LE_TEST_END, + (char *)p, 3, NULL); +} +/******************************************************************************* +** +** Function btif_le_test_mode +** +** Description Sends a HCI BLE Test command to the Controller +** +** Returns BT_STATUS_SUCCESS on success +** +*******************************************************************************/ +bt_status_t btif_le_test_mode(uint16_t opcode, uint8_t *buf, uint8_t len) +{ + switch (opcode) { + case HCI_BLE_TRANSMITTER_TEST: + if (len != 3) return BT_STATUS_PARM_INVALID; + BTM_BleTransmitterTest(buf[0],buf[1],buf[2], btif_dm_ble_tx_test_cback); + break; + case HCI_BLE_RECEIVER_TEST: + if (len != 1) return BT_STATUS_PARM_INVALID; + BTM_BleReceiverTest(buf[0], btif_dm_ble_rx_test_cback); + break; + case HCI_BLE_TEST_END: + BTM_BleTestEnd((tBTM_CMPL_CB*) btif_dm_ble_test_end_cback); + break; + default: + BTIF_TRACE_ERROR2("%s: Unknown LE Test Mode Command 0x%x", __FUNCTION__, opcode); + return BT_STATUS_UNSUPPORTED; + } + return BT_STATUS_SUCCESS; +} + +#endif void btif_dm_on_disable() { diff --git a/btif/src/btif_gatt.c b/btif/src/btif_gatt.c new file mode 100644 index 000000000..bc01c2ec5 --- /dev/null +++ b/btif/src/btif_gatt.c @@ -0,0 +1,113 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2013 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + + +/******************************************************************************* + * + * Filename: btif_gatt.c + * + * Description: GATT Profile Bluetooth Interface + * + *******************************************************************************/ + +#include <hardware/bluetooth.h> +#include <hardware/bt_gatt.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> + +#define LOG_TAG "BtGatt.btif" + +#include "btif_common.h" +#include "btif_util.h" + +#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) + +#include "bta_api.h" +#include "bta_gatt_api.h" +#include "bd.h" +#include "btif_storage.h" + +#include "btif_gatt.h" +#include "btif_gatt_util.h" + +const btgatt_callbacks_t *bt_gatt_callbacks = NULL; + +extern btgatt_client_interface_t btgattClientInterface; +extern btgatt_server_interface_t btgattServerInterface; + +/******************************************************************************* +** +** Function btif_gatt_init +** +** Description Initializes the GATT interface +** +** Returns s bt_status_t +** +*******************************************************************************/ +static bt_status_t btif_gatt_init( const btgatt_callbacks_t* callbacks ) +{ + bt_gatt_callbacks = callbacks; + + BTA_GATTC_Init(); + BTA_GATTS_Init(); + + return BT_STATUS_SUCCESS; +} + +/******************************************************************************* +** +** Function btif_gatt_cleanup +** +** Description Closes the GATT interface +** +** Returns void +** +*******************************************************************************/ +static void btif_gatt_cleanup( void ) +{ + if (bt_gatt_callbacks) + bt_gatt_callbacks = NULL; +} + +static const btgatt_interface_t btgattInterface = { + sizeof(btgattInterface), + + btif_gatt_init, + btif_gatt_cleanup, + + &btgattClientInterface, + &btgattServerInterface, +}; + +/******************************************************************************* +** +** Function btif_gatt_get_interface +** +** Description Get the gatt callback interface +** +** Returns btgatt_interface_t +** +*******************************************************************************/ +const btgatt_interface_t *btif_gatt_get_interface() +{ + return &btgattInterface; +} + +#endif diff --git a/btif/src/btif_gatt_client.c b/btif/src/btif_gatt_client.c new file mode 100644 index 000000000..ac3df5278 --- /dev/null +++ b/btif/src/btif_gatt_client.c @@ -0,0 +1,998 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2013 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + + +/******************************************************************************* + * + * Filename: btif_gatt_client.c + * + * Description: GATT client implementation + * + *******************************************************************************/ + +#include <hardware/bluetooth.h> +#include <hardware/bt_gatt.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> + +#define LOG_TAG "BtGatt.btif" + +#include "btif_common.h" +#include "btif_util.h" + +#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) + +#include "bta_api.h" +#include "bta_gatt_api.h" +#include "bd.h" +#include "btif_storage.h" +#include "btif_config.h" + +#include "btif_gatt.h" +#include "btif_gatt_util.h" +#include "btif_dm.h" +#include "btif_storage.h" + +/******************************************************************************* +** Constants & Macros +********************************************************************************/ + +#define CHECK_BTGATT_INIT() if (bt_gatt_callbacks == NULL)\ + {\ + ALOGW("%s: BTGATT not initialized", __FUNCTION__);\ + return BT_STATUS_NOT_READY;\ + } else {\ + ALOGD("%s", __FUNCTION__);\ + } + + +typedef enum { + BTIF_GATTC_REGISTER_APP = 1000, + BTIF_GATTC_UNREGISTER_APP, + BTIF_GATTC_SCAN_START, + BTIF_GATTC_SCAN_STOP, + BTIF_GATTC_OPEN, + BTIF_GATTC_CLOSE, + BTIF_GATTC_SEARCH_SERVICE, + BTIF_GATTC_GET_FIRST_CHAR, + BTIF_GATTC_GET_NEXT_CHAR, + BTIF_GATTC_GET_FIRST_CHAR_DESCR, + BTIF_GATTC_GET_NEXT_CHAR_DESCR, + BTIF_GATTC_GET_FIRST_INCL_SERVICE, + BTIF_GATTC_GET_NEXT_INCL_SERVICE, + BTIF_GATTC_READ_CHAR, + BTIF_GATTC_READ_CHAR_DESCR, + BTIF_GATTC_WRITE_CHAR, + BTIF_GATTC_WRITE_CHAR_DESCR, + BTIF_GATTC_EXECUTE_WRITE, + BTIF_GATTC_REG_FOR_NOTIFICATION, + BTIF_GATTC_DEREG_FOR_NOTIFICATION, + BTIF_GATTC_REFRESH, + BTIF_GATTC_READ_RSSI +} btif_gattc_event_t; + +#define BTIF_GATT_MAX_OBSERVED_DEV 40 + +#define BTIF_GATT_OBSERVE_EVT 0x1000 +#define BTIF_GATTC_RSSI_EVT 0x1001 + +/******************************************************************************* +** Local type definitions +********************************************************************************/ + +typedef struct +{ + uint8_t value[BTGATT_MAX_ATTR_LEN]; + bt_bdaddr_t bd_addr; + btgatt_srvc_id_t srvc_id; + btgatt_srvc_id_t incl_srvc_id; + btgatt_char_id_t char_id; + bt_uuid_t uuid; + uint16_t conn_id; + uint16_t len; + uint8_t client_if; + uint8_t action; + uint8_t is_direct; + uint8_t search_all; + uint8_t auth_req; + uint8_t write_type; + uint8_t status; + uint8_t addr_type; + int8_t rssi; + tBT_DEVICE_TYPE device_type; +} __attribute__((packed)) btif_gattc_cb_t; + +typedef struct +{ + bt_bdaddr_t bd_addr; + BOOLEAN in_use; +}__attribute__((packed)) btif_gattc_dev_t; + +typedef struct +{ + btif_gattc_dev_t remote_dev[BTIF_GATT_MAX_OBSERVED_DEV]; + uint8_t addr_type; + uint8_t next_storage_idx; +}__attribute__((packed)) btif_gattc_dev_cb_t; + +/******************************************************************************* +** Static variables +********************************************************************************/ + +extern const btgatt_callbacks_t *bt_gatt_callbacks; +static btif_gattc_dev_cb_t btif_gattc_dev_cb; +static btif_gattc_dev_cb_t *p_dev_cb = &btif_gattc_dev_cb; +static uint8_t rssi_request_client_if; + +/******************************************************************************* +** Static functions +********************************************************************************/ + +static void btif_gattc_init_dev_cb(void) +{ + memset(p_dev_cb, 0, sizeof(btif_gattc_dev_cb_t)); +} + +static void btif_gattc_add_remote_bdaddr (BD_ADDR p_bda, uint8_t addr_type) +{ + BOOLEAN found=FALSE; + uint8_t i; + for (i = 0; i < BTIF_GATT_MAX_OBSERVED_DEV; i++) + { + if (!p_dev_cb->remote_dev[i].in_use ) + { + memcpy(p_dev_cb->remote_dev[i].bd_addr.address, p_bda, BD_ADDR_LEN); + p_dev_cb->addr_type = addr_type; + p_dev_cb->remote_dev[i].in_use = TRUE; + ALOGD("%s device added idx=%d", __FUNCTION__, i ); + break; + } + } + + if ( i == BTIF_GATT_MAX_OBSERVED_DEV) + { + i= p_dev_cb->next_storage_idx; + memcpy(p_dev_cb->remote_dev[i].bd_addr.address, p_bda, BD_ADDR_LEN); + p_dev_cb->addr_type = addr_type; + p_dev_cb->remote_dev[i].in_use = TRUE; + ALOGD("%s device overwrite idx=%d", __FUNCTION__, i ); + p_dev_cb->next_storage_idx++; + if(p_dev_cb->next_storage_idx >= BTIF_GATT_MAX_OBSERVED_DEV) + p_dev_cb->next_storage_idx = 0; + } +} + +static BOOLEAN btif_gattc_find_bdaddr (BD_ADDR p_bda) +{ + uint8_t i; + for (i = 0; i < BTIF_GATT_MAX_OBSERVED_DEV; i++) + { + if (p_dev_cb->remote_dev[i].in_use && + !memcmp(p_dev_cb->remote_dev[i].bd_addr.address, p_bda, BD_ADDR_LEN)) + { + return TRUE; + } + } + return FALSE; +} + +static void btif_gattc_update_properties ( btif_gattc_cb_t *p_btif_cb ) +{ + uint8_t remote_name_len; + uint8_t *p_eir_remote_name=NULL; + bt_bdname_t bdname; + + p_eir_remote_name = BTA_CheckEirData(p_btif_cb->value, + BTM_EIR_COMPLETE_LOCAL_NAME_TYPE, &remote_name_len); + + if(p_eir_remote_name == NULL) + { + p_eir_remote_name = BTA_CheckEirData(p_btif_cb->value, + BT_EIR_SHORTENED_LOCAL_NAME_TYPE, &remote_name_len); + } + + if(p_eir_remote_name) + { + memcpy(bdname.name, p_eir_remote_name, remote_name_len); + bdname.name[remote_name_len]='\0'; + + ALOGD("%s BLE device name=%s len=%d dev_type=%d", __FUNCTION__, bdname.name, + remote_name_len, p_btif_cb->device_type ); + btif_dm_update_ble_remote_properties( p_btif_cb->bd_addr.address, bdname.name, + p_btif_cb->device_type); + } + + btif_storage_set_remote_addr_type( &p_btif_cb->bd_addr, p_btif_cb->addr_type); +} + +static void btif_gattc_upstreams_evt(uint16_t event, char* p_param) +{ + ALOGD("%s: Event %d", __FUNCTION__, event); + + tBTA_GATTC *p_data = (tBTA_GATTC*)p_param; + switch (event) + { + case BTA_GATTC_REG_EVT: + { + bt_uuid_t app_uuid; + bta_to_btif_uuid(&app_uuid, &p_data->reg_oper.app_uuid); + HAL_CBACK(bt_gatt_callbacks, client->register_client_cb + , p_data->reg_oper.status + , p_data->reg_oper.client_if + , &app_uuid + ); + break; + } + + case BTA_GATTC_DEREG_EVT: + break; + + case BTA_GATTC_READ_CHAR_EVT: + { + btgatt_read_params_t data; + set_read_value(&data, &p_data->read); + + HAL_CBACK(bt_gatt_callbacks, client->read_characteristic_cb + , p_data->read.conn_id, p_data->read.status, &data); + break; + } + + case BTA_GATTC_WRITE_CHAR_EVT: + case BTA_GATTC_PREP_WRITE_EVT: + { + btgatt_write_params_t data; + bta_to_btif_srvc_id(&data.srvc_id, &p_data->write.srvc_id); + bta_to_btif_char_id(&data.char_id, &p_data->write.char_id); + + HAL_CBACK(bt_gatt_callbacks, client->write_characteristic_cb + , p_data->write.conn_id, p_data->write.status, &data + ); + break; + } + + case BTA_GATTC_EXEC_EVT: + { + HAL_CBACK(bt_gatt_callbacks, client->execute_write_cb + , p_data->exec_cmpl.conn_id, p_data->exec_cmpl.status + ); + break; + } + + case BTA_GATTC_SEARCH_CMPL_EVT: + { + HAL_CBACK(bt_gatt_callbacks, client->search_complete_cb + , p_data->search_cmpl.conn_id, p_data->search_cmpl.status); + break; + } + + case BTA_GATTC_SEARCH_RES_EVT: + { + btgatt_srvc_id_t data; + bta_to_btif_srvc_id(&data, &(p_data->srvc_res.service_uuid)); + HAL_CBACK(bt_gatt_callbacks, client->search_result_cb + , p_data->srvc_res.conn_id, &data); + break; + } + + case BTA_GATTC_READ_DESCR_EVT: + { + btgatt_read_params_t data; + set_read_value(&data, &p_data->read); + + HAL_CBACK(bt_gatt_callbacks, client->read_descriptor_cb + , p_data->read.conn_id, p_data->read.status, &data); + break; + } + + case BTA_GATTC_WRITE_DESCR_EVT: + { + btgatt_write_params_t data; + bta_to_btif_srvc_id(&data.srvc_id, &p_data->write.srvc_id); + bta_to_btif_char_id(&data.char_id, &p_data->write.char_id); + bta_to_btif_uuid(&data.descr_id, &p_data->write.descr_type); + + HAL_CBACK(bt_gatt_callbacks, client->write_descriptor_cb + , p_data->write.conn_id, p_data->write.status, &data); + break; + } + + case BTA_GATTC_NOTIF_EVT: + { + btgatt_notify_params_t data; + + bdcpy(data.bda.address, p_data->notify.bda); + + bta_to_btif_srvc_id(&data.srvc_id, &p_data->notify.char_id.srvc_id); + bta_to_btif_char_id(&data.char_id, &p_data->notify.char_id.char_id); + memcpy(data.value, p_data->notify.value, p_data->notify.len); + + data.is_notify = p_data->notify.is_notify; + data.len = p_data->notify.len; + + HAL_CBACK(bt_gatt_callbacks, client->notify_cb + , p_data->notify.conn_id, &data); + + if (p_data->notify.is_notify == FALSE) + { + BTA_GATTC_SendIndConfirm(p_data->notify.conn_id, + &p_data->notify.char_id); + } + break; + } + + case BTA_GATTC_OPEN_EVT: + { + bt_bdaddr_t bda; + bdcpy(bda.address, p_data->open.remote_bda); + + if (p_data->open.status == BTA_GATT_OK) + btif_gatt_check_encrypted_link(p_data->open.remote_bda); + + HAL_CBACK(bt_gatt_callbacks, client->open_cb, p_data->open.conn_id + , p_data->open.status, p_data->open.client_if, &bda); + break; + } + + case BTA_GATTC_CLOSE_EVT: + { + bt_bdaddr_t bda; + bdcpy(bda.address, p_data->close.remote_bda); + HAL_CBACK(bt_gatt_callbacks, client->close_cb, p_data->close.conn_id + , p_data->status, p_data->close.client_if, &bda); + + if(p_data->status == BTA_GATT_OK) + btif_gatt_remove_encrypted_link(p_data->close.remote_bda); + break; + } + + case BTA_GATTC_ACL_EVT: + ALOGD("BTA_GATTC_ACL_EVT: status = %d", p_data->status); + /* Ignore for now */ + break; + + case BTA_GATTC_CANCEL_OPEN_EVT: + break; + + case BTIF_GATT_OBSERVE_EVT: + { + btif_gattc_cb_t *p_btif_cb = (btif_gattc_cb_t*)p_param; + if (!btif_gattc_find_bdaddr(p_btif_cb->bd_addr.address)) + { + btif_gattc_add_remote_bdaddr(p_btif_cb->bd_addr.address, p_btif_cb->addr_type); + btif_gattc_update_properties(p_btif_cb); + } + HAL_CBACK(bt_gatt_callbacks, client->scan_result_cb, + &p_btif_cb->bd_addr, p_btif_cb->rssi, p_btif_cb->value); + break; + } + + case BTIF_GATTC_RSSI_EVT: + { + btif_gattc_cb_t *p_btif_cb = (btif_gattc_cb_t*)p_param; + HAL_CBACK(bt_gatt_callbacks, client->read_remote_rssi_cb, p_btif_cb->client_if, + &p_btif_cb->bd_addr, p_btif_cb->rssi, p_btif_cb->status); + break; + } + + default: + ALOGE("%s: Unhandled event (%d)!", __FUNCTION__, event); + break; + } +} + +static void bte_gattc_cback(tBTA_GATTC_EVT event, tBTA_GATTC *p_data) +{ + bt_status_t status = btif_transfer_context(btif_gattc_upstreams_evt, + (uint16_t) event, (void*)p_data, sizeof(tBTA_GATTC), NULL); + ASSERTC(status == BT_STATUS_SUCCESS, "Context transfer failed!", status); +} + +static void bte_scan_results_cb (tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data) +{ + btif_gattc_cb_t btif_cb; + uint8_t len; + + switch (event) + { + case BTA_DM_INQ_RES_EVT: + { + bdcpy(btif_cb.bd_addr.address, p_data->inq_res.bd_addr); + btif_cb.device_type = p_data->inq_res.device_type; + btif_cb.rssi = p_data->inq_res.rssi; + btif_cb.addr_type = p_data->inq_res.ble_addr_type; + if (p_data->inq_res.p_eir) + { + memcpy(btif_cb.value, p_data->inq_res.p_eir, 62); + if (BTA_CheckEirData(p_data->inq_res.p_eir, BTM_EIR_COMPLETE_LOCAL_NAME_TYPE, + &len)) + { + p_data->inq_res.remt_name_not_required = TRUE; + } + } + } + break; + + case BTA_DM_INQ_CMPL_EVT: + { + BTIF_TRACE_DEBUG2("%s BLE observe complete. Num Resp %d", + __FUNCTION__,p_data->inq_cmpl.num_resps); + return; + } + + default: + BTIF_TRACE_WARNING2("%s : Unknown event 0x%x", __FUNCTION__, event); + return; + } + btif_transfer_context(btif_gattc_upstreams_evt, BTIF_GATT_OBSERVE_EVT, + (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); +} + +static void btm_read_rssi_cb (tBTM_RSSI_RESULTS *p_result) +{ + btif_gattc_cb_t btif_cb; + + bdcpy(btif_cb.bd_addr.address, p_result->rem_bda); + btif_cb.rssi = p_result->rssi; + btif_cb.status = p_result->status; + btif_cb.client_if = rssi_request_client_if; + btif_transfer_context(btif_gattc_upstreams_evt, BTIF_GATTC_RSSI_EVT, + (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); +} + + +static void btgattc_handle_event(uint16_t event, char* p_param) +{ + tBTA_GATT_STATUS status; + tBT_UUID uuid; + tBTA_GATT_SRVC_ID srvc_id; + tGATT_CHAR_PROP out_char_prop; + tBTA_GATTC_CHAR_ID in_char_id; + tBTA_GATTC_CHAR_ID out_char_id; + tBTA_GATTC_CHAR_DESCR_ID in_char_descr_id; + tBTA_GATTC_CHAR_DESCR_ID out_char_descr_id; + tBTA_GATTC_INCL_SVC_ID in_incl_svc_id; + tBTA_GATTC_INCL_SVC_ID out_incl_svc_id; + tBTA_GATT_UNFMT descr_val; + + btif_gattc_cb_t* p_cb = (btif_gattc_cb_t*)p_param; + if (!p_cb) return; + + ALOGD("%s: Event %d", __FUNCTION__, event); + + switch (event) + { + case BTIF_GATTC_REGISTER_APP: + btif_to_bta_uuid(&uuid, &p_cb->uuid); + BTA_GATTC_AppRegister(&uuid, bte_gattc_cback); + break; + + case BTIF_GATTC_UNREGISTER_APP: + BTA_GATTC_AppDeregister(p_cb->client_if); + break; + + case BTIF_GATTC_SCAN_START: + btif_gattc_init_dev_cb(); + BTA_DmBleObserve(TRUE, 0, bte_scan_results_cb); + break; + + case BTIF_GATTC_SCAN_STOP: + BTA_DmBleObserve(FALSE, 0, 0); + break; + + case BTIF_GATTC_OPEN: + if (!p_cb->is_direct) + BTA_DmBleSetBgConnType(BTM_BLE_CONN_AUTO, NULL); + + BTA_GATTC_Open(p_cb->client_if, p_cb->bd_addr.address, p_cb->is_direct); + break; + + case BTIF_GATTC_CLOSE: + // Disconnect establiched connections + if (p_cb->conn_id != 0) + BTA_GATTC_Close(p_cb->conn_id); + else + BTA_GATTC_CancelOpen(p_cb->client_if, p_cb->bd_addr.address, TRUE); + + // Cancel pending background connections (remove from whitelist) + BTA_GATTC_CancelOpen(p_cb->client_if, p_cb->bd_addr.address, FALSE); + break; + + case BTIF_GATTC_SEARCH_SERVICE: + { + if (p_cb->search_all) + { + BTA_GATTC_ServiceSearchRequest(p_cb->conn_id, NULL); + } else { + btif_to_bta_uuid(&uuid, &p_cb->uuid); + BTA_GATTC_ServiceSearchRequest(p_cb->conn_id, &uuid); + } + break; + } + + case BTIF_GATTC_GET_FIRST_CHAR: + { + btgatt_char_id_t char_id; + btif_to_bta_srvc_id(&srvc_id, &p_cb->srvc_id); + status = BTA_GATTC_GetFirstChar(p_cb->conn_id, &srvc_id, NULL, + &out_char_id, &out_char_prop); + + if (status == 0) + bta_to_btif_char_id(&char_id, &out_char_id.char_id); + + HAL_CBACK(bt_gatt_callbacks, client->get_characteristic_cb, + p_cb->conn_id, status, &p_cb->srvc_id, + &char_id, out_char_prop); + break; + } + + case BTIF_GATTC_GET_NEXT_CHAR: + { + btgatt_char_id_t char_id; + btif_to_bta_srvc_id(&in_char_id.srvc_id, &p_cb->srvc_id); + btif_to_bta_char_id(&in_char_id.char_id, &p_cb->char_id); + + status = BTA_GATTC_GetNextChar(p_cb->conn_id, &in_char_id, NULL, + &out_char_id, &out_char_prop); + + if (status == 0) + bta_to_btif_char_id(&char_id, &out_char_id.char_id); + + HAL_CBACK(bt_gatt_callbacks, client->get_characteristic_cb, + p_cb->conn_id, status, &p_cb->srvc_id, + &char_id, out_char_prop); + break; + } + + case BTIF_GATTC_GET_FIRST_CHAR_DESCR: + { + bt_uuid_t descr_id; + btif_to_bta_srvc_id(&in_char_id.srvc_id, &p_cb->srvc_id); + btif_to_bta_char_id(&in_char_id.char_id, &p_cb->char_id); + + status = BTA_GATTC_GetFirstCharDescr(p_cb->conn_id, &in_char_id, NULL, + &out_char_descr_id); + + if (status == 0) + bta_to_btif_uuid(&descr_id, &out_char_descr_id.descr_type); + + HAL_CBACK(bt_gatt_callbacks, client->get_descriptor_cb, + p_cb->conn_id, status, &p_cb->srvc_id, + &p_cb->char_id, &descr_id); + break; + } + + case BTIF_GATTC_GET_NEXT_CHAR_DESCR: + { + bt_uuid_t descr_id; + btif_to_bta_srvc_id(&in_char_descr_id.char_id.srvc_id, &p_cb->srvc_id); + btif_to_bta_char_id(&in_char_descr_id.char_id.char_id, &p_cb->char_id); + btif_to_bta_uuid(&in_char_descr_id.descr_type, &p_cb->uuid); + + status = BTA_GATTC_GetNextCharDescr(p_cb->conn_id, &in_char_descr_id + , NULL, &out_char_descr_id); + + if (status == 0) + bta_to_btif_uuid(&descr_id, &out_char_descr_id.descr_type); + + HAL_CBACK(bt_gatt_callbacks, client->get_descriptor_cb, + p_cb->conn_id, status, &p_cb->srvc_id, + &p_cb->char_id, &descr_id); + break; + } + + case BTIF_GATTC_GET_FIRST_INCL_SERVICE: + { + btgatt_srvc_id_t incl_srvc_id; + btif_to_bta_srvc_id(&srvc_id, &p_cb->srvc_id); + + status = BTA_GATTC_GetFirstIncludedService(p_cb->conn_id, + &srvc_id, NULL, &out_incl_svc_id); + + bta_to_btif_srvc_id(&incl_srvc_id, &out_incl_svc_id.incl_svc_id); + + HAL_CBACK(bt_gatt_callbacks, client->get_included_service_cb, + p_cb->conn_id, status, &p_cb->srvc_id, + &incl_srvc_id); + break; + } + + case BTIF_GATTC_GET_NEXT_INCL_SERVICE: + { + btgatt_srvc_id_t incl_srvc_id; + btif_to_bta_srvc_id(&in_incl_svc_id.srvc_id, &p_cb->srvc_id); + btif_to_bta_srvc_id(&in_incl_svc_id.incl_svc_id, &p_cb->incl_srvc_id); + + status = BTA_GATTC_GetNextIncludedService(p_cb->conn_id, + &in_incl_svc_id, NULL, &out_incl_svc_id); + + bta_to_btif_srvc_id(&incl_srvc_id, &out_incl_svc_id.incl_svc_id); + + HAL_CBACK(bt_gatt_callbacks, client->get_included_service_cb, + p_cb->conn_id, status, &p_cb->srvc_id, + &incl_srvc_id); + break; + } + + case BTIF_GATTC_READ_CHAR: + btif_to_bta_srvc_id(&in_char_id.srvc_id, &p_cb->srvc_id); + btif_to_bta_char_id(&in_char_id.char_id, &p_cb->char_id); + + BTA_GATTC_ReadCharacteristic(p_cb->conn_id, &in_char_id, p_cb->auth_req); + break; + + case BTIF_GATTC_READ_CHAR_DESCR: + btif_to_bta_srvc_id(&in_char_descr_id.char_id.srvc_id, &p_cb->srvc_id); + btif_to_bta_char_id(&in_char_descr_id.char_id.char_id, &p_cb->char_id); + btif_to_bta_uuid(&in_char_descr_id.descr_type, &p_cb->uuid); + + BTA_GATTC_ReadCharDescr(p_cb->conn_id, &in_char_descr_id, p_cb->auth_req); + break; + + case BTIF_GATTC_WRITE_CHAR: + btif_to_bta_srvc_id(&in_char_id.srvc_id, &p_cb->srvc_id); + btif_to_bta_char_id(&in_char_id.char_id, &p_cb->char_id); + + BTA_GATTC_WriteCharValue(p_cb->conn_id, &in_char_id, + p_cb->write_type, + p_cb->len, + p_cb->value, + p_cb->auth_req); + break; + + case BTIF_GATTC_WRITE_CHAR_DESCR: + btif_to_bta_srvc_id(&in_char_descr_id.char_id.srvc_id, &p_cb->srvc_id); + btif_to_bta_char_id(&in_char_descr_id.char_id.char_id, &p_cb->char_id); + btif_to_bta_uuid(&in_char_descr_id.descr_type, &p_cb->uuid); + + descr_val.len = p_cb->len; + descr_val.p_value = p_cb->value; + + BTA_GATTC_WriteCharDescr(p_cb->conn_id, &in_char_descr_id, + p_cb->write_type, &descr_val, + p_cb->auth_req); + break; + + case BTIF_GATTC_EXECUTE_WRITE: + BTA_GATTC_ExecuteWrite(p_cb->conn_id, p_cb->action); + break; + + case BTIF_GATTC_REG_FOR_NOTIFICATION: + btif_to_bta_srvc_id(&in_char_id.srvc_id, &p_cb->srvc_id); + btif_to_bta_char_id(&in_char_id.char_id, &p_cb->char_id); + + status = BTA_GATTC_RegisterForNotifications(p_cb->client_if, + p_cb->bd_addr.address, &in_char_id); + + HAL_CBACK(bt_gatt_callbacks, client->register_for_notification_cb, + p_cb->conn_id, 1, status, &p_cb->srvc_id, + &p_cb->char_id); + break; + + case BTIF_GATTC_DEREG_FOR_NOTIFICATION: + btif_to_bta_srvc_id(&in_char_id.srvc_id, &p_cb->srvc_id); + btif_to_bta_char_id(&in_char_id.char_id, &p_cb->char_id); + + status = BTA_GATTC_DeregisterForNotifications(p_cb->client_if, + p_cb->bd_addr.address, &in_char_id); + + HAL_CBACK(bt_gatt_callbacks, client->register_for_notification_cb, + p_cb->conn_id, 0, status, &p_cb->srvc_id, + &p_cb->char_id); + break; + + case BTIF_GATTC_REFRESH: + BTA_GATTC_Refresh(p_cb->bd_addr.address); + break; + + case BTIF_GATTC_READ_RSSI: + rssi_request_client_if = p_cb->client_if; + BTM_ReadRSSI (p_cb->bd_addr.address, (tBTM_CMPL_CB *)btm_read_rssi_cb); + break; + + default: + ALOGE("%s: Unknown event (%d)!", __FUNCTION__, event); + break; + } +} + +/******************************************************************************* +** Client API Functions +********************************************************************************/ + +static bt_status_t btif_gattc_register_app(bt_uuid_t *uuid) +{ + CHECK_BTGATT_INIT(); + btif_gattc_cb_t btif_cb; + memcpy(&btif_cb.uuid, uuid, sizeof(bt_uuid_t)); + return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_REGISTER_APP, + (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); +} + +static bt_status_t btif_gattc_unregister_app(int client_if ) +{ + CHECK_BTGATT_INIT(); + btif_gattc_cb_t btif_cb; + btif_cb.client_if = (uint8_t) client_if; + return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_UNREGISTER_APP, + (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); +} + +static bt_status_t btif_gattc_scan( int client_if, bool start ) +{ + CHECK_BTGATT_INIT(); + btif_gattc_cb_t btif_cb; + btif_cb.client_if = (uint8_t) client_if; + return btif_transfer_context(btgattc_handle_event, start ? BTIF_GATTC_SCAN_START : BTIF_GATTC_SCAN_STOP, + (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); +} + +static bt_status_t btif_gattc_open(int client_if, const bt_bdaddr_t *bd_addr, bool is_direct ) +{ + CHECK_BTGATT_INIT(); + btif_gattc_cb_t btif_cb; + btif_cb.client_if = (uint8_t) client_if; + btif_cb.is_direct = is_direct ? 1 : 0; + bdcpy(btif_cb.bd_addr.address, bd_addr->address); + return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_OPEN, + (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); +} + +static bt_status_t btif_gattc_close( int client_if, const bt_bdaddr_t *bd_addr, int conn_id) +{ + CHECK_BTGATT_INIT(); + btif_gattc_cb_t btif_cb; + btif_cb.client_if = (uint8_t) client_if; + btif_cb.conn_id = (uint16_t) conn_id; + bdcpy(btif_cb.bd_addr.address, bd_addr->address); + return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_CLOSE, + (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); +} + +static bt_status_t btif_gattc_refresh( int client_if, const bt_bdaddr_t *bd_addr ) +{ + CHECK_BTGATT_INIT(); + btif_gattc_cb_t btif_cb; + btif_cb.client_if = (uint8_t) client_if; + bdcpy(btif_cb.bd_addr.address, bd_addr->address); + return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_REFRESH, + (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); +} + +static bt_status_t btif_gattc_search_service(int conn_id, bt_uuid_t *filter_uuid ) +{ + CHECK_BTGATT_INIT(); + btif_gattc_cb_t btif_cb; + btif_cb.conn_id = (uint16_t) conn_id; + btif_cb.search_all = filter_uuid ? 0 : 1; + if (filter_uuid) + memcpy(&btif_cb.uuid, filter_uuid, sizeof(bt_uuid_t)); + return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_SEARCH_SERVICE, + (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); +} + +static bt_status_t btif_gattc_get_characteristic( int conn_id + , btgatt_srvc_id_t *srvc_id, btgatt_char_id_t *start_char_id) +{ + CHECK_BTGATT_INIT(); + btif_gattc_cb_t btif_cb; + btif_cb.conn_id = (uint16_t) conn_id; + memcpy(&btif_cb.srvc_id, srvc_id, sizeof(btgatt_srvc_id_t)); + if (start_char_id) + { + memcpy(&btif_cb.char_id, start_char_id, sizeof(btgatt_char_id_t)); + return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_GET_NEXT_CHAR, + (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); + } + return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_GET_FIRST_CHAR, + (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); +} + +static bt_status_t btif_gattc_get_descriptor( int conn_id + , btgatt_srvc_id_t *srvc_id, btgatt_char_id_t *char_id + , bt_uuid_t *start_descr_id) +{ + CHECK_BTGATT_INIT(); + btif_gattc_cb_t btif_cb; + btif_cb.conn_id = (uint16_t) conn_id; + memcpy(&btif_cb.srvc_id, srvc_id, sizeof(btgatt_srvc_id_t)); + memcpy(&btif_cb.char_id, char_id, sizeof(btgatt_char_id_t)); + if (start_descr_id) + { + memcpy(&btif_cb.uuid, start_descr_id, sizeof(bt_uuid_t)); + return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_GET_NEXT_CHAR_DESCR, + (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); + } + + return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_GET_FIRST_CHAR_DESCR, + (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); +} + +static bt_status_t btif_gattc_get_included_service(int conn_id, btgatt_srvc_id_t *srvc_id, + btgatt_srvc_id_t *start_incl_srvc_id) +{ + CHECK_BTGATT_INIT(); + btif_gattc_cb_t btif_cb; + btif_cb.conn_id = (uint16_t) conn_id; + memcpy(&btif_cb.srvc_id, srvc_id, sizeof(btgatt_srvc_id_t)); + if (start_incl_srvc_id) + { + memcpy(&btif_cb.incl_srvc_id, start_incl_srvc_id, sizeof(btgatt_srvc_id_t)); + return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_GET_NEXT_INCL_SERVICE, + (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); + } + return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_GET_FIRST_INCL_SERVICE, + (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); +} + +static bt_status_t btif_gattc_read_char(int conn_id, btgatt_srvc_id_t* srvc_id, + btgatt_char_id_t* char_id, int auth_req ) +{ + CHECK_BTGATT_INIT(); + btif_gattc_cb_t btif_cb; + btif_cb.conn_id = (uint16_t) conn_id; + btif_cb.auth_req = (uint8_t) auth_req; + memcpy(&btif_cb.srvc_id, srvc_id, sizeof(btgatt_srvc_id_t)); + memcpy(&btif_cb.char_id, char_id, sizeof(btgatt_char_id_t)); + return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_READ_CHAR, + (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); +} + +static bt_status_t btif_gattc_read_char_descr(int conn_id, btgatt_srvc_id_t* srvc_id, + btgatt_char_id_t* char_id, bt_uuid_t* descr_id, + int auth_req ) +{ + CHECK_BTGATT_INIT(); + btif_gattc_cb_t btif_cb; + btif_cb.conn_id = (uint16_t) conn_id; + btif_cb.auth_req = (uint8_t) auth_req; + memcpy(&btif_cb.srvc_id, srvc_id, sizeof(btgatt_srvc_id_t)); + memcpy(&btif_cb.char_id, char_id, sizeof(btgatt_char_id_t)); + memcpy(&btif_cb.uuid, descr_id, sizeof(bt_uuid_t)); + return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_READ_CHAR_DESCR, + (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); +} + +static bt_status_t btif_gattc_write_char(int conn_id, btgatt_srvc_id_t* srvc_id, + btgatt_char_id_t* char_id, int write_type, + int len, int auth_req, char* p_value) +{ + CHECK_BTGATT_INIT(); + btif_gattc_cb_t btif_cb; + btif_cb.conn_id = (uint16_t) conn_id; + btif_cb.auth_req = (uint8_t) auth_req; + btif_cb.write_type = (uint8_t) write_type; + btif_cb.len = len > BTGATT_MAX_ATTR_LEN ? BTGATT_MAX_ATTR_LEN : len; + memcpy(&btif_cb.srvc_id, srvc_id, sizeof(btgatt_srvc_id_t)); + memcpy(&btif_cb.char_id, char_id, sizeof(btgatt_char_id_t)); + memcpy(btif_cb.value, p_value, btif_cb.len); + return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_WRITE_CHAR, + (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); +} + +static bt_status_t btif_gattc_write_char_descr(int conn_id, btgatt_srvc_id_t* srvc_id, + btgatt_char_id_t* char_id, bt_uuid_t* descr_id, + int write_type, int len, int auth_req, + char* p_value) +{ + CHECK_BTGATT_INIT(); + btif_gattc_cb_t btif_cb; + btif_cb.conn_id = (uint16_t) conn_id; + btif_cb.auth_req = (uint8_t) auth_req; + btif_cb.write_type = (uint8_t) write_type; + btif_cb.len = len > BTGATT_MAX_ATTR_LEN ? BTGATT_MAX_ATTR_LEN : len; + memcpy(&btif_cb.srvc_id, srvc_id, sizeof(btgatt_srvc_id_t)); + memcpy(&btif_cb.char_id, char_id, sizeof(btgatt_char_id_t)); + memcpy(&btif_cb.uuid, descr_id, sizeof(bt_uuid_t)); + memcpy(btif_cb.value, p_value, btif_cb.len); + return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_WRITE_CHAR_DESCR, + (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); +} + +static bt_status_t btif_gattc_execute_write(int conn_id, int execute) +{ + CHECK_BTGATT_INIT(); + btif_gattc_cb_t btif_cb; + btif_cb.conn_id = (uint16_t) conn_id; + btif_cb.action = (uint8_t) execute; + return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_EXECUTE_WRITE, + (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); +} + +static bt_status_t btif_gattc_reg_for_notification(int client_if, const bt_bdaddr_t *bd_addr, + btgatt_srvc_id_t* srvc_id, + btgatt_char_id_t* char_id) +{ + CHECK_BTGATT_INIT(); + btif_gattc_cb_t btif_cb; + btif_cb.client_if = (uint8_t) client_if; + bdcpy(btif_cb.bd_addr.address, bd_addr->address); + memcpy(&btif_cb.srvc_id, srvc_id, sizeof(btgatt_srvc_id_t)); + memcpy(&btif_cb.char_id, char_id, sizeof(btgatt_char_id_t)); + return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_REG_FOR_NOTIFICATION, + (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); +} + +static bt_status_t btif_gattc_dereg_for_notification(int client_if, const bt_bdaddr_t *bd_addr, + btgatt_srvc_id_t* srvc_id, + btgatt_char_id_t* char_id) +{ + CHECK_BTGATT_INIT(); + btif_gattc_cb_t btif_cb; + btif_cb.client_if = (uint8_t) client_if; + bdcpy(btif_cb.bd_addr.address, bd_addr->address); + memcpy(&btif_cb.srvc_id, srvc_id, sizeof(btgatt_srvc_id_t)); + memcpy(&btif_cb.char_id, char_id, sizeof(btgatt_char_id_t)); + return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_DEREG_FOR_NOTIFICATION, + (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); +} + +static bt_status_t btif_gattc_read_remote_rssi(int client_if, const bt_bdaddr_t *bd_addr) +{ + CHECK_BTGATT_INIT(); + btif_gattc_cb_t btif_cb; + btif_cb.client_if = (uint8_t) client_if; + bdcpy(btif_cb.bd_addr.address, bd_addr->address); + return btif_transfer_context(btgattc_handle_event, BTIF_GATTC_READ_RSSI, + (char*) &btif_cb, sizeof(btif_gattc_cb_t), NULL); +} + +static int btif_gattc_get_device_type( const bt_bdaddr_t *bd_addr ) +{ + int device_type = 0; + char bd_addr_str[18] = {0}; + + bd2str(bd_addr, &bd_addr_str); + if (btif_config_get_int("Remote", bd_addr_str, "DevType", &device_type)) + return device_type; + return 0; +} + +extern bt_status_t btif_gattc_test_command_impl(int command, btgatt_test_params_t* params); + +static bt_status_t btif_gattc_test_command(int command, btgatt_test_params_t* params) +{ + return btif_gattc_test_command_impl(command, params); +} + + +const btgatt_client_interface_t btgattClientInterface = { + btif_gattc_register_app, + btif_gattc_unregister_app, + btif_gattc_scan, + btif_gattc_open, + btif_gattc_close, + btif_gattc_refresh, + btif_gattc_search_service, + btif_gattc_get_included_service, + btif_gattc_get_characteristic, + btif_gattc_get_descriptor, + btif_gattc_read_char, + btif_gattc_write_char, + btif_gattc_read_char_descr, + btif_gattc_write_char_descr, + btif_gattc_execute_write, + btif_gattc_reg_for_notification, + btif_gattc_dereg_for_notification, + btif_gattc_read_remote_rssi, + btif_gattc_get_device_type, + btif_gattc_test_command +}; + +#endif diff --git a/btif/src/btif_gatt_server.c b/btif/src/btif_gatt_server.c new file mode 100644 index 000000000..9de36f95f --- /dev/null +++ b/btif/src/btif_gatt_server.c @@ -0,0 +1,579 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2013 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + + +/************************************************************************************ + * + * Filename: btif_gatt_server.c + * + * Description: GATT server implementation + * + ***********************************************************************************/ + +#include <hardware/bluetooth.h> +#include <hardware/bt_gatt.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> + +#define LOG_TAG "BtGatt.btif" + +#include "btif_common.h" +#include "btif_util.h" + +#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) + +#include "bta_api.h" +#include "bta_gatt_api.h" +#include "bd.h" +#include "btif_dm.h" +#include "btif_storage.h" + +#include "btif_gatt.h" +#include "btif_gatt_util.h" + +/************************************************************************************ +** Constants & Macros +************************************************************************************/ + +#define CHECK_BTGATT_INIT() if (bt_gatt_callbacks == NULL)\ + {\ + ALOGW("%s: BTGATT not initialized", __FUNCTION__);\ + return BT_STATUS_NOT_READY;\ + } else {\ + ALOGD("%s", __FUNCTION__);\ + } + + +typedef enum { + BTIF_GATTS_REGISTER_APP = 2000, + BTIF_GATTS_UNREGISTER_APP, + BTIF_GATTS_OPEN, + BTIF_GATTS_CLOSE, + BTIF_GATTS_CREATE_SERVICE, + BTIF_GATTS_ADD_INCLUDED_SERVICE, + BTIF_GATTS_ADD_CHARACTERISTIC, + BTIF_GATTS_ADD_DESCRIPTOR, + BTIF_GATTS_START_SERVICE, + BTIF_GATTS_STOP_SERVICE, + BTIF_GATTS_DELETE_SERVICE, + BTIF_GATTS_SEND_INDICATION, + BTIF_GATTS_SEND_RESPONSE +} btif_gatts_event_t; + +/************************************************************************************ +** Local type definitions +************************************************************************************/ + +typedef struct +{ + uint8_t value[BTGATT_MAX_ATTR_LEN]; + btgatt_response_t response; + btgatt_srvc_id_t srvc_id; + bt_bdaddr_t bd_addr; + bt_uuid_t uuid; + uint32_t trans_id; + uint16_t conn_id; + uint16_t srvc_handle; + uint16_t incl_handle; + uint16_t attr_handle; + uint16_t permissions; + uint16_t len; + uint8_t server_if; + uint8_t is_direct; + uint8_t num_handles; + uint8_t properties; + uint8_t transport; + uint8_t confirm; + uint8_t status; +} __attribute__((packed)) btif_gatts_cb_t; + + +/************************************************************************************ +** Static variables +************************************************************************************/ + +extern const btgatt_callbacks_t *bt_gatt_callbacks; + + +/************************************************************************************ +** Static functions +************************************************************************************/ + +static void btapp_gatts_handle_cback(uint16_t event, char* p_param) +{ + ALOGD("%s: Event %d", __FUNCTION__, event); + + tBTA_GATTS *p_data = (tBTA_GATTS*)p_param; + switch (event) + { + case BTA_GATTS_REG_EVT: + { + bt_uuid_t app_uuid; + bta_to_btif_uuid(&app_uuid, &p_data->reg_oper.uuid); + HAL_CBACK(bt_gatt_callbacks, server->register_server_cb + , p_data->reg_oper.status + , p_data->reg_oper.server_if + , &app_uuid + ); + break; + } + + case BTA_GATTS_DEREG_EVT: + break; + + case BTA_GATTS_CONNECT_EVT: + { + bt_bdaddr_t bda; + bdcpy(bda.address, p_data->conn.remote_bda); + + btif_gatt_check_encrypted_link(p_data->conn.remote_bda); + + HAL_CBACK(bt_gatt_callbacks, server->connection_cb, + p_data->conn.conn_id, TRUE, &bda); + break; + } + + case BTA_GATTS_DISCONNECT_EVT: + { + bt_bdaddr_t bda; + bdcpy(bda.address, p_data->conn.remote_bda); + + HAL_CBACK(bt_gatt_callbacks, server->connection_cb, + p_data->conn.conn_id, FALSE, &bda); + + btif_gatt_remove_encrypted_link(p_data->conn.remote_bda); + break; + } + + case BTA_GATTS_CREATE_EVT: + { + btgatt_srvc_id_t srvc_id; + srvc_id.is_primary = p_data->create.is_primary; + srvc_id.id.inst_id = p_data->create.svc_instance; + bta_to_btif_uuid(&srvc_id.id.uuid, &p_data->create.uuid); + + HAL_CBACK(bt_gatt_callbacks, server->service_added_cb, + p_data->create.status, p_data->create.server_if, &srvc_id, + p_data->create.service_id + ); + } + break; + + case BTA_GATTS_ADD_INCL_SRVC_EVT: + HAL_CBACK(bt_gatt_callbacks, server->included_service_added_cb, + p_data->add_result.status, + p_data->add_result.server_if, + p_data->add_result.service_id, + p_data->add_result.attr_id); + break; + + case BTA_GATTS_ADD_CHAR_EVT: + { + bt_uuid_t uuid; + bta_to_btif_uuid(&uuid, &p_data->add_result.char_uuid); + + HAL_CBACK(bt_gatt_callbacks, server->characteristic_added_cb, + p_data->add_result.status, + p_data->add_result.server_if, + &uuid, + p_data->add_result.service_id, + p_data->add_result.attr_id); + break; + } + + case BTA_GATTS_ADD_CHAR_DESCR_EVT: + { + bt_uuid_t uuid; + bta_to_btif_uuid(&uuid, &p_data->add_result.char_uuid); + + HAL_CBACK(bt_gatt_callbacks, server->descriptor_added_cb, + p_data->add_result.status, + p_data->add_result.server_if, + &uuid, + p_data->add_result.service_id, + p_data->add_result.attr_id); + break; + } + + case BTA_GATTS_START_EVT: + HAL_CBACK(bt_gatt_callbacks, server->service_started_cb, + p_data->srvc_oper.status, + p_data->srvc_oper.server_if, + p_data->srvc_oper.service_id); + break; + + case BTA_GATTS_STOP_EVT: + HAL_CBACK(bt_gatt_callbacks, server->service_stopped_cb, + p_data->srvc_oper.status, + p_data->srvc_oper.server_if, + p_data->srvc_oper.service_id); + break; + + case BTA_GATTS_DELELTE_EVT: + HAL_CBACK(bt_gatt_callbacks, server->service_deleted_cb, + p_data->srvc_oper.status, + p_data->srvc_oper.server_if, + p_data->srvc_oper.service_id); + break; + + case BTA_GATTS_READ_EVT: + { + bt_bdaddr_t bda; + bdcpy(bda.address, p_data->req_data.remote_bda); + + HAL_CBACK(bt_gatt_callbacks, server->request_read_cb, + p_data->req_data.conn_id,p_data->req_data.trans_id, &bda, + p_data->req_data.p_data->read_req.handle, + p_data->req_data.p_data->read_req.offset, + p_data->req_data.p_data->read_req.is_long); + break; + } + + case BTA_GATTS_WRITE_EVT: + { + bt_bdaddr_t bda; + bdcpy(bda.address, p_data->req_data.remote_bda); + + HAL_CBACK(bt_gatt_callbacks, server->request_write_cb, + p_data->req_data.conn_id,p_data->req_data.trans_id, &bda, + p_data->req_data.p_data->write_req.handle, + p_data->req_data.p_data->write_req.offset, + p_data->req_data.p_data->write_req.len, + p_data->req_data.p_data->write_req.need_rsp, + p_data->req_data.p_data->write_req.is_prep, + p_data->req_data.p_data->write_req.value); + break; + } + + case BTA_GATTS_EXEC_WRITE_EVT: + { + bt_bdaddr_t bda; + bdcpy(bda.address, p_data->req_data.remote_bda); + + HAL_CBACK(bt_gatt_callbacks, server->request_exec_write_cb, + p_data->req_data.conn_id,p_data->req_data.trans_id, &bda, + p_data->req_data.p_data->exec_write); + break; + } + + case BTA_GATTS_MTU_EVT: + case BTA_GATTS_OPEN_EVT: + case BTA_GATTS_CANCEL_OPEN_EVT: + case BTA_GATTS_CLOSE_EVT: + ALOGD("%s: Empty event (%d)!", __FUNCTION__, event); + break; + + default: + ALOGE("%s: Unhandled event (%d)!", __FUNCTION__, event); + break; + } +} + +static void btapp_gatts_cback(tBTA_GATTS_EVT event, tBTA_GATTS *p_data) +{ + bt_status_t status; + status = btif_transfer_context(btapp_gatts_handle_cback, (uint16_t) event, + (void*)p_data, sizeof(tBTA_GATTS), NULL); + ASSERTC(status == BT_STATUS_SUCCESS, "Context transfer failed!", status); +} + +static void btgatts_handle_event(uint16_t event, char* p_param) +{ + btif_gatts_cb_t* p_cb = (btif_gatts_cb_t*)p_param; + if (!p_cb) return; + + ALOGD("%s: Event %d", __FUNCTION__, event); + + switch (event) + { + case BTIF_GATTS_REGISTER_APP: + { + tBT_UUID uuid; + btif_to_bta_uuid(&uuid, &p_cb->uuid); + BTA_GATTS_AppRegister(&uuid, btapp_gatts_cback); + break; + } + + case BTIF_GATTS_UNREGISTER_APP: + BTA_GATTS_AppDeregister(p_cb->server_if); + break; + + case BTIF_GATTS_OPEN: + if (!p_cb->is_direct) + BTA_DmBleSetBgConnType(BTM_BLE_CONN_AUTO, NULL); + BTA_GATTS_Open(p_cb->server_if, p_cb->bd_addr.address, + p_cb->is_direct); + break; + + case BTIF_GATTS_CLOSE: + // Cancel pending foreground/background connections + BTA_GATTS_CancelOpen(p_cb->server_if, p_cb->bd_addr.address, TRUE); + BTA_GATTS_CancelOpen(p_cb->server_if, p_cb->bd_addr.address, FALSE); + + // Close active connection + if (p_cb->conn_id != 0) + BTA_GATTS_Close(p_cb->conn_id); + break; + + case BTIF_GATTS_CREATE_SERVICE: + { + tBTA_GATT_SRVC_ID srvc_id; + btif_to_bta_srvc_id(&srvc_id, &p_cb->srvc_id); + BTA_GATTS_CreateService(p_cb->server_if, &srvc_id.id.uuid, + srvc_id.id.inst_id, p_cb->num_handles, + srvc_id.is_primary); + break; + } + + case BTIF_GATTS_ADD_INCLUDED_SERVICE: + BTA_GATTS_AddIncludeService(p_cb->srvc_handle, p_cb->incl_handle); + break; + + case BTIF_GATTS_ADD_CHARACTERISTIC: + { + tBT_UUID uuid; + btif_to_bta_uuid(&uuid, &p_cb->uuid); + + BTA_GATTS_AddCharacteristic(p_cb->srvc_handle, &uuid, + p_cb->permissions, p_cb->properties); + break; + } + + case BTIF_GATTS_ADD_DESCRIPTOR: + { + tBT_UUID uuid; + btif_to_bta_uuid(&uuid, &p_cb->uuid); + + BTA_GATTS_AddCharDescriptor(p_cb->srvc_handle, p_cb->permissions, + &uuid); + break; + } + + case BTIF_GATTS_START_SERVICE: + BTA_GATTS_StartService(p_cb->srvc_handle, p_cb->transport); + break; + + case BTIF_GATTS_STOP_SERVICE: + BTA_GATTS_StopService(p_cb->srvc_handle); + break; + + case BTIF_GATTS_DELETE_SERVICE: + BTA_GATTS_DeleteService(p_cb->srvc_handle); + break; + + case BTIF_GATTS_SEND_INDICATION: + BTA_GATTS_HandleValueIndication(p_cb->conn_id, p_cb->attr_handle, + p_cb->len, p_cb->value, p_cb->confirm); + // TODO: Might need to send an ACK if handle value indication is + // invoked without need for confirmation. + break; + + case BTIF_GATTS_SEND_RESPONSE: + { + tBTA_GATTS_RSP rsp_struct; + btgatt_response_t *p_rsp = &p_cb->response; + btif_to_bta_response(&rsp_struct, p_rsp); + + BTA_GATTS_SendRsp(p_cb->conn_id, p_cb->trans_id, + p_cb->status, &rsp_struct); + + HAL_CBACK(bt_gatt_callbacks, server->response_confirmation_cb, + 0, rsp_struct.attr_value.handle); + break; + } + + default: + ALOGE("%s: Unknown event (%d)!", __FUNCTION__, event); + break; + } +} + +/************************************************************************************ +** Server API Functions +************************************************************************************/ + +static bt_status_t btif_gatts_register_app(bt_uuid_t *uuid) +{ + CHECK_BTGATT_INIT(); + btif_gatts_cb_t btif_cb; + memcpy(&btif_cb.uuid, uuid, sizeof(bt_uuid_t)); + return btif_transfer_context(btgatts_handle_event, BTIF_GATTS_REGISTER_APP, + (char*) &btif_cb, sizeof(btif_gatts_cb_t), NULL); +} + +static bt_status_t btif_gatts_unregister_app( int server_if ) +{ + CHECK_BTGATT_INIT(); + btif_gatts_cb_t btif_cb; + btif_cb.server_if = (uint8_t) server_if; + return btif_transfer_context(btgatts_handle_event, BTIF_GATTS_UNREGISTER_APP, + (char*) &btif_cb, sizeof(btif_gatts_cb_t), NULL); +} + +static bt_status_t btif_gatts_open( int server_if, const bt_bdaddr_t *bd_addr, bool is_direct ) +{ + CHECK_BTGATT_INIT(); + btif_gatts_cb_t btif_cb; + btif_cb.server_if = (uint8_t) server_if; + btif_cb.is_direct = is_direct ? 1 : 0; + bdcpy(btif_cb.bd_addr.address, bd_addr->address); + return btif_transfer_context(btgatts_handle_event, BTIF_GATTS_OPEN, + (char*) &btif_cb, sizeof(btif_gatts_cb_t), NULL); +} + +static bt_status_t btif_gatts_close(int server_if, const bt_bdaddr_t *bd_addr, int conn_id) +{ + CHECK_BTGATT_INIT(); + btif_gatts_cb_t btif_cb; + btif_cb.server_if = (uint8_t) server_if; + btif_cb.conn_id = (uint16_t) conn_id; + bdcpy(btif_cb.bd_addr.address, bd_addr->address); + return btif_transfer_context(btgatts_handle_event, BTIF_GATTS_CLOSE, + (char*) &btif_cb, sizeof(btif_gatts_cb_t), NULL); +} + +static bt_status_t btif_gatts_add_service(int server_if, btgatt_srvc_id_t *srvc_id, + int num_handles) +{ + CHECK_BTGATT_INIT(); + btif_gatts_cb_t btif_cb; + btif_cb.server_if = (uint8_t) server_if; + btif_cb.num_handles = (uint8_t) num_handles; + memcpy(&btif_cb.srvc_id, srvc_id, sizeof(btgatt_srvc_id_t)); + return btif_transfer_context(btgatts_handle_event, BTIF_GATTS_CREATE_SERVICE, + (char*) &btif_cb, sizeof(btif_gatts_cb_t), NULL); +} + +static bt_status_t btif_gatts_add_included_service(int server_if, int service_handle, + int included_handle) +{ + CHECK_BTGATT_INIT(); + btif_gatts_cb_t btif_cb; + btif_cb.server_if = (uint8_t) server_if; + btif_cb.srvc_handle = (uint16_t) service_handle; + btif_cb.incl_handle = (uint16_t) included_handle; + return btif_transfer_context(btgatts_handle_event, BTIF_GATTS_ADD_INCLUDED_SERVICE, + (char*) &btif_cb, sizeof(btif_gatts_cb_t), NULL); +} + +static bt_status_t btif_gatts_add_characteristic(int server_if, int service_handle, + bt_uuid_t *uuid, int properties, + int permissions) +{ + CHECK_BTGATT_INIT(); + btif_gatts_cb_t btif_cb; + btif_cb.server_if = (uint8_t) server_if; + btif_cb.srvc_handle = (uint16_t) service_handle; + btif_cb.properties = (uint8_t) properties; + btif_cb.permissions = (uint16_t) permissions; + memcpy(&btif_cb.uuid, uuid, sizeof(bt_uuid_t)); + return btif_transfer_context(btgatts_handle_event, BTIF_GATTS_ADD_CHARACTERISTIC, + (char*) &btif_cb, sizeof(btif_gatts_cb_t), NULL); +} + +static bt_status_t btif_gatts_add_descriptor(int server_if, int service_handle, bt_uuid_t *uuid, + int permissions) +{ + CHECK_BTGATT_INIT(); + btif_gatts_cb_t btif_cb; + btif_cb.server_if = (uint8_t) server_if; + btif_cb.srvc_handle = (uint16_t) service_handle; + btif_cb.permissions = (uint16_t) permissions; + memcpy(&btif_cb.uuid, uuid, sizeof(bt_uuid_t)); + return btif_transfer_context(btgatts_handle_event, BTIF_GATTS_ADD_DESCRIPTOR, + (char*) &btif_cb, sizeof(btif_gatts_cb_t), NULL); +} + +static bt_status_t btif_gatts_start_service(int server_if, int service_handle, int transport) +{ + CHECK_BTGATT_INIT(); + btif_gatts_cb_t btif_cb; + btif_cb.server_if = (uint8_t) server_if; + btif_cb.srvc_handle = (uint16_t) service_handle; + btif_cb.transport = (uint8_t) transport; + return btif_transfer_context(btgatts_handle_event, BTIF_GATTS_START_SERVICE, + (char*) &btif_cb, sizeof(btif_gatts_cb_t), NULL); +} + +static bt_status_t btif_gatts_stop_service(int server_if, int service_handle) +{ + CHECK_BTGATT_INIT(); + btif_gatts_cb_t btif_cb; + btif_cb.server_if = (uint8_t) server_if; + btif_cb.srvc_handle = (uint16_t) service_handle; + return btif_transfer_context(btgatts_handle_event, BTIF_GATTS_STOP_SERVICE, + (char*) &btif_cb, sizeof(btif_gatts_cb_t), NULL); +} + +static bt_status_t btif_gatts_delete_service(int server_if, int service_handle) +{ + CHECK_BTGATT_INIT(); + btif_gatts_cb_t btif_cb; + btif_cb.server_if = (uint8_t) server_if; + btif_cb.srvc_handle = (uint16_t) service_handle; + return btif_transfer_context(btgatts_handle_event, BTIF_GATTS_DELETE_SERVICE, + (char*) &btif_cb, sizeof(btif_gatts_cb_t), NULL); +} + +static bt_status_t btif_gatts_send_indication(int server_if, int attribute_handle, int conn_id, + int len, int confirm, char* p_value) +{ + CHECK_BTGATT_INIT(); + btif_gatts_cb_t btif_cb; + btif_cb.server_if = (uint8_t) server_if; + btif_cb.conn_id = (uint16_t) conn_id; + btif_cb.attr_handle = attribute_handle; + btif_cb.confirm = confirm; + btif_cb.len = len; + memcpy(btif_cb.value, p_value, len > BTGATT_MAX_ATTR_LEN ? BTGATT_MAX_ATTR_LEN : len); + return btif_transfer_context(btgatts_handle_event, BTIF_GATTS_SEND_INDICATION, + (char*) &btif_cb, sizeof(btif_gatts_cb_t), NULL); +} + +static bt_status_t btif_gatts_send_response(int conn_id, int trans_id, + int status, btgatt_response_t *response) +{ + CHECK_BTGATT_INIT(); + btif_gatts_cb_t btif_cb; + btif_cb.conn_id = (uint16_t) conn_id; + btif_cb.trans_id = (uint32_t) trans_id; + btif_cb.status = (uint8_t) status; + memcpy(&btif_cb.response, response, sizeof(btgatt_response_t)); + return btif_transfer_context(btgatts_handle_event, BTIF_GATTS_SEND_RESPONSE, + (char*) &btif_cb, sizeof(btif_gatts_cb_t), NULL); +} + +const btgatt_server_interface_t btgattServerInterface = { + btif_gatts_register_app, + btif_gatts_unregister_app, + btif_gatts_open, + btif_gatts_close, + btif_gatts_add_service, + btif_gatts_add_included_service, + btif_gatts_add_characteristic, + btif_gatts_add_descriptor, + btif_gatts_start_service, + btif_gatts_stop_service, + btif_gatts_delete_service, + btif_gatts_send_indication, + btif_gatts_send_response +}; + +#endif diff --git a/btif/src/btif_gatt_test.c b/btif/src/btif_gatt_test.c new file mode 100644 index 000000000..8c23d56ca --- /dev/null +++ b/btif/src/btif_gatt_test.c @@ -0,0 +1,293 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2013 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + + +#include <hardware/bluetooth.h> +#include <hardware/bt_gatt.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> + +#define LOG_TAG "BtGatt.btif_test" + +#include "btif_common.h" +#include "btif_util.h" + +#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) + +#include "bta_api.h" +#include "bta_gatt_api.h" +#include "bd.h" +#include "btif_storage.h" +#include "bte_appl.h" + +#include "btif_gatt.h" +#include "btif_gatt_util.h" +#include "btif_dm.h" + +#include "gatt_api.h" + +/******************************************************************************* + * Typedefs & Macros + *******************************************************************************/ + +typedef struct +{ + tGATT_IF gatt_if; + UINT16 conn_id; +} btif_test_cb_t; + +/******************************************************************************* + * Static variables + *******************************************************************************/ + +static const char * disc_name[GATT_DISC_MAX] = +{ + "Unknown", + "GATT_DISC_SRVC_ALL", + "GATT_DISC_SRVC_BY_UUID", + "GATT_DISC_INC_SRVC", + "GATT_DISC_CHAR", + "GATT_DISC_CHAR_DSCPT" +}; + +static btif_test_cb_t test_cb; + +/******************************************************************************* + * Callback functions + *******************************************************************************/ + +static char * format_uuid(tBT_UUID bt_uuid, char *str_buf) +{ + int x = 0; + + if (bt_uuid.len == LEN_UUID_16) + { + sprintf(str_buf, "0x%04x", bt_uuid.uu.uuid16); + } + else if (bt_uuid.len == LEN_UUID_128) + { + x += sprintf(&str_buf[x], "%02x%02x%02x%02x-%02x%02x-%02x%02x", + bt_uuid.uu.uuid128[15], bt_uuid.uu.uuid128[14], + bt_uuid.uu.uuid128[13], bt_uuid.uu.uuid128[12], + bt_uuid.uu.uuid128[11], bt_uuid.uu.uuid128[10], + bt_uuid.uu.uuid128[9], bt_uuid.uu.uuid128[8]); + sprintf(&str_buf[x], "%02x%02x-%02x%02x%02x%02x%02x%02x", + bt_uuid.uu.uuid128[7], bt_uuid.uu.uuid128[6], + bt_uuid.uu.uuid128[5], bt_uuid.uu.uuid128[4], + bt_uuid.uu.uuid128[3], bt_uuid.uu.uuid128[2], + bt_uuid.uu.uuid128[1], bt_uuid.uu.uuid128[0]); + } + else + sprintf(str_buf, "Unknown (len=%d)", bt_uuid.len); + + return str_buf; +} + +static void btif_test_connect_cback(tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, + BOOLEAN connected, tGATT_DISCONN_REASON reason) +{ + ALOGD("%s: conn_id=%d, connected=%d", __FUNCTION__, conn_id, connected); + test_cb.conn_id = connected ? conn_id : 0; +} + +static void btif_test_command_complete_cback(UINT16 conn_id, tGATTC_OPTYPE op, + tGATT_STATUS status, tGATT_CL_COMPLETE *p_data) +{ + ALOGD ("%s: op_code=0x%02x, conn_id=0x%x. status=0x%x", + __FUNCTION__, op, conn_id, status); + + switch (op) + { + case GATTC_OPTYPE_READ: + case GATTC_OPTYPE_WRITE: + case GATTC_OPTYPE_CONFIG: + case GATTC_OPTYPE_EXE_WRITE: + case GATTC_OPTYPE_NOTIFICATION: + break; + + case GATTC_OPTYPE_INDICATION: + GATTC_SendHandleValueConfirm(conn_id, p_data->handle); + break; + + default: + ALOGD ("%s: Unknown op_code (0x%02x)", __FUNCTION__, op); + break; + } +} + + +static void btif_test_discovery_result_cback(UINT16 conn_id, tGATT_DISC_TYPE disc_type, + tGATT_DISC_RES *p_data) +{ + char str_buf[50]; + + ALOGD("------ GATT Discovery result %-22s -------", disc_name[disc_type]); + ALOGD(" Attribute handle: 0x%04x (%d)", p_data->handle, p_data->handle); + + if (disc_type != GATT_DISC_CHAR_DSCPT) { + ALOGD(" Attribute type: %s", format_uuid(p_data->type, str_buf)); + } + + switch (disc_type) + { + case GATT_DISC_SRVC_ALL: + ALOGD(" Handle range: 0x%04x ~ 0x%04x (%d ~ %d)", + p_data->handle, p_data->value.group_value.e_handle, + p_data->handle, p_data->value.group_value.e_handle); + ALOGD(" Service UUID: %s", + format_uuid(p_data->value.group_value.service_type, str_buf)); + break; + + case GATT_DISC_SRVC_BY_UUID: + ALOGD(" Handle range: 0x%04x ~ 0x%04x (%d ~ %d)", + p_data->handle, p_data->value.handle, + p_data->handle, p_data->value.handle); + break; + + case GATT_DISC_INC_SRVC: + ALOGD(" Handle range: 0x%04x ~ 0x%04x (%d ~ %d)", + p_data->value.incl_service.s_handle, p_data->value.incl_service.e_handle, + p_data->value.incl_service.s_handle, p_data->value.incl_service.e_handle); + ALOGD(" Service UUID: %s", + format_uuid(p_data->value.incl_service.service_type, str_buf)); + break; + + case GATT_DISC_CHAR: + ALOGD(" Properties: 0x%02x", + p_data->value.dclr_value.char_prop); + ALOGD(" Characteristic UUID: %s", + format_uuid(p_data->value.dclr_value.char_uuid, str_buf)); + break; + + case GATT_DISC_CHAR_DSCPT: + ALOGD(" Descriptor UUID: %s", format_uuid(p_data->type, str_buf)); + break; + } + + ALOGD("-----------------------------------------------------------"); +} + +static void btif_test_discovery_complete_cback(UINT16 conn_id, + tGATT_DISC_TYPE disc_type, + tGATT_STATUS status) +{ + ALOGD("%s: status=%d", __FUNCTION__, status); +} + +static tGATT_CBACK btif_test_callbacks = +{ + btif_test_connect_cback , + btif_test_command_complete_cback, + btif_test_discovery_result_cback, + btif_test_discovery_complete_cback, + NULL +}; + +/******************************************************************************* + * Implementation + *******************************************************************************/ + +bt_status_t btif_gattc_test_command_impl(uint16_t command, btgatt_test_params_t* params) +{ + switch(command) { + case 0x01: /* Enable */ + { + ALOGD("%s: ENABLE - enable=%d", __FUNCTION__, params->u1); + if (params->u1) + { + tBT_UUID app_uuid = {LEN_UUID_128,{0xAE}}; + test_cb.gatt_if = GATT_Register(&app_uuid, &btif_test_callbacks); + GATT_StartIf(test_cb.gatt_if); + } else { + GATT_Deregister(test_cb.gatt_if); + test_cb.gatt_if = 0; + } + break; + } + + case 0x02: /* Connect */ + { + ALOGD("%s: CONNECT - device=%02x:%02x:%02x:%02x:%02x:%02x (dev_type=%d)", + __FUNCTION__, + params->bda1->address[0], params->bda1->address[1], + params->bda1->address[2], params->bda1->address[3], + params->bda1->address[4], params->bda1->address[5], + params->u1); + + if (params->u1 == BT_DEVICE_TYPE_BLE) + BTM_SecAddBleDevice(params->bda1->address, NULL, BT_DEVICE_TYPE_BLE, 0); + + if ( !GATT_Connect(test_cb.gatt_if, params->bda1->address, TRUE) ) + { + ALOGE("%s: GATT_Connect failed!", __FUNCTION__); + } + break; + } + + case 0x03: /* Disconnect */ + { + ALOGD("%s: DISCONNECT - conn_id=%d", __FUNCTION__, test_cb.conn_id); + GATT_Disconnect(test_cb.conn_id); + break; + } + + case 0x04: /* Discover */ + { + char buf[50] = {0}; + tGATT_DISC_PARAM param; + memset(¶m, 0, sizeof(tGATT_DISC_PARAM)); + + if (params->u1 >= GATT_DISC_MAX) + { + ALOGE("%s: DISCOVER - Invalid type (%d)!", __FUNCTION__, params->u1); + return 0; + } + + param.s_handle = params->u2; + param.e_handle = params->u3; + btif_to_bta_uuid(¶m.service, params->uuid1); + + ALOGD("%s: DISCOVER (%s), conn_id=%d, uuid=%s, handles=0x%04x-0x%04x", + __FUNCTION__, disc_name[params->u1], test_cb.conn_id, + format_uuid(param.service, buf), params->u2, params->u3); + GATTC_Discover(test_cb.conn_id, params->u1, ¶m); + break; + } + + case 0xF0: /* Pairing configuration */ + ALOGD("%s: Setting pairing config auth=%d, iocaps=%d, keys=%d/%d/%d", + __FUNCTION__, params->u1, params->u2, params->u3, params->u4, + params->u5); + + bte_appl_cfg.ble_auth_req = params->u1; + bte_appl_cfg.ble_io_cap = params->u2; + bte_appl_cfg.ble_init_key = params->u3; + bte_appl_cfg.ble_resp_key = params->u4; + bte_appl_cfg.ble_max_key_size = params->u5; + break; + + default: + ALOGE("%s: UNKNOWN TEST COMMAND 0x%02x", __FUNCTION__, command); + break; + } + return 0; +} + +#endif diff --git a/btif/src/btif_gatt_util.c b/btif/src/btif_gatt_util.c new file mode 100644 index 000000000..a3cbc3d8b --- /dev/null +++ b/btif/src/btif_gatt_util.c @@ -0,0 +1,351 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2013 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + + +#include <hardware/bluetooth.h> +#include <hardware/bt_gatt.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> + +#define LOG_TAG "BtGatt.btif" + +#include "bta_api.h" +#include "bta_gatt_api.h" +#include "bd.h" +#include "btif_storage.h" + +#include "btif_common.h" +#include "btif_dm.h" +#include "btif_util.h" +#include "btif_gatt.h" +#include "btif_gatt_util.h" + +#define GATTC_READ_VALUE_TYPE_VALUE 0x0000 /* Attribute value itself */ +#define GATTC_READ_VALUE_TYPE_AGG_FORMAT 0x2905 /* Characteristic Aggregate Format*/ + +#define BTIF_GATT_MAX_ENC_LINK_RECORDS 10 + +typedef struct +{ + BD_ADDR bd_addr; + BOOLEAN in_use; +}__attribute__((packed)) btif_gatt_encrypted_link_t; + +static char BASE_UUID[16] = { + 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static btif_gatt_encrypted_link_t encrypted_links[BTIF_GATT_MAX_ENC_LINK_RECORDS]; + +int uuidType(unsigned char* p_uuid) +{ + int i = 0; + int match = 0; + int all_zero = 1; + + for(i = 0; i != 16; ++i) + { + if (i == 12 || i == 13) + continue; + + if (p_uuid[i] == BASE_UUID[i]) + ++match; + + if (p_uuid[i] != 0) + all_zero = 0; + } + if (all_zero) + return 0; + if (match == 12) + return LEN_UUID_32; + if (match == 14) + return LEN_UUID_16; + return LEN_UUID_128; +} + +/******************************************************************************* + * BTIF -> BTA conversion functions + *******************************************************************************/ + +void btif_to_bta_uuid(tBT_UUID *p_dest, bt_uuid_t *p_src) +{ + char *p_byte = (char*)p_src; + int i = 0; + + p_dest->len = uuidType(p_src->uu); + + switch (p_dest->len) + { + case LEN_UUID_16: + p_dest->uu.uuid16 = (p_src->uu[13] << 8) + p_src->uu[12]; + break; + + case LEN_UUID_32: + p_dest->uu.uuid32 = (p_src->uu[13] << 8) + p_src->uu[12]; + p_dest->uu.uuid32 += (p_src->uu[15] << 24) + (p_src->uu[14] << 16); + break; + + case LEN_UUID_128: + for(i = 0; i != 16; ++i) + p_dest->uu.uuid128[i] = p_byte[i]; + break; + + default: + ALOGE("%s: Unknown UUID length %d!", __FUNCTION__, p_dest->len); + break; + } +} + +void btif_to_bta_char_id(tBTA_GATT_ID *p_dest, btgatt_char_id_t *p_src) +{ + p_dest->inst_id = p_src->inst_id; + btif_to_bta_uuid(&p_dest->uuid, &p_src->uuid); +} + +void btif_to_bta_srvc_id(tBTA_GATT_SRVC_ID *p_dest, btgatt_srvc_id_t *p_src) +{ + p_dest->id.inst_id = p_src->id.inst_id; + btif_to_bta_uuid(&p_dest->id.uuid, &p_src->id.uuid); + p_dest->is_primary = p_src->is_primary; +} + +void btif_to_bta_response(tBTA_GATTS_RSP *p_dest, btgatt_response_t* p_src) +{ + p_dest->attr_value.auth_req = p_src->attr_value.auth_req; + p_dest->attr_value.handle = p_src->attr_value.handle; + p_dest->attr_value.len = p_src->attr_value.len; + p_dest->attr_value.offset = p_src->attr_value.offset; + memcpy(p_dest->attr_value.value, p_src->attr_value.value, GATT_MAX_ATTR_LEN); +} + +/******************************************************************************* + * BTA -> BTIF conversion functions + *******************************************************************************/ + +void bta_to_btif_uuid(bt_uuid_t *p_dest, tBT_UUID *p_src) +{ + int i = 0; + + if (p_src->len == LEN_UUID_16 || p_src->len == LEN_UUID_32) + { + for(i=0; i != 16; ++i) + p_dest->uu[i] = BASE_UUID[i]; + } + + switch (p_src->len) + { + case 0: + break; + + case LEN_UUID_16: + p_dest->uu[12] = p_src->uu.uuid16 & 0xff; + p_dest->uu[13] = (p_src->uu.uuid16 >> 8) & 0xff; + break; + + case LEN_UUID_32: + p_dest->uu[12] = p_src->uu.uuid16 & 0xff; + p_dest->uu[13] = (p_src->uu.uuid16 >> 8) & 0xff; + p_dest->uu[14] = (p_src->uu.uuid32 >> 16) & 0xff; + p_dest->uu[15] = (p_src->uu.uuid32 >> 24) & 0xff; + break; + + case LEN_UUID_128: + for(i=0; i != 16; ++i) + p_dest->uu[i] = p_src->uu.uuid128[i]; + break; + + default: + ALOGE("%s: Unknown UUID length %d!", __FUNCTION__, p_src->len); + break; + } +} + + +void bta_to_btif_char_id(btgatt_char_id_t *p_dest, tBTA_GATT_ID *p_src) +{ + p_dest->inst_id = p_src->inst_id; + bta_to_btif_uuid(&p_dest->uuid, &p_src->uuid); +} + +void bta_to_btif_srvc_id(btgatt_srvc_id_t *p_dest, tBTA_GATT_SRVC_ID *p_src) +{ + p_dest->id.inst_id = p_src->id.inst_id; + bta_to_btif_uuid(&p_dest->id.uuid, &p_src->id.uuid); + p_dest->is_primary = p_src->is_primary; +} + + +/******************************************************************************* + * Utility functions + *******************************************************************************/ + +uint16_t get_uuid16(tBT_UUID *p_uuid) +{ + if (p_uuid->len == LEN_UUID_16) + { + return p_uuid->uu.uuid16; + } + else if (p_uuid->len == LEN_UUID_128) + { + UINT16 u16; + UINT8 *p = &p_uuid->uu.uuid128[LEN_UUID_128 - 4]; + STREAM_TO_UINT16(u16, p); + return u16; + } + else /* p_uuid->len == LEN_UUID_32 */ + { + return(UINT16) p_uuid->uu.uuid32; + } +} + +uint16_t set_read_value(btgatt_read_params_t *p_dest, tBTA_GATTC_READ *p_src) +{ + int i = 0; + uint16_t descr_type = 0; + uint16_t len = 0; + + p_dest->status = p_src->status; + bta_to_btif_srvc_id(&p_dest->srvc_id, &p_src->srvc_id); + bta_to_btif_char_id(&p_dest->char_id, &p_src->char_id); + bta_to_btif_uuid(&p_dest->descr_id, &p_src->descr_type); + + descr_type = get_uuid16(&p_src->descr_type); + + switch (descr_type) + { + case GATT_UUID_CHAR_AGG_FORMAT: + /* not supported */ + p_dest->value_type = GATTC_READ_VALUE_TYPE_AGG_FORMAT; + break; + + default: + if ( p_src->status == BTA_GATT_OK ) + { + ALOGI("%s unformat.len = %d ", __FUNCTION__, p_src->p_value->unformat.len); + p_dest->value.len = p_src->p_value->unformat.len; + if ( p_src->p_value->unformat.len > 0 && p_src->p_value->unformat.p_value != NULL ) + { + memcpy(p_dest->value.value, p_src->p_value->unformat.p_value, + p_src->p_value->unformat.len); + } + len += p_src->p_value->unformat.len; + } + else + { + p_dest->value.len = 0; + } + + p_dest->value_type = GATTC_READ_VALUE_TYPE_VALUE; + break; + } + + return len; +} + +/******************************************************************************* + * Encrypted link map handling + *******************************************************************************/ + +static void btif_gatt_set_encryption_cb (BD_ADDR bd_addr, tBTA_STATUS result); + +static BOOLEAN btif_gatt_is_link_encrypted (BD_ADDR bd_addr) +{ + btif_gatt_encrypted_link_t *p_link = &encrypted_links[0]; + int i; + + if (bd_addr == NULL) + return FALSE; + + for (i = 0; i != BTIF_GATT_MAX_ENC_LINK_RECORDS; ++i, ++p_link) + { + if (p_link->in_use && (!memcmp(p_link->bd_addr, bd_addr, BD_ADDR_LEN))) + return TRUE; + } + return FALSE; +} + +static BOOLEAN btif_gatt_add_encrypted_link (BD_ADDR bd_addr) +{ + btif_gatt_encrypted_link_t *p_link = &encrypted_links[0]; + int i; + + if (bd_addr == NULL) + return FALSE; + + if (btif_gatt_is_link_encrypted(bd_addr)) + return TRUE; + + for (i = 0; i != BTIF_GATT_MAX_ENC_LINK_RECORDS; ++i, ++p_link) + { + if (!p_link->in_use) + { + p_link->in_use = TRUE; + memcpy( p_link->bd_addr, bd_addr, sizeof(BD_ADDR) ); + return TRUE; + } + } + + return FALSE; +} + +void btif_gatt_remove_encrypted_link (BD_ADDR bd_addr) +{ + btif_gatt_encrypted_link_t *p_link = &encrypted_links[0]; + int i; + + if (bd_addr == NULL) + return; + + for (i = 0; i != BTIF_GATT_MAX_ENC_LINK_RECORDS; ++i, ++p_link) + { + if (p_link->in_use && (!memcmp (p_link->bd_addr, bd_addr, BD_ADDR_LEN))) + { + p_link->in_use = FALSE; + break; + } + } +} + +static void btif_gatt_set_encryption_cb (BD_ADDR bd_addr, tBTA_STATUS result) +{ + if (result == BTA_SUCCESS) + { + btif_gatt_add_encrypted_link(bd_addr); + } else { + btif_gatt_remove_encrypted_link(bd_addr); + } +} + +void btif_gatt_check_encrypted_link (BD_ADDR bd_addr) +{ + char buf[100]; + + bt_bdaddr_t bda; + bdcpy(bda.address, bd_addr); + + if ((btif_storage_get_ble_bonding_key(&bda, BTIF_DM_LE_KEY_PENC, + buf, sizeof(btif_dm_ble_penc_keys_t)) == BT_STATUS_SUCCESS) + && !btif_gatt_is_link_encrypted(bd_addr)) + { + BTA_DmSetEncryption(bd_addr, + &btif_gatt_set_encryption_cb, BTM_BLE_SEC_ENCRYPT); + } +}
\ No newline at end of file diff --git a/btif/src/btif_hf.c b/btif/src/btif_hf.c index 7ce22b101..7688e68b6 100755..100644 --- a/btif/src/btif_hf.c +++ b/btif/src/btif_hf.c @@ -1137,7 +1137,7 @@ static void cleanup( void ) } static const bthf_interface_t bthfInterface = { - sizeof(bt_interface_t), + sizeof(bthfInterface), init, connect, disconnect, diff --git a/btif/src/btif_hh.c b/btif/src/btif_hh.c index e937a710e..61dd89487 100644 --- a/btif/src/btif_hh.c +++ b/btif/src/btif_hh.c @@ -266,6 +266,7 @@ static void update_keyboard_lockstates(btif_hh_device_t *p_dev) if (p_dev->p_buf != NULL) { p_dev->p_buf->len = len; p_dev->p_buf->offset = BTA_HH_MIN_OFFSET; + p_dev->p_buf->layer_specific = BTA_HH_RPTT_OUTPUT; /* LED status updated by data event */ UINT8 *pbuf_data = (UINT8 *)(p_dev->p_buf + 1) @@ -1571,6 +1572,7 @@ static bt_status_t send_data (bt_bdaddr_t *bd_addr, char* data) UINT8* pbuf_data; pbuf_data = (UINT8*) (p_dev->p_buf + 1) + p_dev->p_buf->offset; memcpy(pbuf_data, hexbuf, hex_bytes_filled); + p_dev->p_buf->layer_specific = BTA_HH_RPTT_OUTPUT; BTA_HhSendData(p_dev->dev_handle, *bda, p_dev->p_buf); return BT_STATUS_SUCCESS; } @@ -1619,7 +1621,7 @@ static void cleanup( void ) } static const bthh_interface_t bthhInterface = { - sizeof(bt_interface_t), + sizeof(bthhInterface), init, connect, disconnect, @@ -1649,7 +1651,7 @@ bt_status_t btif_hh_execute_service(BOOLEAN b_enable) if (b_enable) { /* Enable and register with BTA-HH */ - BTA_HhEnable(BTA_SEC_NONE, FALSE, bte_hh_evt); + BTA_HhEnable(BTA_SEC_NONE, bte_hh_evt); } else { /* Disable HH */ diff --git a/btif/src/btif_hl.c b/btif/src/btif_hl.c index e6c3fb7f8..e22ca8aff 100644 --- a/btif/src/btif_hl.c +++ b/btif/src/btif_hl.c @@ -4542,7 +4542,7 @@ static void cleanup( void ){ } static const bthl_interface_t bthlInterface = { - sizeof(bthl_interface_t), + sizeof(bthlInterface), init, register_application, unregister_application, diff --git a/btif/src/btif_storage.c b/btif/src/btif_storage.c index 2190b1cd4..055387410 100755..100644 --- a/btif/src/btif_storage.c +++ b/btif/src/btif_storage.c @@ -59,6 +59,10 @@ #define BTIF_STORAGE_PATH_REMOTE_DEVCLASS "DevClass" #define BTIF_STORAGE_PATH_REMOTE_DEVTYPE "DevType" #define BTIF_STORAGE_PATH_REMOTE_NAME "Name" +#define BTIF_STORAGE_PATH_REMOTE_VER_MFCT "Manufacturer" +#define BTIF_STORAGE_PATH_REMOTE_VER_VER "LmpVer" +#define BTIF_STORAGE_PATH_REMOTE_VER_SUBVER "LmpSubVer" + //#define BTIF_STORAGE_PATH_REMOTE_LINKKEYS "remote_linkkeys" #define BTIF_STORAGE_PATH_REMOTE_ALIASE "Aliase" #define BTIF_STORAGE_PATH_REMOTE_SERVICE "Service" @@ -155,17 +159,30 @@ typedef struct } btif_bonded_devices_t; /************************************************************************************ -** Extern variables +** External variables ************************************************************************************/ extern UINT16 bta_service_id_to_uuid_lkup_tbl [BTA_MAX_SERVICE_ID]; extern bt_bdaddr_t btif_local_bd_addr; + +/************************************************************************************ +** External functions +************************************************************************************/ + +extern void btif_gatts_add_bonded_dev_from_nv(BD_ADDR bda); + /************************************************************************************ -** Static variables +** Internal Functions ************************************************************************************/ +bt_status_t btif_in_fetch_bonded_ble_device(char *remote_bd_addr,int add, + btif_bonded_devices_t *p_bonded_devices); +bt_status_t btif_storage_get_remote_addr_type(bt_bdaddr_t *remote_bd_addr, + int *addr_type); + /************************************************************************************ ** Static functions ************************************************************************************/ + /******************************************************************************* ** ** Function btif_in_make_filename @@ -292,6 +309,22 @@ static int prop2cfg(bt_bdaddr_t *remote_bd_addr, bt_property_t *prop) btif_config_save(); break; } + case BT_PROPERTY_REMOTE_VERSION_INFO: + { + bt_remote_version_t *info = (bt_remote_version_t *)prop->val; + + if (!info) + return FALSE; + + btif_config_set_int("Remote", bdstr, + BTIF_STORAGE_PATH_REMOTE_VER_MFCT, info->manufacturer); + btif_config_set_int("Remote", bdstr, + BTIF_STORAGE_PATH_REMOTE_VER_VER, info->version); + btif_config_set_int("Remote", bdstr, + BTIF_STORAGE_PATH_REMOTE_VER_SUBVER, info->sub_ver); + btif_config_save(); + } break; + default: BTIF_TRACE_ERROR1("Unknow prop type:%d", prop->type); return FALSE; @@ -381,8 +414,32 @@ static int cfg2prop(bt_bdaddr_t *remote_bd_addr, bt_property_t *prop) prop->len = num_uuids * sizeof(bt_uuid_t); ret = TRUE; } - break; - } + else + { + prop->val = NULL; + prop->len = 0; + } + } break; + + case BT_PROPERTY_REMOTE_VERSION_INFO: + { + bt_remote_version_t *info = (bt_remote_version_t *)prop->val; + + if(prop->len >= (int)sizeof(bt_remote_version_t)) + { + ret = btif_config_get_int("Remote", bdstr, + BTIF_STORAGE_PATH_REMOTE_VER_MFCT, &info->manufacturer); + + if (ret == TRUE) + ret = btif_config_get_int("Remote", bdstr, + BTIF_STORAGE_PATH_REMOTE_VER_VER, &info->version); + + if (ret == TRUE) + ret = btif_config_get_int("Remote", bdstr, + BTIF_STORAGE_PATH_REMOTE_VER_SUBVER, &info->sub_ver); + } + } break; + default: BTIF_TRACE_ERROR1("Unknow prop type:%d", prop->type); return FALSE; @@ -412,6 +469,9 @@ static bt_status_t btif_in_fetch_bonded_devices(btif_bonded_devices_t *p_bonded_ kname_size = sizeof(kname); kname[0] = 0; kpos = 0; + BOOLEAN bt_linkkey_file_found=FALSE; + int device_type; + do { kpos = btif_config_next_key(kpos, "Remote", kname, &kname_size); @@ -435,15 +495,38 @@ static bt_status_t btif_in_fetch_bonded_devices(btif_bonded_devices_t *p_bonded_ if(btif_config_get_int("Remote", kname, "DevClass", &cod)) uint2devclass((UINT32)cod, dev_class); BTA_DmAddDevice(bd_addr.address, dev_class, link_key, 0, 0, (UINT8)linkkey_type, 0); + + if (btif_config_get_int("Remote", kname, "DevType", &device_type) && + (device_type == BT_DEVICE_TYPE_DUMO) ) + { + btif_gatts_add_bonded_dev_from_nv(bd_addr.address); + } } + bt_linkkey_file_found = TRUE; memcpy(&p_bonded_devices->devices[p_bonded_devices->num_devices++], &bd_addr, sizeof(bt_bdaddr_t)); } - else BTIF_TRACE_ERROR1("bounded device:%s, LinkKeyType or PinLength is invalid", kname); + else + { +#if (BLE_INCLUDED == TRUE) + bt_linkkey_file_found = FALSE; +#else + BTIF_TRACE_ERROR1("bounded device:%s, LinkKeyType or PinLength is invalid", kname); +#endif + } } - else BTIF_TRACE_DEBUG1("Remote device:%s, no link key", kname); +#if (BLE_INCLUDED == TRUE) + if(!(btif_in_fetch_bonded_ble_device(kname,add, p_bonded_devices)) && (!bt_linkkey_file_found)) + { + BTIF_TRACE_DEBUG1("Remote device:%s, no link key or ble key found", kname); + } +#else + if(!bt_linkkey_file_found) + BTIF_TRACE_DEBUG1("Remote device:%s, no link key", kname); +#endif kname_size = sizeof(kname); kname[0] = 0; } while(kpos != -1); + BTIF_TRACE_DEBUG0("out"); return BT_STATUS_SUCCESS; } @@ -640,7 +723,7 @@ bt_status_t btif_storage_set_remote_device_property(bt_bdaddr_t *remote_bd_addr, ** BT_STATUS_FAIL otherwise ** *******************************************************************************/ -bt_status_t btif_storage_add_remote_device(bt_bdaddr_t *remote_bdaddr, +bt_status_t btif_storage_add_remote_device(bt_bdaddr_t *remote_bd_addr, uint32_t num_properties, bt_property_t *properties) { @@ -659,12 +742,12 @@ bt_status_t btif_storage_add_remote_device(bt_bdaddr_t *remote_bdaddr, bt_property_t addr_prop; memcpy(&addr_prop, &properties[i], sizeof(bt_property_t)); addr_prop.type = BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP; - btif_storage_set_remote_device_property(remote_bdaddr, + btif_storage_set_remote_device_property(remote_bd_addr, &addr_prop); } else { - btif_storage_set_remote_device_property(remote_bdaddr, + btif_storage_set_remote_device_property(remote_bd_addr, &properties[i]); } } @@ -846,6 +929,413 @@ bt_status_t btif_storage_load_bonded_devices(void) return BT_STATUS_SUCCESS; } +#if (BLE_INCLUDED == TRUE) + +/******************************************************************************* +** +** Function btif_storage_add_ble_bonding_key +** +** Description BTIF storage API - Adds the newly bonded device to NVRAM +** along with the ble-key, Key type and Pin key length +** +** Returns BT_STATUS_SUCCESS if the store was successful, +** BT_STATUS_FAIL otherwise +** +*******************************************************************************/ + +bt_status_t btif_storage_add_ble_bonding_key(bt_bdaddr_t *remote_bd_addr, + char *key, + UINT8 key_type, + UINT8 key_length) +{ + bdstr_t bdstr; + bd2str(remote_bd_addr, &bdstr); + const char* name; + switch(key_type) + { + case BTIF_DM_LE_KEY_PENC: + name = "LE_KEY_PENC"; + break; + case BTIF_DM_LE_KEY_PID: + name = "LE_KEY_PID"; + break; + case BTIF_DM_LE_KEY_PCSRK: + name = "LE_KEY_PCSRK"; + break; + case BTIF_DM_LE_KEY_LENC: + name = "LE_KEY_LENC"; + break; + case BTIF_DM_LE_KEY_LCSRK: + name = "LE_KEY_LCSRK"; + break; + default: + return BT_STATUS_FAIL; + } + int ret = btif_config_set("Remote", bdstr, name, (const char*)key, (int)key_length, BTIF_CFG_TYPE_BIN); + btif_config_save(); + return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; +} + +/******************************************************************************* +** +** Function btif_storage_get_ble_bonding_key +** +** Description +** +** Returns BT_STATUS_SUCCESS if the fetch was successful, +** BT_STATUS_FAIL otherwise +** +*******************************************************************************/ +bt_status_t btif_storage_get_ble_bonding_key(bt_bdaddr_t *remote_bd_addr, + UINT8 key_type, + char *key_value, + int key_length) +{ + bdstr_t bdstr; + bd2str(remote_bd_addr, &bdstr); + const char* name; + int type = BTIF_CFG_TYPE_BIN; + switch(key_type) + { + case BTIF_DM_LE_KEY_PENC: + name = "LE_KEY_PENC"; + break; + case BTIF_DM_LE_KEY_PID: + name = "LE_KEY_PID"; + break; + case BTIF_DM_LE_KEY_PCSRK: + name = "LE_KEY_PCSRK"; + break; + case BTIF_DM_LE_KEY_LENC: + name = "LE_KEY_LENC"; + break; + case BTIF_DM_LE_KEY_LCSRK: + name = "LE_KEY_LCSRK"; + break; + default: + return BT_STATUS_FAIL; + } + int ret = btif_config_get("Remote", bdstr, name, key_value, &key_length, &type); + return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; + +} + +/******************************************************************************* +** +** Function btif_storage_remove_ble_keys +** +** Description BTIF storage API - Deletes the bonded device from NVRAM +** +** Returns BT_STATUS_SUCCESS if the deletion was successful, +** BT_STATUS_FAIL otherwise +** +*******************************************************************************/ +bt_status_t btif_storage_remove_ble_bonding_keys(bt_bdaddr_t *remote_bd_addr) +{ + bdstr_t bdstr; + bd2str(remote_bd_addr, &bdstr); + BTIF_TRACE_DEBUG2(" %s in bd addr:%s",__FUNCTION__, bdstr); + int ret = 1; + if(btif_config_exist("Remote", bdstr, "LE_KEY_PENC")) + ret &= btif_config_remove("Remote", bdstr, "LE_KEY_PENC"); + if(btif_config_exist("Remote", bdstr, "LE_KEY_PID")) + ret &= btif_config_remove("Remote", bdstr, "LE_KEY_PID"); + if(btif_config_exist("Remote", bdstr, "LE_KEY_PCSRK")) + ret &= btif_config_remove("Remote", bdstr, "LE_KEY_PCSRK"); + if(btif_config_exist("Remote", bdstr, "LE_KEY_LENC")) + ret &= btif_config_remove("Remote", bdstr, "LE_KEY_LENC"); + if(btif_config_exist("Remote", bdstr, "LE_KEY_LCSRK")) + ret &= btif_config_remove("Remote", bdstr, "LE_KEY_LCSRK"); + btif_config_save(); + return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; +} + +/******************************************************************************* +** +** Function btif_storage_add_ble_local_key +** +** Description BTIF storage API - Adds the ble key to NVRAM +** +** Returns BT_STATUS_SUCCESS if the store was successful, +** BT_STATUS_FAIL otherwise +** +*******************************************************************************/ +bt_status_t btif_storage_add_ble_local_key(char *key, + uint8_t key_type, + uint8_t key_length) +{ + const char* name; + switch(key_type) + { + case BTIF_DM_LE_LOCAL_KEY_IR: + name = "LE_LOCAL_KEY_IR"; + break; + case BTIF_DM_LE_LOCAL_KEY_IRK: + name = "LE_LOCAL_KEY_IRK"; + break; + case BTIF_DM_LE_LOCAL_KEY_DHK: + name = "LE_LOCAL_KEY_DHK"; + break; + case BTIF_DM_LE_LOCAL_KEY_ER: + name = "LE_LOCAL_KEY_ER"; + break; + default: + return BT_STATUS_FAIL; + } + int ret = btif_config_set("Local", "Adapter", name, (const char*)key, key_length, BTIF_CFG_TYPE_BIN); + btif_config_save(); + return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; +} + +/******************************************************************************* +** +** Function btif_storage_get_ble_local_key +** +** Description +** +** Returns BT_STATUS_SUCCESS if the fetch was successful, +** BT_STATUS_FAIL otherwise +** +*******************************************************************************/ +bt_status_t btif_storage_get_ble_local_key(UINT8 key_type, + char *key_value, + int key_length) +{ + const char* name; + int type = BTIF_CFG_TYPE_BIN; + switch(key_type) + { + case BTIF_DM_LE_LOCAL_KEY_IR: + name = "LE_LOCAL_KEY_IR"; + break; + case BTIF_DM_LE_LOCAL_KEY_IRK: + name = "LE_LOCAL_KEY_IRK"; + break; + case BTIF_DM_LE_LOCAL_KEY_DHK: + name = "LE_LOCAL_KEY_DHK"; + break; + case BTIF_DM_LE_LOCAL_KEY_ER: + name = "LE_LOCAL_KEY_ER"; + break; + default: + return BT_STATUS_FAIL; + } + int ret = btif_config_get("Local", "Adapter", name, key_value, &key_length, &type); + return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; + +} + +/******************************************************************************* +** +** Function btif_storage_remove_ble_local_keys +** +** Description BTIF storage API - Deletes the bonded device from NVRAM +** +** Returns BT_STATUS_SUCCESS if the deletion was successful, +** BT_STATUS_FAIL otherwise +** +*******************************************************************************/ +bt_status_t btif_storage_remove_ble_local_keys(void) +{ + int ret = 1; + if(btif_config_exist("Local", "Adapter", "LE_LOCAL_KEY_IR")) + ret &= btif_config_remove("Local", "Adapter", "LE_LOCAL_KEY_IR"); + if(btif_config_exist("Local", "Adapter", "LE_LOCAL_KEY_IRK")) + ret &= btif_config_remove("Local", "Adapter", "LE_LOCAL_KEY_IRK"); + if(btif_config_exist("Local", "Adapter", "LE_LOCAL_KEY_DHK")) + ret &= btif_config_remove("Local", "Adapter", "LE_LOCAL_KEY_DHK"); + if(btif_config_exist("Local", "Adapter", "LE_LOCAL_KEY_ER")) + ret &= btif_config_remove("Local", "Adapter", "LE_LOCAL_KEY_ER"); + btif_config_save(); + return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; +} + +bt_status_t btif_in_fetch_bonded_ble_device(char *remote_bd_addr,int add, btif_bonded_devices_t *p_bonded_devices) +{ + int device_type; + int addr_type; + char buf[100]; + UINT32 i; + bt_bdaddr_t bd_addr; + BD_ADDR bta_bd_addr; + BOOLEAN is_device_added =FALSE; + tBTA_LE_KEY_VALUE *p; + + if(!btif_config_get_int("Remote", remote_bd_addr,"DevType", &device_type)) + return BT_STATUS_FAIL; + if(device_type == BT_DEVICE_TYPE_BLE) + { + BTIF_TRACE_DEBUG2("%s %s found a BLE device", __FUNCTION__,remote_bd_addr); + str2bd(remote_bd_addr, &bd_addr); + bdcpy(bta_bd_addr, bd_addr.address); + if (btif_storage_get_remote_addr_type(&bd_addr, &addr_type) != BT_STATUS_SUCCESS) + { + return BT_STATUS_FAIL; + } + + memset(buf, 0, sizeof(buf)); + if (btif_storage_get_ble_bonding_key(&bd_addr, + BTIF_DM_LE_KEY_PENC, + buf, + sizeof(btif_dm_ble_penc_keys_t)) == BT_STATUS_SUCCESS) + { + if(add) + { + if (!is_device_added) + { + BTA_DmAddBleDevice(bta_bd_addr, addr_type, BT_DEVICE_TYPE_BLE); + is_device_added = TRUE; + } + p = (tBTA_LE_KEY_VALUE *)buf; + for (i=0; i<16; i++) + { + BTIF_TRACE_DEBUG2("penc_key.ltk[%d]=0x%02x",i,p->penc_key.ltk[i]); + } + for (i=0; i<8; i++) + { + BTIF_TRACE_DEBUG2("penc_key.rand[%d]=0x%02x",i,p->penc_key.rand[i]); + } + BTIF_TRACE_DEBUG1("p->penc_key.ediv=0x%04x",p->penc_key.ediv); + BTIF_TRACE_DEBUG1("p->penc_key.sec_level=0x%02x",p->penc_key.sec_level); + BTIF_TRACE_DEBUG1("p->penc_key.key_size=0x%02x",p->penc_key.key_size); + BTA_DmAddBleKey (bta_bd_addr, (tBTA_LE_KEY_VALUE *)buf, BTIF_DM_LE_KEY_PENC); + } + } + + memset(buf, 0, sizeof(buf)); + if (btif_storage_get_ble_bonding_key(&bd_addr, + BTIF_DM_LE_KEY_PID, + buf, + sizeof(btif_dm_ble_pcsrk_keys_t)) == BT_STATUS_SUCCESS) + { + if(add) + { + if (!is_device_added) + { + BTA_DmAddBleDevice(bta_bd_addr, addr_type, BT_DEVICE_TYPE_BLE); + is_device_added = TRUE; + } + p = (tBTA_LE_KEY_VALUE *)buf; + for (i=0; i<16; i++) + { + BTIF_TRACE_DEBUG2("p->pid_key[%d]=0x%02x",i,p->pid_key.irk[i]); + } + + BTA_DmAddBleKey (bta_bd_addr, (tBTA_LE_KEY_VALUE *)buf, BTIF_DM_LE_KEY_PID); + } + } + + memset(buf, 0, sizeof(buf)); + if (btif_storage_get_ble_bonding_key(&bd_addr, + BTIF_DM_LE_KEY_PCSRK, + buf, + sizeof(btif_dm_ble_pcsrk_keys_t)) == BT_STATUS_SUCCESS) + { + if(add) + { + if (!is_device_added) + { + BTA_DmAddBleDevice(bta_bd_addr, addr_type, BT_DEVICE_TYPE_BLE); + is_device_added = TRUE; + } + + p = (tBTA_LE_KEY_VALUE *)buf; + for (i=0; i<16; i++) + { + BTIF_TRACE_DEBUG2("p->pcsrk_key.csrk[%d]=0x%02x",i, p->psrk_key.csrk[i]); + } + BTIF_TRACE_DEBUG1("p->pcsrk_key.counter=0x%08x",p->psrk_key.counter); + BTIF_TRACE_DEBUG1("p->pcsrk_key.sec_level=0x%02x",p->psrk_key.sec_level); + + BTA_DmAddBleKey (bta_bd_addr, (tBTA_LE_KEY_VALUE *)buf, BTIF_DM_LE_KEY_PCSRK); + } + } + + memset(buf, 0, sizeof(buf)); + if (btif_storage_get_ble_bonding_key(&bd_addr, + BTIF_DM_LE_KEY_LENC, + buf, + sizeof(btif_dm_ble_lenc_keys_t)) == BT_STATUS_SUCCESS) + { + if(add) + { + if (!is_device_added) + { + BTA_DmAddBleDevice(bta_bd_addr, addr_type, BT_DEVICE_TYPE_BLE); + is_device_added = TRUE; + } + p = (tBTA_LE_KEY_VALUE *)buf; + BTIF_TRACE_DEBUG1("p->lenc_key.div=0x%04x",p->lenc_key.div); + BTIF_TRACE_DEBUG1("p->lenc_key.key_size=0x%02x",p->lenc_key.key_size); + BTIF_TRACE_DEBUG1("p->lenc_key.sec_level=0x%02x",p->lenc_key.sec_level); + + BTA_DmAddBleKey (bta_bd_addr, (tBTA_LE_KEY_VALUE *)buf, BTIF_DM_LE_KEY_LENC); + } + } + + memset(buf, 0, sizeof(buf)); + if (btif_storage_get_ble_bonding_key(&bd_addr, + BTIF_DM_LE_KEY_LCSRK, + buf, + sizeof(btif_dm_ble_lcsrk_keys_t)) == BT_STATUS_SUCCESS) + { + if(add) + { + if (!is_device_added) + { + BTA_DmAddBleDevice(bta_bd_addr, addr_type, BT_DEVICE_TYPE_BLE); + is_device_added = TRUE; + } + p = (tBTA_LE_KEY_VALUE *)buf; + BTIF_TRACE_DEBUG1("p->lcsrk_key.div=0x%04x",p->lcsrk_key.div); + BTIF_TRACE_DEBUG1("p->lcsrk_key.counter=0x%08x",p->lcsrk_key.counter); + BTIF_TRACE_DEBUG1("p->lcsrk_key.sec_level=0x%02x",p->lcsrk_key.sec_level); + + BTA_DmAddBleKey (bta_bd_addr, (tBTA_LE_KEY_VALUE *)buf, BTIF_DM_LE_KEY_LCSRK); + } + } + + /* Fill in the bonded devices */ + if (is_device_added) + { + memcpy(&p_bonded_devices->devices[p_bonded_devices->num_devices++], &bd_addr, sizeof(bt_bdaddr_t)); + btif_gatts_add_bonded_dev_from_nv(bta_bd_addr); + } + + return BT_STATUS_SUCCESS; + } + return BT_STATUS_FAIL; +} + +bt_status_t btif_storage_set_remote_addr_type(bt_bdaddr_t *remote_bd_addr, + UINT8 addr_type) +{ + bdstr_t bdstr; + bd2str(remote_bd_addr, &bdstr); + int ret = btif_config_set_int("Remote", bdstr, "AddrType", (int)addr_type); + btif_config_save(); + return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; +} + +/******************************************************************************* +** +** Function btif_storage_get_remote_addr_type +** +** Description BTIF storage API - Fetches the remote addr type +** +** Returns BT_STATUS_SUCCESS if the fetch was successful, +** BT_STATUS_FAIL otherwise +** +*******************************************************************************/ +bt_status_t btif_storage_get_remote_addr_type(bt_bdaddr_t *remote_bd_addr, + int*addr_type) +{ + bdstr_t bdstr; + bd2str(remote_bd_addr, &bdstr); + int ret = btif_config_get_int("Remote", bdstr, "AddrType", addr_type); + return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; +} +#endif /******************************************************************************* ** ** Function btif_storage_add_hid_device_info @@ -1273,7 +1763,7 @@ bt_status_t btif_storage_load_autopair_device_list() ** FALSE otherwise ** *******************************************************************************/ -BOOLEAN btif_storage_is_device_autopair_blacklisted(bt_bdaddr_t *remote_dev_addr) +BOOLEAN btif_storage_is_device_autopair_blacklisted(bt_bdaddr_t *remote_bd_addr) { char *token; int ret; @@ -1283,7 +1773,7 @@ BOOLEAN btif_storage_is_device_autopair_blacklisted(bt_bdaddr_t *remote_dev_add char value[BTIF_STORAGE_MAX_LINE_SZ]; int value_size = sizeof(value); - bd2str(remote_dev_addr, &bdstr); + bd2str(remote_bd_addr, &bdstr); /* Consider only Lower Address Part from BD Address */ bdstr[8] = '\0'; @@ -1295,7 +1785,7 @@ BOOLEAN btif_storage_is_device_autopair_blacklisted(bt_bdaddr_t *remote_dev_add return TRUE; } - dev_name_str = BTM_SecReadDevName((remote_dev_addr->address)); + dev_name_str = BTM_SecReadDevName((remote_bd_addr->address)); if (dev_name_str != NULL) { @@ -1339,14 +1829,14 @@ BOOLEAN btif_storage_is_device_autopair_blacklisted(bt_bdaddr_t *remote_dev_add ** BT_STATUS_FAIL otherwise ** *******************************************************************************/ -bt_status_t btif_storage_add_device_to_autopair_blacklist(bt_bdaddr_t *remote_dev_addr) +bt_status_t btif_storage_add_device_to_autopair_blacklist(bt_bdaddr_t *remote_bd_addr) { int ret; bdstr_t bdstr; char linebuf[BTIF_STORAGE_MAX_LINE_SZ+20]; char input_value [20]; - bd2str(remote_dev_addr, &bdstr); + bd2str(remote_bd_addr, &bdstr); strncpy(input_value, (char*)bdstr, 20); strncat(input_value,BTIF_AUTO_PAIR_CONF_VALUE_SEPARATOR, 20); int line_size = sizeof(linebuf); @@ -1378,7 +1868,7 @@ bt_status_t btif_storage_add_device_to_autopair_blacklist(bt_bdaddr_t *remote_de ** FALSE otherwise ** *******************************************************************************/ -BOOLEAN btif_storage_is_fixed_pin_zeros_keyboard(bt_bdaddr_t *remote_dev_addr) +BOOLEAN btif_storage_is_fixed_pin_zeros_keyboard(bt_bdaddr_t *remote_bd_addr) { int ret; bdstr_t bdstr; @@ -1386,7 +1876,7 @@ BOOLEAN btif_storage_is_fixed_pin_zeros_keyboard(bt_bdaddr_t *remote_dev_addr) uint8_t i = 0; char linebuf[BTIF_STORAGE_MAX_LINE_SZ]; - bd2str(remote_dev_addr, &bdstr); + bd2str(remote_bd_addr, &bdstr); /*consider on LAP part of BDA string*/ bdstr[8] = '\0'; diff --git a/btif/src/btif_util.c b/btif/src/btif_util.c index 5539c1132..0096effe9 100644 --- a/btif/src/btif_util.c +++ b/btif/src/btif_util.c @@ -89,7 +89,7 @@ int str2bd(char *str, bt_bdaddr_t *addr) return 0; } -char *bd2str(bt_bdaddr_t *bdaddr, bdstr_t *bdstr) +char *bd2str(const bt_bdaddr_t *bdaddr, bdstr_t *bdstr) { char *addr = (char *) bdaddr->address; @@ -103,9 +103,11 @@ UINT32 devclass2uint(DEV_CLASS dev_class) { UINT32 cod = 0; - /* if COD is 0, irrespective of the device type set it to Unclassified device */ - cod = (dev_class[2]) | (dev_class[1] << 8) | (dev_class[0] << 16); - + if(dev_class != NULL) + { + /* if COD is 0, irrespective of the device type set it to Unclassified device */ + cod = (dev_class[2]) | (dev_class[1] << 8) | (dev_class[0] << 16); + } return cod; } void uint2devclass(UINT32 cod, DEV_CLASS dev_class) @@ -459,4 +461,3 @@ const char* dump_bt_status(bt_status_t status) } - diff --git a/conf/bt_stack.conf b/conf/bt_stack.conf index 2cd2f62f4..2ca20ea89 100644 --- a/conf/bt_stack.conf +++ b/conf/bt_stack.conf @@ -16,6 +16,7 @@ TraceConf=true # BT_TRACE_LEVEL_API 3 ( API traces ) # BT_TRACE_LEVEL_EVENT 4 ( Debug messages for events ) # BT_TRACE_LEVEL_DEBUG 5 ( Full debug messages ) +# BT_TRACE_LEVEL_VERBOSE 6 ( Verbose messages ) - Currently supported for TRC_BTAPP only. TRC_BTM=2 TRC_HCI=2 TRC_L2CAP=2 diff --git a/gki/common/gki_buffer.c b/gki/common/gki_buffer.c index f474bab6b..bcf6f06b3 100644 --- a/gki/common/gki_buffer.c +++ b/gki/common/gki_buffer.c @@ -434,6 +434,7 @@ void *GKI_getbuf (UINT16 size) GKI_enable(); + GKI_exception (GKI_ERROR_OUT_OF_BUFFERS, "getbuf: out of buffers"); return (NULL); } @@ -460,7 +461,10 @@ void *GKI_getpoolbuf (UINT8 pool_id) tGKI_COM_CB *p_cb = &gki_cb.com; if (pool_id >= GKI_NUM_TOTAL_BUF_POOLS) + { + GKI_exception(GKI_ERROR_GETPOOLBUF_BAD_QID, "getpoolbuf bad pool"); return (NULL); + } /* Make sure the buffers aren't disturbed til finished with allocation */ GKI_disable(); diff --git a/gki/common/gki_common.h b/gki/common/gki_common.h index 9bc5005b3..ff5a67573 100644 --- a/gki/common/gki_common.h +++ b/gki/common/gki_common.h @@ -43,6 +43,8 @@ #define GKI_ERROR_BUF_SIZE_TOOBIG 0xFFF7 #define GKI_ERROR_BUF_SIZE_ZERO 0xFFF6 #define GKI_ERROR_ADDR_NOT_IN_BUF 0xFFF5 +#define GKI_ERROR_OUT_OF_BUFFERS 0xFFF4 +#define GKI_ERROR_GETPOOLBUF_BAD_QID 0xFFF3 /******************************************************************** diff --git a/hci/src/userial.c b/hci/src/userial.c index afd301065..d87bea1bf 100644 --- a/hci/src/userial.c +++ b/hci/src/userial.c @@ -52,6 +52,10 @@ #define USERIALDBG(param, ...) {} #endif +#ifndef ENABLE_USERIAL_TIMING_LOGS +#define ENABLE_USERIAL_TIMING_LOGS FALSE +#endif + #define MAX_SERIAL_PORT (USERIAL_PORT_3 + 1) #define READ_LIMIT (BTHC_USERIAL_READ_MEM_SIZE - BT_HC_HDR_SIZE) @@ -91,6 +95,29 @@ static volatile uint8_t userial_running = 0; ** Static functions ******************************************************************************/ +#if defined(ENABLE_USERIAL_TIMING_LOGS) && (ENABLE_USERIAL_TIMING_LOGS==TRUE) + +static void log_userial_tx_timing(int len) +{ + #define USEC_PER_SEC 1000000L + static struct timespec prev = {0, 0}; + struct timespec now, diff; + unsigned int diff_us = 0; + unsigned int now_us = 0; + + clock_gettime(CLOCK_MONOTONIC, &now); + now_us = now.tv_sec*USEC_PER_SEC + now.tv_nsec/1000; + diff_us = (now.tv_sec - prev.tv_sec) * USEC_PER_SEC + (now.tv_nsec - prev.tv_nsec)/1000; + + ALOGW("[userial] ts %08d diff : %08d len %d", now_us, diff_us, + len); + + prev = now; +} + +#endif + + /***************************************************************************** ** Socket signal functions to wake up userial_read_thread for termination ** @@ -125,6 +152,7 @@ static inline int is_signaled(fd_set* set) return FD_ISSET(signal_fds[0], set); } + /******************************************************************************* ** ** Function select_read @@ -454,6 +482,9 @@ uint16_t userial_write(uint16_t msg_id, uint8_t *p_data, uint16_t len) while(len != 0) { +#if defined(ENABLE_USERIAL_TIMING_LOGS) && (ENABLE_USERIAL_TIMING_LOGS==TRUE) + log_userial_tx_timing(len); +#endif ret = write(userial_cb.fd, p_data+total, len); total += ret; len -= ret; diff --git a/include/bt_target.h b/include/bt_target.h index 836868e8b..98968f54f 100755..100644 --- a/include/bt_target.h +++ b/include/bt_target.h @@ -260,7 +260,7 @@ #endif #ifndef BTA_GATT_INCLUDED -#define BTA_GATT_INCLUDED FALSE +#define BTA_GATT_INCLUDED TRUE #endif #ifndef BTA_DISABLE_DELAY @@ -555,11 +555,6 @@ #define BTM_CMD_POOL_ID GKI_POOL_ID_2 #endif -/* Sends TCS messages. */ -#ifndef TCS_MSG_POOL_ID -#define TCS_MSG_POOL_ID GKI_POOL_ID_2 -#endif - #ifndef OBX_CMD_POOL_SIZE #define OBX_CMD_POOL_SIZE GKI_BUF2_SIZE #endif @@ -577,11 +572,6 @@ #define CTP_SDP_DB_POOL_ID GKI_POOL_ID_3 #endif -/* Used for CTP data exchange feature. */ -#ifndef CTP_DATA_EXCHG_POOL_ID -#define CTP_DATA_EXCHG_POOL_ID GKI_POOL_ID_2 -#endif - /* Used to send data to L2CAP. */ #ifndef GAP_DATA_POOL_ID #define GAP_DATA_POOL_ID GKI_POOL_ID_3 @@ -596,24 +586,6 @@ #define SPP_DB_SIZE GKI_BUF3_SIZE #endif -/* HCRP protocol and internal commands. */ -#ifndef HCRP_CMD_POOL_ID -#define HCRP_CMD_POOL_ID GKI_POOL_ID_2 -#endif - -#ifndef HCRP_CMD_POOL_SIZE -#define HCRP_CMD_POOL_SIZE GKI_BUF2_SIZE -#endif - -#ifndef BIP_EVT_POOL_SIZE -#define BIP_EVT_POOL_SIZE GKI_BUF3_SIZE -#endif - -#ifndef BIP_DB_SIZE -#define BIP_DB_SIZE GKI_BUF3_SIZE -#endif - - /* BNEP data and protocol messages. */ #ifndef BNEP_POOL_ID #define BNEP_POOL_ID GKI_POOL_ID_3 @@ -1245,7 +1217,7 @@ and USER_HW_DISABLE_API macros */ /* The maximum number of simultaneous channels that L2CAP can support. */ #ifndef MAX_L2CAP_CHANNELS -#define MAX_L2CAP_CHANNELS 10 +#define MAX_L2CAP_CHANNELS 16 #endif /* The maximum number of simultaneous applications that can register with L2CAP. */ @@ -1417,8 +1389,8 @@ and USER_HW_DISABLE_API macros */ ** ******************************************************************************/ -#ifndef BLE_INCLUDED -#define BLE_INCLUDED FALSE +#ifndef _cac +#define BLE_INCLUDED TRUE #endif #ifndef LOCAL_BLE_CONTROLLER_ID @@ -1431,19 +1403,19 @@ and USER_HW_DISABLE_API macros */ ** ******************************************************************************/ #ifndef ATT_INCLUDED -#define ATT_INCLUDED FALSE +#define ATT_INCLUDED TRUE #endif #ifndef ATT_DEBUG -#define ATT_DEBUG FALSE +#define ATT_DEBUG TRUE #endif #ifndef GATT_SERVER_ENABLED -#define GATT_SERVER_ENABLED FALSE +#define GATT_SERVER_ENABLED TRUE #endif #ifndef GATT_CLIENT_ENABLED -#define GATT_CLIENT_ENABLED FALSE +#define GATT_CLIENT_ENABLED TRUE #endif #ifndef GATT_MAX_SR_PROFILES @@ -1479,11 +1451,11 @@ and USER_HW_DISABLE_API macros */ ** ******************************************************************************/ #ifndef SMP_INCLUDED -#define SMP_INCLUDED FALSE +#define SMP_INCLUDED TRUE #endif #ifndef SMP_DEBUG -#define SMP_DEBUG FALSE +#define SMP_DEBUG TRUE #endif #ifndef SMP_DEFAULT_AUTH_REQ @@ -2189,7 +2161,7 @@ Range: Minimum 12000 (12 secs) on BR/EDR when supporting PBF. ******************************************************************************/ #ifndef GAP_INCLUDED -#define GAP_INCLUDED FALSE +#define GAP_INCLUDED TRUE #endif /* This is set to enable use of GAP L2CAP connections. */ @@ -3749,9 +3721,6 @@ The maximum number of payload octets that the local device can receive in a sing #define L2CAP_FEATURE_RSP_ID 173 -#define L2CAP_ENHANCED_FEATURES 0 - - /****************************************************************************** ** ** BTA diff --git a/include/bt_trace.h b/include/bt_trace.h index 6c3e7b12a..e6a0b71fc 100644 --- a/include/bt_trace.h +++ b/include/bt_trace.h @@ -4668,6 +4668,28 @@ extern UINT8 btif_trace_level; (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5));} #define APPL_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) {if (appl_trace_level >= BT_TRACE_LEVEL_DEBUG) LogMsg_6(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, \ (m), (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5), (UINT32)(p6));} + +#define APPL_TRACE_VERBOSE0(m) {if (appl_trace_level >= BT_TRACE_LEVEL_VERBOSE)\ + LogMsg_0(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, (m));} +#define APPL_TRACE_VERBOSE1(m,p1) {if (appl_trace_level >= BT_TRACE_LEVEL_VERBOSE)\ + LogMsg_1(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, (m), \ + (UINT32)(p1));} +#define APPL_TRACE_VERBOSE2(m,p1,p2) {if (appl_trace_level >= BT_TRACE_LEVEL_VERBOSE)\ + LogMsg_2(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, (m), \ + (UINT32)(p1), (UINT32)(p2));} +#define APPL_TRACE_VERBOSE3(m,p1,p2,p3) {if (appl_trace_level >= BT_TRACE_LEVEL_VERBOSE)\ + LogMsg_3(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, (m), \ + (UINT32)(p1), (UINT32)(p2), (UINT32)(p3));} +#define APPL_TRACE_VERBOSE4(m,p1,p2,p3,p4) {if (appl_trace_level >= BT_TRACE_LEVEL_VERBOSE)\ + LogMsg_4(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, (m), \ + (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4));} +#define APPL_TRACE_VERBOSE5(m,p1,p2,p3,p4,p5) {if (appl_trace_level >= BT_TRACE_LEVEL_VERBOSE)\ + LogMsg_5(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, (m), \ + (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5));} +#define APPL_TRACE_VERBOSE6(m,p1,p2,p3,p4,p5,p6) {if (appl_trace_level >= BT_TRACE_LEVEL_VERBOSE)\ + LogMsg_6(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | TRACE_TYPE_DEBUG, (m), \ + (UINT32)(p1), (UINT32)(p2), (UINT32)(p3), (UINT32)(p4), (UINT32)(p5), (UINT32)(p6));} + #else /* define traces for Application */ @@ -4711,6 +4733,14 @@ extern UINT8 btif_trace_level; #define APPL_TRACE_DEBUG5(m,p1,p2,p3,p4,p5) #define APPL_TRACE_DEBUG6(m,p1,p2,p3,p4,p5,p6) +#define APPL_TRACE_VERBOSE0(m) +#define APPL_TRACE_VERBOSE1(m,p1) +#define APPL_TRACE_VERBOSE2(m,p1,p2) +#define APPL_TRACE_VERBOSE3(m,p1,p2,p3) +#define APPL_TRACE_VERBOSE4(m,p1,p2,p3,p4) +#define APPL_TRACE_VERBOSE5(m,p1,p2,p3,p4,p5) +#define APPL_TRACE_VERBOSE6(m,p1,p2,p3,p4,p5,p6) + #endif #if ((MMI_INCLUDED == TRUE) && (!defined(HID_MSKB_INCLUDED) || (HID_MSKB_INCLUDED == FALSE))) diff --git a/include/bte.h b/include/bte.h index 103b6604e..968b68a40 100644 --- a/include/bte.h +++ b/include/bte.h @@ -100,9 +100,12 @@ extern int (*p_bte_hci_send)(UINT16 port, BT_HDR *p_msg); /* Protocol trace mask */ extern UINT32 bte_proto_trace_mask; -/* Version string */ +/* BTE version string */ extern const UINT8 bte_version_string[]; +/* BTIF version string */ +extern const UINT8 btif_version_string[]; + typedef struct tBAUD_REG_tag { UINT8 DHBR; UINT8 DLBR; diff --git a/include/bte_appl.h b/include/bte_appl.h index 63689daa6..cf0baed24 100644 --- a/include/bte_appl.h +++ b/include/bte_appl.h @@ -70,25 +70,12 @@ #define BTE_APPL_CONTACTS_DB_PATH 256 typedef struct { - char patchram_path[BTE_APPL_PATCHRAM_PATH_MAXLEN+1]; - UINT32 patchram_addr; - UINT32 reconfig_baud; - UINT32 clock_rate; /* clock rate (for uart baud calculation) */ - BD_ADDR local_addr; /* local bd addr */ - BD_ADDR rem_addr; - UINT8 lpm_enabled; - UINT8 bt_wake_polarity; - UINT8 host_wake_polarity; - BOOLEAN ag_enable_3way_conf; - UINT16 ag_voice_settings; - UINT8 ag_vsc_pcm_config[5]; - UINT8 ag_vsc_sco_pcm[5]; - /*tBTM_CMPL_CB*/ tBTM_DEV_STATUS_CB *p_reset_cplt_cb; /* Current reset_cplt_cb */ - char contacts_db[BTE_APPL_CONTACTS_DB_PATH+1]; - UINT32 bta_module_state[BTAPP_NUM_ID_BLOCKS]; /* state of enabled bta modules */ -#if (BTAPP_AHF_API_SUPPORT==TRUE) - UINT8 afh_first; - UINT8 afh_last; +#if ((BLE_INCLUDED == TRUE) && (SMP_INCLUDED == TRUE)) + UINT8 ble_auth_req; + UINT8 ble_io_cap; + UINT8 ble_init_key; + UINT8 ble_resp_key; + UINT8 ble_max_key_size; #endif } tBTE_APPL_CFG; diff --git a/main/Android.mk b/main/Android.mk index 8ecb3c3dc..3e311d4ac 100644 --- a/main/Android.mk +++ b/main/Android.mk @@ -37,6 +37,11 @@ LOCAL_SRC_FILES += \ ../btif/src/btif_sock_sdp.c \ ../btif/src/btif_sock_util.c \ ../btif/src/btif_pan.c \ + ../btif/src/btif_gatt.c \ + ../btif/src/btif_gatt_client.c \ + ../btif/src/btif_gatt_server.c \ + ../btif/src/btif_gatt_util.c \ + ../btif/src/btif_gatt_test.c \ ../btif/src/btif_config.c \ ../btif/src/btif_config_util.cpp \ ../btif/src/btif_profile_queue.c @@ -50,7 +55,9 @@ LOCAL_SRC_FILES+= \ ../btif/co/bta_av_co.c \ ../btif/co/bta_hh_co.c \ ../btif/co/bta_hl_co.c \ - ../btif/co/bta_pan_co.c + ../btif/co/bta_pan_co.c \ + ../btif/co/bta_gattc_co.c \ + ../btif/co/bta_gatts_co.c \ # sbc encoder LOCAL_SRC_FILES+= \ diff --git a/main/bte_logmsg.c b/main/bte_logmsg.c index 7035a578f..6c9a5eb4f 100644 --- a/main/bte_logmsg.c +++ b/main/bte_logmsg.c @@ -91,6 +91,7 @@ #if (BLE_INCLUDED==TRUE) #include "gatt_api.h" +#include "smp_api.h" #endif /* LayerIDs for BTA, currently everything maps onto appl_trace_level */ @@ -282,7 +283,6 @@ ScrLog(UINT32 trace_set_mask, const char *fmt_str, ...) int trace_layer = TRACE_GET_LAYER(trace_set_mask); if (trace_layer >= TRACE_LAYER_MAX_NUM) trace_layer = 0; - gettimeofday(&tv, &tz); time(&t); tm = localtime(&t); @@ -467,8 +467,6 @@ tBTTRC_FUNC_MAP bttrc_set_level_map[] = { {BTTRC_ID_STK_SDP, BTTRC_ID_STK_SDP, SDP_SetTraceLevel, "TRC_SDP", DEFAULT_CONF_TRACE_LEVEL}, #if (BLE_INCLUDED==TRUE) {BTTRC_ID_STK_GATT, BTTRC_ID_STK_GATT, GATT_SetTraceLevel, "TRC_GATT", DEFAULT_CONF_TRACE_LEVEL}, -#endif -#if (BLE_INCLUDED==TRUE) {BTTRC_ID_STK_SMP, BTTRC_ID_STK_SMP, SMP_SetTraceLevel, "TRC_SMP", DEFAULT_CONF_TRACE_LEVEL}, #endif diff --git a/main/bte_version.c b/main/bte_version.c index 0751e1d17..826f31b6b 100644 --- a/main/bte_version.c +++ b/main/bte_version.c @@ -18,5 +18,6 @@ #include "bt_types.h" -const UINT8 bte_version_string[] = "BCM1200_PI_10.3.20.33"; +const UINT8 bte_version_string[] = "BCM1200_PI_10.3.20.52"; +const UINT8 btif_version_string[] = "BDROID-PLUS-420-10_00.10"; diff --git a/stack/Android.mk b/stack/Android.mk index dcbe961b5..e17f4c820 100644 --- a/stack/Android.mk +++ b/stack/Android.mk @@ -80,6 +80,10 @@ LOCAL_SRC_FILES:= \ ./mcap/mca_csm.c \ ./mcap/mca_cact.c \ ./mcap/mca_api.c \ + ./gap/gap_ble.c \ + ./gap/gap_api.c \ + ./gap/gap_utils.c \ + ./gap/gap_conn.c \ ./gatt/gatt_sr.c \ ./gatt/gatt_cl.c \ ./gatt/gatt_api.c \ @@ -96,6 +100,7 @@ LOCAL_SRC_FILES:= \ ./avct/avct_lcb_act.c \ ./smp/smp_main.c \ ./smp/smp_l2c.c \ + ./smp/aes.c \ ./smp/smp_cmac.c \ ./smp/smp_utils.c \ ./smp/smp_act.c \ diff --git a/stack/avdt/avdt_api.c b/stack/avdt/avdt_api.c index 67fe4524c..855f17e4d 100644 --- a/stack/avdt/avdt_api.c +++ b/stack/avdt/avdt_api.c @@ -883,7 +883,7 @@ UINT16 AVDT_SecurityRsp(UINT8 handle, UINT8 label, UINT8 error_code, /******************************************************************************* ** -** Function AVDT_WriteReq +** Function AVDT_WriteReqOpt ** ** Description Send a media packet to the peer device. The stream must ** be started before this function is called. Also, this @@ -901,7 +901,8 @@ UINT16 AVDT_SecurityRsp(UINT8 handle, UINT8 label, UINT8 error_code, ** ** The application passes the packet using the BT_HDR structure. ** This structure is described in section 2.1. The offset -** field must be equal to or greater than AVDT_MEDIA_OFFSET. +** field must be equal to or greater than AVDT_MEDIA_OFFSET +** (if NO_RTP is specified, L2CAP_MIN_OFFSET can be used). ** This allows enough space in the buffer for the L2CAP and ** AVDTP headers. ** @@ -910,11 +911,13 @@ UINT16 AVDT_SecurityRsp(UINT8 handle, UINT8 label, UINT8 error_code, ** by the protocol stack; the application must not free ** this buffer. ** +** The opt parameter allows passing specific options like: +** - NO_RTP : do not add the RTP header to buffer ** ** Returns AVDT_SUCCESS if successful, otherwise error. ** *******************************************************************************/ -UINT16 AVDT_WriteReq(UINT8 handle, BT_HDR *p_pkt, UINT32 time_stamp, UINT8 m_pt) +UINT16 AVDT_WriteReqOpt(UINT8 handle, BT_HDR *p_pkt, UINT32 time_stamp, UINT8 m_pt, tAVDT_DATA_OPT_MASK opt) { tAVDT_SCB *p_scb; tAVDT_SCB_EVT evt; @@ -932,6 +935,7 @@ UINT16 AVDT_WriteReq(UINT8 handle, BT_HDR *p_pkt, UINT32 time_stamp, UINT8 m_pt) evt.apiwrite.p_buf = p_pkt; evt.apiwrite.time_stamp = time_stamp; evt.apiwrite.m_pt = m_pt; + evt.apiwrite.opt = opt; #if AVDT_MULTIPLEXING == TRUE GKI_init_q (&evt.apiwrite.frag_q); #endif @@ -943,6 +947,44 @@ UINT16 AVDT_WriteReq(UINT8 handle, BT_HDR *p_pkt, UINT32 time_stamp, UINT8 m_pt) /******************************************************************************* ** +** Function AVDT_WriteReq +** +** Description Send a media packet to the peer device. The stream must +** be started before this function is called. Also, this +** function can only be called if the stream is a SRC. +** +** When AVDTP has sent the media packet and is ready for the +** next packet, an AVDT_WRITE_CFM_EVT is sent to the +** application via the control callback. The application must +** wait for the AVDT_WRITE_CFM_EVT before it makes the next +** call to AVDT_WriteReq(). If the applications calls +** AVDT_WriteReq() before it receives the event the packet +** will not be sent. The application may make its first call +** to AVDT_WriteReq() after it receives an AVDT_START_CFM_EVT +** or AVDT_START_IND_EVT. +** +** The application passes the packet using the BT_HDR structure. +** This structure is described in section 2.1. The offset +** field must be equal to or greater than AVDT_MEDIA_OFFSET. +** This allows enough space in the buffer for the L2CAP and +** AVDTP headers. +** +** The memory pointed to by p_pkt must be a GKI buffer +** allocated by the application. This buffer will be freed +** by the protocol stack; the application must not free +** this buffer. +** +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +UINT16 AVDT_WriteReq(UINT8 handle, BT_HDR *p_pkt, UINT32 time_stamp, UINT8 m_pt) +{ + return AVDT_WriteReqOpt(handle, p_pkt, time_stamp, m_pt, AVDT_DATA_OPT_NONE); +} + +/******************************************************************************* +** ** Function AVDT_ConnectReq ** ** Description This function initiates an AVDTP signaling connection @@ -1248,7 +1290,7 @@ UINT16 AVDT_SendReport(UINT8 handle, AVDT_REPORT_TYPE type, tAVDT_TC_TBL *p_tbl; UINT8 *p, *plen, *pm1, *p_end; #if AVDT_MULTIPLEXING == TRUE - UINT8 *p_al, u; + UINT8 *p_al=NULL, u; #endif UINT32 ssrc; UINT16 len; diff --git a/stack/avdt/avdt_ccb_act.c b/stack/avdt/avdt_ccb_act.c index 5719be963..12c11b4cb 100644 --- a/stack/avdt/avdt_ccb_act.c +++ b/stack/avdt/avdt_ccb_act.c @@ -167,10 +167,10 @@ void avdt_ccb_hdl_discover_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) if (p_scb->allocated) { /* copy sep info */ - sep_info[i].in_use = p_scb->in_use; - sep_info[i].seid = i + 1; - sep_info[i].media_type = p_scb->cs.media_type; - sep_info[i].tsep = p_scb->cs.tsep; + sep_info[p_data->msg.discover_rsp.num_seps].in_use = p_scb->in_use; + sep_info[p_data->msg.discover_rsp.num_seps].seid = i + 1; + sep_info[p_data->msg.discover_rsp.num_seps].media_type = p_scb->cs.media_type; + sep_info[p_data->msg.discover_rsp.num_seps].tsep = p_scb->cs.tsep; p_data->msg.discover_rsp.num_seps++; } diff --git a/stack/avdt/avdt_int.h b/stack/avdt/avdt_int.h index 9b101fc70..04968a6d5 100644 --- a/stack/avdt/avdt_int.h +++ b/stack/avdt/avdt_int.h @@ -459,6 +459,7 @@ typedef struct { UINT32 data_len; #endif UINT8 m_pt; + tAVDT_DATA_OPT_MASK opt; } tAVDT_SCB_APIWRITE; /* type for AVDT_SCB_TC_CLOSE_EVT */ diff --git a/stack/avdt/avdt_scb_act.c b/stack/avdt/avdt_scb_act.c index c2ced7499..66f9b7d3c 100644 --- a/stack/avdt/avdt_scb_act.c +++ b/stack/avdt/avdt_scb_act.c @@ -1213,19 +1213,22 @@ void avdt_scb_hdl_write_req_no_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) } /* build a media packet */ + /* Add RTP header if required */ + if ( !(p_data->apiwrite.opt & AVDT_DATA_OPT_NO_RTP) ) + { + ssrc = avdt_scb_gen_ssrc(p_scb); - ssrc = avdt_scb_gen_ssrc(p_scb); - - p_data->apiwrite.p_buf->len += AVDT_MEDIA_HDR_SIZE; - p_data->apiwrite.p_buf->offset -= AVDT_MEDIA_HDR_SIZE; + p_data->apiwrite.p_buf->len += AVDT_MEDIA_HDR_SIZE; + p_data->apiwrite.p_buf->offset -= AVDT_MEDIA_HDR_SIZE; - p = (UINT8 *)(p_data->apiwrite.p_buf + 1) + p_data->apiwrite.p_buf->offset; + p = (UINT8 *)(p_data->apiwrite.p_buf + 1) + p_data->apiwrite.p_buf->offset; - UINT8_TO_BE_STREAM(p, AVDT_MEDIA_OCTET1); - UINT8_TO_BE_STREAM(p, p_data->apiwrite.m_pt); - UINT16_TO_BE_STREAM(p, p_scb->media_seq); - UINT32_TO_BE_STREAM(p, p_data->apiwrite.time_stamp); - UINT32_TO_BE_STREAM(p, ssrc); + UINT8_TO_BE_STREAM(p, AVDT_MEDIA_OCTET1); + UINT8_TO_BE_STREAM(p, p_data->apiwrite.m_pt); + UINT16_TO_BE_STREAM(p, p_scb->media_seq); + UINT32_TO_BE_STREAM(p, p_data->apiwrite.time_stamp); + UINT32_TO_BE_STREAM(p, ssrc); + } p_scb->media_seq++; diff --git a/stack/btm/btm_acl.c b/stack/btm/btm_acl.c index e3ac11bea..eb847bbc3 100644 --- a/stack/btm/btm_acl.c +++ b/stack/btm/btm_acl.c @@ -127,8 +127,6 @@ UINT8 btm_handle_to_acl_index (UINT16 hci_handle) /* If here, no BD Addr found */ return(xx); } - - /******************************************************************************* ** ** Function btm_acl_created @@ -142,7 +140,7 @@ UINT8 btm_handle_to_acl_index (UINT16 hci_handle) void btm_acl_created (BD_ADDR bda, DEV_CLASS dc, BD_NAME bdn, UINT16 hci_handle, UINT8 link_role, UINT8 is_le_link) { - tBTM_SEC_DEV_REC *p_dev_rec; + tBTM_SEC_DEV_REC *p_dev_rec = NULL; UINT8 yy; tACL_CONN *p; UINT8 xx; @@ -173,8 +171,16 @@ void btm_acl_created (BD_ADDR bda, DEV_CLASS dc, BD_NAME bdn, p->hci_handle = hci_handle; p->link_role = link_role; p->link_up_issued = FALSE; + #if BLE_INCLUDED == TRUE p->is_le_link = is_le_link; + + if (is_le_link) + { + p->conn_addr_type = BLE_ADDR_PUBLIC; + BTM_GetLocalDeviceAddr(p->conn_addr); + } + #endif p->restore_pkt_types = 0; /* Only exists while SCO is active */ p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE; @@ -193,8 +199,12 @@ void btm_acl_created (BD_ADDR bda, DEV_CLASS dc, BD_NAME bdn, if (bdn) memcpy (p->remote_name, bdn, BTM_MAX_REM_BD_NAME_LEN); - - /* Check if we already know features for this device */ + /* if BR/EDR do something more */ + if (!is_le_link) + { + btsnd_hcic_read_rmt_clk_offset (p->hci_handle); + btsnd_hcic_rmt_ver_req (p->hci_handle); + } p_dev_rec = btm_find_dev_by_handle (hci_handle); #if (BLE_INCLUDED == TRUE) @@ -204,18 +214,9 @@ void btm_acl_created (BD_ADDR bda, DEV_CLASS dc, BD_NAME bdn, } #endif - - if (p_dev_rec -#if (BLE_INCLUDED == TRUE) - && p_dev_rec->device_type != BT_DEVICE_TYPE_BLE -#endif - ) + if (p_dev_rec && !is_le_link) { - /* if BR/EDR do something more */ - btsnd_hcic_read_rmt_clk_offset (p->hci_handle); - btsnd_hcic_rmt_ver_req (p->hci_handle); - for (yy = 0; yy < BD_FEATURES_LEN; yy++) { if (p_dev_rec->features[yy]) @@ -238,17 +239,15 @@ void btm_acl_created (BD_ADDR bda, DEV_CLASS dc, BD_NAME bdn, } } } + #if (BLE_INCLUDED == TRUE) /* If here, features are not known yet */ - if (p_dev_rec && p_dev_rec->device_type == BT_DEVICE_TYPE_BLE) + if (p_dev_rec && is_le_link) { btm_establish_continue(p); if (link_role == HCI_ROLE_MASTER) { - btm_ble_update_bg_state(); - btm_ble_resume_bg_conn (NULL, FALSE); - btsnd_hcic_ble_read_remote_feat(p->hci_handle); } } @@ -282,10 +281,10 @@ void btm_acl_report_role_change (UINT8 hci_status, BD_ADDR bda) if (btm_cb.devcb.p_switch_role_cb && (bda && (0 == memcmp(btm_cb.devcb.switch_role_ref_data.remote_bd_addr, bda, BD_ADDR_LEN)))) { - memset (&btm_cb.devcb.switch_role_ref_data, 0, sizeof(tBTM_ROLE_SWITCH_CMPL)); - ref_data.hci_status = hci_status; memcpy (&ref_data, &btm_cb.devcb.switch_role_ref_data, sizeof(tBTM_ROLE_SWITCH_CMPL)); + ref_data.hci_status = hci_status; (*btm_cb.devcb.p_switch_role_cb)(&ref_data); + memset (&btm_cb.devcb.switch_role_ref_data, 0, sizeof(tBTM_ROLE_SWITCH_CMPL)); btm_cb.devcb.p_switch_role_cb = NULL; } } @@ -309,7 +308,6 @@ void btm_acl_removed (BD_ADDR bda) #endif #if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE) tBTM_SEC_DEV_REC *p_dev_rec=NULL; - UINT16 combined_mode; #endif BTM_TRACE_DEBUG0 ("btm_acl_removed"); @@ -351,23 +349,6 @@ void btm_acl_removed (BD_ADDR bda) btm_cb.ble_ctr_cb.inq_var.connectable_mode, p->link_role); - - /* If we are LE connectable, check if we need to start advertising again */ - if ( p->is_le_link && (btm_cb.ble_ctr_cb.inq_var.connectable_mode != BTM_BLE_NON_CONNECTABLE) ) - { - tACL_CONN *pa = &btm_cb.acl_db[0]; - UINT16 xx; - - for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, pa++) - { - /* If any other LE link is up, we are still not connectable */ - if (pa->in_use && pa->is_le_link) - return; - } - combined_mode = (btm_cb.ble_ctr_cb.inq_var.connectable_mode | btm_cb.btm_inq_vars.connectable_mode); - btm_ble_set_connectability ( combined_mode ); - } - p_dev_rec = btm_find_dev(bda); if ( p_dev_rec) { @@ -451,7 +432,6 @@ void btm_acl_update_busy_level (tBTM_BLI_EVENT event) case BTM_BLI_ACL_UP_EVT: BTM_TRACE_DEBUG0 ("BTM_BLI_ACL_UP_EVT"); btm_cb.num_acl++; - busy_level = (UINT8)btm_cb.num_acl; break; case BTM_BLI_ACL_DOWN_EVT: if (btm_cb.num_acl) @@ -463,35 +443,39 @@ void btm_acl_update_busy_level (tBTM_BLI_EVENT event) { BTM_TRACE_ERROR0 ("BTM_BLI_ACL_DOWN_EVT issued, but num_acl already zero !!!"); } - busy_level = (UINT8)btm_cb.num_acl; break; case BTM_BLI_PAGE_EVT: BTM_TRACE_DEBUG0 ("BTM_BLI_PAGE_EVT"); btm_cb.is_paging = TRUE; - busy_level = BTM_BL_PAGING_STARTED; + evt.busy_level_flags= BTM_BL_PAGING_STARTED; break; case BTM_BLI_PAGE_DONE_EVT: BTM_TRACE_DEBUG0 ("BTM_BLI_PAGE_DONE_EVT"); btm_cb.is_paging = FALSE; - busy_level = BTM_BL_PAGING_COMPLETE; + evt.busy_level_flags = BTM_BL_PAGING_COMPLETE; break; case BTM_BLI_INQ_EVT: BTM_TRACE_DEBUG0 ("BTM_BLI_INQ_EVT"); btm_cb.is_inquiry = TRUE; - busy_level = BTM_BL_INQUIRY_STARTED; + evt.busy_level_flags = BTM_BL_INQUIRY_STARTED; break; case BTM_BLI_INQ_CANCEL_EVT: BTM_TRACE_DEBUG0 ("BTM_BLI_INQ_CANCEL_EVT"); btm_cb.is_inquiry = FALSE; - busy_level = BTM_BL_INQUIRY_CANCELLED; + evt.busy_level_flags = BTM_BL_INQUIRY_CANCELLED; break; case BTM_BLI_INQ_DONE_EVT: BTM_TRACE_DEBUG0 ("BTM_BLI_INQ_DONE_EVT"); btm_cb.is_inquiry = FALSE; - busy_level = BTM_BL_INQUIRY_COMPLETE; + evt.busy_level_flags = BTM_BL_INQUIRY_COMPLETE; break; } + if (btm_cb.is_paging || btm_cb.is_inquiry) + busy_level = 10; + else + busy_level = (UINT8)btm_cb.num_acl; + if (busy_level != btm_cb.busy_level) { evt.event = BTM_BL_UPDATE_EVT; @@ -631,10 +615,7 @@ tBTM_STATUS BTM_SwitchRole (BD_ADDR remote_bd_addr, UINT8 new_role, tBTM_CMPL_CB /* Wake up the link if in sniff or park before attempting switch */ if (pwr_mode == BTM_PM_MD_PARK || pwr_mode == BTM_PM_MD_SNIFF) { -/* Coverity FALSE-POSITIVE error from Coverity tool. Please do NOT remove following comment. */ -/* coverity[uninit_use_in_call] False-positive: setting the mode to BTM_PM_MD_ACTIVE only uses settings.mode - the other data members of tBTM_PM_PWR_MD are ignored -*/ + memset( (void*)&settings, 0, sizeof(settings)); settings.mode = BTM_PM_MD_ACTIVE; status = BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p->remote_addr, &settings); if (status != BTM_CMD_STARTED) @@ -646,7 +627,8 @@ tBTM_STATUS BTM_SwitchRole (BD_ADDR remote_bd_addr, UINT8 new_role, tBTM_CMPL_CB /* some devices do not support switch while encryption is on */ else { - if (((p_dev_rec = btm_find_dev (remote_bd_addr)) != NULL) + p_dev_rec = btm_find_dev (remote_bd_addr); + if ((p_dev_rec != NULL) && ((p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED) != 0) && !BTM_EPR_AVAILABLE(p)) { @@ -741,10 +723,7 @@ tBTM_STATUS BTM_ChangeLinkKey (BD_ADDR remote_bd_addr, tBTM_CMPL_CB *p_cb) /* Wake up the link if in park before attempting to change link keys */ if (pwr_mode == BTM_PM_MD_PARK) { -/* Coverity: FALSE-POSITIVE error from Coverity tool. Please do NOT remove following comment. */ -/* coverity[uninit_use_in_call] False-positive: setting the mode to BTM_PM_MD_ACTIVE only uses settings.mode - the other data members of tBTM_PM_PWR_MD are ignored -*/ + memset( (void*)&settings, 0, sizeof(settings)); settings.mode = BTM_PM_MD_ACTIVE; status = BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p->remote_addr, &settings); if (status != BTM_CMD_STARTED) @@ -863,12 +842,11 @@ void btm_acl_encrypt_change (UINT16 handle, UINT8 status, UINT8 encr_enable) { tACL_CONN *p; UINT8 xx; + tBTM_SEC_DEV_REC *p_dev_rec; #if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE) tBTM_BL_ROLE_CHG_DATA evt; #endif -#if BTM_DISC_DURING_RS == TRUE - tBTM_SEC_DEV_REC *p_dev_rec; -#endif + BTM_TRACE_DEBUG3 ("btm_acl_encrypt_change handle=%d status=%d encr_enabl=%d", handle, status, encr_enable); xx = btm_handle_to_acl_index(handle); /* don't assume that we can never get a bad hci_handle */ @@ -1044,8 +1022,36 @@ tBTM_STATUS BTM_SetLinkPolicy (BD_ADDR remote_bda, UINT16 *settings) *******************************************************************************/ void BTM_SetDefaultLinkPolicy (UINT16 settings) { - BTM_TRACE_DEBUG0 ("BTM_SetDefaultLinkPolicy"); + UINT8 *localFeatures = BTM_ReadLocalFeatures(); + + BTM_TRACE_DEBUG1("BTM_SetDefaultLinkPolicy setting:0x%04x", settings); + + if((settings & HCI_ENABLE_MASTER_SLAVE_SWITCH) && (!HCI_SWITCH_SUPPORTED(localFeatures))) + { + settings &= ~HCI_ENABLE_MASTER_SLAVE_SWITCH; + BTM_TRACE_DEBUG1("BTM_SetDefaultLinkPolicy switch not supported (settings: 0x%04x)", settings); + } + if ((settings & HCI_ENABLE_HOLD_MODE) && (!HCI_HOLD_MODE_SUPPORTED(localFeatures))) + { + settings &= ~HCI_ENABLE_HOLD_MODE; + BTM_TRACE_DEBUG1("BTM_SetDefaultLinkPolicy hold not supported (settings: 0x%04x)", settings); + } + if ((settings & HCI_ENABLE_SNIFF_MODE) && (!HCI_SNIFF_MODE_SUPPORTED(localFeatures))) + { + settings &= ~HCI_ENABLE_SNIFF_MODE; + BTM_TRACE_DEBUG1("BTM_SetDefaultLinkPolicy sniff not supported (settings: 0x%04x)", settings); + } + if ((settings & HCI_ENABLE_PARK_MODE) && (!HCI_PARK_MODE_SUPPORTED(localFeatures))) + { + settings &= ~HCI_ENABLE_PARK_MODE; + BTM_TRACE_DEBUG1("BTM_SetDefaultLinkPolicy park not supported (settings: 0x%04x)", settings); + } + BTM_TRACE_DEBUG1("Set DefaultLinkPolicy:0x%04x", settings); + btm_cb.btm_def_link_policy = settings; + + /* Set the default Link Policy of the controller */ + btsnd_hcic_write_def_policy_set(settings); } @@ -1361,8 +1367,6 @@ static void btm_establish_continue (tACL_CONN *p_acl_cb) if (btm_cb.btm_def_link_policy) BTM_SetLinkPolicy (p_acl_cb->remote_addr, &btm_cb.btm_def_link_policy); - - BTM_SetLinkSuperTout (p_acl_cb->remote_addr, btm_cb.btm_def_link_super_tout); } #endif p_acl_cb->link_up_issued = TRUE; @@ -1377,7 +1381,6 @@ static void btm_establish_continue (tACL_CONN *p_acl_cb) evt_data.conn.p_dc = p_acl_cb->remote_dc; evt_data.conn.p_features = p_acl_cb->features; - (*btm_cb.p_bl_changed_cb)(&evt_data); } btm_acl_update_busy_level (BTM_BLI_ACL_UP_EVT); @@ -1410,6 +1413,30 @@ void BTM_SetDefaultLinkSuperTout (UINT16 timeout) /******************************************************************************* ** +** Function BTM_GetLinkSuperTout +** +** Description Read the link supervision timeout value of the connection +** +** Returns status of the operation +** +*******************************************************************************/ +tBTM_STATUS BTM_GetLinkSuperTout (BD_ADDR remote_bda, UINT16 *p_timeout) +{ + tACL_CONN *p = btm_bda_to_acl(remote_bda); + + BTM_TRACE_DEBUG0 ("BTM_GetLinkSuperTout"); + if (p != (tACL_CONN *)NULL) + { + *p_timeout = p->link_super_tout; + return(BTM_SUCCESS); + } + /* If here, no BD Addr found */ + return(BTM_UNKNOWN_ADDR); +} + + +/******************************************************************************* +** ** Function BTM_SetLinkSuperTout ** ** Description Create and send HCI "Write Link Supervision Timeout" command @@ -1802,7 +1829,7 @@ BOOLEAN BTM_IsAclConnectionUp (BD_ADDR remote_bda) { tACL_CONN *p; - BTM_TRACE_API6 ("BTM_ReadClockOffset: RemBdAddr: %02x%02x%02x%02x%02x%02x", + BTM_TRACE_API6 ("BTM_IsAclConnectionUp: RemBdAddr: %02x%02x%02x%02x%02x%02x", remote_bda[0], remote_bda[1], remote_bda[2], remote_bda[3], remote_bda[4], remote_bda[5]); @@ -1967,12 +1994,11 @@ void btm_acl_role_changed (UINT8 hci_status, BD_ADDR bd_addr, UINT8 new_role) UINT8 *p_bda = (bd_addr) ? bd_addr : btm_cb.devcb.switch_role_ref_data.remote_bd_addr; tACL_CONN *p = btm_bda_to_acl(p_bda); tBTM_ROLE_SWITCH_CMPL *p_data = &btm_cb.devcb.switch_role_ref_data; + tBTM_SEC_DEV_REC *p_dev_rec; #if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE) tBTM_BL_ROLE_CHG_DATA evt; #endif -#if BTM_DISC_DURING_RS == TRUE - tBTM_SEC_DEV_REC *p_dev_rec; -#endif + BTM_TRACE_DEBUG0 ("btm_acl_role_changed"); /* Ignore any stray events */ if (p == NULL) @@ -2297,14 +2323,7 @@ UINT16 btm_get_max_packet_size (BD_ADDR addr) pkt_size = HCI_DM1_PACKET_SIZE; } -#ifdef BRCM_VS - /* Using HCI size 1017 instead of 1021 */ - if ((pkt_size == HCI_EDR3_DH5_PACKET_SIZE) - && (btu_cb.hcit_acl_data_size == 1017)) - pkt_size = 1017; -#endif - - return(pkt_size); + return(pkt_size); } /******************************************************************************* @@ -2830,14 +2849,15 @@ tBTM_STATUS btm_remove_acl (BD_ADDR bd_addr) } else /* otherwise can disconnect right away */ #endif - - if (hci_handle != 0xFFFF) { - if (!btsnd_hcic_disconnect (hci_handle, HCI_ERR_PEER_USER)) - status = BTM_NO_RESOURCES; + if (hci_handle != 0xFFFF) + { + if (!btsnd_hcic_disconnect (hci_handle, HCI_ERR_PEER_USER)) + status = BTM_NO_RESOURCES; + } + else + status = BTM_UNKNOWN_ADDR; } - else - status = BTM_UNKNOWN_ADDR; return status; } diff --git a/stack/btm/btm_ble.c b/stack/btm/btm_ble.c index 74b5767d1..1d2cdf30c 100644 --- a/stack/btm/btm_ble.c +++ b/stack/btm/btm_ble.c @@ -31,14 +31,15 @@ #include "btm_int.h" #include "btm_ble_api.h" #include "smp_api.h" +#include "l2c_int.h" +#include "gap_api.h" #if SMP_INCLUDED == TRUE extern BOOLEAN AES_CMAC ( BT_OCTET16 key, UINT8 *input, UINT16 length, UINT16 tlen, UINT8 *p_signature); extern void smp_link_encrypted(BD_ADDR bda, UINT8 encr_enable); extern BOOLEAN smp_proc_ltk_request(BD_ADDR bda); #endif - -static void btm_ble_update_active_bgconn_scan_params(void); +extern void gatt_notify_enc_cmpl(BD_ADDR bd_addr); /*******************************************************************************/ /* External Function to be called by other modules */ @@ -114,7 +115,7 @@ BOOLEAN BTM_SecAddBleDevice (BD_ADDR bd_addr, BD_NAME bd_name, tBT_DEVICE_TYPE d { p_dev_rec->sec_flags |= BTM_SEC_NAME_KNOWN; BCM_STRNCPY_S ((char *)p_dev_rec->sec_bd_name, sizeof (p_dev_rec->sec_bd_name), - (char *)bd_name, BTM_MAX_REM_BD_NAME_LEN); + (char *)bd_name, BTM_MAX_REM_BD_NAME_LEN); } p_dev_rec->device_type = dev_type; p_dev_rec->ble.ble_addr_type = addr_type; @@ -158,9 +159,10 @@ BOOLEAN BTM_SecAddBleKey (BD_ADDR bd_addr, tBTM_LE_KEY_VALUE *p_le_key, tBTM_LE_ p_dev_rec = btm_find_dev (bd_addr); if (!p_dev_rec || !p_le_key || (key_type != BTM_LE_KEY_PENC && key_type != BTM_LE_KEY_PID && - key_type != BTM_LE_KEY_PCSRK && key_type != BTM_LE_KEY_LENC)) + key_type != BTM_LE_KEY_PCSRK && key_type != BTM_LE_KEY_LENC && + key_type != BTM_LE_KEY_LCSRK)) { - BTM_TRACE_WARNING3 ("BTM_SecAddLeKey() No BT Link Key, Wrong Type, or No Device record \ + BTM_TRACE_WARNING3 ("BTM_SecAddBleKey() Wrong Type, or No Device record \ for bdaddr: %08x%04x, Type: %d", (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3], (bd_addr[4]<<8)+bd_addr[5], key_type); @@ -283,29 +285,54 @@ void BTM_GetDeviceDHK (BT_OCTET16 dhk) ** ** Function BTM_ReadConnectionAddr ** -** Description This function is called to set the local device random address +** Description This function is called to get the local device address information ** . ** ** Returns void ** *******************************************************************************/ -void BTM_ReadConnectionAddr (BD_ADDR conn_addr) +void BTM_ReadConnectionAddr (BD_ADDR remote_bda, BD_ADDR local_conn_addr, tBLE_ADDR_TYPE *p_addr_type) { #if BLE_INCLUDED == TRUE - BTM_TRACE_DEBUG0 ("BTM_ReadConnectionAddr"); - if (btm_cb.ble_ctr_cb.inq_var.own_addr_type == BLE_ADDR_PUBLIC) - { - BTM_GetLocalDeviceAddr(conn_addr); - } - else + tACL_CONN *p_acl = btm_bda_to_acl(remote_bda); + + if (p_acl == NULL) { - memcpy (conn_addr, btm_cb.ble_ctr_cb.addr_mgnt_cb.private_addr, BD_ADDR_LEN); + BTM_TRACE_ERROR0("No connection exist!"); + return; } + memcpy(local_conn_addr, p_acl->conn_addr, BD_ADDR_LEN); + * p_addr_type = p_acl->conn_addr_type; + + BTM_TRACE_DEBUG2 ("BTM_ReadConnectionAddr address type: %d addr: 0x%02x", + p_acl->conn_addr_type, p_acl->conn_addr[0]); + #endif } /******************************************************************************* ** +** Function BTM_ReadRemoteConnectionAddr +** +** Description This function is read the remote device address currently used +** . +** +** Returns void +** +*******************************************************************************/ +BOOLEAN BTM_ReadRemoteConnectionAddr(BD_ADDR pseudo_addr, BD_ADDR conn_addr, tBLE_ADDR_TYPE *p_addr_type) +{ + BOOLEAN st = TRUE; +#if BLE_INCLUDED == TRUE + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(pseudo_addr); + + memcpy(conn_addr, pseudo_addr, BD_ADDR_LEN); + *p_addr_type = p_dev_rec->ble.ble_addr_type; +#endif + return st; +} +/******************************************************************************* +** ** Function BTM_SecurityGrant ** ** Description This function is called to grant security process. @@ -346,6 +373,12 @@ void BTM_BlePasskeyReply (BD_ADDR bd_addr, UINT8 res, UINT32 passkey) tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr); tSMP_STATUS res_smp = (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_PASSKEY_ENTRY_FAIL; + if (p_dev_rec == NULL) + { + BTM_TRACE_ERROR0("Passkey reply to Unknown device"); + return; + } + p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_AUTHED; BTM_TRACE_DEBUG0 ("BTM_BlePasskeyReply"); SMP_PasskeyReply(bd_addr, res_smp, passkey); @@ -371,6 +404,13 @@ void BTM_BleOobDataReply(BD_ADDR bd_addr, UINT8 res, UINT8 len, UINT8 *p_data) tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr); BTM_TRACE_DEBUG0 ("BTM_BleOobDataReply"); + + if (p_dev_rec == NULL) + { + BTM_TRACE_ERROR0("BTM_BleOobDataReply() to Unknown device"); + return; + } + p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_AUTHED; SMP_OobDataReply(bd_addr, res_smp, len, p_data); #endif @@ -411,8 +451,10 @@ void BTM_BleSetConnScanParams (UINT16 scan_interval, UINT16 scan_window) new_param = TRUE; } - if (new_param) - btm_ble_update_active_bgconn_scan_params(); + if (new_param && p_ble_cb->conn_state == BLE_BG_CONN) + { + btm_ble_suspend_bg_conn(); + } } else { @@ -452,7 +494,7 @@ void BTM_BleSetPrefConnParams (BD_ADDR bd_addr, if (BTM_BLE_VALID_PRAM(min_conn_int, BTM_BLE_CONN_INT_MIN, BTM_BLE_CONN_INT_MAX) && BTM_BLE_VALID_PRAM(max_conn_int, BTM_BLE_CONN_INT_MIN, BTM_BLE_CONN_INT_MAX) && BTM_BLE_VALID_PRAM(supervision_tout, BTM_BLE_CONN_SUP_TOUT_MIN, BTM_BLE_CONN_SUP_TOUT_MAX) && - slave_latency <= BTM_BLE_CONN_LATENCY_MAX) + (slave_latency <= BTM_BLE_CONN_LATENCY_MAX || slave_latency == BTM_BLE_CONN_PARAM_UNDEF)) { if (p_dev_rec) { @@ -544,41 +586,83 @@ void BTM_ReadDevInfo (BD_ADDR remote_bda, tBT_DEVICE_TYPE *p_dev_type, tBLE_ADDR return; } +/******************************************************************************* +** +** Function BTM_BleReceiverTest +** +** Description This function is called to start the LE Receiver test +** +** Parameter rx_freq - Frequency Range +** p_cmd_cmpl_cback - Command Complete callback +** +*******************************************************************************/ +void BTM_BleReceiverTest(UINT8 rx_freq, tBTM_CMPL_CB *p_cmd_cmpl_cback) +{ + btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback; + + if (btsnd_hcic_ble_receiver_test(rx_freq) == FALSE) + { + BTM_TRACE_ERROR1("%s: Unable to Trigger LE receiver test", __FUNCTION__); + } +} /******************************************************************************* -** Internal Functions +** +** Function BTM_BleTransmitterTest +** +** Description This function is called to start the LE Transmitter test +** +** Parameter tx_freq - Frequency Range +** test_data_len - Length in bytes of payload data in each packet +** packet_payload - Pattern to use in the payload +** p_cmd_cmpl_cback - Command Complete callback +** *******************************************************************************/ -#if BLE_INCLUDED == TRUE +void BTM_BleTransmitterTest(UINT8 tx_freq, UINT8 test_data_len, + UINT8 packet_payload, tBTM_CMPL_CB *p_cmd_cmpl_cback) +{ + btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback; + if (btsnd_hcic_ble_transmitter_test(tx_freq, test_data_len, packet_payload) == FALSE) + { + BTM_TRACE_ERROR1("%s: Unable to Trigger LE transmitter test", __FUNCTION__); + } +} /******************************************************************************* ** -** Function btm_ble_update_active_bgconn_scan_params +** Function BTM_BleTestEnd +** +** Description This function is called to stop the in-progress TX or RX test ** -** Description This function is called to update the scan parameter if background -** connection has been active. +** Parameter p_cmd_cmpl_cback - Command complete callback ** *******************************************************************************/ -static void btm_ble_update_active_bgconn_scan_params(void) +void BTM_BleTestEnd(tBTM_CMPL_CB *p_cmd_cmpl_cback) { - tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; - tBTM_BLE_SEL_CBACK *p_select_cback; + btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback; + + if (btsnd_hcic_ble_test_end() == FALSE) + { + BTM_TRACE_ERROR1("%s: Unable to End the LE TX/RX test", __FUNCTION__); + } +} + +/******************************************************************************* +** Internal Functions +*******************************************************************************/ +#if BLE_INCLUDED == TRUE - /* if active , cancel and restart and apply the params */ - if (p_cb->bg_conn_state == BLE_BG_CONN_ACTIVE) +void btm_ble_test_command_complete(UINT8 *p) +{ + tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_le_test_cmd_cmpl_cb; + UINT8 status; + + btm_cb.devcb.p_le_test_cmd_cmpl_cb = NULL; + + if (p_cb) { - if (p_cb->bg_conn_type == BTM_BLE_CONN_AUTO) - { - if (btm_ble_start_auto_conn(FALSE)) - btm_ble_start_auto_conn(TRUE); - } - else if (p_cb->bg_conn_type == BTM_BLE_CONN_SELECTIVE) - { - p_select_cback = p_cb->p_select_cback; - if (btm_ble_start_select_conn(FALSE, NULL)) - btm_ble_start_select_conn(TRUE, p_select_cback); - } + (*p_cb)(p); } - return; } /******************************************************************************* @@ -643,7 +727,7 @@ void btm_ble_rand_enc_complete (UINT8 *p, UINT16 op_code, tBTM_RAND_ENC_CB *p_en } -#if (SMP_INCLUDED == TRUE) + #if (SMP_INCLUDED == TRUE) /******************************************************************************* ** @@ -744,6 +828,7 @@ void btm_sec_save_le_key(BD_ADDR bd_addr, tBTM_LE_KEY_TYPE key_type, tBTM_LE_KEY { tBTM_SEC_DEV_REC *p_rec; tBTM_LE_EVT_DATA cb_data; + UINT8 i; BTM_TRACE_DEBUG2 ("btm_sec_save_le_key key_type=0x%x pass_to_application=%d",key_type, pass_to_application); /* Store the updated key in the device database */ @@ -776,7 +861,14 @@ void btm_sec_save_le_key(BD_ADDR bd_addr, tBTM_LE_KEY_TYPE key_type, tBTM_LE_KEY break; case BTM_LE_KEY_PID: - memcpy(p_rec->ble.keys.irk, p_keys->pid_key, BT_OCTET16_LEN); + for (i=0; i<BT_OCTET16_LEN; i++) + { + p_rec->ble.keys.irk[i] = p_keys->pid_key.irk[i]; + } + + //memcpy( p_rec->ble.keys.irk, p_keys->pid_key, BT_OCTET16_LEN); todo will crash the system + memcpy(p_rec->ble.static_addr, p_keys->pid_key.static_addr, BD_ADDR_LEN); + p_rec->ble.static_addr_type = p_keys->pid_key.addr_type; p_rec->ble.key_type |= BTM_LE_KEY_PID; BTM_TRACE_DEBUG1("BTM_LE_KEY_PID key_type=0x%x save peer IRK", p_rec->ble.key_type); break; @@ -839,7 +931,6 @@ void btm_sec_save_le_key(BD_ADDR bd_addr, tBTM_LE_KEY_TYPE key_type, tBTM_LE_KEY { cb_data.key.p_key_value = p_keys; cb_data.key.key_type = key_type; - (*btm_cb.api.p_le_callback) (BTM_LE_KEY_EVT, bd_addr, &cb_data); } return; @@ -919,7 +1010,8 @@ void btm_ble_link_sec_check(BD_ADDR bd_addr, tBTM_LE_AUTH_REQ auth_req, tBTM_BLE return; } - if (p_dev_rec->sec_state == BTM_SEC_STATE_ENCRYPTING) + if (p_dev_rec->sec_state == BTM_SEC_STATE_ENCRYPTING || + p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING) { /* race condition: discard the security request while master is encrypting the link */ *p_sec_req_act = BTM_BLE_SEC_REQ_ACT_DISCARD; @@ -960,12 +1052,13 @@ void btm_ble_link_sec_check(BD_ADDR bd_addr, tBTM_LE_AUTH_REQ auth_req, tBTM_BLE } else { - /* To avoid re-encryption on an encrypted link for an equal condition encryption + /* To avoid re-encryption on an encrypted link for an equal condition encryption */ + /* if link has been encrypted, do nothing, go straight to furhter action if (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED) *p_sec_req_act = BTM_BLE_SEC_REQ_ACT_DISCARD; else */ - *p_sec_req_act = BTM_BLE_SEC_REQ_ACT_ENCRYPT; + *p_sec_req_act = BTM_BLE_SEC_REQ_ACT_ENCRYPT; } } else @@ -1000,13 +1093,14 @@ tBTM_STATUS btm_ble_set_encryption (BD_ADDR bd_addr, void *p_ref_data, UINT8 lin tBTM_BLE_SEC_ACT sec_act = *(tBTM_BLE_SEC_ACT *)p_ref_data ; tBTM_SEC_DEV_REC *p_rec = btm_find_dev (bd_addr); - BTM_TRACE_DEBUG2 ("btm_ble_set_encryption sec_act=0x%x role_master=%d", sec_act, p_rec->role_master); - if (p_rec == NULL) { + BTM_TRACE_WARNING1 ("btm_ble_set_encryption (NULL device record!! sec_act=0x%x", sec_act); return(BTM_WRONG_MODE); } + BTM_TRACE_DEBUG2 ("btm_ble_set_encryption sec_act=0x%x role_master=%d", sec_act, p_rec->role_master); + if (sec_act == BTM_BLE_SEC_ENCRYPT_MITM) { p_rec->security_required |= BTM_SEC_IN_MITM; @@ -1018,9 +1112,11 @@ tBTM_STATUS btm_ble_set_encryption (BD_ADDR bd_addr, void *p_ref_data, UINT8 lin if (link_role == BTM_ROLE_MASTER) { /* start link layer encryption using the security info stored */ - btm_ble_start_encrypt(bd_addr, FALSE, NULL); - p_rec->sec_state = BTM_SEC_STATE_ENCRYPTING; - cmd = BTM_CMD_STARTED; + if (btm_ble_start_encrypt(bd_addr, FALSE, NULL)) + { + p_rec->sec_state = BTM_SEC_STATE_ENCRYPTING; + cmd = BTM_CMD_STARTED; + } break; } /* if salve role then fall through to call SMP_Pair below which will send a @@ -1123,30 +1219,36 @@ BOOLEAN btm_ble_start_encrypt(BD_ADDR bda, BOOLEAN use_stk, BT_OCTET16 stk) void btm_ble_link_encrypted(BD_ADDR bd_addr, UINT8 encr_enable) { tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr); + BOOLEAN enc_cback; + + if (!p_dev_rec) + { + BTM_TRACE_WARNING1 ("btm_ble_link_encrypted (No Device Found!) encr_enable=%d", encr_enable); + return; + } BTM_TRACE_DEBUG1 ("btm_ble_link_encrypted encr_enable=%d", encr_enable); + enc_cback = (p_dev_rec->sec_state == BTM_SEC_STATE_ENCRYPTING); + smp_link_encrypted(bd_addr, encr_enable); - if (p_dev_rec) - { - BTM_TRACE_DEBUG1(" p_dev_rec->sec_flags=0x%x", p_dev_rec->sec_flags); + BTM_TRACE_DEBUG1(" p_dev_rec->sec_flags=0x%x", p_dev_rec->sec_flags); - if (encr_enable && p_dev_rec->enc_key_size == 0) - p_dev_rec->enc_key_size = p_dev_rec->ble.keys.key_size; + if (encr_enable && p_dev_rec->enc_key_size == 0) + p_dev_rec->enc_key_size = p_dev_rec->ble.keys.key_size; + + p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; + if (p_dev_rec->p_callback && enc_cback) + { + if (encr_enable) + btm_sec_dev_rec_cback_event(p_dev_rec, BTM_SUCCESS); + else if (p_dev_rec->role_master) + btm_sec_dev_rec_cback_event(p_dev_rec, BTM_ERR_PROCESSING); - if (p_dev_rec->p_callback) - { - if (p_dev_rec->sec_state == BTM_SEC_STATE_ENCRYPTING) - { - if (encr_enable) - btm_sec_dev_rec_cback_event(p_dev_rec, BTM_SUCCESS); - else if (p_dev_rec->role_master) - btm_sec_dev_rec_cback_event(p_dev_rec, BTM_ERR_PROCESSING); - } - } - p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; } + /* to notify GATT to send data if any request is pending */ + gatt_notify_enc_cmpl(p_dev_rec->bd_addr); } /******************************************************************************* @@ -1186,7 +1288,7 @@ static void btm_enc_proc_slave_y(tSMP_ENC *p) p_dev_rec = btm_find_dev_by_handle (p_cb->enc_handle); if ( p_dev_rec && - p_dev_rec->ble.keys.div == div ) + p_dev_rec->ble.keys.div == div ) { BTM_TRACE_DEBUG0 ("LTK request OK"); /* calculating LTK , LTK = E er(div) */ @@ -1305,6 +1407,110 @@ UINT8 btm_ble_io_capabilities_req(tBTM_SEC_DEV_REC *p_dev_rec, tBTM_LE_IO_REQ *p return callback_rc; } +/******************************************************************************* +** +** Function btm_ble_connected +** +** Description This function is when a LE connection to the peer device is +** establsihed +** +** Returns void +** +*******************************************************************************/ +void btm_ble_connected (UINT8 *bda, UINT16 handle, UINT8 enc_mode, UINT8 role, + tBLE_ADDR_TYPE addr_type, BOOLEAN addr_matched) +{ + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda); + tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; + + BTM_TRACE_EVENT0 ("btm_ble_connected"); + + /* Commenting out trace due to obf/compilation problems. + */ +#if (BT_USE_TRACES == TRUE) + if (p_dev_rec) + { + BTM_TRACE_EVENT4 ("Security Manager: btm_sec_connected : handle:%d enc_mode:%d bda:%x RName:%s", + handle, enc_mode, + (bda[2]<<24)+(bda[3]<<16)+(bda[4]<<8)+bda[5], + p_dev_rec->sec_bd_name); + + BTM_TRACE_DEBUG1 ("btm_ble_connected sec_flags=0x%x",p_dev_rec->sec_flags); + } + else + { + BTM_TRACE_EVENT3 ("Security Manager: btm_sec_connected: handle:%d enc_mode:%d bda:%x ", + handle, enc_mode, + (bda[2]<<24)+(bda[3]<<16)+(bda[4]<<8)+bda[5]); + } +#endif + + if (!p_dev_rec) + { + /* There is no device record for new connection. Allocate one */ + p_dev_rec = btm_sec_alloc_dev (bda); + } + else /* Update the timestamp for this device */ + { + p_dev_rec->timestamp = btm_cb.dev_rec_count++; + } + + /* update device information */ + p_dev_rec->device_type |= BT_DEVICE_TYPE_BLE; + p_dev_rec->hci_handle = handle; + p_dev_rec->ble.ble_addr_type = addr_type; + + if (role == HCI_ROLE_MASTER) + p_dev_rec->role_master = TRUE; + + if (role == HCI_ROLE_SLAVE) + p_cb->inq_var.adv_mode = BTM_BLE_ADV_DISABLE; + p_cb->inq_var.directed_conn = FALSE; + + return; +} + +/***************************************************************************** +** Function btm_ble_conn_complete +** +** Description LE connection complete. +** +******************************************************************************/ +void btm_ble_conn_complete(UINT8 *p, UINT16 evt_len) +{ + UINT8 role, status, bda_type; + UINT16 handle; + BD_ADDR bda; + UINT16 conn_interval, conn_latency, conn_timeout; + BOOLEAN match = FALSE; + + STREAM_TO_UINT8 (status, p); + STREAM_TO_UINT16 (handle, p); + STREAM_TO_UINT8 (role, p); + STREAM_TO_UINT8 (bda_type, p); + STREAM_TO_BDADDR (bda, p); + + if (status == 0) + { + STREAM_TO_UINT16 (conn_interval, p); + STREAM_TO_UINT16 (conn_latency, p); + STREAM_TO_UINT16 (conn_timeout, p); + handle = HCID_GET_HANDLE (handle); + + btm_ble_connected(bda, handle, HCI_ENCRYPT_MODE_DISABLED, role, bda_type, match); + l2cble_conn_comp (handle, role, bda, bda_type, conn_interval, + conn_latency, conn_timeout); + } + else + { + role = HCI_ROLE_UNKNOWN; + + if (status == HCI_ERR_DIRECTED_ADVERTISING_TIMEOUT) + btm_ble_dir_adv_tout(); + } + btm_ble_update_mode_operation(role, bda, TRUE); +} + /***************************************************************************** ** Function btm_proc_smp_cback ** @@ -1314,7 +1520,7 @@ UINT8 btm_ble_io_capabilities_req(tBTM_SEC_DEV_REC *p_dev_rec, tBTM_LE_IO_REQ *p UINT8 btm_proc_smp_cback(tSMP_EVT event, BD_ADDR bd_addr, tSMP_EVT_DATA *p_data) { tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr); - UINT8 res; + UINT8 res = 0; BTM_TRACE_DEBUG1 ("btm_proc_smp_cback event = %d", event); @@ -1336,11 +1542,7 @@ UINT8 btm_proc_smp_cback(tSMP_EVT event, BD_ADDR bd_addr, tSMP_EVT_DATA *p_data) { /* the callback function implementation may change the IO capability... */ BTM_TRACE_DEBUG1 ("btm_cb.api.p_le_callback=0x%x", btm_cb.api.p_le_callback ); - (*btm_cb.api.p_le_callback) (event, bd_addr, (tBTM_LE_EVT_DATA *)p_data); - } - else - { - BTM_TRACE_ERROR0 ("btm_proc_smp_cback: btm_cb.api.p_le_callback ==NULL"); + (*btm_cb.api.p_le_callback) (event, bd_addr, (tBTM_LE_EVT_DATA *)p_data); } if (event == SMP_COMPLT_EVT) @@ -1370,7 +1572,7 @@ UINT8 btm_proc_smp_cback(tSMP_EVT event, BD_ADDR bd_addr, tSMP_EVT_DATA *p_data) else { BTM_TRACE_DEBUG0 ("Pairing failed - Not Removing ACL"); - p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; + p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; } } #else @@ -1406,7 +1608,7 @@ UINT8 btm_proc_smp_cback(tSMP_EVT event, BD_ADDR bd_addr, tSMP_EVT_DATA *p_data) return 0; } -#endif /* SMP_INCLUDED */ + #endif /* SMP_INCLUDED */ #endif /* BLE_INCLUDED */ @@ -1548,7 +1750,7 @@ BOOLEAN BTM_BleDataSignature (BD_ADDR bd_addr, UINT8 *p_text, UINT16 len, ** *******************************************************************************/ BOOLEAN BTM_BleVerifySignature (BD_ADDR bd_addr, UINT8 *p_orig, UINT16 len, UINT32 counter, - UINT8 *p_comp) + UINT8 *p_comp) { BOOLEAN verified = FALSE; #if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE) @@ -1844,7 +2046,7 @@ void btm_ble_reset_id( void ) } } -#if BTM_BLE_CONFORMANCE_TESTING == TRUE + #if BTM_BLE_CONFORMANCE_TESTING == TRUE /******************************************************************************* ** ** Function btm_ble_set_no_disc_if_pair_fail @@ -1894,6 +2096,33 @@ void btm_ble_set_test_local_sign_cntr_value(BOOLEAN enable, UINT32 test_local_si btm_cb.devcb.test_local_sign_cntr = test_local_sign_cntr; } +/******************************************************************************* +** +** Function btm_set_random_address +** +** Description This function set a random address to local controller. +** +** Returns void +** +*******************************************************************************/ +void btm_set_random_address(BD_ADDR random_bda) +{ + tBTM_LE_RANDOM_CB *p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb; + BOOLEAN adv_mode = btm_cb.ble_ctr_cb.inq_var.adv_mode ; + + BTM_TRACE_DEBUG0 ("btm_set_random_address"); + + if (adv_mode == BTM_BLE_ADV_ENABLE) + btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE); + + memcpy(p_cb->private_addr, random_bda, BD_ADDR_LEN); + btsnd_hcic_ble_set_random_addr(p_cb->private_addr); + + if (adv_mode == BTM_BLE_ADV_ENABLE) + btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_ENABLE); + + +} #endif /* BTM_BLE_CONFORMANCE_TESTING */ diff --git a/stack/btm/btm_ble_addr.c b/stack/btm/btm_ble_addr.c index 04872f919..9ae37f957 100644 --- a/stack/btm/btm_ble_addr.c +++ b/stack/btm/btm_ble_addr.c @@ -28,11 +28,13 @@ #include "hcimsgs.h" #include "btu.h" #include "btm_int.h" - +#include "btm_ble_int.h" +#include "gap_api.h" #if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE) - #include "smp_api.h" - #define BTM_BLE_PRIVATE_ADDR_INT 900 /* 15 minutes minimum for random address refreshing */ +#include "smp_api.h" +#define BTM_BLE_PRIVATE_ADDR_INT 900 /* 15 minutes minimum for + random address refreshing */ /******************************************************************************* ** @@ -47,42 +49,24 @@ static void btm_gen_resolve_paddr_cmpl(tSMP_ENC *p) { tBTM_LE_RANDOM_CB *p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb; - tBTM_BLE_INQ_CB *p_inq_cb = &btm_cb.ble_ctr_cb.inq_var; BTM_TRACE_EVENT0 ("btm_gen_resolve_paddr_cmpl"); - if (p && p->param_buf) + + if (p) { - /* get the high bytes of the random address */ - p_cb->private_addr[2] = p->param_buf[0]; - p_cb->private_addr[1] = p->param_buf[1]; - p_cb->private_addr[0] = p->param_buf[2]; - /* mask off the 1st MSB */ - p_cb->private_addr[0] &= 0xfe; - /* set the 2nd MSB to be 1 */ - p_cb->private_addr[0] |= 0x02; + /* set hash to be LSB of rpAddress */ + p_cb->private_addr[5] = p->param_buf[0]; + p_cb->private_addr[4] = p->param_buf[1]; + p_cb->private_addr[3] = p->param_buf[2]; /* set it to controller */ btsnd_hcic_ble_set_random_addr(p_cb->private_addr); - p_inq_cb->own_addr_type = BLE_ADDR_RANDOM; + p_cb->own_addr_type = BLE_ADDR_RANDOM; /* start a periodical timer to refresh random addr */ btu_stop_timer(&p_cb->raddr_timer_ent); btu_start_timer (&p_cb->raddr_timer_ent, BTU_TTYPE_BLE_RANDOM_ADDR, BTM_BLE_PRIVATE_ADDR_INT); - /* if adv is active, restart adv with new private addr */ - if (p_inq_cb->adv_mode == BTM_BLE_ADV_ENABLE) - { - btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE); - - btsnd_hcic_ble_write_adv_params (p_inq_cb->adv_interval_min, - p_inq_cb->adv_interval_max, - p_inq_cb->evt_type, - p_inq_cb->own_addr_type, - p_inq_cb->direct_bda.type, - p_inq_cb->direct_bda.bda, - p_inq_cb->adv_chnl_map, - p_inq_cb->afp); - } } else { @@ -107,11 +91,14 @@ static void btm_gen_resolve_paddr_low(tBTM_RAND_ENC *p) tSMP_ENC output; BTM_TRACE_EVENT0 ("btm_gen_resolve_paddr_low"); - if (p && p->param_buf) + if (p) { - p_cb->private_addr[5] = p->param_buf[0]; - p_cb->private_addr[4] = p->param_buf[1]; - p_cb->private_addr[3] = p->param_buf[2]; + p->param_buf[2] &= (~BLE_RESOLVE_ADDR_MASK); + p->param_buf[2] |= BLE_RESOLVE_ADDR_MSB; + + p_cb->private_addr[2] = p->param_buf[0]; + p_cb->private_addr[1] = p->param_buf[1]; + p_cb->private_addr[0] = p->param_buf[2]; /* encrypt with ur IRK */ if (!SMP_Encrypt(btm_cb.devcb.id_keys.irk, BT_OCTET16_LEN, p->param_buf, 3, &output)) @@ -154,22 +141,31 @@ void btm_gen_resolvable_private_addr (void) static void btm_gen_non_resolve_paddr_cmpl(tBTM_RAND_ENC *p) { tBTM_LE_RANDOM_CB *p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb; + tBTM_BLE_ADDR_CBACK *p_cback = p_cb->p_generate_cback; + void *p_data = p_cb->p; UINT8 *pp; + BD_ADDR static_random; + BTM_TRACE_EVENT0 ("btm_gen_non_resolve_paddr_cmpl"); - if (p && p->param_buf) + + p_cb->p_generate_cback = NULL; + if (p) { + pp = p->param_buf; - STREAM_TO_BDADDR(p_cb->private_addr, pp); + STREAM_TO_BDADDR(static_random, pp); /* mask off the 2 MSB */ - p_cb->private_addr[0] &= 0xfc; - /* write to controller */ - btsnd_hcic_ble_set_random_addr(p_cb->private_addr); + static_random[0] &= BLE_STATIC_PRIVATE_MSB_MASK; - btm_cb.ble_ctr_cb.inq_var.own_addr_type = BLE_ADDR_RANDOM; + /* report complete */ + if (p_cback) + (* p_cback)(static_random, p_data); } else { BTM_TRACE_DEBUG0("btm_gen_non_resolvable_private_addr failed"); + if (p_cback) + (* p_cback)(NULL, p_data); } } /******************************************************************************* @@ -182,13 +178,22 @@ static void btm_gen_non_resolve_paddr_cmpl(tBTM_RAND_ENC *p) ** Returns void ** *******************************************************************************/ -void btm_gen_non_resolvable_private_addr (void) +void btm_gen_non_resolvable_private_addr (tBTM_BLE_ADDR_CBACK *p_cback, void *p) { + tBTM_LE_RANDOM_CB *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb; + BTM_TRACE_EVENT0 ("btm_gen_non_resolvable_private_addr"); + + if (p_mgnt_cb->p_generate_cback != NULL) + return; + + p_mgnt_cb->p_generate_cback = p_cback; + p_mgnt_cb->p = p; if (!btsnd_hcic_ble_rand((void *)btm_gen_non_resolve_paddr_cmpl)) { btm_gen_non_resolve_paddr_cmpl(NULL); } + } #if SMP_INCLUDED == TRUE /******************************************************************************* @@ -209,9 +214,12 @@ static void btm_ble_resolve_address_cmpl(void) tBTM_LE_RANDOM_CB *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb; tBTM_SEC_DEV_REC *p_dev_rec = NULL; - BTM_TRACE_EVENT0 ("btm_ble_resolve_address_cmpl"); + BTM_TRACE_EVENT1 ("btm_ble_resolve_address_cmpl p_mgnt_cb->index = %d", p_mgnt_cb->index); + if (p_mgnt_cb->index < BTM_SEC_MAX_DEVICE_RECORDS) + { p_dev_rec = &btm_cb.sec_dev_rec[p_mgnt_cb->index]; + } p_mgnt_cb->busy = FALSE; @@ -237,7 +245,7 @@ static BOOLEAN btm_ble_proc_resolve_x(tSMP_ENC *p) comp[1] = p_mgnt_cb->random_bda[4]; comp[2] = p_mgnt_cb->random_bda[3]; - if (p && p->param_buf) + if (p) { if (!memcmp(p->param_buf, &comp[0], 3)) { @@ -329,11 +337,12 @@ void btm_ble_resolve_random_addr(BD_ADDR random_bda, tBTM_BLE_RESOLVE_CBACK * p_ /* check for next security record */ while (TRUE) { - if (btm_ble_match_random_bda(p_mgnt_cb->index++)) + if (btm_ble_match_random_bda(p_mgnt_cb->index)) { - // match found or went through the list + /* atch found or went through the list */ break; } + p_mgnt_cb->index ++; } } else @@ -366,18 +375,7 @@ tBLE_ADDR_TYPE btm_ble_map_bda_to_conn_bda(BD_ADDR bd_addr) else return BLE_ADDR_PUBLIC; } -/******************************************************************************* -** -** Function btm_ble_map_bda_to_pseudo_bda -** -** Description This function map a BD address to a pseudo address when the -** address given is a random address. -** -*******************************************************************************/ -void btm_ble_map_bda_to_pseudo_bda(BD_ADDR bd_addr) -{ - BTM_TRACE_EVENT0 ("btm_ble_map_bda_to_pseudo_bda"); -} + #endif diff --git a/stack/btm/btm_ble_bgconn.c b/stack/btm/btm_ble_bgconn.c index aa002e8ef..3b8b1e2ff 100644 --- a/stack/btm/btm_ble_bgconn.c +++ b/stack/btm/btm_ble_bgconn.c @@ -30,11 +30,16 @@ #include "l2c_int.h" #include "hcimsgs.h" + #ifndef BTM_BLE_SCAN_PARAM_TOUT #define BTM_BLE_SCAN_PARAM_TOUT 50 /* 50 seconds */ #endif #if (BLE_INCLUDED == TRUE) + +static void btm_suspend_wl_activity(tBTM_BLE_WL_STATE wl_state); +static void btm_resume_wl_activity(tBTM_BLE_WL_STATE wl_state); + /******************************************************************************* ** ** Function btm_update_scanner_filter_policy @@ -45,9 +50,11 @@ void btm_update_scanner_filter_policy(tBTM_BLE_SFP scan_policy) { tBTM_BLE_INQ_CB *p_inq = &btm_cb.ble_ctr_cb.inq_var; BTM_TRACE_EVENT0 ("btm_update_scanner_filter_policy"); - btm_cb.ble_ctr_cb.inq_var.sfp = scan_policy; - btsnd_hcic_ble_set_scan_params ((UINT8)((p_inq->scan_type == BTM_BLE_SCAN_MODE_NONE) ? BTM_BLE_SCAN_MODE_ACTI: p_inq->scan_type), + p_inq->sfp = scan_policy; + p_inq->scan_type = (p_inq->scan_type == BTM_BLE_SCAN_MODE_NONE) ? BTM_BLE_SCAN_MODE_ACTI: p_inq->scan_type; + + btsnd_hcic_ble_set_scan_params (p_inq->scan_type, (UINT16)(!p_inq->scan_interval ? BTM_BLE_GAP_DISC_SCAN_INT : p_inq->scan_interval), (UINT16)(!p_inq->scan_window ? BTM_BLE_GAP_DISC_SCAN_WIN : p_inq->scan_window), BLE_ADDR_PUBLIC, @@ -55,88 +62,68 @@ void btm_update_scanner_filter_policy(tBTM_BLE_SFP scan_policy) } /******************************************************************************* ** -** Function btm_update_adv_filter_policy -** -** Description This function update the filter policy of scnner or advertiser. -*******************************************************************************/ -void btm_update_adv_filter_policy(tBTM_BLE_AFP adv_policy) -{ - tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var; - BTM_TRACE_EVENT0 ("btm_update_adv_filter_policy"); - p_cb->afp = adv_policy; -} -/******************************************************************************* -** ** Function btm_update_dev_to_white_list ** ** Description This function adds a device into white list. *******************************************************************************/ -BOOLEAN btm_update_dev_to_white_list(BOOLEAN to_add, BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type) +BOOLEAN btm_update_dev_to_white_list(BOOLEAN to_add, BD_ADDR bd_addr, UINT8 attr) { /* look up the sec device record, and find the address */ tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; - tBTM_SEC_DEV_REC *p_dev_rec; + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr); BD_ADDR dummy_bda = {0}; - BOOLEAN started = FALSE, suspend = FALSE; + BOOLEAN started = FALSE; + UINT8 wl_state = p_cb->wl_state; + tBT_DEVICE_TYPE dev_type; + tBLE_ADDR_TYPE addr_type = BLE_ADDR_PUBLIC; - if (btm_cb.btm_inq_vars.inq_active) + if ((to_add && p_cb->num_empty_filter == 0) || + (!to_add && p_cb->num_empty_filter == p_cb->max_filter_entries)) { - suspend = TRUE; - btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE); + BTM_TRACE_ERROR1("WL full or empty, unable to update to WL. num_entry available: %d", p_cb->num_empty_filter); + return started; } - if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL && + btm_suspend_wl_activity(wl_state); + + if (p_dev_rec != NULL && p_dev_rec->device_type == BT_DEVICE_TYPE_BLE) { - BTM_TRACE_DEBUG0("btm_update_dev_to_white_list 1"); - - if ((to_add && p_cb->num_empty_filter == 0) || - (!to_add && p_cb->num_empty_filter == p_cb->max_filter_entries)) - { - BTM_TRACE_ERROR1("num_entry available in controller: %d", p_cb->num_empty_filter); - return started; - } - - if ( p_dev_rec->ble.ble_addr_type == BLE_ADDR_PUBLIC) + if (to_add) { - if (to_add) - started = btsnd_hcic_ble_add_white_list (BLE_ADDR_PUBLIC, bd_addr); - else - started = btsnd_hcic_ble_remove_from_white_list (BLE_ADDR_PUBLIC, bd_addr); + if (!BTM_BLE_IS_RESOLVE_BDA(bd_addr)) + { + started = btsnd_hcic_ble_add_white_list (p_dev_rec->ble.ble_addr_type, bd_addr); + } + if (memcmp(p_dev_rec->ble.static_addr, bd_addr, BD_ADDR_LEN) != 0 && + memcmp(p_dev_rec->ble.static_addr, dummy_bda, BD_ADDR_LEN) != 0) + { + started = btsnd_hcic_ble_add_white_list (p_dev_rec->ble.static_addr_type, p_dev_rec->ble.static_addr); + } } else { - if (BLE_ADDR_IS_STATIC(bd_addr)) + if (!BTM_BLE_IS_RESOLVE_BDA(bd_addr)) { - if (to_add) - started = btsnd_hcic_ble_add_white_list (BLE_ADDR_RANDOM, bd_addr); - else - started = btsnd_hcic_ble_remove_from_white_list (BLE_ADDR_RANDOM, bd_addr); - + started = btsnd_hcic_ble_remove_from_white_list (p_dev_rec->ble.ble_addr_type, bd_addr); } - if (memcmp(p_dev_rec->ble.reconn_addr, dummy_bda, BD_ADDR_LEN) != 0) + if (memcmp(p_dev_rec->ble.static_addr, dummy_bda, BD_ADDR_LEN) != 0) { - if (to_add) - started = btsnd_hcic_ble_add_white_list (BLE_ADDR_RANDOM, p_dev_rec->ble.reconn_addr); - else - started = btsnd_hcic_ble_remove_from_white_list (BLE_ADDR_RANDOM, p_dev_rec->ble.reconn_addr); + started = btsnd_hcic_ble_remove_from_white_list (p_dev_rec->ble.static_addr_type, p_dev_rec->ble.static_addr); } } - } - /* if not a known device, shall we add it? */ + } /* if not a known device, shall we add it? */ else { + BTM_ReadDevInfo(bd_addr, &dev_type, &addr_type); if (to_add) started = btsnd_hcic_ble_add_white_list (addr_type, bd_addr); else started = btsnd_hcic_ble_remove_from_white_list (addr_type, bd_addr); } - if (suspend) - { - btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_ENABLE, BTM_BLE_DUPLICATE_DISABLE); - } + btm_resume_wl_activity(wl_state); return started; } @@ -175,12 +162,12 @@ void btm_ble_clear_white_list_complete(UINT8 *p_data, UINT16 evt_len) ** ** Description This function read the current white list size. *******************************************************************************/ -void btm_ble_add_2_white_list_complete(UINT8 *p, UINT16 evt_len) +void btm_ble_add_2_white_list_complete(UINT8 status) { tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; BTM_TRACE_EVENT0 ("btm_ble_add_2_white_list_complete"); - if (*p == HCI_SUCCESS) + if (status == HCI_SUCCESS) { p_cb->num_empty_filter --; } @@ -202,54 +189,25 @@ void btm_ble_remove_from_white_list_complete(UINT8 *p, UINT16 evt_len) } /******************************************************************************* ** -** Function btm_ble_find_dev_in_whitelist -** -** Description This function check if the device is in the white list -*******************************************************************************/ -BOOLEAN btm_ble_find_dev_in_whitelist(BD_ADDR bd_addr) -{ - tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; - UINT8 i; - - BTM_TRACE_EVENT0 ("btm_ble_find_dev_in_whitelist"); - - /* empty wl */ - if (p_cb->num_empty_filter == p_cb->max_filter_entries) - { - BTM_TRACE_DEBUG0("white list empty"); - return FALSE; - } - - for (i = 0; i < BTM_BLE_MAX_BG_CONN_DEV_NUM && i < p_cb->max_filter_entries; i ++) - { - if (memcmp(p_cb->bg_conn_dev_list[i], bd_addr, BD_ADDR_LEN) == 0) - return TRUE; - } - return FALSE; -} -/******************************************************************************* -** ** Function btm_ble_count_unconn_dev_in_whitelist ** -** Description This function check the number of unconnected device in white list. +** Description This function find the number of un-connected background device *******************************************************************************/ UINT8 btm_ble_count_unconn_dev_in_whitelist(void) { tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; - UINT8 count = 0, i; - BD_ADDR dummy_bda ={0}; - - BTM_TRACE_EVENT0 ("btm_ble_find_dev_in_whitelist"); + UINT8 i, count = 0; - for (i = 0; i < BTM_BLE_MAX_BG_CONN_DEV_NUM && i < p_cb->max_filter_entries; i ++) + for (i = 0; i < BTM_BLE_MAX_BG_CONN_DEV_NUM; i ++) { - if (memcmp(p_cb->bg_conn_dev_list[i], dummy_bda, BD_ADDR_LEN) != 0 && - !BTM_IsAclConnectionUp(p_cb->bg_conn_dev_list[i])) + if (p_cb->bg_dev_list[i].in_use && + !BTM_IsAclConnectionUp(p_cb->bg_dev_list[i].bd_addr)) { count ++; } } return count; + } /******************************************************************************* ** @@ -257,59 +215,63 @@ UINT8 btm_ble_count_unconn_dev_in_whitelist(void) ** ** Description This function update the local background connection device list. *******************************************************************************/ -BOOLEAN btm_update_bg_conn_list(BOOLEAN to_add, BD_ADDR bd_addr) +BOOLEAN btm_update_bg_conn_list(BOOLEAN to_add, BD_ADDR bd_addr, UINT8 *p_attr_tag) { - tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; - UINT8 i; - BD_ADDR dummy_bda = {0}; + UINT8 white_list_type = *p_attr_tag; + tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; + tBTM_LE_BG_CONN_DEV *p_bg_dev = &p_cb->bg_dev_list[0], *p_next, *p_cur; + UINT8 i, j; + BOOLEAN ret = FALSE; + BTM_TRACE_EVENT0 ("btm_update_bg_conn_list"); - if ((to_add && (p_cb->bg_conn_dev_num == BTM_BLE_MAX_BG_CONN_DEV_NUM || p_cb->num_empty_filter == 0)) || - (!to_add && p_cb->num_empty_filter == p_cb->max_filter_entries)) + + if ((to_add && (p_cb->bg_dev_num == BTM_BLE_MAX_BG_CONN_DEV_NUM || p_cb->num_empty_filter == 0))) { BTM_TRACE_DEBUG1("num_empty_filter = %d", p_cb->num_empty_filter); - return FALSE; + return ret; } - for (i = 0; i < BTM_BLE_MAX_BG_CONN_DEV_NUM && i < p_cb->max_filter_entries; i ++) + for (i = 0; i < BTM_BLE_MAX_BG_CONN_DEV_NUM; i ++, p_bg_dev ++) { - /* to add */ - if (memcmp(p_cb->bg_conn_dev_list[i], dummy_bda, BD_ADDR_LEN) == 0 && to_add) + if (p_bg_dev->in_use && memcmp(p_bg_dev->bd_addr, bd_addr, BD_ADDR_LEN) == 0) { - memcpy(p_cb->bg_conn_dev_list[i], bd_addr, BD_ADDR_LEN); - p_cb->bg_conn_dev_num ++; - return TRUE; + if (to_add) + p_bg_dev->attr |= white_list_type; + else + p_bg_dev->attr &= ~white_list_type; + + if (p_bg_dev->attr == 0) + { + memset(p_bg_dev, 0, sizeof(tBTM_LE_BG_CONN_DEV)); + p_cb->bg_dev_num --; + p_cur = p_bg_dev; + p_next = p_bg_dev + 1; + for (j = i + 1 ;j < BTM_BLE_MAX_BG_CONN_DEV_NUM && p_next->in_use ; j ++, p_cur ++, p_next ++ ) + memcpy(p_cur, p_next, sizeof(tBTM_LE_BG_CONN_DEV)); + } + ret = TRUE; + break; } - /* to remove */ - if (!to_add && memcmp(p_cb->bg_conn_dev_list[i], bd_addr, BD_ADDR_LEN) == 0) + else if (!p_bg_dev->in_use && to_add) { - memset(p_cb->bg_conn_dev_list[i], 0, BD_ADDR_LEN); - p_cb->bg_conn_dev_num --; - return TRUE; - } - } - return FALSE; -} -/******************************************************************************* -** -** Function btm_write_bg_conn_wl -** -** Description This function write background connection device list into -** controller. -*******************************************************************************/ -void btm_write_bg_conn_wl(void) -{ - tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; - UINT8 i; - BTM_TRACE_EVENT0 ("btm_write_bg_conn_wl"); - btm_ble_clear_white_list(); + BTM_TRACE_DEBUG0("add new WL entry in bg_dev_list"); - for (i = 0; i < p_cb->bg_conn_dev_num; i ++) - { - if (!btm_update_dev_to_white_list(TRUE, p_cb->bg_conn_dev_list[i], BLE_ADDR_PUBLIC)) + memcpy(p_bg_dev->bd_addr, bd_addr, BD_ADDR_LEN); + p_bg_dev->in_use = TRUE; + p_bg_dev->attr |= white_list_type; + p_cb->bg_dev_num ++; + + ret = TRUE; break; + } } - return; + + if (i != BTM_BLE_MAX_BG_CONN_DEV_NUM) + *p_attr_tag = p_bg_dev->attr; + + return ret; } + /******************************************************************************* ** ** Function btm_ble_start_auto_conn @@ -326,51 +288,58 @@ BOOLEAN btm_ble_start_auto_conn(BOOLEAN start) tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; BD_ADDR dummy_bda = {0}; BOOLEAN exec = TRUE; + UINT8 own_addr_type = BLE_ADDR_PUBLIC; UINT16 scan_int, scan_win; - scan_int = (p_cb->scan_int == BTM_BLE_CONN_PARAM_UNDEF) ? BTM_BLE_CONN_EST_SCAN_INT : p_cb->scan_int; - scan_win = (p_cb->scan_win == BTM_BLE_CONN_PARAM_UNDEF) ? BTM_BLE_CONN_EST_SCAN_WIND : p_cb->scan_win; - if (start) { - if (!l2cb.is_ble_connecting && - btm_ble_count_unconn_dev_in_whitelist() > 0) + if (p_cb->conn_state == BLE_CONN_IDLE && btm_ble_count_unconn_dev_in_whitelist() > 0) { - if (p_cb->bg_conn_state != BLE_BG_CONN_ACTIVE && p_cb->bg_conn_dev_num > 0) + + scan_int = (p_cb->scan_int == BTM_BLE_CONN_PARAM_UNDEF) ? BTM_BLE_SCAN_SLOW_INT_1 : p_cb->scan_int; + scan_win = (p_cb->scan_win == BTM_BLE_CONN_PARAM_UNDEF) ? BTM_BLE_SCAN_SLOW_WIN_1 : p_cb->scan_win; + + if (!btsnd_hcic_ble_create_ll_conn (scan_int, /* UINT16 scan_int */ + scan_win, /* UINT16 scan_win */ + 0x01, /* UINT8 white_list */ + BLE_ADDR_PUBLIC, /* UINT8 addr_type_peer */ + dummy_bda, /* BD_ADDR bda_peer */ + own_addr_type, /* UINT8 addr_type_own, not allow random address for central */ + BTM_BLE_CONN_INT_MIN_DEF, /* UINT16 conn_int_min */ + BTM_BLE_CONN_INT_MAX_DEF, /* UINT16 conn_int_max */ + BTM_BLE_CONN_SLAVE_LATENCY_DEF, /* UINT16 conn_latency */ + BTM_BLE_CONN_TIMEOUT_DEF, /* UINT16 conn_timeout */ + 0, /* UINT16 min_len */ + 0)) /* UINT16 max_len */ + { + /* start auto connection failed */ + exec = FALSE; + } + else { - if (!btsnd_hcic_ble_create_ll_conn (scan_int, /* UINT16 scan_int */ - scan_win, /* UINT16 scan_win */ - 0x01, /* UINT8 white_list */ - BLE_ADDR_PUBLIC, /* UINT8 addr_type_peer */ - dummy_bda, /* BD_ADDR bda_peer */ - BLE_ADDR_PUBLIC, /* UINT8 addr_type_own */ - BTM_BLE_CONN_INT_MIN_DEF, /* UINT16 conn_int_min */ - BTM_BLE_CONN_INT_MAX_DEF, /* UINT16 conn_int_max */ - BTM_BLE_CONN_SLAVE_LATENCY_DEF, /* UINT16 conn_latency */ - BTM_BLE_CONN_TIMEOUT_DEF, /* UINT16 conn_timeout */ - 0, /* UINT16 min_len */ - 0)) /* UINT16 max_len */ - { - /* start auto connection failed */ - exec = FALSE; - } - else - { - p_cb->bg_conn_state = BLE_BG_CONN_ACTIVE; - } + p_cb->conn_state = BLE_BG_CONN; + } } else + { exec = FALSE; + } } else { - if (p_cb->bg_conn_state == BLE_BG_CONN_ACTIVE) + if (p_cb->conn_state == BLE_BG_CONN) { - if (!btsnd_hcic_ble_create_conn_cancel()) - exec = FALSE; - else - p_cb->bg_conn_state = BLE_BG_CONN_IDLE; + btsnd_hcic_ble_create_conn_cancel(); + p_cb->conn_state = BLE_CONN_IDLE; + + } + else + { +#if 0 + BTM_TRACE_ERROR1("conn_st = %d, not in auto conn state, can not stop.", p_cb->conn_state); + exec = FALSE; +#endif } } return exec; @@ -396,16 +365,18 @@ BOOLEAN btm_ble_start_select_conn(BOOLEAN start,tBTM_BLE_SEL_CBACK *p_select_c BTM_TRACE_EVENT0 ("btm_ble_start_select_conn"); - scan_int = (p_cb->scan_int == BTM_BLE_CONN_PARAM_UNDEF) ? BTM_BLE_CONN_EST_SCAN_INT : p_cb->scan_int; - scan_win = (p_cb->scan_win == BTM_BLE_CONN_PARAM_UNDEF) ? BTM_BLE_CONN_EST_SCAN_WIND : p_cb->scan_win; + scan_int = (p_cb->scan_int == BTM_BLE_CONN_PARAM_UNDEF) ? BTM_BLE_SCAN_FAST_INT : p_cb->scan_int; + scan_win = (p_cb->scan_win == BTM_BLE_CONN_PARAM_UNDEF) ? BTM_BLE_SCAN_FAST_WIN : p_cb->scan_win; if (start) { - if (!btm_cb.btm_inq_vars.inq_active) + if (btm_cb.btm_inq_vars.inq_active == BTM_INQUIRY_INACTIVE) { - btm_cb.ble_ctr_cb.p_select_cback = p_select_cback; + if (p_select_cback != NULL) + btm_cb.ble_ctr_cb.p_select_cback = p_select_cback; btm_update_scanner_filter_policy(SP_ADV_WL); + btm_cb.ble_ctr_cb.inq_var.scan_type = BTM_BLE_SCAN_MODE_PASS; if (!btsnd_hcic_ble_set_scan_params(BTM_BLE_SCAN_MODE_PASS, /* use passive scan by default */ scan_int, /* scan interval */ @@ -415,23 +386,22 @@ BOOLEAN btm_ble_start_select_conn(BOOLEAN start,tBTM_BLE_SEL_CBACK *p_select_c ) return FALSE; - if (p_cb->inq_var.adv_mode == BTM_BLE_ADV_ENABLE) + if (p_cb->inq_var.adv_mode == BTM_BLE_ADV_ENABLE + ) { BTM_TRACE_ERROR0("peripheral device cannot initiate a selective connection"); return FALSE; } - else if (p_cb->bg_conn_dev_num > 0 && btm_ble_count_unconn_dev_in_whitelist() > 0 ) + else if (p_cb->bg_dev_num > 0 && btm_ble_count_unconn_dev_in_whitelist() > 0 ) { if (!btsnd_hcic_ble_set_scan_enable(TRUE, TRUE)) /* duplicate filtering enabled */ return FALSE; /* mark up inquiry status flag */ - btm_cb.btm_inq_vars.inq_active = TRUE; - btm_cb.ble_ctr_cb.inq_var.proc_mode = BTM_BLE_SELECT_SCAN; - - p_cb->bg_conn_state = BLE_BG_CONN_ACTIVE; - + btm_cb.btm_inq_vars.inq_active |= BTM_LE_SELECT_CONN_ACTIVE; + p_cb->inq_var.proc_mode = BTM_BLE_SELECT_SCAN; + p_cb->conn_state = BLE_BG_CONN; } } else @@ -442,14 +412,12 @@ BOOLEAN btm_ble_start_select_conn(BOOLEAN start,tBTM_BLE_SEL_CBACK *p_select_c } else /* disable selective connection mode */ { - p_cb->p_select_cback = NULL; - btm_cb.btm_inq_vars.inq_active = FALSE; + btm_cb.btm_inq_vars.inq_active &= ~BTM_LE_SELECT_CONN_ACTIVE; btm_cb.ble_ctr_cb.inq_var.proc_mode = BTM_BLE_INQUIRY_NONE; btm_update_scanner_filter_policy(SP_ADV_ALL); - /* stop scanning */ - if (p_cb->bg_conn_dev_num > 0) + if (p_cb->bg_dev_num > 0) { if (!btsnd_hcic_ble_set_scan_enable(FALSE, TRUE)) /* duplicate filtering enabled */ return FALSE; @@ -472,9 +440,7 @@ BOOLEAN btm_ble_start_select_conn(BOOLEAN start,tBTM_BLE_SEL_CBACK *p_select_c *******************************************************************************/ void btm_ble_initiate_select_conn(BD_ADDR bda) { - UINT8 addr_type; BTM_TRACE_EVENT0 ("btm_ble_initiate_select_conn"); - addr_type = btm_ble_map_bda_to_conn_bda(bda); /* use direct connection procedure to initiate connection */ if (!L2CA_ConnectFixedChnl(L2CAP_ATT_CID, bda)) @@ -484,7 +450,7 @@ void btm_ble_initiate_select_conn(BD_ADDR bda) } /******************************************************************************* ** -** Function btm_ble_suspend_bg_sele_conn +** Function btm_ble_suspend_bg_conn ** ** Description This function is to suspend an active background connection ** procedure. @@ -494,50 +460,63 @@ void btm_ble_initiate_select_conn(BD_ADDR bda) ** Returns none. ** *******************************************************************************/ -void btm_ble_suspend_bg_sele_conn(void) +void btm_ble_suspend_bg_conn(void) { tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; - BTM_TRACE_EVENT0 ("btm_ble_suspend_bg_sele_conn"); + BTM_TRACE_EVENT0 ("btm_ble_suspend_bg_conn"); - if (p_cb->bg_conn_type == BTM_BLE_CONN_SELECTIVE) + if (p_cb->bg_conn_type == BTM_BLE_CONN_AUTO) + { + btm_ble_start_auto_conn(FALSE); + } + else if (p_cb->bg_conn_type == BTM_BLE_CONN_SELECTIVE) { - p_cb->bg_conn_state = BLE_BG_CONN_SUSPEND; btm_ble_start_select_conn(FALSE, NULL); } } /******************************************************************************* ** -** Function btm_ble_suspend_bg_conn -** -** Description This function is to suspend an active background connection -** procedure. +** Function btm_suspend_wl_activity ** -** Parameters none. +** Description This function is to suspend white list related activity ** ** Returns none. ** *******************************************************************************/ -void btm_ble_suspend_bg_conn(void) +static void btm_suspend_wl_activity(tBTM_BLE_WL_STATE wl_state) { - tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; - BTM_TRACE_EVENT0 ("btm_ble_suspend_bg_conn"); - - if (p_cb->bg_conn_type == BTM_BLE_CONN_AUTO) + if (wl_state & BTM_BLE_WL_INIT) + { + btm_ble_start_auto_conn(FALSE); + } + if (wl_state & BTM_BLE_WL_SCAN) { - if (btm_ble_start_auto_conn(FALSE)) - p_cb->bg_conn_state = BLE_BG_CONN_SUSPEND; + btm_ble_start_select_conn(FALSE, NULL); } + if (wl_state & BTM_BLE_WL_ADV) + { + btsnd_hcic_ble_set_adv_enable(BTM_BLE_ADV_DISABLE); + } + } /******************************************************************************* ** -** Function btm_ble_scan_param_idle +** Function btm_resume_wl_activity ** -** Description This function is to process the scan parameter idle timeout -** timeout. -********************************************************************************/ -void btm_ble_scan_param_idle(void) +** Description This function is to resume white list related activity +** +** Returns none. +** +*******************************************************************************/ +static void btm_resume_wl_activity(tBTM_BLE_WL_STATE wl_state) { - BTM_BleSetConnScanParams(BTM_BLE_CONN_EST_SCAN_INT_LO, BTM_BLE_CONN_EST_SCAN_WIND_LO); + btm_ble_resume_bg_conn(); + + if (wl_state & BTM_BLE_WL_ADV) + { + btsnd_hcic_ble_set_adv_enable(BTM_BLE_ADV_ENABLE); + } + } /******************************************************************************* ** @@ -551,66 +530,91 @@ void btm_ble_scan_param_idle(void) ** Returns none. ** *******************************************************************************/ -BOOLEAN btm_ble_resume_bg_conn(tBTM_BLE_SEL_CBACK *p_sele_callback, BOOLEAN def_param) +BOOLEAN btm_ble_resume_bg_conn(void) { tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; BOOLEAN ret = FALSE; - if (p_cb->bg_conn_state != BLE_BG_CONN_ACTIVE ) + if (p_cb->bg_conn_type != BTM_BLE_CONN_NONE) { - if (def_param) - { - p_cb->scan_int = BTM_BLE_CONN_PARAM_UNDEF; - p_cb->scan_win = BTM_BLE_CONN_PARAM_UNDEF; - - /* start scan param idle timer */ - btu_start_timer(&p_cb->scan_param_idle_timer, - BTU_TTYPE_BLE_SCAN_PARAM_IDLE, - BTM_BLE_SCAN_PARAM_TOUT); - } - if (p_cb->bg_conn_type == BTM_BLE_CONN_AUTO) ret = btm_ble_start_auto_conn(TRUE); if (p_cb->bg_conn_type == BTM_BLE_CONN_SELECTIVE) - { - /* terminate selective connection mode if all devices are connected */ - if (btm_ble_count_unconn_dev_in_whitelist() == 0) - { - btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_DISABLE); - btm_cb.ble_ctr_cb.inq_var.proc_mode = BTM_BLE_INQUIRY_NONE; - btm_cb.btm_inq_vars.inq_active = FALSE; - } - else if (!btm_cb.btm_inq_vars.inq_active) - btm_ble_start_select_conn(TRUE, btm_cb.ble_ctr_cb.p_select_cback); - } - - if (ret) - p_cb->bg_conn_state = BLE_BG_CONN_ACTIVE; - + ret = btm_ble_start_select_conn(TRUE, btm_cb.ble_ctr_cb.p_select_cback); } return ret; } /******************************************************************************* ** -** Function btm_ble_update_bg_state +** Function btm_ble_get_conn_st ** -** Description This function is to update the bg connection status. +** Description This function get BLE connection state ** -** Parameters none. +** Returns connection state ** -** Returns none. +*******************************************************************************/ +tBTM_BLE_CONN_ST btm_ble_get_conn_st(void) +{ + return btm_cb.ble_ctr_cb.conn_state; +} +/******************************************************************************* +** +** Function btm_ble_set_conn_st +** +** Description This function set BLE connection state +** +** Returns None. ** *******************************************************************************/ -void btm_ble_update_bg_state(void) +void btm_ble_set_conn_st(tBTM_BLE_CONN_ST new_st) { - tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; + btm_cb.ble_ctr_cb.conn_state = new_st; +} - if (!l2cb.is_ble_connecting && (p_cb->bg_conn_state != BLE_BG_CONN_SUSPEND)) - p_cb->bg_conn_state = BLE_BG_CONN_IDLE; +/******************************************************************************* +** +** Function btm_ble_enqueue_direct_conn_req +** +** Description This function enqueue the direct connection request +** +** Returns None. +** +*******************************************************************************/ +void btm_ble_enqueue_direct_conn_req(void *p_param) +{ + tBTM_BLE_CONN_REQ *p = (tBTM_BLE_CONN_REQ *)GKI_getbuf(sizeof(tBTM_BLE_CONN_REQ)); + p->p_param = p_param; + + GKI_enqueue (&btm_cb.ble_ctr_cb.conn_pending_q, p); } +/******************************************************************************* +** +** Function btm_send_pending_direct_conn +** +** Description This function send the pending direct connection request in queue +** +** Returns TRUE if started, FALSE otherwise +** +*******************************************************************************/ +BOOLEAN btm_send_pending_direct_conn(void ) +{ + tBTM_BLE_CONN_REQ *p_req; + BOOLEAN rt = FALSE; + + if ( btm_cb.ble_ctr_cb.conn_pending_q.count ) + { + p_req = (tBTM_BLE_CONN_REQ*)GKI_dequeue (&btm_cb.ble_ctr_cb.conn_pending_q); + rt = l2cble_init_direct_conn((tL2C_LCB *)(p_req->p_param)); + + GKI_freebuf((void *)p_req); + } + + return rt; +} #endif + diff --git a/stack/btm/btm_ble_gap.c b/stack/btm/btm_ble_gap.c index b9e17c0f9..d13e36bce 100644 --- a/stack/btm/btm_ble_gap.c +++ b/stack/btm/btm_ble_gap.c @@ -33,23 +33,16 @@ #if (GAP_INCLUDED == TRUE) #include "gap_api.h" #endif - #if (BLE_INCLUDED == TRUE) +#include "gattdefs.h" + #define BTM_BLE_NAME_SHORT 0x01 #define BTM_BLE_NAME_CMPL 0x02 #define BTM_BLE_FILTER_TARGET_UNKNOWN 0xff #define BTM_BLE_POLICY_UNKNOWN 0xff -#define BLE_RESOLVE_ADDR_MSB 0x40 /* most significant bit, bit7, bit6 is 01 to be resolvable random */ -#define BLE_RESOLVE_ADDR_MASK 0xc0 /* bit 6, and bit7 */ -#define BTM_BLE_IS_RESOLVE_BDA(x) ((x[0] & BLE_RESOLVE_ADDR_MASK) == BLE_RESOLVE_ADDR_MSB) - #define BTM_EXT_BLE_RMT_NAME_TIMEOUT 30 -static tBLE_BD_ADDR le_bda_any ={BLE_ADDR_PUBLIC, {0x00,0x00,0x00,0x00,0x00,0x00}}; - - -#define BTM_BLE_VALID_CONN_DIRECT(x) (memcmp(&le_bda_any, x, sizeof(tBLE_BD_ADDR)) != 0) /******************************************************************************* ** Local functions @@ -57,11 +50,12 @@ static tBLE_BD_ADDR le_bda_any ={BLE_ADDR_PUBLIC, {0x00,0x00,0x00,0x00,0x00,0x00 static void btm_ble_update_adv_flag(UINT8 flag); static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt_type, UINT8 *p); static UINT8 *btm_ble_build_adv_data(tBTM_BLE_AD_MASK *p_data_mask, UINT8 **p_dst, tBTM_BLE_ADV_DATA *p_data); - - - - - +static UINT8 btm_set_conn_mode_adv_init_addr(tBTM_BLE_INQ_CB *p_cb, + BD_ADDR_PTR p_addr_ptr, + tBLE_ADDR_TYPE *p_init_addr_type, + tBLE_ADDR_TYPE *p_own_addr_type); +static BOOLEAN btm_ble_start_adv(void); +static tBTM_STATUS btm_ble_stop_adv(void); @@ -80,9 +74,65 @@ void BTM_BleReset(void) { btsnd_hcic_ble_reset(); } +/******************************************************************************* +** +** Function BTM_BleUpdateAdvWhitelist +** +** Description Add or remove device from advertising white list +** +** Returns void +** +*******************************************************************************/ +BOOLEAN BTM_BleUpdateAdvWhitelist(BOOLEAN add_remove, BD_ADDR remote_bda) +{ + return FALSE; +} /******************************************************************************* ** +** Function BTM_BleUpdateAdvFilterPolicy +** +** Description This function update the filter policy of advertiser. +** +** Parameter adv_policy: advertising filter policy +** +** Return void +*******************************************************************************/ +void BTM_BleUpdateAdvFilterPolicy(tBTM_BLE_AFP adv_policy) +{ + tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var; + tBLE_ADDR_TYPE init_addr_type = BLE_ADDR_PUBLIC; + BD_ADDR p_addr_ptr= {0}; + UINT8 adv_mode = p_cb->adv_mode; + + BTM_TRACE_EVENT0 ("BTM_BleUpdateAdvFilterPolicy"); + + if (p_cb->afp != adv_policy) + { + p_cb->afp = adv_policy; + + /* if adv active, stop and restart */ + btm_ble_stop_adv (); + + if (p_cb->connectable_mode & BTM_BLE_CONNECTABLE) + p_cb->evt_type = btm_set_conn_mode_adv_init_addr(p_cb, p_addr_ptr, &init_addr_type, &p_cb->adv_addr_type); + + btsnd_hcic_ble_write_adv_params (p_cb->adv_interval_min, + p_cb->adv_interval_max, + p_cb->evt_type, + p_cb->adv_addr_type, + init_addr_type, + p_addr_ptr, + p_cb->adv_chnl_map, + p_cb->afp); + + if (adv_mode == BTM_BLE_ADV_ENABLE) + btm_ble_start_adv (); + + } +} +/******************************************************************************* +** ** Function BTM_BleObserve ** ** Description This procedure keep the device listening for advertising @@ -104,14 +154,16 @@ tBTM_STATUS BTM_BleObserve(BOOLEAN start, UINT8 duration, if (start) { - if (p_inq->proc_mode != BTM_BLE_INQUIRY_NONE) + /* shared inquiry database, do not allow observe if any inquiry is active */ + if (btm_cb.btm_inq_vars.inq_active || p_inq->proc_mode != BTM_BLE_INQUIRY_NONE) return BTM_BUSY; btm_cb.btm_inq_vars.p_inq_results_cb = p_results_cb; btm_cb.btm_inq_vars.p_inq_cmpl_cb = p_cmpl_cb; + p_inq->scan_type = (p_inq->scan_type == BTM_BLE_SCAN_MODE_NONE) ? BTM_BLE_SCAN_MODE_ACTI: p_inq->scan_type; /* allow config scanning type */ - if (btsnd_hcic_ble_set_scan_params ((UINT8)((p_inq->scan_type == BTM_BLE_SCAN_MODE_NONE) ? BTM_BLE_SCAN_MODE_ACTI: p_inq->scan_type), + if (btsnd_hcic_ble_set_scan_params (p_inq->scan_type, (UINT16)(!p_inq->scan_interval ? BTM_BLE_GAP_DISC_SCAN_INT : p_inq->scan_interval), (UINT16)(!p_inq->scan_window ? BTM_BLE_GAP_DISC_SCAN_WIN : p_inq->scan_window), BLE_ADDR_PUBLIC, @@ -122,7 +174,7 @@ tBTM_STATUS BTM_BleObserve(BOOLEAN start, UINT8 duration, { status = BTM_SUCCESS; p_inq->proc_mode = BTM_BLE_OBSERVE; - btm_cb.btm_inq_vars.inq_active = TRUE; + btm_cb.btm_inq_vars.inq_active |= BTM_LE_OBSERVE_ACTIVE; if (duration != 0) { @@ -134,6 +186,7 @@ tBTM_STATUS BTM_BleObserve(BOOLEAN start, UINT8 duration, } else if (p_inq->proc_mode == BTM_BLE_OBSERVE) { + btm_cb.btm_inq_vars.inq_active &= ~BTM_LE_OBSERVE_ACTIVE; btm_ble_stop_scan(); } @@ -154,6 +207,7 @@ tBTM_STATUS BTM_BleObserve(BOOLEAN start, UINT8 duration, tBTM_STATUS BTM_BleBroadcast(BOOLEAN start) { tBTM_STATUS status = BTM_NO_RESOURCES; + tBTM_LE_RANDOM_CB *p_addr_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb; tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var; UINT8 evt_type = p_cb->scan_rsp ? BTM_BLE_DISCOVER_EVT: BTM_BLE_NON_CONNECT_EVT; @@ -170,8 +224,9 @@ tBTM_STATUS BTM_BleBroadcast(BOOLEAN start) if (!btsnd_hcic_ble_write_adv_params ((UINT16)(p_cb->adv_interval_min ? p_cb->adv_interval_min : BTM_BLE_GAP_ADV_INT), (UINT16)(p_cb->adv_interval_max ? p_cb->adv_interval_max : BTM_BLE_GAP_ADV_INT), evt_type, - p_cb->own_addr_type, - p_cb->direct_bda.type, p_cb->direct_bda.bda, + p_addr_cb->own_addr_type, + p_cb->direct_bda.type, + p_cb->direct_bda.bda, p_cb->adv_chnl_map, p_cb->afp)) @@ -179,21 +234,11 @@ tBTM_STATUS BTM_BleBroadcast(BOOLEAN start) else p_cb->evt_type = evt_type; - if (btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_ENABLE)) - { - p_cb->adv_mode = BTM_BLE_ADV_ENABLE; - - status = BTM_SUCCESS; - } + status = btm_ble_start_adv (); } else if (!start && p_cb->adv_mode == BTM_BLE_ADV_ENABLE) { - if (btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE)) - { - p_cb->adv_mode = BTM_BLE_ADV_DISABLE; - - status = BTM_SUCCESS; - } + status = btm_ble_stop_adv(); } else { @@ -201,16 +246,9 @@ tBTM_STATUS BTM_BleBroadcast(BOOLEAN start) BTM_TRACE_ERROR2("Can not %s Broadcast, device %s in Broadcast mode", (start ? "Start" : "Stop"), (start ? "alerady" :"not")); } - return status; } - - - - - - /******************************************************************************* ** ** Function BTM_RegisterScanReqEvt @@ -226,32 +264,14 @@ tBTM_STATUS BTM_BleBroadcast(BOOLEAN start) *******************************************************************************/ void BTM_RegisterScanReqEvt(tBTM_BLE_SCAN_REQ_CBACK *p_scan_req_cback) { -#ifdef BTM_BLE_PC_ADV_TEST_MODE // For general stack code (e.g. BTInsight testing), we simply do not define it to exclude or set it to TRUE to include - if (BTM_BLE_PC_ADV_TEST_MODE) // For stack component, it is always defined and maps to a global variable g_bDraculaAdvertisingMode +#ifdef BTM_BLE_PC_ADV_TEST_MODE /* For general stack code (e.g. BTInsight testing), we simply do not define it to exclude or set it to TRUE to include */ + if (BTM_BLE_PC_ADV_TEST_MODE) /* For stack component, it is always defined and maps to a global variable g_bDraculaAdvertisingMode */ { tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; p_cb->p_scan_req_cback = p_scan_req_cback; } #endif } -/******************************************************************************* -** -** Function BTM_BleConfigPrivacy -** -** Description This function is called to enable or disable the privacy in -** the local device. -** -** Parameters enable: TRUE to enable it; FALSE to disable it. -** -** Returns void -** -*******************************************************************************/ -void BTM_BleConfigPrivacy(BOOLEAN enable) -{ - tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; - BTM_TRACE_EVENT0 (" BTM_BleConfigPrivacy"); - p_cb->privacy = enable; -} /******************************************************************************* ** @@ -331,46 +351,8 @@ BOOLEAN BTM_BleSetBgConnType(tBTM_BLE_CONN_TYPE bg_conn_type, *******************************************************************************/ BOOLEAN BTM_BleUpdateBgConnDev(BOOLEAN add_remove, BD_ADDR remote_bda) { - tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; - tBTM_BLE_SEL_CBACK *p_select_cback; BOOLEAN ret = TRUE; - BTM_TRACE_EVENT0 (" BTM_BleUpdateBgConnDev"); - - /* if auto connection is active */ - if (p_cb->bg_conn_state == BLE_BG_CONN_ACTIVE) - { - if (p_cb->bg_conn_type == BTM_BLE_CONN_AUTO) - { - /* terminate auto connection first */ - ret = btm_ble_start_auto_conn(FALSE); - } - else if (p_cb->bg_conn_type == BTM_BLE_CONN_SELECTIVE) - { - p_select_cback = btm_cb.ble_ctr_cb.p_select_cback; - ret = btm_ble_start_select_conn(FALSE, NULL); - } - } - if (ret) - { - /* update white list */ - ret = btm_update_bg_conn_list(add_remove, remote_bda); - btm_update_dev_to_white_list(add_remove, remote_bda, BLE_ADDR_PUBLIC); - } - - if (ret && p_cb->bg_conn_state == BLE_BG_CONN_IDLE) - { - if (p_cb->bg_conn_type == BTM_BLE_CONN_AUTO) - { - /* restart auto connection */ - btm_ble_start_auto_conn(TRUE); - } - else if (p_cb->bg_conn_type == BTM_BLE_CONN_SELECTIVE) - { - p_select_cback = btm_cb.ble_ctr_cb.p_select_cback; - btm_ble_start_select_conn(TRUE, p_select_cback); - } - } return ret; } @@ -387,44 +369,49 @@ BOOLEAN BTM_BleUpdateBgConnDev(BOOLEAN add_remove, BD_ADDR remote_bda) ** Returns void ** *******************************************************************************/ -tBTM_STATUS BTM_BleSetConnMode(BOOLEAN directed, tBLE_BD_ADDR *p_dir_bda) +tBTM_STATUS BTM_BleSetConnMode(BOOLEAN is_directed) { tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var; - tBTM_STATUS status = BTM_SUCCESS; - BD_ADDR reconn_bda; - BTM_TRACE_EVENT0 ("BTM_BleSetConnMode "); + BTM_TRACE_EVENT1 ("BTM_BleSetConnMode is_directed = %d ", is_directed); - memcpy(&p_cb->direct_bda, &le_bda_any, sizeof(tBLE_BD_ADDR)); - p_cb->own_addr_type = BLE_ADDR_PUBLIC; + p_cb->directed_conn = is_directed; + return btm_ble_set_connectability( p_cb->connectable_mode); - if (directed) - { - if (p_dir_bda) - { - memcpy(&p_cb->direct_bda, p_dir_bda, sizeof(tBLE_BD_ADDR)); +} - if (btm_cb.ble_ctr_cb.privacy /* && GAP privacy ad reconnect addr exist */) - { - /* write reconnect address to controller*/ - btsnd_hcic_ble_set_random_addr(reconn_bda); - } - /* else use static address or publich address */ +/******************************************************************************* +** +** Function btm_set_conn_mode_adv_init_addr +** +** Description set initator address type and local address type based on adv +** mode. +** +** +*******************************************************************************/ +static UINT8 btm_set_conn_mode_adv_init_addr(tBTM_BLE_INQ_CB *p_cb, + BD_ADDR_PTR p_addr_ptr, + tBLE_ADDR_TYPE *p_init_addr_type, + tBLE_ADDR_TYPE *p_own_addr_type) +{ + UINT8 evt_type; - } - else - status = BTM_ILLEGAL_VALUE; + if ( p_cb->directed_conn) + { + /* direct adv mode does not have privacy if privacy + is not enabled or no reconn addr config */ + *p_own_addr_type = BLE_ADDR_PUBLIC; + *p_init_addr_type = p_cb->direct_bda.type; + memcpy(p_addr_ptr, p_cb->direct_bda.bda, BD_ADDR_LEN); + evt_type = BTM_BLE_CONNECT_DIR_EVT; } - else /* undirected connecatable */ + else /* undirect adv mode */ { - if (btm_cb.ble_ctr_cb.privacy /* GAP privacy flag enabled */) - { - /* generate resolvable private address */ - btm_gen_resolvable_private_addr(); - } /* else use publich address */ - + evt_type = BTM_BLE_CONNECT_EVT; } - return status; + + return evt_type; + } /******************************************************************************* @@ -445,8 +432,13 @@ tBTM_STATUS BTM_BleSetAdvParams(UINT16 adv_int_min, UINT16 adv_int_max, tBLE_BD_ADDR *p_dir_bda, tBTM_BLE_ADV_CHNL_MAP chnl_map) { + tBTM_LE_RANDOM_CB *p_addr_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb; tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var; tBTM_STATUS status = BTM_SUCCESS; + BD_ADDR p_addr_ptr = {0}; + tBLE_ADDR_TYPE init_addr_type = BLE_ADDR_PUBLIC; + tBLE_ADDR_TYPE own_addr_type = p_addr_cb->own_addr_type; + UINT8 adv_mode = p_cb->adv_mode; BTM_TRACE_EVENT0 ("BTM_BleSetAdvParams"); @@ -464,46 +456,26 @@ tBTM_STATUS BTM_BleSetAdvParams(UINT16 adv_int_min, UINT16 adv_int_max, { memcpy(&p_cb->direct_bda, p_dir_bda, sizeof(tBLE_BD_ADDR)); } - else - memcpy(&p_cb->direct_bda, &le_bda_any, sizeof(tBLE_BD_ADDR)); - if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE) - { - BTM_TRACE_EVENT0 ("update params for an active adv"); + BTM_TRACE_EVENT0 ("update params for an active adv"); - if (p_cb->connectable_mode == BTM_BLE_NON_CONNECTABLE) - { - if (BTM_BLE_VALID_CONN_DIRECT(&p_cb->direct_bda)) - p_cb->evt_type = BTM_BLE_CONNECT_DIR_EVT; - else - p_cb->evt_type = BTM_BLE_CONNECT_EVT; + btm_ble_stop_adv(); - BTM_TRACE_DEBUG1(" evt_type = %d", p_cb->evt_type); - } + if (p_cb->connectable_mode & BTM_BLE_CONNECTABLE) + p_cb->evt_type = btm_set_conn_mode_adv_init_addr(p_cb, p_addr_ptr, &init_addr_type, &own_addr_type); - if (!btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE)) - status = BTM_NO_RESOURCES; - else - /* update adv params */ - if (!btsnd_hcic_ble_write_adv_params (p_cb->adv_interval_min, - p_cb->adv_interval_max, - p_cb->evt_type, - p_cb->own_addr_type, - p_cb->direct_bda.type, - p_cb->direct_bda.bda, - p_cb->adv_chnl_map, - p_cb->afp)) + /* update adv params */ + btsnd_hcic_ble_write_adv_params (p_cb->adv_interval_min, + p_cb->adv_interval_max, + p_cb->evt_type, + own_addr_type, + init_addr_type, + p_addr_ptr, + p_cb->adv_chnl_map, + p_cb->afp); - status = BTM_NO_RESOURCES; - - else if (!btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_ENABLE)) - { - p_cb->adv_mode = BTM_BLE_ADV_DISABLE; - - status = BTM_NO_RESOURCES; - } - - } + if (adv_mode == BTM_BLE_ADV_ENABLE) + btm_ble_start_adv(); return status; } @@ -539,7 +511,6 @@ void BTM_BleReadAdvParams (UINT16 *adv_int_min, UINT16 *adv_int_max, } } - /******************************************************************************* ** ** Function BTM_BleSetScanParams @@ -606,7 +577,7 @@ tBTM_STATUS BTM_BleWriteScanRsp(tBTM_BLE_AD_MASK data_mask, tBTM_BLE_ADV_DATA *p { status = BTM_SUCCESS; - if (p_data != NULL) + if (data_mask != 0) btm_cb.ble_ctr_cb.inq_var.scan_rsp = TRUE; else btm_cb.ble_ctr_cb.inq_var.scan_rsp = FALSE; @@ -711,7 +682,6 @@ static UINT8 *btm_ble_build_adv_data(tBTM_BLE_AD_MASK *p_data_mask, UINT8 **p_ds *p_flag = NULL; UINT16 len = BTM_BLE_AD_DATA_LEN, cp_len = 0; UINT8 i = 0; - tBTM_BLE_ATTR *p_attr; tBTM_BLE_PROP_ELEM *p_elem; BTM_TRACE_EVENT0 (" btm_ble_build_adv_data"); @@ -734,7 +704,18 @@ static UINT8 *btm_ble_build_adv_data(tBTM_BLE_AD_MASK *p_data_mask, UINT8 **p_ds data_mask &= ~BTM_BLE_AD_BIT_FLAGS; } + /* appearance data */ + if (len > 3 && data_mask & BTM_BLE_AD_BIT_APPEARANCE) + { + *p++ = 3; /* length */ + *p++ = BTM_BLE_AD_TYPE_APPEARANCE; + UINT16_TO_STREAM(p, p_data->appearance); + len -= 4; + + data_mask &= ~BTM_BLE_AD_BIT_APPEARANCE; + } /* device name */ +#if BTM_MAX_LOC_BD_NAME_LEN > 0 if (len > 2 && data_mask & BTM_BLE_AD_BIT_DEV_NAME) { if (strlen(btm_cb.cfg.bd_name) > (UINT16)(len - 2)) @@ -750,10 +731,10 @@ static UINT8 *btm_ble_build_adv_data(tBTM_BLE_AD_MASK *p_data_mask, UINT8 **p_ds *p++ = BTM_BLE_AD_TYPE_NAME_CMPL; ARRAY_TO_STREAM(p, btm_cb.cfg.bd_name, cp_len); } - len -= (cp_len + 2); data_mask &= ~BTM_BLE_AD_BIT_DEV_NAME; } +#endif /* manufacturer data */ if (len > 2 && data_mask & BTM_BLE_AD_BIT_MANU && p_data && p_data->manu.len != 0 && p_data->manu.p_val) @@ -789,13 +770,13 @@ static UINT8 *btm_ble_build_adv_data(tBTM_BLE_AD_MASK *p_data_mask, UINT8 **p_ds { cp_len = (len - 2)/2; *p ++ = 1 + cp_len * 2; - *p++ = BTM_BLE_AD_TYPE_SRV_PART; + *p++ = BTM_BLE_AD_TYPE_16SRV_PART; } else { cp_len = p_data->services.num_service; *p++ = 1 + cp_len * 2; - *p++ = BTM_BLE_AD_TYPE_SRV_CMPL; + *p++ = BTM_BLE_AD_TYPE_16SRV_CMPL; } for (i = 0; i < cp_len; i ++) { @@ -815,27 +796,6 @@ static UINT8 *btm_ble_build_adv_data(tBTM_BLE_AD_MASK *p_data_mask, UINT8 **p_ds len -= 6; data_mask &= ~BTM_BLE_AD_BIT_INT_RANGE; } - if (data_mask & BTM_BLE_AD_BIT_ATTR && p_data && p_data->attr.num_attr != 0) - { - for (i = 0; i < p_data->attr.num_attr ; i ++) - { - p_attr = p_data->attr.attr_list + i; - - if (len >= (2 + 2 + p_attr->data_len))/* len byte(1) + ATTR type(1) + Uuid len(2) + value length */ - { - *p ++ = p_attr->data_len + 2 + 1; /* Uuid len + value length */ - *p ++ = BTM_BLE_AD_TYPE_ATTR; - UINT16_TO_STREAM(p, p_attr->uuid); - ARRAY_TO_STREAM(p, p_attr->p_data, p_attr->data_len); - - len -= (4 + p_attr->data_len); - } - else - break; - } - if (i == p_data->attr.num_attr) - data_mask &= ~BTM_BLE_AD_BIT_ATTR; - } if (data_mask & BTM_BLE_AD_BIT_PROPRIETARY && p_data && p_data->p_proprietary) { for (i = 0; i < p_data->p_proprietary->num_elem ; i ++) @@ -879,6 +839,7 @@ static UINT8 *btm_ble_build_adv_data(tBTM_BLE_AD_MASK *p_data_mask, UINT8 **p_ds *******************************************************************************/ tBTM_STATUS btm_ble_set_discoverability(UINT16 combined_mode) { + tBTM_LE_RANDOM_CB *p_addr_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb; tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var; UINT16 mode = (combined_mode & BTM_BLE_DISCOVERABLE_MASK); UINT8 flag = 0; @@ -887,6 +848,9 @@ tBTM_STATUS btm_ble_set_discoverability(UINT16 combined_mode) ((p_cb->scan_rsp) ? BTM_BLE_DISCOVER_EVT : BTM_BLE_NON_CONNECT_EVT )\ : BTM_BLE_CONNECT_EVT; tBTM_STATUS status = BTM_SUCCESS; + BD_ADDR p_addr_ptr= {0}; + tBLE_ADDR_TYPE init_addr_type = BLE_ADDR_PUBLIC, + own_addr_type = p_addr_cb->own_addr_type;; BTM_TRACE_EVENT2 ("btm_ble_set_discoverability mode=0x%0x combined_mode=0x%x", mode, combined_mode); @@ -925,55 +889,47 @@ tBTM_STATUS btm_ble_set_discoverability(UINT16 combined_mode) BTM_TRACE_EVENT0 ("always disable adv in non-discoverable non-connectable mode if no scan rsp "); if (!p_cb->scan_rsp ) new_mode = BTM_BLE_ADV_DISABLE; + } else { - if (BTM_BLE_VALID_CONN_DIRECT(&p_cb->direct_bda)) - { - BTM_TRACE_DEBUG0("evt_type = BTM_BLE_CONNECT_DIR_EVT"); - evt_type = BTM_BLE_CONNECT_DIR_EVT; - } - else - { - BTM_TRACE_DEBUG0(" evt_type = BTM_BLE_CONNECT_EVT"); - evt_type = BTM_BLE_CONNECT_EVT; - } + p_cb->evt_type = btm_set_conn_mode_adv_init_addr(p_cb, p_addr_ptr, &init_addr_type, &own_addr_type); } } btm_ble_update_adv_flag(flag); /* update adv params if start advertising */ BTM_TRACE_EVENT2 ("evt_type=0x%x p-cb->evt_type=0x%x ", evt_type, p_cb->evt_type); - if (new_mode == BTM_BLE_ADV_ENABLE && evt_type != p_cb->evt_type) + if (new_mode == BTM_BLE_ADV_ENABLE && + (evt_type != p_cb->evt_type ||p_cb->adv_addr_type != own_addr_type)) { - if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE) - { - BTM_TRACE_EVENT0 ("Set Adv disable"); - p_cb->adv_mode = BTM_BLE_ADV_DISABLE; - btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE); - } + btm_ble_stop_adv(); /* update adv params */ if (!btsnd_hcic_ble_write_adv_params ((UINT16)(p_cb->adv_interval_min ? p_cb->adv_interval_min : BTM_BLE_GAP_ADV_INT), (UINT16)(p_cb->adv_interval_max ? p_cb->adv_interval_max : BTM_BLE_GAP_ADV_INT), evt_type, - p_cb->own_addr_type, - p_cb->direct_bda.type, p_cb->direct_bda.bda, + own_addr_type, + init_addr_type, + p_addr_ptr, p_cb->adv_chnl_map, p_cb->afp)) status = BTM_NO_RESOURCES; else + { p_cb->evt_type = evt_type; + p_cb->adv_addr_type = own_addr_type; + } } + if (status == BTM_SUCCESS && p_cb->adv_mode != new_mode) { - /* update advertising mode */ - if (!btsnd_hcic_ble_set_adv_enable (new_mode)) - status = BTM_NO_RESOURCES; + if (new_mode == BTM_BLE_ADV_ENABLE) + status = btm_ble_start_adv(); else - p_cb->adv_mode = new_mode; + status = btm_ble_stop_adv(); } /* set up stop advertising timer */ @@ -1000,6 +956,7 @@ tBTM_STATUS btm_ble_set_discoverability(UINT16 combined_mode) *******************************************************************************/ tBTM_STATUS btm_ble_set_connectability(UINT16 combined_mode) { + tBTM_LE_RANDOM_CB *p_addr_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb; tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var; UINT16 mode = (combined_mode & BTM_BLE_CONNECTABLE_MASK); UINT8 cur_flag = 0; @@ -1008,9 +965,11 @@ tBTM_STATUS btm_ble_set_connectability(UINT16 combined_mode) UINT8 new_mode = BTM_BLE_ADV_ENABLE; UINT8 evt_type = (p_cb->scan_rsp) ? BTM_BLE_DISCOVER_EVT: BTM_BLE_NON_CONNECT_EVT; tBTM_STATUS status = BTM_SUCCESS; + BD_ADDR p_addr_ptr = {0}; + tBLE_ADDR_TYPE init_addr_type = BLE_ADDR_PUBLIC, + own_addr_type = p_addr_cb->own_addr_type; BTM_TRACE_EVENT2 ("btm_ble_set_connectability mode=0x%0x combined_mode=0x%x", mode, combined_mode); - /*** Check mode parameter ***/ if (mode > BTM_BLE_MAX_CONNECTABLE) return(BTM_ILLEGAL_VALUE); @@ -1035,45 +994,36 @@ tBTM_STATUS btm_ble_set_connectability(UINT16 combined_mode) BTM_TRACE_EVENT0 ("always disable adv in non-discoverable non-connectable mode with no scan rsp"); if(!p_cb->scan_rsp) new_mode = BTM_BLE_ADV_DISABLE; + } } else /* connectable */ { - BTM_TRACE_DEBUG2("btm_ble_set_connectability: mode = %04x discoverable_mode= %02x", mode, p_cb->discoverable_mode); - - if (BTM_BLE_VALID_CONN_DIRECT(&p_cb->direct_bda)) - { - BTM_TRACE_DEBUG0("evt_type = BTM_BLE_CONNECT_DIR_EVT"); - evt_type = BTM_BLE_CONNECT_DIR_EVT; - } - else - { - BTM_TRACE_DEBUG0(" evt_type = BTM_BLE_CONNECT_EVT"); - evt_type = BTM_BLE_CONNECT_EVT; - } + evt_type = btm_set_conn_mode_adv_init_addr(p_cb, p_addr_ptr, &init_addr_type, &own_addr_type); } /* update adv params if needed */ - if (p_cb->evt_type != evt_type && new_mode == BTM_BLE_ADV_ENABLE) + if ((p_cb->evt_type != evt_type || p_cb->adv_addr_type != p_addr_cb->own_addr_type) + && new_mode == BTM_BLE_ADV_ENABLE) { - if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE) - { - p_cb->adv_mode = BTM_BLE_ADV_DISABLE; - btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE); - } + btm_ble_stop_adv(); if (!btsnd_hcic_ble_write_adv_params ((UINT16)(p_cb->adv_interval_min ? p_cb->adv_interval_min : BTM_BLE_GAP_ADV_INT), (UINT16)(p_cb->adv_interval_max ? p_cb->adv_interval_max : BTM_BLE_GAP_ADV_INT), evt_type, - p_cb->own_addr_type, - p_cb->direct_bda.type, - p_cb->direct_bda.bda, + own_addr_type, + init_addr_type, + p_addr_ptr, p_cb->adv_chnl_map, p_cb->afp)) status = BTM_NO_RESOURCES; else + { p_cb->evt_type = evt_type; + p_cb->adv_addr_type = own_addr_type; + } } + /* update advertising mode */ if (status == BTM_SUCCESS && new_mode != p_cb->adv_mode) { @@ -1082,6 +1032,13 @@ tBTM_STATUS btm_ble_set_connectability(UINT16 combined_mode) status = BTM_SUCCESS; p_cb->adv_mode = new_mode; + + if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE && + p_cb->afp != AP_SCAN_CONN_ALL) + btm_cb.ble_ctr_cb.wl_state |= BTM_BLE_WL_ADV; + else + btm_cb.ble_ctr_cb.wl_state &= ~BTM_BLE_WL_ADV; + } } @@ -1103,11 +1060,8 @@ tBTM_STATUS btm_ble_set_connectability(UINT16 combined_mode) ** ** ** Returns BTM_CMD_STARTED if successfully started -** BTM_ILLEGAL_VALUE if a bad parameter is detected ** BTM_NO_RESOURCES if could not allocate a message buffer -** BTM_SUCCESS - if cancelling the periodic inquiry ** BTM_BUSY - if an inquiry is already active -** BTM_WRONG_MODE if the device is not up. ** *******************************************************************************/ tBTM_STATUS btm_ble_start_inquiry (UINT8 mode, UINT8 duration) @@ -1128,7 +1082,7 @@ tBTM_STATUS btm_ble_start_inquiry (UINT8 mode, UINT8 duration) /* start scan, already enable duplicate filtering */ if (btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_ENABLE, BTM_BLE_DUPLICATE_DISABLE)) { - status = BTM_SUCCESS; + status = BTM_CMD_STARTED; p_inq->proc_mode = mode; if (duration != 0) @@ -1155,7 +1109,7 @@ void btm_ble_read_remote_name_cmpl(BOOLEAN status, BD_ADDR bda, UINT16 length, c UINT8 hci_status = HCI_SUCCESS; BD_NAME bd_name; - memset(bd_name, 0, BD_NAME_LEN); + memset(bd_name, 0, (BD_NAME_LEN + 1)); memcpy((UINT8*)bd_name, p_name, length); if ((!status) || (length==0)) @@ -1163,7 +1117,7 @@ void btm_ble_read_remote_name_cmpl(BOOLEAN status, BD_ADDR bda, UINT16 length, c hci_status = HCI_ERR_HOST_TIMEOUT; } - btm_process_remote_name(bda, bd_name, length, hci_status); + btm_process_remote_name(bda, bd_name, length +1, hci_status); btm_sec_rmt_name_request_complete (bda, (UINT8 *)p_name, hci_status); } @@ -1298,7 +1252,6 @@ static void btm_ble_parse_adv_data(tBTM_INQ_INFO *p_info, UINT8 *p_data, { UINT8 *p_cur = p_data; UINT8 ad_len, ad_type, ad_flag; - tBTM_BLE_ATTR *p_attr; BTM_TRACE_EVENT0 (" btm_ble_parse_adv_data"); @@ -1348,35 +1301,38 @@ static void btm_ble_parse_adv_data(tBTM_INQ_INFO *p_info, UINT8 *p_data, BTM_TRACE_DEBUG1("BTM_BLE_AD_TYPE_TX_PWR tx_level = %d", p_adv_data->tx_power_level); break; - case BTM_BLE_AD_TYPE_ATTR: - p_adv_data->ad_mask |= BTM_BLE_AD_BIT_ATTR; - p_attr = &p_adv_data->attr_data.attr_list[p_adv_data->attr_data.num_attr]; - p_attr->uuid = *p_cur ++; - - if (ad_len > 3) - { - p_attr->data_len = ad_len - 3; - p_attr->p_data = p_buf; - memcpy(p_attr->p_data, p_cur, p_attr->data_len); - p_buf += p_attr->data_len; - } + case BTM_BLE_AD_TYPE_MANU: - p_adv_data->attr_data.num_attr ++; - BTM_TRACE_DEBUG2("BTM_BLE_AD_TYPE_ATTR[%d] uuid = 0x%04x",p_adv_data->attr_data.num_attr, p_attr->uuid); + case BTM_BLE_AD_TYPE_16SRV_PART: + case BTM_BLE_AD_TYPE_16SRV_CMPL: + p_adv_data->ad_mask |= BTM_BLE_AD_BIT_SERVICE; + /* need allocate memory to store UUID list */ + p_adv_data->service.num_service = (ad_len - 1)/2; + BTM_TRACE_DEBUG1("service UUID list, num = %d", p_adv_data->service.num_service); + p_cur += (ad_len - 1); break; - case BTM_BLE_AD_TYPE_MANU: - - case BTM_BLE_AD_TYPE_SRV_CMPL: - case BTM_BLE_AD_TYPE_SRV_PART: - p_adv_data->ad_mask |= ad_type; + case BTM_BLE_AD_TYPE_SOL_SRV_UUID: + p_adv_data->ad_mask |= BTM_BLE_AD_BIT_SERVICE_SOL; /* need allocate memory to store UUID list */ p_adv_data->service.num_service = (ad_len - 1)/2; BTM_TRACE_DEBUG1("service UUID list, num = %d", p_adv_data->service.num_service); + p_cur += (ad_len - 1); + break; - default: + case BTM_BLE_AD_TYPE_128SOL_SRV_UUID: + p_adv_data->ad_mask |= BTM_BLE_AD_BIT_SERVICE_128SOL; + /* need allocate memory to store UUID list */ + p_adv_data->service.num_service = (ad_len - 1)/16; + BTM_TRACE_DEBUG1("service UUID list, num = %d", p_adv_data->service.num_service); p_cur += (ad_len - 1); break; + + case BTM_BLE_AD_TYPE_APPEARANCE: + case BTM_BLE_AD_TYPE_PUBLIC_TARGET: + case BTM_BLE_AD_TYPE_RANDOM_TARGET: + default: + break; } len -= (ad_len + 1); } @@ -1426,6 +1382,7 @@ void btm_ble_cache_adv_data(tBTM_INQ_RESULTS *p_cur, UINT8 data_len, UINT8 *p, U /* parse service UUID from adv packet and save it in inq db eir_uuid */ /* TODO */ } + /******************************************************************************* ** ** Function btm_ble_is_discoverable @@ -1501,6 +1458,7 @@ BOOLEAN btm_ble_is_discoverable(BD_ADDR bda, UINT8 evt_type, UINT8 *p) return is_discoverable; } + /******************************************************************************* ** ** Function btm_ble_update_inq_result @@ -1567,9 +1525,10 @@ BOOLEAN btm_ble_update_inq_result(tINQ_DB_ENT *p_i, UINT8 addr_type, UINT8 evt_t } /* if BR/EDR not supported is not set, assume is a DUMO device */ - if ((p_cur->flag & BTM_BLE_BREDR_NOT_SPT) == 0) + if ((p_cur->flag & BTM_BLE_BREDR_NOT_SPT) == 0 && + evt_type != BTM_BLE_CONNECT_DIR_EVT) { - BTM_TRACE_ERROR0("BR/EDR NOT support bit not set, treat as DUMO"); + BTM_TRACE_DEBUG0("BR/EDR NOT support bit not set, treat as DUMO"); p_cur->device_type |= BT_DEVICE_TYPE_DUMO; } else @@ -1625,45 +1584,6 @@ void btm_send_sel_conn_callback(BD_ADDR remote_bda, UINT8 evt_type, UINT8 *p_dat /******************************************************************************* ** -** Function btm_ble_resolve_random_addr_cmpl -** -** Description resolve random address complete callback. -** -** Returns void -** -*******************************************************************************/ -static void btm_ble_resolve_random_addr_cmpl(void * p_rec, void *p) -{ - tBTM_SEC_DEV_REC *match_rec = (tBTM_SEC_DEV_REC *) p_rec; - UINT8 addr_type = BLE_ADDR_RANDOM; - BD_ADDR bda; - UINT8 *pp = (UINT8 *)p + 1; - UINT8 evt_type; - - BTM_TRACE_EVENT0 ("btm_ble_resolve_random_addr_cmpl "); - - STREAM_TO_UINT8 (evt_type, pp); - STREAM_TO_UINT8 (addr_type, pp); - STREAM_TO_BDADDR (bda, pp); - - if (match_rec) - { - BTM_TRACE_ERROR0("Random match"); - memcpy(match_rec->ble.cur_rand_addr, bda, BD_ADDR_LEN); - memcpy(bda, match_rec->bd_addr, BD_ADDR_LEN); - } - else - { - BTM_TRACE_ERROR0("Random unmatch"); - } - - btm_ble_process_adv_pkt_cont(bda, addr_type, evt_type, pp); - - return; -} - -/******************************************************************************* -** ** Function btm_ble_process_adv_pkt ** ** Description This function is called when adv packet report events are @@ -1681,8 +1601,6 @@ void btm_ble_process_adv_pkt (UINT8 *p_data) UINT8 evt_type = 0, *p = p_data; UINT8 addr_type = 0; - BTM_TRACE_EVENT0 ("btm_ble_process_adv_pkt "); - /* always get one device at a time */ p ++; @@ -1691,30 +1609,24 @@ void btm_ble_process_adv_pkt (UINT8 *p_data) STREAM_TO_UINT8 (addr_type, p); STREAM_TO_BDADDR (bda, p); -#ifdef BTM_BLE_PC_ADV_TEST_MODE // For general stack code (e.g. BTInsight testing), we simply do not define it to exclude or set it to TRUE to include - if (BTM_BLE_PC_ADV_TEST_MODE) // For stack component, it is always defined and maps to a global variable g_bDraculaAdvertisingMode +#ifdef BTM_BLE_PC_ADV_TEST_MODE /* For general stack code (e.g. BTInsight testing), we simply do not define it to exclude or set it to TRUE to include */ + if (BTM_BLE_PC_ADV_TEST_MODE) /* For stack component, it is always defined and maps to a global variable g_bDraculaAdvertisingMode */ { if (btm_cb.ble_ctr_cb.p_scan_req_cback) (*btm_cb.ble_ctr_cb.p_scan_req_cback)(bda, addr_type, evt_type); } #endif + + /* Only process the results if the inquiry is still active */ - if (!btm_cb.btm_inq_vars.inq_active && + if ((btm_cb.btm_inq_vars.inq_active & BTM_LE_SCAN_ACTIVE_MASK) == 0 && (btm_cb.ble_ctr_cb.bg_conn_type != BTM_BLE_CONN_SELECTIVE || /* or selective auto connection is active */ btm_cb.ble_ctr_cb.p_select_cback == NULL)) return; - -#if SMP_INCLUDED == TRUE - if (addr_type == BLE_ADDR_RANDOM && BTM_BLE_IS_RESOLVE_BDA(bda)) - { - btm_ble_resolve_random_addr(bda, btm_ble_resolve_random_addr_cmpl, p_data); - } - else -#endif - btm_ble_process_adv_pkt_cont(bda, addr_type, evt_type, p); + btm_ble_process_adv_pkt_cont(bda, addr_type, evt_type, p); } /******************************************************************************* @@ -1755,14 +1667,12 @@ static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt } else { - BTM_TRACE_DEBUG0("LE in le_bd_db already"); /* if yes, skip it */ return; /* assumption: one result per event */ } } else /* not been processed int his round */ { - BTM_TRACE_DEBUG0("new LE BD_ADDR"); to_report = TRUE; } @@ -1774,7 +1684,6 @@ static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt if ((p_i = btm_inq_db_new (bda)) != NULL) { p_inq->inq_cmpl_info.num_resp++; - BTM_TRACE_DEBUG0("adv pkt process: new record is added into inq db"); to_report = TRUE; } else @@ -1809,7 +1718,9 @@ static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt { BTM_TRACE_WARNING0("INQ RES: Extra Response Received...cancelling inquiry.."); - if (!(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) ) + /* if is non-periodic inquiry active, cancel now */ + if ((p_inq->inq_active & BTM_BR_INQ_ACTIVE_MASK) != 0 && + (p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) == 0) btsnd_hcic_inq_cancel(); /* stop LE scan now */ @@ -1825,14 +1736,17 @@ static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt /* background connection in selective connection mode */ if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_SELECTIVE) { - btm_send_sel_conn_callback(bda, evt_type, p, addr_type); + if (p_i->inq_info.results.device_type == BT_DEVICE_TYPE_BLE && + (evt_type == BTM_BLE_CONNECT_EVT || evt_type == BTM_BLE_CONNECT_DIR_EVT)) + btm_send_sel_conn_callback(bda, evt_type, p, addr_type); + else + { + BTM_TRACE_DEBUG0("None LE device, can not initiate selective connection"); + } } else if (p_inq_results_cb && to_report) { - BTM_TRACE_DEBUG0("BTMINQ LE: Found devices, send callback btm_inqrslt_cb"); - - if (p_inq->inq_active) - (p_inq_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache); + (p_inq_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache); } } @@ -1873,6 +1787,36 @@ void btm_ble_stop_scan(void) /******************************************************************************* ** +** Function btm_ble_start_adv +** +** Description Stop the BLE advertising. +** +** Returns void +** +*******************************************************************************/ +static tBTM_STATUS btm_ble_start_adv(void) +{ + tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var; + tBTM_STATUS rt = BTM_NO_RESOURCES; + + if (btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_ENABLE)) + { + if (p_cb->afp != AP_SCAN_CONN_ALL) + btm_cb.ble_ctr_cb.wl_state |= BTM_BLE_WL_ADV; + + p_cb->adv_mode = BTM_BLE_ADV_ENABLE; + + rt = BTM_SUCCESS; + } + else + { + p_cb->adv_mode = BTM_BLE_ADV_DISABLE; + btm_cb.ble_ctr_cb.wl_state &= ~BTM_BLE_WL_ADV; + } + return rt; +} +/******************************************************************************* +** ** Function btm_ble_stop_adv ** ** Description Stop the BLE advertising. @@ -1880,14 +1824,23 @@ void btm_ble_stop_scan(void) ** Returns void ** *******************************************************************************/ -void btm_ble_stop_adv(void) +static tBTM_STATUS btm_ble_stop_adv(void) { - BTM_TRACE_EVENT0 (" btm_ble_stop_adv"); + tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var; + tBTM_STATUS rt = BTM_SUCCESS; - if (btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE)) + if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE) { - btm_cb.ble_ctr_cb.inq_var.adv_mode = BTM_BLE_ADV_DISABLE; + if (btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE)) + { + p_cb->adv_mode = BTM_BLE_ADV_DISABLE; + btm_cb.ble_ctr_cb.wl_state &= ~BTM_BLE_WL_ADV; + } + else + rt = BTM_NO_RESOURCES; } + return rt; + } /******************************************************************************* @@ -1917,8 +1870,7 @@ void btm_ble_timeout(TIMER_LIST_ENT *p_tle) break; case BTU_TTYPE_BLE_RANDOM_ADDR: - if (btm_cb.ble_ctr_cb.inq_var.adv_mode == BTM_BLE_ADV_ENABLE && - btm_cb.ble_ctr_cb.inq_var.own_addr_type == BLE_ADDR_RANDOM) + if (btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type == BLE_ADDR_RANDOM) { /* refresh the random addr */ btm_gen_resolvable_private_addr(); @@ -1928,62 +1880,6 @@ void btm_ble_timeout(TIMER_LIST_ENT *p_tle) } } -/******************************************************************************* -** -** Function btm_ble_connected -** -** Description This function is when a LE connection to the peer device is -** establsihed -** -** Returns void -** -*******************************************************************************/ -void btm_ble_connected (UINT8 *bda, UINT16 handle, UINT8 enc_mode, UINT8 role) -{ - tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda); - tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; - - BTM_TRACE_EVENT0 ("btm_ble_connected"); - - /* Commenting out trace due to obf/compilation problems. - */ -#if (BT_USE_TRACES == TRUE) - if (p_dev_rec) - { - BTM_TRACE_EVENT4 ("Security Manager: btm_sec_connected : handle:%d enc_mode:%d bda:%x RName:%s", - handle, enc_mode, - (bda[2]<<24)+(bda[3]<<16)+(bda[4]<<8)+bda[5], - p_dev_rec->sec_bd_name); - - BTM_TRACE_DEBUG1 ("btm_ble_connected sec_flags=0x%x",p_dev_rec->sec_flags); - } - else - { - BTM_TRACE_EVENT3 ("Security Manager: btm_sec_connected: handle:%d enc_mode:%d bda:%x ", - handle, enc_mode, - (bda[2]<<24)+(bda[3]<<16)+(bda[4]<<8)+bda[5]); - } -#endif - - if (!p_dev_rec) - { - /* There is no device record for new connection. Allocate one */ - p_dev_rec = btm_sec_alloc_dev (bda); - } - else /* Update the timestamp for this device */ - { - p_dev_rec->timestamp = btm_cb.dev_rec_count++; - } - - p_dev_rec->device_type = BT_DEVICE_TYPE_BLE; - p_dev_rec->hci_handle = handle; - if (role == HCI_ROLE_MASTER) - p_dev_rec->role_master = TRUE; - - p_cb->inq_var.adv_mode = BTM_BLE_ADV_DISABLE; - - return; -} /******************************************************************************* ** @@ -2049,7 +1945,81 @@ void btm_ble_write_adv_enable_complete(UINT8 * p) /* toggle back the adv mode */ p_cb->adv_mode = !p_cb->adv_mode; } + + } + +/******************************************************************************* +** +** Function btm_ble_dir_adv_tout +** +** Description when directed adv time out +** +** Returns void +** +*******************************************************************************/ +void btm_ble_dir_adv_tout(void) +{ + btm_cb.ble_ctr_cb.inq_var.adv_mode = BTM_BLE_ADV_DISABLE; + + /* make device fall back into undirected adv mode by default */ + btm_cb.ble_ctr_cb.inq_var.directed_conn = FALSE; +} + +/******************************************************************************* +** +** Function btm_ble_update_mode_operation +** +** Description This function update the GAP role operation when a link status +** is updated. +** +** Returns void +** +*******************************************************************************/ +void btm_ble_update_mode_operation(UINT8 link_role, BD_ADDR bd_addr, BOOLEAN conn_cancel) +{ + tACL_CONN *pa = &btm_cb.acl_db[0]; + UINT16 xx; + UINT8 dev_role = link_role; + + BTM_TRACE_DEBUG1("btm_ble_update_mode_operation adv_mode = %d", btm_cb.ble_ctr_cb.inq_var.adv_mode ); + + /* update periphera role operation */ + /* If we are LE connectable, check if we need to start advertising again */ + if (link_role == HCI_ROLE_UNKNOWN) + /* && btm_cb.ble_ctr_cb.inq_var.connectable_mode != BTM_BLE_NON_CONNECTABLE) */ + { + for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, pa++) + { + /* If any other LE link is up, we are still not connectable */ + if (pa->in_use && pa->is_le_link) + { + dev_role = pa->link_role; + break; + } + } + } + + if (btm_cb.ble_ctr_cb.inq_var.connectable_mode == BTM_BLE_CONNECTABLE && + (dev_role == HCI_ROLE_UNKNOWN )) /* when device has no connection, update adv here */ + /* if already in connection, no connectable adv is allowed unless scatternet is enabled */ + { + btm_ble_set_connectability ( btm_cb.ble_ctr_cb.inq_var.connectable_mode ); + } + + /* if connection complete */ + if (conn_cancel || link_role != HCI_ROLE_UNKNOWN) + btm_ble_set_conn_st(BLE_CONN_IDLE); + + if (btm_ble_get_conn_st() == BLE_CONN_IDLE) + { + if (!btm_send_pending_direct_conn()) + { + btm_ble_resume_bg_conn(); + } + } +} + /******************************************************************************* ** ** Function btm_ble_init diff --git a/stack/btm/btm_ble_int.h b/stack/btm/btm_ble_int.h index 449de8f68..878037b64 100644 --- a/stack/btm/btm_ble_int.h +++ b/stack/btm/btm_ble_int.h @@ -36,15 +36,6 @@ #include "smp_api.h" #endif -#define BTM_BLE_CONNECT_EVT 0x00 -#define BTM_BLE_CONNECT_DIR_EVT 0x01 -#define BTM_BLE_DISCOVER_EVT 0x02 -#define BTM_BLE_NON_CONNECT_EVT 0x03 -#define BTM_BLE_SCAN_RSP_EVT 0x04 -#define BTM_BLE_SCAN_REQ_EVT 0x06 -#define BTM_BLE_UNKNOWN_EVT 0xff - -#define BTM_BLE_UNKNOWN_EVT 0xff /* scanning enable status */ #define BTM_BLE_SCAN_ENABLE 0x01 @@ -79,7 +70,10 @@ #define BTM_BLE_SEC_REQ_ACT_DISCARD 3 /* discard the sec request while encryption is started but not completed */ typedef UINT8 tBTM_BLE_SEC_REQ_ACT; - +#define BLE_STATIC_PRIVATE_MSB_MASK 0x3f +#define BLE_RESOLVE_ADDR_MSB 0x40 /* most significant bit, bit7, bit6 is 01 to be resolvable random */ +#define BLE_RESOLVE_ADDR_MASK 0xc0 /* bit 6, and bit7 */ +#define BTM_BLE_IS_RESOLVE_BDA(x) ((x[0] & BLE_RESOLVE_ADDR_MASK) == BLE_RESOLVE_ADDR_MSB) typedef struct { @@ -119,13 +113,14 @@ typedef struct UINT8 scan_type; /* current scan type: active or passive */ UINT16 adv_interval_min; UINT16 adv_interval_max; - tBLE_ADDR_TYPE own_addr_type; tBTM_BLE_AFP afp; /* advertising filter policy */ tBTM_BLE_SFP sfp; /* scanning filter policy */ + tBLE_ADDR_TYPE adv_addr_type; UINT8 evt_type; UINT8 adv_mode; tBLE_BD_ADDR direct_bda; + BOOLEAN directed_conn; UINT8 adv_len; UINT8 adv_data_cache[BTM_BLE_CACHE_ADV_DATA_MAX]; @@ -134,7 +129,6 @@ typedef struct UINT8 num_bd_entries; UINT8 max_bd_entries; - tBLE_BD_ADDR local_bda; tBTM_BLE_LOCAL_ADV_DATA adv_data; tBTM_BLE_ADV_CHNL_MAP adv_chnl_map; @@ -142,21 +136,25 @@ typedef struct TIMER_LIST_ENT inq_timer_ent; BOOLEAN scan_rsp; UINT8 state; /* Current state that the inquiry process is in */ - UINT8 tx_power; + INT8 tx_power; } tBTM_BLE_INQ_CB; /* random address resolving complete callback */ typedef void (tBTM_BLE_RESOLVE_CBACK) (void * match_rec, void *p); +typedef void (tBTM_BLE_ADDR_CBACK) (BD_ADDR_PTR static_random, void *p); + /* random address management control block */ typedef struct { + tBLE_ADDR_TYPE own_addr_type; /* local device LE address type */ BD_ADDR private_addr; BD_ADDR random_bda; BOOLEAN busy; UINT16 index; tBTM_BLE_RESOLVE_CBACK *p_resolve_cback; + tBTM_BLE_ADDR_CBACK *p_generate_cback; void *p; TIMER_LIST_ENT raddr_timer_ent; } tBTM_LE_RANDOM_CB; @@ -172,6 +170,32 @@ typedef struct }tBTM_LE_CONN_PRAMS; + +typedef struct +{ + BD_ADDR bd_addr; + UINT8 attr; + BOOLEAN is_connected; + BOOLEAN in_use; +}tBTM_LE_BG_CONN_DEV; + + /* white list using state as a bit mask */ +#define BTM_BLE_WL_IDLE 0 +#define BTM_BLE_WL_INIT 1 +#define BTM_BLE_WL_SCAN 2 +#define BTM_BLE_WL_ADV 4 +typedef UINT8 tBTM_BLE_WL_STATE; + +/* BLE connection state */ +#define BLE_CONN_IDLE 0 +#define BLE_DIR_CONN 1 +#define BLE_BG_CONN 2 +typedef UINT8 tBTM_BLE_CONN_ST; + +typedef struct +{ + void *p_param; +}tBTM_BLE_CONN_REQ; /* Define BLE Device Management control structure */ typedef struct @@ -188,28 +212,26 @@ typedef struct tBTM_BLE_SEL_CBACK *p_select_cback; TIMER_LIST_ENT scan_param_idle_timer; - UINT8 bg_conn_dev_num; - BD_ADDR bg_conn_dev_list[BTM_BLE_MAX_BG_CONN_DEV_NUM]; - -#define BLE_BG_CONN_IDLE 0 -#define BLE_BG_CONN_ACTIVE 1 -#define BLE_BG_CONN_SUSPEND 2 + /* white list information */ + UINT8 num_empty_filter; /* Number of entries in white list */ + UINT8 max_filter_entries; /* Maximum number of entries that can be stored */ + tBTM_BLE_WL_STATE wl_state; + UINT8 bg_dev_num; + tBTM_LE_BG_CONN_DEV bg_dev_list[BTM_BLE_MAX_BG_CONN_DEV_NUM]; - UINT8 bg_conn_state; + BUFFER_Q conn_pending_q; + tBTM_BLE_CONN_ST conn_state; /* random address management control block */ tBTM_LE_RANDOM_CB addr_mgnt_cb; - /* white list information */ - UINT8 num_empty_filter; /* Number of entries in white list */ - UINT8 max_filter_entries; /* Maximum number of entries that can be stored */ BOOLEAN enabled; - BOOLEAN privacy; /* privacy enabled or disabled */ #ifdef BTM_BLE_PC_ADV_TEST_MODE tBTM_BLE_SCAN_REQ_CBACK *p_scan_req_cback; #endif + BOOLEAN scatternet_enable; } tBTM_BLE_CB; #ifdef __cplusplus @@ -225,17 +247,21 @@ extern BOOLEAN btm_ble_cancel_remote_name(BD_ADDR remote_bda); extern tBTM_STATUS btm_ble_set_discoverability(UINT16 combined_mode); extern tBTM_STATUS btm_ble_set_connectability(UINT16 combined_mode); extern tBTM_STATUS btm_ble_start_inquiry (UINT8 mode, UINT8 duration); +extern void btm_ble_dir_adv_tout(void); extern void btm_ble_stop_scan(void); extern void btm_ble_att_db_init(void); extern void btm_ble_init (void); -extern void btm_ble_connected (UINT8 *bda, UINT16 handle, UINT8 enc_mode, UINT8 role); +extern void btm_ble_connected (UINT8 *bda, UINT16 handle, UINT8 enc_mode, UINT8 role, tBLE_ADDR_TYPE addr_type, BOOLEAN addr_matched); extern void btm_ble_read_remote_features_complete(UINT8 *p); -extern void btm_ble_stop_adv(void); extern void btm_ble_write_adv_enable_complete(UINT8 * p); +extern void btm_ble_conn_complete(UINT8 *p, UINT16 evt_len); +extern tBTM_BLE_CONN_ST btm_ble_get_conn_st(void); +extern void btm_ble_set_conn_st(tBTM_BLE_CONN_ST new_st); + /* LE security function from btm_sec.c */ -#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE +#if SMP_INCLUDED == TRUE extern void btm_ble_link_sec_check(BD_ADDR bd_addr, tBTM_LE_AUTH_REQ auth_req, tBTM_BLE_SEC_REQ_ACT *p_sec_req_act); extern void btm_ble_ltk_request_reply(BD_ADDR bda, BOOLEAN use_stk, BT_OCTET16 stk); extern UINT8 btm_proc_smp_cback(tSMP_EVT event, BD_ADDR bd_addr, tSMP_EVT_DATA *p_data); @@ -260,35 +286,38 @@ extern void btm_ble_update_sec_key_size(BD_ADDR bd_addr, UINT8 enc_key_size); extern UINT8 btm_ble_read_sec_key_size(BD_ADDR bd_addr); /* white list function */ -extern BOOLEAN btm_update_dev_to_white_list(BOOLEAN to_add, BD_ADDR bd_addr,tBLE_ADDR_TYPE addr_type); -extern BOOLEAN btm_update_bg_conn_list(BOOLEAN to_add, BD_ADDR bd_addr); +extern BOOLEAN btm_update_dev_to_white_list(BOOLEAN to_add, BD_ADDR bd_addr,UINT8 wl_type); +extern BOOLEAN btm_update_bg_conn_list(BOOLEAN to_add, BD_ADDR bd_addr, UINT8 *p_attr_tag); extern void btm_update_scanner_filter_policy(tBTM_BLE_SFP scan_policy); extern void btm_update_adv_filter_policy(tBTM_BLE_AFP adv_policy); extern void btm_ble_clear_white_list (void); -extern void btm_write_bg_conn_wl(void); /* background connection function */ extern void btm_ble_suspend_bg_conn(void); -extern BOOLEAN btm_ble_resume_bg_conn(tBTM_BLE_SEL_CBACK *p_sele_callback, BOOLEAN def_param); -extern void btm_ble_update_bg_state(void); +extern BOOLEAN btm_ble_resume_bg_conn(void); extern void btm_ble_initiate_select_conn(BD_ADDR bda); extern BOOLEAN btm_ble_start_auto_conn(BOOLEAN start); extern BOOLEAN btm_ble_start_select_conn(BOOLEAN start,tBTM_BLE_SEL_CBACK *p_select_cback); -extern BOOLEAN btm_ble_find_dev_in_whitelist(BD_ADDR bd_addr); extern BOOLEAN btm_ble_renew_bg_conn_params(BOOLEAN add, BD_ADDR bd_addr); -extern void btm_ble_scan_param_idle(void); extern UINT8 btm_ble_count_unconn_dev_in_whitelist(void); +extern void btm_write_dir_conn_wl(BD_ADDR target_addr); +extern void btm_ble_update_mode_operation(UINT8 link_role, BD_ADDR bda, BOOLEAN conn_ccancel); + +/* direct connection utility */ +extern BOOLEAN btm_send_pending_direct_conn(void); +extern void btm_ble_enqueue_direct_conn_req(void *p_param); /* BLE address management */ -extern tBLE_ADDR_TYPE btm_ble_map_bda_to_conn_bda(BD_ADDR bda); extern void btm_gen_resolvable_private_addr (void); -extern void btm_gen_non_resolvable_private_addr (void); +extern void btm_gen_non_resolvable_private_addr (tBTM_BLE_ADDR_CBACK *p_cback, void *p); extern void btm_ble_resolve_random_addr(BD_ADDR random_bda, tBTM_BLE_RESOLVE_CBACK * p_cback, void *p); +extern void btm_ble_update_reconnect_address(BD_ADDR bd_addr); #if BTM_BLE_CONFORMANCE_TESTING == TRUE BT_API extern void btm_ble_set_no_disc_if_pair_fail (BOOLEAN disble_disc); BT_API extern void btm_ble_set_test_mac_value (BOOLEAN enable, UINT8 *p_test_mac_val); BT_API extern void btm_ble_set_test_local_sign_cntr_value(BOOLEAN enable, UINT32 test_local_sign_cntr); +BT_API extern void btm_set_random_address(BD_ADDR random_bda); #endif diff --git a/stack/btm/btm_dev.c b/stack/btm/btm_dev.c index 04994d1eb..40919fada 100644 --- a/stack/btm/btm_dev.c +++ b/stack/btm/btm_dev.c @@ -125,7 +125,10 @@ BOOLEAN BTM_SecAddDevice (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name, } #if defined(BTIF_MIXED_MODE_INCLUDED) && (BTIF_MIXED_MODE_INCLUDED == TRUE) - p_dev_rec->sm4 = BTM_SM4_KNOWN; + if (key_type < BTM_MAX_PRE_SM4_LKEY_TYPE) + p_dev_rec->sm4 = BTM_SM4_KNOWN; + else + p_dev_rec->sm4 = BTM_SM4_TRUE; #endif p_dev_rec->rmt_io_caps = io_cap; @@ -245,7 +248,6 @@ tBTM_SEC_DEV_REC *btm_sec_alloc_dev (BD_ADDR bd_addr) else { #if BLE_INCLUDED == TRUE - p_dev_rec->device_type = BT_DEVICE_TYPE_BREDR; /* initialize it as BR/EDR device */ /* update conn params, use default value for background connection params */ memset(&p_dev_rec->conn_params, 0xff, sizeof(tBTM_LE_CONN_PRAMS)); #endif diff --git a/stack/btm/btm_devctl.c b/stack/btm/btm_devctl.c index f0fc43710..5a88a7741 100644 --- a/stack/btm/btm_devctl.c +++ b/stack/btm/btm_devctl.c @@ -37,11 +37,6 @@ #if BLE_INCLUDED == TRUE #include "gatt_int.h" -#if GAP_INCLUDED == TRUE -#include "gap_api.h" -#include "gattdefs.h" -#endif - #endif /* BLE_INCLUDED */ /* BTM_APP_DEV_INIT should be defined if additional controller initialization is @@ -112,10 +107,6 @@ response message */ #define BTM_SCO_HOST_BUF_SIZE 0xff #endif -#ifndef BTM_GPS_UIPC_CH_NB -#define BTM_GPS_UIPC_CH_NB UIPC_CH_ID_1 -#endif - /********************************************************************************/ /* L O C A L F U N C T I O N P R O T O T Y P E S */ /********************************************************************************/ @@ -551,11 +542,6 @@ void btm_reset_complete (void) BTM_TRACE_EVENT0 ("btm_reset_complete"); -#ifdef BRCM_VS - btm_vs_reset_complete(); -#endif - - /* Handle if btm initiated the reset */ if (btm_cb.devcb.state == BTM_DEV_STATE_WAIT_RESET_CMPLT) { @@ -587,11 +573,11 @@ void btm_reset_complete (void) #endif #if (BLE_INCLUDED == TRUE) - btm_cb.ble_ctr_cb.bg_conn_state = BLE_BG_CONN_IDLE; - btm_cb.ble_ctr_cb.bg_conn_dev_num = 0; + btm_cb.ble_ctr_cb.conn_state = BLE_CONN_IDLE; + btm_cb.ble_ctr_cb.bg_dev_num = 0; btm_cb.ble_ctr_cb.bg_conn_type = BTM_BLE_CONN_NONE; btm_cb.ble_ctr_cb.p_select_cback = NULL; - memset(&btm_cb.ble_ctr_cb.bg_conn_dev_list, 0, (sizeof(BD_ADDR)*BTM_BLE_MAX_BG_CONN_DEV_NUM)); + memset(&btm_cb.ble_ctr_cb.bg_dev_list, 0, (sizeof(tBTM_LE_BG_CONN_DEV)*BTM_BLE_MAX_BG_CONN_DEV_NUM)); gatt_reset_bgdev_list(); #endif } @@ -753,13 +739,9 @@ void btm_read_ble_buf_size_complete (UINT8 *p, UINT16 evt_len) btm_read_local_features_complete( buf, 9 ); } #else -#ifdef BRCM_VS - btm_brcm_feat_init(); -#else /* get local feature if BRCM specific feature is not included */ btm_get_local_features (); #endif -#endif } @@ -781,6 +763,8 @@ void btm_read_white_list_size_complete(UINT8 *p, UINT16 evt_len) STREAM_TO_UINT8(btm_cb.ble_ctr_cb.max_filter_entries, p); btm_cb.ble_ctr_cb.num_empty_filter = btm_cb.ble_ctr_cb.max_filter_entries; } + /* write LE host support and simultaneous LE supported */ + btsnd_hcic_ble_write_host_supported(BTM_BLE_HOST_SUPPORT, BTM_BLE_SIMULTANEOUS_HOST); btm_get_ble_buffer_size(); } @@ -827,32 +811,43 @@ void btm_read_local_version_complete (UINT8 *p, UINT16 evt_len) btm_read_local_features_complete( buf, 9 ); } #else -#ifdef BRCM_VS - btm_brcm_feat_init(); -#else /* get local feature if BRCM specific feature is not included */ btm_get_local_features (); #endif -#endif } +/******************************************************************************* +** +** Function btm_read_local_extended_feature +** +** Description Local function called to send a read local extended feature to controller +** +** Returns void +** +*******************************************************************************/ +void btm_read_local_extended_feature (void) +{ + btu_start_timer (&btm_cb.devcb.reset_timer, BTU_TTYPE_BTM_DEV_CTL, BTM_DEV_REPLY_TIMEOUT); + + /* Send a Read Local extended feature message to the Controller. */ + btsnd_hcic_read_local_ext_features (1); +} /******************************************************************************* ** -** Function btm_read_local_features_complete +** Function btm_read_local_ext_features_complete ** + ** Description This function is called when local features read is complete. ** This is the last step of the startup sequence. ** ** Returns void ** *******************************************************************************/ -void btm_read_local_features_complete (UINT8 *p, UINT16 evt_len) +void btm_read_local_ext_features_complete(UINT8 *p, UINT16 evt_len) { tBTM_DEVCB *p_devcb = &btm_cb.devcb; tBTM_CMPL_CB *p_cb = p_devcb->p_reset_cmpl_cb; - UINT8 status; - UINT16 xx; UINT8 last; UINT8 first; @@ -860,6 +855,46 @@ void btm_read_local_features_complete (UINT8 *p, UINT16 evt_len) /* If there was a callback address for reset complete, call it */ p_devcb->p_reset_cmpl_cb = NULL; + btm_sec_dev_reset (); + + /* If 802.11 present might have to disable some channels */ + if (btm_cb.last_disabled_channel != 0xff) + { + last = btm_cb.last_disabled_channel; + first = btm_cb.first_disabled_channel; + btm_cb.last_disabled_channel = 0xff; + btm_cb.first_disabled_channel = 0xff; + BTM_SetAfhChannels(first, last); + } + + BTM_SetPageScanType (BTM_DEFAULT_SCAN_TYPE); + BTM_SetInquiryScanType (BTM_DEFAULT_SCAN_TYPE); + + /* If anyone wants device status notifications, give him one */ + btm_report_device_status (BTM_DEV_STATUS_UP); + + /* Reset sequence is complete. If this was an application originated */ + /* reset, tell him its done. */ + if (p_cb) + (*p_cb)((void *) NULL); +} +/******************************************************************************* +** +** Function btm_read_local_features_complete +** + +** Description This function is called when local features read is complete. +** This is the last step of the startup sequence. +** +** Returns void +** +*******************************************************************************/ +void btm_read_local_features_complete (UINT8 *p, UINT16 evt_len) +{ + tBTM_DEVCB *p_devcb = &btm_cb.devcb; + UINT8 status; + UINT16 xx; + STREAM_TO_UINT8 (status, p); if (status == HCI_SUCCESS) { @@ -1003,18 +1038,6 @@ void btm_read_local_features_complete (UINT8 *p, UINT16 evt_len) else btm_cb.btm_def_link_policy &= ~HCI_ENABLE_PARK_MODE; - btm_sec_dev_reset (); - - /* If 802.11 present might have to disable some channels */ - if (btm_cb.last_disabled_channel != 0xff) - { - last = btm_cb.last_disabled_channel; - first = btm_cb.first_disabled_channel; - btm_cb.last_disabled_channel = 0xff; - btm_cb.first_disabled_channel = 0xff; - BTM_SetAfhChannels(first, last); - } - #if ((BTM_EIR_SERVER_INCLUDED == TRUE)||(BTM_EIR_CLIENT_INCLUDED == TRUE)) if (HCI_LMP_INQ_RSSI_SUPPORTED(p_devcb->local_features)) { @@ -1033,21 +1056,8 @@ void btm_read_local_features_complete (UINT8 *p, UINT16 evt_len) else l2cu_set_non_flushable_pbf(FALSE); #endif - BTM_SetPageScanType (BTM_DEFAULT_SCAN_TYPE); - BTM_SetInquiryScanType (BTM_DEFAULT_SCAN_TYPE); - - /* If anyone wants device status notifications, give him one */ - btm_report_device_status (BTM_DEV_STATUS_UP); - -#ifdef BRCM_VS - btm_brcm_arc_init(); -#endif - - /* Reset sequence is complete. If this was an application originated */ - /* reset, tell him its done. */ - if (p_cb) - (*p_cb)((void *) NULL); } + btm_read_local_extended_feature (); } /******************************************************************************* @@ -1086,9 +1096,6 @@ UINT8 btm_get_voice_coding_support( void ) tBTM_STATUS BTM_SetLocalDeviceName (char *p_name) { UINT8 *p; -#if BLE_INCLUDED == TRUE && GAP_INCLUDED == TRUE - tGAP_BLE_ATTR_VALUE attr_value; -#endif if (!p_name || !p_name[0] || (strlen ((char *)p_name) > BD_NAME_LEN)) return (BTM_ILLEGAL_VALUE); @@ -1109,11 +1116,6 @@ tBTM_STATUS BTM_SetLocalDeviceName (char *p_name) p = (UINT8 *)p_name; #endif -#if BLE_INCLUDED == TRUE && GAP_INCLUDED == TRUE - attr_value.p_dev_name = (UINT8 *)p_name; - GAP_BleAttrDBUpdate(GATT_UUID_GAP_DEVICE_NAME, &attr_value); -#endif - if (btsnd_hcic_change_name(p)) return (BTM_CMD_STARTED); else diff --git a/stack/btm/btm_inq.c b/stack/btm/btm_inq.c index 55985625c..a9feed72d 100644 --- a/stack/btm/btm_inq.c +++ b/stack/btm/btm_inq.c @@ -502,8 +502,9 @@ tBTM_STATUS BTM_SetPeriodicInquiryMode (tBTM_INQ_PARMS *p_inqparms, UINT16 max_d min_delay < BTM_PER_INQ_MIN_MIN_PERIOD || min_delay > BTM_PER_INQ_MAX_MIN_PERIOD || max_delay <= min_delay || - max_delay < BTM_PER_INQ_MIN_MAX_PERIOD || - max_delay > BTM_PER_INQ_MAX_MAX_PERIOD) + max_delay < BTM_PER_INQ_MIN_MAX_PERIOD) + /* max_delay > BTM_PER_INQ_MAX_MAX_PERIOD)*/ + /* BTM_PER_INQ_MAX_MAX_PERIOD set to 1's in all bits. Condition resulting in false always*/ { return (BTM_ILLEGAL_VALUE); } @@ -618,13 +619,13 @@ tBTM_STATUS BTM_SetConnectability (UINT16 page_mode, UINT16 window, UINT16 inter BTM_TRACE_API0 ("BTM_SetConnectability"); #if (BLE_INCLUDED == TRUE && BLE_INCLUDED == TRUE) - if (btm_ble_set_connectability(page_mode) == BTM_SUCCESS) + if (btm_ble_set_connectability(page_mode) != BTM_SUCCESS) { - p_inq->connectable_mode &= (~BTM_BLE_CONNECTABLE_MASK); - p_inq->connectable_mode |= (page_mode & BTM_BLE_CONNECTABLE_MASK); + return BTM_NO_RESOURCES; } + p_inq->connectable_mode &= (~BTM_BLE_CONNECTABLE_MASK); + p_inq->connectable_mode |= (page_mode & BTM_BLE_CONNECTABLE_MASK); page_mode &= ~BTM_BLE_CONNECTABLE_MASK; - #endif /*** Check mode parameter ***/ @@ -757,7 +758,7 @@ tBTM_STATUS BTM_CancelInquiry(void) return (BTM_WRONG_MODE); /* Only cancel if not in periodic mode, otherwise the caller should call BTM_CancelPeriodicMode */ - if (p_inq->inq_active && + if ((p_inq->inq_active &BTM_INQUIRY_ACTIVE_MASK) != 0 && (!(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE))) { p_inq->inq_active = BTM_INQUIRY_INACTIVE; @@ -775,8 +776,11 @@ tBTM_STATUS BTM_CancelInquiry(void) /* Initiate the cancel inquiry */ else { - if (!btsnd_hcic_inq_cancel()) - status = BTM_NO_RESOURCES; + if ((p_inq->inqparms.mode & BTM_BR_INQUIRY_MASK) != 0) + { + if (!btsnd_hcic_inq_cancel()) + status = BTM_NO_RESOURCES; + } #if BLE_INCLUDED == TRUE if ((p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) != 0) btm_ble_stop_scan(); @@ -805,7 +809,7 @@ tBTM_STATUS BTM_CancelInquiry(void) ** Description This function is called to start an inquiry. ** ** Parameters: p_inqparms - pointer to the inquiry information -** mode - GENERAL or LIMITED inquiry +** mode - GENERAL or LIMITED inquiry, BR/LE bit mask seperately ** duration - length in 1.28 sec intervals (If '0', the inquiry is CANCELLED) ** max_resps - maximum amount of devices to search for before ending the inquiry ** filter_cond_type - BTM_CLR_INQUIRY_FILTER, BTM_FILTER_COND_DEVICE_CLASS, or @@ -830,7 +834,7 @@ tBTM_STATUS BTM_CancelInquiry(void) tBTM_STATUS BTM_StartInquiry (tBTM_INQ_PARMS *p_inqparms, tBTM_INQ_RESULTS_CB *p_results_cb, tBTM_CMPL_CB *p_cmpl_cb) { - tBTM_STATUS status; + tBTM_STATUS status = BTM_CMD_STARTED; tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; BTM_TRACE_API4 ("BTM_StartInquiry: mode: %d, dur: %d, rsps: %d, flt: %d", @@ -847,23 +851,23 @@ tBTM_STATUS BTM_StartInquiry (tBTM_INQ_PARMS *p_inqparms, tBTM_INQ_RESULTS_CB *p return (BTM_WRONG_MODE); if ((p_inqparms->mode & BTM_BR_INQUIRY_MASK)!= BTM_GENERAL_INQUIRY && - (p_inqparms->mode & BTM_BR_INQUIRY_MASK)!= BTM_LIMITED_INQUIRY) + (p_inqparms->mode & BTM_BR_INQUIRY_MASK)!= BTM_LIMITED_INQUIRY +#if (BLE_INCLUDED == TRUE) + && (p_inqparms->mode & BTM_BLE_INQUIRY_MASK)!= BTM_BLE_GENERAL_INQUIRY + && (p_inqparms->mode & BTM_BLE_INQUIRY_MASK)!= BTM_BLE_LIMITED_INQUIRY +#endif + ) return (BTM_ILLEGAL_VALUE); /* Save the inquiry parameters to be used upon the completion of setting/clearing the inquiry filter */ p_inq->inqparms = *p_inqparms; -#if (BLE_INCLUDED == TRUE) - p_inq->inqparms.mode = (UINT8)(p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) | (UINT8)(1 << (p_inqparms->mode & BTM_BR_INQUIRY_MASK)); -#else - p_inq->inqparms.mode = (UINT8)(1 << (p_inqparms->mode & BTM_BR_INQUIRY_MASK)); -#endif /* Initialize the inquiry variables */ p_inq->state = BTM_INQ_ACTIVE_STATE; p_inq->p_inq_cmpl_cb = p_cmpl_cb; p_inq->p_inq_results_cb = p_results_cb; p_inq->inq_cmpl_info.num_resp = 0; /* Clear the results counter */ - p_inq->inq_active = (UINT8)(1 << (p_inqparms->mode & BTM_BR_INQUIRY_MASK)); + p_inq->inq_active = p_inqparms->mode; BTM_TRACE_DEBUG1("BTM_StartInquiry: p_inq->inq_active = 0x%02x", p_inq->inq_active); @@ -872,8 +876,8 @@ tBTM_STATUS BTM_StartInquiry (tBTM_INQ_PARMS *p_inqparms, tBTM_INQ_RESULTS_CB *p if (p_inqparms->mode & BTM_BLE_INQUIRY_MASK) { /* BLE for now does not support filter condition for inquiry */ - if (btm_ble_start_inquiry((UINT8)(p_inqparms->mode & BTM_BLE_INQUIRY_MASK), - p_inq->inqparms.duration) != BTM_SUCCESS) + if ((status = btm_ble_start_inquiry((UINT8)(p_inqparms->mode & BTM_BLE_INQUIRY_MASK), + p_inq->inqparms.duration)) != BTM_CMD_STARTED) { BTM_TRACE_ERROR0("Err Starting LE Inquiry."); p_inq->inqparms.mode &= ~ BTM_BLE_INQUIRY_MASK; @@ -885,6 +889,10 @@ tBTM_STATUS BTM_StartInquiry (tBTM_INQ_PARMS *p_inqparms, tBTM_INQ_RESULTS_CB *p } #endif /* end of BLE_INCLUDED */ + /* we're done with this routine if BR/EDR inquiry is not desired. */ + if ((p_inqparms->mode & BTM_BR_INQUIRY_MASK) == BTM_INQUIRY_NONE) + return status; + #if (defined(BTM_BYPASS_EVENT_FILTERING) && BTM_BYPASS_EVENT_FILTERING == TRUE) BTM_TRACE_WARNING0("BTM: Bypassing event filtering..."); p_inq->inqfilt_active = FALSE; @@ -1954,7 +1962,7 @@ void btm_process_inq_results (UINT8 *p, UINT8 inq_res_mode) UINT8 num_resp, xx; BD_ADDR bda; tINQ_DB_ENT *p_i; - tBTM_INQ_RESULTS *p_cur; + tBTM_INQ_RESULTS *p_cur=NULL; BOOLEAN is_new = TRUE; BOOLEAN update = FALSE; INT8 i_rssi; @@ -1977,8 +1985,8 @@ void btm_process_inq_results (UINT8 *p, UINT8 inq_res_mode) BTM_TRACE_DEBUG3 ("btm_process_inq_results inq_active:0x%x state:%d inqfilt_active:%d", btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active); #endif - /* Only process the results if the inquiry is still active */ - if (!p_inq->inq_active) + /* Only process the results if the BR inquiry is still active */ + if (!(p_inq->inq_active & BTM_BR_INQ_ACTIVE_MASK)) return; STREAM_TO_UINT8 (num_resp, p); @@ -2499,7 +2507,7 @@ tBTM_STATUS btm_initiate_rem_name (BD_ADDR remote_bda, tBTM_INQ_INFO *p_cur, *******************************************************************************/ void btm_process_remote_name (BD_ADDR bda, BD_NAME bdn, UINT16 evt_len, UINT8 hci_status) { - tBTM_REMOTE_DEV_NAME rem_name = {0}; + tBTM_REMOTE_DEV_NAME rem_name; tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; tBTM_CMPL_CB *p_cb = p_inq->p_remname_cmpl_cb; UINT8 *p_n1; @@ -2559,6 +2567,7 @@ void btm_process_remote_name (BD_ADDR bda, BD_NAME bdn, UINT16 evt_len, UINT8 hc /* temporary buffer. */ p_n1 = (UINT8 *)rem_name.remote_bd_name; rem_name.length = (evt_len < BD_NAME_LEN) ? evt_len : BD_NAME_LEN; + rem_name.remote_bd_name[rem_name.length] = 0; rem_name.status = BTM_SUCCESS; temp_evt_len = rem_name.length; @@ -2567,6 +2576,7 @@ void btm_process_remote_name (BD_ADDR bda, BD_NAME bdn, UINT16 evt_len, UINT8 hc *p_n1++ = *bdn++; temp_evt_len--; } + rem_name.remote_bd_name[rem_name.length] = 0; } diff --git a/stack/btm/btm_int.h b/stack/btm/btm_int.h index e5f4c1506..0b8305111 100644 --- a/stack/btm/btm_int.h +++ b/stack/btm/btm_int.h @@ -117,6 +117,11 @@ typedef struct #endif /* BTM_PWR_MGR_INCLUDED */ #if BLE_INCLUDED == TRUE UINT8 is_le_link; + BD_ADDR conn_addr; /* local device address used for this connection */ + UINT8 conn_addr_type; /* local device address type for this connection */ + BD_ADDR active_remote_addr; /* remote address used on this connection */ + UINT8 active_remote_addr_type; /* local device address type for this connection */ + #endif } tACL_CONN; @@ -171,6 +176,10 @@ typedef struct TIMER_LIST_ENT tx_power_timer; tBTM_CMPL_CB *p_tx_power_cmpl_cb; /* Callback function to be called */ +#if BLE_INCLUDED == TRUE + tBTM_CMPL_CB *p_le_test_cmd_cmpl_cb; /* Callback function to be called when + LE test mode command has been sent successfully */ +#endif BD_ADDR local_addr; /* BD_ADDR of the local device */ tBTM_VERSION_INFO local_version; /* Local Version Information */ BD_FEATURES local_features; /* Local features bit mask */ @@ -464,8 +473,7 @@ typedef struct typedef struct { tBLE_ADDR_TYPE ble_addr_type; /* LE device type: public or random address */ - BD_ADDR reconn_addr; /* reconnect address */ - BD_ADDR cur_rand_addr; /* current random address */ + tBLE_ADDR_TYPE static_addr_type; /* static address type */ BD_ADDR static_addr; /* static address */ #if SMP_INCLUDED == TRUE @@ -491,17 +499,18 @@ typedef struct DEV_CLASS dev_class; /* DEV_CLASS of the device */ LINK_KEY link_key; /* Device link key */ -#define BTM_SEC_AUTHORIZED BTM_SEC_FLAG_AUTHORIZED -#define BTM_SEC_AUTHENTICATED BTM_SEC_FLAG_AUTHENTICATED -#define BTM_SEC_ENCRYPTED BTM_SEC_FLAG_ENCRYPTED +#define BTM_SEC_AUTHORIZED BTM_SEC_FLAG_AUTHORIZED /* 0x01 */ +#define BTM_SEC_AUTHENTICATED BTM_SEC_FLAG_AUTHENTICATED /* 0x02 */ +#define BTM_SEC_ENCRYPTED BTM_SEC_FLAG_ENCRYPTED /* 0x04 */ #define BTM_SEC_NAME_KNOWN 0x08 -#define BTM_SEC_LINK_KEY_KNOWN BTM_SEC_FLAG_LKEY_KNOWN +#define BTM_SEC_LINK_KEY_KNOWN BTM_SEC_FLAG_LKEY_KNOWN /* 0x10 */ #define BTM_SEC_LINK_KEY_AUTHED 0x20 #define BTM_SEC_ROLE_SWITCHED 0x40 #define BTM_SEC_IN_USE 0x80 - tBTM_BD_NAME sec_bd_name; /* User friendly name of the device. (may be truncated to save space in dev_rec table) */ UINT8 sec_flags; /* Current device security state */ + + tBTM_BD_NAME sec_bd_name; /* User friendly name of the device. (may be truncated to save space in dev_rec table) */ BD_FEATURES features; /* Features suported by the device */ #define BTM_SEC_STATE_IDLE 0 @@ -525,6 +534,8 @@ typedef struct UINT8 link_key_type; /* Type of key used in pairing */ BOOLEAN link_key_changed; /* Changed link key during current connection */ +#define BTM_MAX_PRE_SM4_LKEY_TYPE BTM_LKEY_TYPE_REMOTE_UNIT /* the link key type used by legacy pairing */ + #define BTM_SM4_UNKNOWN 0x00 #define BTM_SM4_KNOWN 0x10 #define BTM_SM4_TRUE 0x11 @@ -552,6 +563,9 @@ typedef struct UINT8 rs_disc_pending; #endif // btla-specific -- +#define BTM_SEC_NO_LAST_SERVICE_ID 0 + UINT8 last_author_service_id; /* ID of last serviced authorized: Reset after each l2cap connection */ + } tBTM_SEC_DEV_REC; #define BTM_SEC_IS_SM4(sm) ((BOOLEAN)(BTM_SM4_TRUE == ((sm)&BTM_SM4_TRUE))) @@ -676,6 +690,7 @@ typedef UINT8 tBTM_PAIRING_STATE; #define BTM_PAIR_FLAGS_PIN_REQD 0x08 /* set this bit when pin_callback is called */ #define BTM_PAIR_FLAGS_PRE_FETCH_PIN 0x10 /* set this bit when pre-fetch pin */ #define BTM_PAIR_FLAGS_REJECTED_CONNECT 0x20 /* set this bit when rejected incoming connection */ +#define BTM_PAIR_FLAGS_WE_CANCEL_DD 0x40 /* set this bit when cancelling a bonding procedure */ typedef struct { @@ -1003,6 +1018,7 @@ extern void btm_reset_complete (void); extern void btm_read_local_version_complete (UINT8 *p, UINT16 evt_len); extern void btm_read_hci_buf_size_complete (UINT8 *p, UINT16 evt_len); extern void btm_read_local_features_complete (UINT8 *p, UINT16 evt_len); +extern void btm_read_local_ext_features_complete (UINT8 *p, UINT16 evt_len); extern void btm_read_local_name_complete (UINT8 *p, UINT16 evt_len); extern void btm_read_local_addr_complete (UINT8 *p, UINT16 evt_len); extern void btm_get_local_features (void); @@ -1010,7 +1026,7 @@ extern void btm_get_local_features (void); #if (BLE_INCLUDED == TRUE) extern void btm_read_ble_buf_size_complete (UINT8 *p, UINT16 evt_len); extern void btm_read_white_list_size_complete(UINT8 *p, UINT16 evt_len); -extern void btm_ble_add_2_white_list_complete(UINT8 *p, UINT16 evt_len); +extern void btm_ble_add_2_white_list_complete(UINT8 status); extern void btm_ble_remove_from_white_list_complete(UINT8 *p, UINT16 evt_len); extern void btm_ble_clear_white_list_complete(UINT8 *p, UINT16 evt_len); #endif /* BLE_INCLUDED */ @@ -1081,6 +1097,7 @@ extern void btm_sec_dev_rec_cback_event (tBTM_SEC_DEV_REC *p_dev_rec, UINT8 res extern void btm_sec_clear_ble_keys (tBTM_SEC_DEV_REC *p_dev_rec); extern BOOLEAN btm_sec_find_bonded_dev (UINT8 start_idx, UINT8 *p_found_idx, tBTM_SEC_DEV_REC *p_rec); extern BOOLEAN btm_sec_is_a_bonded_dev (BD_ADDR bda); +extern BOOLEAN btm_sec_is_le_capable_dev (BD_ADDR bda); #endif /* BLE_INCLUDED */ extern tINQ_DB_ENT *btm_inq_db_new (BD_ADDR p_bda); @@ -1098,13 +1115,7 @@ extern void btm_acl_reset_paging (void); extern void btm_acl_paging (BT_HDR *p, BD_ADDR dest); extern void btm_acl_set_discing (BOOLEAN discing); extern UINT8 btm_sec_clr_service_by_psm (UINT16 psm); - -#ifdef BRCM_VS -extern void btm_brcm_feat_init(void); -extern void btm_vs_reset_complete (void); -extern void btm_brcm_arc_init (void); - -#endif +extern void btm_sec_clr_temp_auth_service (BD_ADDR bda); #ifdef __cplusplus } diff --git a/stack/btm/btm_sco.c b/stack/btm/btm_sco.c index 5a11404fa..f58023253 100644 --- a/stack/btm/btm_sco.c +++ b/stack/btm/btm_sco.c @@ -308,8 +308,6 @@ void btm_route_sco_data(BT_HDR *p_msg) #endif } - - /******************************************************************************* ** ** Function BTM_WriteScoData @@ -619,10 +617,7 @@ tBTM_STATUS BTM_CreateSco (BD_ADDR remote_bda, BOOLEAN is_orig, UINT16 pkt_types { if (md == BTM_PM_MD_PARK || md == BTM_PM_MD_SNIFF) { -/* Coverity: FALSE-POSITIVE error from Coverity tool. Please do NOT remove following comment. */ -/* coverity[uninit_use_in_call] False-positive: setting the mode to BTM_PM_MD_ACTIVE only uses settings.mode - the other data members of tBTM_PM_PWR_MD are ignored -*/ + memset( (void*)&pm, 0, sizeof(pm)); pm.mode = BTM_PM_MD_ACTIVE; BTM_SetPowerMode(BTM_PM_SET_ONLY_ID, remote_bda, &pm); p->state = SCO_ST_PEND_UNPARK; @@ -1447,6 +1442,8 @@ tBTM_STATUS BTM_RegForEScoEvts (UINT16 sco_inx, tBTM_ESCO_CBACK *p_esco_cback) tBTM_STATUS BTM_ReadEScoLinkParms (UINT16 sco_inx, tBTM_ESCO_DATA *p_parms) { #if (BTM_MAX_SCO_LINKS>0) + UINT8 index; + BTM_TRACE_API1("BTM_ReadEScoLinkParms -> sco_inx 0x%04x", sco_inx); if (sco_inx < BTM_MAX_SCO_LINKS && @@ -1455,8 +1452,23 @@ tBTM_STATUS BTM_ReadEScoLinkParms (UINT16 sco_inx, tBTM_ESCO_DATA *p_parms) *p_parms = btm_cb.sco_cb.sco_db[sco_inx].esco.data; return (BTM_SUCCESS); } + + if (sco_inx == BTM_FIRST_ACTIVE_SCO_INDEX) + { + for (index = 0; index < BTM_MAX_SCO_LINKS; index++) + { + if (btm_cb.sco_cb.sco_db[index].state >= SCO_ST_CONNECTED) + { + BTM_TRACE_API1("BTM_ReadEScoLinkParms the first active SCO index is %d",index); + *p_parms = btm_cb.sco_cb.sco_db[index].esco.data; + return (BTM_SUCCESS); + } + } + } + #endif + BTM_TRACE_API0("BTM_ReadEScoLinkParms cannot find the SCO index!"); memset(p_parms, 0, sizeof(tBTM_ESCO_DATA)); return (BTM_WRONG_MODE); } diff --git a/stack/btm/btm_sec.c b/stack/btm/btm_sec.c index 956364e5d..212b11871 100644 --- a/stack/btm/btm_sec.c +++ b/stack/btm/btm_sec.c @@ -288,7 +288,7 @@ void BTM_SetSecurityMode (UINT8 security_mode) { UINT8 old_mode = btm_cb.security_mode; - UINT8 sp_mode = HCI_SPD_MODE_ENABLED; + UINT8 sp_mode = HCI_SP_MODE_ENABLED; UINT8 sp_debug_mode = HCI_SPD_MODE_DISABLED; switch (security_mode) @@ -777,6 +777,39 @@ UINT8 btm_sec_clr_service_by_psm (UINT16 psm) /******************************************************************************* ** +** Function btm_sec_clr_temp_auth_service +** +** Description Removes specified device record's temporary authorization +** flag from the security database. +** +** Parameters Device address to be cleared +** +** Returns void. +** +*******************************************************************************/ +void btm_sec_clr_temp_auth_service (BD_ADDR bda) +{ + tBTM_SEC_DEV_REC *p_dev_rec; + + if ((p_dev_rec = btm_find_dev (bda)) == NULL) + { + BTM_TRACE_WARNING0 ("btm_sec_clr_temp_auth_service() - no dev CB"); + return; + } + + /* Reset the temporary authorized flag so that next time (untrusted) service is accessed autorization will take place */ + if (p_dev_rec->last_author_service_id != BTM_SEC_NO_LAST_SERVICE_ID && p_dev_rec->p_cur_service) + { + BTM_TRACE_DEBUG6 ("btm_sec_clr_auth_service_by_psm [clearing device: %02x:%02x:%02x:%02x:%02x:%02x]", + bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]); + + p_dev_rec->last_author_service_id = BTM_SEC_NO_LAST_SERVICE_ID; + } +} + +/******************************************************************************* +** +** ** Function BTM_SecClrUCDService ** ** Description @@ -964,7 +997,18 @@ void BTM_DeviceAuthorized (BD_ADDR bd_addr, UINT8 res, UINT32 trusted_mask[]) { p_dev_rec->sec_flags |= BTM_SEC_AUTHORIZED; if (trusted_mask) + { BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask); + } + + /* Save the currently authorized service in case we are asked again + by another multiplexer layer */ + if (!p_dev_rec->is_originator) + { + BTM_TRACE_DEBUG1("BTM_DeviceAuthorized: Setting last_author_service_id to %d", + p_dev_rec->p_cur_service->service_id); + p_dev_rec->last_author_service_id = p_dev_rec->p_cur_service->service_id; + } } if (p_dev_rec->sec_state != BTM_SEC_STATE_AUTHORIZING) @@ -1008,6 +1052,8 @@ tBTM_STATUS BTM_SecBond (BD_ADDR bd_addr, UINT8 pin_len, UINT8 *p_pin, UINT32 tr #if SMP_INCLUDED == TRUE tACL_CONN *p=NULL; BOOLEAN is_le_slave_role=FALSE; + tBT_DEVICE_TYPE dev_type; + tBLE_ADDR_TYPE addr_type; #endif BTM_TRACE_API6 ("BTM_SecBond BDA: %02x:%02x:%02x:%02x:%02x:%02x", bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]); @@ -1100,10 +1146,11 @@ tBTM_STATUS BTM_SecBond (BD_ADDR bd_addr, UINT8 pin_len, UINT8 *p_pin, UINT32 tr } + BTM_ReadDevInfo(bd_addr, &dev_type, &addr_type); /* LE device, do SMP pairing */ - if (p_dev_rec->device_type == BT_DEVICE_TYPE_BLE) + if (dev_type == BT_DEVICE_TYPE_BLE) { - if (SMP_Pair(p_dev_rec->bd_addr) == SMP_STARTED) + if (SMP_Pair(bd_addr) == SMP_STARTED) { p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING; return BTM_CMD_STARTED; @@ -1275,7 +1322,12 @@ tBTM_STATUS BTM_SecBondCancel (BD_ADDR bd_addr) return BTM_NO_RESOURCES; } - + if (btm_cb.pairing_state == BTM_PAIR_STATE_GET_REM_NAME) + { + BTM_CancelRemoteDeviceName(); + btm_cb.pairing_flags |= BTM_PAIR_FLAGS_WE_CANCEL_DD; + return BTM_CMD_STARTED; + } return BTM_NOT_AUTHORIZED; } } @@ -1450,7 +1502,8 @@ tBTM_STATUS BTM_SetEncryption (BD_ADDR bd_addr, tBTM_SEC_CBACK *p_callback, *******************************************************************************/ static tBTM_STATUS btm_sec_send_hci_disconnect (tBTM_SEC_DEV_REC *p_dev_rec, UINT8 reason) { - UINT8 old_state = p_dev_rec->sec_state; + UINT8 old_state = p_dev_rec->sec_state; + tBTM_STATUS status = BTM_CMD_STARTED; BTM_TRACE_EVENT2 ("btm_sec_send_hci_disconnect: handle:0x%x, reason=0x%x", p_dev_rec->hci_handle, reason); @@ -1466,18 +1519,19 @@ static tBTM_STATUS btm_sec_send_hci_disconnect (tBTM_SEC_DEV_REC *p_dev_rec, UIN { BTM_TRACE_ERROR0("RS in progress - Set DISC Pending flag in btm_sec_send_hci_disconnect to delay disconnect"); p_dev_rec->rs_disc_pending = BTM_SEC_DISC_PENDING; - return BTM_SUCCESS; + status = BTM_SUCCESS; } + else #endif /* Tear down the HCI link */ if (!btsnd_hcic_disconnect (p_dev_rec->hci_handle, reason)) { /* could not send disconnect. restore old state */ p_dev_rec->sec_state = old_state; - return(BTM_NO_RESOURCES); + status = BTM_NO_RESOURCES; } } - return(BTM_CMD_STARTED); + return (status); } /******************************************************************************* @@ -1916,23 +1970,23 @@ void BTM_SetOutService(BD_ADDR bd_addr, UINT8 service_id, UINT32 mx_chan_id) *************************************************************************/ /******************************************************************************* ** -** Function btm_sec_check_upgrade +** Function btm_sec_is_upgrade_possible ** -** Description This function is called to check if the existing link key -** needs to be upgraded. +** Description This function returns TRUE if the existing link key +** can be upgraded or if the link key does not exist. ** -** Returns void +** Returns BOOLEAN ** *******************************************************************************/ -static void btm_sec_check_upgrade(tBTM_SEC_DEV_REC *p_dev_rec, BOOLEAN is_originator) +static BOOLEAN btm_sec_is_upgrade_possible(tBTM_SEC_DEV_REC *p_dev_rec, BOOLEAN is_originator) { - tBTM_SP_UPGRADE evt_data; UINT16 mtm_check = is_originator ? BTM_SEC_OUT_MITM : BTM_SEC_IN_MITM; + BOOLEAN is_possible = TRUE; if (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) { - - BTM_TRACE_DEBUG5 ("btm_sec_check_upgrade id:%d, link_key_typet:%d, rmt_io_caps:%d, chk flags:x%x, flags:x%x", + is_possible = FALSE; + BTM_TRACE_DEBUG5 ("btm_sec_is_upgrade_possible id:%d, link_key_typet:%d, rmt_io_caps:%d, chk flags:x%x, flags:x%x", p_dev_rec->p_cur_service->service_id, p_dev_rec->link_key_type, p_dev_rec->rmt_io_caps, mtm_check, p_dev_rec->p_cur_service->security_flags); /* Already have a link key to the connected peer. Is the link key secure enough? @@ -1943,26 +1997,56 @@ static void btm_sec_check_upgrade(tBTM_SEC_DEV_REC *p_dev_rec, BOOLEAN is_origi && (p_dev_rec->rmt_io_caps < BTM_IO_CAP_MAX) /* a valid peer IO cap */ && (btm_sec_io_map[p_dev_rec->rmt_io_caps][btm_cb.devcb.loc_io_caps])) /* authenticated link key is possible */ { - BTM_TRACE_DEBUG1 ("need upgrade!! sec_flags:0x%x", p_dev_rec->sec_flags); /* upgrade is possible: check if the application wants the upgrade. * If the application is configured to use a global MITM flag, * it probably would not want to upgrade the link key based on the security level database */ - memcpy (evt_data.bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN); - evt_data.upgrade = TRUE; - if (btm_cb.api.p_sp_callback) - (*btm_cb.api.p_sp_callback) (BTM_SP_UPGRADE_EVT, (tBTM_SP_EVT_DATA *)&evt_data); + is_possible = TRUE; + } + } + BTM_TRACE_DEBUG2 ("btm_sec_is_upgrade_possible is_possible:%d sec_flags:0x%x", is_possible, p_dev_rec->sec_flags); + return is_possible; +} - BTM_TRACE_DEBUG1 ("evt_data.upgrade:0x%x", evt_data.upgrade); - if (evt_data.upgrade) - { - /* if the application confirms the upgrade, set the upgrade bit */ - p_dev_rec->sm4 |= BTM_SM4_UPGRADE; +/******************************************************************************* +** +** Function btm_sec_check_upgrade +** +** Description This function is called to check if the existing link key +** needs to be upgraded. +** +** Returns void +** +*******************************************************************************/ +static void btm_sec_check_upgrade(tBTM_SEC_DEV_REC *p_dev_rec, BOOLEAN is_originator) +{ + tBTM_SP_UPGRADE evt_data; - /* Clear the link key known to go through authentication/pairing again */ - p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED); - p_dev_rec->sec_flags &= ~BTM_SEC_AUTHENTICATED; - BTM_TRACE_DEBUG1 ("sec_flags:0x%x", p_dev_rec->sec_flags); - } + BTM_TRACE_DEBUG0 ("btm_sec_check_upgrade..."); + + /* Only check if link key already exists */ + if (!(p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)) + return; + if (btm_sec_is_upgrade_possible (p_dev_rec, is_originator) == TRUE) + { + BTM_TRACE_DEBUG1 ("need upgrade!! sec_flags:0x%x", p_dev_rec->sec_flags); + /* upgrade is possible: check if the application wants the upgrade. + * If the application is configured to use a global MITM flag, + * it probably would not want to upgrade the link key based on the security level database */ + memcpy (evt_data.bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN); + evt_data.upgrade = TRUE; + if (btm_cb.api.p_sp_callback) + (*btm_cb.api.p_sp_callback) (BTM_SP_UPGRADE_EVT, (tBTM_SP_EVT_DATA *)&evt_data); + + BTM_TRACE_DEBUG1 ("evt_data.upgrade:0x%x", evt_data.upgrade); + if (evt_data.upgrade) + { + /* if the application confirms the upgrade, set the upgrade bit */ + p_dev_rec->sm4 |= BTM_SM4_UPGRADE; + + /* Clear the link key known to go through authentication/pairing again */ + p_dev_rec->sec_flags &= ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED); + p_dev_rec->sec_flags &= ~BTM_SEC_AUTHENTICATED; + BTM_TRACE_DEBUG1 ("sec_flags:0x%x", p_dev_rec->sec_flags); } } } @@ -2085,15 +2169,17 @@ tBTM_STATUS btm_sec_l2cap_access_req (BD_ADDR bd_addr, UINT16 psm, UINT16 handle /* we will process one after another */ if ( (p_dev_rec->p_callback) || (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) ) { - BTM_TRACE_EVENT2 ("btm_sec_l2cap_access_req() - busy - PSM:%d delayed state: %s", - psm, btm_pair_state_descr(btm_cb.pairing_state)); + BTM_TRACE_EVENT4 ("btm_sec_l2cap_access_req() - busy - PSM:%d delayed state: %s mode:%d, sm4:0x%x", + psm, btm_pair_state_descr(btm_cb.pairing_state), btm_cb.security_mode, p_dev_rec->sm4); + BTM_TRACE_EVENT2 ("security_flags:x%x, sec_flags:x%x", security_required, p_dev_rec->sec_flags); rc = BTM_CMD_STARTED; if ((BTM_SEC_MODE_SP != btm_cb.security_mode) || ((BTM_SEC_MODE_SP == btm_cb.security_mode) && (BTM_SM4_KNOWN == p_dev_rec->sm4)) + || (BTM_SEC_IS_SM4(p_dev_rec->sm4) && (btm_sec_is_upgrade_possible(p_dev_rec, is_originator) == FALSE)) ) { - BTM_TRACE_EVENT2 ("security_flags:x%x, sec_flags:x%x", security_required, p_dev_rec->sec_flags); - /* legacy mode - local is legacy or local is lisbon/peer is legacy */ + /* legacy mode - local is legacy or local is lisbon/peer is legacy + * or SM4 with no possibility of link key upgrade */ if (is_originator) { if (((security_required & BTM_SEC_OUT_FLAGS) == 0) || @@ -2256,11 +2342,16 @@ tBTM_STATUS btm_sec_l2cap_access_req (BD_ADDR bd_addr, UINT16 psm, UINT16 handle p_dev_rec->p_callback = p_callback; - /* Although authentication and encryption are per connection */ - /* authorization is per access request. For example when serial connection */ - /* is up and authorized and client requests to read file (access to other */ - /* scn, we need to request user's permission again. */ - p_dev_rec->sec_flags &= ~BTM_SEC_AUTHORIZED; + if (p_dev_rec->last_author_service_id == BTM_SEC_NO_LAST_SERVICE_ID + || p_dev_rec->last_author_service_id != p_dev_rec->p_cur_service->service_id) + { + /* Although authentication and encryption are per connection + ** authorization is per access request. For example when serial connection + ** is up and authorized and client requests to read file (access to other + ** scn), we need to request user's permission again. + */ + p_dev_rec->sec_flags &= ~BTM_SEC_AUTHORIZED; + } if (BTM_SEC_IS_SM4(p_dev_rec->sm4)) { @@ -2311,6 +2402,7 @@ tBTM_STATUS btm_sec_mx_access_request (BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_o tBTM_SEC_DEV_REC *p_dev_rec; tBTM_SEC_SERV_REC *p_serv_rec; tBTM_STATUS rc; + UINT16 security_required; BTM_TRACE_DEBUG1 ("btm_sec_mx_access_request is_originator:%d", is_originator); /* Find or get oldest record */ @@ -2337,8 +2429,41 @@ tBTM_STATUS btm_sec_mx_access_request (BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_o BTM_TRACE_EVENT4 ("btm_sec_mx_access_request service PSM:%d Proto:%d SCN:%d delayed state: %s", psm, mx_proto_id, mx_chan_id, btm_pair_state_descr(btm_cb.pairing_state)); - btm_sec_queue_mx_request (bd_addr, psm, is_originator, mx_proto_id, mx_chan_id, p_callback, p_ref_data); - return BTM_CMD_STARTED; + rc = BTM_CMD_STARTED; + security_required = p_serv_rec->security_flags; + if ((BTM_SEC_MODE_SP != btm_cb.security_mode) + || ((BTM_SEC_MODE_SP == btm_cb.security_mode) && (BTM_SM4_KNOWN == p_dev_rec->sm4)) + || (BTM_SEC_IS_SM4(p_dev_rec->sm4) && (btm_sec_is_upgrade_possible(p_dev_rec, is_originator) == FALSE)) + ) + { + /* legacy mode - local is legacy or local is lisbon/peer is legacy + * or SM4 with no possibility of link key upgrade */ + if (is_originator) + { + if (((security_required & BTM_SEC_OUT_FLAGS) == 0) || + ((((security_required & BTM_SEC_OUT_FLAGS) == BTM_SEC_OUT_AUTHENTICATE) && (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))) || + ((((security_required & BTM_SEC_OUT_FLAGS) == (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT)) && (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED))) + ) + { + rc = BTM_SUCCESS; + } + } + else + { + if (((security_required & BTM_SEC_IN_FLAGS) == 0) || + ((((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_AUTHENTICATE) && (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))) || + ((((security_required & BTM_SEC_IN_FLAGS) == (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT)) && (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED))) + ) + { + rc = BTM_SUCCESS; + } + } + } + if (rc == BTM_CMD_STARTED) + { + btm_sec_queue_mx_request (bd_addr, psm, is_originator, mx_proto_id, mx_chan_id, p_callback, p_ref_data); + return rc; + } } p_dev_rec->p_cur_service = p_serv_rec; @@ -2487,7 +2612,9 @@ static void btm_sec_bond_cancel_complete (void) if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE) || (BTM_PAIR_STATE_WAIT_LOCAL_PIN == btm_cb.pairing_state && - BTM_PAIR_FLAGS_WE_STARTED_DD & btm_cb.pairing_flags)) + BTM_PAIR_FLAGS_WE_STARTED_DD & btm_cb.pairing_flags) || + (btm_cb.pairing_state == BTM_PAIR_STATE_GET_REM_NAME && + BTM_PAIR_FLAGS_WE_CANCEL_DD & btm_cb.pairing_flags)) { /* for dedicated bonding in legacy mode, authentication happens at "link level" * btm_sec_connected is called with failed status. @@ -2894,6 +3021,12 @@ void btm_sec_rmt_name_request_complete (UINT8 *p_bd_addr, UINT8 *p_bd_name, UINT if (p_bd_addr && memcmp (btm_cb.pairing_bda, p_bd_addr, BD_ADDR_LEN) == 0) { BTM_TRACE_EVENT2 ("btm_sec_rmt_name_request_complete() continue bonding sm4: 0x%04x, status:0x%x", p_dev_rec->sm4, status); + if(btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_CANCEL_DD) + { + btm_sec_bond_cancel_complete(); + return; + } + if (status != HCI_SUCCESS) { btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); @@ -3531,6 +3664,7 @@ void btm_rem_oob_req (UINT8 *p) memcpy (evt_data.bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN); memcpy (evt_data.dev_class, p_dev_rec->dev_class, DEV_CLASS_LEN); BCM_STRNCPY_S((char *)evt_data.bd_name, sizeof(evt_data.bd_name), (char *)p_dev_rec->sec_bd_name, BTM_MAX_REM_BD_NAME_LEN+1); + evt_data.bd_name[BTM_MAX_REM_BD_NAME_LEN] = 0; btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP); if ((*btm_cb.api.p_sp_callback) (BTM_SP_RMT_OOB_EVT, (tBTM_SP_EVT_DATA *)&evt_data) == BTM_NOT_AUTHORIZED) @@ -3834,10 +3968,12 @@ void btm_sec_mkey_comp_event (UINT16 handle, UINT8 status, UINT8 key_flg) void btm_sec_encrypt_change (UINT16 handle, UINT8 status, UINT8 encr_enable) { tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle); - +#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE + tACL_CONN *p_acl; +#endif BTM_TRACE_EVENT3 ("Security Manager: encrypt_change status:%d State:%d, encr_enable = %d", status, (p_dev_rec) ? p_dev_rec->sec_state : 0, encr_enable); - BTM_TRACE_DEBUG1 ("before update p_dev_rec->sec_flags=0x%x", p_dev_rec->sec_flags ); + BTM_TRACE_DEBUG1 ("before update p_dev_rec->sec_flags=0x%x", (p_dev_rec) ? p_dev_rec->sec_flags : 0 ); /* For transaction collision we need to wait and repeat. There is no need */ /* for random timeout because only slave should receive the result */ @@ -3860,8 +3996,11 @@ void btm_sec_encrypt_change (UINT16 handle, UINT8 status, UINT8 encr_enable) p_dev_rec->sec_flags &= ~BTM_SEC_ENCRYPTED; BTM_TRACE_DEBUG1 ("after update p_dev_rec->sec_flags=0x%x", p_dev_rec->sec_flags ); + #if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE - if (p_dev_rec->device_type == BT_DEVICE_TYPE_BLE) + p_acl = btm_bda_to_acl(p_dev_rec->bd_addr); + + if (p_acl && p_acl->is_le_link) { btm_ble_link_encrypted(p_dev_rec->bd_addr, encr_enable); return; @@ -4004,6 +4143,9 @@ void btm_sec_connected (UINT8 *bda, UINT16 handle, UINT8 status, UINT8 enc_mode) if (status == HCI_SUCCESS) { p_dev_rec = btm_sec_alloc_dev (bda); +#if BLE_INCLUDED == TRUE + p_dev_rec->device_type |= BT_DEVICE_TYPE_BREDR; +#endif } else { @@ -4061,6 +4203,8 @@ void btm_sec_connected (UINT8 *bda, UINT16 handle, UINT8 status, UINT8 enc_mode) p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */ #endif + p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */ + if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) && (memcmp (btm_cb.pairing_bda, bda, BD_ADDR_LEN) == 0) ) { @@ -4208,8 +4352,6 @@ void btm_sec_connected (UINT8 *bda, UINT16 handle, UINT8 status, UINT8 enc_mode) if (btm_cb.btm_def_link_policy) BTM_SetLinkPolicy (p_acl_cb->remote_addr, &btm_cb.btm_def_link_policy); #endif - - BTM_SetLinkSuperTout (p_acl_cb->remote_addr, btm_cb.btm_def_link_super_tout); } btm_acl_created (bda, p_dev_rec->dev_class, p_dev_rec->sec_bd_name, handle, HCI_ROLE_SLAVE, FALSE); @@ -4338,6 +4480,8 @@ void btm_sec_disconnected (UINT16 handle, UINT8 reason) if (!p_dev_rec) return; + p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */ + #if BTM_DISC_DURING_RS == TRUE BTM_TRACE_ERROR0("btm_sec_disconnected - Clearing Pending flag"); p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */ @@ -4382,7 +4526,7 @@ void btm_sec_disconnected (UINT16 handle, UINT8 reason) #if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE p_dev_rec->enc_key_size = 0; - btm_ble_resume_bg_conn(NULL, TRUE); + btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, p_dev_rec->bd_addr, FALSE); /* see sec_flags processing in btm_acl_removed */ #endif p_dev_rec->sec_flags &= ~(BTM_SEC_AUTHORIZED | BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED | BTM_SEC_ROLE_SWITCHED); @@ -4421,7 +4565,10 @@ void btm_sec_link_key_notification (UINT8 *p_bda, UINT8 *p_link_key, UINT8 key_t p_dev_rec->link_key_type = key_type; p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_KNOWN; - +#if (BLE_INCLUDED == TRUE) + /* BR/EDR connection, update the encryption key size to be 16 as always */ + p_dev_rec->enc_key_size = 16; +#endif memcpy (p_dev_rec->link_key, p_link_key, LINK_KEY_LEN); if ( (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) @@ -5059,16 +5206,33 @@ static UINT8 btm_sec_start_authorization (tBTM_SEC_DEV_REC *p_dev_rec) else service_id = 0; - p_dev_rec->sec_state = BTM_SEC_STATE_AUTHORIZING; - result = (*btm_cb.api.p_authorize_callback) (p_dev_rec->bd_addr, + /* Send authorization request if not already sent during this service connection */ + if (p_dev_rec->last_author_service_id == BTM_SEC_NO_LAST_SERVICE_ID + || p_dev_rec->last_author_service_id != service_id) + { + p_dev_rec->sec_state = BTM_SEC_STATE_AUTHORIZING; + result = (*btm_cb.api.p_authorize_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class, p_dev_rec->sec_bd_name, p_service_name, service_id, p_dev_rec->is_originator); + } + + else /* Already authorized once for this L2CAP bringup */ + { + BTM_TRACE_DEBUG1 ("btm_sec_start_authorization: (Ignoring extra Authorization prompt for service %d)", service_id); + return (BTM_SUCCESS); + } + if (result == BTM_SUCCESS) { p_dev_rec->sec_flags |= BTM_SEC_AUTHORIZED; + + /* Save the currently authorized service in case we are asked again by another multiplexer layer */ + if (!p_dev_rec->is_originator) + p_dev_rec->last_author_service_id = service_id; + p_dev_rec->sec_state = BTM_SEC_STATE_IDLE; } return(result); @@ -5088,7 +5252,7 @@ static UINT8 btm_sec_start_authorization (tBTM_SEC_DEV_REC *p_dev_rec) *******************************************************************************/ BOOLEAN btm_sec_are_all_trusted(UINT32 p_mask[]) { - int trusted_inx; + UINT32 trusted_inx; for (trusted_inx = 0; trusted_inx < BTM_SEC_SERVICE_ARRAY_SIZE; trusted_inx++) { if (p_mask[trusted_inx] != BTM_SEC_TRUST_ALL) @@ -5611,6 +5775,30 @@ BOOLEAN btm_sec_is_a_bonded_dev (BD_ADDR bda) /******************************************************************************* ** +** Function btm_sec_is_le_capable_dev +** +** Description Is the specified device is dual mode or LE only device +** +** Returns TRUE - dev is a dual mode +** +*******************************************************************************/ +BOOLEAN btm_sec_is_le_capable_dev (BD_ADDR bda) +{ + tBTM_SEC_DEV_REC *p_dev_rec= btm_find_dev (bda); + BOOLEAN le_capable = FALSE; + +#if (BLE_INCLUDED== TRUE) + if (p_dev_rec && ((p_dev_rec->device_type == BT_DEVICE_TYPE_DUMO) || + (p_dev_rec->device_type == BT_DEVICE_TYPE_BLE) ) ) + { + le_capable = TRUE; + } +#endif + return le_capable; +} + +/******************************************************************************* +** ** Function btm_sec_find_bonded_dev ** ** Description Find a bonded device starting from the specified index diff --git a/stack/btu/btu_hcif.c b/stack/btu/btu_hcif.c index 63803bdc7..4aa82ef7e 100644 --- a/stack/btu/btu_hcif.c +++ b/stack/btu/btu_hcif.c @@ -150,10 +150,17 @@ static void btu_hcif_encyption_key_refresh_cmpl_evt (UINT8 *p, UINT16 evt_len); *******************************************************************************/ static void btu_hcif_store_cmd (UINT8 controller_id, BT_HDR *p_buf) { - tHCI_CMD_CB * p_hci_cmd_cb = &(btu_cb.hci_cmd_cb[controller_id]); + tHCI_CMD_CB *p_hci_cmd_cb; UINT16 opcode; BT_HDR *p_cmd; - UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset; + UINT8 *p; + + /* Validate controller ID */ + if (controller_id >= BTU_MAX_LOCAL_CTRLS) + return; + + p_hci_cmd_cb = &(btu_cb.hci_cmd_cb[controller_id]); + p = (UINT8 *)(p_buf + 1) + p_buf->offset; /* get command opcode */ STREAM_TO_UINT16 (opcode, p); @@ -1033,6 +1040,10 @@ static void btu_hcif_hdl_command_complete (UINT16 opcode, UINT8 *p, UINT16 evt_l btm_read_local_features_complete (p, evt_len); break; + case HCI_READ_LOCAL_EXT_FEATURES: + btm_read_local_ext_features_complete (p, evt_len); + break; + case HCI_READ_LOCAL_NAME: btm_read_local_name_complete (p, evt_len); break; @@ -1075,7 +1086,7 @@ static void btu_hcif_hdl_command_complete (UINT16 opcode, UINT8 *p, UINT16 evt_l break; case HCI_BLE_ADD_WHITE_LIST: - btm_ble_add_2_white_list_complete(p, evt_len); + btm_ble_add_2_white_list_complete(*p); break; case HCI_BLE_CLEAR_WHITE_LIST: @@ -1103,6 +1114,11 @@ static void btu_hcif_hdl_command_complete (UINT16 opcode, UINT8 *p, UINT16 evt_l btm_ble_write_adv_enable_complete(p); break; + case HCI_BLE_TRANSMITTER_TEST: + case HCI_BLE_RECEIVER_TEST: + case HCI_BLE_TEST_END: + btm_ble_test_command_complete(p); + break; #endif /* (BLE_INCLUDED == TRUE) */ default: @@ -1470,9 +1486,7 @@ void btu_hcif_cmd_timeout (UINT8 controller_id) UINT8 *p; void *p_cplt_cback = NULL; UINT16 opcode; -// btla-specific ++ UINT16 event; -// btla-specific -- #if (defined(BTU_CMD_CMPL_TOUT_DOUBLE_CHECK) && BTU_CMD_CMPL_TOUT_DOUBLE_CHECK == TRUE) if (!(p_hci_cmd_cb->checked_hcisu)) @@ -1586,10 +1600,8 @@ void btu_hcif_cmd_timeout (UINT8 controller_id) } /* fake a command complete; first create a fake event */ -// btla-specific ++ event = HCI_ERR_UNSPECIFIED; btu_hcif_hdl_command_complete (opcode, (UINT8 *)&event, 1, p_cplt_cback, controller_id); -// btla-specific -- break; } @@ -2202,51 +2214,9 @@ static void btu_ble_process_adv_pkt (UINT8 *p, UINT16 evt_len) btm_ble_process_adv_pkt(p); } - static void btu_ble_ll_conn_complete_evt ( UINT8 *p, UINT16 evt_len) { - UINT8 role, status, bda_type; - UINT16 handle; - BD_ADDR bda; - UINT16 conn_interval, conn_latency, conn_timeout; - UINT16 combined_mode; - - STREAM_TO_UINT8 (status, p); - STREAM_TO_UINT16 (handle, p); - STREAM_TO_UINT8 (role, p); - STREAM_TO_UINT8 (bda_type, p); - STREAM_TO_BDADDR (bda, p); - STREAM_TO_UINT16 (conn_interval, p); - STREAM_TO_UINT16 (conn_latency, p); - STREAM_TO_UINT16 (conn_timeout, p); - - handle = HCID_GET_HANDLE (handle); - - if (status == 0) - { - btm_ble_connected(bda, handle, HCI_ENCRYPT_MODE_DISABLED, role); - - l2cble_conn_comp (handle, role, bda, bda_type, conn_interval, - conn_latency, conn_timeout); - } - else - { - /* If we are LE connectable, check if we need to start advertising again */ - if (btm_cb.ble_ctr_cb.inq_var.connectable_mode != BTM_BLE_NON_CONNECTABLE) - { - tACL_CONN *pa = &btm_cb.acl_db[0]; - UINT16 xx; - - for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, pa++) - { - /* If any other LE link is up, we are still not connectable */ - if (pa->in_use && pa->is_le_link) - return; - } - combined_mode = (btm_cb.ble_ctr_cb.inq_var.connectable_mode | btm_cb.btm_inq_vars.connectable_mode); - btm_ble_set_connectability ( combined_mode ); - } - } + btm_ble_conn_complete(p, evt_len); } static void btu_ble_ll_conn_param_upd_evt (UINT8 *p, UINT16 evt_len) @@ -2267,7 +2237,7 @@ static void btu_ble_proc_ltk_req (UINT8 *p, UINT16 evt_len) STREAM_TO_UINT16(handle, p); pp = p + 8; STREAM_TO_UINT16(ediv, pp); -#if SMP_INCLUDED == TRUE +#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE btm_ble_ltk_request(handle, p, ediv); #endif /* This is empty until an upper layer cares about returning event */ diff --git a/stack/btu/btu_task.c b/stack/btu/btu_task.c index 48ce48991..514751804 100644 --- a/stack/btu/btu_task.c +++ b/stack/btu/btu_task.c @@ -169,7 +169,10 @@ BTU_API UINT32 btu_task (UINT32 param) #if (defined(HCISU_H4_INCLUDED) && HCISU_H4_INCLUDED == TRUE) /* wait an event that HCISU is ready */ - GKI_wait(0xFFFF, 0); + event = GKI_wait (0xFFFF, 0); + if (event & EVENT_MASK(GKI_SHUTDOWN_EVT)) + /* indicates BT ENABLE abort */ + return (0); #endif /* Initialize the mandatory core stack control blocks (BTU, BTM, L2CAP, and SDP) @@ -302,6 +305,14 @@ BTU_API UINT32 btu_task (UINT32 param) GKI_freebuf (p_msg); break; + case BT_EVT_TO_STOP_TIMER: + if (btu_cb.timer_queue.p_first == NULL) + { + GKI_stop_timer(TIMER_0); + } + GKI_freebuf (p_msg); + break; + #if defined(QUICK_TIMER_TICKS_PER_SEC) && (QUICK_TIMER_TICKS_PER_SEC > 0) case BT_EVT_TO_START_QUICK_TIMER : GKI_start_timer (TIMER_2, QUICK_TIMER_TICKS, TRUE); @@ -440,10 +451,6 @@ BTU_API UINT32 btu_task (UINT32 param) btm_ble_timeout(p_tle); break; - case BTU_TTYPE_BLE_SCAN_PARAM_IDLE: - btm_ble_scan_param_idle(); - break; - case BTU_TTYPE_ATT_WAIT_FOR_RSP: gatt_rsp_timeout(p_tle); break; @@ -602,14 +609,27 @@ UINT32 btu_remaining_time (TIMER_LIST_ENT *p_tle) *******************************************************************************/ void btu_stop_timer (TIMER_LIST_ENT *p_tle) { + BT_HDR *p_msg; GKI_remove_from_timer_list (&btu_cb.timer_queue, p_tle); - /* if timer list is empty stop periodic GKI timer */ - if (btu_cb.timer_queue.p_first == NULL) + /* if timer is stopped on other than BTU task */ + if (GKI_get_taskid() != BTU_TASK) { - GKI_stop_timer(TIMER_0); + /* post event to stop timer in BTU task */ + if ((p_msg = (BT_HDR *)GKI_getbuf(BT_HDR_SIZE)) != NULL) + { + p_msg->event = BT_EVT_TO_STOP_TIMER; + GKI_send_msg (BTU_TASK, TASK_MBOX_0, p_msg); + } + } + else + { + /* if timer list is empty stop periodic GKI timer */ + if (btu_cb.timer_queue.p_first == NULL) + { + GKI_stop_timer(TIMER_0); + } } - } #if defined(QUICK_TIMER_TICKS_PER_SEC) && (QUICK_TIMER_TICKS_PER_SEC > 0) diff --git a/stack/gap/gap_api.c b/stack/gap/gap_api.c new file mode 100644 index 000000000..d17895d3a --- /dev/null +++ b/stack/gap/gap_api.c @@ -0,0 +1,903 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2013 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#include <string.h> + +#include "bt_target.h" +#include "gap_int.h" +#include "btm_int.h" +#include "gki.h" +#include "btu.h" + +/******************************************************************************* +** +** Function GAP_SetDiscoverableMode +** +** Description This function is called to allow or disallow a service to +** discovered (Inquiry Scans). +** +** Parameters: mode - GAP_NON_DISCOVERABLE, GAP_LIMITED_DISCOVERABLE, +** or GAP_GENERAL_DISCOVERABLE +** +** duration - Amount of time for the duration of an inquiry scan. +** The step size is in 0.625 msec intervals. +** Range: 0x0012 - 0x1000 (11.25 - 2560 msecs) +** +** If a value of '0' is entered the default of +** 0x0012 (11.25 msecs) will be used. +** Note: The duration must be less than or equal to +** the interval. +** +** interval - Amount of time between the start of two inquiry scans. +** The step size is in 0.625 msec intervals. +** Range: 0x0012 - 0x1000 (11.25 - 2560 msecs) +** If a value of '0' is entered the default of +** 0x800 (1.28 secs) will be used. +** +** +** Returns BT_PASS (0) if successful, +** GAP_ERR_ILL_PARM if a bad parameter is detected, +** GAP_DEVICE_NOT_UP if the device is not active, +** GAP_ERR_PROCESSING if not enough resources to carry out request +** +*******************************************************************************/ +UINT16 GAP_SetDiscoverableMode (UINT16 mode, UINT16 duration, UINT16 interval) +{ + tBTM_STATUS status; + + status = BTM_SetDiscoverability(mode, duration, interval); + + return (gap_convert_btm_status (status)); +} + + +/******************************************************************************* +** +** Function GAP_ReadDiscoverableMode +** +** Description This function is called to retrieve the current discoverable mode +** for the local device. +** +** Parameters: duration - pointer to the amount of time of an inquiry scan. +** The step size is in 0.625 msec intervals. +** Range: 0x0012 - 0x1000 (11.25 - 2560 msecs) +** +** interval - pointer to the amount of time between the start of +** two inquiry scans. +** The step size is in 0.625 msec intervals. +** Range: 0x0012 - 0x1000 (11.25 - 2560 msecs) +** +** +** Returns GAP_NON_DISCOVERABLE, GAP_LIMITED_DISCOVERABLE, or +** GAP_GENERAL_DISCOVERABLE +** +*******************************************************************************/ +UINT16 GAP_ReadDiscoverableMode (UINT16 *duration, UINT16 *interval) +{ + return (BTM_ReadDiscoverability(duration, interval)); +} + + +/******************************************************************************* +** +** Function GAP_SetConnectableMode +** +** Description This function is called to allow or disallow a +** connections on the local device. +** +** Parameters: mode - GAP_NON_CONNECTABLE, GAP_CONNECTABLE, +** +** duration - Amount of time for the duration of a page scan. +** The step size is in 0.625 msec intervals. +** Range: 0x0012 - 0x1000 (11.25 - 2560 msecs) +** +** If a value of '0' is entered the default of +** 0x0012 (11.25 msecs) will be used. +** Note: The duration must be less than or equal to +** the interval. +** +** interval - Amount of time between the start of two page scans. +** The step size is in 0.625 msec intervals. +** Range: 0x0012 - 0x1000 (11.25 - 2560 msecs) +** If a value of '0' is entered the default of +** 0x800 (1.28 secs) will be used. +** +** +** Returns BT_PASS (0) if successful, +** GAP_ERR_ILL_PARM if a bad parameter is detected, +** GAP_DEVICE_NOT_UP if the device is not active, +** GAP_ERR_PROCESSING if not enough resources to carry out request +** +*******************************************************************************/ +UINT16 GAP_SetConnectableMode (UINT16 mode, UINT16 duration, UINT16 interval) +{ + tBTM_STATUS status; + + status = BTM_SetConnectability(mode, duration, interval); + + return (gap_convert_btm_status (status)); +} + + +/******************************************************************************* +** +** Function GAP_FindAddrByName +** +** Description This function is called to retrieve a device address given +** a device name. It first looks in the current local inquiry +** database for the device with the specified name. If not found +** it initiates a general inquiry. Upon completion, it retrieves +** the name for each device until a match is found or all devices +** have been checked. Note: This process can take a while to +** complete. +** +** Parameters: devname - +** +** inqparms - pointer to the inquiry information +** mode - GAP_GENERAL_INQUIRY or GAP_LIMITED_INQUIRY inquiry +** duration - length in 1.28 sec intervals +** max_resps - maximum amount of devices to search for before ending the inquiry +** filter_cond_type - GAP_CLR_INQUIRY_FILTER, GAP_FILTER_COND_DEVICE_CLASS, or +** GAP_FILTER_COND_BD_ADDR +** filter_cond - value for the filter (based on filter_cond_type) +** +** +** Returns BT_PASS if the name was immediately available. (BD_ADDR is returned) +** GAP_CMD_INITIATED if an inquiry has been initiated +** +*******************************************************************************/ +UINT16 GAP_FindAddrByName (BD_NAME devname, tGAP_INQ_PARMS *p_inq_parms, tGAP_CALLBACK *p_addr_cb, + BD_ADDR bd_addr) +{ + UINT16 status; + tBTM_STATUS btm_status; + + + /* If the remote name is retrieved automatically during an inquiry search the local db first */ + if ((status = gap_find_local_addr_by_name (devname, bd_addr)) != BT_PASS) + { + /* If this code is used, the name wasn't in the current inquiry database */ + /* A general inquiry must now be initiated */ + if (gap_cb.findaddr_cb.in_use == FALSE) + { + gap_cb.findaddr_cb.p_cback = p_addr_cb; + gap_cb.findaddr_cb.p_cur_inq = (tBTM_INQ_INFO *) NULL; /* Reset to the beginning of the database */ + BCM_STRNCPY_S ((char *)gap_cb.findaddr_cb.results.devname, sizeof(gap_cb.findaddr_cb.results.devname), (char *)devname, BTM_MAX_REM_BD_NAME_LEN); + + /* make sure we have an end of string char */ + gap_cb.findaddr_cb.results.devname[BTM_MAX_REM_BD_NAME_LEN] = 0; + + btm_status = BTM_StartInquiry (p_inq_parms, (tBTM_INQ_RESULTS_CB *) NULL, + (tBTM_CMPL_CB *) gap_find_addr_inq_cb); + gap_cb.findaddr_cb.in_use = TRUE; + + /* convert the error code into a GAP code and check the results for any errors */ + if ((status = gap_convert_btm_status (btm_status)) == GAP_CMD_INITIATED) + gap_cb.findaddr_cb.in_use = TRUE; + } + else + status = GAP_ERR_BUSY; + } + + return (status); +} + + +/******************************************************************************* +** +** Function GAP_ReadConnectableMode +** +** Description This function is called to retrieve the current connectability +** mode for the local device. +** +** Parameters: duration - pointer to the amount of time of an page scan. +** The step size is in 0.625 msec intervals. +** Range: 0x0012 - 0x1000 (11.25 - 2560 msecs) +** +** interval - pointer to the amount of time between the start of +** two page scans. +** The step size is in 0.625 msec intervals. +** Range: 0x0012 - 0x1000 (11.25 - 2560 msecs) +** +** +** Returns GAP_NON_CONNECTABLE, GAP_CONNECTABLE +** +*******************************************************************************/ + +UINT16 GAP_ReadConnectableMode (UINT16 *duration, UINT16 *interval) +{ + return (BTM_ReadConnectability(duration, interval)); +} + + +/******************************************************************************* +** +** Function GAP_SetSecurityMode +** +** Description Set security mode for the device +** +** Returns void +** +*******************************************************************************/ +void GAP_SetSecurityMode (UINT8 sec_mode) +{ + BTM_SetSecurityMode (sec_mode); +} + + +/******************************************************************************* +** +** Function GAP_Bond +** +** Description This function is called to perform bonding with peer device +** +** Parameters: bd_addr - Address of the device to bond +** pin_len - length in bytes of the PIN Code +** p_pin - pointer to array with the PIN Code +** trusted_mask - bitwise OR of trusted services (array of UINT32) +** +*******************************************************************************/ +UINT8 GAP_Bond (BD_ADDR bd_addr, UINT8 pin_len, UINT8 *p_pin, UINT32 trusted_mask[]) +{ + return ((UINT8) BTM_SecBond (bd_addr, pin_len, p_pin, trusted_mask)); +} + + +/******************************************************************************* +** +** Function GAP_SecRegister +** +** Description Application manager calls this function to register for +** security services. There can be one and only one application +** saving link keys. BTM allows only first registration. +** +** Returns TRUE if registered OK, else FALSE +** +*******************************************************************************/ +BOOLEAN GAP_SecRegister (tBTM_APPL_INFO *p_cb_info) +{ + return (BTM_SecRegister (p_cb_info)); +} + + +/******************************************************************************* +** +** Function GAP_PinRsp +** +** Description This function is called from UI after Security Manager submitted +** PIN code request. +** +** Parameters: bd_addr - Address of the device for which PIN was requested +** res - result of the operation BTM_SUCCESS if success +** pin_len - length in bytes of the PIN Code +** p_pin - pointer to array with the PIN Code +** trusted_mask - bitwise OR of trusted services (array of UINT32) +** +*******************************************************************************/ +void GAP_PinRsp (BD_ADDR bd_addr, UINT8 res, UINT8 pin_len, UINT8 *p_pin, UINT32 trusted_mask[]) +{ + BTM_PINCodeReply (bd_addr, res, pin_len, p_pin, trusted_mask); +} + + +/******************************************************************************* +** +** Function GAP_AuthorizeRsp +** +** Description This function is called from UI after Security Manager submitted +** authorization request +** +** Parameters: bd_addr - Address of the device for which PIN was requested +** res - result of the operation BTM_SUCCESS if success +** trusted_mask - bitwise OR of trusted services (array of UINT32) +** +*******************************************************************************/ +void GAP_AuthorizeRsp (BD_ADDR bd_addr, UINT8 res, UINT32 trusted_mask[]) +{ + BTM_DeviceAuthorized (bd_addr, res, trusted_mask); +} + + +/******************************************************************************* +** +** Function GAP_SetPairableMode +** +** Description This function is called to allow or disallow pairing +** on the local device. +** +** Parameters: mode - GAP_ALLOW_PAIRING, GAP_DISALLOW_PAIRING +** connect_only_pairable - TRUE or FALSE connect only to paired devices +** +** callback - The callback is called when a pin number is requested. +** +** Returns BT_PASS (0) if successful, or a non-zero error code +** +*******************************************************************************/ + +UINT16 GAP_SetPairableMode (UINT16 mode, BOOLEAN connect_only_paired) +{ + tBTM_STATUS btm_status; + UINT16 status = BT_PASS; + + if (mode == GAP_ALLOW_PAIRING) + { + btm_status = BTM_SetConnectability(BTM_CONNECTABLE, 0, 0); + + if ((status = gap_convert_btm_status (btm_status)) == BT_PASS) + BTM_SetPairableMode (TRUE, connect_only_paired); + } + else if (mode == GAP_DISALLOW_PAIRING) + { + BTM_SetPairableMode (FALSE, connect_only_paired); + } + else + { + GAP_TRACE_ERROR1 ("GAP_SetPairableMode: illegal mode %d", mode); + status = GAP_ERR_ILL_MODE; + } + return (status); +} + + +/******************************************************************************* +** +** Function GAP_StartInquiry +** +** Description This function initiates a single inquiry. +** +** Parameters: p_inqparms - pointer to the inquiry information +** mode - GAP_GENERAL_INQUIRY or GAP_LIMITED_INQUIRY inquiry +** duration - length in 1.28 sec intervals +** max_resps - maximum amount of devices to search for before ending the inquiry +** filter_cond_type - GAP_CLR_INQUIRY_FILTER, GAP_FILTER_COND_DEVICE_CLASS, or +** GAP_FILTER_COND_BD_ADDR +** filter_cond - value for the filter (based on filter_cond_type) +** +** p_results_cb - Pointer to the callback routine which gets called +** upon receipt of an inquiry result. If this field is +** NULL, the application is not notified. +** +** p_cmpl_cb - Pointer to the callback routine which gets called +** upon completion. If this field is NULL, the +** application is not notified when completed. +** +** +** Returns BT_PASS (0) if successful, +** GAP_ERR_ILL_MODE if a bad mode parameter was passed +** GAP_ERR_ILL_INQ_TIME if a bad interval or duration was passed +** GAP_ERR_NO_CTRL_BLK if out of control blocks +** GAP_ERR_ILL_PARM if a bad parameter was detected in BTM +** GAP_ERR_BUSY if the device already has an iquiry active +** GAP_DEVICE_NOT_UP if the device is not initialized yet +** GAP_ERR_PROCESSING if any other BTM error was returned +** +*******************************************************************************/ +UINT16 GAP_StartInquiry (tGAP_INQ_PARMS *p_inq_parms, tGAP_CALLBACK *p_results_cb, tGAP_CALLBACK *p_cmpl_cb) +{ + tGAP_INFO *p_cb; + tBTM_STATUS btm_status; + UINT16 retval; + + /*** Make sure the parameters are valid before continuing ***/ + if (p_inq_parms->mode != GAP_GENERAL_INQUIRY && p_inq_parms->mode != GAP_LIMITED_INQUIRY) + return (GAP_ERR_ILL_MODE); + + if (p_inq_parms->duration < GAP_MIN_INQUIRY_LEN || + p_inq_parms->duration > GAP_MAX_INQUIRY_LENGTH) + return (GAP_ERR_ILL_INQ_TIME); + + /*** get a control block for this operation ***/ + if ((p_cb = gap_allocate_cb()) != NULL) + { + p_cb->gap_cback = p_cmpl_cb; + p_cb->gap_inq_rslt_cback = p_results_cb; + p_cb->event = GAP_EVT_INQUIRY_COMPLETE; /* Return event expected */ + + btm_status = BTM_StartInquiry(p_inq_parms, gap_inq_results_cb, + (tBTM_CMPL_CB *) gap_cb.btm_cback[p_cb->index]); + + /* convert the error code into a GAP code and check the results for any errors */ + if ((retval = gap_convert_btm_status (btm_status)) != GAP_CMD_INITIATED) + gap_free_cb(p_cb); /* Error starting the inquiry */ + } + else + retval = GAP_ERR_NO_CTRL_BLK; + + return (retval); +} + + +/******************************************************************************* +** +** Function GAP_StartPeriodicInquiry +** +** Description This function initiates a periodic inquiry. +** +** Parameters: p_inqparms - pointer to the inquiry information +** mode - GAP_GENERAL_INQUIRY or GAP_LIMITED_INQUIRY inquiry +** duration - length in 1.28 sec intervals +** max_resps - maximum amount of devices to search for before ending the inquiry +** filter_cond_type - GAP_CLR_INQUIRY_FILTER, GAP_FILTER_COND_DEVICE_CLASS, or +** GAP_FILTER_COND_BD_ADDR +** filter_cond - value for the filter (based on filter_cond_type) +** +** min_time - Minimum amount of time between consecutive inquiries. +** The value is in 1.28 second intervals. +** Range: 0x0002 - 0xFFFE (2.56 - 83883.52 seconds) +** +** max_time - Maximum amount of time between consecutive inquiries. +** The value is in 1.28 sec intervals. +** Range: 0x0003 - 0xFFFF (3.84 - 83884.8 seconds) +** +** p_results_cb - Pointer to the callback routine which gets called +** upon receipt of an inquiry result. If this field is +** NULL, the application is not notified. +** +** +** Returns BT_PASS (0) if successful, +** GAP_ERR_ILL_MODE if a bad mode parameter was passed +** GAP_ERR_ILL_INQ_TIME if a bad interval or duration was passed +** GAP_ERR_NO_CTRL_BLK if out of control blocks +** GAP_ERR_ILL_PARM if a bad parameter was detected in BTM +** GAP_ERR_BUSY if the device already has an iquiry active +** GAP_DEVICE_NOT_UP if the device is not initialized yet +** GAP_ERR_PROCESSING if any other BTM error was returned +** +*******************************************************************************/ + +UINT16 GAP_StartPeriodicInquiry (tGAP_INQ_PARMS *p_inq_parms, UINT16 min_time, + UINT16 max_time, tGAP_CALLBACK *p_results_cb) +{ + tGAP_INFO *p_cb; + tBTM_STATUS btm_status; + UINT16 retval = BT_PASS; + + /*** Make sure the parameters are valid before continuing ***/ + if (p_inq_parms->mode != GAP_GENERAL_INQUIRY && p_inq_parms->mode != GAP_LIMITED_INQUIRY) + return (GAP_ERR_ILL_MODE); + + if (p_inq_parms->duration < GAP_MIN_INQUIRY_LEN || + p_inq_parms->duration > GAP_MAX_INQUIRY_LENGTH || + min_time <= p_inq_parms->duration || + min_time < GAP_PER_INQ_MIN_MIN_PERIOD || + min_time > GAP_PER_INQ_MAX_MIN_PERIOD || + max_time <= min_time || + max_time < GAP_PER_INQ_MIN_MAX_PERIOD) + { + return (GAP_ERR_ILL_INQ_TIME); + } + + /*** get a control block for this operation ***/ + if ((p_cb = gap_allocate_cb()) != NULL) + { + p_cb->gap_inq_rslt_cback = p_results_cb; + p_cb->event = GAP_EVT_INQUIRY_COMPLETE; /* mark the inquiry event active */ + + btm_status = BTM_SetPeriodicInquiryMode(p_inq_parms, max_time, min_time, + gap_inq_results_cb); + + /* convert the error code into a GAP code and check the results for any errors */ + if ((retval = gap_convert_btm_status (btm_status)) != GAP_CMD_INITIATED) + gap_free_cb(p_cb); /* Error starting the inquiry */ + } + else + retval = GAP_ERR_NO_CTRL_BLK; + + return (retval); +} + + +/******************************************************************************* +** +** Function GAP_CancelInquiry +** +** Description This function cancels a single inquiry (if in progress) +** +** Parameters: None +** +** Returns BOOLEAN (TRUE if successful, otherwise FALSE) +** +*******************************************************************************/ +UINT16 GAP_CancelInquiry(void) +{ + tGAP_INFO *p_cb = &gap_cb.blk[0]; + UINT8 x; + tBTM_STATUS btm_status; + UINT16 status; + + btm_status = BTM_CancelInquiry(); + if ((status = gap_convert_btm_status (btm_status)) == BT_PASS) + { + /* Free the control block that is waiting for the inquiry complete event */ + for (x = 0; x < GAP_MAX_BLOCKS; x++, p_cb++) + { + if (p_cb->in_use && p_cb->event == GAP_EVT_INQUIRY_COMPLETE) + { + gap_free_cb(p_cb); + return (BT_PASS); + } + } + + /* If here the control block was not found */ + status = GAP_ERR_NO_CTRL_BLK; + } + + return (status); +} + + +/******************************************************************************* +** +** Function GAP_CancelPeriodicInquiry +** +** Description This function cancels a periodic inquiry (if in progress) +** +** Parameters: None +** +** Returns BOOLEAN: (TRUE if successful, otherwise FALSE) +** +*******************************************************************************/ +UINT16 GAP_CancelPeriodicInquiry(void) +{ + tGAP_INFO *p_cb = &gap_cb.blk[0]; + UINT8 x; + tBTM_STATUS btm_status; + UINT16 status; + + btm_status = BTM_CancelPeriodicInquiry(); + if ((status = gap_convert_btm_status (btm_status)) == BT_PASS) + { + /* Free the control block that is waiting for the inquiry complete event */ + for (x = 0; x < GAP_MAX_BLOCKS; x++, p_cb++) + { + if (p_cb->in_use && p_cb->event == GAP_EVT_INQUIRY_COMPLETE) + { + gap_free_cb(p_cb); + return (BT_PASS); + } + } + + /* If here the control block was not found */ + status = GAP_ERR_NO_CTRL_BLK; + } + + return (status); +} + + +/******************************************************************************* +** +** Function GAP_GetFirstInquiryResult +** +** Description This function retrieves the first valid inquiry result. +** +** Parameters: p_results - pointer to the inquiry results +** +** Returns BT_PASS (0) if successful, or a non-zero error code +** GAP_EOINQDB if no more entries in the database. +** +*******************************************************************************/ +UINT16 GAP_GetFirstInquiryResult(tGAP_INQ_RESULTS *p_results) +{ + UINT8 *ptr; + + gap_cb.cur_inqptr = BTM_InqFirstResult(); + + if (gap_cb.cur_inqptr != NULL) + { + memcpy(p_results, &gap_cb.cur_inqptr->results, sizeof(tBTM_INQ_RESULTS)); + + ptr = (UINT8 *)gap_cb.cur_inqptr->results.remote_bd_addr; + GAP_TRACE_EVENT6("GAP_GetFirstInqResult %02x%02x%02x%02x%02x%02x", + ptr[0],ptr[1],ptr[2],ptr[3],ptr[4],ptr[5]); + return(BT_PASS); + } + else + { + GAP_TRACE_EVENT0("GAP_FirstInqResults: No BD_ADDRs Found"); + memset(p_results, 0, sizeof(tBTM_INQ_RESULTS)); + return(GAP_EOINQDB); + } +} + + +/******************************************************************************* +** +** Function GAP_GetNextInquiryResult +** +** Description This function retrieves the next valid inquiry result. +** +** Parameters: p_results - pointer to the inquiry results +** +** Returns BT_PASS (0) if successful, or a non-zero status code +** GAP_EOINQDB if no more entries in the database. +** +*******************************************************************************/ +UINT16 GAP_GetNextInquiryResult(tGAP_INQ_RESULTS *p_results) +{ + UINT8 *ptr; + + /*** if the current inquiry db pointer is NULL then call the first entry ***/ + if (gap_cb.cur_inqptr) + { + gap_cb.cur_inqptr = BTM_InqNextResult(gap_cb.cur_inqptr); + if (gap_cb.cur_inqptr != NULL) + { + memcpy(p_results, &gap_cb.cur_inqptr->results, + sizeof(tGAP_INQ_RESULTS)); + + ptr = (UINT8 *)gap_cb.cur_inqptr->results.remote_bd_addr; + GAP_TRACE_EVENT6("GAP_GetNextInqResult %02x%02x%02x%02x%02x%02x", + ptr[0],ptr[1],ptr[2],ptr[3],ptr[4],ptr[5]); + + return(BT_PASS); + } + else + { + GAP_TRACE_EVENT0("GAP_NextInqResults: No BD_ADDRs Found"); + memset(p_results, 0, sizeof(tBTM_INQ_RESULTS)); + return(GAP_EOINQDB); + } + } + else + return (GAP_GetFirstInquiryResult(p_results)); +} + + +/******************************************************************************* +** +** Function GAP_ReadLocalDeviceInfo +** +** Description This function retrieves local device information to the caller. +** +** Parameters: name - (output) pointer to the UTF-8 encoded string representing +** the device name. +** +** addr - (output) pointer to the Bluetooth device address (BD_ADDR). +** +** verinfo - (output) pointer to the LMP version information. +** +** features - (output) pointer to the LMP features for the device. +** +** NOTE: Return parameters that are set to NULL are not retrieved. +** +** Returns BT_PASS (0) if successful, or a non-zero error code +** +*******************************************************************************/ + +UINT16 GAP_ReadLocalDeviceInfo(UINT8 *name, BD_ADDR *addr, tGAP_LMP_VERSION *verinfo, + tGAP_LMP_FEATURES *features) +{ + return (GAP_UNSUPPORTED); +} + + + +/******************************************************************************* +** +** Function GAP_GetRemoteDeviceName +** +** Description The remote name is retrieved from the specified remote device. If +** GAP_CMD_INITIATED is returned by the function, the command was +** successfully sent to the controller. The GAP_EVT_NAME_RESP event +** is passed in the callback when the remote device name has been retrieved. +** +** Parameters: addr - The Bluetooth device address (BD_ADDR) of the remote +** device. +** +** callback - pointer to the callback which is called after the +** remote device has been retrieved. +** p_data in the callback points to the structure containing the +** status, device name length, and the UTF-8 encoded +** device name. (type tBTM_REMOTE_DEV_NAME) +** The event field in the callback is set to GAP_EVT_REM_NAME_COMPLETE. +** The callback is not called unless (GAP_CMD_INITIATED) is returned. +** +** +** Returns +** GAP_CMD_INITIATED if remote search successfully initiated +** GAP_ERR_BUSY if a remote name request is already in progress, +** GAP_ERR_NO_CTRL_BLK if out of control blocks (too many commands pending) +** GAP_BAD_BD_ADDR if the device address is bad, +** GAP_DEVICE_NOT_UP if the device has not been initialized yet +** GAP_ERR_PROCESSING if any other BTM error has been returned +** +*******************************************************************************/ +UINT16 GAP_GetRemoteDeviceName (BD_ADDR addr, tGAP_CALLBACK *callback) +{ + tGAP_INFO *p_cb; + UINT16 retval; + tBTM_STATUS btm_status; + + if ((p_cb = gap_allocate_cb()) != NULL) + { + p_cb->gap_cback = callback; + p_cb->event = GAP_EVT_REM_NAME_COMPLETE; /* Return event expected */ + + btm_status = BTM_ReadRemoteDeviceName (addr, gap_cb.btm_cback[p_cb->index]); + + /* If the name was not returned immediately, or if an error occurred, release the control block */ + if ((retval = gap_convert_btm_status (btm_status)) != GAP_CMD_INITIATED) + gap_free_cb (p_cb); + } + else + retval = GAP_ERR_NO_CTRL_BLK; + + return (retval); +} + +/******************************************************************************* +** +** Function GAP_SetDeviceClass +** +** Description This function updates the local Device Class. +** +** Parameters: +** p_cod - Pointer to the device class to set to +** +** cmd - the fields of the device class to update. +** GAP_SET_COD_MAJOR_MINOR, - overwrite major, minor class +** GAP_SET_COD_SERVICE_CLASS - set the bits in the input +** GAP_CLR_COD_SERVICE_CLASS - clear the bits in the input +** GAP_SET_COD_ALL - overwrite major, minor, set the bits in service class +** GAP_INIT_COD - overwrite major, minor, and service class +** +** Returns BT_PASS (0) if successful, +** GAP_ERR_BUSY if a discovery is already in progress +** GAP_ERR_ILL_PARM if an illegal parameter was detected +** GAP_ERR_PROCESSING if any other BTM error has been returned +** +*******************************************************************************/ +UINT16 GAP_SetDeviceClass(tGAP_COD *p_cod, UINT8 cmd) +{ + tBTM_STATUS btm_status; + UINT8 *dev; + UINT16 service; + UINT8 minor, major; + DEV_CLASS dev_class; + + dev = BTM_ReadDeviceClass(); + BTM_COD_SERVICE_CLASS( service, dev ); + BTM_COD_MINOR_CLASS(minor, dev ); + BTM_COD_MAJOR_CLASS(major, dev ); + + switch(cmd) + { + case GAP_SET_COD_MAJOR_MINOR: + minor = p_cod->minor & BTM_COD_MINOR_CLASS_MASK; + major = p_cod->major & BTM_COD_MAJOR_CLASS_MASK; + break; + + case GAP_SET_COD_SERVICE_CLASS: + /* clear out the bits that is not SERVICE_CLASS bits */ + p_cod->service &= BTM_COD_SERVICE_CLASS_MASK; + service = service | p_cod->service; + break; + + case GAP_CLR_COD_SERVICE_CLASS: + p_cod->service &= BTM_COD_SERVICE_CLASS_MASK; + service = service & (~p_cod->service); + break; + + case GAP_SET_COD_ALL: + minor = p_cod->minor & BTM_COD_MINOR_CLASS_MASK; + major = p_cod->major & BTM_COD_MAJOR_CLASS_MASK; + p_cod->service &= BTM_COD_SERVICE_CLASS_MASK; + service = service | p_cod->service; + break; + + case GAP_INIT_COD: + minor = p_cod->minor & BTM_COD_MINOR_CLASS_MASK; + major = p_cod->major & BTM_COD_MAJOR_CLASS_MASK; + service = p_cod->service & BTM_COD_SERVICE_CLASS_MASK; + break; + + default: + return GAP_ERR_ILL_PARM; + } + + /* convert the fields into the device class type */ + FIELDS_TO_COD(dev_class, minor, major, service); + + btm_status = BTM_SetDeviceClass(dev_class); + return (gap_convert_btm_status (btm_status)); +} + +/******************************************************************************* +** +** Function GAP_ReadDeviceClass +** +** Description This function reads the local Device Class. +** +** Parameters: +** +** Returns PASS +** +*******************************************************************************/ +UINT16 GAP_ReadDeviceClass(tGAP_COD *p_cod) +{ + UINT8 *dev; + + dev = BTM_ReadDeviceClass(); + + BTM_COD_SERVICE_CLASS( p_cod->service, dev ); + BTM_COD_MINOR_CLASS( p_cod->minor, dev ); + BTM_COD_MAJOR_CLASS( p_cod->major, dev ); + + return (BT_PASS); +} + +/******************************************************************************* +** +** Function GAP_SetTraceLevel +** +** Description This function sets the trace level for GAP. If called with +** a value of 0xFF, it simply returns the current trace level. +** +** Returns The new or current trace level +** +*******************************************************************************/ +UINT8 GAP_SetTraceLevel (UINT8 new_level) +{ + if (new_level != 0xFF) + gap_cb.trace_level = new_level; + + return (gap_cb.trace_level); +} + +/******************************************************************************* +** +** Function GAP_Init +** +** Description Initializes the control blocks used by GAP. +** +** This routine should not be called except once per +** stack invocation. +** +** Returns Nothing +** +*******************************************************************************/ +void GAP_Init(void) +{ + memset (&gap_cb, 0, sizeof (tGAP_CB)); + + /*** Initialize the callbacks for BTM; Needs to be one per GAP_MAX_BLOCKS ***/ + gap_cb.btm_cback[0] = gap_btm_cback0; +#if GAP_MAX_BLOCKS > 1 + gap_cb.btm_cback[1] = gap_btm_cback1; +#endif +#if GAP_MAX_BLOCKS > 2 + gap_cb.btm_cback[2] = gap_btm_cback2; +#endif + +#if defined(GAP_INITIAL_TRACE_LEVEL) + gap_cb.trace_level = GAP_INITIAL_TRACE_LEVEL; +#else + gap_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */ +#endif + + /* Initialize the connection control block if included in build */ +#if GAP_CONN_INCLUDED == TRUE + gap_conn_init(); +#endif /* GAP_CONN_INCLUDED */ + +#if BLE_INCLUDED == TRUE + gap_attr_db_init(); +#endif +} + diff --git a/stack/gap/gap_ble.c b/stack/gap/gap_ble.c new file mode 100644 index 000000000..19e24a9da --- /dev/null +++ b/stack/gap/gap_ble.c @@ -0,0 +1,967 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2013 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE) + +#include <string.h> +#include "gap_int.h" +#include "gap_api.h" +#include "gattdefs.h" +#include "gatt_api.h" +#include "gatt_int.h" +#include "btm_int.h" +#include "hcimsgs.h" + +#define GAP_CHAR_ICON_SIZE 2 +#define GAP_CHAR_DEV_NAME_SIZE 248 +#define GAP_BLE_PRIVACY_FLAG_SIZE 1 + +#define GAP_MAX_NUM_INC_SVR 0 +#define GAP_MAX_ATTR_NUM (2 * GAP_MAX_CHAR_NUM + GAP_MAX_NUM_INC_SVR + 1) +#define GAP_MAX_CHAR_VALUE_SIZE (30 + GAP_CHAR_DEV_NAME_SIZE) + + +#ifndef GAP_ATTR_DB_SIZE +#define GAP_ATTR_DB_SIZE GATT_DB_MEM_SIZE(GAP_MAX_NUM_INC_SVR, GAP_MAX_CHAR_NUM, GAP_MAX_CHAR_VALUE_SIZE) +#endif + +/* privacy flag readable and writable with encryption on */ +#ifndef GAP_BLE_PRIVACY_FLAG_PERM +#define GAP_BLE_PRIVACY_FLAG_PERM (GATT_PERM_READ|GATT_PERM_WRITE) +#endif + +#define GATT_READ_GAP_PRIVACY_FLAG 1 +#define GATT_SET_GAP_PRIVACY_FLAG 2 +#define GATT_READ_GAP_REMOTE_NAME 3 +#define GATT_UPDATE_RECONN_ADDR 4 + +#define GAP_BLE_PRIVACY_UNKNOWN 0xff + +static void gap_ble_s_attr_request_cback (UINT16 conn_id, UINT32 trans_id, tGATTS_REQ_TYPE op_code, tGATTS_DATA *p_data); + +/* client connection callback */ +static void gap_ble_c_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, BOOLEAN connected, tGATT_DISCONN_REASON reason); +static void gap_ble_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE *p_data); + +static tGATT_CBACK gap_cback = +{ + gap_ble_c_connect_cback, + gap_ble_c_cmpl_cback, + NULL, + NULL, + gap_ble_s_attr_request_cback +}; + + + +/******************************************************************************* +** +** Function gap_find_clcb_by_bd_addr +** +** Description The function searches all LCB with macthing bd address +** +** Returns total number of clcb found. +** +*******************************************************************************/ +tGAP_CLCB *gap_find_clcb_by_bd_addr(BD_ADDR bda) +{ + UINT8 i_clcb; + tGAP_CLCB *p_clcb = NULL; + + for (i_clcb = 0, p_clcb= gap_cb.clcb; i_clcb < GAP_MAX_CL; i_clcb++, p_clcb++) + { + if (p_clcb->in_use && !memcmp(p_clcb->bda, bda, BD_ADDR_LEN)) + { + return p_clcb; + } + } + + return NULL; +} + +/******************************************************************************* +** +** Function gap_ble_find_clcb_by_conn_id +** +** Description The function searches all LCB with macthing connection ID +** +** Returns total number of clcb found. +** +*******************************************************************************/ +tGAP_CLCB *gap_ble_find_clcb_by_conn_id(UINT16 conn_id) +{ + UINT8 i_clcb; + tGAP_CLCB *p_clcb = NULL; + + for (i_clcb = 0, p_clcb= gap_cb.clcb; i_clcb < GAP_MAX_CL; i_clcb++, p_clcb++) + { + if (p_clcb->in_use && p_clcb->connected && p_clcb->conn_id == conn_id) + { + return p_clcb; + } + } + + return p_clcb; +} + +/******************************************************************************* +** +** Function gap_clcb_alloc +** +** Description The function allocates a GAP connection link control block +** +** Returns NULL if not found. Otherwise pointer to the connection link block. +** +*******************************************************************************/ +tGAP_CLCB *gap_clcb_alloc (UINT16 conn_id, BD_ADDR bda) +{ + UINT8 i_clcb = 0; + tGAP_CLCB *p_clcb = NULL; + + for (i_clcb = 0, p_clcb= gap_cb.clcb; i_clcb < GAP_MAX_CL; i_clcb++, p_clcb++) + { + if (!p_clcb->in_use) + { + p_clcb->in_use = TRUE; + p_clcb->conn_id = conn_id; + p_clcb->connected = TRUE; + memcpy (p_clcb->bda, bda, BD_ADDR_LEN); + break; + } + } + return p_clcb; +} + +/******************************************************************************* +** +** Function gap_find_alloc_clcb +** +** Description The function find or allocates a GAP connection link control block +** +** Returns NULL if not found. Otherwise pointer to the connection link block. +** +*******************************************************************************/ +tGAP_CLCB *gap_find_alloc_clcb (UINT16 conn_id, BD_ADDR bda) +{ + UINT8 i_clcb = 0; + tGAP_CLCB *p_clcb = NULL; + + for (i_clcb = 0, p_clcb= gap_cb.clcb; i_clcb < GAP_MAX_CL; i_clcb++, p_clcb++) + { + if (!p_clcb->in_use) + { + p_clcb->in_use = TRUE; + p_clcb->conn_id = conn_id; + p_clcb->connected = TRUE; + memcpy (p_clcb->bda, bda, BD_ADDR_LEN); + break; + } + } + return p_clcb; +} + +/******************************************************************************* +** +** Function gap_get_conn_id_if_connected +** +** Description This function returns a connecttion handle to a ATT server +** if the server is already connected +** +** Parameters client_if: client interface. +** bd_addr: peer device address. +** +** Returns Connection handle or invalid handle value +** +*******************************************************************************/ +UINT16 gap_get_conn_id_if_connected (BD_ADDR bd_addr) +{ + tGAP_CLCB *p_clcb; + UINT16 i; + + GAP_TRACE_EVENT2 ("gap_get_conn_id_if_connected() - BDA: %08x%04x ", + (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3], + (bd_addr[4]<<8)+bd_addr[5]); + + for (i = 0, p_clcb = gap_cb.clcb; i < GAP_MAX_CL; i++, p_clcb++) + { + if (p_clcb->in_use && p_clcb->connected && !memcmp(p_clcb->bda, bd_addr, BD_ADDR_LEN) ) + { + return(p_clcb->conn_id); + } + } + + /* If here, failed to allocate a client control block */ + GATT_TRACE_DEBUG0 ("gap_get_conn_id_if_connected: not connected"); + return(GATT_INVALID_CONN_ID); +} + +/******************************************************************************* +** +** Function gap_ble_enqueue_op +** +** Description enqueue a GAP operation when GAP client is busy +** +** Returns void +** +*******************************************************************************/ +void gap_ble_enqueue_op( tGAP_CLCB * p_clcb, UINT8 op, BD_ADDR reconn_addr, UINT8 privacy_flag, void *p_cback) +{ + tGAP_BLE_PENDING_OP *p_op = (tGAP_BLE_PENDING_OP *)GKI_getbuf(sizeof(tGAP_BLE_PENDING_OP)); + + if (p_op != NULL) + { + p_op->op = op; + p_op->p_pending_cback = p_cback; + + if (op == GATT_SET_GAP_PRIVACY_FLAG) + p_op->pending_data.privacy_flag = privacy_flag; + else if (op == GATT_UPDATE_RECONN_ADDR) + memcpy(p_op->pending_data.reconn_addr, reconn_addr, BD_ADDR_LEN); + + GKI_enqueue(&p_clcb->pending_op_q, p_op); + } +} + +/******************************************************************************* +** +** Function gap_ble_process_pending_op +** +** Description get next pending operation and process it +** +** Returns void +** +*******************************************************************************/ +static BOOLEAN gap_ble_process_pending_op(tGAP_CLCB *p_clcb) +{ + tGAP_BLE_PENDING_OP *p_pending_op = (tGAP_BLE_PENDING_OP *)GKI_dequeue(&p_clcb->pending_op_q); + BOOLEAN started = FALSE; + + if (p_pending_op != NULL) + { + if (p_pending_op->op == GATT_UPDATE_RECONN_ADDR) + { + GAP_BleUpdateReconnectAddr( p_clcb->bda, + p_pending_op->pending_data.reconn_addr, + (tGAP_BLE_RECONN_ADDR_CBACK *)p_pending_op->p_pending_cback); + started = TRUE; + } + GKI_freebuf(p_pending_op); + } + else + { + GAP_TRACE_EVENT0("No pending operation"); + } + + return started; +} + +/******************************************************************************* +** GAP Attributes Database Request callback +*******************************************************************************/ +tGATT_STATUS gap_read_attr_value (UINT16 handle, tGATT_VALUE *p_value, BOOLEAN is_long) +{ + tGAP_ATTR *p_db_attr = gap_cb.gatt_attr; + UINT8 *p = p_value->value, i; + UINT16 offset = p_value->offset; + UINT8 *p_dev_name = NULL; + + for (i = 0; i < GAP_MAX_CHAR_NUM; i ++, p_db_attr ++) + { + if (handle == p_db_attr->handle) + { + if (p_db_attr->uuid != GATT_UUID_GAP_DEVICE_NAME && + is_long == TRUE) + return GATT_NOT_LONG; + + switch (p_db_attr->uuid) + { + case GATT_UUID_GAP_DEVICE_NAME: + BTM_ReadLocalDeviceName((char **)&p_dev_name); + if (strlen ((char *)p_dev_name) > GATT_MAX_ATTR_LEN) + p_value->len = GATT_MAX_ATTR_LEN; + else + p_value->len = (UINT16)strlen ((char *)p_dev_name); + + if (offset > p_value->len) + return GATT_INVALID_OFFSET; + else + { + p_value->len -= offset; + p_dev_name += offset; + ARRAY_TO_STREAM(p, p_dev_name, p_value->len); + GAP_TRACE_EVENT1("GATT_UUID_GAP_DEVICE_NAME len=0x%04x", p_value->len); + } + break; + + case GATT_UUID_GAP_ICON: + UINT16_TO_STREAM(p, p_db_attr->attr_value.icon); + p_value->len = 2; + break; + + case GATT_UUID_GAP_PRIVACY_FLAG: + UINT8_TO_STREAM(p, p_db_attr->attr_value.privacy); + p_value->len = 1; + break; + + case GATT_UUID_GAP_RECONN_ADDR: + p_value->len = BD_ADDR_LEN; + BDADDR_TO_STREAM(p, p_db_attr->attr_value.reconn_bda); + break; + + case GATT_UUID_GAP_PREF_CONN_PARAM: + UINT16_TO_STREAM(p, p_db_attr->attr_value.conn_param.int_min); /* int_min */ + UINT16_TO_STREAM(p, p_db_attr->attr_value.conn_param.int_max); /* int_max */ + UINT16_TO_STREAM(p, p_db_attr->attr_value.conn_param.latency); /* latency */ + UINT16_TO_STREAM(p, p_db_attr->attr_value.conn_param.sp_tout); /* sp_tout */ + p_value->len =8; + break; + } + return GATT_SUCCESS; + } + } + return GATT_NOT_FOUND; +} + +/******************************************************************************* +** GAP Attributes Database Read/Read Blob Request process +*******************************************************************************/ +tGATT_STATUS gap_proc_read (tGATTS_REQ_TYPE type, tGATT_READ_REQ *p_data, tGATTS_RSP *p_rsp) +{ + tGATT_STATUS status = GATT_NO_RESOURCES; + + if (p_data->is_long) + p_rsp->attr_value.offset = p_data->offset; + + p_rsp->attr_value.handle = p_data->handle; + + status = gap_read_attr_value(p_data->handle, &p_rsp->attr_value, p_data->is_long); + + return status; +} +BOOLEAN gap_read_local_reconn_addr(BD_ADDR_PTR reconn_bda) +{ + BD_ADDR dummy_bda = {0}; + + if (memcmp(gap_cb.reconn_bda, dummy_bda, BD_ADDR_LEN) != 0) + { + memcpy(reconn_bda, gap_cb.reconn_bda, BD_ADDR_LEN); + return TRUE; + } + else + return FALSE; +} + +/****************************************************************************** +** +** Function gap_proc_write_req +** +** Description GAP ATT server process a write request. +** +** Returns void. +** +*******************************************************************************/ +UINT8 gap_proc_write_req( tGATTS_REQ_TYPE type, tGATT_WRITE_REQ *p_data) +{ + tGAP_ATTR *p_db_attr = gap_cb.gatt_attr; + UINT8 i; + + for (i = 0; i < GAP_MAX_CHAR_NUM; i ++, p_db_attr ++) + { + if (p_data-> handle == p_db_attr->handle) + { + if (p_data->offset != 0) return GATT_NOT_LONG; + if (p_data->is_prep) return GATT_REQ_NOT_SUPPORTED; + +/* DO NOT SUPPORT RECONNECTION ADDRESS FOR NOW + + if (p_db_attr->uuid == GATT_UUID_GAP_RECONN_ADDR) + { + if (!btm_cb.ble_ctr_cb.privacy) + return GATT_WRITE_NOT_PERMIT; + if (p_data->len != BD_ADDR_LEN) return GATT_INVALID_ATTR_LEN; + + STREAM_TO_BDADDR(p_db_attr->attr_value.reconn_bda, p); + // write direct connection address + memcpy(&gap_cb.reconn_bda, p_db_attr->attr_value.reconn_bda, BD_ADDR_LEN); + + return GATT_SUCCESS; + } + else +*/ + return GATT_WRITE_NOT_PERMIT; + } + } + return GATT_NOT_FOUND; + +} + +/****************************************************************************** +** +** Function gap_ble_s_attr_request_cback +** +** Description GAP ATT server attribute access request callback. +** +** Returns void. +** +*******************************************************************************/ +void gap_ble_s_attr_request_cback (UINT16 conn_id, UINT32 trans_id, + tGATTS_REQ_TYPE type, tGATTS_DATA *p_data) +{ + UINT8 status = GATT_INVALID_PDU; + tGATTS_RSP rsp_msg; + BOOLEAN ignore = FALSE; + + GAP_TRACE_EVENT1("gap_ble_s_attr_request_cback : recv type (0x%02x)", type); + + memset(&rsp_msg, 0, sizeof(tGATTS_RSP)); + + switch (type) + { + case GATTS_REQ_TYPE_READ: + status = gap_proc_read(type, &p_data->read_req, &rsp_msg); + break; + + case GATTS_REQ_TYPE_WRITE: + if (!p_data->write_req.need_rsp) + ignore = TRUE; + + status = gap_proc_write_req(type, &p_data->write_req); + break; + + case GATTS_REQ_TYPE_WRITE_EXEC: + ignore = TRUE; + GAP_TRACE_EVENT0("Ignore GATTS_REQ_TYPE_WRITE_EXEC" ); + break; + + case GATTS_REQ_TYPE_MTU: + GAP_TRACE_EVENT1("Get MTU exchange new mtu size: %d", p_data->mtu); + ignore = TRUE; + break; + + default: + GAP_TRACE_EVENT1("Unknown/unexpected LE GAP ATT request: 0x%02x", type); + break; + } + + if (!ignore) + GATTS_SendRsp (conn_id, trans_id, status, &rsp_msg); +} + +/******************************************************************************* +** +** Function btm_ble_att_db_init +** +** Description GAP ATT database initalization. +** +** Returns void. +** +*******************************************************************************/ +void gap_attr_db_init(void) +{ + tBT_UUID app_uuid = {LEN_UUID_128,{0}}; + tBT_UUID uuid = {LEN_UUID_16,{UUID_SERVCLASS_GAP_SERVER}}; + UINT16 service_handle; + tGAP_ATTR *p_db_attr = &gap_cb.gatt_attr[0]; + tGATT_STATUS status; + + /* Fill our internal UUID with a fixed pattern 0x82 */ + memset (&app_uuid.uu.uuid128, 0x82, LEN_UUID_128); + memset(gap_cb.gatt_attr, 0, sizeof(tGAP_ATTR) *GAP_MAX_CHAR_NUM); + + gap_cb.gatt_if = GATT_Register(&app_uuid, &gap_cback); + + GATT_StartIf(gap_cb.gatt_if); + + /* Create a GAP service */ + service_handle = GATTS_CreateService (gap_cb.gatt_if, &uuid, 0, GAP_MAX_ATTR_NUM, TRUE); + + GAP_TRACE_EVENT1 ("gap_attr_db_init service_handle = %d", service_handle); + + /* add Device Name Characteristic + */ + uuid.len = LEN_UUID_16; + uuid.uu.uuid16 = p_db_attr->uuid = GATT_UUID_GAP_DEVICE_NAME; + p_db_attr->handle = GATTS_AddCharacteristic(service_handle, &uuid, GATT_PERM_READ, GATT_CHAR_PROP_BIT_READ); + p_db_attr ++; + + /* add Icon characteristic + */ + uuid.uu.uuid16 = p_db_attr->uuid = GATT_UUID_GAP_ICON; + p_db_attr->handle = GATTS_AddCharacteristic(service_handle, + &uuid, + GATT_PERM_READ, + GATT_CHAR_PROP_BIT_READ); + p_db_attr ++; + + /* start service now */ + memset (&app_uuid.uu.uuid128, 0x81, LEN_UUID_128); + + status = GATTS_StartService(gap_cb.gatt_if, service_handle, GAP_TRANSPORT_SUPPORTED ); + + GAP_TRACE_EVENT3 ("GAP App gatt_if: %d s_hdl = %d start_status=%d", + gap_cb.gatt_if, service_handle, status); + + + +} + +/******************************************************************************* +** +** Function GAP_BleAttrDBUpdate +** +** Description GAP ATT database update. +** +** Returns void. +** +*******************************************************************************/ +void GAP_BleAttrDBUpdate(UINT16 attr_uuid, tGAP_BLE_ATTR_VALUE *p_value) +{ + tGAP_ATTR *p_db_attr = gap_cb.gatt_attr; + UINT8 i = 0; + + GAP_TRACE_EVENT1("GAP_BleAttrDBUpdate attr_uuid=0x%04x", attr_uuid); + + for (i = 0; i < GAP_MAX_CHAR_NUM; i ++, p_db_attr ++) + { + if (p_db_attr->uuid == attr_uuid) + { + GAP_TRACE_EVENT1("Found attr_uuid=0x%04x", attr_uuid); + + switch (attr_uuid) + { + case GATT_UUID_GAP_ICON: + p_db_attr->attr_value.icon = p_value->icon; + break; + + case GATT_UUID_GAP_PREF_CONN_PARAM: + memcpy((void *)&p_db_attr->attr_value.conn_param, (const void *)&p_value->conn_param, sizeof(tGAP_BLE_PREF_PARAM)); + break; + + case GATT_UUID_GAP_DEVICE_NAME: + BTM_SetLocalDeviceName((char *)p_value->p_dev_name); + break; + + } + break; + } + } + + return; +} + +/******************************************************************************* +** +** Function gap_ble_cl_op_cmpl +** +** Description GAP client operation complete callback +** +** Returns void +** +*******************************************************************************/ +void gap_ble_cl_op_cmpl(tGAP_CLCB *p_clcb, BOOLEAN status, UINT16 len, UINT8 *p_name) +{ + tGAP_BLE_DEV_NAME_CBACK *p_dev_name_cback = (tGAP_BLE_DEV_NAME_CBACK *)(p_clcb->p_cback); + UINT16 op = p_clcb->cl_op_uuid; + + GAP_TRACE_EVENT1("gap_ble_cl_op_cmpl status: %d", status); + + p_clcb->cl_op_uuid = 0; + p_clcb->p_cback=NULL; + + if (!gap_ble_process_pending_op(p_clcb) && op != 0) + GATT_Disconnect(p_clcb->conn_id); + + if (p_dev_name_cback) + { + GAP_TRACE_EVENT0("calling gap_ble_cl_op_cmpl"); + + if (op == GATT_UUID_GAP_DEVICE_NAME) + (* p_dev_name_cback)(status, p_clcb->bda, len, (char *)p_name); + } + +} + +/******************************************************************************* +** +** Function gap_ble_c_connect_cback +** +** Description Client connection callback. +** +** Returns void +** +*******************************************************************************/ +static void gap_ble_c_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, + BOOLEAN connected, tGATT_DISCONN_REASON reason) +{ + tGAP_CLCB *p_clcb = gap_find_clcb_by_bd_addr (bda); + UINT16 cl_op_uuid; + + GAP_TRACE_EVENT5 ("gap_ble_c_connect_cback: from %08x%04x connected:%d conn_id=%d reason = 0x%04x", + (bda[0]<<24)+(bda[1]<<16)+(bda[2]<<8)+bda[3], + (bda[4]<<8)+bda[5], connected, conn_id, reason); + + + if (connected) + { + if (p_clcb == NULL) + { + if ((p_clcb = gap_clcb_alloc(conn_id, bda))== NULL) + { + GAP_TRACE_ERROR0 ("gap_ble_c_connect_cback: no_resource"); + return; + } + } + p_clcb->conn_id = conn_id; + p_clcb->connected = TRUE; + + /* Do not use reconnection address for now --> + check privacy enabled? set reconnect address + btm_ble_update_reconnect_address(bda);*/ + } + else + { + if (p_clcb != NULL) + p_clcb->connected = FALSE; + } + + if (p_clcb) + { + cl_op_uuid = p_clcb->cl_op_uuid; + + GAP_TRACE_EVENT1 ("cl_op_uuid=0x%04x", cl_op_uuid ); + + if (p_clcb->connected) + { + p_clcb->cl_op_uuid = 0; + if (cl_op_uuid == GATT_UUID_GAP_DEVICE_NAME) + { + GAP_BleReadPeerDevName (bda, (tGAP_BLE_DEV_NAME_CBACK *)p_clcb->p_cback); + } + } + /* current link disconnect */ + else + { + gap_ble_cl_op_cmpl(p_clcb, FALSE, 0, NULL); + memset(p_clcb, 0, sizeof(tGAP_CLCB)); + } + } + +} + +/******************************************************************************* +** +** Function gap_ble_c_cmpl_cback +** +** Description Client operation complete callback. +** +** Returns void +** +*******************************************************************************/ +static void gap_ble_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE *p_data) + +{ + tGAP_CLCB *p_clcb = gap_ble_find_clcb_by_conn_id(conn_id); + UINT16 op_type; + UINT16 min, max, latency, tout; + UINT16 len; + UINT8 *pp; + + if (p_clcb == NULL) + return; + + op_type = p_clcb->cl_op_uuid; + + GAP_TRACE_EVENT3 ("gap_ble_c_cmpl_cback() - op_code: 0x%02x status: 0x%02x read_type: 0x%04x", op, status, op_type); + /* Currently we only issue read commands */ + if (op != GATTC_OPTYPE_READ && op != GATTC_OPTYPE_WRITE) + return; + + if (status != GATT_SUCCESS) + { + gap_ble_cl_op_cmpl(p_clcb, FALSE, 0, NULL); + return; + } + + pp = p_data->att_value.value; + + switch (op_type) + { + case GATT_UUID_GAP_PREF_CONN_PARAM: + GAP_TRACE_EVENT0 ("GATT_UUID_GAP_PREF_CONN_PARAM"); + /* Extract the peripheral preferred connection parameters and save them */ + + STREAM_TO_UINT16 (min, pp); + STREAM_TO_UINT16 (max, pp); + STREAM_TO_UINT16 (latency, pp); + STREAM_TO_UINT16 (tout, pp); + + BTM_BleSetPrefConnParams (p_clcb->bda, min, max, latency, tout); + /* release the connection here */ + gap_ble_cl_op_cmpl(p_clcb, TRUE, 0, NULL); + break; + + case GATT_UUID_GAP_DEVICE_NAME: + GAP_TRACE_EVENT0 ("GATT_UUID_GAP_DEVICE_NAME"); + len = (UINT16)strlen((char *)pp); + if (len > GAP_CHAR_DEV_NAME_SIZE) + len = GAP_CHAR_DEV_NAME_SIZE; + gap_ble_cl_op_cmpl(p_clcb, TRUE, len, pp); + break; + case GATT_UUID_GAP_ICON: + break; + + } +} + +/******************************************************************************* +** +** Function gap_ble_cl_read_request +** +** Description utility function to start a read request for a GAP charactersitic +** +** Returns TRUE if read started, else FALSE if GAP is busy +** +*******************************************************************************/ +BOOLEAN gap_ble_cl_read_request(tGAP_CLCB *p_clcb, UINT16 uuid, void * p_cback) +{ + tGATT_READ_PARAM param; + + memset(¶m, 0, sizeof(tGATT_READ_PARAM)); + + param.service.uuid.len = LEN_UUID_16; + param.service.uuid.uu.uuid16 = uuid; + param.service.s_handle = 1; + param.service.e_handle = 0xFFFF; + param.service.auth_req = 0; + + if (GATTC_Read(p_clcb->conn_id, GATT_READ_BY_TYPE, ¶m) != GATT_SUCCESS) + { + GAP_TRACE_ERROR0 ("GAP_BleReadPeerPrefConnParams: GATT_Read Failed"); + /* release the link here */ + GATT_Disconnect(p_clcb->conn_id); + return(FALSE); + } + else + { + p_clcb->p_cback = p_cback; + p_clcb->cl_op_uuid = uuid; + return TRUE; + } + +} + +/******************************************************************************* +** +** Function GAP_BleReadPeerPrefConnParams +** +** Description Start a process to read a connected peripheral's preferred +** connection parameters +** +** Returns TRUE if read started, else FALSE if GAP is busy +** +*******************************************************************************/ +BOOLEAN GAP_BleReadPeerPrefConnParams (BD_ADDR peer_bda) +{ + tGAP_CLCB *p_clcb; + + + /* This function should only be called if there is a connection to */ + /* the peer. Get a client handle for that connection. */ + if ((p_clcb = gap_find_clcb_by_bd_addr (peer_bda)) == NULL || + !p_clcb->connected) + { + GAP_TRACE_ERROR0("No connection, can not update reconnect address"); + return(FALSE); + } + + GAP_TRACE_API3 ("GAP_BleReadPeerPrefConnParams() - BDA: %08x%04x cl_op_uuid: 0x%04x", + (peer_bda[0]<<24)+(peer_bda[1]<<16)+(peer_bda[2]<<8)+peer_bda[3], + (peer_bda[4]<<8)+peer_bda[5], p_clcb->cl_op_uuid); + + /* For now we only handle one at a time */ + if (p_clcb->cl_op_uuid != 0) + return(FALSE); + + return gap_ble_cl_read_request(p_clcb, GATT_UUID_GAP_PREF_CONN_PARAM, NULL); + +} + +/******************************************************************************* +** +** Function GAP_BleReadPeerDevName +** +** Description Start a process to read a connected peripheral's device name. +** +** Returns TRUE if request accepted +** +*******************************************************************************/ +BOOLEAN GAP_BleReadPeerDevName (BD_ADDR peer_bda, tGAP_BLE_DEV_NAME_CBACK *p_cback) +{ + tGAP_CLCB *p_clcb = gap_find_clcb_by_bd_addr (peer_bda); + + if (p_cback == NULL) + return(FALSE); + + if (p_clcb == NULL) + { + p_clcb = gap_clcb_alloc(0, peer_bda); + p_clcb->connected = FALSE; + } + + if (p_clcb == NULL) + { + GAP_TRACE_ERROR0("GAP_BleReadPeerDevName max connection reached"); + } + + + GAP_TRACE_EVENT3 ("GAP_BleReadPeerDevName() - BDA: %08x%04x cl_op_uuid: 0x%04x", + (peer_bda[0]<<24)+(peer_bda[1]<<16)+(peer_bda[2]<<8)+peer_bda[3], + (peer_bda[4]<<8)+peer_bda[5], p_clcb->cl_op_uuid); + + /* For now we only handle one at a time */ + if (p_clcb->cl_op_uuid != 0) + return(FALSE); + + /* hold the link here */ + GATT_Connect(gap_cb.gatt_if, p_clcb->bda, TRUE); + + if (p_clcb->connected) + { + return gap_ble_cl_read_request(p_clcb, GATT_UUID_GAP_DEVICE_NAME, (void *)p_cback); + } + + p_clcb->p_cback = (void *)p_cback; + /* Mark currently active operation */ + p_clcb->cl_op_uuid = GATT_UUID_GAP_DEVICE_NAME; + + + return(TRUE); +} + +/******************************************************************************* +** +** Function GAP_BleCancelReadPeerDevName +** +** Description Cancel reading a peripheral's device name. +** +** Returns TRUE if request accepted +** +*******************************************************************************/ +BOOLEAN GAP_BleCancelReadPeerDevName (BD_ADDR peer_bda) +{ + tGAP_CLCB *p_clcb = gap_find_clcb_by_bd_addr (peer_bda); + + GAP_TRACE_EVENT3 ("GAP_BleCancelReadPeerDevName() - BDA: %08x%04x cl_op_uuid: 0x%04x", + (peer_bda[0]<<24)+(peer_bda[1]<<16)+(peer_bda[2]<<8)+peer_bda[3], + (peer_bda[4]<<8)+peer_bda[5], (p_clcb == NULL)? 0 : p_clcb->cl_op_uuid); + + if (p_clcb == NULL || p_clcb->cl_op_uuid != GATT_UUID_GAP_DEVICE_NAME) + { + GAP_TRACE_ERROR0 ("Cannot cancel current op is not get dev name"); + return FALSE; + } + + if (!p_clcb->connected) + { + if (!GATT_CancelConnect(gap_cb.gatt_if, peer_bda, TRUE)) + { + GAP_TRACE_ERROR0 ("Cannot cancel where No connection id"); + return FALSE; + } + } + + gap_ble_cl_op_cmpl(p_clcb, FALSE, 0, NULL); + + return(TRUE); +} + +/******************************************************************************* +** +** Function GAP_BleUpdateReconnectAddr +** +** Description Start a process to udpate the reconnect address if remote devive +** has privacy enabled. +** +** Returns TRUE if read started, else FALSE if GAP is busy +** +*******************************************************************************/ +BOOLEAN GAP_BleUpdateReconnectAddr (BD_ADDR peer_bda, BD_ADDR reconn_addr, + tGAP_BLE_RECONN_ADDR_CBACK *p_cback) +{ + tGAP_CLCB *p_clcb; + tGATT_DISC_PARAM param; + + if (p_cback == NULL) + return(FALSE); + + /* This function should only be called if there is a connection to */ + /* the peer. Get a client handle for that connection. */ + if ((p_clcb = gap_find_clcb_by_bd_addr (peer_bda)) == NULL || + !p_clcb->connected) + { + GAP_TRACE_ERROR0("No connection, can not update reconnect address"); + return(FALSE); + } + + GAP_TRACE_API3 ("GAP_BleUpdateReconnectAddr() - BDA: %08x%04x cl_op_uuid: 0x%04x", + (peer_bda[0]<<24)+(peer_bda[1]<<16)+(peer_bda[2]<<8)+peer_bda[3], + (peer_bda[4]<<8)+peer_bda[5], p_clcb->cl_op_uuid); + + /* For now we only handle one at a time */ + if (p_clcb->cl_op_uuid != 0) + { + gap_ble_enqueue_op(p_clcb, GATT_UPDATE_RECONN_ADDR, reconn_addr, 0, (void *)p_cback); + return(FALSE); + } + + /* hold the link here */ + GATT_Connect(gap_cb.gatt_if, p_clcb->bda, TRUE); + + memset(¶m, 0, sizeof(tGATT_DISC_PARAM)); + + param.service.len = LEN_UUID_16; + param.service.uu.uuid16 = GATT_UUID_GAP_RECONN_ADDR; + param.s_handle = 1; + param.e_handle = 0xFFFF; + + if (GATTC_Discover(p_clcb->conn_id, GATT_DISC_CHAR, ¶m) != GATT_SUCCESS) + { + GAP_TRACE_ERROR0 ("GAP_BleReadPeerPrefConnParams: GATT_Read Failed"); + /* release the link here */ + GATT_Disconnect(p_clcb->conn_id); + return(FALSE); + } + else + { + p_clcb->p_cback = (void *)p_cback; + memcpy(p_clcb->reconn_addr, reconn_addr, BD_ADDR_LEN); + p_clcb->cl_op_uuid = GATT_UUID_GAP_RECONN_ADDR; + } + + return TRUE; + +} + +#endif /* BLE_INCLUDED */ + + + + + diff --git a/stack/gap/gap_conn.c b/stack/gap/gap_conn.c new file mode 100644 index 000000000..43765b767 --- /dev/null +++ b/stack/gap/gap_conn.c @@ -0,0 +1,1270 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2013 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + + +#include "bt_target.h" +#include "btu.h" +#include "gap_int.h" +#include "l2cdefs.h" +#include "l2c_int.h" +#include <string.h> +#if GAP_CONN_INCLUDED == TRUE +#include "btm_int.h" + +/********************************************************************************/ +/* L O C A L F U N C T I O N P R O T O T Y P E S */ +/********************************************************************************/ +static void gap_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid, UINT16 psm, UINT8 l2cap_id); +static void gap_connect_cfm (UINT16 l2cap_cid, UINT16 result); +static void gap_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg); +static void gap_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg); +static void gap_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed); +static void gap_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg); +static void gap_congestion_ind (UINT16 lcid, BOOLEAN is_congested); + +static tGAP_CCB *gap_find_ccb_by_cid (UINT16 cid); +static tGAP_CCB *gap_find_ccb_by_handle (UINT16 handle); +static tGAP_CCB *gap_allocate_ccb (void); +static void gap_release_ccb (tGAP_CCB *p_ccb); + +/******************************************************************************* +** +** Function gap_conn_init +** +** Description This function is called to initialize GAP connection management +** +** Returns void +** +*******************************************************************************/ +void gap_conn_init (void) +{ +#if AMP_INCLUDED == TRUE + gap_cb.conn.reg_info.pAMP_ConnectInd_Cb = gap_connect_ind; + gap_cb.conn.reg_info.pAMP_ConnectCfm_Cb = gap_connect_cfm; + gap_cb.conn.reg_info.pAMP_ConnectPnd_Cb = NULL; + gap_cb.conn.reg_info.pAMP_ConfigInd_Cb = gap_config_ind; + gap_cb.conn.reg_info.pAMP_ConfigCfm_Cb = gap_config_cfm; + gap_cb.conn.reg_info.pAMP_DisconnectInd_Cb = gap_disconnect_ind; + gap_cb.conn.reg_info.pAMP_DisconnectCfm_Cb = NULL; + gap_cb.conn.reg_info.pAMP_QoSViolationInd_Cb = NULL; + gap_cb.conn.reg_info.pAMP_DataInd_Cb = gap_data_ind; + gap_cb.conn.reg_info.pAMP_CongestionStatus_Cb = gap_congestion_ind; + gap_cb.conn.reg_info.pAMP_TxComplete_Cb = NULL; + gap_cb.conn.reg_info.pAMP_MoveInd_Cb = NULL; + gap_cb.conn.reg_info.pAMP_MoveRsp_Cb = NULL; + gap_cb.conn.reg_info.pAMP_MoveCfm_Cb = NULL; //gap_move_cfm + gap_cb.conn.reg_info.pAMP_MoveCfmRsp_Cb = NULL; //gap_move_cfm_rsp + +#else + gap_cb.conn.reg_info.pL2CA_ConnectInd_Cb = gap_connect_ind; + gap_cb.conn.reg_info.pL2CA_ConnectCfm_Cb = gap_connect_cfm; + gap_cb.conn.reg_info.pL2CA_ConnectPnd_Cb = NULL; + gap_cb.conn.reg_info.pL2CA_ConfigInd_Cb = gap_config_ind; + gap_cb.conn.reg_info.pL2CA_ConfigCfm_Cb = gap_config_cfm; + gap_cb.conn.reg_info.pL2CA_DisconnectInd_Cb = gap_disconnect_ind; + gap_cb.conn.reg_info.pL2CA_DisconnectCfm_Cb = NULL; + gap_cb.conn.reg_info.pL2CA_QoSViolationInd_Cb = NULL; + gap_cb.conn.reg_info.pL2CA_DataInd_Cb = gap_data_ind; + gap_cb.conn.reg_info.pL2CA_CongestionStatus_Cb = gap_congestion_ind; + gap_cb.conn.reg_info.pL2CA_TxComplete_Cb = NULL; +#endif +} + + +/******************************************************************************* +** +** Function GAP_ConnOpen +** +** Description This function is called to open an L2CAP connection. +** +** Parameters: is_server - If TRUE, the connection is not created +** but put into a "listen" mode waiting for +** the remote side to connect. +** +** service_id - Unique service ID from +** BTM_SEC_SERVICE_FIRST_EMPTY (6) +** to BTM_SEC_MAX_SERVICE_RECORDS (32) +** +** p_rem_bda - Pointer to remote BD Address. +** If a server, and we don't care about the +** remote BD Address, then NULL should be passed. +** +** psm - the PSM used for the connection +** +** p_config - Optional pointer to configuration structure. +** If NULL, the default GAP configuration will +** be used. +** +** security - security flags +** chan_mode_mask - (GAP_FCR_CHAN_OPT_BASIC, GAP_FCR_CHAN_OPT_ERTM, GAP_FCR_CHAN_OPT_STREAM) +** +** p_cb - Pointer to callback function for events. +** +** Returns handle of the connection if successful, else GAP_INVALID_HANDLE +** +*******************************************************************************/ +UINT16 GAP_ConnOpen (char *p_serv_name, UINT8 service_id, BOOLEAN is_server, + BD_ADDR p_rem_bda, UINT16 psm, tL2CAP_CFG_INFO *p_cfg, + UINT16 security, UINT8 chan_mode_mask, tGAP_CONN_CALLBACK *p_cb) +{ + tGAP_CCB *p_ccb; + UINT16 cid; + tBT_UUID bt_uuid = {2, {GAP_PROTOCOL_ID}}; + + GAP_TRACE_EVENT0 ("GAP_CONN - Open Request"); + + /* Allocate a new CCB. Return if none available. */ + if ((p_ccb = gap_allocate_ccb()) == NULL) + return (GAP_INVALID_HANDLE); + + /* If caller specified a BD address, save it */ + if (p_rem_bda) + { + /* the bd addr is not BT_BD_ANY, then a bd address was specified */ + if (memcmp (p_rem_bda, BT_BD_ANY, BD_ADDR_LEN)) + p_ccb->rem_addr_specified = TRUE; + + memcpy (&p_ccb->rem_dev_address[0], p_rem_bda, BD_ADDR_LEN); + } + else if (!is_server) + { + /* remore addr is not specified and is not a server -> bad */ + return (GAP_INVALID_HANDLE); + } + + /* A client MUST have specified a bd addr to connect with */ + if (!p_ccb->rem_addr_specified && !is_server) + { + gap_release_ccb (p_ccb); + GAP_TRACE_ERROR0 ("GAP ERROR: Client must specify a remote BD ADDR to connect to!"); + return (GAP_INVALID_HANDLE); + } + + /* Check if configuration was specified */ + if (p_cfg) + p_ccb->cfg = *p_cfg; + + p_ccb->p_callback = p_cb; + + /* If originator, use a dynamic PSM */ +#if AMP_INCLUDED == TRUE + if (!is_server) + gap_cb.conn.reg_info.pAMP_ConnectInd_Cb = NULL; + else + gap_cb.conn.reg_info.pAMP_ConnectInd_Cb = gap_connect_ind; +#else + if (!is_server) + gap_cb.conn.reg_info.pL2CA_ConnectInd_Cb = NULL; + else + gap_cb.conn.reg_info.pL2CA_ConnectInd_Cb = gap_connect_ind; +#endif + + /* Register the PSM with L2CAP */ + if ((p_ccb->psm = L2CA_REGISTER (psm, &gap_cb.conn.reg_info, AMP_AUTOSWITCH_ALLOWED|AMP_USE_AMP_IF_POSSIBLE)) == 0) + { + GAP_TRACE_ERROR1 ("GAP_ConnOpen: Failure registering PSM 0x%04x", psm); + gap_release_ccb (p_ccb); + return (GAP_INVALID_HANDLE); + } + + /* Register with Security Manager for the specific security level */ + p_ccb->service_id = service_id; + if (!BTM_SetSecurityLevel ((UINT8)!is_server, p_serv_name, p_ccb->service_id, security, p_ccb->psm, 0, 0)) + { + GAP_TRACE_ERROR0 ("GAP_CONN - Security Error"); + gap_release_ccb (p_ccb); + return (GAP_INVALID_HANDLE); + } + + /* Fill in eL2CAP parameter data */ + if( p_ccb->cfg.fcr_present ) + { + p_ccb->ertm_info.preferred_mode = p_ccb->cfg.fcr.mode; + p_ccb->ertm_info.user_rx_pool_id = GAP_DATA_POOL_ID; + p_ccb->ertm_info.user_tx_pool_id = GAP_DATA_POOL_ID; + p_ccb->ertm_info.fcr_rx_pool_id = L2CAP_DEFAULT_ERM_POOL_ID; + p_ccb->ertm_info.fcr_tx_pool_id = L2CAP_DEFAULT_ERM_POOL_ID; + } + + /* optional FCR channel modes */ + p_ccb->ertm_info.allowed_modes = (chan_mode_mask) ? chan_mode_mask : (UINT8)L2CAP_FCR_CHAN_OPT_BASIC; + + if (is_server) + { + p_ccb->con_flags |= GAP_CCB_FLAGS_SEC_DONE; /* assume btm/l2cap would handle it */ + p_ccb->con_state = GAP_CCB_STATE_LISTENING; + return (p_ccb->gap_handle); + } + else + { + /* We are the originator of this connection */ + p_ccb->con_flags = GAP_CCB_FLAGS_IS_ORIG; + + /* Transition to the next appropriate state, waiting for connection confirm. */ + p_ccb->con_state = GAP_CCB_STATE_CONN_SETUP; + + /* mark security done flag, when security is not required */ + if ((security & (BTM_SEC_OUT_AUTHORIZE | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT) ) == 0) + p_ccb->con_flags |= GAP_CCB_FLAGS_SEC_DONE; + + /* Check if L2CAP started the connection process */ + if (p_rem_bda && ((cid = L2CA_CONNECT_REQ (p_ccb->psm, p_rem_bda, &p_ccb->ertm_info, &bt_uuid)) != 0)) + { + p_ccb->connection_id = cid; + return (p_ccb->gap_handle); + } + else + { + gap_release_ccb (p_ccb); + return (GAP_INVALID_HANDLE); + } + } +} + + +/******************************************************************************* +** +** Function GAP_ConnClose +** +** Description This function is called to close a connection. +** +** Parameters: handle - Handle of the connection returned by GAP_ConnOpen +** +** Returns BT_PASS - closed OK +** GAP_ERR_BAD_HANDLE - invalid handle +** +*******************************************************************************/ +UINT16 GAP_ConnClose (UINT16 gap_handle) +{ + tGAP_CCB *p_ccb = gap_find_ccb_by_handle (gap_handle); + + GAP_TRACE_EVENT1 ("GAP_CONN - close handle: 0x%x", gap_handle); + + if (p_ccb) + { + /* Check if we have a connection ID */ + if (p_ccb->con_state != GAP_CCB_STATE_LISTENING) + L2CA_DISCONNECT_REQ (p_ccb->connection_id); + + gap_release_ccb (p_ccb); + + return (BT_PASS); + } + + return (GAP_ERR_BAD_HANDLE); +} + + + +/******************************************************************************* +** +** Function GAP_ConnReadData +** +** Description Normally not GKI aware application will call this function +** after receiving GAP_EVT_RXDATA event. +** +** Parameters: handle - Handle of the connection returned in the Open +** p_data - Data area +** max_len - Byte count requested +** p_len - Byte count received +** +** Returns BT_PASS - data read +** GAP_ERR_BAD_HANDLE - invalid handle +** GAP_NO_DATA_AVAIL - no data available +** +*******************************************************************************/ +UINT16 GAP_ConnReadData (UINT16 gap_handle, UINT8 *p_data, UINT16 max_len, UINT16 *p_len) +{ + tGAP_CCB *p_ccb = gap_find_ccb_by_handle (gap_handle); + BT_HDR *p_buf; + UINT16 copy_len; + + if (!p_ccb) + return (GAP_ERR_BAD_HANDLE); + + *p_len = 0; + + p_buf = (BT_HDR *)GKI_getfirst (&p_ccb->rx_queue); + if (!p_buf) + return (GAP_NO_DATA_AVAIL); + + GKI_disable(); + + while (max_len && p_buf) + { + copy_len = (p_buf->len > max_len)?max_len:p_buf->len; + max_len -= copy_len; + *p_len += copy_len; + if (p_data) + { + memcpy (p_data, (UINT8 *)(p_buf + 1) + p_buf->offset, copy_len); + p_data += copy_len; + } + + if (p_buf->len > copy_len) + { + p_buf->offset += copy_len; + p_buf->len -= copy_len; + break; + } + else + { + if (max_len) + { + p_buf = (BT_HDR *)GKI_getnext (p_buf); + } + GKI_freebuf (GKI_dequeue (&p_ccb->rx_queue)); + } + } + + p_ccb->rx_queue_size -= *p_len; + + GKI_enable(); + + GAP_TRACE_EVENT2 ("GAP_ConnReadData - rx_queue_size left=%d, *p_len=%d", + p_ccb->rx_queue_size, *p_len); + + return (BT_PASS); +} + +/******************************************************************************* +** +** Function GAP_GetRxQueueCnt +** +** Description This function return number of bytes on the rx queue. +** +** Parameters: handle - Handle returned in the GAP_ConnOpen +** p_rx_queue_count - Pointer to return queue count in. +** +** +*******************************************************************************/ +int GAP_GetRxQueueCnt (UINT16 handle, UINT32 *p_rx_queue_count) +{ + tGAP_CCB *p_ccb; + int rc = BT_PASS; + + /* Check that handle is valid */ + if (handle < GAP_MAX_CONNECTIONS) + { + p_ccb = &gap_cb.conn.ccb_pool[handle]; + + if (p_ccb->con_state == GAP_CCB_STATE_CONNECTED) + { + *p_rx_queue_count = p_ccb->rx_queue_size; + } + else + rc = GAP_INVALID_HANDLE; + } + else + rc = GAP_INVALID_HANDLE; + + GAP_TRACE_EVENT2 ("GAP_GetRxQueueCnt - rc = 0x%04x, rx_queue_count=%d", + rc , *p_rx_queue_count); + + return (rc); +} + +/******************************************************************************* +** +** Function GAP_ConnBTRead +** +** Description Bluetooth aware applications will call this function after receiving +** GAP_EVT_RXDATA event. +** +** Parameters: handle - Handle of the connection returned in the Open +** pp_buf - pointer to address of buffer with data, +** +** Returns BT_PASS - data read +** GAP_ERR_BAD_HANDLE - invalid handle +** GAP_NO_DATA_AVAIL - no data available +** +*******************************************************************************/ +UINT16 GAP_ConnBTRead (UINT16 gap_handle, BT_HDR **pp_buf) +{ + tGAP_CCB *p_ccb = gap_find_ccb_by_handle (gap_handle); + BT_HDR *p_buf; + + if (!p_ccb) + return (GAP_ERR_BAD_HANDLE); + + p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->rx_queue); + + if (p_buf) + { + *pp_buf = p_buf; + + p_ccb->rx_queue_size -= p_buf->len; + return (BT_PASS); + } + else + { + *pp_buf = NULL; + return (GAP_NO_DATA_AVAIL); + } +} + + +/******************************************************************************* +** +** Function GAP_ConnBTWrite +** +** Description Bluetooth Aware applications can call this function to write data. +** +** Parameters: handle - Handle of the connection returned in the Open +** p_buf - pointer to address of buffer with data, +** +** Returns BT_PASS - data read +** GAP_ERR_BAD_HANDLE - invalid handle +** GAP_ERR_BAD_STATE - connection not established +** GAP_INVALID_BUF_OFFSET - buffer offset is invalid +*******************************************************************************/ +UINT16 GAP_ConnBTWrite (UINT16 gap_handle, BT_HDR *p_buf) +{ + tGAP_CCB *p_ccb = gap_find_ccb_by_handle (gap_handle); + + if (!p_ccb) + { + GKI_freebuf (p_buf); + return (GAP_ERR_BAD_HANDLE); + } + + if (p_ccb->con_state != GAP_CCB_STATE_CONNECTED) + { + GKI_freebuf (p_buf); + return (GAP_ERR_BAD_STATE); + } + + if (p_buf->offset < L2CAP_MIN_OFFSET) + { + GKI_freebuf (p_buf); + return (GAP_ERR_BUF_OFFSET); + } + + GKI_enqueue (&p_ccb->tx_queue, p_buf); + + if (p_ccb->is_congested) + { + return (BT_PASS); + } + + /* Send the buffer through L2CAP */ +#if (GAP_CONN_POST_EVT_INCLUDED == TRUE) + gap_send_event (gap_handle); +#else + while ((p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->tx_queue)) != NULL) + { + UINT8 status = L2CA_DATA_WRITE (p_ccb->connection_id, p_buf); + + if (status == L2CAP_DW_CONGESTED) + { + p_ccb->is_congested = TRUE; + break; + } + else if (status != L2CAP_DW_SUCCESS) + return (GAP_ERR_BAD_STATE); + } +#endif + return (BT_PASS); +} + + +/******************************************************************************* +** +** Function GAP_ConnWriteData +** +** Description Normally not GKI aware application will call this function +** to send data to the connection. +** +** Parameters: handle - Handle of the connection returned in the Open +** p_data - Data area +** max_len - Byte count requested +** p_len - Byte count received +** +** Returns BT_PASS - data read +** GAP_ERR_BAD_HANDLE - invalid handle +** GAP_ERR_BAD_STATE - connection not established +** GAP_CONGESTION - system is congested +** +*******************************************************************************/ +UINT16 GAP_ConnWriteData (UINT16 gap_handle, UINT8 *p_data, UINT16 max_len, UINT16 *p_len) +{ + tGAP_CCB *p_ccb = gap_find_ccb_by_handle (gap_handle); + BT_HDR *p_buf; + + *p_len = 0; + + if (!p_ccb) + return (GAP_ERR_BAD_HANDLE); + + if (p_ccb->con_state != GAP_CCB_STATE_CONNECTED) + return (GAP_ERR_BAD_STATE); + + while (max_len) + { + if (p_ccb->cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) + { + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (p_ccb->ertm_info.user_tx_pool_id)) == NULL) + return (GAP_ERR_CONGESTED); + } + else + { + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (GAP_DATA_POOL_ID)) == NULL) + return (GAP_ERR_CONGESTED); + } + + p_buf->offset = L2CAP_MIN_OFFSET; + p_buf->len = (p_ccb->rem_mtu_size < max_len) ? p_ccb->rem_mtu_size : max_len; + p_buf->event = BT_EVT_TO_BTU_SP_DATA; + + memcpy ((UINT8 *)(p_buf + 1) + p_buf->offset, p_data, p_buf->len); + + *p_len += p_buf->len; + max_len -= p_buf->len; + p_data += p_buf->len; + + GAP_TRACE_EVENT1 ("GAP_WriteData %d bytes", p_buf->len); + + GKI_enqueue (&p_ccb->tx_queue, p_buf); + } + + if (p_ccb->is_congested) + { + return (BT_PASS); + } + + /* Send the buffer through L2CAP */ +#if (GAP_CONN_POST_EVT_INCLUDED == TRUE) + gap_send_event (gap_handle); +#else + while ((p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->tx_queue)) != NULL) + { + UINT8 status = L2CA_DATA_WRITE (p_ccb->connection_id, p_buf); + + if (status == L2CAP_DW_CONGESTED) + { + p_ccb->is_congested = TRUE; + break; + } + else if (status != L2CAP_DW_SUCCESS) + return (GAP_ERR_BAD_STATE); + } +#endif + return (BT_PASS); +} + + +/******************************************************************************* +** +** Function GAP_ConnReconfig +** +** Description Applications can call this function to reconfigure the connection. +** +** Parameters: handle - Handle of the connection +** p_cfg - Pointer to new configuration +** +** Returns BT_PASS - config process started +** GAP_ERR_BAD_HANDLE - invalid handle +** +*******************************************************************************/ +UINT16 GAP_ConnReconfig (UINT16 gap_handle, tL2CAP_CFG_INFO *p_cfg) +{ + tGAP_CCB *p_ccb = gap_find_ccb_by_handle (gap_handle); + + if (!p_ccb) + return (GAP_ERR_BAD_HANDLE); + + p_ccb->cfg = *p_cfg; + + if (p_ccb->con_state == GAP_CCB_STATE_CONNECTED) + L2CA_CONFIG_REQ (p_ccb->connection_id, p_cfg); + + return (BT_PASS); +} + + + +/******************************************************************************* +** +** Function GAP_ConnSetIdleTimeout +** +** Description Higher layers call this function to set the idle timeout for +** a connection, or for all future connections. The "idle timeout" +** is the amount of time that a connection can remain up with +** no L2CAP channels on it. A timeout of zero means that the +** connection will be torn down immediately when the last channel +** is removed. A timeout of 0xFFFF means no timeout. Values are +** in seconds. +** +** Parameters: handle - Handle of the connection +** timeout - in secs +** 0 = immediate disconnect when last channel is removed +** 0xFFFF = no idle timeout +** +** Returns BT_PASS - config process started +** GAP_ERR_BAD_HANDLE - invalid handle +** +*******************************************************************************/ +UINT16 GAP_ConnSetIdleTimeout (UINT16 gap_handle, UINT16 timeout) +{ + tGAP_CCB *p_ccb; + + if ((p_ccb = gap_find_ccb_by_handle (gap_handle)) == NULL) + return (GAP_ERR_BAD_HANDLE); + + if (L2CA_SetIdleTimeout (p_ccb->connection_id, timeout, FALSE)) + return (BT_PASS); + else + return (GAP_ERR_BAD_HANDLE); +} + + + +/******************************************************************************* +** +** Function GAP_ConnGetRemoteAddr +** +** Description This function is called to get the remote BD address +** of a connection. +** +** Parameters: handle - Handle of the connection returned by GAP_ConnOpen +** +** Returns BT_PASS - closed OK +** GAP_ERR_BAD_HANDLE - invalid handle +** +*******************************************************************************/ +UINT8 *GAP_ConnGetRemoteAddr (UINT16 gap_handle) +{ + tGAP_CCB *p_ccb = gap_find_ccb_by_handle (gap_handle); + + GAP_TRACE_EVENT1 ("GAP_ConnGetRemoteAddr gap_handle = %d", gap_handle); + + if ((p_ccb) && (p_ccb->con_state > GAP_CCB_STATE_LISTENING)) + { + GAP_TRACE_EVENT6("GAP_ConnGetRemoteAddr bda :0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", \ + p_ccb->rem_dev_address[0],p_ccb->rem_dev_address[1],p_ccb->rem_dev_address[2], + p_ccb->rem_dev_address[3],p_ccb->rem_dev_address[4],p_ccb->rem_dev_address[5]); + return (p_ccb->rem_dev_address); + } + else + { + GAP_TRACE_EVENT0 ("GAP_ConnGetRemoteAddr return Error "); + return (NULL); + } +} + + +/******************************************************************************* +** +** Function GAP_ConnGetRemMtuSize +** +** Description Returns the remote device's MTU size +** +** Parameters: handle - Handle of the connection +** +** Returns UINT16 - maximum size buffer that can be transmitted to the peer +** +*******************************************************************************/ +UINT16 GAP_ConnGetRemMtuSize (UINT16 gap_handle) +{ + tGAP_CCB *p_ccb; + + if ((p_ccb = gap_find_ccb_by_handle (gap_handle)) == NULL) + return (0); + + return (p_ccb->rem_mtu_size); +} + +/******************************************************************************* +** +** Function GAP_ConnGetL2CAPCid +** +** Description Returns the L2CAP channel id +** +** Parameters: handle - Handle of the connection +** +** Returns UINT16 - The L2CAP channel id +** 0, if error +** +*******************************************************************************/ +UINT16 GAP_ConnGetL2CAPCid (UINT16 gap_handle) +{ + tGAP_CCB *p_ccb; + + if ((p_ccb = gap_find_ccb_by_handle (gap_handle)) == NULL) + return (0); + + return (p_ccb->connection_id); +} + + +/******************************************************************************* +** +** Function gap_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 gap_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid, UINT16 psm, UINT8 l2cap_id) +{ + UINT16 xx; + tGAP_CCB *p_ccb; + tBT_UUID bt_uuid = {2, {GAP_PROTOCOL_ID}}; + + /* See if we have a CCB listening for the connection */ + for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS; xx++, p_ccb++) + { + if ((p_ccb->con_state == GAP_CCB_STATE_LISTENING) + && (p_ccb->psm == psm) + && ((p_ccb->rem_addr_specified == FALSE) + || (!memcmp (bd_addr, p_ccb->rem_dev_address, BD_ADDR_LEN)))) + break; + } + + if (xx == GAP_MAX_CONNECTIONS) + { + GAP_TRACE_WARNING0("*******"); + GAP_TRACE_WARNING0("WARNING: GAP Conn Indication for Unexpected Bd Addr...Disconnecting"); + GAP_TRACE_WARNING0("*******"); + + /* Disconnect because it is an unexpected connection */ + L2CA_DISCONNECT_REQ (l2cap_cid); + return; + } + + /* Transition to the next appropriate state, waiting for config setup. */ + p_ccb->con_state = GAP_CCB_STATE_CFG_SETUP; + + /* Save the BD Address and Channel ID. */ + memcpy (&p_ccb->rem_dev_address[0], bd_addr, BD_ADDR_LEN); + p_ccb->connection_id = l2cap_cid; + + /* Send response to the L2CAP layer. */ + L2CA_CONNECT_RSP (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK, &p_ccb->ertm_info, &bt_uuid); + + GAP_TRACE_EVENT1("GAP_CONN - Rcvd L2CAP conn ind, CID: 0x%x", p_ccb->connection_id); + + /* Send a Configuration Request. */ + L2CA_CONFIG_REQ (l2cap_cid, &p_ccb->cfg); +} + +/******************************************************************************* +** +** Function gap_checks_con_flags +** +** Description This function processes the L2CAP configuration indication +** event. +** +** Returns void +** +*******************************************************************************/ +static void gap_checks_con_flags (tGAP_CCB *p_ccb) +{ + GAP_TRACE_EVENT1 ("gap_checks_con_flags conn_flags:0x%x, ", p_ccb->con_flags); + /* if all the required con_flags are set, report the OPEN event now */ + if ((p_ccb->con_flags & GAP_CCB_FLAGS_CONN_DONE) == GAP_CCB_FLAGS_CONN_DONE) + { + p_ccb->con_state = GAP_CCB_STATE_CONNECTED; + + p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_OPENED); + } +} + +/******************************************************************************* +** +** Function gap_sec_check_complete +** +** Description The function called when Security Manager finishes +** verification of the service side connection +** +** Returns void +** +*******************************************************************************/ +static void gap_sec_check_complete (BD_ADDR bd_addr, void *p_ref_data, UINT8 res) +{ + tGAP_CCB *p_ccb = (tGAP_CCB *)p_ref_data; + + GAP_TRACE_EVENT3 ("gap_sec_check_complete conn_state:%d, conn_flags:0x%x, status:%d", + p_ccb->con_state, p_ccb->con_flags, res); + if (p_ccb->con_state == GAP_CCB_STATE_IDLE) + return; + + if (res == BTM_SUCCESS) + { + p_ccb->con_flags |= GAP_CCB_FLAGS_SEC_DONE; + gap_checks_con_flags (p_ccb); + } + else + { + /* security failed - disconnect the channel */ + L2CA_DISCONNECT_REQ (p_ccb->connection_id); + } +} + +/******************************************************************************* +** +** Function gap_connect_cfm +** +** Description This function handles the connect confirm events +** from L2CAP. This is the case when we are acting as a +** client and have sent a connect request. +** +** Returns void +** +*******************************************************************************/ +static void gap_connect_cfm (UINT16 l2cap_cid, UINT16 result) +{ + tGAP_CCB *p_ccb; + + /* Find CCB based on CID */ + if ((p_ccb = gap_find_ccb_by_cid (l2cap_cid)) == NULL) + return; + + /* initiate security process, if needed */ + if ( (p_ccb->con_flags & GAP_CCB_FLAGS_SEC_DONE) == 0) + { + btm_sec_mx_access_request (p_ccb->rem_dev_address, p_ccb->psm, TRUE, + 0, 0, &gap_sec_check_complete, p_ccb); + } + + /* If the connection response contains success status, then */ + /* Transition to the next state and startup the timer. */ + if ((result == L2CAP_CONN_OK) && (p_ccb->con_state == GAP_CCB_STATE_CONN_SETUP)) + { + p_ccb->con_state = GAP_CCB_STATE_CFG_SETUP; + + /* Send a Configuration Request. */ + L2CA_CONFIG_REQ (l2cap_cid, &p_ccb->cfg); + } + else + { + /* Tell the user if he has a callback */ + if (p_ccb->p_callback) + (*p_ccb->p_callback) (p_ccb->gap_handle, GAP_EVT_CONN_CLOSED); + + gap_release_ccb (p_ccb); + } +} + +/******************************************************************************* +** +** Function gap_config_ind +** +** Description This function processes the L2CAP configuration indication +** event. +** +** Returns void +** +*******************************************************************************/ +static void gap_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg) +{ + tGAP_CCB *p_ccb; + UINT16 local_mtu_size; + + /* Find CCB based on CID */ + if ((p_ccb = gap_find_ccb_by_cid (l2cap_cid)) == NULL) + return; + + /* Remember the remote MTU size */ + + if (p_ccb->cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) + { + local_mtu_size = GKI_get_pool_bufsize (p_ccb->ertm_info.user_tx_pool_id) + - sizeof(BT_HDR) - L2CAP_MIN_OFFSET; + } + else + local_mtu_size = L2CAP_MTU_SIZE; + + if ((!p_cfg->mtu_present)||(p_cfg->mtu > local_mtu_size)) + { + p_ccb->rem_mtu_size = local_mtu_size; + } + else + p_ccb->rem_mtu_size = p_cfg->mtu; + + /* For now, always accept configuration from the other side */ + p_cfg->flush_to_present = FALSE; + p_cfg->mtu_present = FALSE; + p_cfg->result = L2CAP_CFG_OK; + p_cfg->fcs_present = FALSE; + + L2CA_CONFIG_RSP (l2cap_cid, p_cfg); + + p_ccb->con_flags |= GAP_CCB_FLAGS_HIS_CFG_DONE; + + gap_checks_con_flags (p_ccb); +} + + +/******************************************************************************* +** +** Function gap_config_cfm +** +** Description This function processes the L2CAP configuration confirmation +** event. +** +** Returns void +** +*******************************************************************************/ +static void gap_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg) +{ + tGAP_CCB *p_ccb; + + /* Find CCB based on CID */ + if ((p_ccb = gap_find_ccb_by_cid (l2cap_cid)) == NULL) + return; + + if (p_cfg->result == L2CAP_CFG_OK) + { + p_ccb->con_flags |= GAP_CCB_FLAGS_MY_CFG_DONE; + + + if (p_ccb->cfg.fcr_present) + p_ccb->cfg.fcr.mode = p_cfg->fcr.mode; + else + p_ccb->cfg.fcr.mode = L2CAP_FCR_BASIC_MODE; + + gap_checks_con_flags (p_ccb); + } + else + { + p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_CLOSED); + gap_release_ccb (p_ccb); + } +} + + +/******************************************************************************* +** +** Function gap_disconnect_ind +** +** Description This function handles a disconnect event from L2CAP. If +** requested to, we ack the disconnect before dropping the CCB +** +** Returns void +** +*******************************************************************************/ +static void gap_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed) +{ + tGAP_CCB *p_ccb; + + GAP_TRACE_EVENT1 ("GAP_CONN - Rcvd L2CAP disc, CID: 0x%x", l2cap_cid); + + /* Find CCB based on CID */ + if ((p_ccb = gap_find_ccb_by_cid (l2cap_cid)) == NULL) + return; + + if (ack_needed) + L2CA_DISCONNECT_RSP (l2cap_cid); + + p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_CLOSED); + gap_release_ccb (p_ccb); +} + + +/******************************************************************************* +** +** Function gap_data_ind +** +** Description This function is called when data is received from L2CAP. +** +** Returns void +** +*******************************************************************************/ +static void gap_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg) +{ + tGAP_CCB *p_ccb; + + /* Find CCB based on CID */ + if ((p_ccb = gap_find_ccb_by_cid (l2cap_cid)) == NULL) + { + GKI_freebuf (p_msg); + return; + } + + if (p_ccb->con_state == GAP_CCB_STATE_CONNECTED) + { + GKI_enqueue (&p_ccb->rx_queue, p_msg); + + p_ccb->rx_queue_size += p_msg->len; + /* + GAP_TRACE_EVENT2 ("gap_data_ind - rx_queue_size=%d, msg len=%d", + p_ccb->rx_queue_size, p_msg->len); + */ + + p_ccb->p_callback (p_ccb->gap_handle, GAP_EVT_CONN_DATA_AVAIL); + } + else + { + GKI_freebuf (p_msg); + } +} + + +/******************************************************************************* +** +** Function gap_congestion_ind +** +** Description This is a callback function called by L2CAP when +** data L2CAP congestion status changes +** +*******************************************************************************/ +static void gap_congestion_ind (UINT16 lcid, BOOLEAN is_congested) +{ + tGAP_CCB *p_ccb; + UINT16 event; + BT_HDR *p_buf; + UINT8 status; + + GAP_TRACE_EVENT2 ("GAP_CONN - Rcvd L2CAP Is Congested (%d), CID: 0x%x", + is_congested, lcid); + + /* Find CCB based on CID */ + if ((p_ccb = gap_find_ccb_by_cid (lcid)) == NULL) + return; + + p_ccb->is_congested = is_congested; + + event = (is_congested) ? GAP_EVT_CONN_CONGESTED : GAP_EVT_CONN_UNCONGESTED; + p_ccb->p_callback (p_ccb->gap_handle, event); + + if (!is_congested) + { + while ((p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->tx_queue)) != NULL) + { + status = L2CA_DATA_WRITE (p_ccb->connection_id, p_buf); + + if (status == L2CAP_DW_CONGESTED) + { + p_ccb->is_congested = TRUE; + break; + } + else if (status != L2CAP_DW_SUCCESS) + break; + } + } +} + + +/******************************************************************************* +** +** Function gap_find_ccb_by_cid +** +** Description This function searches the CCB table for an entry with the +** passed CID. +** +** Returns the CCB address, or NULL if not found. +** +*******************************************************************************/ +static tGAP_CCB *gap_find_ccb_by_cid (UINT16 cid) +{ + UINT16 xx; + tGAP_CCB *p_ccb; + + /* Look through each connection control block */ + for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS; xx++, p_ccb++) + { + if ((p_ccb->con_state != GAP_CCB_STATE_IDLE) && (p_ccb->connection_id == cid)) + return (p_ccb); + } + + /* If here, not found */ + return (NULL); +} + + +/******************************************************************************* +** +** Function gap_find_ccb_by_handle +** +** Description This function searches the CCB table for an entry with the +** passed handle. +** +** Returns the CCB address, or NULL if not found. +** +*******************************************************************************/ +static tGAP_CCB *gap_find_ccb_by_handle (UINT16 handle) +{ + tGAP_CCB *p_ccb; + + /* Check that handle is valid */ + if (handle < GAP_MAX_CONNECTIONS) + { + p_ccb = &gap_cb.conn.ccb_pool[handle]; + + if (p_ccb->con_state != GAP_CCB_STATE_IDLE) + return (p_ccb); + } + + /* If here, handle points to invalid connection */ + return (NULL); +} + + +/******************************************************************************* +** +** Function gap_allocate_ccb +** +** Description This function allocates a new CCB. +** +** Returns CCB address, or NULL if none available. +** +*******************************************************************************/ +static tGAP_CCB *gap_allocate_ccb (void) +{ + UINT16 xx; + tGAP_CCB *p_ccb; + + /* Look through each connection control block for a free one */ + for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS; xx++, p_ccb++) + { + if (p_ccb->con_state == GAP_CCB_STATE_IDLE) + { + memset (p_ccb, 0, sizeof (tGAP_CCB)); + + p_ccb->gap_handle = xx; + p_ccb->rem_mtu_size = L2CAP_MTU_SIZE; + + return (p_ccb); + } + } + + /* If here, no free CCB found */ + return (NULL); +} + + +/******************************************************************************* +** +** Function gap_release_ccb +** +** Description This function releases a CCB. +** +** Returns void +** +*******************************************************************************/ +static void gap_release_ccb (tGAP_CCB *p_ccb) +{ + UINT16 xx; + UINT16 psm = p_ccb->psm; + UINT8 service_id = p_ccb->service_id; + + /* Drop any buffers we may be holding */ + p_ccb->rx_queue_size = 0; + + while (p_ccb->rx_queue.p_first) + GKI_freebuf (GKI_dequeue (&p_ccb->rx_queue)); + + while (p_ccb->tx_queue.p_first) + GKI_freebuf (GKI_dequeue (&p_ccb->tx_queue)); + + p_ccb->con_state = GAP_CCB_STATE_IDLE; + + /* If no-one else is using the PSM, deregister from L2CAP */ + for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS; xx++, p_ccb++) + { + if ((p_ccb->con_state != GAP_CCB_STATE_IDLE) && (p_ccb->psm == psm)) + return; + } + + /* Free the security record for this PSM */ + BTM_SecClrService(service_id); + L2CA_DEREGISTER (psm); +} + +#if (GAP_CONN_POST_EVT_INCLUDED == TRUE) + +/******************************************************************************* +** +** Function gap_send_event +** +** Description Send BT_EVT_TO_GAP_MSG event to BTU task +** +** Returns None +** +*******************************************************************************/ +void gap_send_event (UINT16 gap_handle) +{ + BT_HDR *p_msg; + + if ((p_msg = (BT_HDR*)GKI_getbuf(BT_HDR_SIZE)) != NULL) + { + p_msg->event = BT_EVT_TO_GAP_MSG; + p_msg->len = 0; + p_msg->offset = 0; + p_msg->layer_specific = gap_handle; + + GKI_send_msg(BTU_TASK, BTU_HCI_RCV_MBOX, p_msg); + } + else + { + GAP_TRACE_ERROR0("Unable to allocate message buffer for event."); + } +} + +/******************************************************************************* +** +** Function gap_proc_btu_event +** +** Description Event handler for BT_EVT_TO_GAP_MSG event from BTU task +** +** Returns None +** +*******************************************************************************/ +void gap_proc_btu_event(BT_HDR *p_msg) +{ + tGAP_CCB *p_ccb = gap_find_ccb_by_handle (p_msg->layer_specific); + UINT8 status; + BT_HDR *p_buf; + + if (!p_ccb) + { + return; + } + + if (p_ccb->con_state != GAP_CCB_STATE_CONNECTED) + { + return; + } + + if (p_ccb->is_congested) + { + return; + } + + /* Send the buffer through L2CAP */ + + while ((p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->tx_queue)) != NULL) + { + status = L2CA_DATA_WRITE (p_ccb->connection_id, p_buf); + + if (status == L2CAP_DW_CONGESTED) + { + p_ccb->is_congested = TRUE; + break; + } + else if (status != L2CAP_DW_SUCCESS) + break; + } + +} +#endif /* (GAP_CONN_POST_EVT_INCLUDED == TRUE) */ +#endif /* GAP_CONN_INCLUDED */ diff --git a/stack/gap/gap_int.h b/stack/gap/gap_int.h new file mode 100644 index 000000000..295ad831e --- /dev/null +++ b/stack/gap/gap_int.h @@ -0,0 +1,231 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2013 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + + +#ifndef GAP_INT_H +#define GAP_INT_H + +#include "bt_target.h" +#include "gap_api.h" +#include "btm_api.h" +#include "gki.h" +#include "gatt_api.h" +#if AMP_INCLUDED == TRUE + #include "amp_api.h" +#endif + +#if defined BLE_INCLUDED && BLE_INCLUDED == TRUE + #include "gatt_api.h" +#endif + +#define GAP_MAX_BLOCKS 2 /* Concurrent GAP commands pending at a time*/ +/* There must be a different btm callback for*/ +/* each control block.*/ + + +/* Definitions of limits for inquiries */ +#define GAP_PER_INQ_MIN_MAX_PERIOD BTM_PER_INQ_MIN_MAX_PERIOD +#define GAP_PER_INQ_MAX_MAX_PERIOD BTM_PER_INQ_MAX_MAX_PERIOD +#define GAP_PER_INQ_MIN_MIN_PERIOD BTM_PER_INQ_MIN_MIN_PERIOD +#define GAP_PER_INQ_MAX_MIN_PERIOD BTM_PER_INQ_MAX_MIN_PERIOD +#define GAP_MAX_INQUIRY_LENGTH BTM_MAX_INQUIRY_LENGTH +#define GAP_MIN_INQUIRY_LEN BTM_MIN_INQUIRY_LEN + +/* Define the Generic Access Profile control structure */ +typedef struct +{ + void *p_data; /* Pointer to any data returned in callback */ + tGAP_CALLBACK *gap_cback; /* Pointer to users callback function */ + tGAP_CALLBACK *gap_inq_rslt_cback; /* Used for inquiry results */ + UINT16 event; /* Passed back in the callback */ + UINT8 index; /* Index of this control block and callback */ + BOOLEAN in_use; /* True when structure is allocated */ +} tGAP_INFO; + +/* Define the control block for the FindAddrByName operation (Only 1 active at a time) */ +typedef struct +{ + tGAP_CALLBACK *p_cback; + tBTM_INQ_INFO *p_cur_inq; /* Pointer to the current inquiry database entry */ + tGAP_FINDADDR_RESULTS results; + BOOLEAN in_use; +} tGAP_FINDADDR_CB; + + +/* Define the GAP Connection Control Block. +*/ +typedef struct +{ +#define GAP_CCB_STATE_IDLE 0 +#define GAP_CCB_STATE_LISTENING 1 +#define GAP_CCB_STATE_CONN_SETUP 2 +#define GAP_CCB_STATE_CFG_SETUP 3 +#define GAP_CCB_STATE_WAIT_SEC 4 +#define GAP_CCB_STATE_CONNECTED 5 + UINT8 con_state; + +#define GAP_CCB_FLAGS_IS_ORIG 0x01 +#define GAP_CCB_FLAGS_HIS_CFG_DONE 0x02 +#define GAP_CCB_FLAGS_MY_CFG_DONE 0x04 +#define GAP_CCB_FLAGS_SEC_DONE 0x08 +#define GAP_CCB_FLAGS_CONN_DONE 0x0E + UINT8 con_flags; + + UINT8 service_id; /* Used by BTM */ + UINT16 gap_handle; /* GAP handle */ + UINT16 connection_id; /* L2CAP CID */ + BOOLEAN rem_addr_specified; + UINT8 chan_mode_mask; /* Supported channel modes (FCR) */ + BD_ADDR rem_dev_address; + UINT16 psm; + UINT16 rem_mtu_size; + + BOOLEAN is_congested; + BUFFER_Q tx_queue; /* Queue of buffers waiting to be sent */ + BUFFER_Q rx_queue; /* Queue of buffers waiting to be read */ + + UINT32 rx_queue_size; /* Total data count in rx_queue */ + + tGAP_CONN_CALLBACK *p_callback; /* Users callback function */ + + tL2CAP_CFG_INFO cfg; /* Configuration */ + tL2CAP_ERTM_INFO ertm_info; /* Pools and modes for ertm */ +} tGAP_CCB; + +typedef struct +{ +#if AMP_INCLUDED == TRUE + tAMP_APPL_INFO reg_info; +#else + tL2CAP_APPL_INFO reg_info; /* L2CAP Registration info */ +#endif + tGAP_CCB ccb_pool[GAP_MAX_CONNECTIONS]; +} tGAP_CONN; + + +#if BLE_INCLUDED == TRUE + #define GAP_MAX_CHAR_NUM 5 + +typedef struct +{ + UINT16 handle; + UINT16 uuid; + tGAP_BLE_ATTR_VALUE attr_value; +}tGAP_ATTR; +#endif +/********************************************************************** +** M A I N C O N T R O L B L O C K +***********************************************************************/ + +#define GAP_MAX_CL GATT_CL_MAX_LCB + +typedef struct +{ + union + { + BD_ADDR reconn_addr; + UINT8 privacy_flag; + } pending_data; + UINT8 op; + void *p_pending_cback; +}tGAP_BLE_PENDING_OP; + +typedef struct +{ + BD_ADDR bda; + BD_ADDR reconn_addr; + void * p_cback; + UINT16 conn_id; + UINT16 cl_op_uuid; + UINT16 disc_handle; + BOOLEAN in_use; + BOOLEAN connected; + UINT8 privacy_flag; + BUFFER_Q pending_op_q; +}tGAP_CLCB; + +typedef struct +{ + tGAP_INFO blk[GAP_MAX_BLOCKS]; + tBTM_CMPL_CB *btm_cback[GAP_MAX_BLOCKS]; + UINT8 trace_level; + tGAP_FINDADDR_CB findaddr_cb; /* Contains the control block for finding a device addr */ + tBTM_INQ_INFO *cur_inqptr; + +#if GAP_CONN_INCLUDED == TRUE + tGAP_CONN conn; +#endif + + /* LE GAP attribute database */ +#if BLE_INCLUDED == TRUE + tGAP_ATTR gatt_attr[GAP_MAX_CHAR_NUM]; + BD_ADDR reconn_bda; + tGAP_CLCB clcb[GAP_MAX_CL]; /* connection link*/ + + tGATT_IF gatt_if; +#endif +} tGAP_CB; + + +#ifdef __cplusplus +extern "C" { +#endif + +#if GAP_DYNAMIC_MEMORY == FALSE + GAP_API extern tGAP_CB gap_cb; +#else + GAP_API extern tGAP_CB *gap_cb_ptr; +#define gap_cb (*gap_cb_ptr) +#endif + + extern tGAP_INFO *gap_allocate_cb(void); + extern void gap_free_cb(tGAP_INFO *p_cb); + + /* GAP inquiry functions */ + extern void gap_inq_results_cb(tGAP_INQ_RESULTS *p_results, UINT8 *p_eir); + extern UINT16 gap_find_local_addr_by_name (const BD_NAME devname, BD_ADDR bd_addr); + extern void gap_find_addr_inq_cb (tBTM_INQUIRY_CMPL *p); + + extern BOOLEAN gap_is_service_busy (UINT16 request); + extern UINT16 gap_convert_btm_status (tBTM_STATUS btm_status); + + extern void gap_btm_cback0(void *p1); +#if GAP_MAX_BLOCKS > 1 + extern void gap_btm_cback1(void *p1); +#endif +#if GAP_MAX_BLOCKS > 2 + extern void gap_btm_cback2(void *p1); +#endif + +#if (GAP_CONN_INCLUDED == TRUE) + extern void gap_conn_init(void); +#if (GAP_CONN_POST_EVT_INCLUDED == TRUE) + void gap_send_event (UINT16 gap_handle); + void gap_proc_btu_event(BT_HDR *p_msg); +#endif +#endif + +#if (BLE_INCLUDED == TRUE) + extern void gap_attr_db_init(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/stack/gap/gap_utils.c b/stack/gap/gap_utils.c new file mode 100644 index 000000000..d253a9937 --- /dev/null +++ b/stack/gap/gap_utils.c @@ -0,0 +1,432 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2013 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#include <string.h> +#include "bt_target.h" +#include "gap_int.h" + +/*****************************************************************************/ +/* G L O B A L GAP D A T A */ +/*****************************************************************************/ +#if GAP_DYNAMIC_MEMORY == FALSE +tGAP_CB gap_cb; +#endif + +/***************************************************************************** +** Callbacks passed to BTM - +** There are different callbacks based on the control block index so that +** more than one command can be pending at a time. +** NOTE: There must be 1 callback for each control block defined +** GAP_MAX_BLOCKS +** +** Also, the inquiry results event has its own callback; Not handled here! +******************************************************************************/ +static void btm_cback(UINT16 index, void *p_data) +{ + tGAP_INFO *p_cb; + tGAP_INQ_CMPL inq_cmpl; + + /* Make sure that the index is valid AND it is in use */ + if (index < GAP_MAX_BLOCKS && gap_cb.blk[index].in_use) + { + p_cb = &gap_cb.blk[index]; + + /* If the callback is non-NULL, call it with the specified event */ + switch (p_cb->event) + { + case GAP_EVT_INQUIRY_COMPLETE: + /* pass the number of results to caller */ + inq_cmpl.num_results = ((tBTM_INQUIRY_CMPL *)p_data)->num_resp; + + inq_cmpl.status = (((tBTM_INQUIRY_CMPL *)p_data)->status == BTM_SUCCESS) ? BT_PASS : GAP_ERR_PROCESSING; + + p_data = &inq_cmpl; + + GAP_TRACE_EVENT2(" GAP Inquiry Complete Event (Status 0x%04x, Result(s) %d)", + inq_cmpl.status, inq_cmpl.num_results); + break; + + case GAP_EVT_DISCOVERY_COMPLETE: + if (*((UINT16 *) p_data)) + { + GAP_TRACE_EVENT1(" GAP Discovery Complete Event(SDP Result: 0x%04x)", *((UINT16 *) p_data)); + } + else + { + GAP_TRACE_EVENT0(" GAP Discovery Successfully Completed"); + } + + break; + + case GAP_EVT_REM_NAME_COMPLETE: + /* override the BTM error code with a GAP error code */ + ((tGAP_REMOTE_DEV_NAME *)p_data)->status = + gap_convert_btm_status ((tBTM_STATUS)((tBTM_REMOTE_DEV_NAME *)p_data)->status); + + GAP_TRACE_EVENT1(" GAP Remote Name Complete Event (status 0x%04x)", ((tGAP_REMOTE_DEV_NAME *)p_data)->status); + + break; + }; + + if (p_cb->gap_cback) + p_cb->gap_cback(p_cb->event, p_data); + + /* Deallocate the control block */ + gap_free_cb(p_cb); + } +} + + +/*** Callback functions for BTM_CMPL_CB ***/ +void gap_btm_cback0(void *p1) +{ + btm_cback(0, p1); +} + +#if GAP_MAX_BLOCKS > 1 +void gap_btm_cback1(void *p1) +{ + btm_cback(1, p1); +} +#endif +#if GAP_MAX_BLOCKS > 2 +void gap_btm_cback2(void *p1) +{ + btm_cback(2, p1); +} +#endif + +/* There is only one instance of this because only 1 inquiry can be active at a time */ +void gap_inq_results_cb(tBTM_INQ_RESULTS *p_results, UINT8 *p_eir) +{ + tGAP_INFO *p_cb; + UINT8 index; + + GAP_TRACE_EVENT6 ("GAP Inquiry Results Callback (bdaddr [%02x%02x%02x%02x%02x%02x])", + p_results->remote_bd_addr[0], p_results->remote_bd_addr[1], + p_results->remote_bd_addr[2], p_results->remote_bd_addr[3], + p_results->remote_bd_addr[4], p_results->remote_bd_addr[5]); + GAP_TRACE_EVENT4 (" (COD [%02x%02x%02x], clkoff 0x%04x)", + p_results->dev_class[0], p_results->dev_class[1], p_results->dev_class[2], + p_results->clock_offset); + + /* Find the control block which has an Inquiry Active and call its results callback */ + for (index = 0, p_cb = &gap_cb.blk[0]; index < GAP_MAX_BLOCKS; index++, p_cb++) + { + /* Look for the control block that is using inquiry */ + if (p_cb->in_use && (p_cb->event == GAP_EVT_INQUIRY_COMPLETE)) + { + /* Notify the higher layer if they care */ + if (p_cb->gap_inq_rslt_cback) + p_cb->gap_inq_rslt_cback (GAP_EVT_INQUIRY_RESULTS, (tGAP_INQ_RESULTS *)p_results); + } + } +} + + +/******************************************************************************* +** +** Function gap_find_addr_name_cb +** +** Description Processes the remote name request event when the Find Addr by Name +** request is active. The following procedure takes place: +** 1. Check the resulting name (If return status is ok) +** 2. If name matches requested name, we're done, call the appl's callback +** with the BD ADDR. +** 3. Otherwise get the next BD ADDR out of the inquiry database and intiate +** another remote name request. +** 4. If there are no more BD ADDRs, then call the appl's callback with a FAIL +** status. +** +** Returns void +** +*******************************************************************************/ +void gap_find_addr_name_cb (tBTM_REMOTE_DEV_NAME *p) +{ + tGAP_FINDADDR_CB *p_cb = &gap_cb.findaddr_cb; + tGAP_FINDADDR_RESULTS *p_result = &p_cb->results; + + if (p_cb->in_use) + { + if (p->status == BTM_SUCCESS) + { + GAP_TRACE_EVENT2(" GAP: FindAddrByName Rem Name Cmpl Evt (Status 0x%04x, Name [%s])", + p->status, p->remote_bd_name); + + /* See if the returned name matches the desired name; if not initiate another search */ + if (!strncmp ((char *)p_result->devname, (char *) p->remote_bd_name, strlen ((char *) p_result->devname))) + { + /* We found the device! Copy it into the return structure */ + memcpy (p_result->bd_addr, p_cb->p_cur_inq->results.remote_bd_addr, BD_ADDR_LEN); + p_result->status = BT_PASS; + } + else /* The name doesn't match so initiate another search */ + { + /* Get the device address of the next database entry */ + if ((p_cb->p_cur_inq = BTM_InqDbNext(p_cb->p_cur_inq)) != NULL) + { + if ((BTM_ReadRemoteDeviceName (p_cb->p_cur_inq->results.remote_bd_addr, + (tBTM_CMPL_CB *) gap_find_addr_name_cb)) == BTM_CMD_STARTED) + return; /* This routine will get called again with the next results */ + else + p_result->status = gap_convert_btm_status ((tBTM_STATUS) p->status); + } + else + p_result->status = GAP_EOINQDB; /* No inquiry results; we're done! */ + } + } + else + { + GAP_TRACE_EVENT1(" GAP: FindAddrByName Rem Name Cmpl Evt (Status 0x%04x)", p->status); + p_result->status = gap_convert_btm_status ((tBTM_STATUS) p->status); + } + + /* If this code is reached, the process has completed so call the appl's callback with results */ + if (p_cb->p_cback) + p_cb->p_cback (GAP_EVT_FIND_ADDR_COMPLETE, (tGAP_FINDADDR_RESULTS *) p_result); + + /* Clear out the control block */ + p_cb->in_use = FALSE; + p_cb->p_cback = (tGAP_CALLBACK *) NULL; + } +} + +/******************************************************************************* +** +** Function gap_find_addr_inq_cb +** +** Description Processes the inquiry complete event when the Find Addr by Name +** request is active. This callback performs one of the two following +** steps: +** 1. If the remote name is retrieved automatically, the DB is searched +** immediately, and the results are returned in the appls callback. +** +** 2. If remote name is not automatic, retrieve the first BTM INQ +** database entry and initiate a remote name request. +** +** Returns void +** +*******************************************************************************/ +void gap_find_addr_inq_cb (tBTM_INQUIRY_CMPL *p) +{ + tGAP_FINDADDR_CB *p_cb = &gap_cb.findaddr_cb; + tGAP_FINDADDR_RESULTS *p_result = &p_cb->results; + + if (p_cb->in_use) + { + + GAP_TRACE_EVENT2(" GAP: FindAddrByName Inq Cmpl Evt (Status 0x%04x, Result(s) %d)", + p->status, p->num_resp); + + if (p->status == BTM_SUCCESS) + { + /* Step 1: If automatically retrieving remote names then search the local database */ + if ((p_result->status = gap_find_local_addr_by_name (p_result->devname, p_result->bd_addr)) == GAP_NO_DATA_AVAIL) + { + /* Step 2: The name is not stored automatically, so a search of all devices needs to + * be initiated. + */ + if ((p_cb->p_cur_inq = BTM_InqDbFirst()) != NULL) + { + if ((BTM_ReadRemoteDeviceName (p_cb->p_cur_inq->results.remote_bd_addr, + (tBTM_CMPL_CB *) gap_find_addr_name_cb)) == BTM_CMD_STARTED) + return; /* Wait for the response in gap_find_addr_name_cb() */ + else + p_result->status = gap_convert_btm_status (p->status); + } + else + p_result->status = GAP_EOINQDB; /* No inquiry results; we're done! */ + } + } + else + p_result->status = gap_convert_btm_status (p->status); + + /* If this code is reached, the process has completed so call the appl's callback with results */ + if (p_cb->p_cback) + p_cb->p_cback (GAP_EVT_FIND_ADDR_COMPLETE, (tGAP_FINDADDR_RESULTS *) p_result); + + /* Clear out the control block */ + p_cb->in_use = FALSE; + p_cb->p_cback = (tGAP_CALLBACK *) NULL; + } +} + +/******************************************************************************* +** +** Function gap_find_local_addr_by_name +** +** Description Searches through the internal inquiry database for a device +** that has the same name as the one passed in. If found, the +** device address is filled in. +** +** NOTE: It only searches up to the first BTM_MAX_REM_BD_NAME_LEN +** bytes because the inquiry database uses tBTM_BD_NAME. +** +** Returns BT_PASS if the name was found and the device address is filled in +** GAP_EOINQDB if the name was not found in the database +** GAP_NO_DATA_AVAIL if the name is not saved with the inquiry +** +*******************************************************************************/ +UINT16 gap_find_local_addr_by_name (const tBTM_BD_NAME devname, BD_ADDR bd_addr) +{ + +/* If the remote name is retrieved automatically during an inquiry search the local db */ +#if (BTM_INQ_GET_REMOTE_NAME == TRUE) + tBTM_INQ_INFO *p_result; + + p_result = BTM_InqDbFirst(); + + while (p_result) + { + /* Check the entry for a device name match */ + if (!strncmp ((char *)devname, (char *)p_result->remote_name, BTM_MAX_REM_BD_NAME_LEN)) + { + memcpy (bd_addr, p_result->results.remote_bd_addr, BD_ADDR_LEN); + return (BT_PASS); + } + else + p_result = BTM_InqDbNext(p_result); + }; + + return (GAP_EOINQDB); +#else + /* No data available because we are not automatically saving the data */ + return (GAP_NO_DATA_AVAIL); +#endif +} + + +/******************************************************************************* +** +** Function gap_allocate_cb +** +** Description Look through the GAP Control Blocks for a free one. +** +** Returns Pointer to the control block or NULL if not found +** +*******************************************************************************/ +tGAP_INFO *gap_allocate_cb (void) +{ + tGAP_INFO *p_cb = &gap_cb.blk[0]; + UINT8 x; + + for (x = 0; x < GAP_MAX_BLOCKS; x++, p_cb++) + { + if (!p_cb->in_use) + { + memset (p_cb, 0, sizeof (tGAP_INFO)); + + p_cb->in_use = TRUE; + p_cb->index = x; + p_cb->p_data = (void *)NULL; + return (p_cb); + } + } + + /* If here, no free control blocks found */ + return (NULL); +} + + +/******************************************************************************* +** +** Function gap_free_cb +** +** Description Release GAP control block. +** +** Returns Pointer to the control block or NULL if not found +** +*******************************************************************************/ +void gap_free_cb (tGAP_INFO *p_cb) +{ + if (p_cb) + { + p_cb->gap_cback = NULL; + p_cb->in_use = FALSE; + } +} + + +/******************************************************************************* +** +** Function gap_is_service_busy +** +** Description Look through the GAP Control Blocks that are in use +** and check to see if the event waiting for is the command +** requested. +** +** Returns TRUE if already in use +** FALSE if not busy +** +*******************************************************************************/ +BOOLEAN gap_is_service_busy (UINT16 request) +{ + tGAP_INFO *p_cb = &gap_cb.blk[0]; + UINT8 x; + + for (x = 0; x < GAP_MAX_BLOCKS; x++, p_cb++) + { + if (p_cb->in_use && p_cb->event == request) + return (TRUE); + } + + /* If here, service is not busy */ + return (FALSE); +} + + +/******************************************************************************* +** +** Function gap_convert_btm_status +** +** Description Converts a BTM error status into a GAP error status +** +** +** Returns GAP_UNKNOWN_BTM_STATUS is returned if not recognized +** +*******************************************************************************/ +UINT16 gap_convert_btm_status (tBTM_STATUS btm_status) +{ + switch (btm_status) + { + case BTM_SUCCESS: + return (BT_PASS); + + case BTM_CMD_STARTED: + return (GAP_CMD_INITIATED); + + case BTM_BUSY: + return (GAP_ERR_BUSY); + + case BTM_MODE_UNSUPPORTED: + case BTM_ILLEGAL_VALUE: + return (GAP_ERR_ILL_PARM); + + case BTM_WRONG_MODE: + return (GAP_DEVICE_NOT_UP); + + case BTM_UNKNOWN_ADDR: + return (GAP_BAD_BD_ADDR); + + case BTM_DEVICE_TIMEOUT: + return (GAP_ERR_TIMEOUT); + + default: + return (GAP_ERR_PROCESSING); + } +} diff --git a/stack/gatt/att_protocol.c b/stack/gatt/att_protocol.c index a114a3338..9c715af6a 100644 --- a/stack/gatt/att_protocol.c +++ b/stack/gatt/att_protocol.c @@ -390,13 +390,13 @@ BT_HDR *attp_build_sr_msg(tGATT_TCB *p_tcb, UINT8 op_code, tGATT_SR_MSG *p_msg) switch (op_code) { case GATT_RSP_READ_BLOB: - GATT_TRACE_EVENT2 ("ATT_RSP_READ_BLOB: len = %d offset = %d", p_msg->attr_value.len, p_msg->attr_value.offset); - offset = p_msg->attr_value.offset; - case GATT_RSP_PREPARE_WRITE: - if (offset == 0) - offset = p_msg->attr_value.offset; - + GATT_TRACE_EVENT2 ("ATT_RSP_READ_BLOB/GATT_RSP_PREPARE_WRITE: len = %d offset = %d", + p_msg->attr_value.len, p_msg->attr_value.offset); + offset = p_msg->attr_value.offset; +/* Coverity: [FALSE-POSITIVE error] intended fall through */ +/* Missing break statement between cases in switch statement */ + /* fall through */ case GATT_RSP_READ_BY_TYPE: case GATT_RSP_READ: case GATT_HANDLE_VALUE_NOTIF: @@ -503,7 +503,10 @@ UINT8 attp_cl_send_cmd(tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 cmd_code, BT_HDR att_ret = GATT_INTERNAL_ERROR; } else + { + att_ret = GATT_CMD_STARTED; gatt_cmd_enq(p_tcb, clcb_idx, TRUE, cmd_code, p_cmd); + } } else att_ret = GATT_ILLEGAL_PARAMETER; diff --git a/stack/gatt/gatt_api.c b/stack/gatt/gatt_api.c index 7845f3c2c..ef437e130 100644 --- a/stack/gatt/gatt_api.c +++ b/stack/gatt/gatt_api.c @@ -849,6 +849,7 @@ tGATT_STATUS GATTC_Discover (UINT16 conn_id, tGATT_DISC_TYPE disc_type, (disc_type == GATT_DISC_SRVC_BY_UUID && p_param->service.len == 0)) { + gatt_clcb_dealloc(p_clcb); return GATT_ILLEGAL_PARAMETER; } @@ -1313,7 +1314,6 @@ void GATT_StartIf (tGATT_IF gatt_if) { tGATT_REG *p_reg; tGATT_TCB *p_tcb; - //tGATT_CLCB *p_clcb; BD_ADDR bda; UINT8 start_idx, found_idx; UINT16 conn_id; @@ -1326,7 +1326,7 @@ void GATT_StartIf (tGATT_IF gatt_if) while (gatt_find_the_connected_bda(start_idx, bda, &found_idx)) { p_tcb = gatt_find_tcb_by_addr(bda); - if (p_reg->app_cb.p_conn_cb) + if (p_reg->app_cb.p_conn_cb && p_tcb) { conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if); (*p_reg->app_cb.p_conn_cb)(gatt_if, bda, conn_id, TRUE, 0); @@ -1341,7 +1341,8 @@ void GATT_StartIf (tGATT_IF gatt_if) ** ** Function GATT_Connect ** -** Description This function initiate a connecttion to a ATT server. +** Description This function initiate a connecttion to a remote device on GATT +** channel. ** ** Parameters gatt_if: applicaiton interface ** bd_addr: peer device address. @@ -1366,7 +1367,7 @@ BOOLEAN GATT_Connect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct){ if (is_direct) status = gatt_act_connect (p_reg, bd_addr); else - status = gatt_update_auto_connect_dev(gatt_if,TRUE, bd_addr); + status = gatt_update_auto_connect_dev(gatt_if,TRUE, bd_addr, TRUE); return status; @@ -1376,7 +1377,8 @@ BOOLEAN GATT_Connect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct){ ** ** Function GATT_CancelConnect ** -** Description This function initiate a connecttion to a ATT server. +** Description This function terminate the connection initaition to a remote +** device on GATT channel. ** ** Parameters gatt_if: client interface. If 0 used as unconditionally disconnect, ** typically used for direct connection cancellation. @@ -1454,7 +1456,8 @@ BOOLEAN GATT_CancelConnect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct ** ** Function GATT_Disconnect ** -** Description This function disconnect a logic channel. +** Description This function disconnect the GATT channel for this registered +** application. ** ** Parameters conn_id: connection identifier. ** @@ -1550,6 +1553,50 @@ BOOLEAN GATT_GetConnIdIfConnected(tGATT_IF gatt_if, BD_ADDR bd_addr, UINT16 *p_c return status; } -#endif +/******************************************************************************* +** +** Function GATT_Listen +** +** Description This function start or stop LE advertisement and listen for +** connection. +** +** Parameters gatt_if: applicaiton interface +** p_bd_addr: listen for specific address connection, or NULL for +** listen to all device connection. +** start: is a direct conenection or a background auto connection +** +** Returns TRUE if advertisement is started; FALSE if adv start failure. +** +*******************************************************************************/ +BOOLEAN GATT_Listen (tGATT_IF gatt_if, BOOLEAN start, BD_ADDR_PTR bd_addr) +{ + tGATT_REG *p_reg; + BOOLEAN status = TRUE; + + GATT_TRACE_API1 ("GATT_Listen gatt_if=%d", gatt_if); + + /* Make sure app is registered */ + if ((p_reg = gatt_get_regcb(gatt_if)) == NULL) + { + GATT_TRACE_ERROR1("GATT_Listen - gatt_if =%d is not registered", gatt_if); + return(FALSE); + } + + if (bd_addr != NULL) + { + status = gatt_update_auto_connect_dev(gatt_if,start, bd_addr, FALSE); + } + else + { + p_reg->listening = start ? GATT_LISTEN_TO_ALL : GATT_LISTEN_TO_NONE; + } + + gatt_update_listen_mode(); + + return status; + +} + +#endif diff --git a/stack/gatt/gatt_attr.c b/stack/gatt/gatt_attr.c index b7ec2fcbd..459580ed3 100644 --- a/stack/gatt/gatt_attr.c +++ b/stack/gatt/gatt_attr.c @@ -183,7 +183,7 @@ static void gatt_profile_request_cback (UINT16 conn_id, UINT32 trans_id, tGATTS_ break; case GATTS_REQ_TYPE_WRITE_EXEC: - //case GATT_CMD_WRITE: + case GATT_CMD_WRITE: ignore = TRUE; GATT_TRACE_EVENT0("Ignore GATT_REQ_EXEC_WRITE/WRITE_CMD" ); break; @@ -269,7 +269,7 @@ void gatt_profile_db_init (void) /* start service */ - status = GATTS_StartService (gatt_cb.gatt_if, service_handle, GATT_TRANSPORT_LE_BR_EDR); + status = GATTS_StartService (gatt_cb.gatt_if, service_handle, GATTP_TRANSPORT_SUPPORTED ); GATT_TRACE_DEBUG2 ("gatt_profile_db_init: gatt_if=%d start status%d", gatt_cb.gatt_if, status); diff --git a/stack/gatt/gatt_auth.c b/stack/gatt/gatt_auth.c index de0c14f9b..df42758c2 100644 --- a/stack/gatt/gatt_auth.c +++ b/stack/gatt/gatt_auth.c @@ -48,6 +48,9 @@ static BOOLEAN gatt_sign_data (tGATT_CLCB *p_clcb) BOOLEAN status = FALSE; UINT8 *p_signature; + /* do not need to mark channel securoty activity for data signing */ + gatt_set_sec_act(p_clcb->p_tcb, GATT_SEC_OK); + p_data = (UINT8 *)GKI_getbuf((UINT16)(p_attr->len + 3)); /* 3 = 2 byte handle + opcode */ if (p_data != NULL) @@ -69,7 +72,7 @@ static BOOLEAN gatt_sign_data (tGATT_CLCB *p_clcb) { p_attr->len += BTM_BLE_AUTH_SIGN_LEN; gatt_set_ch_state(p_clcb->p_tcb, GATT_CH_OPEN); - gatt_act_write(p_clcb); + gatt_act_write(p_clcb, GATT_SEC_SIGN_DATA); } else { @@ -126,10 +129,10 @@ void gatt_verify_signature(tGATT_TCB *p_tcb, BT_HDR *p_buf) ** Returns void. ** *******************************************************************************/ -void gatt_sec_check_complete(BOOLEAN sec_check_ok, tGATT_CLCB *p_clcb) +void gatt_sec_check_complete(BOOLEAN sec_check_ok, tGATT_CLCB *p_clcb, UINT8 sec_act) { - p_clcb->p_tcb->p_clcb = NULL; - gatt_set_sec_act(p_clcb->p_tcb, GATT_SEC_NONE); + if (GKI_queue_is_empty(&p_clcb->p_tcb->pending_enc_clcb)) + gatt_set_sec_act(p_clcb->p_tcb, GATT_SEC_NONE); if (!sec_check_ok) { @@ -137,7 +140,7 @@ void gatt_sec_check_complete(BOOLEAN sec_check_ok, tGATT_CLCB *p_clcb) } else if (p_clcb->operation == GATTC_OPTYPE_WRITE) { - gatt_act_write(p_clcb); + gatt_act_write(p_clcb, sec_act); } else if (p_clcb->operation == GATTC_OPTYPE_READ) { @@ -158,28 +161,51 @@ void gatt_enc_cmpl_cback(BD_ADDR bd_addr, void *p_ref_data, tBTM_STATUS result) tGATT_TCB *p_tcb; UINT8 sec_flag; BOOLEAN status = FALSE; + tGATT_PENDING_ENC_CLCB *p_buf; + UINT16 count; GATT_TRACE_DEBUG0("gatt_enc_cmpl_cback"); if ((p_tcb = gatt_find_tcb_by_addr(bd_addr)) != NULL) { - gatt_set_ch_state(p_tcb, GATT_CH_OPEN); + if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENC_PENDING) + return; - if (result == BTM_SUCCESS) + if ((p_buf = (tGATT_PENDING_ENC_CLCB *)GKI_dequeue (&p_tcb->pending_enc_clcb)) != NULL) { - if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENCRYPT_MITM ) + if (result == BTM_SUCCESS) { - BTM_GetSecurityFlags(bd_addr, &sec_flag); - if (sec_flag & sec_flag & BTM_SEC_FLAG_LKEY_AUTHED) + if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENCRYPT_MITM ) + { + BTM_GetSecurityFlags(bd_addr, &sec_flag); + if (sec_flag & sec_flag & BTM_SEC_FLAG_LKEY_AUTHED) + { + status = TRUE; + } + } + else { status = TRUE; } } - else + gatt_sec_check_complete(status , p_buf->p_clcb, p_tcb->sec_act); + GKI_freebuf(p_buf); + /* start all other pending operation in queue */ + count = p_tcb->pending_enc_clcb.count; + for (; count > 0; count --) { - status = TRUE; + if ((p_buf = (tGATT_PENDING_ENC_CLCB *)GKI_dequeue (&p_tcb->pending_enc_clcb)) != NULL) + { + gatt_security_check_start(p_buf->p_clcb); + GKI_freebuf(p_buf); + } + else + break; } } - gatt_sec_check_complete(status , (tGATT_CLCB *)p_tcb->p_clcb); + else + { + GATT_TRACE_ERROR0("Unknown operation encryption completed"); + } } else { @@ -189,6 +215,48 @@ void gatt_enc_cmpl_cback(BD_ADDR bd_addr, void *p_ref_data, tBTM_STATUS result) /******************************************************************************* ** +** Function gatt_notify_enc_cmpl +** +** Description link encryption complete notification for all encryption process +** initiated outside GATT. +** +** Returns +** +*******************************************************************************/ +void gatt_notify_enc_cmpl(BD_ADDR bd_addr) +{ + tGATT_TCB *p_tcb; + tGATT_PENDING_ENC_CLCB *p_buf; + UINT16 count; + + if ((p_tcb = gatt_find_tcb_by_addr(bd_addr)) != NULL) + { + if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENC_PENDING) + { + gatt_set_sec_act(p_tcb, GATT_SEC_NONE); + + count = p_tcb->pending_enc_clcb.count; + + for (; count > 0; count --) + { + if ((p_buf = (tGATT_PENDING_ENC_CLCB *)GKI_dequeue (&p_tcb->pending_enc_clcb)) != NULL) + { + gatt_security_check_start(p_buf->p_clcb); + GKI_freebuf(p_buf); + } + else + break; + } + } + } + else + { + GATT_TRACE_DEBUG0("notify GATT for encryption completion of unknown device"); + } + return; +} +/******************************************************************************* +** ** Function gatt_set_sec_act ** ** Description This function set the sec_act in clcb @@ -243,18 +311,32 @@ tGATT_SEC_ACTION gatt_determine_sec_act(tGATT_CLCB *p_clcb ) BOOLEAN is_link_key_known=FALSE; BOOLEAN is_key_mitm=FALSE; UINT8 key_type; + tBTM_BLE_SEC_REQ_ACT sec_act = BTM_LE_SEC_NONE; if (auth_req == GATT_AUTH_REQ_NONE ) return act; is_le_link = btm_ble_check_link_type(p_tcb->peer_bda); BTM_GetSecurityFlags(p_tcb->peer_bda, &sec_flag); + btm_ble_link_sec_check(p_tcb->peer_bda, auth_req, &sec_act); + + /* if a encryption is pending, need to wait */ + if (sec_act == BTM_BLE_SEC_REQ_ACT_DISCARD && + auth_req != GATT_AUTH_REQ_NONE) + return GATT_SEC_ENC_PENDING; if (sec_flag & BTM_SEC_FLAG_ENCRYPTED) { is_link_encrypted = TRUE; + is_link_key_known = TRUE; + + if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED) + { + is_key_mitm = TRUE; + } + } - if (sec_flag & BTM_SEC_FLAG_LKEY_KNOWN) + else if (sec_flag & BTM_SEC_FLAG_LKEY_KNOWN) { is_link_key_known = TRUE; if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED) @@ -397,48 +479,49 @@ BOOLEAN gatt_security_check_start(tGATT_CLCB *p_clcb) tBTM_BLE_SEC_ACT btm_ble_sec_act; BOOLEAN status = TRUE; tBTM_STATUS btm_status; + tGATT_SEC_ACTION sec_act_old = gatt_get_sec_act(p_tcb); - if ( gatt_get_ch_state(p_tcb) == GATT_CH_OPEN) - { - gatt_sec_act = gatt_determine_sec_act(p_clcb); + gatt_sec_act = gatt_determine_sec_act(p_clcb); + + if (sec_act_old == GATT_SEC_NONE) gatt_set_sec_act(p_tcb, gatt_sec_act); - switch (gatt_sec_act ) - { - case GATT_SEC_SIGN_DATA: - GATT_TRACE_DEBUG0("gatt_security_check_start: Do data signing"); - gatt_set_ch_state(p_tcb, GATT_CH_W4_DATA_SIGN_COMP); - gatt_sign_data(p_clcb); - break; - case GATT_SEC_ENCRYPT: - case GATT_SEC_ENCRYPT_NO_MITM: - case GATT_SEC_ENCRYPT_MITM: + + switch (gatt_sec_act ) + { + case GATT_SEC_SIGN_DATA: + GATT_TRACE_DEBUG0("gatt_security_check_start: Do data signing"); + gatt_sign_data(p_clcb); + break; + case GATT_SEC_ENCRYPT: + case GATT_SEC_ENCRYPT_NO_MITM: + case GATT_SEC_ENCRYPT_MITM: + if (sec_act_old < GATT_SEC_ENCRYPT) + { GATT_TRACE_DEBUG0("gatt_security_check_start: Encrypt now or key upgreade first"); - gatt_convert_sec_action(p_tcb->sec_act, &btm_ble_sec_act); - gatt_set_ch_state(p_tcb, GATT_CH_W4_SEC_COMP); - p_tcb->p_clcb = p_clcb; /* keep the clcb pointer in CCB */ + gatt_convert_sec_action(gatt_sec_act, &btm_ble_sec_act); btm_status = BTM_SetEncryption(p_tcb->peer_bda, gatt_enc_cmpl_cback, &btm_ble_sec_act); if ( (btm_status != BTM_SUCCESS) && (btm_status != BTM_CMD_STARTED)) { GATT_TRACE_ERROR1("gatt_security_check_start BTM_SetEncryption failed btm_status=%d", btm_status); - p_tcb->p_clcb = NULL; status = FALSE; } - break; - default: - gatt_sec_check_complete(TRUE, p_clcb); - break; - } - - if (status == FALSE) - { - gatt_set_sec_act(p_tcb, GATT_SEC_NONE); - gatt_set_ch_state(p_tcb, GATT_CH_OPEN); - } + } + if (status) + gatt_add_pending_enc_channel_clcb (p_tcb, p_clcb); + break; + case GATT_SEC_ENC_PENDING: + gatt_add_pending_enc_channel_clcb (p_tcb, p_clcb); + /* wait for link encrypotion to finish */ + break; + default: + gatt_sec_check_complete(TRUE, p_clcb, gatt_sec_act); + break; } - else + + if (status == FALSE) { - GATT_TRACE_ERROR0("gatt_security_check_start channel not open"); - status = FALSE; + gatt_set_sec_act(p_tcb, GATT_SEC_NONE); + gatt_set_ch_state(p_tcb, GATT_CH_OPEN); } return status; diff --git a/stack/gatt/gatt_cl.c b/stack/gatt/gatt_cl.c index 91fb98516..e9402aaed 100644 --- a/stack/gatt/gatt_cl.c +++ b/stack/gatt/gatt_cl.c @@ -201,7 +201,7 @@ void gatt_act_read (tGATT_CLCB *p_clcb, UINT16 offset) ** Returns void. ** *******************************************************************************/ -void gatt_act_write (tGATT_CLCB *p_clcb) +void gatt_act_write (tGATT_CLCB *p_clcb, UINT8 sec_act) { tGATT_TCB *p_tcb = p_clcb->p_tcb; UINT8 rt = GATT_SUCCESS, op_code; @@ -213,7 +213,7 @@ void gatt_act_write (tGATT_CLCB *p_clcb) { case GATT_WRITE_NO_RSP: p_clcb->s_handle = p_attr->handle; - op_code = (p_tcb->sec_act & GATT_SEC_SIGN_DATA) ? GATT_SIGN_CMD_WRITE : GATT_CMD_WRITE; + op_code = (sec_act == GATT_SEC_SIGN_DATA) ? GATT_SIGN_CMD_WRITE : GATT_CMD_WRITE; rt = gatt_send_write_msg(p_tcb, p_clcb->clcb_idx, op_code, @@ -379,59 +379,7 @@ void gatt_send_prepare_write(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb) } } -/******************************************************************************* -** -** Function gatt_proc_disc_read_by_type_rsp -** -** Description This function process the read by type response and send another -** request if needed. -** -** Returns void. -** -*******************************************************************************/ -void gatt_proc_disc_read_by_type_rsp(tGATT_CLCB *p_clcb, UINT16 len, UINT8 *p_data) -{ - /* - tGATT_TCB *p_tcb = p_clcb->p_tcb; - tGATT_DISCOVERY_DB *p_db = p_clcb->p_disc_db; - tGATT_DISC_REC *p_rec; - tGATT_STATUS status = GATT_INTERNAL_ERROR; - - - if ((p_rec = gatt_add_record(p_clcb->p_disc_db)) != NULL) - { - p_rec->handle = handle; - p_rec->type = p_db->uuid_filter; - p_rec->attr_len = len; - - // copy the attibute value into DB - p_rec->p_value = p_db->p_free_mem; - memcpy(p_rec->p_value, p_value, len); - p_db->p_free_mem += len; - p_db->mem_free -= len; - - if (handle < p_clcb->e_handle) - { - // send another request - if (gatt_act_send_browse(p_tcb, p_clcb->conn_id, - GATT_REQ_READ_BY_TYPE, - (UINT16)(handle + 1), // starting handle - p_clcb->e_handle, // end handle - p_clcb->p_disc_db->uuid_filter) // uuid filter / - == GATT_SUCCESS) - { - status = GATT_SUCCESS; - } - } - } - else - status = GATT_DB_FULL; - - if (status != GATT_SUCCESS) // DB full - { - gatt_end_operation(p_clcb, status, NULL); - }*/ -} + /******************************************************************************* ** ** Function gatt_process_find_type_value_rsp @@ -445,7 +393,6 @@ void gatt_proc_disc_read_by_type_rsp(tGATT_CLCB *p_clcb, UINT16 len, UINT8 *p_da void gatt_process_find_type_value_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT16 len, UINT8 *p_data) { tGATT_DISC_RES result; - tGATT_DISC_VALUE record_value; UINT8 *p = p_data; GATT_TRACE_DEBUG0("gatt_process_find_type_value_rsp "); @@ -453,7 +400,7 @@ void gatt_process_find_type_value_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UIN if (p_clcb->operation != GATTC_OPTYPE_DISCOVERY || p_clcb->op_subtype != GATT_DISC_SRVC_BY_UUID) return; - memset (&record_value, 0, sizeof(tGATT_DISC_VALUE)); + memset (&result, 0, sizeof(tGATT_DISC_RES)); result.type.len = 2; result.type.uu.uuid16 = GATT_UUID_PRI_SERVICE; @@ -461,17 +408,17 @@ void gatt_process_find_type_value_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UIN while (len >= 4) { STREAM_TO_UINT16 (result.handle, p); - STREAM_TO_UINT16 (record_value.handle, p); - len -= 4; + STREAM_TO_UINT16 (result.value.group_value.e_handle, p); + memcpy (&result.value.group_value.service_type, &p_clcb->uuid, sizeof(tBT_UUID)); - memcpy (&result.value, &record_value, sizeof (result.value));; + 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 = (record_value.handle == 0) ? 0 : (record_value.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) ; } @@ -721,12 +668,12 @@ void gatt_process_notification(tGATT_TCB *p_tcb, UINT8 op_code, 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); - encrypt_status = gatt_get_link_encrypt_status(p_tcb); (*p_reg->app_cb.p_cmpl_cb) (conn_id, event, encrypt_status, (tGATT_CL_COMPLETE *)&value); } } @@ -882,7 +829,12 @@ void gatt_process_read_by_type_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL); return; } - gatt_parse_uuid_from_cmd(&record_value.dclr_value.char_uuid, (UINT16)(value_len - 3), &p); + if (!gatt_parse_uuid_from_cmd(&record_value.dclr_value.char_uuid, (UINT16)(value_len - 3), &p)) + { + gatt_end_operation(p_clcb, GATT_SUCCESS, NULL); + /* invalid format, and skip the result */ + return; + } /* UUID not matching */ if (!gatt_uuid_compare(record_value.dclr_value.char_uuid, p_clcb->uuid)) @@ -1087,6 +1039,8 @@ BOOLEAN gatt_cl_send_next_cmd_inq(tGATT_TCB *p_tcb) { tGATT_CMD_Q *p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req]; BOOLEAN sent = FALSE; + UINT8 rsp_code; + tGATT_CLCB *p_clcb = NULL; while (!sent && p_tcb->pending_cl_req != p_tcb->next_slot_inq && @@ -1099,7 +1053,21 @@ BOOLEAN gatt_cl_send_next_cmd_inq(tGATT_TCB *p_tcb) p_cmd->to_send = FALSE; p_cmd->p_cmd = NULL; - gatt_start_rsp_timer (p_tcb); + /* dequeue the request if is write command or sign write */ + if (p_cmd->op_code != GATT_CMD_WRITE && p_cmd->op_code != GATT_SIGN_CMD_WRITE) + { + gatt_start_rsp_timer (p_tcb); + } + else + { + p_clcb = gatt_cmd_dequeue(p_tcb, &rsp_code); + + /* if no ack needed, keep sending */ + sent = FALSE; + p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req]; + /* send command complete callback here */ + gatt_end_operation(p_clcb, GATT_SUCCESS, NULL); + } } else { @@ -1109,6 +1077,7 @@ BOOLEAN gatt_cl_send_next_cmd_inq(tGATT_TCB *p_tcb) p_tcb->pending_cl_req ++; p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req]; } + } return sent; } diff --git a/stack/gatt/gatt_db.c b/stack/gatt/gatt_db.c index bd94e5060..fa636fba9 100644 --- a/stack/gatt/gatt_db.c +++ b/stack/gatt/gatt_db.c @@ -134,7 +134,8 @@ static tGATT_STATUS gatts_check_attr_readability(tGATT_ATTR16 *p_attr, return GATT_READ_NOT_PERMIT; } - if ((perm & GATT_READ_AUTH_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_LKEY_UNAUTHED)) + if ((perm & GATT_READ_AUTH_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_LKEY_UNAUTHED) && + !(sec_flag & BTM_SEC_FLAG_ENCRYPTED)) { GATT_TRACE_ERROR0( "GATT_INSUF_AUTHENTICATION"); return GATT_INSUF_AUTHENTICATION; @@ -731,14 +732,21 @@ tGATT_STATUS gatts_write_attr_perm_check (tGATT_SVC_DB *p_db, UINT8 op_code, p_attr->permission, min_key_size); - if ((op_code == GATT_CMD_WRITE) && (perm & GATT_WRITE_SIGNED_PERM) ) + if ((op_code == GATT_CMD_WRITE || op_code == GATT_REQ_WRITE) + && (perm & GATT_WRITE_SIGNED_PERM)) { /* use the rules for the mixed security see section 10.2.3*/ - if (perm & GATT_PERM_WRITE_SIGNED) + /* use security mode 1 level 2 when the following condition follows */ + /* LE security mode 2 level 1 and LE security mode 1 level 2 */ + if ((perm & GATT_PERM_WRITE_SIGNED) && (perm & GATT_PERM_WRITE_ENCRYPTED)) { perm = GATT_PERM_WRITE_ENCRYPTED; } - else + /* use security mode 1 level 3 when the following condition follows */ + /* LE security mode 2 level 2 and security mode 1 and LE */ + else if (((perm & GATT_PERM_WRITE_SIGNED_MITM) && (perm & GATT_PERM_WRITE_ENCRYPTED)) || + /* LE security mode 2 and security mode 1 level 3 */ + ((perm & GATT_WRITE_SIGNED_PERM) && (perm & GATT_PERM_WRITE_ENC_MITM))) { perm = GATT_PERM_WRITE_ENC_MITM; } @@ -759,6 +767,7 @@ tGATT_STATUS gatts_write_attr_perm_check (tGATT_SVC_DB *p_db, UINT8 op_code, status = GATT_WRITE_NOT_PERMIT; GATT_TRACE_ERROR0( "gatts_write_attr_perm_check - GATT_WRITE_NOT_PERMIT"); } + /* require authentication, but not been authenticated */ else if ((perm & GATT_WRITE_AUTH_REQUIRED ) && !(sec_flag & GATT_SEC_FLAG_LKEY_UNAUTHED)) { status = GATT_INSUF_AUTHENTICATION; @@ -779,6 +788,12 @@ tGATT_STATUS gatts_write_attr_perm_check (tGATT_SVC_DB *p_db, UINT8 op_code, status = GATT_INSUF_KEY_SIZE; GATT_TRACE_ERROR0( "gatts_write_attr_perm_check - GATT_INSUF_KEY_SIZE"); } + /* LE security mode 2 attribute */ + else if (perm & GATT_WRITE_SIGNED_PERM && op_code != GATT_SIGN_CMD_WRITE && !(sec_flag & GATT_SEC_FLAG_ENCRYPTED)) + { + status = GATT_INSUF_AUTHENTICATION; + GATT_TRACE_ERROR0( "gatts_write_attr_perm_check - GATT_INSUF_AUTHENTICATION: LE security mode 2 required"); + } else /* writable: must be char value declaration or char descritpors */ { if(p_attr->uuid_type == GATT_ATTR_UUID_TYPE_16) @@ -793,6 +808,9 @@ tGATT_STATUS gatts_write_attr_perm_check (tGATT_SVC_DB *p_db, UINT8 op_code, break; case GATT_UUID_CHAR_CLIENT_CONFIG: +/* coverity[MISSING_BREAK] */ +/* intnended fall through, ignored */ + /* fall through */ case GATT_UUID_CHAR_SRVR_CONFIG: max_size = 2; case GATT_UUID_CHAR_DESCRIPTION: @@ -828,7 +846,7 @@ tGATT_STATUS gatts_write_attr_perm_check (tGATT_SVC_DB *p_db, UINT8 op_code, } else if (len != max_size) /* data does not match the required format */ { - status = GATT_INVALID_PDU; + status = GATT_INVALID_ATTR_LEN; GATT_TRACE_ERROR0( "gatts_write_attr_perm_check - GATT_INVALID_PDU"); } else diff --git a/stack/gatt/gatt_int.h b/stack/gatt/gatt_int.h index 44a2bc1d9..48278c20e 100644 --- a/stack/gatt/gatt_int.h +++ b/stack/gatt/gatt_int.h @@ -42,10 +42,11 @@ /* security action for GATT write and read request */ #define GATT_SEC_NONE 0 #define GATT_SEC_OK 1 -#define GATT_SEC_ENCRYPT 2 /* encrypt the link with current key */ -#define GATT_SEC_ENCRYPT_NO_MITM 3 /* unauthenticated encryption or better */ -#define GATT_SEC_ENCRYPT_MITM 4 /* authenticated encryption */ -#define GATT_SEC_SIGN_DATA 5 /* compute the signature for the write cmd */ +#define GATT_SEC_SIGN_DATA 2 /* compute the signature for the write cmd */ +#define GATT_SEC_ENCRYPT 3 /* encrypt the link with current key */ +#define GATT_SEC_ENCRYPT_NO_MITM 4 /* unauthenticated encryption or better */ +#define GATT_SEC_ENCRYPT_MITM 5 /* authenticated encryption */ +#define GATT_SEC_ENC_PENDING 6 /* wait for link encryption pending */ typedef UINT8 tGATT_SEC_ACTION; @@ -214,7 +215,6 @@ typedef struct typedef struct { tGATT_SVC_DB *p_db; /* pointer to the service database */ - //tGATT_SR_CBACK sr_cb; /* server callback functions */ tBT_UUID app_uuid; /* applicatino UUID */ UINT32 sdp_handle; /* primamry service SDP handle */ UINT16 service_instance; /* service instance number */ @@ -225,6 +225,8 @@ typedef struct BOOLEAN in_use; } tGATT_SR_REG; +#define GATT_LISTEN_TO_ALL 0xff +#define GATT_LISTEN_TO_NONE 0 /* Data Structure used for GATT server */ /* An GATT registration record consists of a handle, and 1 or more attributes */ @@ -237,6 +239,7 @@ typedef struct tGATT_CBACK app_cb; tGATT_IF gatt_if; /* one based */ BOOLEAN in_use; + UINT8 listening; /* if adv for all has been enabled */ } tGATT_REG; @@ -332,7 +335,7 @@ typedef struct typedef struct { - void *p_clcb; /* which clcb is doing encryption */ + BUFFER_Q pending_enc_clcb; /* pending encryption channel q */ tGATT_SEC_ACTION sec_act; BD_ADDR peer_bda; UINT32 trans_id; @@ -366,6 +369,7 @@ typedef struct UINT8 tcb_idx; } tGATT_TCB; + /* logic channel */ typedef struct { @@ -395,6 +399,12 @@ typedef struct BOOLEAN in_use; } tGATT_CLCB; +typedef struct +{ + tGATT_CLCB *p_clcb; +}tGATT_PENDING_ENC_CLCB; + + #define GATT_SIGN_WRITE 1 #define GATT_VERIFY_SIGN_DATA 2 @@ -429,6 +439,7 @@ typedef struct typedef struct { tGATT_IF gatt_if[GATT_MAX_APPS]; + tGATT_IF listen_gif[GATT_MAX_APPS]; BD_ADDR remote_bda; BOOLEAN in_use; }tGATT_BG_CONN_DEV; @@ -468,6 +479,7 @@ typedef struct BOOLEAN enable_err_rsp; UINT8 req_op_code; UINT8 err_status; + UINT16 handle; #endif tGATT_PROFILE_CLCB profile_clcb[GATT_MAX_APPS]; @@ -551,6 +563,7 @@ extern void gatt_ind_ack_timeout(TIMER_LIST_ENT *p_tle); extern void gatt_start_ind_ack_timer(tGATT_TCB *p_tcb); extern tGATT_STATUS gatt_send_error_rsp(tGATT_TCB *p_tcb, UINT8 err_code, UINT8 op_code, UINT16 handle, BOOLEAN deq); extern void gatt_dbg_display_uuid(tBT_UUID bt_uuid); +extern tGATT_PENDING_ENC_CLCB* gatt_add_pending_enc_channel_clcb(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb ); extern tGATTS_PENDING_NEW_SRV_START *gatt_sr_is_new_srv_chg(tBT_UUID *p_app_uuid128, tBT_UUID *p_svc_uuid, UINT16 svc_inst); @@ -563,6 +576,7 @@ extern void gatt_delete_dev_from_srv_chg_clt_list(BD_ADDR bd_addr); extern tGATT_VALUE *gatt_add_pending_ind(tGATT_TCB *p_tcb, tGATT_VALUE *p_ind); extern tGATTS_PENDING_NEW_SRV_START *gatt_add_pending_new_srv_start( tGATTS_HNDL_RANGE *p_new_srv_start); extern void gatt_free_srvc_db_buffer_app_id(tBT_UUID *p_app_id); +extern void gatt_update_listen_mode(void); /* reserved handle list */ extern tGATT_HDL_LIST_ELEM *gatt_find_hdl_buffer_by_app_id (tBT_UUID *p_app_uuid128, tBT_UUID *p_svc_uuid, UINT16 svc_inst); @@ -578,13 +592,11 @@ extern BOOLEAN gatt_remove_an_item_from_list(tGATT_HDL_LIST_INFO *p_list, tGATT_ extern tGATTS_SRV_CHG *gatt_add_srv_chg_clt(tGATTS_SRV_CHG *p_srv_chg); /* for background connection */ -extern BOOLEAN gatt_update_auto_connect_dev (tGATT_IF gatt_if, BOOLEAN add, BD_ADDR bd_addr); -extern BOOLEAN gatt_add_bg_dev_list(tGATT_IF gatt_if, BD_ADDR bd_addr); +extern BOOLEAN gatt_update_auto_connect_dev (tGATT_IF gatt_if, BOOLEAN add, BD_ADDR bd_addr, BOOLEAN is_initiator); extern BOOLEAN gatt_is_bg_dev_for_app(tGATT_BG_CONN_DEV *p_dev, tGATT_IF gatt_if); extern BOOLEAN gatt_remove_bg_dev_for_app(tGATT_IF gatt_if, BD_ADDR bd_addr); extern UINT8 gatt_get_num_apps_for_bg_dev(BD_ADDR bd_addr); extern BOOLEAN gatt_find_app_for_bg_dev(BD_ADDR bd_addr, tGATT_IF *p_gatt_if); -extern BOOLEAN gatt_remove_bg_dev_from_list(tGATT_IF gatt_if, BD_ADDR bd_addr); extern tGATT_BG_CONN_DEV * gatt_find_bg_dev(BD_ADDR remote_bda); extern void gatt_deregister_bgdev_list(tGATT_IF gatt_if); extern void gatt_reset_bgdev_list(void); @@ -634,7 +646,7 @@ extern void gatt_end_operation(tGATT_CLCB *p_clcb, tGATT_STATUS status, void *p_ extern void gatt_act_discovery(tGATT_CLCB *p_clcb); extern void gatt_act_read(tGATT_CLCB *p_clcb, UINT16 offset); -extern void gatt_act_write(tGATT_CLCB *p_clcb); +extern void gatt_act_write(tGATT_CLCB *p_clcb, UINT8 sec_act); extern UINT8 gatt_act_send_browse(tGATT_TCB *p_tcb, UINT16 index, UINT8 op, UINT16 s_handle, UINT16 e_handle, tBT_UUID uuid); extern tGATT_CLCB *gatt_cmd_dequeue(tGATT_TCB *p_tcb, UINT8 *p_opcode); @@ -666,6 +678,7 @@ extern tGATT_STATUS gatts_read_attr_perm_check(tGATT_SVC_DB *p_db, BOOLEAN is_lo extern void gatts_update_srv_list_elem(UINT8 i_sreg, UINT16 handle, BOOLEAN is_primary); extern tBT_UUID * gatts_get_service_uuid (tGATT_SVC_DB *p_db); +extern void gatt_reset_bgdev_list(void); #endif #endif /* BLE_INCLUDED */ diff --git a/stack/gatt/gatt_main.c b/stack/gatt/gatt_main.c index 06d87bb24..dcd939840 100644 --- a/stack/gatt/gatt_main.c +++ b/stack/gatt/gatt_main.c @@ -49,7 +49,7 @@ static void gatt_l2cif_config_cfm_cback (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cf static void gatt_l2cif_disconnect_ind_cback (UINT16 l2cap_cid, BOOLEAN ack_needed); static void gatt_l2cif_disconnect_cfm_cback (UINT16 l2cap_cid, UINT16 result); static void gatt_l2cif_data_ind_cback (UINT16 l2cap_cid, BT_HDR *p_msg); -static void gatt_send_conn_cback (BOOLEAN is_bg_conn, tGATT_TCB *p_tcb); +static void gatt_send_conn_cback (tGATT_TCB *p_tcb); static const tL2CAP_APPL_INFO dyn_info = { @@ -145,7 +145,8 @@ BOOLEAN gatt_connect (BD_ADDR rem_bda, tGATT_TCB *p_tcb) BTM_ReadDevInfo(rem_bda, &dev_type, &addr_type); - gatt_set_ch_state(p_tcb, GATT_CH_CONN); + if (gatt_get_ch_state(p_tcb) != GATT_CH_OPEN) + gatt_set_ch_state(p_tcb, GATT_CH_CONN); if (dev_type == BT_DEVICE_TYPE_BLE) { @@ -188,8 +189,10 @@ BOOLEAN gatt_disconnect (BD_ADDR rem_bda) 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); @@ -315,13 +318,22 @@ 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; - if(gatt_get_ch_state(p_tcb) == GATT_CH_CLOSING ) + 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 ) + { + if (!gatt_connect(bd_addr, p_tcb)) + ret = FALSE; + } + else if(st == GATT_CH_CLOSING) { /* need to complete the closing first */ ret = FALSE; @@ -370,8 +382,6 @@ static void gatt_le_connect_cback (BD_ADDR bd_addr, BOOLEAN connected, UINT16 re 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], @@ -407,7 +417,7 @@ static void gatt_le_connect_cback (BD_ADDR bd_addr, BOOLEAN connected, UINT16 re 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); + gatt_send_conn_cback(p_tcb); } else /* there was an exisiting link, ignore the callback */ { @@ -425,11 +435,8 @@ static void gatt_le_connect_cback (BD_ADDR bd_addr, BOOLEAN connected, UINT16 re 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); + + gatt_send_conn_cback (p_tcb); if (check_srv_chg) { gatt_chk_srv_chg (p_srv_chg_clt); @@ -630,12 +637,15 @@ void gatt_l2cif_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg) } else { - if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda)) + if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda) && + btm_sec_is_le_capable_dev(p_tcb->peer_bda)) + { gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda); + } } /* send callback */ - gatt_send_conn_cback(FALSE, p_tcb); + gatt_send_conn_cback(p_tcb); } } /* else failure */ @@ -692,12 +702,15 @@ void gatt_l2cif_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg) } else { - if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda)) + if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda) && + btm_sec_is_le_capable_dev(p_tcb->peer_bda)) + { gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda); + } } /* send callback */ - gatt_send_conn_cback(FALSE, p_tcb); + gatt_send_conn_cback(p_tcb); } } } @@ -726,8 +739,13 @@ void gatt_l2cif_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed) /* send L2CAP disconnect response */ L2CA_DisconnectRsp(lcid); } - if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda)) + + if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda) && + btm_sec_is_le_capable_dev(p_tcb->peer_bda)) + { gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda); + } + /* if ACL link is still up, no reason is logged, l2cap is disconnect from peer */ if ((reason = L2CA_GetDisconnectReason(p_tcb->peer_bda)) == 0) reason = GATT_CONN_TERMINATE_PEER_USER; @@ -755,8 +773,12 @@ void gatt_l2cif_disconnect_cfm_cback(UINT16 lcid, UINT16 result) /* look up clcb for this channel */ if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL) { - if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda)) + if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda) && + btm_sec_is_le_capable_dev(p_tcb->peer_bda)) + { gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda); + } + /* send disconnect callback */ /* if ACL link is still up, no reason is logged, l2cap is disconnect from peer */ if ((reason = L2CA_GetDisconnectReason(p_tcb->peer_bda)) == 0) @@ -801,15 +823,14 @@ void gatt_l2cif_data_ind_cback(UINT16 lcid, BT_HDR *p_buf) ** Returns void ** *******************************************************************************/ -static void gatt_send_conn_cback(BOOLEAN is_bg_conn, tGATT_TCB *p_tcb) +static void gatt_send_conn_cback(tGATT_TCB *p_tcb) { UINT8 i; tGATT_REG *p_reg; tGATT_BG_CONN_DEV *p_bg_dev=NULL; UINT16 conn_id; - if (is_bg_conn) - p_bg_dev = gatt_find_bg_dev(p_tcb->peer_bda); + p_bg_dev = gatt_find_bg_dev(p_tcb->peer_bda); /* notifying all applications for the connection up event */ for (i = 0, p_reg = gatt_cb.cl_rcb ; i < GATT_MAX_APPS; i++, p_reg++) @@ -1015,7 +1036,7 @@ void gatt_init_srv_chg (void) 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))) + if ((status = (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_READ_CLENT, &req, &rsp)) == TRUE) { memcpy(&srv_chg_clt, &rsp.srv_chg ,sizeof(tGATTS_SRV_CHG)); if (gatt_add_srv_chg_clt(&srv_chg_clt) == NULL) diff --git a/stack/gatt/gatt_sr.c b/stack/gatt/gatt_sr.c index ddecdb3a8..71ba6a52c 100644 --- a/stack/gatt/gatt_sr.c +++ b/stack/gatt/gatt_sr.c @@ -332,6 +332,18 @@ void gatt_process_exec_write_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, U tGATT_IF gatt_if; UINT16 conn_id; +#if GATT_CONFORMANCE_TESTING == TRUE + if (gatt_cb.enable_err_rsp && gatt_cb.req_op_code == op_code) + { + GATT_TRACE_DEBUG2("conf test forced err rsp for %s error status=%d", + __FUNCTION__,gatt_cb.err_status); + + gatt_send_error_rsp (p_tcb, gatt_cb.err_status, gatt_cb.req_op_code, 0, FALSE); + + return; + } +#endif + STREAM_TO_UINT8(flag, p); /* mask the flag */ diff --git a/stack/gatt/gatt_utils.c b/stack/gatt/gatt_utils.c index bd3aaf62a..5470f4ef8 100644 --- a/stack/gatt/gatt_utils.c +++ b/stack/gatt/gatt_utils.c @@ -98,6 +98,23 @@ void gatt_free_pending_ind(tGATT_TCB *p_tcb) /******************************************************************************* ** +** Function gatt_free_pending_enc_queue +** +** Description Free all buffers in pending encyption queue +** +** Returns None +** +*******************************************************************************/ +void gatt_free_pending_enc_queue(tGATT_TCB *p_tcb) +{ + GATT_TRACE_DEBUG0("gatt_free_pending_enc_queue"); + /* release all queued indications */ + while (p_tcb->pending_enc_clcb.p_first) + GKI_freebuf (GKI_dequeue (&p_tcb->pending_enc_clcb)); +} + +/******************************************************************************* +** ** Function gatt_delete_dev_from_srv_chg_clt_list ** ** Description Delete a device from the service changed client lit @@ -920,6 +937,8 @@ tGATT_TCB * gatt_allocate_tcb_by_bdaddr(BD_ADDR bda) if (allocated) { memset(p_tcb, 0, sizeof(tGATT_TCB)); + GKI_init_q (&p_tcb->pending_enc_clcb); + GKI_init_q (&p_tcb->pending_ind_q); p_tcb->in_use = TRUE; p_tcb->tcb_idx = i; } @@ -1258,7 +1277,6 @@ UINT8 gatt_sr_alloc_rcb(tGATT_HDL_LIST_ELEM *p_list ) p_sreg->type = p_list->asgn_range.is_primary ? GATT_UUID_PRI_SERVICE: GATT_UUID_SEC_SERVICE; p_sreg->s_hdl = p_list->asgn_range.s_handle; p_sreg->e_hdl = p_list->asgn_range.e_handle; - //p_sreg->sr_cb = *p_cback; p_sreg->p_db = &p_list->svc_db; GATT_TRACE_DEBUG1 ("total GKI buffer in db [%d]",p_sreg->p_db->svc_buffer.count); @@ -2109,6 +2127,7 @@ void gatt_cleanup_upon_disc(BD_ADDR bda, UINT16 reason) btu_stop_timer (&p_tcb->ind_ack_timer_ent); btu_stop_timer (&p_tcb->conf_timer_ent); gatt_free_pending_ind(p_tcb); + gatt_free_pending_enc_queue(p_tcb); for (i = 0; i < GATT_MAX_APPS; i ++) { @@ -2272,13 +2291,15 @@ tGATT_BG_CONN_DEV * gatt_alloc_bg_dev(BD_ADDR remote_bda) ** ** Description add/remove device from the back ground connection device list ** -** Returns pointer to the device record +** Returns TRUE if device added to the list; FALSE failed ** *******************************************************************************/ -BOOLEAN gatt_add_bg_dev_list(tGATT_IF gatt_if, BD_ADDR bd_addr) +BOOLEAN gatt_add_bg_dev_list(tGATT_REG *p_reg, BD_ADDR bd_addr, BOOLEAN is_initator) { + tGATT_IF gatt_if = p_reg->gatt_if; tGATT_BG_CONN_DEV *p_dev = NULL; - UINT8 i; + UINT8 i; + BOOLEAN ret = FALSE; if ((p_dev = gatt_find_bg_dev(bd_addr)) == NULL) { @@ -2289,26 +2310,51 @@ BOOLEAN gatt_add_bg_dev_list(tGATT_IF gatt_if, BD_ADDR bd_addr) { for (i = 0; i < GATT_MAX_APPS; i ++) { - if (p_dev->gatt_if[i] == gatt_if) + if (is_initator) { - GATT_TRACE_ERROR0("device already in list"); - return FALSE; + if (p_dev->gatt_if[i] == gatt_if) + { + GATT_TRACE_ERROR0("device already in iniator white list"); + break; + } + else if (p_dev->gatt_if[i] == 0) + { + p_dev->gatt_if[i] = gatt_if; + if (i == 0) + ret = BTM_BleUpdateBgConnDev(TRUE, bd_addr); + break; + } } - else if (p_dev->gatt_if[i] == 0) + else { - GATT_TRACE_DEBUG0("add device into list"); - p_dev->gatt_if[i] = gatt_if; - return TRUE; + if (p_dev->listen_gif[i] == gatt_if) + { + GATT_TRACE_ERROR0("device already in adv white list"); + return FALSE; + } + else if (p_dev->listen_gif[i] == 0) + { + if (p_reg->listening == GATT_LISTEN_TO_ALL) + p_reg->listening = GATT_LISTEN_TO_NONE; + + p_reg->listening ++; + p_dev->listen_gif[i] = gatt_if; + + if (i == 0) + ret = BTM_BleUpdateAdvWhitelist(TRUE, bd_addr); + break; + } } } } + else + { + GATT_TRACE_ERROR0("no device record available"); + } - GATT_TRACE_ERROR0("no device record available"); - - return FALSE; + return ret; } - /******************************************************************************* ** ** Function gatt_remove_bg_dev_for_app @@ -2325,7 +2371,7 @@ BOOLEAN gatt_remove_bg_dev_for_app(tGATT_IF gatt_if, BD_ADDR bd_addr) if (p_tcb) gatt_update_app_use_link_flag(gatt_if, p_tcb, FALSE, FALSE); - status = gatt_update_auto_connect_dev(gatt_if, FALSE, bd_addr); + status = gatt_update_auto_connect_dev(gatt_if, FALSE, bd_addr, TRUE); return status; } @@ -2393,13 +2439,15 @@ BOOLEAN gatt_find_app_for_bg_dev(BD_ADDR bd_addr, tGATT_IF *p_gatt_if) ** ** Function gatt_remove_bg_dev_from_list ** -** Description add/remove device from the back ground connection device list +** Description add/remove device from the back ground connection device list or +** listening to advertising list. ** ** Returns pointer to the device record ** *******************************************************************************/ -BOOLEAN gatt_remove_bg_dev_from_list(tGATT_IF gatt_if, BD_ADDR bd_addr) +BOOLEAN gatt_remove_bg_dev_from_list(tGATT_REG *p_reg, BD_ADDR bd_addr, BOOLEAN is_initiator) { + tGATT_IF gatt_if = p_reg->gatt_if; tGATT_BG_CONN_DEV *p_dev = NULL; UINT8 i, j; BOOLEAN ret = FALSE; @@ -2409,27 +2457,49 @@ BOOLEAN gatt_remove_bg_dev_from_list(tGATT_IF gatt_if, BD_ADDR bd_addr) return ret; } - for (i = 0; i < GATT_MAX_APPS && p_dev->gatt_if[i] > 0; i ++) + for (i = 0; i < GATT_MAX_APPS && (p_dev->gatt_if[i] > 0 || p_dev->listen_gif[i]); i ++) { - if (p_dev->gatt_if[i] == gatt_if) + if (is_initiator) { - p_dev->gatt_if[i] = 0; + if (p_dev->gatt_if[i] == gatt_if) + { + p_dev->gatt_if[i] = 0; + /* move all element behind one forward */ + for (j = i + 1; j < GATT_MAX_APPS; j ++) + p_dev->gatt_if[j - 1] = p_dev->gatt_if[j]; - for (j = i + 1; j < GATT_MAX_APPS; j ++) - p_dev->gatt_if[j - 1] = p_dev->gatt_if[j]; + if (p_dev->gatt_if[0] == 0) + ret = BTM_BleUpdateBgConnDev(FALSE, p_dev->remote_bda); + else + ret = TRUE; - if (p_dev->gatt_if[0] == 0) + break; + } + } + else + { + if (p_dev->listen_gif[i] == gatt_if) { - ret = BTM_BleUpdateBgConnDev(FALSE, p_dev->remote_bda); - memset(p_dev, 0, sizeof(tGATT_BG_CONN_DEV)); + p_dev->listen_gif[i] = 0; + p_reg->listening --; + /* move all element behind one forward */ + for (j = i + 1; j < GATT_MAX_APPS; j ++) + p_dev->listen_gif[j - 1] = p_dev->listen_gif[j]; + + if (p_dev->listen_gif[0] == 0) + ret = BTM_BleUpdateAdvWhitelist(FALSE, p_dev->remote_bda); + else + ret = TRUE; + break; } - else - ret = TRUE; - - break; } } + if (i != GATT_MAX_APPS && p_dev->gatt_if[0] == 0 && p_dev->listen_gif[0] == 0) + { + memset(p_dev, 0, sizeof(tGATT_BG_CONN_DEV)); + } + return ret; } /******************************************************************************* @@ -2500,9 +2570,9 @@ void gatt_reset_bgdev_list(void) ** Returns TRUE if connection started; FALSE if connection start failure. ** *******************************************************************************/ -BOOLEAN gatt_update_auto_connect_dev (tGATT_IF gatt_if, BOOLEAN add, BD_ADDR bd_addr) +BOOLEAN gatt_update_auto_connect_dev (tGATT_IF gatt_if, BOOLEAN add, BD_ADDR bd_addr, BOOLEAN is_initator) { - BOOLEAN ret = FALSE, exist_dev = FALSE; + BOOLEAN ret = FALSE; tGATT_REG *p_reg; tGATT_TCB *p_tcb = gatt_find_tcb_by_addr(bd_addr); @@ -2516,27 +2586,17 @@ BOOLEAN gatt_update_auto_connect_dev (tGATT_IF gatt_if, BOOLEAN add, BD_ADDR bd_ if (add) { - /* new device */ - if (gatt_find_bg_dev(bd_addr)) - exist_dev = TRUE; + ret = gatt_add_bg_dev_list(p_reg, bd_addr, is_initator); - if (gatt_add_bg_dev_list(gatt_if, bd_addr)) + if (ret && p_tcb != NULL) { - if (!exist_dev) - { - ret = BTM_BleUpdateBgConnDev(TRUE, bd_addr); - } - else - ret = TRUE; - /* if a connected device, update the link holding number */ - if (p_tcb != NULL) - gatt_update_app_use_link_flag(gatt_if, p_tcb, TRUE, TRUE); + gatt_update_app_use_link_flag(gatt_if, p_tcb, TRUE, TRUE); } } else { - ret = gatt_remove_bg_dev_from_list(gatt_if, bd_addr); + ret = gatt_remove_bg_dev_from_list(p_reg, bd_addr, is_initator); } return ret; } @@ -2591,10 +2651,70 @@ UINT16 gatt_get_conn_id (tGATT_IF gatt_if, BD_ADDR bd_addr) GATT_TRACE_ERROR1 ("gatt_get_conn_id: not connected- gatt_if: %u", gatt_if); return(GATT_INVALID_CONN_ID); } +/******************************************************************************* +** +** Function gatt_add_pending_new_srv_start +** +** Description Add a pending new srv start to the new service start queue +** +** Returns Pointer to the new service start buffer, NULL no buffer available +** +*******************************************************************************/ +tGATT_PENDING_ENC_CLCB* gatt_add_pending_enc_channel_clcb(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb ) +{ + tGATT_PENDING_ENC_CLCB *p_buf; + GATT_TRACE_DEBUG0 ("gatt_add_pending_new_srv_start"); + if ((p_buf = (tGATT_PENDING_ENC_CLCB *)GKI_getbuf((UINT16)sizeof(tGATT_PENDING_ENC_CLCB))) != NULL) + { + GATT_TRACE_DEBUG0 ("enqueue a new pending encryption channel clcb"); + p_buf->p_clcb = p_clcb; + GKI_enqueue (&p_tcb->pending_enc_clcb, p_buf); + } + return p_buf; +} +/******************************************************************************* +** +** Function gatt_update_listen_mode +** +** Description update peripheral role listening mode +** +** Returns Pointer to the new service start buffer, NULL no buffer available +** +*******************************************************************************/ +void gatt_update_listen_mode(void) +{ + UINT8 ii = 0; + tGATT_REG *p_reg = &gatt_cb.cl_rcb[0]; + UINT8 listening = 0; + UINT16 connectability, window, interval; + for (; ii < GATT_MAX_APPS; ii ++, p_reg ++) + { + if ( p_reg->in_use && p_reg->listening > listening) + { + listening = p_reg->listening; + } + } + + if (listening == GATT_LISTEN_TO_ALL || + listening == GATT_LISTEN_TO_NONE) + BTM_BleUpdateAdvFilterPolicy (AP_SCAN_CONN_ALL); + else + BTM_BleUpdateAdvFilterPolicy (AP_SCAN_CONN_WL); + connectability = BTM_ReadConnectability (&window, &interval); + if (listening != GATT_LISTEN_TO_NONE) + { + connectability |= BTM_BLE_CONNECTABLE; + } + else + connectability &= ~BTM_BLE_CONNECTABLE; + /* turning on the adv now */ + BTM_SetConnectability(connectability, window, interval); + +} #endif diff --git a/stack/hcic/hciblecmds.c b/stack/hcic/hciblecmds.c index 417297b71..a4e55da7e 100644 --- a/stack/hcic/hciblecmds.c +++ b/stack/hcic/hciblecmds.c @@ -748,4 +748,112 @@ BOOLEAN btsnd_hcic_ble_read_supported_states (void) return (TRUE); } +BOOLEAN btsnd_hcic_ble_receiver_test(UINT8 rx_freq) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM1)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_RECEIVER_TEST); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM1); + + UINT8_TO_STREAM (pp, rx_freq); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_transmitter_test(UINT8 tx_freq, UINT8 test_data_len, UINT8 payload) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_PARAM3)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM3; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_TRANSMITTER_TEST); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_PARAM3); + + UINT8_TO_STREAM (pp, tx_freq); + UINT8_TO_STREAM (pp, test_data_len); + UINT8_TO_STREAM (pp, payload); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_test_end(void) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_BLE_TEST_END); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_read_host_supported (void) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_READ_CMD)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_READ_LE_HOST_SUPPORTED); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_READ_CMD); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + +BOOLEAN btsnd_hcic_ble_write_host_supported (UINT8 le_host_spt, UINT8 simul_le_host_spt) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_WRITE_LE_HOST_SUPPORTED)) == NULL) + return (FALSE); + + pp = (UINT8 *)(p + 1); + + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_LE_HOST_SUPPORTED; + p->offset = 0; + + UINT16_TO_STREAM (pp, HCI_WRITE_LE_HOST_SUPPORTED); + UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_WRITE_LE_HOST_SUPPORTED); + UINT8_TO_STREAM (pp, le_host_spt); + UINT8_TO_STREAM (pp, simul_le_host_spt); + + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} + #endif diff --git a/stack/hcic/hcicmds.c b/stack/hcic/hcicmds.c index 71a5dc551..21222bd6b 100644 --- a/stack/hcic/hcicmds.c +++ b/stack/hcic/hcicmds.c @@ -1371,6 +1371,9 @@ BOOLEAN btsnd_hcic_change_name (BD_NAME name) UINT16_TO_STREAM (pp, HCI_CHANGE_LOCAL_NAME); UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_CHANGE_NAME); + if (len > HCIC_PARAM_SIZE_CHANGE_NAME) + len = HCIC_PARAM_SIZE_CHANGE_NAME; + ARRAY_TO_STREAM (pp, name, len); btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); diff --git a/stack/hid/hidh_api.c b/stack/hid/hidh_api.c index 36ee5ea98..4f048fcb8 100644 --- a/stack/hid/hidh_api.c +++ b/stack/hid/hidh_api.c @@ -88,7 +88,7 @@ void hidh_get_str_attr( tSDP_DISC_REC *p_rec, UINT16 attr_id, UINT16 max_len, ch else { memcpy( str, (char *) p_attr->attr_value.v.array, max_len-1 ); - str[max_len] = '\0'; + str[max_len-1] = '\0'; } } else @@ -220,7 +220,7 @@ static void hidh_search_callback (UINT16 sdp_result) p_nvi->ssr_min_tout = p_attr->attr_value.v.u16; } else - p_nvi->ssr_max_latency = HID_SSR_PARAM_INVALID; + p_nvi->ssr_min_tout = HID_SSR_PARAM_INVALID; hh_cb.sdp_rec.p_sdp_layer_rec = p_rec; hh_cb.sdp_cback(SDP_SUCCESS, attr_mask, &hh_cb.sdp_rec); @@ -454,7 +454,7 @@ tHID_STATUS HID_HostWriteDev( UINT8 dev_handle, UINT8 t_type, status = HID_ERR_INVALID_PARAM; } - if( hh_cb.devices[dev_handle].state != HID_DEV_CONNECTED ) + else if( hh_cb.devices[dev_handle].state != HID_DEV_CONNECTED ) { HIDH_TRACE_ERROR1("HID_ERR_NO_CONNECTION dev_handle %d", dev_handle); status = HID_ERR_NO_CONNECTION; diff --git a/stack/hid/hidh_conn.c b/stack/hid/hidh_conn.c index 9ed3a0ee1..2fe1f3da1 100644 --- a/stack/hid/hidh_conn.c +++ b/stack/hid/hidh_conn.c @@ -322,7 +322,7 @@ void hidh_sec_check_complete_orig (BD_ADDR bd_addr, void *p_ref_data, UINT8 res) #endif UINT32 reason; - dhandle = p_dev - &(hh_cb.devices[0]) ; + dhandle = ((UINT32)p_dev - (UINT32)&(hh_cb.devices[0]))/ sizeof(tHID_HOST_DEV_CTB); if( res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY ) { HIDH_TRACE_EVENT0 ("HID - Originator security pass."); @@ -975,7 +975,6 @@ tHID_STATUS hidh_conn_initiate (UINT8 dhandle) if ((p_dev->conn.ctrl_cid = L2CA_ConnectReq (HID_PSM_CONTROL, p_dev->addr)) == 0) { HIDH_TRACE_WARNING0 ("HID - Originate failed"); - dhandle = (p_dev - &(hh_cb.devices[0]))/(sizeof( tHID_HOST_DEV_CTB )) ; hh_cb.callback( dhandle, HID_HDEV_EVT_CLOSE, HID_ERR_L2CAP_FAILED, NULL ) ; } else diff --git a/stack/include/avdt_api.h b/stack/include/avdt_api.h index 0a9b7f8c7..beaecf61e 100644 --- a/stack/include/avdt_api.h +++ b/stack/include/avdt_api.h @@ -407,6 +407,13 @@ typedef struct { UINT16 nsc_mask; /* Nonsupported protocol command messages */ } tAVDT_CS; +/* AVDT data option mask is used in the write request */ +#define AVDT_DATA_OPT_NONE 0x00 /* No option still add RTP header */ +#define AVDT_DATA_OPT_NO_RTP (0x01 << 0) /* Skip adding RTP header */ + +typedef UINT8 tAVDT_DATA_OPT_MASK; + + /***************************************************************************** ** External Function Declarations @@ -758,6 +765,44 @@ AVDT_API extern UINT16 AVDT_SecurityRsp(UINT8 handle, UINT8 label, UINT8 error_c *******************************************************************************/ AVDT_API extern UINT16 AVDT_WriteReq(UINT8 handle, BT_HDR *p_pkt, UINT32 time_stamp, UINT8 m_pt); +/******************************************************************************* +** +** Function AVDT_WriteReqOpt +** +** Description Send a media packet to the peer device. The stream must +** be started before this function is called. Also, this +** function can only be called if the stream is a SRC +** +** When AVDTP has sent the media packet and is ready for the +** next packet, an AVDT_WRITE_CFM_EVT is sent to the +** application via the control callback. The application must +** wait for the AVDT_WRITE_CFM_EVT before it makes the next +** call to AVDT_WriteReq(). If the applications calls +** AVDT_WriteReq() before it receives the event the packet +** will not be sent. The application may make its first call +** to AVDT_WriteReq() after it receives an AVDT_START_CFM_EVT +** or AVDT_START_IND_EVT. +** +** The application passes the packet using the BT_HDR structure +** This structure is described in section 2.1. The offset +** field must be equal to or greater than AVDT_MEDIA_OFFSET +** (if NO_RTP is specified, L2CAP_MIN_OFFSET can be used) +** This allows enough space in the buffer for the L2CAP and +** AVDTP headers. +** +** The memory pointed to by p_pkt must be a GKI buffer +** allocated by the application. This buffer will be freed +** by the protocol stack; the application must not free +** this buffer. +** +** The opt parameter allows passing specific options like: +** - NO_RTP : do not add the RTP header to buffer +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +AVDT_API extern UINT16 AVDT_WriteReqOpt(UINT8 handle, BT_HDR *p_pkt, UINT32 time_stamp, + UINT8 m_pt, tAVDT_DATA_OPT_MASK opt); /******************************************************************************* ** diff --git a/stack/include/avrc_api.h b/stack/include/avrc_api.h index 1f4bb7f52..cc6db7f3e 100644 --- a/stack/include/avrc_api.h +++ b/stack/include/avrc_api.h @@ -563,7 +563,8 @@ AVRC_API extern void AVRC_Init(void); ** Otherwise, the error code defined by AVRCP 1.4 ** *******************************************************************************/ -AVRC_API extern tAVRC_STS AVRC_ParsCommand (tAVRC_MSG *p_msg, tAVRC_COMMAND *p_result, UINT8 *p_buf, UINT16 buf_len); +AVRC_API extern tAVRC_STS AVRC_ParsCommand (tAVRC_MSG *p_msg, tAVRC_COMMAND *p_result, + UINT8 *p_buf, UINT16 buf_len); /******************************************************************************* ** @@ -575,7 +576,8 @@ AVRC_API extern tAVRC_STS AVRC_ParsCommand (tAVRC_MSG *p_msg, tAVRC_COMMAND *p_r ** Otherwise, the error code defined by AVRCP 1.4 ** *******************************************************************************/ -AVRC_API extern tAVRC_STS AVRC_ParsResponse (tAVRC_MSG *p_msg, tAVRC_RESPONSE *p_result, UINT8 *p_buf, UINT16 buf_len); +AVRC_API extern tAVRC_STS AVRC_ParsResponse (tAVRC_MSG *p_msg, tAVRC_RESPONSE *p_result, + UINT8 *p_buf, UINT16 buf_len); /******************************************************************************* ** diff --git a/stack/include/bt_types.h b/stack/include/bt_types.h index 580996848..020a2810d 100644 --- a/stack/include/bt_types.h +++ b/stack/include/bt_types.h @@ -97,33 +97,34 @@ #define BT_EVT_TO_OBX_SR_L2C_MSG 0x3500 /* ftp events */ -#define BT_EVT_TO_FTP_SRVR_CMDS 0x3800 -#define BT_EVT_TO_FTP_CLNT_CMDS 0x3900 +#define BT_EVT_TO_FTP_SRVR_CMDS 0x3600 +#define BT_EVT_TO_FTP_CLNT_CMDS 0x3700 -#define BT_EVT_TO_BTU_SAP 0x3a00 /* SIM Access Profile events */ +#define BT_EVT_TO_BTU_SAP 0x3800 /* SIM Access Profile events */ /* opp events */ -#define BT_EVT_TO_OPP_SRVR_CMDS 0x3b00 -#define BT_EVT_TO_OPP_CLNT_CMDS 0x3c00 +#define BT_EVT_TO_OPP_SRVR_CMDS 0x3900 +#define BT_EVT_TO_OPP_CLNT_CMDS 0x3a00 /* gap events */ -#define BT_EVT_TO_GAP_MSG 0x3d00 +#define BT_EVT_TO_GAP_MSG 0x3b00 /* start timer */ -#define BT_EVT_TO_START_TIMER 0x3e00 +#define BT_EVT_TO_START_TIMER 0x3c00 + +/* stop timer */ +#define BT_EVT_TO_STOP_TIMER 0x3d00 /* start quick timer */ -#define BT_EVT_TO_START_QUICK_TIMER 0x3f00 +#define BT_EVT_TO_START_QUICK_TIMER 0x3e00 /* for NFC */ /************************************/ #define BT_EVT_TO_NFC_NCI 0x4000 /* NCI Command, Notification or Data*/ #define BT_EVT_TO_NFC_INIT 0x4100 /* Initialization message */ -#define BT_EVT_TO_LLCP_ECHO 0x4200 /* LLCP Echo Service */ -#define BT_EVT_TO_LLCP_SOCKET 0x4300 /* LLCP over TCP/IP */ -#define BT_EVT_TO_NCI_LP 0x4400 /* Low power */ -#define BT_EVT_TO_NFC_ERR 0x4500 /* Error notification to NFC Task */ +#define BT_EVT_TO_NCI_LP 0x4200 /* Low power */ +#define BT_EVT_TO_NFC_ERR 0x4300 /* Error notification to NFC Task */ #define BT_EVT_TO_NFCCSIM_NCI 0x4a00 /* events to NFCC simulation (NCI packets) */ @@ -330,7 +331,7 @@ typedef UINT8 EXT_INQ_RESP[EXT_INQ_RESP_LEN];/* Extended Inquiry Response */ typedef UINT8 *EXT_INQ_RESP_PTR; /* Pointer to Extended Inquiry Response */ #define BD_NAME_LEN 248 -typedef UINT8 BD_NAME[BD_NAME_LEN]; /* Device name */ +typedef UINT8 BD_NAME[BD_NAME_LEN + 1]; /* Device name */ typedef UINT8 *BD_NAME_PTR; /* Pointer to Device name */ #define BD_FEATURES_LEN 8 @@ -580,13 +581,13 @@ typedef UINT8 tBT_DEVICE_TYPE; #define TRACE_LAYER_SMP 0x00260000 #define TRACE_LAYER_NFC 0x00270000 #define TRACE_LAYER_NCI 0x00280000 -#define TRACE_LAYER_IDEP 0x00290000 -#define TRACE_LAYER_NDEP 0x002a0000 -#define TRACE_LAYER_LLCP 0x002b0000 -#define TRACE_LAYER_RW 0x002c0000 -#define TRACE_LAYER_CE 0x002d0000 +#define TRACE_LAYER_LLCP 0x00290000 +#define TRACE_LAYER_NDEF 0x002a0000 +#define TRACE_LAYER_RW 0x002b0000 +#define TRACE_LAYER_CE 0x002c0000 +#define TRACE_LAYER_P2P 0x002d0000 #define TRACE_LAYER_SNEP 0x002e0000 -#define TRACE_LAYER_NDEF 0x002f0000 +#define TRACE_LAYER_CHO 0x002f0000 #define TRACE_LAYER_NFA 0x00300000 #define TRACE_LAYER_MAX_NUM 0x0031 @@ -667,11 +668,13 @@ typedef UINT8 tBT_DEVICE_TYPE; #define SCR_PROTO_TRACE_ATT 0x00001000 #define SCR_PROTO_TRACE_SMP 0x00002000 #define SCR_PROTO_TRACE_NCI 0x00004000 -#define SCR_PROTO_TRACE_DEP 0x00008000 -#define SCR_PROTO_TRACE_LLCP 0x00010000 -#define SCR_PROTO_TRACE_NDEF 0x00020000 -#define SCR_PROTO_TRACE_TAGS 0x00040000 -#define SCR_PROTO_TRACE_ALL 0x0007ffff +#define SCR_PROTO_TRACE_LLCP 0x00008000 +#define SCR_PROTO_TRACE_NDEF 0x00010000 +#define SCR_PROTO_TRACE_RW 0x00020000 +#define SCR_PROTO_TRACE_CE 0x00040000 +#define SCR_PROTO_TRACE_SNEP 0x00080000 +#define SCR_PROTO_TRACE_CHO 0x00100000 +#define SCR_PROTO_TRACE_ALL 0x001fffff #define SCR_PROTO_TRACE_HCI_LOGGING_VSE 0x0800 /* Brcm vs event for logmsg and protocol traces */ #define MAX_SCRIPT_TYPE 5 diff --git a/stack/include/btm_api.h b/stack/include/btm_api.h index 09bb749cd..a639fa686 100644 --- a/stack/include/btm_api.h +++ b/stack/include/btm_api.h @@ -172,9 +172,11 @@ typedef UINT8 (tBTM_FILTER_CB) (BD_ADDR bd_addr, DEV_CLASS dc); /* Inquiry modes * Note: These modes are associated with the inquiry active values (BTM_*ACTIVE) */ -#define BTM_GENERAL_INQUIRY 0 -#define BTM_LIMITED_INQUIRY 1 -#define BTM_BR_INQUIRY_MASK 0x0f +#define BTM_INQUIRY_NONE 0 +#define BTM_GENERAL_INQUIRY 0x01 +#define BTM_LIMITED_INQUIRY 0x02 +#define BTM_BR_INQUIRY_MASK (BTM_GENERAL_INQUIRY | BTM_LIMITED_INQUIRY) + /* high byte of inquiry mode for BLE inquiry mode */ #define BTM_BLE_INQUIRY_NONE 0x00 #define BTM_BLE_GENERAL_INQUIRY 0x10 @@ -188,6 +190,16 @@ typedef UINT8 (tBTM_FILTER_CB) (BD_ADDR bd_addr, DEV_CLASS dc); #define BTM_LIMITED_INQUIRY_ACTIVE 0x2 /* a limited inquiry is in progress */ #define BTM_PERIODIC_INQUIRY_ACTIVE 0x8 /* a periodic inquiry is active */ #define BTM_SSP_INQUIRY_ACTIVE 0x4 /* SSP is active, so inquiry is disallowed (work around for FW bug) */ +#define BTM_LE_GENERAL_INQUIRY_ACTIVE 0x10 /* a general inquiry is in progress */ +#define BTM_LE_LIMITED_INQUIRY_ACTIVE 0x20 /* a limited inquiry is in progress */ +#define BTM_LE_SELECT_CONN_ACTIVE 0x40 /* selection connection is in progress */ +#define BTM_LE_OBSERVE_ACTIVE 0x80 /* selection connection is in progress */ + +/* inquiry activity mask */ +#define BTM_BR_INQ_ACTIVE_MASK (BTM_GENERAL_INQUIRY_ACTIVE|BTM_LIMITED_INQUIRY_ACTIVE|BTM_PERIODIC_INQUIRY_ACTIVE) /* BR/EDR inquiry activity mask */ +#define BTM_LE_SCAN_ACTIVE_MASK 0xF0 /* LE scan activity mask */ +#define BTM_LE_INQ_ACTIVE_MASK (BTM_LE_GENERAL_INQUIRY_ACTIVE|BTM_LE_LIMITED_INQUIRY_ACTIVE) /* LE inquiry activity mask*/ +#define BTM_INQUIRY_ACTIVE_MASK (BTM_BR_INQ_ACTIVE_MASK | BTM_LE_INQ_ACTIVE_MASK) /* inquiry activity mask */ /* Define scan types */ #define BTM_SCAN_TYPE_STANDARD 0 @@ -825,8 +837,9 @@ typedef struct typedef struct { tBTM_BL_EVENT event; /* The event reported. */ - UINT8 busy_level;/* when paging or inquiring, level is as above. + UINT8 busy_level;/* when paging or inquiring, level is 10. * Otherwise, the number of ACL links. */ + UINT8 busy_level_flags; /* Notifies actual inquiry/page activities */ } tBTM_BL_UPDATE_DATA; /* the data type associated with BTM_BL_ROLE_CHG_EVT */ @@ -877,6 +890,9 @@ typedef void (tBTM_ACL_DB_CHANGE_CB) (BD_ADDR p_bda, DEV_CLASS p_dc, /* Define an invalid SCO disconnect reason */ #define BTM_INVALID_SCO_DISC_REASON 0xFFFF +/* Define first active SCO index */ +#define BTM_FIRST_ACTIVE_SCO_INDEX BTM_MAX_SCO_LINKS + /* Define SCO packet types used in APIs */ #define BTM_SCO_PKT_TYPES_MASK_HV1 HCI_ESCO_PKT_TYPES_MASK_HV1 #define BTM_SCO_PKT_TYPES_MASK_HV2 HCI_ESCO_PKT_TYPES_MASK_HV2 @@ -929,6 +945,17 @@ typedef UINT8 tBTM_SCO_ROUTE_TYPE; #define BTM_SCO_CODEC_MSBC 0x0002 typedef UINT16 tBTM_SCO_CODEC_TYPE; + + +/******************* +** SCO Air Mode Types +********************/ +#define BTM_SCO_AIR_MODE_U_LAW 0 +#define BTM_SCO_AIR_MODE_A_LAW 1 +#define BTM_SCO_AIR_MODE_CVSD 2 +#define BTM_SCO_AIR_MODE_TRANSPNT 3 +typedef UINT8 tBTM_SCO_AIR_MODE_TYPE; + /******************* ** SCO Voice Settings ********************/ @@ -1198,11 +1225,11 @@ typedef void (tBTM_ESCO_CBACK) (tBTM_ESCO_EVT event, tBTM_ESCO_EVT_DATA *p_data) (UINT32)(((UINT32)1 << (((UINT32)(service)) % BTM_SEC_ARRAY_BITS)))) ? TRUE : FALSE) /* MACRO to copy two trusted device bitmask */ -#define BTM_SEC_COPY_TRUSTED_DEVICE(p_src, p_dst) {int trst; for (trst = 0; trst < BTM_SEC_SERVICE_ARRAY_SIZE; trst++) \ +#define BTM_SEC_COPY_TRUSTED_DEVICE(p_src, p_dst) {UINT32 trst; for (trst = 0; trst < BTM_SEC_SERVICE_ARRAY_SIZE; trst++) \ ((UINT32 *)(p_dst))[trst] = ((UINT32 *)(p_src))[trst];} /* MACRO to clear two trusted device bitmask */ -#define BTM_SEC_CLR_TRUSTED_DEVICE(p_dst) {int trst; for (trst = 0; trst < BTM_SEC_SERVICE_ARRAY_SIZE; trst++) \ +#define BTM_SEC_CLR_TRUSTED_DEVICE(p_dst) {UINT32 trst; for (trst = 0; trst < BTM_SEC_SERVICE_ARRAY_SIZE; trst++) \ ((UINT32 *)(p_dst))[trst] = 0;} /* Following bits can be provided by host in the trusted_mask array */ @@ -1556,8 +1583,8 @@ typedef UINT8 tBTM_LE_AUTH_REQ; /* LE security level */ #define BTM_LE_SEC_NONE SMP_SEC_NONE -#define BTM_LE_SEC_UNAUTHENTICATE SMP_SEC_UNAUTHENTICATE -#define BTM_LE_SEC_AUTHENTICATED SMP_SEC_AUTHENTICATED +#define BTM_LE_SEC_UNAUTHENTICATE SMP_SEC_UNAUTHENTICATE /* 1 */ +#define BTM_LE_SEC_AUTHENTICATED SMP_SEC_AUTHENTICATED /* 4 */ typedef UINT8 tBTM_LE_SEC; @@ -1577,6 +1604,8 @@ typedef struct { UINT8 reason; UINT8 sec_level; + BOOLEAN privacy_supported; + BOOLEAN is_pair_cancel; }tBTM_LE_COMPLT; #endif @@ -1615,12 +1644,18 @@ typedef struct }tBTM_LE_LCSRK_KEYS; +typedef struct +{ + BT_OCTET16 irk; + tBLE_ADDR_TYPE addr_type; + BD_ADDR static_addr; +}tBTM_LE_PID_KEYS; typedef union { tBTM_LE_PENC_KEYS penc_key; /* received peer encryption key */ - tBTM_LE_PCSRK_KEYS pcsrk_key; /* received peer device SRK */ - BT_OCTET16 pid_key; /* peer device ID key */ + tBTM_LE_PCSRK_KEYS pcsrk_key; /* received peer device SRK */ + tBTM_LE_PID_KEYS pid_key; /* peer device ID key */ tBTM_LE_LENC_KEYS lenc_key; /* local encryption reproduction keys LTK = = d1(ER,DIV,0)*/ tBTM_LE_LCSRK_KEYS lcsrk_key; /* local device CSRK = d1(ER,DIV,1)*/ }tBTM_LE_KEY_VALUE; @@ -2907,6 +2942,17 @@ BTM_API extern BOOLEAN BTM_TryAllocateSCN(UINT8 scn); *******************************************************************************/ BTM_API extern tBTM_STATUS BTM_SetLinkSuperTout (BD_ADDR remote_bda, UINT16 timeout); +/******************************************************************************* +** +** Function BTM_GetLinkSuperTout +** +** Description Read the link supervision timeout value of the connection +** +** Returns status of the operation +** +*******************************************************************************/ + BTM_API extern tBTM_STATUS BTM_GetLinkSuperTout (BD_ADDR remote_bda, + UINT16 *p_timeout); /******************************************************************************* ** @@ -3415,6 +3461,11 @@ BTM_API extern tBTM_STATUS BTM_SetWBSCodec (tBTM_SCO_CODEC_TYPE codec_type); ** is active, but is typically called after receiving the SCO ** opened callback. ** +** Note: If called over a 1.1 controller, only the packet types +** field has meaning. +** Note: If the upper layer doesn't know the current sco index, +** BTM_FIRST_ACTIVE_SCO_INDEX can be used as the first parameter to +** find the first active SCO index ** ** Returns BTM_SUCCESS if returned data is valid connection. ** BTM_ILLEGAL_VALUE if no connection for specified sco_inx. @@ -4450,27 +4501,6 @@ BTM_API extern tBTM_STATUS BTM_SetWBSCodec (tBTM_SCO_CODEC_TYPE codec_type); *******************************************************************************/ BTM_API extern void BTM_N2BtDisconnect(void); - -/******************************************************************************* -** -** Function BTM_ConfigI2SPCM -** -** Description This function sends VSC Write_I2SPCM_Interface_Param -** as to the specified codec_type. -** -** -** Parameter codec_type: codec_type to be used for sco connection. -** role: master or slave role -** sample_rate: sampling rate -** clock_rate:clock rate 128K to 2048K -** -** -** Returns BTM_SUCCESS if the successful. -** BTM_ILLEGAL_VALUE: wrong codec type -** -*******************************************************************************/ - BTM_API extern tBTM_STATUS BTM_ConfigI2SPCM (tBTM_SCO_CODEC_TYPE codec_type, UINT8 role, UINT8 sample_rate, UINT8 clock_rate); - /***************************************************************************** ** SCO OVER HCI *****************************************************************************/ diff --git a/stack/include/btm_ble_api.h b/stack/include/btm_ble_api.h index 8456b9f6c..b86968d71 100644 --- a/stack/include/btm_ble_api.h +++ b/stack/include/btm_ble_api.h @@ -30,6 +30,16 @@ #define CHNL_MAP_LEN 5 typedef UINT8 tBTM_BLE_CHNL_MAP[CHNL_MAP_LEN]; +#define BTM_BLE_CONNECT_EVT 0x00 +#define BTM_BLE_CONNECT_DIR_EVT 0x01 +#define BTM_BLE_DISCOVER_EVT 0x02 +#define BTM_BLE_NON_CONNECT_EVT 0x03 +#define BTM_BLE_SCAN_RSP_EVT 0x04 +#define BTM_BLE_SCAN_REQ_EVT 0x06 +#define BTM_BLE_UNKNOWN_EVT 0xff + +#define BTM_BLE_UNKNOWN_EVT 0xff + #define BTM_BLE_SCAN_MODE_PASS 0 #define BTM_BLE_SCAN_MODE_ACTI 1 #define BTM_BLE_SCAN_MODE_NONE 0xff @@ -72,7 +82,7 @@ typedef UINT8 tBTM_BLE_SFP; #define BTM_BLE_ADV_INT_MIN 0x0020 #define BTM_BLE_ADV_INT_MAX 0x4000 -/* connection parameter boundary value */ +/* connection parameter boundary values */ #define BTM_BLE_SCAN_INT_MIN 0x0004 #define BTM_BLE_SCAN_INT_MAX 0x4000 #define BTM_BLE_SCAN_WIN_MIN 0x0004 @@ -83,32 +93,41 @@ typedef UINT8 tBTM_BLE_SFP; #define BTM_BLE_CONN_SUP_TOUT_MIN 0x000A #define BTM_BLE_CONN_SUP_TOUT_MAX 0x0C80 #define BTM_BLE_CONN_PARAM_UNDEF 0xffff /* use this value when a specific value not to be overwritten */ +#define BTM_BLE_CONN_SUP_TOUT_DEF 700 /* default connection parameters if not configured, use GAP recommend value for auto/selective connection */ /* default scan interval */ -#ifndef BTM_BLE_CONN_EST_SCAN_INT -#define BTM_BLE_CONN_EST_SCAN_INT 96 /* 312.5 ms = 500 *0.625 */ +#ifndef BTM_BLE_SCAN_FAST_INT +#define BTM_BLE_SCAN_FAST_INT 96 /* 30 ~ 60 ms (use 60) = 96 *0.625 */ #endif /* default scan window for background connection, applicable for auto connection or selective conenction */ -#ifndef BTM_BLE_CONN_EST_SCAN_WIND -#define BTM_BLE_CONN_EST_SCAN_WIND 48 /* 187.5 ms = 400 *0.625 */ +#ifndef BTM_BLE_SCAN_FAST_WIN +#define BTM_BLE_SCAN_FAST_WIN 48 /* 30 ms = 48 *0.625 */ +#endif + +/* default scan paramter used in reduced power cycle (background scanning) */ +#ifndef BTM_BLE_SCAN_SLOW_INT_1 +#define BTM_BLE_SCAN_SLOW_INT_1 2048 /* 1.28 s = 2048 *0.625 */ +#endif +#ifndef BTM_BLE_SCAN_SLOW_WIN_1 +#define BTM_BLE_SCAN_SLOW_WIN_1 18 /* 11.25 ms = 18 *0.625 */ #endif -/* default scan paramter used in reduced power cycle */ -#ifndef BTM_BLE_CONN_EST_SCAN_INT_LO -#define BTM_BLE_CONN_EST_SCAN_INT_LO 2048 /* 1.28 s = 500 *0.625 */ +/* default scan paramter used in reduced power cycle (background scanning) */ +#ifndef BTM_BLE_SCAN_SLOW_INT_2 +#define BTM_BLE_SCAN_SLOW_INT_2 4096 /* 2.56 s = 4096 *0.625 */ #endif -#ifndef BTM_BLE_CONN_EST_SCAN_WIND_LO -#define BTM_BLE_CONN_EST_SCAN_WIND_LO 18 /* 11.25 ms = 400 *0.625 */ +#ifndef BTM_BLE_SCAN_SLOW_WIN_2 +#define BTM_BLE_SCAN_SLOW_WIN_2 36 /* 22.5 ms = 36 *0.625 */ #endif /* default connection interval min */ #ifndef BTM_BLE_CONN_INT_MIN_DEF -#define BTM_BLE_CONN_INT_MIN_DEF 40 /* 50ms = 400 * 1.25 */ +#define BTM_BLE_CONN_INT_MIN_DEF 24 /* recommended min: 30ms = 24 * 1.25 */ #endif /* default connectino interval max */ #ifndef BTM_BLE_CONN_INT_MAX_DEF -#define BTM_BLE_CONN_INT_MAX_DEF 56 /* 70ms = 56 * 1.25 */ +#define BTM_BLE_CONN_INT_MAX_DEF 40 /* recommended max: 50 ms = 56 * 1.25 */ #endif /* default slave latency */ #ifndef BTM_BLE_CONN_SLAVE_LATENCY_DEF @@ -119,10 +138,25 @@ typedef UINT8 tBTM_BLE_SFP; #define BTM_BLE_CONN_TIMEOUT_DEF 2000 #endif +#define BTM_BLE_DIR_CONN_FALLBACK_UNDIR 1 +#define BTM_BLE_DIR_CONN_FALLBACK_NO_ADV 2 + +#ifndef BTM_BLE_DIR_CONN_FALLBACK +#define BTM_BLE_DIR_CONN_FALLBACK BTM_BLE_DIR_CONN_FALLBACK_UNDIR +#endif + #define BTM_CMAC_TLEN_SIZE 8 /* 64 bits */ #define BTM_BLE_AUTH_SIGN_LEN 12 /* BLE data signature length 8 Bytes + 4 bytes counter*/ typedef UINT8 BLE_SIGNATURE[BTM_BLE_AUTH_SIGN_LEN]; /* Device address */ +#ifndef BTM_BLE_HOST_SUPPORT +#define BTM_BLE_HOST_SUPPORT 0x01 +#endif + +#ifndef BTM_BLE_SIMULTANEOUS_HOST +#define BTM_BLE_SIMULTANEOUS_HOST 0x01 +#endif + /* Structure returned with Rand/Encrypt complete callback */ typedef struct { @@ -165,27 +199,41 @@ typedef struct #define BTM_BLE_AD_BIT_FLAGS (0x0001 << 1) #define BTM_BLE_AD_BIT_MANU (0x0001 << 2) #define BTM_BLE_AD_BIT_TX_PWR (0x0001 << 3) -#define BTM_BLE_AD_BIT_ATTR (0x0001 << 4) #define BTM_BLE_AD_BIT_INT_RANGE (0x0001 << 5) #define BTM_BLE_AD_BIT_SERVICE (0x0001 << 6) #define BTM_BLE_AD_BIT_SERVICE_SOL (0x0001 << 7) #define BTM_BLE_AD_BIT_SERVICE_DATA (0x0001 << 8) #define BTM_BLE_AD_BIT_SIGN_DATA (0x0001 << 9) +#define BTM_BLE_AD_BIT_SERVICE_128SOL (0x0001 << 10) +#define BTM_BLE_AD_BIT_APPEARANCE (0x0001 << 11) +#define BTM_BLE_AD_BIT_PUBLIC_ADDR (0x0001 << 12) +#define BTM_BLE_AD_BIT_RANDOM_ADDR (0x0001 << 13) + #define BTM_BLE_AD_BIT_PROPRIETARY (0x0001 << 15) typedef UINT16 tBTM_BLE_AD_MASK; -#define BTM_BLE_AD_TYPE_FLAG 0x01 -#define BTM_BLE_AD_TYPE_SRV_PART 0x02 -#define BTM_BLE_AD_TYPE_SRV_CMPL 0x03 -#define BTM_BLE_AD_TYPE_NAME_SHORT 0x08 -#define BTM_BLE_AD_TYPE_NAME_CMPL 0x09 -#define BTM_BLE_AD_TYPE_TX_PWR 0x0A +#define BTM_BLE_AD_TYPE_FLAG HCI_EIR_FLAGS_TYPE /* 0x01 */ +#define BTM_BLE_AD_TYPE_16SRV_PART HCI_EIR_MORE_16BITS_UUID_TYPE /* 0x02 */ +#define BTM_BLE_AD_TYPE_16SRV_CMPL HCI_EIR_COMPLETE_16BITS_UUID_TYPE /* 0x03 */ +#define BTM_BLE_AD_TYPE_32SRV_PART HCI_EIR_MORE_32BITS_UUID_TYPE /* 0x04 */ +#define BTM_BLE_AD_TYPE_32SRV_CMPL HCI_EIR_COMPLETE_32BITS_UUID_TYPE /* 0x05 */ +#define BTM_BLE_AD_TYPE_128SRV_PART HCI_EIR_MORE_128BITS_UUID_TYPE /* 0x06 */ +#define BTM_BLE_AD_TYPE_128SRV_CMPL HCI_EIR_COMPLETE_128BITS_UUID_TYPE /* 0x07 */ +#define BTM_BLE_AD_TYPE_NAME_SHORT HCI_EIR_SHORTENED_LOCAL_NAME_TYPE /* 0x08 */ +#define BTM_BLE_AD_TYPE_NAME_CMPL HCI_EIR_COMPLETE_LOCAL_NAME_TYPE /* 0x09 */ +#define BTM_BLE_AD_TYPE_TX_PWR HCI_EIR_TX_POWER_LEVEL_TYPE /* 0x0A */ #define BTM_BLE_AD_TYPE_DEV_CLASS 0x0D -#define BTM_BLE_AD_TYPE_ATTR 0x10 -#define BTM_BLE_AD_TYPE_MANU 0xff +#define BTM_BLE_AD_TYPE_SM_TK 0x10 +#define BTM_BLE_AD_TYPE_SM_OOB_FLAG 0x11 #define BTM_BLE_AD_TYPE_INT_RANGE 0x12 #define BTM_BLE_AD_TYPE_SOL_SRV_UUID 0x14 +#define BTM_BLE_AD_TYPE_128SOL_SRV_UUID 0x15 +#define BTM_BLE_AD_TYPE_SERVICE_DATA 0x16 +#define BTM_BLE_AD_TYPE_PUBLIC_TARGET 0x17 +#define BTM_BLE_AD_TYPE_RANDOM_TARGET 0x18 +#define BTM_BLE_AD_TYPE_APPEARANCE 0x19 +#define BTM_BLE_AD_TYPE_MANU HCI_EIR_MANUFACTURER_SPECIFIC_TYPE /* 0xff */ typedef UINT8 tBTM_BLE_AD_TYPE; /* slave preferred connection interval range */ @@ -204,24 +252,6 @@ typedef struct UINT16 *p_uuid; }tBTM_BLE_SERVICE; -/* attribute data */ -typedef struct -{ - UINT16 uuid; - UINT16 data_len; - UINT8 *p_data; -}tBTM_BLE_ATTR; - -#ifndef BTM_BLE_NUM_AD_ATTR_MAX -#define BTM_BLE_NUM_AD_ATTR_MAX 10 -#endif -/* attribute list contained in adv data */ -typedef struct -{ - UINT8 num_attr; - tBTM_BLE_ATTR attr_list[BTM_BLE_NUM_AD_ATTR_MAX]; -}tBTM_BLE_ATTR_DATA; - typedef struct { UINT8 len; @@ -243,11 +273,11 @@ typedef struct typedef struct { - tBTM_BLE_MANU manu; /* manufactuer data */ + tBTM_BLE_MANU manu; /* manufactuer data */ tBTM_BLE_INT_RANGE int_range; /* slave prefered conn interval range */ tBTM_BLE_SERVICE services; /* services */ - tBTM_BLE_ATTR_DATA attr; /* attribute data */ UINT8 flag; + UINT16 appearance; tBTM_BLE_PROPRIETARY *p_proprietary; }tBTM_BLE_ADV_DATA; @@ -262,7 +292,6 @@ typedef struct UINT8 tx_power_level; UINT8 remote_name_len; UINT8 *p_remote_name; - tBTM_BLE_ATTR_DATA attr_data; tBTM_BLE_SERVICE service; } tBTM_BLE_INQ_DATA; @@ -283,6 +312,7 @@ typedef void (tBTM_BLE_VERIFY_CBACK)(void *p_ref_data, BOOLEAN match); typedef void (tBTM_BLE_RANDOM_SET_CBACK) (BD_ADDR random_bda); typedef void (tBTM_BLE_SCAN_REQ_CBACK)(BD_ADDR remote_bda, tBLE_ADDR_TYPE addr_type, UINT8 adv_evt); + /***************************************************************************** ** EXTERNAL FUNCTION DECLARATIONS *****************************************************************************/ @@ -554,7 +584,7 @@ BTM_API extern BOOLEAN BTM_BleVerifySignature (BD_ADDR bd_addr, UINT8 *p_orig, /******************************************************************************* ** -** Function BTM_SetRandomAddr +** Function BTM_ReadConnectionAddr ** ** Description This function is called to set the local device random address ** . @@ -562,19 +592,24 @@ BTM_API extern BOOLEAN BTM_BleVerifySignature (BD_ADDR bd_addr, UINT8 *p_orig, ** Returns void ** *******************************************************************************/ -BTM_API extern void BTM_SetRandomAddr (tBTM_BLE_RANDOM_SET_CBACK *p_cback); +BTM_API extern void BTM_ReadConnectionAddr (BD_ADDR remote_bda, BD_ADDR local_conn_addr, + tBLE_ADDR_TYPE *p_addr_type); + + /******************************************************************************* ** -** Function BTM_ReadConnectionAddr +** Function BTM_ReadRemoteConnectionAddr ** -** Description This function is called to set the local device random address +** Description This function is read the remote device address currently used ** . ** ** Returns void ** *******************************************************************************/ -BTM_API extern void BTM_ReadConnectionAddr (BD_ADDR conn_addr); +BTM_API extern BOOLEAN BTM_ReadRemoteConnectionAddr(BD_ADDR pseudo_addr, + BD_ADDR conn_addr, + tBLE_ADDR_TYPE *p_addr_type); /******************************************************************************* ** @@ -721,7 +756,113 @@ BTM_API extern tBTM_STATUS BTM_BleBroadcast(BOOLEAN start); *******************************************************************************/ BTM_API extern void BTM_RegisterScanReqEvt(tBTM_BLE_SCAN_REQ_CBACK *p_scan_req_cback); +/******************************************************************************* +** +** Function BTM_BleConfigPrivacy +** +** Description This function is called to enable or disable the privacy in +** the local device. +** +** Parameters enable: TRUE to enable it; FALSE to disable it. +** +** Returns void +** +*******************************************************************************/ +BTM_API extern void BTM_BleConfigPrivacy(BOOLEAN enable); + +/******************************************************************************* +** +** Function BTM_BleSetConnMode +** +** Description This function is called to set BLE connectable mode for a +** peripheral device. +** +** Parameters directed: is directed connectable mode, or non-directed. +** p_dir_bda: connectable direct initiator's LE device address +** +** Returns void +** +*******************************************************************************/ +BTM_API extern tBTM_STATUS BTM_BleSetConnMode(BOOLEAN directed); + +/******************************************************************************* +** +** Function BTM_BleTurnOnPrivacyOnRemote +** +** Description This function is called to enable or disable the privacy on the +** remote device. +** +** Parameters bd_addr: remote device address. +** privacy_on: TRUE to enable it; FALSE to disable it. +** +** Returns void +** +*******************************************************************************/ +BTM_API extern void BTM_BleTurnOnPrivacyOnRemote(BD_ADDR bd_addr, + BOOLEAN privacy_on); + +/******************************************************************************* +** +** Function BTM_BleUpdateAdvWhitelist +** +** Description Add or remove device from advertising white list +** +** Returns void +** +*******************************************************************************/ +BTM_API extern BOOLEAN BTM_BleUpdateAdvWhitelist(BOOLEAN add_remove, BD_ADDR emote_bda); + +/******************************************************************************* +** +** Function BTM_BleUpdateAdvFilterPolicy +** +** Description This function update the filter policy of advertiser. +** +** Parameter adv_policy: advertising filter policy +** +** Return void +*******************************************************************************/ +BTM_API extern void BTM_BleUpdateAdvFilterPolicy(tBTM_BLE_AFP adv_policy); + +/******************************************************************************* +** +** Function BTM_BleReceiverTest +** +** Description This function is called to start the LE Receiver test +** +** Parameter rx_freq - Frequency Range +** p_cmd_cmpl_cback - Command Complete callback +** +*******************************************************************************/ +void BTM_BleReceiverTest(UINT8 rx_freq, tBTM_CMPL_CB *p_cmd_cmpl_cback); + + +/******************************************************************************* +** +** Function BTM_BleTransmitterTest +** +** Description This function is called to start the LE Transmitter test +** +** Parameter tx_freq - Frequency Range +** test_data_len - Length in bytes of payload data in each packet +** packet_payload - Pattern to use in the payload +** p_cmd_cmpl_cback - Command Complete callback +** +*******************************************************************************/ +void BTM_BleTransmitterTest(UINT8 tx_freq, UINT8 test_data_len, + UINT8 packet_payload, tBTM_CMPL_CB *p_cmd_cmpl_cback); + +/******************************************************************************* +** +** Function BTM_BleTestEnd +** +** Description This function is called to stop the in-progress TX or RX test +** +** Parameter p_cmd_cmpl_cback - Command complete callback +** +*******************************************************************************/ +void BTM_BleTestEnd(tBTM_CMPL_CB *p_cmd_cmpl_cback); #ifdef __cplusplus } #endif diff --git a/stack/include/btu.h b/stack/include/btu.h index d33f0bb38..4f0e1622c 100644 --- a/stack/include/btu.h +++ b/stack/include/btu.h @@ -152,7 +152,11 @@ typedef void (*tBTU_EVENT_CALLBACK)(BT_HDR *p_hdr); #define BTU_TTYPE_BLE_RANDOM_ADDR 103 #define BTU_TTYPE_ATT_WAIT_FOR_APP_RSP 104 #define BTU_TTYPE_ATT_WAIT_FOR_IND_ACK 105 -#define BTU_TTYPE_BLE_SCAN_PARAM_IDLE 106 + +#define BTU_TTYPE_UCD_TO 106 + +/* BTU timer event for TBFC */ +#define BTU_TTYPE_TBFC_RESUME 107 /* Define the BTU_TASK APPL events */ diff --git a/stack/include/gap_api.h b/stack/include/gap_api.h new file mode 100644 index 000000000..05affed7e --- /dev/null +++ b/stack/include/gap_api.h @@ -0,0 +1,802 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2013 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#ifndef GAP_API_H +#define GAP_API_H + +#include "profiles_api.h" +#include "btm_api.h" +#include "l2c_api.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + +/*** GAP Error and Status Codes ***/ +#define GAP_UNSUPPORTED (GAP_ERR_GRP + 0x01) /* Unsupported call */ +#define GAP_EOINQDB (GAP_ERR_GRP + 0x02) /* End of inquiry database marker */ +#define GAP_ERR_BUSY (GAP_ERR_GRP + 0x03) /* The requested function was busy */ +#define GAP_ERR_NO_CTRL_BLK (GAP_ERR_GRP + 0x04) /* No control blocks available */ +#define GAP_ERR_STARTING_CMD (GAP_ERR_GRP + 0x05) /* Error occurred while initiating the command */ +#define GAP_NO_BDADDR_REC (GAP_ERR_GRP + 0x06) /* No Inquiry DB record for BD_ADDR */ +#define GAP_ERR_ILL_MODE (GAP_ERR_GRP + 0x07) /* An illegal mode parameter was detected */ +#define GAP_ERR_ILL_INQ_TIME (GAP_ERR_GRP + 0x08) /* An illegal time parameter was detected */ +#define GAP_ERR_ILL_PARM (GAP_ERR_GRP + 0x09) /* An illegal parameter was detected */ +#define GAP_ERR_REM_NAME (GAP_ERR_GRP + 0x0a) /* Error starting the remote device name request */ +#define GAP_CMD_INITIATED (GAP_ERR_GRP + 0x0b) /* The GAP command was started (result pending) */ +#define GAP_DEVICE_NOT_UP (GAP_ERR_GRP + 0x0c) /* The device was not up; the request was not executed */ +#define GAP_BAD_BD_ADDR (GAP_ERR_GRP + 0x0d) /* The bd addr passed in was not found or invalid */ + +#define GAP_ERR_BAD_HANDLE (GAP_ERR_GRP + 0x0e) /* Bad GAP handle */ +#define GAP_ERR_BUF_OFFSET (GAP_ERR_GRP + 0x0f) /* Buffer offset invalid */ +#define GAP_ERR_BAD_STATE (GAP_ERR_GRP + 0x10) /* Connection is in invalid state */ +#define GAP_NO_DATA_AVAIL (GAP_ERR_GRP + 0x11) /* No data available */ +#define GAP_ERR_CONGESTED (GAP_ERR_GRP + 0x12) /* BT stack is congested */ +#define GAP_ERR_SECURITY (GAP_ERR_GRP + 0x13) /* Security failed */ + +#define GAP_ERR_PROCESSING (GAP_ERR_GRP + 0x14) /* General error processing BTM request */ +#define GAP_ERR_TIMEOUT (GAP_ERR_GRP + 0x15) /* Timeout occurred while processing cmd */ + +/** GAP Events - definitions of GAP return events ***/ +#define GAP_EVT_INQUIRY_RESULTS 0x0001 +#define GAP_EVT_INQUIRY_COMPLETE 0x0002 +#define GAP_EVT_DISCOVERY_COMPLETE 0x0003 +#define GAP_EVT_REM_NAME_COMPLETE 0x0004 +#define GAP_EVT_FIND_ADDR_COMPLETE 0x0005 + +#define GAP_EVT_CONN_OPENED 0x0100 +#define GAP_EVT_CONN_CLOSED 0x0101 +#define GAP_EVT_CONN_DATA_AVAIL 0x0102 +#define GAP_EVT_CONN_CONGESTED 0x0103 +#define GAP_EVT_CONN_UNCONGESTED 0x0104 + +/* Values for 'chan_mode_mask' field */ +/* GAP_ConnOpen() - optional channels to negotiate */ +#define GAP_FCR_CHAN_OPT_BASIC L2CAP_FCR_CHAN_OPT_BASIC +#define GAP_FCR_CHAN_OPT_ERTM L2CAP_FCR_CHAN_OPT_ERTM +#define GAP_FCR_CHAN_OPT_STREAM L2CAP_FCR_CHAN_OPT_STREAM + +/*** discovery of devices ***/ +#define GAP_INQUIRY_NONE BTM_INQUIRY_NONE +#define GAP_GENERAL_INQUIRY BTM_GENERAL_INQUIRY +#define GAP_LIMITED_INQUIRY BTM_LIMITED_INQUIRY + +#if BLE_INCLUDED == TRUE +#define GAP_BLE_INQUIRY_NONE BTM_BLE_INQUIRY_NONE +#define GAP_BLE_GENERAL_INQUIRY BTM_BLE_GENERAL_INQUIRY +#define GAP_BLE_LIMITED_INQUIRY BTM_BLE_LIMITED_INQUIRY +#endif + +/*** discoverable modes ***/ +#define GAP_NON_DISCOVERABLE BTM_NON_DISCOVERABLE +#define GAP_LIMITED_DISCOVERABLE BTM_LIMITED_DISCOVERABLE +#define GAP_GENERAL_DISCOVERABLE BTM_GENERAL_DISCOVERABLE + +/*** Inquiry Filter Condition types (The values are defined in btm_api.h) ***/ +#define GAP_CLR_INQUIRY_FILTER BTM_CLR_INQUIRY_FILTER /* Inquiry Filtering is turned off */ +#define GAP_FILTER_COND_DEVICE_CLASS BTM_FILTER_COND_DEVICE_CLASS /* Filter on device class */ +#define GAP_FILTER_COND_BD_ADDR BTM_FILTER_COND_BD_ADDR /* Filter on device addr */ + +/*** connectability ***/ +#define GAP_NON_CONNECTABLE BTM_NON_CONNECTABLE +#define GAP_CONNECTABLE BTM_CONNECTABLE + +/*** security features ***/ +#define GAP_DISALLOW_PAIRING 0 +#define GAP_ALLOW_PAIRING 1 + +/*** class of device settings ***/ +#define GAP_SET_COD_MAJOR_MINOR 0x01 +#define GAP_SET_COD_SERVICE_CLASS 0x02 /* only set the bits in the input */ +#define GAP_CLR_COD_SERVICE_CLASS 0x04 +#define GAP_SET_COD_ALL 0x08 /* take service class as the input (may clear some set bits!!) */ +#define GAP_INIT_COD 0x0a + +/*** used in connection variables and functions ***/ +#define GAP_INVALID_HANDLE 0xFFFF + +/* This is used to change the criteria for AMP */ +#define GAP_PROTOCOL_ID (UUID_PROTOCOL_UDP) + +/* slave preferred parameter, minimum connection interval */ +#ifndef GAP_SL_CONN_INT_MIN +#define GAP_SL_CONN_INT_MIN 6 +#endif +/* slave preferred parameter, maximum connection interval */ +#ifndef GAP_SL_CONN_INT_MAX +#define GAP_SL_CONN_INT_MAX 20 +#endif +/* slave preferred parameter */ +#ifndef GAP_SL_LATENCY +#define GAP_SL_LATENCY 2 +#endif + +#ifndef GAP_BLE_PRIVACY_RECONN_ADDR_PERM +#define GAP_BLE_PRIVACY_RECONN_ADDR_PERM (GATT_PERM_READ|GATT_PERM_WRITE) +#endif + +#ifndef GAP_PREFER_CONN_INT_MAX +#define GAP_PREFER_CONN_INT_MAX BTM_BLE_CONN_INT_MIN +#endif + +#ifndef GAP_PREFER_CONN_INT_MIN +#define GAP_PREFER_CONN_INT_MIN BTM_BLE_CONN_INT_MIN +#endif + +#ifndef GAP_PREFER_CONN_LATENCY +#define GAP_PREFER_CONN_LATENCY 0 +#endif + +#ifndef GAP_PREFER_CONN_SP_TOUT +#define GAP_PREFER_CONN_SP_TOUT 2000 +#endif + +#if BLE_INCLUDED == TRUE +#ifndef GAP_TRANSPORT_SUPPORTED +#define GAP_TRANSPORT_SUPPORTED GATT_TRANSPORT_LE_BR_EDR +#endif +#endif +/***************************************************************************** +** Type Definitions +*****************************************************************************/ +/* +** Callback function for connection services +*/ +typedef void (tGAP_CONN_CALLBACK) (UINT16 gap_handle, UINT16 event); + +/* +** Define the callback function prototypes. Parameters are specific +** to each event and are described below +*/ +typedef void (tGAP_CALLBACK) (UINT16 event, void *p_data); + +typedef tBTM_REMOTE_DEV_NAME tGAP_REMOTE_DEV_NAME; /* see btm_api.h */ +typedef tBTM_INQ_PARMS tGAP_INQ_PARMS; /* see btm_api.h */ +typedef tBTM_INQ_RESULTS tGAP_INQ_RESULTS; /* see btm_api.h */ + +/* Inquiry results structure */ +typedef struct +{ + UINT16 status; + UINT8 num_results; +} tGAP_INQ_CMPL; + +/* Definition of the GAP_FindAddrByName results structure */ +typedef struct +{ + UINT16 status; + BD_ADDR bd_addr; + tBTM_BD_NAME devname; +} tGAP_FINDADDR_RESULTS; + +/** for GAP_SetDeviceClass() **/ +/* Define Class of Device related values + * + * >>> changes to this type need to also be made to tHSP_COD in hsp2_int.h + */ +typedef struct +{ + UINT8 minor; + UINT8 major; + UINT16 service; +} tGAP_COD; + +/*** Constants and functions for device features ***/ +typedef struct +{ + UINT8 lmp_version; + UINT16 mfc_name; + UINT16 lmp_subversion; +} tGAP_LMP_VERSION; + +typedef struct +{ + UINT8 lmp_features[8]; +} tGAP_LMP_FEATURES; + +typedef struct +{ + UINT16 int_min; + UINT16 int_max; + UINT16 latency; + UINT16 sp_tout; +}tGAP_BLE_PREF_PARAM; + +typedef union +{ + tGAP_BLE_PREF_PARAM conn_param; + BD_ADDR reconn_bda; + UINT16 icon; + UINT8 *p_dev_name; + UINT8 privacy; + +}tGAP_BLE_ATTR_VALUE; + +typedef void (tGAP_BLE_DEV_NAME_CBACK)(BOOLEAN status, BD_ADDR addr, UINT16 length, char *p_name); + +typedef void (tGAP_BLE_RECONN_ADDR_CBACK)(BOOLEAN status, BD_ADDR addr, BD_ADDR reconn_bda); + +/***************************************************************************** +** External Function Declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************************* +** +** Function GAP_SetDiscoverableMode +** +** Description This function is called to allow or disallow a service to +** discovered (Inquiry Scans). +** +** Returns BT_PASS (0) if successful, +** GAP_ERR_ILL_PARM if a bad parameter is detected, +** GAP_DEVICE_NOT_UP if the device is not active, +** GAP_ERR_PROCESSING if not enough resources to carry out request +** +*******************************************************************************/ +GAP_API extern UINT16 GAP_SetDiscoverableMode (UINT16 mode, UINT16 duration, + UINT16 interval); + +/******************************************************************************* +** +** Function GAP_ReadDiscoverableMode +** +** Description This function is called to retrieve the current discoverable +** mode for the local device. +** +** Returns GAP_NON_DISCOVERABLE, GAP_LIMITED_DISCOVERABLE, or +** GAP_GENERAL_DISCOVERABLE +** +*******************************************************************************/ +GAP_API extern UINT16 GAP_ReadDiscoverableMode (UINT16 *duration, UINT16 *interval); + +/******************************************************************************* +** +** Function GAP_StartInquiry +** +** Description This function initiates a single inquiry. +** +** Returns BT_PASS (0) if successful, +** GAP_ERR_ILL_MODE if a bad mode parameter was passed +** GAP_ERR_ILL_INQ_TIME if a bad interval or duration was passed +** GAP_ERR_NO_CTRL_BLK if out of control blocks +** GAP_ERR_ILL_PARM if a bad parameter was detected in BTM +** GAP_ERR_BUSY if the device already has an iquiry active +** GAP_DEVICE_NOT_UP if the device is not initialized yet +** GAP_ERR_PROCESSING if any other BTM error was returned +** +*******************************************************************************/ +GAP_API extern UINT16 GAP_StartInquiry (tGAP_INQ_PARMS *p_inq_parms, + tGAP_CALLBACK *p_results_cb, + tGAP_CALLBACK *p_cmpl_cb); + +/******************************************************************************* +** +** Function GAP_StartPeriodicInquiry +** +** Description This function initiates a periodic inquiry. +** +** Returns BT_PASS (0) if successful, +** GAP_ERR_ILL_MODE if a bad mode parameter was passed +** GAP_ERR_ILL_INQ_TIME if a bad interval or duration was passed +** GAP_ERR_NO_CTRL_BLK if out of control blocks +** GAP_ERR_ILL_PARM if a bad parameter was detected in BTM +** GAP_ERR_BUSY if the device already has an iquiry active +** GAP_DEVICE_NOT_UP if the device is not initialized yet +** GAP_ERR_PROCESSING if any other BTM error was returned +** +*******************************************************************************/ +GAP_API extern UINT16 GAP_StartPeriodicInquiry (tGAP_INQ_PARMS *p_inq_parms, + UINT16 min_time, + UINT16 max_time, + tGAP_CALLBACK *p_results_cb); + +/******************************************************************************* +** +** Function GAP_CancelInquiry +** +** Description This function cancels a single inquiry (if in progress) +** +** Returns BOOLEAN (TRUE if successful, otherwise FALSE) +** +*******************************************************************************/ +GAP_API extern UINT16 GAP_CancelInquiry(void); + +/******************************************************************************* +** +** Function GAP_CancelPeriodicInquiry +** +** Description This function cancels a periodic inquiry (if in progress) +** +** Returns BOOLEAN: (TRUE if successful, otherwise FALSE) +** +*******************************************************************************/ +GAP_API extern UINT16 GAP_CancelPeriodicInquiry(void); + +/******************************************************************************* +** +** Function GAP_GetFirstInquiryResult +** +** Description This function retrieves the first valid inquiry result. +** +** Returns BT_PASS (0) if successful, or a non-zero error code +** GAP_EOINQDB if no more entries in the database. +** +*******************************************************************************/ +GAP_API extern UINT16 GAP_GetFirstInquiryResult(tGAP_INQ_RESULTS *p_results); + +/******************************************************************************* +** +** Function GAP_GetNextInquiryResult +** +** Description This function retrieves the next valid inquiry result. +** +** Returns BT_PASS (0) if successful, or a non-zero status code +** GAP_EOINQDB if no more entries in the database. +** +*******************************************************************************/ +GAP_API extern UINT16 GAP_GetNextInquiryResult(tGAP_INQ_RESULTS *p_results); + +/******************************************************************************* +** +** Function GAP_FindAddrByName +** +** Description This function is called to retrieve a device address given +** a device name. It first looks in the current local inquiry +** database for the device with the specified name. If not found +** it initiates a general inquiry. Upon completion, it retrieves +** the name for each device until a match is found or all devices +** have been checked. Note: This process can take a while to +** complete. +** +** Returns BT_PASS if the name was immediately available. (BD_ADDR is returned) +** GAP_CMD_INITIATED if an inquiry has been initiated +** +*******************************************************************************/ +GAP_API extern UINT16 GAP_FindAddrByName (BD_NAME devname, + tGAP_INQ_PARMS *p_inq_parms, + tGAP_CALLBACK *p_addr_cb, + BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function GAP_SetConnectableMode +** +** Description This function is called to allow or disallow a +** connections on the local device. +** +** Returns BT_PASS (0) if successful, +** GAP_ERR_ILL_PARM if a bad parameter is detected, +** GAP_DEVICE_NOT_UP if the device is not active, +** GAP_ERR_PROCESSING if not enough resources to carry out request +** +*******************************************************************************/ +GAP_API extern UINT16 GAP_SetConnectableMode (UINT16 mode, UINT16 duration, + UINT16 interval); + +/******************************************************************************* +** +** Function GAP_ReadConnectableMode +** +** Description This function is called to retrieve the current connectability +** mode for the local device. +** +** Returns GAP_NON_CONNECTABLE, GAP_CONNECTABLE +** +*******************************************************************************/ +GAP_API extern UINT16 GAP_ReadConnectableMode (UINT16 *duration, UINT16 *interval); + +/******************************************************************************* +** +** Function GAP_SetSecurityMode +** +** Description Set security mode for the device (Service or Link level) +** +** Returns void +** +*******************************************************************************/ +GAP_API extern void GAP_SetSecurityMode (UINT8 sec_mode); + +/******************************************************************************* +** +** Function GAP_SecRegister +** +** Description Application calls this function to register for +** security services. +** +** Returns TRUE if registered OK, else FALSE +** +*******************************************************************************/ +GAP_API extern BOOLEAN GAP_SecRegister (tBTM_APPL_INFO *p_cb_info); + +/******************************************************************************* +** +** Function GAP_SetPairableMode +** +** Description This function is called to allow or disallow pairing +** on the local device. +** +** Returns BT_PASS (0) if successful, or a non-zero error code +** +*******************************************************************************/ +GAP_API extern UINT16 GAP_SetPairableMode (UINT16 mode, BOOLEAN connect_only_paired); + +/******************************************************************************* +** +** Function GAP_Bond +** +** Description This function is called to initiate bonding with peer device +** +** Returns tBTM_STATUS - BTM_CMD_STARTED of successfully initiated +** +*******************************************************************************/ +GAP_API extern UINT8 GAP_Bond (BD_ADDR bd_addr, UINT8 pin_len, UINT8 *p_pin, UINT32 trusted_mask[]); + +/******************************************************************************* +** +** Function GAP_PinRsp +** +** Description This function is called from UI after Security Manager submitted +** PIN code request. +** +** Returns void +** +*******************************************************************************/ +GAP_API extern void GAP_PinRsp (BD_ADDR bd_addr, UINT8 res, UINT8 pin_len, + UINT8 *p_pin, UINT32 trusted_mask[]); + +/******************************************************************************* +** +** Function GAP_AuthorizeRsp +** +** Description This function is called from UI after Security Manager submitted +** an authorization request. +** +** Returns void +** +*******************************************************************************/ +GAP_API extern void GAP_AuthorizeRsp (BD_ADDR bd_addr, UINT8 res, + UINT32 trusted_mask[]); + +/******************************************************************************* +** +** Function GAP_SetDeviceClass +** +** Description This function updates the local Device Class. +** +** Returns BT_PASS (0) if successful, +** GAP_ERR_BUSY if a discovery is already in progress +** GAP_ERR_ILL_PARM if an illegal parameter was detected +** GAP_ERR_PROCESSING if any other BTM error has been returned +** +*******************************************************************************/ +GAP_API extern UINT16 GAP_SetDeviceClass(tGAP_COD *p_cod, UINT8 cmd); + +/******************************************************************************* +** +** Function GAP_ReadDeviceClass +** +** Description This function reads the current local Device Class setting. +** +** Returns BT_PASS +** +*******************************************************************************/ +GAP_API extern UINT16 GAP_ReadDeviceClass(tGAP_COD *p_cod); + +/******************************************************************************* +** +** Function GAP_ReadLocalDeviceInfo +** +** Description This function retrieves local device information to the caller. +** NOTE: Return parameters that are set to NULL are not retrieved. +** +** Returns BT_PASS (0) if successful, or a non-zero error code +** +*******************************************************************************/ +GAP_API extern UINT16 GAP_ReadLocalDeviceInfo( UINT8 *name, BD_ADDR *addr, + tGAP_LMP_VERSION *verinfo, + tGAP_LMP_FEATURES *features); + + +/******************************************************************************* +** +** Function GAP_GetRemoteDeviceName +** +** Description The remote name is retrieved from the specified remote device. If +** GAP_CMD_INITIATED is returned by the function, the command was +** successfully sent to the controller. The GAP_EVT_NAME_RESP event +** is passed in the callback when the remote device name has been retrieved. +** +** Returns +** GAP_CMD_INITIATED if remote search successfully initiated +** GAP_ERR_BUSY if a remote name request is already in progress, +** GAP_ERR_NO_CTRL_BLK if out of control blocks (too many commands pending) +** GAP_BAD_BD_ADDR if the device address is bad, +** GAP_DEVICE_NOT_UP if the device has not been initialized yet +** GAP_ERR_PROCESSING if any other BTM error has been returned +** +*******************************************************************************/ +GAP_API extern UINT16 GAP_GetRemoteDeviceName (BD_ADDR addr, tGAP_CALLBACK *callback); + +/*** Functions for L2CAP connection interface ***/ +/******************************************************************************* +** +** Function GAP_ConnOpen +** +** Description This function is called to open a generic L2CAP connection. +** +** Returns handle of the connection if successful, else GAP_INVALID_HANDLE +** +*******************************************************************************/ +GAP_API extern UINT16 GAP_ConnOpen (char *p_serv_name, UINT8 service_id, BOOLEAN is_server, + BD_ADDR p_rem_bda, UINT16 psm, tL2CAP_CFG_INFO *p_cfg, + UINT16 security, UINT8 chan_mode_mask, tGAP_CONN_CALLBACK *p_cb); + +/******************************************************************************* +** +** Function GAP_ConnClose +** +** Description This function is called to close a connection. +** +** Returns BT_PASS - closed OK +** GAP_ERR_BAD_HANDLE - invalid handle +** +*******************************************************************************/ +GAP_API extern UINT16 GAP_ConnClose (UINT16 gap_handle); + +/******************************************************************************* +** +** Function GAP_ConnReadData +** +** Description GKI buffer unaware application will call this function +** after receiving GAP_EVT_RXDATA event. A data copy is made +** into the receive buffer parameter. +** +** Returns BT_PASS - data read +** GAP_ERR_BAD_HANDLE - invalid handle +** GAP_NO_DATA_AVAIL - no data available +** +*******************************************************************************/ +GAP_API extern UINT16 GAP_ConnReadData (UINT16 gap_handle, UINT8 *p_data, + UINT16 max_len, UINT16 *p_len); + +/******************************************************************************* +** +** Function GAP_GetRxQueueCnt +** +** Description This function return number of bytes on the rx queue. +** +** Parameters: handle - Handle returned in the GAP_ConnOpen +** p_rx_queue_count - Pointer to return queue count in. +** +** +*******************************************************************************/ +GAP_API extern int GAP_GetRxQueueCnt (UINT16 handle, UINT32 *p_rx_queue_count); + +/******************************************************************************* +** +** Function GAP_ConnBTRead +** +** Description GKI buffer aware applications will call this function after +** receiving an GAP_EVT_RXDATA event to process the incoming +** data buffer. +** +** Returns BT_PASS - data read +** GAP_ERR_BAD_HANDLE - invalid handle +** GAP_NO_DATA_AVAIL - no data available +** +*******************************************************************************/ +GAP_API extern UINT16 GAP_ConnBTRead (UINT16 gap_handle, BT_HDR **pp_buf); + +/******************************************************************************* +** +** Function GAP_ConnBTWrite +** +** Description GKI buffer aware applications can call this function to write data +** by passing a pointer to the GKI buffer of data. +** +** Returns BT_PASS - data read +** GAP_ERR_BAD_HANDLE - invalid handle +** GAP_ERR_BAD_STATE - connection not established +** GAP_INVALID_BUF_OFFSET - buffer offset is invalid +*******************************************************************************/ +GAP_API extern UINT16 GAP_ConnBTWrite (UINT16 gap_handle, BT_HDR *p_buf); + +/******************************************************************************* +** +** Function GAP_ConnWriteData +** +** Description GKI buffer unaware application will call this function +** to send data to the connection. A data copy is made into a GKI +** buffer. +** +** Returns BT_PASS - data read +** GAP_ERR_BAD_HANDLE - invalid handle +** GAP_ERR_BAD_STATE - connection not established +** GAP_CONGESTION - system is congested +** +*******************************************************************************/ +GAP_API extern UINT16 GAP_ConnWriteData (UINT16 gap_handle, UINT8 *p_data, + UINT16 max_len, UINT16 *p_len); + +/******************************************************************************* +** +** Function GAP_ConnReconfig +** +** Description Applications can call this function to reconfigure the connection. +** +** Returns BT_PASS - config process started +** GAP_ERR_BAD_HANDLE - invalid handle +** +*******************************************************************************/ +GAP_API extern UINT16 GAP_ConnReconfig (UINT16 gap_handle, tL2CAP_CFG_INFO *p_cfg); + +/******************************************************************************* +** +** Function GAP_ConnSetIdleTimeout +** +** Description Higher layers call this function to set the idle timeout for +** a connection, or for all future connections. The "idle timeout" +** is the amount of time that a connection can remain up with +** no L2CAP channels on it. A timeout of zero means that the +** connection will be torn down immediately when the last channel +** is removed. A timeout of 0xFFFF means no timeout. Values are +** in seconds. +** +** Returns BT_PASS - config process started +** GAP_ERR_BAD_HANDLE - invalid handle +** +*******************************************************************************/ +GAP_API extern UINT16 GAP_ConnSetIdleTimeout (UINT16 gap_handle, UINT16 timeout); + +/******************************************************************************* +** +** Function GAP_ConnGetRemoteAddr +** +** Description This function is called to get the remote BD address +** of a connection. +** +** Returns BT_PASS - closed OK +** GAP_ERR_BAD_HANDLE - invalid handle +** +*******************************************************************************/ +GAP_API extern UINT8 *GAP_ConnGetRemoteAddr (UINT16 gap_handle); + +/******************************************************************************* +** +** Function GAP_ConnGetRemMtuSize +** +** Description Returns the remote device's MTU size. +** +** Returns UINT16 - maximum size buffer that can be transmitted to the peer +** +*******************************************************************************/ +GAP_API extern UINT16 GAP_ConnGetRemMtuSize (UINT16 gap_handle); + +/******************************************************************************* +** +** Function GAP_ConnGetL2CAPCid +** +** Description Returns the L2CAP channel id +** +** Parameters: handle - Handle of the connection +** +** Returns UINT16 - The L2CAP channel id +** 0, if error +** +*******************************************************************************/ +GAP_API extern UINT16 GAP_ConnGetL2CAPCid (UINT16 gap_handle); + +/******************************************************************************* +** +** Function GAP_SetTraceLevel +** +** Description This function sets the trace level for GAP. If called with +** a value of 0xFF, it simply returns the current trace level. +** +** Returns The new or current trace level +** +*******************************************************************************/ +GAP_API extern UINT8 GAP_SetTraceLevel (UINT8 new_level); + +/******************************************************************************* +** +** Function GAP_Init +** +** Description Initializes the control blocks used by GAP. +** This routine should not be called except once per +** stack invocation. +** +** Returns Nothing +** +*******************************************************************************/ +GAP_API extern void GAP_Init(void); + +#if (BLE_INCLUDED == TRUE) +/******************************************************************************* +** +** Function GAP_BleAttrDBUpdate +** +** Description update GAP local BLE attribute database. +** +** Returns Nothing +** +*******************************************************************************/ +GAP_API extern void GAP_BleAttrDBUpdate(UINT16 attr_uuid, tGAP_BLE_ATTR_VALUE *p_value); + + +/******************************************************************************* +** +** Function GAP_BleReadPeerPrefConnParams +** +** Description Start a process to read a connected peripheral's preferred +** connection parameters +** +** Returns TRUE if read started, else FALSE if GAP is busy +** +*******************************************************************************/ +GAP_API extern BOOLEAN GAP_BleReadPeerPrefConnParams (BD_ADDR peer_bda); + +/******************************************************************************* +** +** Function GAP_BleReadPeerDevName +** +** Description Start a process to read a connected peripheral's device name. +** +** Returns TRUE if request accepted +** +*******************************************************************************/ +GAP_API extern BOOLEAN GAP_BleReadPeerDevName (BD_ADDR peer_bda, tGAP_BLE_DEV_NAME_CBACK *p_cback); + + +/******************************************************************************* +** +** Function GAP_BleCancelReadPeerDevName +** +** Description Cancel reading a peripheral's device name. +** +** Returns TRUE if request accepted +** +*******************************************************************************/ +GAP_API extern BOOLEAN GAP_BleCancelReadPeerDevName (BD_ADDR peer_bda); + +/******************************************************************************* +** +** Function GAP_BleUpdateReconnectAddr +** +** Description Start a process to udpate the reconnect address if remote devive +** has privacy enabled. +** +** Returns TRUE if read started, else FALSE if GAP is busy +** +*******************************************************************************/ +GAP_API extern BOOLEAN GAP_BleUpdateReconnectAddr (BD_ADDR peer_bda, + BD_ADDR reconn_addr, + tGAP_BLE_RECONN_ADDR_CBACK *p_cback); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* GAP_API_H */ + diff --git a/stack/include/gatt_api.h b/stack/include/gatt_api.h index 2d13e5a32..d53a80e1a 100644 --- a/stack/include/gatt_api.h +++ b/stack/include/gatt_api.h @@ -137,6 +137,9 @@ typedef UINT16 tGATT_DISCONN_REASON; #define GATT_MAX_SCCB 10 #endif +#ifndef GATTP_TRANSPORT_SUPPORTED +#define GATTP_TRANSPORT_SUPPORTED GATT_TRANSPORT_LE_BR_EDR +#endif /* GATT notification caching timer, default to be three seconds @@ -164,7 +167,7 @@ typedef UINT16 tGATT_PERM; #define GATT_ENCRYPT_KEY_SIZE_MASK (0xF000) /* the MS nibble of tGATT_PERM; key size 7=0; size 16=9 */ #define GATT_READ_ALLOWED (GATT_PERM_READ | GATT_PERM_READ_ENCRYPTED | GATT_PERM_READ_ENC_MITM) -#define GATT_READ_AUTH_REQUIRED (GATT_PERM_READ_ENC_MITM) +#define GATT_READ_AUTH_REQUIRED (GATT_PERM_READ_ENCRYPTED) #define GATT_READ_MITM_REQUIRED (GATT_PERM_READ_ENC_MITM) #define GATT_READ_ENCRYPTED_REQUIRED (GATT_PERM_READ_ENCRYPTED | GATT_PERM_READ_ENC_MITM) @@ -1120,6 +1123,25 @@ extern "C" *******************************************************************************/ GATT_API extern BOOLEAN GATT_GetConnIdIfConnected(tGATT_IF gatt_if, BD_ADDR bd_addr, UINT16 *p_conn_id); + +/******************************************************************************* +** +** Function GATT_Listen +** +** Description This function start or stop LE advertisement and listen for +** connection. +** +** Parameters gatt_if: applicaiton interface +** p_bd_addr: listen for specific address connection, or NULL for +** listen to all device connection. +** start: is a direct conenection or a background auto connection +** +** Returns TRUE if advertisement is started; FALSE if adv start failure. +** +*******************************************************************************/ + GATT_API extern BOOLEAN GATT_Listen (tGATT_IF gatt_if, BOOLEAN start, BD_ADDR_PTR bd_addr); + + #ifdef __cplusplus } diff --git a/stack/include/gattdefs.h b/stack/include/gattdefs.h index 6eac0f438..e2150f2a6 100644 --- a/stack/include/gattdefs.h +++ b/stack/include/gattdefs.h @@ -57,53 +57,4 @@ #define GATT_UUID_GATT_SRV_CHGD 0x2A05 /* Attribute Protocol Test */ -/* Link Loss Service */ -#define GATT_UUID_ALERT_LEVEL 0x2A06 /* Alert Level */ -#define GATT_UUID_TX_POWER_LEVEL 0x2A07 /* TX power level */ - -/* Time Profile */ -/* Current Time Service */ -#define GATT_UUID_CURRENT_TIME 0x2A2B /* Current Time */ -#define GATT_UUID_LOCAL_TIME_INFO 0x2A0F /* Local time info */ -#define GATT_UUID_REF_TIME_INFO 0x2A14 /* reference time information */ - -/* NwA Profile */ -#define GATT_UUID_NW_STATUS 0x2A18 /* network availability status */ -#define GATT_UUID_NW_TRIGGER 0x2A1A /* Network availability trigger */ - -/* phone alert */ -#define GATT_UUID_ALERT_STATUS 0x2A40 /* alert status */ -#define GATT_UUID_RINGER_CP 0x2A42 /* ringer control point */ -#define GATT_UUID_RINGER_SETTING 0x2A41 /* ringer setting */ - -/* Glucose Service */ -#define GATT_UUID_GM_MEASUREMENT 0x2A18 -#define GATT_UUID_GM_CONTEXT 0x2A34 -#define GATT_UUID_GM_CONTROL_POINT 0x2A52 -#define GATT_UUID_GM_FEATURE 0x2A51 - -/* device infor characteristic */ -#define GATT_UUID_SYSTEM_ID 0x2A23 -#define GATT_UUID_MODEL_NUMBER_STR 0x2A24 -#define GATT_UUID_SERIAL_NUMBER_STR 0x2A25 -#define GATT_UUID_FW_VERSION_STR 0x2A26 -#define GATT_UUID_HW_VERSION_STR 0x2A27 -#define GATT_UUID_SW_VERSION_STR 0x2A28 -#define GATT_UUID_MANU_NAME 0x2A29 -#define GATT_UUID_IEEE_DATA 0x2A2A -#define GATT_UUID_PNP_ID 0x2A50 - -/* HID characteristics */ -#define GATT_UUID_HID_INFORMATION 0x2A4A -#define GATT_UUID_HID_REPORT_MAP 0x2A4B -#define GATT_UUID_HID_CONTROL_POINT 0x2A4C -#define GATT_UUID_HID_REPORT 0x2A4D -#define GATT_UUID_HID_PROTO_MODE 0x2A4E -#define GATT_UUID_HID_BT_KB_INPUT 0x2A22 -#define GATT_UUID_HID_BT_KB_OUTPUT 0x2A32 -#define GATT_UUID_HID_BT_MOUSE_INPUT 0x2A33 - -/* Battery Service char */ -#define GATT_UUID_BATTERY_LEVEL 0x2A19 - #endif diff --git a/stack/include/hcidefs.h b/stack/include/hcidefs.h index 1a0b3e818..0584f65c6 100644 --- a/stack/include/hcidefs.h +++ b/stack/include/hcidefs.h @@ -19,10 +19,6 @@ #ifndef HCIDEFS_H #define HCIDEFS_H -#ifdef BRCM_VS -#include "brcm_vs_include.h" -#endif - #define HCI_PROTO_VERSION 0x01 /* Version for BT spec 1.1 */ #define HCI_PROTO_VERSION_1_2 0x02 /* Version for BT spec 1.2 */ #define HCI_PROTO_VERSION_2_0 0x03 /* Version for BT spec 2.0 */ @@ -100,8 +96,19 @@ #define HCI_LOGICAL_LINK_CANCEL (0x003B | HCI_GRP_LINK_CONTROL_CMDS) #define HCI_FLOW_SPEC_MODIFY (0x003C | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_ENH_SETUP_ESCO_CONNECTION (0x003D | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_ENH_ACCEPT_ESCO_CONNECTION (0x003E | HCI_GRP_LINK_CONTROL_CMDS) + +/* ConnectionLess Broadcast */ +#define HCI_TRUNCATED_PAGE (0x003F | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_TRUNCATED_PAGE_CANCEL (0x0040 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_SET_CLB (0x0041 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_RECEIVE_CLB (0x0042 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_START_SYNC_TRAIN (0x0043 | HCI_GRP_LINK_CONTROL_CMDS) +#define HCI_RECEIVE_SYNC_TRAIN (0x0044 | HCI_GRP_LINK_CONTROL_CMDS) + #define HCI_LINK_CTRL_CMDS_FIRST HCI_INQUIRY -#define HCI_LINK_CTRL_CMDS_LAST HCI_FLOW_SPEC_MODIFY +#define HCI_LINK_CTRL_CMDS_LAST HCI_RECEIVE_SYNC_TRAIN /* Commands of HCI_GRP_LINK_POLICY_CMDS */ #define HCI_HOLD_MODE (0x0001 | HCI_GRP_LINK_POLICY_CMDS) @@ -131,6 +138,7 @@ #define HCI_READ_PIN_TYPE (0x0009 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) #define HCI_WRITE_PIN_TYPE (0x000A | HCI_GRP_HOST_CONT_BASEBAND_CMDS) #define HCI_CREATE_NEW_UNIT_KEY (0x000B | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_GET_MWS_TRANS_LAYER_CFG (0x000C | HCI_GRP_HOST_CONT_BASEBAND_CMDS) #define HCI_READ_STORED_LINK_KEY (0x000D | HCI_GRP_HOST_CONT_BASEBAND_CMDS) #define HCI_WRITE_STORED_LINK_KEY (0x0011 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) #define HCI_DELETE_STORED_LINK_KEY (0x0012 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) @@ -210,9 +218,27 @@ #define HCI_READ_BE_FLUSH_TOUT (0x0069 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) #define HCI_WRITE_BE_FLUSH_TOUT (0x006A | HCI_GRP_HOST_CONT_BASEBAND_CMDS) #define HCI_SHORT_RANGE_MODE (0x006B | HCI_GRP_HOST_CONT_BASEBAND_CMDS) /* 802.11 only */ +#define HCI_READ_LE_HOST_SUPPORTED (0x006C | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_LE_HOST_SUPPORTED (0x006D | HCI_GRP_HOST_CONT_BASEBAND_CMDS) + + +/* MWS coexistence */ +#define HCI_SET_MWS_CHANNEL_PARAMETERS (0x006E | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_SET_EXTERNAL_FRAME_CONFIGURATION (0x006F | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_SET_MWS_SIGNALING (0x0070 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_SET_MWS_TRANSPORT_LAYER (0x0071 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_SET_MWS_SCAN_FREQUENCY_TABLE (0x0072 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_SET_MWS_PATTERN_CONFIGURATION (0x0073 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) + +/* ConnectionLess Broadcast */ +#define HCI_SET_RESERVED_LT_ADDR (0x0077 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_DELETE_RESERVED_LT_ADDR (0x0078 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_CLB_DATA (0x0079 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_WRITE_SYNC_TRAIN_PARAM (0x007A | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_READ_SYNC_TRAIN_PARAM (0x007B | HCI_GRP_HOST_CONT_BASEBAND_CMDS) #define HCI_CONT_BASEBAND_CMDS_FIRST HCI_SET_EVENT_MASK -#define HCI_CONT_BASEBAND_CMDS_LAST HCI_SHORT_RANGE_MODE +#define HCI_CONT_BASEBAND_CMDS_LAST HCI_READ_SYNC_TRAIN_PARAM /* Commands of HCI_GRP_INFORMATIONAL_PARAMS group */ @@ -224,9 +250,10 @@ #define HCI_READ_COUNTRY_CODE (0x0007 | HCI_GRP_INFORMATIONAL_PARAMS) #define HCI_READ_BD_ADDR (0x0009 | HCI_GRP_INFORMATIONAL_PARAMS) #define HCI_READ_DATA_BLOCK_SIZE (0x000A | HCI_GRP_INFORMATIONAL_PARAMS) +#define HCI_READ_LOCAL_SUPPORTED_CODECS (0x000B | HCI_GRP_INFORMATIONAL_PARAMS) #define HCI_INFORMATIONAL_CMDS_FIRST HCI_READ_LOCAL_VERSION_INFO -#define HCI_INFORMATIONAL_CMDS_LAST HCI_READ_BD_ADDR +#define HCI_INFORMATIONAL_CMDS_LAST HCI_READ_LOCAL_SUPPORTED_CODECS /* Commands of HCI_GRP_STATUS_PARAMS group */ @@ -296,6 +323,10 @@ #define HCI_BLE_LTK_REQ_REPLY (0x001A | HCI_GRP_BLE_CMDS) #define HCI_BLE_LTK_REQ_NEG_REPLY (0x001B | HCI_GRP_BLE_CMDS) #define HCI_BLE_READ_SUPPORTED_STATES (0x001C | HCI_GRP_BLE_CMDS) +/* BLE TEST COMMANDS */ +#define HCI_BLE_RECEIVER_TEST (0x001D | HCI_GRP_BLE_CMDS) +#define HCI_BLE_TRANSMITTER_TEST (0x001E | HCI_GRP_BLE_CMDS) +#define HCI_BLE_TEST_END (0x001F | HCI_GRP_BLE_CMDS) #define HCI_BLE_RESET (0x0020 | HCI_GRP_BLE_CMDS) @@ -390,8 +421,18 @@ #define HCI_BLE_READ_REMOTE_FEAT_CMPL_EVT 0x04 #define HCI_BLE_LTK_REQ_EVT 0x05 -#define HCI_EVENT_RSP_FIRST HCI_INQUIRY_COMP_EVT -#define HCI_EVENT_RSP_LAST HCI_AMP_STATUS_CHANGE_EVT +/* ConnectionLess Broadcast events */ +#define HCI_SYNC_TRAIN_COMP_EVT 0x4F +#define HCI_SYNC_TRAIN_RECEIVED_EVT 0x50 +#define HCI_CLB_RX_DATA_EVT 0x51 +#define HCI_CLB_RX_TIMEOUT_EVT 0x52 +#define HCI_TRUNCATED_PAGE_COMP_EVT 0x53 +#define HCI_SLAVE_PAGE_RESP_TIMEOUT_EVT 0x54 +#define HCI_CLB_CHANNEL_CHANGE_EVT 0x55 +#define HCI_INQUIRY_RESPONSE_NOTIF 0x56 + +#define HCI_EVENT_RSP_FIRST HCI_INQUIRY_COMP_EVT +#define HCI_EVENT_RSP_LAST HCI_CLB_CHANNEL_CHANGE_EVT #define HCI_VENDOR_SPECIFIC_EVT 0xFF /* Vendor specific events */ #define HCI_NAP_TRACE_EVT 0xFF /* was define 0xFE, 0xFD, change to 0xFF @@ -469,7 +510,13 @@ #define HCI_ERR_CONN_FAILED_ESTABLISHMENT 0x3E #define HCI_ERR_MAC_CONNECTION_FAILED 0x3F -#define HCI_ERR_MAX_ERR 0x40 +/* ConnectionLess Broadcast errors */ +#define HCI_ERR_LT_ADDR_ALREADY_IN_USE 0x40 +#define HCI_ERR_LT_ADDR_NOT_ALLOCATED 0x41 +#define HCI_ERR_CLB_NOT_ENABLED 0x42 +#define HCI_ERR_CLB_DATA_TOO_BIG 0x43 + +#define HCI_ERR_MAX_ERR 0x43 #define HCI_HINT_TO_RECREATE_AMP_PHYS_LINK 0xFF @@ -965,8 +1012,15 @@ #define HCI_CONTROLLER_TYPE_ECMA 2 #define HCI_MAX_CONTROLLER_TYPES 3 +/* ConnectionLess Broadcast */ +#define HCI_CLB_DISABLE 0x00 +#define HCI_CLB_ENABLE 0x01 - +/* ConnectionLess Broadcast Data fragment */ +#define HCI_CLB_FRAGMENT_CONT 0x00 +#define HCI_CLB_FRAGMENT_START 0x01 +#define HCI_CLB_FRAGMENT_END 0x02 +#define HCI_CLB_FRAGMENT_SINGLE 0x03 /* AMP Controller Status codes */ @@ -1152,7 +1206,43 @@ typedef struct #define LMP_COMPID_SOUND ID 111 #define LMP_COMPID_MONSTER LLC 112 #define LMP_COMPID_CONNECTBLU 113 -#define LMP_COMPID_MAX_ID 114 /* this is a place holder */ + +#define LMP_COMPID_SHANGHAI_SSE 114 +#define LMP_COMPID_GROUP_SENSE 115 +#define LMP_COMPID_ZOMM 116 +#define LMP_COMPID_SAMSUNG 117 +#define LMP_COMPID_CREATIVE_TECH 118 +#define LMP_COMPID_LAIRD_TECH 119 +#define LMP_COMPID_NIKE 120 +#define LMP_COMPID_LESSWIRE 121 +#define LMP_COMPID_MSTAR_SEMI 122 +#define LMP_COMPID_HANLYNN_TECH 123 +#define LMP_COMPID_AR_CAMBRIDGE 124 +#define LMP_COMPID_SEERS_TECH 125 +#define LMP_COMPID_SPORTS_TRACKING 126 +#define LMP_COMPID_AUTONET_MOBILE 127 +#define LMP_COMPID_DELORME_PUBLISH 128 +#define LMP_COMPID_WUXI_VIMICRO 129 +#define LMP_COMPID_SENNHEISER 130 +#define LMP_COMPID_TIME_KEEPING_SYS 131 +#define LMP_COMPID_LUDUS_HELSINKI 132 +#define LMP_COMPID_BLUE_RADIOS 133 +#define LMP_COMPID_EQUINUX 134 +#define LMP_COMPID_GARMIN_INTL 135 +#define LMP_COMPID_ECOTEST 136 +#define LMP_COMPID_GN_RESOUND 137 +#define LMP_COMPID_JAWBONE 138 +#define LMP_COMPID_TOPCON_POSITIONING 139 +#define LMP_COMPID_QUALCOMM_LABS 140 +#define LMP_COMPID_ZSCAN_SOFTWARE 141 +#define LMP_COMPID_QUINTIC 142 +#define LMP_COMPID_STOLLMAN_EV 143 +#define LMP_COMPID_FUNAI_ELECTRONIC 144 +#define LMP_COMPID_ADV_PANMOBILE 145 +#define LMP_COMPID_THINK_OPTICS 146 +#define LMP_COMPID_UNIVERSAL_ELEC 147 +#define LMP_COMPID_AIROHA_TECH 148 +#define LMP_COMPID_MAX_ID 149 /* this is a place holder */ #define LMP_COMPID_INTERNAL 65535 #define MAX_LMP_COMPID (LMP_COMPID_MAX_ID) @@ -1349,6 +1439,16 @@ typedef struct #define HCI_FEATURE_AFH_CLASS_SLAVE_OFF 4 #define HCI_LMP_AFH_CLASS_SLAVE_SUPPORTED(x) ((x)[HCI_FEATURE_AFH_CLASS_SLAVE_OFF] & HCI_FEATURE_AFH_CLASS_SLAVE_MASK) +#if 1 +#define HCI_FEATURE_BREDR_NOT_SPT_MASK 0x20 +#define HCI_FEATURE_BREDR_NOT_SPT_OFF 4 +#define HCI_BREDR_NOT_SPT_SUPPORTED(x) ((x)[HCI_FEATURE_BREDR_NOT_SPT_OFF] & HCI_FEATURE_BREDR_NOT_SPT_MASK) + +#define HCI_FEATURE_LE_SPT_MASK 0x40 +#define HCI_FEATURE_LE_SPT_OFF 4 +#define HCI_LE_SPT_SUPPORTED(x) ((x)[HCI_FEATURE_LE_SPT_OFF] & HCI_FEATURE_LE_SPT_MASK) +#else + #define HCI_FEATURE_ALIAS_AUTH_MASK 0x20 #define HCI_FEATURE_ALIAS_AUTH_OFF 4 #define HCI_LMP_ALIAS_AUTH_SUPPORTED(x) ((x)[HCI_FEATURE_ALIAS_AUTH_OFF] & HCI_FEATURE_ALIAS_AUTH_MASK) @@ -1356,6 +1456,7 @@ typedef struct #define HCI_FEATURE_ANON_MODE_MASK 0x40 #define HCI_FEATURE_ANON_MODE_OFF 4 #define HCI_LMP_ANON_MODE_SUPPORTED(x) ((x)[HCI_FEATURE_ANON_MODE_OFF] & HCI_FEATURE_ANON_MODE_MASK) +#endif #define HCI_FEATURE_3_SLOT_EDR_ACL_MASK 0x80 #define HCI_FEATURE_3_SLOT_EDR_ACL_OFF 4 @@ -1397,9 +1498,16 @@ typedef struct #define HCI_FEATURE_EXT_INQ_RSP_OFF 6 #define HCI_EXT_INQ_RSP_SUPPORTED(x) ((x)[HCI_FEATURE_EXT_INQ_RSP_OFF] & HCI_FEATURE_EXT_INQ_RSP_MASK) +#if 1 /* TOKYO spec definition */ +#define HCI_FEATURE_SIMUL_LE_BREDR_MASK 0x02 +#define HCI_FEATURE_SIMUL_LE_BREDR_OFF 6 +#define HCI_SIMUL_LE_BREDR_SUPPORTED(x) ((x)[HCI_FEATURE_SIMUL_LE_BREDR_OFF] & HCI_FEATURE_SIMUL_LE_BREDR_MASK) + +#else #define HCI_FEATURE_ANUM_PIN_AWARE_MASK 0x02 #define HCI_FEATURE_ANUM_PIN_AWARE_OFF 6 #define HCI_ANUM_PIN_AWARE_SUPPORTED(x) ((x)[HCI_FEATURE_ANUM_PIN_AWARE_OFF] & HCI_FEATURE_ANUM_PIN_AWARE_MASK) +#endif #define HCI_FEATURE_ANUM_PIN_CAP_MASK 0x04 #define HCI_FEATURE_ANUM_PIN_CAP_OFF 6 @@ -1448,6 +1556,14 @@ typedef struct #define HCI_EXT_FEATURE_SSP_HOST_OFF 0 #define HCI_SSP_HOST_SUPPORTED(x) ((x)[HCI_EXT_FEATURE_SSP_HOST_OFF] & HCI_EXT_FEATURE_SSP_HOST_MASK) +#define HCI_EXT_FEATURE_LE_HOST_MASK 0x02 +#define HCI_EXT_FEATURE_LE_HOST_OFF 0 +#define HCI_LE_HOST_SUPPORTED(x) ((x)[HCI_EXT_FEATURE_LE_HOST_OFF] & HCI_EXT_FEATURE_LE_HOST_MASK) + +#define HCI_EXT_FEATURE_SIMUL_DUMO_HOST_MASK 0x04 +#define HCI_EXT_FEATURE_SIMUL_DUMO_HOST_OFF 0 +#define HCI_SIMUL_DUMO_HOST_SUPPORTED(x) ((x)[HCI_EXT_FEATURE_SIMUL_DUMO_HOST_OFF] & HCI_EXT_FEATURE_SIMUL_DUMO_HOST_MASK) + /* ** Local Supported Commands encoding */ @@ -2136,6 +2252,99 @@ typedef struct ** Supported Commands (Byte 28) */ +/* Supported Commands (Byte 29) */ +#define HCI_SUPP_COMMANDS_ENH_SETUP_SYNCH_CONN_MASK 0x08 +#define HCI_SUPP_COMMANDS_ENH_SETUP_SYNCH_CONN_OFF 29 +#define HCI_READ_ENH_SETUP_SYNCH_CONN_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_ENH_SETUP_SYNCH_CONN_OFF] & HCI_SUPP_COMMANDS_ENH_SETUP_SYNCH_CONN_MASK) + +#define HCI_SUPP_COMMANDS_ENH_ACCEPT_SYNCH_CONN_MASK 0x10 +#define HCI_SUPP_COMMANDS_ENH_ACCEPT_SYNCH_CONN_OFF 29 +#define HCI_READ_ENH_ACCEPT_SYNCH_CONN_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_ENH_ACCEPT_SYNCH_CONN_OFF] & HCI_SUPP_COMMANDS_ENH_ACCEPT_SYNCH_CONN_MASK) + +#define HCI_SUPP_COMMANDS_READ_LOCAL_CODECS_MASK 0x20 +#define HCI_SUPP_COMMANDS_READ_LOCAL_CODECS_OFF 29 +#define HCI_READ_LOCAL_CODECS_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_CODECS_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_CODECS_MASK) + +#define HCI_SUPP_COMMANDS_SET_MWS_CHANN_PARAM_MASK 0x40 +#define HCI_SUPP_COMMANDS_SET_MWS_CHANN_PARAM_OFF 29 +#define HCI_SET_MWS_CHANNEL_PARAMETERS_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_MWS_CHANN_PARAM_OFF] & HCI_SUPP_COMMANDS_SET_MWS_CHANN_PARAM_MASK) + +#define HCI_SUPP_COMMANDS_SET_EXT_FRAME_CONF_MASK 0x80 +#define HCI_SUPP_COMMANDS_SET_EXT_FRAME_CONF_OFF 29 +#define HCI_SET_EXTERNAL_FRAME_CONFIGURATION_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_EXT_FRAME_CONF_OFF] & HCI_SUPP_COMMANDS_SET_EXT_FRAME_CONF_MASK) + + +/* Supported Commands (Byte 30) */ +#define HCI_SUPP_COMMANDS_SET_MWS_SIGNALING_MASK 0x01 +#define HCI_SUPP_COMMANDS_SET_MWS_SIGNALING_OFF 30 +#define HCI_SET_MWS_SIGNALING_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_MWS_SIGNALING_OFF] & HCI_SUPP_COMMANDS_SET_MWS_SIGNALING_MASK) + +#define HCI_SUPP_COMMANDS_SET_MWS_TRANS_LAYER_MASK 0x02 +#define HCI_SUPP_COMMANDS_SET_MWS_TRANS_LAYER_OFF 30 +#define HCI_SET_MWS_TRANSPORT_LAYER_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_MWS_TRANS_LAYER_OFF] & HCI_SUPP_COMMANDS_SET_MWS_TRANS_LAYER_MASK) + +#define HCI_SUPP_COMMANDS_SET_MWS_SCAN_FREQ_TABLE_MASK 0x04 +#define HCI_SUPP_COMMANDS_SET_MWS_SCAN_FREQ_TABLE_OFF 30 +#define HCI_SET_MWS_SCAN_FREQUENCY_TABLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_MWS_SCAN_FREQ_TABLE_OFF] & HCI_SUPP_COMMANDS_SET_MWS_SCAN_FREQ_TABLE_MASK) + +#define HCI_SUPP_COMMANDS_GET_TRANS_LAYER_CONF_MASK 0x08 +#define HCI_SUPP_COMMANDS_GET_TRANS_LAYER_CONF_OFF 30 +#define HCI_GET_MWS_TRANS_LAYER_CFG_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_GET_TRANS_LAYER_CONF_OFF] & HCI_SUPP_COMMANDS_GET_TRANS_LAYER_CONF_MASK) + +#define HCI_SUPP_COMMANDS_SET_MWS_PATTERN_CONF_MASK 0x10 +#define HCI_SUPP_COMMANDS_SET_MWS_PATTERN_CONF_OFF 30 +#define HCI_SET_MWS_PATTERN_CONFIGURATION_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_MWS_PATTERN_CONF_OFF] & HCI_SUPP_COMMANDS_SET_MWS_PATTERN_CONF_MASK) + +/* Supported Commands (Byte 30 bit 6-7) */ +#define HCI_SUPP_COMMANDS_TRUNCATED_PAGE 0x06 +#define HCI_SUPP_COMMANDS_TRUNCATED_PAGE_OFF 30 +#define HCI_TRUNCATED_PAGE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_TRUNCATED_PAGE_OFF] & HCI_SUPP_COMMANDS_TRUNCATED_PAGE) + +#define HCI_SUPP_COMMANDS_TRUNCATED_PAGE_CANCEL 0x07 +#define HCI_SUPP_COMMANDS_TRUNCATED_PAGE_CANCEL_OFF 30 +#define HCI_TRUNCATED_PAGE_CANCEL_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_TRUNCATED_PAGE_CANCEL_OFF] & HCI_SUPP_COMMANDS_TRUNCATED_PAGE_CANCEL) + +/* Supported Commands (Byte 31 bit 6-7) */ +#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST 0x00 +#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_OFF 31 +#define HCI_SET_CONLESS_SLAVE_BRCST_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_OFF] & HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST) + +#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_RECEIVE 0x01 +#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_RECEIVE_OFF 31 +#define HCI_SET_CONLESS_SLAVE_BRCST_RECEIVE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_RECEIVE_OFF] & HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_RECEIVE) + +#define HCI_SUPP_COMMANDS_START_SYNC_TRAIN 0x02 +#define HCI_SUPP_COMMANDS_START_SYNC_TRAIN_OFF 31 +#define HCI_START_SYNC_TRAIN_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_START_SYNC_TRAIN_OFF] & HCI_SUPP_COMMANDS_START_SYNC_TRAIN) + +#define HCI_SUPP_COMMANDS_RECEIVE_SYNC_TRAIN 0x03 +#define HCI_SUPP_COMMANDS_RECEIVE_SYNC_TRAIN_OFF 31 +#define HCI_RECEIVE_SYNC_TRAIN_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_RECEIVE_SYNC_TRAIN_OFF] & HCI_SUPP_COMMANDS_RECEIVE_SYNC_TRAIN) + +#define HCI_SUPP_COMMANDS_SET_RESERVED_LT_ADDR 0x04 +#define HCI_SUPP_COMMANDS_SET_RESERVED_LT_ADDR_OFF 31 +#define HCI_SET_RESERVED_LT_ADDR_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_RESERVED_LT_ADDR_OFF] & HCI_SUPP_COMMANDS_SET_RESERVED_LT_ADDR) + +#define HCI_SUPP_COMMANDS_DELETE_RESERVED_LT_ADDR 0x05 +#define HCI_SUPP_COMMANDS_DELETE_RESERVED_LT_ADDR_OFF 31 +#define HCI_DELETE_RESERVED_LT_ADDR_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_DELETE_RESERVED_LT_ADDR_OFF] & HCI_SUPP_COMMANDS_DELETE_RESERVED_LT_ADDR) + +#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_DATA 0x06 +#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_DATA_OFF 31 +#define HCI_SET_CONLESS_SLAVE_BRCST_DATA_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_DATA_OFF] & HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_DATA) + +#define HCI_SUPP_COMMANDS_READ_SYNC_TRAIN_PARAM 0x07 +#define HCI_SUPP_COMMANDS_READ_SYNC_TRAIN_PARAM_OFF 31 +#define HCI_READ_SYNC_TRAIN_PARAM_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_SYNC_TRAIN_PARAM_OFF] & HCI_SUPP_COMMANDS_READ_SYNC_TRAIN_PARAM) + +/* Supported Commands (Byte 32 bit 0) */ +#define HCI_SUPP_COMMANDS_WRITE_SYNC_TRAIN_PARAM 0x00 +#define HCI_SUPP_COMMANDS_WRITE_SYNC_TRAIN_PARAM_OFF 32 +#define HCI_WRITE_SYNC_TRAIN_PARAM_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_SYNC_TRAIN_PARAM_OFF] & HCI_SUPP_COMMANDS_WRITE_SYNC_TRAIN_PARAM) + + + + /* Commands of HCI_GRP_VENDOR_SPECIFIC group for WIDCOMM SW LM Simulator */ diff --git a/stack/include/hcimsgs.h b/stack/include/hcimsgs.h index 3a23dbe25..cb85cb127 100644 --- a/stack/include/hcimsgs.h +++ b/stack/include/hcimsgs.h @@ -1241,6 +1241,7 @@ HCI_API extern void btsnd_hcie_ext_inquiry_result(void *buffer, UINT8 num_resp, #define HCIC_PARAM_SIZE_BLE_READ_REMOTE_FEAT 2 #define HCIC_PARAM_SIZE_BLE_ENCRYPT 32 #define HCIC_PARAM_SIZE_BLE_RAND 0 +#define HCIC_PARAM_SIZE_WRITE_LE_HOST_SUPPORTED 2 #define HCIC_BLE_RAND_DI_SIZE 8 #define HCIC_BLE_ENCRYT_KEY_SIZE 16 @@ -1320,6 +1321,15 @@ HCI_API extern BOOLEAN btsnd_hcic_ble_ltk_req_neg_reply (UINT16 handle); HCI_API extern BOOLEAN btsnd_hcic_ble_read_supported_states (void); +HCI_API extern BOOLEAN btsnd_hcic_ble_write_host_supported (UINT8 le_host_spt, UINT8 simul_le_host_spt); + +HCI_API extern BOOLEAN btsnd_hcic_ble_read_host_supported (void); + +HCI_API extern BOOLEAN btsnd_hcic_ble_receiver_test(UINT8 rx_freq); + +HCI_API extern BOOLEAN btsnd_hcic_ble_transmitter_test(UINT8 tx_freq, UINT8 test_data_len, + UINT8 payload); +HCI_API extern BOOLEAN btsnd_hcic_ble_test_end(void); #endif /* BLE_INCLUDED */ diff --git a/stack/include/l2c_api.h b/stack/include/l2c_api.h index 618ea8d54..95c44e0a4 100644 --- a/stack/include/l2c_api.h +++ b/stack/include/l2c_api.h @@ -123,16 +123,6 @@ typedef UINT8 tL2CAP_CHNL_DATA_RATE; #define L2C_INVALID_PSM(psm) (((psm) & 0x0101) != 0x0001) #define L2C_IS_VALID_PSM(psm) (((psm) & 0x0101) == 0x0001) -#if (BLE_INCLUDED == TRUE) -#define L2CAP_LE_INT_MIN 0x0006 -#define L2CAP_LE_INT_MAX 0x0C80 -#define L2CAP_LE_LATENCY_MAX 500 -#define L2CAP_LE_TIMEOUT_MIN 0x000a -#define L2CAP_LE_TIMEOUT_MAX 0x0C80 -#define L2CAP_LE_TIMEOUT_DEFAULT 0x07D0 -#endif - - /***************************************************************************** ** Type Definitions *****************************************************************************/ diff --git a/stack/include/profiles_api.h b/stack/include/profiles_api.h new file mode 100644 index 000000000..eee0dd834 --- /dev/null +++ b/stack/include/profiles_api.h @@ -0,0 +1,71 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2013 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#ifndef PROFILES_API_H +#define PROFILES_API_H + +#include "bt_target.h" +#include "btm_api.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ +#define BT_PASS 0 /* Used for general successful function returns */ + +/*** Port entity passes back 8 bit errors; will use upper byte offset ***/ +#define PORT_ERR_GRP 0x0000 /* base offset for port entity */ +#define GAP_ERR_GRP 0x0100 /* base offset for GAP profile */ +#define SPP_ERR_GRP 0x0200 /* base offset for serial port profile */ +#define HCRP_ERR_GRP 0x0300 /* base offset for HCRP */ +#define HCRPM_ERR_GRP 0x0400 /* base offset for HCRPM */ + +/* #define HSP2_ERR_GRP 0x0F00 */ + +/* security level definitions (tBT_SECURITY) */ +#define BT_USE_DEF_SECURITY 0 +#define BT_SEC_MODE_NONE BTM_SEC_MODE_NONE +#define BT_SEC_MODE_SERVICE BTM_SEC_MODE_SERVICE +#define BT_SEC_MODE_LINK BTM_SEC_MODE_LINK + +/* security mask definitions (tBT_SECURITY) */ +/* The following definitions are OR'd together to form the security requirements */ +#define BT_SEC_IN_AUTHORIZE BTM_SEC_IN_AUTHORIZE /* Inbound call requires authorization */ +#define BT_SEC_IN_AUTHENTICATE BTM_SEC_IN_AUTHENTICATE /* Inbound call requires authentication */ +#define BT_SEC_IN_ENCRYPT BTM_SEC_IN_ENCRYPT /* Inbound call requires encryption */ +#define BT_SEC_OUT_AUTHORIZE BTM_SEC_OUT_AUTHORIZE /* Outbound call requires authorization */ +#define BT_SEC_OUT_AUTHENTICATE BTM_SEC_OUT_AUTHENTICATE /* Outbound call requires authentication */ +#define BT_SEC_OUT_ENCRYPT BTM_SEC_OUT_ENCRYPT /* Outbound call requires encryption */ + + +/***************************************************************************** +** Type Definitions +*****************************************************************************/ + +/* +** Security Definitions +** This following definitions are used to indicate the security +** requirements for a service. +*/ +typedef struct +{ + UINT8 level; + UINT8 mask; +} tBT_SECURITY; + +#endif /* PROFILES_API_H */ + diff --git a/stack/include/sdpdefs.h b/stack/include/sdpdefs.h index c290e03c1..fcd4a5e6f 100644 --- a/stack/include/sdpdefs.h +++ b/stack/include/sdpdefs.h @@ -262,10 +262,20 @@ #define UUID_SERVCLASS_CURRENT_TIME 0x1805 /* Link Loss Alert */ #define UUID_SERVCLASS_DST_CHG 0x1806 /* DST Time change */ #define UUID_SERVCLASS_REF_TIME_UPD 0x1807 /* reference time update */ +#define UUID_SERVCLASS_THERMOMETER 0x1809 /* Thermometer UUID */ #define UUID_SERVCLASS_DEVICE_INFO 0x180A /* device info service */ #define UUID_SERVCLASS_NWA 0x180B /* Network availability */ -#define UUID_SERVCLASS_PHALERT 0x180C /* phone alert service */ -#define UUID_SERVCLASS_GLUCOSE 0xC000 /* Glucose Meter Service */ +#define UUID_SERVCLASS_HEART_RATE 0x180D /* Heart Rate service */ +#define UUID_SERVCLASS_PHALERT 0x180E /* phone alert service */ +#define UUID_SERVCLASS_BATTERY 0x180F /* battery service */ +#define UUID_SERVCLASS_BPM 0x1810 /* blood pressure service */ +#define UUID_SERVCLASS_ALERT_NOTIFICATION 0x1811 /* alert notification service */ +#define UUID_SERVCLASS_LE_HID 0x1812 /* HID over LE */ +#define UUID_SERVCLASS_SCAN_PARAM 0x1813 /* Scan Parameter service */ +#define UUID_SERVCLASS_GLUCOSE 0x1808 /* Glucose Meter Service */ +#define UUID_SERVCLASS_RSC 0x1814 /* RUNNERS SPEED AND CADENCE SERVICE */ +#define UUID_SERVCLASS_CSC 0x1816 /* Cycling SPEED AND CADENCE SERVICE */ + #define UUID_SERVCLASS_TEST_SERVER 0x9000 /* Test Group UUID */ #if (BTM_WBS_INCLUDED == TRUE ) diff --git a/stack/include/smp_api.h b/stack/include/smp_api.h index bd7b13147..68c9ebff5 100644 --- a/stack/include/smp_api.h +++ b/stack/include/smp_api.h @@ -61,6 +61,7 @@ typedef UINT8 tSMP_EVT; #define SMP_RSP_TIMEOUT 0x11 #define SMP_DIV_NOT_AVAIL 0x12 #define SMP_FAIL 0x13 /* unspecified failed reason */ +#define SMP_CONN_TOUT 0x14 /* unspecified failed reason */ #define SMP_SUCCESS 0 typedef UINT8 tSMP_STATUS; diff --git a/stack/l2cap/l2c_ble.c b/stack/l2cap/l2c_ble.c index f464ff34d..0a296c88a 100644 --- a/stack/l2cap/l2c_ble.c +++ b/stack/l2cap/l2c_ble.c @@ -48,7 +48,7 @@ BOOLEAN L2CA_CancelBleConnectReq (BD_ADDR rem_bda) tL2C_LCB *p_lcb; /* There can be only one BLE connection request outstanding at a time */ - if (!l2cb.is_ble_connecting) + if (btm_ble_get_conn_st() == BLE_DIR_CONN) { L2CAP_TRACE_WARNING0 ("L2CA_CancelBleConnectReq - no connection pending"); return(FALSE); @@ -72,10 +72,8 @@ BOOLEAN L2CA_CancelBleConnectReq (BD_ADDR rem_bda) p_lcb->disc_reason = L2CAP_CONN_CANCEL; l2cu_release_lcb (p_lcb); } - - l2cb.is_ble_connecting = FALSE; - btm_ble_update_bg_state(); - btm_ble_resume_bg_conn(NULL, TRUE); + /* update conn state to IDLE */ + btm_ble_set_conn_st (BLE_CONN_IDLE); return(TRUE); } @@ -186,10 +184,10 @@ BOOLEAN L2CA_EnableUpdateBleConnParams (BD_ADDR rem_bda, BOOLEAN enable) tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (rem_bda); btsnd_hcic_ble_upd_ll_conn_params (p_lcb->handle, - (UINT16)((p_dev_rec->conn_params.min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.min_conn_int : L2CAP_LE_INT_MIN), - (UINT16)((p_dev_rec->conn_params.max_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.max_conn_int : L2CAP_LE_INT_MAX), - (UINT16)((p_dev_rec->conn_params.slave_latency != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.slave_latency : 0), - (UINT16) ((p_dev_rec->conn_params.supervision_tout != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.supervision_tout : L2CAP_LE_TIMEOUT_MAX), + (UINT16)((p_dev_rec->conn_params.min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.min_conn_int : BTM_BLE_CONN_INT_MIN_DEF), + (UINT16)((p_dev_rec->conn_params.max_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.max_conn_int : BTM_BLE_CONN_INT_MAX_DEF), + (UINT16)((p_dev_rec->conn_params.slave_latency != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.slave_latency : BTM_BLE_CONN_SLAVE_LATENCY_DEF), + (UINT16) ((p_dev_rec->conn_params.supervision_tout != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.supervision_tout : BTM_BLE_CONN_TIMEOUT_DEF), 0, 0); } p_lcb->upd_disabled = UPD_DISABLED; @@ -250,7 +248,8 @@ UINT16 L2CA_GetDisconnectReason (BD_ADDR remote_bda) ** Returns void ** *******************************************************************************/ -void l2cble_scanner_conn_comp (UINT16 handle, BD_ADDR bda, tBLE_ADDR_TYPE type, UINT16 conn_interval, UINT16 conn_latency, UINT16 conn_timeout) +void l2cble_scanner_conn_comp (UINT16 handle, BD_ADDR bda, tBLE_ADDR_TYPE type, + UINT16 conn_interval, UINT16 conn_latency, UINT16 conn_timeout) { tL2C_LCB *p_lcb; tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (bda); @@ -260,9 +259,6 @@ void l2cble_scanner_conn_comp (UINT16 handle, BD_ADDR bda, tBLE_ADDR_TYPE type, l2cb.is_ble_connecting = FALSE; - p_dev_rec->device_type = BT_DEVICE_TYPE_BLE; - p_dev_rec->ble.ble_addr_type = type; - /* See if we have a link control block for the remote device */ p_lcb = l2cu_find_lcb_by_bd_addr (bda); @@ -302,13 +298,13 @@ void l2cble_scanner_conn_comp (UINT16 handle, BD_ADDR bda, tBLE_ADDR_TYPE type, p_lcb->is_ble_link = TRUE; /* If there are any preferred connection parameters, set them now */ - if ( (p_dev_rec->conn_params.min_conn_int >= L2CAP_LE_INT_MIN ) && - (p_dev_rec->conn_params.min_conn_int <= L2CAP_LE_INT_MAX ) && - (p_dev_rec->conn_params.max_conn_int >= L2CAP_LE_INT_MIN ) && - (p_dev_rec->conn_params.max_conn_int <= L2CAP_LE_INT_MAX ) && - (p_dev_rec->conn_params.slave_latency <= L2CAP_LE_LATENCY_MAX ) && - (p_dev_rec->conn_params.supervision_tout >= L2CAP_LE_TIMEOUT_MIN) && - (p_dev_rec->conn_params.supervision_tout <= L2CAP_LE_TIMEOUT_MAX) && + if ( (p_dev_rec->conn_params.min_conn_int >= BTM_BLE_CONN_INT_MIN ) && + (p_dev_rec->conn_params.min_conn_int <= BTM_BLE_CONN_INT_MAX ) && + (p_dev_rec->conn_params.max_conn_int >= BTM_BLE_CONN_INT_MIN ) && + (p_dev_rec->conn_params.max_conn_int <= BTM_BLE_CONN_INT_MAX ) && + (p_dev_rec->conn_params.slave_latency <= BTM_BLE_CONN_LATENCY_MAX ) && + (p_dev_rec->conn_params.supervision_tout >= BTM_BLE_CONN_SUP_TOUT_MIN) && + (p_dev_rec->conn_params.supervision_tout <= BTM_BLE_CONN_SUP_TOUT_MAX) && ((conn_interval < p_dev_rec->conn_params.min_conn_int && p_dev_rec->conn_params.min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) || (conn_interval > p_dev_rec->conn_params.max_conn_int) || @@ -393,9 +389,6 @@ void l2cble_advertiser_conn_comp (UINT16 handle, BD_ADDR bda, tBLE_ADDR_TYPE typ /* Tell BTM Acl management about the link */ p_dev_rec = btm_find_or_alloc_dev (bda); - p_dev_rec->device_type = BT_DEVICE_TYPE_BLE; - p_dev_rec->ble.ble_addr_type = type; - btm_acl_created (bda, NULL, p_dev_rec->sec_bd_name, handle, p_lcb->link_role, TRUE); p_lcb->peer_chnl_mask[0] = L2CAP_FIXED_CHNL_ATT_BIT | L2CAP_FIXED_CHNL_BLE_SIG_BIT | L2CAP_FIXED_CHNL_SMP_BIT; @@ -476,14 +469,14 @@ void l2cble_process_sig_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len) /* If we are a master, the slave wants to update the parameters */ if (p_lcb->link_role == HCI_ROLE_MASTER) { - if (min_interval < L2CAP_LE_INT_MIN || min_interval > L2CAP_LE_INT_MAX || - max_interval < L2CAP_LE_INT_MIN || max_interval > L2CAP_LE_INT_MAX || - latency > L2CAP_LE_LATENCY_MAX || + if (min_interval < BTM_BLE_CONN_INT_MIN || min_interval > BTM_BLE_CONN_INT_MAX || + max_interval < BTM_BLE_CONN_INT_MIN || max_interval > BTM_BLE_CONN_INT_MAX || + latency > BTM_BLE_CONN_LATENCY_MAX || /*(timeout >= max_interval && latency > (timeout * 10/(max_interval * 1.25) - 1)) ||*/ - timeout < L2CAP_LE_TIMEOUT_MIN || timeout > L2CAP_LE_TIMEOUT_MAX || + timeout < BTM_BLE_CONN_SUP_TOUT_MIN || timeout > BTM_BLE_CONN_SUP_TOUT_MAX || max_interval < min_interval) { - result = L2CAP_CFG_UNACCEPTABLE_PARAMS; + l2cu_send_peer_ble_par_rsp (p_lcb, L2CAP_CFG_UNACCEPTABLE_PARAMS, id); } else { @@ -526,58 +519,94 @@ void l2cble_process_sig_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len) /******************************************************************************* ** -** Function l2cble_create_conn +** Function l2cble_init_direct_conn ** -** Description This function initiates an acl connection via HCI +** Description This function is to initate a direct connection ** -** Returns TRUE if successful, FALSE if connection not started. +** Returns TRUE connection initiated, FALSE otherwise. ** *******************************************************************************/ -BOOLEAN l2cble_create_conn (tL2C_LCB *p_lcb) +BOOLEAN l2cble_init_direct_conn (tL2C_LCB *p_lcb) { tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (p_lcb->remote_bd_addr); - tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; - UINT16 scan_int, scan_win; + tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; + UINT16 scan_int, scan_win; + BD_ADDR init_addr; + UINT8 init_addr_type = BLE_ADDR_PUBLIC, + own_addr_type = BLE_ADDR_PUBLIC; /* There can be only one BLE connection request outstanding at a time */ - if (l2cb.is_ble_connecting) + if (p_dev_rec == NULL) { - L2CAP_TRACE_WARNING0 ("L2CAP - LE - cannot start new connection, already connecting"); + BTM_TRACE_WARNING0 ("unknown device, can not initate connection"); return(FALSE); } - p_lcb->link_state = LST_CONNECTING; - l2cb.is_ble_connecting = TRUE; + scan_int = (p_cb->scan_int == BTM_BLE_CONN_PARAM_UNDEF) ? BTM_BLE_SCAN_FAST_INT : p_cb->scan_int; + scan_win = (p_cb->scan_win == BTM_BLE_CONN_PARAM_UNDEF) ? BTM_BLE_SCAN_FAST_WIN : p_cb->scan_win; - memcpy (l2cb.ble_connecting_bda, p_lcb->remote_bd_addr, BD_ADDR_LEN); - btm_ble_suspend_bg_conn(); - - scan_int = (p_cb->scan_int == BTM_BLE_CONN_PARAM_UNDEF) ? L2CAP_LE_INT_MIN : p_cb->scan_int; - scan_win = (p_cb->scan_win == BTM_BLE_CONN_PARAM_UNDEF) ? L2CAP_LE_INT_MIN : p_cb->scan_win; + init_addr_type = p_lcb->ble_addr_type; + memcpy(init_addr, p_lcb->remote_bd_addr, BD_ADDR_LEN); if (!btsnd_hcic_ble_create_ll_conn (scan_int,/* UINT16 scan_int */ scan_win, /* UINT16 scan_win */ FALSE, /* UINT8 white_list */ - p_lcb->ble_addr_type, /* UINT8 addr_type_peer */ - p_lcb->remote_bd_addr, /* BD_ADDR bda_peer */ + p_lcb->ble_addr_type, /* UINT8 addr_type_peer */ + p_lcb->remote_bd_addr, /* BD_ADDR bda_peer */ BLE_ADDR_PUBLIC, /* UINT8 addr_type_own */ - (UINT16) ((p_dev_rec->conn_params.min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.min_conn_int : L2CAP_LE_INT_MIN), /* UINT16 conn_int_min */ - (UINT16) ((p_dev_rec->conn_params.max_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.max_conn_int : L2CAP_LE_INT_MIN), /* UINT16 conn_int_max */ + (UINT16) ((p_dev_rec->conn_params.min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.min_conn_int : BTM_BLE_CONN_INT_MIN), /* UINT16 conn_int_min */ + (UINT16) ((p_dev_rec->conn_params.max_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.max_conn_int : BTM_BLE_CONN_INT_MIN), /* UINT16 conn_int_max */ (UINT16) ((p_dev_rec->conn_params.slave_latency != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.slave_latency : 0), /* UINT16 conn_latency */ - (UINT16) ((p_dev_rec->conn_params.supervision_tout != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.supervision_tout : L2CAP_LE_TIMEOUT_MAX), /* UINT16 conn_timeout */ + (UINT16) ((p_dev_rec->conn_params.supervision_tout != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.supervision_tout : BTM_BLE_CONN_SUP_TOUT_DEF), /* UINT16 conn_timeout */ 0, /* UINT16 min_len */ 0)) /* UINT16 max_len */ { - /* No buffer for connection request ? */ - l2cb.is_ble_connecting = FALSE; - p_lcb->disc_reason = L2CAP_CONN_NO_RESOURCES; l2cu_release_lcb (p_lcb); - return(FALSE); + L2CAP_TRACE_ERROR0("initate direct connection fail, no resources"); + return (FALSE); } else + { + p_lcb->link_state = LST_CONNECTING; + memcpy (l2cb.ble_connecting_bda, p_lcb->remote_bd_addr, BD_ADDR_LEN); btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_BLE_LINK_CONNECT_TOUT); + btm_ble_set_conn_st (BLE_DIR_CONN); - return(TRUE); + return (TRUE); + } +} + +/******************************************************************************* +** +** Function l2cble_create_conn +** +** Description This function initiates an acl connection via HCI +** +** Returns TRUE if successful, FALSE if connection not started. +** +*******************************************************************************/ +BOOLEAN l2cble_create_conn (tL2C_LCB *p_lcb) +{ + tBTM_BLE_CONN_ST conn_st = btm_ble_get_conn_st(); + BOOLEAN rt = FALSE; + + /* There can be only one BLE connection request outstanding at a time */ + if (conn_st == BLE_CONN_IDLE) + { + rt = l2cble_init_direct_conn(p_lcb); + } + else + { + L2CAP_TRACE_WARNING1 ("L2CAP - LE - cannot start new connection at conn st: %d", conn_st); + + btm_ble_enqueue_direct_conn_req(p_lcb); + + if (conn_st == BLE_BG_CONN) + btm_ble_suspend_bg_conn(); + + rt = TRUE; + } + return rt; } /******************************************************************************* diff --git a/stack/l2cap/l2c_fcr.c b/stack/l2cap/l2c_fcr.c index ff018c5cb..9685f774b 100644 --- a/stack/l2cap/l2c_fcr.c +++ b/stack/l2cap/l2c_fcr.c @@ -1486,8 +1486,12 @@ static BOOLEAN do_sar_reassembly (tL2C_CCB *p_ccb, BT_HDR *p_buf, UINT16 ctrl_wo else if (p_buf != NULL) { #if (L2CAP_NUM_FIXED_CHNLS > 0) - if (p_ccb->local_cid < L2CAP_BASE_APPL_CID) - (*l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)(p_ccb->p_lcb->remote_bd_addr, p_buf); + if (p_ccb->local_cid < L2CAP_BASE_APPL_CID && + (p_ccb->local_cid >= L2CAP_FIRST_FIXED_CHNL && p_ccb->local_cid <= L2CAP_LAST_FIXED_CHNL)) + { + if (l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb) + (*l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)(p_ccb->p_lcb->remote_bd_addr, p_buf); + } else #endif l2c_csm_execute (p_ccb, L2CEVT_L2CAP_DATA, p_buf); @@ -1622,7 +1626,7 @@ BT_HDR *l2c_fcr_get_next_xmit_sdu_seg (tL2C_CCB *p_ccb, UINT16 max_packet_length BOOLEAN first_seg = FALSE, /* The segment is the first part of data */ mid_seg = FALSE, /* The segment is the middle part of data */ last_seg = FALSE; /* The segment is the last part of data */ - UINT16 sdu_len; + UINT16 sdu_len = 0; BT_HDR *p_buf, *p_xmit; UINT8 *p; UINT16 max_pdu = p_ccb->tx_mps /* Needed? - L2CAP_MAX_HEADER_FCS*/; diff --git a/stack/l2cap/l2c_int.h b/stack/l2cap/l2c_int.h index 609c8251e..f4eb0086a 100644 --- a/stack/l2cap/l2c_int.h +++ b/stack/l2cap/l2c_int.h @@ -761,6 +761,7 @@ extern BOOLEAN l2cble_create_conn (tL2C_LCB *p_lcb); extern void l2cble_process_sig_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len); extern void l2cble_conn_comp (UINT16 handle, UINT8 role, BD_ADDR bda, tBLE_ADDR_TYPE type, UINT16 conn_interval, UINT16 conn_latency, UINT16 conn_timeout); +extern BOOLEAN l2cble_init_direct_conn (tL2C_LCB *p_lcb); #endif diff --git a/stack/l2cap/l2c_link.c b/stack/l2cap/l2c_link.c index 401084a93..4bb2be7e2 100644 --- a/stack/l2cap/l2c_link.c +++ b/stack/l2cap/l2c_link.c @@ -133,7 +133,10 @@ BOOLEAN l2c_link_hci_conn_req (BD_ADDR bd_addr) } else { - L2CAP_TRACE_ERROR0 ("L2CAP got conn_req while connected"); + L2CAP_TRACE_ERROR1("L2CAP got conn_req while connected (state:%d). Reject it", + p_lcb->link_state); + /* Reject the connection with ACL Connection Already exist reason */ + btsnd_hcic_reject_conn (bd_addr, HCI_ERR_CONNECTION_EXISTS); } return (FALSE); } @@ -202,6 +205,8 @@ BOOLEAN l2c_link_hci_conn_comp (UINT8 status, UINT16 handle, BD_ADDR p_bda) else btm_acl_created (ci.bd_addr, NULL, NULL, handle, p_lcb->link_role, FALSE); + BTM_SetLinkSuperTout (ci.bd_addr, btm_cb.btm_def_link_super_tout); + /* If dedicated bonding do not process any further */ if (p_lcb->is_bonding) { @@ -677,7 +682,7 @@ void l2c_link_adjust_allocation (void) UINT16 controller_xmit_quota = l2cb.num_lm_acl_bufs; UINT16 high_pri_link_quota = L2CAP_HIGH_PRI_MIN_XMIT_QUOTA_A; - /* If no links active, nothing to do. */ + /* If no links active, reset buffer quotas and controller buffers */ if (l2cb.num_links_active == 0) { l2cb.controller_xmit_window = l2cb.num_lm_acl_bufs; @@ -1027,7 +1032,6 @@ void l2c_pin_code_request (BD_ADDR bd_addr) BOOLEAN l2c_link_check_power_mode (tL2C_LCB *p_lcb) { tBTM_PM_MODE mode; - tBTM_PM_PWR_MD pm; tL2C_CCB *p_ccb; BOOLEAN need_to_active = FALSE; @@ -1054,29 +1058,10 @@ BOOLEAN l2c_link_check_power_mode (tL2C_LCB *p_lcb) /* check power mode */ if (BTM_ReadPowerMode(p_lcb->remote_bd_addr, &mode) == BTM_SUCCESS) { - /* - if ( mode == BTM_PM_MD_PARK ) - { - L2CAP_TRACE_DEBUG1 ("LCB(0x%x) is in park mode", p_lcb->handle); -// Coverity: -// FALSE-POSITIVE error from Coverity test tool. Please do NOT remove following comment. -// coverity[uninit_use_in_call] False-positive: setting the mode to BTM_PM_MD_ACTIVE only uses settings.mode - the other data members of tBTM_PM_PWR_MD are ignored - - memset((void*)&pm, 0, sizeof(pm)); - pm.mode = BTM_PM_MD_ACTIVE; - BTM_SetPowerMode(BTM_PM_SET_ONLY_ID, p_lcb->remote_bd_addr, &pm); - btu_start_timer (&p_lcb->timer_entry, - BTU_TTYPE_L2CAP_LINK, L2CAP_WAIT_UNPARK_TOUT); - return TRUE; - } - */ if ( mode == BTM_PM_STS_PENDING ) { L2CAP_TRACE_DEBUG1 ("LCB(0x%x) is in PM pending state", p_lcb->handle); - btu_start_timer (&p_lcb->timer_entry, - BTU_TTYPE_L2CAP_LINK, L2CAP_WAIT_UNPARK_TOUT); return TRUE; } } diff --git a/stack/l2cap/l2c_main.c b/stack/l2cap/l2c_main.c index 6c29cff31..49dd8113e 100644 --- a/stack/l2cap/l2c_main.c +++ b/stack/l2cap/l2c_main.c @@ -50,7 +50,7 @@ tL2C_CB l2cb; /* Temporary - until l2cap implements group management */ #if (TCS_BCST_SETUP_INCLUDED == TRUE && TCS_INCLUDED == TRUE) extern void tcs_proc_bcst_msg( BD_ADDR addr, BT_HDR *p_msg ) ; - +#endif /******************************************************************************* ** ** Function l2c_bcst_msg @@ -104,7 +104,7 @@ void l2c_bcst_msg( BT_HDR *p_buf, UINT16 psm ) HCI_ACL_DATA_TO_LOWER (p_buf); } } -#endif + /******************************************************************************* ** @@ -680,31 +680,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len) break; case L2CAP_CMD_ECHO_REQ: - -#if (L2CAP_ENHANCED_FEATURES != 0) - if (!l2cu_check_feature_req (p_lcb, id, p, cmd_len)) - { - if (cmd_len < (btu_cb.hcit_acl_pkt_size - L2CAP_PKT_OVERHEAD - - L2CAP_CMD_OVERHEAD - - L2CAP_ECHO_RSP_LEN - - HCI_DATA_PREAMBLE_SIZE)) - { - l2cu_send_peer_echo_rsp (p_lcb, id, p, cmd_len); - } - else - { - l2cu_send_peer_echo_rsp (p_lcb, id, NULL, 0); - } - } -#else l2cu_send_peer_echo_rsp (p_lcb, id, NULL, 0); -#endif break; case L2CAP_CMD_ECHO_RSP: -#if (L2CAP_ENHANCED_FEATURES != 0) - l2cu_check_feature_rsp (p_lcb, id, p, cmd_len); -#endif if (p_lcb->p_echo_rsp_cb) { tL2CA_ECHO_RSP_CB *p_cb = p_lcb->p_echo_rsp_cb; diff --git a/stack/l2cap/l2c_utils.c b/stack/l2cap/l2c_utils.c index fd618ed6a..581930f1c 100644 --- a/stack/l2cap/l2c_utils.c +++ b/stack/l2cap/l2c_utils.c @@ -307,13 +307,6 @@ BT_HDR *l2cu_build_header (tL2C_LCB *p_lcb, UINT16 len, UINT8 cmd, UINT8 id) *******************************************************************************/ void l2cu_adj_id (tL2C_LCB *p_lcb, UINT8 adj_mask) { -#if (L2CAP_ENHANCED_FEATURES != 0) - if ((adj_mask & L2CAP_ADJ_BRCM_ID) && p_lcb->id == L2CAP_FEATURE_REQ_ID) - { - p_lcb->id++; - } -#endif - if ((adj_mask & L2CAP_ADJ_ZERO_ID) && !p_lcb->id) { p_lcb->id++; @@ -1546,6 +1539,9 @@ void l2cu_release_ccb (tL2C_CCB *p_ccb) { btm_sec_clr_service_by_psm(p_rcb->psm); } + + btm_sec_clr_temp_auth_service (p_lcb->remote_bd_addr); + /* Stop the timer */ btu_stop_timer (&p_ccb->timer_entry); @@ -2056,6 +2052,9 @@ void l2cu_device_reset (void) l2c_link_hci_disc_comp (p_lcb->handle, (UINT8) -1); } } +#if (BLE_INCLUDED == TRUE) + l2cb.is_ble_connecting = FALSE; +#endif } #if (TCS_WUG_MEMBER_INCLUDED == TRUE && TCS_INCLUDED == TRUE) @@ -2391,153 +2390,6 @@ BOOLEAN l2cu_set_acl_priority (BD_ADDR bd_addr, UINT8 priority, BOOLEAN reset_af return(TRUE); } -#if (L2CAP_ENHANCED_FEATURES != 0) -/******************************************************************************* -** -** Function l2cu_send_feature_req -** -** Description Called at connection establishment by the originator -** of the connection to send an L2CAP Echo request message -** to the peer to determine if he supports Widcomm proprietary -** features. -** -** Returns void -** -*******************************************************************************/ -void l2cu_send_feature_req (tL2C_CCB *p_ccb) -{ - UINT8 saved_id; - UINT8 buff[100], *p = buff; - - UINT8_TO_STREAM (p, 'R'); - UINT8_TO_STREAM (p, 'Q'); - - UINT8_TO_STREAM (p, 'r'); - UINT8_TO_STREAM (p, 'q'); - - /* save current ID to be restored after feature request */ - saved_id = p_ccb->p_lcb->id; - - /* Set appropriate ID */ - p_ccb->p_lcb->id = L2CAP_FEATURE_REQ_ID - 1; - - l2cu_send_peer_echo_req (p_ccb->p_lcb, buff, (UINT16)(p - buff)); - - /* packet has been built so we can restore the control block id */ - p_ccb->p_lcb->id = saved_id; -} - - - -/******************************************************************************* -** -** Function l2cu_check_feature_req -** -** Description Called when an echo request is received to check if the -** other side is doing a proprietary feature request. If so, -** extract the values and reply with a features response. -** -** Returns void -** -*******************************************************************************/ -BOOLEAN l2cu_check_feature_req (tL2C_LCB *p_lcb, UINT8 id, UINT8 *p_data, UINT16 data_len) -{ - UINT8 buff[100]; - UINT8 *p_out = buff; - UINT8 *p_end = p_data + data_len - 2; - UINT8 pe_type, pe_len; - - if ((data_len <= 4) - || (p_data[0] != 'R') - || (p_data[1] != 'Q') - || (p_data[data_len - 2] != 'r') - || (p_data[data_len - 1] != 'q') - || (id != L2CAP_FEATURE_REQ_ID)) - return (FALSE); - - /* Skip leading frame characters */ - p_data += 2; - - UINT8_TO_STREAM (p_out, 'R'); - UINT8_TO_STREAM (p_out, 'S'); - - while (p_data < p_end) - { - pe_type = *p_data++; - pe_len = *p_data++; - - switch (pe_type) - { - default: - p_data += pe_len; - break; - } - } - - /* Sanity check - we should not overrun the input */ - if (p_data != p_end) - { - L2CAP_TRACE_ERROR0 ("L2CAP - badly formatted feature req"); - return (FALSE); - } - - UINT8_TO_STREAM (p_out, 'r'); - UINT8_TO_STREAM (p_out, 's'); - - l2cu_send_peer_echo_rsp (p_lcb, L2CAP_FEATURE_RSP_ID, buff, (UINT16)(p_out - buff)); - - return (TRUE); -} - -/******************************************************************************* -** -** Function l2cu_check_feature_rsp -** -** Description Called when an echo response is received to check if the -** other side is suports proprietary feature(s). If so, -** extract the values. -** -** Returns void -** -*******************************************************************************/ -void l2cu_check_feature_rsp (tL2C_LCB *p_lcb, UINT8 id, UINT8 *p_data, UINT16 data_len) -{ - UINT8 *p_end = p_data + data_len - 2; - - if ((data_len <= 4) - || (p_data[0] != 'R') - || (p_data[1] != 'S') - || (p_data[data_len - 2] != 'r') - || (p_data[data_len - 1] != 's') - || (id != L2CAP_FEATURE_RSP_ID)) - { - return; - } - - /* Skip leading frame characters */ - p_data += 2; - - while (p_data < p_end) - { - UINT8 pe_id = *p_data++; - UINT8 pe_len = *p_data++; - - switch (pe_id) - { - default: - p_data += pe_len; - break; - } - } - - /* Sanity check - we should not overrun the input */ - if (p_data != p_end) - { - L2CAP_TRACE_ERROR0 ("L2CAP - badly formatted feature rsp"); - } -} -#endif /* L2CAP_ENHANCED_FEATURES != 0 */ - #if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE) /****************************************************************************** ** @@ -2697,6 +2549,8 @@ BOOLEAN l2cu_initialize_fixed_ccb (tL2C_LCB *p_lcb, UINT16 fixed_cid, tL2CAP_FCR if ((p_ccb = l2cu_allocate_ccb (NULL, 0)) == NULL) return (FALSE); + btu_stop_timer(&p_lcb->timer_entry); + /* Set CID for the connection */ p_ccb->local_cid = fixed_cid; p_ccb->remote_cid = fixed_cid; @@ -2836,11 +2690,15 @@ void l2cu_process_fixed_chnl_resp (tL2C_LCB *p_lcb) (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(p_lcb->remote_bd_addr, TRUE, reason); } - else if (p_lcb->p_fixed_ccbs[xx]) + else { (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(p_lcb->remote_bd_addr, FALSE, p_lcb->disc_reason); - l2cu_release_ccb (p_lcb->p_fixed_ccbs[xx]); - p_lcb->p_fixed_ccbs[xx] = NULL; + + if (p_lcb->p_fixed_ccbs[xx]) + { + l2cu_release_ccb (p_lcb->p_fixed_ccbs[xx]); + p_lcb->p_fixed_ccbs[xx] = NULL; + } } } } @@ -3219,6 +3077,11 @@ BT_HDR *l2cu_get_next_buffer_to_send (tL2C_LCB *p_lcb) if (p_ccb->xmit_hold_q.count != 0) { p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->xmit_hold_q); + if(NULL == p_buf) + { + L2CAP_TRACE_ERROR0("l2cu_get_buffer_to_send: No data to be sent"); + return (NULL); + } l2cu_set_acl_hci_header (p_buf, p_ccb); return (p_buf); } @@ -3245,6 +3108,11 @@ BT_HDR *l2cu_get_next_buffer_to_send (tL2C_LCB *p_lcb) else { p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->xmit_hold_q); + if(NULL == p_buf) + { + L2CAP_TRACE_ERROR0("l2cu_get_buffer_to_send() #2: No data to be sent"); + return (NULL); + } } if ( p_ccb->p_rcb && p_ccb->p_rcb->api.pL2CA_TxComplete_Cb && (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_ERTM_MODE) ) diff --git a/stack/mcap/mca_int.h b/stack/mcap/mca_int.h index 2563f7fb8..54ff0c039 100644 --- a/stack/mcap/mca_int.h +++ b/stack/mcap/mca_int.h @@ -322,9 +322,18 @@ extern void mca_process_timeout(TIMER_LIST_ENT *p_tle); extern void mca_stop_timer(tMCA_CCB *p_ccb); /* l2c functions */ +extern UINT16 mca_l2c_open_req(BD_ADDR bd_addr, UINT16 PSM, const tMCA_CHNL_CFG *p_chnl_cfg); + +/* callback function declarations */ extern void mca_l2c_cconn_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id); extern void mca_l2c_dconn_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id); -extern UINT16 mca_l2c_open_req(BD_ADDR bd_addr, UINT16 PSM, const tMCA_CHNL_CFG *p_chnl_cfg); +extern void mca_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result); +extern void mca_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg); +extern void mca_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg); +extern void mca_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed); +extern void mca_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result); +extern void mca_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested); +extern void mca_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf); /***************************************************************************** ** global data diff --git a/stack/mcap/mca_l2c.c b/stack/mcap/mca_l2c.c index f8a48bfc4..23d56f5d6 100644 --- a/stack/mcap/mca_l2c.c +++ b/stack/mcap/mca_l2c.c @@ -30,19 +30,10 @@ #include "mca_defs.h" #include "mca_int.h" -/* callback function declarations */ -void mca_l2c_cconn_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id); -void mca_l2c_dconn_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id); -void mca_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result); -void mca_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg); -void mca_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg); -void mca_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed); -void mca_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result); -void mca_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested); -void mca_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf); /* L2CAP callback function structure */ -const tL2CAP_APPL_INFO mca_l2c_int_appl = { +const tL2CAP_APPL_INFO mca_l2c_int_appl = +{ NULL, mca_l2c_connect_cfm_cback, NULL, @@ -52,11 +43,13 @@ const tL2CAP_APPL_INFO mca_l2c_int_appl = { mca_l2c_disconnect_cfm_cback, NULL, mca_l2c_data_ind_cback, - mca_l2c_congestion_ind_cback + mca_l2c_congestion_ind_cback, + NULL }; /* Control channel eL2CAP default options */ -const tL2CAP_FCR_OPTS mca_l2c_fcr_opts_def = { +const tL2CAP_FCR_OPTS mca_l2c_fcr_opts_def = +{ L2CAP_FCR_ERTM_MODE, /* Mandatory for MCAP */ MCA_FCR_OPT_TX_WINDOW_SIZE, /* Tx window size */ MCA_FCR_OPT_MAX_TX_B4_DISCNT, /* Maximum transmissions before disconnecting */ diff --git a/stack/mcap/mca_main.c b/stack/mcap/mca_main.c index 2e05d5ee4..d09319df5 100644 --- a/stack/mcap/mca_main.c +++ b/stack/mcap/mca_main.c @@ -563,6 +563,7 @@ void mca_rcb_dealloc(tMCA_HANDLE handle) if (done) { memset (p_rcb, 0, sizeof(tMCA_RCB)); + MCA_TRACE_DEBUG1("Reset MCA_RCB index=%d",handle); } } } diff --git a/stack/sdp/sdp_db.c b/stack/sdp/sdp_db.c index b5ab31a78..318a8cc24 100644 --- a/stack/sdp/sdp_db.c +++ b/stack/sdp/sdp_db.c @@ -538,11 +538,18 @@ BOOLEAN SDP_AddSequence (UINT32 handle, UINT16 attr_id, UINT16 num_elem, { #if SDP_SERVER_ENABLED == TRUE UINT16 xx; - UINT8 buff[SDP_MAX_ATTR_LEN * 2]; + UINT8 *p_buff; UINT8 *p; UINT8 *p_head; + BOOLEAN result; + + if ((p_buff = (UINT8 *) GKI_getbuf(sizeof(UINT8) * SDP_MAX_ATTR_LEN * 2)) == NULL) + { + SDP_TRACE_ERROR0("SDP_AddSequence cannot get a buffer!"); + return (FALSE); + } + p = p_buff; - p = buff; /* First, build the sequence */ for (xx = 0; xx < num_elem; xx++) { @@ -572,14 +579,15 @@ BOOLEAN SDP_AddSequence (UINT32 handle, UINT16 attr_id, UINT16 num_elem, ARRAY_TO_BE_STREAM (p, p_val[xx], len[xx]); - if (p - buff > SDP_MAX_ATTR_LEN) + if (p - p_buff > SDP_MAX_ATTR_LEN) { /* go back to before we add this element */ p = p_head; - if(p_head == buff) + if(p_head == p_buff) { /* the first element exceed the max length */ SDP_TRACE_ERROR0 ("SDP_AddSequence - too long(attribute is not added)!!"); + GKI_freebuf(p_buff); return FALSE; } else @@ -587,9 +595,9 @@ BOOLEAN SDP_AddSequence (UINT32 handle, UINT16 attr_id, UINT16 num_elem, break; } } - - return (SDP_AddAttribute (handle, attr_id, DATA_ELE_SEQ_DESC_TYPE, - (UINT32) (p - buff), buff)); + result = SDP_AddAttribute (handle, attr_id, DATA_ELE_SEQ_DESC_TYPE,(UINT32) (p - p_buff), p_buff); + GKI_freebuf(p_buff); + return result; #else /* SDP_SERVER_ENABLED == FALSE */ return (FALSE); #endif @@ -613,9 +621,17 @@ BOOLEAN SDP_AddUuidSequence (UINT32 handle, UINT16 attr_id, UINT16 num_uuids, { #if SDP_SERVER_ENABLED == TRUE UINT16 xx; - UINT8 buff[SDP_MAX_ATTR_LEN * 2]; - UINT8 *p = buff; + UINT8 *p_buff; + UINT8 *p; INT32 max_len = SDP_MAX_ATTR_LEN -3; + BOOLEAN result; + + if ((p_buff = (UINT8 *) GKI_getbuf(sizeof(UINT8) * SDP_MAX_ATTR_LEN * 2)) == NULL) + { + SDP_TRACE_ERROR0("SDP_AddUuidSequence cannot get a buffer!"); + return (FALSE); + } + p = p_buff; /* First, build the sequence */ for (xx = 0; xx < num_uuids ; xx++, p_uuids++) @@ -623,15 +639,16 @@ BOOLEAN SDP_AddUuidSequence (UINT32 handle, UINT16 attr_id, UINT16 num_uuids, UINT8_TO_BE_STREAM (p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES); UINT16_TO_BE_STREAM (p, *p_uuids); - if((p - buff) > max_len) + if((p - p_buff) > max_len) { SDP_TRACE_WARNING2 ("SDP_AddUuidSequence - too long, add %d uuids of %d", xx, num_uuids); break; } } - return (SDP_AddAttribute (handle, attr_id, DATA_ELE_SEQ_DESC_TYPE, - (UINT32) (p - buff), buff)); + result = SDP_AddAttribute (handle, attr_id, DATA_ELE_SEQ_DESC_TYPE,(UINT32) (p - p_buff), p_buff); + GKI_freebuf(p_buff); + return result; #else /* SDP_SERVER_ENABLED == FALSE */ return (FALSE); #endif @@ -653,13 +670,20 @@ BOOLEAN SDP_AddProtocolList (UINT32 handle, UINT16 num_elem, tSDP_PROTOCOL_ELEM *p_elem_list) { #if SDP_SERVER_ENABLED == TRUE - UINT8 buff[SDP_MAX_ATTR_LEN * 2]; - int offset; + UINT8 *p_buff; + int offset; + BOOLEAN result; - offset = sdp_compose_proto_list(buff, num_elem, p_elem_list); + if ((p_buff = (UINT8 *) GKI_getbuf(sizeof(UINT8) * SDP_MAX_ATTR_LEN * 2)) == NULL) + { + SDP_TRACE_ERROR0("SDP_AddProtocolList cannot get a buffer!"); + return (FALSE); + } - return (SDP_AddAttribute (handle, ATTR_ID_PROTOCOL_DESC_LIST, - DATA_ELE_SEQ_DESC_TYPE, (UINT32) offset, buff)); + offset = sdp_compose_proto_list(p_buff, num_elem, p_elem_list); + result = SDP_AddAttribute (handle, ATTR_ID_PROTOCOL_DESC_LIST,DATA_ELE_SEQ_DESC_TYPE, (UINT32) offset, p_buff); + GKI_freebuf(p_buff); + return result; #else /* SDP_SERVER_ENABLED == FALSE */ return (FALSE); #endif @@ -683,10 +707,18 @@ BOOLEAN SDP_AddAdditionProtoLists (UINT32 handle, UINT16 num_elem, { #if SDP_SERVER_ENABLED == TRUE UINT16 xx; - UINT8 buff[SDP_MAX_ATTR_LEN * 2]; - UINT8 *p = buff; - UINT8 *p_len; - int offset; + UINT8 *p_buff; + UINT8 *p; + UINT8 *p_len; + int offset; + BOOLEAN result; + + if ((p_buff = (UINT8 *) GKI_getbuf(sizeof(UINT8) * SDP_MAX_ATTR_LEN * 2)) == NULL) + { + SDP_TRACE_ERROR0("SDP_AddAdditionProtoLists cannot get a buffer!"); + return (FALSE); + } + p = p_buff; /* for each ProtocolDescriptorList */ for (xx = 0; xx < num_elem; xx++, p_proto_list++) @@ -700,9 +732,11 @@ BOOLEAN SDP_AddAdditionProtoLists (UINT32 handle, UINT16 num_elem, *p_len = (UINT8)(p - p_len - 1); } + result = SDP_AddAttribute (handle, ATTR_ID_ADDITION_PROTO_DESC_LISTS,DATA_ELE_SEQ_DESC_TYPE, + (UINT32) (p - p_buff), p_buff); + GKI_freebuf(p_buff); + return result; - return (SDP_AddAttribute (handle, ATTR_ID_ADDITION_PROTO_DESC_LISTS, - DATA_ELE_SEQ_DESC_TYPE, (UINT32) (p - buff), buff)); #else /* SDP_SERVER_ENABLED == FALSE */ return (FALSE); #endif @@ -724,8 +758,16 @@ BOOLEAN SDP_AddProfileDescriptorList (UINT32 handle, UINT16 profile_uuid, UINT16 version) { #if SDP_SERVER_ENABLED == TRUE - UINT8 buff[SDP_MAX_ATTR_LEN]; - UINT8 *p = &buff[2]; + UINT8 *p_buff; + UINT8 *p; + BOOLEAN result; + + if ((p_buff = (UINT8 *) GKI_getbuf(sizeof(UINT8) * SDP_MAX_ATTR_LEN)) == NULL) + { + SDP_TRACE_ERROR0("SDP_AddProfileDescriptorList cannot get a buffer!"); + return (FALSE); + } + p = p_buff+2; /* First, build the profile descriptor list. This consists of a data element sequence. */ /* The sequence consists of profile's UUID and version number */ @@ -736,11 +778,13 @@ BOOLEAN SDP_AddProfileDescriptorList (UINT32 handle, UINT16 profile_uuid, UINT16_TO_BE_STREAM (p, version); /* Add in type and length fields */ - buff[0] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE); - buff[1] = (UINT8) (p - &buff[2]); + *p_buff = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE); + *(p_buff+1) = (UINT8) (p - (p_buff+2)); + + result = SDP_AddAttribute (handle, ATTR_ID_BT_PROFILE_DESC_LIST,DATA_ELE_SEQ_DESC_TYPE, (UINT32) (p - p_buff), p_buff); + GKI_freebuf(p_buff); + return result; - return (SDP_AddAttribute (handle, ATTR_ID_BT_PROFILE_DESC_LIST, - DATA_ELE_SEQ_DESC_TYPE, (UINT32) (p - buff), buff)); #else /* SDP_SERVER_ENABLED == FALSE */ return (FALSE); #endif @@ -763,8 +807,16 @@ BOOLEAN SDP_AddLanguageBaseAttrIDList (UINT32 handle, UINT16 lang, UINT16 char_enc, UINT16 base_id) { #if SDP_SERVER_ENABLED == TRUE - UINT8 buff[SDP_MAX_ATTR_LEN]; - UINT8 *p = buff; + UINT8 *p_buff; + UINT8 *p; + BOOLEAN result; + + if ((p_buff = (UINT8 *) GKI_getbuf(sizeof(UINT8) * SDP_MAX_ATTR_LEN)) == NULL) + { + SDP_TRACE_ERROR0("SDP_AddLanguageBaseAttrIDList cannot get a buffer!"); + return (FALSE); + } + p = p_buff; /* First, build the language base descriptor list. This consists of a data */ /* element sequence. The sequence consists of 9 bytes (3 UINt16 fields) */ @@ -777,8 +829,10 @@ BOOLEAN SDP_AddLanguageBaseAttrIDList (UINT32 handle, UINT16 lang, UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES); UINT16_TO_BE_STREAM (p, base_id); - return (SDP_AddAttribute (handle, ATTR_ID_LANGUAGE_BASE_ATTR_ID_LIST, - DATA_ELE_SEQ_DESC_TYPE, (UINT32) (p - buff), buff)); + result = SDP_AddAttribute (handle, ATTR_ID_LANGUAGE_BASE_ATTR_ID_LIST,DATA_ELE_SEQ_DESC_TYPE, + (UINT32) (p - p_buff), p_buff); + GKI_freebuf(p_buff); + return result; #else /* SDP_SERVER_ENABLED == FALSE */ return (FALSE); #endif @@ -802,8 +856,16 @@ BOOLEAN SDP_AddServiceClassIdList (UINT32 handle, UINT16 num_services, { #if SDP_SERVER_ENABLED == TRUE UINT16 xx; - UINT8 buff[SDP_MAX_ATTR_LEN * 2]; - UINT8 *p = buff; + UINT8 *p_buff; + UINT8 *p; + BOOLEAN result; + + if ((p_buff = (UINT8 *) GKI_getbuf(sizeof(UINT8) * SDP_MAX_ATTR_LEN * 2)) == NULL) + { + SDP_TRACE_ERROR0("SDP_AddServiceClassIdList cannot get a buffer!"); + return (FALSE); + } + p = p_buff; for (xx = 0; xx < num_services; xx++, p_service_uuids++) { @@ -811,8 +873,10 @@ BOOLEAN SDP_AddServiceClassIdList (UINT32 handle, UINT16 num_services, UINT16_TO_BE_STREAM (p, *p_service_uuids); } - return (SDP_AddAttribute (handle, ATTR_ID_SERVICE_CLASS_ID_LIST, - DATA_ELE_SEQ_DESC_TYPE, (UINT32) (p - buff), buff)); + result = SDP_AddAttribute (handle, ATTR_ID_SERVICE_CLASS_ID_LIST,DATA_ELE_SEQ_DESC_TYPE, + (UINT32) (p - p_buff), p_buff); + GKI_freebuf(p_buff); + return result; #else /* SDP_SERVER_ENABLED == FALSE */ return (FALSE); #endif diff --git a/stack/sdp/sdp_server.c b/stack/sdp/sdp_server.c index 5736b8dea..342d93e7a 100644 --- a/stack/sdp/sdp_server.c +++ b/stack/sdp/sdp_server.c @@ -173,7 +173,7 @@ static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num, tSDP_UUID_SEQ uid_seq; UINT8 *p_rsp, *p_rsp_start, *p_rsp_param_len; UINT16 rsp_param_len, num_rsp_handles, xx; - UINT32 rsp_handles[SDP_MAX_RECORDS]; + UINT32 rsp_handles[SDP_MAX_RECORDS] = {0}; tSDP_RECORD *p_rec = NULL; BT_HDR *p_buf; BOOLEAN is_cont = FALSE; @@ -430,7 +430,7 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num, } else if (rem_len < attr_len) /* Not enough space for attr... so add partially */ { - if (attr_len >= MAX_ATTR_LEN) + if (attr_len >= SDP_MAX_ATTR_LEN) { SDP_TRACE_ERROR2("SDP attr too big: max_list_len=%d,attr_len=%d", max_list_len, attr_len); sdpu_build_n_send_error (p_ccb, trans_num, SDP_NO_RESOURCES, NULL); @@ -697,7 +697,7 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num, } else if (rem_len < attr_len) /* Not enough space for attr... so add partially */ { - if (attr_len >= MAX_ATTR_LEN) + if (attr_len >= SDP_MAX_ATTR_LEN) { SDP_TRACE_ERROR2("SDP attr too big: max_list_len=%d,attr_len=%d", max_list_len, attr_len); sdpu_build_n_send_error (p_ccb, trans_num, SDP_NO_RESOURCES, NULL); diff --git a/stack/sdp/sdp_utils.c b/stack/sdp/sdp_utils.c index cda0570d9..842e75784 100644 --- a/stack/sdp/sdp_utils.c +++ b/stack/sdp/sdp_utils.c @@ -884,7 +884,7 @@ UINT16 sdpu_get_attrib_seq_len(tSDP_RECORD *p_rec, tSDP_ATTR_SEQ *attr_seq) UINT16 len1 = 0; UINT16 xx; BOOLEAN is_range = FALSE; - UINT16 start_id, end_id; + UINT16 start_id=0, end_id=0; for (xx = 0; xx < attr_seq->num_attr; xx++) { @@ -999,21 +999,29 @@ UINT16 sdpu_get_attrib_entry_len(tSDP_ATTRIBUTE *p_attr) *******************************************************************************/ UINT8 *sdpu_build_partial_attrib_entry (UINT8 *p_out, tSDP_ATTRIBUTE *p_attr, UINT16 len, UINT16 *offset) { - UINT8 tmp_attr[MAX_ATTR_LEN]; - UINT8 *p_tmp_attr = &tmp_attr[0]; + UINT8 *p_attr_buff; + UINT8 *p_tmp_attr; size_t len_to_copy; UINT16 attr_len; + if ((p_attr_buff = (UINT8 *) GKI_getbuf(sizeof(UINT8) * SDP_MAX_ATTR_LEN )) == NULL) + { + SDP_TRACE_ERROR0("sdpu_build_partial_attrib_entry cannot get a buffer!"); + return NULL; + } + p_tmp_attr = p_attr_buff; + sdpu_build_attrib_entry(p_tmp_attr, p_attr); attr_len = sdpu_get_attrib_entry_len(p_attr); len_to_copy = ((attr_len - *offset) < len) ? (attr_len - *offset): len; - memcpy(p_out, &tmp_attr[*offset], len_to_copy); + memcpy(p_out, &p_attr_buff[*offset], len_to_copy); p_out = &p_out[len_to_copy]; *offset += len_to_copy; + GKI_freebuf(p_attr_buff); return p_out; } diff --git a/stack/smp/aes.c b/stack/smp/aes.c new file mode 100644 index 000000000..1028d5b06 --- /dev/null +++ b/stack/smp/aes.c @@ -0,0 +1,926 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The redistribution and use of this software (with or without changes) + is allowed without the payment of fees or royalties provided that: + + 1. source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + 2. binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation; + + 3. the name of the copyright holder is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue 09/09/2006 + + This is an AES implementation that uses only 8-bit byte operations on the + cipher state (there are options to use 32-bit types if available). + + The combination of mix columns and byte substitution used here is based on + that developed by Karl Malbrain. His contribution is acknowledged. + */ + +/* define if you have a fast memcpy function on your system */ +#if 1 +# define HAVE_MEMCPY +# include <string.h> +#if 0 +# if defined( _MSC_VER ) +# include <intrin.h> +# pragma intrinsic( memcpy ) +# endif +#endif +#endif + +#include <stdlib.h> + +/* define if you have fast 32-bit types on your system */ +#if 1 +# define HAVE_UINT_32T +#endif + +/* define if you don't want any tables */ +#if 1 +# define USE_TABLES +#endif + +/* On Intel Core 2 duo VERSION_1 is faster */ + +/* alternative versions (test for performance on your system) */ +#if 1 +# define VERSION_1 +#endif + +#include "aes.h" + +#if defined( HAVE_UINT_32T ) + typedef unsigned long uint_32t; +#endif + +/* functions for finite field multiplication in the AES Galois field */ + +#define WPOLY 0x011b +#define BPOLY 0x1b +#define DPOLY 0x008d + +#define f1(x) (x) +#define f2(x) ((x << 1) ^ (((x >> 7) & 1) * WPOLY)) +#define f4(x) ((x << 2) ^ (((x >> 6) & 1) * WPOLY) ^ (((x >> 6) & 2) * WPOLY)) +#define f8(x) ((x << 3) ^ (((x >> 5) & 1) * WPOLY) ^ (((x >> 5) & 2) * WPOLY) \ + ^ (((x >> 5) & 4) * WPOLY)) +#define d2(x) (((x) >> 1) ^ ((x) & 1 ? DPOLY : 0)) + +#define f3(x) (f2(x) ^ x) +#define f9(x) (f8(x) ^ x) +#define fb(x) (f8(x) ^ f2(x) ^ x) +#define fd(x) (f8(x) ^ f4(x) ^ x) +#define fe(x) (f8(x) ^ f4(x) ^ f2(x)) + +#if defined( USE_TABLES ) + +#define sb_data(w) { /* S Box data values */ \ + w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\ + w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\ + w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\ + w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\ + w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\ + w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\ + w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\ + w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\ + w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\ + w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\ + w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\ + w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\ + w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\ + w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\ + w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\ + w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\ + w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\ + w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\ + w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\ + w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\ + w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\ + w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\ + w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\ + w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\ + w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\ + w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\ + w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\ + w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\ + w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\ + w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\ + w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\ + w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) } + +#define isb_data(w) { /* inverse S Box data values */ \ + w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38),\ + w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb),\ + w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87),\ + w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb),\ + w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d),\ + w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e),\ + w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2),\ + w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25),\ + w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16),\ + w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92),\ + w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda),\ + w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84),\ + w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a),\ + w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06),\ + w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02),\ + w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b),\ + w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea),\ + w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73),\ + w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85),\ + w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e),\ + w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89),\ + w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b),\ + w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20),\ + w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4),\ + w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31),\ + w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f),\ + w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d),\ + w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef),\ + w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0),\ + w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61),\ + w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26),\ + w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d) } + +#define mm_data(w) { /* basic data for forming finite field tables */ \ + w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07),\ + w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f),\ + w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17),\ + w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f),\ + w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27),\ + w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f),\ + w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37),\ + w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f),\ + w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47),\ + w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f),\ + w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57),\ + w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f),\ + w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67),\ + w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f),\ + w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77),\ + w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f),\ + w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87),\ + w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f),\ + w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97),\ + w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f),\ + w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7),\ + w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf),\ + w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7),\ + w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf),\ + w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7),\ + w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf),\ + w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7),\ + w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf),\ + w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7),\ + w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef),\ + w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7),\ + w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff) } + +static const uint_8t sbox[256] = sb_data(f1); +static const uint_8t isbox[256] = isb_data(f1); + +static const uint_8t gfm2_sbox[256] = sb_data(f2); +static const uint_8t gfm3_sbox[256] = sb_data(f3); + +static const uint_8t gfmul_9[256] = mm_data(f9); +static const uint_8t gfmul_b[256] = mm_data(fb); +static const uint_8t gfmul_d[256] = mm_data(fd); +static const uint_8t gfmul_e[256] = mm_data(fe); + +#define s_box(x) sbox[(x)] +#define is_box(x) isbox[(x)] +#define gfm2_sb(x) gfm2_sbox[(x)] +#define gfm3_sb(x) gfm3_sbox[(x)] +#define gfm_9(x) gfmul_9[(x)] +#define gfm_b(x) gfmul_b[(x)] +#define gfm_d(x) gfmul_d[(x)] +#define gfm_e(x) gfmul_e[(x)] + +#else + +/* this is the high bit of x right shifted by 1 */ +/* position. Since the starting polynomial has */ +/* 9 bits (0x11b), this right shift keeps the */ +/* values of all top bits within a byte */ + +static uint_8t hibit(const uint_8t x) +{ uint_8t r = (uint_8t)((x >> 1) | (x >> 2)); + + r |= (r >> 2); + r |= (r >> 4); + return (r + 1) >> 1; +} + +/* return the inverse of the finite field element x */ + +static uint_8t gf_inv(const uint_8t x) +{ uint_8t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0; + + if(x < 2) + return x; + + for( ; ; ) + { + if(n1) + while(n2 >= n1) /* divide polynomial p2 by p1 */ + { + n2 /= n1; /* shift smaller polynomial left */ + p2 ^= (p1 * n2) & 0xff; /* and remove from larger one */ + v2 ^= (v1 * n2); /* shift accumulated value and */ + n2 = hibit(p2); /* add into result */ + } + else + return v1; + + if(n2) /* repeat with values swapped */ + while(n1 >= n2) + { + n1 /= n2; + p1 ^= p2 * n1; + v1 ^= v2 * n1; + n1 = hibit(p1); + } + else + return v2; + } +} + +/* The forward and inverse affine transformations used in the S-box */ +uint_8t fwd_affine(const uint_8t x) +{ +#if defined( HAVE_UINT_32T ) + uint_32t w = x; + w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4); + return 0x63 ^ ((w ^ (w >> 8)) & 0xff); +#else + return 0x63 ^ x ^ (x << 1) ^ (x << 2) ^ (x << 3) ^ (x << 4) + ^ (x >> 7) ^ (x >> 6) ^ (x >> 5) ^ (x >> 4); +#endif +} + +uint_8t inv_affine(const uint_8t x) +{ +#if defined( HAVE_UINT_32T ) + uint_32t w = x; + w = (w << 1) ^ (w << 3) ^ (w << 6); + return 0x05 ^ ((w ^ (w >> 8)) & 0xff); +#else + return 0x05 ^ (x << 1) ^ (x << 3) ^ (x << 6) + ^ (x >> 7) ^ (x >> 5) ^ (x >> 2); +#endif +} + +#define s_box(x) fwd_affine(gf_inv(x)) +#define is_box(x) gf_inv(inv_affine(x)) +#define gfm2_sb(x) f2(s_box(x)) +#define gfm3_sb(x) f3(s_box(x)) +#define gfm_9(x) f9(x) +#define gfm_b(x) fb(x) +#define gfm_d(x) fd(x) +#define gfm_e(x) fe(x) + +#endif + +#if defined( HAVE_MEMCPY ) +# define block_copy_nn(d, s, l) memcpy(d, s, l) +# define block_copy(d, s) memcpy(d, s, N_BLOCK) +#else +# define block_copy_nn(d, s, l) copy_block_nn(d, s, l) +# define block_copy(d, s) copy_block(d, s) +#endif + +#if !defined( HAVE_MEMCPY ) +static void copy_block( void *d, const void *s ) +{ +#if defined( HAVE_UINT_32T ) + ((uint_32t*)d)[ 0] = ((uint_32t*)s)[ 0]; + ((uint_32t*)d)[ 1] = ((uint_32t*)s)[ 1]; + ((uint_32t*)d)[ 2] = ((uint_32t*)s)[ 2]; + ((uint_32t*)d)[ 3] = ((uint_32t*)s)[ 3]; +#else + ((uint_8t*)d)[ 0] = ((uint_8t*)s)[ 0]; + ((uint_8t*)d)[ 1] = ((uint_8t*)s)[ 1]; + ((uint_8t*)d)[ 2] = ((uint_8t*)s)[ 2]; + ((uint_8t*)d)[ 3] = ((uint_8t*)s)[ 3]; + ((uint_8t*)d)[ 4] = ((uint_8t*)s)[ 4]; + ((uint_8t*)d)[ 5] = ((uint_8t*)s)[ 5]; + ((uint_8t*)d)[ 6] = ((uint_8t*)s)[ 6]; + ((uint_8t*)d)[ 7] = ((uint_8t*)s)[ 7]; + ((uint_8t*)d)[ 8] = ((uint_8t*)s)[ 8]; + ((uint_8t*)d)[ 9] = ((uint_8t*)s)[ 9]; + ((uint_8t*)d)[10] = ((uint_8t*)s)[10]; + ((uint_8t*)d)[11] = ((uint_8t*)s)[11]; + ((uint_8t*)d)[12] = ((uint_8t*)s)[12]; + ((uint_8t*)d)[13] = ((uint_8t*)s)[13]; + ((uint_8t*)d)[14] = ((uint_8t*)s)[14]; + ((uint_8t*)d)[15] = ((uint_8t*)s)[15]; +#endif +} + +static void copy_block_nn( void * d, const void *s, uint_8t nn ) +{ + while( nn-- ) + *((uint_8t*)d)++ = *((uint_8t*)s)++; +} +#endif + +static void xor_block( void *d, const void *s ) +{ +#if defined( HAVE_UINT_32T ) + ((uint_32t*)d)[ 0] ^= ((uint_32t*)s)[ 0]; + ((uint_32t*)d)[ 1] ^= ((uint_32t*)s)[ 1]; + ((uint_32t*)d)[ 2] ^= ((uint_32t*)s)[ 2]; + ((uint_32t*)d)[ 3] ^= ((uint_32t*)s)[ 3]; +#else + ((uint_8t*)d)[ 0] ^= ((uint_8t*)s)[ 0]; + ((uint_8t*)d)[ 1] ^= ((uint_8t*)s)[ 1]; + ((uint_8t*)d)[ 2] ^= ((uint_8t*)s)[ 2]; + ((uint_8t*)d)[ 3] ^= ((uint_8t*)s)[ 3]; + ((uint_8t*)d)[ 4] ^= ((uint_8t*)s)[ 4]; + ((uint_8t*)d)[ 5] ^= ((uint_8t*)s)[ 5]; + ((uint_8t*)d)[ 6] ^= ((uint_8t*)s)[ 6]; + ((uint_8t*)d)[ 7] ^= ((uint_8t*)s)[ 7]; + ((uint_8t*)d)[ 8] ^= ((uint_8t*)s)[ 8]; + ((uint_8t*)d)[ 9] ^= ((uint_8t*)s)[ 9]; + ((uint_8t*)d)[10] ^= ((uint_8t*)s)[10]; + ((uint_8t*)d)[11] ^= ((uint_8t*)s)[11]; + ((uint_8t*)d)[12] ^= ((uint_8t*)s)[12]; + ((uint_8t*)d)[13] ^= ((uint_8t*)s)[13]; + ((uint_8t*)d)[14] ^= ((uint_8t*)s)[14]; + ((uint_8t*)d)[15] ^= ((uint_8t*)s)[15]; +#endif +} + +static void copy_and_key( void *d, const void *s, const void *k ) +{ +#if defined( HAVE_UINT_32T ) + ((uint_32t*)d)[ 0] = ((uint_32t*)s)[ 0] ^ ((uint_32t*)k)[ 0]; + ((uint_32t*)d)[ 1] = ((uint_32t*)s)[ 1] ^ ((uint_32t*)k)[ 1]; + ((uint_32t*)d)[ 2] = ((uint_32t*)s)[ 2] ^ ((uint_32t*)k)[ 2]; + ((uint_32t*)d)[ 3] = ((uint_32t*)s)[ 3] ^ ((uint_32t*)k)[ 3]; +#elif 1 + ((uint_8t*)d)[ 0] = ((uint_8t*)s)[ 0] ^ ((uint_8t*)k)[ 0]; + ((uint_8t*)d)[ 1] = ((uint_8t*)s)[ 1] ^ ((uint_8t*)k)[ 1]; + ((uint_8t*)d)[ 2] = ((uint_8t*)s)[ 2] ^ ((uint_8t*)k)[ 2]; + ((uint_8t*)d)[ 3] = ((uint_8t*)s)[ 3] ^ ((uint_8t*)k)[ 3]; + ((uint_8t*)d)[ 4] = ((uint_8t*)s)[ 4] ^ ((uint_8t*)k)[ 4]; + ((uint_8t*)d)[ 5] = ((uint_8t*)s)[ 5] ^ ((uint_8t*)k)[ 5]; + ((uint_8t*)d)[ 6] = ((uint_8t*)s)[ 6] ^ ((uint_8t*)k)[ 6]; + ((uint_8t*)d)[ 7] = ((uint_8t*)s)[ 7] ^ ((uint_8t*)k)[ 7]; + ((uint_8t*)d)[ 8] = ((uint_8t*)s)[ 8] ^ ((uint_8t*)k)[ 8]; + ((uint_8t*)d)[ 9] = ((uint_8t*)s)[ 9] ^ ((uint_8t*)k)[ 9]; + ((uint_8t*)d)[10] = ((uint_8t*)s)[10] ^ ((uint_8t*)k)[10]; + ((uint_8t*)d)[11] = ((uint_8t*)s)[11] ^ ((uint_8t*)k)[11]; + ((uint_8t*)d)[12] = ((uint_8t*)s)[12] ^ ((uint_8t*)k)[12]; + ((uint_8t*)d)[13] = ((uint_8t*)s)[13] ^ ((uint_8t*)k)[13]; + ((uint_8t*)d)[14] = ((uint_8t*)s)[14] ^ ((uint_8t*)k)[14]; + ((uint_8t*)d)[15] = ((uint_8t*)s)[15] ^ ((uint_8t*)k)[15]; +#else + block_copy(d, s); + xor_block(d, k); +#endif +} + +static void add_round_key( uint_8t d[N_BLOCK], const uint_8t k[N_BLOCK] ) +{ + xor_block(d, k); +} + +static void shift_sub_rows( uint_8t st[N_BLOCK] ) +{ uint_8t tt; + + st[ 0] = s_box(st[ 0]); st[ 4] = s_box(st[ 4]); + st[ 8] = s_box(st[ 8]); st[12] = s_box(st[12]); + + tt = st[1]; st[ 1] = s_box(st[ 5]); st[ 5] = s_box(st[ 9]); + st[ 9] = s_box(st[13]); st[13] = s_box( tt ); + + tt = st[2]; st[ 2] = s_box(st[10]); st[10] = s_box( tt ); + tt = st[6]; st[ 6] = s_box(st[14]); st[14] = s_box( tt ); + + tt = st[15]; st[15] = s_box(st[11]); st[11] = s_box(st[ 7]); + st[ 7] = s_box(st[ 3]); st[ 3] = s_box( tt ); +} + +static void inv_shift_sub_rows( uint_8t st[N_BLOCK] ) +{ uint_8t tt; + + st[ 0] = is_box(st[ 0]); st[ 4] = is_box(st[ 4]); + st[ 8] = is_box(st[ 8]); st[12] = is_box(st[12]); + + tt = st[13]; st[13] = is_box(st[9]); st[ 9] = is_box(st[5]); + st[ 5] = is_box(st[1]); st[ 1] = is_box( tt ); + + tt = st[2]; st[ 2] = is_box(st[10]); st[10] = is_box( tt ); + tt = st[6]; st[ 6] = is_box(st[14]); st[14] = is_box( tt ); + + tt = st[3]; st[ 3] = is_box(st[ 7]); st[ 7] = is_box(st[11]); + st[11] = is_box(st[15]); st[15] = is_box( tt ); +} + +#if defined( VERSION_1 ) + static void mix_sub_columns( uint_8t dt[N_BLOCK] ) + { uint_8t st[N_BLOCK]; + block_copy(st, dt); +#else + static void mix_sub_columns( uint_8t dt[N_BLOCK], uint_8t st[N_BLOCK] ) + { +#endif + dt[ 0] = gfm2_sb(st[0]) ^ gfm3_sb(st[5]) ^ s_box(st[10]) ^ s_box(st[15]); + dt[ 1] = s_box(st[0]) ^ gfm2_sb(st[5]) ^ gfm3_sb(st[10]) ^ s_box(st[15]); + dt[ 2] = s_box(st[0]) ^ s_box(st[5]) ^ gfm2_sb(st[10]) ^ gfm3_sb(st[15]); + dt[ 3] = gfm3_sb(st[0]) ^ s_box(st[5]) ^ s_box(st[10]) ^ gfm2_sb(st[15]); + + dt[ 4] = gfm2_sb(st[4]) ^ gfm3_sb(st[9]) ^ s_box(st[14]) ^ s_box(st[3]); + dt[ 5] = s_box(st[4]) ^ gfm2_sb(st[9]) ^ gfm3_sb(st[14]) ^ s_box(st[3]); + dt[ 6] = s_box(st[4]) ^ s_box(st[9]) ^ gfm2_sb(st[14]) ^ gfm3_sb(st[3]); + dt[ 7] = gfm3_sb(st[4]) ^ s_box(st[9]) ^ s_box(st[14]) ^ gfm2_sb(st[3]); + + dt[ 8] = gfm2_sb(st[8]) ^ gfm3_sb(st[13]) ^ s_box(st[2]) ^ s_box(st[7]); + dt[ 9] = s_box(st[8]) ^ gfm2_sb(st[13]) ^ gfm3_sb(st[2]) ^ s_box(st[7]); + dt[10] = s_box(st[8]) ^ s_box(st[13]) ^ gfm2_sb(st[2]) ^ gfm3_sb(st[7]); + dt[11] = gfm3_sb(st[8]) ^ s_box(st[13]) ^ s_box(st[2]) ^ gfm2_sb(st[7]); + + dt[12] = gfm2_sb(st[12]) ^ gfm3_sb(st[1]) ^ s_box(st[6]) ^ s_box(st[11]); + dt[13] = s_box(st[12]) ^ gfm2_sb(st[1]) ^ gfm3_sb(st[6]) ^ s_box(st[11]); + dt[14] = s_box(st[12]) ^ s_box(st[1]) ^ gfm2_sb(st[6]) ^ gfm3_sb(st[11]); + dt[15] = gfm3_sb(st[12]) ^ s_box(st[1]) ^ s_box(st[6]) ^ gfm2_sb(st[11]); + } + +#if defined( VERSION_1 ) + static void inv_mix_sub_columns( uint_8t dt[N_BLOCK] ) + { uint_8t st[N_BLOCK]; + block_copy(st, dt); +#else + static void inv_mix_sub_columns( uint_8t dt[N_BLOCK], uint_8t st[N_BLOCK] ) + { +#endif + dt[ 0] = is_box(gfm_e(st[ 0]) ^ gfm_b(st[ 1]) ^ gfm_d(st[ 2]) ^ gfm_9(st[ 3])); + dt[ 5] = is_box(gfm_9(st[ 0]) ^ gfm_e(st[ 1]) ^ gfm_b(st[ 2]) ^ gfm_d(st[ 3])); + dt[10] = is_box(gfm_d(st[ 0]) ^ gfm_9(st[ 1]) ^ gfm_e(st[ 2]) ^ gfm_b(st[ 3])); + dt[15] = is_box(gfm_b(st[ 0]) ^ gfm_d(st[ 1]) ^ gfm_9(st[ 2]) ^ gfm_e(st[ 3])); + + dt[ 4] = is_box(gfm_e(st[ 4]) ^ gfm_b(st[ 5]) ^ gfm_d(st[ 6]) ^ gfm_9(st[ 7])); + dt[ 9] = is_box(gfm_9(st[ 4]) ^ gfm_e(st[ 5]) ^ gfm_b(st[ 6]) ^ gfm_d(st[ 7])); + dt[14] = is_box(gfm_d(st[ 4]) ^ gfm_9(st[ 5]) ^ gfm_e(st[ 6]) ^ gfm_b(st[ 7])); + dt[ 3] = is_box(gfm_b(st[ 4]) ^ gfm_d(st[ 5]) ^ gfm_9(st[ 6]) ^ gfm_e(st[ 7])); + + dt[ 8] = is_box(gfm_e(st[ 8]) ^ gfm_b(st[ 9]) ^ gfm_d(st[10]) ^ gfm_9(st[11])); + dt[13] = is_box(gfm_9(st[ 8]) ^ gfm_e(st[ 9]) ^ gfm_b(st[10]) ^ gfm_d(st[11])); + dt[ 2] = is_box(gfm_d(st[ 8]) ^ gfm_9(st[ 9]) ^ gfm_e(st[10]) ^ gfm_b(st[11])); + dt[ 7] = is_box(gfm_b(st[ 8]) ^ gfm_d(st[ 9]) ^ gfm_9(st[10]) ^ gfm_e(st[11])); + + dt[12] = is_box(gfm_e(st[12]) ^ gfm_b(st[13]) ^ gfm_d(st[14]) ^ gfm_9(st[15])); + dt[ 1] = is_box(gfm_9(st[12]) ^ gfm_e(st[13]) ^ gfm_b(st[14]) ^ gfm_d(st[15])); + dt[ 6] = is_box(gfm_d(st[12]) ^ gfm_9(st[13]) ^ gfm_e(st[14]) ^ gfm_b(st[15])); + dt[11] = is_box(gfm_b(st[12]) ^ gfm_d(st[13]) ^ gfm_9(st[14]) ^ gfm_e(st[15])); + } + +#if defined( AES_ENC_PREKEYED ) || defined( AES_DEC_PREKEYED ) + +/* Set the cipher key for the pre-keyed version */ + +return_type aes_set_key( const unsigned char key[], length_type keylen, aes_context ctx[1] ) +{ + uint_8t cc, rc, hi; + + switch( keylen ) + { + case 16: + case 128: + keylen = 16; + break; + case 24: + case 192: + keylen = 24; + break; + case 32: + case 256: + keylen = 32; + break; + default: + ctx->rnd = 0; + return (return_type)-1; + } + block_copy_nn(ctx->ksch, key, keylen); + hi = (keylen + 28) << 2; + ctx->rnd = (hi >> 4) - 1; + for( cc = keylen, rc = 1; cc < hi; cc += 4 ) + { uint_8t tt, t0, t1, t2, t3; + + t0 = ctx->ksch[cc - 4]; + t1 = ctx->ksch[cc - 3]; + t2 = ctx->ksch[cc - 2]; + t3 = ctx->ksch[cc - 1]; + if( cc % keylen == 0 ) + { + tt = t0; + t0 = s_box(t1) ^ rc; + t1 = s_box(t2); + t2 = s_box(t3); + t3 = s_box(tt); + rc = f2(rc); + } + else if( keylen > 24 && cc % keylen == 16 ) + { + t0 = s_box(t0); + t1 = s_box(t1); + t2 = s_box(t2); + t3 = s_box(t3); + } + tt = cc - keylen; + ctx->ksch[cc + 0] = ctx->ksch[tt + 0] ^ t0; + ctx->ksch[cc + 1] = ctx->ksch[tt + 1] ^ t1; + ctx->ksch[cc + 2] = ctx->ksch[tt + 2] ^ t2; + ctx->ksch[cc + 3] = ctx->ksch[tt + 3] ^ t3; + } + return 0; +} + +#endif + +#if defined( AES_ENC_PREKEYED ) + +/* Encrypt a single block of 16 bytes */ + +return_type aes_encrypt( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK], const aes_context ctx[1] ) +{ + if( ctx->rnd ) + { + uint_8t s1[N_BLOCK], r; + copy_and_key( s1, in, ctx->ksch ); + + for( r = 1 ; r < ctx->rnd ; ++r ) +#if defined( VERSION_1 ) + { + mix_sub_columns( s1 ); + add_round_key( s1, ctx->ksch + r * N_BLOCK); + } +#else + { uint_8t s2[N_BLOCK]; + mix_sub_columns( s2, s1 ); + copy_and_key( s1, s2, ctx->ksch + r * N_BLOCK); + } +#endif + shift_sub_rows( s1 ); + copy_and_key( out, s1, ctx->ksch + r * N_BLOCK ); + } + else + return (return_type)-1; + return 0; +} + +/* CBC encrypt a number of blocks (input and return an IV) */ + +return_type aes_cbc_encrypt( const unsigned char *in, unsigned char *out, + int n_block, unsigned char iv[N_BLOCK], const aes_context ctx[1] ) +{ + + while(n_block--) + { + xor_block(iv, in); + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + memcpy(out, iv, N_BLOCK); + in += N_BLOCK; + out += N_BLOCK; + } + return EXIT_SUCCESS; +} + +#endif + +#if defined( AES_DEC_PREKEYED ) + +/* Decrypt a single block of 16 bytes */ + +return_type aes_decrypt( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK], const aes_context ctx[1] ) +{ + if( ctx->rnd ) + { + uint_8t s1[N_BLOCK], r; + copy_and_key( s1, in, ctx->ksch + ctx->rnd * N_BLOCK ); + inv_shift_sub_rows( s1 ); + + for( r = ctx->rnd ; --r ; ) +#if defined( VERSION_1 ) + { + add_round_key( s1, ctx->ksch + r * N_BLOCK ); + inv_mix_sub_columns( s1 ); + } +#else + { uint_8t s2[N_BLOCK]; + copy_and_key( s2, s1, ctx->ksch + r * N_BLOCK ); + inv_mix_sub_columns( s1, s2 ); + } +#endif + copy_and_key( out, s1, ctx->ksch ); + } + else + return (return_type)-1; + return 0; +} + +/* CBC decrypt a number of blocks (input and return an IV) */ + +return_type aes_cbc_decrypt( const unsigned char *in, unsigned char *out, + int n_block, unsigned char iv[N_BLOCK], const aes_context ctx[1] ) +{ + while(n_block--) + { uint_8t tmp[N_BLOCK]; + + memcpy(tmp, in, N_BLOCK); + if(aes_decrypt(in, out, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + xor_block(out, iv); + memcpy(iv, tmp, N_BLOCK); + in += N_BLOCK; + out += N_BLOCK; + } + return EXIT_SUCCESS; +} + +#endif + +#if defined( AES_ENC_128_OTFK ) + +/* The 'on the fly' encryption key update for for 128 bit keys */ + +static void update_encrypt_key_128( uint_8t k[N_BLOCK], uint_8t *rc ) +{ uint_8t cc; + + k[0] ^= s_box(k[13]) ^ *rc; + k[1] ^= s_box(k[14]); + k[2] ^= s_box(k[15]); + k[3] ^= s_box(k[12]); + *rc = f2( *rc ); + + for(cc = 4; cc < 16; cc += 4 ) + { + k[cc + 0] ^= k[cc - 4]; + k[cc + 1] ^= k[cc - 3]; + k[cc + 2] ^= k[cc - 2]; + k[cc + 3] ^= k[cc - 1]; + } +} + +/* Encrypt a single block of 16 bytes with 'on the fly' 128 bit keying */ + +void aes_encrypt_128( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK], + const unsigned char key[N_BLOCK], unsigned char o_key[N_BLOCK] ) +{ uint_8t s1[N_BLOCK], r, rc = 1; + + if(o_key != key) + block_copy( o_key, key ); + copy_and_key( s1, in, o_key ); + + for( r = 1 ; r < 10 ; ++r ) +#if defined( VERSION_1 ) + { + mix_sub_columns( s1 ); + update_encrypt_key_128( o_key, &rc ); + add_round_key( s1, o_key ); + } +#else + { uint_8t s2[N_BLOCK]; + mix_sub_columns( s2, s1 ); + update_encrypt_key_128( o_key, &rc ); + copy_and_key( s1, s2, o_key ); + } +#endif + + shift_sub_rows( s1 ); + update_encrypt_key_128( o_key, &rc ); + copy_and_key( out, s1, o_key ); +} + +#endif + +#if defined( AES_DEC_128_OTFK ) + +/* The 'on the fly' decryption key update for for 128 bit keys */ + +static void update_decrypt_key_128( uint_8t k[N_BLOCK], uint_8t *rc ) +{ uint_8t cc; + + for( cc = 12; cc > 0; cc -= 4 ) + { + k[cc + 0] ^= k[cc - 4]; + k[cc + 1] ^= k[cc - 3]; + k[cc + 2] ^= k[cc - 2]; + k[cc + 3] ^= k[cc - 1]; + } + *rc = d2(*rc); + k[0] ^= s_box(k[13]) ^ *rc; + k[1] ^= s_box(k[14]); + k[2] ^= s_box(k[15]); + k[3] ^= s_box(k[12]); +} + +/* Decrypt a single block of 16 bytes with 'on the fly' 128 bit keying */ + +void aes_decrypt_128( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK], + const unsigned char key[N_BLOCK], unsigned char o_key[N_BLOCK] ) +{ + uint_8t s1[N_BLOCK], r, rc = 0x6c; + if(o_key != key) + block_copy( o_key, key ); + + copy_and_key( s1, in, o_key ); + inv_shift_sub_rows( s1 ); + + for( r = 10 ; --r ; ) +#if defined( VERSION_1 ) + { + update_decrypt_key_128( o_key, &rc ); + add_round_key( s1, o_key ); + inv_mix_sub_columns( s1 ); + } +#else + { uint_8t s2[N_BLOCK]; + update_decrypt_key_128( o_key, &rc ); + copy_and_key( s2, s1, o_key ); + inv_mix_sub_columns( s1, s2 ); + } +#endif + update_decrypt_key_128( o_key, &rc ); + copy_and_key( out, s1, o_key ); +} + +#endif + +#if defined( AES_ENC_256_OTFK ) + +/* The 'on the fly' encryption key update for for 256 bit keys */ + +static void update_encrypt_key_256( uint_8t k[2 * N_BLOCK], uint_8t *rc ) +{ uint_8t cc; + + k[0] ^= s_box(k[29]) ^ *rc; + k[1] ^= s_box(k[30]); + k[2] ^= s_box(k[31]); + k[3] ^= s_box(k[28]); + *rc = f2( *rc ); + + for(cc = 4; cc < 16; cc += 4) + { + k[cc + 0] ^= k[cc - 4]; + k[cc + 1] ^= k[cc - 3]; + k[cc + 2] ^= k[cc - 2]; + k[cc + 3] ^= k[cc - 1]; + } + + k[16] ^= s_box(k[12]); + k[17] ^= s_box(k[13]); + k[18] ^= s_box(k[14]); + k[19] ^= s_box(k[15]); + + for( cc = 20; cc < 32; cc += 4 ) + { + k[cc + 0] ^= k[cc - 4]; + k[cc + 1] ^= k[cc - 3]; + k[cc + 2] ^= k[cc - 2]; + k[cc + 3] ^= k[cc - 1]; + } +} + +/* Encrypt a single block of 16 bytes with 'on the fly' 256 bit keying */ + +void aes_encrypt_256( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK], + const unsigned char key[2 * N_BLOCK], unsigned char o_key[2 * N_BLOCK] ) +{ + uint_8t s1[N_BLOCK], r, rc = 1; + if(o_key != key) + { + block_copy( o_key, key ); + block_copy( o_key + 16, key + 16 ); + } + copy_and_key( s1, in, o_key ); + + for( r = 1 ; r < 14 ; ++r ) +#if defined( VERSION_1 ) + { + mix_sub_columns(s1); + if( r & 1 ) + add_round_key( s1, o_key + 16 ); + else + { + update_encrypt_key_256( o_key, &rc ); + add_round_key( s1, o_key ); + } + } +#else + { uint_8t s2[N_BLOCK]; + mix_sub_columns( s2, s1 ); + if( r & 1 ) + copy_and_key( s1, s2, o_key + 16 ); + else + { + update_encrypt_key_256( o_key, &rc ); + copy_and_key( s1, s2, o_key ); + } + } +#endif + + shift_sub_rows( s1 ); + update_encrypt_key_256( o_key, &rc ); + copy_and_key( out, s1, o_key ); +} + +#endif + +#if defined( AES_DEC_256_OTFK ) + +/* The 'on the fly' encryption key update for for 256 bit keys */ + +static void update_decrypt_key_256( uint_8t k[2 * N_BLOCK], uint_8t *rc ) +{ uint_8t cc; + + for(cc = 28; cc > 16; cc -= 4) + { + k[cc + 0] ^= k[cc - 4]; + k[cc + 1] ^= k[cc - 3]; + k[cc + 2] ^= k[cc - 2]; + k[cc + 3] ^= k[cc - 1]; + } + + k[16] ^= s_box(k[12]); + k[17] ^= s_box(k[13]); + k[18] ^= s_box(k[14]); + k[19] ^= s_box(k[15]); + + for(cc = 12; cc > 0; cc -= 4) + { + k[cc + 0] ^= k[cc - 4]; + k[cc + 1] ^= k[cc - 3]; + k[cc + 2] ^= k[cc - 2]; + k[cc + 3] ^= k[cc - 1]; + } + + *rc = d2(*rc); + k[0] ^= s_box(k[29]) ^ *rc; + k[1] ^= s_box(k[30]); + k[2] ^= s_box(k[31]); + k[3] ^= s_box(k[28]); +} + +/* Decrypt a single block of 16 bytes with 'on the fly' + 256 bit keying +*/ +void aes_decrypt_256( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK], + const unsigned char key[2 * N_BLOCK], unsigned char o_key[2 * N_BLOCK] ) +{ + uint_8t s1[N_BLOCK], r, rc = 0x80; + + if(o_key != key) + { + block_copy( o_key, key ); + block_copy( o_key + 16, key + 16 ); + } + + copy_and_key( s1, in, o_key ); + inv_shift_sub_rows( s1 ); + + for( r = 14 ; --r ; ) +#if defined( VERSION_1 ) + { + if( ( r & 1 ) ) + { + update_decrypt_key_256( o_key, &rc ); + add_round_key( s1, o_key + 16 ); + } + else + add_round_key( s1, o_key ); + inv_mix_sub_columns( s1 ); + } +#else + { uint_8t s2[N_BLOCK]; + if( ( r & 1 ) ) + { + update_decrypt_key_256( o_key, &rc ); + copy_and_key( s2, s1, o_key + 16 ); + } + else + copy_and_key( s2, s1, o_key ); + inv_mix_sub_columns( s1, s2 ); + } +#endif + copy_and_key( out, s1, o_key ); +} + +#endif diff --git a/stack/smp/aes.h b/stack/smp/aes.h new file mode 100644 index 000000000..dcfde93c0 --- /dev/null +++ b/stack/smp/aes.h @@ -0,0 +1,162 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The redistribution and use of this software (with or without changes) + is allowed without the payment of fees or royalties provided that: + + 1. source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + 2. binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation; + + 3. the name of the copyright holder is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue 09/09/2006 + + This is an AES implementation that uses only 8-bit byte operations on the + cipher state. + */ + +#ifndef AES_H +#define AES_H + +#if 1 +# define AES_ENC_PREKEYED /* AES encryption with a precomputed key schedule */ +#endif +#if 1 +# define AES_DEC_PREKEYED /* AES decryption with a precomputed key schedule */ +#endif +#if 1 +# define AES_ENC_128_OTFK /* AES encryption with 'on the fly' 128 bit keying */ +#endif +#if 1 +# define AES_DEC_128_OTFK /* AES decryption with 'on the fly' 128 bit keying */ +#endif +#if 1 +# define AES_ENC_256_OTFK /* AES encryption with 'on the fly' 256 bit keying */ +#endif +#if 1 +# define AES_DEC_256_OTFK /* AES decryption with 'on the fly' 256 bit keying */ +#endif + +#define N_ROW 4 +#define N_COL 4 +#define N_BLOCK (N_ROW * N_COL) +#define N_MAX_ROUNDS 14 + +typedef unsigned char uint_8t; + +typedef uint_8t return_type; + +/* Warning: The key length for 256 bit keys overflows a byte + (see comment below) +*/ + +typedef uint_8t length_type; + +typedef struct +{ uint_8t ksch[(N_MAX_ROUNDS + 1) * N_BLOCK]; + uint_8t rnd; +} aes_context; + +/* The following calls are for a precomputed key schedule + + NOTE: If the length_type used for the key length is an + unsigned 8-bit character, a key length of 256 bits must + be entered as a length in bytes (valid inputs are hence + 128, 192, 16, 24 and 32). +*/ + +#if defined( AES_ENC_PREKEYED ) || defined( AES_DEC_PREKEYED ) + +return_type aes_set_key( const unsigned char key[], + length_type keylen, + aes_context ctx[1] ); +#endif + +#if defined( AES_ENC_PREKEYED ) + +return_type aes_encrypt( const unsigned char in[N_BLOCK], + unsigned char out[N_BLOCK], + const aes_context ctx[1] ); + +return_type aes_cbc_encrypt( const unsigned char *in, + unsigned char *out, + int n_block, + unsigned char iv[N_BLOCK], + const aes_context ctx[1] ); +#endif + +#if defined( AES_DEC_PREKEYED ) + +return_type aes_decrypt( const unsigned char in[N_BLOCK], + unsigned char out[N_BLOCK], + const aes_context ctx[1] ); + +return_type aes_cbc_decrypt( const unsigned char *in, + unsigned char *out, + int n_block, + unsigned char iv[N_BLOCK], + const aes_context ctx[1] ); +#endif + +/* The following calls are for 'on the fly' keying. In this case the + encryption and decryption keys are different. + + The encryption subroutines take a key in an array of bytes in + key[L] where L is 16, 24 or 32 bytes for key lengths of 128, + 192, and 256 bits respectively. They then encrypts the input + data, in[] with this key and put the reult in the output array + out[]. In addition, the second key array, o_key[L], is used + to output the key that is needed by the decryption subroutine + to reverse the encryption operation. The two key arrays can + be the same array but in this case the original key will be + overwritten. + + In the same way, the decryption subroutines output keys that + can be used to reverse their effect when used for encryption. + + Only 128 and 256 bit keys are supported in these 'on the fly' + modes. +*/ + +#if defined( AES_ENC_128_OTFK ) +void aes_encrypt_128( const unsigned char in[N_BLOCK], + unsigned char out[N_BLOCK], + const unsigned char key[N_BLOCK], + uint_8t o_key[N_BLOCK] ); +#endif + +#if defined( AES_DEC_128_OTFK ) +void aes_decrypt_128( const unsigned char in[N_BLOCK], + unsigned char out[N_BLOCK], + const unsigned char key[N_BLOCK], + unsigned char o_key[N_BLOCK] ); +#endif + +#if defined( AES_ENC_256_OTFK ) +void aes_encrypt_256( const unsigned char in[N_BLOCK], + unsigned char out[N_BLOCK], + const unsigned char key[2 * N_BLOCK], + unsigned char o_key[2 * N_BLOCK] ); +#endif + +#if defined( AES_DEC_256_OTFK ) +void aes_decrypt_256( const unsigned char in[N_BLOCK], + unsigned char out[N_BLOCK], + const unsigned char key[2 * N_BLOCK], + unsigned char o_key[2 * N_BLOCK] ); +#endif + +#endif diff --git a/stack/smp/smp_act.c b/stack/smp/smp_act.c index ca24225d6..73f481139 100644 --- a/stack/smp/smp_act.c +++ b/stack/smp/smp_act.c @@ -36,7 +36,7 @@ const UINT8 smp_association_table[2][SMP_IO_CAP_MAX][SMP_IO_CAP_MAX] = {SMP_MODEL_KEY_NOTIF, SMP_MODEL_KEY_NOTIF, SMP_MODEL_PASSKEY, SMP_MODEL_ENC_ONLY, SMP_MODEL_KEY_NOTIF}}, /* keyboard display */ /* responder */ {{SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY, SMP_MODEL_KEY_NOTIF, SMP_MODEL_ENC_ONLY, SMP_MODEL_KEY_NOTIF}, /* Display Only */ - {SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY, SMP_MODEL_PASSKEY, SMP_MODEL_ENC_ONLY, SMP_MODEL_KEY_NOTIF}, /* SMP_CAP_IO = 1 */ + {SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY, SMP_MODEL_KEY_NOTIF, SMP_MODEL_ENC_ONLY, SMP_MODEL_KEY_NOTIF}, /* SMP_CAP_IO = 1 */ {SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_ENC_ONLY, SMP_MODEL_PASSKEY}, /* keyboard only */ {SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY, SMP_MODEL_ENC_ONLY},/* No Input No Output */ {SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_KEY_NOTIF, SMP_MODEL_ENC_ONLY, SMP_MODEL_PASSKEY}} /* keyboard display */ @@ -477,8 +477,6 @@ void smp_proc_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) SMP_TRACE_DEBUG0 ("smp_proc_id_info "); STREAM_TO_ARRAY (p_cb->tk, p, BT_OCTET16_LEN); /* reuse TK for IRK */ - /* store the ID key from peer device */ - btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PID, (tBTM_LE_KEY_VALUE *)&p_cb->tk, TRUE); smp_key_distribution(p_cb, NULL); } @@ -489,14 +487,17 @@ void smp_proc_id_info(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) void smp_proc_id_addr(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) { UINT8 *p = (UINT8 *)p_data; - BD_ADDR mac_bda; + tBTM_LE_PID_KEYS pid_key; SMP_TRACE_DEBUG0 ("smp_proc_id_addr "); smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_ID, TRUE); - STREAM_TO_BDADDR(mac_bda, p); + STREAM_TO_UINT8(pid_key.addr_type, p); + STREAM_TO_BDADDR(pid_key.static_addr, p); + memcpy(pid_key.irk, p_cb->tk, BT_OCTET16_LEN); - /* TODO, update MAC address */ + /* store the ID key from peer device */ + btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PID, (tBTM_LE_KEY_VALUE *)&pid_key, TRUE); smp_key_distribution(p_cb, NULL); } @@ -529,7 +530,11 @@ void smp_proc_compare(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) UINT8 reason; SMP_TRACE_DEBUG0 ("smp_proc_compare "); - if (!memcmp(p_cb->rconfirm, p_data->key.p_data, BT_OCTET16_LEN)) + if ( +#if SMP_CONFORMANCE_TESTING == TRUE + p_cb->skip_test_compare_check || +#endif + !memcmp(p_cb->rconfirm, p_data->key.p_data, BT_OCTET16_LEN)) { /* compare the max encryption key size, and save the smaller one for the link */ if ( p_cb->peer_enc_size < p_cb->loc_enc_size) @@ -602,7 +607,7 @@ void smp_start_enc(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) void smp_proc_discard(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) { SMP_TRACE_DEBUG0 ("smp_proc_discard "); - smp_cb_cleanup(p_cb); + smp_reset_control_value(p_cb); } /******************************************************************************* ** Function smp_proc_release_delay @@ -736,7 +741,7 @@ void smp_decide_asso_model(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) tSMP_ASSO_MODEL model = SMP_MODEL_MAX; UINT8 int_evt = 0; tSMP_KEY key; - tSMP_INT_DATA *p; + tSMP_INT_DATA *p = NULL; SMP_TRACE_DEBUG3 ("smp_decide_asso_model p_cb->peer_io_caps = %d p_cb->loc_io_caps = %d \ p_cb->peer_auth_req = %02x", @@ -875,7 +880,12 @@ void smp_pairing_cmpl(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) void smp_pair_terminate(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) { SMP_TRACE_DEBUG0 ("smp_pair_terminate "); - p_cb->status = SMP_PAIR_FAIL_UNKNOWN; + + if (p_data->reason == L2CAP_CONN_CANCEL) + p_cb->status = SMP_CONN_TOUT; + else + p_cb->status = SMP_PAIR_FAIL_UNKNOWN; + smp_proc_pairing_cmpl(p_cb); } /******************************************************************************* diff --git a/stack/smp/smp_int.h b/stack/smp/smp_int.h index 9eb2f1074..e8d93deb4 100644 --- a/stack/smp/smp_int.h +++ b/stack/smp/smp_int.h @@ -198,6 +198,7 @@ typedef struct UINT8 rand_enc_proc; BOOLEAN last_cmd; + UINT8 addr_type; BD_ADDR local_bda; BOOLEAN is_pair_cancel; BOOLEAN discard_sec_req; @@ -209,6 +210,7 @@ typedef struct BOOLEAN enable_test_pair_fail; UINT8 pair_fail_status; BOOLEAN remove_fixed_channel_disable; + BOOLEAN skip_test_compare_check; #endif }tSMP_CB; @@ -242,6 +244,7 @@ SMP_API extern void smp_set_test_confirm_value (BOOLEAN enable, UINT8 *p_c_valu SMP_API extern void smp_set_test_rand_value (BOOLEAN enable, UINT8 *p_c_value); SMP_API extern void smp_set_test_pair_fail_status (BOOLEAN enable, UINT8 status); SMP_API extern void smp_remove_fixed_channel_disable (BOOLEAN disable); +SMP_API extern void smp_skip_compare_check (BOOLEAN enable); #endif /* smp main */ extern void smp_sm_event(tSMP_CB *p_cb, tSMP_EVENT event, void *p_data); diff --git a/stack/smp/smp_keys.c b/stack/smp/smp_keys.c index c61b54809..a1955f202 100644 --- a/stack/smp/smp_keys.c +++ b/stack/smp/smp_keys.c @@ -181,7 +181,7 @@ void smp_proc_passkey(tSMP_CB *p_cb , tBTM_RAND_ENC *p) { UINT8 *tt = p_cb->tk; tSMP_KEY key; - UINT32 passkey; //= 19655 test number; */ + UINT32 passkey; /* 19655 test number; */ UINT8 *pp = p->param_buf; SMP_TRACE_DEBUG0 ("smp_proc_passkey "); @@ -445,23 +445,25 @@ void smp_concatenate_peer( tSMP_CB *p_cb, UINT8 **p_data, UINT8 op_code) void smp_gen_p1_4_confirm( tSMP_CB *p_cb, BT_OCTET16 p1) { UINT8 *p = (UINT8 *)p1; - tBTM_SEC_DEV_REC *p_dev_rec; + tBLE_ADDR_TYPE addr_type = 0; + BD_ADDR remote_bda; SMP_TRACE_DEBUG0 ("smp_gen_p1_4_confirm"); - if ((p_dev_rec = btm_find_dev (p_cb->pairing_bda)) == NULL) + + if (!BTM_ReadRemoteConnectionAddr(p_cb->pairing_bda, remote_bda, &addr_type)) { SMP_TRACE_ERROR0("can not generate confirm for unknown device"); return; } - BTM_ReadConnectionAddr(p_cb->local_bda); + BTM_ReadConnectionAddr( p_cb->pairing_bda, p_cb->local_bda, &p_cb->addr_type); if (p_cb->role == HCI_ROLE_MASTER) { /* LSB : rat': initiator's(local) address type */ - UINT8_TO_STREAM(p, 0); + UINT8_TO_STREAM(p, p_cb->addr_type); /* LSB : iat': responder's address type */ - UINT8_TO_STREAM(p, p_dev_rec->ble.ble_addr_type); + UINT8_TO_STREAM(p, addr_type); /* concatinate preq */ smp_concatenate_local(p_cb, &p, SMP_OPCODE_PAIRING_REQ); /* concatinate pres */ @@ -470,9 +472,9 @@ void smp_gen_p1_4_confirm( tSMP_CB *p_cb, BT_OCTET16 p1) else { /* LSB : iat': initiator's address type */ - UINT8_TO_STREAM(p, p_dev_rec->ble.ble_addr_type); + UINT8_TO_STREAM(p, addr_type); /* LSB : rat': responder's(local) address type */ - UINT8_TO_STREAM(p, 0); + UINT8_TO_STREAM(p, p_cb->addr_type); /* concatinate preq */ smp_concatenate_peer(p_cb, &p, SMP_OPCODE_PAIRING_REQ); /* concatinate pres */ @@ -495,15 +497,24 @@ void smp_gen_p1_4_confirm( tSMP_CB *p_cb, BT_OCTET16 p1) *******************************************************************************/ void smp_gen_p2_4_confirm( tSMP_CB *p_cb, BT_OCTET16 p2) { - UINT8 *p = (UINT8 *)p2; + UINT8 *p = (UINT8 *)p2; + BD_ADDR remote_bda; + tBLE_ADDR_TYPE addr_type = 0; + + if (!BTM_ReadRemoteConnectionAddr(p_cb->pairing_bda, remote_bda, &addr_type)) + { + SMP_TRACE_ERROR0("can not generate confirm p2 for unknown device"); + return; + } SMP_TRACE_DEBUG0 ("smp_gen_p2_4_confirm"); + memset(p, 0, sizeof(BT_OCTET16)); if (p_cb->role == HCI_ROLE_MASTER) { /* LSB ra */ - BDADDR_TO_STREAM(p, p_cb->pairing_bda); + BDADDR_TO_STREAM(p, remote_bda); /* ia */ BDADDR_TO_STREAM(p, p_cb->local_bda); } @@ -512,7 +523,7 @@ void smp_gen_p2_4_confirm( tSMP_CB *p_cb, BT_OCTET16 p2) /* LSB ra */ BDADDR_TO_STREAM(p, p_cb->local_bda); /* ia */ - BDADDR_TO_STREAM(p, p_cb->pairing_bda); + BDADDR_TO_STREAM(p, remote_bda); } #if SMP_DEBUG == TRUE SMP_TRACE_DEBUG0("p2 = padding || ia || ra"); diff --git a/stack/smp/smp_l2c.c b/stack/smp/smp_l2c.c index 648cd5901..54b78b451 100644 --- a/stack/smp/smp_l2c.c +++ b/stack/smp/smp_l2c.c @@ -99,8 +99,6 @@ static void smp_connect_cback (BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason p_cb->loc_auth_req = p_cb->peer_auth_req = SMP_DEFAULT_AUTH_REQ; p_cb->cb_evt = SMP_IO_CAP_REQ_EVT; smp_sm_event(p_cb, SMP_L2CAP_CONN_EVT, NULL); - - BTM_ReadConnectionAddr(p_cb->local_bda); } } else diff --git a/stack/smp/smp_main.c b/stack/smp/smp_main.c index a60f54bed..59dddb470 100644 --- a/stack/smp/smp_main.c +++ b/stack/smp/smp_main.c @@ -174,7 +174,7 @@ static const UINT8 smp_ma_entry_map[][SMP_ST_MAX] = /* KEY_READY */{ 0, 3, 0, 3, 1, 0, 2, 1, 6, 0 }, /* ENC_CMPL */{ 0, 0, 0, 0, 0, 0, 0, 2, 0, 0 }, /* L2C_CONN */{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, -/* L2C_DISC */{ 0, 0x83, 0, 0x83, 0x83,0x83, 0x83,0x83, 0x83, 2 }, +/* L2C_DISC */{ 0x83, 0x83, 0, 0x83, 0x83,0x83, 0x83,0x83, 0x83, 2 }, /* IO_RSP */{ 0, 2, 0, 0, 0, 0, 0, 0, 0, 0 }, /* SEC_GRANT */{ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, /* TK_REQ */{ 0, 0, 0, 2, 0, 0, 0, 0, 0, 0 }, diff --git a/stack/smp/smp_utils.c b/stack/smp/smp_utils.c index 562288028..168d6bd11 100644 --- a/stack/smp/smp_utils.c +++ b/stack/smp/smp_utils.c @@ -336,18 +336,18 @@ static BT_HDR * smp_build_id_addr_cmd(UINT8 cmd_code, tSMP_CB *p_cb) { BT_HDR *p_buf = NULL ; UINT8 *p; - BT_OCTET16 irk; + BD_ADDR static_addr; + + SMP_TRACE_EVENT0("smp_build_id_addr_cmd"); if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + SMP_ID_ADDR_SIZE + L2CAP_MIN_OFFSET)) != NULL) { p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; - BTM_GetDeviceIDRoot(irk); - UINT8_TO_STREAM (p, SMP_OPCODE_ID_ADDR); UINT8_TO_STREAM (p, 0); /* TODO: update with local address type */ - BTM_ReadConnectionAddr(p_cb->local_bda); - BDADDR_TO_STREAM (p, p_cb->local_bda); + BTM_GetLocalDeviceAddr(static_addr); + BDADDR_TO_STREAM (p, static_addr); p_buf->offset = L2CAP_MIN_OFFSET; p_buf->len = SMP_ID_ADDR_SIZE; @@ -367,7 +367,7 @@ static BT_HDR * smp_build_signing_info_cmd(UINT8 cmd_code, tSMP_CB *p_cb) { BT_HDR *p_buf = NULL ; UINT8 *p; - //BT_OCTET16 srk; remove + SMP_TRACE_EVENT0("smp_build_signing_info_cmd"); if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + SMP_SIGN_INFO_SIZE + L2CAP_MIN_OFFSET)) != NULL) { @@ -667,6 +667,20 @@ void smp_remove_fixed_channel_disable (BOOLEAN disable) SMP_TRACE_DEBUG1("smp_remove_fixed_channel_disable disable =%d", disable); smp_cb.remove_fixed_channel_disable = disable; } +/******************************************************************************* +** +** Function smp_skip_compare_check +** +** Description This function is called to skip the compare value check +** +** Returns void +** +*******************************************************************************/ +void smp_skip_compare_check(BOOLEAN enable) +{ + SMP_TRACE_DEBUG1("smp_skip_compare_check enable=%d", enable); + smp_cb.skip_test_compare_check = enable; +} #endif diff --git a/test/bluedroidtest/README.txt b/test/bluedroidtest/README.txt index a443a2955..0a4705074 100644 --- a/test/bluedroidtest/README.txt +++ b/test/bluedroidtest/README.txt @@ -41,16 +41,29 @@ HAL REQUEST SUCCESS Enabling Test Mode (Bluetooth must be enabled for this command to work) ====================================================================== ->enable_test_mode -ENABLE BT TEST MODE +>dut_mode_configure 1 +BT DUT MODE CONFIGURE HAL REQUEST SUCCESS > Disabling Test Mode =================== ->disable_test_mode -DISABLE BT TEST MODE +>dut_mode_configure 0 +BT DUT MODE CONFIGURE HAL REQUEST SUCCESS +> + +Running BLE Test commands (Bluetooth must be enabled) +===================================================== +NOTE: Unlike BR/EDR, there is no explicit DUT mode to run these BLE tests. + +> le_test_mode 1 <rx_freq> + +> le_test_mode 2 <tx_freq> <test_data_len> <payload_pattern> + +> le_test_mode 3 <no_args> +Please refer to the BT Core spec pages-1099 to 1102 for possible values for +the above parameters. These values need to be provided in Decimal format. Exit the test application ========================= @@ -68,6 +81,8 @@ help lists all available console commands quit enable :: enables bluetooth disable :: disables bluetooth -enable_test_mode :: enters bluedroid test mode -disable_test_mode :: exits bluedroid test mode +dut_mode_configure :: DUT mode - 1 to enter,0 to exit +le_test_mode :: LE Test Mode - RxTest - 1 <rx_freq>, + TxTest - 2 <tx_freq> <test_data_len> <payload_pattern>, + End Test - 3 <no_args> diff --git a/test/bluedroidtest/bluedroidtest.c b/test/bluedroidtest/bluedroidtest.c index 130bc6054..ad9f4023c 100644 --- a/test/bluedroidtest/bluedroidtest.c +++ b/test/bluedroidtest/bluedroidtest.c @@ -474,6 +474,11 @@ static void dut_mode_recv(uint16_t opcode, uint8_t *buf, uint8_t len) bdt_log("DUT MODE RECV : NOT IMPLEMENTED"); } +static void le_test_mode(bt_status_t status, uint16_t packet_count) +{ + bdt_log("LE TEST MODE END status:%s number_of_packets:%d", dump_bt_status(status), packet_count); +} + static bt_callbacks_t bt_callbacks = { sizeof(bt_callbacks_t), adapter_state_changed, @@ -487,6 +492,8 @@ static bt_callbacks_t bt_callbacks = { NULL, /* acl_state_changed_cb */ NULL, /* thread_evt_cb */ dut_mode_recv, /*dut_mode_recv_cb */ + NULL, /*authorize_request_cb */ + le_test_mode /* le_test_mode_cb */ }; void bdt_init(void) @@ -538,6 +545,58 @@ void bdt_dut_mode_configure(char *p) check_return_status(status); } +#define HCI_LE_RECEIVER_TEST_OPCODE 0x201D +#define HCI_LE_TRANSMITTER_TEST_OPCODE 0x201E +#define HCI_LE_END_TEST_OPCODE 0x201F + +void bdt_le_test_mode(char *p) +{ + int cmd; + unsigned char buf[3]; + int arg1, arg2, arg3; + + bdt_log("BT LE TEST MODE"); + if (!bt_enabled) { + bdt_log("Bluetooth must be enabled for le_test to work."); + return; + } + + memset(buf, 0, sizeof(buf)); + cmd = get_int(&p, 0); + switch (cmd) + { + case 0x1: /* RX TEST */ + arg1 = get_int(&p, -1); + if (arg1 < 0) bdt_log("%s Invalid arguments", __FUNCTION__); + buf[0] = arg1; + status = sBtInterface->le_test_mode(HCI_LE_RECEIVER_TEST_OPCODE, buf, 1); + break; + case 0x2: /* TX TEST */ + arg1 = get_int(&p, -1); + arg2 = get_int(&p, -1); + arg3 = get_int(&p, -1); + if ((arg1 < 0) || (arg2 < 0) || (arg3 < 0)) + bdt_log("%s Invalid arguments", __FUNCTION__); + buf[0] = arg1; + buf[1] = arg2; + buf[2] = arg3; + status = sBtInterface->le_test_mode(HCI_LE_TRANSMITTER_TEST_OPCODE, buf, 3); + break; + case 0x3: /* END TEST */ + status = sBtInterface->le_test_mode(HCI_LE_END_TEST_OPCODE, buf, 0); + break; + default: + bdt_log("Unsupported command"); + return; + break; + } + if (status != BT_STATUS_SUCCESS) + { + bdt_log("%s Test 0x%x Failed with status:0x%x", __FUNCTION__, cmd, status); + } + return; +} + void bdt_cleanup(void) { bdt_log("CLEANUP"); @@ -595,6 +654,11 @@ void do_dut_mode_configure(char *p) bdt_dut_mode_configure(p); } +void do_le_test_mode(char *p) +{ + bdt_le_test_mode(p); +} + void do_cleanup(char *p) { bdt_cleanup(); @@ -623,7 +687,9 @@ const t_cmd console_cmd_list[] = { "enable", do_enable, ":: enables bluetooth", 0 }, { "disable", do_disable, ":: disables bluetooth", 0 }, { "dut_mode_configure", do_dut_mode_configure, ":: DUT mode - 1 to enter,0 to exit", 0 }, - + { "le_test_mode", do_le_test_mode, ":: LE Test Mode - RxTest - 1 <rx_freq>, \n\t \ + TxTest - 2 <tx_freq> <test_data_len> <payload_pattern>, \n\t \ + End Test - 3 <no_args>", 0 }, /* add here */ /* last entry */ |