Read the correct amount of attributes am: 636b754cfa am: 5ec93991d7 am: 6e7c360c85
am: a51aaf2366
Change-Id: Ie8dfa4cff72aef91a87b4dbbc5b82f88213994e2
diff --git a/Android.bp b/Android.bp
index 69ed54b..dae6460 100644
--- a/Android.bp
+++ b/Android.bp
@@ -15,4 +15,5 @@
"vendor_libs",
"test",
"udrv",
+ "tools",
]
diff --git a/BUILD.gn b/BUILD.gn
index 3cb29e1..618de1c 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -39,3 +39,10 @@
"//device:net_test_device",
]
}
+
+group("test_tools") {
+ testonly = true
+ deps = [
+ "//tools/mcap_tool:mcap_tool"
+ ]
+}
diff --git a/bta/ag/bta_ag_cmd.cc b/bta/ag/bta_ag_cmd.cc
index 779f005..952e3cb 100644
--- a/bta/ag/bta_ag_cmd.cc
+++ b/bta/ag/bta_ag_cmd.cc
@@ -613,6 +613,19 @@
(*bta_ag_cb.p_cback)(command_id, (tBTA_AG*)&val);
}
+static void remove_spaces(char* str) {
+ char* dest_str = str;
+
+ while (*str) {
+ if (*str == ' ') {
+ str++;
+ } else {
+ *dest_str++ = *str++;
+ }
+ }
+ *dest_str = '\0';
+}
+
/*******************************************************************************
*
* Function bta_ag_find_empty_hf_ind)
@@ -874,12 +887,16 @@
** Let application decide whether to send OK or ERROR*/
/* if mem dial cmd, make sure string contains only digits */
- if (p_arg[0] == '>') {
- if (!utl_isintstr(p_arg + 1)) {
+ if (val.str[0] == '>') {
+ /* Some car kits may add some unwanted space characters in the
+ ** input string. This workaround will trim the unwanted chars. */
+ remove_spaces(val.str + 1);
+
+ if (!utl_isintstr(val.str + 1)) {
event = 0;
bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_DSTR);
}
- } else if (p_arg[0] == 'V') /* ATDV : Dial VoIP Call */
+ } else if (val.str[0] == 'V') /* ATDV : Dial VoIP Call */
{
/* We do not check string. Code will be added later if needed. */
if (!((p_scb->peer_features & BTA_AG_PEER_FEAT_VOIP) &&
@@ -891,7 +908,11 @@
/* If dial cmd, make sure string contains only dial digits
** Dial digits are 0-9, A-C, *, #, + */
else {
- if (!utl_isdialstr(p_arg)) {
+ /* Some car kits may add some unwanted space characters in the
+ ** input string. This workaround will trim the unwanted chars. */
+ remove_spaces(val.str);
+
+ if (!utl_isdialstr(val.str)) {
event = 0;
bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_DSTR);
}
diff --git a/bta/av/bta_av_aact.cc b/bta/av/bta_av_aact.cc
index 886ed0c..ed8ee30 100644
--- a/bta/av/bta_av_aact.cc
+++ b/bta/av/bta_av_aact.cc
@@ -387,7 +387,8 @@
/* we got a stream; get its capabilities */
if (p_scb->p_cap == NULL)
p_scb->p_cap = (tAVDT_CFG*)osi_malloc(sizeof(tAVDT_CFG));
- if (p_scb->avdt_version >= AVDT_VERSION_SYNC) {
+ if ((p_scb->avdt_version >= AVDT_VERSION_1_3) &&
+ (A2DP_GetAvdtpVersion() >= AVDT_VERSION_1_3)) {
p_req = AVDT_GetAllCapReq;
} else {
p_req = AVDT_GetCapReq;
@@ -1096,6 +1097,10 @@
local_sep = bta_av_get_scb_sep_type(p_scb, p_msg->handle);
p_scb->avdt_label = p_data->str_msg.msg.hdr.label;
+
+ APPL_TRACE_DEBUG("%s: local_sep = %d", __func__, local_sep);
+ A2DP_DumpCodecInfo(p_evt_cfg->codec_info);
+
memcpy(p_scb->cfg.codec_info, p_evt_cfg->codec_info, AVDT_CODEC_SIZE);
bta_av_save_addr(p_scb, p_data->str_msg.bd_addr);
@@ -1264,7 +1269,7 @@
p_scb->num_seps = num;
if (p_scb->cur_psc_mask & AVDT_PSC_DELAY_RPT)
- p_scb->avdt_version = AVDT_VERSION_SYNC;
+ p_scb->avdt_version = AVDT_VERSION_1_3;
if (A2DP_GetCodecType(p_scb->cfg.codec_info) == A2DP_MEDIA_CT_SBC ||
num > 1) {
@@ -1333,8 +1338,8 @@
p_scb->l2c_cid, p_scb->stream_mtu, mtu);
if (mtu == 0 || mtu > p_scb->stream_mtu) mtu = p_scb->stream_mtu;
- /* Set the media channel as medium priority */
- L2CA_SetTxPriority(p_scb->l2c_cid, L2CAP_CHNL_PRIORITY_MEDIUM);
+ /* Set the media channel as high priority */
+ L2CA_SetTxPriority(p_scb->l2c_cid, L2CAP_CHNL_PRIORITY_HIGH);
L2CA_SetChnlFlushability(p_scb->l2c_cid, true);
bta_sys_conn_open(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
@@ -1363,7 +1368,12 @@
p = BTM_ReadRemoteFeatures(p_scb->peer_addr);
if (p != NULL) {
if (HCI_EDR_ACL_2MPS_SUPPORTED(p)) open.edr |= BTA_AV_EDR_2MBPS;
- if (HCI_EDR_ACL_3MPS_SUPPORTED(p)) open.edr |= BTA_AV_EDR_3MBPS;
+ if (HCI_EDR_ACL_3MPS_SUPPORTED(p)) {
+ if (!interop_match_addr(INTEROP_2MBPS_LINK_ONLY,
+ (const bt_bdaddr_t*)&p_scb->peer_addr)) {
+ open.edr |= BTA_AV_EDR_3MBPS;
+ }
+ }
}
#if (BTA_AR_INCLUDED == TRUE)
bta_ar_avdt_conn(BTA_ID_AV, open.bd_addr);
@@ -1450,6 +1460,8 @@
*
******************************************************************************/
void bta_av_do_close(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+ APPL_TRACE_DEBUG("%s: p_scb->co_started=%d", __func__, p_scb->co_started);
+
/* stop stream if started */
if (p_scb->co_started) {
bta_av_str_stopped(p_scb, NULL);
@@ -1628,12 +1640,18 @@
APPL_TRACE_DEBUG("%s: num_seps:%d sep_info_idx:%d wait:x%x", __func__,
p_scb->num_seps, p_scb->sep_info_idx, p_scb->wait);
+ A2DP_DumpCodecInfo(p_scb->p_cap->codec_info);
+
memcpy(&cfg, p_scb->p_cap, sizeof(tAVDT_CFG));
/* let application know the capability of the SNK */
p_scb->p_cos->getcfg(p_scb->hndl, cfg.codec_info, &p_scb->sep_info_idx,
p_info->seid, &cfg.num_protect, cfg.protect_info);
p_scb->sep_info_idx++;
+ APPL_TRACE_DEBUG("%s: result: sep_info_idx:%d", __func__,
+ p_scb->sep_info_idx);
+ A2DP_DumpCodecInfo(cfg.codec_info);
+
if (p_scb->num_seps > p_scb->sep_info_idx) {
/* Some devices have seps at the end of the discover list, which is not */
/* matching media type(video not audio). */
@@ -1644,8 +1662,9 @@
getcap_done = true;
if (getcap_done) {
- /* we are done getting capabilities. restore the p_cb->sep_info_idx */
- p_scb->sep_info_idx = 0;
+ APPL_TRACE_DEBUG("%s: getcap_done: num_seps:%d sep_info_idx:%d wait:x%x",
+ __func__, p_scb->num_seps, p_scb->sep_info_idx,
+ p_scb->wait);
p_scb->wait &= ~(BTA_AV_WAIT_ACP_CAPS_ON | BTA_AV_WAIT_ACP_CAPS_STARTED);
if (old_wait & BTA_AV_WAIT_ACP_CAPS_STARTED) {
bta_av_start_ok(p_scb, NULL);
@@ -1763,6 +1782,7 @@
APPL_TRACE_DEBUG("%s: num_codec %d", __func__, p_scb->p_cap->num_codec);
APPL_TRACE_DEBUG("%s: media type x%x, x%x", __func__, media_type,
p_scb->media_type);
+ A2DP_DumpCodecInfo(p_scb->cfg.codec_info);
/* if codec present and we get a codec configuration */
if ((p_scb->p_cap->num_codec != 0) && (media_type == p_scb->media_type) &&
@@ -1772,6 +1792,10 @@
/* save copy of codec configuration */
memcpy(&p_scb->cfg, &cfg, sizeof(tAVDT_CFG));
+ APPL_TRACE_DEBUG("%s: result: sep_info_idx=%d", __func__,
+ p_scb->sep_info_idx);
+ A2DP_DumpCodecInfo(p_scb->cfg.codec_info);
+
uuid_int = p_scb->uuid_int;
APPL_TRACE_DEBUG("%s: initiator UUID = 0x%x", __func__, uuid_int);
if (uuid_int == UUID_SERVCLASS_AUDIO_SOURCE)
@@ -2030,16 +2054,22 @@
/* store the new configuration in control block */
if (p_scb->p_cap == NULL)
p_scb->p_cap = (tAVDT_CFG*)osi_malloc(sizeof(tAVDT_CFG));
- p_cfg = p_scb->p_cap;
+ p_cfg = &p_scb->cfg;
alarm_cancel(p_scb->avrc_ct_timer);
- memcpy(p_cfg, &p_scb->cfg, sizeof(tAVDT_CFG));
+ APPL_TRACE_DEBUG(
+ "%s: p_scb->sep_info_idx=%d p_scb->rcfg_idx=%d p_rcfg->sep_info_idx=%d",
+ __func__, p_scb->sep_info_idx, p_scb->rcfg_idx, p_rcfg->sep_info_idx);
+ A2DP_DumpCodecInfo(p_scb->p_cap->codec_info);
+ A2DP_DumpCodecInfo(p_scb->cfg.codec_info);
+ A2DP_DumpCodecInfo(p_rcfg->codec_info);
+
p_cfg->num_protect = p_rcfg->num_protect;
memcpy(p_cfg->codec_info, p_rcfg->codec_info, AVDT_CODEC_SIZE);
memcpy(p_cfg->protect_info, p_rcfg->p_protect_info, p_rcfg->num_protect);
p_scb->rcfg_idx = p_rcfg->sep_info_idx;
- p_scb->p_cap->psc_mask = p_scb->cur_psc_mask;
+ p_cfg->psc_mask = p_scb->cur_psc_mask;
// If the requested SEP index is same as the current one, then we
// can Suspend->Reconfigure->Start.
@@ -2056,8 +2086,9 @@
} else {
// Reconfigure
APPL_TRACE_DEBUG("%s: reconfig", __func__);
- AVDT_ReconfigReq(p_scb->avdt_handle, p_scb->p_cap);
- p_scb->p_cap->psc_mask = p_scb->cur_psc_mask;
+ A2DP_DumpCodecInfo(p_scb->cfg.codec_info);
+ AVDT_ReconfigReq(p_scb->avdt_handle, &p_scb->cfg);
+ p_scb->cfg.psc_mask = p_scb->cur_psc_mask;
}
} else {
// Close the stream first, and then Configure it
@@ -2725,8 +2756,9 @@
APPL_TRACE_DEBUG("%s: calling AVDT_ReconfigReq", __func__);
/* reconfig the stream */
- AVDT_ReconfigReq(p_scb->avdt_handle, p_scb->p_cap);
- p_scb->p_cap->psc_mask = p_scb->cur_psc_mask;
+ A2DP_DumpCodecInfo(p_scb->cfg.codec_info);
+ AVDT_ReconfigReq(p_scb->avdt_handle, &p_scb->cfg);
+ p_scb->cfg.psc_mask = p_scb->cur_psc_mask;
}
}
@@ -2811,7 +2843,9 @@
AVDT_DiscoverReq(p_scb->peer_addr, p_scb->sep_info, BTA_AV_NUM_SEPS,
bta_av_dt_cback[p_scb->hdi]);
} else {
- memcpy(p_scb->cfg.codec_info, p_scb->p_cap->codec_info, AVDT_CODEC_SIZE);
+ APPL_TRACE_DEBUG("%s: calling AVDT_OpenReq()", __func__);
+ A2DP_DumpCodecInfo(p_scb->cfg.codec_info);
+
/* we may choose to use a different SEP at reconfig.
* adjust the sep_idx now */
bta_av_adjust_seps_idx(p_scb, bta_av_get_scb_handle(p_scb, AVDT_TSEP_SRC));
@@ -2819,7 +2853,7 @@
/* open the stream with the new config */
p_scb->sep_info_idx = p_scb->rcfg_idx;
AVDT_OpenReq(p_scb->avdt_handle, p_scb->peer_addr,
- p_scb->sep_info[p_scb->sep_info_idx].seid, p_scb->p_cap);
+ p_scb->sep_info[p_scb->sep_info_idx].seid, &p_scb->cfg);
}
}
diff --git a/bta/dm/bta_dm_act.cc b/bta/dm/bta_dm_act.cc
index d6dddd9..f708cc6 100644
--- a/bta/dm/bta_dm_act.cc
+++ b/bta/dm/bta_dm_act.cc
@@ -38,6 +38,7 @@
#include "bta_dm_co.h"
#include "bta_dm_int.h"
#include "bta_sys.h"
+#include "btcore/include/bdaddr.h"
#include "btm_api.h"
#include "btm_int.h"
#include "btu.h"
@@ -665,7 +666,9 @@
BTM_SecDeleteDevice(bd_addr);
/* remove all cached GATT information */
- BTA_GATTC_Refresh(bd_addr);
+ bt_bdaddr_t tmp_addr;
+ memcpy(tmp_addr.address, bd_addr, BD_ADDR_LEN);
+ BTA_GATTC_Refresh(tmp_addr);
if (bta_dm_cb.p_sec_cback) {
tBTA_DM_SEC sec_event;
@@ -848,7 +851,9 @@
/* 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);
+ bt_bdaddr_t tmp_addr;
+ memcpy(tmp_addr.address, p_remove_acl->bd_addr, BD_ADDR_LEN);
+ BTA_GATTC_Refresh(tmp_addr);
}
/* otherwise, no action needed */
}
@@ -2607,9 +2612,14 @@
if (bta_dm_cb.p_sec_cback)
bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event);
- if (result != HCI_ERR_LMP_RESPONSE_TIMEOUT &&
- result != HCI_ERR_PAGE_TIMEOUT &&
- result != HCI_ERR_CONN_FAILED_ESTABLISHMENT) {
+ if (result == HCI_ERR_AUTH_FAILURE || result == HCI_ERR_KEY_MISSING ||
+ result == HCI_ERR_HOST_REJECT_SECURITY ||
+ result == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE) {
+ bdstr_t bd_addr_str;
+ APPL_TRACE_WARNING("%s deleting %s - result: 0x%02x", __func__,
+ bdaddr_to_string((bt_bdaddr_t*)bd_addr, bd_addr_str,
+ sizeof(bd_addr_str)),
+ result);
bta_dm_remove_sec_dev_entry(bd_addr);
}
}
@@ -3110,7 +3120,9 @@
/* need to remove all pending background connection */
BTA_GATTC_CancelOpen(0, p_bda, false);
/* remove all cached GATT information */
- BTA_GATTC_Refresh(p_bda);
+ bt_bdaddr_t tmp_addr;
+ memcpy(tmp_addr.address, p_bda, BD_ADDR_LEN);
+ BTA_GATTC_Refresh(tmp_addr);
}
bdcpy(conn.link_down.bd_addr, p_bda);
@@ -3283,7 +3295,9 @@
/* need to remove all pending background connection */
BTA_GATTC_CancelOpen(0, remote_bd_addr, false);
/* remove all cached GATT information */
- BTA_GATTC_Refresh(remote_bd_addr);
+ bt_bdaddr_t tmp_addr;
+ memcpy(tmp_addr.address, remote_bd_addr, BD_ADDR_LEN);
+ BTA_GATTC_Refresh(tmp_addr);
}
}
diff --git a/bta/dm/bta_dm_cfg.cc b/bta/dm/bta_dm_cfg.cc
index 787e11a..4202975 100644
--- a/bta/dm/bta_dm_cfg.cc
+++ b/bta/dm/bta_dm_cfg.cc
@@ -434,9 +434,6 @@
{{BTA_DM_PM_SNIFF_A2DP_IDX, 10000},
{BTA_DM_PM_NO_ACTION, 0}}, /* idle */
{{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
-#if (AMP_INCLUDED == TRUE)
- {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* amp */
-#endif
{{BTA_DM_PM_RETRY, 5000},
{BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
}}
@@ -456,9 +453,6 @@
{{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */
{{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
{{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
-#if (AMP_INCLUDED == TRUE)
- {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* amp */
-#endif
{{BTA_DM_PM_RETRY, 5000},
{BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
}}
diff --git a/bta/dm/bta_dm_pm.cc b/bta/dm/bta_dm_pm.cc
index aad921c..472b7e1 100644
--- a/bta/dm/bta_dm_pm.cc
+++ b/bta/dm/bta_dm_pm.cc
@@ -26,6 +26,8 @@
#include <base/logging.h>
#include <string.h>
+#include <mutex>
+
#include "bt_common.h"
#include "bta_api.h"
#include "bta_dm_api.h"
@@ -63,6 +65,8 @@
#endif
tBTA_DM_CONNECTED_SRVCS bta_dm_conn_srvcs;
+static std::recursive_mutex pm_timer_schedule_mutex;
+static std::recursive_mutex pm_timer_state_mutex;
/*******************************************************************************
*
@@ -267,6 +271,8 @@
static void bta_dm_pm_start_timer(tBTA_PM_TIMER* p_timer, uint8_t timer_idx,
period_ms_t timeout_ms, uint8_t srvc_id,
uint8_t pm_action) {
+ std::unique_lock<std::recursive_mutex> schedule_lock(pm_timer_schedule_mutex);
+ std::unique_lock<std::recursive_mutex> state_lock(pm_timer_state_mutex);
p_timer->in_use = true;
if (p_timer->srvc_id[timer_idx] == BTA_ID_MAX) p_timer->active++;
@@ -275,6 +281,7 @@
p_timer->pm_action[timer_idx] = pm_action;
p_timer->srvc_id[timer_idx] = srvc_id;
+ state_lock.unlock();
alarm_set_on_queue(p_timer->timer[timer_idx], timeout_ms,
bta_dm_pm_timer_cback, p_timer->timer[timer_idx],
@@ -295,17 +302,21 @@
uint8_t timer_idx) {
if ((p_timer == NULL) || (timer_idx >= BTA_DM_PM_MODE_TIMER_MAX)) return;
+ std::unique_lock<std::recursive_mutex> schedule_lock(pm_timer_schedule_mutex);
+ std::unique_lock<std::recursive_mutex> state_lock(pm_timer_state_mutex);
if (p_timer->srvc_id[timer_idx] == BTA_ID_MAX)
return; /* The timer was not scheduled */
CHECK(p_timer->in_use && (p_timer->active > 0));
- alarm_cancel(p_timer->timer[timer_idx]);
p_timer->srvc_id[timer_idx] = BTA_ID_MAX;
/* NOTE: pm_action[timer_idx] intentionally not reset */
p_timer->active--;
if (p_timer->active == 0) p_timer->in_use = false;
+ state_lock.unlock();
+
+ alarm_cancel(p_timer->timer[timer_idx]);
}
/*******************************************************************************
@@ -871,6 +882,7 @@
uint8_t i, j;
alarm_t* alarm = (alarm_t*)data;
+ std::unique_lock<std::recursive_mutex> state_lock(pm_timer_state_mutex);
for (i = 0; i < BTA_DM_NUM_PM_TIMER; i++) {
APPL_TRACE_DEBUG("dm_pm_timer[%d] in use? %d", i,
bta_dm_cb.pm_timer[i].in_use);
@@ -888,6 +900,7 @@
if (j < BTA_DM_PM_MODE_TIMER_MAX) break;
}
}
+ state_lock.unlock();
/* no more timers */
if (i == BTA_DM_NUM_PM_TIMER) return;
diff --git a/bta/gatt/bta_gattc_act.cc b/bta/gatt/bta_gattc_act.cc
index 1a7c279..5d9a127 100644
--- a/bta/gatt/bta_gattc_act.cc
+++ b/bta/gatt/bta_gattc_act.cc
@@ -30,6 +30,7 @@
#include <base/callback.h>
#include "bt_common.h"
#include "bt_target.h"
+#include "bta_closure_api.h"
#include "bta_gattc_int.h"
#include "bta_sys.h"
#include "btif/include/btif_debug_conn.h"
@@ -157,15 +158,17 @@
}
}
-/*******************************************************************************
- *
- * Function bta_gattc_register
- *
- * Description Register a GATT client application with BTA.
- *
- * Returns void
- *
- ******************************************************************************/
+/** start an application interface */
+void bta_gattc_start_if(uint8_t client_if) {
+ if (!bta_gattc_cl_get_regcb(client_if)) {
+ APPL_TRACE_ERROR("Unable to start app.: Unknown interface =%d", client_if);
+ return;
+ }
+
+ GATT_StartIf(client_if);
+}
+
+/** Register a GATT client application with BTA */
void bta_gattc_register(tBT_UUID* p_app_uuid, tBTA_GATTC_CBACK* p_cback,
BtaAppRegisterCallback cb) {
tBTA_GATT_STATUS status = BTA_GATT_NO_RESOURCES;
@@ -192,12 +195,8 @@
/* BTA use the same client interface as BTE GATT statck */
client_if = bta_gattc_cb.cl_rcb[i].client_if;
- tBTA_GATTC_INT_START_IF* p_buf = (tBTA_GATTC_INT_START_IF*)osi_malloc(
- sizeof(tBTA_GATTC_INT_START_IF));
- p_buf->hdr.event = BTA_GATTC_INT_START_IF_EVT;
- p_buf->client_if = bta_gattc_cb.cl_rcb[i].client_if;
+ do_in_bta_thread(FROM_HERE, base::Bind(&bta_gattc_start_if, client_if));
- bta_sys_sendmsg(p_buf);
status = BTA_GATT_OK;
break;
}
@@ -206,23 +205,7 @@
if (!cb.is_null()) cb.Run(client_if, status);
}
-/*******************************************************************************
- *
- * Function bta_gattc_start_if
- *
- * Description start an application interface.
- *
- * Returns none.
- *
- ******************************************************************************/
-void bta_gattc_start_if(tBTA_GATTC_DATA* p_msg) {
- if (bta_gattc_cl_get_regcb(p_msg->int_start_if.client_if) != NULL) {
- GATT_StartIf(p_msg->int_start_if.client_if);
- } else {
- APPL_TRACE_ERROR("Unable to start app.: Unknown interface =%d",
- p_msg->int_start_if.client_if);
- }
-}
+
/*******************************************************************************
*
* Function bta_gattc_deregister
@@ -341,26 +324,18 @@
}
}
-/*******************************************************************************
- *
- * Function bta_gattc_process_enc_cmpl
- *
- * Description process encryption complete message.
- *
- * Returns void
- *
- ******************************************************************************/
-void bta_gattc_process_enc_cmpl(tBTA_GATTC_DATA* p_msg) {
+/** process encryption complete message */
+void bta_gattc_process_enc_cmpl(tGATT_IF client_if, bt_bdaddr_t bda) {
tBTA_GATTC_RCB* p_clreg;
tBTA_GATTC cb_data;
- p_clreg = bta_gattc_cl_get_regcb(p_msg->enc_cmpl.client_if);
+ p_clreg = bta_gattc_cl_get_regcb(client_if);
if (p_clreg && p_clreg->p_cback) {
memset(&cb_data, 0, sizeof(tBTA_GATTC));
- cb_data.enc_cmpl.client_if = p_msg->enc_cmpl.client_if;
- bdcpy(cb_data.enc_cmpl.remote_bda, p_msg->enc_cmpl.remote_bda);
+ cb_data.enc_cmpl.client_if = client_if;
+ memcpy(cb_data.enc_cmpl.remote_bda, bda.address, BD_ADDR_LEN);
(*p_clreg->p_cback)(BTA_GATTC_ENC_CMPL_CB_EVT, &cb_data);
}
@@ -1400,14 +1375,10 @@
APPL_TRACE_DEBUG("%s: cif = %d", __func__, gattc_if);
- tBTA_GATTC_DATA* p_buf =
- (tBTA_GATTC_DATA*)osi_calloc(sizeof(tBTA_GATTC_DATA));
- p_buf->enc_cmpl.hdr.event = BTA_GATTC_ENC_CMPL_EVT;
- p_buf->enc_cmpl.hdr.layer_specific = p_clcb->bta_conn_id;
- p_buf->enc_cmpl.client_if = gattc_if;
- bdcpy(p_buf->enc_cmpl.remote_bda, bda);
-
- bta_sys_sendmsg(p_buf);
+ bt_bdaddr_t addr;
+ memcpy(addr.address, bda, BD_ADDR_LEN);
+ do_in_bta_thread(FROM_HERE,
+ base::Bind(&bta_gattc_process_enc_cmpl, gattc_if, addr));
}
/*******************************************************************************
@@ -1420,9 +1391,8 @@
* Returns None.
*
******************************************************************************/
-void bta_gattc_process_api_refresh(tBTA_GATTC_DATA* p_msg) {
- tBTA_GATTC_SERV* p_srvc_cb =
- bta_gattc_find_srvr_cache(p_msg->api_conn.remote_bda);
+void bta_gattc_process_api_refresh(bt_bdaddr_t remote_bda) {
+ tBTA_GATTC_SERV* p_srvc_cb = bta_gattc_find_srvr_cache(remote_bda.address);
tBTA_GATTC_CLCB* p_clcb = &bta_gattc_cb.clcb[0];
bool found = false;
uint8_t i;
@@ -1448,7 +1418,7 @@
}
}
/* used to reset cache in application */
- bta_gattc_cache_reset(p_msg->api_conn.remote_bda);
+ bta_gattc_cache_reset(remote_bda.address);
}
/*******************************************************************************
*
diff --git a/bta/gatt/bta_gattc_api.cc b/bta/gatt/bta_gattc_api.cc
index 01f17c9..36fc36e 100644
--- a/bta/gatt/bta_gattc_api.cc
+++ b/bta/gatt/bta_gattc_api.cc
@@ -60,10 +60,7 @@
return;
}
- BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
- p_buf->event = BTA_GATTC_API_DISABLE_EVT;
-
- bta_sys_sendmsg(p_buf);
+ do_in_bta_thread(FROM_HERE, base::Bind(&bta_gattc_disable));
bta_sys_deregister(BTA_ID_GATTC);
}
@@ -92,6 +89,9 @@
p_client_cb, std::move(cb)));
}
+static void app_deregister_impl(tBTA_GATTC_IF client_if) {
+ bta_gattc_deregister(bta_gattc_cl_get_regcb(client_if));
+}
/*******************************************************************************
*
* Function BTA_GATTC_AppDeregister
@@ -105,13 +105,7 @@
*
******************************************************************************/
void BTA_GATTC_AppDeregister(tBTA_GATTC_IF client_if) {
- tBTA_GATTC_API_DEREG* p_buf =
- (tBTA_GATTC_API_DEREG*)osi_malloc(sizeof(tBTA_GATTC_API_DEREG));
-
- p_buf->hdr.event = BTA_GATTC_API_DEREG_EVT;
- p_buf->client_if = client_if;
-
- bta_sys_sendmsg(p_buf);
+ do_in_bta_thread(FROM_HERE, base::Bind(&app_deregister_impl, client_if));
}
/*******************************************************************************
@@ -738,12 +732,7 @@
* Returns void
*
******************************************************************************/
-void BTA_GATTC_Refresh(const BD_ADDR remote_bda) {
- tBTA_GATTC_API_OPEN* p_buf =
- (tBTA_GATTC_API_OPEN*)osi_malloc(sizeof(tBTA_GATTC_API_OPEN));
-
- p_buf->hdr.event = BTA_GATTC_API_REFRESH_EVT;
- memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN);
-
- bta_sys_sendmsg(p_buf);
+void BTA_GATTC_Refresh(const bt_bdaddr_t& remote_bda) {
+ do_in_bta_thread(FROM_HERE,
+ base::Bind(&bta_gattc_process_api_refresh, remote_bda));
}
diff --git a/bta/gatt/bta_gattc_cache.cc b/bta/gatt/bta_gattc_cache.cc
index 07bae93..adcb62d 100644
--- a/bta/gatt/bta_gattc_cache.cc
+++ b/bta/gatt/bta_gattc_cache.cc
@@ -1085,6 +1085,10 @@
p_attr->end_handle = e_handle;
p_attr->id = id;
p_attr->properties = prop;
+
+ // Permissions are not discoverable using the attribute protocol.
+ // Core 5.0, Part F, 3.2.5 Attribute Permissions
+ p_attr->permissions = 0;
bta_to_btif_uuid(&p_attr->uuid, &uuid);
}
diff --git a/bta/gatt/bta_gattc_int.h b/bta/gatt/bta_gattc_int.h
index 7a1158b..598262b 100644
--- a/bta/gatt/bta_gattc_int.h
+++ b/bta/gatt/bta_gattc_int.h
@@ -51,18 +51,12 @@
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,
BTA_GATTC_DISCOVER_CMPL_EVT,
BTA_GATTC_OP_CMPL_EVT,
- BTA_GATTC_INT_DISCONN_EVT,
-
- BTA_GATTC_INT_START_IF_EVT,
- BTA_GATTC_API_DEREG_EVT,
- BTA_GATTC_API_DISABLE_EVT,
- BTA_GATTC_ENC_CMPL_EVT
+ BTA_GATTC_INT_DISCONN_EVT
};
typedef uint16_t tBTA_GATTC_INT_EVT;
@@ -89,14 +83,6 @@
/* internal strucutre for GATTC register API */
typedef struct {
BT_HDR hdr;
- tBTA_GATTC_IF client_if;
-} tBTA_GATTC_INT_START_IF;
-
-typedef tBTA_GATTC_INT_START_IF tBTA_GATTC_API_DEREG;
-typedef tBTA_GATTC_INT_START_IF tBTA_GATTC_INT_DEREG;
-
-typedef struct {
- BT_HDR hdr;
BD_ADDR remote_bda;
tBTA_GATTC_IF client_if;
bool is_direct;
@@ -181,15 +167,8 @@
tGATT_DISCONN_REASON reason;
} tBTA_GATTC_INT_CONN;
-typedef struct {
- BT_HDR hdr;
- BD_ADDR remote_bda;
- tBTA_GATTC_IF client_if;
-} tBTA_GATTC_ENC_CMPL;
-
typedef union {
BT_HDR hdr;
- tBTA_GATTC_API_DEREG api_dereg;
tBTA_GATTC_API_OPEN api_conn;
tBTA_GATTC_API_CANCEL_OPEN api_cancel_conn;
tBTA_GATTC_API_READ api_read;
@@ -201,11 +180,6 @@
tBTA_GATTC_API_CFG_MTU api_mtu;
tBTA_GATTC_OP_CMPL op_cmpl;
tBTA_GATTC_INT_CONN int_conn;
- tBTA_GATTC_ENC_CMPL enc_cmpl;
-
- tBTA_GATTC_INT_START_IF int_start_if;
- tBTA_GATTC_INT_DEREG int_dereg;
-
} tBTA_GATTC_DATA;
/* GATT server cache on the client */
@@ -366,11 +340,9 @@
extern void bta_gattc_disable();
extern void bta_gattc_register(tBT_UUID* p_app_uuid, tBTA_GATTC_CBACK* p_data,
BtaAppRegisterCallback cb);
-extern void bta_gattc_start_if(tBTA_GATTC_DATA* p_data);
extern void bta_gattc_process_api_open(tBTA_GATTC_DATA* p_msg);
extern void bta_gattc_process_api_open_cancel(tBTA_GATTC_DATA* p_msg);
extern void bta_gattc_deregister(tBTA_GATTC_RCB* p_clreg);
-extern void bta_gattc_process_enc_cmpl(tBTA_GATTC_DATA* p_msg);
/* function within state machine */
extern void bta_gattc_open(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
@@ -422,7 +394,7 @@
tBTA_GATT_STATUS status,
BD_ADDR remote_bda, uint16_t conn_id,
tBTA_TRANSPORT transport, uint16_t mtu);
-extern void bta_gattc_process_api_refresh(tBTA_GATTC_DATA* p_msg);
+extern void bta_gattc_process_api_refresh(bt_bdaddr_t remote_bda);
extern void bta_gattc_cfg_mtu(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
extern void bta_gattc_listen(tBTA_GATTC_DATA* p_msg);
extern void bta_gattc_broadcast(tBTA_GATTC_DATA* p_msg);
diff --git a/bta/gatt/bta_gattc_main.cc b/bta/gatt/bta_gattc_main.cc
index 16efce0..9a2deb6 100644
--- a/bta/gatt/bta_gattc_main.cc
+++ b/bta/gatt/bta_gattc_main.cc
@@ -125,8 +125,6 @@
/* 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,
@@ -169,8 +167,6 @@
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,
@@ -209,8 +205,6 @@
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},
@@ -255,8 +249,6 @@
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_CONN,
BTA_GATTC_DISCOVER_ST},
@@ -361,26 +353,12 @@
******************************************************************************/
bool bta_gattc_hdl_event(BT_HDR* p_msg) {
tBTA_GATTC_CLCB* p_clcb = NULL;
- tBTA_GATTC_RCB* p_clreg;
bool rt = true;
#if (BTA_GATT_DEBUG == TRUE)
APPL_TRACE_DEBUG("bta_gattc_hdl_event: Event [%s]",
gattc_evt_code(p_msg->event));
#endif
switch (p_msg->event) {
- case BTA_GATTC_API_DISABLE_EVT:
- bta_gattc_disable();
- break;
-
- case BTA_GATTC_INT_START_IF_EVT:
- bta_gattc_start_if((tBTA_GATTC_DATA*)p_msg);
- break;
-
- case BTA_GATTC_API_DEREG_EVT:
- p_clreg = bta_gattc_cl_get_regcb(
- ((tBTA_GATTC_DATA*)p_msg)->api_dereg.client_if);
- bta_gattc_deregister(p_clreg);
- break;
case BTA_GATTC_API_OPEN_EVT:
bta_gattc_process_api_open((tBTA_GATTC_DATA*)p_msg);
@@ -390,14 +368,6 @@
bta_gattc_process_api_open_cancel((tBTA_GATTC_DATA*)p_msg);
break;
- case BTA_GATTC_API_REFRESH_EVT:
- bta_gattc_process_api_refresh((tBTA_GATTC_DATA*)p_msg);
- break;
-
- case BTA_GATTC_ENC_CMPL_EVT:
- bta_gattc_process_enc_cmpl((tBTA_GATTC_DATA*)p_msg);
- break;
-
default:
if (p_msg->event == BTA_GATTC_INT_CONN_EVT)
p_clcb = bta_gattc_find_int_conn_clcb((tBTA_GATTC_DATA*)p_msg);
@@ -467,14 +437,6 @@
return "BTA_GATTC_OP_CMPL_EVT";
case BTA_GATTC_INT_DISCONN_EVT:
return "BTA_GATTC_INT_DISCONN_EVT";
- case BTA_GATTC_INT_START_IF_EVT:
- return "BTA_GATTC_INT_START_IF_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";
- case BTA_GATTC_API_DISABLE_EVT:
- return "BTA_GATTC_API_DISABLE_EVT";
case BTA_GATTC_API_CFG_MTU_EVT:
return "BTA_GATTC_API_CFG_MTU_EVT";
default:
diff --git a/bta/include/bta_gatt_api.h b/bta/include/bta_gatt_api.h
index 40f274a..fb8581e 100644
--- a/bta/include/bta_gatt_api.h
+++ b/bta/include/bta_gatt_api.h
@@ -959,7 +959,7 @@
* Returns void
*
******************************************************************************/
-extern void BTA_GATTC_Refresh(const BD_ADDR remote_bda);
+extern void BTA_GATTC_Refresh(const bt_bdaddr_t& remote_bda);
/*******************************************************************************
*
diff --git a/bta/sys/bta_sys_main.cc b/bta/sys/bta_sys_main.cc
index 32985e8..6386539 100644
--- a/bta/sys/bta_sys_main.cc
+++ b/bta/sys/bta_sys_main.cc
@@ -24,7 +24,9 @@
#define LOG_TAG "bt_bta_sys_main"
+#include <base/bind.h>
#include <base/logging.h>
+#include <base/threading/thread.h>
#include <pthread.h>
#include <string.h>
@@ -34,6 +36,7 @@
#include "bta_sys.h"
#include "bta_sys_int.h"
#include "btm_api.h"
+#include "btu.h"
#include "osi/include/alarm.h"
#include "osi/include/fixed_queue.h"
#include "osi/include/log.h"
@@ -529,16 +532,23 @@
* optimize sending of messages to BTA. It is called by BTA
* API functions and call-in functions.
*
+ * TODO (apanicke): Add location object as parameter for easier
+ * future debugging when doing alarm refactor
+ *
*
* Returns void
*
******************************************************************************/
void bta_sys_sendmsg(void* p_msg) {
- // There is a race condition that occurs if the stack is shut down while
- // there is a procedure in progress that can schedule a task via this
- // message queue. This causes |btu_bta_msg_queue| to get cleaned up before
- // it gets used here; hence we check for NULL before using it.
- if (btu_bta_msg_queue) fixed_queue_enqueue(btu_bta_msg_queue, p_msg);
+ base::MessageLoop* bta_message_loop = get_message_loop();
+
+ if (!bta_message_loop || !bta_message_loop->task_runner().get()) {
+ APPL_TRACE_ERROR("%s: MessageLooper not initialized", __func__);
+ return;
+ }
+
+ bta_message_loop->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&bta_sys_event, static_cast<BT_HDR*>(p_msg)));
}
/*******************************************************************************
@@ -557,6 +567,7 @@
p_buf->event = event;
p_buf->layer_specific = layer_specific;
+
alarm_set_on_queue(alarm, interval, bta_sys_sendmsg, p_buf,
btu_bta_alarm_queue);
}
diff --git a/btcore/Android.bp b/btcore/Android.bp
index 6e058d2..442cc60 100644
--- a/btcore/Android.bp
+++ b/btcore/Android.bp
@@ -34,6 +34,7 @@
// ========================================================
cc_test {
name: "net_test_btcore",
+ test_suites: ["device-tests"],
defaults: ["fluoride_defaults"],
local_include_dirs: ["include"],
include_dirs: ["system/bt"],
diff --git a/btcore/AndroidTest.xml b/btcore/AndroidTest.xml
new file mode 100644
index 0000000..be321c5
--- /dev/null
+++ b/btcore/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ 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.
+-->
+<configuration description="Config for net_test_btcore">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="net_test_btcore->/data/local/tmp/net_test_btcore" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="net_test_btcore" />
+ </test>
+</configuration>
\ No newline at end of file
diff --git a/btif/Android.bp b/btif/Android.bp
index b455e90..c94b767 100644
--- a/btif/Android.bp
+++ b/btif/Android.bp
@@ -119,3 +119,25 @@
],
cflags: ["-DBUILDCFG"],
}
+
+// btif profile queue unit tests for target
+// ========================================================
+cc_test {
+ name: "net_test_btif_profile_queue",
+ defaults: ["fluoride_defaults"],
+ include_dirs: btifCommonIncludes,
+ srcs: [
+ "src/btif_profile_queue.cc",
+ "test/btif_profile_queue_test.cc"
+ ],
+ shared_libs: [
+ "liblog",
+ "libhardware",
+ "libcutils",
+ ],
+ static_libs: [
+ "libbtcore",
+ "libosi",
+ ],
+ cflags: ["-DBUILDCFG"],
+}
diff --git a/btif/co/bta_av_co.cc b/btif/co/bta_av_co.cc
index 76b0199..687499a 100644
--- a/btif/co/bta_av_co.cc
+++ b/btif/co/bta_av_co.cc
@@ -395,6 +395,7 @@
tBTA_AV_CO_PEER* p_peer;
APPL_TRACE_DEBUG("%s", __func__);
+ A2DP_DumpCodecInfo(p_codec_info);
/* Retrieve the peer info */
p_peer = bta_av_co_get_peer(hndl);
@@ -506,6 +507,7 @@
APPL_TRACE_DEBUG("num_protect:0x%02x protect_info:0x%02x%02x%02x",
num_protect, p_protect_info[0], p_protect_info[1],
p_protect_info[2]);
+ A2DP_DumpCodecInfo(p_codec_info);
/* Retrieve the peer info */
p_peer = bta_av_co_get_peer(hndl);
@@ -991,6 +993,9 @@
const uint8_t* new_codec_config,
uint8_t num_protect,
const uint8_t* p_protect_info) {
+ APPL_TRACE_DEBUG("%s", __func__);
+ A2DP_DumpCodecInfo(new_codec_config);
+
// Protect access to bta_av_co_cb.codec_config
mutex_global_lock();
@@ -1113,6 +1118,15 @@
success = false;
goto done;
}
+ // Don't call BTA_AvReconfig() prior to retrieving all peer's capabilities
+ if ((p_peer->num_rx_sinks != p_peer->num_sinks) &&
+ (p_peer->num_sup_sinks != BTA_AV_CO_NUM_ELEMENTS(p_peer->sinks))) {
+ APPL_TRACE_WARNING("%s: not all peer's capabilities have been retrieved",
+ __func__);
+ success = false;
+ goto done;
+ }
+
APPL_TRACE_DEBUG("%s: call BTA_AvReconfig(x%x)", __func__, p_peer->handle);
BTA_AvReconfig(p_peer->handle, true, p_sink->sep_info_idx,
p_peer->codec_config, num_protect, bta_av_co_cp_scmst);
@@ -1153,6 +1167,9 @@
bool restart_output = false;
bool config_updated = false;
+ APPL_TRACE_DEBUG("%s", __func__);
+ A2DP_DumpCodecInfo(p_ota_codec_config);
+
*p_restart_output = false;
// Find the peer SEP codec to use
@@ -1189,6 +1206,9 @@
}
if (restart_output) {
+ APPL_TRACE_DEBUG("%s: restart output", __func__);
+ A2DP_DumpCodecInfo(result_codec_config);
+
*p_restart_output = true;
p_peer->p_sink = p_sink;
bta_av_co_save_new_codec_config(p_peer, result_codec_config, num_protect,
@@ -1248,9 +1268,17 @@
bta_av_co_save_new_codec_config(p_peer, result_codec_config,
p_sink->num_protect, p_sink->protect_info);
- APPL_TRACE_DEBUG("%s: call BTA_AvReconfig(x%x)", __func__, p_peer->handle);
- BTA_AvReconfig(p_peer->handle, true, p_sink->sep_info_idx,
- p_peer->codec_config, num_protect, bta_av_co_cp_scmst);
+ // Don't call BTA_AvReconfig() prior to retrieving all peer's capabilities
+ if ((p_peer->num_rx_sinks != p_peer->num_sinks) &&
+ (p_peer->num_sup_sinks != BTA_AV_CO_NUM_ELEMENTS(p_peer->sinks))) {
+ APPL_TRACE_WARNING("%s: not all peer's capabilities have been retrieved",
+ __func__);
+ } else {
+ APPL_TRACE_DEBUG("%s: call BTA_AvReconfig(x%x)", __func__,
+ p_peer->handle);
+ BTA_AvReconfig(p_peer->handle, true, p_sink->sep_info_idx,
+ p_peer->codec_config, num_protect, bta_av_co_cp_scmst);
+ }
}
if (config_updated) {
diff --git a/btif/include/btif_profile_queue.h b/btif/include/btif_profile_queue.h
index 01aa8f0..fca75f3 100644
--- a/btif/include/btif_profile_queue.h
+++ b/btif/include/btif_profile_queue.h
@@ -33,6 +33,7 @@
bt_status_t btif_queue_connect(uint16_t uuid, const bt_bdaddr_t* bda,
btif_connect_cb_t connect_cb);
+void btif_queue_cleanup(uint16_t uuid);
void btif_queue_advance();
bt_status_t btif_queue_connect_next(void);
void btif_queue_release();
diff --git a/btif/src/btif_a2dp_source.cc b/btif/src/btif_a2dp_source.cc
index 6104370..fbe3d07 100644
--- a/btif/src/btif_a2dp_source.cc
+++ b/btif/src/btif_a2dp_source.cc
@@ -18,8 +18,10 @@
******************************************************************************/
#define LOG_TAG "bt_btif_a2dp_source"
+#define ATRACE_TAG ATRACE_TAG_AUDIO
#include <base/logging.h>
+#include <cutils/trace.h>
#include <limits.h>
#include <string.h>
#include <algorithm>
@@ -660,10 +662,11 @@
if (alarm_is_scheduled(btif_a2dp_source_cb.media_alarm)) {
CHECK(btif_a2dp_source_cb.encoder_interface != NULL);
+ size_t transmit_queue_length =
+ fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue);
+ ATRACE_INT("btif TX queue", transmit_queue_length);
if (btif_a2dp_source_cb.encoder_interface->set_transmit_queue_length !=
NULL) {
- size_t transmit_queue_length =
- fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue);
btif_a2dp_source_cb.encoder_interface->set_transmit_queue_length(
transmit_queue_length);
}
diff --git a/btif/src/btif_av.cc b/btif/src/btif_av.cc
index 4e78fbf..dd17bb8 100644
--- a/btif/src/btif_av.cc
+++ b/btif/src/btif_av.cc
@@ -1419,6 +1419,7 @@
static void cleanup_src(void) {
BTIF_TRACE_EVENT("%s", __func__);
+ btif_queue_cleanup(UUID_SERVCLASS_AUDIO_SOURCE);
if (bt_av_src_callbacks) {
bt_av_src_callbacks = NULL;
if (bt_av_sink_callbacks == NULL) cleanup(BTA_A2DP_SOURCE_SERVICE_ID);
@@ -1428,6 +1429,7 @@
static void cleanup_sink(void) {
BTIF_TRACE_EVENT("%s", __func__);
+ btif_queue_cleanup(UUID_SERVCLASS_AUDIO_SINK);
if (bt_av_sink_callbacks) {
bt_av_sink_callbacks = NULL;
if (bt_av_src_callbacks == NULL) cleanup(BTA_A2DP_SINK_SERVICE_ID);
diff --git a/btif/src/btif_ble_advertiser.cc b/btif/src/btif_ble_advertiser.cc
index a37b095..3c02882 100644
--- a/btif/src/btif_ble_advertiser.cc
+++ b/btif/src/btif_ble_advertiser.cc
@@ -103,8 +103,15 @@
void Unregister(uint8_t advertiser_id) override {
do_in_bta_thread(
FROM_HERE,
- Bind(&BleAdvertisingManager::Unregister,
- base::Unretained(BleAdvertisingManager::Get()), advertiser_id));
+ Bind(
+ [](uint8_t advertiser_id) {
+ if (!BleAdvertisingManager::IsInitialized()) {
+ LOG(WARNING) << "Stack already shutdown";
+ return;
+ }
+ BleAdvertisingManager::Get()->Unregister(advertiser_id);
+ },
+ advertiser_id));
}
void GetOwnAddress(uint8_t advertiser_id, GetAddressCallback cb) override {
diff --git a/btif/src/btif_config.cc b/btif/src/btif_config.cc
index 3b3dc4f..f6faa7d 100644
--- a/btif/src/btif_config.cc
+++ b/btif/src/btif_config.cc
@@ -231,8 +231,10 @@
btif_config_flush();
alarm_free(config_timer);
- config_free(config);
config_timer = NULL;
+
+ std::unique_lock<std::mutex> lock(config_lock);
+ config_free(config);
config = NULL;
return future_new_immediate(FUTURE_SUCCESS);
}
diff --git a/btif/src/btif_dm.cc b/btif/src/btif_dm.cc
index f5c2c88..07cb00d 100644
--- a/btif/src/btif_dm.cc
+++ b/btif/src/btif_dm.cc
@@ -2027,7 +2027,7 @@
* to the end of the tBTA_DM_SEARCH */
switch (event) {
case BTA_DM_INQ_RES_EVT: {
- if (p_data->inq_res.p_eir) param_len += HCI_EXT_INQ_RESPONSE_LEN;
+ if (p_data->inq_res.p_eir) param_len += p_data->inq_res.eir_len;
} break;
case BTA_DM_DISC_RES_EVT: {
@@ -2909,7 +2909,7 @@
state = BT_BOND_STATE_NONE;
} else {
btif_dm_save_ble_bonding_keys();
- BTA_GATTC_Refresh(bd_addr.address);
+ BTA_GATTC_Refresh(bd_addr);
btif_dm_get_remote_services_by_transport(&bd_addr, BTA_GATT_TRANSPORT_LE);
}
} else {
diff --git a/btif/src/btif_gatt_client.cc b/btif/src/btif_gatt_client.cc
index 70b7d4e..e0636ff 100644
--- a/btif/src/btif_gatt_client.cc
+++ b/btif/src/btif_gatt_client.cc
@@ -255,7 +255,8 @@
}
void btif_gattc_open_impl(int client_if, BD_ADDR address, bool is_direct,
- int transport_p, int initiating_phys) {
+ int transport_p, bool opportunistic,
+ int initiating_phys) {
// Ensure device is in inquiry database
int addr_type = 0;
int device_type = 0;
@@ -308,14 +309,15 @@
}
// Connect!
- BTIF_TRACE_DEBUG("%s Transport=%d, device type=%d, phy=%d", __func__,
- transport, device_type, initiating_phys);
- BTA_GATTC_Open(client_if, address, is_direct, transport, false,
+ BTIF_TRACE_DEBUG("%s Transport=%d, device type=%d, opportunistic=%d, phy=%d",
+ __func__, transport, device_type, opportunistic,
+ initiating_phys);
+ BTA_GATTC_Open(client_if, address, is_direct, transport, opportunistic,
initiating_phys);
}
bt_status_t btif_gattc_open(int client_if, const bt_bdaddr_t* bd_addr,
- bool is_direct, int transport,
+ bool is_direct, int transport, bool opportunistic,
int initiating_phys) {
CHECK_BTGATT_INIT();
// Closure will own this value and free it.
@@ -323,7 +325,7 @@
bdcpy(address, bd_addr->address);
return do_in_jni_thread(Bind(&btif_gattc_open_impl, client_if,
base::Owned(address), is_direct, transport,
- initiating_phys));
+ opportunistic, initiating_phys));
}
void btif_gattc_close_impl(int client_if, BD_ADDR address, int conn_id) {
@@ -349,10 +351,7 @@
bt_status_t btif_gattc_refresh(int client_if, const bt_bdaddr_t* bd_addr) {
CHECK_BTGATT_INIT();
- // Closure will own this value and free it.
- uint8_t* address = new BD_ADDR;
- bdcpy(address, bd_addr->address);
- return do_in_jni_thread(Bind(&BTA_GATTC_Refresh, base::Owned(address)));
+ return do_in_jni_thread(Bind(&BTA_GATTC_Refresh, *bd_addr));
}
bt_status_t btif_gattc_search_service(int conn_id, bt_uuid_t* filter_uuid) {
@@ -402,7 +401,9 @@
CHECK(len <= BTGATT_MAX_ATTR_LEN);
if (len > 0) memcpy(params->value.value, value, len);
- CLI_CBACK_IN_JNI(read_characteristic_cb, conn_id, status,
+ // clang-tidy analyzer complains about |params| is leaked. It doesn't know
+ // that |param| will be freed by the callback function.
+ CLI_CBACK_IN_JNI(read_characteristic_cb, conn_id, status, /* NOLINT */
base::Owned(params));
}
@@ -423,7 +424,9 @@
CHECK(len <= BTGATT_MAX_ATTR_LEN);
if (len > 0) memcpy(params->value.value, value, len);
- CLI_CBACK_IN_JNI(read_characteristic_cb, conn_id, status,
+ // clang-tidy analyzer complains about |params| is leaked. It doesn't know
+ // that |param| will be freed by the callback function.
+ CLI_CBACK_IN_JNI(read_characteristic_cb, conn_id, status, /* NOLINT */
base::Owned(params));
}
@@ -448,7 +451,10 @@
CHECK(len <= BTGATT_MAX_ATTR_LEN);
if (len > 0) memcpy(params->value.value, value, len);
- CLI_CBACK_IN_JNI(read_descriptor_cb, conn_id, status, base::Owned(params));
+ // clang-tidy analyzer complains about |params| is leaked. It doesn't know
+ // that |param| will be freed by the callback function.
+ CLI_CBACK_IN_JNI(read_descriptor_cb, conn_id, status,
+ base::Owned(params)); /* NOLINT */
}
bt_status_t btif_gattc_read_char_descr(int conn_id, uint16_t handle,
diff --git a/btif/src/btif_hf.cc b/btif/src/btif_hf.cc
index a8b3181..765ad21 100644
--- a/btif/src/btif_hf.cc
+++ b/btif/src/btif_hf.cc
@@ -666,7 +666,7 @@
static bool inband_ringing_property_enabled() {
char inband_ringing_flag[PROPERTY_VALUE_MAX] = {0};
osi_property_get("persist.bluetooth.enableinbandringing", inband_ringing_flag,
- "false");
+ "true");
if (strncmp(inband_ringing_flag, "true", 4) == 0) {
BTIF_TRACE_DEBUG("%s: In-band ringing enabled by property", __func__);
return true;
@@ -1493,6 +1493,7 @@
static void cleanup(void) {
BTIF_TRACE_EVENT("%s", __func__);
+ btif_queue_cleanup(UUID_SERVCLASS_AG_HANDSFREE);
if (bt_hf_callbacks) {
#if (defined(BTIF_HF_SERVICES) && (BTIF_HF_SERVICES & BTA_HFP_SERVICE_MASK))
btif_disable_service(BTA_HFP_SERVICE_ID);
diff --git a/btif/src/btif_hf_client.cc b/btif/src/btif_hf_client.cc
index 3b86aaa..0de1c7e 100644
--- a/btif/src/btif_hf_client.cc
+++ b/btif/src/btif_hf_client.cc
@@ -708,6 +708,7 @@
static void cleanup(void) {
BTIF_TRACE_EVENT("%s", __func__);
+ btif_queue_cleanup(UUID_SERVCLASS_HF_HANDSFREE);
if (bt_hf_client_callbacks) {
btif_disable_service(BTA_HFP_HS_SERVICE_ID);
bt_hf_client_callbacks = NULL;
diff --git a/btif/src/btif_hh.cc b/btif/src/btif_hh.cc
index b60c8c8..eac9eeb 100644
--- a/btif/src/btif_hh.cc
+++ b/btif/src/btif_hh.cc
@@ -38,6 +38,7 @@
#include "bt_common.h"
#include "bta_api.h"
+#include "btcore/include/bdaddr.h"
#include "btif_common.h"
#include "btif_storage.h"
#include "btif_util.h"
@@ -901,7 +902,7 @@
break;
case BTA_HH_GET_PROTO_EVT:
- p_dev = btif_hh_find_connected_dev_by_handle(p_data->dev_status.handle);
+ p_dev = btif_hh_find_connected_dev_by_handle(p_data->hs_data.handle);
BTIF_TRACE_WARNING(
"BTA_HH_GET_PROTO_EVT: status = %d, handle = %d, proto = [%d], %s",
p_data->hs_data.status, p_data->hs_data.handle,
@@ -939,6 +940,10 @@
"BTA_HH_GET_IDLE_EVT: handle = %d, status = %d, rate = %d",
p_data->hs_data.handle, p_data->hs_data.status,
p_data->hs_data.rsp_data.idle_rate);
+ p_dev = btif_hh_find_connected_dev_by_handle(p_data->hs_data.handle);
+ HAL_CBACK(bt_hh_callbacks, idle_time_cb, (bt_bdaddr_t*)&(p_dev->bd_addr),
+ (bthh_status_t)p_data->hs_data.status,
+ p_data->hs_data.rsp_data.idle_rate);
break;
case BTA_HH_SET_IDLE_EVT:
@@ -1319,6 +1324,66 @@
}
/*******************************************************************************
+**
+** Function get_idle_time
+**
+** Description Get the HID idle time
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t get_idle_time(bt_bdaddr_t* bd_addr) {
+ CHECK_BTHH_INIT();
+
+ char bdstr[20] = {0};
+ BTIF_TRACE_DEBUG("%s: addr = %s", __func__,
+ bdaddr_to_string(bd_addr, bdstr, sizeof(bdstr)));
+
+ if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+ BTIF_TRACE_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+
+ btif_hh_device_t* p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if (p_dev == NULL) return BT_STATUS_FAIL;
+
+ BTA_HhGetIdle(p_dev->dev_handle);
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function set_idle_time
+**
+** Description Set the HID idle time
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t set_idle_time(bt_bdaddr_t* bd_addr, uint8_t idle_time) {
+ CHECK_BTHH_INIT();
+
+ char bdstr[20] = {0};
+ BTIF_TRACE_DEBUG("%s: addr = %s, idle time = %d", __func__,
+ bdaddr_to_string(bd_addr, bdstr, sizeof(bdstr)), idle_time);
+
+ if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+ BTIF_TRACE_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+
+ btif_hh_device_t* p_dev = p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if (p_dev == NULL) {
+ BTIF_TRACE_WARNING("%s: addr = %s not opened", __func__,
+ bdaddr_to_string(bd_addr, bdstr, sizeof(bdstr)));
+ return BT_STATUS_FAIL;
+ }
+
+ BTA_HhSetIdle(p_dev->dev_handle, idle_time);
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
*
* Function set_info
*
@@ -1655,11 +1720,20 @@
}
static const bthh_interface_t bthhInterface = {
- sizeof(bthhInterface), init, connect, disconnect, virtual_unplug, set_info,
- get_protocol, set_protocol,
- // get_idle_time,
- // set_idle_time,
- get_report, set_report, send_data, cleanup,
+ sizeof(bthhInterface),
+ init,
+ connect,
+ disconnect,
+ virtual_unplug,
+ set_info,
+ get_protocol,
+ set_protocol,
+ get_idle_time,
+ set_idle_time,
+ get_report,
+ set_report,
+ send_data,
+ cleanup,
};
/*******************************************************************************
diff --git a/btif/src/btif_profile_queue.cc b/btif/src/btif_profile_queue.cc
index 1346092..d5061d6 100644
--- a/btif/src/btif_profile_queue.cc
+++ b/btif/src/btif_profile_queue.cc
@@ -32,6 +32,7 @@
#include <string.h>
#include "bt_common.h"
+#include "btcore/include/bdaddr.h"
#include "btif_common.h"
#include "osi/include/allocator.h"
#include "osi/include/list.h"
@@ -44,6 +45,7 @@
typedef enum {
BTIF_QUEUE_CONNECT_EVT,
BTIF_QUEUE_ADVANCE_EVT,
+ BTIF_QUEUE_CLEANUP_EVT
} btif_queue_event_t;
typedef struct {
@@ -67,6 +69,7 @@
static void queue_int_add(connect_node_t* p_param) {
if (!connect_queue) {
+ LOG_INFO(LOG_TAG, "%s: allocating profile queue", __func__);
connect_queue = list_new(osi_free);
CHECK(connect_queue != NULL);
}
@@ -77,8 +80,14 @@
for (const list_node_t* node = list_begin(connect_queue);
node != list_end(connect_queue); node = list_next(node)) {
if (((connect_node_t*)list_node(node))->uuid == p_param->uuid) {
- LOG_INFO(LOG_TAG, "%s dropping duplicate connect request for uuid: %04x",
- __func__, p_param->uuid);
+ bdstr_t bd_addr_str;
+ LOG_ERROR(
+ LOG_TAG,
+ "%s dropping duplicate connection request UUID=%04X, "
+ "bd_addr=%s, busy=%d",
+ __func__, p_param->uuid,
+ bdaddr_to_string(&p_param->bda, bd_addr_str, sizeof(bd_addr_str)),
+ p_param->busy);
return;
}
}
@@ -93,6 +102,34 @@
list_remove(connect_queue, list_front(connect_queue));
}
+static void queue_int_cleanup(uint16_t* p_uuid) {
+ if (!p_uuid) {
+ LOG_ERROR(LOG_TAG, "%s: UUID is null", __func__);
+ return;
+ }
+ uint16_t uuid = *p_uuid;
+ LOG_INFO(LOG_TAG, "%s: UUID=%04X", __func__, uuid);
+ if (!connect_queue) {
+ return;
+ }
+ connect_node_t* connection_request;
+ const list_node_t* node = list_begin(connect_queue);
+ while (node && node != list_end(connect_queue)) {
+ connection_request = (connect_node_t*)list_node(node);
+ node = list_next(node);
+ if (connection_request->uuid == uuid) {
+ bdstr_t bd_addr_str;
+ LOG_INFO(LOG_TAG,
+ "%s: removing connection request UUID=%04X, bd_addr=%s, busy=%d",
+ __func__, connection_request->uuid,
+ bdaddr_to_string(&connection_request->bda, bd_addr_str,
+ sizeof(bd_addr_str)),
+ connection_request->busy);
+ list_remove(connect_queue, connection_request);
+ }
+ }
+}
+
static void queue_int_handle_evt(uint16_t event, char* p_param) {
switch (event) {
case BTIF_QUEUE_CONNECT_EVT:
@@ -102,6 +139,10 @@
case BTIF_QUEUE_ADVANCE_EVT:
queue_int_advance();
break;
+
+ case BTIF_QUEUE_CLEANUP_EVT:
+ queue_int_cleanup((uint16_t*)(p_param));
+ return;
}
if (stack_manager_get_interface()->get_stack_is_running())
@@ -132,6 +173,20 @@
/*******************************************************************************
*
+ * Function btif_queue_cleanup
+ *
+ * Description Clean up existing connection requests for a UUID
+ *
+ * Returns void, always succeed
+ *
+ ******************************************************************************/
+void btif_queue_cleanup(uint16_t uuid) {
+ btif_transfer_context(queue_int_handle_evt, BTIF_QUEUE_CLEANUP_EVT,
+ (char*)&uuid, sizeof(uint16_t), NULL);
+}
+
+/*******************************************************************************
+ *
* Function btif_queue_advance
*
* Description Clear the queue's busy status and advance to the next
@@ -152,6 +207,12 @@
connect_node_t* p_head = (connect_node_t*)list_front(connect_queue);
+ bdstr_t bd_addr_str;
+ LOG_INFO(LOG_TAG,
+ "%s: executing connection request UUID=%04X, bd_addr=%s, busy=%d",
+ __func__, p_head->uuid,
+ bdaddr_to_string(&p_head->bda, bd_addr_str, sizeof(bd_addr_str)),
+ p_head->busy);
// If the queue is currently busy, we return success anyway,
// since the connection has been queued...
if (p_head->busy) return BT_STATUS_SUCCESS;
@@ -170,6 +231,7 @@
*
******************************************************************************/
void btif_queue_release() {
+ LOG_INFO(LOG_TAG, "%s", __func__);
list_free(connect_queue);
connect_queue = NULL;
}
diff --git a/btif/src/btif_rc.cc b/btif/src/btif_rc.cc
index 2653658..f235b73 100644
--- a/btif/src/btif_rc.cc
+++ b/btif/src/btif_rc.cc
@@ -1889,32 +1889,6 @@
/***************************************************************************
*
- * Function reject_pending_notification
- *
- * Description Utility function to reject a pending notification. When
- * AddressedPlayer change is received, all pending
- * notifications should be completed.
- *
- * Returns void
- *
- **************************************************************************/
-static void reject_pending_notification(btrc_event_id_t event_id, int idx) {
- tAVRC_RESPONSE avrc_rsp;
- memset(&(avrc_rsp.reg_notif), 0, sizeof(tAVRC_REG_NOTIF_RSP));
-
- avrc_rsp.reg_notif.event_id = event_id;
- avrc_rsp.reg_notif.pdu = AVRC_PDU_REGISTER_NOTIFICATION;
- avrc_rsp.reg_notif.opcode = opcode_from_pdu(AVRC_PDU_REGISTER_NOTIFICATION);
- avrc_rsp.reg_notif.status = AVRC_STS_ADDR_PLAYER_CHG;
- BTIF_TRACE_WARNING("%s: Handling event ID: 0x%x", __func__, event_id);
-
- send_metamsg_rsp(&btif_rc_cb.rc_multi_cb[idx], -1,
- btif_rc_cb.rc_multi_cb[idx].rc_notif[event_id - 1].label,
- AVRC_RSP_REJ, &avrc_rsp);
-}
-
-/***************************************************************************
- *
* Function register_notification_rsp
*
* Description Response to the register notification request.
@@ -1997,22 +1971,6 @@
((type == BTRC_NOTIFICATION_TYPE_INTERIM) ? AVRC_CMD_NOTIF
: AVRC_RSP_CHANGED),
&avrc_rsp);
-
- /* if notification type is address player changed, then complete all player
- * specific
- * notifications with AV/C C-Type REJECTED with error code Addressed Player
- * Changed. */
- if (event_id == BTRC_EVT_ADDR_PLAYER_CHANGE &&
- type == BTRC_NOTIFICATION_TYPE_CHANGED) {
- /* array includes notifications to be completed on addressed player change
- */
- btrc_event_id_t evt_id[] = {
- BTRC_EVT_PLAY_STATUS_CHANGED, BTRC_EVT_TRACK_CHANGE,
- BTRC_EVT_PLAY_POS_CHANGED, BTRC_EVT_NOW_PLAYING_CONTENT_CHANGED};
- for (uint8_t id = 0; id < sizeof(evt_id) / sizeof((evt_id)[0]); id++) {
- reject_pending_notification(evt_id[id], idx);
- }
- }
}
return BT_STATUS_SUCCESS;
}
diff --git a/btif/src/btif_sock_sdp.cc b/btif/src/btif_sock_sdp.cc
index 21b2c0b..afbfab4 100644
--- a/btif/src/btif_sock_sdp.cc
+++ b/btif/src/btif_sock_sdp.cc
@@ -127,7 +127,7 @@
if (name[0] != '\0') {
stage = "service_name";
if (!SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
- (uint32_t)(strlen(name) + 1), (uint8_t*)name))
+ (uint32_t)strlen(name), (uint8_t*)name))
goto error;
}
diff --git a/btif/test/btif_profile_queue_test.cc b/btif/test/btif_profile_queue_test.cc
new file mode 100644
index 0000000..199844e
--- /dev/null
+++ b/btif/test/btif_profile_queue_test.cc
@@ -0,0 +1,203 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2017 Google, Inc.
+ *
+ * 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 <gtest/gtest.h>
+
+#include "btif/include/btif_profile_queue.h"
+#include "stack_manager.h"
+
+static bool sStackRunning;
+
+bool get_stack_is_running(void) { return sStackRunning; }
+
+static stack_manager_t sStackManager = {nullptr, nullptr, nullptr, nullptr,
+ get_stack_is_running};
+
+const stack_manager_t* stack_manager_get_interface() { return &sStackManager; }
+
+typedef void(tBTIF_CBACK)(uint16_t event, char* p_param);
+typedef void(tBTIF_COPY_CBACK)(uint16_t event, char* p_dest, char* p_src);
+bt_status_t btif_transfer_context(tBTIF_CBACK* p_cback, uint16_t event,
+ char* p_params, int param_len,
+ tBTIF_COPY_CBACK* p_copy_cback) {
+ p_cback(event, p_params);
+ return BT_STATUS_SUCCESS;
+}
+
+enum ResultType {
+ NOT_SET = 0,
+ UNKNOWN,
+ UUID1_ADDR1,
+ UUID1_ADDR2,
+ UUID2_ADDR1,
+ UUID2_ADDR2
+};
+
+static ResultType sResult;
+
+class BtifProfileQueueTest : public ::testing::Test {
+ public:
+ static const uint16_t kTestUuid1 = 0x9527;
+ static const uint16_t kTestUuid2 = 0x819F;
+ static const bt_bdaddr_t kTestAddr1;
+ static const bt_bdaddr_t kTestAddr2;
+
+ protected:
+ void SetUp() override {
+ sStackRunning = true;
+ sResult = NOT_SET;
+ };
+ void TearDown() override { btif_queue_release(); };
+};
+
+const bt_bdaddr_t BtifProfileQueueTest::kTestAddr1{
+ {0x11, 0x22, 0x33, 0x44, 0x55, 0x66}};
+const bt_bdaddr_t BtifProfileQueueTest::kTestAddr2{
+ {0xAB, 0xCD, 0xEF, 0x12, 0x34, 0x56}};
+
+static bt_status_t test_connect_cb(bt_bdaddr_t* bda, uint16_t uuid) {
+ sResult = UNKNOWN;
+ if (!memcmp(bda, &BtifProfileQueueTest::kTestAddr1, sizeof(bt_bdaddr_t))) {
+ if (uuid == BtifProfileQueueTest::kTestUuid1) {
+ sResult = UUID1_ADDR1;
+ } else if (uuid == BtifProfileQueueTest::kTestUuid2) {
+ sResult = UUID2_ADDR1;
+ }
+ } else if (!memcmp(bda, &BtifProfileQueueTest::kTestAddr2,
+ sizeof(bt_bdaddr_t))) {
+ if (uuid == BtifProfileQueueTest::kTestUuid1) {
+ sResult = UUID1_ADDR2;
+ } else if (uuid == BtifProfileQueueTest::kTestUuid2) {
+ sResult = UUID2_ADDR2;
+ }
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+TEST_F(BtifProfileQueueTest, test_connect) {
+ sResult = NOT_SET;
+ btif_queue_connect(kTestUuid1, &kTestAddr1, test_connect_cb);
+ EXPECT_EQ(sResult, UUID1_ADDR1);
+}
+
+TEST_F(BtifProfileQueueTest, test_connect_same_uuid_do_not_repeat) {
+ sResult = NOT_SET;
+ btif_queue_connect(kTestUuid1, &kTestAddr1, test_connect_cb);
+ EXPECT_EQ(sResult, UUID1_ADDR1);
+ // Second connection request on the same UUID do not repeat
+ sResult = NOT_SET;
+ btif_queue_connect(kTestUuid1, &kTestAddr1, test_connect_cb);
+ EXPECT_EQ(sResult, NOT_SET);
+ // Not even after we advance the queue
+ sResult = NOT_SET;
+ btif_queue_advance();
+ btif_queue_connect_next();
+ EXPECT_EQ(sResult, NOT_SET);
+}
+
+TEST_F(BtifProfileQueueTest, test_multiple_connects) {
+ // First item is executed
+ sResult = NOT_SET;
+ btif_queue_connect(kTestUuid1, &kTestAddr1, test_connect_cb);
+ EXPECT_EQ(sResult, UUID1_ADDR1);
+ // Second item with advance is executed
+ sResult = NOT_SET;
+ btif_queue_advance();
+ btif_queue_connect(kTestUuid2, &kTestAddr1, test_connect_cb);
+ EXPECT_EQ(sResult, UUID2_ADDR1);
+}
+
+TEST_F(BtifProfileQueueTest, test_multiple_connects_without_advance) {
+ // First item is executed
+ sResult = NOT_SET;
+ btif_queue_connect(kTestUuid1, &kTestAddr1, test_connect_cb);
+ EXPECT_EQ(sResult, UUID1_ADDR1);
+ // Second item without advance is not executed
+ sResult = NOT_SET;
+ btif_queue_connect(kTestUuid2, &kTestAddr1, test_connect_cb);
+ EXPECT_EQ(sResult, NOT_SET);
+ sResult = NOT_SET;
+ // Connect next doesn't work
+ btif_queue_connect_next();
+ EXPECT_EQ(sResult, NOT_SET);
+ // Advance moves queue to execute next item
+ sResult = NOT_SET;
+ btif_queue_advance();
+ EXPECT_EQ(sResult, UUID2_ADDR1);
+}
+
+TEST_F(BtifProfileQueueTest, test_cleanup_first_allow_second) {
+ // First item is executed
+ sResult = NOT_SET;
+ btif_queue_connect(kTestUuid1, &kTestAddr1, test_connect_cb);
+ EXPECT_EQ(sResult, UUID1_ADDR1);
+ // Second item without advance is not executed
+ sResult = NOT_SET;
+ btif_queue_connect(kTestUuid2, &kTestAddr1, test_connect_cb);
+ EXPECT_EQ(sResult, NOT_SET);
+ // Connect next doesn't work
+ sResult = NOT_SET;
+ btif_queue_connect_next();
+ EXPECT_EQ(sResult, NOT_SET);
+ // Cleanup UUID1 allows the next profile connection to be executed
+ sResult = NOT_SET;
+ btif_queue_cleanup(kTestUuid1);
+ btif_queue_connect_next();
+ EXPECT_EQ(sResult, UUID2_ADDR1);
+}
+
+TEST_F(BtifProfileQueueTest, test_cleanup_both) {
+ // First item is executed
+ sResult = NOT_SET;
+ btif_queue_connect(kTestUuid1, &kTestAddr1, test_connect_cb);
+ EXPECT_EQ(sResult, UUID1_ADDR1);
+ // Second item without advance is not executed
+ sResult = NOT_SET;
+ btif_queue_connect(kTestUuid2, &kTestAddr1, test_connect_cb);
+ EXPECT_EQ(sResult, NOT_SET);
+ // Connect next doesn't work
+ sResult = NOT_SET;
+ btif_queue_connect_next();
+ EXPECT_EQ(sResult, NOT_SET);
+ // Cleanup both leaves nothing to execute
+ sResult = NOT_SET;
+ btif_queue_cleanup(kTestUuid1);
+ btif_queue_cleanup(kTestUuid2);
+ btif_queue_connect_next();
+ EXPECT_EQ(sResult, NOT_SET);
+}
+
+TEST_F(BtifProfileQueueTest, test_cleanup_both_reverse_order) {
+ // First item is executed
+ sResult = NOT_SET;
+ btif_queue_connect(kTestUuid1, &kTestAddr1, test_connect_cb);
+ EXPECT_EQ(sResult, UUID1_ADDR1);
+ // Second item without advance is not executed
+ sResult = NOT_SET;
+ btif_queue_connect(kTestUuid2, &kTestAddr1, test_connect_cb);
+ EXPECT_EQ(sResult, NOT_SET);
+ // Connect next doesn't work
+ sResult = NOT_SET;
+ btif_queue_connect_next();
+ EXPECT_EQ(sResult, NOT_SET);
+ // Cleanup both in reverse order leaves nothing to execute
+ sResult = NOT_SET;
+ btif_queue_cleanup(kTestUuid2);
+ btif_queue_cleanup(kTestUuid1);
+ btif_queue_connect_next();
+ EXPECT_EQ(sResult, NOT_SET);
+}
diff --git a/build/secondary/third_party/libchrome/BUILD.gn b/build/secondary/third_party/libchrome/BUILD.gn
index fc58cb60..d0d94b2 100644
--- a/build/secondary/third_party/libchrome/BUILD.gn
+++ b/build/secondary/third_party/libchrome/BUILD.gn
@@ -201,6 +201,20 @@
"base/tracking_info.cc",
"base/values.cc",
"base/vlog.cc",
+
+ "dbus/bus.cc",
+ "dbus/dbus_statistics.cc",
+ "dbus/exported_object.cc",
+ "dbus/file_descriptor.cc",
+ "dbus/message.cc",
+ "dbus/object_manager.cc",
+ "dbus/object_path.cc",
+ "dbus/object_proxy.cc",
+ "dbus/property.cc",
+ "dbus/scoped_dbus_error.cc",
+ "dbus/string_util.cc",
+ "dbus/util.cc",
+ "dbus/values_util.cc"
]
defines = [
@@ -219,7 +233,13 @@
"//third_party/libevent",
"//third_party/libevent/include",
"//third_party/libchrome/base",
+ "//third_party/libchrome/dbus",
"//third_party/modp_b64",
+
+ # paths to dbus headers, can be obtained by "pkg-config --cflags dbus-1"
+ #TODO(jpawlowski) use pkg-config script like build/config/linux/pkg_config.gni
+ "/usr/include/dbus-1.0/",
+ "/usr/lib/x86_64-linux-gnu/dbus-1.0/include",
]
}
@@ -228,6 +248,11 @@
include_dirs = [
"//third_party/googletest/googletest/include",
"//third_party/libchrome",
+
+ # paths to dbus headers, can be obtained by "pkg-config --cflags dbus-1"
+ #TODO(jpawlowski) use pkg-config script like build/config/linux/pkg_config.gni
+ "/usr/include/dbus-1.0/",
+ "/usr/lib/x86_64-linux-gnu/dbus-1.0/include",
]
}
@@ -252,6 +277,7 @@
"-levent",
"-levent_core",
"-lpthread",
+ "-ldbus-1",
]
public_configs = [ ":libchrome_config" ]
diff --git a/conf/bt_stack.conf b/conf/bt_stack.conf
index 8641434..856cdc4 100644
--- a/conf/bt_stack.conf
+++ b/conf/bt_stack.conf
@@ -53,17 +53,17 @@
#PTS_SmpOptions=0xD,0x4,0xf,0xf,0x10
# SMP Certification Failure Cases
-# Fail case number range from 1 to 9 will set up remote device for test
-# case execution. Setting PTS_SmpFailureCase to 0 means normal operation.
+# Set any of the following SMP error values (from smp_api_types.h)
+# to induce pairing failues for various PTS SMP test cases.
+# Setting PTS_SmpFailureCase to 0 means normal operation.
# Failure modes:
-# 1 = SMP_CONFIRM_VALUE_ERR
-# 2 = SMP_PAIR_AUTH_FAIL
-# 3 = SMP_PAIR_FAIL_UNKNOWN
-# 4 = SMP_PAIR_NOT_SUPPORT
-# 5 = SMP_PASSKEY_ENTRY_FAIL
-# 6 = SMP_REPEATED_ATTEMPTS
-# 7 = PIN generation failure?
-# 8 = SMP_PASSKEY_ENTRY_FAIL
-# 9 = SMP_NUMERIC_COMPAR_FAIL;
+#
+# SMP_PASSKEY_ENTRY_FAIL = 1
+# SMP_PAIR_AUTH_FAIL = 3
+# SMP_CONFIRM_VALUE_ERR = 4
+# SMP_PAIR_NOT_SUPPORT = 5
+# SMP_PAIR_FAIL_UNKNOWN = 8
+# SMP_REPEATED_ATTEMPTS = 9
+# SMP_NUMERIC_COMPAR_FAIL = 12
#PTS_SmpFailureCase=0
diff --git a/device/Android.bp b/device/Android.bp
index c8cc772..e7dd2d0 100644
--- a/device/Android.bp
+++ b/device/Android.bp
@@ -27,6 +27,7 @@
// ========================================================
cc_test {
name: "net_test_device",
+ test_suites: ["device-tests"],
defaults: ["fluoride_defaults"],
include_dirs: ["system/bt"],
srcs: [
diff --git a/device/AndroidTest.xml b/device/AndroidTest.xml
new file mode 100644
index 0000000..45a7e51
--- /dev/null
+++ b/device/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ 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.
+-->
+<configuration description="Config for net_test_device">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="net_test_device->/data/local/tmp/net_test_device" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="net_test_device" />
+ </test>
+</configuration>
\ No newline at end of file
diff --git a/device/include/interop.h b/device/include/interop.h
index a3b252b..ec2067a 100644
--- a/device/include/interop.h
+++ b/device/include/interop.h
@@ -79,6 +79,17 @@
// Some A2DP Sink devices report SUCCESS to the AVDTP RECONFIGURE command,
// but fail to play the reconfigured audio stream.
INTEROP_DISABLE_AVDTP_RECONFIGURE,
+
+ // Create dynamic blacklist to disable role switch.
+ // Some car kits indicate that role switch is supported, but then reject
+ // role switch attempts. After rejecting several role switch attempts,
+ // such car kits will go into bad state.
+ INTEROP_DYNAMIC_ROLE_SWITCH,
+
+ // Disable role switch for headsets/car-kits.
+ // Some car kits allow role switch but when the Phone initiates role switch,
+ // the Remote device will go into bad state that will lead to LMP time out.
+ INTEROP_DISABLE_ROLE_SWITCH
} interop_feature_t;
// Check if a given |addr| matches a known interoperability workaround as
diff --git a/device/include/interop_database.h b/device/include/interop_database.h
index 36a8ae2..7f4f229 100644
--- a/device/include/interop_database.h
+++ b/device/include/interop_database.h
@@ -67,9 +67,19 @@
{{{0x44, 0x5e, 0xf3, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
{{{0xd4, 0x9c, 0x28, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+ // Bose QuiteComfort 35, SoundSport and similar (because of older firmware)
+ {{{0x04, 0x52, 0xc7, 0, 0, 0}}, 3, INTEROP_2MBPS_LINK_ONLY},
+
// JayBird Family
{{{0x00, 0x18, 0x91, 0, 0, 0}}, 3, INTEROP_2MBPS_LINK_ONLY},
+ // Sony MBH-10
+ {{{0x20, 0x15, 0x06, 0, 0, 0}}, 3, INTEROP_2MBPS_LINK_ONLY},
+
+ // Uconnect
+ {{{0x00, 0x54, 0xaf, 0, 0, 0}}, 3, INTEROP_2MBPS_LINK_ONLY},
+ {{{0x30, 0x14, 0x4a, 0, 0, 0}}, 3, INTEROP_2MBPS_LINK_ONLY},
+
// LG Tone HBS-730 - unacceptably loud volume
{{{0x00, 0x18, 0x6b, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
{{{0xb8, 0xad, 0x3e, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
@@ -106,11 +116,26 @@
// Unknown keyboard (carried over from auto_pair_devlist.conf)
{{{0x00, 0x0F, 0xF6, 0, 0, 0}}, 3, INTEROP_KEYBOARD_REQUIRES_FIXED_PIN},
- // Kinivo BTC-450 - volume is erratic when using Absolute Volume
- {{{0x00, 0x18, 0x91, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
-
// Kenwood KMM-BT518HD - no audio when A2DP codec sample rate is changed
{{{0x00, 0x1d, 0x86, 0, 0, 0}}, 3, INTEROP_DISABLE_AVDTP_RECONFIGURE},
+
+ // NAC FORD-2013 - Lincoln
+ {{{0x00, 0x26, 0xb4, 0, 0, 0}}, 3, INTEROP_DISABLE_ROLE_SWITCH},
+
+ // Toyota Prius - 2015
+ {{{0xfc, 0xc2, 0xde, 0, 0, 0}}, 3, INTEROP_DISABLE_ROLE_SWITCH},
+
+ // OBU II Bluetooth dongle
+ {{{0x00, 0x04, 0x3e, 0, 0, 0}}, 3, INTEROP_DISABLE_ROLE_SWITCH},
+
+ // Roman R9020
+ {{{0x00, 0x23, 0x01, 0, 0, 0}}, 3, INTEROP_DISABLE_ROLE_SWITCH},
+
+ // Jabra Storm
+ {{{0x1c, 0x48, 0xf9, 0, 0, 0}}, 3, INTEROP_DISABLE_ROLE_SWITCH},
+
+ // Jeep Uconnect
+ {{{0x00, 0x54, 0xaf, 0, 0, 0}}, 3, INTEROP_DISABLE_ROLE_SWITCH},
};
typedef struct {
diff --git a/device/src/interop.cc b/device/src/interop.cc
index c6b5062..8e36181 100644
--- a/device/src/interop.cc
+++ b/device/src/interop.cc
@@ -127,6 +127,8 @@
CASE_RETURN_STR(INTEROP_HID_PREF_CONN_SUP_TIMEOUT_3S)
CASE_RETURN_STR(INTEROP_GATTC_NO_SERVICE_CHANGED_IND)
CASE_RETURN_STR(INTEROP_DISABLE_AVDTP_RECONFIGURE)
+ CASE_RETURN_STR(INTEROP_DYNAMIC_ROLE_SWITCH)
+ CASE_RETURN_STR(INTEROP_DISABLE_ROLE_SWITCH)
}
return "UNKNOWN";
diff --git a/hci/Android.bp b/hci/Android.bp
index a2bf907..4edcfee 100644
--- a/hci/Android.bp
+++ b/hci/Android.bp
@@ -44,6 +44,7 @@
// ========================================================
cc_test {
name: "net_test_hci",
+ test_suites: ["device-tests"],
defaults: ["libbt-hci_defaults"],
local_include_dirs: [
"include",
diff --git a/hci/AndroidTest.xml b/hci/AndroidTest.xml
new file mode 100644
index 0000000..b7c1e64
--- /dev/null
+++ b/hci/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ 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.
+-->
+<configuration description="Config for net_test_hci">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="net_test_hci->/data/local/tmp/net_test_hci" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="net_test_hci" />
+ </test>
+</configuration>
\ No newline at end of file
diff --git a/hci/include/hci_layer.h b/hci/include/hci_layer.h
index e44c0ae..acb86de 100644
--- a/hci/include/hci_layer.h
+++ b/hci/include/hci_layer.h
@@ -18,11 +18,12 @@
#pragma once
+#include <base/bind.h>
+#include <base/tracked_objects.h>
#include <stdbool.h>
#include "bt_types.h"
#include "osi/include/allocator.h"
-#include "osi/include/data_dispatcher.h"
#include "osi/include/fixed_queue.h"
#include "osi/include/future.h"
#include "osi/include/osi.h"
@@ -67,12 +68,10 @@
void* context);
typedef struct hci_t {
- // Register with this data dispatcher to receive events flowing upward out of
- // the HCI layer
- data_dispatcher_t* event_dispatcher;
-
- // Set the queue to receive ACL data in
- void (*set_data_queue)(fixed_queue_t* queue);
+ // Set the callback that the HCI layer uses to send data upwards
+ void (*set_data_cb)(
+ base::Callback<void(const tracked_objects::Location&, BT_HDR*)>
+ send_data_cb);
// Send a command through the HCI layer
void (*transmit_command)(BT_HDR* command,
@@ -82,7 +81,7 @@
future_t* (*transmit_command_futured)(BT_HDR* command);
// Send some data downward through the HCI layer
- void (*transmit_downward)(data_dispatcher_type_t type, void* data);
+ void (*transmit_downward)(uint16_t type, void* data);
} hci_t;
const hci_t* hci_layer_get_interface();
@@ -92,4 +91,7 @@
const btsnoop_t* btsnoop_interface,
const packet_fragmenter_t* packet_fragmenter_interface);
+void post_to_hci_message_loop(const tracked_objects::Location& from_here,
+ BT_HDR* p_msg);
+
void hci_layer_cleanup_interface();
diff --git a/hci/src/hci_layer.cc b/hci/src/hci_layer.cc
index d13b671..563379f 100644
--- a/hci/src/hci_layer.cc
+++ b/hci/src/hci_layer.cc
@@ -108,7 +108,8 @@
static std::recursive_mutex commands_pending_response_mutex;
// The hand-off point for data going to a higher layer, set by the higher layer
-static fixed_queue_t* upwards_data_queue;
+static base::Callback<void(const tracked_objects::Location&, BT_HDR*)>
+ send_data_upwards;
static bool filter_incoming_event(BT_HDR* packet);
static waiting_command_t* get_waiting_command(command_opcode_t opcode);
@@ -139,12 +140,12 @@
FROM_HERE, base::Bind(&event_finish_startup, nullptr));
}
-void hci_event_received(BT_HDR* packet) {
+void hci_event_received(const tracked_objects::Location& from_here,
+ BT_HDR* packet) {
btsnoop->capture(packet, true);
if (!filter_incoming_event(packet)) {
- data_dispatcher_dispatch(interface.event_dispatcher, packet->data[0],
- packet);
+ send_data_upwards.Run(from_here, packet);
}
}
@@ -298,7 +299,11 @@
// Interface functions
-static void set_data_queue(fixed_queue_t* queue) { upwards_data_queue = queue; }
+static void set_data_cb(
+ base::Callback<void(const tracked_objects::Location&, BT_HDR*)>
+ send_data_cb) {
+ send_data_upwards = std::move(send_data_cb);
+}
static void transmit_command(BT_HDR* command,
command_complete_cb complete_callback,
@@ -338,7 +343,7 @@
return future;
}
-static void transmit_downward(data_dispatcher_type_t type, void* data) {
+static void transmit_downward(uint16_t type, void* data) {
if (type == MSG_STACK_TO_HC_HCI_CMD) {
// TODO(zachoverflow): eliminate this call
transmit_command((BT_HDR*)data, NULL, NULL, NULL);
@@ -436,8 +441,8 @@
// This is kind of a weird case, since we're dispatching a partially sent
// packet up to a higher layer.
// TODO(zachoverflow): rework upper layer so this isn't necessary.
- data_dispatcher_dispatch(interface.event_dispatcher,
- packet->event & MSG_EVT_MASK, packet);
+
+ send_data_upwards.Run(FROM_HERE, packet);
}
}
@@ -627,9 +632,9 @@
static void dispatch_reassembled(BT_HDR* packet) {
// Events should already have been dispatched before this point
CHECK((packet->event & MSG_EVT_MASK) != MSG_HC_TO_STACK_HCI_EVT);
- CHECK(upwards_data_queue != NULL);
+ CHECK(!send_data_upwards.is_null());
- fixed_queue_enqueue(upwards_data_queue, packet);
+ send_data_upwards.Run(FROM_HERE, packet);
}
// Misc internal functions
@@ -673,13 +678,8 @@
if (!interface_created) {
// It's probably ok for this to live forever. It's small and
// there's only one instance of the hci interface.
- interface.event_dispatcher = data_dispatcher_new("hci_layer");
- if (!interface.event_dispatcher) {
- LOG_ERROR(LOG_TAG, "%s could not create upward dispatcher.", __func__);
- return;
- }
- interface.set_data_queue = set_data_queue;
+ interface.set_data_cb = set_data_cb;
interface.transmit_command = transmit_command;
interface.transmit_command_futured = transmit_command_futured;
interface.transmit_downward = transmit_downward;
@@ -689,10 +689,9 @@
void hci_layer_cleanup_interface() {
if (interface_created) {
- data_dispatcher_free(interface.event_dispatcher);
- interface.event_dispatcher = NULL;
+ send_data_upwards.Reset();
- interface.set_data_queue = NULL;
+ interface.set_data_cb = NULL;
interface.transmit_command = NULL;
interface.transmit_command_futured = NULL;
interface.transmit_downward = NULL;
diff --git a/hci/src/hci_layer_android.cc b/hci/src/hci_layer_android.cc
index dff6bfa..ce4f42c 100644
--- a/hci/src/hci_layer_android.cc
+++ b/hci/src/hci_layer_android.cc
@@ -20,6 +20,7 @@
#include "hci_layer.h"
+#include <base/location.h>
#include <base/logging.h>
#include "buffer_allocator.h"
#include "osi/include/log.h"
@@ -44,7 +45,8 @@
using ::android::hardware::hidl_vec;
extern void initialization_complete();
-extern void hci_event_received(BT_HDR* packet);
+extern void hci_event_received(const tracked_objects::Location& from_here,
+ BT_HDR* packet);
extern void acl_event_received(BT_HDR* packet);
extern void sco_data_received(BT_HDR* packet);
@@ -78,7 +80,7 @@
Return<void> hciEventReceived(const hidl_vec<uint8_t>& event) {
BT_HDR* packet = WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_EVT, event);
- hci_event_received(packet);
+ hci_event_received(FROM_HERE, packet);
return Void();
}
diff --git a/hci/src/hci_layer_linux.cc b/hci/src/hci_layer_linux.cc
index 51d8429..aa37f78 100644
--- a/hci/src/hci_layer_linux.cc
+++ b/hci/src/hci_layer_linux.cc
@@ -18,6 +18,7 @@
*
**********************************************************************/
#include <base/bind.h>
+#include <base/location.h>
#include <base/logging.h>
#include <base/threading/thread.h>
#include <errno.h>
@@ -92,7 +93,8 @@
};
extern void initialization_complete();
-extern void hci_event_received(BT_HDR* packet);
+extern void hci_event_received(const tracked_objects::Location& from_here,
+ BT_HDR* packet);
extern void acl_event_received(BT_HDR* packet);
extern void sco_data_received(BT_HDR* packet);
@@ -129,7 +131,7 @@
switch (type) {
case HCI_PACKET_TYPE_COMMAND:
packet->event = MSG_HC_TO_STACK_HCI_EVT;
- hci_event_received(packet);
+ hci_event_received(FROM_HERE, packet);
break;
case HCI_PACKET_TYPE_ACL_DATA:
packet->event = MSG_HC_TO_STACK_HCI_ACL;
@@ -141,7 +143,7 @@
break;
case HCI_PACKET_TYPE_EVENT:
packet->event = MSG_HC_TO_STACK_HCI_EVT;
- hci_event_received(packet);
+ hci_event_received(FROM_HERE, packet);
break;
default:
LOG(FATAL) << "Unexpected event type: " << +type;
diff --git a/include/bt_target.h b/include/bt_target.h
index 05b5ff1..eadfc92 100644
--- a/include/bt_target.h
+++ b/include/bt_target.h
@@ -738,13 +738,6 @@
#define GATT_CONFORMANCE_TESTING FALSE
#endif
-/* number of background connection device allowence, ideally to be the same as
- * WL size
-*/
-#ifndef GATT_MAX_BG_CONN_DEV
-#define GATT_MAX_BG_CONN_DEV 32
-#endif
-
/******************************************************************************
*
* SMP
@@ -1206,11 +1199,6 @@
#define GAP_INCLUDED TRUE
#endif
-/* This is set to enable use of GAP L2CAP connections. */
-#ifndef GAP_CONN_INCLUDED
-#define GAP_CONN_INCLUDED TRUE
-#endif
-
/* The maximum number of simultaneous GAP L2CAP connections. */
#ifndef GAP_MAX_CONNECTIONS
#define GAP_MAX_CONNECTIONS 30
diff --git a/include/bt_trace.h b/include/bt_trace.h
index e89299a..900e41b 100644
--- a/include/bt_trace.h
+++ b/include/bt_trace.h
@@ -55,7 +55,6 @@
#define BTTRC_ID_STK_CTP 26
#define BTTRC_ID_STK_FTC 27
#define BTTRC_ID_STK_FTS 28
-#define BTTRC_ID_STK_GAP 29
#define BTTRC_ID_STK_HCRP 31
#define BTTRC_ID_STK_ICP 32
#define BTTRC_ID_STK_OPC 33
@@ -159,10 +158,6 @@
#define SDP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
#endif
-#ifndef GAP_INITIAL_TRACE_LEVEL
-#define GAP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
-#endif
-
#ifndef BNEP_INITIAL_TRACE_LEVEL
#define BNEP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
#endif
@@ -340,28 +335,6 @@
BT_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
}
-/* Generic Access Profile traces */
-#define GAP_TRACE_ERROR(...) \
- { \
- if (gap_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
- BT_TRACE(TRACE_LAYER_GAP, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
- }
-#define GAP_TRACE_EVENT(...) \
- { \
- if (gap_cb.trace_level >= BT_TRACE_LEVEL_EVENT) \
- BT_TRACE(TRACE_LAYER_GAP, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
- }
-#define GAP_TRACE_API(...) \
- { \
- if (gap_cb.trace_level >= BT_TRACE_LEVEL_API) \
- BT_TRACE(TRACE_LAYER_GAP, TRACE_TYPE_API, ##__VA_ARGS__); \
- }
-#define GAP_TRACE_WARNING(...) \
- { \
- if (gap_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \
- BT_TRACE(TRACE_LAYER_GAP, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
- }
-
/* define traces for HID Host */
#define HIDH_TRACE_ERROR(...) \
{ \
diff --git a/main/bte_logmsg.cc b/main/bte_logmsg.cc
index 42c2db8..80a5372 100644
--- a/main/bte_logmsg.cc
+++ b/main/bte_logmsg.cc
@@ -32,7 +32,6 @@
#include "bte.h"
#include "btm_api.h"
#include "btu.h"
-#include "gap_api.h"
#include "l2c_api.h"
#include "main_int.h"
#include "osi/include/config.h"
@@ -123,8 +122,6 @@
{BTTRC_ID_STK_HID, BTTRC_ID_STK_HID, HID_HostSetTraceLevel, "TRC_HID_HOST",
DEFAULT_CONF_TRACE_LEVEL},
#endif
- {BTTRC_ID_STK_GAP, BTTRC_ID_STK_GAP, GAP_SetTraceLevel, "TRC_GAP",
- DEFAULT_CONF_TRACE_LEVEL},
#if (PAN_INCLUDED == TRUE)
{BTTRC_ID_STK_PAN, BTTRC_ID_STK_PAN, PAN_SetTraceLevel, "TRC_PAN",
DEFAULT_CONF_TRACE_LEVEL},
diff --git a/main/bte_main.cc b/main/bte_main.cc
index 58e44fd..527d93e 100644
--- a/main/bte_main.cc
+++ b/main/bte_main.cc
@@ -27,6 +27,7 @@
#define LOG_TAG "bt_main"
#include <base/logging.h>
+#include <base/threading/thread.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
@@ -79,13 +80,35 @@
static const hci_t* hci;
/*******************************************************************************
+ * Externs
+ ******************************************************************************/
+extern void btu_hci_msg_process(BT_HDR* p_msg);
+
+/*******************************************************************************
* Static functions
******************************************************************************/
-/*******************************************************************************
- * Externs
- ******************************************************************************/
-fixed_queue_t* btu_hci_msg_queue;
+/******************************************************************************
+ *
+ * Function post_to_hci_message_loop
+ *
+ * Description Post an HCI event to the hci message queue
+ *
+ * Returns None
+ *
+ *****************************************************************************/
+void post_to_hci_message_loop(const tracked_objects::Location& from_here,
+ BT_HDR* p_msg) {
+ base::MessageLoop* hci_message_loop = get_message_loop();
+ if (!hci_message_loop || !hci_message_loop->task_runner().get()) {
+ LOG_ERROR(LOG_TAG, "%s: HCI message loop not running, accessed from %s",
+ __func__, from_here.ToString().c_str());
+ return;
+ }
+
+ hci_message_loop->task_runner()->PostTask(
+ from_here, base::Bind(&btu_hci_msg_process, p_msg));
+}
/******************************************************************************
*
@@ -105,14 +128,7 @@
return;
}
- btu_hci_msg_queue = fixed_queue_new(SIZE_MAX);
- if (btu_hci_msg_queue == NULL) {
- LOG_ERROR(LOG_TAG, "%s unable to allocate hci message queue.", __func__);
- return;
- }
-
- data_dispatcher_register_default(hci->event_dispatcher, btu_hci_msg_queue);
- hci->set_data_queue(btu_hci_msg_queue);
+ hci->set_data_cb(base::Bind(&post_to_hci_message_loop));
module_init(get_module(STACK_CONFIG_MODULE));
}
@@ -127,13 +143,6 @@
*
*****************************************************************************/
void bte_main_cleanup() {
- data_dispatcher_register_default(hci_layer_get_interface()->event_dispatcher,
- NULL);
- hci->set_data_queue(NULL);
- fixed_queue_free(btu_hci_msg_queue, NULL);
-
- btu_hci_msg_queue = NULL;
-
module_clean_up(get_module(STACK_CONFIG_MODULE));
module_clean_up(get_module(INTEROP_MODULE));
diff --git a/osi/Android.bp b/osi/Android.bp
index f11b6f7..b93593c 100644
--- a/osi/Android.bp
+++ b/osi/Android.bp
@@ -64,7 +64,6 @@
"src/buffer.cc",
"src/compat.cc",
"src/config.cc",
- "src/data_dispatcher.cc",
"src/fixed_queue.cc",
"src/future.cc",
"src/hash_map_utils.cc",
@@ -108,6 +107,7 @@
// ========================================================
cc_test {
name: "net_test_osi",
+ test_suites: ["device-tests"],
defaults: ["fluoride_osi_defaults"],
host_supported: true,
srcs: [
@@ -118,7 +118,6 @@
"test/allocator_test.cc",
"test/array_test.cc",
"test/config_test.cc",
- "test/data_dispatcher_test.cc",
"test/fixed_queue_test.cc",
"test/future_test.cc",
"test/hash_map_utils_test.cc",
diff --git a/osi/AndroidTest.xml b/osi/AndroidTest.xml
new file mode 100644
index 0000000..a64158c
--- /dev/null
+++ b/osi/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ 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.
+-->
+<configuration description="Config for net_test_osi">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="net_test_osi->/data/local/tmp/net_test_osi" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="net_test_osi" />
+ </test>
+</configuration>
\ No newline at end of file
diff --git a/osi/BUILD.gn b/osi/BUILD.gn
index 92a8a2a..daecda4 100644
--- a/osi/BUILD.gn
+++ b/osi/BUILD.gn
@@ -23,7 +23,6 @@
"src/buffer.cc",
"src/compat.cc",
"src/config.cc",
- "src/data_dispatcher.cc",
"src/fixed_queue.cc",
"src/future.cc",
"src/hash_map_utils.cc",
@@ -67,7 +66,6 @@
"test/allocator_test.cc",
"test/array_test.cc",
"test/config_test.cc",
- "test/data_dispatcher_test.cc",
"test/future_test.cc",
"test/hash_map_utils_test.cc",
"test/leaky_bonded_queue_test.cc",
diff --git a/osi/include/data_dispatcher.h b/osi/include/data_dispatcher.h
deleted file mode 100644
index 7c231f8..0000000
--- a/osi/include/data_dispatcher.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/******************************************************************************
- *
- * Copyright (C) 2014 Google, Inc.
- *
- * 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.
- *
- ******************************************************************************/
-
-#pragma once
-
-#include <stdbool.h>
-#include <stdint.h>
-
-#include "osi/include/fixed_queue.h"
-
-#define DISPATCHER_NAME_MAX 16
-
-typedef struct data_dispatcher_t data_dispatcher_t;
-typedef uintptr_t data_dispatcher_type_t;
-
-// Creates a new data dispatcher object, with the given name.
-// The returned object must be freed by calling |data_dispatcher_free|.
-// Returns NULL on failure. |name| may not be NULL.
-data_dispatcher_t* data_dispatcher_new(const char* name);
-
-// Frees a data dispatcher object created by |data_dispatcher_new|.
-// |data_dispatcher| may be NULL.
-void data_dispatcher_free(data_dispatcher_t* dispatcher);
-
-// Registers |type| and |queue| with the data dispatcher so that data
-// sent under |type| ends up in |queue|. If |type| is already registered,
-// it is replaced. If |queue| is NULL, the existing registration is
-// removed, if it exists. |dispatcher| may not be NULL.
-void data_dispatcher_register(data_dispatcher_t* dispatcher,
- data_dispatcher_type_t type,
- fixed_queue_t* queue);
-
-// Registers a default queue to send data to when there is not a specific
-// type/queue relationship registered. If a default queue is already registered,
-// it is replaced. If |queue| is NULL, the existing registration is
-// removed, if it exists. |dispatcher| may not be NULL.
-void data_dispatcher_register_default(data_dispatcher_t* dispatcher,
- fixed_queue_t* queue);
-
-// Dispatches |data| to the queue registered for |type|. If no such registration
-// exists, it is dispatched to the default queue if it exists.
-// Neither |dispatcher| nor |data| may be NULL.
-// Returns true if data dispatch was successful.
-bool data_dispatcher_dispatch(data_dispatcher_t* dispatcher,
- data_dispatcher_type_t type, void* data);
diff --git a/osi/src/data_dispatcher.cc b/osi/src/data_dispatcher.cc
deleted file mode 100644
index 385f395..0000000
--- a/osi/src/data_dispatcher.cc
+++ /dev/null
@@ -1,108 +0,0 @@
-/******************************************************************************
- *
- * Copyright (C) 2014 Google, Inc.
- *
- * 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.
- *
- ******************************************************************************/
-
-#define LOG_TAG "bt_osi_data_dispatcher"
-
-#include "osi/include/data_dispatcher.h"
-
-#include <base/logging.h>
-#include <unordered_map>
-
-#include "osi/include/allocator.h"
-#include "osi/include/log.h"
-#include "osi/include/osi.h"
-
-#define DEFAULT_TABLE_BUCKETS 10
-
-typedef std::unordered_map<data_dispatcher_type_t, fixed_queue_t*>
- DispatchTableMap;
-
-struct data_dispatcher_t {
- char* name;
- DispatchTableMap* dispatch_table;
- fixed_queue_t* default_queue; // We don't own this queue
-};
-
-data_dispatcher_t* data_dispatcher_new(const char* name) {
- CHECK(name != NULL);
-
- data_dispatcher_t* ret =
- (data_dispatcher_t*)osi_calloc(sizeof(data_dispatcher_t));
-
- ret->dispatch_table = new DispatchTableMap();
-
- ret->name = osi_strdup(name);
- if (!ret->name) {
- LOG_ERROR(LOG_TAG, "%s unable to duplicate provided name.", __func__);
- goto error;
- }
-
- return ret;
-
-error:;
- data_dispatcher_free(ret);
- return NULL;
-}
-
-void data_dispatcher_free(data_dispatcher_t* dispatcher) {
- if (!dispatcher) return;
-
- delete dispatcher->dispatch_table;
- osi_free(dispatcher->name);
- osi_free(dispatcher);
-}
-
-void data_dispatcher_register(data_dispatcher_t* dispatcher,
- data_dispatcher_type_t type,
- fixed_queue_t* queue) {
- CHECK(dispatcher != NULL);
-
- if (queue)
- (*dispatcher->dispatch_table)[type] = queue;
- else
- dispatcher->dispatch_table->erase(type);
-}
-
-void data_dispatcher_register_default(data_dispatcher_t* dispatcher,
- fixed_queue_t* queue) {
- CHECK(dispatcher != NULL);
-
- dispatcher->default_queue = queue;
-}
-
-bool data_dispatcher_dispatch(data_dispatcher_t* dispatcher,
- data_dispatcher_type_t type, void* data) {
- CHECK(dispatcher != NULL);
- CHECK(data != NULL);
-
- fixed_queue_t* queue;
- auto iter = dispatcher->dispatch_table->find(type);
- if (iter == dispatcher->dispatch_table->end())
- queue = dispatcher->default_queue;
- else
- queue = iter->second;
-
- if (queue)
- fixed_queue_enqueue(queue, data);
- else
- LOG_WARN(LOG_TAG,
- "%s has no handler for type (%zd) in data dispatcher named: %s",
- __func__, type, dispatcher->name);
-
- return queue != NULL;
-}
diff --git a/osi/test/data_dispatcher_test.cc b/osi/test/data_dispatcher_test.cc
deleted file mode 100644
index cc7d78d..0000000
--- a/osi/test/data_dispatcher_test.cc
+++ /dev/null
@@ -1,258 +0,0 @@
-#include <gtest/gtest.h>
-
-#include <climits>
-
-#include "AllocationTestHarness.h"
-
-#include "osi/include/data_dispatcher.h"
-
-#include "osi/include/fixed_queue.h"
-#include "osi/include/osi.h"
-
-#define DUMMY_TYPE_0 34
-#define DUMMY_TYPE_1 42
-#define TYPE_EDGE_CASE_ZERO 0
-#define TYPE_EDGE_CASE_MAX INT_MAX
-
-#define DUMMY_QUEUE_SIZE 10
-
-class DataDispatcherTest : public AllocationTestHarness {};
-
-static char dummy_data_0[42] = "please test your code";
-static char dummy_data_1[42] = "testing is good for your sanity";
-
-TEST_F(DataDispatcherTest, test_new_free_simple) {
- data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
- ASSERT_TRUE(dispatcher != NULL);
- data_dispatcher_free(dispatcher);
-}
-
-TEST_F(DataDispatcherTest, test_dispatch_single_to_nowhere) {
- data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
- EXPECT_FALSE(
- data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_0, dummy_data_0));
- data_dispatcher_free(dispatcher);
-}
-
-TEST_F(DataDispatcherTest, test_dispatch_single_to_single) {
- data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
-
- // Register a queue
- fixed_queue_t* dummy_queue = fixed_queue_new(DUMMY_QUEUE_SIZE);
- data_dispatcher_register(dispatcher, DUMMY_TYPE_0, dummy_queue);
- EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
-
- // Send data to the queue
- EXPECT_TRUE(data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_0, dummy_data_0));
-
- // Did we get it?
- EXPECT_FALSE(fixed_queue_is_empty(dummy_queue));
- EXPECT_STREQ(dummy_data_0, (char*)fixed_queue_try_dequeue(dummy_queue));
- EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
-
- fixed_queue_free(dummy_queue, NULL);
- data_dispatcher_free(dispatcher);
-}
-
-TEST_F(DataDispatcherTest, test_dispatch_single_to_multiple) {
- data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
-
- // Register two queues
- fixed_queue_t* dummy_queue0 = fixed_queue_new(DUMMY_QUEUE_SIZE);
- fixed_queue_t* dummy_queue1 = fixed_queue_new(DUMMY_QUEUE_SIZE);
- data_dispatcher_register(dispatcher, DUMMY_TYPE_0, dummy_queue0);
- data_dispatcher_register(dispatcher, DUMMY_TYPE_1, dummy_queue1);
- EXPECT_TRUE(fixed_queue_is_empty(dummy_queue0));
- EXPECT_TRUE(fixed_queue_is_empty(dummy_queue1));
-
- // Send data to one of them
- EXPECT_TRUE(data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_0, dummy_data_0));
-
- // Did we get it?
- EXPECT_FALSE(fixed_queue_is_empty(dummy_queue0));
- EXPECT_TRUE(fixed_queue_is_empty(dummy_queue1));
- EXPECT_STREQ(dummy_data_0, (char*)fixed_queue_try_dequeue(dummy_queue0));
- EXPECT_TRUE(fixed_queue_is_empty(dummy_queue0));
-
- fixed_queue_free(dummy_queue0, NULL);
- fixed_queue_free(dummy_queue1, NULL);
- data_dispatcher_free(dispatcher);
-}
-
-TEST_F(DataDispatcherTest, test_dispatch_single_to_default) {
- data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
-
- // Register two queues, a default and a typed one
- fixed_queue_t* dummy_queue = fixed_queue_new(DUMMY_QUEUE_SIZE);
- fixed_queue_t* default_queue = fixed_queue_new(DUMMY_QUEUE_SIZE);
- data_dispatcher_register(dispatcher, DUMMY_TYPE_0, dummy_queue);
- data_dispatcher_register_default(dispatcher, default_queue);
- EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
- EXPECT_TRUE(fixed_queue_is_empty(default_queue));
-
- // Send data to nowhere
- EXPECT_TRUE(data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_1, dummy_data_1));
-
- // Did we get it?
- EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
- EXPECT_FALSE(fixed_queue_is_empty(default_queue));
- EXPECT_STREQ(dummy_data_1, (char*)fixed_queue_try_dequeue(default_queue));
- EXPECT_TRUE(fixed_queue_is_empty(default_queue));
-
- fixed_queue_free(dummy_queue, NULL);
- fixed_queue_free(default_queue, NULL);
- data_dispatcher_free(dispatcher);
-}
-
-TEST_F(DataDispatcherTest, test_dispatch_multiple_to_single) {
- data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
-
- // Register a queue
- fixed_queue_t* dummy_queue = fixed_queue_new(DUMMY_QUEUE_SIZE);
- data_dispatcher_register(dispatcher, DUMMY_TYPE_0, dummy_queue);
- EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
-
- // Send data to the queue
- EXPECT_TRUE(data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_0, dummy_data_0));
- EXPECT_TRUE(data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_0, dummy_data_1));
-
- // Did we get it?
- EXPECT_FALSE(fixed_queue_is_empty(dummy_queue));
- EXPECT_STREQ(dummy_data_0, (char*)fixed_queue_try_dequeue(dummy_queue));
- EXPECT_FALSE(fixed_queue_is_empty(dummy_queue));
- EXPECT_STREQ(dummy_data_1, (char*)fixed_queue_try_dequeue(dummy_queue));
- EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
-
- fixed_queue_free(dummy_queue, NULL);
- data_dispatcher_free(dispatcher);
-}
-
-TEST_F(DataDispatcherTest, test_dispatch_multiple_to_multiple) {
- data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
-
- // Register two queues
- fixed_queue_t* dummy_queue0 = fixed_queue_new(DUMMY_QUEUE_SIZE);
- fixed_queue_t* dummy_queue1 = fixed_queue_new(DUMMY_QUEUE_SIZE);
- data_dispatcher_register(dispatcher, DUMMY_TYPE_0, dummy_queue0);
- data_dispatcher_register(dispatcher, DUMMY_TYPE_1, dummy_queue1);
- EXPECT_TRUE(fixed_queue_is_empty(dummy_queue0));
- EXPECT_TRUE(fixed_queue_is_empty(dummy_queue1));
-
- // Send data to both of them
- EXPECT_TRUE(data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_0, dummy_data_0));
- EXPECT_TRUE(data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_1, dummy_data_1));
-
- // Did we get it?
- EXPECT_FALSE(fixed_queue_is_empty(dummy_queue0));
- EXPECT_FALSE(fixed_queue_is_empty(dummy_queue1));
- EXPECT_STREQ(dummy_data_0, (char*)fixed_queue_try_dequeue(dummy_queue0));
- EXPECT_STREQ(dummy_data_1, (char*)fixed_queue_try_dequeue(dummy_queue1));
- EXPECT_TRUE(fixed_queue_is_empty(dummy_queue0));
- EXPECT_TRUE(fixed_queue_is_empty(dummy_queue1));
-
- fixed_queue_free(dummy_queue0, NULL);
- fixed_queue_free(dummy_queue1, NULL);
- data_dispatcher_free(dispatcher);
-}
-
-TEST_F(DataDispatcherTest, test_dispatch_single_to_single_reregistered) {
- data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
-
- // Register a queue, then reregister
- fixed_queue_t* dummy_queue = fixed_queue_new(DUMMY_QUEUE_SIZE);
- fixed_queue_t* dummy_queue_reregistered = fixed_queue_new(DUMMY_QUEUE_SIZE);
- data_dispatcher_register(dispatcher, DUMMY_TYPE_0, dummy_queue);
- data_dispatcher_register(dispatcher, DUMMY_TYPE_0, dummy_queue_reregistered);
- EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
- EXPECT_TRUE(fixed_queue_is_empty(dummy_queue_reregistered));
-
- // Send data to the queue
- EXPECT_TRUE(data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_0, dummy_data_0));
-
- // Did we get it?
- EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
- EXPECT_FALSE(fixed_queue_is_empty(dummy_queue_reregistered));
- EXPECT_STREQ(dummy_data_0,
- (char*)fixed_queue_try_dequeue(dummy_queue_reregistered));
- EXPECT_TRUE(fixed_queue_is_empty(dummy_queue_reregistered));
-
- fixed_queue_free(dummy_queue, NULL);
- fixed_queue_free(dummy_queue_reregistered, NULL);
- data_dispatcher_free(dispatcher);
-}
-
-TEST_F(DataDispatcherTest, test_dispatch_single_to_reregistered_null) {
- data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
-
- // Register a queue
- fixed_queue_t* dummy_queue = fixed_queue_new(DUMMY_QUEUE_SIZE);
- data_dispatcher_register(dispatcher, DUMMY_TYPE_0, dummy_queue);
- data_dispatcher_register(dispatcher, DUMMY_TYPE_0, NULL);
- EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
-
- EXPECT_FALSE(
- data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_0, dummy_data_0));
- EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
-
- fixed_queue_free(dummy_queue, NULL);
- data_dispatcher_free(dispatcher);
-}
-
-TEST_F(DataDispatcherTest, test_dispatch_single_to_default_reregistered_null) {
- data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
-
- // Register a queue
- fixed_queue_t* dummy_queue = fixed_queue_new(DUMMY_QUEUE_SIZE);
- data_dispatcher_register_default(dispatcher, dummy_queue);
- data_dispatcher_register_default(dispatcher, NULL);
- EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
-
- EXPECT_FALSE(
- data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_0, dummy_data_0));
- EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
-
- fixed_queue_free(dummy_queue, NULL);
- data_dispatcher_free(dispatcher);
-}
-
-TEST_F(DataDispatcherTest, test_dispatch_edge_zero) {
- data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
-
- // Register a queue
- fixed_queue_t* dummy_queue = fixed_queue_new(DUMMY_QUEUE_SIZE);
- data_dispatcher_register(dispatcher, TYPE_EDGE_CASE_ZERO, dummy_queue);
- EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
-
- // Send data to the queue
- EXPECT_TRUE(
- data_dispatcher_dispatch(dispatcher, TYPE_EDGE_CASE_ZERO, dummy_data_0));
-
- // Did we get it?
- EXPECT_FALSE(fixed_queue_is_empty(dummy_queue));
- EXPECT_STREQ(dummy_data_0, (char*)fixed_queue_try_dequeue(dummy_queue));
- EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
-
- fixed_queue_free(dummy_queue, NULL);
- data_dispatcher_free(dispatcher);
-}
-
-TEST_F(DataDispatcherTest, test_dispatch_edge_max) {
- data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
-
- // Register a queue
- fixed_queue_t* dummy_queue = fixed_queue_new(DUMMY_QUEUE_SIZE);
- data_dispatcher_register(dispatcher, TYPE_EDGE_CASE_MAX, dummy_queue);
- EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
-
- // Send data to the queue
- EXPECT_TRUE(
- data_dispatcher_dispatch(dispatcher, TYPE_EDGE_CASE_MAX, dummy_data_0));
-
- // Did we get it?
- EXPECT_FALSE(fixed_queue_is_empty(dummy_queue));
- EXPECT_STREQ(dummy_data_0, (char*)fixed_queue_try_dequeue(dummy_queue));
- EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
-
- fixed_queue_free(dummy_queue, NULL);
- data_dispatcher_free(dispatcher);
-}
diff --git a/service/Android.bp b/service/Android.bp
index 4c6d018..83761c9 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -137,6 +137,7 @@
// ========================================================
cc_test {
name: "bluetoothtbd_test",
+ test_suites: ["device-tests"],
defaults: ["fluoride_service_defaults"],
srcs: btserviceBaseTestSrc
+ btserviceDaemonSrc + [
diff --git a/service/AndroidTest.xml b/service/AndroidTest.xml
new file mode 100644
index 0000000..d16e371
--- /dev/null
+++ b/service/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ 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.
+-->
+<configuration description="Config for bluetoothtbd_test">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="bluetoothtbd_test->/data/local/tmp/bluetoothtbd_test" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="bluetoothtbd_test" />
+ </test>
+</configuration>
\ No newline at end of file
diff --git a/service/BUILD.gn b/service/BUILD.gn
index e156c72..ba49728 100644
--- a/service/BUILD.gn
+++ b/service/BUILD.gn
@@ -35,6 +35,8 @@
"gatt_server_old.cc",
"hal/bluetooth_gatt_interface.cc",
"hal/bluetooth_interface.cc",
+ "ipc/dbus/bluetooth_adapter.cc",
+ "ipc/dbus/ipc_handler_dbus.cc",
"hal/fake_bluetooth_gatt_interface.cc",
"hal/fake_bluetooth_interface.cc",
"ipc/ipc_handler.cc",
diff --git a/service/daemon.cc b/service/daemon.cc
index bc022d2..48d098c 100644
--- a/service/daemon.cc
+++ b/service/daemon.cc
@@ -86,10 +86,20 @@
LOG(ERROR) << "Failed to set up UNIX domain-socket IPCManager";
return false;
}
- } else if (!ipc_manager_->Start(ipc::IPCManager::TYPE_BINDER, nullptr)) {
+ return true;
+ }
+
+#if !defined(OS_GENERIC)
+ if (!ipc_manager_->Start(ipc::IPCManager::TYPE_BINDER, nullptr)) {
LOG(ERROR) << "Failed to set up Binder IPCManager";
return false;
}
+#else
+ if (!ipc_manager_->Start(ipc::IPCManager::TYPE_DBUS, nullptr)) {
+ LOG(ERROR) << "Failed to set up DBus IPCManager";
+ return false;
+ }
+#endif
return true;
}
diff --git a/service/hal/fake_bluetooth_gatt_interface.cc b/service/hal/fake_bluetooth_gatt_interface.cc
index 1250e85..dba1f57 100644
--- a/service/hal/fake_bluetooth_gatt_interface.cc
+++ b/service/hal/fake_bluetooth_gatt_interface.cc
@@ -41,7 +41,8 @@
}
bt_status_t FakeConnect(int client_if, const bt_bdaddr_t* bd_addr,
- bool is_direct, int transport, int phy) {
+ bool is_direct, int transport, bool opportunistic,
+ int phy) {
if (g_client_handler)
return g_client_handler->Connect(client_if, bd_addr, is_direct, transport);
diff --git a/service/ipc/dbus/bluetooth_adapter.cc b/service/ipc/dbus/bluetooth_adapter.cc
new file mode 100644
index 0000000..171fef0
--- /dev/null
+++ b/service/ipc/dbus/bluetooth_adapter.cc
@@ -0,0 +1,107 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// 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 "service/ipc/dbus/bluetooth_adapter.h"
+#include <base/files/file_util.h>
+#include <base/logging.h>
+#include "service/common/bluetooth/util/address_helper.h"
+#include "service/hal/bluetooth_interface.h"
+
+using ::dbus::Bus;
+using ::dbus::ExportedObject;
+using ::dbus::MethodCall;
+using ::dbus::MessageWriter;
+using ::dbus::Response;
+using ::dbus::ObjectPath;
+using ::dbus::ErrorResponse;
+
+namespace {
+
+const std::string kBluetoothAdapterInterface = "org.fluoride.BluetoothAdapter";
+const std::string kEnable = "Enable";
+const std::string kDisable = "Disable";
+const std::string kBluetoothAdapter = "org.fluoride.BluetoothAdapter";
+const std::string kBluetoothAdapterPath = "/org/fluoride/BluetoothAdapter";
+
+// TODO(jpawlowski): right now xml interface files are in service/ipc/dbus/
+// folder. Make a script to move them into /usr/share/dbus-1/interfaces
+const char kBindingsPath[] =
+ "/usr/share/dbus-1/interfaces/org.fluoride.BluetoothAdapter.xml";
+const char kDBusIntrospectMethod[] = "Introspect";
+
+} // namespace
+
+namespace ipc {
+namespace dbus {
+
+BluetoothAdapter::BluetoothAdapter(scoped_refptr<Bus> bus,
+ bluetooth::Adapter* adapter)
+ : adapter_(adapter) {
+ exported_object_ = bus->GetExportedObject(ObjectPath(kBluetoothAdapterPath));
+
+ CHECK(exported_object_->ExportMethodAndBlock(
+ kBluetoothAdapterInterface, kEnable,
+ base::Bind(&BluetoothAdapter::Enable, base::Unretained(this))));
+
+ CHECK(exported_object_->ExportMethodAndBlock(
+ kBluetoothAdapterInterface, kDisable,
+ base::Bind(&BluetoothAdapter::Disable, base::Unretained(this))));
+
+ CHECK(exported_object_->ExportMethodAndBlock(
+ DBUS_INTERFACE_INTROSPECTABLE, kDBusIntrospectMethod,
+ base::Bind(&BluetoothAdapter::Introspect, base::Unretained(this))));
+
+ CHECK(bus->RequestOwnershipAndBlock(kBluetoothAdapter, Bus::REQUIRE_PRIMARY))
+ << "Unable to take ownership of " << kBluetoothAdapter
+ << ". Make sure you have proper busconfig file "
+ "/etc/dbus-1/system.d/org.fluoride.conf";
+}
+
+void BluetoothAdapter::Enable(MethodCall* method_call,
+ ExportedObject::ResponseSender response_sender) {
+ VLOG(1) << __func__;
+ adapter_->Enable(false);
+ response_sender.Run(Response::FromMethodCall(method_call));
+}
+
+void BluetoothAdapter::Disable(MethodCall* method_call,
+ ExportedObject::ResponseSender response_sender) {
+ VLOG(1) << __func__;
+ adapter_->Disable();
+ response_sender.Run(Response::FromMethodCall(method_call));
+}
+
+void BluetoothAdapter::Introspect(
+ MethodCall* method_call, ExportedObject::ResponseSender response_sender) {
+ VLOG(1) << __func__;
+
+ std::string output;
+ if (!base::ReadFileToString(base::FilePath(kBindingsPath), &output)) {
+ PLOG(ERROR) << "Can't read XML bindings from disk:";
+ response_sender.Run(ErrorResponse::FromMethodCall(
+ method_call, "Can't read XML bindings from disk.", ""));
+ }
+ std::unique_ptr<Response> response(Response::FromMethodCall(method_call));
+ MessageWriter writer(response.get());
+ writer.AppendString(output);
+
+ response_sender.Run(std::move(response));
+}
+
+BluetoothAdapter::~BluetoothAdapter() {}
+
+} // namespace dbus
+} // namespace ipc
diff --git a/service/ipc/dbus/bluetooth_adapter.h b/service/ipc/dbus/bluetooth_adapter.h
new file mode 100644
index 0000000..1d8dd8f
--- /dev/null
+++ b/service/ipc/dbus/bluetooth_adapter.h
@@ -0,0 +1,56 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// 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.
+//
+
+#pragma once
+
+#include "service/adapter.h"
+
+#include <base/memory/ref_counted.h>
+#include <dbus/bus.h>
+#include <dbus/exported_object.h>
+#include <dbus/message.h>
+#include <dbus/object_path.h>
+#include <dbus/property.h>
+
+using ::dbus::Bus;
+using ::dbus::ExportedObject;
+using ::dbus::MethodCall;
+
+namespace ipc {
+namespace dbus {
+
+class BluetoothAdapter {
+ public:
+ explicit BluetoothAdapter(scoped_refptr<Bus> bus,
+ bluetooth::Adapter* adapter);
+ virtual ~BluetoothAdapter();
+
+ void Enable(MethodCall* method_call,
+ ExportedObject::ResponseSender response_sender);
+
+ void Disable(MethodCall* method_call,
+ ExportedObject::ResponseSender response_sender);
+
+ void Introspect(MethodCall* method_call,
+ ExportedObject::ResponseSender response_sender);
+
+ private:
+ ExportedObject* exported_object_;
+ bluetooth::Adapter* adapter_;
+};
+
+} // namespace dbus
+} // namespace ipc
diff --git a/service/ipc/dbus/ipc_handler_dbus.cc b/service/ipc/dbus/ipc_handler_dbus.cc
new file mode 100644
index 0000000..ff7ff43
--- /dev/null
+++ b/service/ipc/dbus/ipc_handler_dbus.cc
@@ -0,0 +1,67 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// 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 "service/ipc/dbus/ipc_handler_dbus.h"
+
+#include <base/bind.h>
+#include <base/threading/thread_task_runner_handle.h>
+#include <dbus/bus.h>
+#include "service/daemon.h"
+#include "service/ipc/dbus/bluetooth_adapter.h"
+
+using dbus::Bus;
+
+namespace ipc {
+
+IPCHandlerDBus::IPCHandlerDBus(bluetooth::Adapter* adapter,
+ IPCManager::Delegate* delegate)
+ : IPCHandler(adapter, delegate) {}
+
+IPCHandlerDBus::~IPCHandlerDBus() {}
+
+bool IPCHandlerDBus::Run() {
+ LOG(INFO) << __func__;
+
+ dbus_thread_ = new base::Thread("D-Bus Thread");
+ base::Thread::Options thread_options;
+ thread_options.message_loop_type = base::MessageLoop::TYPE_IO;
+ dbus_thread_->StartWithOptions(thread_options);
+
+ dbus_thread_->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&IPCHandlerDBus::InitDbus, base::Unretained(this)));
+
+ return true;
+}
+
+void IPCHandlerDBus::InitDbus() {
+ LOG(INFO) << __func__;
+
+ Bus::Options bus_options;
+ bus_options.bus_type = Bus::SYSTEM;
+ bus_options.connection_type = Bus::PRIVATE;
+ bus_options.dbus_task_runner = base::ThreadTaskRunnerHandle::Get();
+
+ scoped_refptr<Bus> bus_ = new Bus(bus_options);
+
+ ipc::dbus::BluetoothAdapter* bluetooth_adapter =
+ new ipc::dbus::BluetoothAdapter(bus_, adapter());
+
+ LOG(INFO) << __func__ << ": all services added";
+}
+
+void IPCHandlerDBus::Stop() { dbus_thread_->Stop(); }
+
+} // namespace ipc
diff --git a/service/ipc/dbus/ipc_handler_dbus.h b/service/ipc/dbus/ipc_handler_dbus.h
new file mode 100644
index 0000000..03f7720
--- /dev/null
+++ b/service/ipc/dbus/ipc_handler_dbus.h
@@ -0,0 +1,48 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// 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.
+//
+#pragma once
+
+#include <base/threading/thread.h>
+#include "service/ipc/ipc_handler.h"
+#include "service/ipc/ipc_manager.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+} // namespace base
+
+namespace ipc {
+
+// Implements a DBus based IPCHandler
+class IPCHandlerDBus : public IPCHandler {
+ public:
+ IPCHandlerDBus(bluetooth::Adapter* adapter, IPCManager::Delegate* delegate);
+ ~IPCHandlerDBus() override;
+
+ void InitDbus();
+
+ // IPCHandler overrides:
+ bool Run() override;
+ void Stop() override;
+
+ private:
+ base::Thread* dbus_thread_;
+
+ IPCHandlerDBus() = default;
+
+ DISALLOW_COPY_AND_ASSIGN(IPCHandlerDBus);
+};
+
+} // namespace ipc
diff --git a/service/ipc/dbus/org.fluoride.BluetoothAdapter.xml b/service/ipc/dbus/org.fluoride.BluetoothAdapter.xml
new file mode 100644
index 0000000..4a718e6
--- /dev/null
+++ b/service/ipc/dbus/org.fluoride.BluetoothAdapter.xml
@@ -0,0 +1,28 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node name="/org/chromium/SessionManager"
+ xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
+
+ <!--
+ org.fluoride.BluetoothAdapter:
+ @short_description: Bluetooth adapter manager.
+
+ Interface for user bluetooth adapter. Right now allows only to enable
+ and disable the adapter.
+ -->
+ <interface name="org.fluoride.BluetoothAdapter">
+ <!--
+ Enable:
+
+ Enable the bluetooth adapter.
+ -->
+ <method name="Enable"></method>
+
+ <!--
+ Disable:
+
+ Disable the bluetooth adapter.
+ -->
+ <method name="Disable"></method>
+ </interface>
+</node>
\ No newline at end of file
diff --git a/service/ipc/ipc_manager.cc b/service/ipc/ipc_manager.cc
index 74c53bc..71dc6c7 100644
--- a/service/ipc/ipc_manager.cc
+++ b/service/ipc/ipc_manager.cc
@@ -18,6 +18,8 @@
#if !defined(OS_GENERIC)
#include "service/ipc/binder/ipc_handler_binder.h"
+#else
+#include "service/ipc/dbus/ipc_handler_dbus.h"
#endif // !defined(OS_GENERIC)
#include "service/ipc/ipc_handler_linux.h"
@@ -32,6 +34,7 @@
// holding a reference to them. Instead, explicitly stop them here.
if (BinderStarted()) binder_handler_->Stop();
if (LinuxStarted()) linux_handler_->Stop();
+ if (DBusStarted()) dbus_handler_->Stop();
}
bool IPCManager::Start(Type type, Delegate* delegate) {
@@ -48,6 +51,7 @@
return false;
}
return true;
+
#if !defined(OS_GENERIC)
case TYPE_BINDER:
if (BinderStarted()) {
@@ -61,7 +65,21 @@
return false;
}
return true;
+#else
+ case TYPE_DBUS:
+ if (DBusStarted()) {
+ LOG(ERROR) << "IPCManagerDBus already started.";
+ return false;
+ }
+
+ dbus_handler_ = new IPCHandlerDBus(adapter_, delegate);
+ if (!dbus_handler_->Run()) {
+ dbus_handler_ = nullptr;
+ return false;
+ }
+ return true;
#endif // !defined(OS_GENERIC)
+
default:
LOG(ERROR) << "Unsupported IPC type given: " << type;
}
@@ -73,4 +91,6 @@
bool IPCManager::LinuxStarted() const { return linux_handler_.get(); }
+bool IPCManager::DBusStarted() const { return dbus_handler_.get(); }
+
} // namespace ipc
diff --git a/service/ipc/ipc_manager.h b/service/ipc/ipc_manager.h
index c0ade0e..bf0967c 100644
--- a/service/ipc/ipc_manager.h
+++ b/service/ipc/ipc_manager.h
@@ -37,8 +37,9 @@
public:
// Possible IPC types.
enum Type {
- TYPE_LINUX, // IPC based on a Linux sequential packet domain socket
- TYPE_BINDER // IPC based on the Binder
+ TYPE_LINUX, // IPC based on a Linux sequential packet domain socket
+ TYPE_BINDER, // IPC based on the Binder
+ TYPE_DBUS // IPC based on the DBus
};
// Interface for observing events from an IPC mechanism. These methods will be
@@ -81,6 +82,7 @@
// Returns true if an IPC type has been initialized.
bool BinderStarted() const;
bool LinuxStarted() const;
+ bool DBusStarted() const;
private:
IPCManager() = default;
@@ -89,6 +91,7 @@
// owned by us.
scoped_refptr<IPCHandler> binder_handler_;
scoped_refptr<IPCHandler> linux_handler_;
+ scoped_refptr<IPCHandler> dbus_handler_;
// The Bluetooth adapter instance. This is owned by Daemon so we keep a raw
// pointer to it.
diff --git a/service/low_energy_client.cc b/service/low_energy_client.cc
index 1e2d7f3..b8f5e98 100644
--- a/service/low_energy_client.cc
+++ b/service/low_energy_client.cc
@@ -59,7 +59,7 @@
bt_status_t status =
hal::BluetoothGattInterface::Get()->GetClientHALInterface()->connect(
- client_id_, &bda, is_direct, BT_TRANSPORT_LE, PHY_LE_1M_MASK);
+ client_id_, &bda, is_direct, BT_TRANSPORT_LE, false, PHY_LE_1M_MASK);
if (status != BT_STATUS_SUCCESS) {
LOG(ERROR) << "HAL call to connect failed";
return false;
diff --git a/stack/Android.bp b/stack/Android.bp
index 58c8fe9..f5ec040 100644
--- a/stack/Android.bp
+++ b/stack/Android.bp
@@ -99,10 +99,8 @@
"btu/btu_hcif.cc",
"btu/btu_init.cc",
"btu/btu_task.cc",
- "gap/gap_api.cc",
"gap/gap_ble.cc",
"gap/gap_conn.cc",
- "gap/gap_utils.cc",
"gatt/att_protocol.cc",
"gatt/gatt_api.cc",
"gatt/gatt_attr.cc",
@@ -197,6 +195,7 @@
srcs: ["test/stack_a2dp_test.cc"],
shared_libs: [
"liblog",
+ "libcutils",
],
static_libs: [
"libbt-stack",
@@ -289,3 +288,34 @@
"libgmock",
],
}
+
+// Bluetooth stack message loop tests for target
+// ========================================================
+cc_test {
+ name: "net_test_btu_message_loop",
+ defaults: ["fluoride_defaults"],
+ local_include_dirs: [
+ "include",
+ "btm",
+ ],
+ include_dirs: [
+ "system/bt/",
+ "system/bt/include",
+ "system/bt/btcore/include",
+ "system/bt/bta/include",
+ ],
+ srcs: [
+ "btu/btu_task.cc",
+ "test/stack_btu_test.cc",
+ ],
+ shared_libs: [
+ "liblog",
+ "libcutils",
+ "libprotobuf-cpp-lite",
+ ],
+ static_libs: [
+ "libgmock",
+ "libosi",
+ "libbt-protos",
+ ],
+}
diff --git a/stack/BUILD.gn b/stack/BUILD.gn
index 87535d4..0be4333 100644
--- a/stack/BUILD.gn
+++ b/stack/BUILD.gn
@@ -78,10 +78,8 @@
"btu/btu_hcif.cc",
"btu/btu_init.cc",
"btu/btu_task.cc",
- "gap/gap_api.cc",
"gap/gap_ble.cc",
"gap/gap_conn.cc",
- "gap/gap_utils.cc",
"gatt/att_protocol.cc",
"gatt/gatt_api.cc",
"gatt/gatt_attr.cc",
diff --git a/stack/a2dp/a2dp_aac.cc b/stack/a2dp/a2dp_aac.cc
index 8c0927d..7027df7 100644
--- a/stack/a2dp/a2dp_aac.cc
+++ b/stack/a2dp/a2dp_aac.cc
@@ -369,22 +369,6 @@
return -1;
}
-int A2DP_GetTrackBitsPerSampleAac(const uint8_t* p_codec_info) {
- tA2DP_AAC_CIE aac_cie;
-
- // Check whether the codec info contains valid data
- tA2DP_STATUS a2dp_status = A2DP_ParseInfoAac(&aac_cie, p_codec_info, false);
- if (a2dp_status != A2DP_SUCCESS) {
- LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
- a2dp_status);
- return -1;
- }
-
- // NOTE: Hard-coded value - currently the AAC encoder library
- // is compiled with 16 bits per sample
- return 16;
-}
-
int A2DP_GetTrackChannelCountAac(const uint8_t* p_codec_info) {
tA2DP_AAC_CIE aac_cie;
@@ -545,7 +529,7 @@
return true;
}
-void A2DP_DumpCodecInfoAac(const uint8_t* p_codec_info) {
+bool A2DP_DumpCodecInfoAac(const uint8_t* p_codec_info) {
tA2DP_STATUS a2dp_status;
tA2DP_AAC_CIE aac_cie;
@@ -554,7 +538,7 @@
a2dp_status = A2DP_ParseInfoAac(&aac_cie, p_codec_info, true);
if (a2dp_status != A2DP_SUCCESS) {
LOG_ERROR(LOG_TAG, "%s: A2DP_ParseInfoAac fail:%d", __func__, a2dp_status);
- return;
+ return false;
}
LOG_DEBUG(LOG_TAG, "\tobjectType: 0x%x", aac_cie.objectType);
@@ -621,6 +605,8 @@
(aac_cie.variableBitRateSupport != 0) ? "true" : "false");
LOG_DEBUG(LOG_TAG, "\tbitRate: %u", aac_cie.bitRate);
+
+ return true;
}
const tA2DP_ENCODER_INTERFACE* A2DP_GetEncoderInterfaceAac(
diff --git a/stack/a2dp/a2dp_aac_encoder.cc b/stack/a2dp/a2dp_aac_encoder.cc
index 9c69588..6c79149 100644
--- a/stack/a2dp/a2dp_aac_encoder.cc
+++ b/stack/a2dp/a2dp_aac_encoder.cc
@@ -37,6 +37,12 @@
// A2DP AAC encoder interval in milliseconds
#define A2DP_AAC_ENCODER_INTERVAL_MS 20
+/*
+ * 2DH5 payload size of:
+ * 679 bytes - (4 bytes L2CAP Header + 12 bytes AVDTP Header)
+ */
+#define MAX_2MBPS_AVDTP_MTU 663
+
// offset
#if (BTA_AV_CO_CP_SCMS_T == TRUE)
#define A2DP_AAC_OFFSET (AVDT_MEDIA_OFFSET + 1)
@@ -222,6 +228,22 @@
a2dp_aac_encoder_cb.feeding_params.sample_rate;
p_encoder_params->channel_mode = A2DP_GetChannelModeCodeAac(p_codec_info);
+ LOG_VERBOSE(LOG_TAG, "%s: original AVDTP MTU size: %d", __func__,
+ a2dp_aac_encoder_cb.TxAaMtuSize);
+ if (a2dp_aac_encoder_cb.is_peer_edr &&
+ !a2dp_aac_encoder_cb.peer_supports_3mbps) {
+ // This condition would be satisfied only if the remote device is
+ // EDR and supports only 2 Mbps, but the effective AVDTP MTU size
+ // exceeds the 2DH5 packet size.
+ LOG_VERBOSE(LOG_TAG,
+ "%s: The remote device is EDR but does not support 3 Mbps",
+ __func__);
+ if (peer_mtu > MAX_2MBPS_AVDTP_MTU) {
+ LOG_WARN(LOG_TAG, "%s: Restricting AVDTP MTU size from %d to %d",
+ __func__, peer_mtu, MAX_2MBPS_AVDTP_MTU);
+ peer_mtu = MAX_2MBPS_AVDTP_MTU;
+ }
+ }
uint16_t mtu_size = BT_DEFAULT_BUFFER_SIZE - A2DP_AAC_OFFSET - sizeof(BT_HDR);
if (mtu_size < peer_mtu) {
a2dp_aac_encoder_cb.TxAaMtuSize = mtu_size;
diff --git a/stack/a2dp/a2dp_api.cc b/stack/a2dp/a2dp_api.cc
index a52924a..11d3bf2 100644
--- a/stack/a2dp/a2dp_api.cc
+++ b/stack/a2dp/a2dp_api.cc
@@ -377,3 +377,5 @@
a2dp_cb.trace_level = BT_TRACE_LEVEL_NONE;
#endif
}
+
+uint16_t A2DP_GetAvdtpVersion() { return a2dp_cb.avdt_sdp_ver; }
diff --git a/stack/a2dp/a2dp_codec_config.cc b/stack/a2dp/a2dp_codec_config.cc
index e5f06d6..0bf5985 100644
--- a/stack/a2dp/a2dp_codec_config.cc
+++ b/stack/a2dp/a2dp_codec_config.cc
@@ -1053,26 +1053,6 @@
return -1;
}
-int A2DP_GetTrackBitsPerSample(const uint8_t* p_codec_info) {
- tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
-
- LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
-
- switch (codec_type) {
- case A2DP_MEDIA_CT_SBC:
- return A2DP_GetTrackBitsPerSampleSbc(p_codec_info);
- case A2DP_MEDIA_CT_AAC:
- return A2DP_GetTrackBitsPerSampleAac(p_codec_info);
- case A2DP_MEDIA_CT_NON_A2DP:
- return A2DP_VendorGetTrackBitsPerSample(p_codec_info);
- default:
- break;
- }
-
- LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
- return -1;
-}
-
int A2DP_GetTrackChannelCount(const uint8_t* p_codec_info) {
tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
@@ -1278,3 +1258,23 @@
return false;
}
+
+bool A2DP_DumpCodecInfo(const uint8_t* p_codec_info) {
+ tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+ LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+ switch (codec_type) {
+ case A2DP_MEDIA_CT_SBC:
+ return A2DP_DumpCodecInfoSbc(p_codec_info);
+ case A2DP_MEDIA_CT_AAC:
+ return A2DP_DumpCodecInfoAac(p_codec_info);
+ case A2DP_MEDIA_CT_NON_A2DP:
+ return A2DP_VendorDumpCodecInfo(p_codec_info);
+ default:
+ break;
+ }
+
+ LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+ return false;
+}
diff --git a/stack/a2dp/a2dp_sbc.cc b/stack/a2dp/a2dp_sbc.cc
index f3918dd..ce3934a 100644
--- a/stack/a2dp/a2dp_sbc.cc
+++ b/stack/a2dp/a2dp_sbc.cc
@@ -54,9 +54,10 @@
/* SBC SRC codec capabilities */
static const tA2DP_SBC_CIE a2dp_sbc_caps = {
- A2DP_SBC_IE_SAMP_FREQ_44, /* samp_freq */
- A2DP_SBC_IE_CH_MD_JOINT, /* ch_mode */
- A2DP_SBC_IE_BLOCKS_16, /* block_len */
+ A2DP_SBC_IE_SAMP_FREQ_44, /* samp_freq */
+ (A2DP_SBC_IE_CH_MD_MONO | A2DP_SBC_IE_CH_MD_JOINT), /* ch_mode */
+ (A2DP_SBC_IE_BLOCKS_16 | A2DP_SBC_IE_BLOCKS_12 | A2DP_SBC_IE_BLOCKS_8 |
+ A2DP_SBC_IE_BLOCKS_4), /* block_len */
A2DP_SBC_IE_SUBBAND_8, /* num_subbands */
A2DP_SBC_IE_ALLOC_MD_L, /* alloc_method */
A2DP_SBC_IE_MIN_BITPOOL, /* min_bitpool */
@@ -519,19 +520,6 @@
return -1;
}
-int A2DP_GetTrackBitsPerSampleSbc(const uint8_t* p_codec_info) {
- tA2DP_SBC_CIE sbc_cie;
-
- tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, false);
- if (a2dp_status != A2DP_SUCCESS) {
- LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
- a2dp_status);
- return -1;
- }
-
- return 16; // For SBC we always use 16 bits per audio sample
-}
-
int A2DP_GetTrackChannelCountSbc(const uint8_t* p_codec_info) {
tA2DP_SBC_CIE sbc_cie;
@@ -879,7 +867,7 @@
return true;
}
-void A2DP_DumpCodecInfoSbc(const uint8_t* p_codec_info) {
+bool A2DP_DumpCodecInfoSbc(const uint8_t* p_codec_info) {
tA2DP_STATUS a2dp_status;
tA2DP_SBC_CIE sbc_cie;
@@ -888,7 +876,7 @@
a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, true);
if (a2dp_status != A2DP_SUCCESS) {
LOG_ERROR(LOG_TAG, "%s: A2DP_ParseInfoSbc fail:%d", __func__, a2dp_status);
- return;
+ return false;
}
LOG_DEBUG(LOG_TAG, "\tsamp_freq: 0x%x", sbc_cie.samp_freq);
@@ -951,6 +939,8 @@
LOG_DEBUG(LOG_TAG, "\tBit pool Min:%d Max:%d", sbc_cie.min_bitpool,
sbc_cie.max_bitpool);
+
+ return true;
}
const tA2DP_ENCODER_INTERFACE* A2DP_GetEncoderInterfaceSbc(
diff --git a/stack/a2dp/a2dp_sbc_encoder.cc b/stack/a2dp/a2dp_sbc_encoder.cc
index 939a68a..e4c2049 100644
--- a/stack/a2dp/a2dp_sbc_encoder.cc
+++ b/stack/a2dp/a2dp_sbc_encoder.cc
@@ -217,7 +217,7 @@
tA2DP_FEEDING_PARAMS* p_feeding_params = &a2dp_sbc_encoder_cb.feeding_params;
p_feeding_params->sample_rate = A2DP_GetTrackSampleRateSbc(p_codec_info);
p_feeding_params->bits_per_sample =
- A2DP_GetTrackBitsPerSampleSbc(p_codec_info);
+ a2dp_codec_config->getAudioBitsPerSample();
p_feeding_params->channel_count = A2DP_GetTrackChannelCountSbc(p_codec_info);
LOG_DEBUG(LOG_TAG, "%s: sample_rate=%u bits_per_sample=%u channel_count=%u",
__func__, p_feeding_params->sample_rate,
@@ -753,14 +753,21 @@
LOG_VERBOSE(LOG_TAG, "%s: original AVDTP MTU size: %d", __func__,
a2dp_sbc_encoder_cb.TxAaMtuSize);
+ if (a2dp_sbc_encoder_cb.is_peer_edr &&
+ !a2dp_sbc_encoder_cb.peer_supports_3mbps) {
+ // This condition would be satisfied only if the remote device is
+ // EDR and supports only 2 Mbps, but the effective AVDTP MTU size
+ // exceeds the 2DH5 packet size.
+ LOG_VERBOSE(LOG_TAG,
+ "%s: The remote device is EDR but does not support 3 Mbps",
+ __func__);
- // Restrict the MTU - even though some Sink devices are advertising large
- // MTU, they are not able to handle the packets and are stuttering.
- if (effective_mtu_size > MAX_2MBPS_AVDTP_MTU) {
- LOG_WARN(LOG_TAG, "%s: Restricting AVDTP MTU size to %d", __func__,
- MAX_2MBPS_AVDTP_MTU);
- effective_mtu_size = MAX_2MBPS_AVDTP_MTU;
- a2dp_sbc_encoder_cb.TxAaMtuSize = effective_mtu_size;
+ if (effective_mtu_size > MAX_2MBPS_AVDTP_MTU) {
+ LOG_WARN(LOG_TAG, "%s: Restricting AVDTP MTU size to %d", __func__,
+ MAX_2MBPS_AVDTP_MTU);
+ effective_mtu_size = MAX_2MBPS_AVDTP_MTU;
+ a2dp_sbc_encoder_cb.TxAaMtuSize = effective_mtu_size;
+ }
}
if (!p_encoder_params->s16NumOfSubBands) {
diff --git a/stack/a2dp/a2dp_vendor.cc b/stack/a2dp/a2dp_vendor.cc
index e1d88b1..f0fc277 100644
--- a/stack/a2dp/a2dp_vendor.cc
+++ b/stack/a2dp/a2dp_vendor.cc
@@ -313,32 +313,6 @@
return -1;
}
-int A2DP_VendorGetTrackBitsPerSample(const uint8_t* p_codec_info) {
- uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
- uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
-
- // Check for aptX
- if (vendor_id == A2DP_APTX_VENDOR_ID &&
- codec_id == A2DP_APTX_CODEC_ID_BLUETOOTH) {
- return A2DP_VendorGetTrackBitsPerSampleAptx(p_codec_info);
- }
-
- // Check for aptX-HD
- if (vendor_id == A2DP_APTX_HD_VENDOR_ID &&
- codec_id == A2DP_APTX_HD_CODEC_ID_BLUETOOTH) {
- return A2DP_VendorGetTrackBitsPerSampleAptxHd(p_codec_info);
- }
-
- // Check for LDAC
- if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
- return A2DP_VendorGetTrackBitsPerSampleLdac(p_codec_info);
- }
-
- // Add checks based on <vendor_id, codec_id>
-
- return -1;
-}
-
int A2DP_VendorGetTrackChannelCount(const uint8_t* p_codec_info) {
uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
@@ -569,3 +543,29 @@
return false;
}
+
+bool A2DP_VendorDumpCodecInfo(const uint8_t* p_codec_info) {
+ uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+ uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+ // Check for aptX
+ if (vendor_id == A2DP_APTX_VENDOR_ID &&
+ codec_id == A2DP_APTX_CODEC_ID_BLUETOOTH) {
+ return A2DP_VendorDumpCodecInfoAptx(p_codec_info);
+ }
+
+ // Check for aptX-HD
+ if (vendor_id == A2DP_APTX_HD_VENDOR_ID &&
+ codec_id == A2DP_APTX_HD_CODEC_ID_BLUETOOTH) {
+ return A2DP_VendorDumpCodecInfoAptxHd(p_codec_info);
+ }
+
+ // Check for LDAC
+ if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+ return A2DP_VendorDumpCodecInfoLdac(p_codec_info);
+ }
+
+ // Add checks based on <vendor_id, codec_id>
+
+ return false;
+}
diff --git a/stack/a2dp/a2dp_vendor_aptx.cc b/stack/a2dp/a2dp_vendor_aptx.cc
index 10e15bc..9d4d0e1 100644
--- a/stack/a2dp/a2dp_vendor_aptx.cc
+++ b/stack/a2dp/a2dp_vendor_aptx.cc
@@ -296,20 +296,6 @@
return -1;
}
-int A2DP_VendorGetTrackBitsPerSampleAptx(const uint8_t* p_codec_info) {
- tA2DP_APTX_CIE aptx_cie;
-
- // Check whether the codec info contains valid data
- tA2DP_STATUS a2dp_status = A2DP_ParseInfoAptx(&aptx_cie, p_codec_info, false);
- if (a2dp_status != A2DP_SUCCESS) {
- LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
- a2dp_status);
- return -1;
- }
-
- return 16; // For aptX we always use 16 bits per audio sample
-}
-
int A2DP_VendorGetTrackChannelCountAptx(const uint8_t* p_codec_info) {
tA2DP_APTX_CIE aptx_cie;
@@ -346,7 +332,7 @@
return true;
}
-void A2DP_VendorDumpCodecInfoAptx(const uint8_t* p_codec_info) {
+bool A2DP_VendorDumpCodecInfoAptx(const uint8_t* p_codec_info) {
tA2DP_STATUS a2dp_status;
tA2DP_APTX_CIE aptx_cie;
@@ -355,7 +341,7 @@
a2dp_status = A2DP_ParseInfoAptx(&aptx_cie, p_codec_info, true);
if (a2dp_status != A2DP_SUCCESS) {
LOG_ERROR(LOG_TAG, "%s: A2DP_ParseInfoAptx fail:%d", __func__, a2dp_status);
- return;
+ return false;
}
LOG_DEBUG(LOG_TAG, "\tsamp_freq: 0x%x", aptx_cie.sampleRate);
@@ -373,6 +359,8 @@
if (aptx_cie.channelMode & A2DP_APTX_CHANNELS_STEREO) {
LOG_DEBUG(LOG_TAG, "\tch_mode: (Stereo)");
}
+
+ return true;
}
const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterfaceAptx(
diff --git a/stack/a2dp/a2dp_vendor_aptx_encoder.cc b/stack/a2dp/a2dp_vendor_aptx_encoder.cc
index 4c8554d..3fcb6de 100644
--- a/stack/a2dp/a2dp_vendor_aptx_encoder.cc
+++ b/stack/a2dp/a2dp_vendor_aptx_encoder.cc
@@ -257,7 +257,7 @@
p_feeding_params->sample_rate =
A2DP_VendorGetTrackSampleRateAptx(p_codec_info);
p_feeding_params->bits_per_sample =
- A2DP_VendorGetTrackBitsPerSampleAptx(p_codec_info);
+ a2dp_codec_config->getAudioBitsPerSample();
p_feeding_params->channel_count =
A2DP_VendorGetTrackChannelCountAptx(p_codec_info);
LOG_DEBUG(LOG_TAG, "%s: sample_rate=%u bits_per_sample=%u channel_count=%u",
diff --git a/stack/a2dp/a2dp_vendor_aptx_hd.cc b/stack/a2dp/a2dp_vendor_aptx_hd.cc
index 919aef1..9002729 100644
--- a/stack/a2dp/a2dp_vendor_aptx_hd.cc
+++ b/stack/a2dp/a2dp_vendor_aptx_hd.cc
@@ -311,21 +311,6 @@
return -1;
}
-int A2DP_VendorGetTrackBitsPerSampleAptxHd(const uint8_t* p_codec_info) {
- tA2DP_APTX_HD_CIE aptx_hd_cie;
-
- // Check whether the codec info contains valid data
- tA2DP_STATUS a2dp_status =
- A2DP_ParseInfoAptxHd(&aptx_hd_cie, p_codec_info, false);
- if (a2dp_status != A2DP_SUCCESS) {
- LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
- a2dp_status);
- return -1;
- }
-
- return 24; // For aptX-HD we always use 24 bits per audio sample
-}
-
int A2DP_VendorGetTrackChannelCountAptxHd(const uint8_t* p_codec_info) {
tA2DP_APTX_HD_CIE aptx_hd_cie;
@@ -363,7 +348,7 @@
return true;
}
-void A2DP_VendorDumpCodecInfoAptxHd(const uint8_t* p_codec_info) {
+bool A2DP_VendorDumpCodecInfoAptxHd(const uint8_t* p_codec_info) {
tA2DP_STATUS a2dp_status;
tA2DP_APTX_HD_CIE aptx_hd_cie;
@@ -373,7 +358,7 @@
if (a2dp_status != A2DP_SUCCESS) {
LOG_ERROR(LOG_TAG, "%s: A2DP_ParseInfoAptxHd fail:%d", __func__,
a2dp_status);
- return;
+ return false;
}
LOG_DEBUG(LOG_TAG, "\tsamp_freq: 0x%x", aptx_hd_cie.sampleRate);
@@ -391,6 +376,8 @@
if (aptx_hd_cie.channelMode & A2DP_APTX_HD_CHANNELS_STEREO) {
LOG_DEBUG(LOG_TAG, "\tch_mode: (Stereo)");
}
+
+ return true;
}
const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterfaceAptxHd(
diff --git a/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc b/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc
index d35d872..084291f 100644
--- a/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc
+++ b/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc
@@ -258,7 +258,7 @@
p_feeding_params->sample_rate =
A2DP_VendorGetTrackSampleRateAptxHd(p_codec_info);
p_feeding_params->bits_per_sample =
- A2DP_VendorGetTrackBitsPerSampleAptxHd(p_codec_info);
+ a2dp_codec_config->getAudioBitsPerSample();
p_feeding_params->channel_count =
A2DP_VendorGetTrackChannelCountAptxHd(p_codec_info);
LOG_DEBUG(LOG_TAG, "%s: sample_rate=%u bits_per_sample=%u channel_count=%u",
diff --git a/stack/a2dp/a2dp_vendor_ldac.cc b/stack/a2dp/a2dp_vendor_ldac.cc
index e822a2f..08d4362 100644
--- a/stack/a2dp/a2dp_vendor_ldac.cc
+++ b/stack/a2dp/a2dp_vendor_ldac.cc
@@ -330,30 +330,6 @@
return -1;
}
-int A2DP_VendorGetTrackBitsPerSampleLdac(const uint8_t* p_codec_info) {
- tA2DP_LDAC_CIE ldac_cie;
-
- // Check whether the codec info contains valid data
- tA2DP_STATUS a2dp_status = A2DP_ParseInfoLdac(&ldac_cie, p_codec_info, false);
- if (a2dp_status != A2DP_SUCCESS) {
- LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
- a2dp_status);
- return -1;
- }
-
- switch (a2dp_ldac_caps.bits_per_sample) {
- case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
- return 16;
- case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24:
- return 24;
- case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32:
- return 32;
- case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE:
- break;
- }
- return -1;
-}
-
int A2DP_VendorGetTrackChannelCountLdac(const uint8_t* p_codec_info) {
tA2DP_LDAC_CIE ldac_cie;
@@ -422,7 +398,7 @@
return true;
}
-void A2DP_VendorDumpCodecInfoLdac(const uint8_t* p_codec_info) {
+bool A2DP_VendorDumpCodecInfoLdac(const uint8_t* p_codec_info) {
tA2DP_STATUS a2dp_status;
tA2DP_LDAC_CIE ldac_cie;
@@ -431,7 +407,7 @@
a2dp_status = A2DP_ParseInfoLdac(&ldac_cie, p_codec_info, true);
if (a2dp_status != A2DP_SUCCESS) {
LOG_ERROR(LOG_TAG, "%s: A2DP_ParseInfoLdac fail:%d", __func__, a2dp_status);
- return;
+ return false;
}
LOG_DEBUG(LOG_TAG, "\tsamp_freq: 0x%x", ldac_cie.sampleRate);
@@ -464,6 +440,8 @@
if (ldac_cie.channelMode & A2DP_LDAC_CHANNEL_MODE_STEREO) {
LOG_DEBUG(LOG_TAG, "\tch_mode: (Stereo)");
}
+
+ return true;
}
const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterfaceLdac(
diff --git a/stack/a2dp/a2dp_vendor_ldac_encoder.cc b/stack/a2dp/a2dp_vendor_ldac_encoder.cc
index 68deea8..47f7764 100644
--- a/stack/a2dp/a2dp_vendor_ldac_encoder.cc
+++ b/stack/a2dp/a2dp_vendor_ldac_encoder.cc
@@ -15,9 +15,11 @@
*/
#define LOG_TAG "a2dp_vendor_ldac_encoder"
+#define ATRACE_TAG ATRACE_TAG_AUDIO
#include "a2dp_vendor_ldac_encoder.h"
+#include <cutils/trace.h>
#include <dlfcn.h>
#include <inttypes.h>
#include <stdio.h>
@@ -545,6 +547,7 @@
a2dp_ldac_encoder_cb.TxQueueLength, flag_enable);
if (prev_eqmid != a2dp_ldac_encoder_cb.last_ldac_abr_eqmid)
a2dp_ldac_encoder_cb.ldac_abr_adjustments++;
+ ATRACE_INT("LDAC ABR level", a2dp_ldac_encoder_cb.last_ldac_abr_eqmid);
}
// Transcode frame and enqueue
a2dp_ldac_encode_frames(nb_frame);
diff --git a/stack/avdt/avdt_api.cc b/stack/avdt/avdt_api.cc
index bf45ad3..5369f6e 100644
--- a/stack/avdt/avdt_api.cc
+++ b/stack/avdt/avdt_api.cc
@@ -32,6 +32,7 @@
#include "btm_api.h"
#include "btu.h"
#include "l2c_api.h"
+#include "stack/include/a2dp_codec_api.h"
/* Control block for AVDT */
tAVDT_CB avdt_cb;
@@ -135,7 +136,7 @@
}
void AVDT_AbortReq(uint8_t handle) {
- AVDT_TRACE_ERROR("%s", __func__);
+ AVDT_TRACE_WARNING("%s: handle=%d", __func__, handle);
tAVDT_SCB* p_scb = avdt_scb_by_hdl(handle);
if (p_scb != NULL) {
@@ -163,6 +164,8 @@
uint16_t result = AVDT_SUCCESS;
tAVDT_SCB* p_scb;
+ AVDT_TRACE_DEBUG("%s", __func__);
+
/* Verify parameters; if invalid, return failure */
if (((p_cs->cfg.psc_mask & (~AVDT_PSC)) != 0) ||
(p_cs->p_ctrl_cback == NULL)) {
@@ -177,6 +180,9 @@
*p_handle = avdt_scb_to_hdl(p_scb);
}
}
+
+ AVDT_TRACE_DEBUG("%s: result=%d", __func__, result);
+
return result;
}
@@ -198,6 +204,8 @@
uint16_t result = AVDT_SUCCESS;
tAVDT_SCB* p_scb;
+ AVDT_TRACE_DEBUG("%s: handle=%d", __func__, handle);
+
/* look up scb */
p_scb = avdt_scb_by_hdl(handle);
if (p_scb == NULL) {
@@ -206,6 +214,9 @@
/* send remove event to scb */
avdt_scb_event(p_scb, AVDT_SCB_API_REMOVE_EVT, NULL);
}
+
+ AVDT_TRACE_DEBUG("%s: result=%d", __func__, result);
+
return result;
}
@@ -241,6 +252,8 @@
uint16_t result = AVDT_SUCCESS;
tAVDT_CCB_EVT evt;
+ AVDT_TRACE_DEBUG("%s", __func__);
+
/* find channel control block for this bd addr; if none, allocate one */
p_ccb = avdt_ccb_by_bd(bd_addr);
if (p_ccb == NULL) {
@@ -264,6 +277,9 @@
avdt_ccb_event(p_ccb, AVDT_CCB_API_DISCOVER_REQ_EVT, &evt);
}
}
+
+ AVDT_TRACE_DEBUG("%s: result=%d", __func__, result);
+
return result;
}
@@ -281,6 +297,8 @@
tAVDT_CCB* p_ccb = NULL;
uint16_t result = AVDT_SUCCESS;
+ AVDT_TRACE_DEBUG("%s", __func__);
+
/* verify SEID */
if ((p_evt->single.seid < AVDT_SEID_MIN) ||
(p_evt->single.seid > AVDT_SEID_MAX)) {
@@ -309,6 +327,9 @@
avdt_ccb_event(p_ccb, AVDT_CCB_API_GETCAP_REQ_EVT, (tAVDT_CCB_EVT*)p_evt);
}
}
+
+ AVDT_TRACE_DEBUG("%s: result=%d", __func__, result);
+
return result;
}
@@ -339,12 +360,19 @@
uint16_t AVDT_GetCapReq(BD_ADDR bd_addr, uint8_t seid, tAVDT_CFG* p_cfg,
tAVDT_CTRL_CBACK* p_cback) {
tAVDT_CCB_API_GETCAP getcap;
+ uint16_t result = AVDT_SUCCESS;
+
+ AVDT_TRACE_DEBUG("%s", __func__);
getcap.single.seid = seid;
getcap.single.sig_id = AVDT_SIG_GETCAP;
getcap.p_cfg = p_cfg;
getcap.p_cback = p_cback;
- return avdt_get_cap_req(bd_addr, &getcap);
+ result = avdt_get_cap_req(bd_addr, &getcap);
+
+ AVDT_TRACE_DEBUG("%s: result=%d", __func__, result);
+
+ return result;
}
/*******************************************************************************
@@ -374,12 +402,19 @@
uint16_t AVDT_GetAllCapReq(BD_ADDR bd_addr, uint8_t seid, tAVDT_CFG* p_cfg,
tAVDT_CTRL_CBACK* p_cback) {
tAVDT_CCB_API_GETCAP getcap;
+ uint16_t result = AVDT_SUCCESS;
+
+ AVDT_TRACE_DEBUG("%s", __func__);
getcap.single.seid = seid;
getcap.single.sig_id = AVDT_SIG_GET_ALLCAP;
getcap.p_cfg = p_cfg;
getcap.p_cback = p_cback;
- return avdt_get_cap_req(bd_addr, &getcap);
+ result = avdt_get_cap_req(bd_addr, &getcap);
+
+ AVDT_TRACE_DEBUG("%s: result=%d", __func__, result);
+
+ return result;
}
/*******************************************************************************
@@ -398,6 +433,9 @@
uint16_t result = AVDT_SUCCESS;
tAVDT_SCB_EVT evt;
+ AVDT_TRACE_DEBUG("%s: handle=%d ceid=%d delay=%d", __func__, handle, seid,
+ delay);
+
/* map handle to scb */
p_scb = avdt_scb_by_hdl(handle);
if (p_scb == NULL) {
@@ -410,6 +448,8 @@
avdt_scb_event(p_scb, AVDT_SCB_API_DELAY_RPT_REQ_EVT, &evt);
}
+ AVDT_TRACE_DEBUG("%s: result=%d", __func__, result);
+
return result;
}
@@ -434,6 +474,8 @@
uint16_t result = AVDT_SUCCESS;
tAVDT_SCB_EVT evt;
+ AVDT_TRACE_DEBUG("%s: handle=%d seid=%d", __func__, handle, seid);
+
/* verify SEID */
if ((seid < AVDT_SEID_MIN) || (seid > AVDT_SEID_MAX)) {
result = AVDT_BAD_PARAMS;
@@ -459,12 +501,17 @@
/* send event to scb */
if (result == AVDT_SUCCESS) {
+ A2DP_DumpCodecInfo(p_cfg->codec_info);
+
evt.msg.config_cmd.hdr.seid = seid;
evt.msg.config_cmd.hdr.ccb_idx = avdt_ccb_to_idx(p_ccb);
evt.msg.config_cmd.int_seid = handle;
evt.msg.config_cmd.p_cfg = p_cfg;
avdt_scb_event(p_scb, AVDT_SCB_API_SETCONFIG_REQ_EVT, &evt);
}
+
+ AVDT_TRACE_DEBUG("%s: result=%d", __func__, result);
+
return result;
}
@@ -487,6 +534,9 @@
uint16_t result = AVDT_SUCCESS;
uint8_t event_code;
+ AVDT_TRACE_DEBUG("%s: handle=%d label=%d error_code=%d category=%d", __func__,
+ handle, label, error_code, category);
+
/* map handle to scb */
p_scb = avdt_scb_by_hdl(handle);
if (p_scb == NULL) {
@@ -511,6 +561,8 @@
avdt_scb_event(p_scb, event_code, &evt);
}
+ AVDT_TRACE_DEBUG("%s: result=%d", __func__, result);
+
return result;
}
@@ -535,6 +587,8 @@
uint16_t result = AVDT_SUCCESS;
int i;
+ AVDT_TRACE_DEBUG("%s: num_handles=%d", __func__, num_handles);
+
if ((num_handles == 0) || (num_handles > AVDT_NUM_SEPS)) {
result = AVDT_BAD_PARAMS;
} else {
@@ -558,6 +612,9 @@
avdt_ccb_event(p_scb->p_ccb, AVDT_CCB_API_START_REQ_EVT, &evt);
}
}
+
+ AVDT_TRACE_DEBUG("%s: result=%d", __func__, result);
+
return result;
}
@@ -582,6 +639,8 @@
uint16_t result = AVDT_SUCCESS;
int i;
+ AVDT_TRACE_DEBUG("%s: num_handles=%d", __func__, num_handles);
+
if ((num_handles == 0) || (num_handles > AVDT_NUM_SEPS)) {
result = AVDT_BAD_PARAMS;
} else {
@@ -606,6 +665,8 @@
}
}
+ AVDT_TRACE_DEBUG("%s: result=%d", __func__, result);
+
return result;
}
@@ -627,6 +688,8 @@
tAVDT_SCB* p_scb;
uint16_t result = AVDT_SUCCESS;
+ AVDT_TRACE_DEBUG("%s: handle=%d", __func__, handle);
+
/* map handle to scb */
p_scb = avdt_scb_by_hdl(handle);
if (p_scb == NULL) {
@@ -637,6 +700,8 @@
avdt_scb_event(p_scb, AVDT_SCB_API_CLOSE_REQ_EVT, NULL);
}
+ AVDT_TRACE_DEBUG("%s: result=%d", __func__, result);
+
return result;
}
@@ -662,6 +727,8 @@
uint16_t result = AVDT_SUCCESS;
tAVDT_SCB_EVT evt;
+ AVDT_TRACE_DEBUG("%s: handle=%d", __func__, handle);
+
/* map handle to scb */
p_scb = avdt_scb_by_hdl(handle);
if (p_scb == NULL) {
@@ -671,10 +738,12 @@
else {
/* force psc_mask to zero */
p_cfg->psc_mask = 0;
-
evt.msg.reconfig_cmd.p_cfg = p_cfg;
avdt_scb_event(p_scb, AVDT_SCB_API_RECONFIG_REQ_EVT, &evt);
}
+
+ AVDT_TRACE_DEBUG("%s: result=%d", __func__, result);
+
return result;
}
@@ -696,6 +765,9 @@
tAVDT_SCB_EVT evt;
uint16_t result = AVDT_SUCCESS;
+ AVDT_TRACE_DEBUG("%s: handle=%d label=%d error_code=%d category=%d", __func__,
+ handle, label, error_code, category);
+
/* map handle to scb */
p_scb = avdt_scb_by_hdl(handle);
if (p_scb == NULL) {
@@ -709,6 +781,8 @@
avdt_scb_event(p_scb, AVDT_SCB_API_RECONFIG_RSP_EVT, &evt);
}
+ AVDT_TRACE_DEBUG("%s: result=%d", __func__, result);
+
return result;
}
@@ -731,6 +805,8 @@
uint16_t result = AVDT_SUCCESS;
tAVDT_SCB_EVT evt;
+ AVDT_TRACE_DEBUG("%s: handle=%d len=%d", __func__, handle, len);
+
/* map handle to scb */
p_scb = avdt_scb_by_hdl(handle);
if (p_scb == NULL) {
@@ -742,6 +818,9 @@
evt.msg.security_rsp.len = len;
avdt_scb_event(p_scb, AVDT_SCB_API_SECURITY_REQ_EVT, &evt);
}
+
+ AVDT_TRACE_DEBUG("%s: result=%d", __func__, result);
+
return result;
}
@@ -765,6 +844,9 @@
uint16_t result = AVDT_SUCCESS;
tAVDT_SCB_EVT evt;
+ AVDT_TRACE_DEBUG("%s: handle=%d label=%d error_code=%d len=%d", __func__,
+ handle, label, error_code, len);
+
/* map handle to scb */
p_scb = avdt_scb_by_hdl(handle);
if (p_scb == NULL) {
@@ -778,6 +860,9 @@
evt.msg.security_rsp.len = len;
avdt_scb_event(p_scb, AVDT_SCB_API_SECURITY_RSP_EVT, &evt);
}
+
+ AVDT_TRACE_DEBUG("%s: result=%d", __func__, result);
+
return result;
}
@@ -824,6 +909,9 @@
tAVDT_SCB_EVT evt;
uint16_t result = AVDT_SUCCESS;
+ AVDT_TRACE_DEBUG("%s: handle=%d timestamp=%d m_pt=0x%x opt=0x%x", __func__,
+ handle, time_stamp, m_pt, opt);
+
/* map handle to scb */
p_scb = avdt_scb_by_hdl(handle);
if (p_scb == NULL) {
@@ -836,6 +924,8 @@
avdt_scb_event(p_scb, AVDT_SCB_API_WRITE_REQ_EVT, &evt);
}
+ AVDT_TRACE_DEBUG("%s: result=%d", __func__, result);
+
return result;
}
@@ -899,6 +989,8 @@
uint16_t result = AVDT_SUCCESS;
tAVDT_CCB_EVT evt;
+ AVDT_TRACE_DEBUG("%s: sec_mask=0x%x", __func__, sec_mask);
+
/* find channel control block for this bd addr; if none, allocate one */
p_ccb = avdt_ccb_by_bd(bd_addr);
if (p_ccb == NULL) {
@@ -920,6 +1012,9 @@
evt.connect.sec_mask = sec_mask;
avdt_ccb_event(p_ccb, AVDT_CCB_API_CONNECT_REQ_EVT, &evt);
}
+
+ AVDT_TRACE_DEBUG("%s: result=%d", __func__, result);
+
return result;
}
@@ -940,6 +1035,8 @@
uint16_t result = AVDT_SUCCESS;
tAVDT_CCB_EVT evt;
+ AVDT_TRACE_DEBUG("%s", __func__);
+
/* find channel control block for this bd addr; if none, error */
p_ccb = avdt_ccb_by_bd(bd_addr);
if (p_ccb == NULL) {
@@ -951,6 +1048,9 @@
evt.disconnect.p_cback = p_cback;
avdt_ccb_event(p_ccb, AVDT_CCB_API_DISCONNECT_REQ_EVT, &evt);
}
+
+ AVDT_TRACE_DEBUG("%s: result=%d", __func__, result);
+
return result;
}
@@ -1032,6 +1132,8 @@
uint32_t ssrc;
uint16_t len;
+ AVDT_TRACE_DEBUG("%s: handle=%d type=%d", __func__, handle, type);
+
/* map handle to scb && verify parameters */
if (((p_scb = avdt_scb_by_hdl(handle)) != NULL) && (p_scb->p_ccb != NULL) &&
(((type == AVDT_RTCP_PT_SR) && (p_scb->cs.tsep == AVDT_TSEP_SRC)) ||
@@ -1099,6 +1201,8 @@
}
}
+ AVDT_TRACE_DEBUG("%s: result=%d", __func__, result);
+
return result;
}
#endif
diff --git a/stack/avdt/avdt_ccb.cc b/stack/avdt/avdt_ccb.cc
index c1f1469..a9ca128 100644
--- a/stack/avdt/avdt_ccb.cc
+++ b/stack/avdt/avdt_ccb.cc
@@ -37,7 +37,6 @@
/*****************************************************************************
* state machine constants and types
****************************************************************************/
-#if (AVDT_DEBUG == TRUE)
/* verbose state strings for trace */
const char* const avdt_ccb_st_str[] = {"CCB_IDLE_ST", "CCB_OPENING_ST",
@@ -60,8 +59,6 @@
"UL_CLOSE_EVT", "LL_OPEN_EVT",
"LL_CLOSE_EVT", "LL_CONG_EVT"};
-#endif
-
/* action function list */
const tAVDT_CCB_ACTION avdt_ccb_action[] = {
avdt_ccb_chan_open, avdt_ccb_chan_close,
@@ -387,6 +384,9 @@
/* execute action functions */
for (i = 0; i < AVDT_CCB_ACTIONS; i++) {
action = state_table[event][i];
+ AVDT_TRACE_DEBUG("%s: event=%s state=%s action=%d", __func__,
+ avdt_ccb_evt_str[event], avdt_ccb_st_str[p_ccb->state],
+ action);
if (action != AVDT_CCB_IGNORE) {
(*avdt_cb.p_ccb_act[action])(p_ccb, p_data);
} else {
diff --git a/stack/avdt/avdt_ccb_act.cc b/stack/avdt/avdt_ccb_act.cc
index 943855f..9347646 100644
--- a/stack/avdt/avdt_ccb_act.cc
+++ b/stack/avdt/avdt_ccb_act.cc
@@ -486,6 +486,8 @@
tAVDT_MSG avdt_msg;
uint8_t seid_list[AVDT_NUM_SEPS];
+ AVDT_TRACE_DEBUG("%s", __func__);
+
/* make copy of our seid list */
memcpy(seid_list, p_data->msg.multi.seid_list, p_data->msg.multi.num_seps);
@@ -494,6 +496,8 @@
avdt_scb_verify(p_ccb, AVDT_VERIFY_OPEN, p_data->msg.multi.seid_list,
p_data->msg.multi.num_seps, &avdt_msg.hdr.err_code);
if (avdt_msg.hdr.err_param == 0) {
+ AVDT_TRACE_DEBUG("%s: AVDT_SIG_START", __func__);
+
/* set peer seid list in messsage */
avdt_scb_peer_seid_list(&p_data->msg.multi);
@@ -504,6 +508,7 @@
for (i = 0; i < p_data->msg.multi.num_seps; i++) {
p_scb = avdt_scb_by_hdl(seid_list[i]);
if (p_scb != NULL) {
+ AVDT_TRACE_DEBUG("%s: AVDT_SCB_MSG_START_REJ_EVT: i=%d", __func__, i);
avdt_scb_event(p_scb, AVDT_SCB_MSG_START_REJ_EVT,
(tAVDT_SCB_EVT*)&avdt_msg.hdr);
}
diff --git a/stack/avdt/avdt_scb_act.cc b/stack/avdt/avdt_scb_act.cc
index 8832d44..c44a5a2 100644
--- a/stack/avdt/avdt_scb_act.cc
+++ b/stack/avdt/avdt_scb_act.cc
@@ -503,7 +503,11 @@
void avdt_scb_hdl_setconfig_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
tAVDT_CFG* p_cfg;
+ AVDT_TRACE_DEBUG("%s: p_scb->in_use=%d", __func__, p_scb->in_use);
+
if (!p_scb->in_use) {
+ A2DP_DumpCodecInfo(p_scb->cs.cfg.codec_info);
+ A2DP_DumpCodecInfo(p_data->msg.config_cmd.p_cfg->codec_info);
p_cfg = p_data->msg.config_cmd.p_cfg;
if (A2DP_GetCodecType(p_scb->cs.cfg.codec_info) ==
A2DP_GetCodecType(p_cfg->codec_info)) {
@@ -526,6 +530,7 @@
p_data->msg.hdr.sig_id, &p_data->msg);
}
} else {
+ AVDT_TRACE_DEBUG("%s: calling avdt_scb_rej_in_use()", __func__);
avdt_scb_rej_in_use(p_scb, p_data);
}
}
@@ -916,6 +921,8 @@
UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
tAVDT_EVT_HDR hdr;
+ AVDT_TRACE_DEBUG("%s: p_scb->p_ccb=%p", __func__, p_scb->p_ccb);
+
if (p_scb->p_ccb != NULL) {
p_scb->role = AVDT_CLOSE_INT;
@@ -1071,6 +1078,10 @@
*
******************************************************************************/
void avdt_scb_snd_reconfig_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ AVDT_TRACE_DEBUG("%s: p_scb->peer_seid=%d p_data->msg.hdr.seid=%d", __func__,
+ p_scb->peer_seid, p_data->msg.hdr.seid);
+ A2DP_DumpCodecInfo(p_data->msg.config_cmd.p_cfg->codec_info);
+
memcpy(&p_scb->req_cfg, p_data->msg.config_cmd.p_cfg, sizeof(tAVDT_CFG));
p_data->msg.hdr.seid = p_scb->peer_seid;
avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_RECONFIG, &p_data->msg);
@@ -1173,6 +1184,9 @@
void avdt_scb_snd_setconfig_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
tAVDT_CFG *p_req, *p_cfg;
+ AVDT_TRACE_DEBUG("%s", __func__);
+ A2DP_DumpCodecInfo(p_data->msg.config_cmd.p_cfg->codec_info);
+
/* copy API parameters to scb, set scb as in use */
p_scb->in_use = true;
p_scb->p_ccb = avdt_ccb_by_idx(p_data->msg.config_cmd.hdr.ccb_idx);
diff --git a/stack/btm/btm_acl.cc b/stack/btm/btm_acl.cc
index 97f1871..07a80fb 100644
--- a/stack/btm/btm_acl.cc
+++ b/stack/btm/btm_acl.cc
@@ -44,6 +44,7 @@
#include "btm_int.h"
#include "btu.h"
#include "device/include/controller.h"
+#include "device/include/interop.h"
#include "hcidefs.h"
#include "hcimsgs.h"
#include "l2c_int.h"
@@ -231,6 +232,7 @@
BD_ADDR_LEN);
#endif
+ p->switch_role_failed_attempts = 0;
p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
btm_pm_sm_alloc(xx);
@@ -569,6 +571,11 @@
/* Finished if already in desired role */
if (p->link_role == new_role) return (BTM_SUCCESS);
+ if (interop_match_addr(INTEROP_DISABLE_ROLE_SWITCH,
+ (const bt_bdaddr_t*)&remote_bd_addr)) {
+ return BTM_DEV_BLACKLISTED;
+ }
+
#if (BTM_SCO_INCLUDED == TRUE)
/* Check if there is any SCO Active on this BD Address */
is_sco_active = btm_is_sco_active_by_bdaddr(remote_bd_addr);
@@ -582,6 +589,13 @@
return (BTM_BUSY);
}
+ if (interop_match_addr(INTEROP_DYNAMIC_ROLE_SWITCH,
+ (const bt_bdaddr_t*)&remote_bd_addr)) {
+ BTM_TRACE_DEBUG("%s, Device blacklisted under INTEROP_DYNAMIC_ROLE_SWITCH.",
+ __func__);
+ return BTM_DEV_BLACKLISTED;
+ }
+
status = BTM_ReadPowerMode(p->remote_addr, &pwr_mode);
if (status != BTM_SUCCESS) return (status);
@@ -1364,6 +1378,58 @@
}
/*******************************************************************************
+*
+* Function btm_blacklist_role_change_device
+*
+* Description This function is used to blacklist the device if the role
+* switch fails for maximum number of times. It also removes
+* the device from the black list if the role switch succeeds.
+*
+* Input Parms bd_addr - remote BD addr
+* hci_status - role switch status
+*
+* Returns void
+*
+*******************************************************************************/
+void btm_blacklist_role_change_device(BD_ADDR bd_addr, uint8_t hci_status) {
+ tACL_CONN* p = btm_bda_to_acl(bd_addr, BT_TRANSPORT_BR_EDR);
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+
+ if (!p || !p_dev_rec) {
+ return;
+ }
+ if (hci_status == HCI_SUCCESS) {
+ p->switch_role_failed_attempts = 0;
+ return;
+ }
+
+ /* check for carkits */
+ const uint32_t cod_audio_device =
+ (BTM_COD_SERVICE_AUDIO | BTM_COD_MAJOR_AUDIO) << 8;
+ const uint32_t cod =
+ ((p_dev_rec->dev_class[0] << 16) | (p_dev_rec->dev_class[1] << 8) |
+ p_dev_rec->dev_class[2]) &
+ 0xffffff;
+ if ((hci_status != HCI_SUCCESS) &&
+ ((p->switch_role_state == BTM_ACL_SWKEY_STATE_SWITCHING) ||
+ (p->switch_role_state == BTM_ACL_SWKEY_STATE_IN_PROGRESS)) &&
+ ((cod & cod_audio_device) == cod_audio_device) &&
+ (!interop_match_addr(INTEROP_DYNAMIC_ROLE_SWITCH,
+ (const bt_bdaddr_t*)&bd_addr))) {
+ p->switch_role_failed_attempts++;
+ if (p->switch_role_failed_attempts == BTM_MAX_SW_ROLE_FAILED_ATTEMPTS) {
+ BTM_TRACE_WARNING(
+ "%s: Device %02x:%02x:%02x:%02x:%02x:%02x blacklisted for role "
+ "switching - multiple role switch failed attempts: %u",
+ __func__, bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4],
+ bd_addr[5], p->switch_role_failed_attempts);
+ interop_database_add(INTEROP_DYNAMIC_ROLE_SWITCH,
+ (const bt_bdaddr_t*)&bd_addr, 3);
+ }
+ }
+}
+
+/*******************************************************************************
*
* Function btm_acl_role_changed
*
diff --git a/stack/btm/btm_ble_bgconn.cc b/stack/btm/btm_ble_bgconn.cc
index 76eb509..c3d8dbb 100644
--- a/stack/btm/btm_ble_bgconn.cc
+++ b/stack/btm/btm_ble_bgconn.cc
@@ -50,39 +50,63 @@
// TODO: Move all of this to controller/le/background_list or similar?
typedef struct background_connection_t {
bt_bdaddr_t address;
+ uint8_t addr_type;
+
+ bool in_controller_wl;
+ uint8_t addr_type_in_wl;
+
+ bool pending_removal;
} background_connection_t;
-struct KeyEqual {
- bool operator()(const bt_bdaddr_t* x, const bt_bdaddr_t* y) const {
- return bdaddr_equals(x, y);
+struct BgConnHash {
+ bool operator()(const bt_bdaddr_t& x) const {
+ const uint8_t* a = x.address;
+ return a[0] ^ (a[1] << 8) ^ (a[2] << 16) ^ (a[3] << 24) ^ a[4] ^
+ (a[5] << 8);
}
};
-static std::unordered_map<bt_bdaddr_t*, background_connection_t*,
- std::hash<bt_bdaddr_t*>, KeyEqual>
+struct BgConnKeyEqual {
+ bool operator()(const bt_bdaddr_t& x, const bt_bdaddr_t& y) const {
+ return bdaddr_equals(&x, &y);
+ }
+};
+
+static std::unordered_map<bt_bdaddr_t, background_connection_t, BgConnHash,
+ BgConnKeyEqual>
background_connections;
-static void background_connection_add(bt_bdaddr_t* address) {
+static void background_connection_add(uint8_t addr_type, bt_bdaddr_t* address) {
CHECK(address);
- auto map_iter = background_connections.find(address);
+ auto map_iter = background_connections.find(*address);
if (map_iter == background_connections.end()) {
- background_connection_t* connection =
- (background_connection_t*)osi_calloc(sizeof(background_connection_t));
- connection->address = *address;
- background_connections[&(connection->address)] = connection;
+ background_connections[*address] =
+ background_connection_t{*address, addr_type, false, 0, false};
+ } else {
+ background_connection_t* connection = &map_iter->second;
+ connection->addr_type = addr_type;
+ connection->pending_removal = false;
}
}
static void background_connection_remove(bt_bdaddr_t* address) {
- background_connections.erase(address);
+ auto map_iter = background_connections.find(*address);
+ if (map_iter != background_connections.end()) {
+ if (map_iter->second.in_controller_wl) {
+ map_iter->second.pending_removal = true;
+ } else {
+ background_connections.erase(map_iter);
+ }
+ }
}
static void background_connections_clear() { background_connections.clear(); }
static bool background_connections_pending() {
- for (const auto& map_el : background_connections) {
- background_connection_t* connection = map_el.second;
+ for (auto& map_el : background_connections) {
+ background_connection_t* connection = &map_el.second;
+ if (connection->pending_removal) continue;
const bool connected =
BTM_IsAclConnectionUp(connection->address.address, BT_TRANSPORT_LE);
if (!connected) {
@@ -92,6 +116,14 @@
return false;
}
+static int background_connections_count() {
+ int count = 0;
+ for (auto& map_el : background_connections) {
+ if (!map_el.second.pending_removal) ++count;
+ }
+ return count;
+}
+
/*******************************************************************************
*
* Function btm_update_scanner_filter_policy
@@ -117,6 +149,34 @@
p_inq->scan_type, (uint16_t)scan_interval, (uint16_t)scan_window,
btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type, scan_policy);
}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_bgconn_cancel_if_disconnected
+ *
+ * Description If a device has been disconnected, it must be re-added to
+ * the white list. If needed, this function cancels a pending
+ * initiate command in order to trigger restart of the initiate
+ * command which in turn updates the white list.
+ *
+ * Parameters bd_addr: updated device
+ *
+ ******************************************************************************/
+void btm_ble_bgconn_cancel_if_disconnected(BD_ADDR bd_addr) {
+ if (btm_cb.ble_ctr_cb.conn_state != BLE_BG_CONN) return;
+
+ bt_bdaddr_t addr = *(bt_bdaddr_t*)bd_addr;
+
+ auto map_it = background_connections.find(addr);
+ if (map_it != background_connections.end()) {
+ background_connection_t* connection = &map_it->second;
+ if (!connection->in_controller_wl && !connection->pending_removal &&
+ !BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_LE)) {
+ btm_ble_start_auto_conn(false);
+ }
+ }
+}
+
/*******************************************************************************
*
* Function btm_add_dev_to_controller
@@ -132,30 +192,29 @@
if (to_add) {
if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_PUBLIC ||
!BTM_BLE_IS_RESOLVE_BDA(bd_addr)) {
- btsnd_hcic_ble_add_white_list(p_dev_rec->ble.ble_addr_type, bd_addr);
+ background_connection_add(p_dev_rec->ble.ble_addr_type,
+ (bt_bdaddr_t*)bd_addr);
started = true;
p_dev_rec->ble.in_controller_list |= BTM_WHITE_LIST_BIT;
} else 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) {
- btsnd_hcic_ble_add_white_list(p_dev_rec->ble.static_addr_type,
- p_dev_rec->ble.static_addr);
+ background_connection_add(p_dev_rec->ble.static_addr_type,
+ (bt_bdaddr_t*)p_dev_rec->ble.static_addr);
started = true;
p_dev_rec->ble.in_controller_list |= BTM_WHITE_LIST_BIT;
}
} else {
if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_PUBLIC ||
!BTM_BLE_IS_RESOLVE_BDA(bd_addr)) {
- btsnd_hcic_ble_remove_from_white_list(p_dev_rec->ble.ble_addr_type,
- bd_addr);
+ background_connection_remove((bt_bdaddr_t*)bd_addr);
started = true;
}
if (memcmp(p_dev_rec->ble.static_addr, dummy_bda, BD_ADDR_LEN) != 0 &&
memcmp(p_dev_rec->ble.static_addr, bd_addr, BD_ADDR_LEN) != 0) {
- btsnd_hcic_ble_remove_from_white_list(p_dev_rec->ble.static_addr_type,
- p_dev_rec->ble.static_addr);
+ background_connection_remove((bt_bdaddr_t*)p_dev_rec->ble.static_addr);
started = true;
}
@@ -166,9 +225,11 @@
*/
uint8_t addr_type =
BTM_IS_PUBLIC_BDA(bd_addr) ? BLE_ADDR_PUBLIC : BLE_ADDR_RANDOM;
- btsnd_hcic_ble_remove_from_white_list(addr_type, bd_addr);
started = true;
- if (to_add) btsnd_hcic_ble_add_white_list(addr_type, bd_addr);
+ if (to_add)
+ background_connection_add(addr_type, (bt_bdaddr_t*)bd_addr);
+ else
+ background_connection_remove((bt_bdaddr_t*)bd_addr);
}
return started;
@@ -181,45 +242,37 @@
* removing)
******************************************************************************/
bool btm_execute_wl_dev_operation(void) {
- tBTM_BLE_WL_OP* p_dev_op = btm_cb.ble_ctr_cb.wl_op_q;
- uint8_t i = 0;
- bool rt = true;
-
- for (i = 0; i < BTM_BLE_MAX_BG_CONN_DEV_NUM && rt; i++, p_dev_op++) {
- if (p_dev_op->in_use) {
- rt = btm_add_dev_to_controller(p_dev_op->to_add, p_dev_op->bd_addr);
- memset(p_dev_op, 0, sizeof(tBTM_BLE_WL_OP));
+ // handle removals first to avoid filling up controller's white list
+ for (auto map_it = background_connections.begin();
+ map_it != background_connections.end();) {
+ background_connection_t* connection = &map_it->second;
+ if (connection->pending_removal) {
+ btsnd_hcic_ble_remove_from_white_list(connection->addr_type_in_wl,
+ connection->address.address);
+ map_it = background_connections.erase(map_it);
} else
- break;
+ ++map_it;
}
- return rt;
-}
-/*******************************************************************************
- *
- * Function btm_enq_wl_dev_operation
- *
- * Description enqueue the pending whitelist device operation (loading or
- * removing).
- ******************************************************************************/
-void btm_enq_wl_dev_operation(bool to_add, BD_ADDR bd_addr) {
- tBTM_BLE_WL_OP* p_dev_op = btm_cb.ble_ctr_cb.wl_op_q;
- uint8_t i = 0;
-
- for (i = 0; i < BTM_BLE_MAX_BG_CONN_DEV_NUM; i++, p_dev_op++) {
- if (p_dev_op->in_use && !memcmp(p_dev_op->bd_addr, bd_addr, BD_ADDR_LEN)) {
- p_dev_op->to_add = to_add;
- return;
- } else if (!p_dev_op->in_use)
- break;
+ for (auto& map_el : background_connections) {
+ background_connection_t* connection = &map_el.second;
+ const bool connected =
+ BTM_IsAclConnectionUp(connection->address.address, BT_TRANSPORT_LE);
+ if (!connection->in_controller_wl && !connected) {
+ btsnd_hcic_ble_add_white_list(connection->addr_type,
+ connection->address.address);
+ connection->in_controller_wl = true;
+ connection->addr_type_in_wl = connection->addr_type;
+ } else if (connection->in_controller_wl && connected) {
+ /* Bluetooth Core 4.2 as well as ESR08 disallows more than one
+ connection between two LE addresses. Not all controllers handle this
+ correctly, therefore we must make sure connected devices are not in
+ the white list when bg connection attempt is active. */
+ btsnd_hcic_ble_remove_from_white_list(connection->addr_type_in_wl,
+ connection->address.address);
+ connection->in_controller_wl = false;
+ }
}
- if (i != BTM_BLE_MAX_BG_CONN_DEV_NUM) {
- p_dev_op->in_use = true;
- p_dev_op->to_add = to_add;
- memcpy(p_dev_op->bd_addr, bd_addr, BD_ADDR_LEN);
- } else {
- BTM_TRACE_ERROR("max pending WL operation reached, discard");
- }
- return;
+ return true;
}
/*******************************************************************************
@@ -233,18 +286,15 @@
bool btm_update_dev_to_white_list(bool to_add, BD_ADDR bd_addr) {
tBTM_BLE_CB* p_cb = &btm_cb.ble_ctr_cb;
- if (to_add && p_cb->white_list_avail_size == 0) {
+ if (to_add &&
+ background_connections_count() ==
+ controller_get_interface()->get_ble_white_list_size()) {
BTM_TRACE_ERROR("%s Whitelist full, unable to add device", __func__);
return false;
}
- if (to_add)
- background_connection_add((bt_bdaddr_t*)bd_addr);
- else
- background_connection_remove((bt_bdaddr_t*)bd_addr);
-
btm_suspend_wl_activity(p_cb->wl_state);
- btm_enq_wl_dev_operation(to_add, bd_addr);
+ btm_add_dev_to_controller(to_add, bd_addr);
btm_resume_wl_activity(p_cb->wl_state);
return true;
}
@@ -271,15 +321,10 @@
******************************************************************************/
void btm_ble_clear_white_list_complete(uint8_t* p_data,
UNUSED_ATTR uint16_t evt_len) {
- tBTM_BLE_CB* p_cb = &btm_cb.ble_ctr_cb;
uint8_t status;
- BTM_TRACE_EVENT("btm_ble_clear_white_list_complete");
STREAM_TO_UINT8(status, p_data);
-
- if (status == HCI_SUCCESS)
- p_cb->white_list_avail_size =
- controller_get_interface()->get_ble_white_list_size();
+ BTM_TRACE_EVENT("%s status=%d", __func__, status);
}
/*******************************************************************************
@@ -291,7 +336,6 @@
******************************************************************************/
void btm_ble_white_list_init(uint8_t white_list_size) {
BTM_TRACE_DEBUG("%s white_list_size = %d", __func__, white_list_size);
- btm_cb.ble_ctr_cb.white_list_avail_size = white_list_size;
}
/*******************************************************************************
@@ -303,7 +347,6 @@
******************************************************************************/
void btm_ble_add_2_white_list_complete(uint8_t status) {
BTM_TRACE_EVENT("%s status=%d", __func__, status);
- if (status == HCI_SUCCESS) --btm_cb.ble_ctr_cb.white_list_avail_size;
}
/*******************************************************************************
@@ -316,7 +359,6 @@
void btm_ble_remove_from_white_list_complete(uint8_t* p,
UNUSED_ATTR uint16_t evt_len) {
BTM_TRACE_EVENT("%s status=%d", __func__, *p);
- if (*p == HCI_SUCCESS) ++btm_cb.ble_ctr_cb.white_list_avail_size;
}
void btm_send_hci_create_connection(
@@ -381,9 +423,11 @@
if (controller_get_interface()->supports_ble_2m_phy()) phy |= PHY_LE_2M;
if (controller_get_interface()->supports_ble_coded_phy()) phy |= PHY_LE_CODED;
+ BTM_TRACE_EVENT("%s start=%d", __func__, start);
+
if (start) {
if (p_cb->conn_state == BLE_CONN_IDLE && background_connections_pending() &&
- btm_ble_topology_check(BTM_BLE_STATE_INIT)) {
+ btm_ble_topology_check(BTM_BLE_STATE_INIT) && l2cu_can_allocate_lcb()) {
p_cb->wl_state |= BTM_BLE_WL_INIT;
btm_execute_wl_dev_operation();
@@ -471,9 +515,6 @@
if (wl_state & BTM_BLE_WL_INIT) {
btm_ble_start_auto_conn(false);
}
- if (wl_state & BTM_BLE_WL_ADV) {
- btm_ble_stop_adv();
- }
}
/*******************************************************************************
*
@@ -486,10 +527,6 @@
******************************************************************************/
static void btm_resume_wl_activity(tBTM_BLE_WL_STATE wl_state) {
btm_ble_resume_bg_conn();
-
- if (wl_state & BTM_BLE_WL_ADV) {
- btm_ble_start_adv();
- }
}
/*******************************************************************************
*
diff --git a/stack/btm/btm_ble_gap.cc b/stack/btm/btm_ble_gap.cc
index caf610f..fe093e2 100644
--- a/stack/btm/btm_ble_gap.cc
+++ b/stack/btm/btm_ble_gap.cc
@@ -2103,11 +2103,14 @@
bool is_scannable = ble_evt_type_is_scannable(evt_type);
bool is_scan_resp = ble_evt_type_is_scan_resp(evt_type);
+ bool is_start =
+ ble_evt_type_is_legacy(evt_type) && is_scannable && !is_scan_resp;
+
+ if (is_start) AdvertiseDataParser::RemoveTrailingZeros(tmp);
+
// We might have send scan request to this device before, but didn't get the
// response. In such case make sure data is put at start, not appended to
// already existing data.
- bool is_start =
- ble_evt_type_is_legacy(evt_type) && is_scannable && !is_scan_resp;
std::vector<uint8_t> const& adv_data =
is_start ? cache.Set(addr_type, bda, std::move(tmp))
: cache.Append(addr_type, bda, std::move(tmp));
@@ -2417,10 +2420,6 @@
/* enable resolving list is desired */
btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_ADV);
#endif
- if (p_cb->afp != AP_SCAN_CONN_ALL) {
- btm_execute_wl_dev_operation();
- btm_cb.ble_ctr_cb.wl_state |= BTM_BLE_WL_ADV;
- }
btsnd_hcic_ble_set_adv_enable(BTM_BLE_ADV_ENABLE);
p_cb->adv_mode = BTM_BLE_ADV_ENABLE;
@@ -2445,7 +2444,6 @@
p_cb->fast_adv_on = false;
p_cb->adv_mode = BTM_BLE_ADV_DISABLE;
- btm_cb.ble_ctr_cb.wl_state &= ~BTM_BLE_WL_ADV;
/* clear all adv states */
btm_ble_clear_topology_mask(BTM_BLE_STATE_ALL_ADV_MASK);
@@ -2675,6 +2673,10 @@
btm_cb.ble_ctr_cb.inq_var.connectable_mode);
}
+ /* in case of disconnected, we must cancel bgconn and restart
+ in order to add back device to white list in order to reconnect */
+ btm_ble_bgconn_cancel_if_disconnected(bd_addr);
+
/* when no connection is attempted, and controller is not rejecting last
request
due to resource limitation, start next direct connection or background
diff --git a/stack/btm/btm_ble_int.h b/stack/btm/btm_ble_int.h
index e645994..f7da237 100644
--- a/stack/btm/btm_ble_int.h
+++ b/stack/btm/btm_ble_int.h
@@ -138,6 +138,7 @@
uint8_t status);
extern bool btm_execute_wl_dev_operation(void);
extern void btm_ble_update_link_topology_mask(uint8_t role, bool increase);
+extern void btm_ble_bgconn_cancel_if_disconnected(BD_ADDR bd_addr);
/* direct connection utility */
extern bool btm_send_pending_direct_conn(void);
diff --git a/stack/btm/btm_ble_int_types.h b/stack/btm/btm_ble_int_types.h
index 51b5118..3e16fea 100644
--- a/stack/btm/btm_ble_int_types.h
+++ b/stack/btm/btm_ble_int_types.h
@@ -174,8 +174,6 @@
alarm_t* refresh_raddr_timer;
} tBTM_LE_RANDOM_CB;
-#define BTM_BLE_MAX_BG_CONN_DEV_NUM 10
-
typedef struct {
uint16_t min_conn_int;
uint16_t max_conn_int;
@@ -194,7 +192,6 @@
/* white list using state as a bit mask */
#define BTM_BLE_WL_IDLE 0
#define BTM_BLE_WL_INIT 1
-#define BTM_BLE_WL_ADV 4
typedef uint8_t tBTM_BLE_WL_STATE;
/* resolving list using state as a bit mask */
@@ -300,7 +297,6 @@
uint32_t scan_win;
/* white list information */
- uint8_t white_list_avail_size;
tBTM_BLE_WL_STATE wl_state;
fixed_queue_t* conn_pending_q;
@@ -321,8 +317,6 @@
tBTM_BLE_RL_STATE rl_state; /* Resolving list state */
#endif
- tBTM_BLE_WL_OP wl_op_q[BTM_BLE_MAX_BG_CONN_DEV_NUM];
-
/* current BLE link state */
tBTM_BLE_STATE_MASK cur_states; /* bit mask of tBTM_BLE_STATE */
uint8_t link_count[2]; /* total link count master and slave*/
diff --git a/stack/btm/btm_ble_multi_adv.cc b/stack/btm/btm_ble_multi_adv.cc
index ba31c81..e64766c 100644
--- a/stack/btm/btm_ble_multi_adv.cc
+++ b/stack/btm/btm_ble_multi_adv.cc
@@ -629,7 +629,7 @@
p_params->adv_int_min, p_params->adv_int_max, p_params->channel_map,
p_inst->own_address_type, p_inst->own_address, 0x00, peer_address,
p_params->adv_filter_policy, p_inst->tx_power,
- p_params->primary_advertising_phy, 0x01,
+ p_params->primary_advertising_phy, 0x00,
p_params->secondary_advertising_phy, 0x01 /* TODO: proper SID */,
p_params->scan_request_notification_enable, cb);
@@ -843,6 +843,8 @@
instance = new BleAdvertisingManagerImpl(interface);
}
+bool BleAdvertisingManager::IsInitialized() { return instance; }
+
BleAdvertisingManager* BleAdvertisingManager::Get() {
CHECK(instance);
return instance;
diff --git a/stack/btm/btm_inq.cc b/stack/btm/btm_inq.cc
index 7f9cb40..687e89d 100644
--- a/stack/btm/btm_inq.cc
+++ b/stack/btm/btm_inq.cc
@@ -765,8 +765,8 @@
btm_cb.ble_ctr_cb.inq_var.scan_type = BTM_BLE_SCAN_MODE_NONE;
btm_send_hci_scan_enable(BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE);
} else {
- return (BTM_BUSY);
BTM_TRACE_API("BTM_StartInquiry: return BUSY");
+ return (BTM_BUSY);
}
} else
p_inq->scan_type = INQ_GENERAL;
diff --git a/stack/btm/btm_int.h b/stack/btm/btm_int.h
index 18b9e30..a71af77 100644
--- a/stack/btm/btm_int.h
+++ b/stack/btm/btm_int.h
@@ -105,6 +105,8 @@
uint16_t clock_offset);
extern void btm_acl_role_changed(uint8_t hci_status, BD_ADDR bd_addr,
uint8_t new_role);
+extern void btm_blacklist_role_change_device(BD_ADDR bd_addr,
+ uint8_t hci_status);
extern void btm_acl_encrypt_change(uint16_t handle, uint8_t status,
uint8_t encr_enable);
extern uint16_t btm_get_acl_disc_reason_code(void);
diff --git a/stack/btm/btm_int_types.h b/stack/btm/btm_int_types.h
index 5905aeb..b36eaab 100644
--- a/stack/btm/btm_int_types.h
+++ b/stack/btm/btm_int_types.h
@@ -89,6 +89,9 @@
#define BTM_ACL_SWKEY_STATE_IN_PROGRESS 5
uint8_t switch_role_state;
+#define BTM_MAX_SW_ROLE_FAILED_ATTEMPTS 3
+ uint8_t switch_role_failed_attempts;
+
#define BTM_ACL_ENCRYPT_STATE_IDLE 0
#define BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF 1 /* encryption turning off */
#define BTM_ACL_ENCRYPT_STATE_TEMP_FUNC \
diff --git a/stack/btm/btm_sec.cc b/stack/btm/btm_sec.cc
index 2c18a19..febb4c5 100644
--- a/stack/btm/btm_sec.cc
+++ b/stack/btm/btm_sec.cc
@@ -3875,6 +3875,50 @@
}
}
+/******************************************************************************
+ *
+ * Function btm_sec_auth_retry
+ *
+ * Description This function is called when authentication or encryption
+ * needs to be retried at a later time.
+ *
+ * Returns TRUE if a security retry required
+ *
+ *****************************************************************************/
+static bool btm_sec_auth_retry(uint16_t handle, uint8_t status) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(handle);
+ if (!p_dev_rec) return false;
+
+ /* keep the old sm4 flag and clear the retry bit in control block */
+ uint8_t old_sm4 = p_dev_rec->sm4;
+ p_dev_rec->sm4 &= ~BTM_SM4_RETRY;
+
+ if ((btm_cb.pairing_state == BTM_PAIR_STATE_IDLE) &&
+ ((old_sm4 & BTM_SM4_RETRY) == 0) && (HCI_ERR_KEY_MISSING == status) &&
+ BTM_SEC_IS_SM4(p_dev_rec->sm4)) {
+ /* This retry for missing key is for Lisbon or later only.
+ Legacy device do not need this. the controller will drive the retry
+ automatically
+ set the retry bit */
+ btm_cb.collision_start_time = 0;
+ btm_restore_mode();
+ p_dev_rec->sm4 |= BTM_SM4_RETRY;
+ p_dev_rec->sec_flags &= ~BTM_SEC_LINK_KEY_KNOWN;
+ BTM_TRACE_DEBUG("%s Retry for missing key sm4:x%x sec_flags:0x%x", __func__,
+ p_dev_rec->sm4, p_dev_rec->sec_flags);
+
+ /* With BRCM controller, we do not need to delete the stored link key in
+ controller.
+ If the stack may sit on top of other controller, we may need this
+ BTM_DeleteStoredLinkKey (bd_addr, NULL); */
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ btm_sec_execute_procedure(p_dev_rec);
+ return true;
+ }
+
+ return false;
+}
+
/*******************************************************************************
*
* Function btm_sec_auth_complete
@@ -3886,7 +3930,6 @@
*
******************************************************************************/
void btm_sec_auth_complete(uint16_t handle, uint8_t status) {
- uint8_t old_sm4;
tBTM_PAIRING_STATE old_state = btm_cb.pairing_state;
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(handle);
bool are_bonding = false;
@@ -3912,7 +3955,10 @@
(status == HCI_ERR_DIFF_TRANSACTION_COLLISION)) {
btm_sec_auth_collision(handle);
return;
+ } else if (btm_sec_auth_retry(handle, status)) {
+ return;
}
+
btm_cb.collision_start_time = 0;
btm_restore_mode();
@@ -3929,10 +3975,6 @@
if (!p_dev_rec) return;
- /* keep the old sm4 flag and clear the retry bit in control block */
- old_sm4 = p_dev_rec->sm4;
- p_dev_rec->sm4 &= ~BTM_SM4_RETRY;
-
if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) &&
(btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) &&
(memcmp(p_dev_rec->bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN) == 0))
@@ -4011,37 +4053,6 @@
/* If authentication failed, notify the waiting layer */
if (status != HCI_SUCCESS) {
- if ((old_sm4 & BTM_SM4_RETRY) == 0) {
- /* allow retry only once */
- if (status == HCI_ERR_LMP_ERR_TRANS_COLLISION) {
- /* not retried yet. set the retry bit */
- p_dev_rec->sm4 |= BTM_SM4_RETRY;
- BTM_TRACE_DEBUG("Collision retry sm4:x%x sec_flags:0x%x",
- p_dev_rec->sm4, p_dev_rec->sec_flags);
- }
- /* this retry for missing key is for Lisbon or later only.
- * Legacy device do not need this. the controller will drive the retry
- * automatically */
- else if (HCI_ERR_KEY_MISSING == status &&
- BTM_SEC_IS_SM4(p_dev_rec->sm4)) {
- /* not retried yet. set the retry bit */
- p_dev_rec->sm4 |= BTM_SM4_RETRY;
- p_dev_rec->sec_flags &= ~BTM_SEC_LINK_KEY_KNOWN;
- BTM_TRACE_DEBUG("Retry for missing key sm4:x%x sec_flags:0x%x",
- p_dev_rec->sm4, p_dev_rec->sec_flags);
-
- /* With BRCM controller, we do not need to delete the stored link key in
- controller.
- If the stack may sit on top of other controller, we may need this
- BTM_DeleteStoredLinkKey (bd_addr, NULL); */
- }
-
- if (p_dev_rec->sm4 & BTM_SM4_RETRY) {
- btm_sec_execute_procedure(p_dev_rec);
- return;
- }
- }
-
btm_sec_dev_rec_cback_event(p_dev_rec, BTM_ERR_PROCESSING, false);
if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE) {
diff --git a/stack/btu/btu_hcif.cc b/stack/btu/btu_hcif.cc
index 0fb63d4..144e36c 100644
--- a/stack/btu/btu_hcif.cc
+++ b/stack/btu/btu_hcif.cc
@@ -27,9 +27,11 @@
#define LOG_TAG "bt_btu_hcif"
+#include <base/bind.h>
#include <base/callback.h>
#include <base/location.h>
#include <base/logging.h>
+#include <base/threading/thread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -49,9 +51,6 @@
using tracked_objects::Location;
-// TODO(zachoverflow): remove this horrible hack
-extern fixed_queue_t* btu_hci_msg_queue;
-
extern void btm_process_cancel_complete(uint8_t status, uint8_t mode);
extern void btm_ble_test_command_complete(uint8_t* p);
@@ -127,6 +126,18 @@
static void btu_ble_proc_enhanced_conn_cmpl(uint8_t* p, uint16_t evt_len);
#endif
+static void do_in_hci_thread(const tracked_objects::Location& from_here,
+ const base::Closure& task) {
+ base::MessageLoop* hci_message_loop = get_message_loop();
+ if (!hci_message_loop || !hci_message_loop->task_runner().get()) {
+ LOG_ERROR(LOG_TAG, "%s: HCI message loop not running, accessed from %s",
+ __func__, from_here.ToString().c_str());
+ return;
+ }
+
+ hci_message_loop->task_runner()->PostTask(from_here, task);
+}
+
/*******************************************************************************
*
* Function btu_hcif_process_event
@@ -402,58 +413,48 @@
cb_wrapper->posted_from.~Location();
}
-static void btu_hcif_command_complete_evt_with_cb_on_task(BT_HDR* event) {
- command_complete_hack_t* hack = (command_complete_hack_t*)&event->data[0];
-
+static void btu_hcif_command_complete_evt_with_cb_on_task(BT_HDR* event,
+ void* context) {
command_opcode_t opcode;
uint8_t* stream =
- hack->response->data + hack->response->offset +
+ event->data + event->offset +
3; // 2 to skip the event headers, 1 to skip the command credits
STREAM_TO_UINT16(opcode, stream);
- cmd_with_cb_data* cb_wrapper = (cmd_with_cb_data*)hack->context;
+ cmd_with_cb_data* cb_wrapper = (cmd_with_cb_data*)context;
HCI_TRACE_DEBUG("command complete for: %s",
cb_wrapper->posted_from.ToString().c_str());
- cb_wrapper->cb.Run(stream, hack->response->len - 5);
+ cb_wrapper->cb.Run(stream, event->len - 5);
cmd_with_cb_data_cleanup(cb_wrapper);
osi_free(cb_wrapper);
- osi_free(hack->response);
osi_free(event);
}
static void btu_hcif_command_complete_evt_with_cb(BT_HDR* response,
void* context) {
- BT_HDR* event = static_cast<BT_HDR*>(
- osi_calloc(sizeof(BT_HDR) + sizeof(command_complete_hack_t)));
- command_complete_hack_t* hack = (command_complete_hack_t*)&event->data[0];
-
- hack->callback = btu_hcif_command_complete_evt_with_cb_on_task;
- hack->response = response;
- hack->context = context;
- event->event = BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK;
-
- fixed_queue_enqueue(btu_hci_msg_queue, event);
+ do_in_hci_thread(FROM_HERE,
+ base::Bind(btu_hcif_command_complete_evt_with_cb_on_task,
+ response, context));
}
-static void btu_hcif_command_status_evt_with_cb_on_task(BT_HDR* event) {
- command_status_hack_t* hack = (command_status_hack_t*)&event->data[0];
-
+static void btu_hcif_command_status_evt_with_cb_on_task(uint8_t status,
+ BT_HDR* event,
+ void* context) {
command_opcode_t opcode;
- uint8_t* stream = hack->command->data + hack->command->offset;
+ uint8_t* stream = event->data + event->offset;
STREAM_TO_UINT16(opcode, stream);
- CHECK(hack->status != 0);
+ CHECK(status != 0);
// report command status error
- cmd_with_cb_data* cb_wrapper = (cmd_with_cb_data*)hack->context;
+ cmd_with_cb_data* cb_wrapper = (cmd_with_cb_data*)context;
HCI_TRACE_DEBUG("command status for: %s",
cb_wrapper->posted_from.ToString().c_str());
- cb_wrapper->cb.Run(&hack->status, sizeof(uint16_t));
+ cb_wrapper->cb.Run(&status, sizeof(uint16_t));
cmd_with_cb_data_cleanup(cb_wrapper);
osi_free(cb_wrapper);
- osi_free(hack->command);
osi_free(event);
}
@@ -465,18 +466,9 @@
return;
}
- BT_HDR* event = static_cast<BT_HDR*>(
- osi_calloc(sizeof(BT_HDR) + sizeof(command_status_hack_t)));
- command_status_hack_t* hack = (command_status_hack_t*)&event->data[0];
-
- hack->callback = btu_hcif_command_status_evt_with_cb_on_task;
- hack->status = status;
- hack->command = command;
- hack->context = context;
-
- event->event = BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK;
-
- fixed_queue_enqueue(btu_hci_msg_queue, event);
+ do_in_hci_thread(
+ FROM_HERE, base::Bind(btu_hcif_command_status_evt_with_cb_on_task, status,
+ command, context));
}
/* This function is called to send commands to the Host Controller. |cb| is
@@ -1001,37 +993,26 @@
* Returns void
*
******************************************************************************/
-static void btu_hcif_command_complete_evt_on_task(BT_HDR* event) {
- command_complete_hack_t* hack = (command_complete_hack_t*)&event->data[0];
-
+static void btu_hcif_command_complete_evt_on_task(BT_HDR* event,
+ void* context) {
command_opcode_t opcode;
uint8_t* stream =
- hack->response->data + hack->response->offset +
+ event->data + event->offset +
3; // 2 to skip the event headers, 1 to skip the command credits
STREAM_TO_UINT16(opcode, stream);
btu_hcif_hdl_command_complete(
opcode, stream,
- hack->response->len -
+ event->len -
5, // 3 for the command complete headers, 2 for the event headers
- hack->context);
+ context);
- osi_free(hack->response);
osi_free(event);
}
static void btu_hcif_command_complete_evt(BT_HDR* response, void* context) {
- BT_HDR* event = static_cast<BT_HDR*>(
- osi_calloc(sizeof(BT_HDR) + sizeof(command_complete_hack_t)));
- command_complete_hack_t* hack = (command_complete_hack_t*)&event->data[0];
-
- hack->callback = btu_hcif_command_complete_evt_on_task;
- hack->response = response;
- hack->context = context;
-
- event->event = BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK;
-
- fixed_queue_enqueue(btu_hci_msg_queue, event);
+ do_in_hci_thread(FROM_HERE, base::Bind(btu_hcif_command_complete_evt_on_task,
+ response, context));
}
/*******************************************************************************
@@ -1192,33 +1173,20 @@
* Returns void
*
******************************************************************************/
-static void btu_hcif_command_status_evt_on_task(BT_HDR* event) {
- command_status_hack_t* hack = (command_status_hack_t*)&event->data[0];
-
+static void btu_hcif_command_status_evt_on_task(uint8_t status, BT_HDR* event,
+ void* context) {
command_opcode_t opcode;
- uint8_t* stream = hack->command->data + hack->command->offset;
+ uint8_t* stream = event->data + event->offset;
STREAM_TO_UINT16(opcode, stream);
- btu_hcif_hdl_command_status(opcode, hack->status, stream, hack->context);
-
- osi_free(hack->command);
+ btu_hcif_hdl_command_status(opcode, status, stream, context);
osi_free(event);
}
static void btu_hcif_command_status_evt(uint8_t status, BT_HDR* command,
void* context) {
- BT_HDR* event = static_cast<BT_HDR*>(
- osi_calloc(sizeof(BT_HDR) + sizeof(command_status_hack_t)));
- command_status_hack_t* hack = (command_status_hack_t*)&event->data[0];
-
- hack->callback = btu_hcif_command_status_evt_on_task;
- hack->status = status;
- hack->command = command;
- hack->context = context;
-
- event->event = BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK;
-
- fixed_queue_enqueue(btu_hci_msg_queue, event);
+ do_in_hci_thread(FROM_HERE, base::Bind(btu_hcif_command_status_evt_on_task,
+ status, command, context));
}
/*******************************************************************************
@@ -1269,6 +1237,7 @@
STREAM_TO_BDADDR(bda, p);
STREAM_TO_UINT8(role, p);
+ btm_blacklist_role_change_device(bda, status);
l2c_link_role_changed(bda, role, status);
btm_acl_role_changed(status, bda, role);
}
diff --git a/stack/btu/btu_task.cc b/stack/btu/btu_task.cc
index 8152d3e..103990e 100644
--- a/stack/btu/btu_task.cc
+++ b/stack/btu/btu_task.cc
@@ -23,96 +23,36 @@
#include <stdlib.h>
#include <string.h>
-#include "bt_common.h"
-#include "bt_target.h"
-#include "bt_trace.h"
-#include "bt_types.h"
-#include "bt_utils.h"
+#include <base/bind.h>
+#include <base/logging.h>
+#include <base/run_loop.h>
+#include <base/threading/thread.h>
+
+#include "bta/sys/bta_sys.h"
#include "btcore/include/module.h"
#include "bte.h"
-#include "btif_common.h"
-#include "btm_api.h"
-#include "btm_int.h"
-#include "btu.h"
-#include "gap_int.h"
-#include "hcimsgs.h"
-#include "l2c_int.h"
-#include "osi/include/alarm.h"
-#include "osi/include/fixed_queue.h"
-#include "osi/include/future.h"
-#include "osi/include/log.h"
+#include "btif/include/btif_common.h"
#include "osi/include/osi.h"
#include "osi/include/thread.h"
-#include "port_api.h"
-#include "port_ext.h"
-#include "sdpint.h"
+#include "stack/btm/btm_int.h"
+#include "stack/include/btu.h"
+#include "stack/l2cap/l2c_int.h"
-#if (BNEP_INCLUDED == TRUE)
-#include "bnep_int.h"
-#endif
-
-#if (PAN_INCLUDED == TRUE)
-#include "pan_int.h"
-#endif
-
-#if (HID_HOST_INCLUDED == TRUE)
-#include "hidh_int.h"
-#endif
-
-#if (AVDT_INCLUDED == TRUE)
-#include "avdt_int.h"
-#else
-extern void avdt_rcv_sync_info(BT_HDR* p_buf); /* this is for hci_test */
-#endif
-
-#if (MCA_INCLUDED == TRUE)
-#include "mca_api.h"
-#include "mca_defs.h"
-#include "mca_int.h"
-#endif
-
-#include "bta_sys.h"
-#include "btm_ble_int.h"
-#include "gatt_int.h"
-#include "smp_int.h"
-
-/* Define BTU storage area
-*/
+/* Define BTU storage area */
uint8_t btu_trace_level = HCI_INITIAL_TRACE_LEVEL;
-// Communication queue between btu_task and bta.
-extern fixed_queue_t* btu_bta_msg_queue;
-
-// Communication queue between btu_task and hci.
-extern fixed_queue_t* btu_hci_msg_queue;
-
// General timer queue.
extern fixed_queue_t* btu_general_alarm_queue;
-extern fixed_queue_t* event_queue;
-extern fixed_queue_t* btif_msg_queue;
-
extern thread_t* bt_workqueue_thread;
-static void btu_hci_msg_process(BT_HDR* p_msg);
+static base::MessageLoop* message_loop_ = NULL;
+static base::RunLoop* run_loop_ = NULL;
+static thread_t* message_loop_thread_;
-void btu_hci_msg_ready(fixed_queue_t* queue, UNUSED_ATTR void* context) {
- BT_HDR* p_msg = (BT_HDR*)fixed_queue_dequeue(queue);
- btu_hci_msg_process(p_msg);
-}
-
-void btu_bta_msg_ready(fixed_queue_t* queue, UNUSED_ATTR void* context) {
- BT_HDR* p_msg = (BT_HDR*)fixed_queue_dequeue(queue);
- bta_sys_event(p_msg);
-}
-
-static void btu_hci_msg_process(BT_HDR* p_msg) {
+void btu_hci_msg_process(BT_HDR* p_msg) {
/* Determine the input message type. */
switch (p_msg->event & BT_EVT_MASK) {
- case BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK: // TODO(zachoverflow): remove
- // this
- ((post_to_task_hack_t*)(&p_msg->data[0]))->callback(p_msg);
- break;
case BT_EVT_TO_BTU_HCI_ACL:
/* All Acl Data goes to L2CAP */
l2c_rcv_acl_data(p_msg);
@@ -144,14 +84,28 @@
}
}
+base::MessageLoop* get_message_loop() { return message_loop_; }
+
+void btu_message_loop_run(UNUSED_ATTR void* context) {
+ message_loop_ = new base::MessageLoop();
+ run_loop_ = new base::RunLoop();
+
+ // Inform the bt jni thread initialization is ok.
+ message_loop_->task_runner()->PostTask(
+ FROM_HERE, base::Bind(base::IgnoreResult(&btif_transfer_context),
+ btif_init_ok, 0, nullptr, 0, nullptr));
+
+ run_loop_->Run();
+
+ delete message_loop_;
+ message_loop_ = NULL;
+
+ delete run_loop_;
+ run_loop_ = NULL;
+}
+
void btu_task_start_up(UNUSED_ATTR void* context) {
- BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_API,
- "btu_task pending for preload complete event");
-
- LOG_INFO(LOG_TAG, "Bluetooth chip preload is complete");
-
- BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_API,
- "btu_task received preload complete event");
+ LOG(INFO) << "Bluetooth chip preload is complete";
/* Initialize the mandatory core stack control blocks
(BTU, BTM, L2CAP, and SDP)
@@ -170,23 +124,18 @@
*/
module_init(get_module(BTE_LOGMSG_MODULE));
- // Inform the bt jni thread initialization is ok.
- btif_transfer_context(btif_init_ok, 0, NULL, 0, NULL);
-
- fixed_queue_register_dequeue(btu_bta_msg_queue,
- thread_get_reactor(bt_workqueue_thread),
- btu_bta_msg_ready, NULL);
-
- fixed_queue_register_dequeue(btu_hci_msg_queue,
- thread_get_reactor(bt_workqueue_thread),
- btu_hci_msg_ready, NULL);
+ message_loop_thread_ = thread_new("btu message loop");
+ thread_post(message_loop_thread_, btu_message_loop_run, nullptr);
alarm_register_processing_queue(btu_general_alarm_queue, bt_workqueue_thread);
}
void btu_task_shut_down(UNUSED_ATTR void* context) {
- fixed_queue_unregister_dequeue(btu_bta_msg_queue);
- fixed_queue_unregister_dequeue(btu_hci_msg_queue);
+ // Shutdown message loop on task completed
+ if (run_loop_ && message_loop_) {
+ message_loop_->task_runner()->PostTask(FROM_HERE, run_loop_->QuitClosure());
+ }
+
alarm_unregister_processing_queue(btu_general_alarm_queue);
module_clean_up(get_module(BTE_LOGMSG_MODULE));
diff --git a/stack/gap/gap_api.cc b/stack/gap/gap_api.cc
deleted file mode 100644
index 994ba65..0000000
--- a/stack/gap/gap_api.cc
+++ /dev/null
@@ -1,69 +0,0 @@
-/******************************************************************************
- *
- * 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 "bt_utils.h"
-#include "gap_int.h"
-
-tGAP_CB gap_cb;
-
-/*******************************************************************************
- *
- * 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_t GAP_SetTraceLevel(uint8_t 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));
-
-#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
-
-#if (GAP_CONN_INCLUDED == TRUE)
- gap_conn_init();
-#endif
-
- gap_attr_db_init();
-}
diff --git a/stack/gap/gap_ble.cc b/stack/gap/gap_ble.cc
index 3c8de00..37c91f5 100644
--- a/stack/gap/gap_ble.cc
+++ b/stack/gap/gap_ble.cc
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright (C) 2009-2013 Broadcom Corporation
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,206 +15,118 @@
* limitations under the License.
*
******************************************************************************/
-#include "bt_target.h"
+#include <base/logging.h>
+#include <base/strings/stringprintf.h>
#include <string.h>
-#include "bt_utils.h"
-#include "btcore/include/uuid.h"
-#include "btm_int.h"
+#include <array>
+#include <list>
+#include <queue>
#include "gap_api.h"
-#include "gap_int.h"
#include "gatt_api.h"
-#include "gatt_int.h"
-#include "gattdefs.h"
-#include "hcimsgs.h"
-#include "osi/include/osi.h"
-#define GAP_CHAR_ICON_SIZE 2
-#define GAP_CHAR_DEV_NAME_SIZE 248
-#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)
+using base::StringPrintf;
-#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
+namespace {
-static void gap_ble_s_attr_request_cback(uint16_t conn_id, uint32_t trans_id,
- tGATTS_REQ_TYPE op_code,
- tGATTS_DATA* p_data);
+typedef struct {
+ uint16_t uuid;
+ tGAP_BLE_CMPL_CBACK* p_cback;
+} tGAP_REQUEST;
-/* client connection callback */
-static void gap_ble_c_connect_cback(tGATT_IF gatt_if, BD_ADDR bda,
- uint16_t conn_id, bool connected,
- tGATT_DISCONN_REASON reason,
- tGATT_TRANSPORT transport);
-static void gap_ble_c_cmpl_cback(uint16_t conn_id, tGATTC_OPTYPE op,
- tGATT_STATUS status,
- tGATT_CL_COMPLETE* p_data);
+typedef struct {
+ BD_ADDR bda;
+ tGAP_BLE_CMPL_CBACK* p_cback;
+ uint16_t conn_id;
+ uint16_t cl_op_uuid;
+ bool connected;
+ std::queue<tGAP_REQUEST> requests;
+} tGAP_CLCB;
-static tGATT_CBACK gap_cback = {gap_ble_c_connect_cback,
- gap_ble_c_cmpl_cback,
- NULL,
- NULL,
- gap_ble_s_attr_request_cback,
- NULL,
- NULL,
- NULL,
- NULL};
+typedef struct {
+ uint16_t handle;
+ uint16_t uuid;
+ tGAP_BLE_ATTR_VALUE attr_value;
+} tGAP_ATTR;
-/*******************************************************************************
- *
- * 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_t i_clcb;
- tGAP_CLCB* p_clcb = NULL;
+void server_attr_request_cback(uint16_t, uint32_t, tGATTS_REQ_TYPE,
+ tGATTS_DATA*);
+void client_connect_cback(tGATT_IF, BD_ADDR, uint16_t, bool,
+ tGATT_DISCONN_REASON, tGATT_TRANSPORT);
+void client_cmpl_cback(uint16_t, tGATTC_OPTYPE, tGATT_STATUS,
+ tGATT_CL_COMPLETE*);
- 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;
+tGATT_CBACK gap_cback = {client_connect_cback,
+ client_cmpl_cback,
+ NULL,
+ NULL,
+ server_attr_request_cback,
+ NULL,
+ NULL,
+ NULL,
+ NULL};
+
+constexpr int GAP_CHAR_DEV_NAME_SIZE = BD_NAME_LEN;
+constexpr int GAP_MAX_CHAR_NUM = 4;
+
+std::vector<tGAP_CLCB> gap_clcbs;
+/* LE GAP attribute database */
+std::array<tGAP_ATTR, GAP_MAX_CHAR_NUM> gatt_attr;
+tGATT_IF gatt_if;
+
+/** returns LCB with macthing bd address, or nullptr */
+tGAP_CLCB* find_clcb_by_bd_addr(BD_ADDR bda) {
+ for (auto& cb : gap_clcbs)
+ if (!memcmp(cb.bda, bda, BD_ADDR_LEN)) return &cb;
+
+ return nullptr;
+}
+
+/** returns LCB with macthing connection ID, or nullptr if not found */
+tGAP_CLCB* ble_find_clcb_by_conn_id(uint16_t conn_id) {
+ for (auto& cb : gap_clcbs)
+ if (cb.connected && cb.conn_id == conn_id) return &cb;
+
+ return nullptr;
+}
+
+/** allocates a GAP connection link control block */
+tGAP_CLCB* clcb_alloc(BD_ADDR bda) {
+ gap_clcbs.emplace_back();
+ tGAP_CLCB& cb = gap_clcbs.back();
+
+ memcpy(cb.bda, bda, BD_ADDR_LEN);
+ return &cb;
+}
+
+/** The function clean up the pending request queue in GAP */
+void clcb_dealloc(tGAP_CLCB& clcb) {
+ // put last element into place of current element, and remove last one - just
+ // fast remove.
+ for (auto it = gap_clcbs.begin(); it != gap_clcbs.end(); it++) {
+ if (it->conn_id == clcb.conn_id) {
+ auto last_one = std::prev(gap_clcbs.end());
+ *it = *last_one;
+ gap_clcbs.erase(last_one);
+ return;
}
}
-
- return NULL;
}
-/* returns LCB with matching connection ID, or NULL if not found */
-tGAP_CLCB* gap_ble_find_clcb_by_conn_id(uint16_t conn_id) {
- uint8_t 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 NULL;
-}
-
-/*******************************************************************************
- *
- * 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(BD_ADDR bda) {
- uint8_t 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) {
- fixed_queue_free(p_clcb->pending_req_q, NULL);
- memset(p_clcb, 0, sizeof(tGAP_CLCB));
- p_clcb->in_use = true;
- memcpy(p_clcb->bda, bda, BD_ADDR_LEN);
- p_clcb->pending_req_q = fixed_queue_new(SIZE_MAX);
- return p_clcb;
- }
- }
- return NULL;
-}
-
-/*******************************************************************************
- *
- * Function gap_ble_dealloc_clcb
- *
- * Description The function clean up the pending request queue in GAP
- *
- * Returns none
- *
- ******************************************************************************/
-void gap_ble_dealloc_clcb(tGAP_CLCB* p_clcb) {
- tGAP_BLE_REQ* p_q;
-
- while ((p_q = (tGAP_BLE_REQ*)fixed_queue_try_dequeue(
- p_clcb->pending_req_q)) != NULL) {
- /* send callback to all pending requests if being removed*/
- if (p_q->p_cback != NULL) (*p_q->p_cback)(false, p_clcb->bda, 0, NULL);
-
- osi_free(p_q);
- }
- fixed_queue_free(p_clcb->pending_req_q, NULL);
-
- memset(p_clcb, 0, sizeof(tGAP_CLCB));
-}
-
-/*******************************************************************************
- *
- * Function gap_ble_enqueue_request
- *
- * Description The function enqueue a GAP client request
- *
- * Returns true is successul; false otherwise
- *
- ******************************************************************************/
-bool gap_ble_enqueue_request(tGAP_CLCB* p_clcb, uint16_t uuid,
- tGAP_BLE_CMPL_CBACK* p_cback) {
- tGAP_BLE_REQ* p_q = (tGAP_BLE_REQ*)osi_malloc(sizeof(tGAP_BLE_REQ));
-
- p_q->p_cback = p_cback;
- p_q->uuid = uuid;
- fixed_queue_enqueue(p_clcb->pending_req_q, p_q);
-
- return true;
-}
-
-/*******************************************************************************
- *
- * Function gap_ble_dequeue_request
- *
- * Description The function dequeue a GAP client request if any
- *
- * Returns true is successul; false otherwise
- *
- ******************************************************************************/
-bool gap_ble_dequeue_request(tGAP_CLCB* p_clcb, uint16_t* p_uuid,
- tGAP_BLE_CMPL_CBACK** p_cback) {
- tGAP_BLE_REQ* p_q =
- (tGAP_BLE_REQ*)fixed_queue_try_dequeue(p_clcb->pending_req_q);
- ;
-
- if (p_q != NULL) {
- *p_cback = p_q->p_cback;
- *p_uuid = p_q->uuid;
- osi_free(p_q);
- return true;
- }
-
- return false;
-}
-
-/*******************************************************************************
- * GAP Attributes Database Request callback
- ******************************************************************************/
-tGATT_STATUS gap_read_attr_value(uint16_t handle, tGATT_VALUE* p_value,
- bool is_long) {
- tGAP_ATTR* p_db_attr = gap_cb.gatt_attr;
- uint8_t *p = p_value->value, i;
+/** GAP Attributes Database Request callback */
+tGATT_STATUS read_attr_value(uint16_t handle, tGATT_VALUE* p_value,
+ bool is_long) {
+ uint8_t* p = p_value->value;
uint16_t offset = p_value->offset;
uint8_t* 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)
+ for (const tGAP_ATTR& db_attr : gatt_attr) {
+ const tGAP_BLE_ATTR_VALUE& attr_value = db_attr.attr_value;
+ if (handle == db_attr.handle) {
+ if (db_attr.uuid != GATT_UUID_GAP_DEVICE_NAME && is_long == true)
return GATT_NOT_LONG;
- switch (p_db_attr->uuid) {
+ switch (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)
@@ -228,31 +140,26 @@
p_value->len -= offset;
p_dev_name += offset;
ARRAY_TO_STREAM(p, p_dev_name, p_value->len);
- GAP_TRACE_EVENT("GATT_UUID_GAP_DEVICE_NAME len=0x%04x",
- p_value->len);
+ DVLOG(1) << "GATT_UUID_GAP_DEVICE_NAME len=" << +p_value->len;
}
break;
case GATT_UUID_GAP_ICON:
- UINT16_TO_STREAM(p, p_db_attr->attr_value.icon);
+ UINT16_TO_STREAM(p, attr_value.icon);
p_value->len = 2;
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 */
+ UINT16_TO_STREAM(p, attr_value.conn_param.int_min); /* int_min */
+ UINT16_TO_STREAM(p, attr_value.conn_param.int_max); /* int_max */
+ UINT16_TO_STREAM(p, attr_value.conn_param.latency); /* latency */
+ UINT16_TO_STREAM(p, attr_value.conn_param.sp_tout); /* sp_tout */
p_value->len = 8;
break;
/* address resolution */
case GATT_UUID_GAP_CENTRAL_ADDR_RESOL:
- UINT8_TO_STREAM(p, p_db_attr->attr_value.addr_resolution);
+ UINT8_TO_STREAM(p, attr_value.addr_resolution);
p_value->len = 1;
break;
}
@@ -262,95 +169,223 @@
return GATT_NOT_FOUND;
}
-/*******************************************************************************
- * GAP Attributes Database Read/Read Blob Request process
- ******************************************************************************/
-tGATT_STATUS gap_proc_read(UNUSED_ATTR tGATTS_REQ_TYPE type,
- tGATT_READ_REQ* p_data, tGATTS_RSP* p_rsp) {
- tGATT_STATUS status = GATT_NO_RESOURCES;
-
+/** GAP Attributes Database Read/Read Blob Request process */
+tGATT_STATUS proc_read(tGATTS_REQ_TYPE, tGATT_READ_REQ* p_data,
+ tGATTS_RSP* p_rsp) {
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;
+ return read_attr_value(p_data->handle, &p_rsp->attr_value, p_data->is_long);
}
-/******************************************************************************
- *
- * Function gap_proc_write_req
- *
- * Description GAP ATT server process a write request.
- *
- * Returns void.
- *
- ******************************************************************************/
-uint8_t gap_proc_write_req(UNUSED_ATTR tGATTS_REQ_TYPE type,
- tGATT_WRITE_REQ* p_data) {
- tGAP_ATTR* p_db_attr = gap_cb.gatt_attr;
- uint8_t i;
+/** GAP ATT server process a write request */
+uint8_t proc_write_req(tGATTS_REQ_TYPE, tGATT_WRITE_REQ* p_data) {
+ for (const auto& db_addr : gatt_attr)
+ if (p_data->handle == db_addr.handle) return GATT_WRITE_NOT_PERMIT;
- for (i = 0; i < GAP_MAX_CHAR_NUM; i++, p_db_attr++) {
- if (p_data->handle == p_db_attr->handle) {
- 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_t conn_id, uint32_t trans_id,
- tGATTS_REQ_TYPE type, tGATTS_DATA* p_data) {
+/** GAP ATT server attribute access request callback */
+void server_attr_request_cback(uint16_t conn_id, uint32_t trans_id,
+ tGATTS_REQ_TYPE type, tGATTS_DATA* p_data) {
uint8_t status = GATT_INVALID_PDU;
- tGATTS_RSP rsp_msg;
bool ignore = false;
- GAP_TRACE_EVENT("gap_ble_s_attr_request_cback : recv type (0x%02x)", type);
+ DVLOG(1) << StringPrintf("%s: recv type (0x%02x)", __func__, type);
+ tGATTS_RSP rsp_msg;
memset(&rsp_msg, 0, sizeof(tGATTS_RSP));
switch (type) {
case GATTS_REQ_TYPE_READ_CHARACTERISTIC:
case GATTS_REQ_TYPE_READ_DESCRIPTOR:
- status = gap_proc_read(type, &p_data->read_req, &rsp_msg);
+ status = proc_read(type, &p_data->read_req, &rsp_msg);
break;
case GATTS_REQ_TYPE_WRITE_CHARACTERISTIC:
case GATTS_REQ_TYPE_WRITE_DESCRIPTOR:
if (!p_data->write_req.need_rsp) ignore = true;
- status = gap_proc_write_req(type, &p_data->write_req);
+ status = proc_write_req(type, &p_data->write_req);
break;
case GATTS_REQ_TYPE_WRITE_EXEC:
ignore = true;
- GAP_TRACE_EVENT("Ignore GATTS_REQ_TYPE_WRITE_EXEC");
+ DVLOG(1) << "Ignore GATTS_REQ_TYPE_WRITE_EXEC";
break;
case GATTS_REQ_TYPE_MTU:
- GAP_TRACE_EVENT("Get MTU exchange new mtu size: %d", p_data->mtu);
+ DVLOG(1) << "Get MTU exchange new mtu size: " << +p_data->mtu;
ignore = true;
break;
default:
- GAP_TRACE_EVENT("Unknown/unexpected LE GAP ATT request: 0x%02x", type);
+ DVLOG(1) << StringPrintf("Unknown/unexpected LE GAP ATT request: 0x%02x",
+ type);
break;
}
if (!ignore) GATTS_SendRsp(conn_id, trans_id, status, &rsp_msg);
}
+/**
+ * utility function to send a read request for a GAP charactersitic.
+ * Returns true if read started, else false if GAP is busy.
+ */
+bool send_cl_read_request(tGAP_CLCB& clcb) {
+ if (!clcb.requests.size()) {
+ return false;
+ }
+
+ tGAP_REQUEST& req = clcb.requests.front();
+ clcb.p_cback = req.p_cback;
+ uint16_t uuid = req.uuid;
+ clcb.requests.pop();
+
+ 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(clcb.conn_id, GATT_READ_BY_TYPE, ¶m) == GATT_SUCCESS) {
+ clcb.cl_op_uuid = uuid;
+ }
+
+ return true;
+}
+
+/** GAP client operation complete callback */
+void cl_op_cmpl(tGAP_CLCB& clcb, bool status, uint16_t len, uint8_t* p_name) {
+ tGAP_BLE_CMPL_CBACK* p_cback = clcb.p_cback;
+ uint16_t op = clcb.cl_op_uuid;
+
+ DVLOG(1) << StringPrintf("%s: status: %d", __func__, status);
+
+ clcb.cl_op_uuid = 0;
+ clcb.p_cback = NULL;
+
+ if (p_cback && op) {
+ DVLOG(1) << __func__ << ": calling";
+ (*p_cback)(status, clcb.bda, len, (char*)p_name);
+ }
+
+ /* if no further activity is requested in callback, drop the link */
+ if (clcb.connected) {
+ if (!send_cl_read_request(clcb)) {
+ GATT_Disconnect(clcb.conn_id);
+ clcb_dealloc(clcb);
+ }
+ }
+}
+
+/** Client connection callback */
+void client_connect_cback(tGATT_IF, BD_ADDR bda, uint16_t conn_id,
+ bool connected, tGATT_DISCONN_REASON reason,
+ tGATT_TRANSPORT) {
+ tGAP_CLCB* p_clcb = find_clcb_by_bd_addr(bda);
+ if (p_clcb == NULL) return;
+
+ if (connected) {
+ p_clcb->conn_id = conn_id;
+ p_clcb->connected = true;
+ /* start operation is pending */
+ send_cl_read_request(*p_clcb);
+ } else {
+ p_clcb->connected = false;
+ cl_op_cmpl(*p_clcb, false, 0, NULL);
+ /* clean up clcb */
+ clcb_dealloc(*p_clcb);
+ }
+}
+
+/** Client operation complete callback */
+void client_cmpl_cback(uint16_t conn_id, tGATTC_OPTYPE op, tGATT_STATUS status,
+ tGATT_CL_COMPLETE* p_data) {
+ tGAP_CLCB* p_clcb = ble_find_clcb_by_conn_id(conn_id);
+ uint16_t op_type;
+ uint16_t min, max, latency, tout;
+ uint16_t len;
+ uint8_t* pp;
+
+ if (p_clcb == NULL) return;
+
+ op_type = p_clcb->cl_op_uuid;
+
+ DVLOG(1) << StringPrintf(
+ "%s: - op_code: 0x%02x status: 0x%02x read_type: 0x%04x", __func__, op,
+ status, op_type);
+ /* Currently we only issue read commands */
+ if (op != GATTC_OPTYPE_READ) return;
+
+ if (status != GATT_SUCCESS) {
+ 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:
+ /* 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 */
+ cl_op_cmpl(*p_clcb, true, 0, NULL);
+ break;
+
+ case GATT_UUID_GAP_DEVICE_NAME:
+ len = (uint16_t)strlen((char*)pp);
+ if (len > GAP_CHAR_DEV_NAME_SIZE) len = GAP_CHAR_DEV_NAME_SIZE;
+ cl_op_cmpl(*p_clcb, true, len, pp);
+ break;
+
+ case GATT_UUID_GAP_CENTRAL_ADDR_RESOL:
+ cl_op_cmpl(*p_clcb, true, 1, pp);
+ break;
+ }
+}
+
+bool accept_client_operation(BD_ADDR peer_bda, uint16_t uuid,
+ tGAP_BLE_CMPL_CBACK* p_cback) {
+ if (p_cback == NULL && uuid != GATT_UUID_GAP_PREF_CONN_PARAM) return false;
+
+ tGAP_CLCB* p_clcb = find_clcb_by_bd_addr(peer_bda);
+ if (p_clcb == NULL) {
+ p_clcb = clcb_alloc(peer_bda);
+ }
+
+ DVLOG(1) << StringPrintf("%s() - BDA: %08x%04x cl_op_uuid: 0x%04x", __func__,
+ (peer_bda[0] << 24) + (peer_bda[1] << 16) +
+ (peer_bda[2] << 8) + peer_bda[3],
+ (peer_bda[4] << 8) + peer_bda[5], uuid);
+
+ if (GATT_GetConnIdIfConnected(gatt_if, peer_bda, &p_clcb->conn_id,
+ BT_TRANSPORT_LE))
+ p_clcb->connected = true;
+
+ if (!GATT_Connect(gatt_if, p_clcb->bda, true, BT_TRANSPORT_LE, true))
+ return false;
+
+ /* enqueue the request */
+ p_clcb->requests.push({.uuid = uuid, .p_cback = p_cback});
+
+ if (p_clcb->connected && p_clcb->cl_op_uuid == 0)
+ return send_cl_read_request(*p_clcb);
+ else /* wait for connection up or pending operation to finish */
+ return true;
+}
+
+} // namespace
+
/*******************************************************************************
*
* Function btm_ble_att_db_init
@@ -366,11 +401,11 @@
/* 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);
+ gatt_attr.fill({});
- gap_cb.gatt_if = GATT_Register(&app_uuid, &gap_cback);
+ gatt_if = GATT_Register(&app_uuid, &gap_cback);
- GATT_StartIf(gap_cb.gatt_if);
+ GATT_StartIf(gatt_if);
bt_uuid_t svc_uuid, name_uuid, icon_uuid, pref_uuid, addr_res_uuid;
uuid_128_from_16(&svc_uuid, UUID_SERVCLASS_GAP_SERVER);
@@ -403,34 +438,31 @@
};
/* Add a GAP service */
- GATTS_AddService(gap_cb.gatt_if, service,
+ GATTS_AddService(gatt_if, service,
sizeof(service) / sizeof(btgatt_db_element_t));
service_handle = service[0].attribute_handle;
- GAP_TRACE_EVENT("%s: service_handle = %d", __func__, service_handle);
+ DVLOG(1) << __func__ << ": service_handle = " << +service_handle;
- gap_cb.gatt_attr[0].uuid = GATT_UUID_GAP_DEVICE_NAME;
- gap_cb.gatt_attr[0].handle = service[1].attribute_handle;
+ gatt_attr[0].uuid = GATT_UUID_GAP_DEVICE_NAME;
+ gatt_attr[0].handle = service[1].attribute_handle;
- gap_cb.gatt_attr[1].uuid = GATT_UUID_GAP_ICON;
- gap_cb.gatt_attr[1].handle = service[2].attribute_handle;
+ gatt_attr[1].uuid = GATT_UUID_GAP_ICON;
+ gatt_attr[1].handle = service[2].attribute_handle;
- gap_cb.gatt_attr[2].uuid = GATT_UUID_GAP_CENTRAL_ADDR_RESOL;
- gap_cb.gatt_attr[2].handle = service[3].attribute_handle;
- gap_cb.gatt_attr[2].attr_value.addr_resolution = 0;
+ gatt_attr[2].uuid = GATT_UUID_GAP_CENTRAL_ADDR_RESOL;
+ gatt_attr[2].handle = service[3].attribute_handle;
+ gatt_attr[2].attr_value.addr_resolution = 0;
#if (BTM_PERIPHERAL_ENABLED == TRUE) /* Only needed for peripheral testing */
- gap_cb.gatt_attr[3].uuid = GATT_UUID_GAP_PREF_CONN_PARAM;
- gap_cb.gatt_attr[3].attr_value.conn_param.int_max =
- GAP_PREFER_CONN_INT_MAX; /* 6 */
- gap_cb.gatt_attr[3].attr_value.conn_param.int_min =
- GAP_PREFER_CONN_INT_MIN; /* 0 */
- gap_cb.gatt_attr[3].attr_value.conn_param.latency =
- GAP_PREFER_CONN_LATENCY; /* 0 */
- gap_cb.gatt_attr[3].attr_value.conn_param.sp_tout =
+ gatt_attr[3].uuid = GATT_UUID_GAP_PREF_CONN_PARAM;
+ gatt_attr[3].attr_value.conn_param.int_max = GAP_PREFER_CONN_INT_MAX; /* 6 */
+ gatt_attr[3].attr_value.conn_param.int_min = GAP_PREFER_CONN_INT_MIN; /* 0 */
+ gatt_attr[3].attr_value.conn_param.latency = GAP_PREFER_CONN_LATENCY; /* 0 */
+ gatt_attr[3].attr_value.conn_param.sp_tout =
GAP_PREFER_CONN_SP_TOUT; /* 2000 */
- gap_cb.gatt_attr[3].handle = service[4].attribute_handle;
+ gatt_attr[3].handle = service[4].attribute_handle;
#endif
}
@@ -440,26 +472,21 @@
*
* Description GAP ATT database update.
*
- * Returns void.
- *
******************************************************************************/
void GAP_BleAttrDBUpdate(uint16_t attr_uuid, tGAP_BLE_ATTR_VALUE* p_value) {
- tGAP_ATTR* p_db_attr = gap_cb.gatt_attr;
- uint8_t i = 0;
+ DVLOG(1) << StringPrintf("%s: attr_uuid=0x%04x", __func__, attr_uuid);
- GAP_TRACE_EVENT("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_EVENT("Found attr_uuid=0x%04x", attr_uuid);
+ for (tGAP_ATTR& db_attr : gatt_attr) {
+ if (db_attr.uuid == attr_uuid) {
+ DVLOG(1) << StringPrintf("Found attr_uuid=0x%04x", attr_uuid);
switch (attr_uuid) {
case GATT_UUID_GAP_ICON:
- p_db_attr->attr_value.icon = p_value->icon;
+ 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,
+ memcpy((void*)&db_attr.attr_value.conn_param,
(const void*)&p_value->conn_param,
sizeof(tGAP_BLE_PREF_PARAM));
break;
@@ -469,7 +496,7 @@
break;
case GATT_UUID_GAP_CENTRAL_ADDR_RESOL:
- p_db_attr->attr_value.addr_resolution = p_value->addr_resolution;
+ db_attr.attr_value.addr_resolution = p_value->addr_resolution;
break;
}
break;
@@ -481,216 +508,6 @@
/*******************************************************************************
*
- * Function gap_ble_send_cl_read_request
- *
- * Description utility function to send a read request for a GAP
- * charactersitic
- *
- * Returns true if read started, else false if GAP is busy
- *
- ******************************************************************************/
-bool gap_ble_send_cl_read_request(tGAP_CLCB* p_clcb) {
- tGATT_READ_PARAM param;
- uint16_t uuid = 0;
- bool started = false;
-
- if (gap_ble_dequeue_request(p_clcb, &uuid, &p_clcb->p_cback)) {
- 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) {
- p_clcb->cl_op_uuid = uuid;
- started = true;
- }
- }
-
- return started;
-}
-
-/*******************************************************************************
- *
- * Function gap_ble_cl_op_cmpl
- *
- * Description GAP client operation complete callback
- *
- * Returns void
- *
- ******************************************************************************/
-void gap_ble_cl_op_cmpl(tGAP_CLCB* p_clcb, bool status, uint16_t len,
- uint8_t* p_name) {
- tGAP_BLE_CMPL_CBACK* p_cback = p_clcb->p_cback;
- uint16_t op = p_clcb->cl_op_uuid;
-
- GAP_TRACE_EVENT("gap_ble_cl_op_cmpl status: %d", status);
-
- p_clcb->cl_op_uuid = 0;
- p_clcb->p_cback = NULL;
-
- if (p_cback && op) {
- GAP_TRACE_EVENT("calling gap_ble_cl_op_cmpl");
- (*p_cback)(status, p_clcb->bda, len, (char*)p_name);
- }
-
- /* if no further activity is requested in callback, drop the link */
- if (p_clcb->connected) {
- if (!gap_ble_send_cl_read_request(p_clcb)) {
- GATT_Disconnect(p_clcb->conn_id);
- gap_ble_dealloc_clcb(p_clcb);
- }
- }
-}
-
-/*******************************************************************************
- *
- * Function gap_ble_c_connect_cback
- *
- * Description Client connection callback.
- *
- * Returns void
- *
- ******************************************************************************/
-static void gap_ble_c_connect_cback(UNUSED_ATTR tGATT_IF gatt_if, BD_ADDR bda,
- uint16_t conn_id, bool connected,
- tGATT_DISCONN_REASON reason,
- UNUSED_ATTR tGATT_TRANSPORT transport) {
- tGAP_CLCB* p_clcb = gap_find_clcb_by_bd_addr(bda);
-
- if (p_clcb != NULL) {
- if (connected) {
- p_clcb->conn_id = conn_id;
- p_clcb->connected = true;
- /* start operation is pending */
- gap_ble_send_cl_read_request(p_clcb);
- } else {
- p_clcb->connected = false;
- gap_ble_cl_op_cmpl(p_clcb, false, 0, NULL);
- /* clean up clcb */
- gap_ble_dealloc_clcb(p_clcb);
- }
- }
-}
-
-/*******************************************************************************
- *
- * Function gap_ble_c_cmpl_cback
- *
- * Description Client operation complete callback.
- *
- * Returns void
- *
- ******************************************************************************/
-static void gap_ble_c_cmpl_cback(uint16_t 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_t op_type;
- uint16_t min, max, latency, tout;
- uint16_t len;
- uint8_t* pp;
-
- if (p_clcb == NULL) return;
-
- op_type = p_clcb->cl_op_uuid;
-
- GAP_TRACE_EVENT(
- "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) 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_EVENT("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_EVENT("GATT_UUID_GAP_DEVICE_NAME");
- len = (uint16_t)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_CENTRAL_ADDR_RESOL:
- gap_ble_cl_op_cmpl(p_clcb, true, 1, pp);
- break;
- }
-}
-
-/*******************************************************************************
- *
- * Function gap_ble_accept_cl_operation
- *
- * Description Start a process to read peer address resolution capability
- *
- * Returns true if request accepted
- *
- ******************************************************************************/
-bool gap_ble_accept_cl_operation(BD_ADDR peer_bda, uint16_t uuid,
- tGAP_BLE_CMPL_CBACK* p_cback) {
- tGAP_CLCB* p_clcb;
- bool started = false;
-
- if (p_cback == NULL && uuid != GATT_UUID_GAP_PREF_CONN_PARAM)
- return (started);
-
- p_clcb = gap_find_clcb_by_bd_addr(peer_bda);
- if (p_clcb == NULL) {
- p_clcb = gap_clcb_alloc(peer_bda);
- if (p_clcb == NULL) {
- GAP_TRACE_ERROR("gap_ble_accept_cl_operation max connection reached");
- return started;
- }
- }
-
- GAP_TRACE_EVENT("%s() - BDA: %08x%04x cl_op_uuid: 0x%04x", __func__,
- (peer_bda[0] << 24) + (peer_bda[1] << 16) +
- (peer_bda[2] << 8) + peer_bda[3],
- (peer_bda[4] << 8) + peer_bda[5], uuid);
-
- if (GATT_GetConnIdIfConnected(gap_cb.gatt_if, peer_bda, &p_clcb->conn_id,
- BT_TRANSPORT_LE))
- p_clcb->connected = true;
-
- if (!GATT_Connect(gap_cb.gatt_if, p_clcb->bda, true, BT_TRANSPORT_LE, true))
- return started;
-
- /* enqueue the request */
- gap_ble_enqueue_request(p_clcb, uuid, p_cback);
-
- if (p_clcb->connected && p_clcb->cl_op_uuid == 0)
- started = gap_ble_send_cl_read_request(p_clcb);
- else /* wait for connection up or pending operation to finish */
- started = true;
-
- return started;
-}
-/*******************************************************************************
- *
* Function GAP_BleReadPeerPrefConnParams
*
* Description Start a process to read a connected peripheral's preferred
@@ -700,8 +517,7 @@
*
******************************************************************************/
bool GAP_BleReadPeerPrefConnParams(BD_ADDR peer_bda) {
- return gap_ble_accept_cl_operation(peer_bda, GATT_UUID_GAP_PREF_CONN_PARAM,
- NULL);
+ return accept_client_operation(peer_bda, GATT_UUID_GAP_PREF_CONN_PARAM, NULL);
}
/*******************************************************************************
@@ -715,8 +531,7 @@
*
******************************************************************************/
bool GAP_BleReadPeerDevName(BD_ADDR peer_bda, tGAP_BLE_CMPL_CBACK* p_cback) {
- return gap_ble_accept_cl_operation(peer_bda, GATT_UUID_GAP_DEVICE_NAME,
- p_cback);
+ return accept_client_operation(peer_bda, GATT_UUID_GAP_DEVICE_NAME, p_cback);
}
/*******************************************************************************
@@ -730,8 +545,8 @@
******************************************************************************/
bool GAP_BleReadPeerAddressResolutionCap(BD_ADDR peer_bda,
tGAP_BLE_CMPL_CBACK* p_cback) {
- return gap_ble_accept_cl_operation(peer_bda, GATT_UUID_GAP_CENTRAL_ADDR_RESOL,
- p_cback);
+ return accept_client_operation(peer_bda, GATT_UUID_GAP_CENTRAL_ADDR_RESOL,
+ p_cback);
}
/*******************************************************************************
@@ -744,28 +559,27 @@
*
******************************************************************************/
bool GAP_BleCancelReadPeerDevName(BD_ADDR peer_bda) {
- tGAP_CLCB* p_clcb = gap_find_clcb_by_bd_addr(peer_bda);
+ tGAP_CLCB* p_clcb = find_clcb_by_bd_addr(peer_bda);
- GAP_TRACE_EVENT(
- "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);
+ DVLOG(1) << StringPrintf("%s: BDA: %08x%04x cl_op_uuid: 0x%04x", __func__,
+ (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) {
- GAP_TRACE_ERROR("Cannot cancel current op is not get dev name");
+ LOG(ERROR) << "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_ERROR("Cannot cancel where No connection id");
+ if (!GATT_CancelConnect(gatt_if, peer_bda, true)) {
+ LOG(ERROR) << "Cannot cancel where No connection id";
return false;
}
}
- gap_ble_cl_op_cmpl(p_clcb, false, 0, NULL);
+ cl_op_cmpl(*p_clcb, false, 0, NULL);
return (true);
}
diff --git a/stack/gap/gap_conn.cc b/stack/gap/gap_conn.cc
index fcc2161..b05a7b2 100644
--- a/stack/gap/gap_conn.cc
+++ b/stack/gap/gap_conn.cc
@@ -16,17 +16,69 @@
*
******************************************************************************/
+#include <base/strings/stringprintf.h>
#include <string.h>
#include "bt_target.h"
#include "bt_utils.h"
+#include "btm_int.h"
#include "btu.h"
-#include "gap_int.h"
+#include "gap_api.h"
#include "l2c_int.h"
#include "l2cdefs.h"
+#include "osi/include/fixed_queue.h"
#include "osi/include/mutex.h"
-#include "osi/include/osi.h"
-#if (GAP_CONN_INCLUDED == TRUE)
-#include "btm_int.h"
+
+using base::StringPrintf;
+
+/* 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_t 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_t con_flags;
+
+ uint8_t service_id; /* Used by BTM */
+ uint16_t gap_handle; /* GAP handle */
+ uint16_t connection_id; /* L2CAP CID */
+ bool rem_addr_specified;
+ uint8_t chan_mode_mask; /* Supported channel modes (FCR) */
+ BD_ADDR rem_dev_address;
+ uint16_t psm;
+ uint16_t rem_mtu_size;
+
+ bool is_congested;
+ fixed_queue_t* tx_queue; /* Queue of buffers waiting to be sent */
+ fixed_queue_t* rx_queue; /* Queue of buffers waiting to be read */
+
+ uint32_t 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 */
+ tBT_TRANSPORT transport; /* Transport channel BR/EDR or BLE */
+ tL2CAP_LE_CFG_INFO local_coc_cfg; /* local configuration for LE Coc */
+ tL2CAP_LE_CFG_INFO peer_coc_cfg; /* local configuration for LE Coc */
+} tGAP_CCB;
+
+typedef struct {
+ tL2CAP_APPL_INFO reg_info; /* L2CAP Registration info */
+ tGAP_CCB ccb_pool[GAP_MAX_CONNECTIONS];
+} tGAP_CONN;
+
+namespace {
+tGAP_CONN conn;
+}
/******************************************************************************/
/* L O C A L F U N C T I O N P R O T O T Y P E S */
@@ -58,36 +110,18 @@
*
******************************************************************************/
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 = gap_tx_complete_ind;
-#endif
+ memset(&conn, 0, sizeof(tGAP_CONN));
+ conn.reg_info.pL2CA_ConnectInd_Cb = gap_connect_ind;
+ conn.reg_info.pL2CA_ConnectCfm_Cb = gap_connect_cfm;
+ conn.reg_info.pL2CA_ConnectPnd_Cb = NULL;
+ conn.reg_info.pL2CA_ConfigInd_Cb = gap_config_ind;
+ conn.reg_info.pL2CA_ConfigCfm_Cb = gap_config_cfm;
+ conn.reg_info.pL2CA_DisconnectInd_Cb = gap_disconnect_ind;
+ conn.reg_info.pL2CA_DisconnectCfm_Cb = NULL;
+ conn.reg_info.pL2CA_QoSViolationInd_Cb = NULL;
+ conn.reg_info.pL2CA_DataInd_Cb = gap_data_ind;
+ conn.reg_info.pL2CA_CongestionStatus_Cb = gap_congestion_ind;
+ conn.reg_info.pL2CA_TxComplete_Cb = gap_tx_complete_ind;
}
/*******************************************************************************
@@ -133,7 +167,7 @@
tGAP_CCB* p_ccb;
uint16_t cid;
- GAP_TRACE_EVENT("GAP_CONN - Open Request");
+ DVLOG(1) << "GAP_CONN - Open Request";
/* Allocate a new CCB. Return if none available. */
p_ccb = gap_allocate_ccb();
@@ -160,8 +194,8 @@
/* 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_ERROR(
- "GAP ERROR: Client must specify a remote BD ADDR to connect to!");
+ LOG(ERROR)
+ << "GAP ERROR: Client must specify a remote BD ADDR to connect to!";
return (GAP_INVALID_HANDLE);
}
@@ -177,37 +211,30 @@
p_ccb->p_callback = p_cb;
-/* If originator, use a dynamic PSM */
-#if (AMP_INCLUDED == TRUE)
+ /* If originator, use a dynamic PSM */
if (!is_server)
- gap_cb.conn.reg_info.pAMP_ConnectInd_Cb = NULL;
+ conn.reg_info.pL2CA_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
+ conn.reg_info.pL2CA_ConnectInd_Cb = gap_connect_ind;
/* Register the PSM with L2CAP */
if (transport == BT_TRANSPORT_BR_EDR) {
- p_ccb->psm =
- L2CA_REGISTER(psm, &gap_cb.conn.reg_info,
- AMP_AUTOSWITCH_ALLOWED | AMP_USE_AMP_IF_POSSIBLE);
+ p_ccb->psm = L2CA_REGISTER(
+ psm, &conn.reg_info, AMP_AUTOSWITCH_ALLOWED | AMP_USE_AMP_IF_POSSIBLE);
if (p_ccb->psm == 0) {
- GAP_TRACE_ERROR("%s: Failure registering PSM 0x%04x", __func__, psm);
+ LOG(ERROR) << StringPrintf("%s: Failure registering PSM 0x%04x", __func__,
+ psm);
gap_release_ccb(p_ccb);
return (GAP_INVALID_HANDLE);
}
}
if (transport == BT_TRANSPORT_LE) {
- p_ccb->psm =
- L2CA_REGISTER_COC(psm, &gap_cb.conn.reg_info,
- AMP_AUTOSWITCH_ALLOWED | AMP_USE_AMP_IF_POSSIBLE);
+ p_ccb->psm = L2CA_REGISTER_COC(
+ psm, &conn.reg_info, AMP_AUTOSWITCH_ALLOWED | AMP_USE_AMP_IF_POSSIBLE);
if (p_ccb->psm == 0) {
- GAP_TRACE_ERROR("%s: Failure registering PSM 0x%04x", __func__, psm);
+ LOG(ERROR) << StringPrintf("%s: Failure registering PSM 0x%04x", __func__,
+ psm);
gap_release_ccb(p_ccb);
return (GAP_INVALID_HANDLE);
}
@@ -216,7 +243,7 @@
/* Register with Security Manager for the specific security level */
if (!BTM_SetSecurityLevel((uint8_t)!is_server, p_serv_name, p_ccb->service_id,
security, p_ccb->psm, 0, 0)) {
- GAP_TRACE_ERROR("GAP_CONN - Security Error");
+ LOG(ERROR) << "GAP_CONN - Security Error";
gap_release_ccb(p_ccb);
return (GAP_INVALID_HANDLE);
}
@@ -295,7 +322,7 @@
uint16_t GAP_ConnClose(uint16_t gap_handle) {
tGAP_CCB* p_ccb = gap_find_ccb_by_handle(gap_handle);
- GAP_TRACE_EVENT("GAP_CONN - close handle: 0x%x", gap_handle);
+ DVLOG(1) << StringPrintf("GAP_CONN - close handle: 0x%x", gap_handle);
if (p_ccb) {
/* Check if we have a connection ID */
@@ -365,7 +392,7 @@
mutex_global_unlock();
- GAP_TRACE_EVENT("GAP_ConnReadData - rx_queue_size left=%d, *p_len=%d",
+ DVLOG(1) << StringPrintf("GAP_ConnReadData - rx_queue_size left=%d, *p_len=%d",
p_ccb->rx_queue_size, *p_len);
return (BT_PASS);
@@ -388,7 +415,7 @@
/* Check that handle is valid */
if (handle < GAP_MAX_CONNECTIONS) {
- p_ccb = &gap_cb.conn.ccb_pool[handle];
+ p_ccb = &conn.ccb_pool[handle];
if (p_ccb->con_state == GAP_CCB_STATE_CONNECTED) {
*p_rx_queue_count = p_ccb->rx_queue_size;
@@ -397,7 +424,7 @@
} else
rc = GAP_INVALID_HANDLE;
- GAP_TRACE_EVENT("GAP_GetRxQueueCnt - rc = 0x%04x, rx_queue_count=%d", rc,
+ DVLOG(1) << StringPrintf("GAP_GetRxQueueCnt - rc = 0x%04x, rx_queue_count=%d", rc,
*p_rx_queue_count);
return (rc);
@@ -483,7 +510,7 @@
max_len -= p_buf->len;
p_data += p_buf->len;
- GAP_TRACE_EVENT("GAP_WriteData %d bytes", p_buf->len);
+ DVLOG(1) << StringPrintf("GAP_WriteData %d bytes", p_buf->len);
fixed_queue_enqueue(p_ccb->tx_queue, p_buf);
}
@@ -583,10 +610,10 @@
uint8_t* GAP_ConnGetRemoteAddr(uint16_t gap_handle) {
tGAP_CCB* p_ccb = gap_find_ccb_by_handle(gap_handle);
- GAP_TRACE_EVENT("GAP_ConnGetRemoteAddr gap_handle = %d", gap_handle);
+ DVLOG(1) << StringPrintf("GAP_ConnGetRemoteAddr gap_handle = %d", gap_handle);
if ((p_ccb) && (p_ccb->con_state > GAP_CCB_STATE_LISTENING)) {
- GAP_TRACE_EVENT(
+ DVLOG(1) << StringPrintf(
"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],
@@ -594,7 +621,7 @@
p_ccb->rem_dev_address[4], p_ccb->rem_dev_address[5]);
return (p_ccb->rem_dev_address);
} else {
- GAP_TRACE_EVENT("GAP_ConnGetRemoteAddr return Error ");
+ DVLOG(1) << StringPrintf("GAP_ConnGetRemoteAddr return Error ");
return (NULL);
}
}
@@ -656,7 +683,7 @@
if (p_ccb == NULL) return;
if ((p_ccb->con_state == GAP_CCB_STATE_CONNECTED) && (sdu_sent == 0xFFFF)) {
- GAP_TRACE_EVENT("%s: GAP_EVT_TX_EMPTY", __func__);
+ DVLOG(1) << StringPrintf("%s: GAP_EVT_TX_EMPTY", __func__);
p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_TX_EMPTY);
}
}
@@ -678,8 +705,7 @@
tGAP_CCB* p_ccb;
/* 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++) {
+ for (xx = 0, p_ccb = 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))))
@@ -687,10 +713,10 @@
}
if (xx == GAP_MAX_CONNECTIONS) {
- GAP_TRACE_WARNING("*******");
- GAP_TRACE_WARNING(
- "WARNING: GAP Conn Indication for Unexpected Bd Addr...Disconnecting");
- GAP_TRACE_WARNING("*******");
+ LOG(WARNING) << "*******";
+ LOG(WARNING) << "WARNING: GAP Conn Indication for Unexpected Bd "
+ "Addr...Disconnecting";
+ LOG(WARNING) << "*******";
/* Disconnect because it is an unexpected connection */
L2CA_DISCONNECT_REQ(l2cap_cid);
@@ -724,7 +750,7 @@
gap_checks_con_flags(p_ccb);
}
- GAP_TRACE_EVENT("GAP_CONN - Rcvd L2CAP conn ind, CID: 0x%x",
+ DVLOG(1) << StringPrintf("GAP_CONN - Rcvd L2CAP conn ind, CID: 0x%x",
p_ccb->connection_id);
/* Send a Configuration Request. */
@@ -743,7 +769,7 @@
*
******************************************************************************/
static void gap_checks_con_flags(tGAP_CCB* p_ccb) {
- GAP_TRACE_EVENT("gap_checks_con_flags conn_flags:0x%x, ", p_ccb->con_flags);
+ DVLOG(1) << __func__ << " conn_flags:0x" << +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;
@@ -762,12 +788,11 @@
* Returns void
*
******************************************************************************/
-static void gap_sec_check_complete(UNUSED_ATTR BD_ADDR bd_addr,
- UNUSED_ATTR tBT_TRANSPORT transport,
- void* p_ref_data, uint8_t res) {
+static void gap_sec_check_complete(BD_ADDR, tBT_TRANSPORT, void* p_ref_data,
+ uint8_t res) {
tGAP_CCB* p_ccb = (tGAP_CCB*)p_ref_data;
- GAP_TRACE_EVENT(
+ DVLOG(1) << StringPrintf(
"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;
@@ -926,7 +951,7 @@
static void gap_disconnect_ind(uint16_t l2cap_cid, bool ack_needed) {
tGAP_CCB* p_ccb;
- GAP_TRACE_EVENT("GAP_CONN - Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
+ DVLOG(1) << StringPrintf("GAP_CONN - Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
/* Find CCB based on CID */
p_ccb = gap_find_ccb_by_cid(l2cap_cid);
@@ -962,7 +987,7 @@
p_ccb->rx_queue_size += p_msg->len;
/*
- GAP_TRACE_EVENT ("gap_data_ind - rx_queue_size=%d, msg len=%d",
+ DVLOG(1) << StringPrintf ("gap_data_ind - rx_queue_size=%d, msg len=%d",
p_ccb->rx_queue_size, p_msg->len);
*/
@@ -986,7 +1011,7 @@
BT_HDR* p_buf;
uint8_t status;
- GAP_TRACE_EVENT("GAP_CONN - Rcvd L2CAP Is Congested (%d), CID: 0x%x",
+ DVLOG(1) << StringPrintf("GAP_CONN - Rcvd L2CAP Is Congested (%d), CID: 0x%x",
is_congested, lcid);
/* Find CCB based on CID */
@@ -1027,8 +1052,7 @@
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++) {
+ for (xx = 0, p_ccb = 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);
@@ -1053,7 +1077,7 @@
/* Check that handle is valid */
if (handle < GAP_MAX_CONNECTIONS) {
- p_ccb = &gap_cb.conn.ccb_pool[handle];
+ p_ccb = &conn.ccb_pool[handle];
if (p_ccb->con_state != GAP_CCB_STATE_IDLE) return (p_ccb);
}
@@ -1076,8 +1100,7 @@
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++) {
+ for (xx = 0, p_ccb = 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->tx_queue = fixed_queue_new(SIZE_MAX);
@@ -1120,12 +1143,12 @@
p_ccb->con_state = GAP_CCB_STATE_IDLE;
/* If no-one else is using the PSM, deregister from L2CAP */
- tGAP_CCB* p_ccb_local = gap_cb.conn.ccb_pool;
+ tGAP_CCB* p_ccb_local = conn.ccb_pool;
for (uint16_t i = 0; i < GAP_MAX_CONNECTIONS; i++, p_ccb_local++) {
if ((p_ccb_local->con_state != GAP_CCB_STATE_IDLE) &&
(p_ccb_local->psm == p_ccb->psm)) {
- GAP_TRACE_EVENT("%s :%d PSM is still in use, do not deregister",
- __func__, p_ccb_local->psm);
+ DVLOG(1) << __func__ << " : " << +p_ccb_local->psm
+ << " PSM is still in use, do not deregister";
return;
}
}
@@ -1136,4 +1159,12 @@
if (p_ccb->transport == BT_TRANSPORT_LE) L2CA_DEREGISTER_COC(p_ccb->psm);
}
-#endif /* GAP_CONN_INCLUDED */
+extern void gap_attr_db_init(void);
+
+/*
+ * This routine should not be called except once per stack invocation.
+ */
+void GAP_Init(void) {
+ gap_conn_init();
+ gap_attr_db_init();
+}
diff --git a/stack/gap/gap_int.h b/stack/gap/gap_int.h
deleted file mode 100644
index 0f27f04..0000000
--- a/stack/gap/gap_int.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/******************************************************************************
- *
- * 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_common.h"
-#include "bt_target.h"
-#include "gap_api.h"
-#include "gatt_api.h"
-#include "osi/include/fixed_queue.h"
-#define GAP_MAX_BLOCKS 2 /* Concurrent GAP commands pending at a time*/
-/* 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_t event; /* Passed back in the callback */
- uint8_t index; /* Index of this control block and callback */
- bool in_use; /* True when structure is allocated */
-} tGAP_INFO;
-
-/* The control block for FindAddrByName (Only 1 active at a time) */
-typedef struct {
- tGAP_CALLBACK* p_cback;
- /* Pointer to the current inquiry database entry */
- tBTM_INQ_INFO* p_cur_inq;
- tGAP_FINDADDR_RESULTS results;
- bool 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_t 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_t con_flags;
-
- uint8_t service_id; /* Used by BTM */
- uint16_t gap_handle; /* GAP handle */
- uint16_t connection_id; /* L2CAP CID */
- bool rem_addr_specified;
- uint8_t chan_mode_mask; /* Supported channel modes (FCR) */
- BD_ADDR rem_dev_address;
- uint16_t psm;
- uint16_t rem_mtu_size;
-
- bool is_congested;
- fixed_queue_t* tx_queue; /* Queue of buffers waiting to be sent */
- fixed_queue_t* rx_queue; /* Queue of buffers waiting to be read */
-
- uint32_t 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 */
- tBT_TRANSPORT transport; /* Transport channel BR/EDR or BLE */
- tL2CAP_LE_CFG_INFO local_coc_cfg; /* local configuration for LE Coc */
- tL2CAP_LE_CFG_INFO peer_coc_cfg; /* local configuration for LE Coc */
-} 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;
-
-#define GAP_MAX_CHAR_NUM 4
-
-typedef struct {
- uint16_t handle;
- uint16_t uuid;
- tGAP_BLE_ATTR_VALUE attr_value;
-} tGAP_ATTR;
-/**********************************************************************
- * 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 {
- uint16_t uuid;
- tGAP_BLE_CMPL_CBACK* p_cback;
-} tGAP_BLE_REQ;
-
-typedef struct {
- BD_ADDR bda;
- tGAP_BLE_CMPL_CBACK* p_cback;
- uint16_t conn_id;
- uint16_t cl_op_uuid;
- bool in_use;
- bool connected;
- fixed_queue_t* pending_req_q;
-
-} tGAP_CLCB;
-
-typedef struct {
- tGAP_INFO blk[GAP_MAX_BLOCKS];
- tBTM_CMPL_CB* btm_cback[GAP_MAX_BLOCKS];
- uint8_t 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 */
- tGAP_ATTR gatt_attr[GAP_MAX_CHAR_NUM];
- tGAP_CLCB clcb[GAP_MAX_CL]; /* connection link*/
- tGATT_IF gatt_if;
-} tGAP_CB;
-
-extern tGAP_CB gap_cb;
-#if (GAP_CONN_INCLUDED == TRUE)
-extern void gap_conn_init(void);
-#endif
-extern void gap_attr_db_init(void);
-#endif
diff --git a/stack/gap/gap_utils.cc b/stack/gap/gap_utils.cc
deleted file mode 100644
index fa8b30e..0000000
--- a/stack/gap/gap_utils.cc
+++ /dev/null
@@ -1,129 +0,0 @@
-/******************************************************************************
- *
- * 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 "bt_utils.h"
-#include "gap_int.h"
-
-/*******************************************************************************
- *
- * 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_t 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
- *
- ******************************************************************************/
-bool gap_is_service_busy(uint16_t request) {
- tGAP_INFO* p_cb = &gap_cb.blk[0];
- uint8_t 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_t 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.cc b/stack/gatt/att_protocol.cc
index 26bacc0..f157dd0 100644
--- a/stack/gatt/att_protocol.cc
+++ b/stack/gatt/att_protocol.cc
@@ -320,14 +320,14 @@
* Description Send message to L2CAP.
*
******************************************************************************/
-tGATT_STATUS attp_send_msg_to_l2cap(tGATT_TCB* p_tcb, BT_HDR* p_toL2CAP) {
+tGATT_STATUS attp_send_msg_to_l2cap(tGATT_TCB& tcb, BT_HDR* p_toL2CAP) {
uint16_t l2cap_ret;
- if (p_tcb->att_lcid == L2CAP_ATT_CID)
- l2cap_ret =
- L2CA_SendFixedChnlData(L2CAP_ATT_CID, p_tcb->peer_bda, p_toL2CAP);
+ if (tcb.att_lcid == L2CAP_ATT_CID)
+ l2cap_ret = L2CA_SendFixedChnlData(L2CAP_ATT_CID, tcb.peer_bda, p_toL2CAP);
else
- l2cap_ret = (uint16_t)L2CA_DataWrite(p_tcb->att_lcid, p_toL2CAP);
+
+ l2cap_ret = (uint16_t)L2CA_DataWrite(tcb.att_lcid, p_toL2CAP);
if (l2cap_ret == L2CAP_DW_FAILED) {
GATT_TRACE_ERROR("ATT failed to pass msg:0x%0x to L2CAP",
@@ -347,7 +347,7 @@
* Description Build ATT Server PDUs.
*
******************************************************************************/
-BT_HDR* attp_build_sr_msg(tGATT_TCB* p_tcb, uint8_t op_code,
+BT_HDR* attp_build_sr_msg(tGATT_TCB& tcb, uint8_t op_code,
tGATT_SR_MSG* p_msg) {
BT_HDR* p_cmd = NULL;
uint16_t offset = 0;
@@ -367,7 +367,7 @@
case GATT_HANDLE_VALUE_NOTIF:
case GATT_HANDLE_VALUE_IND:
p_cmd = attp_build_value_cmd(
- p_tcb->payload_size, op_code, p_msg->attr_value.handle, offset,
+ tcb.payload_size, op_code, p_msg->attr_value.handle, offset,
p_msg->attr_value.len, p_msg->attr_value.value);
break;
@@ -412,16 +412,11 @@
*
*
******************************************************************************/
-tGATT_STATUS attp_send_sr_msg(tGATT_TCB* p_tcb, BT_HDR* p_msg) {
- tGATT_STATUS cmd_sent = GATT_NO_RESOURCES;
+tGATT_STATUS attp_send_sr_msg(tGATT_TCB& tcb, BT_HDR* p_msg) {
+ if (p_msg == NULL) return GATT_NO_RESOURCES;
- if (p_tcb != NULL) {
- if (p_msg != NULL) {
- p_msg->offset = L2CAP_MIN_OFFSET;
- cmd_sent = attp_send_msg_to_l2cap(p_tcb, p_msg);
- }
- }
- return cmd_sent;
+ p_msg->offset = L2CAP_MIN_OFFSET;
+ return attp_send_msg_to_l2cap(tcb, p_msg);
}
/*******************************************************************************
@@ -436,34 +431,31 @@
* GATT_ERROR if command sending failure
*
******************************************************************************/
-tGATT_STATUS attp_cl_send_cmd(tGATT_TCB* p_tcb, uint16_t clcb_idx,
+tGATT_STATUS attp_cl_send_cmd(tGATT_TCB& tcb, tGATT_CLCB* p_clcb,
uint8_t cmd_code, BT_HDR* p_cmd) {
- tGATT_STATUS att_ret = GATT_SUCCESS;
+ cmd_code &= ~GATT_AUTH_SIGN_MASK;
- if (p_tcb != NULL) {
- cmd_code &= ~GATT_AUTH_SIGN_MASK;
+ if (!tcb.cl_cmd_q.empty() && cmd_code != GATT_HANDLE_VALUE_CONF) {
+ gatt_cmd_enq(tcb, p_clcb, true, cmd_code, p_cmd);
+ return GATT_CMD_STARTED;
+ }
- /* no pending request or value confirmation */
- if (p_tcb->pending_cl_req == p_tcb->next_slot_inq ||
- cmd_code == GATT_HANDLE_VALUE_CONF) {
- att_ret = attp_send_msg_to_l2cap(p_tcb, p_cmd);
- if (att_ret == GATT_CONGESTED || att_ret == GATT_SUCCESS) {
- /* do not enq cmd if handle value confirmation or set request */
- if (cmd_code != GATT_HANDLE_VALUE_CONF && cmd_code != GATT_CMD_WRITE) {
- gatt_start_rsp_timer(clcb_idx);
- gatt_cmd_enq(p_tcb, clcb_idx, false, cmd_code, NULL);
- }
- } else
- 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_ERROR;
+ /* no pending request or value confirmation */
+ tGATT_STATUS att_ret = attp_send_msg_to_l2cap(tcb, p_cmd);
+ if (att_ret != GATT_CONGESTED && att_ret != GATT_SUCCESS) {
+ return GATT_INTERNAL_ERROR;
+ }
+ /* do not enq cmd if handle value confirmation or set request */
+ if (cmd_code == GATT_HANDLE_VALUE_CONF || cmd_code == GATT_CMD_WRITE) {
+ return att_ret;
+ }
+
+ gatt_start_rsp_timer(p_clcb);
+ gatt_cmd_enq(tcb, p_clcb, false, cmd_code, NULL);
return att_ret;
}
+
/*******************************************************************************
*
* Function attp_send_cl_msg
@@ -472,7 +464,7 @@
* message to server.
*
* Parameter p_tcb: pointer to the connectino control block.
- * clcb_idx: clcb index
+ * p_clcb: clcb
* op_code: message op code.
* p_msg: pointer to message parameters structure.
*
@@ -480,91 +472,80 @@
*
*
******************************************************************************/
-tGATT_STATUS attp_send_cl_msg(tGATT_TCB* p_tcb, uint16_t clcb_idx,
+tGATT_STATUS attp_send_cl_msg(tGATT_TCB& tcb, tGATT_CLCB* p_clcb,
uint8_t op_code, tGATT_CL_MSG* p_msg) {
- tGATT_STATUS status = GATT_NO_RESOURCES;
BT_HDR* p_cmd = NULL;
uint16_t offset = 0, handle;
+ switch (op_code) {
+ case GATT_REQ_MTU:
+ if (p_msg->mtu > GATT_MAX_MTU_SIZE) return GATT_ILLEGAL_PARAMETER;
- if (p_tcb != NULL) {
- switch (op_code) {
- case GATT_REQ_MTU:
- if (p_msg->mtu <= GATT_MAX_MTU_SIZE) {
- p_tcb->payload_size = p_msg->mtu;
- p_cmd = attp_build_mtu_cmd(GATT_REQ_MTU, p_msg->mtu);
- } else
- status = GATT_ILLEGAL_PARAMETER;
- break;
+ tcb.payload_size = p_msg->mtu;
+ p_cmd = attp_build_mtu_cmd(GATT_REQ_MTU, p_msg->mtu);
+ break;
- case GATT_REQ_FIND_INFO:
- case GATT_REQ_READ_BY_TYPE:
- case GATT_REQ_READ_BY_GRP_TYPE:
- if (GATT_HANDLE_IS_VALID(p_msg->browse.s_handle) &&
- GATT_HANDLE_IS_VALID(p_msg->browse.e_handle) &&
- p_msg->browse.s_handle <= p_msg->browse.e_handle) {
- p_cmd =
- attp_build_browse_cmd(op_code, p_msg->browse.s_handle,
+ case GATT_REQ_FIND_INFO:
+ case GATT_REQ_READ_BY_TYPE:
+ case GATT_REQ_READ_BY_GRP_TYPE:
+ if (!GATT_HANDLE_IS_VALID(p_msg->browse.s_handle) ||
+ !GATT_HANDLE_IS_VALID(p_msg->browse.e_handle) ||
+ p_msg->browse.s_handle > p_msg->browse.e_handle)
+ return GATT_ILLEGAL_PARAMETER;
+
+ p_cmd = attp_build_browse_cmd(op_code, p_msg->browse.s_handle,
p_msg->browse.e_handle, p_msg->browse.uuid);
- } else
- status = GATT_ILLEGAL_PARAMETER;
- break;
+ break;
- case GATT_REQ_READ_BLOB:
- offset = p_msg->read_blob.offset;
- /* fall through */
- case GATT_REQ_READ:
- handle = (op_code == GATT_REQ_READ) ? p_msg->handle
- : p_msg->read_blob.handle;
- /* handle checking */
- if (GATT_HANDLE_IS_VALID(handle)) {
- p_cmd = attp_build_handle_cmd(op_code, handle, offset);
- } else
- status = GATT_ILLEGAL_PARAMETER;
- break;
+ case GATT_REQ_READ_BLOB:
+ offset = p_msg->read_blob.offset;
+ /* fall through */
+ case GATT_REQ_READ:
+ handle =
+ (op_code == GATT_REQ_READ) ? p_msg->handle : p_msg->read_blob.handle;
+ /* handle checking */
+ if (!GATT_HANDLE_IS_VALID(handle)) return GATT_ILLEGAL_PARAMETER;
- case GATT_HANDLE_VALUE_CONF:
- p_cmd = attp_build_opcode_cmd(op_code);
- break;
+ p_cmd = attp_build_handle_cmd(op_code, handle, offset);
+ break;
- case GATT_REQ_PREPARE_WRITE:
- offset = p_msg->attr_value.offset;
- /* fall through */
- case GATT_REQ_WRITE:
- case GATT_CMD_WRITE:
- case GATT_SIGN_CMD_WRITE:
- if (GATT_HANDLE_IS_VALID(p_msg->attr_value.handle)) {
- p_cmd = attp_build_value_cmd(
- p_tcb->payload_size, op_code, p_msg->attr_value.handle, offset,
- p_msg->attr_value.len, p_msg->attr_value.value);
- } else
- status = GATT_ILLEGAL_PARAMETER;
- break;
+ case GATT_HANDLE_VALUE_CONF:
+ p_cmd = attp_build_opcode_cmd(op_code);
+ break;
- case GATT_REQ_EXEC_WRITE:
- p_cmd = attp_build_exec_write_cmd(op_code, p_msg->exec_write);
- break;
+ case GATT_REQ_PREPARE_WRITE:
+ offset = p_msg->attr_value.offset;
+ /* fall through */
+ case GATT_REQ_WRITE:
+ case GATT_CMD_WRITE:
+ case GATT_SIGN_CMD_WRITE:
+ if (!GATT_HANDLE_IS_VALID(p_msg->attr_value.handle))
+ return GATT_ILLEGAL_PARAMETER;
- case GATT_REQ_FIND_TYPE_VALUE:
- p_cmd = attp_build_read_by_type_value_cmd(p_tcb->payload_size,
- &p_msg->find_type_value);
- break;
+ p_cmd = attp_build_value_cmd(
+ tcb.payload_size, op_code, p_msg->attr_value.handle, offset,
+ p_msg->attr_value.len, p_msg->attr_value.value);
+ break;
- case GATT_REQ_READ_MULTI:
- p_cmd = attp_build_read_multi_cmd(p_tcb->payload_size,
- p_msg->read_multi.num_handles,
- p_msg->read_multi.handles);
- break;
+ case GATT_REQ_EXEC_WRITE:
+ p_cmd = attp_build_exec_write_cmd(op_code, p_msg->exec_write);
+ break;
- default:
- break;
- }
+ case GATT_REQ_FIND_TYPE_VALUE:
+ p_cmd = attp_build_read_by_type_value_cmd(tcb.payload_size,
+ &p_msg->find_type_value);
+ break;
- if (p_cmd != NULL)
- status = attp_cl_send_cmd(p_tcb, clcb_idx, op_code, p_cmd);
+ case GATT_REQ_READ_MULTI:
+ p_cmd = attp_build_read_multi_cmd(tcb.payload_size,
+ p_msg->read_multi.num_handles,
+ p_msg->read_multi.handles);
+ break;
- } else {
- GATT_TRACE_ERROR("Peer device not connected");
+ default:
+ break;
}
- return status;
+ if (p_cmd == NULL) return GATT_NO_RESOURCES;
+
+ return attp_cl_send_cmd(tcb, p_clcb, op_code, p_cmd);
}
diff --git a/stack/gatt/gatt_api.cc b/stack/gatt/gatt_api.cc
index a91b48e..1c4d2cc 100644
--- a/stack/gatt/gatt_api.cc
+++ b/stack/gatt/gatt_api.cc
@@ -522,10 +522,10 @@
cmd_status = GATT_NO_RESOURCES;
}
} else {
- p_msg = attp_build_sr_msg(p_tcb, GATT_HANDLE_VALUE_IND,
+ p_msg = attp_build_sr_msg(*p_tcb, GATT_HANDLE_VALUE_IND,
(tGATT_SR_MSG*)&indication);
if (p_msg != NULL) {
- cmd_status = attp_send_sr_msg(p_tcb, p_msg);
+ cmd_status = attp_send_sr_msg(*p_tcb, p_msg);
if (cmd_status == GATT_SUCCESS || cmd_status == GATT_CONGESTED) {
p_tcb->indicate_handle = indication.handle;
@@ -554,8 +554,6 @@
tGATT_STATUS GATTS_HandleValueNotification(uint16_t conn_id,
uint16_t attr_handle,
uint16_t val_len, uint8_t* p_val) {
- tGATT_STATUS cmd_sent = GATT_ILLEGAL_PARAMETER;
- BT_HDR* p_buf;
tGATT_VALUE notif;
tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
@@ -570,20 +568,22 @@
return (tGATT_STATUS)GATT_INVALID_CONN_ID;
}
- if (GATT_HANDLE_IS_VALID(attr_handle)) {
- notif.handle = attr_handle;
- notif.len = val_len;
- memcpy(notif.value, p_val, val_len);
- notif.auth_req = GATT_AUTH_REQ_NONE;
- ;
-
- p_buf = attp_build_sr_msg(p_tcb, GATT_HANDLE_VALUE_NOTIF,
- (tGATT_SR_MSG*)¬if);
- if (p_buf != NULL) {
- cmd_sent = attp_send_sr_msg(p_tcb, p_buf);
- } else
- cmd_sent = GATT_NO_RESOURCES;
+ if (!GATT_HANDLE_IS_VALID(attr_handle)) {
+ return GATT_ILLEGAL_PARAMETER;
}
+
+ notif.handle = attr_handle;
+ notif.len = val_len;
+ memcpy(notif.value, p_val, val_len);
+ notif.auth_req = GATT_AUTH_REQ_NONE;
+
+ tGATT_STATUS cmd_sent;
+ BT_HDR* p_buf =
+ attp_build_sr_msg(*p_tcb, GATT_HANDLE_VALUE_NOTIF, (tGATT_SR_MSG*)¬if);
+ if (p_buf != NULL) {
+ cmd_sent = attp_send_sr_msg(*p_tcb, p_buf);
+ } else
+ cmd_sent = GATT_NO_RESOURCES;
return cmd_sent;
}
@@ -624,7 +624,7 @@
return (GATT_WRONG_STATE);
}
/* Process App response */
- cmd_sent = gatt_sr_process_app_rsp(p_tcb, gatt_if, trans_id,
+ cmd_sent = gatt_sr_process_app_rsp(*p_tcb, gatt_if, trans_id,
p_tcb->sr_cmd.op_code, status, p_msg);
return cmd_sent;
@@ -683,7 +683,7 @@
p_clcb->p_tcb->payload_size = mtu;
p_clcb->operation = GATTC_OPTYPE_CONFIG;
- ret = attp_send_cl_msg(p_clcb->p_tcb, p_clcb->clcb_idx, GATT_REQ_MTU,
+ ret = attp_send_cl_msg(*p_clcb->p_tcb, p_clcb, GATT_REQ_MTU,
(tGATT_CL_MSG*)&mtu);
}
@@ -1016,7 +1016,7 @@
if (p_clcb != NULL) {
p_clcb->operation = GATTC_OPTYPE_EXE_WRITE;
flag = is_execute ? GATT_PREP_WRITE_EXEC : GATT_PREP_WRITE_CANCEL;
- gatt_send_queue_write_cancel(p_clcb->p_tcb, p_clcb, flag);
+ gatt_send_queue_write_cancel(*p_clcb->p_tcb, p_clcb, flag);
} else {
GATT_TRACE_ERROR("Unable to allocate client CB for conn_id %d ", conn_id);
status = GATT_NO_RESOURCES;
@@ -1038,34 +1038,30 @@
*
******************************************************************************/
tGATT_STATUS GATTC_SendHandleValueConfirm(uint16_t conn_id, uint16_t handle) {
- tGATT_STATUS ret = GATT_ILLEGAL_PARAMETER;
+ GATT_TRACE_API("%s conn_id=%d handle=0x%x", __func__, conn_id, handle);
+
tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(GATT_GET_TCB_IDX(conn_id));
-
- GATT_TRACE_API("GATTC_SendHandleValueConfirm conn_id=%d handle=0x%x", conn_id,
- handle);
-
- if (p_tcb) {
- if (p_tcb->ind_count > 0) {
- alarm_cancel(p_tcb->ind_ack_timer);
-
- GATT_TRACE_DEBUG("notif_count=%d ", p_tcb->ind_count);
- /* send confirmation now */
- ret = attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF,
- (tGATT_CL_MSG*)&handle);
-
- p_tcb->ind_count = 0;
-
- } else {
- GATT_TRACE_DEBUG(
- "GATTC_SendHandleValueConfirm - conn_id: %u - ignored not waiting "
- "for indicaiton ack",
- conn_id);
- ret = GATT_SUCCESS;
- }
- } else {
- GATT_TRACE_ERROR("GATTC_SendHandleValueConfirm - Unknown conn_id: %u",
- conn_id);
+ if (!p_tcb) {
+ GATT_TRACE_ERROR("%s - Unknown conn_id: %u", __func__, conn_id);
+ return GATT_ILLEGAL_PARAMETER;
}
+
+ if (p_tcb->ind_count == 0) {
+ GATT_TRACE_DEBUG(
+ "%s - conn_id: %u - ignored not waiting for indicaiton ack", __func__,
+ conn_id);
+ return GATT_SUCCESS;
+ }
+
+ alarm_cancel(p_tcb->ind_ack_timer);
+
+ GATT_TRACE_DEBUG("notif_count=%d ", p_tcb->ind_count);
+ /* send confirmation now */
+ tGATT_STATUS ret = attp_send_cl_msg(*p_tcb, nullptr, GATT_HANDLE_VALUE_CONF,
+ (tGATT_CL_MSG*)&handle);
+
+ p_tcb->ind_count = 0;
+
return ret;
}
@@ -1331,59 +1327,49 @@
*
******************************************************************************/
bool GATT_CancelConnect(tGATT_IF gatt_if, BD_ADDR bd_addr, bool is_direct) {
- tGATT_REG* p_reg;
- tGATT_TCB* p_tcb;
- bool status = true;
- tGATT_IF temp_gatt_if;
- uint8_t start_idx, found_idx;
+ GATT_TRACE_API("%s: gatt_if=%d", __func__, gatt_if);
- GATT_TRACE_API("GATT_CancelConnect gatt_if=%d", gatt_if);
-
- if (gatt_if != 0) {
- p_reg = gatt_get_regcb(gatt_if);
- if (p_reg == NULL) {
- GATT_TRACE_ERROR("GATT_CancelConnect - gatt_if =%d is not registered",
- gatt_if);
- return (false);
- }
+ if (gatt_if && !gatt_get_regcb(gatt_if)) {
+ GATT_TRACE_ERROR("%s: gatt_if =%d is not registered", __func__, gatt_if);
+ return false;
}
if (is_direct) {
- if (!gatt_if) {
- GATT_TRACE_DEBUG("GATT_CancelConnect - unconditional");
- start_idx = 0;
- /* only LE connection can be cancelled */
- p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE);
- if (p_tcb && gatt_num_apps_hold_link(p_tcb)) {
- while (status && gatt_find_app_hold_link(p_tcb, start_idx, &found_idx,
- &temp_gatt_if)) {
- status = gatt_cancel_open(temp_gatt_if, bd_addr);
- start_idx = ++found_idx;
- }
- } else {
- GATT_TRACE_ERROR("GATT_CancelConnect - no app found");
- status = false;
- }
- } else {
- status = gatt_cancel_open(gatt_if, bd_addr);
+ if (gatt_if) {
+ return gatt_cancel_open(gatt_if, bd_addr);
}
- } else {
- if (!gatt_if) {
- if (gatt_get_num_apps_for_bg_dev(bd_addr)) {
- while (gatt_find_app_for_bg_dev(bd_addr, &temp_gatt_if))
- gatt_remove_bg_dev_for_app(temp_gatt_if, bd_addr);
- } else {
- GATT_TRACE_ERROR(
- "GATT_CancelConnect -no app associated with the bg device for "
- "unconditional removal");
- status = false;
- }
- } else {
- status = gatt_remove_bg_dev_for_app(gatt_if, bd_addr);
+
+ GATT_TRACE_DEBUG("%s: unconditional", __func__);
+ /* only LE connection can be cancelled */
+ tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE);
+ if (!p_tcb || p_tcb->app_hold_link.empty()) {
+ GATT_TRACE_ERROR("%s: no app found", __func__);
+ return false;
}
+
+ for (auto it = p_tcb->app_hold_link.begin();
+ it != p_tcb->app_hold_link.end();) {
+ auto next = std::next(it);
+ // gatt_cancel_open modifies the app_hold_link.
+ if (!gatt_cancel_open(*it, bd_addr)) return false;
+
+ it = next;
+ }
+
+ return true;
+ }
+ // is not direct
+
+ if (gatt_if) return gatt_remove_bg_dev_for_app(gatt_if, bd_addr);
+
+ if (!gatt_clear_bg_dev_for_addr(bd_addr)) {
+ GATT_TRACE_ERROR(
+ "%s: no app associated with the bg device for unconditional removal",
+ __func__);
+ return false;
}
- return status;
+ return true;
}
/*******************************************************************************
diff --git a/stack/gatt/gatt_auth.cc b/stack/gatt/gatt_auth.cc
index 82b03a6..ae7cb30 100644
--- a/stack/gatt/gatt_auth.cc
+++ b/stack/gatt/gatt_auth.cc
@@ -91,10 +91,10 @@
* Returns
*
******************************************************************************/
-void gatt_verify_signature(tGATT_TCB* p_tcb, BT_HDR* p_buf) {
+void gatt_verify_signature(tGATT_TCB& tcb, BT_HDR* p_buf) {
uint16_t cmd_len;
uint8_t op_code;
- uint8_t *p, *p_orig = (uint8_t *)(p_buf + 1) + p_buf->offset;
+ uint8_t *p, *p_orig = (uint8_t*)(p_buf + 1) + p_buf->offset;
uint32_t counter;
if (p_buf->len < GATT_AUTH_SIGN_LEN + 4) {
@@ -106,16 +106,15 @@
p = p_orig + cmd_len - 4;
STREAM_TO_UINT32(counter, p);
- if (BTM_BleVerifySignature(p_tcb->peer_bda, p_orig, cmd_len, counter, p)) {
- STREAM_TO_UINT8(op_code, p_orig);
- gatt_server_handle_client_req(p_tcb, op_code, (uint16_t)(p_buf->len - 1),
- p_orig);
- } else {
+ if (!BTM_BleVerifySignature(tcb.peer_bda, p_orig, cmd_len, counter, p)) {
/* if this is a bad signature, assume from attacker, ignore it */
GATT_TRACE_ERROR("Signature Verification Failed, data ignored");
+ return;
}
- return;
+ STREAM_TO_UINT8(op_code, p_orig);
+ gatt_server_handle_client_req(tcb, op_code, (uint16_t)(p_buf->len - 1),
+ p_orig);
}
/*******************************************************************************
*
@@ -128,8 +127,7 @@
******************************************************************************/
void gatt_sec_check_complete(bool sec_check_ok, tGATT_CLCB* p_clcb,
uint8_t sec_act) {
- if (p_clcb && p_clcb->p_tcb &&
- fixed_queue_is_empty(p_clcb->p_tcb->pending_enc_clcb)) {
+ if (p_clcb && p_clcb->p_tcb && p_clcb->p_tcb->pending_enc_clcb.empty()) {
gatt_set_sec_act(p_clcb->p_tcb, GATT_SEC_NONE);
}
@@ -152,48 +150,44 @@
******************************************************************************/
void gatt_enc_cmpl_cback(BD_ADDR bd_addr, tBT_TRANSPORT transport,
UNUSED_ATTR void* p_ref_data, tBTM_STATUS result) {
- tGATT_TCB* p_tcb;
- uint8_t sec_flag;
- bool status = false;
-
GATT_TRACE_DEBUG("gatt_enc_cmpl_cback");
- p_tcb = gatt_find_tcb_by_addr(bd_addr, transport);
- if (p_tcb != NULL) {
- if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENC_PENDING) return;
+ tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, transport);
+ if (!p_tcb) {
+ GATT_TRACE_ERROR("%s: enc callback for unknown bd_addr", __func__);
+ return;
+ }
- tGATT_PENDING_ENC_CLCB* p_buf =
- (tGATT_PENDING_ENC_CLCB*)fixed_queue_try_dequeue(
- p_tcb->pending_enc_clcb);
- if (p_buf != NULL) {
- if (result == BTM_SUCCESS) {
- if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENCRYPT_MITM) {
- BTM_GetSecurityFlagsByTransport(bd_addr, &sec_flag, transport);
+ if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENC_PENDING) return;
- if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED) {
- status = true;
- }
- } else {
- status = true;
- }
- }
- gatt_sec_check_complete(status, p_buf->p_clcb, p_tcb->sec_act);
- osi_free(p_buf);
- /* start all other pending operation in queue */
- for (size_t count = fixed_queue_length(p_tcb->pending_enc_clcb);
- count > 0; count--) {
- p_buf = (tGATT_PENDING_ENC_CLCB*)fixed_queue_try_dequeue(
- p_tcb->pending_enc_clcb);
- if (p_buf != NULL) {
- gatt_security_check_start(p_buf->p_clcb);
- osi_free(p_buf);
- } else
- break;
+ if (p_tcb->pending_enc_clcb.empty()) {
+ GATT_TRACE_ERROR("%s: no operation waiting for encrypting", __func__);
+ return;
+ }
+
+ tGATT_CLCB* p_clcb = p_tcb->pending_enc_clcb.front();
+ p_tcb->pending_enc_clcb.pop();
+
+ bool status = false;
+ if (result == BTM_SUCCESS) {
+ if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENCRYPT_MITM) {
+ uint8_t sec_flag = 0;
+ BTM_GetSecurityFlagsByTransport(bd_addr, &sec_flag, transport);
+
+ if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED) {
+ status = true;
}
} else {
- GATT_TRACE_ERROR("Unknown operation encryption completed");
+ status = true;
}
- } else {
- GATT_TRACE_ERROR("enc callback for unknown bd_addr");
+ }
+
+ gatt_sec_check_complete(status, p_clcb, p_tcb->sec_act);
+
+ /* start all other pending operation in queue */
+ while (!p_tcb->pending_enc_clcb.empty()) {
+ tGATT_CLCB* p_clcb = p_tcb->pending_enc_clcb.front();
+ p_tcb->pending_enc_clcb.pop();
+ gatt_security_check_start(p_clcb);
}
}
@@ -208,37 +202,28 @@
*
******************************************************************************/
void gatt_notify_enc_cmpl(BD_ADDR bd_addr) {
- tGATT_TCB* p_tcb;
- uint8_t i = 0;
-
- p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE);
- if (p_tcb != NULL) {
- for (i = 0; i < GATT_MAX_APPS; i++) {
- if (gatt_cb.cl_rcb[i].in_use && gatt_cb.cl_rcb[i].app_cb.p_enc_cmpl_cb) {
- (*gatt_cb.cl_rcb[i].app_cb.p_enc_cmpl_cb)(gatt_cb.cl_rcb[i].gatt_if,
- bd_addr);
- }
- }
-
- if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENC_PENDING) {
- gatt_set_sec_act(p_tcb, GATT_SEC_NONE);
-
- size_t count = fixed_queue_length(p_tcb->pending_enc_clcb);
- for (; count > 0; count--) {
- tGATT_PENDING_ENC_CLCB* p_buf =
- (tGATT_PENDING_ENC_CLCB*)fixed_queue_try_dequeue(
- p_tcb->pending_enc_clcb);
- if (p_buf != NULL) {
- gatt_security_check_start(p_buf->p_clcb);
- osi_free(p_buf);
- } else
- break;
- }
- }
- } else {
+ tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE);
+ if (!p_tcb) {
GATT_TRACE_DEBUG("notify GATT for encryption completion of unknown device");
+ return;
}
- return;
+
+ for (uint8_t i = 0; i < GATT_MAX_APPS; i++) {
+ if (gatt_cb.cl_rcb[i].in_use && gatt_cb.cl_rcb[i].app_cb.p_enc_cmpl_cb) {
+ (*gatt_cb.cl_rcb[i].app_cb.p_enc_cmpl_cb)(gatt_cb.cl_rcb[i].gatt_if,
+ bd_addr);
+ }
+ }
+
+ if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENC_PENDING) {
+ gatt_set_sec_act(p_tcb, GATT_SEC_NONE);
+
+ while (!p_tcb->pending_enc_clcb.empty()) {
+ tGATT_CLCB* p_clcb = p_tcb->pending_enc_clcb.front();
+ p_tcb->pending_enc_clcb.pop();
+ gatt_security_check_start(p_clcb);
+ }
+ }
}
/*******************************************************************************
*
@@ -270,16 +255,10 @@
}
return sec_act;
}
-/*******************************************************************************
- *
- * Function gatt_determine_sec_act
- *
- * Description This routine determine the security action based on
- * auth_request and current link status
- *
- * Returns tGATT_SEC_ACTION security action
- *
- ******************************************************************************/
+/**
+ * This routine determine the security action based on auth_request and current
+ * link status. Returns tGATT_SEC_ACTION (security action)
+ */
tGATT_SEC_ACTION gatt_determine_sec_act(tGATT_CLCB* p_clcb) {
tGATT_SEC_ACTION act = GATT_SEC_OK;
uint8_t sec_flag;
@@ -364,11 +343,11 @@
* Returns tGATT_STATUS link encryption status
*
******************************************************************************/
-tGATT_STATUS gatt_get_link_encrypt_status(tGATT_TCB* p_tcb) {
+tGATT_STATUS gatt_get_link_encrypt_status(tGATT_TCB& tcb) {
tGATT_STATUS encrypt_status = GATT_NOT_ENCRYPTED;
uint8_t sec_flag = 0;
- BTM_GetSecurityFlagsByTransport(p_tcb->peer_bda, &sec_flag, p_tcb->transport);
+ BTM_GetSecurityFlagsByTransport(tcb.peer_bda, &sec_flag, tcb.transport);
if ((sec_flag & BTM_SEC_FLAG_ENCRYPTED) &&
(sec_flag & BTM_SEC_FLAG_LKEY_KNOWN)) {
@@ -455,10 +434,10 @@
status = false;
}
}
- if (status) gatt_add_pending_enc_channel_clcb(p_tcb, p_clcb);
+ if (status) p_tcb->pending_enc_clcb.push(p_clcb);
break;
case GATT_SEC_ENC_PENDING:
- gatt_add_pending_enc_channel_clcb(p_tcb, p_clcb);
+ p_tcb->pending_enc_clcb.push(p_clcb);
/* wait for link encrypotion to finish */
break;
default:
diff --git a/stack/gatt/gatt_cl.cc b/stack/gatt/gatt_cl.cc
index a714c4a..d04f7f1 100644
--- a/stack/gatt/gatt_cl.cc
+++ b/stack/gatt/gatt_cl.cc
@@ -45,7 +45,7 @@
/*******************************************************************************
* G L O B A L G A T T D A T A *
******************************************************************************/
-void gatt_send_prepare_write(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb);
+void gatt_send_prepare_write(tGATT_TCB& tcb, tGATT_CLCB* p_clcb);
uint8_t disc_type_to_att_opcode[GATT_DISC_MAX] = {
0,
@@ -109,7 +109,7 @@
p_clcb->uuid.len);
}
- st = attp_send_cl_msg(p_clcb->p_tcb, p_clcb->clcb_idx, op_code, &cl_req);
+ st = attp_send_cl_msg(*p_clcb->p_tcb, p_clcb, op_code, &cl_req);
if (st != GATT_SUCCESS && st != GATT_CMD_STARTED) {
gatt_end_operation(p_clcb, GATT_ERROR, NULL);
@@ -128,7 +128,7 @@
*
******************************************************************************/
void gatt_act_read(tGATT_CLCB* p_clcb, uint16_t offset) {
- tGATT_TCB* p_tcb = p_clcb->p_tcb;
+ tGATT_TCB& tcb = *p_clcb->p_tcb;
uint8_t rt = GATT_INTERNAL_ERROR;
tGATT_CL_MSG msg;
uint8_t op_code = 0;
@@ -191,8 +191,7 @@
break;
}
- if (op_code != 0)
- rt = attp_send_cl_msg(p_tcb, p_clcb->clcb_idx, op_code, &msg);
+ if (op_code != 0) rt = attp_send_cl_msg(tcb, p_clcb, op_code, &msg);
if (op_code == 0 || (rt != GATT_SUCCESS && rt != GATT_CMD_STARTED)) {
gatt_end_operation(p_clcb, rt, NULL);
@@ -209,7 +208,7 @@
*
******************************************************************************/
void gatt_act_write(tGATT_CLCB* p_clcb, uint8_t sec_act) {
- tGATT_TCB* p_tcb = p_clcb->p_tcb;
+ tGATT_TCB& tcb = *p_clcb->p_tcb;
uint8_t rt = GATT_SUCCESS, op_code = 0;
tGATT_VALUE* p_attr = (tGATT_VALUE*)p_clcb->p_attr_buf;
@@ -219,25 +218,24 @@
p_clcb->s_handle = p_attr->handle;
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,
- p_attr->handle, p_attr->len, 0, p_attr->value);
+ rt = gatt_send_write_msg(tcb, p_clcb, op_code, p_attr->handle,
+ p_attr->len, 0, p_attr->value);
break;
case GATT_WRITE:
- if (p_attr->len <= (p_tcb->payload_size - GATT_HDR_SIZE)) {
+ if (p_attr->len <= (tcb.payload_size - GATT_HDR_SIZE)) {
p_clcb->s_handle = p_attr->handle;
- rt = gatt_send_write_msg(p_tcb, p_clcb->clcb_idx, GATT_REQ_WRITE,
- p_attr->handle, p_attr->len, 0,
- p_attr->value);
+ rt = gatt_send_write_msg(tcb, p_clcb, GATT_REQ_WRITE, p_attr->handle,
+ p_attr->len, 0, p_attr->value);
} else /* prepare write for long attribute */
{
- gatt_send_prepare_write(p_tcb, p_clcb);
+ gatt_send_prepare_write(tcb, p_clcb);
}
break;
case GATT_WRITE_PREPARE:
- gatt_send_prepare_write(p_tcb, p_clcb);
+ gatt_send_prepare_write(tcb, p_clcb);
break;
default:
@@ -266,14 +264,13 @@
* Returns void.
*
******************************************************************************/
-void gatt_send_queue_write_cancel(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
+void gatt_send_queue_write_cancel(tGATT_TCB& tcb, tGATT_CLCB* p_clcb,
tGATT_EXEC_FLAG flag) {
uint8_t rt;
GATT_TRACE_DEBUG("gatt_send_queue_write_cancel ");
- rt = attp_send_cl_msg(p_tcb, p_clcb->clcb_idx, GATT_REQ_EXEC_WRITE,
- (tGATT_CL_MSG*)&flag);
+ rt = attp_send_cl_msg(tcb, p_clcb, GATT_REQ_EXEC_WRITE, (tGATT_CL_MSG*)&flag);
if (rt != GATT_SUCCESS) {
gatt_end_operation(p_clcb, rt, NULL);
@@ -288,7 +285,7 @@
* Returns true: write long is terminated; false keep sending.
*
******************************************************************************/
-bool gatt_check_write_long_terminate(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
+bool gatt_check_write_long_terminate(tGATT_TCB& tcb, tGATT_CLCB* p_clcb,
tGATT_VALUE* p_rsp_value) {
tGATT_VALUE* p_attr = (tGATT_VALUE*)p_clcb->p_attr_buf;
bool exec = false;
@@ -313,7 +310,7 @@
}
}
if (exec) {
- gatt_send_queue_write_cancel(p_tcb, p_clcb, flag);
+ gatt_send_queue_write_cancel(tcb, p_clcb, flag);
return true;
}
return false;
@@ -327,7 +324,7 @@
* Returns void.
*
******************************************************************************/
-void gatt_send_prepare_write(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb) {
+void gatt_send_prepare_write(tGATT_TCB& tcb, tGATT_CLCB* p_clcb) {
tGATT_VALUE* p_attr = (tGATT_VALUE*)p_clcb->p_attr_buf;
uint16_t to_send, offset;
uint8_t rt = GATT_SUCCESS;
@@ -336,9 +333,9 @@
GATT_TRACE_DEBUG("gatt_send_prepare_write type=0x%x", type);
to_send = p_attr->len - p_attr->offset;
- if (to_send > (p_tcb->payload_size -
+ if (to_send > (tcb.payload_size -
GATT_WRITE_LONG_HDR_SIZE)) /* 2 = uint16_t offset bytes */
- to_send = p_tcb->payload_size - GATT_WRITE_LONG_HDR_SIZE;
+ to_send = tcb.payload_size - GATT_WRITE_LONG_HDR_SIZE;
p_clcb->s_handle = p_attr->handle;
@@ -349,8 +346,8 @@
GATT_TRACE_DEBUG("offset =0x%x len=%d", offset, to_send);
- rt = gatt_send_write_msg(p_tcb, p_clcb->clcb_idx, GATT_REQ_PREPARE_WRITE,
- p_attr->handle, to_send, /* length */
+ rt = gatt_send_write_msg(tcb, p_clcb, GATT_REQ_PREPARE_WRITE, p_attr->handle,
+ to_send, /* length */
offset, /* used as offset */
p_attr->value + p_attr->offset); /* data */
@@ -372,7 +369,7 @@
* Returns void
*
******************************************************************************/
-void gatt_process_find_type_value_rsp(UNUSED_ATTR tGATT_TCB* p_tcb,
+void gatt_process_find_type_value_rsp(UNUSED_ATTR tGATT_TCB& tcb,
tGATT_CLCB* p_clcb, uint16_t len,
uint8_t* p_data) {
tGATT_DISC_RES result;
@@ -420,9 +417,9 @@
* Returns void
*
******************************************************************************/
-void gatt_process_read_info_rsp(UNUSED_ATTR tGATT_TCB* p_tcb,
- tGATT_CLCB* p_clcb, UNUSED_ATTR uint8_t op_code,
- uint16_t len, uint8_t* p_data) {
+void gatt_process_read_info_rsp(UNUSED_ATTR tGATT_TCB& tcb, tGATT_CLCB* p_clcb,
+ UNUSED_ATTR uint8_t op_code, uint16_t len,
+ uint8_t* p_data) {
tGATT_DISC_RES result;
uint8_t *p = p_data, uuid_len = 0, type;
@@ -473,7 +470,7 @@
* Returns void.
*
******************************************************************************/
-void gatt_proc_disc_error_rsp(UNUSED_ATTR tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
+void gatt_proc_disc_error_rsp(UNUSED_ATTR tGATT_TCB& tcb, tGATT_CLCB* p_clcb,
uint8_t opcode, UNUSED_ATTR uint16_t handle,
uint8_t reason) {
tGATT_STATUS status = (tGATT_STATUS)reason;
@@ -509,7 +506,7 @@
* Returns void
*
******************************************************************************/
-void gatt_process_error_rsp(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
+void gatt_process_error_rsp(tGATT_TCB& tcb, tGATT_CLCB* p_clcb,
UNUSED_ATTR uint8_t op_code,
UNUSED_ATTR uint16_t len, uint8_t* p_data) {
uint8_t opcode, reason, *p = p_data;
@@ -522,14 +519,14 @@
STREAM_TO_UINT8(reason, p);
if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY) {
- gatt_proc_disc_error_rsp(p_tcb, p_clcb, opcode, handle, reason);
+ gatt_proc_disc_error_rsp(tcb, p_clcb, opcode, handle, reason);
} else {
if ((p_clcb->operation == GATTC_OPTYPE_WRITE) &&
(p_clcb->op_subtype == GATT_WRITE) &&
(opcode == GATT_REQ_PREPARE_WRITE) && (p_attr) &&
(handle == p_attr->handle)) {
p_clcb->status = reason;
- gatt_send_queue_write_cancel(p_tcb, p_clcb, GATT_PREP_WRITE_CANCEL);
+ gatt_send_queue_write_cancel(tcb, p_clcb, GATT_PREP_WRITE_CANCEL);
} else if ((p_clcb->operation == GATTC_OPTYPE_READ) &&
((p_clcb->op_subtype == GATT_READ_CHAR_VALUE_HDL) ||
(p_clcb->op_subtype == GATT_READ_BY_HANDLE)) &&
@@ -551,7 +548,7 @@
* Returns void
*
******************************************************************************/
-void gatt_process_prep_write_rsp(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
+void gatt_process_prep_write_rsp(tGATT_TCB& tcb, tGATT_CLCB* p_clcb,
uint8_t op_code, uint16_t len,
uint8_t* p_data) {
uint8_t* p = p_data;
@@ -583,8 +580,8 @@
gatt_end_operation(p_clcb, p_clcb->status, &value);
} else if (p_clcb->op_subtype == GATT_WRITE) {
- if (!gatt_check_write_long_terminate(p_tcb, p_clcb, &value))
- gatt_send_prepare_write(p_tcb, p_clcb);
+ if (!gatt_check_write_long_terminate(tcb, p_clcb, &value))
+ gatt_send_prepare_write(tcb, p_clcb);
}
}
/*******************************************************************************
@@ -596,7 +593,7 @@
* Returns void
*
******************************************************************************/
-void gatt_process_notification(tGATT_TCB* p_tcb, uint8_t op_code, uint16_t len,
+void gatt_process_notification(tGATT_TCB& tcb, uint8_t op_code, uint16_t len,
uint8_t* p_data) {
tGATT_VALUE value;
tGATT_REG* p_reg;
@@ -621,12 +618,12 @@
if (!GATT_HANDLE_IS_VALID(value.handle)) {
/* illegal handle, send ack now */
if (op_code == GATT_HANDLE_VALUE_IND)
- attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL);
+ attp_send_cl_msg(tcb, nullptr, GATT_HANDLE_VALUE_CONF, NULL);
return;
}
if (event == GATTC_OPTYPE_INDICATION) {
- if (p_tcb->ind_count) {
+ if (tcb.ind_count) {
/* this is an error case that receiving an indication but we
still has an indication not being acked yet.
For now, just log the error reset the counter.
@@ -635,9 +632,9 @@
GATT_TRACE_ERROR(
"gatt_process_notification rcv Ind. but ind_count=%d (will reset "
"ind_count)",
- p_tcb->ind_count);
+ tcb.ind_count);
}
- p_tcb->ind_count = 0;
+ tcb.ind_count = 0;
}
/* should notify all registered client with the handle value
@@ -649,21 +646,21 @@
for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) {
if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb &&
(event == GATTC_OPTYPE_INDICATION))
- p_tcb->ind_count++;
+ tcb.ind_count++;
}
if (event == GATTC_OPTYPE_INDICATION) {
/* start a timer for app confirmation */
- if (p_tcb->ind_count > 0)
- gatt_start_ind_ack_timer(p_tcb);
+ if (tcb.ind_count > 0)
+ gatt_start_ind_ack_timer(tcb);
else /* no app to indicate, or invalid handle */
- attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL);
+ attp_send_cl_msg(tcb, nullptr, GATT_HANDLE_VALUE_CONF, NULL);
}
- encrypt_status = gatt_get_link_encrypt_status(p_tcb);
+ encrypt_status = gatt_get_link_encrypt_status(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);
+ conn_id = GATT_CREATE_CONN_ID(tcb.tcb_idx, p_reg->gatt_if);
(*p_reg->app_cb.p_cmpl_cb)(conn_id, event, encrypt_status,
(tGATT_CL_COMPLETE*)&value);
}
@@ -681,7 +678,7 @@
* Returns void
*
******************************************************************************/
-void gatt_process_read_by_type_rsp(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
+void gatt_process_read_by_type_rsp(tGATT_TCB& tcb, tGATT_CLCB* p_clcb,
uint8_t op_code, uint16_t len,
uint8_t* p_data) {
tGATT_DISC_RES result;
@@ -703,14 +700,14 @@
STREAM_TO_UINT8(value_len, p);
- if ((value_len > (p_tcb->payload_size - 2)) || (value_len > (len - 1))) {
+ if ((value_len > (tcb.payload_size - 2)) || (value_len > (len - 1))) {
/* this is an error case that server's response containing a value length
which is larger than MTU-2
or value_len > message total length -1 */
GATT_TRACE_ERROR(
"gatt_process_read_by_type_rsp: Discard response op_code=%d "
"vale_len=%d > (MTU-2=%d or msg_len-1=%d)",
- op_code, value_len, (p_tcb->payload_size - 2), (len - 1));
+ op_code, value_len, (tcb.payload_size - 2), (len - 1));
gatt_end_operation(p_clcb, GATT_ERROR, NULL);
return;
}
@@ -869,7 +866,7 @@
* Returns void
*
******************************************************************************/
-void gatt_process_read_rsp(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
+void gatt_process_read_rsp(tGATT_TCB& tcb, tGATT_CLCB* p_clcb,
UNUSED_ATTR uint8_t op_code, uint16_t len,
uint8_t* p_data) {
uint16_t offset = p_clcb->counter;
@@ -895,7 +892,7 @@
/* send next request if needed */
- if (len == (p_tcb->payload_size -
+ if (len == (tcb.payload_size -
1) && /* full packet for read or read blob rsp */
len + offset < GATT_MAX_ATTR_LEN) {
GATT_TRACE_DEBUG(
@@ -962,7 +959,7 @@
* Returns void
*
******************************************************************************/
-void gatt_process_mtu_rsp(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb, uint16_t len,
+void gatt_process_mtu_rsp(tGATT_TCB& tcb, tGATT_CLCB* p_clcb, uint16_t len,
uint8_t* p_data) {
uint16_t mtu;
tGATT_STATUS status = GATT_SUCCESS;
@@ -973,12 +970,12 @@
} else {
STREAM_TO_UINT16(mtu, p_data);
- if (mtu < p_tcb->payload_size && mtu >= GATT_DEF_BLE_MTU_SIZE)
- p_tcb->payload_size = mtu;
+ if (mtu < tcb.payload_size && mtu >= GATT_DEF_BLE_MTU_SIZE)
+ tcb.payload_size = mtu;
}
- l2cble_set_fixed_channel_tx_data_length(p_tcb->peer_bda, L2CAP_ATT_CID,
- p_tcb->payload_size);
+ l2cble_set_fixed_channel_tx_data_length(tcb.peer_bda, L2CAP_ATT_CID,
+ tcb.payload_size);
gatt_end_operation(p_clcb, status, NULL);
}
/*******************************************************************************
@@ -999,54 +996,42 @@
}
return rsp_code;
}
-/*******************************************************************************
- *
- * Function gatt_cl_send_next_cmd_inq
- *
- * Description Find next command in queue and sent to server
- *
- * Returns true if command sent, otherwise false.
- *
- ******************************************************************************/
-bool 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];
- bool sent = false;
- uint8_t rsp_code;
- tGATT_CLCB* p_clcb = NULL;
- tGATT_STATUS att_ret = GATT_SUCCESS;
- while (!sent && p_tcb->pending_cl_req != p_tcb->next_slot_inq &&
- p_cmd->to_send && p_cmd->p_cmd != NULL) {
- att_ret = attp_send_msg_to_l2cap(p_tcb, p_cmd->p_cmd);
+/** Find next command in queue and sent to server */
+bool gatt_cl_send_next_cmd_inq(tGATT_TCB& tcb) {
+ while (!tcb.cl_cmd_q.empty()) {
+ tGATT_CMD_Q& cmd = tcb.cl_cmd_q.front();
+ if (!cmd.to_send || cmd.p_cmd == NULL) return false;
- if (att_ret == GATT_SUCCESS || att_ret == GATT_CONGESTED) {
- sent = true;
- p_cmd->to_send = false;
- p_cmd->p_cmd = NULL;
-
- /* 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_cmd->clcb_idx);
- } else {
- p_clcb = gatt_cmd_dequeue(p_tcb, &rsp_code);
-
- /* if no ack needed, keep sending */
- if (att_ret == GATT_SUCCESS) sent = false;
-
- p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
- /* send command complete callback here */
- gatt_end_operation(p_clcb, att_ret, NULL);
- }
- } else {
- GATT_TRACE_ERROR("gatt_cl_send_next_cmd_inq: L2CAP sent error");
-
- memset(p_cmd, 0, sizeof(tGATT_CMD_Q));
- p_tcb->pending_cl_req++;
- p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
+ tGATT_STATUS att_ret = attp_send_msg_to_l2cap(tcb, cmd.p_cmd);
+ if (att_ret != GATT_SUCCESS && att_ret != GATT_CONGESTED) {
+ GATT_TRACE_ERROR("%s: L2CAP sent error", __func__);
+ tcb.cl_cmd_q.pop();
+ continue;
}
+
+ cmd.to_send = false;
+ cmd.p_cmd = NULL;
+
+ if (cmd.op_code == GATT_CMD_WRITE || cmd.op_code == GATT_SIGN_CMD_WRITE) {
+ /* dequeue the request if is write command or sign write */
+ uint8_t rsp_code;
+ tGATT_CLCB* p_clcb = gatt_cmd_dequeue(tcb, &rsp_code);
+
+ /* send command complete callback here */
+ gatt_end_operation(p_clcb, att_ret, NULL);
+
+ /* if no ack needed, keep sending */
+ if (att_ret == GATT_SUCCESS) continue;
+
+ return true;
+ }
+
+ gatt_start_rsp_timer(cmd.p_clcb);
+ return true;
}
- return sent;
+
+ return false;
}
/*******************************************************************************
@@ -1060,63 +1045,61 @@
* Returns void
*
******************************************************************************/
-void gatt_client_handle_server_rsp(tGATT_TCB* p_tcb, uint8_t op_code,
+void gatt_client_handle_server_rsp(tGATT_TCB& tcb, uint8_t op_code,
uint16_t len, uint8_t* p_data) {
tGATT_CLCB* p_clcb = NULL;
- uint8_t rsp_code;
if (op_code != GATT_HANDLE_VALUE_IND && op_code != GATT_HANDLE_VALUE_NOTIF) {
- p_clcb = gatt_cmd_dequeue(p_tcb, &rsp_code);
+ uint8_t rsp_code;
+ p_clcb = gatt_cmd_dequeue(tcb, &rsp_code);
rsp_code = gatt_cmd_to_rsp_code(rsp_code);
if (p_clcb == NULL || (rsp_code != op_code && op_code != GATT_RSP_ERROR)) {
GATT_TRACE_WARNING(
- "ATT - Ignore wrong response. Receives (%02x) \
- Request(%02x) Ignored",
+ "ATT - Ignore wrong response. Receives (%02x) Request(%02x) Ignored",
op_code, rsp_code);
-
return;
- } else {
- alarm_cancel(p_clcb->gatt_rsp_timer_ent);
- p_clcb->retry_count = 0;
}
+
+ alarm_cancel(p_clcb->gatt_rsp_timer_ent);
+ p_clcb->retry_count = 0;
}
/* the size of the message may not be bigger than the local max PDU size*/
/* The message has to be smaller than the agreed MTU, len does not count
* op_code */
- if (len >= p_tcb->payload_size) {
+ if (len >= tcb.payload_size) {
GATT_TRACE_ERROR("invalid response/indicate pkt size: %d, PDU size: %d",
- len + 1, p_tcb->payload_size);
+ len + 1, tcb.payload_size);
if (op_code != GATT_HANDLE_VALUE_NOTIF && op_code != GATT_HANDLE_VALUE_IND)
gatt_end_operation(p_clcb, GATT_ERROR, NULL);
} else {
switch (op_code) {
case GATT_RSP_ERROR:
- gatt_process_error_rsp(p_tcb, p_clcb, op_code, len, p_data);
+ gatt_process_error_rsp(tcb, p_clcb, op_code, len, p_data);
break;
case GATT_RSP_MTU: /* 2 bytes mtu */
- gatt_process_mtu_rsp(p_tcb, p_clcb, len, p_data);
+ gatt_process_mtu_rsp(tcb, p_clcb, len, p_data);
break;
case GATT_RSP_FIND_INFO:
- gatt_process_read_info_rsp(p_tcb, p_clcb, op_code, len, p_data);
+ gatt_process_read_info_rsp(tcb, p_clcb, op_code, len, p_data);
break;
case GATT_RSP_READ_BY_TYPE:
case GATT_RSP_READ_BY_GRP_TYPE:
- gatt_process_read_by_type_rsp(p_tcb, p_clcb, op_code, len, p_data);
+ gatt_process_read_by_type_rsp(tcb, p_clcb, op_code, len, p_data);
break;
case GATT_RSP_READ:
case GATT_RSP_READ_BLOB:
case GATT_RSP_READ_MULTI:
- gatt_process_read_rsp(p_tcb, p_clcb, op_code, len, p_data);
+ gatt_process_read_rsp(tcb, p_clcb, op_code, len, p_data);
break;
case GATT_RSP_FIND_TYPE_VALUE: /* disc service with UUID */
- gatt_process_find_type_value_rsp(p_tcb, p_clcb, len, p_data);
+ gatt_process_find_type_value_rsp(tcb, p_clcb, len, p_data);
break;
case GATT_RSP_WRITE:
@@ -1124,7 +1107,7 @@
break;
case GATT_RSP_PREPARE_WRITE:
- gatt_process_prep_write_rsp(p_tcb, p_clcb, op_code, len, p_data);
+ gatt_process_prep_write_rsp(tcb, p_clcb, op_code, len, p_data);
break;
case GATT_RSP_EXEC_WRITE:
@@ -1133,7 +1116,7 @@
case GATT_HANDLE_VALUE_NOTIF:
case GATT_HANDLE_VALUE_IND:
- gatt_process_notification(p_tcb, op_code, len, p_data);
+ gatt_process_notification(tcb, op_code, len, p_data);
break;
default:
@@ -1143,7 +1126,7 @@
}
if (op_code != GATT_HANDLE_VALUE_IND && op_code != GATT_HANDLE_VALUE_NOTIF) {
- gatt_cl_send_next_cmd_inq(p_tcb);
+ gatt_cl_send_next_cmd_inq(tcb);
}
return;
diff --git a/stack/gatt/gatt_db.cc b/stack/gatt/gatt_db.cc
index 736958d..2819b0d 100644
--- a/stack/gatt/gatt_db.cc
+++ b/stack/gatt/gatt_db.cc
@@ -40,7 +40,7 @@
static tGATT_ATTR& allocate_attr_in_db(tGATT_SVC_DB& db, const tBT_UUID& uuid,
tGATT_PERM perm);
static tGATT_STATUS gatts_send_app_read_request(
- tGATT_TCB* p_tcb, uint8_t op_code, uint16_t handle, uint16_t offset,
+ tGATT_TCB& tcb, uint8_t op_code, uint16_t handle, uint16_t offset,
uint32_t trans_id, bt_gatt_db_attribute_type_t gatt_type);
/**
@@ -247,7 +247,7 @@
*
******************************************************************************/
tGATT_STATUS gatts_db_read_attr_value_by_type(
- tGATT_TCB* p_tcb, tGATT_SVC_DB* p_db, uint8_t op_code, BT_HDR* p_rsp,
+ tGATT_TCB& tcb, tGATT_SVC_DB* p_db, uint8_t op_code, BT_HDR* p_rsp,
uint16_t s_handle, uint16_t e_handle, tBT_UUID type, uint16_t* p_len,
tGATT_SEC_FLAG sec_flag, uint8_t key_size, uint32_t trans_id,
uint16_t* p_cur_handle) {
@@ -271,7 +271,7 @@
&len, sec_flag, key_size);
if (status == GATT_PENDING) {
- status = gatts_send_app_read_request(p_tcb, op_code, attr.handle, 0,
+ status = gatts_send_app_read_request(tcb, op_code, attr.handle, 0,
trans_id, attr.gatt_type);
/* one callback at a time */
@@ -297,14 +297,14 @@
#if (BLE_DELAY_REQUEST_ENC == TRUE)
uint8_t flag = 0;
- if (BTM_GetSecurityFlags(p_tcb->peer_bda, &flag)) {
- if ((p_tcb->att_lcid == L2CAP_ATT_CID) && (status == GATT_PENDING) &&
+ if (BTM_GetSecurityFlags(tcb.peer_bda, &flag)) {
+ if ((tcb.att_lcid == L2CAP_ATT_CID) && (status == GATT_PENDING) &&
(type.uu.uuid16 == GATT_UUID_GAP_DEVICE_NAME)) {
if ((flag & (BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_FLAG_ENCRYPTED)) ==
BTM_SEC_LINK_KEY_KNOWN) {
- tACL_CONN* p = btm_bda_to_acl(p_tcb->peer_bda, BT_TRANSPORT_LE);
+ tACL_CONN* p = btm_bda_to_acl(tcb.peer_bda, BT_TRANSPORT_LE);
if ((p != NULL) && (p->link_role == BTM_ROLE_MASTER))
- btm_ble_set_encryption(p_tcb->peer_bda, BTM_BLE_SEC_ENCRYPT,
+ btm_ble_set_encryption(tcb.peer_bda, BTM_BLE_SEC_ENCRYPT,
p->link_role);
}
}
@@ -474,7 +474,7 @@
*
******************************************************************************/
tGATT_STATUS gatts_read_attr_value_by_handle(
- tGATT_TCB* p_tcb, tGATT_SVC_DB* p_db, uint8_t op_code, uint16_t handle,
+ tGATT_TCB& tcb, tGATT_SVC_DB* p_db, uint8_t op_code, uint16_t handle,
uint16_t offset, uint8_t* p_value, uint16_t* p_len, uint16_t mtu,
tGATT_SEC_FLAG sec_flag, uint8_t key_size, uint32_t trans_id) {
tGATT_ATTR* p_attr = find_attr_by_handle(p_db, handle);
@@ -486,7 +486,7 @@
mtu, p_len, sec_flag, key_size);
if (status == GATT_PENDING) {
- status = gatts_send_app_read_request(p_tcb, op_code, p_attr->handle, offset,
+ status = gatts_send_app_read_request(tcb, op_code, p_attr->handle, offset,
trans_id, p_attr->gatt_type);
}
return status;
@@ -736,14 +736,14 @@
*
******************************************************************************/
static tGATT_STATUS gatts_send_app_read_request(
- tGATT_TCB* p_tcb, uint8_t op_code, uint16_t handle, uint16_t offset,
+ tGATT_TCB& tcb, uint8_t op_code, uint16_t handle, uint16_t offset,
uint32_t trans_id, bt_gatt_db_attribute_type_t gatt_type) {
tGATT_SRV_LIST_ELEM& el = *gatt_sr_find_i_rcb_by_handle(handle);
- uint16_t conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, el.gatt_if);
+ uint16_t conn_id = GATT_CREATE_CONN_ID(tcb.tcb_idx, el.gatt_if);
if (trans_id == 0) {
- trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, handle);
- gatt_sr_update_cback_cnt(p_tcb, el.gatt_if, true, true);
+ trans_id = gatt_sr_enqueue_cmd(tcb, op_code, handle);
+ gatt_sr_update_cback_cnt(tcb, el.gatt_if, true, true);
}
if (trans_id != 0) {
diff --git a/stack/gatt/gatt_int.h b/stack/gatt/gatt_int.h
index 812d156..bb9186f 100644
--- a/stack/gatt/gatt_int.h
+++ b/stack/gatt/gatt_int.h
@@ -29,6 +29,7 @@
#include <string.h>
#include <list>
+#include <unordered_set>
#include <vector>
#define GATT_CREATE_CONN_ID(tcb_idx, gatt_if) \
@@ -194,10 +195,12 @@
uint8_t listening; /* if adv for all has been enabled */
} tGATT_REG;
+struct tGATT_CLCB;
+
/* command queue for each connection */
typedef struct {
BT_HDR* p_cmd;
- uint16_t clcb_idx;
+ tGATT_CLCB* p_clcb;
uint8_t op_code;
bool to_send;
} tGATT_CMD_Q;
@@ -261,7 +264,7 @@
} tGATT_SRV_LIST_ELEM;
typedef struct {
- fixed_queue_t* pending_enc_clcb; /* pending encryption channel q */
+ std::queue<tGATT_CLCB*> pending_enc_clcb; /* pending encryption channel q */
tGATT_SEC_ACTION sec_act;
BD_ADDR peer_bda;
tBT_TRANSPORT transport;
@@ -273,7 +276,7 @@
tGATT_CH_STATE ch_state;
uint8_t ch_flags;
- tGATT_IF app_hold_link[GATT_MAX_APPS];
+ std::unordered_set<uint8_t> app_hold_link;
/* server needs */
/* server response data */
@@ -286,10 +289,8 @@
uint8_t prep_cnt[GATT_MAX_APPS];
uint8_t ind_count;
- tGATT_CMD_Q cl_cmd_q[GATT_CL_MAX_LCB];
+ std::queue<tGATT_CMD_Q> cl_cmd_q;
alarm_t* ind_ack_timer; /* local app confirm to indication timer */
- uint8_t pending_cl_req;
- uint8_t next_slot_inq; /* index of next available slot in queue */
bool in_use;
uint8_t tcb_idx;
@@ -302,14 +303,13 @@
tGATT_DISC_RES result;
bool wait_for_read_rsp;
} tGATT_READ_INC_UUID128;
-typedef struct {
+struct tGATT_CLCB {
tGATT_TCB* p_tcb; /* associated TCB of this CLCB */
tGATT_REG* p_reg; /* owner of this CLCB */
uint8_t sccb_idx;
uint8_t* p_attr_buf; /* attribute buffer for read multiple, prepare write */
tBT_UUID uuid;
uint16_t conn_id; /* connection handle */
- uint16_t clcb_idx;
uint16_t s_handle; /* starting handle of the active request */
uint16_t e_handle; /* ending handle of the active request */
uint16_t counter; /* used as offset, attribute length, num of prepare write */
@@ -323,15 +323,7 @@
bool in_use;
alarm_t* gatt_rsp_timer_ent; /* peer response timer */
uint8_t retry_count;
-
-} tGATT_CLCB;
-
-typedef struct { tGATT_CLCB* p_clcb; } tGATT_PENDING_ENC_CLCB;
-
-typedef struct {
- uint16_t clcb_idx;
- bool in_use;
-} tGATT_SCCB;
+};
typedef struct {
uint16_t handle;
@@ -340,9 +332,8 @@
} tGATT_SVC_CHG;
typedef struct {
- tGATT_IF gatt_if[GATT_MAX_APPS];
+ std::unordered_set<tGATT_IF> gatt_if;
BD_ADDR remote_bda;
- bool in_use;
} tGATT_BG_CONN_DEV;
#define GATT_SVC_CHANGED_CONNECTING 1 /* wait for connection */
@@ -379,8 +370,6 @@
fixed_queue_t* srv_chg_clt_q; /* service change clients queue */
tGATT_REG cl_rcb[GATT_MAX_APPS];
tGATT_CLCB clcb[GATT_CL_MAX_LCB]; /* connection link control block*/
- tGATT_SCCB sccb[GATT_MAX_SCCB]; /* sign complete callback function
- GATT_MAX_SCCB <= GATT_CL_MAX_LCB */
uint8_t trace_level;
uint16_t def_mtu_size;
@@ -398,8 +387,7 @@
tGATT_APPL_INFO cb_info;
tGATT_HDL_CFG hdl_cfg;
- tGATT_BG_CONN_DEV bgconn_dev[GATT_MAX_BG_CONN_DEV];
-
+ std::list<tGATT_BG_CONN_DEV> bgconn_dev;
} tGATT_CB;
#define GATT_SIZE_OF_SRV_CHG_HNDL_RANGE 4
@@ -419,7 +407,7 @@
int8_t initiating_phys);
extern bool gatt_connect(BD_ADDR rem_bda, tGATT_TCB* p_tcb,
tBT_TRANSPORT transport, uint8_t initiating_phys);
-extern void gatt_data_process(tGATT_TCB* p_tcb, BT_HDR* p_buf);
+extern void gatt_data_process(tGATT_TCB& p_tcb, BT_HDR* p_buf);
extern void gatt_update_app_use_link_flag(tGATT_IF gatt_if, tGATT_TCB* p_tcb,
bool is_add, bool check_acl_link);
@@ -436,12 +424,12 @@
extern uint16_t gatt_profile_find_conn_id_by_bd_addr(BD_ADDR bda);
/* Functions provided by att_protocol.cc */
-extern tGATT_STATUS attp_send_cl_msg(tGATT_TCB* p_tcb, uint16_t clcb_idx,
+extern tGATT_STATUS attp_send_cl_msg(tGATT_TCB& tcb, tGATT_CLCB* p_clcb,
uint8_t op_code, tGATT_CL_MSG* p_msg);
-extern BT_HDR* attp_build_sr_msg(tGATT_TCB* p_tcb, uint8_t op_code,
+extern BT_HDR* attp_build_sr_msg(tGATT_TCB& tcb, uint8_t op_code,
tGATT_SR_MSG* p_msg);
-extern tGATT_STATUS attp_send_sr_msg(tGATT_TCB* p_tcb, BT_HDR* p_msg);
-extern tGATT_STATUS attp_send_msg_to_l2cap(tGATT_TCB* p_tcb, BT_HDR* p_toL2CAP);
+extern tGATT_STATUS attp_send_sr_msg(tGATT_TCB& tcb, BT_HDR* p_msg);
+extern tGATT_STATUS attp_send_msg_to_l2cap(tGATT_TCB& tcb, BT_HDR* p_toL2CAP);
/* utility functions */
extern uint8_t* gatt_dbg_op_name(uint8_t op_code);
@@ -455,18 +443,16 @@
uint32_t uuid_32);
extern void gatt_sr_get_sec_info(BD_ADDR rem_bda, tBT_TRANSPORT transport,
uint8_t* p_sec_flag, uint8_t* p_key_size);
-extern void gatt_start_rsp_timer(uint16_t clcb_idx);
+extern void gatt_start_rsp_timer(tGATT_CLCB* p_clcb);
extern void gatt_start_conf_timer(tGATT_TCB* p_tcb);
extern void gatt_rsp_timeout(void* data);
extern void gatt_indication_confirmation_timeout(void* data);
extern void gatt_ind_ack_timeout(void* data);
-extern void gatt_start_ind_ack_timer(tGATT_TCB* p_tcb);
-extern tGATT_STATUS gatt_send_error_rsp(tGATT_TCB* p_tcb, uint8_t err_code,
+extern void gatt_start_ind_ack_timer(tGATT_TCB& tcb);
+extern tGATT_STATUS gatt_send_error_rsp(tGATT_TCB& tcb, uint8_t err_code,
uint8_t op_code, uint16_t handle,
bool 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 bool gatt_is_srv_chg_ind_pending(tGATT_TCB* p_tcb);
extern tGATTS_SRV_CHG* gatt_is_bda_in_the_srv_chg_clt_list(BD_ADDR bda);
@@ -478,7 +464,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 void gatt_free_srvc_db_buffer_app_id(tBT_UUID* p_app_id);
-extern bool gatt_cl_send_next_cmd_inq(tGATT_TCB* p_tcb);
+extern bool gatt_cl_send_next_cmd_inq(tGATT_TCB& tcb);
/* reserved handle list */
extern std::list<tGATT_HDL_LIST_ELEM>::iterator gatt_find_hdl_buffer_by_app_id(
@@ -491,8 +477,7 @@
BD_ADDR bd_addr);
extern bool gatt_is_bg_dev_for_app(tGATT_BG_CONN_DEV* p_dev, tGATT_IF gatt_if);
extern bool gatt_remove_bg_dev_for_app(tGATT_IF gatt_if, BD_ADDR bd_addr);
-extern uint8_t gatt_get_num_apps_for_bg_dev(BD_ADDR bd_addr);
-extern bool gatt_find_app_for_bg_dev(BD_ADDR bd_addr, tGATT_IF* p_gatt_if);
+extern uint8_t gatt_clear_bg_dev_for_addr(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);
@@ -502,15 +487,15 @@
extern bool gatt_sr_find_i_rcb_by_app_id(tBT_UUID* p_app_uuid128,
tBT_UUID* p_svc_uuid,
uint16_t svc_inst);
-extern tGATT_STATUS gatt_sr_process_app_rsp(tGATT_TCB* p_tcb, tGATT_IF gatt_if,
+extern tGATT_STATUS gatt_sr_process_app_rsp(tGATT_TCB& tcb, tGATT_IF gatt_if,
uint32_t trans_id, uint8_t op_code,
tGATT_STATUS status,
tGATTS_RSP* p_msg);
-extern void gatt_server_handle_client_req(tGATT_TCB* p_tcb, uint8_t op_code,
+extern void gatt_server_handle_client_req(tGATT_TCB& p_tcb, uint8_t op_code,
uint16_t len, uint8_t* p_data);
extern void gatt_sr_send_req_callback(uint16_t conn_id, uint32_t trans_id,
uint8_t op_code, tGATTS_DATA* p_req_data);
-extern uint32_t gatt_sr_enqueue_cmd(tGATT_TCB* p_tcb, uint8_t op_code,
+extern uint32_t gatt_sr_enqueue_cmd(tGATT_TCB& tcb, uint8_t op_code,
uint16_t handle);
extern bool gatt_cancel_open(tGATT_IF gatt_if, BD_ADDR bda);
extern void gatt_notify_phy_updated(tGATT_TCB* p_tcb, uint8_t tx_phy,
@@ -523,19 +508,16 @@
extern tGATT_CLCB* gatt_clcb_alloc(uint16_t conn_id);
extern void gatt_clcb_dealloc(tGATT_CLCB* p_clcb);
-extern void gatt_sr_copy_prep_cnt_to_cback_cnt(tGATT_TCB* p_tcb);
-extern bool gatt_sr_is_cback_cnt_zero(tGATT_TCB* p_tcb);
-extern bool gatt_sr_is_prep_cnt_zero(tGATT_TCB* p_tcb);
-extern void gatt_sr_reset_cback_cnt(tGATT_TCB* p_tcb);
-extern void gatt_sr_reset_prep_cnt(tGATT_TCB* p_tcb);
-extern void gatt_sr_update_cback_cnt(tGATT_TCB* p_tcb, tGATT_IF gatt_if,
+extern void gatt_sr_copy_prep_cnt_to_cback_cnt(tGATT_TCB& p_tcb);
+extern bool gatt_sr_is_cback_cnt_zero(tGATT_TCB& p_tcb);
+extern bool gatt_sr_is_prep_cnt_zero(tGATT_TCB& p_tcb);
+extern void gatt_sr_reset_cback_cnt(tGATT_TCB& p_tcb);
+extern void gatt_sr_reset_prep_cnt(tGATT_TCB& tcb);
+extern void gatt_sr_update_cback_cnt(tGATT_TCB& p_tcb, tGATT_IF gatt_if,
bool is_inc, bool is_reset_first);
-extern void gatt_sr_update_prep_cnt(tGATT_TCB* p_tcb, tGATT_IF gatt_if,
+extern void gatt_sr_update_prep_cnt(tGATT_TCB& tcb, tGATT_IF gatt_if,
bool is_inc, bool is_reset_first);
-extern bool gatt_find_app_hold_link(tGATT_TCB* p_tcb, uint8_t start_idx,
- uint8_t* p_found_idx, tGATT_IF* p_gatt_if);
-extern uint8_t gatt_num_apps_hold_link(tGATT_TCB* p_tcb);
extern uint8_t gatt_num_clcb_by_bd_addr(BD_ADDR bda);
extern tGATT_TCB* gatt_find_tcb_by_cid(uint16_t lcid);
extern tGATT_TCB* gatt_allocate_tcb_by_bdaddr(BD_ADDR bda,
@@ -545,8 +527,8 @@
extern bool gatt_send_ble_burst_data(BD_ADDR remote_bda, BT_HDR* p_buf);
/* GATT client functions */
-extern void gatt_dequeue_sr_cmd(tGATT_TCB* p_tcb);
-extern uint8_t gatt_send_write_msg(tGATT_TCB* p_tcb, uint16_t clcb_idx,
+extern void gatt_dequeue_sr_cmd(tGATT_TCB& tcb);
+extern uint8_t gatt_send_write_msg(tGATT_TCB& p_tcb, tGATT_CLCB* p_clcb,
uint8_t op_code, uint16_t handle,
uint16_t len, uint16_t offset,
uint8_t* p_data);
@@ -558,22 +540,19 @@
extern void gatt_act_discovery(tGATT_CLCB* p_clcb);
extern void gatt_act_read(tGATT_CLCB* p_clcb, uint16_t offset);
extern void gatt_act_write(tGATT_CLCB* p_clcb, uint8_t sec_act);
-extern uint8_t gatt_act_send_browse(tGATT_TCB* p_tcb, uint16_t index,
- uint8_t op, uint16_t s_handle,
- uint16_t e_handle, tBT_UUID uuid);
-extern tGATT_CLCB* gatt_cmd_dequeue(tGATT_TCB* p_tcb, uint8_t* p_opcode);
-extern bool gatt_cmd_enq(tGATT_TCB* p_tcb, uint16_t clcb_idx, bool to_send,
+extern tGATT_CLCB* gatt_cmd_dequeue(tGATT_TCB& tcb, uint8_t* p_opcode);
+extern void gatt_cmd_enq(tGATT_TCB& tcb, tGATT_CLCB* p_clcb, bool to_send,
uint8_t op_code, BT_HDR* p_buf);
-extern void gatt_client_handle_server_rsp(tGATT_TCB* p_tcb, uint8_t op_code,
+extern void gatt_client_handle_server_rsp(tGATT_TCB& tcb, uint8_t op_code,
uint16_t len, uint8_t* p_data);
-extern void gatt_send_queue_write_cancel(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
+extern void gatt_send_queue_write_cancel(tGATT_TCB& tcb, tGATT_CLCB* p_clcb,
tGATT_EXEC_FLAG flag);
/* gatt_auth.cc */
extern bool gatt_security_check_start(tGATT_CLCB* p_clcb);
-extern void gatt_verify_signature(tGATT_TCB* p_tcb, BT_HDR* p_buf);
+extern void gatt_verify_signature(tGATT_TCB& tcb, BT_HDR* p_buf);
extern tGATT_SEC_ACTION gatt_determine_sec_act(tGATT_CLCB* p_clcb);
-extern tGATT_STATUS gatt_get_link_encrypt_status(tGATT_TCB* p_tcb);
+extern tGATT_STATUS gatt_get_link_encrypt_status(tGATT_TCB& tcb);
extern tGATT_SEC_ACTION gatt_get_sec_act(tGATT_TCB* p_tcb);
extern void gatt_set_sec_act(tGATT_TCB* p_tcb, tGATT_SEC_ACTION sec_act);
@@ -589,12 +568,12 @@
extern uint16_t gatts_add_char_descr(tGATT_SVC_DB& db, tGATT_PERM perm,
tBT_UUID& dscp_uuid);
extern tGATT_STATUS gatts_db_read_attr_value_by_type(
- tGATT_TCB* p_tcb, tGATT_SVC_DB* p_db, uint8_t op_code, BT_HDR* p_rsp,
+ tGATT_TCB& tcb, tGATT_SVC_DB* p_db, uint8_t op_code, BT_HDR* p_rsp,
uint16_t s_handle, uint16_t e_handle, tBT_UUID type, uint16_t* p_len,
tGATT_SEC_FLAG sec_flag, uint8_t key_size, uint32_t trans_id,
uint16_t* p_cur_handle);
extern tGATT_STATUS gatts_read_attr_value_by_handle(
- tGATT_TCB* p_tcb, tGATT_SVC_DB* p_db, uint8_t op_code, uint16_t handle,
+ tGATT_TCB& tcb, tGATT_SVC_DB* p_db, uint8_t op_code, uint16_t handle,
uint16_t offset, uint8_t* p_value, uint16_t* p_len, uint16_t mtu,
tGATT_SEC_FLAG sec_flag, uint8_t key_size, uint32_t trans_id);
extern tGATT_STATUS gatts_write_attr_perm_check(
diff --git a/stack/gatt/gatt_main.cc b/stack/gatt/gatt_main.cc
index d375b84..3f5e639 100644
--- a/stack/gatt/gatt_main.cc
+++ b/stack/gatt/gatt_main.cc
@@ -95,7 +95,7 @@
GATT_TRACE_DEBUG("gatt_init()");
- memset(&gatt_cb, 0, sizeof(tGATT_CB));
+ gatt_cb = tGATT_CB();
memset(&fixed_reg, 0, sizeof(tL2CAP_FIXED_CHNL_REG));
#if defined(GATT_INITIAL_TRACE_LEVEL)
@@ -158,8 +158,7 @@
fixed_queue_free(gatt_cb.srv_chg_clt_q, NULL);
gatt_cb.srv_chg_clt_q = NULL;
for (i = 0; i < GATT_MAX_PHY_CHANNEL; i++) {
- fixed_queue_free(gatt_cb.tcb[i].pending_enc_clcb, NULL);
- gatt_cb.tcb[i].pending_enc_clcb = NULL;
+ gatt_cb.tcb[i].pending_enc_clcb = std::queue<tGATT_CLCB*>();
fixed_queue_free(gatt_cb.tcb[i].pending_ind_q, NULL);
gatt_cb.tcb[i].pending_ind_q = NULL;
@@ -267,29 +266,28 @@
******************************************************************************/
bool gatt_update_app_hold_link_status(tGATT_IF gatt_if, tGATT_TCB* p_tcb,
bool is_add) {
- for (int i = 0; i < GATT_MAX_APPS; i++) {
- if (p_tcb->app_hold_link[i] == gatt_if && is_add) {
- GATT_TRACE_DEBUG("%s: gatt_if %d already exists at idx %d", __func__,
- gatt_if, i);
- return true;
+ auto& holders = p_tcb->app_hold_link;
+
+ if (is_add) {
+ auto ret = holders.insert(gatt_if);
+ if (ret.second) {
+ GATT_TRACE_DEBUG("%s: added gatt_if=%d", __func__, gatt_if);
+ } else {
+ GATT_TRACE_DEBUG("%s: attempt to add already existing gatt_if=%d",
+ __func__, gatt_if);
}
+ return true;
}
- for (int i = 0; i < GATT_MAX_APPS; i++) {
- if (p_tcb->app_hold_link[i] == 0 && is_add) {
- p_tcb->app_hold_link[i] = gatt_if;
- GATT_TRACE_DEBUG("%s: added gatt_if=%d idx=%d ", __func__, gatt_if, i);
- return true;
- } else if (p_tcb->app_hold_link[i] == gatt_if && !is_add) {
- p_tcb->app_hold_link[i] = 0;
- GATT_TRACE_DEBUG("%s: removed gatt_if=%d idx=%d", __func__, gatt_if, i);
- return true;
- }
+ //! is_add
+ if (!holders.erase(gatt_if)) {
+ GATT_TRACE_DEBUG("%s: attempt to remove nonexisting gatt_if=%d", __func__,
+ gatt_if);
+ return false;
}
- GATT_TRACE_DEBUG("%s: gatt_if=%d not found; is_add=%d", __func__, gatt_if,
- is_add);
- return false;
+ GATT_TRACE_DEBUG("%s: removed gatt_if=%d", __func__, gatt_if);
+ return true;
}
/*******************************************************************************
@@ -328,7 +326,7 @@
GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_NO_IDLE_TIMEOUT,
p_tcb->transport);
} else {
- if (!gatt_num_apps_hold_link(p_tcb)) {
+ if (p_tcb->app_hold_link.empty()) {
/* acl link is connected but no application needs to use the link
so set the timeout value to GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP seconds
*/
@@ -362,7 +360,7 @@
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 (st == GATT_CH_OPEN && p_tcb->app_hold_link.empty() &&
transport == BT_TRANSPORT_LE) {
if (!gatt_connect(bd_addr, p_tcb, transport, initiating_phys))
ret = false;
@@ -375,9 +373,8 @@
if (p_tcb != NULL) {
if (!gatt_connect(bd_addr, p_tcb, transport, initiating_phys)) {
GATT_TRACE_ERROR("gatt_connect failed");
- fixed_queue_free(p_tcb->pending_enc_clcb, NULL);
fixed_queue_free(p_tcb->pending_ind_q, NULL);
- memset(p_tcb, 0, sizeof(tGATT_TCB));
+ *p_tcb = tGATT_TCB();
} else
ret = true;
} else {
@@ -485,7 +482,7 @@
/* if uncongested, check to see if there is any more pending data */
if (p_tcb != NULL && congested == false) {
- gatt_cl_send_next_cmd_inq(p_tcb);
+ gatt_cl_send_next_cmd_inq(*p_tcb);
}
/* notifying all applications for the connection up event */
for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) {
@@ -571,17 +568,15 @@
tGATT_TCB* p_tcb;
/* Find CCB based on bd addr */
- if ((p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE)) != NULL &&
- gatt_get_ch_state(p_tcb) >= GATT_CH_OPEN) {
- gatt_data_process(p_tcb, p_buf);
- } else {
- osi_free(p_buf);
-
- if (p_tcb != NULL) {
+ if ((p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE)) != NULL) {
+ if (gatt_get_ch_state(p_tcb) < GATT_CH_OPEN) {
GATT_TRACE_WARNING("ATT - Ignored L2CAP data while in state: %d",
gatt_get_ch_state(p_tcb));
- }
+ } else
+ gatt_data_process(*p_tcb, p_buf);
}
+
+ osi_free(p_buf);
}
/*******************************************************************************
@@ -870,9 +865,10 @@
if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL &&
gatt_get_ch_state(p_tcb) == GATT_CH_OPEN) {
/* process the data */
- gatt_data_process(p_tcb, p_buf);
- } else /* prevent buffer leak */
- osi_free(p_buf);
+ gatt_data_process(*p_tcb, p_buf);
+ }
+
+ osi_free(p_buf);
}
/*******************************************************************************
@@ -905,10 +901,9 @@
static void gatt_send_conn_cback(tGATT_TCB* p_tcb) {
uint8_t i;
tGATT_REG* p_reg;
- tGATT_BG_CONN_DEV* p_bg_dev = NULL;
uint16_t conn_id;
- p_bg_dev = gatt_find_bg_dev(p_tcb->peer_bda);
+ tGATT_BG_CONN_DEV* 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++) {
@@ -924,7 +919,7 @@
}
}
- if (gatt_num_apps_hold_link(p_tcb) && p_tcb->att_lcid == L2CAP_ATT_CID) {
+ if (!p_tcb->app_hold_link.empty() && p_tcb->att_lcid == L2CAP_ATT_CID) {
/* disable idle timeout if one or more clients are holding the link disable
* the idle timer */
GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_NO_IDLE_TIMEOUT,
@@ -948,36 +943,35 @@
* Returns void
*
******************************************************************************/
-void gatt_data_process(tGATT_TCB* p_tcb, BT_HDR* p_buf) {
+void gatt_data_process(tGATT_TCB& tcb, BT_HDR* p_buf) {
uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset;
uint8_t op_code, pseudo_op_code;
- uint16_t msg_len;
- if (p_buf->len > 0) {
- msg_len = p_buf->len - 1;
- STREAM_TO_UINT8(op_code, p);
-
- /* remove the two MSBs associated with sign write and write cmd */
- pseudo_op_code = op_code & (~GATT_WRITE_CMD_MASK);
-
- if (pseudo_op_code < GATT_OP_CODE_MAX) {
- if (op_code == GATT_SIGN_CMD_WRITE) {
- gatt_verify_signature(p_tcb, p_buf);
- } else {
- /* message from client */
- if ((op_code % 2) == 0)
- gatt_server_handle_client_req(p_tcb, op_code, msg_len, p);
- else
- gatt_client_handle_server_rsp(p_tcb, op_code, msg_len, p);
- }
- } else {
- GATT_TRACE_ERROR("ATT - Rcvd L2CAP data, unknown cmd: 0x%x", op_code);
- }
- } else {
+ if (p_buf->len <= 0) {
GATT_TRACE_ERROR("invalid data length, ignore");
+ return;
}
- osi_free(p_buf);
+ uint16_t msg_len = p_buf->len - 1;
+ STREAM_TO_UINT8(op_code, p);
+
+ /* remove the two MSBs associated with sign write and write cmd */
+ pseudo_op_code = op_code & (~GATT_WRITE_CMD_MASK);
+
+ if (pseudo_op_code >= GATT_OP_CODE_MAX) {
+ GATT_TRACE_ERROR("ATT - Rcvd L2CAP data, unknown cmd: 0x%x", op_code);
+ return;
+ }
+
+ if (op_code == GATT_SIGN_CMD_WRITE) {
+ gatt_verify_signature(tcb, p_buf);
+ } else {
+ /* message from client */
+ if ((op_code % 2) == 0)
+ gatt_server_handle_client_req(tcb, op_code, msg_len, p);
+ else
+ gatt_client_handle_server_rsp(tcb, op_code, msg_len, p);
+ }
}
/*******************************************************************************
diff --git a/stack/gatt/gatt_sr.cc b/stack/gatt/gatt_sr.cc
index a999193..2b332d9 100644
--- a/stack/gatt/gatt_sr.cc
+++ b/stack/gatt/gatt_sr.cc
@@ -42,9 +42,8 @@
* Returns void
*
******************************************************************************/
-uint32_t gatt_sr_enqueue_cmd(tGATT_TCB* p_tcb, uint8_t op_code,
- uint16_t handle) {
- tGATT_SR_CMD* p_cmd = &p_tcb->sr_cmd;
+uint32_t gatt_sr_enqueue_cmd(tGATT_TCB& tcb, uint8_t op_code, uint16_t handle) {
+ tGATT_SR_CMD* p_cmd = &tcb.sr_cmd;
uint32_t trans_id = 0;
if ((p_cmd->op_code == 0) ||
@@ -52,13 +51,13 @@
{
if (op_code == GATT_CMD_WRITE || op_code == GATT_SIGN_CMD_WRITE ||
op_code == GATT_REQ_MTU || op_code == GATT_HANDLE_VALUE_CONF) {
- trans_id = ++p_tcb->trans_id;
+ trans_id = ++tcb.trans_id;
} else {
- p_cmd->trans_id = ++p_tcb->trans_id;
+ p_cmd->trans_id = ++tcb.trans_id;
p_cmd->op_code = op_code;
p_cmd->handle = handle;
p_cmd->status = GATT_NOT_FOUND;
- p_tcb->trans_id %= GATT_TRANS_ID_MAX;
+ tcb.trans_id %= GATT_TRANS_ID_MAX;
trans_id = p_cmd->trans_id;
}
}
@@ -75,9 +74,7 @@
* Returns true if empty, false if there is pending command.
*
******************************************************************************/
-bool gatt_sr_cmd_empty(tGATT_TCB* p_tcb) {
- return (p_tcb->sr_cmd.op_code == 0);
-}
+bool gatt_sr_cmd_empty(tGATT_TCB& tcb) { return (tcb.sr_cmd.op_code == 0); }
/*******************************************************************************
*
@@ -88,18 +85,17 @@
* Returns void
*
******************************************************************************/
-void gatt_dequeue_sr_cmd(tGATT_TCB* p_tcb) {
+void gatt_dequeue_sr_cmd(tGATT_TCB& tcb) {
/* Double check in case any buffers are queued */
GATT_TRACE_DEBUG("gatt_dequeue_sr_cmd");
- if (p_tcb->sr_cmd.p_rsp_msg)
- GATT_TRACE_ERROR("free p_tcb->sr_cmd.p_rsp_msg = %d",
- p_tcb->sr_cmd.p_rsp_msg);
- osi_free_and_reset((void**)&p_tcb->sr_cmd.p_rsp_msg);
+ if (tcb.sr_cmd.p_rsp_msg)
+ GATT_TRACE_ERROR("free tcb.sr_cmd.p_rsp_msg = %d", tcb.sr_cmd.p_rsp_msg);
+ osi_free_and_reset((void**)&tcb.sr_cmd.p_rsp_msg);
- while (!fixed_queue_is_empty(p_tcb->sr_cmd.multi_rsp_q))
- osi_free(fixed_queue_try_dequeue(p_tcb->sr_cmd.multi_rsp_q));
- fixed_queue_free(p_tcb->sr_cmd.multi_rsp_q, NULL);
- memset(&p_tcb->sr_cmd, 0, sizeof(tGATT_SR_CMD));
+ while (!fixed_queue_is_empty(tcb.sr_cmd.multi_rsp_q))
+ osi_free(fixed_queue_try_dequeue(tcb.sr_cmd.multi_rsp_q));
+ fixed_queue_free(tcb.sr_cmd.multi_rsp_q, NULL);
+ memset(&tcb.sr_cmd, 0, sizeof(tGATT_SR_CMD));
}
/*******************************************************************************
@@ -225,52 +221,51 @@
* Returns void
*
******************************************************************************/
-tGATT_STATUS gatt_sr_process_app_rsp(tGATT_TCB* p_tcb, tGATT_IF gatt_if,
+tGATT_STATUS gatt_sr_process_app_rsp(tGATT_TCB& tcb, tGATT_IF gatt_if,
UNUSED_ATTR uint32_t trans_id,
uint8_t op_code, tGATT_STATUS status,
tGATTS_RSP* p_msg) {
tGATT_STATUS ret_code = GATT_SUCCESS;
- GATT_TRACE_DEBUG("gatt_sr_process_app_rsp gatt_if=%d", gatt_if);
+ GATT_TRACE_DEBUG("%s gatt_if=%d", __func__, gatt_if);
- gatt_sr_update_cback_cnt(p_tcb, gatt_if, false, false);
+ gatt_sr_update_cback_cnt(tcb, gatt_if, false, false);
if (op_code == GATT_REQ_READ_MULTI) {
/* If no error and still waiting, just return */
- if (!process_read_multi_rsp(&p_tcb->sr_cmd, status, p_msg,
- p_tcb->payload_size))
+ if (!process_read_multi_rsp(&tcb.sr_cmd, status, p_msg, tcb.payload_size))
return (GATT_SUCCESS);
} else {
if (op_code == GATT_REQ_PREPARE_WRITE && status == GATT_SUCCESS)
- gatt_sr_update_prep_cnt(p_tcb, gatt_if, true, false);
+ gatt_sr_update_prep_cnt(tcb, gatt_if, true, false);
if (op_code == GATT_REQ_EXEC_WRITE && status != GATT_SUCCESS)
- gatt_sr_reset_cback_cnt(p_tcb);
+ gatt_sr_reset_cback_cnt(tcb);
- p_tcb->sr_cmd.status = status;
+ tcb.sr_cmd.status = status;
- if (gatt_sr_is_cback_cnt_zero(p_tcb) && status == GATT_SUCCESS) {
- if (p_tcb->sr_cmd.p_rsp_msg == NULL) {
- p_tcb->sr_cmd.p_rsp_msg = attp_build_sr_msg(
- p_tcb, (uint8_t)(op_code + 1), (tGATT_SR_MSG*)p_msg);
+ if (gatt_sr_is_cback_cnt_zero(tcb) && status == GATT_SUCCESS) {
+ if (tcb.sr_cmd.p_rsp_msg == NULL) {
+ tcb.sr_cmd.p_rsp_msg = attp_build_sr_msg(tcb, (uint8_t)(op_code + 1),
+ (tGATT_SR_MSG*)p_msg);
} else {
GATT_TRACE_ERROR("Exception!!! already has respond message");
}
}
}
- if (gatt_sr_is_cback_cnt_zero(p_tcb)) {
- if ((p_tcb->sr_cmd.status == GATT_SUCCESS) && (p_tcb->sr_cmd.p_rsp_msg)) {
- ret_code = attp_send_sr_msg(p_tcb, p_tcb->sr_cmd.p_rsp_msg);
- p_tcb->sr_cmd.p_rsp_msg = NULL;
+ if (gatt_sr_is_cback_cnt_zero(tcb)) {
+ if ((tcb.sr_cmd.status == GATT_SUCCESS) && (tcb.sr_cmd.p_rsp_msg)) {
+ ret_code = attp_send_sr_msg(tcb, tcb.sr_cmd.p_rsp_msg);
+ tcb.sr_cmd.p_rsp_msg = NULL;
} else {
- ret_code = gatt_send_error_rsp(p_tcb, status, op_code,
- p_tcb->sr_cmd.handle, false);
+ ret_code =
+ gatt_send_error_rsp(tcb, status, op_code, tcb.sr_cmd.handle, false);
}
- gatt_dequeue_sr_cmd(p_tcb);
+ gatt_dequeue_sr_cmd(tcb);
}
- GATT_TRACE_DEBUG("gatt_sr_process_app_rsp ret_code=%d", ret_code);
+ GATT_TRACE_DEBUG("%s ret_code=%d", __func__, ret_code);
return ret_code;
}
@@ -285,7 +280,7 @@
* Returns void
*
******************************************************************************/
-void gatt_process_exec_write_req(tGATT_TCB* p_tcb, uint8_t op_code,
+void gatt_process_exec_write_req(tGATT_TCB& tcb, uint8_t op_code,
UNUSED_ATTR uint16_t len, uint8_t* p_data) {
uint8_t *p = p_data, flag, i = 0;
uint32_t trans_id = 0;
@@ -298,7 +293,7 @@
"Conformance tst: forced err rspv for Execute Write: error status=%d",
gatt_cb.err_status);
- gatt_send_error_rsp(p_tcb, gatt_cb.err_status, gatt_cb.req_op_code,
+ gatt_send_error_rsp(tcb, gatt_cb.err_status, gatt_cb.req_op_code,
gatt_cb.handle, false);
return;
@@ -311,23 +306,23 @@
flag &= GATT_PREP_WRITE_EXEC;
/* no prep write is queued */
- if (!gatt_sr_is_prep_cnt_zero(p_tcb)) {
- trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, 0);
- gatt_sr_copy_prep_cnt_to_cback_cnt(p_tcb);
+ if (!gatt_sr_is_prep_cnt_zero(tcb)) {
+ trans_id = gatt_sr_enqueue_cmd(tcb, op_code, 0);
+ gatt_sr_copy_prep_cnt_to_cback_cnt(tcb);
for (i = 0; i < GATT_MAX_APPS; i++) {
- if (p_tcb->prep_cnt[i]) {
+ if (tcb.prep_cnt[i]) {
gatt_if = (tGATT_IF)(i + 1);
- conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
+ conn_id = GATT_CREATE_CONN_ID(tcb.tcb_idx, gatt_if);
gatt_sr_send_req_callback(conn_id, trans_id, GATTS_REQ_TYPE_WRITE_EXEC,
(tGATTS_DATA*)&flag);
- p_tcb->prep_cnt[i] = 0;
+ tcb.prep_cnt[i] = 0;
}
}
} else /* nothing needs to be executed , send response now */
{
GATT_TRACE_ERROR("gatt_process_exec_write_req: no prepare write pending");
- gatt_send_error_rsp(p_tcb, GATT_ERROR, GATT_REQ_EXEC_WRITE, 0, false);
+ gatt_send_error_rsp(tcb, GATT_ERROR, GATT_REQ_EXEC_WRITE, 0, false);
}
}
@@ -341,8 +336,8 @@
* Returns void
*
******************************************************************************/
-void gatt_process_read_multi_req(tGATT_TCB* p_tcb, uint8_t op_code,
- uint16_t len, uint8_t* p_data) {
+void gatt_process_read_multi_req(tGATT_TCB& tcb, uint8_t op_code, uint16_t len,
+ uint8_t* p_data) {
uint32_t trans_id;
uint16_t handle = 0, ll = len;
uint8_t* p = p_data;
@@ -350,9 +345,9 @@
uint8_t sec_flag, key_size;
GATT_TRACE_DEBUG("gatt_process_read_multi_req");
- p_tcb->sr_cmd.multi_req.num_handles = 0;
+ tcb.sr_cmd.multi_req.num_handles = 0;
- gatt_sr_get_sec_info(p_tcb->peer_bda, p_tcb->transport, &sec_flag, &key_size);
+ gatt_sr_get_sec_info(tcb.peer_bda, tcb.transport, &sec_flag, &key_size);
#if (GATT_CONFORMANCE_TESTING == TRUE)
if (gatt_cb.enable_err_rsp && gatt_cb.req_op_code == op_code) {
@@ -362,7 +357,7 @@
STREAM_TO_UINT16(handle, p);
- gatt_send_error_rsp(p_tcb, gatt_cb.err_status, gatt_cb.req_op_code, handle,
+ gatt_send_error_rsp(tcb, gatt_cb.err_status, gatt_cb.req_op_code, handle,
false);
return;
@@ -370,13 +365,12 @@
#endif
while (ll >= 2 &&
- p_tcb->sr_cmd.multi_req.num_handles < GATT_MAX_READ_MULTI_HANDLES) {
+ tcb.sr_cmd.multi_req.num_handles < GATT_MAX_READ_MULTI_HANDLES) {
STREAM_TO_UINT16(handle, p);
auto it = gatt_sr_find_i_rcb_by_handle(handle);
if (it != gatt_cb.srv_list_info->end()) {
- p_tcb->sr_cmd.multi_req.handles[p_tcb->sr_cmd.multi_req.num_handles++] =
- handle;
+ tcb.sr_cmd.multi_req.handles[tcb.sr_cmd.multi_req.num_handles++] = handle;
/* check read permission */
err = gatts_read_attr_perm_check(it->p_db, false, handle, sec_flag,
@@ -397,27 +391,27 @@
GATT_TRACE_ERROR("max attribute handle reached in ReadMultiple Request.");
}
- if (p_tcb->sr_cmd.multi_req.num_handles == 0) err = GATT_INVALID_HANDLE;
+ if (tcb.sr_cmd.multi_req.num_handles == 0) err = GATT_INVALID_HANDLE;
if (err == GATT_SUCCESS) {
trans_id =
- gatt_sr_enqueue_cmd(p_tcb, op_code, p_tcb->sr_cmd.multi_req.handles[0]);
+ gatt_sr_enqueue_cmd(tcb, op_code, tcb.sr_cmd.multi_req.handles[0]);
if (trans_id != 0) {
- gatt_sr_reset_cback_cnt(p_tcb); /* read multiple use multi_rsp_q's count*/
+ gatt_sr_reset_cback_cnt(tcb); /* read multiple use multi_rsp_q's count*/
- for (ll = 0; ll < p_tcb->sr_cmd.multi_req.num_handles; ll++) {
+ for (ll = 0; ll < tcb.sr_cmd.multi_req.num_handles; ll++) {
tGATTS_RSP* p_msg = (tGATTS_RSP*)osi_calloc(sizeof(tGATTS_RSP));
- handle = p_tcb->sr_cmd.multi_req.handles[ll];
+ handle = tcb.sr_cmd.multi_req.handles[ll];
auto it = gatt_sr_find_i_rcb_by_handle(handle);
p_msg->attr_value.handle = handle;
err = gatts_read_attr_value_by_handle(
- p_tcb, it->p_db, op_code, handle, 0, p_msg->attr_value.value,
+ tcb, it->p_db, op_code, handle, 0, p_msg->attr_value.value,
&p_msg->attr_value.len, GATT_MAX_ATTR_LEN, sec_flag, key_size,
trans_id);
if (err == GATT_SUCCESS) {
- gatt_sr_process_app_rsp(p_tcb, it->gatt_if, trans_id, op_code,
+ gatt_sr_process_app_rsp(tcb, it->gatt_if, trans_id, op_code,
GATT_SUCCESS, p_msg);
}
/* either not using or done using the buffer, release it now */
@@ -430,7 +424,7 @@
/* in theroy BUSY is not possible(should already been checked), protected
* check */
if (err != GATT_SUCCESS && err != GATT_PENDING && err != GATT_BUSY)
- gatt_send_error_rsp(p_tcb, err, op_code, handle, false);
+ gatt_send_error_rsp(tcb, err, op_code, handle, false);
}
/*******************************************************************************
@@ -444,7 +438,7 @@
*
******************************************************************************/
static tGATT_STATUS gatt_build_primary_service_rsp(
- BT_HDR* p_msg, tGATT_TCB* p_tcb, uint8_t op_code, uint16_t s_hdl,
+ BT_HDR* p_msg, tGATT_TCB& tcb, uint8_t op_code, uint16_t s_hdl,
uint16_t e_hdl, UNUSED_ATTR uint8_t* p_data, tBT_UUID value) {
tGATT_STATUS status = GATT_NOT_FOUND;
uint8_t handle_len = 4, *p;
@@ -471,7 +465,7 @@
}
}
- if (p_msg->len + p_msg->offset <= p_tcb->payload_size &&
+ if (p_msg->len + p_msg->offset <= tcb.payload_size &&
handle_len == p_msg->offset) {
if (op_code != GATT_REQ_FIND_TYPE_VALUE ||
gatt_uuid_compare(value, *p_uuid)) {
@@ -635,7 +629,7 @@
* Returns void
*
******************************************************************************/
-void gatts_process_primary_service_req(tGATT_TCB* p_tcb, uint8_t op_code,
+void gatts_process_primary_service_req(tGATT_TCB& tcb, uint8_t op_code,
uint16_t len, uint8_t* p_data) {
uint8_t reason = GATT_INVALID_PDU;
uint16_t s_hdl = 0, e_hdl = 0;
@@ -643,7 +637,7 @@
primary_service = {LEN_UUID_16, {GATT_UUID_PRI_SERVICE}};
BT_HDR* p_msg = NULL;
uint16_t msg_len =
- (uint16_t)(sizeof(BT_HDR) + p_tcb->payload_size + L2CAP_MIN_OFFSET);
+ (uint16_t)(sizeof(BT_HDR) + tcb.payload_size + L2CAP_MIN_OFFSET);
memset(&value, 0, sizeof(tBT_UUID));
reason = gatts_validate_packet_format(op_code, &len, &p_data, &uuid, &s_hdl,
@@ -658,7 +652,7 @@
if (reason == GATT_SUCCESS) {
p_msg = (BT_HDR*)osi_calloc(msg_len);
- reason = gatt_build_primary_service_rsp(p_msg, p_tcb, op_code, s_hdl,
+ reason = gatt_build_primary_service_rsp(p_msg, tcb, op_code, s_hdl,
e_hdl, p_data, value);
}
} else {
@@ -678,9 +672,9 @@
if (reason != GATT_SUCCESS) {
osi_free(p_msg);
- gatt_send_error_rsp(p_tcb, reason, op_code, s_hdl, false);
+ gatt_send_error_rsp(tcb, reason, op_code, s_hdl, false);
} else
- attp_send_sr_msg(p_tcb, p_msg);
+ attp_send_sr_msg(tcb, p_msg);
}
/*******************************************************************************
@@ -693,48 +687,48 @@
* Returns void
*
******************************************************************************/
-static void gatts_process_find_info(tGATT_TCB* p_tcb, uint8_t op_code,
+static void gatts_process_find_info(tGATT_TCB& tcb, uint8_t op_code,
uint16_t len, uint8_t* p_data) {
- uint8_t reason = GATT_INVALID_PDU, *p;
- uint16_t s_hdl = 0, e_hdl = 0, buf_len;
- BT_HDR* p_msg = NULL;
+ uint16_t s_hdl = 0, e_hdl = 0;
- reason = gatts_validate_packet_format(op_code, &len, &p_data, NULL, &s_hdl,
- &e_hdl);
+ uint8_t reason = gatts_validate_packet_format(op_code, &len, &p_data, NULL,
+ &s_hdl, &e_hdl);
+ if (reason != GATT_SUCCESS) {
+ gatt_send_error_rsp(tcb, reason, op_code, s_hdl, false);
+ return;
+ }
- if (reason == GATT_SUCCESS) {
- buf_len =
- (uint16_t)(sizeof(BT_HDR) + p_tcb->payload_size + L2CAP_MIN_OFFSET);
+ uint16_t buf_len =
+ (uint16_t)(sizeof(BT_HDR) + tcb.payload_size + L2CAP_MIN_OFFSET);
- p_msg = (BT_HDR*)osi_calloc(buf_len);
- reason = GATT_NOT_FOUND;
+ BT_HDR* p_msg = (BT_HDR*)osi_calloc(buf_len);
+ reason = GATT_NOT_FOUND;
- p = (uint8_t*)(p_msg + 1) + L2CAP_MIN_OFFSET;
- *p++ = op_code + 1;
- p_msg->len = 2;
+ uint8_t* p = (uint8_t*)(p_msg + 1) + L2CAP_MIN_OFFSET;
+ *p++ = op_code + 1;
+ p_msg->len = 2;
- buf_len = p_tcb->payload_size - 2;
+ buf_len = tcb.payload_size - 2;
- for (tGATT_SRV_LIST_ELEM& el : *gatt_cb.srv_list_info) {
- if (el.s_hdl <= e_hdl && el.e_hdl >= s_hdl) {
- reason = gatt_build_find_info_rsp(el, p_msg, &buf_len, s_hdl, e_hdl);
- if (reason == GATT_NO_RESOURCES) {
- reason = GATT_SUCCESS;
- break;
- }
+ for (tGATT_SRV_LIST_ELEM& el : *gatt_cb.srv_list_info) {
+ if (el.s_hdl <= e_hdl && el.e_hdl >= s_hdl) {
+ reason = gatt_build_find_info_rsp(el, p_msg, &buf_len, s_hdl, e_hdl);
+ if (reason == GATT_NO_RESOURCES) {
+ reason = GATT_SUCCESS;
+ break;
}
}
-
- *p = (uint8_t)p_msg->offset;
-
- p_msg->offset = L2CAP_MIN_OFFSET;
}
+ *p = (uint8_t)p_msg->offset;
+
+ p_msg->offset = L2CAP_MIN_OFFSET;
+
if (reason != GATT_SUCCESS) {
osi_free(p_msg);
- gatt_send_error_rsp(p_tcb, reason, op_code, s_hdl, false);
+ gatt_send_error_rsp(tcb, reason, op_code, s_hdl, false);
} else
- attp_send_sr_msg(p_tcb, p_msg);
+ attp_send_sr_msg(tcb, p_msg);
}
/*******************************************************************************
@@ -747,7 +741,7 @@
* Returns void
*
******************************************************************************/
-static void gatts_process_mtu_req(tGATT_TCB* p_tcb, uint16_t len,
+static void gatts_process_mtu_req(tGATT_TCB& tcb, uint16_t len,
uint8_t* p_data) {
uint16_t mtu = 0;
uint8_t *p = p_data, i;
@@ -755,30 +749,30 @@
uint16_t conn_id;
/* BR/EDR conenction, send error response */
- if (p_tcb->att_lcid != L2CAP_ATT_CID) {
- gatt_send_error_rsp(p_tcb, GATT_REQ_NOT_SUPPORTED, GATT_REQ_MTU, 0, false);
+ if (tcb.att_lcid != L2CAP_ATT_CID) {
+ gatt_send_error_rsp(tcb, GATT_REQ_NOT_SUPPORTED, GATT_REQ_MTU, 0, false);
} else if (len < GATT_MTU_REQ_MIN_LEN) {
GATT_TRACE_ERROR("invalid MTU request PDU received.");
- gatt_send_error_rsp(p_tcb, GATT_INVALID_PDU, GATT_REQ_MTU, 0, false);
+ gatt_send_error_rsp(tcb, GATT_INVALID_PDU, GATT_REQ_MTU, 0, false);
} else {
STREAM_TO_UINT16(mtu, p);
/* mtu must be greater than default MTU which is 23/48 */
if (mtu < GATT_DEF_BLE_MTU_SIZE)
- p_tcb->payload_size = GATT_DEF_BLE_MTU_SIZE;
+ tcb.payload_size = GATT_DEF_BLE_MTU_SIZE;
else if (mtu > GATT_MAX_MTU_SIZE)
- p_tcb->payload_size = GATT_MAX_MTU_SIZE;
+ tcb.payload_size = GATT_MAX_MTU_SIZE;
else
- p_tcb->payload_size = mtu;
+ tcb.payload_size = mtu;
- GATT_TRACE_ERROR("MTU request PDU with MTU size %d", p_tcb->payload_size);
+ GATT_TRACE_ERROR("MTU request PDU with MTU size %d", tcb.payload_size);
- l2cble_set_fixed_channel_tx_data_length(p_tcb->peer_bda, L2CAP_ATT_CID,
- p_tcb->payload_size);
+ l2cble_set_fixed_channel_tx_data_length(tcb.peer_bda, L2CAP_ATT_CID,
+ tcb.payload_size);
- p_buf = attp_build_sr_msg(p_tcb, GATT_RSP_MTU,
- (tGATT_SR_MSG*)&p_tcb->payload_size);
+ p_buf =
+ attp_build_sr_msg(tcb, GATT_RSP_MTU, (tGATT_SR_MSG*)&tcb.payload_size);
if (p_buf != NULL) {
- attp_send_sr_msg(p_tcb, p_buf);
+ attp_send_sr_msg(tcb, p_buf);
/* Notify all registered applicaiton with new MTU size. Us a transaction
* ID */
@@ -786,10 +780,9 @@
for (i = 0; i < GATT_MAX_APPS; i++) {
if (gatt_cb.cl_rcb[i].in_use) {
- conn_id =
- GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_cb.cl_rcb[i].gatt_if);
+ conn_id = GATT_CREATE_CONN_ID(tcb.tcb_idx, gatt_cb.cl_rcb[i].gatt_if);
gatt_sr_send_req_callback(conn_id, 0, GATTS_REQ_TYPE_MTU,
- (tGATTS_DATA*)&p_tcb->payload_size);
+ (tGATTS_DATA*)&tcb.payload_size);
}
}
}
@@ -811,10 +804,10 @@
* Returns void
*
******************************************************************************/
-void gatts_process_read_by_type_req(tGATT_TCB* p_tcb, uint8_t op_code,
+void gatts_process_read_by_type_req(tGATT_TCB& tcb, uint8_t op_code,
uint16_t len, uint8_t* p_data) {
tBT_UUID uuid;
- size_t msg_len = sizeof(BT_HDR) + p_tcb->payload_size + L2CAP_MIN_OFFSET;
+ size_t msg_len = sizeof(BT_HDR) + tcb.payload_size + L2CAP_MIN_OFFSET;
uint16_t buf_len, s_hdl, e_hdl, err_hdl = 0;
BT_HDR* p_msg = NULL;
tGATT_STATUS reason, ret;
@@ -830,7 +823,7 @@
"Conformance tst: forced err rsp for ReadByType: error status=%d",
gatt_cb.err_status);
- gatt_send_error_rsp(p_tcb, gatt_cb.err_status, gatt_cb.req_op_code, s_hdl,
+ gatt_send_error_rsp(tcb, gatt_cb.err_status, gatt_cb.req_op_code, s_hdl,
false);
return;
@@ -844,16 +837,15 @@
*p++ = op_code + 1;
/* reserve length byte */
p_msg->len = 2;
- buf_len = p_tcb->payload_size - 2;
+ buf_len = tcb.payload_size - 2;
reason = GATT_NOT_FOUND;
for (tGATT_SRV_LIST_ELEM& el : *gatt_cb.srv_list_info) {
if (el.s_hdl <= e_hdl && el.e_hdl >= s_hdl) {
- gatt_sr_get_sec_info(p_tcb->peer_bda, p_tcb->transport, &sec_flag,
- &key_size);
+ gatt_sr_get_sec_info(tcb.peer_bda, tcb.transport, &sec_flag, &key_size);
- ret = gatts_db_read_attr_value_by_type(p_tcb, el.p_db, op_code, p_msg,
+ ret = gatts_db_read_attr_value_by_type(tcb, el.p_db, op_code, p_msg,
s_hdl, e_hdl, uuid, &buf_len,
sec_flag, key_size, 0, &err_hdl);
if (ret != GATT_NOT_FOUND) {
@@ -876,15 +868,15 @@
/* in theroy BUSY is not possible(should already been checked), protected
* check */
if (reason != GATT_PENDING && reason != GATT_BUSY)
- gatt_send_error_rsp(p_tcb, reason, op_code, s_hdl, false);
+ gatt_send_error_rsp(tcb, reason, op_code, s_hdl, false);
} else
- attp_send_sr_msg(p_tcb, p_msg);
+ attp_send_sr_msg(tcb, p_msg);
}
/**
* This function is called to process the write request from client.
*/
-void gatts_process_write_req(tGATT_TCB* p_tcb, tGATT_SRV_LIST_ELEM& el,
+void gatts_process_write_req(tGATT_TCB& tcb, tGATT_SRV_LIST_ELEM& el,
uint16_t handle, uint8_t op_code, uint16_t len,
uint8_t* p_data,
bt_gatt_db_attribute_type_t gatt_type) {
@@ -903,7 +895,7 @@
"%s: Prepare write request was invalid - missing offset, sending "
"error response",
__func__);
- gatt_send_error_rsp(p_tcb, GATT_INVALID_PDU, op_code, handle, false);
+ gatt_send_error_rsp(tcb, GATT_INVALID_PDU, op_code, handle, false);
return;
}
sr_data.write_req.is_prep = true;
@@ -928,16 +920,16 @@
break;
}
- gatt_sr_get_sec_info(p_tcb->peer_bda, p_tcb->transport, &sec_flag, &key_size);
+ gatt_sr_get_sec_info(tcb.peer_bda, tcb.transport, &sec_flag, &key_size);
status = gatts_write_attr_perm_check(el.p_db, op_code, handle,
sr_data.write_req.offset, p, len,
sec_flag, key_size);
if (status == GATT_SUCCESS) {
- trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, handle);
+ trans_id = gatt_sr_enqueue_cmd(tcb, op_code, handle);
if (trans_id != 0) {
- conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, el.gatt_if);
+ conn_id = GATT_CREATE_CONN_ID(tcb.tcb_idx, el.gatt_if);
uint8_t opcode = 0;
if (gatt_type == BTGATT_DB_DESCRIPTOR) {
@@ -966,7 +958,7 @@
* check */
if (status != GATT_PENDING && status != GATT_BUSY &&
(op_code == GATT_REQ_PREPARE_WRITE || op_code == GATT_REQ_WRITE)) {
- gatt_send_error_rsp(p_tcb, status, op_code, handle, false);
+ gatt_send_error_rsp(tcb, status, op_code, handle, false);
}
return;
}
@@ -974,10 +966,10 @@
/**
* This function is called to process the read request from client.
*/
-static void gatts_process_read_req(tGATT_TCB* p_tcb, tGATT_SRV_LIST_ELEM& el,
+static void gatts_process_read_req(tGATT_TCB& tcb, tGATT_SRV_LIST_ELEM& el,
uint8_t op_code, uint16_t handle,
UNUSED_ATTR uint16_t len, uint8_t* p_data) {
- size_t buf_len = sizeof(BT_HDR) + p_tcb->payload_size + L2CAP_MIN_OFFSET;
+ size_t buf_len = sizeof(BT_HDR) + tcb.payload_size + L2CAP_MIN_OFFSET;
tGATT_STATUS reason;
uint8_t sec_flag, key_size, *p;
uint16_t offset = 0, value_len = 0;
@@ -988,12 +980,12 @@
p = (uint8_t*)(p_msg + 1) + L2CAP_MIN_OFFSET;
*p++ = op_code + 1;
p_msg->len = 1;
- buf_len = p_tcb->payload_size - 1;
+ buf_len = tcb.payload_size - 1;
- gatt_sr_get_sec_info(p_tcb->peer_bda, p_tcb->transport, &sec_flag, &key_size);
+ gatt_sr_get_sec_info(tcb.peer_bda, tcb.transport, &sec_flag, &key_size);
reason = gatts_read_attr_value_by_handle(
- p_tcb, el.p_db, op_code, handle, offset, p, &value_len, (uint16_t)buf_len,
+ tcb, el.p_db, op_code, handle, offset, p, &value_len, (uint16_t)buf_len,
sec_flag, key_size, 0);
p_msg->len += value_len;
@@ -1004,9 +996,9 @@
/* in theroy BUSY is not possible(should already been checked), protected
* check */
if (reason != GATT_PENDING && reason != GATT_BUSY)
- gatt_send_error_rsp(p_tcb, reason, op_code, handle, false);
+ gatt_send_error_rsp(tcb, reason, op_code, handle, false);
} else
- attp_send_sr_msg(p_tcb, p_msg);
+ attp_send_sr_msg(tcb, p_msg);
}
/*******************************************************************************
@@ -1019,8 +1011,8 @@
* Returns void
*
******************************************************************************/
-void gatts_process_attribute_req(tGATT_TCB* p_tcb, uint8_t op_code,
- uint16_t len, uint8_t* p_data) {
+void gatts_process_attribute_req(tGATT_TCB& tcb, uint8_t op_code, uint16_t len,
+ uint8_t* p_data) {
uint16_t handle = 0;
uint8_t* p = p_data;
tGATT_STATUS status = GATT_INVALID_HANDLE;
@@ -1039,7 +1031,7 @@
GATT_TRACE_DEBUG("Conformance tst: forced err rsp: error status=%d",
gatt_cb.err_status);
- gatt_send_error_rsp(p_tcb, gatt_cb.err_status, gatt_cb.req_op_code, handle,
+ gatt_send_error_rsp(tcb, gatt_cb.err_status, gatt_cb.req_op_code, handle,
false);
return;
@@ -1054,14 +1046,14 @@
switch (op_code) {
case GATT_REQ_READ: /* read char/char descriptor value */
case GATT_REQ_READ_BLOB:
- gatts_process_read_req(p_tcb, el, op_code, handle, len, p);
+ gatts_process_read_req(tcb, el, op_code, handle, len, p);
break;
case GATT_REQ_WRITE: /* write char/char descriptor value */
case GATT_CMD_WRITE:
case GATT_SIGN_CMD_WRITE:
case GATT_REQ_PREPARE_WRITE:
- gatts_process_write_req(p_tcb, el, handle, op_code, len, p,
+ gatts_process_write_req(tcb, el, handle, op_code, len, p,
attr.gatt_type);
break;
default:
@@ -1078,7 +1070,7 @@
if (status != GATT_SUCCESS && op_code != GATT_CMD_WRITE &&
op_code != GATT_SIGN_CMD_WRITE)
- gatt_send_error_rsp(p_tcb, status, op_code, handle, false);
+ gatt_send_error_rsp(tcb, status, op_code, handle, false);
}
/*******************************************************************************
@@ -1090,13 +1082,13 @@
* Returns void
*
******************************************************************************/
-static void gatts_proc_srv_chg_ind_ack(tGATT_TCB* p_tcb) {
+static void gatts_proc_srv_chg_ind_ack(tGATT_TCB tcb) {
tGATTS_SRV_CHG_REQ req;
tGATTS_SRV_CHG* p_buf = NULL;
- GATT_TRACE_DEBUG("gatts_proc_srv_chg_ind_ack");
+ GATT_TRACE_DEBUG("%s", __func__);
- p_buf = gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda);
+ p_buf = gatt_is_bda_in_the_srv_chg_clt_list(tcb.peer_bda);
if (p_buf != NULL) {
GATT_TRACE_DEBUG("NV update set srv chg = false");
p_buf->srv_changed = false;
@@ -1117,15 +1109,15 @@
* Returns void
*
******************************************************************************/
-static void gatts_chk_pending_ind(tGATT_TCB* p_tcb) {
+static void gatts_chk_pending_ind(tGATT_TCB& tcb) {
GATT_TRACE_DEBUG("%s", __func__);
tGATT_VALUE* p_buf =
- (tGATT_VALUE*)fixed_queue_try_peek_first(p_tcb->pending_ind_q);
+ (tGATT_VALUE*)fixed_queue_try_peek_first(tcb.pending_ind_q);
if (p_buf != NULL) {
GATTS_HandleValueIndication(p_buf->conn_id, p_buf->handle, p_buf->len,
p_buf->value);
- osi_free(fixed_queue_try_remove_from_queue(p_tcb->pending_ind_q, p_buf));
+ osi_free(fixed_queue_try_remove_from_queue(tcb.pending_ind_q, p_buf));
}
}
@@ -1139,19 +1131,19 @@
* application if the ACK is not a Service Changed Indication
*
******************************************************************************/
-static bool gatts_proc_ind_ack(tGATT_TCB* p_tcb, uint16_t ack_handle) {
+static bool gatts_proc_ind_ack(tGATT_TCB& tcb, uint16_t ack_handle) {
bool continue_processing = true;
GATT_TRACE_DEBUG("gatts_proc_ind_ack ack handle=%d", ack_handle);
if (ack_handle == gatt_cb.handle_of_h_r) {
- gatts_proc_srv_chg_ind_ack(p_tcb);
+ gatts_proc_srv_chg_ind_ack(tcb);
/* there is no need to inform the application since srv chg is handled
* internally by GATT */
continue_processing = false;
}
- gatts_chk_pending_ind(p_tcb);
+ gatts_chk_pending_ind(tcb);
return continue_processing;
}
@@ -1165,75 +1157,63 @@
* Returns void
*
******************************************************************************/
-void gatts_process_value_conf(tGATT_TCB* p_tcb, uint8_t op_code) {
- uint16_t handle = p_tcb->indicate_handle;
- uint32_t trans_id;
- bool continue_processing;
- uint16_t conn_id;
+void gatts_process_value_conf(tGATT_TCB& tcb, uint8_t op_code) {
+ uint16_t handle = tcb.indicate_handle;
- alarm_cancel(p_tcb->conf_timer);
- if (GATT_HANDLE_IS_VALID(handle)) {
- p_tcb->indicate_handle = 0;
- continue_processing = gatts_proc_ind_ack(p_tcb, handle);
+ alarm_cancel(tcb.conf_timer);
+ if (!GATT_HANDLE_IS_VALID(handle)) {
+ GATT_TRACE_ERROR("unexpected handle value confirmation");
+ return;
+ }
- if (continue_processing) {
- for (auto& el : *gatt_cb.srv_list_info) {
- if (el.s_hdl <= handle && el.e_hdl >= handle) {
- trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, handle);
- conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, el.gatt_if);
- gatt_sr_send_req_callback(conn_id, trans_id, GATTS_REQ_TYPE_CONF,
- (tGATTS_DATA*)&handle);
- }
+ tcb.indicate_handle = 0;
+ bool continue_processing = gatts_proc_ind_ack(tcb, handle);
+
+ if (continue_processing) {
+ for (auto& el : *gatt_cb.srv_list_info) {
+ if (el.s_hdl <= handle && el.e_hdl >= handle) {
+ uint32_t trans_id = gatt_sr_enqueue_cmd(tcb, op_code, handle);
+ uint16_t conn_id = GATT_CREATE_CONN_ID(tcb.tcb_idx, el.gatt_if);
+ gatt_sr_send_req_callback(conn_id, trans_id, GATTS_REQ_TYPE_CONF,
+ (tGATTS_DATA*)&handle);
}
}
- } else {
- GATT_TRACE_ERROR("unexpected handle value confirmation");
}
}
-/*******************************************************************************
- *
- * Function gatt_server_handle_client_req
- *
- * Description This function is called to handle the client requests to
- * server.
- *
- *
- * Returns void
- *
- ******************************************************************************/
-void gatt_server_handle_client_req(tGATT_TCB* p_tcb, uint8_t op_code,
+/** This function is called to handle the client requests to server */
+void gatt_server_handle_client_req(tGATT_TCB& tcb, uint8_t op_code,
uint16_t len, uint8_t* p_data) {
/* there is pending command, discard this one */
- if (!gatt_sr_cmd_empty(p_tcb) && op_code != GATT_HANDLE_VALUE_CONF) return;
+ if (!gatt_sr_cmd_empty(tcb) && op_code != GATT_HANDLE_VALUE_CONF) return;
/* the size of the message may not be bigger than the local max PDU size*/
/* The message has to be smaller than the agreed MTU, len does not include op
* code */
- if (len >= p_tcb->payload_size) {
+ if (len >= tcb.payload_size) {
GATT_TRACE_ERROR("server receive invalid PDU size:%d pdu size:%d", len + 1,
- p_tcb->payload_size);
+ tcb.payload_size);
/* for invalid request expecting response, send it now */
if (op_code != GATT_CMD_WRITE && op_code != GATT_SIGN_CMD_WRITE &&
op_code != GATT_HANDLE_VALUE_CONF) {
- gatt_send_error_rsp(p_tcb, GATT_INVALID_PDU, op_code, 0, false);
+ gatt_send_error_rsp(tcb, GATT_INVALID_PDU, op_code, 0, false);
}
/* otherwise, ignore the pkt */
} else {
switch (op_code) {
case GATT_REQ_READ_BY_GRP_TYPE: /* discover primary services */
case GATT_REQ_FIND_TYPE_VALUE: /* discover service by UUID */
- gatts_process_primary_service_req(p_tcb, op_code, len, p_data);
+ gatts_process_primary_service_req(tcb, op_code, len, p_data);
break;
case GATT_REQ_FIND_INFO: /* discover char descrptor */
- gatts_process_find_info(p_tcb, op_code, len, p_data);
+ gatts_process_find_info(tcb, op_code, len, p_data);
break;
case GATT_REQ_READ_BY_TYPE: /* read characteristic value, char descriptor
value */
/* discover characteristic, discover char by UUID */
- gatts_process_read_by_type_req(p_tcb, op_code, len, p_data);
+ gatts_process_read_by_type_req(tcb, op_code, len, p_data);
break;
case GATT_REQ_READ: /* read char/char descriptor value */
@@ -1242,23 +1222,23 @@
case GATT_CMD_WRITE:
case GATT_SIGN_CMD_WRITE:
case GATT_REQ_PREPARE_WRITE:
- gatts_process_attribute_req(p_tcb, op_code, len, p_data);
+ gatts_process_attribute_req(tcb, op_code, len, p_data);
break;
case GATT_HANDLE_VALUE_CONF:
- gatts_process_value_conf(p_tcb, op_code);
+ gatts_process_value_conf(tcb, op_code);
break;
case GATT_REQ_MTU:
- gatts_process_mtu_req(p_tcb, len, p_data);
+ gatts_process_mtu_req(tcb, len, p_data);
break;
case GATT_REQ_EXEC_WRITE:
- gatt_process_exec_write_req(p_tcb, op_code, len, p_data);
+ gatt_process_exec_write_req(tcb, op_code, len, p_data);
break;
case GATT_REQ_READ_MULTI:
- gatt_process_read_multi_req(p_tcb, op_code, len, p_data);
+ gatt_process_read_multi_req(tcb, op_code, len, p_data);
break;
default:
diff --git a/stack/gatt/gatt_utils.cc b/stack/gatt/gatt_utils.cc
index 5f1f316..8cb2745 100644
--- a/stack/gatt/gatt_utils.cc
+++ b/stack/gatt/gatt_utils.cc
@@ -102,27 +102,6 @@
/*******************************************************************************
*
- * 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_DEBUG("%s", __func__);
-
- if (p_tcb->pending_enc_clcb == NULL) return;
-
- /* release all queued indications */
- while (!fixed_queue_is_empty(p_tcb->pending_enc_clcb))
- osi_free(fixed_queue_try_dequeue(p_tcb->pending_enc_clcb));
- fixed_queue_free(p_tcb->pending_enc_clcb, NULL);
- p_tcb->pending_enc_clcb = NULL;
-}
-
-/*******************************************************************************
- *
* Function gatt_delete_dev_from_srv_chg_clt_list
*
* Description Delete a device from the service changed client lit
@@ -262,10 +241,13 @@
* ID.
*/
void gatt_free_srvc_db_buffer_app_id(tBT_UUID* p_app_id) {
- auto end_it = gatt_cb.hdl_list_info->end();
- for (auto it = gatt_cb.hdl_list_info->begin(); it != end_it; it++) {
+ auto it = gatt_cb.hdl_list_info->begin();
+ auto end = gatt_cb.hdl_list_info->end();
+ while (it != end) {
if (memcmp(p_app_id, &it->asgn_range.app_uuid128, sizeof(tBT_UUID)) == 0) {
it = gatt_cb.hdl_list_info->erase(it);
+ } else {
+ it++;
}
}
}
@@ -449,26 +431,7 @@
return p_tcb;
}
-/*******************************************************************************
- *
- * Function gatt_find_i_tcb_free
- *
- * Description Search for an empty tcb entry, and return the index.
- *
- * Returns GATT_INDEX_INVALID if not found. Otherwise index to the tcb.
- *
- ******************************************************************************/
-uint8_t gatt_find_i_tcb_free(void) {
- uint8_t i = 0, j = GATT_INDEX_INVALID;
- for (i = 0; i < GATT_MAX_PHY_CHANNEL; i++) {
- if (!gatt_cb.tcb[i].in_use) {
- j = i;
- break;
- }
- }
- return j;
-}
/*******************************************************************************
*
* Function gatt_allocate_tcb_by_bdaddr
@@ -479,33 +442,28 @@
*
******************************************************************************/
tGATT_TCB* gatt_allocate_tcb_by_bdaddr(BD_ADDR bda, tBT_TRANSPORT transport) {
- uint8_t i = 0;
- bool allocated = false;
- tGATT_TCB* p_tcb = NULL;
-
/* search for existing tcb with matching bda */
- i = gatt_find_i_tcb_by_addr(bda, transport);
- /* find free tcb */
- if (i == GATT_INDEX_INVALID) {
- i = gatt_find_i_tcb_free();
- allocated = true;
- }
- if (i != GATT_INDEX_INVALID) {
- p_tcb = &gatt_cb.tcb[i];
+ uint8_t j = gatt_find_i_tcb_by_addr(bda, transport);
+ if (j != GATT_INDEX_INVALID) return &gatt_cb.tcb[j];
- if (allocated) {
- memset(p_tcb, 0, sizeof(tGATT_TCB));
- p_tcb->pending_enc_clcb = fixed_queue_new(SIZE_MAX);
- p_tcb->pending_ind_q = fixed_queue_new(SIZE_MAX);
- p_tcb->conf_timer = alarm_new("gatt.conf_timer");
- p_tcb->ind_ack_timer = alarm_new("gatt.ind_ack_timer");
- p_tcb->in_use = true;
- p_tcb->tcb_idx = i;
- p_tcb->transport = transport;
- }
+ /* find free tcb */
+ for (int i = 0; i < GATT_MAX_PHY_CHANNEL; i++) {
+ tGATT_TCB* p_tcb = &gatt_cb.tcb[i];
+ if (p_tcb->in_use) continue;
+
+ *p_tcb = tGATT_TCB();
+
+ p_tcb->pending_ind_q = fixed_queue_new(SIZE_MAX);
+ p_tcb->conf_timer = alarm_new("gatt.conf_timer");
+ p_tcb->ind_ack_timer = alarm_new("gatt.ind_ack_timer");
+ p_tcb->in_use = true;
+ p_tcb->tcb_idx = i;
+ p_tcb->transport = transport;
memcpy(p_tcb->peer_bda, bda, BD_ADDR_LEN);
+ return p_tcb;
}
- return p_tcb;
+
+ return NULL;
}
/*******************************************************************************
@@ -702,8 +660,7 @@
* Returns void
*
******************************************************************************/
-void gatt_start_rsp_timer(uint16_t clcb_idx) {
- tGATT_CLCB* p_clcb = &gatt_cb.clcb[clcb_idx];
+void gatt_start_rsp_timer(tGATT_CLCB* p_clcb) {
period_ms_t timeout_ms = GATT_WAIT_FOR_RSP_TIMEOUT_MS;
if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
@@ -744,10 +701,10 @@
* Returns void
*
******************************************************************************/
-void gatt_start_ind_ack_timer(tGATT_TCB* p_tcb) {
+void gatt_start_ind_ack_timer(tGATT_TCB& tcb) {
/* start notification cache timer */
- alarm_set_on_queue(p_tcb->ind_ack_timer, GATT_WAIT_FOR_RSP_TIMEOUT_MS,
- gatt_ind_ack_timeout, p_tcb, btu_general_alarm_queue);
+ alarm_set_on_queue(tcb.ind_ack_timer, GATT_WAIT_FOR_RSP_TIMEOUT_MS,
+ gatt_ind_ack_timeout, &tcb, btu_general_alarm_queue);
}
/*******************************************************************************
@@ -771,7 +728,7 @@
p_clcb->retry_count < GATT_REQ_RETRY_LIMIT) {
uint8_t rsp_code;
GATT_TRACE_WARNING("%s retry discovery primary service", __func__);
- if (p_clcb != gatt_cmd_dequeue(p_clcb->p_tcb, &rsp_code)) {
+ if (p_clcb != gatt_cmd_dequeue(*p_clcb->p_tcb, &rsp_code)) {
GATT_TRACE_ERROR("%s command queue out of sync, disconnect", __func__);
} else {
p_clcb->retry_count++;
@@ -811,12 +768,11 @@
******************************************************************************/
void gatt_ind_ack_timeout(void* data) {
tGATT_TCB* p_tcb = (tGATT_TCB*)data;
+ CHECK(p_tcb);
GATT_TRACE_WARNING("%s send ack now", __func__);
-
- if (p_tcb != NULL) p_tcb->ind_count = 0;
-
- attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL);
+ p_tcb->ind_count = 0;
+ attp_send_cl_msg(*p_tcb, nullptr, GATT_HANDLE_VALUE_CONF, NULL);
}
/*******************************************************************************
*
@@ -898,7 +854,7 @@
* Returns void
*
******************************************************************************/
-tGATT_STATUS gatt_send_error_rsp(tGATT_TCB* p_tcb, uint8_t err_code,
+tGATT_STATUS gatt_send_error_rsp(tGATT_TCB& tcb, uint8_t err_code,
uint8_t op_code, uint16_t handle, bool deq) {
tGATT_ERROR error;
tGATT_STATUS status;
@@ -908,13 +864,13 @@
error.reason = err_code;
error.handle = handle;
- p_buf = attp_build_sr_msg(p_tcb, GATT_RSP_ERROR, (tGATT_SR_MSG*)&error);
+ p_buf = attp_build_sr_msg(tcb, GATT_RSP_ERROR, (tGATT_SR_MSG*)&error);
if (p_buf != NULL) {
- status = attp_send_sr_msg(p_tcb, p_buf);
+ status = attp_send_sr_msg(tcb, p_buf);
} else
status = GATT_INSUF_RESOURCE;
- if (deq) gatt_dequeue_sr_cmd(p_tcb);
+ if (deq) gatt_dequeue_sr_cmd(tcb);
return status;
}
@@ -1081,7 +1037,6 @@
p_clcb->in_use = true;
p_clcb->conn_id = conn_id;
- p_clcb->clcb_idx = i;
p_clcb->p_reg = p_reg;
p_clcb->p_tcb = p_tcb;
break;
@@ -1132,27 +1087,6 @@
/*******************************************************************************
*
- * Function gatt_num_apps_hold_link
- *
- * Description The function find the number of applcaitions is holding the
- * link
- *
- * Returns total number of applications holding this acl link.
- *
- ******************************************************************************/
-uint8_t gatt_num_apps_hold_link(tGATT_TCB* p_tcb) {
- uint8_t i, num = 0;
-
- for (i = 0; i < GATT_MAX_APPS; i++) {
- if (p_tcb->app_hold_link[i]) num++;
- }
-
- GATT_TRACE_DEBUG("gatt_num_apps_hold_link num=%d", num);
- return num;
-}
-
-/*******************************************************************************
- *
* Function gatt_num_clcb_by_bd_addr
*
* Description The function searches all LCB with macthing bd address
@@ -1171,23 +1105,10 @@
return num;
}
-/*******************************************************************************
- *
- * Function gatt_sr_update_cback_cnt
- *
- * Description The function searches all LCB with macthing bd address
- *
- * Returns total number of clcb found.
- *
- ******************************************************************************/
-void gatt_sr_copy_prep_cnt_to_cback_cnt(tGATT_TCB* p_tcb) {
- uint8_t i;
-
- if (p_tcb) {
- for (i = 0; i < GATT_MAX_APPS; i++) {
- if (p_tcb->prep_cnt[i]) {
- p_tcb->sr_cmd.cback_cnt[i] = 1;
- }
+void gatt_sr_copy_prep_cnt_to_cback_cnt(tGATT_TCB& tcb) {
+ for (uint8_t i = 0; i < GATT_MAX_APPS; i++) {
+ if (tcb.prep_cnt[i]) {
+ tcb.sr_cmd.cback_cnt[i] = 1;
}
}
}
@@ -1201,21 +1122,13 @@
* Returns True if thetotal application callback count is zero
*
******************************************************************************/
-bool gatt_sr_is_cback_cnt_zero(tGATT_TCB* p_tcb) {
- bool status = true;
- uint8_t i;
-
- if (p_tcb) {
- for (i = 0; i < GATT_MAX_APPS; i++) {
- if (p_tcb->sr_cmd.cback_cnt[i]) {
- status = false;
- break;
- }
+bool gatt_sr_is_cback_cnt_zero(tGATT_TCB& tcb) {
+ for (uint8_t i = 0; i < GATT_MAX_APPS; i++) {
+ if (tcb.sr_cmd.cback_cnt[i]) {
+ return false;
}
- } else {
- status = false;
}
- return status;
+ return true;
}
/*******************************************************************************
@@ -1227,21 +1140,13 @@
* Returns True no prepare write request
*
******************************************************************************/
-bool gatt_sr_is_prep_cnt_zero(tGATT_TCB* p_tcb) {
- bool status = true;
- uint8_t i;
-
- if (p_tcb) {
- for (i = 0; i < GATT_MAX_APPS; i++) {
- if (p_tcb->prep_cnt[i]) {
- status = false;
- break;
- }
+bool gatt_sr_is_prep_cnt_zero(tGATT_TCB& tcb) {
+ for (uint8_t i = 0; i < GATT_MAX_APPS; i++) {
+ if (tcb.prep_cnt[i]) {
+ return false;
}
- } else {
- status = false;
}
- return status;
+ return true;
}
/*******************************************************************************
@@ -1253,13 +1158,9 @@
* Returns None
*
******************************************************************************/
-void gatt_sr_reset_cback_cnt(tGATT_TCB* p_tcb) {
- uint8_t i;
-
- if (p_tcb) {
- for (i = 0; i < GATT_MAX_APPS; i++) {
- p_tcb->sr_cmd.cback_cnt[i] = 0;
- }
+void gatt_sr_reset_cback_cnt(tGATT_TCB& tcb) {
+ for (uint8_t i = 0; i < GATT_MAX_APPS; i++) {
+ tcb.sr_cmd.cback_cnt[i] = 0;
}
}
@@ -1272,12 +1173,9 @@
* Returns None
*
******************************************************************************/
-void gatt_sr_reset_prep_cnt(tGATT_TCB* p_tcb) {
- uint8_t i;
- if (p_tcb) {
- for (i = 0; i < GATT_MAX_APPS; i++) {
- p_tcb->prep_cnt[i] = 0;
- }
+void gatt_sr_reset_prep_cnt(tGATT_TCB& tcb) {
+ for (uint8_t i = 0; i < GATT_MAX_APPS; i++) {
+ tcb.prep_cnt[i] = 0;
}
}
@@ -1290,20 +1188,18 @@
* Returns None
*
******************************************************************************/
-void gatt_sr_update_cback_cnt(tGATT_TCB* p_tcb, tGATT_IF gatt_if, bool is_inc,
+void gatt_sr_update_cback_cnt(tGATT_TCB& tcb, tGATT_IF gatt_if, bool is_inc,
bool is_reset_first) {
uint8_t idx = ((uint8_t)gatt_if) - 1;
- if (p_tcb) {
- if (is_reset_first) {
- gatt_sr_reset_cback_cnt(p_tcb);
- }
- if (is_inc) {
- p_tcb->sr_cmd.cback_cnt[idx]++;
- } else {
- if (p_tcb->sr_cmd.cback_cnt[idx]) {
- p_tcb->sr_cmd.cback_cnt[idx]--;
- }
+ if (is_reset_first) {
+ gatt_sr_reset_cback_cnt(tcb);
+ }
+ if (is_inc) {
+ tcb.sr_cmd.cback_cnt[idx]++;
+ } else {
+ if (tcb.sr_cmd.cback_cnt[idx]) {
+ tcb.sr_cmd.cback_cnt[idx]--;
}
}
}
@@ -1317,25 +1213,21 @@
* Returns None
*
******************************************************************************/
-void gatt_sr_update_prep_cnt(tGATT_TCB* p_tcb, tGATT_IF gatt_if, bool is_inc,
+void gatt_sr_update_prep_cnt(tGATT_TCB& tcb, tGATT_IF gatt_if, bool is_inc,
bool is_reset_first) {
uint8_t idx = ((uint8_t)gatt_if) - 1;
- GATT_TRACE_DEBUG(
- "gatt_sr_update_prep_cnt tcb idx=%d gatt_if=%d is_inc=%d "
- "is_reset_first=%d",
- p_tcb->tcb_idx, gatt_if, is_inc, is_reset_first);
+ GATT_TRACE_DEBUG("%s tcb idx=%d gatt_if=%d is_inc=%d is_reset_first=%d",
+ __func__, tcb.tcb_idx, gatt_if, is_inc, is_reset_first);
- if (p_tcb) {
- if (is_reset_first) {
- gatt_sr_reset_prep_cnt(p_tcb);
- }
- if (is_inc) {
- p_tcb->prep_cnt[idx]++;
- } else {
- if (p_tcb->prep_cnt[idx]) {
- p_tcb->prep_cnt[idx]--;
- }
+ if (is_reset_first) {
+ gatt_sr_reset_prep_cnt(tcb);
+ }
+ if (is_inc) {
+ tcb.prep_cnt[idx]++;
+ } else {
+ if (tcb.prep_cnt[idx]) {
+ tcb.prep_cnt[idx]--;
}
}
}
@@ -1361,7 +1253,7 @@
status = false;
} else {
gatt_update_app_use_link_flag(gatt_if, p_tcb, false, false);
- if (!gatt_num_apps_hold_link(p_tcb)) {
+ if (p_tcb->app_hold_link.empty()) {
gatt_disconnect(p_tcb);
}
}
@@ -1370,80 +1262,31 @@
return status;
}
-/*******************************************************************************
- *
- * Function gatt_find_app_hold_link
- *
- * Description find the applicaiton that is holding the specified link
- *
- * Returns Boolean
- *
- ******************************************************************************/
-bool gatt_find_app_hold_link(tGATT_TCB* p_tcb, uint8_t start_idx,
- uint8_t* p_found_idx, tGATT_IF* p_gatt_if) {
- uint8_t i;
- bool found = false;
-
- for (i = start_idx; i < GATT_MAX_APPS; i++) {
- if (p_tcb->app_hold_link[i]) {
- *p_gatt_if = gatt_cb.clcb[i].p_reg->gatt_if;
- *p_found_idx = i;
- found = true;
- break;
- }
- }
- return found;
-}
-
-/*******************************************************************************
- *
- * Function gatt_cmd_enq
- *
- * Description Enqueue this command.
- *
- * Returns None.
- *
- ******************************************************************************/
-bool gatt_cmd_enq(tGATT_TCB* p_tcb, uint16_t clcb_idx, bool to_send,
+/** Enqueue this command */
+void gatt_cmd_enq(tGATT_TCB& tcb, tGATT_CLCB* p_clcb, bool to_send,
uint8_t op_code, BT_HDR* p_buf) {
- tGATT_CMD_Q* p_cmd = &p_tcb->cl_cmd_q[p_tcb->next_slot_inq];
-
- p_cmd->to_send = to_send; /* waiting to be sent */
- p_cmd->op_code = op_code;
- p_cmd->p_cmd = p_buf;
- p_cmd->clcb_idx = clcb_idx;
+ tGATT_CMD_Q cmd;
+ cmd.to_send = to_send; /* waiting to be sent */
+ cmd.op_code = op_code;
+ cmd.p_cmd = p_buf;
+ cmd.p_clcb = p_clcb;
if (!to_send) {
- p_tcb->pending_cl_req = p_tcb->next_slot_inq;
+ // TODO: WTF why do we clear the queue here ?!
+ tcb.cl_cmd_q = std::queue<tGATT_CMD_Q>();
}
- p_tcb->next_slot_inq++;
- p_tcb->next_slot_inq %= GATT_CL_MAX_LCB;
-
- return true;
+ tcb.cl_cmd_q.push(cmd);
}
-/*******************************************************************************
- *
- * Function gatt_cmd_dequeue
- *
- * Description dequeue the command in the client CCB command queue.
- *
- * Returns total number of clcb found.
- *
- ******************************************************************************/
-tGATT_CLCB* gatt_cmd_dequeue(tGATT_TCB* p_tcb, uint8_t* p_op_code) {
- tGATT_CMD_Q* p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
- tGATT_CLCB* p_clcb = NULL;
+/** dequeue the command in the client CCB command queue */
+tGATT_CLCB* gatt_cmd_dequeue(tGATT_TCB& tcb, uint8_t* p_op_code) {
+ if (tcb.cl_cmd_q.empty()) return nullptr;
- if (p_tcb->pending_cl_req != p_tcb->next_slot_inq) {
- p_clcb = &gatt_cb.clcb[p_cmd->clcb_idx];
-
- *p_op_code = p_cmd->op_code;
-
- p_tcb->pending_cl_req++;
- p_tcb->pending_cl_req %= GATT_CL_MAX_LCB;
- }
+ tGATT_CMD_Q cmd = tcb.cl_cmd_q.front();
+ tGATT_CLCB* p_clcb = cmd.p_clcb;
+ *p_op_code = cmd.op_code;
+ tcb.cl_cmd_q.pop();
return p_clcb;
}
@@ -1457,9 +1300,9 @@
* Returns status code
*
******************************************************************************/
-uint8_t gatt_send_write_msg(tGATT_TCB* p_tcb, uint16_t clcb_idx,
- uint8_t op_code, uint16_t handle, uint16_t len,
- uint16_t offset, uint8_t* p_data) {
+uint8_t gatt_send_write_msg(tGATT_TCB& tcb, tGATT_CLCB* p_clcb, uint8_t op_code,
+ uint16_t handle, uint16_t len, uint16_t offset,
+ uint8_t* p_data) {
tGATT_CL_MSG msg;
msg.attr_value.handle = handle;
@@ -1469,30 +1312,7 @@
memcpy(msg.attr_value.value, p_data, len);
/* write by handle */
- return attp_send_cl_msg(p_tcb, clcb_idx, op_code, &msg);
-}
-
-/*******************************************************************************
- *
- * Function gatt_act_send_browse
- *
- * Description This function ends a browse command request, including read
- * information request and read by type request.
- *
- * Returns status code
- *
- ******************************************************************************/
-uint8_t gatt_act_send_browse(tGATT_TCB* p_tcb, uint16_t index, uint8_t op,
- uint16_t s_handle, uint16_t e_handle,
- tBT_UUID uuid) {
- tGATT_CL_MSG msg;
-
- msg.browse.s_handle = s_handle;
- msg.browse.e_handle = e_handle;
- memcpy(&msg.browse.uuid, &uuid, sizeof(tBT_UUID));
-
- /* write by handle */
- return attp_send_cl_msg(p_tcb, index, op, &msg);
+ return attp_send_cl_msg(tcb, p_clcb, op_code, &msg);
}
/*******************************************************************************
@@ -1594,8 +1414,7 @@
p_clcb = &gatt_cb.clcb[i];
if (p_clcb->in_use && p_clcb->p_tcb == p_tcb) {
alarm_cancel(p_clcb->gatt_rsp_timer_ent);
- GATT_TRACE_DEBUG("found p_clcb conn_id=%d clcb_idx=%d", p_clcb->conn_id,
- p_clcb->clcb_idx);
+ GATT_TRACE_DEBUG("found p_clcb conn_id=%d", p_clcb->conn_id);
if (p_clcb->operation != GATTC_OPTYPE_NONE)
gatt_end_operation(p_clcb, GATT_ERROR, NULL);
@@ -1608,7 +1427,6 @@
alarm_free(p_tcb->conf_timer);
p_tcb->conf_timer = NULL;
gatt_free_pending_ind(p_tcb);
- gatt_free_pending_enc_queue(p_tcb);
fixed_queue_free(p_tcb->sr_cmd.multi_rsp_q, NULL);
p_tcb->sr_cmd.multi_rsp_q = NULL;
@@ -1622,7 +1440,7 @@
transport);
}
}
- memset(p_tcb, 0, sizeof(tGATT_TCB));
+ *p_tcb = tGATT_TCB();
}
GATT_TRACE_DEBUG("exit gatt_cleanup_upon_disc ");
}
@@ -1686,121 +1504,59 @@
GATT_TRACE_DEBUG("UUID=[%s]", str_buf);
}
-/*******************************************************************************
- *
- * Function gatt_is_bg_dev_for_app
- *
- * Description Is this one of the background devices for the application
- *
- * Returns true if it is, otherwise false
- *
- ******************************************************************************/
+/** Returns true if this is one of the background devices for the application,
+ * false otherwise */
bool gatt_is_bg_dev_for_app(tGATT_BG_CONN_DEV* p_dev, tGATT_IF gatt_if) {
- uint8_t i;
-
- for (i = 0; i < GATT_MAX_APPS; i++) {
- if (p_dev->in_use && (p_dev->gatt_if[i] == gatt_if)) {
- return true;
- }
- }
- return false;
+ return p_dev->gatt_if.count(gatt_if);
}
-/*******************************************************************************
- *
- * Function gatt_find_bg_dev
- *
- * Description find background connection device from the list.
- *
- * Returns pointer to the device record
- *
- ******************************************************************************/
+
+/** background connection device from the list. Returns pointer to the device
+ * record, or nullptr if not found */
tGATT_BG_CONN_DEV* gatt_find_bg_dev(BD_ADDR remote_bda) {
- tGATT_BG_CONN_DEV* p_dev_list = &gatt_cb.bgconn_dev[0];
- uint8_t i;
-
- for (i = 0; i < GATT_MAX_BG_CONN_DEV; i++, p_dev_list++) {
- if (p_dev_list->in_use &&
- !memcmp(p_dev_list->remote_bda, remote_bda, BD_ADDR_LEN)) {
- return p_dev_list;
+ for (tGATT_BG_CONN_DEV& dev : gatt_cb.bgconn_dev) {
+ if (!memcmp(dev.remote_bda, remote_bda, BD_ADDR_LEN)) {
+ return &dev;
}
}
- return NULL;
+ return nullptr;
}
-/*******************************************************************************
- *
- * Function gatt_alloc_bg_dev
- *
- * Description allocate a background connection device record
- *
- * Returns pointer to the device record
- *
- ******************************************************************************/
-tGATT_BG_CONN_DEV* gatt_alloc_bg_dev(BD_ADDR remote_bda) {
- tGATT_BG_CONN_DEV* p_dev_list = &gatt_cb.bgconn_dev[0];
- uint8_t i;
- for (i = 0; i < GATT_MAX_BG_CONN_DEV; i++, p_dev_list++) {
- if (!p_dev_list->in_use) {
- p_dev_list->in_use = true;
- memcpy(p_dev_list->remote_bda, remote_bda, BD_ADDR_LEN);
-
- return p_dev_list;
+std::list<tGATT_BG_CONN_DEV>::iterator gatt_find_bg_dev_it(BD_ADDR remote_bda) {
+ auto& list = gatt_cb.bgconn_dev;
+ for (auto it = list.begin(); it != list.end(); it++) {
+ if (!memcmp(it->remote_bda, remote_bda, BD_ADDR_LEN)) {
+ return it;
}
}
- return NULL;
+ return list.end();
}
-/*******************************************************************************
- *
- * Function gatt_add_bg_dev_list
- *
- * Description Add/remove a device from the background connection list
- *
- * Returns true if device added to the list; false failed
- *
- ******************************************************************************/
+/** Add a device from the background connection list. Returns true if device
+ * added to the list, or already in list, false otherwise */
bool gatt_add_bg_dev_list(tGATT_REG* p_reg, BD_ADDR bd_addr) {
tGATT_IF gatt_if = p_reg->gatt_if;
- tGATT_BG_CONN_DEV* p_dev = NULL;
- uint8_t i;
- bool ret = false;
- p_dev = gatt_find_bg_dev(bd_addr);
- if (p_dev == NULL) {
- p_dev = gatt_alloc_bg_dev(bd_addr);
- }
-
+ tGATT_BG_CONN_DEV* p_dev = gatt_find_bg_dev(bd_addr);
if (p_dev) {
- for (i = 0; i < GATT_MAX_APPS; i++) {
- if (p_dev->gatt_if[i] == gatt_if) {
- GATT_TRACE_ERROR("device already in iniator white list");
- return true;
- } else if (p_dev->gatt_if[i] == 0) {
- p_dev->gatt_if[i] = gatt_if;
- if (i == 0)
- ret = BTM_BleUpdateBgConnDev(true, bd_addr);
- else
- ret = true;
- break;
- }
+ // device already in the whitelist, just add interested app to the list
+ if (!p_dev->gatt_if.insert(gatt_if).second) {
+ GATT_TRACE_ERROR("device already in iniator white list");
}
- } else {
- GATT_TRACE_ERROR("no device record available");
- }
- return ret;
+ return true;
+ }
+ // the device is not in the whitelist
+
+ if (!BTM_BleUpdateBgConnDev(true, bd_addr)) return false;
+
+ gatt_cb.bgconn_dev.emplace_back();
+ tGATT_BG_CONN_DEV& dev = gatt_cb.bgconn_dev.back();
+ memcpy(dev.remote_bda, bd_addr, BD_ADDR_LEN);
+ dev.gatt_if.insert(gatt_if);
+ return true;
}
-/*******************************************************************************
- *
- * Function gatt_remove_bg_dev_for_app
- *
- * Description Remove the application interface for the specified
- * background device
- *
- * Returns Boolean
- *
- ******************************************************************************/
+/** Remove the application interface for the specified background device */
bool gatt_remove_bg_dev_for_app(tGATT_IF gatt_if, BD_ADDR bd_addr) {
tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE);
bool status;
@@ -1810,131 +1566,48 @@
return status;
}
-/*******************************************************************************
- *
- * Function gatt_get_num_apps_for_bg_dev
- *
- * Description Get the number of applciations for the specified background
- * device
- *
- * Returns uint8_t total number fo applications
- *
- ******************************************************************************/
-uint8_t gatt_get_num_apps_for_bg_dev(BD_ADDR bd_addr) {
- tGATT_BG_CONN_DEV* p_dev = NULL;
- uint8_t i;
- uint8_t cnt = 0;
+/** Removes all registrations for background connection for given device.
+ * Returns true if anything was removed, false otherwise */
+uint8_t gatt_clear_bg_dev_for_addr(BD_ADDR bd_addr) {
+ auto dev_it = gatt_find_bg_dev_it(bd_addr);
+ if (dev_it == gatt_cb.bgconn_dev.end()) return false;
- p_dev = gatt_find_bg_dev(bd_addr);
- if (p_dev != NULL) {
- for (i = 0; i < GATT_MAX_APPS; i++) {
- if (p_dev->gatt_if[i]) cnt++;
- }
- }
- return cnt;
+ CHECK(BTM_BleUpdateBgConnDev(false, dev_it->remote_bda));
+ gatt_cb.bgconn_dev.erase(dev_it);
+ return true;
}
-/*******************************************************************************
- *
- * Function gatt_find_app_for_bg_dev
- *
- * Description Find the application interface for the specified background
- * device
- *
- * Returns Boolean
- *
- ******************************************************************************/
-bool gatt_find_app_for_bg_dev(BD_ADDR bd_addr, tGATT_IF* p_gatt_if) {
- tGATT_BG_CONN_DEV* p_dev = NULL;
- uint8_t i;
- bool ret = false;
-
- p_dev = gatt_find_bg_dev(bd_addr);
- if (p_dev == NULL) {
- return ret;
- }
-
- for (i = 0; i < GATT_MAX_APPS; i++) {
- if (p_dev->gatt_if[i] != 0) {
- *p_gatt_if = p_dev->gatt_if[i];
- ret = true;
- break;
- }
- }
- return ret;
-}
-
-/*******************************************************************************
- *
- * Function gatt_remove_bg_dev_from_list
- *
- * Description add/remove device from the back ground connection device
- * list or listening to advertising list.
- *
- * Returns pointer to the device record
- *
- ******************************************************************************/
+/** Remove device from the background connection device list or listening to
+ * advertising list. Returns true if device was on the list and was succesfully
+ * removed */
bool gatt_remove_bg_dev_from_list(tGATT_REG* p_reg, BD_ADDR bd_addr) {
tGATT_IF gatt_if = p_reg->gatt_if;
- tGATT_BG_CONN_DEV* p_dev = NULL;
- uint8_t i, j;
- bool ret = false;
+ auto dev_it = gatt_find_bg_dev_it(bd_addr);
+ if (dev_it == gatt_cb.bgconn_dev.end()) return false;
- p_dev = gatt_find_bg_dev(bd_addr);
- if (p_dev == NULL) {
- return ret;
- }
+ if (!dev_it->gatt_if.erase(gatt_if)) return false;
- for (i = 0; i < GATT_MAX_APPS && (p_dev->gatt_if[i] > 0); i++) {
- 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];
+ if (!dev_it->gatt_if.empty()) return true;
- if (p_dev->gatt_if[0] == 0)
- ret = BTM_BleUpdateBgConnDev(false, p_dev->remote_bda);
- else
- ret = true;
-
- break;
- }
- }
-
- if (i != GATT_MAX_APPS && p_dev->gatt_if[0] == 0) {
- memset(p_dev, 0, sizeof(tGATT_BG_CONN_DEV));
- }
-
- return ret;
+ // no more apps interested - remove from whitelist and delete record
+ CHECK(BTM_BleUpdateBgConnDev(false, dev_it->remote_bda));
+ gatt_cb.bgconn_dev.erase(dev_it);
+ return true;
}
-/*******************************************************************************
- *
- * Function gatt_deregister_bgdev_list
- *
- * Description deregister all related back ground connetion device.
- *
- * Returns pointer to the device record
- *
- ******************************************************************************/
+/** deregister all related back ground connetion device. */
void gatt_deregister_bgdev_list(tGATT_IF gatt_if) {
- tGATT_BG_CONN_DEV* p_dev_list = &gatt_cb.bgconn_dev[0];
- uint8_t i, j, k;
-
+ auto it = gatt_cb.bgconn_dev.begin();
+ auto end = gatt_cb.bgconn_dev.end();
/* update the BG conn device list */
- for (i = 0; i < GATT_MAX_BG_CONN_DEV; i++, p_dev_list++) {
- if (p_dev_list->in_use) {
- for (j = 0; j < GATT_MAX_APPS; j++) {
- if (p_dev_list->gatt_if[j] == 0) break;
-
- if (p_dev_list->gatt_if[j] == gatt_if) {
- for (k = j + 1; k < GATT_MAX_APPS; k++)
- p_dev_list->gatt_if[k - 1] = p_dev_list->gatt_if[k];
-
- if (p_dev_list->gatt_if[0] == 0)
- BTM_BleUpdateBgConnDev(false, p_dev_list->remote_bda);
- }
- }
+ while (it != end) {
+ it->gatt_if.erase(gatt_if);
+ if (it->gatt_if.size()) {
+ it++;
+ continue;
}
+
+ BTM_BleUpdateBgConnDev(false, it->remote_bda);
+ it = gatt_cb.bgconn_dev.erase(it);
}
}
@@ -1947,10 +1620,7 @@
* Returns pointer to the device record
*
******************************************************************************/
-void gatt_reset_bgdev_list(void) {
- memset(&gatt_cb.bgconn_dev, 0,
- sizeof(tGATT_BG_CONN_DEV) * GATT_MAX_BG_CONN_DEV);
-}
+void gatt_reset_bgdev_list(void) { gatt_cb.bgconn_dev.clear(); }
/*******************************************************************************
*
* Function gatt_update_auto_connect_dev
@@ -1970,12 +1640,11 @@
tGATT_REG* p_reg;
tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE);
- GATT_TRACE_API("gatt_update_auto_connect_dev ");
+ GATT_TRACE_API("%s:", __func__);
/* Make sure app is registered */
p_reg = gatt_get_regcb(gatt_if);
if (p_reg == NULL) {
- GATT_TRACE_ERROR("gatt_update_auto_connect_dev - gatt_if is not registered",
- gatt_if);
+ GATT_TRACE_ERROR("%s - gatt_if is not registered", __func__, gatt_if);
return (false);
}
@@ -1991,26 +1660,3 @@
}
return ret;
}
-
-/*******************************************************************************
- *
- * 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 =
- (tGATT_PENDING_ENC_CLCB*)osi_malloc(sizeof(tGATT_PENDING_ENC_CLCB));
-
- GATT_TRACE_DEBUG("%s", __func__);
- GATT_TRACE_DEBUG("enqueue a new pending encryption channel clcb");
-
- p_buf->p_clcb = p_clcb;
- fixed_queue_enqueue(p_tcb->pending_enc_clcb, p_buf);
-
- return p_buf;
-}
diff --git a/stack/include/a2dp_aac.h b/stack/include/a2dp_aac.h
index 7ee7acf..43f7965 100644
--- a/stack/include/a2dp_aac.h
+++ b/stack/include/a2dp_aac.h
@@ -122,12 +122,6 @@
// contains invalid codec information.
int A2DP_GetTrackSampleRateAac(const uint8_t* p_codec_info);
-// Gets the bits per audio sample for the A2DP AAC codec.
-// |p_codec_info| is a pointer to the AAC codec_info to decode.
-// Returns the bits per audio sample on success, or -1 if |p_codec_info|
-// contains invalid codec information.
-int A2DP_GetTrackBitsPerSampleAac(const uint8_t* p_codec_info);
-
// Gets the channel count for the A2DP AAC codec.
// |p_codec_info| is a pointer to the AAC codec_info to decode.
// Returns the channel count on success, or -1 if |p_codec_info|
@@ -201,9 +195,10 @@
bool A2DP_BuildCodecHeaderAac(const uint8_t* p_codec_info, BT_HDR* p_buf,
uint16_t frames_per_packet);
-// Decodes and displays AAC codec info (for debugging).
+// Decodes and displays A2DP AAC codec info when using |LOG_DEBUG|.
// |p_codec_info| is a pointer to the AAC codec_info to decode and display.
-void A2DP_DumpCodecInfoAac(const uint8_t* p_codec_info);
+// Returns true if the codec information is valid, otherwise false.
+bool A2DP_DumpCodecInfoAac(const uint8_t* p_codec_info);
// Gets the A2DP AAC encoder interface that can be used to encode and prepare
// A2DP packets for transmission - see |tA2DP_ENCODER_INTERFACE|.
diff --git a/stack/include/a2dp_api.h b/stack/include/a2dp_api.h
index c4ab737..15d30d87 100644
--- a/stack/include/a2dp_api.h
+++ b/stack/include/a2dp_api.h
@@ -162,6 +162,17 @@
/******************************************************************************
*
+ * Function A2DP_GetAvdtpVersion()
+ *
+ * Description Gets the local version of AVDTP
+ *
+ * Returns The local version of AVDTP.
+ *
+ *****************************************************************************/
+extern uint16_t A2DP_GetAvdtpVersion(void);
+
+/******************************************************************************
+ *
* Function A2DP_SetTraceLevel
*
* Description Sets the trace level for A2D. If 0xff is passed, the
diff --git a/stack/include/a2dp_codec_api.h b/stack/include/a2dp_codec_api.h
index 1c5b261..94871ce 100644
--- a/stack/include/a2dp_codec_api.h
+++ b/stack/include/a2dp_codec_api.h
@@ -579,12 +579,6 @@
// contains invalid codec information.
int A2DP_GetTrackSampleRate(const uint8_t* p_codec_info);
-// Gets the bits per audio sample for the A2DP codec.
-// |p_codec_info| is a pointer to the codec_info to decode.
-// Returns the bits per audio sample on success, or -1 if |p_codec_info|
-// contains invalid codec information.
-int A2DP_GetTrackBitsPerSample(const uint8_t* p_codec_info);
-
// Gets the channel count for the A2DP codec.
// |p_codec_info| is a pointer to the codec_info to decode.
// Returns the channel count on success, or -1 if |p_codec_info|
@@ -649,6 +643,11 @@
bool A2DP_InitCodecConfig(btav_a2dp_codec_index_t codec_index,
tAVDT_CFG* p_cfg);
+// Decodes and displays A2DP codec info when using |LOG_DEBUG|.
+// |p_codec_info| is a pointer to the codec_info to decode and display.
+// Returns true if the codec information is valid, otherwise false.
+bool A2DP_DumpCodecInfo(const uint8_t* p_codec_info);
+
// Add enum-based flag operators to the btav_a2dp_codec_config_t fields
#ifndef DEFINE_ENUM_FLAG_OPERATORS
#define DEFINE_ENUM_FLAG_OPERATORS(bitmask) \
diff --git a/stack/include/a2dp_sbc.h b/stack/include/a2dp_sbc.h
index 971523e..a19dd20 100644
--- a/stack/include/a2dp_sbc.h
+++ b/stack/include/a2dp_sbc.h
@@ -136,12 +136,6 @@
// contains invalid codec information.
int A2DP_GetTrackSampleRateSbc(const uint8_t* p_codec_info);
-// Gets the bits per audio sample for the A2DP SBC codec.
-// |p_codec_info| is a pointer to the SBC codec_info to decode.
-// Returns the bits per audio sample on success, or -1 if |p_codec_info|
-// contains invalid codec information.
-int A2DP_GetTrackBitsPerSampleSbc(const uint8_t* p_codec_info);
-
// Gets the channel count for the A2DP SBC codec.
// |p_codec_info| is a pointer to the SBC codec_info to decode.
// Returns the channel count on success, or -1 if |p_codec_info|
@@ -226,9 +220,10 @@
bool A2DP_BuildCodecHeaderSbc(const uint8_t* p_codec_info, BT_HDR* p_buf,
uint16_t frames_per_packet);
-// Decodes and displays SBC codec info (for debugging).
+// Decodes and displays A2DP SBC codec info when using |LOG_DEBUG|.
// |p_codec_info| is a pointer to the SBC codec_info to decode and display.
-void A2DP_DumpCodecInfoSbc(const uint8_t* p_codec_info);
+// Returns true if the codec information is valid, otherwise false.
+bool A2DP_DumpCodecInfoSbc(const uint8_t* p_codec_info);
// Gets the A2DP SBC encoder interface that can be used to encode and prepare
// A2DP packets for transmission - see |tA2DP_ENCODER_INTERFACE|.
diff --git a/stack/include/a2dp_vendor.h b/stack/include/a2dp_vendor.h
index 2a0a6c8..2b90041 100644
--- a/stack/include/a2dp_vendor.h
+++ b/stack/include/a2dp_vendor.h
@@ -126,12 +126,6 @@
// contains invalid codec information.
int A2DP_VendorGetTrackSampleRate(const uint8_t* p_codec_info);
-// Gets the bits per audio sample for the A2DP vendor-specific codec.
-// |p_codec_info| is a pointer to the vendor-specific codec_info to decode.
-// Returns the bits per audio sample on success, or -1 if |p_codec_info|
-// contains invalid codec information.
-int A2DP_VendorGetTrackBitsPerSample(const uint8_t* p_codec_info);
-
// Gets the channel count for the A2DP vendor-specific codec.
// |p_codec_info| is a pointer to the vendor-specific codec_info to decode.
// Returns the channel count on success, or -1 if |p_codec_info|
@@ -201,4 +195,9 @@
bool A2DP_VendorInitCodecConfig(btav_a2dp_codec_index_t codec_index,
tAVDT_CFG* p_cfg);
+// Decodes and displays A2DP vendor codec info when using |LOG_DEBUG|.
+// |p_codec_info| is a pointer to the codec_info to decode and display.
+// Returns true if the codec information is valid, otherwise false.
+bool A2DP_VendorDumpCodecInfo(const uint8_t* p_codec_info);
+
#endif // A2DP_VENDOR_H
diff --git a/stack/include/a2dp_vendor_aptx.h b/stack/include/a2dp_vendor_aptx.h
index 9fbc5f9..b1bebf0 100644
--- a/stack/include/a2dp_vendor_aptx.h
+++ b/stack/include/a2dp_vendor_aptx.h
@@ -88,12 +88,6 @@
// contains invalid codec information.
int A2DP_VendorGetTrackSampleRateAptx(const uint8_t* p_codec_info);
-// Gets the bits per audio sample for the A2DP aptX codec.
-// |p_codec_info| is a pointer to the aptX codec_info to decode.
-// Returns the bits per audio sample on success, or -1 if |p_codec_info|
-// contains invalid codec information.
-int A2DP_VendorGetTrackBitsPerSampleAptx(const uint8_t* p_codec_info);
-
// Gets the channel count for the A2DP aptX codec.
// |p_codec_info| is a pointer to the aptX codec_info to decode.
// Returns the channel count on success, or -1 if |p_codec_info|
@@ -117,9 +111,10 @@
bool A2DP_VendorBuildCodecHeaderAptx(const uint8_t* p_codec_info, BT_HDR* p_buf,
uint16_t frames_per_packet);
-// Decodes and displays aptX codec info (for debugging).
+// Decodes and displays A2DP aptX codec info when using |LOG_DEBUG|.
// |p_codec_info| is a pointer to the aptX codec_info to decode and display.
-void A2DP_VendorDumpCodecInfoAptx(const uint8_t* p_codec_info);
+// Returns true if the codec information is valid, otherwise false.
+bool A2DP_VendorDumpCodecInfoAptx(const uint8_t* p_codec_info);
// Gets the A2DP aptX encoder interface that can be used to encode and prepare
// A2DP packets for transmission - see |tA2DP_ENCODER_INTERFACE|.
diff --git a/stack/include/a2dp_vendor_aptx_hd.h b/stack/include/a2dp_vendor_aptx_hd.h
index 384390c..5a4a748 100644
--- a/stack/include/a2dp_vendor_aptx_hd.h
+++ b/stack/include/a2dp_vendor_aptx_hd.h
@@ -88,12 +88,6 @@
// contains invalid codec information.
int A2DP_VendorGetTrackSampleRateAptxHd(const uint8_t* p_codec_info);
-// Gets the bits per audio sample for the A2DP aptX-HD codec.
-// |p_codec_info| is a pointer to the aptX-HD codec_info to decode.
-// Returns the bits per audio sample on success, or -1 if |p_codec_info|
-// contains invalid codec information.
-int A2DP_VendorGetTrackBitsPerSampleAptxHd(const uint8_t* p_codec_info);
-
// Gets the channel count for the A2DP aptX-HD codec.
// |p_codec_info| is a pointer to the aptX-HD codec_info to decode.
// Returns the channel count on success, or -1 if |p_codec_info|
@@ -118,9 +112,10 @@
BT_HDR* p_buf,
uint16_t frames_per_packet);
-// Decodes and displays aptX-HD codec info (for debugging).
+// Decodes and displays A2DP aptX-HD codec info when using |LOG_DEBUG|.
// |p_codec_info| is a pointer to the aptX-HD codec_info to decode and display.
-void A2DP_VendorDumpCodecInfoAptxHd(const uint8_t* p_codec_info);
+// Returns true if the codec information is valid, otherwise false.
+bool A2DP_VendorDumpCodecInfoAptxHd(const uint8_t* p_codec_info);
// Gets the A2DP aptX-HD encoder interface that can be used to encode and
// prepare A2DP packets for transmission - see |tA2DP_ENCODER_INTERFACE|.
diff --git a/stack/include/a2dp_vendor_ldac.h b/stack/include/a2dp_vendor_ldac.h
index b3f91f2..5302c07 100644
--- a/stack/include/a2dp_vendor_ldac.h
+++ b/stack/include/a2dp_vendor_ldac.h
@@ -88,12 +88,6 @@
// contains invalid codec information.
int A2DP_VendorGetTrackSampleRateLdac(const uint8_t* p_codec_info);
-// Gets the bits per audio sample for the A2DP LDAC codec.
-// |p_codec_info| is a pointer to the LDAC codec_info to decode.
-// Returns the bits per audio sample on success, or -1 if |p_codec_info|
-// contains invalid codec information.
-int A2DP_VendorGetTrackBitsPerSampleLdac(const uint8_t* p_codec_info);
-
// Gets the channel count for the A2DP LDAC codec.
// |p_codec_info| is a pointer to the LDAC codec_info to decode.
// Returns the channel count on success, or -1 if |p_codec_info|
@@ -124,9 +118,10 @@
bool A2DP_VendorBuildCodecHeaderLdac(const uint8_t* p_codec_info, BT_HDR* p_buf,
uint16_t frames_per_packet);
-// Decodes and displays LDAC codec info (for debugging).
+// Decodes and displays A2DP LDAC codec info when using |LOG_DEBUG|.
// |p_codec_info| is a pointer to the LDAC codec_info to decode and display.
-void A2DP_VendorDumpCodecInfoLdac(const uint8_t* p_codec_info);
+// Returns true if the codec information is valid, otherwise false.
+bool A2DP_VendorDumpCodecInfoLdac(const uint8_t* p_codec_info);
// Gets the A2DP LDAC encoder interface that can be used to encode and prepare
// A2DP packets for transmission - see |tA2DP_ENCODER_INTERFACE|.
diff --git a/stack/include/advertise_data_parser.h b/stack/include/advertise_data_parser.h
index 24ee2b3..0efac4f 100644
--- a/stack/include/advertise_data_parser.h
+++ b/stack/include/advertise_data_parser.h
@@ -22,6 +22,36 @@
class AdvertiseDataParser {
public:
+ static void RemoveTrailingZeros(std::vector<uint8_t>& ad) {
+ size_t position = 0;
+
+ size_t ad_len = ad.size();
+ while (position != ad_len) {
+ uint8_t len = ad[position];
+
+ // A field length of 0 would be invalid as it should at least contain the
+ // EIR field type. However, some existing devices send zero padding at the
+ // end of advertisement. If this is the case, cut the zero padding from
+ // end of the packet. Otherwise i.e. gluing scan response to advertise
+ // data will result in data with zero padding in the middle.
+ if (len == 0) {
+ size_t zeros_start = position;
+ for (size_t i = position + 1; i < ad_len; i++) {
+ if (ad[i] != 0) return;
+ }
+
+ ad.erase(ad.begin() + zeros_start, ad.end());
+ return;
+ }
+
+ if (position + len >= ad_len) {
+ return;
+ }
+
+ position += len + 1;
+ }
+ }
+
/**
* Return true if this |ad| represent properly formatted advertising data.
*/
@@ -33,8 +63,14 @@
uint8_t len = ad[position];
// A field length of 0 would be invalid as it should at least contain the
- // EIR field type.
- if (len == 0) return false;
+ // EIR field type. However, some existing devices send zero padding at the
+ // end of advertisement. If this is the case, treat the packet as valid.
+ if (len == 0) {
+ for (size_t i = position + 1; i < ad_len; i++) {
+ if (ad[i] != 0) return false;
+ }
+ return true;
+ }
// If the length of the current field would exceed the total data length,
// then the data is badly formatted.
diff --git a/stack/include/avdt_api.h b/stack/include/avdt_api.h
index 24108bc..aaee2da 100644
--- a/stack/include/avdt_api.h
+++ b/stack/include/avdt_api.h
@@ -34,7 +34,7 @@
#ifndef AVDT_VERSION
#define AVDT_VERSION 0x0102
#endif
-#define AVDT_VERSION_SYNC 0x0103
+#define AVDT_VERSION_1_3 0x0103
/* Maximum size in bytes of the codec capabilities information element. */
#define AVDT_CODEC_SIZE 20
diff --git a/stack/include/ble_advertiser.h b/stack/include/ble_advertiser.h
index d51161c..b717c5a 100644
--- a/stack/include/ble_advertiser.h
+++ b/stack/include/ble_advertiser.h
@@ -71,6 +71,7 @@
static void Initialize(BleAdvertiserHciInterface* interface);
static void CleanUp();
+ static bool IsInitialized();
static BleAdvertisingManager* Get();
/* Register an advertising instance, status will be returned in |cb|
diff --git a/stack/include/bt_types.h b/stack/include/bt_types.h
index da0baac..5540a7e 100644
--- a/stack/include/bt_types.h
+++ b/stack/include/bt_types.h
@@ -138,9 +138,6 @@
#define BT_EVT_TO_OPP_SRVR_CMDS 0x3900
#define BT_EVT_TO_OPP_CLNT_CMDS 0x3a00
-/* gap events */
-#define BT_EVT_TO_GAP_MSG 0x3b00
-
/* for NFC */
/************************************/
/* NCI Command, Notification or Data*/
@@ -798,7 +795,6 @@
#define TRACE_LAYER_TCS 0x000b0000
#define TRACE_LAYER_OBEX 0x000c0000
#define TRACE_LAYER_BTM 0x000d0000
-#define TRACE_LAYER_GAP 0x000e0000
#define TRACE_LAYER_ICP 0x00110000
#define TRACE_LAYER_HSP2 0x00120000
#define TRACE_LAYER_SPP 0x00130000
diff --git a/stack/include/btm_api_types.h b/stack/include/btm_api_types.h
index a4712da..e4a1106 100644
--- a/stack/include/btm_api_types.h
+++ b/stack/include/btm_api_types.h
@@ -49,8 +49,9 @@
BTM_SUCCESS_NO_SECURITY, /* 17 security passed, no security set */
BTM_FAILED_ON_SECURITY, /* 18 security failed */
BTM_REPEATED_ATTEMPTS, /* 19 repeated attempts for LE security requests */
- BTM_MODE4_LEVEL4_NOT_SUPPORTED /* 20 Secure Connections Only Mode can't be
- supported */
+ BTM_MODE4_LEVEL4_NOT_SUPPORTED, /* 20 Secure Connections Only Mode can't be
+ supported */
+ BTM_DEV_BLACKLISTED /* 21 The device is Blacklisted */
};
typedef uint8_t tBTM_STATUS;
diff --git a/stack/include/btu.h b/stack/include/btu.h
index aef8781..2b6834d 100644
--- a/stack/include/btu.h
+++ b/stack/include/btu.h
@@ -29,28 +29,11 @@
#include <base/callback.h>
#include <base/location.h>
+#include <base/threading/thread.h>
#include "bt_common.h"
#include "bt_target.h"
#include "osi/include/alarm.h"
-// HACK(zachoverflow): temporary dark magic
-#define BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK \
- 0x1700 // didn't look used in bt_types...here goes nothing
-typedef struct { void (*callback)(BT_HDR*); } post_to_task_hack_t;
-
-typedef struct {
- void (*callback)(BT_HDR*);
- BT_HDR* response;
- void* context;
-} command_complete_hack_t;
-
-typedef struct {
- void (*callback)(BT_HDR*);
- uint8_t status;
- BT_HDR* command;
- void* context;
-} command_status_hack_t;
-
/* Global BTU data */
extern uint8_t btu_trace_level;
@@ -59,18 +42,23 @@
/* Functions provided by btu_hcif.cc
***********************************
*/
-extern void btu_hcif_process_event(uint8_t controller_id, BT_HDR* p_buf);
-extern void btu_hcif_send_cmd(uint8_t controller_id, BT_HDR* p_msg);
-extern void btu_hcif_send_cmd_with_cb(
- const tracked_objects::Location& posted_from, uint16_t opcode,
- uint8_t* params, uint8_t params_len,
- base::Callback<void(uint8_t*, uint16_t)> cb);
+void btu_hcif_process_event(uint8_t controller_id, BT_HDR* p_buf);
+void btu_hcif_send_cmd(uint8_t controller_id, BT_HDR* p_msg);
+void btu_hcif_send_cmd_with_cb(const tracked_objects::Location& posted_from,
+ uint16_t opcode, uint8_t* params,
+ uint8_t params_len,
+ base::Callback<void(uint8_t*, uint16_t)> cb);
/* Functions provided by btu_init.cc
***********************************
*/
-extern void btu_init_core(void);
-extern void btu_free_core(void);
+void btu_init_core(void);
+void btu_free_core(void);
+
+/* Functions provided by btu_task.cc
+ ***********************************
+*/
+base::MessageLoop* get_message_loop();
void BTU_StartUp(void);
void BTU_ShutDown(void);
diff --git a/stack/include/gap_api.h b/stack/include/gap_api.h
index 7954296..024ea54 100644
--- a/stack/include/gap_api.h
+++ b/stack/include/gap_api.h
@@ -313,18 +313,6 @@
/*******************************************************************************
*
- * 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
- *
- ******************************************************************************/
-extern uint8_t GAP_SetTraceLevel(uint8_t new_level);
-
-/*******************************************************************************
- *
* Function GAP_Init
*
* Description Initializes the control blocks used by GAP.
diff --git a/stack/include/gatt_api.h b/stack/include/gatt_api.h
index 815dce7..18aa91f 100644
--- a/stack/include/gatt_api.h
+++ b/stack/include/gatt_api.h
@@ -150,10 +150,6 @@
#define GATT_CL_MAX_LCB 22
#endif
-#ifndef GATT_MAX_SCCB
-#define GATT_MAX_SCCB 10
-#endif
-
/* GATT notification caching timer, default to be three seconds
*/
#ifndef GATTC_NOTIF_TIMEOUT
diff --git a/stack/l2cap/l2c_ble.cc b/stack/l2cap/l2c_ble.cc
index d15a87a..07f8105 100644
--- a/stack/l2cap/l2c_ble.cc
+++ b/stack/l2cap/l2c_ble.cc
@@ -292,6 +292,7 @@
if (!p_lcb) {
btm_sec_disconnect(handle, HCI_ERR_NO_CONNECTION);
L2CAP_TRACE_ERROR("l2cble_scanner_conn_comp - failed to allocate LCB");
+ btm_ble_set_conn_st(BLE_CONN_IDLE);
return;
} else {
if (!l2cu_initialize_fixed_ccb(
@@ -300,12 +301,14 @@
.fixed_chnl_opts)) {
btm_sec_disconnect(handle, HCI_ERR_NO_CONNECTION);
L2CAP_TRACE_WARNING("l2cble_scanner_conn_comp - LCB but no CCB");
+ btm_ble_set_conn_st(BLE_CONN_IDLE);
return;
}
}
} else if (p_lcb->link_state != LST_CONNECTING) {
L2CAP_TRACE_ERROR("L2CAP got BLE scanner conn_comp in bad state: %d",
p_lcb->link_state);
+ btm_ble_set_conn_st(BLE_CONN_IDLE);
return;
}
alarm_cancel(p_lcb->l2c_lcb_timer);
diff --git a/stack/l2cap/l2c_int.h b/stack/l2cap/l2c_int.h
index d6758bb..dde6c8a 100644
--- a/stack/l2cap/l2c_int.h
+++ b/stack/l2cap/l2c_int.h
@@ -546,6 +546,14 @@
typedef void(tL2C_FCR_MGMT_EVT_HDLR)(uint8_t, tL2C_CCB*);
+/* Necessary info for postponed TX completion callback
+*/
+typedef struct {
+ uint16_t local_cid;
+ uint16_t num_sdu;
+ tL2CA_TX_COMPLETE_CB* cb;
+} tL2C_TX_COMPLETE_CB_INFO;
+
/* The offset in a buffer that L2CAP will use when building commands.
*/
#define L2CAP_SEND_CMD_OFFSET 0
@@ -580,6 +588,7 @@
/* Functions provided by l2c_utils.cc
***********************************
*/
+extern bool l2cu_can_allocate_lcb(void);
extern tL2C_LCB* l2cu_allocate_lcb(BD_ADDR p_bd_addr, bool is_bonding,
tBT_TRANSPORT transport);
extern bool l2cu_start_post_bond_timer(uint16_t handle);
@@ -630,6 +639,8 @@
extern void l2cu_check_channel_congestion(tL2C_CCB* p_ccb);
extern void l2cu_disconnect_chnl(tL2C_CCB* p_ccb);
+extern void l2cu_tx_complete(tL2C_TX_COMPLETE_CB_INFO* p_cbi);
+
#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
extern void l2cu_set_non_flushable_pbf(bool);
#endif
@@ -700,7 +711,8 @@
extern bool l2cu_create_conn(tL2C_LCB* p_lcb, tBT_TRANSPORT transport,
uint8_t initiating_phys);
extern bool l2cu_create_conn_after_switch(tL2C_LCB* p_lcb);
-extern BT_HDR* l2cu_get_next_buffer_to_send(tL2C_LCB* p_lcb);
+extern BT_HDR* l2cu_get_next_buffer_to_send(tL2C_LCB* p_lcb,
+ tL2C_TX_COMPLETE_CB_INFO* p_cbi);
extern void l2cu_resubmit_pending_sec_req(BD_ADDR p_bda);
extern void l2cu_initialize_amp_ccb(tL2C_LCB* p_lcb);
extern void l2cu_adjust_out_mps(tL2C_CCB* p_ccb);
diff --git a/stack/l2cap/l2c_link.cc b/stack/l2cap/l2c_link.cc
index 7110cff..2730242 100644
--- a/stack/l2cap/l2c_link.cc
+++ b/stack/l2cap/l2c_link.cc
@@ -45,7 +45,8 @@
extern fixed_queue_t* btu_general_alarm_queue;
-static bool l2c_link_send_to_lower(tL2C_LCB* p_lcb, BT_HDR* p_buf);
+static bool l2c_link_send_to_lower(tL2C_LCB* p_lcb, BT_HDR* p_buf,
+ tL2C_TX_COMPLETE_CB_INFO* p_cbi);
/*******************************************************************************
*
@@ -992,6 +993,9 @@
/* Loop through, starting at the next */
for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++) {
+ /* Check for wraparound */
+ if (p_lcb == &l2cb.lcb_pool[MAX_L2CAP_LINKS]) p_lcb = &l2cb.lcb_pool[0];
+
/* If controller window is full, nothing to do */
if (((l2cb.controller_xmit_window == 0 ||
(l2cb.round_robin_unacked >= l2cb.round_robin_quota)) &&
@@ -999,10 +1003,7 @@
(p_lcb->transport == BT_TRANSPORT_LE &&
(l2cb.ble_round_robin_unacked >= l2cb.ble_round_robin_quota ||
l2cb.controller_le_xmit_window == 0)))
- break;
-
- /* Check for wraparound */
- if (p_lcb == &l2cb.lcb_pool[MAX_L2CAP_LINKS]) p_lcb = &l2cb.lcb_pool[0];
+ continue;
if ((!p_lcb->in_use) || (p_lcb->partial_segment_being_sent) ||
(p_lcb->link_state != LST_CONNECTED) ||
@@ -1013,16 +1014,17 @@
if (!list_is_empty(p_lcb->link_xmit_data_q)) {
p_buf = (BT_HDR*)list_front(p_lcb->link_xmit_data_q);
list_remove(p_lcb->link_xmit_data_q, p_buf);
- l2c_link_send_to_lower(p_lcb, p_buf);
+ l2c_link_send_to_lower(p_lcb, p_buf, NULL);
} else if (single_write) {
/* If only doing one write, break out */
break;
}
/* If nothing on the link queue, check the channel queue */
else {
- p_buf = l2cu_get_next_buffer_to_send(p_lcb);
+ tL2C_TX_COMPLETE_CB_INFO cbi;
+ p_buf = l2cu_get_next_buffer_to_send(p_lcb, &cbi);
if (p_buf != NULL) {
- l2c_link_send_to_lower(p_lcb, p_buf);
+ l2c_link_send_to_lower(p_lcb, p_buf, &cbi);
}
}
}
@@ -1055,7 +1057,7 @@
p_buf = (BT_HDR*)list_front(p_lcb->link_xmit_data_q);
list_remove(p_lcb->link_xmit_data_q, p_buf);
- if (!l2c_link_send_to_lower(p_lcb, p_buf)) break;
+ if (!l2c_link_send_to_lower(p_lcb, p_buf, NULL)) break;
}
if (!single_write) {
@@ -1065,10 +1067,11 @@
(l2cb.controller_le_xmit_window != 0 &&
(p_lcb->transport == BT_TRANSPORT_LE))) &&
(p_lcb->sent_not_acked < p_lcb->link_xmit_quota)) {
- p_buf = l2cu_get_next_buffer_to_send(p_lcb);
+ tL2C_TX_COMPLETE_CB_INFO cbi;
+ p_buf = l2cu_get_next_buffer_to_send(p_lcb, &cbi);
if (p_buf == NULL) break;
- if (!l2c_link_send_to_lower(p_lcb, p_buf)) break;
+ if (!l2c_link_send_to_lower(p_lcb, p_buf, &cbi)) break;
}
}
@@ -1093,7 +1096,7 @@
* Returns true for success, false for fail
*
******************************************************************************/
-static bool l2c_link_send_to_lower(tL2C_LCB* p_lcb, BT_HDR* p_buf) {
+static bool l2c_link_send_to_lower(tL2C_LCB* p_lcb, BT_HDR* p_buf, tL2C_TX_COMPLETE_CB_INFO* p_cbi) {
uint16_t num_segs;
uint16_t xmit_window, acl_data_size;
const controller_t* controller = controller_get_interface();
@@ -1183,6 +1186,9 @@
}
#endif
+ if (p_cbi)
+ l2cu_tx_complete(p_cbi);
+
return true;
}
diff --git a/stack/l2cap/l2c_utils.cc b/stack/l2cap/l2c_utils.cc
index f6728d6b..d0f0053 100644
--- a/stack/l2cap/l2c_utils.cc
+++ b/stack/l2cap/l2c_utils.cc
@@ -43,6 +43,22 @@
/*******************************************************************************
*
+ * Function l2cu_can_allocate_lcb
+ *
+ * Description Look for an unused LCB
+ *
+ * Returns true if there is space for one more lcb
+ *
+ ******************************************************************************/
+bool l2cu_can_allocate_lcb(void) {
+ for (int i = 0; i < MAX_L2CAP_LINKS; i++) {
+ if (!l2cb.lcb_pool[i].in_use) return true;
+ }
+ return false;
+}
+
+/*******************************************************************************
+ *
* Function l2cu_allocate_lcb
*
* Description Look for an unused LCB
@@ -2375,14 +2391,14 @@
BTM_VendorSpecificCommand(HCI_BRCM_SET_ACL_PRIORITY,
HCI_BRCM_ACL_PRIORITY_PARAM_SIZE, command,
NULL);
-
- /* Adjust lmp buffer allocation for this channel if priority changed */
- if (p_lcb->acl_priority != priority) {
- p_lcb->acl_priority = priority;
- l2c_link_adjust_allocation();
- }
}
}
+
+ /* Adjust lmp buffer allocation for this channel if priority changed */
+ if (p_lcb->acl_priority != priority) {
+ p_lcb->acl_priority = priority;
+ l2c_link_adjust_allocation();
+ }
return (true);
}
@@ -3225,6 +3241,11 @@
}
#endif /* (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE) */
+void l2cu_tx_complete(tL2C_TX_COMPLETE_CB_INFO* p_cbi) {
+ if (p_cbi->cb != NULL)
+ p_cbi->cb(p_cbi->local_cid, p_cbi->num_sdu);
+}
+
/******************************************************************************
*
* Function l2cu_get_next_buffer_to_send
@@ -3235,7 +3256,7 @@
* Returns pointer to buffer or NULL
*
******************************************************************************/
-BT_HDR* l2cu_get_next_buffer_to_send(tL2C_LCB* p_lcb) {
+BT_HDR* l2cu_get_next_buffer_to_send(tL2C_LCB* p_lcb, tL2C_TX_COMPLETE_CB_INFO* p_cbi) {
tL2C_CCB* p_ccb;
BT_HDR* p_buf;
@@ -3243,6 +3264,8 @@
#if (L2CAP_NUM_FIXED_CHNLS > 0)
int xx;
+ p_cbi->cb = NULL;
+
for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++) {
p_ccb = p_lcb->p_fixed_ccbs[xx];
if (p_ccb == NULL) continue;
@@ -3271,12 +3294,14 @@
if (!fixed_queue_is_empty(p_ccb->xmit_hold_q)) {
p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->xmit_hold_q);
if (NULL == p_buf) {
- L2CAP_TRACE_ERROR("l2cu_get_buffer_to_send: No data to be sent");
+ L2CAP_TRACE_ERROR("%s: No data to be sent", __func__);
return (NULL);
}
- /* send tx complete */
- if (l2cb.fixed_reg[xx].pL2CA_FixedTxComplete_Cb)
- (*l2cb.fixed_reg[xx].pL2CA_FixedTxComplete_Cb)(p_ccb->local_cid, 1);
+
+ /* Prepare callback info for TX completion */
+ p_cbi->cb = l2cb.fixed_reg[xx].pL2CA_FixedTxComplete_Cb;
+ p_cbi->local_cid = p_ccb->local_cid;
+ p_cbi->num_sdu = 1;
l2cu_check_channel_congestion(p_ccb);
l2cu_set_acl_hci_header(p_buf, p_ccb);
diff --git a/stack/rfcomm/port_utils.cc b/stack/rfcomm/port_utils.cc
index 20e6a88..32fabec 100644
--- a/stack/rfcomm/port_utils.cc
+++ b/stack/rfcomm/port_utils.cc
@@ -231,10 +231,13 @@
}
rfc_port_timer_stop(p_port);
+
+ mutex_global_lock();
fixed_queue_free(p_port->tx.queue, NULL);
p_port->tx.queue = NULL;
fixed_queue_free(p_port->rx.queue, NULL);
p_port->rx.queue = NULL;
+ mutex_global_unlock();
if (p_port->keep_port_handle) {
RFCOMM_TRACE_DEBUG("%s Re-initialize handle: %d", __func__, p_port->inx);
diff --git a/stack/smp/smp_act.cc b/stack/smp/smp_act.cc
index 51b8972..0c8fb28 100644
--- a/stack/smp/smp_act.cc
+++ b/stack/smp/smp_act.cc
@@ -28,6 +28,7 @@
extern fixed_queue_t* btu_general_alarm_queue;
#define SMP_KEY_DIST_TYPE_MAX 4
+
const tSMP_ACT smp_distribute_act[] = {smp_generate_ltk, smp_send_id_info,
smp_generate_csrk,
smp_set_derive_link_key};
@@ -44,37 +45,14 @@
}
static bool pts_test_send_authentication_complete_failure(tSMP_CB* p_cb) {
- uint8_t reason = 0;
-
- if (p_cb->cert_failure < 2 || p_cb->cert_failure > 6) return false;
-
- SMP_TRACE_ERROR("%s failure case = %d", __func__, p_cb->cert_failure);
-
- switch (p_cb->cert_failure) {
- case 2:
- reason = SMP_PAIR_AUTH_FAIL;
- smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
- break;
- case 3:
- reason = SMP_PAIR_FAIL_UNKNOWN;
- smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
- break;
- case 4:
- reason = SMP_PAIR_NOT_SUPPORT;
- smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
- break;
- case 5:
- reason = SMP_PASSKEY_ENTRY_FAIL;
- smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
- break;
- case 6:
- reason = SMP_REPEATED_ATTEMPTS;
- smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
- break;
+ uint8_t reason = p_cb->cert_failure;
+ if (reason == SMP_PAIR_AUTH_FAIL || reason == SMP_PAIR_FAIL_UNKNOWN ||
+ reason == SMP_PAIR_NOT_SUPPORT || reason == SMP_PASSKEY_ENTRY_FAIL ||
+ reason == SMP_REPEATED_ATTEMPTS) {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return true;
}
-
- return true;
- ;
+ return false;
}
/*******************************************************************************
@@ -1556,12 +1534,21 @@
SMP_TRACE_DEBUG("%s start ", __func__);
// PTS Testing failure modes
- if (p_cb->cert_failure == 1) {
+ if (p_cb->cert_failure == SMP_CONFIRM_VALUE_ERR) {
SMP_TRACE_ERROR("%s failure case = %d", __func__, p_cb->cert_failure);
reason = p_cb->failure = SMP_CONFIRM_VALUE_ERR;
smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
return;
}
+ // PTS Testing failure modes (for LT)
+ if ((p_cb->cert_failure == SMP_NUMERIC_COMPAR_FAIL) &&
+ (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS) &&
+ (p_cb->role == HCI_ROLE_SLAVE)) {
+ SMP_TRACE_ERROR("%s failure case = %d", __func__, p_cb->cert_failure);
+ reason = p_cb->failure = SMP_NUMERIC_COMPAR_FAIL;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
switch (p_cb->selected_association_model) {
case SMP_MODEL_SEC_CONN_JUSTWORKS:
@@ -1589,7 +1576,8 @@
break;
case SMP_MODEL_SEC_CONN_PASSKEY_ENT:
case SMP_MODEL_SEC_CONN_PASSKEY_DISP:
- if (!smp_check_commitment(p_cb) && p_cb->cert_failure != 9) {
+ if (!smp_check_commitment(p_cb) &&
+ p_cb->cert_failure != SMP_NUMERIC_COMPAR_FAIL) {
reason = p_cb->failure = SMP_CONFIRM_VALUE_ERR;
smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
break;
diff --git a/stack/smp/smp_api.cc b/stack/smp/smp_api.cc
index ebd300b..ae9b8ab 100644
--- a/stack/smp/smp_api.cc
+++ b/stack/smp/smp_api.cc
@@ -212,10 +212,9 @@
bool status = false;
// PTS SMP failure test cases
- if (p_cb->cert_failure == 7)
- err_code = SMP_PASSKEY_ENTRY_FAIL;
- else if (p_cb->cert_failure == 8)
- err_code = SMP_NUMERIC_COMPAR_FAIL;
+ if (p_cb->cert_failure == SMP_PASSKEY_ENTRY_FAIL ||
+ p_cb->cert_failure == SMP_NUMERIC_COMPAR_FAIL)
+ err_code = p_cb->cert_failure;
BTM_TRACE_EVENT("SMP_CancelPair state=%d flag=0x%x ", p_cb->state,
p_cb->flags);
diff --git a/stack/test/ad_parser_unittest.cc b/stack/test/ad_parser_unittest.cc
index 46ff3ec..ab6df56 100644
--- a/stack/test/ad_parser_unittest.cc
+++ b/stack/test/ad_parser_unittest.cc
@@ -23,9 +23,9 @@
const std::vector<uint8_t> data0;
EXPECT_TRUE(AdvertiseDataParser::IsValid(data0));
- // Single empty field not allowed.
+ // Single empty field allowed (treated as zero padding).
const std::vector<uint8_t> data1{0x00};
- EXPECT_FALSE(AdvertiseDataParser::IsValid(data1));
+ EXPECT_TRUE(AdvertiseDataParser::IsValid(data1));
}
TEST(AdvertiseDataParserTest, IsValidBad) {
@@ -44,6 +44,16 @@
// Two fields, second field empty.
const std::vector<uint8_t> data3{0x02, 0x02, 0x00, 0x01};
EXPECT_FALSE(AdvertiseDataParser::IsValid(data3));
+
+ // Non-zero padding at end of packet.
+ const std::vector<uint8_t> data4{0x03, 0x02, 0x01, 0x02, 0x02, 0x03, 0x01,
+ 0x00, 0x00, 0xBA, 0xBA, 0x00, 0x00};
+ EXPECT_FALSE(AdvertiseDataParser::IsValid(data1));
+
+ // Non-zero padding at end of packet.
+ const std::vector<uint8_t> data5{0x03, 0x02, 0x01, 0x02, 0x02,
+ 0x03, 0x01, 0x00, 0xBA};
+ EXPECT_FALSE(AdvertiseDataParser::IsValid(data1));
}
TEST(AdvertiseDataParserTest, IsValidGood) {
@@ -54,6 +64,18 @@
// Two fields.
const std::vector<uint8_t> data1{0x03, 0x02, 0x01, 0x02, 0x02, 0x03, 0x01};
EXPECT_TRUE(AdvertiseDataParser::IsValid(data1));
+
+ // Zero padding at end of packet.
+ const std::vector<uint8_t> data2{0x03, 0x02, 0x01, 0x02,
+ 0x02, 0x03, 0x01, 0x00};
+ EXPECT_TRUE(AdvertiseDataParser::IsValid(data2));
+
+ // zero padding at end of packet, sample data from real device
+ const std::vector<uint8_t> data3{
+ 0x10, 0x096, 0x85, 0x44, 0x32, 0x04, 0x74, 0x32, 0x03, 0x13, 0x93,
+ 0xa, 0x32, 0x39, 0x3a, 0x65, 0x32, 0x05, 0x12, 0x50, 0x00, 0x50,
+ 0x00, 0x02, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ EXPECT_TRUE(AdvertiseDataParser::IsValid(data3));
}
TEST(AdvertiseDataParserTest, GetFieldByType) {
@@ -78,4 +100,25 @@
data = AdvertiseDataParser::GetFieldByType(data1, 0x03, &p_length);
EXPECT_EQ(nullptr, data);
EXPECT_EQ(0, p_length);
+}
+
+// This test makes sure that RemoveTrailingZeros is working correctly. It does
+// run the RemoveTrailingZeros for ad data, then glue scan response at end of
+// it, and checks that the resulting data is good.
+TEST(AdvertiseDataParserTest, RemoveTrailingZeros) {
+ std::vector<uint8_t> podo_ad_data{
+ 0x02, 0x01, 0x02, 0x11, 0x06, 0x66, 0x9a, 0x0c, 0x20, 0x00, 0x08,
+ 0x37, 0xa8, 0xe5, 0x11, 0x81, 0x8b, 0xd0, 0xf0, 0xf0, 0xf0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ const std::vector<uint8_t> podo_scan_resp{
+ 0x03, 0x19, 0x00, 0x80, 0x09, 0x09, 0x50, 0x6f, 0x64, 0x6f, 0x51,
+ 0x35, 0x56, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+ AdvertiseDataParser::RemoveTrailingZeros(podo_ad_data);
+
+ std::vector<uint8_t> glued(podo_ad_data);
+ glued.insert(glued.end(), podo_ad_data.begin(), podo_ad_data.end());
+
+ EXPECT_TRUE(AdvertiseDataParser::IsValid(glued));
}
\ No newline at end of file
diff --git a/stack/test/stack_a2dp_test.cc b/stack/test/stack_a2dp_test.cc
index 06808d1..3808df4 100644
--- a/stack/test/stack_a2dp_test.cc
+++ b/stack/test/stack_a2dp_test.cc
@@ -46,6 +46,26 @@
9 // Dummy
};
+const uint8_t codec_info_sbc_capability[AVDT_CODEC_SIZE] = {
+ 6, // Length (A2DP_SBC_INFO_LEN)
+ 0, // Media Type: AVDT_MEDIA_TYPE_AUDIO
+ 0, // Media Codec Type: A2DP_MEDIA_CT_SBC
+ 0x20 | // Sample Frequency: A2DP_SBC_IE_SAMP_FREQ_44 |
+ 0x08 | 0x01, // Channel Mode: A2DP_SBC_IE_CH_MD_MONO |
+ // A2DP_SBC_IE_CH_MD_JOINT
+ 0x80 | 0x40 | 0x20 | 0x10 | // Block Length: A2DP_SBC_IE_BLOCKS_4 |
+ // A2DP_SBC_IE_BLOCKS_8 |
+ // A2DP_SBC_IE_BLOCKS_12 |
+ // A2DP_SBC_IE_BLOCKS_16 |
+ 0x04 | // Subbands: A2DP_SBC_IE_SUBBAND_8 |
+ 0x01, // Allocation Method: A2DP_SBC_IE_ALLOC_MD_L
+ 2, // MinimumBitpool Value: A2DP_SBC_IE_MIN_BITPOOL
+ 53, // Maximum Bitpool Value: A2DP_SBC_MAX_BITPOOL
+ 7, // Dummy
+ 8, // Dummy
+ 9 // Dummy
+};
+
const uint8_t codec_info_sbc_sink_capability[AVDT_CODEC_SIZE] = {
6, // Length (A2DP_SBC_INFO_LEN)
0, // Media Type: AVDT_MEDIA_TYPE_AUDIO
@@ -252,7 +272,9 @@
TEST_F(StackA2dpTest, test_a2dp_is_codec_valid_sbc) {
EXPECT_TRUE(A2DP_IsSourceCodecValid(codec_info_sbc));
+ EXPECT_TRUE(A2DP_IsSourceCodecValid(codec_info_sbc_capability));
EXPECT_TRUE(A2DP_IsPeerSourceCodecValid(codec_info_sbc));
+ EXPECT_TRUE(A2DP_IsPeerSourceCodecValid(codec_info_sbc_capability));
EXPECT_TRUE(A2DP_IsSinkCodecValid(codec_info_sbc_sink_capability));
EXPECT_TRUE(A2DP_IsPeerSinkCodecValid(codec_info_sbc_sink_capability));
@@ -287,23 +309,27 @@
TEST_F(StackA2dpTest, test_a2dp_is_codec_valid_aac) {
EXPECT_TRUE(A2DP_IsSourceCodecValid(codec_info_aac));
- EXPECT_TRUE(A2DP_IsPeerSinkCodecValid(codec_info_aac_capability));
+ EXPECT_TRUE(A2DP_IsSourceCodecValid(codec_info_aac_capability));
+ EXPECT_FALSE(A2DP_IsPeerSourceCodecValid(codec_info_aac));
+ EXPECT_FALSE(A2DP_IsPeerSourceCodecValid(codec_info_aac_capability));
+
+ EXPECT_FALSE(A2DP_IsSinkCodecValid(codec_info_aac_sink_capability));
EXPECT_TRUE(A2DP_IsPeerSinkCodecValid(codec_info_aac_sink_capability));
// Test with invalid AAC codecs
uint8_t codec_info_aac_invalid[AVDT_CODEC_SIZE];
- memset(codec_info_aac_invalid, 0, sizeof(codec_info_aac_invalid));
- EXPECT_FALSE(A2DP_IsSourceCodecValid(codec_info_aac_invalid));
- EXPECT_FALSE(A2DP_IsPeerSinkCodecValid(codec_info_aac_invalid));
-
memcpy(codec_info_aac_invalid, codec_info_aac, sizeof(codec_info_aac));
codec_info_aac_invalid[0] = 0; // Corrupt the Length field
EXPECT_FALSE(A2DP_IsSourceCodecValid(codec_info_aac_invalid));
+ EXPECT_FALSE(A2DP_IsSinkCodecValid(codec_info_aac_invalid));
+ EXPECT_FALSE(A2DP_IsPeerSourceCodecValid(codec_info_aac_invalid));
EXPECT_FALSE(A2DP_IsPeerSinkCodecValid(codec_info_aac_invalid));
memcpy(codec_info_aac_invalid, codec_info_aac, sizeof(codec_info_aac));
codec_info_aac_invalid[1] = 0xff; // Corrupt the Media Type field
EXPECT_FALSE(A2DP_IsSourceCodecValid(codec_info_aac_invalid));
+ EXPECT_FALSE(A2DP_IsSinkCodecValid(codec_info_aac_invalid));
+ EXPECT_FALSE(A2DP_IsPeerSourceCodecValid(codec_info_aac_invalid));
EXPECT_FALSE(A2DP_IsPeerSinkCodecValid(codec_info_aac_invalid));
}
@@ -320,6 +346,7 @@
TEST_F(StackA2dpTest, test_a2dp_is_sink_codec_supported) {
EXPECT_TRUE(A2DP_IsSinkCodecSupported(codec_info_sbc));
+ EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_sbc_capability));
EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_sbc_sink_capability));
EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_aac));
@@ -331,6 +358,7 @@
TEST_F(StackA2dpTest, test_a2dp_is_peer_source_codec_supported) {
EXPECT_TRUE(A2DP_IsPeerSourceCodecSupported(codec_info_sbc));
+ EXPECT_TRUE(A2DP_IsPeerSourceCodecSupported(codec_info_sbc_capability));
EXPECT_TRUE(A2DP_IsPeerSourceCodecSupported(codec_info_sbc_sink_capability));
EXPECT_FALSE(A2DP_IsPeerSourceCodecSupported(codec_info_aac));
@@ -423,6 +451,7 @@
// Explicit tests for known codecs
EXPECT_STREQ(A2DP_CodecName(codec_info_sbc), "SBC");
+ EXPECT_STREQ(A2DP_CodecName(codec_info_sbc_capability), "SBC");
EXPECT_STREQ(A2DP_CodecName(codec_info_sbc_sink_capability), "SBC");
EXPECT_STREQ(A2DP_CodecName(codec_info_aac), "AAC");
EXPECT_STREQ(A2DP_CodecName(codec_info_aac_capability), "AAC");
@@ -447,6 +476,7 @@
}
TEST_F(StackA2dpTest, test_a2dp_codec_type_equals) {
+ EXPECT_TRUE(A2DP_CodecTypeEquals(codec_info_sbc, codec_info_sbc_capability));
EXPECT_TRUE(
A2DP_CodecTypeEquals(codec_info_sbc, codec_info_sbc_sink_capability));
EXPECT_TRUE(A2DP_CodecTypeEquals(codec_info_aac, codec_info_aac_capability));
@@ -523,12 +553,6 @@
EXPECT_EQ(A2DP_GetTrackSampleRate(codec_info_non_a2dp), -1);
}
-TEST_F(StackA2dpTest, test_a2dp_get_track_bits_per_sample) {
- EXPECT_EQ(A2DP_GetTrackBitsPerSample(codec_info_sbc), 16);
- EXPECT_EQ(A2DP_GetTrackBitsPerSample(codec_info_aac), 16);
- EXPECT_EQ(A2DP_GetTrackBitsPerSample(codec_info_non_a2dp), -1);
-}
-
TEST_F(StackA2dpTest, test_a2dp_get_track_channel_count) {
EXPECT_EQ(A2DP_GetTrackChannelCount(codec_info_sbc), 2);
EXPECT_EQ(A2DP_GetTrackChannelCount(codec_info_aac), 2);
@@ -567,6 +591,7 @@
TEST_F(StackA2dpTest, test_a2dp_get_min_bitpool_sbc) {
EXPECT_EQ(A2DP_GetMinBitpoolSbc(codec_info_sbc), 2);
+ EXPECT_EQ(A2DP_GetMinBitpoolSbc(codec_info_sbc_capability), 2);
EXPECT_EQ(A2DP_GetMinBitpoolSbc(codec_info_sbc_sink_capability), 2);
EXPECT_EQ(A2DP_GetMinBitpoolSbc(codec_info_aac), -1);
EXPECT_EQ(A2DP_GetMinBitpoolSbc(codec_info_non_a2dp), -1);
@@ -574,6 +599,7 @@
TEST_F(StackA2dpTest, test_a2dp_get_max_bitpool_sbc) {
EXPECT_EQ(A2DP_GetMaxBitpoolSbc(codec_info_sbc), 53);
+ EXPECT_EQ(A2DP_GetMaxBitpoolSbc(codec_info_sbc_capability), 53);
EXPECT_EQ(A2DP_GetMaxBitpoolSbc(codec_info_sbc_sink_capability), 53);
EXPECT_EQ(A2DP_GetMaxBitpoolSbc(codec_info_aac), -1);
EXPECT_EQ(A2DP_GetMaxBitpoolSbc(codec_info_non_a2dp), -1);
@@ -714,6 +740,8 @@
// Explicit tests for known codecs
EXPECT_EQ(A2DP_SourceCodecIndex(codec_info_sbc),
BTAV_A2DP_CODEC_INDEX_SOURCE_SBC);
+ EXPECT_EQ(A2DP_SourceCodecIndex(codec_info_sbc_capability),
+ BTAV_A2DP_CODEC_INDEX_SOURCE_SBC);
EXPECT_EQ(A2DP_SourceCodecIndex(codec_info_sbc_sink_capability),
BTAV_A2DP_CODEC_INDEX_SOURCE_SBC);
EXPECT_EQ(A2DP_SourceCodecIndex(codec_info_aac),
@@ -754,8 +782,8 @@
EXPECT_TRUE(
A2DP_InitCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_SBC, &avdt_cfg));
// Compare the result codec with the local test codec info
- for (size_t i = 0; i < codec_info_sbc[0] + 1; i++) {
- EXPECT_EQ(avdt_cfg.codec_info[i], codec_info_sbc[i]);
+ for (size_t i = 0; i < codec_info_sbc_capability[0] + 1; i++) {
+ EXPECT_EQ(avdt_cfg.codec_info[i], codec_info_sbc_capability[i]);
}
// Test for content protection
#if (BTA_AV_CO_CP_SCMS_T == TRUE)
@@ -838,6 +866,7 @@
for (size_t i = 0; i < codec_info_sbc[0] + 1; i++) {
EXPECT_EQ(codec_info_result[i], codec_info_sbc[i]);
}
+ EXPECT_EQ(codec_config->getAudioBitsPerSample(), 16);
// Create the codec capability - AAC
memset(codec_info_result, 0, sizeof(codec_info_result));
@@ -854,6 +883,7 @@
for (size_t i = 0; i < codec_info_aac[0] + 1; i++) {
EXPECT_EQ(codec_info_result[i], codec_info_aac[i]);
}
+ EXPECT_EQ(codec_config->getAudioBitsPerSample(), 16);
// Create the codec config - SBC
memset(codec_info_result, 0, sizeof(codec_info_result));
diff --git a/stack/test/stack_btu_test.cc b/stack/test/stack_btu_test.cc
new file mode 100644
index 0000000..9d72509
--- /dev/null
+++ b/stack/test/stack_btu_test.cc
@@ -0,0 +1,129 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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 <base/bind.h>
+#include <base/logging.h>
+#include <base/threading/thread.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <semaphore.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "btcore/include/module.h"
+#include "osi/include/alarm.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/thread.h"
+#include "stack/include/btu.h"
+
+class TimeoutHelper {
+ public:
+ TimeoutHelper() { sem_init(&sem, 0, 0); }
+
+ ~TimeoutHelper() { sem_destroy(&sem); }
+
+ void wait(int seconds, base::Closure callback) {
+ struct timespec timeout;
+ clock_gettime(CLOCK_REALTIME, &timeout);
+ timeout.tv_sec += seconds;
+
+ int semvalue;
+ sem_getvalue(&sem, &semvalue);
+
+ // Call the callback if timeout occured
+ if (sem_timedwait(&sem, &timeout) == -1 && !callback.is_null()) {
+ callback.Run();
+ }
+ }
+
+ void notify() { sem_post(&sem); }
+
+ private:
+ sem_t sem;
+};
+
+TimeoutHelper helper;
+
+// External function definitions
+void btu_message_loop_run(void* context);
+void btu_task_start_up(void* context);
+void btu_task_shut_down(void* context);
+
+/* Below are methods and variables that must be implemented if we don't want to
+ * compile the whole stack. They will be removed, or changed into mocks one by
+ * one in the future, as the refactoring progresses */
+void btif_transfer_context(void (*)(unsigned short, char*), uint16_t, char*,
+ int, void (*)(unsigned short, char*, char*)) {
+ helper.notify();
+};
+
+void btu_init_core(){};
+void btif_init_ok(unsigned short, char*){};
+void BTE_InitStack(){};
+void bta_sys_init(){};
+void bta_sys_free(){};
+void btu_free_core(){};
+const module_t* get_module(const char*) { return nullptr; };
+bool module_init(module_t const*) { return true; };
+void module_clean_up(module_t const*){};
+
+thread_t* bt_workqueue_thread;
+fixed_queue_t* btu_general_alarm_queue;
+
+class BtuMessageLoopTest : public testing::Test {
+ public:
+ MOCK_METHOD0(TestCallback, void(void));
+ base::MessageLoop* message_loop;
+
+ virtual void SetUp() {
+ // Initialize alarms to prevent btu_task_shut_down from crashing
+ alarm_new("test alarm");
+ btu_general_alarm_queue = fixed_queue_new(SIZE_MAX);
+ bt_workqueue_thread = thread_new("test alarm thread");
+
+ // btu_task_start_up calls btif_transfer_context to let the stack know
+ // start up is finished
+ btu_task_start_up(nullptr);
+ helper.wait(5, base::Bind(&BtuMessageLoopTest::Fail, base::Unretained(this),
+ "BTU startup timed out"));
+ }
+
+ virtual void TearDown() {
+ btu_task_shut_down(nullptr);
+ alarm_cleanup();
+ }
+
+ void Fail(std::string message) { FAIL() << message; }
+};
+
+TEST_F(BtuMessageLoopTest, send_message) {
+ message_loop = get_message_loop();
+ EXPECT_FALSE(message_loop == nullptr);
+
+ EXPECT_CALL(*this, TestCallback()).Times(1);
+ message_loop->task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&BtuMessageLoopTest::TestCallback, base::Unretained(this)));
+
+ message_loop->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&TimeoutHelper::notify, base::Unretained(&helper)));
+
+ // Prevent the test from ending before the message loop posts the function
+ helper.wait(5, base::Bind(&BtuMessageLoopTest::Fail, base::Unretained(this),
+ "Timed out waiting for callback"));
+}
diff --git a/test/run_unit_tests.sh b/test/run_unit_tests.sh
index f8488d7..9df3d47 100755
--- a/test/run_unit_tests.sh
+++ b/test/run_unit_tests.sh
@@ -7,13 +7,16 @@
net_test_btcore
net_test_bta
net_test_btif
+ net_test_btif_profile_queue
net_test_device
net_test_hci
net_test_stack
net_test_stack_multi_adv
net_test_stack_ad_parser
net_test_stack_smp
+ net_test_btu_message_loop
net_test_osi
+ performance_test
)
known_remote_tests=(
diff --git a/test/suite/Android.bp b/test/suite/Android.bp
index a576901..e4d3a2b 100644
--- a/test/suite/Android.bp
+++ b/test/suite/Android.bp
@@ -2,6 +2,7 @@
// ========================================================
cc_test {
name: "net_test_bluetooth",
+ test_suites: ["device-tests"],
defaults: ["fluoride_defaults"],
include_dirs: ["system/bt"],
srcs: [
@@ -48,3 +49,21 @@
"libbluetoothtbd_hal",
],
}
+
+// Bluetooth test suite for target
+// ========================================================
+cc_test {
+ name: "performance_test",
+ defaults: ["fluoride_defaults"],
+ include_dirs: ["system/bt"],
+ srcs: [
+ "core/thread_performance_test.cc",
+ ],
+ shared_libs: [
+ "liblog",
+ ],
+ static_libs: [
+ "libgmock",
+ "libosi",
+ ],
+}
diff --git a/test/suite/AndroidTest.xml b/test/suite/AndroidTest.xml
new file mode 100644
index 0000000..eee642a
--- /dev/null
+++ b/test/suite/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ 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.
+-->
+<configuration description="Config for net_test_bluetooth">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="net_test_bluetooth->/data/local/tmp/net_test_bluetooth" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="stop" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="net_test_bluetooth" />
+ </test>
+</configuration>
diff --git a/test/suite/core/thread_performance_test.cc b/test/suite/core/thread_performance_test.cc
new file mode 100644
index 0000000..b3f7461
--- /dev/null
+++ b/test/suite/core/thread_performance_test.cc
@@ -0,0 +1,130 @@
+#include <base/bind.h>
+#include <base/logging.h>
+#include <base/run_loop.h>
+#include <base/threading/thread.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <unistd.h>
+#include <chrono>
+#include <iostream>
+
+#include "osi/include/fixed_queue.h"
+#include "osi/include/thread.h"
+
+#define NUM_MESSAGES_TO_SEND 1000000
+
+base::MessageLoop* message_loop;
+base::RunLoop* run_loop;
+thread_t* thread;
+
+volatile static int counter = 0;
+volatile bool loop_ready = false;
+
+void set_loop_ready() { loop_ready = true; }
+
+void callback(fixed_queue_t* queue, void* data) {
+ if (queue != nullptr) {
+ fixed_queue_dequeue(queue);
+ }
+
+ counter++;
+}
+
+void run_message_loop(void* UNUSED) {
+ message_loop = new base::MessageLoop();
+ run_loop = new base::RunLoop();
+
+ message_loop->task_runner()->PostTask(FROM_HERE, base::Bind(&set_loop_ready));
+
+ run_loop->Run();
+
+ delete message_loop;
+ message_loop = nullptr;
+
+ delete run_loop;
+ run_loop = nullptr;
+}
+
+class PerformanceTest : public testing::Test {
+ public:
+ fixed_queue_t* bt_msg_queue;
+
+ void SetUp() override {
+ counter = 0;
+
+ bt_msg_queue = fixed_queue_new(SIZE_MAX);
+ thread = thread_new("performance test thread");
+ thread_post(thread, run_message_loop, nullptr);
+ }
+
+ void TearDown() override {
+ fixed_queue_free(bt_msg_queue, NULL);
+ bt_msg_queue = nullptr;
+
+ thread_free(thread);
+ thread = nullptr;
+ }
+};
+
+TEST_F(PerformanceTest, message_loop_speed_test) {
+ loop_ready = false;
+ int test_data = 0;
+
+ std::chrono::steady_clock::time_point start_time =
+ std::chrono::steady_clock::now();
+ while (!loop_ready) {
+ }
+ for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
+ fixed_queue_enqueue(bt_msg_queue, (void*)&test_data);
+ message_loop->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&callback, bt_msg_queue, nullptr));
+ }
+
+ message_loop->task_runner()->PostTask(FROM_HERE,
+ run_loop->QuitWhenIdleClosure());
+ while (counter < NUM_MESSAGES_TO_SEND) {
+ }
+
+ std::chrono::steady_clock::time_point end_time =
+ std::chrono::steady_clock::now();
+ std::chrono::milliseconds duration =
+ std::chrono::duration_cast<std::chrono::milliseconds>(end_time -
+ start_time);
+
+ LOG(INFO) << "Message loop took " << duration.count() << "ms for "
+ << NUM_MESSAGES_TO_SEND << " messages";
+}
+
+TEST_F(PerformanceTest, reactor_thread_speed_test) {
+ counter = 0;
+ int test_data = 0;
+
+ thread = thread_new("queue performance test thread");
+ bt_msg_queue = fixed_queue_new(SIZE_MAX);
+ fixed_queue_register_dequeue(bt_msg_queue, thread_get_reactor(thread),
+ callback, NULL);
+
+ std::chrono::steady_clock::time_point start_time =
+ std::chrono::steady_clock::now();
+ for (int i = 0; i < NUM_MESSAGES_TO_SEND; i++) {
+ fixed_queue_enqueue(bt_msg_queue, (void*)&test_data);
+ }
+
+ while (counter < NUM_MESSAGES_TO_SEND) {
+ };
+
+ std::chrono::steady_clock::time_point end_time =
+ std::chrono::steady_clock::now();
+ std::chrono::milliseconds duration =
+ std::chrono::duration_cast<std::chrono::milliseconds>(end_time -
+ start_time);
+
+ LOG(INFO) << "Reactor thread took " << duration.count() << "ms for "
+ << NUM_MESSAGES_TO_SEND << " messages";
+
+ fixed_queue_free(bt_msg_queue, NULL);
+ bt_msg_queue = nullptr;
+
+ thread_free(thread);
+ thread = nullptr;
+}
diff --git a/tools/Android.bp b/tools/Android.bp
new file mode 100644
index 0000000..1357a93
--- /dev/null
+++ b/tools/Android.bp
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.
+ */
+subdirs = [
+ "mcap_tool",
+]
diff --git a/tools/mcap_tool/Android.bp b/tools/mcap_tool/Android.bp
new file mode 100644
index 0000000..aca07dd
--- /dev/null
+++ b/tools/mcap_tool/Android.bp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.
+ */
+cc_binary {
+ name: "mcap_tool",
+ defaults : ["fluoride_defaults"],
+ srcs: [
+ "mcap_test_app.cc",
+ "mcap_test_mcl.cc",
+ "mcap_test_mdep.cc",
+ "mcap_test_mdl.cc",
+ "mcap_tool.cc",
+ ],
+ include_dirs: [
+ "system/bt",
+ "system/bt/include",
+ "system/bt/stack/include",
+ "system/bt/btcore/include",
+ ],
+ tags: ["debug", "optional"],
+ shared_libs: [
+ "libcutils",
+ "libutils",
+ "libhardware",
+ ],
+ static_libs: [
+ "libbtcore",
+ "libosi",
+ ]
+}
diff --git a/tools/mcap_tool/BUILD.gn b/tools/mcap_tool/BUILD.gn
new file mode 100644
index 0000000..a5fef31
--- /dev/null
+++ b/tools/mcap_tool/BUILD.gn
@@ -0,0 +1,43 @@
+#
+# Copyright (C) 2017 Google, Inc.
+#
+# 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.
+#
+executable("mcap_tool") {
+ testonly = true
+ sources = [
+ "mcap_tool.cc",
+ "mcap_test_app.cc",
+ "mcap_test_mcl.cc",
+ "mcap_test_mdep.cc",
+ "mcap_test_mdl.cc",
+ ]
+ include_dirs = [
+ "//",
+ "//include",
+ "//stack/include",
+ "//btif/include",
+ "//btcore/include",
+ "//tools/mcap_tool",
+ ]
+ libs = [
+ "-lpthread",
+ "-lrt",
+ "-ldl",
+ ]
+ deps = [
+ "//btcore",
+ "//osi",
+ "//third_party/libchrome:base",
+ ]
+}
diff --git a/tools/mcap_tool/mcap_test_app.cc b/tools/mcap_tool/mcap_test_app.cc
new file mode 100644
index 0000000..29e50dc
--- /dev/null
+++ b/tools/mcap_tool/mcap_test_app.cc
@@ -0,0 +1,547 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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 "mcap_test_app.h"
+#include "mca_defs.h"
+
+namespace SYSTEM_BT_TOOLS_MCAP_TOOL {
+
+#define CASE_RETURN_STR(const) \
+ case const: \
+ return #const;
+
+static const char* dump_mcap_events(const uint8_t event) {
+ switch (event) {
+ CASE_RETURN_STR(MCA_ERROR_RSP_EVT)
+ CASE_RETURN_STR(MCA_CREATE_IND_EVT)
+ CASE_RETURN_STR(MCA_CREATE_CFM_EVT)
+ CASE_RETURN_STR(MCA_RECONNECT_IND_EVT)
+ CASE_RETURN_STR(MCA_RECONNECT_CFM_EVT)
+ CASE_RETURN_STR(MCA_ABORT_IND_EVT)
+ CASE_RETURN_STR(MCA_ABORT_CFM_EVT)
+ CASE_RETURN_STR(MCA_DELETE_IND_EVT)
+ CASE_RETURN_STR(MCA_DELETE_CFM_EVT)
+ CASE_RETURN_STR(MCA_SYNC_CAP_IND_EVT)
+ CASE_RETURN_STR(MCA_SYNC_CAP_CFM_EVT)
+ CASE_RETURN_STR(MCA_SYNC_SET_IND_EVT)
+ CASE_RETURN_STR(MCA_SYNC_SET_CFM_EVT)
+ CASE_RETURN_STR(MCA_SYNC_INFO_IND_EVT)
+ CASE_RETURN_STR(MCA_CONNECT_IND_EVT)
+ CASE_RETURN_STR(MCA_DISCONNECT_IND_EVT)
+ CASE_RETURN_STR(MCA_OPEN_IND_EVT)
+ CASE_RETURN_STR(MCA_OPEN_CFM_EVT)
+ CASE_RETURN_STR(MCA_CLOSE_IND_EVT)
+ CASE_RETURN_STR(MCA_CLOSE_CFM_EVT)
+ CASE_RETURN_STR(MCA_CONG_CHG_EVT)
+ CASE_RETURN_STR(MCA_RSP_TOUT_IND_EVT)
+ default:
+ return "Unknown event";
+ }
+}
+
+static void print_mcap_event(const tMCA_DISCONNECT_IND* mcap_disconnect_ind) {
+ bdstr_t bd_addr_str;
+ printf("%s: peer_bd_addr=%s,l2cap_disconnect_reason=0x%04x\n", __func__,
+ bdaddr_to_string((bt_bdaddr_t*)mcap_disconnect_ind->bd_addr,
+ bd_addr_str, sizeof(bd_addr_str)),
+ mcap_disconnect_ind->reason);
+}
+
+static void print_mcap_event(const tMCA_CONNECT_IND* mcap_connect_ind) {
+ bdstr_t bd_addr_str;
+ printf("%s: peer_bd_addr=%s, peer_mtu=%d \n", __func__,
+ bdaddr_to_string((bt_bdaddr_t*)mcap_connect_ind->bd_addr, bd_addr_str,
+ sizeof(bd_addr_str)),
+ mcap_connect_ind->mtu);
+}
+
+static void print_mcap_event(const tMCA_RSP_EVT* mcap_rsp) {
+ printf("%s: response, mdl_id=%d, op_code=0x%02x, rsp_code=0x%02x\n", __func__,
+ mcap_rsp->mdl_id, mcap_rsp->op_code, mcap_rsp->rsp_code);
+}
+
+static void print_mcap_event(const tMCA_EVT_HDR* mcap_evt_hdr) {
+ printf("%s: event, mdl_id=%d, op_code=0x%02x\n", __func__,
+ mcap_evt_hdr->mdl_id, mcap_evt_hdr->op_code);
+}
+
+static void print_mcap_event(const tMCA_CREATE_IND* mcap_create_ind) {
+ printf("%s: mdl_id=%d, op_code=0x%02x, dep_id=%d, cfg=0x%02x\n", __func__,
+ mcap_create_ind->mdl_id, mcap_create_ind->op_code,
+ mcap_create_ind->dep_id, mcap_create_ind->cfg);
+}
+
+static void print_mcap_event(const tMCA_CREATE_CFM* mcap_create_cfm) {
+ printf("%s: mdl_id=%d, op_code=0x%02x, rsp_code=%d, cfg=0x%02x\n", __func__,
+ mcap_create_cfm->mdl_id, mcap_create_cfm->op_code,
+ mcap_create_cfm->rsp_code, mcap_create_cfm->cfg);
+}
+
+static void print_mcap_event(const tMCA_DL_OPEN* mcap_dl_open) {
+ printf("%s: mdl_id=%d, mdl_handle=%d, mtu=%d\n", __func__,
+ mcap_dl_open->mdl_id, mcap_dl_open->mdl, mcap_dl_open->mtu);
+}
+
+static void print_mcap_event(const tMCA_DL_CLOSE* mcap_dl_close) {
+ printf("%s: mdl_id=%d, mdl_handle=%d, l2cap_disconnect_reason=0x%04x\n",
+ __func__, mcap_dl_close->mdl_id, mcap_dl_close->mdl,
+ mcap_dl_close->reason);
+}
+
+static void print_mcap_event(const tMCA_CONG_CHG* mcap_congestion_change) {
+ printf("%s: mdl_id=%d, mdl_handle=%d, congested=%d\n", __func__,
+ mcap_congestion_change->mdl_id, mcap_congestion_change->mdl,
+ mcap_congestion_change->cong);
+}
+
+McapTestApp::McapTestApp(btmcap_test_interface_t* mcap_test_interface)
+ : _mcl_list(), _mdep_list() {
+ _mcap_test_interface = mcap_test_interface;
+}
+
+btmcap_test_interface_t* McapTestApp::GetInterface() {
+ return _mcap_test_interface;
+}
+
+bool McapTestApp::Register(uint16_t ctrl_psm, uint16_t data_psm,
+ uint16_t sec_mask, tMCA_CTRL_CBACK* callback) {
+ if (!callback) {
+ LOG(ERROR) << "callback is null";
+ return false;
+ }
+ _mca_reg.rsp_tout = 5000;
+ _mca_reg.ctrl_psm = ctrl_psm;
+ _mca_reg.data_psm = data_psm;
+ _mca_reg.sec_mask = sec_mask;
+ _mcap_handle =
+ _mcap_test_interface->register_application(&_mca_reg, callback);
+ return _mcap_handle > 0;
+}
+
+void McapTestApp::Deregister() {
+ _mcap_test_interface->deregister_application(_mcap_handle);
+ _mcap_handle = 0;
+}
+
+bool McapTestApp::Registered() { return _mcap_handle > 0; }
+
+bool McapTestApp::ConnectMcl(const bt_bdaddr_t& bd_addr, uint16_t ctrl_psm,
+ uint16_t sec_mask) {
+ if (!Registered()) {
+ LOG(ERROR) << "Application not registered";
+ return false;
+ }
+ McapMcl* mcap_mcl = FindMclByPeerAddress(bd_addr);
+ if (!mcap_mcl) {
+ LOG(INFO) << "MCL does not exist, creating new MCL";
+ _mcl_list.push_back(McapMcl(_mcap_test_interface, _mcap_handle, bd_addr));
+ mcap_mcl = &_mcl_list[_mcl_list.size() - 1];
+ }
+ if (mcap_mcl->GetHandle() != 0) {
+ LOG(ERROR) << "MCL is still active, cannot make another connection";
+ return false;
+ }
+ return mcap_mcl->Connect(ctrl_psm, sec_mask);
+}
+
+bool McapTestApp::CreateMdep(uint8_t type, uint8_t max_mdl,
+ tMCA_DATA_CBACK* data_callback) {
+ if (!data_callback) {
+ LOG(ERROR) << "Data callback is null";
+ return false;
+ }
+ _mdep_list.push_back(McapMdep(_mcap_test_interface, _mcap_handle, type,
+ max_mdl, data_callback));
+ return _mdep_list[_mdep_list.size() - 1].Create();
+}
+
+uint8_t McapTestApp::GetHandle() { return _mcap_handle; }
+
+McapMcl* McapTestApp::FindMclByPeerAddress(const bt_bdaddr_t& bd_addr) {
+ for (McapMcl& mcl : _mcl_list) {
+ if (bdaddr_equals(&mcl.GetPeerAddress(), &bd_addr)) {
+ return &mcl;
+ }
+ }
+ return nullptr;
+}
+
+McapMcl* McapTestApp::FindMclByHandle(tMCA_CL mcl_handle) {
+ for (McapMcl& mcl : _mcl_list) {
+ if (mcl.GetHandle() == mcl_handle) {
+ return &mcl;
+ }
+ }
+ return nullptr;
+}
+
+McapMdep* McapTestApp::FindMdepByHandle(tMCA_DEP mdep_handle) {
+ for (McapMdep& mdep : _mdep_list) {
+ if (mdep.GetHandle() == mdep_handle) {
+ return &mdep;
+ }
+ }
+ return nullptr;
+}
+
+void McapTestApp::RemoveMclByHandle(tMCA_CL mcl_handle) {
+ LOG(INFO) << "Removing MCL handle " << (int)mcl_handle;
+ for (std::vector<McapMcl>::iterator it = _mcl_list.begin();
+ it != _mcl_list.end(); ++it) {
+ if (it->GetHandle() == mcl_handle) {
+ _mcl_list.erase(it);
+ LOG(INFO) << "Removed MCL handle " << (int)mcl_handle;
+ return;
+ }
+ }
+}
+
+bool McapTestApp::IsRegistered() { return _mcap_handle > 0; }
+
+void McapTestApp::ControlCallback(tMCA_HANDLE handle, tMCA_CL mcl,
+ uint8_t event, tMCA_CTRL* p_data) {
+ McapMcl* mcap_mcl = FindMclByHandle(mcl);
+ McapMdl* mcap_mdl = nullptr;
+ printf("%s: mcap_handle=%d, mcl_handle=%d, event=%s (0x%02x)\n", __func__,
+ handle, mcl, dump_mcap_events(event), event);
+ if (_mcap_handle != handle) {
+ LOG(ERROR) << "MCAP handle mismatch, self=" << _mcap_handle
+ << ", other=" << handle;
+ return;
+ }
+ switch (event) {
+ case MCA_ERROR_RSP_EVT:
+ print_mcap_event(&p_data->rsp);
+ break;
+
+ case MCA_CREATE_CFM_EVT:
+ // Called when MCA_CreateMdl succeeded step 1 when response is received
+ print_mcap_event(&p_data->create_cfm);
+ if (!mcap_mcl) {
+ LOG(ERROR) << "No MCL for mcl_handle " << (int)mcl;
+ break;
+ }
+ if (!mcap_mcl->IsConnected()) {
+ LOG(ERROR) << "MCL " << (int)mcl << " not connected";
+ break;
+ }
+ mcap_mdl = mcap_mcl->FindMdlById(p_data->create_cfm.mdl_id);
+ if (!mcap_mdl) {
+ LOG(ERROR) << "MDL not found for id " << p_data->create_cfm.mdl_id;
+ break;
+ }
+ if (mcap_mdl->GetResponseCode() >= 0) {
+ LOG(ERROR) << "MDL already got response " << mcap_mdl->GetResponseCode()
+ << " for id " << p_data->create_cfm.mdl_id;
+ break;
+ }
+ mcap_mdl->SetResponseCode(p_data->create_cfm.rsp_code);
+ break;
+
+ case MCA_CREATE_IND_EVT: {
+ // Should be replied with MCA_CreateMdlRsp
+ print_mcap_event(&p_data->create_ind);
+ if (!mcap_mcl) {
+ LOG(ERROR) << "No MCL for mcl_handle " << (int)mcl;
+ break;
+ }
+ if (!mcap_mcl->IsConnected()) {
+ LOG(ERROR) << "MCL " << (int)mcl << " not connected";
+ break;
+ }
+ McapMdep* mcap_mdep = FindMdepByHandle(p_data->create_ind.dep_id);
+ if (!mcap_mdep) {
+ LOG(ERROR) << "MDEP ID " << (int)p_data->create_ind.dep_id
+ << " does not exist";
+ _mcap_test_interface->create_mdl_response(
+ mcl, p_data->create_ind.dep_id, p_data->create_ind.mdl_id, 0,
+ MCA_RSP_BAD_MDEP, get_test_channel_config());
+ break;
+ }
+ bool ret = mcap_mcl->CreateMdlResponse(
+ mcap_mdep->GetHandle(), p_data->create_ind.mdl_id,
+ p_data->create_ind.dep_id, p_data->create_ind.cfg);
+ LOG(INFO) << (ret ? "SUCCESS" : "FAIL");
+ if (!ret) {
+ _mcap_test_interface->create_mdl_response(
+ mcl, p_data->create_ind.dep_id, p_data->create_ind.mdl_id, 0,
+ MCA_RSP_NO_RESOURCE, get_test_channel_config());
+ }
+ break;
+ }
+ case MCA_RECONNECT_IND_EVT: {
+ // Called when remote device asks to reconnect
+ // reply with MCA_ReconnectMdlRsp
+ print_mcap_event(&p_data->reconnect_ind);
+ if (!mcap_mcl) {
+ LOG(ERROR) << "No MCL for mcl_handle " << (int)mcl;
+ break;
+ }
+ if (!mcap_mcl->IsConnected()) {
+ LOG(ERROR) << "MCL " << (int)mcl << " not connected";
+ break;
+ }
+ mcap_mdl = mcap_mcl->FindMdlById(p_data->reconnect_ind.mdl_id);
+ if (mcap_mdl && !mcap_mdl->IsConnected()) {
+ LOG(INFO) << "Creating reconnect response for MDL "
+ << (int)p_data->reconnect_ind.mdl_id;
+ mcap_mdl->ReconnectResponse();
+ break;
+ }
+ LOG_IF(WARNING, mcap_mdl && mcap_mdl->IsConnected())
+ << "MDL ID " << (int)p_data->reconnect_ind.mdl_id
+ << " is already connected";
+ LOG_IF(WARNING, !mcap_mdl) << "No MDL for mdl_id "
+ << p_data->reconnect_ind.mdl_id;
+ tMCA_DEP mdep_handle = 0;
+ if (_mdep_list.size() > 0) {
+ mdep_handle = _mdep_list[0].GetHandle();
+ } else {
+ LOG(ERROR) << "Cannot find any available MDEP";
+ }
+ tMCA_RESULT ret = _mcap_test_interface->reconnect_mdl_response(
+ mcl, mdep_handle, p_data->reconnect_ind.mdl_id, MCA_RSP_BAD_MDL,
+ get_test_channel_config());
+ LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << ret;
+ break;
+ }
+ case MCA_RECONNECT_CFM_EVT:
+ // Called when MCA_ReconnectMdl step 1, receives a response
+ print_mcap_event(&p_data->reconnect_cfm);
+ if (!mcap_mcl) {
+ LOG(ERROR) << "No MCL for mcl_handle " << (int)mcl;
+ break;
+ }
+ if (!mcap_mcl->IsConnected()) {
+ LOG(ERROR) << "MCL not connected for mcl_handle " << (int)mcl;
+ break;
+ }
+ mcap_mdl = mcap_mcl->FindMdlById(p_data->reconnect_cfm.mdl_id);
+ if (!mcap_mdl) {
+ LOG(ERROR) << "MDL not found for id " << p_data->reconnect_cfm.mdl_id;
+ break;
+ }
+ if (mcap_mdl->GetResponseCode() >= 0) {
+ LOG(ERROR) << "MDL already got response " << mcap_mdl->GetResponseCode()
+ << " for id " << p_data->reconnect_cfm.mdl_id;
+ break;
+ }
+ mcap_mdl->SetResponseCode(p_data->reconnect_cfm.rsp_code);
+ break;
+
+ case MCA_ABORT_IND_EVT:
+ print_mcap_event(&p_data->abort_ind);
+ if (!mcap_mcl) {
+ LOG(ERROR) << "No MCL for mcl_handle " << (int)mcl;
+ break;
+ }
+ if (!mcap_mcl->IsConnected()) {
+ LOG(ERROR) << "MCL not connected for mcl_handle " << (int)mcl;
+ break;
+ }
+ mcap_mdl = mcap_mcl->FindMdlById(p_data->abort_ind.mdl_id);
+ if (!mcap_mdl) {
+ LOG(ERROR) << "MDL not found for id " << (int)p_data->abort_ind.mdl_id;
+ break;
+ }
+ if (mcap_mdl->IsConnected()) {
+ LOG(ERROR) << "MDL is already connected for id "
+ << (int)p_data->abort_ind.mdl_id;
+ }
+ mcap_mcl->RemoveMdl(p_data->abort_ind.mdl_id);
+ break;
+
+ case MCA_ABORT_CFM_EVT:
+ // Called when MCA_Abort succeeded
+ print_mcap_event(&p_data->abort_cfm);
+ if (!mcap_mcl) {
+ LOG(ERROR) << "No MCL for mcl_handle " << (int)mcl;
+ break;
+ }
+ if (!mcap_mcl->IsConnected()) {
+ LOG(ERROR) << "MCL " << (int)mcl << " not connected";
+ break;
+ }
+ mcap_mdl = mcap_mcl->FindMdlById(p_data->abort_cfm.mdl_id);
+ if (!mcap_mdl) {
+ LOG(ERROR) << "MDL not found for id " << (int)p_data->abort_cfm.mdl_id;
+ break;
+ }
+ if (mcap_mdl->IsConnected()) {
+ LOG(ERROR) << "MDL is already connected for id "
+ << (int)p_data->abort_cfm.mdl_id;
+ }
+ mcap_mcl->RemoveMdl(p_data->abort_cfm.mdl_id);
+ break;
+
+ case MCA_DELETE_IND_EVT:
+ print_mcap_event(&p_data->delete_ind);
+ if (!mcap_mcl) {
+ LOG(ERROR) << "No MCL for mcl_handle " << (int)mcl;
+ break;
+ }
+ if (!mcap_mcl->IsConnected()) {
+ LOG(ERROR) << "MCL " << (int)mcl << " not connected";
+ break;
+ }
+ if (p_data->delete_ind.mdl_id == MCA_ALL_MDL_ID) {
+ mcap_mcl->RemoveAllMdl();
+ } else {
+ mcap_mcl->RemoveMdl(p_data->delete_ind.mdl_id);
+ }
+ break;
+
+ case MCA_DELETE_CFM_EVT:
+ // Called when MCA_Delete succeeded
+ print_mcap_event(&p_data->delete_cfm);
+ if (!mcap_mcl) {
+ LOG(ERROR) << "No MCL for mcl_handle " << (int)mcl;
+ break;
+ }
+ if (!mcap_mcl->IsConnected()) {
+ LOG(ERROR) << "MCL " << (int)mcl << " not connected";
+ break;
+ }
+ if (p_data->delete_cfm.rsp_code) {
+ LOG(ERROR) << "No success response " << (int)p_data->delete_cfm.rsp_code
+ << " when deleting MDL_ID "
+ << (int)p_data->delete_cfm.mdl_id;
+ break;
+ }
+ if (p_data->delete_cfm.mdl_id == MCA_ALL_MDL_ID) {
+ mcap_mcl->RemoveAllMdl();
+ } else {
+ mcap_mcl->RemoveMdl(p_data->delete_cfm.mdl_id);
+ }
+ break;
+
+ case MCA_CONNECT_IND_EVT: {
+ // Called when MCA_ConnectReq succeeded
+ print_mcap_event(&p_data->connect_ind);
+ LOG(INFO) << "Received MCL handle " << (int)mcl;
+ bt_bdaddr_t bd_addr = *((bt_bdaddr_t*)p_data->connect_ind.bd_addr);
+ mcap_mcl = FindMclByPeerAddress(bd_addr);
+ if (!mcap_mcl) {
+ LOG(INFO) << "Creating new MCL for ID " << (int)mcl;
+ _mcl_list.push_back(
+ McapMcl(_mcap_test_interface, _mcap_handle, bd_addr));
+ mcap_mcl = &_mcl_list[_mcl_list.size() - 1];
+ }
+ if (mcap_mcl->IsConnected()) {
+ LOG(ERROR) << "MCL is already connected for handle " << (int)mcl;
+ break;
+ }
+ mcap_mcl->SetHandle(mcl);
+ mcap_mcl->SetMtu(p_data->connect_ind.mtu);
+ break;
+ }
+ case MCA_DISCONNECT_IND_EVT: {
+ // Called when MCA_ConnectReq failed or MCA_DisconnectReq succeeded
+ print_mcap_event(&p_data->disconnect_ind);
+ bt_bdaddr_t bd_addr = *((bt_bdaddr_t*)p_data->disconnect_ind.bd_addr);
+ mcap_mcl = FindMclByPeerAddress(bd_addr);
+ if (!mcap_mcl) {
+ bdstr_t bd_addr_str;
+ LOG(ERROR) << "No MCL for BD addr "
+ << bdaddr_to_string(&bd_addr, bd_addr_str,
+ sizeof(bd_addr_str));
+ break;
+ }
+ if (!mcap_mcl->IsConnected()) {
+ bdstr_t bd_addr_str;
+ LOG(WARNING) << "MCL for " << bdaddr_to_string(&bd_addr, bd_addr_str,
+ sizeof(bd_addr_str))
+ << " is already disconnected";
+ }
+ mcap_mcl->SetHandle(0);
+ mcap_mcl->SetMtu(0);
+ mcap_mcl->ResetAllMdl();
+ break;
+ }
+ case MCA_OPEN_IND_EVT:
+ // Called when MCA_CreateMdlRsp succeeded step 2, data channel is open
+ // Called when MCA_ReconnectMdlRsp succeeded step 2, data channel is open
+ case MCA_OPEN_CFM_EVT:
+ // Called when MCA_CreateMdl succeeded step 2, data channel is open
+ // Called when MCA_ReconnectMdl succeeded step 2, data channel is open
+ // Called when MCA_DataChnlCfg succeeded
+ print_mcap_event(&p_data->open_ind);
+ if (!mcap_mcl) {
+ LOG(ERROR) << "No MCL for mcl_handle " << (int)mcl;
+ break;
+ }
+ if (!mcap_mcl->IsConnected()) {
+ LOG(ERROR) << "MCL not connected for mcl_handle " << (int)mcl;
+ break;
+ }
+ mcap_mdl = mcap_mcl->FindMdlById(p_data->open_ind.mdl_id);
+ if (mcap_mdl) {
+ if (mcap_mdl->IsConnected()) {
+ LOG(ERROR) << "MDL is already connected for mcl_handle "
+ << (int)p_data->open_ind.mdl_id;
+ break;
+ }
+ mcap_mdl->SetMtu(p_data->open_ind.mtu);
+ mcap_mdl->SetHandle(p_data->open_ind.mdl);
+ } else {
+ LOG(ERROR) << "No MDL for mdl_id " << (int)p_data->reconnect_ind.mdl_id;
+ }
+ break;
+
+ case MCA_CLOSE_IND_EVT:
+ case MCA_CLOSE_CFM_EVT:
+ // Called when MCA_CloseReq is successful
+ print_mcap_event(&p_data->close_cfm);
+ if (!mcap_mcl) {
+ LOG(ERROR) << "No MCL for mcl_handle " << (int)mcl;
+ break;
+ }
+ if (!mcap_mcl->IsConnected()) {
+ LOG(ERROR) << "MCL not connected for mcl_handle " << (int)mcl;
+ break;
+ }
+ mcap_mdl = mcap_mcl->FindMdlById(p_data->close_cfm.mdl_id);
+ if (mcap_mdl) {
+ mcap_mdl->SetMtu(0);
+ mcap_mdl->SetHandle(0);
+ } else {
+ LOG(WARNING) << "No MDL for mdl_id " << (int)p_data->close_cfm.mdl_id;
+ }
+ break;
+
+ case MCA_CONG_CHG_EVT:
+ print_mcap_event(&p_data->cong_chg);
+ if (!mcap_mcl) {
+ LOG(ERROR) << "No MCL for mcl_handle " << (int)mcl;
+ break;
+ }
+ if (!mcap_mcl->IsConnected()) {
+ LOG(ERROR) << "MCL not connected for mcl_handle " << (int)mcl;
+ break;
+ }
+ break;
+
+ case MCA_RSP_TOUT_IND_EVT:
+ case MCA_SYNC_CAP_IND_EVT:
+ case MCA_SYNC_CAP_CFM_EVT:
+ case MCA_SYNC_SET_IND_EVT:
+ case MCA_SYNC_SET_CFM_EVT:
+ case MCA_SYNC_INFO_IND_EVT:
+ print_mcap_event(&p_data->hdr);
+ break;
+ }
+}
+
+} // namespace SYSTEM_BT_TOOLS_MCAP_TOOL
diff --git a/tools/mcap_tool/mcap_test_app.h b/tools/mcap_tool/mcap_test_app.h
new file mode 100644
index 0000000..23dfa37
--- /dev/null
+++ b/tools/mcap_tool/mcap_test_app.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.
+ */
+#pragma once
+
+#include <functional>
+#include <iterator>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <base/logging.h>
+
+#include "bdaddr.h"
+#include "mca_api.h"
+
+#include "mcap_test_mcl.h"
+#include "mcap_test_mdep.h"
+
+namespace SYSTEM_BT_TOOLS_MCAP_TOOL {
+
+extern const tMCA_CHNL_CFG MCAP_TEST_CHANNEL_CONFIG;
+
+class McapTestApp {
+ public:
+ /**
+ * McapTestApp is the root node for an MCAP application
+ *
+ * @param mcap_test_interface interface to MCAP APIs on Bluetooth stack
+ * from get_test_interface()
+ */
+ McapTestApp(btmcap_test_interface_t* mcap_test_interface);
+ btmcap_test_interface_t* GetInterface();
+ /**
+ * Register an application with the Bluetooth stack
+ * @param ctrl_psm Control channel L2CAP PSM
+ * @param data_psm Data channel L2CAP PSM
+ * @param sec_mask Security Mask
+ * @param callback Control channel callback
+ * @return
+ */
+ bool Register(uint16_t ctrl_psm, uint16_t data_psm, uint16_t sec_mask,
+ tMCA_CTRL_CBACK* callback);
+ /**
+ * De-register the current application
+ */
+ void Deregister();
+ /**
+ * Check if current application is registered
+ * @return True if registered
+ */
+ bool Registered();
+ /**
+ * Create MCAP Communication Link
+ * @param bd_addr Peer Bluetooth Address
+ * @param ctrl_psm Control channel L2CAP PSM, should be the same as registered
+ * value for most cases
+ * @param sec_mask Security mask
+ * @return True on success
+ */
+ bool ConnectMcl(const bt_bdaddr_t& bd_addr, uint16_t ctrl_psm,
+ uint16_t sec_mask);
+ /**
+ * Create MCAP Data End Point
+ * @param type 0 - MCA_TDEP_ECHO, 1 - MCA_TDEP_DATA
+ * @param max_mdl Maximum number of data channels for this end point
+ * @param data_callback Data callback
+ * @return True on success
+ */
+ bool CreateMdep(uint8_t type, uint8_t max_mdl,
+ tMCA_DATA_CBACK* data_callback);
+ // Simple methods that are self-explanatory
+ uint8_t GetHandle();
+ McapMcl* FindMclByPeerAddress(const bt_bdaddr_t& bd_addr);
+ McapMcl* FindMclByHandle(tMCA_CL mcl_handle);
+ McapMdep* FindMdepByHandle(tMCA_DEP mdep_handle);
+ void RemoveMclByHandle(tMCA_CL mcl_handle);
+ bool IsRegistered();
+ /**
+ * Callback function for control channel, need to be called by an external
+ * function registered during McapTestApp::Register()
+ * @param handle MCAP application handle, should be the same as GetHandle()
+ * @param mcl MCL handle, FindMclByHandle(mcl) should return non-null value
+ * @param event Control event
+ * @param p_data Control data
+ */
+ void ControlCallback(tMCA_HANDLE handle, tMCA_CL mcl, uint8_t event,
+ tMCA_CTRL* p_data);
+
+ private:
+ // Initialized during start up
+ tMCA_REG _mca_reg;
+ btmcap_test_interface_t* _mcap_test_interface = nullptr;
+ std::vector<McapMcl> _mcl_list;
+ std::vector<McapMdep> _mdep_list;
+
+ // Initialized later
+ tMCA_HANDLE _mcap_handle = 0;
+};
+
+} // namespace SYSTEM_BT_TOOLS_MCAP_TOOL
diff --git a/tools/mcap_tool/mcap_test_mcl.cc b/tools/mcap_tool/mcap_test_mcl.cc
new file mode 100644
index 0000000..8842c04
--- /dev/null
+++ b/tools/mcap_tool/mcap_test_mcl.cc
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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 <cstring>
+
+#include <base/logging.h>
+
+#include "bdaddr.h"
+#include "mca_api.h"
+#include "mca_defs.h"
+#include "mcap_test_mcl.h"
+
+namespace SYSTEM_BT_TOOLS_MCAP_TOOL {
+
+McapMcl::McapMcl(btmcap_test_interface_t* mcap_test_interface,
+ tMCA_HANDLE mcap_handle, const bt_bdaddr_t& peer_bd_addr)
+ : _mdl_list() {
+ _mcap_handle = mcap_handle;
+ _mcap_test_interface = mcap_test_interface;
+ memcpy(_peer_bd_addr.address, peer_bd_addr.address,
+ sizeof(_peer_bd_addr.address));
+}
+
+bool McapMcl::Connect(uint16_t ctrl_psm, uint16_t sec_mask) {
+ tMCA_RESULT ret = _mcap_test_interface->connect_mcl(
+ _mcap_handle, _peer_bd_addr.address, ctrl_psm, sec_mask);
+ LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
+ return ret == MCA_SUCCESS;
+}
+
+bool McapMcl::Disconnect() {
+ if (!IsConnected()) {
+ LOG(ERROR) << "MCL is not connected";
+ return false;
+ }
+ tMCA_RESULT ret = _mcap_test_interface->disconnect_mcl(_mcl_handle);
+ LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
+ return ret == MCA_SUCCESS;
+}
+
+McapMdl* McapMcl::AllocateMdl(tMCA_DEP mdep_handle, uint16_t mdl_id,
+ uint8_t dep_id, uint8_t cfg) {
+ if (!IsConnected()) {
+ LOG(ERROR) << "MCL is not connected";
+ return nullptr;
+ }
+ if (FindMdlById(mdl_id) != nullptr) {
+ LOG(ERROR) << "mdl_id=" << mdl_id << "already exists";
+ return nullptr;
+ }
+ if (!HasAvailableMdl()) {
+ LOG(ERROR) << "No more avaible MDL, currently " << _mdl_list.size();
+ return nullptr;
+ }
+ _mdl_list.push_back(McapMdl(_mcap_test_interface, _mcl_handle, mdep_handle,
+ mdl_id, dep_id, cfg));
+ return &_mdl_list[_mdl_list.size() - 1];
+}
+
+bool McapMcl::CreateMdl(tMCA_DEP mdep_handle, uint16_t data_psm,
+ uint16_t mdl_id, uint8_t peer_dep_id, uint8_t cfg,
+ bool should_connect) {
+ if (!IsConnected()) {
+ LOG(ERROR) << "MCL is not connected";
+ return false;
+ }
+ McapMdl* mcap_mdl = FindMdlById(mdl_id);
+ if (!mcap_mdl) {
+ LOG(INFO) << "mdl_id=" << mdl_id << "does not exists, creating new one";
+ mcap_mdl = AllocateMdl(mdep_handle, mdl_id, peer_dep_id, cfg);
+ if (!mcap_mdl) {
+ return false;
+ }
+ }
+ if (mcap_mdl->IsConnected()) {
+ LOG(ERROR) << "mdl_id=" << mdl_id << "is already connected with handle "
+ << (int)mcap_mdl->GetHandle();
+ return false;
+ }
+ return mcap_mdl->Create(data_psm, should_connect);
+}
+
+bool McapMcl::DataChannelConfig() {
+ tMCA_RESULT ret = _mcap_test_interface->data_channel_config(
+ _mcl_handle, get_test_channel_config());
+ LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
+ return ret == MCA_SUCCESS;
+}
+
+bool McapMcl::CreateMdlResponse(tMCA_DEP mdep_handle, uint16_t mdl_id,
+ uint8_t my_dep_id, uint8_t cfg) {
+ if (!IsConnected()) {
+ LOG(ERROR) << "MCL is not connected";
+ return false;
+ }
+ McapMdl* mcap_mdl = FindMdlById(mdl_id);
+ if (!mcap_mdl) {
+ LOG(INFO) << "mdl_id=" << mdl_id << " does not exists, creating new one";
+ mcap_mdl = AllocateMdl(mdep_handle, mdl_id, my_dep_id, cfg);
+ if (!mcap_mdl) {
+ LOG(ERROR) << "MDL cannot be created";
+ return false;
+ }
+ }
+ if (mcap_mdl->IsConnected()) {
+ LOG(INFO) << "mdl_id=" << mdl_id << " is already connected with handle "
+ << (int)mcap_mdl->GetHandle() << ", updating context";
+ mcap_mdl->UpdateContext(mdep_handle, my_dep_id, cfg);
+ }
+ return mcap_mdl->CreateResponse();
+}
+
+bool McapMcl::AbortMdl() {
+ tMCA_RESULT ret = _mcap_test_interface->abort_mdl(_mcl_handle);
+ LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
+ return ret == MCA_SUCCESS;
+}
+
+bool McapMcl::DeleteMdl(uint16_t mdl_id) {
+ tMCA_RESULT ret = _mcap_test_interface->delete_mdl(_mcl_handle, mdl_id);
+ LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
+ return ret == MCA_SUCCESS;
+}
+
+bt_bdaddr_t& McapMcl::GetPeerAddress() { return _peer_bd_addr; }
+
+void McapMcl::SetHandle(tMCA_CL handle) { _mcl_handle = handle; }
+
+tMCA_CL McapMcl::GetHandle() const { return _mcl_handle; }
+
+void McapMcl::SetMtu(uint16_t mtu) { _control_mtu = mtu; }
+
+uint16_t McapMcl::GetMtu() { return _control_mtu; }
+
+McapMdl* McapMcl::FindMdlById(uint16_t mdl_id) {
+ for (McapMdl& mdl : _mdl_list) {
+ if (mdl.GetId() == mdl_id) {
+ return &mdl;
+ }
+ }
+ return nullptr;
+}
+
+McapMdl* McapMcl::FindMdlByHandle(tMCA_DL mdl_handle) {
+ for (McapMdl& mdl : _mdl_list) {
+ if (mdl.GetHandle() == mdl_handle) {
+ return &mdl;
+ }
+ }
+ return nullptr;
+}
+
+void McapMcl::RemoveAllMdl() { _mdl_list.clear(); }
+
+void McapMcl::RemoveMdl(uint16_t mdl_id) {
+ LOG(INFO) << "Removing MDL id " << (int)mdl_id;
+ for (std::vector<McapMdl>::iterator it = _mdl_list.begin();
+ it != _mdl_list.end(); ++it) {
+ if (it->GetId() == mdl_id) {
+ _mdl_list.erase(it);
+ LOG(INFO) << "Removed MDL id " << (int)mdl_id;
+ return;
+ }
+ }
+}
+
+void McapMcl::ResetAllMdl() {
+ for (McapMdl& mcap_mdl : _mdl_list) {
+ mcap_mdl.SetHandle(0);
+ mcap_mdl.SetMtu(0);
+ mcap_mdl.SetResponseCode(-1);
+ }
+}
+
+void McapMcl::ResetMdl(uint16_t mdl_id) {
+ LOG(INFO) << "Closing MDL id " << (int)mdl_id;
+ McapMdl* mcap_mdl = FindMdlById(mdl_id);
+ if (!mcap_mdl) {
+ LOG(ERROR) << "Cannot find MDL for id " << (int)mdl_id;
+ return;
+ }
+ if (mcap_mdl->IsConnected()) {
+ LOG(ERROR) << "MDL " << (int)mdl_id << " is still connected";
+ return;
+ }
+ mcap_mdl->SetHandle(0);
+ mcap_mdl->SetMtu(0);
+ mcap_mdl->SetResponseCode(-1);
+}
+
+bool McapMcl::IsConnected() { return _mcl_handle > 0; }
+
+int McapMcl::ConnectedMdlCount() {
+ int count = 0;
+ for (McapMdl& mcap_mdl : _mdl_list) {
+ if (mcap_mdl.IsConnected()) {
+ count++;
+ }
+ }
+ return count;
+}
+
+bool McapMcl::HasAvailableMdl() { return ConnectedMdlCount() < MCA_NUM_MDLS; }
+
+} // namespace SYSTEM_BT_TOOLS_MCAP_TOOL
diff --git a/tools/mcap_tool/mcap_test_mcl.h b/tools/mcap_tool/mcap_test_mcl.h
new file mode 100644
index 0000000..2d71ee6
--- /dev/null
+++ b/tools/mcap_tool/mcap_test_mcl.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.
+ */
+#pragma once
+
+#include <vector>
+
+#include "bdaddr.h"
+#include "mca_api.h"
+#include "mcap_test_mdl.h"
+
+namespace SYSTEM_BT_TOOLS_MCAP_TOOL {
+
+class McapMcl {
+ public:
+ /**
+ * A controller for a MCAP Communication Link (MCL)
+ * @param mcap_test_interface Underlining interface to Bluetooth stack
+ * @param mcap_handle Parent application handle
+ * @param peer_bd_addr Peer Bluetooth MAC address
+ */
+ McapMcl(btmcap_test_interface_t* mcap_test_interface, tMCA_HANDLE mcap_handle,
+ const bt_bdaddr_t& peer_bd_addr);
+ /**
+ * Connect this MCL's control channel
+ * @param ctrl_psm Control channel L2CAP PSM
+ * @param sec_mask Security mask
+ * @return True on success
+ */
+ bool Connect(uint16_t ctrl_psm, uint16_t sec_mask);
+ /**
+ * Disconnect from control channel
+ * @return
+ */
+ bool Disconnect();
+ /**
+ * Close this MCL connection
+ * @return
+ */
+ bool Close();
+ /**
+ * Allocate an MCAP Data Link (MDL) object and save to this MCL object
+ * @param mdep_handle MDEP handle for data, MDEP must be prior created
+ * @param mdl_id Desired MDL ID, user supported
+ * @param dep_id Peer MDEP ID
+ * @param cfg Configuration flags
+ * @return True on success
+ */
+ McapMdl* AllocateMdl(tMCA_DEP mdep_handle, uint16_t mdl_id, uint8_t dep_id,
+ uint8_t cfg);
+ /**
+ * Send CREATE_MDL message to peer device, will allocate an MDL if the MDL for
+ * corresponding MDL ID was not allocated before
+ * @param mdep_handle MDEP handle for data, MDEP must be prior created
+ * @param data_psm Data channel L2CAP PSM
+ * @param mdl_id Desired MDL ID, user supported
+ * @param peer_dep_id Peer MDEP ID
+ * @param cfg Configuration flags
+ * @param should_connect whether we should connect L2CAP immediately
+ * @return True on success
+ */
+ bool CreateMdl(tMCA_DEP mdep_handle, uint16_t data_psm, uint16_t mdl_id,
+ uint8_t peer_dep_id, uint8_t cfg, bool should_connect);
+ /**
+ * Configure data channel, unblock any pending MDL L2CAP connection requests
+ * @return True on Success
+ */
+ bool DataChannelConfig();
+ /**
+ * Respond to CREATE_MDL message received from peer device, will allocate an
+ * MDL if the MDL for corresponding MDL ID was not allocated before
+ * @param mdep_handle MDEP handle for data, MDEP must be prior created
+ * @param mdl_id Desired MDL ID, peer supported
+ * @param my_dep_id My MDEP ID
+ * @param cfg Configuration flags
+ * @return True on success
+ */
+ bool CreateMdlResponse(tMCA_DEP mdep_handle, uint16_t mdl_id,
+ uint8_t my_dep_id, uint8_t cfg);
+ /**
+ * Send ABORT_MDL request, aborting all pending CREATE_MDL requests
+ * @return
+ */
+ bool AbortMdl();
+ /**
+ * Send DELETE_MDL request to remote
+ * @param mdl_id None zero value mdl_id, 0xFFFF for all remote MDLs
+ * @return True on success
+ */
+ bool DeleteMdl(uint16_t mdl_id);
+ // Simple methods that are self-explanatory
+ bt_bdaddr_t& GetPeerAddress();
+ void SetHandle(tMCA_CL handle);
+ tMCA_CL GetHandle() const;
+ void SetMtu(uint16_t mtu);
+ uint16_t GetMtu();
+ McapMdl* FindMdlById(uint16_t mdl_id);
+ McapMdl* FindMdlByHandle(tMCA_DL mdl_handle);
+ void RemoveAllMdl();
+ void RemoveMdl(uint16_t mdl_id);
+ void ResetAllMdl();
+ void ResetMdl(uint16_t mdl_id);
+ bool IsConnected();
+ int ConnectedMdlCount();
+ bool HasAvailableMdl();
+
+ private:
+ // Initialized during start up
+ btmcap_test_interface_t* _mcap_test_interface;
+ tMCA_HANDLE _mcap_handle;
+ bt_bdaddr_t _peer_bd_addr;
+ std::vector<McapMdl> _mdl_list;
+
+ // Initialized later
+ tMCA_CL _mcl_handle = 0;
+ uint16_t _control_mtu = 0;
+};
+
+} // namespace SYSTEM_BT_TOOLS_MCAP_TOOL
diff --git a/tools/mcap_tool/mcap_test_mdep.cc b/tools/mcap_tool/mcap_test_mdep.cc
new file mode 100644
index 0000000..1fb6412
--- /dev/null
+++ b/tools/mcap_tool/mcap_test_mdep.cc
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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 <base/logging.h>
+
+#include "mcap_test_mdep.h"
+
+namespace SYSTEM_BT_TOOLS_MCAP_TOOL {
+
+McapMdep::McapMdep(btmcap_test_interface_t* mcap_test_interface,
+ tMCA_HANDLE mcap_handle, uint8_t type, uint8_t max_mdl,
+ tMCA_DATA_CBACK* data_callback) {
+ _mcap_test_interface = mcap_test_interface;
+ _mcap_handle = mcap_handle;
+ _mca_cs.type = (0 == type) ? MCA_TDEP_ECHO : MCA_TDEP_DATA;
+ _mca_cs.max_mdl = max_mdl;
+ _mca_cs.p_data_cback = data_callback;
+}
+
+bool McapMdep::Create() {
+ tMCA_RESULT ret =
+ _mcap_test_interface->create_mdep(_mcap_handle, &_mdep_handle, &_mca_cs);
+ LOG(INFO) << "mdep_handle=" << (int)_mdep_handle;
+ LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
+ return ret == MCA_SUCCESS;
+}
+
+bool McapMdep::Delete() {
+ tMCA_RESULT ret =
+ _mcap_test_interface->create_mdep(_mcap_handle, &_mdep_handle, &_mca_cs);
+ LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
+ return ret == MCA_SUCCESS;
+}
+
+tMCA_DEP McapMdep::GetHandle() const { return _mdep_handle; }
+
+bool McapMdep::IsRegistered() { return _mdep_handle > 0; }
+
+} // namespace SYSTEM_BT_TOOLS_MCAP_TOOL
diff --git a/tools/mcap_tool/mcap_test_mdep.h b/tools/mcap_tool/mcap_test_mdep.h
new file mode 100644
index 0000000..a852d52
--- /dev/null
+++ b/tools/mcap_tool/mcap_test_mdep.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.
+ */
+#pragma once
+
+#include "mca_api.h"
+
+namespace SYSTEM_BT_TOOLS_MCAP_TOOL {
+
+class McapMdep {
+ public:
+ /**
+ * A control abstraction for a MCAP Data End Point (MDEP)
+ * @param mcap_test_interface Underlining MCAP interface to Bluetooth stack
+ * @param mcap_handle Parent MCAP application handle
+ * @param type 0 for Echo, 1 for Normal, nothing else
+ * @param max_mdl Maximum number of MDL's allowed
+ * @param data_callback Data channel callback function
+ */
+ McapMdep(btmcap_test_interface_t* mcap_test_interface,
+ tMCA_HANDLE mcap_handle, uint8_t type, uint8_t max_mdl,
+ tMCA_DATA_CBACK* data_callback);
+ /**
+ * Actually create the MDEP in the stack
+ * @return True if success
+ */
+ bool Create();
+ /**
+ * Destroy the MDEP in the stack
+ * @return True if success
+ */
+ bool Delete();
+ // Simple methods that are self-explanatory
+ tMCA_DEP GetHandle() const;
+ bool IsRegistered();
+
+ private:
+ // Initialized during start up
+ btmcap_test_interface_t* _mcap_test_interface;
+ tMCA_HANDLE _mcap_handle;
+ tMCA_CS _mca_cs;
+
+ // Initialized later
+ tMCA_DEP _mdep_handle = 0;
+};
+
+} // namespace SYSTEM_BT_TOOLS_MCAP_TOOL
diff --git a/tools/mcap_tool/mcap_test_mdl.cc b/tools/mcap_tool/mcap_test_mdl.cc
new file mode 100644
index 0000000..e7b8083
--- /dev/null
+++ b/tools/mcap_tool/mcap_test_mdl.cc
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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 <base/logging.h>
+
+#include "mca_defs.h"
+#include "mcap_test_mdl.h"
+
+namespace SYSTEM_BT_TOOLS_MCAP_TOOL {
+
+/* Test MCAP Channel Configurations */
+const tMCA_CHNL_CFG MCAP_TEST_CHANNEL_CONFIG = {
+ .fcr_opt =
+ {
+ L2CAP_FCR_ERTM_MODE,
+ MCA_FCR_OPT_TX_WINDOW_SIZE, /* Tx window size */
+ /* Maximum transmissions before disconnecting */
+ MCA_FCR_OPT_MAX_TX_B4_DISCNT,
+ MCA_FCR_OPT_RETX_TOUT, /* retransmission timeout (2 secs) */
+ MCA_FCR_OPT_MONITOR_TOUT, /* Monitor timeout (12 secs) */
+ MCA_FCR_OPT_MPS_SIZE, /* MPS segment size */
+ },
+ .user_rx_buf_size = BT_DEFAULT_BUFFER_SIZE,
+ .user_tx_buf_size = BT_DEFAULT_BUFFER_SIZE,
+ .fcr_rx_buf_size = BT_DEFAULT_BUFFER_SIZE,
+ .fcr_tx_buf_size = BT_DEFAULT_BUFFER_SIZE,
+ .fcs = MCA_FCS_NONE,
+ .data_mtu = 572 /* L2CAP MTU of the MCAP data channel */
+};
+
+const tMCA_CHNL_CFG* get_test_channel_config() {
+ return &MCAP_TEST_CHANNEL_CONFIG;
+}
+
+McapMdl::McapMdl(btmcap_test_interface_t* mcap_test_interface,
+ tMCA_CL mcl_handle, tMCA_DEP mdep_handle, uint16_t mdl_id,
+ uint8_t dep_id, uint8_t cfg) {
+ _mcap_test_interface = mcap_test_interface;
+ _mcl_handle = mcl_handle;
+ _mdep_handle = mdep_handle;
+ _mdl_id = mdl_id;
+ _dep_id = dep_id;
+ _cfg = cfg;
+}
+
+bool McapMdl::UpdateContext(tMCA_DEP mdep_handle, uint8_t dep_id, uint8_t cfg) {
+ if (!_mdl_handle) {
+ LOG(ERROR) << "MDL handle not initialized";
+ }
+ _mdep_handle = mdep_handle;
+ _dep_id = dep_id;
+ _cfg = cfg;
+ tMCA_RESULT ret = _mcap_test_interface->close_mdl_request(_mdl_handle);
+ LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
+ if (ret != MCA_SUCCESS) return false;
+ SetHandle(0);
+ SetResponseCode(-1);
+ SetMtu(0);
+ return true;
+}
+
+bool McapMdl::Create(uint16_t data_psm, bool should_connect) {
+ tMCA_RESULT ret = _mcap_test_interface->create_mdl_request(
+ _mcl_handle, _mdep_handle, data_psm, _mdl_id, _dep_id, _cfg,
+ should_connect ? &MCAP_TEST_CHANNEL_CONFIG : nullptr);
+ LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
+ return ret == MCA_SUCCESS;
+}
+
+bool McapMdl::Close() {
+ if (!_mdl_handle) {
+ LOG(ERROR) << "MDL handle not initialized";
+ return false;
+ }
+ tMCA_RESULT ret = _mcap_test_interface->close_mdl_request(_mdl_handle);
+ LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
+ return ret == MCA_SUCCESS;
+}
+
+bool McapMdl::Reconnect(uint16_t data_psm) {
+ tMCA_RESULT ret = _mcap_test_interface->reconnect_mdl_request(
+ _mcl_handle, _mdep_handle, data_psm, _mdl_id, &MCAP_TEST_CHANNEL_CONFIG);
+ LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
+ return ret == MCA_SUCCESS;
+}
+
+bool McapMdl::ReconnectResponse() {
+ tMCA_RESULT ret = _mcap_test_interface->reconnect_mdl_response(
+ _mcl_handle, _mdep_handle, _mdl_id, MCA_RSP_SUCCESS,
+ &MCAP_TEST_CHANNEL_CONFIG);
+ LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
+ return ret == MCA_SUCCESS;
+}
+
+bool McapMdl::CreateResponse() {
+ tMCA_RESULT ret = _mcap_test_interface->create_mdl_response(
+ _mcl_handle, _dep_id, _mdl_id, _cfg, MCA_SUCCESS,
+ &MCAP_TEST_CHANNEL_CONFIG);
+ LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret;
+ return ret == MCA_SUCCESS;
+}
+
+bool McapMdl::IsConnected() { return _mdl_handle > 0; }
+
+uint16_t McapMdl::GetId() { return _mdl_id; }
+
+int32_t McapMdl::GetResponseCode() { return _mdl_rsp_code; }
+
+void McapMdl::SetResponseCode(int32_t rsp_code) { _mdl_rsp_code = rsp_code; }
+
+void McapMdl::SetHandle(tMCA_DL mdl_handle) { _mdl_handle = mdl_handle; }
+
+tMCA_DL McapMdl::GetHandle() { return _mdl_handle; }
+
+void McapMdl::SetMtu(uint16_t mtu) { _data_mtu = mtu; }
+
+uint16_t McapMdl::GetMtu() { return _data_mtu; }
+
+} // namespace SYSTEM_BT_TOOLS_MCAP_TOOL
diff --git a/tools/mcap_tool/mcap_test_mdl.h b/tools/mcap_tool/mcap_test_mdl.h
new file mode 100644
index 0000000..7dadc34
--- /dev/null
+++ b/tools/mcap_tool/mcap_test_mdl.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.
+ */
+#pragma once
+
+#include "mca_api.h"
+
+namespace SYSTEM_BT_TOOLS_MCAP_TOOL {
+
+const tMCA_CHNL_CFG* get_test_channel_config();
+
+class McapMdl {
+ public:
+ /**
+ * An abstraction for the MCAP Data Link (MDL)
+ * @param mcap_test_interface Underlining MCAP interface to Bluetooth stack
+ * @param mcl_handle Parent MCL handle
+ * @param mdep_handle Associated MDEP handle
+ * @param mdl_id Desired MDL ID, application supported
+ * @param dep_id Peer or self MDEP ID
+ * @param cfg Configuration flags
+ */
+ McapMdl(btmcap_test_interface_t* mcap_test_interface, tMCA_CL mcl_handle,
+ tMCA_DEP mdep_handle, uint16_t mdl_id, uint8_t dep_id, uint8_t cfg);
+ /**
+ * Update this MDL's context so that it can be reused for a new connection
+ * This will close this MDL connection at the same time
+ * @param mdep_handle Associated MDEP handle
+ * @param dep_id Peer or self MDEP ID
+ * @param cfg Configuration flags
+ * @return True on success
+ */
+ bool UpdateContext(tMCA_DEP mdep_handle, uint8_t dep_id, uint8_t cfg);
+ /**
+ * Request to create this MDL to remote device through MCL
+ * The create command won't initiate an L2CAP connection unless a non-null
+ * config is given
+ * @param data_psm Data channel L2CAP PSM
+ * @return True on success
+ */
+ bool Create(uint16_t data_psm, bool should_connect);
+ /**
+ * Connect this MDL to remote by configuring the data channel
+ * @return True on success
+ */
+ bool Connect();
+ /**
+ * Close this MDL connection
+ * @return True on success
+ */
+ bool Close();
+ /**
+ * Request to reconnect connect this MDL to remote device through MCL
+ * @param data_psm Data channel L2CAP PSM
+ * @return True on success
+ */
+ bool Reconnect(uint16_t data_psm);
+ /**
+ * Respond to a reconnect request from peer
+ * @return True on success
+ */
+ bool ReconnectResponse();
+ /**
+ * Respond to a connect request from peer
+ * @return True on success
+ */
+ bool CreateResponse();
+ bool IsConnected();
+ int32_t GetResponseCode();
+ void SetResponseCode(int32_t rsp_code);
+ uint16_t GetId();
+ void SetHandle(tMCA_DL mdl_handle);
+ tMCA_DL GetHandle();
+ void SetMtu(uint16_t mtu);
+ uint16_t GetMtu();
+
+ private:
+ // Initialized at start up
+ btmcap_test_interface_t* _mcap_test_interface;
+ tMCA_CL _mcl_handle;
+ tMCA_DEP _mdep_handle;
+ uint16_t _mdl_id;
+ uint8_t _dep_id;
+ uint8_t _cfg;
+
+ // Initialized later
+ tMCA_DL _mdl_handle = 0;
+ uint16_t _data_mtu = 0;
+ int32_t _mdl_rsp_code = -1;
+};
+
+} // namespace SYSTEM_BT_TOOLS_MCAP_TOOL
diff --git a/tools/mcap_tool/mcap_tool.cc b/tools/mcap_tool/mcap_tool.cc
new file mode 100644
index 0000000..c7abd55
--- /dev/null
+++ b/tools/mcap_tool/mcap_tool.cc
@@ -0,0 +1,975 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015, The linux Foundation. All rights reserved.
+ *
+ * Not a Contribution.
+ *
+ * Copyright (C) 2009-2012 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: mcap_tool.cc
+ *
+ * Description: Fluoride MCAP Test Tool application
+ *
+ ***********************************************************************************/
+#include <pthread.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef OS_GENERIC
+#include <sys/capability.h>
+#endif
+#include <sys/prctl.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/hardware.h>
+#ifndef OS_GENERIC
+#include <private/android_filesystem_config.h>
+#endif
+#include <base/logging.h>
+
+#include "bdaddr.h"
+#include "bt_types.h"
+#include "l2c_api.h"
+#include "mca_api.h"
+#include "mca_defs.h"
+#include "osi/include/compat.h"
+#if defined(OS_GENERIC)
+#include "hal_util.h"
+#endif
+#include "mcap_test_app.h"
+#include "mcap_test_mcl.h"
+#include "mcap_test_mdep.h"
+#include "mcap_test_mdl.h"
+
+using SYSTEM_BT_TOOLS_MCAP_TOOL::McapTestApp;
+using SYSTEM_BT_TOOLS_MCAP_TOOL::McapMcl;
+using SYSTEM_BT_TOOLS_MCAP_TOOL::McapMdep;
+using SYSTEM_BT_TOOLS_MCAP_TOOL::McapMdl;
+
+/******************************************************************************
+ * Constants & Macros
+ *****************************************************************************/
+#define PID_FILE "/data/.bdt_pid"
+
+#ifndef MAX
+#define MAX(x, y) ((x) > (y) ? (x) : (y))
+#endif
+
+#ifndef MIN
+#define MIN(x, y) ((x) < (y) ? (x) : (y))
+#endif
+
+#define CASE_RETURN_STR(const) \
+ case const: \
+ return #const;
+
+#ifndef OS_GENERIC
+/* Permission Groups */
+static gid_t groups[] = {AID_NET_BT, AID_INET, AID_NET_BT_ADMIN,
+ AID_SYSTEM, AID_MISC, AID_SDCARD_RW,
+ AID_NET_ADMIN, AID_VPN};
+#endif
+/******************************************************************************
+ * Static variables
+ *****************************************************************************/
+/* Console loop states */
+static bool global_main_done = false;
+static bt_status_t global_status;
+static bool global_strict_mode = false;
+
+/* Device and Profile Interfaces */
+static bluetooth_device_t* sBtDevice = nullptr;
+const bt_interface_t* sBtInterface = nullptr;
+static btmcap_test_interface_t* sMcapTestInterface = nullptr;
+static McapTestApp* sMcapTestApp = nullptr;
+
+/* Bluetooth stack states */
+static bool global_bt_enabled = false;
+static int global_adapter_state = BT_STATE_OFF;
+static int global_pair_state = BT_BOND_STATE_NONE;
+/************************************************************************************
+** Static functions
+************************************************************************************/
+static void process_cmd(char* p, bool is_job);
+
+/*******************************************************************************
+ ** Misc helper functions
+ *******************************************************************************/
+static const char* dump_bt_status(const bt_status_t status) {
+ switch (status) {
+ CASE_RETURN_STR(BT_STATUS_SUCCESS)
+ CASE_RETURN_STR(BT_STATUS_FAIL)
+ CASE_RETURN_STR(BT_STATUS_NOT_READY)
+ CASE_RETURN_STR(BT_STATUS_NOMEM)
+ CASE_RETURN_STR(BT_STATUS_BUSY)
+ CASE_RETURN_STR(BT_STATUS_UNSUPPORTED)
+ default:
+ return "unknown status code";
+ }
+}
+
+/************************************************************************************
+** MCAP Callbacks
+************************************************************************************/
+static void mcap_ctrl_callback(tMCA_HANDLE handle, tMCA_CL mcl, uint8_t event,
+ tMCA_CTRL* p_data) {
+ sMcapTestApp->ControlCallback(handle, mcl, event, p_data);
+}
+
+static void mcap_data_cb(tMCA_DL mdl, BT_HDR* p_pkt) {
+ printf("%s: mdl=%d, event=%d, len=%d, offset=%d, layer_specific=%d\n",
+ __func__, mdl, p_pkt->event, p_pkt->len, p_pkt->offset,
+ p_pkt->layer_specific);
+ printf("%s: HEXDUMP OF DATA LENGTH %u:\n", __func__, p_pkt->len);
+ printf("=========================Begin=========================\n");
+ bool newline = false;
+ for (int i = 0; i < p_pkt->len; ++i) {
+ printf("%02x", p_pkt->data[i]);
+ if (i > 0 && (i % 25) == 0) {
+ printf("\n");
+ newline = true;
+ } else {
+ printf(" ");
+ newline = false;
+ }
+ }
+ if (!newline) printf("\n");
+ printf("=========================End===========================\n");
+}
+
+/************************************************************************************
+** Shutdown helper functions
+************************************************************************************/
+
+static void console_shutdown(void) {
+ LOG(INFO) << __func__ << ": Shutdown Fluoride MCAP test app";
+ global_main_done = true;
+}
+
+/*****************************************************************************
+** Android's init.rc does not yet support applying linux capabilities
+*****************************************************************************/
+
+#ifndef OS_GENERIC
+static void config_permissions(void) {
+ struct __user_cap_header_struct header;
+ struct __user_cap_data_struct cap[2];
+
+ printf("set_aid_and_cap : pid %d, uid %d gid %d", getpid(), getuid(),
+ getgid());
+
+ header.pid = 0;
+
+ prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+
+ setuid(AID_BLUETOOTH);
+ setgid(AID_BLUETOOTH);
+
+ header.version = _LINUX_CAPABILITY_VERSION_3;
+
+ cap[CAP_TO_INDEX(CAP_NET_RAW)].permitted |= CAP_TO_MASK(CAP_NET_RAW);
+ cap[CAP_TO_INDEX(CAP_NET_ADMIN)].permitted |= CAP_TO_MASK(CAP_NET_ADMIN);
+ cap[CAP_TO_INDEX(CAP_NET_BIND_SERVICE)].permitted |=
+ CAP_TO_MASK(CAP_NET_BIND_SERVICE);
+ cap[CAP_TO_INDEX(CAP_SYS_RAWIO)].permitted |= CAP_TO_MASK(CAP_SYS_RAWIO);
+ cap[CAP_TO_INDEX(CAP_SYS_NICE)].permitted |= CAP_TO_MASK(CAP_SYS_NICE);
+ cap[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
+ cap[CAP_TO_INDEX(CAP_WAKE_ALARM)].permitted |= CAP_TO_MASK(CAP_WAKE_ALARM);
+
+ cap[CAP_TO_INDEX(CAP_NET_RAW)].effective |= CAP_TO_MASK(CAP_NET_RAW);
+ cap[CAP_TO_INDEX(CAP_NET_ADMIN)].effective |= CAP_TO_MASK(CAP_NET_ADMIN);
+ cap[CAP_TO_INDEX(CAP_NET_BIND_SERVICE)].effective |=
+ CAP_TO_MASK(CAP_NET_BIND_SERVICE);
+ cap[CAP_TO_INDEX(CAP_SYS_RAWIO)].effective |= CAP_TO_MASK(CAP_SYS_RAWIO);
+ cap[CAP_TO_INDEX(CAP_SYS_NICE)].effective |= CAP_TO_MASK(CAP_SYS_NICE);
+ cap[CAP_TO_INDEX(CAP_SETGID)].effective |= CAP_TO_MASK(CAP_SETGID);
+ cap[CAP_TO_INDEX(CAP_WAKE_ALARM)].effective |= CAP_TO_MASK(CAP_WAKE_ALARM);
+
+ capset(&header, &cap[0]);
+ setgroups(sizeof(groups) / sizeof(groups[0]), groups);
+}
+#endif
+
+/*******************************************************************************
+ ** Console helper functions
+ *******************************************************************************/
+
+void skip_blanks(char** p) {
+ while (**p == ' ') (*p)++;
+}
+
+uint32_t get_int(char** p, int DefaultValue) {
+ uint32_t Value = 0;
+ unsigned char UseDefault;
+
+ UseDefault = 1;
+ skip_blanks(p);
+
+ while (((**p) <= '9' && (**p) >= '0')) {
+ Value = Value * 10 + (**p) - '0';
+ UseDefault = 0;
+ (*p)++;
+ }
+
+ if (UseDefault)
+ return DefaultValue;
+ else
+ return Value;
+}
+
+int get_signed_int(char** p, int DefaultValue) {
+ int Value = 0;
+ unsigned char UseDefault;
+ unsigned char NegativeNum = 0;
+
+ UseDefault = 1;
+ skip_blanks(p);
+
+ if ((**p) == '-') {
+ NegativeNum = 1;
+ (*p)++;
+ }
+ while (((**p) <= '9' && (**p) >= '0')) {
+ Value = Value * 10 + (**p) - '0';
+ UseDefault = 0;
+ (*p)++;
+ }
+
+ if (UseDefault)
+ return DefaultValue;
+ else
+ return ((NegativeNum == 0) ? Value : -Value);
+}
+
+void get_str(char** p, char* Buffer) {
+ skip_blanks(p);
+
+ while (**p != 0 && **p != ' ') {
+ *Buffer = **p;
+ (*p)++;
+ Buffer++;
+ }
+
+ *Buffer = 0;
+}
+
+uint32_t get_hex_any(char** p, int DefaultValue, unsigned int NumOfNibble) {
+ uint32_t Value = 0;
+ unsigned char UseDefault;
+ // unsigned char NumOfNibble = 8; //Since we are returning uint32, max
+ // allowed is 4 bytes(8 nibbles).
+
+ UseDefault = 1;
+ skip_blanks(p);
+
+ while ((NumOfNibble) &&
+ (((**p) <= '9' && (**p) >= '0') || ((**p) <= 'f' && (**p) >= 'a') ||
+ ((**p) <= 'F' && (**p) >= 'A'))) {
+ if (**p >= 'a')
+ Value = Value * 16 + (**p) - 'a' + 10;
+ else if (**p >= 'A')
+ Value = Value * 16 + (**p) - 'A' + 10;
+ else
+ Value = Value * 16 + (**p) - '0';
+ UseDefault = 0;
+ (*p)++;
+ NumOfNibble--;
+ }
+
+ if (UseDefault)
+ return DefaultValue;
+ else
+ return Value;
+}
+uint32_t get_hex(char** p, int DefaultValue) {
+ return get_hex_any(p, DefaultValue, 8);
+}
+uint8_t get_hex_byte(char** p, int DefaultValue) {
+ return get_hex_any(p, DefaultValue, 2);
+}
+
+bool is_cmd(const char* cmd, const char* str) {
+ return (strlen(str) == strlen(cmd)) && (strncmp(cmd, str, strlen(str)) == 0);
+}
+
+typedef void(console_cmd_handler_t)(char* p);
+
+typedef struct {
+ const char* name;
+ console_cmd_handler_t* handler;
+ const char* help;
+ bool is_job;
+} cmd_t;
+
+extern const cmd_t console_cmd_list[];
+static int console_cmd_maxlen = 0;
+
+static void* cmdjob_handler(void* param) {
+ char* job_cmd = (char*)param;
+ LOG(INFO) << "cmdjob starting: " << job_cmd;
+ process_cmd(job_cmd, true);
+ LOG(INFO) << "cmdjob terminating";
+ free(job_cmd);
+ return nullptr;
+}
+
+static int create_cmdjob(char* cmd) {
+ CHECK(cmd);
+ char* job_cmd = (char*)calloc(1, strlen(cmd) + 1); /* freed in job handler */
+ if (job_cmd) {
+ strlcpy(job_cmd, cmd, strlen(job_cmd) + 1);
+ pthread_t thread_id;
+ int ret =
+ pthread_create(&thread_id, nullptr, cmdjob_handler, (void*)job_cmd);
+ LOG_IF(ERROR, ret != 0) << "Error during pthread_create";
+ } else {
+ LOG(INFO) << "Cannot Allocate memory for cmdjob: " << cmd;
+ }
+ return 0;
+}
+
+/*******************************************************************************
+ ** Load stack lib
+ *******************************************************************************/
+
+int HAL_load(void) {
+ int err = 0;
+ hw_module_t* module;
+ hw_device_t* device;
+ LOG(INFO) << "Loading HAL library and extensions";
+#if defined(OS_GENERIC)
+ err = hal_util_load_bt_library((hw_module_t const**)&module);
+#else
+ err = hw_get_module(BT_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
+#endif
+ if (!err) {
+ err = module->methods->open(module, BT_HARDWARE_MODULE_ID, &device);
+ if (!err) {
+ sBtDevice = (bluetooth_device_t*)device;
+ sBtInterface = sBtDevice->get_bluetooth_interface();
+ }
+ }
+ LOG(INFO) << "HAL library loaded, status: " << strerror(err);
+ return err;
+}
+
+int HAL_unload(void) {
+ int err = 0;
+ LOG(INFO) << "Unloading HAL lib";
+ sBtInterface = nullptr;
+ LOG(INFO) << "HAL library unloaded, status: " << strerror(err);
+ return err;
+}
+
+/*******************************************************************************
+ ** HAL test functions & callbacks
+ *******************************************************************************/
+
+void setup_test_env(void) {
+ int i = 0;
+ while (console_cmd_list[i].name) {
+ console_cmd_maxlen =
+ MAX(console_cmd_maxlen, (int)strlen(console_cmd_list[i].name));
+ i++;
+ }
+}
+
+void check_return_status(bt_status_t status) {
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(INFO) << "HAL REQUEST FAILED status : " << status << " ("
+ << dump_bt_status(status) << ")";
+ } else {
+ LOG(INFO) << "HAL REQUEST SUCCESS";
+ }
+}
+
+static void adapter_state_changed(bt_state_t state) {
+ int V1 = 1000, V2 = 2;
+ bt_property_t property = {BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT, 4, &V1};
+ bt_property_t property1 = {BT_PROPERTY_ADAPTER_SCAN_MODE, 2, &V2};
+ bt_property_t property2 = {BT_PROPERTY_BDNAME, 6, (void*)"Fluoride_Test"};
+
+ global_adapter_state = state;
+
+ if (state == BT_STATE_ON) {
+ global_bt_enabled = true;
+ global_status = (bt_status_t)sBtInterface->set_adapter_property(&property1);
+ global_status = (bt_status_t)sBtInterface->set_adapter_property(&property);
+ global_status = (bt_status_t)sBtInterface->set_adapter_property(&property2);
+ } else {
+ global_bt_enabled = false;
+ }
+}
+
+static void adapter_properties_changed(bt_status_t status, int num_properties,
+ bt_property_t* properties) {
+ bt_bdaddr_t bd_addr;
+ bdstr_t bd_addr_str;
+ if (!properties) {
+ printf("properties is null\n");
+ return;
+ }
+ switch (properties->type) {
+ case BT_PROPERTY_BDADDR:
+ memcpy(bd_addr.address, properties->val,
+ MIN((size_t)properties->len, sizeof(bd_addr)));
+ bdaddr_to_string(&bd_addr, bd_addr_str, sizeof(bd_addr_str));
+ LOG(INFO) << "Local Bd Addr = " << bd_addr_str;
+ break;
+ default:
+ break;
+ }
+ return;
+}
+
+static void discovery_state_changed(bt_discovery_state_t state) {
+ LOG(INFO) << "Discovery State Updated: "
+ << (state == BT_DISCOVERY_STOPPED ? "STOPPED" : "STARTED");
+}
+
+static void pin_request_cb(bt_bdaddr_t* remote_bd_addr, bt_bdname_t* bd_name,
+ uint32_t cod, bool min_16_digit) {
+ bt_pin_code_t pincode = {{0x31, 0x32, 0x33, 0x34}};
+
+ if (BT_STATUS_SUCCESS !=
+ sBtInterface->pin_reply(remote_bd_addr, true, 4, &pincode)) {
+ LOG(INFO) << "Pin Reply failed";
+ }
+}
+
+static void ssp_request_cb(bt_bdaddr_t* remote_bd_addr, bt_bdname_t* bd_name,
+ uint32_t cod, bt_ssp_variant_t pairing_variant,
+ uint32_t pass_key) {
+ LOG(INFO) << __func__ << ": device_name:" << bd_name->name
+ << ", pairing_variant: " << (int)pairing_variant
+ << ", passkey: " << unsigned(pass_key);
+ if (BT_STATUS_SUCCESS !=
+ sBtInterface->ssp_reply(remote_bd_addr, pairing_variant, true,
+ pass_key)) {
+ LOG(ERROR) << "SSP Reply failed";
+ }
+}
+
+static void bond_state_changed_cb(bt_status_t status,
+ bt_bdaddr_t* remote_bd_addr,
+ bt_bond_state_t state) {
+ LOG(INFO) << "Bond State Changed = " << state;
+ global_pair_state = state;
+}
+
+static void acl_state_changed(bt_status_t status, bt_bdaddr_t* remote_bd_addr,
+ bt_acl_state_t state) {
+ bdstr_t bd_addr_str;
+ bdaddr_to_string(remote_bd_addr, bd_addr_str, sizeof(bd_addr_str));
+ LOG(INFO) << __func__ << ": remote_bd_addr=" << bd_addr_str << ", acl status="
+ << (state == BT_ACL_STATE_CONNECTED ? "ACL Connected"
+ : "ACL Disconnected");
+}
+
+static void dut_mode_recv(uint16_t opcode, uint8_t* buf, uint8_t len) {
+ LOG(INFO) << "DUT MODE RECV : NOT IMPLEMENTED";
+}
+
+static bt_callbacks_t bt_callbacks = {
+ sizeof(bt_callbacks_t),
+ adapter_state_changed,
+ adapter_properties_changed, /*adapter_properties_cb */
+ nullptr, /* remote_device_properties_cb */
+ nullptr, /* device_found_cb */
+ discovery_state_changed, /* discovery_state_changed_cb */
+ pin_request_cb, /* pin_request_cb */
+ ssp_request_cb, /* ssp_request_cb */
+ bond_state_changed_cb, /*bond_state_changed_cb */
+ acl_state_changed, /* acl_state_changed_cb */
+ nullptr, /* thread_evt_cb */
+ dut_mode_recv, /*dut_mode_recv_cb */
+ nullptr, /* le_test_mode_cb */
+ nullptr /* energy_info_cb */
+};
+
+static bool set_wake_alarm(uint64_t delay_millis, bool should_wake, alarm_cb cb,
+ void* data) {
+ static timer_t timer;
+ static bool timer_created;
+
+ if (!timer_created) {
+ struct sigevent sigevent;
+ memset(&sigevent, 0, sizeof(sigevent));
+ sigevent.sigev_notify = SIGEV_THREAD;
+ sigevent.sigev_notify_function = (void (*)(union sigval))cb;
+ sigevent.sigev_value.sival_ptr = data;
+ timer_create(CLOCK_MONOTONIC, &sigevent, &timer);
+ timer_created = true;
+ }
+
+ struct itimerspec new_value;
+ new_value.it_value.tv_sec = delay_millis / 1000;
+ new_value.it_value.tv_nsec = (delay_millis % 1000) * 1000 * 1000;
+ new_value.it_interval.tv_sec = 0;
+ new_value.it_interval.tv_nsec = 0;
+ timer_settime(timer, 0, &new_value, nullptr);
+
+ return true;
+}
+
+static int acquire_wake_lock(const char* lock_name) {
+ return BT_STATUS_SUCCESS;
+}
+
+static int release_wake_lock(const char* lock_name) {
+ return BT_STATUS_SUCCESS;
+}
+
+static bt_os_callouts_t callouts = {
+ sizeof(bt_os_callouts_t), set_wake_alarm, acquire_wake_lock,
+ release_wake_lock,
+};
+
+void adapter_init(void) {
+ LOG(INFO) << __func__;
+ global_status = (bt_status_t)sBtInterface->init(&bt_callbacks);
+ if (global_status == BT_STATUS_SUCCESS) {
+ global_status = (bt_status_t)sBtInterface->set_os_callouts(&callouts);
+ }
+ check_return_status(global_status);
+}
+
+void adapter_enable(void) {
+ LOG(INFO) << __func__;
+ if (global_bt_enabled) {
+ LOG(INFO) << __func__ << ": Bluetooth is already enabled";
+ return;
+ }
+ global_status = (bt_status_t)sBtInterface->enable(global_strict_mode);
+ check_return_status(global_status);
+}
+
+void adapter_disable(void) {
+ LOG(INFO) << __func__;
+ if (!global_bt_enabled) {
+ LOG(INFO) << __func__ << ": Bluetooth is already disabled";
+ return;
+ }
+ global_status = (bt_status_t)sBtInterface->disable();
+ check_return_status(global_status);
+}
+void adapter_dut_mode_configure(char* p) {
+ LOG(INFO) << __func__;
+ if (!global_bt_enabled) {
+ LOG(INFO) << __func__
+ << ": Bluetooth must be enabled for test_mode to work.";
+ return;
+ }
+ int32_t mode = get_signed_int(&p, -1); // arg1
+ if ((mode != 0) && (mode != 1)) {
+ LOG(INFO) << __func__ << "Please specify mode: 1 to enter, 0 to exit";
+ return;
+ }
+ global_status = (bt_status_t)sBtInterface->dut_mode_configure(mode);
+ check_return_status(global_status);
+}
+
+void adapter_cleanup(void) {
+ LOG(INFO) << __func__;
+ sBtInterface->cleanup();
+}
+
+/*******************************************************************************
+ ** Console commands
+ *******************************************************************************/
+
+void do_help(char* p) {
+ int i = 0;
+ char line[128];
+ int pos = 0;
+
+ while (console_cmd_list[i].name != nullptr) {
+ pos = snprintf(line, sizeof(line), "%s", (char*)console_cmd_list[i].name);
+ printf("%s %s\n", (char*)line, (char*)console_cmd_list[i].help);
+ i++;
+ }
+}
+
+void do_quit(char* p) { console_shutdown(); }
+
+/*******************************************************************
+ *
+ * BT TEST CONSOLE COMMANDS
+ *
+ * Parses argument lists and passes to API test function
+ *
+ */
+
+void do_init(char* p) { adapter_init(); }
+
+void do_enable(char* p) { adapter_enable(); }
+
+void do_disable(char* p) { adapter_disable(); }
+
+void do_cleanup(char* p) { adapter_cleanup(); }
+
+/**
+ * MCAP API commands
+ */
+void do_mcap_register(char* p) {
+ uint16_t ctrl_psm = get_hex(&p, 0); // arg1
+ uint16_t data_psm = get_hex(&p, 0); // arg2
+ uint16_t sec_mask = get_int(&p, 0); // arg3
+ printf("%s: ctrl_psm=0x%04x, data_psm=0x%04x, sec_mask=0x%04x\n", __func__,
+ ctrl_psm, data_psm, sec_mask);
+ if (!ctrl_psm || !data_psm) {
+ printf("%s: Invalid Parameters\n", __func__);
+ return;
+ }
+ sMcapTestApp->Register(ctrl_psm, data_psm, sec_mask, mcap_ctrl_callback);
+ printf("%s: mcap_handle=%d\n", __func__, sMcapTestApp->GetHandle());
+}
+
+void do_mcap_deregister(char* p) {
+ printf("%s: mcap_handle=%d\n", __func__, sMcapTestApp->GetHandle());
+ sMcapTestApp->Deregister();
+ printf("%s: handle=%d\n", __func__, sMcapTestApp->GetHandle());
+}
+
+void do_mcap_create_mdep(char* p) {
+ int type = get_int(&p, -1); // arg1
+ printf("%s: mcap_handle=%d, type=%d\n", __func__, sMcapTestApp->GetHandle(),
+ type);
+ bool ret = sMcapTestApp->CreateMdep(type, MCA_NUM_MDLS, mcap_data_cb);
+ printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL");
+}
+
+static void do_mcap_delete_mdep(char* p) {
+ uint8_t mdep_handle = get_int(&p, 0);
+ printf("%s: mcap_handle=%d, mdep_handle=%d\n", __func__,
+ sMcapTestApp->GetHandle(), mdep_handle);
+ if (!mdep_handle) {
+ printf("%s: Invalid Parameters\n", __func__);
+ return;
+ }
+ McapMdep* mcap_mdep = sMcapTestApp->FindMdepByHandle(mdep_handle);
+ if (!mcap_mdep) {
+ LOG(ERROR) << "No MDEP for handle " << (int)mdep_handle;
+ return;
+ }
+ bool ret = mcap_mdep->Delete();
+ printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL");
+}
+
+static void do_mcap_connect_mcl(char* p) {
+ char buf[64];
+ get_str(&p, buf); // arg1
+ bt_bdaddr_t bd_addr;
+ bool valid_bd_addr = string_to_bdaddr(buf, &bd_addr);
+ uint16_t ctrl_psm = get_hex(&p, 0); // arg2
+ uint16_t sec_mask = get_int(&p, 0); // arg3
+ printf("%s: mcap_handle=%d, ctrl_psm=0x%04x, secMask=0x%04x, bd_addr=%s\n",
+ __func__, sMcapTestApp->GetHandle(), ctrl_psm, sec_mask, buf);
+ if (!ctrl_psm || !valid_bd_addr) {
+ printf("%s: Invalid Parameters\n", __func__);
+ return;
+ }
+ bool ret = sMcapTestApp->ConnectMcl(bd_addr, ctrl_psm, sec_mask);
+ printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL");
+}
+
+static void do_mcap_disconnect_mcl(char* p) {
+ char buf[64];
+ get_str(&p, buf); // arg1
+ bt_bdaddr_t bd_addr;
+ bool valid_bd_addr = string_to_bdaddr(buf, &bd_addr);
+ printf("%s: bd_addr=%s\n", __func__, buf);
+ if (!valid_bd_addr) {
+ printf("%s: Invalid Parameters\n", __func__);
+ return;
+ }
+ McapMcl* mcap_mcl = sMcapTestApp->FindMclByPeerAddress(bd_addr);
+ if (!mcap_mcl) {
+ LOG(ERROR) << "No MCL for bd_addr " << buf;
+ return;
+ }
+ bool ret = mcap_mcl->Disconnect();
+ printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL");
+}
+
+static void do_mcap_create_mdl(char* p) {
+ char buf[64];
+ get_str(&p, buf); // arg1
+ bt_bdaddr_t bd_addr;
+ bool valid_bd_addr = string_to_bdaddr(buf, &bd_addr);
+ uint16_t mdep_handle = get_int(&p, 0); // arg2
+ uint16_t data_psm = get_hex(&p, 0); // arg3
+ uint16_t mdl_id = get_int(&p, 0); // arg4
+ uint8_t peer_dep_id = get_int(&p, 0); // arg5
+ uint8_t cfg = get_hex(&p, 0); // arg6
+ int do_not_connect = get_int(&p, 0); // arg7
+ printf(
+ "%s: bd_addr=%s, mdep_handle=%d, data_psm=0x%04x, mdl_id=%d,"
+ " peer_dep_id=%d, cfg=0x%02x, do_not_connect=%d\n",
+ __func__, buf, mdep_handle, data_psm, mdl_id, peer_dep_id, cfg,
+ do_not_connect);
+ if (!data_psm || !peer_dep_id || !valid_bd_addr || !mdep_handle) {
+ printf("%s: Invalid Parameters\n", __func__);
+ return;
+ }
+ McapMcl* mcap_mcl = sMcapTestApp->FindMclByPeerAddress(bd_addr);
+ if (!mcap_mcl) {
+ LOG(ERROR) << "No MCL for bd_addr " << buf;
+ return;
+ }
+ bool ret = mcap_mcl->CreateMdl(mdep_handle, data_psm, mdl_id, peer_dep_id,
+ cfg, !do_not_connect);
+ printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL");
+}
+
+static void do_mcap_data_channel_config(char* p) {
+ char buf[64];
+ get_str(&p, buf); // arg1
+ bt_bdaddr_t bd_addr;
+ bool valid_bd_addr = string_to_bdaddr(buf, &bd_addr);
+ printf("%s: bd_addr=%s\n", __func__, buf);
+ if (!valid_bd_addr) {
+ printf("%s: Invalid Parameters\n", __func__);
+ return;
+ }
+ McapMcl* mcap_mcl = sMcapTestApp->FindMclByPeerAddress(bd_addr);
+ if (!mcap_mcl) {
+ LOG(ERROR) << "No MCL for bd_addr " << buf;
+ return;
+ }
+ bool ret = mcap_mcl->DataChannelConfig();
+ printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL");
+}
+
+static void do_mcap_abort_mdl(char* p) {
+ char buf[64];
+ get_str(&p, buf); // arg1
+ bt_bdaddr_t bd_addr;
+ bool valid_bd_addr = string_to_bdaddr(buf, &bd_addr);
+ printf("%s: bd_addr=%s\n", __func__, buf);
+ if (!valid_bd_addr) {
+ printf("%s: Invalid Parameters\n", __func__);
+ return;
+ }
+ McapMcl* mcap_mcl = sMcapTestApp->FindMclByPeerAddress(bd_addr);
+ if (!mcap_mcl) {
+ LOG(ERROR) << "No MCL for bd_addr " << buf;
+ return;
+ }
+ bool ret = mcap_mcl->AbortMdl();
+ printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL");
+}
+
+static void do_mcap_delete_mdl(char* p) {
+ char buf[64];
+ get_str(&p, buf); // arg1
+ bt_bdaddr_t bd_addr;
+ bool valid_bd_addr = string_to_bdaddr(buf, &bd_addr);
+ uint16_t mdl_id = get_int(&p, 0); // arg2
+ printf("%s: bd_addr=%s, mdl_id=%d\n", __func__, buf, mdl_id);
+ if (!valid_bd_addr) {
+ printf("%s: Invalid Parameters\n", __func__);
+ return;
+ }
+ McapMcl* mcap_mcl = sMcapTestApp->FindMclByPeerAddress(bd_addr);
+ if (!mcap_mcl) {
+ LOG(ERROR) << "No MCL for bd_addr " << buf;
+ return;
+ }
+ bool ret = mcap_mcl->DeleteMdl(mdl_id);
+ printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL");
+}
+
+static void do_mcap_close_mdl(char* p) {
+ char buf[64];
+ get_str(&p, buf); // arg1
+ bt_bdaddr_t bd_addr;
+ bool valid_bd_addr = string_to_bdaddr(buf, &bd_addr);
+ uint16_t mdl_id = get_int(&p, 0); // arg2
+ printf("%s: bd_addr=%s, mdl_id=%d\n", __func__, buf, mdl_id);
+ if (!valid_bd_addr || !mdl_id) {
+ printf("%s: Invalid Parameters\n", __func__);
+ return;
+ }
+ McapMcl* mcap_mcl = sMcapTestApp->FindMclByPeerAddress(bd_addr);
+ if (!mcap_mcl) {
+ LOG(ERROR) << "No MCL for bd_addr " << buf;
+ return;
+ }
+ McapMdl* mcap_mdl = mcap_mcl->FindMdlById(mdl_id);
+ if (!mcap_mdl) {
+ LOG(ERROR) << "No MDL for ID " << (int)mdl_id;
+ return;
+ }
+ bool ret = mcap_mdl->Close();
+ printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL");
+}
+
+static void do_mcap_reconnect_mdl(char* p) {
+ char buf[64];
+ get_str(&p, buf); // arg1
+ bt_bdaddr_t bd_addr;
+ bool valid_bd_addr = string_to_bdaddr(buf, &bd_addr);
+ uint16_t data_psm = get_hex(&p, 0); // arg1
+ uint16_t mdl_id = get_int(&p, 0); // arg2
+ printf("%s: data_psm=0x%04x, mdl_id=%d\n", __func__, data_psm, mdl_id);
+ if (!valid_bd_addr) {
+ printf("%s: Invalid Parameters\n", __func__);
+ return;
+ }
+ McapMcl* mcap_mcl = sMcapTestApp->FindMclByPeerAddress(bd_addr);
+ if (!mcap_mcl) {
+ LOG(ERROR) << "No MCL for bd_addr " << buf;
+ return;
+ }
+ McapMdl* mcap_mdl = mcap_mcl->FindMdlById(mdl_id);
+ if (!mcap_mdl) {
+ LOG(ERROR) << "No MDL for ID " << (int)mdl_id;
+ return;
+ }
+ bool ret = mcap_mdl->Reconnect(data_psm);
+ printf("%s: %s\n", __func__, ret ? "SUCCESS" : "FAIL");
+}
+
+static void do_pairing(char* p) {
+ bt_bdaddr_t bd_addr;
+ if (!string_to_bdaddr(p, &bd_addr)) {
+ LOG(ERROR) << "Invalid Bluetooth address " << p;
+ return;
+ }
+ if (BT_STATUS_SUCCESS !=
+ sBtInterface->create_bond(&bd_addr, BT_TRANSPORT_BR_EDR)) {
+ LOG(ERROR) << "Failed to Initiate Pairing";
+ return;
+ }
+}
+
+/** CONSOLE COMMAND TABLE */
+
+const cmd_t console_cmd_list[] = {
+ /* INTERNAL */
+ {"help", do_help, "", 0},
+ {"quit", do_quit, "", 0},
+ /* API CONSOLE COMMANDS */
+ /* Init and Cleanup shall be called automatically */
+ {"enable_bluetooth", do_enable, "", 0},
+ {"disable_bluetooth", do_disable, "", 0},
+ {"pair", do_pairing, "BD_ADDR<xx:xx:xx:xx:xx:xx>", 0},
+ {"register", do_mcap_register,
+ "ctrl_psm<hex> data_psm<hex> security_mask<0-10>", 0},
+ {"deregister", do_mcap_deregister, "", 0},
+ {"create_mdep", do_mcap_create_mdep, "type<0-Echo, 1-Normal>", 0},
+ {"delete_mdep", do_mcap_delete_mdep, "mdep_handle<int>", 0},
+ {"connect_mcl", do_mcap_connect_mcl,
+ "BD_ADDR<xx:xx:xx:xx:xx:xx> ctrl_psm<hex> security_mask<0-10>", 0},
+ {"disconnect_mcl", do_mcap_disconnect_mcl, "BD_ADDR<xx:xx:xx:xx:xx:xx>", 0},
+ {"create_mdl", do_mcap_create_mdl,
+ "BD_ADDR<xx:xx:xx:xx:xx:xx> mdep_handle<int> data_psm<hex> mdl_id<int> "
+ "peer_dep_id<int> cfg<hex> "
+ "do_not_connect<0-connect,1-wait_for_data_channel_config>",
+ 0},
+ {"data_channel_config", do_mcap_data_channel_config,
+ "BD_ADDR<xx:xx:xx:xx:xx:xx>", 0},
+ {"abort_mdl", do_mcap_abort_mdl, "BD_ADDR<xx:xx:xx:xx:xx:xx>", 0},
+ {"close_mdl", do_mcap_close_mdl, "BD_ADDR<xx:xx:xx:xx:xx:xx> mdl_id<int>",
+ 0},
+ {"delete_mdl", do_mcap_delete_mdl, "BD_ADDR<xx:xx:xx:xx:xx:xx> mdl_id<int>",
+ 0},
+ {"reconnect_mdl", do_mcap_reconnect_mdl,
+ "BD_ADDR<xx:xx:xx:xx:xx:xx> data_psm<hex> mdl_id<int>", 0},
+ /* last entry */
+ {nullptr, nullptr, "", 0},
+};
+
+/** Main console command handler */
+
+static void process_cmd(char* p, bool is_job) {
+ char cmd[2048];
+ int i = 0;
+ char* p_saved = p;
+
+ get_str(&p, cmd); // arg1
+
+ /* table commands */
+ while (console_cmd_list[i].name != nullptr) {
+ if (is_cmd(cmd, console_cmd_list[i].name)) {
+ if (!is_job && console_cmd_list[i].is_job)
+ create_cmdjob(p_saved);
+ else {
+ console_cmd_list[i].handler(p);
+ }
+ return;
+ }
+ i++;
+ }
+ LOG(ERROR) << "Unknown command: " << p_saved;
+ do_help(nullptr);
+}
+
+int main(int argc, char* argv[]) {
+ setbuf(stdout, NULL);
+#if !defined(OS_GENERIC)
+ config_permissions();
+#endif
+ LOG(INFO) << "Fluoride MCAP test app is starting";
+
+ if (HAL_load() < 0) {
+ fprintf(stderr, "%s: HAL failed to initialize, exit\n", __func__);
+ unlink(PID_FILE);
+ exit(0);
+ }
+
+ setup_test_env();
+
+ /* Automatically perform the init */
+ adapter_init();
+ sleep(2);
+ adapter_enable();
+ sleep(2);
+ sMcapTestInterface =
+ (btmcap_test_interface_t*)sBtInterface->get_profile_interface(
+ BT_TEST_INTERFACE_MCAP_ID);
+ sMcapTestInterface->init();
+ sMcapTestApp = new McapTestApp(sMcapTestInterface);
+
+ /* Main loop */
+ char line[2048];
+ while (!global_main_done) {
+ memset(line, '\0', sizeof(line));
+ /* command prompt */
+ printf(">");
+ fflush(stdout);
+ fgets(line, sizeof(line), stdin);
+ if (line[0] != '\0') {
+ /* Remove line feed */
+ line[strlen(line) - 1] = 0;
+ if (strlen(line) != 0) process_cmd(line, false);
+ }
+ }
+ adapter_cleanup();
+ HAL_unload();
+ LOG(INFO) << "Fluoride MCAP test app is terminating";
+
+ return 0;
+}