OSDN Git Service

Merge "Fix potential OOB write in btm_read_remote_ext_features_complete" into oc...
authorAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
Wed, 4 Dec 2019 08:13:37 +0000 (08:13 +0000)
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
Wed, 4 Dec 2019 08:13:37 +0000 (08:13 +0000)
Change-Id: I0767ba267fc51a926930288752a1a079414d5a76

167 files changed:
Android.bp
BUILD.gn
bta/ag/bta_ag_cmd.cc
bta/av/bta_av_aact.cc
bta/dm/bta_dm_act.cc
bta/dm/bta_dm_cfg.cc
bta/dm/bta_dm_pm.cc
bta/gatt/bta_gattc_act.cc
bta/gatt/bta_gattc_api.cc
bta/gatt/bta_gattc_cache.cc
bta/gatt/bta_gattc_int.h
bta/gatt/bta_gattc_main.cc
bta/include/bta_gatt_api.h
bta/pan/bta_pan_act.cc
bta/sys/bta_sys_main.cc
btcore/Android.bp
btcore/AndroidTest.xml [new file with mode: 0644]
btif/Android.bp
btif/co/bta_av_co.cc
btif/include/btif_profile_queue.h
btif/src/btif_a2dp_source.cc
btif/src/btif_av.cc
btif/src/btif_ble_advertiser.cc
btif/src/btif_config.cc
btif/src/btif_dm.cc
btif/src/btif_gatt_client.cc
btif/src/btif_hf.cc
btif/src/btif_hf_client.cc
btif/src/btif_hh.cc
btif/src/btif_profile_queue.cc
btif/src/btif_rc.cc
btif/src/btif_sock_sdp.cc
btif/src/btif_storage.cc
btif/test/btif_profile_queue_test.cc [new file with mode: 0644]
build/secondary/third_party/libchrome/BUILD.gn
conf/bt_stack.conf
device/Android.bp
device/AndroidTest.xml [new file with mode: 0644]
device/include/interop.h
device/include/interop_database.h
device/src/controller.cc
device/src/interop.cc
hci/Android.bp
hci/AndroidTest.xml [new file with mode: 0644]
hci/include/hci_layer.h
hci/src/hci_layer.cc
hci/src/hci_layer_android.cc
hci/src/hci_layer_linux.cc
include/bt_target.h
include/bt_trace.h
main/bte_logmsg.cc
main/bte_main.cc
osi/Android.bp
osi/AndroidTest.xml [new file with mode: 0644]
osi/BUILD.gn
osi/include/data_dispatcher.h [deleted file]
osi/src/data_dispatcher.cc [deleted file]
osi/test/data_dispatcher_test.cc [deleted file]
service/Android.bp
service/AndroidTest.xml [new file with mode: 0644]
service/BUILD.gn
service/daemon.cc
service/hal/fake_bluetooth_gatt_interface.cc
service/ipc/dbus/bluetooth_adapter.cc [new file with mode: 0644]
service/ipc/dbus/bluetooth_adapter.h [new file with mode: 0644]
service/ipc/dbus/ipc_handler_dbus.cc [new file with mode: 0644]
service/ipc/dbus/ipc_handler_dbus.h [new file with mode: 0644]
service/ipc/dbus/org.fluoride.BluetoothAdapter.xml [new file with mode: 0644]
service/ipc/ipc_manager.cc
service/ipc/ipc_manager.h
service/low_energy_client.cc
stack/Android.bp
stack/BUILD.gn
stack/a2dp/a2dp_aac.cc
stack/a2dp/a2dp_aac_encoder.cc
stack/a2dp/a2dp_api.cc
stack/a2dp/a2dp_codec_config.cc
stack/a2dp/a2dp_sbc.cc
stack/a2dp/a2dp_sbc_encoder.cc
stack/a2dp/a2dp_vendor.cc
stack/a2dp/a2dp_vendor_aptx.cc
stack/a2dp/a2dp_vendor_aptx_encoder.cc
stack/a2dp/a2dp_vendor_aptx_hd.cc
stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc
stack/a2dp/a2dp_vendor_ldac.cc
stack/a2dp/a2dp_vendor_ldac_encoder.cc
stack/avdt/avdt_api.cc
stack/avdt/avdt_ccb.cc
stack/avdt/avdt_ccb_act.cc
stack/avdt/avdt_scb_act.cc
stack/bnep/bnep_main.cc
stack/btm/btm_acl.cc
stack/btm/btm_ble_bgconn.cc
stack/btm/btm_ble_gap.cc
stack/btm/btm_ble_int.h
stack/btm/btm_ble_int_types.h
stack/btm/btm_ble_multi_adv.cc
stack/btm/btm_dev.cc
stack/btm/btm_inq.cc
stack/btm/btm_int.h
stack/btm/btm_int_types.h
stack/btm/btm_sec.cc
stack/btu/btu_hcif.cc
stack/btu/btu_task.cc
stack/gap/gap_api.cc [deleted file]
stack/gap/gap_ble.cc
stack/gap/gap_conn.cc
stack/gap/gap_int.h [deleted file]
stack/gap/gap_utils.cc [deleted file]
stack/gatt/att_protocol.cc
stack/gatt/gatt_api.cc
stack/gatt/gatt_auth.cc
stack/gatt/gatt_cl.cc
stack/gatt/gatt_db.cc
stack/gatt/gatt_int.h
stack/gatt/gatt_main.cc
stack/gatt/gatt_sr.cc
stack/gatt/gatt_utils.cc
stack/hcic/hcicmds.cc
stack/include/a2dp_aac.h
stack/include/a2dp_api.h
stack/include/a2dp_codec_api.h
stack/include/a2dp_sbc.h
stack/include/a2dp_vendor.h
stack/include/a2dp_vendor_aptx.h
stack/include/a2dp_vendor_aptx_hd.h
stack/include/a2dp_vendor_ldac.h
stack/include/advertise_data_parser.h
stack/include/avdt_api.h
stack/include/ble_advertiser.h
stack/include/bt_types.h
stack/include/btm_api.h
stack/include/btm_api_types.h
stack/include/btm_ble_api.h
stack/include/btu.h
stack/include/gap_api.h
stack/include/gatt_api.h
stack/include/hcimsgs.h
stack/l2cap/l2c_ble.cc
stack/l2cap/l2c_fcr.cc
stack/l2cap/l2c_int.h
stack/l2cap/l2c_link.cc
stack/l2cap/l2c_utils.cc
stack/pan/pan_main.cc
stack/rfcomm/port_utils.cc
stack/smp/smp_act.cc
stack/smp/smp_api.cc
stack/smp/smp_utils.cc
stack/test/ad_parser_unittest.cc
stack/test/stack_a2dp_test.cc
stack/test/stack_btu_test.cc [new file with mode: 0644]
test/run_unit_tests.sh
test/suite/Android.bp
test/suite/AndroidTest.xml [new file with mode: 0644]
test/suite/core/thread_performance_test.cc [new file with mode: 0644]
tools/Android.bp [new file with mode: 0644]
tools/mcap_tool/Android.bp [new file with mode: 0644]
tools/mcap_tool/BUILD.gn [new file with mode: 0644]
tools/mcap_tool/mcap_test_app.cc [new file with mode: 0644]
tools/mcap_tool/mcap_test_app.h [new file with mode: 0644]
tools/mcap_tool/mcap_test_mcl.cc [new file with mode: 0644]
tools/mcap_tool/mcap_test_mcl.h [new file with mode: 0644]
tools/mcap_tool/mcap_test_mdep.cc [new file with mode: 0644]
tools/mcap_tool/mcap_test_mdep.h [new file with mode: 0644]
tools/mcap_tool/mcap_test_mdl.cc [new file with mode: 0644]
tools/mcap_tool/mcap_test_mdl.h [new file with mode: 0644]
tools/mcap_tool/mcap_tool.cc [new file with mode: 0644]

index 69ed54b..dae6460 100644 (file)
@@ -15,4 +15,5 @@ subdirs = [
     "vendor_libs",
     "test",
     "udrv",
+    "tools",
 ]
index 3cb29e1..618de1c 100644 (file)
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -39,3 +39,10 @@ group("bluetooth_tests") {
     "//device:net_test_device",
   ]
 }
+
+group("test_tools") {
+  testonly = true
+  deps = [
+    "//tools/mcap_tool:mcap_tool"
+  ]
+}
index 7dd98c1..1264b77 100644 (file)
@@ -627,6 +627,19 @@ void bta_ag_at_hsp_cback(tBTA_AG_SCB* p_scb, uint16_t command_id,
   (*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)
@@ -895,12 +908,16 @@ void bta_ag_at_hfp_cback(tBTA_AG_SCB* p_scb, uint16_t cmd, uint8_t arg_type,
       ** 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) &&
@@ -912,7 +929,11 @@ void bta_ag_at_hfp_cback(tBTA_AG_SCB* p_scb, uint16_t cmd, uint8_t arg_type,
       /* 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);
         }
index 886ed0c..ed8ee30 100644 (file)
@@ -387,7 +387,8 @@ static bool bta_av_next_getcap(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
       /* 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 @@ void bta_av_config_ind(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
 
   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 @@ void bta_av_setconfig_rsp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
     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 @@ void bta_av_str_opened(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
                    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 @@ void bta_av_str_opened(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
     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_security_cfm(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
  *
  ******************************************************************************/
 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 @@ void bta_av_save_caps(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
 
   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 @@ void bta_av_save_caps(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
     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 @@ void bta_av_getcap_results(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
   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 @@ void bta_av_getcap_results(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
     /* 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 @@ void bta_av_reconfig(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
   /* 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 @@ void bta_av_reconfig(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
     } 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 @@ void bta_av_suspend_cont(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
     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 @@ void bta_av_rcfg_open(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
     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 @@ void bta_av_rcfg_open(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
     /* 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);
   }
 }
 
index b6ca628..df082ae 100644 (file)
@@ -39,6 +39,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"
@@ -668,7 +669,9 @@ void bta_dm_process_remove_device(BD_ADDR bd_addr) {
   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;
@@ -851,7 +854,9 @@ void bta_dm_close_acl(tBTA_DM_MSG* p_data) {
     /* 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 */
 }
@@ -2618,9 +2623,14 @@ static uint8_t bta_dm_authentication_complete_cback(
     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);
     }
   }
@@ -3117,15 +3127,13 @@ void bta_dm_acl_change(tBTA_DM_MSG* p_data) {
       }
     }
     if (conn.link_down.is_removed) {
-      // p_bda points to security record, which is removed in
-      // BTM_SecDeleteDevice.
-      BD_ADDR addr_copy;
-      memcpy(addr_copy, p_bda, BD_ADDR_LEN);
-      BTM_SecDeleteDevice(addr_copy);
+      BTM_SecDeleteDevice(p_bda);
       /* need to remove all pending background connection */
-      BTA_GATTC_CancelOpen(0, addr_copy, false);
+      BTA_GATTC_CancelOpen(0, p_bda, false);
       /* remove all cached GATT information */
-      BTA_GATTC_Refresh(addr_copy);
+      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);
@@ -3298,7 +3306,9 @@ static void bta_dm_remove_sec_dev_entry(BD_ADDR remote_bd_addr) {
     /* 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);
   }
 }
 
index 787e11a..4202975 100644 (file)
@@ -434,9 +434,6 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = {
          {{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 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = {
          {{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 */
      }}
index aad921c..472b7e1 100644 (file)
@@ -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 @@ static void bta_dm_pm_ssr(BD_ADDR peer_addr);
 #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_stop_timer_by_srvc_id(BD_ADDR peer_addr,
 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 @@ static void bta_dm_pm_start_timer(tBTA_PM_TIMER* p_timer, uint8_t timer_idx,
     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 @@ static void bta_dm_pm_stop_timer_by_index(tBTA_PM_TIMER* p_timer,
                                           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 @@ static void bta_dm_pm_timer_cback(void* data) {
   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 @@ static void bta_dm_pm_timer_cback(void* data) {
       if (j < BTA_DM_PM_MODE_TIMER_MAX) break;
     }
   }
+  state_lock.unlock();
 
   /* no more timers */
   if (i == BTA_DM_NUM_PM_TIMER) return;
index 1a7c279..5d9a127 100644 (file)
@@ -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 @@ void bta_gattc_disable() {
   }
 }
 
-/*******************************************************************************
- *
- * 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 @@ void bta_gattc_register(tBT_UUID* p_app_uuid, tBTA_GATTC_CBACK* p_cback,
         /* 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 @@ void bta_gattc_register(tBT_UUID* p_app_uuid, tBTA_GATTC_CBACK* p_cback,
 
   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 @@ void bta_gattc_process_api_open_cancel(tBTA_GATTC_DATA* p_msg) {
   }
 }
 
-/*******************************************************************************
- *
- * 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 @@ static void bta_gattc_enc_cmpl_cback(tGATT_IF gattc_if, BD_ADDR bda) {
 
   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 @@ static void bta_gattc_enc_cmpl_cback(tGATT_IF gattc_if, BD_ADDR bda) {
  * 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 @@ void bta_gattc_process_api_refresh(tBTA_GATTC_DATA* p_msg) {
     }
   }
   /* used to reset cache in application */
-  bta_gattc_cache_reset(p_msg->api_conn.remote_bda);
+  bta_gattc_cache_reset(remote_bda.address);
 }
 /*******************************************************************************
  *
index 01f17c9..36fc36e 100644 (file)
@@ -60,10 +60,7 @@ void BTA_GATTC_Disable(void) {
     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 @@ void BTA_GATTC_AppRegister(tBTA_GATTC_CBACK* p_client_cb,
                                          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_AppRegister(tBTA_GATTC_CBACK* p_client_cb,
  *
  ******************************************************************************/
 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 @@ tBTA_GATT_STATUS BTA_GATTC_DeregisterForNotifications(tBTA_GATTC_IF client_if,
  * 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));
 }
index 07bae93..adcb62d 100644 (file)
@@ -1085,6 +1085,10 @@ void bta_gattc_fill_gatt_db_el(btgatt_db_element_t* p_attr,
   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);
 }
 
index 7a1158b..598262b 100644 (file)
@@ -51,18 +51,12 @@ enum {
   BTA_GATTC_API_SEARCH_EVT,
   BTA_GATTC_API_CONFIRM_EVT,
   BTA_GATTC_API_READ_MULTI_EVT,
-  BTA_GATTC_API_REFRESH_EVT,
 
   BTA_GATTC_INT_CONN_EVT,
   BTA_GATTC_INT_DISCOVER_EVT,
   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 @@ typedef uint16_t tBTA_GATTC_INT_EVT;
 /* 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 @@ typedef struct {
   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 @@ typedef union {
   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 bool bta_gattc_sm_execute(tBTA_GATTC_CLCB* p_clcb, uint16_t event,
 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 @@ extern void bta_gattc_send_open_cback(tBTA_GATTC_RCB* p_clreg,
                                       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);
index 16efce0..9a2deb6 100644 (file)
@@ -125,8 +125,6 @@ static const uint8_t bta_gattc_st_idle[][BTA_GATTC_NUM_COLS] = {
     /* BTA_GATTC_API_SEARCH_EVT         */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST},
     /* BTA_GATTC_API_CONFIRM_EVT        */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST},
     /* BTA_GATTC_API_READ_MULTI_EVT     */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST},
-    /* BTA_GATTC_API_REFRESH_EVT        */ {BTA_GATTC_IGNORE,
-                                            BTA_GATTC_IDLE_ST},
 
     /* BTA_GATTC_INT_CONN_EVT           */ {BTA_GATTC_CONN, BTA_GATTC_CONN_ST},
     /* BTA_GATTC_INT_DISCOVER_EVT       */ {BTA_GATTC_IGNORE,
@@ -169,8 +167,6 @@ static const uint8_t bta_gattc_st_w4_conn[][BTA_GATTC_NUM_COLS] = {
                                             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 @@ static const uint8_t bta_gattc_st_connected[][BTA_GATTC_NUM_COLS] = {
                                             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 @@ static const uint8_t bta_gattc_st_discover[][BTA_GATTC_NUM_COLS] = {
                                             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_sm_execute(tBTA_GATTC_CLCB* p_clcb, uint16_t event,
  ******************************************************************************/
 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 @@ bool bta_gattc_hdl_event(BT_HDR* p_msg) {
       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 @@ static char* gattc_evt_code(tBTA_GATTC_INT_EVT evt_code) {
       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:
index 40f274a..fb8581e 100644 (file)
@@ -959,7 +959,7 @@ extern void BTA_GATTC_ReadMultiple(uint16_t conn_id,
  * Returns          void
  *
  ******************************************************************************/
-extern void BTA_GATTC_Refresh(const BD_ADDR remote_bda);
+extern void BTA_GATTC_Refresh(const bt_bdaddr_t& remote_bda);
 
 /*******************************************************************************
  *
index 74c5146..fe63ba5 100644 (file)
@@ -171,25 +171,31 @@ static void bta_pan_data_flow_cb(uint16_t handle, tPAN_RESULT result) {
 static void bta_pan_data_buf_ind_cback(uint16_t handle, BD_ADDR src,
                                        BD_ADDR dst, uint16_t protocol,
                                        BT_HDR* p_buf, bool ext, bool forward) {
-  tBTA_PAN_SCB* p_scb = bta_pan_scb_by_handle(handle);
+  tBTA_PAN_SCB* p_scb;
+  BT_HDR* p_new_buf;
+
+  p_scb = bta_pan_scb_by_handle(handle);
   if (p_scb == NULL) {
     return;
   }
 
-  if (sizeof(BT_HDR) + sizeof(tBTA_PAN_DATA_PARAMS) + p_buf->len >
-      PAN_BUF_SIZE) {
-    android_errorWriteLog(0x534e4554, "63146237");
-    APPL_TRACE_ERROR("%s: received buffer length too large: %d", __func__,
-                     p_buf->len);
-    return;
+  if (sizeof(tBTA_PAN_DATA_PARAMS) > p_buf->offset) {
+    /* offset smaller than data structure in front of actual data */
+    if (sizeof(BT_HDR) + sizeof(tBTA_PAN_DATA_PARAMS) + p_buf->len >
+        PAN_BUF_SIZE) {
+      android_errorWriteLog(0x534e4554, "63146237");
+      APPL_TRACE_ERROR("%s: received buffer length too large: %d", __func__,
+                       p_buf->len);
+      return;
+    }
+    p_new_buf = (BT_HDR*)osi_malloc(PAN_BUF_SIZE);
+    memcpy((uint8_t*)(p_new_buf + 1) + sizeof(tBTA_PAN_DATA_PARAMS),
+           (uint8_t*)(p_buf + 1) + p_buf->offset, p_buf->len);
+    p_new_buf->len = p_buf->len;
+    p_new_buf->offset = sizeof(tBTA_PAN_DATA_PARAMS);
+  } else {
+    p_new_buf = p_buf;
   }
-
-  BT_HDR* p_new_buf = (BT_HDR*)osi_malloc(PAN_BUF_SIZE);
-  memcpy((uint8_t*)(p_new_buf + 1) + sizeof(tBTA_PAN_DATA_PARAMS),
-         (uint8_t*)(p_buf + 1) + p_buf->offset, p_buf->len);
-  p_new_buf->len = p_buf->len;
-  p_new_buf->offset = sizeof(tBTA_PAN_DATA_PARAMS);
-
   /* copy params into the space before the data */
   bdcpy(((tBTA_PAN_DATA_PARAMS*)p_new_buf)->src, src);
   bdcpy(((tBTA_PAN_DATA_PARAMS*)p_new_buf)->dst, dst);
index 32985e8..6386539 100644 (file)
@@ -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 @@ bool bta_sys_is_register(uint8_t id) { return bta_sys_cb.is_reg[id]; }
  *                  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 @@ void bta_sys_start_timer(alarm_t* alarm, period_ms_t interval, uint16_t event,
 
   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);
 }
index 6e058d2..442cc60 100644 (file)
@@ -34,6 +34,7 @@ cc_library_static {
 // ========================================================
 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 (file)
index 0000000..be321c5
--- /dev/null
@@ -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
index b455e90..c94b767 100644 (file)
@@ -119,3 +119,25 @@ cc_test {
     ],
     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"],
+}
index 76b0199..687499a 100644 (file)
@@ -395,6 +395,7 @@ tA2DP_STATUS bta_av_co_audio_getconfig(tBTA_AV_HNDL hndl, uint8_t* p_codec_info,
   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 @@ void bta_av_co_audio_setconfig(tBTA_AV_HNDL hndl, const uint8_t* p_codec_info,
   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 @@ static void bta_av_co_save_new_codec_config(tBTA_AV_CO_PEER* p_peer,
                                             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 @@ bool bta_av_co_set_codec_user_config(
       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 @@ static bool bta_av_co_set_codec_ota_config(tBTA_AV_CO_PEER* p_peer,
   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 @@ static bool bta_av_co_set_codec_ota_config(tBTA_AV_CO_PEER* p_peer,
   }
 
   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 @@ bool bta_av_co_set_codec_audio_config(
     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) {
index 01aa8f0..fca75f3 100644 (file)
@@ -33,6 +33,7 @@ typedef bt_status_t (*btif_connect_cb_t)(bt_bdaddr_t* bda, uint16_t uuid);
 
 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();
index 6104370..fbe3d07 100644 (file)
  ******************************************************************************/
 
 #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 @@ static void btif_a2dp_source_audio_handle_timer(UNUSED_ATTR void* context) {
 
   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);
     }
index 9d4ddb6..34780ad 100644 (file)
@@ -1430,6 +1430,7 @@ static void cleanup(int service_uuid) {
 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);
@@ -1439,6 +1440,7 @@ static void cleanup_src(void) {
 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);
index a37b095..3c02882 100644 (file)
@@ -103,8 +103,15 @@ class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface {
   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 {
index 3b3dc4f..f6faa7d 100644 (file)
@@ -231,8 +231,10 @@ static future_t* clean_up(void) {
   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);
 }
index 2685027..3aa56d2 100644 (file)
@@ -2051,7 +2051,7 @@ static void bte_search_devices_evt(tBTA_DM_SEARCH_EVT event,
    * 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: {
@@ -2933,7 +2933,7 @@ static void btif_dm_ble_auth_cmpl_evt(tBTA_DM_AUTH_CMPL* p_auth_cmpl) {
       state = BT_BOND_STATE_NONE;
     } else {
       btif_dm_save_ble_bonding_keys(bdaddr);
-      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 {
index 70b7d4e..e0636ff 100644 (file)
@@ -255,7 +255,8 @@ bt_status_t btif_gattc_unregister_app(int client_if) {
 }
 
 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 @@ void btif_gattc_open_impl(int client_if, BD_ADDR address, bool is_direct,
   }
 
   // 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 @@ bt_status_t btif_gattc_open(int client_if, const bt_bdaddr_t* bd_addr,
   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_close(int client_if, const bt_bdaddr_t* bd_addr,
 
 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 @@ void read_char_cb(uint16_t conn_id, tGATT_STATUS status, uint16_t handle,
   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 @@ void read_using_char_uuid_cb(uint16_t conn_id, tGATT_STATUS status,
   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 @@ void read_desc_cb(uint16_t conn_id, tGATT_STATUS status, uint16_t handle,
   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,
index ec7007d..765ad21 100644 (file)
@@ -33,7 +33,6 @@
 
 #include <hardware/bluetooth.h>
 #include <hardware/bt_hf.h>
-#include <log/log.h>
 
 #include "bta/include/utl.h"
 #include "bta_ag_api.h"
@@ -667,7 +666,7 @@ static void btif_in_hf_generic_evt(uint16_t event, char* p_param) {
 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;
@@ -1198,20 +1197,13 @@ static bt_status_t clcc_response(int index, bthf_call_direction_t dir,
           dialnum[newidx++] = '+';
         }
         for (size_t i = 0; number[i] != 0; i++) {
-          if (newidx >= (sizeof(dialnum) - res_strlen - 1)) {
-            android_errorWriteLog(0x534e4554, "79266386");
-            break;
-          }
           if (utl_isdialchar(number[i])) {
             dialnum[newidx++] = number[i];
           }
         }
         dialnum[newidx] = 0;
-        // Reserve 5 bytes for ["][,][3_digit_type]
-        snprintf(&ag_res.str[res_strlen], rem_bytes - 5, ",\"%s", dialnum);
-        std::stringstream remaining_string;
-        remaining_string << "\"," << type;
-        strncat(&ag_res.str[res_strlen], remaining_string.str().c_str(), 5);
+        snprintf(&ag_res.str[res_strlen], rem_bytes, ",\"%s\",%d", dialnum,
+                 type);
       }
     }
     BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_CLCC_RES, &ag_res);
@@ -1364,13 +1356,6 @@ static bt_status_t phone_state_change(int num_active, int num_held,
           else
             xx = snprintf(ag_res.str, sizeof(ag_res.str), "\"%s\"", number);
           ag_res.num = type;
-          // 5 = [,][3_digit_type][null_terminator]
-          if (xx > static_cast<int>(sizeof(ag_res.str) - 5)) {
-            android_errorWriteLog(0x534e4554, "79431031");
-            xx = sizeof(ag_res.str) - 5;
-            // Null terminating the string
-            memset(&ag_res.str[xx], 0, 5);
-          }
 
           if (res == BTA_AG_CALL_WAIT_RES)
             snprintf(&ag_res.str[xx], sizeof(ag_res.str) - xx, ",%d", type);
@@ -1508,6 +1493,7 @@ bool btif_hf_call_terminated_recently() {
 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);
index 3b86aaa..0de1c7e 100644 (file)
@@ -708,6 +708,7 @@ static bt_status_t request_last_voice_tag_number(const bt_bdaddr_t* bd_addr) {
 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;
index b60c8c8..eac9eeb 100644 (file)
@@ -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 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) {
       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 @@ static void btif_hh_upstreams_evt(uint16_t event, char* p_param) {
           "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 @@ static bt_status_t virtual_unplug(bt_bdaddr_t* bd_addr) {
 }
 
 /*******************************************************************************
+**
+** 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 void cleanup(void) {
 }
 
 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,
 };
 
 /*******************************************************************************
index 1346092..d5061d6 100644 (file)
@@ -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 const size_t MAX_REASONABLE_REQUESTS = 10;
 
 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 @@ static void queue_int_add(connect_node_t* p_param) {
   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 @@ static void queue_int_advance() {
     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 @@ static void queue_int_handle_evt(uint16_t event, char* p_param) {
     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 @@ bt_status_t btif_queue_connect(uint16_t uuid, const bt_bdaddr_t* bda,
 
 /*******************************************************************************
  *
+ * 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 @@ bt_status_t btif_queue_connect_next(void) {
 
   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 @@ bt_status_t btif_queue_connect_next(void) {
  *
  ******************************************************************************/
 void btif_queue_release() {
+  LOG_INFO(LOG_TAG, "%s", __func__);
   list_free(connect_queue);
   connect_queue = NULL;
 }
index ad9116d..2e33842 100644 (file)
@@ -1890,32 +1890,6 @@ static bt_status_t get_element_attr_rsp(bt_bdaddr_t* bd_addr, uint8_t num_attr,
 
 /***************************************************************************
  *
- * 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.
@@ -1998,22 +1972,6 @@ static bt_status_t register_notification_rsp(
         ((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;
 }
index 21b2c0b..afbfab4 100644 (file)
@@ -127,7 +127,7 @@ static bool create_base_record(const uint32_t sdp_handle, const char* name,
   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;
   }
 
index d45790b..c8dfcde 100644 (file)
@@ -35,7 +35,6 @@
 #include <alloca.h>
 #include <base/logging.h>
 #include <ctype.h>
-#include <log/log.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
@@ -780,46 +779,6 @@ bt_status_t btif_storage_remove_bonded_device(bt_bdaddr_t* remote_bd_addr) {
   return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
 }
 
-/* Some devices hardcode sample LTK value from spec, instead of generating one.
- * Treat such devices as insecure, and remove such bonds when bluetooth
- * restarts. Removing them after disconnection is handled separately.
- *
- * We still allow such devices to bond in order to give the user a chance to
- * update firmware.
- */
-static void remove_devices_with_sample_ltk() {
-  std::vector<bt_bdaddr_t> bad_ltk;
-  for (const btif_config_section_iter_t* iter = btif_config_section_begin();
-       iter != btif_config_section_end();
-       iter = btif_config_section_next(iter)) {
-    const char* name = btif_config_section_name(iter);
-    if (!string_is_bdaddr(name)) {
-      continue;
-    }
-
-    bt_bdaddr_t bda;
-    string_to_bdaddr(name, &bda);
-
-    tBTA_LE_KEY_VALUE key;
-    memset(&key, 0, sizeof(key));
-
-    if (btif_storage_get_ble_bonding_key(&bda, BTIF_DM_LE_KEY_PENC, (char*)&key,
-                                         sizeof(tBTM_LE_PENC_KEYS)) ==
-        BT_STATUS_SUCCESS) {
-      if (is_sample_ltk(key.penc_key.ltk)) {
-        bad_ltk.push_back(bda);
-      }
-    }
-  }
-
-  for (bt_bdaddr_t address : bad_ltk) {
-    android_errorWriteLog(0x534e4554, "128437297");
-    LOG(ERROR) << __func__ << ": removing bond to device using test TLK";
-
-    btif_storage_remove_bonded_device(&address);
-  }
-}
-
 /*******************************************************************************
  *
  * Function         btif_storage_load_bonded_devices
@@ -847,8 +806,6 @@ bt_status_t btif_storage_load_bonded_devices(void) {
   bt_uuid_t remote_uuids[BT_MAX_NUM_UUIDS];
   bt_status_t status;
 
-  remove_devices_with_sample_ltk();
-
   btif_in_fetch_bonded_devices(&bonded_devices, 1);
 
   /* Now send the adapter_properties_cb with all adapter_properties */
diff --git a/btif/test/btif_profile_queue_test.cc b/btif/test/btif_profile_queue_test.cc
new file mode 100644 (file)
index 0000000..199844e
--- /dev/null
@@ -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);
+}
index fc58cb6..d0d94b2 100644 (file)
@@ -201,6 +201,20 @@ source_set("base_sources") {
     "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 @@ source_set("base_sources") {
     "//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 @@ config("libchrome_config") {
   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 @@ static_library("base") {
     "-levent",
     "-levent_core",
     "-lpthread",
+    "-ldbus-1",
   ]
 
   public_configs = [ ":libchrome_config" ]
index 8641434..856cdc4 100644 (file)
@@ -53,17 +53,17 @@ TRC_HID_DEV=2
 #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
 
index c8cc772..e7dd2d0 100644 (file)
@@ -27,6 +27,7 @@ cc_library_static {
 // ========================================================
 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 (file)
index 0000000..45a7e51
--- /dev/null
@@ -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
index a3b252b..ec2067a 100644 (file)
@@ -79,6 +79,17 @@ typedef enum {
   // 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
index 36a8ae2..7f4f229 100644 (file)
@@ -67,9 +67,19 @@ static const interop_addr_entry_t interop_addr_database[] = {
     {{{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 @@ static const interop_addr_entry_t interop_addr_database[] = {
     // 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 {
index e2af13d..1076bbf 100644 (file)
@@ -253,10 +253,6 @@ static future_t* start_up(void) {
         response, &number_of_local_supported_codecs, local_supported_codecs);
   }
 
-  if (!HCI_READ_ENCR_KEY_SIZE_SUPPORTED(supported_commands)) {
-    LOG(FATAL) << " Controller must support Read Encryption Key Size command";
-  }
-
   readable = true;
   return future_new_immediate(FUTURE_SUCCESS);
 }
index c6b5062..8e36181 100644 (file)
@@ -127,6 +127,8 @@ static const char* interop_feature_string_(const interop_feature_t feature) {
     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";
index a2bf907..4edcfee 100644 (file)
@@ -44,6 +44,7 @@ cc_library_static {
 // ========================================================
 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 (file)
index 0000000..b7c1e64
--- /dev/null
@@ -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
index e44c0ae..acb86de 100644 (file)
 
 #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 @@ typedef void (*command_status_cb)(uint8_t status, BT_HDR* command,
                                   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 @@ typedef struct hci_t {
   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 hci_t* hci_layer_get_test_interface(
     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();
index d13b671..563379f 100644 (file)
@@ -108,7 +108,8 @@ static list_t* commands_pending_response;
 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 @@ void initialization_complete() {
       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 @@ EXPORT_SYMBOL extern const module_t hci_module = {
 
 // 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 @@ static future_t* transmit_command_futured(BT_HDR* command) {
   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 @@ static void fragmenter_transmit_finished(BT_HDR* packet,
     // 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 @@ intercepted:
 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 @@ static void init_layer_interface() {
   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 @@ static void init_layer_interface() {
 
 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;
index dff6bfa..ce4f42c 100644 (file)
@@ -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::Void;
 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 @@ class BluetoothHciCallbacks : public IBluetoothHciCallbacks {
 
   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();
   }
 
index 51d8429..aa37f78 100644 (file)
@@ -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 @@ enum HciPacketType {
 };
 
 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 @@ void monitor_socket(int ctrl_fd, int fd) {
     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 @@ void monitor_socket(int ctrl_fd, int fd) {
         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;
index 05b5ff1..eadfc92 100644 (file)
 #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
 #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
index e89299a..900e41b 100644 (file)
@@ -55,7 +55,6 @@ static const char BTE_LOGMSG_MODULE[] = "bte_logmsg_module";
 #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 @@ static const char BTE_LOGMSG_MODULE[] = "bte_logmsg_module";
 #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 @@ static const char BTE_LOGMSG_MODULE[] = "bte_logmsg_module";
       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(...)                                     \
   {                                                               \
index 42c2db8..80a5372 100644 (file)
@@ -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 @@ static tBTTRC_FUNC_MAP bttrc_set_level_map[] = {
     {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},
index 58e44fd..527d93e 100644 (file)
@@ -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>
 static const hci_t* hci;
 
 /*******************************************************************************
- *  Static functions
+ *  Externs
  ******************************************************************************/
+extern void btu_hci_msg_process(BT_HDR* p_msg);
 
 /*******************************************************************************
- *  Externs
+ *  Static functions
  ******************************************************************************/
-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 @@ void bte_main_boot_entry(void) {
     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_boot_entry(void) {
  *
  *****************************************************************************/
 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));
index f11b6f7..b93593c 100644 (file)
@@ -64,7 +64,6 @@ cc_library_static {
         "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_library_static {
 // ========================================================
 cc_test {
     name: "net_test_osi",
+    test_suites: ["device-tests"],
     defaults: ["fluoride_osi_defaults"],
     host_supported: true,
     srcs: [
@@ -118,7 +118,6 @@ cc_test {
         "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 (file)
index 0000000..a64158c
--- /dev/null
@@ -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
index 92a8a2a..daecda4 100644 (file)
@@ -23,7 +23,6 @@ static_library("osi") {
     "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 @@ executable("net_test_osi") {
     "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 (file)
index 7c231f8..0000000
+++ /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 (file)
index 385f395..0000000
+++ /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 (file)
index cc7d78d..0000000
+++ /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);
-}
index 4c6d018..83761c9 100644 (file)
@@ -137,6 +137,7 @@ cc_binary {
 // ========================================================
 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 (file)
index 0000000..d16e371
--- /dev/null
@@ -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
index e156c72..ba49728 100644 (file)
@@ -35,6 +35,8 @@ source_set("service") {
     "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",
index bc022d2..48d098c 100644 (file)
@@ -86,10 +86,20 @@ class DaemonImpl : public Daemon {
         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;
   }
index 1250e85..dba1f57 100644 (file)
@@ -41,7 +41,8 @@ bt_status_t FakeUnregisterClient(int client_if) {
 }
 
 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 (file)
index 0000000..171fef0
--- /dev/null
@@ -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 (file)
index 0000000..1d8dd8f
--- /dev/null
@@ -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 (file)
index 0000000..ff7ff43
--- /dev/null
@@ -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 (file)
index 0000000..03f7720
--- /dev/null
@@ -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 (file)
index 0000000..4a718e6
--- /dev/null
@@ -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
index 74c53bc..71dc6c7 100644 (file)
@@ -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 @@ IPCManager::~IPCManager() {
   // 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 @@ bool IPCManager::Start(Type type, Delegate* delegate) {
         return false;
       }
       return true;
+
 #if !defined(OS_GENERIC)
     case TYPE_BINDER:
       if (BinderStarted()) {
@@ -61,7 +65,21 @@ bool IPCManager::Start(Type type, Delegate* delegate) {
         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::BinderStarted() const { return binder_handler_.get(); }
 
 bool IPCManager::LinuxStarted() const { return linux_handler_.get(); }
 
+bool IPCManager::DBusStarted() const { return dbus_handler_.get(); }
+
 }  // namespace ipc
index c0ade0e..bf0967c 100644 (file)
@@ -37,8 +37,9 @@ class IPCManager {
  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 @@ class IPCManager {
   // 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 @@ class IPCManager {
   // 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.
index 3e56624..ed1cf46 100644 (file)
@@ -59,7 +59,7 @@ bool LowEnergyClient::Connect(const std::string& address, bool is_direct) {
 
   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;
index 58c8fe9..f5ec040 100644 (file)
@@ -99,10 +99,8 @@ cc_library_static {
         "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 @@ cc_test {
     srcs: ["test/stack_a2dp_test.cc"],
     shared_libs: [
         "liblog",
+        "libcutils",
     ],
     static_libs: [
         "libbt-stack",
@@ -289,3 +288,34 @@ cc_test {
         "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",
+    ],
+}
index 87535d4..0be4333 100644 (file)
@@ -78,10 +78,8 @@ static_library("stack") {
     "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",
index 8c0927d..7027df7 100644 (file)
@@ -369,22 +369,6 @@ int A2DP_GetTrackSampleRateAac(const uint8_t* p_codec_info) {
   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 @@ bool A2DP_BuildCodecHeaderAac(UNUSED_ATTR const uint8_t* p_codec_info,
   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 @@ void A2DP_DumpCodecInfoAac(const uint8_t* p_codec_info) {
   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 @@ void A2DP_DumpCodecInfoAac(const uint8_t* p_codec_info) {
             (aac_cie.variableBitRateSupport != 0) ? "true" : "false");
 
   LOG_DEBUG(LOG_TAG, "\tbitRate: %u", aac_cie.bitRate);
+
+  return true;
 }
 
 const tA2DP_ENCODER_INTERFACE* A2DP_GetEncoderInterfaceAac(
index 9c69588..6c79149 100644 (file)
 // 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 @@ static void a2dp_aac_encoder_update(uint16_t peer_mtu,
       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;
index a52924a..11d3bf2 100644 (file)
@@ -377,3 +377,5 @@ void A2DP_Init(void) {
   a2dp_cb.trace_level = BT_TRACE_LEVEL_NONE;
 #endif
 }
+
+uint16_t A2DP_GetAvdtpVersion() { return a2dp_cb.avdt_sdp_ver; }
index e5f06d6..0bf5985 100644 (file)
@@ -1053,26 +1053,6 @@ int A2DP_GetTrackSampleRate(const uint8_t* p_codec_info) {
   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 @@ bool A2DP_InitCodecConfig(btav_a2dp_codec_index_t codec_index,
 
   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;
+}
index f3918dd..ce3934a 100644 (file)
@@ -54,9 +54,10 @@ typedef struct {
 
 /* 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 @@ int A2DP_GetTrackSampleRateSbc(const uint8_t* p_codec_info) {
   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 @@ bool A2DP_BuildCodecHeaderSbc(UNUSED_ATTR const uint8_t* p_codec_info,
   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 @@ void A2DP_DumpCodecInfoSbc(const uint8_t* p_codec_info) {
   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 @@ void A2DP_DumpCodecInfoSbc(const uint8_t* p_codec_info) {
 
   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(
index 939a68a..e4c2049 100644 (file)
@@ -217,7 +217,7 @@ static void a2dp_sbc_encoder_update(uint16_t peer_mtu,
   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 @@ static uint8_t calculate_max_frames_per_packet(void) {
 
   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) {
index e1d88b1..f0fc277 100644 (file)
@@ -313,32 +313,6 @@ int A2DP_VendorGetTrackSampleRate(const uint8_t* p_codec_info) {
   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 @@ bool A2DP_VendorInitCodecConfig(btav_a2dp_codec_index_t codec_index,
 
   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;
+}
index 10e15bc..9d4d0e1 100644 (file)
@@ -296,20 +296,6 @@ int A2DP_VendorGetTrackSampleRateAptx(const uint8_t* p_codec_info) {
   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 @@ bool A2DP_VendorBuildCodecHeaderAptx(UNUSED_ATTR const uint8_t* p_codec_info,
   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 @@ void A2DP_VendorDumpCodecInfoAptx(const uint8_t* p_codec_info) {
   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 @@ void A2DP_VendorDumpCodecInfoAptx(const uint8_t* p_codec_info) {
   if (aptx_cie.channelMode & A2DP_APTX_CHANNELS_STEREO) {
     LOG_DEBUG(LOG_TAG, "\tch_mode: (Stereo)");
   }
+
+  return true;
 }
 
 const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterfaceAptx(
index 4c8554d..3fcb6de 100644 (file)
@@ -257,7 +257,7 @@ static void a2dp_vendor_aptx_encoder_update(uint16_t peer_mtu,
   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",
index 919aef1..9002729 100644 (file)
@@ -311,21 +311,6 @@ int A2DP_VendorGetTrackSampleRateAptxHd(const uint8_t* p_codec_info) {
   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 @@ bool A2DP_VendorBuildCodecHeaderAptxHd(UNUSED_ATTR const uint8_t* p_codec_info,
   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 @@ void A2DP_VendorDumpCodecInfoAptxHd(const uint8_t* p_codec_info) {
   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 @@ void A2DP_VendorDumpCodecInfoAptxHd(const uint8_t* p_codec_info) {
   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(
index d35d872..084291f 100644 (file)
@@ -258,7 +258,7 @@ static void a2dp_vendor_aptx_hd_encoder_update(
   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",
index e822a2f..08d4362 100644 (file)
@@ -330,30 +330,6 @@ int A2DP_VendorGetTrackSampleRateLdac(const uint8_t* p_codec_info) {
   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 @@ bool A2DP_VendorBuildCodecHeaderLdac(UNUSED_ATTR const uint8_t* p_codec_info,
   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 @@ void A2DP_VendorDumpCodecInfoLdac(const uint8_t* p_codec_info) {
   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 @@ void A2DP_VendorDumpCodecInfoLdac(const uint8_t* p_codec_info) {
   if (ldac_cie.channelMode & A2DP_LDAC_CHANNEL_MODE_STEREO) {
     LOG_DEBUG(LOG_TAG, "\tch_mode: (Stereo)");
   }
+
+  return true;
 }
 
 const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterfaceLdac(
index 68deea8..47f7764 100644 (file)
  */
 
 #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 @@ void a2dp_vendor_ldac_send_frames(uint64_t timestamp_us) {
                              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);
index bf45ad3..5369f6e 100644 (file)
@@ -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_Deregister(void) {
 }
 
 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 AVDT_CreateStream(uint8_t* p_handle, tAVDT_CS* p_cs) {
   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 @@ uint16_t AVDT_CreateStream(uint8_t* p_handle, tAVDT_CS* p_cs) {
       *p_handle = avdt_scb_to_hdl(p_scb);
     }
   }
+
+  AVDT_TRACE_DEBUG("%s: result=%d", __func__, result);
+
   return result;
 }
 
@@ -198,6 +204,8 @@ uint16_t AVDT_RemoveStream(uint8_t handle) {
   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 @@ uint16_t AVDT_RemoveStream(uint8_t handle) {
     /* 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 AVDT_DiscoverReq(BD_ADDR bd_addr, tAVDT_SEP_INFO* p_sep_info,
   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 @@ uint16_t AVDT_DiscoverReq(BD_ADDR bd_addr, tAVDT_SEP_INFO* p_sep_info,
       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 @@ static uint16_t avdt_get_cap_req(BD_ADDR bd_addr, tAVDT_CCB_API_GETCAP* p_evt) {
   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 @@ static uint16_t avdt_get_cap_req(BD_ADDR bd_addr, tAVDT_CCB_API_GETCAP* p_evt) {
       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 @@ static uint16_t avdt_get_cap_req(BD_ADDR bd_addr, tAVDT_CCB_API_GETCAP* p_evt) {
 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_GetCapReq(BD_ADDR bd_addr, uint8_t seid, tAVDT_CFG* p_cfg,
 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 AVDT_DelayReport(uint8_t handle, uint8_t seid, uint16_t delay) {
   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 @@ uint16_t AVDT_DelayReport(uint8_t handle, uint8_t seid, uint16_t delay) {
     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 AVDT_OpenReq(uint8_t handle, BD_ADDR bd_addr, uint8_t seid,
   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 @@ uint16_t AVDT_OpenReq(uint8_t handle, BD_ADDR bd_addr, uint8_t seid,
 
   /* 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 AVDT_ConfigRsp(uint8_t handle, uint8_t label, uint8_t error_code,
   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 @@ uint16_t AVDT_ConfigRsp(uint8_t handle, uint8_t label, uint8_t error_code,
     avdt_scb_event(p_scb, event_code, &evt);
   }
 
+  AVDT_TRACE_DEBUG("%s: result=%d", __func__, result);
+
   return result;
 }
 
@@ -535,6 +587,8 @@ uint16_t AVDT_StartReq(uint8_t* p_handles, uint8_t num_handles) {
   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 @@ uint16_t AVDT_StartReq(uint8_t* p_handles, uint8_t num_handles) {
       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 AVDT_SuspendReq(uint8_t* p_handles, uint8_t num_handles) {
   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 @@ uint16_t AVDT_SuspendReq(uint8_t* p_handles, uint8_t num_handles) {
     }
   }
 
+  AVDT_TRACE_DEBUG("%s: result=%d", __func__, result);
+
   return result;
 }
 
@@ -627,6 +688,8 @@ uint16_t AVDT_CloseReq(uint8_t handle) {
   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 @@ uint16_t AVDT_CloseReq(uint8_t handle) {
     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 AVDT_ReconfigReq(uint8_t handle, tAVDT_CFG* p_cfg) {
   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 @@ uint16_t AVDT_ReconfigReq(uint8_t handle, tAVDT_CFG* p_cfg) {
   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 @@ uint16_t AVDT_ReconfigRsp(uint8_t handle, uint8_t label, uint8_t error_code,
   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 @@ uint16_t AVDT_ReconfigRsp(uint8_t handle, uint8_t label, uint8_t error_code,
     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 AVDT_SecurityReq(uint8_t handle, uint8_t* p_data, uint16_t len) {
   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 @@ uint16_t AVDT_SecurityReq(uint8_t handle, uint8_t* p_data, uint16_t len) {
     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 AVDT_SecurityRsp(uint8_t handle, uint8_t label, uint8_t error_code,
   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 @@ uint16_t AVDT_SecurityRsp(uint8_t handle, uint8_t label, uint8_t error_code,
     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 @@ uint16_t AVDT_WriteReqOpt(uint8_t handle, BT_HDR* p_pkt, uint32_t time_stamp,
   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 @@ uint16_t AVDT_WriteReqOpt(uint8_t handle, BT_HDR* p_pkt, uint32_t time_stamp,
     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 AVDT_ConnectReq(BD_ADDR bd_addr, uint8_t sec_mask,
   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 @@ uint16_t AVDT_ConnectReq(BD_ADDR bd_addr, uint8_t sec_mask,
     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 AVDT_DisconnectReq(BD_ADDR bd_addr, tAVDT_CTRL_CBACK* p_cback) {
   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 @@ uint16_t AVDT_DisconnectReq(BD_ADDR bd_addr, tAVDT_CTRL_CBACK* p_cback) {
     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 @@ uint16_t AVDT_SendReport(uint8_t handle, AVDT_REPORT_TYPE type,
   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 @@ uint16_t AVDT_SendReport(uint8_t handle, AVDT_REPORT_TYPE type,
     }
   }
 
+  AVDT_TRACE_DEBUG("%s: result=%d", __func__, result);
+
   return result;
 }
 #endif
index c1f1469..a9ca128 100644 (file)
@@ -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 @@ const char* const avdt_ccb_evt_str[] = {
     "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 @@ void avdt_ccb_event(tAVDT_CCB* p_ccb, uint8_t event, tAVDT_CCB_EVT* p_data) {
   /* 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 {
index 943855f..9347646 100644 (file)
@@ -486,6 +486,8 @@ void avdt_ccb_snd_start_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
   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 @@ void avdt_ccb_snd_start_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
       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 @@ void avdt_ccb_snd_start_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
     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);
       }
index 21d9251..c44a5a2 100644 (file)
@@ -23,7 +23,6 @@
  *
  ******************************************************************************/
 
-#include <cutils/log.h>
 #include <string.h>
 #include "a2dp_codec_api.h"
 #include "avdt_api.h"
@@ -234,14 +233,10 @@ void avdt_scb_hdl_pkt_no_frag(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
   uint16_t offset;
   uint16_t ex_len;
   uint8_t pad_len = 0;
-  uint16_t len = p_data->p_pkt->len;
 
   p = p_start = (uint8_t*)(p_data->p_pkt + 1) + p_data->p_pkt->offset;
 
   /* parse media packet header */
-  offset = 12;
-  // AVDT_MSG_PRS_OCTET1(1) + AVDT_MSG_PRS_M_PT(1) + UINT16(2) + UINT32(4) + 4
-  if (offset > len) goto length_error;
   AVDT_MSG_PRS_OCTET1(p, o_v, o_p, o_x, o_cc);
   AVDT_MSG_PRS_M_PT(p, m_pt, marker);
   BE_STREAM_TO_UINT16(seq, p);
@@ -249,19 +244,18 @@ void avdt_scb_hdl_pkt_no_frag(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
   p += 4;
 
   /* skip over any csrc's in packet */
-  offset += o_cc * 4;
   p += o_cc * 4;
 
   /* check for and skip over extension header */
   if (o_x) {
-    offset += 4;
-    if (offset > len) goto length_error;
     p += 2;
     BE_STREAM_TO_UINT16(ex_len, p);
-    offset += ex_len * 4;
     p += ex_len * 4;
   }
 
+  /* save our new offset */
+  offset = (uint16_t)(p - p_start);
+
   /* adjust length for any padding at end of packet */
   if (o_p) {
     /* padding length in last byte of packet */
@@ -289,12 +283,6 @@ void avdt_scb_hdl_pkt_no_frag(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
       osi_free_and_reset((void**)&p_data->p_pkt);
     }
   }
-  return;
-length_error:
-  android_errorWriteLog(0x534e4554, "111450156");
-  AVDT_TRACE_WARNING("%s: hdl packet length %d too short: must be at least %d",
-                     __func__, len, offset);
-  osi_free_and_reset((void**)&p_data->p_pkt);
 }
 
 #if (AVDT_REPORTING == TRUE)
@@ -312,7 +300,6 @@ uint8_t* avdt_scb_hdl_report(tAVDT_SCB* p_scb, uint8_t* p, uint16_t len) {
   uint8_t* p_start = p;
   uint32_t ssrc;
   uint8_t o_v, o_p, o_cc;
-  uint16_t min_len = 0;
   AVDT_REPORT_TYPE pt;
   tAVDT_REPORT_DATA report, *p_rpt;
 
@@ -320,14 +307,6 @@ uint8_t* avdt_scb_hdl_report(tAVDT_SCB* p_scb, uint8_t* p, uint16_t len) {
   if (p_scb->cs.p_report_cback) {
     p_rpt = &report;
     /* parse report packet header */
-    min_len += 8;
-    if (min_len > len) {
-      android_errorWriteLog(0x534e4554, "111450156");
-      AVDT_TRACE_WARNING(
-          "%s: hdl packet length %d too short: must be at least %d", __func__,
-          len, min_len);
-      goto avdt_scb_hdl_report_exit;
-    }
     AVDT_MSG_PRS_RPT_OCTET1(p, o_v, o_p, o_cc);
     pt = *p++;
     p += 2;
@@ -335,14 +314,6 @@ uint8_t* avdt_scb_hdl_report(tAVDT_SCB* p_scb, uint8_t* p, uint16_t len) {
 
     switch (pt) {
       case AVDT_RTCP_PT_SR: /* the packet type - SR (Sender Report) */
-        min_len += 20;
-        if (min_len > len) {
-          android_errorWriteLog(0x534e4554, "111450156");
-          AVDT_TRACE_WARNING(
-              "%s: hdl packet length %d too short: must be at least %d",
-              __func__, len, min_len);
-          goto avdt_scb_hdl_report_exit;
-        }
         BE_STREAM_TO_UINT32(report.sr.ntp_sec, p);
         BE_STREAM_TO_UINT32(report.sr.ntp_frac, p);
         BE_STREAM_TO_UINT32(report.sr.rtp_time, p);
@@ -351,14 +322,6 @@ uint8_t* avdt_scb_hdl_report(tAVDT_SCB* p_scb, uint8_t* p, uint16_t len) {
         break;
 
       case AVDT_RTCP_PT_RR: /* the packet type - RR (Receiver Report) */
-        min_len += 20;
-        if (min_len > len) {
-          android_errorWriteLog(0x534e4554, "111450156");
-          AVDT_TRACE_WARNING(
-              "%s: hdl packet length %d too short: must be at least %d",
-              __func__, len, min_len);
-          goto avdt_scb_hdl_report_exit;
-        }
         report.rr.frag_lost = *p;
         BE_STREAM_TO_UINT32(report.rr.packet_lost, p);
         report.rr.packet_lost &= 0xFFFFFF;
@@ -370,23 +333,8 @@ uint8_t* avdt_scb_hdl_report(tAVDT_SCB* p_scb, uint8_t* p, uint16_t len) {
 
       case AVDT_RTCP_PT_SDES: /* the packet type - SDES (Source Description) */
         if (*p == AVDT_RTCP_SDES_CNAME) {
-          min_len += sizeof(tAVDT_REPORT_DATA) + 2;
-          if (min_len > len) {
-            android_errorWriteLog(0x534e4554, "111450156");
-            AVDT_TRACE_WARNING(
-                "%s: hdl packet length %d too short: must be at least %d",
-                __func__, len, min_len);
-            goto avdt_scb_hdl_report_exit;
-          }
           p_rpt = (tAVDT_REPORT_DATA*)(p + 2);
         } else {
-          if (min_len + 1 > len) {
-            android_errorWriteLog(0x534e4554, "111450156");
-            AVDT_TRACE_WARNING(
-                "%s: hdl packet length %d too short: must be at least %d",
-                __func__, len, min_len + 2);
-            goto avdt_scb_hdl_report_exit;
-          }
           AVDT_TRACE_WARNING(" - SDES SSRC=0x%08x sc=%d %d len=%d %s", ssrc,
                              o_cc, *p, *(p + 1), p + 2);
           result = AVDT_BUSY;
@@ -401,7 +349,6 @@ uint8_t* avdt_scb_hdl_report(tAVDT_SCB* p_scb, uint8_t* p, uint16_t len) {
     if (result == AVDT_SUCCESS)
       (*p_scb->cs.p_report_cback)(avdt_scb_to_hdl(p_scb), pt, p_rpt);
   }
-avdt_scb_hdl_report_exit:
   p_start += len;
   return p_start;
 }
@@ -556,7 +503,11 @@ void avdt_scb_hdl_security_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
 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)) {
@@ -579,6 +530,7 @@ void avdt_scb_hdl_setconfig_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
                         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);
   }
 }
@@ -969,6 +921,8 @@ void avdt_scb_snd_abort_req(tAVDT_SCB* p_scb,
                             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;
 
@@ -1124,6 +1078,10 @@ void avdt_scb_snd_open_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
  *
  ******************************************************************************/
 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);
@@ -1226,6 +1184,9 @@ void avdt_scb_snd_setconfig_rej(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
 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);
index e9c032c..9eae106 100644 (file)
@@ -627,6 +627,7 @@ static void bnep_data_ind(uint16_t l2cap_cid, BT_HDR* p_buf) {
   if (bnep_cb.p_data_buf_cb) {
     (*bnep_cb.p_data_buf_cb)(p_bcb->handle, p_src_addr, p_dst_addr, protocol,
                              p_buf, fw_ext_present);
+    osi_free(p_buf);
   } else if (bnep_cb.p_data_ind_cb) {
     (*bnep_cb.p_data_ind_cb)(p_bcb->handle, p_src_addr, p_dst_addr, protocol, p,
                              rem_len, fw_ext_present);
index d9720c7..34041d6 100644 (file)
@@ -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 "log/log.h"
@@ -232,6 +233,7 @@ void btm_acl_created(BD_ADDR bda, DEV_CLASS dc, BD_NAME bdn,
              BD_ADDR_LEN);
 
 #endif
+      p->switch_role_failed_attempts = 0;
       p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
 
       btm_pm_sm_alloc(xx);
@@ -570,6 +572,11 @@ tBTM_STATUS BTM_SwitchRole(BD_ADDR remote_bd_addr, uint8_t new_role,
   /* 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);
@@ -583,6 +590,13 @@ tBTM_STATUS BTM_SwitchRole(BD_ADDR remote_bd_addr, uint8_t new_role,
     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);
 
@@ -1386,6 +1400,58 @@ void btm_process_clk_off_comp_evt(uint16_t hci_handle, uint16_t clock_offset) {
 }
 
 /*******************************************************************************
+*
+* 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
  *
index 76eb509..c3d8dbb 100644 (file)
@@ -50,39 +50,63 @@ static void btm_resume_wl_activity(tBTM_BLE_WL_STATE wl_state);
 // 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);
+  }
+};
+
+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*,
-                          std::hash<bt_bdaddr_t*>, KeyEqual>
+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 @@ static bool background_connections_pending() {
   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 @@ void btm_update_scanner_filter_policy(tBTM_BLE_SFP scan_policy) {
       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 @@ bool btm_add_dev_to_controller(bool to_add, BD_ADDR bd_addr) {
     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 @@ bool btm_add_dev_to_controller(bool to_add, BD_ADDR bd_addr) {
      */
     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 @@ bool btm_add_dev_to_controller(bool to_add, BD_ADDR bd_addr) {
  *                                                                  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;
-  }
-  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;
+      ++map_it;
   }
-  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");
+  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;
+    }
   }
-  return;
+  return true;
 }
 
 /*******************************************************************************
@@ -233,18 +286,15 @@ void btm_enq_wl_dev_operation(bool to_add, BD_ADDR bd_addr) {
 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(void) {
  ******************************************************************************/
 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_clear_white_list_complete(uint8_t* p_data,
  ******************************************************************************/
 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_white_list_init(uint8_t white_list_size) {
  ******************************************************************************/
 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_add_2_white_list_complete(uint8_t status) {
 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 @@ bool btm_ble_start_auto_conn(bool start) {
   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 @@ static void btm_suspend_wl_activity(tBTM_BLE_WL_STATE wl_state) {
   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_suspend_wl_activity(tBTM_BLE_WL_STATE wl_state) {
  ******************************************************************************/
 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();
-  }
 }
 /*******************************************************************************
  *
index caf610f..fe093e2 100644 (file)
@@ -2103,11 +2103,14 @@ static void btm_ble_process_adv_pkt_cont(
   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 @@ tBTM_STATUS btm_ble_start_adv(void) {
     /* 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 @@ tBTM_STATUS btm_ble_stop_adv(void) {
 
     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 @@ void btm_ble_update_mode_operation(uint8_t link_role, BD_ADDR bd_addr,
                                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
index e645994..f7da237 100644 (file)
@@ -138,6 +138,7 @@ extern void btm_ble_update_mode_operation(uint8_t link_role, BD_ADDR bda,
                                           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);
index 51b5118..3e16fea 100644 (file)
@@ -174,8 +174,6 @@ typedef struct {
   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 @@ typedef struct {
 /* 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 @@ typedef struct {
   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 @@ typedef struct {
   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*/
index ba31c81..e64766c 100644 (file)
@@ -629,7 +629,7 @@ class BleAdvertisingManagerImpl
         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 @@ void BleAdvertisingManager::Initialize(BleAdvertiserHciInterface* interface) {
   instance = new BleAdvertisingManagerImpl(interface);
 }
 
+bool BleAdvertisingManager::IsInitialized() { return instance; }
+
 BleAdvertisingManager* BleAdvertisingManager::Get() {
   CHECK(instance);
   return instance;
index aa6646f..808f1cd 100644 (file)
@@ -148,16 +148,17 @@ bool BTM_SecAddDevice(BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name,
   return true;
 }
 
-/** Free resources associated with the device associated with |bd_addr| address.
+/*******************************************************************************
+ *
+ * Function         BTM_SecDeleteDevice
+ *
+ * Description      Free resources associated with the device.
  *
- * *** WARNING ***
- * tBTM_SEC_DEV_REC associated with bd_addr becomes invalid after this function
- * is called, also any of it's fields. i.e. if you use p_dev_rec->bd_addr, it is
- * no longer valid!
- * *** WARNING ***
+ * Parameters:      bd_addr          - BD address of the peer
+ *
+ * Returns          true if removed OK, false if not found or ACL link is active
  *
- * Returns true if removed OK, false if not found or ACL link is active.
- */
+ ******************************************************************************/
 bool BTM_SecDeleteDevice(BD_ADDR bd_addr) {
   if (BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_LE) ||
       BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_BR_EDR)) {
@@ -168,11 +169,9 @@ bool BTM_SecDeleteDevice(BD_ADDR bd_addr) {
 
   tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
   if (p_dev_rec != NULL) {
-    BD_ADDR bda;
-    memcpy(bda, bd_addr, BD_ADDR_LEN);
     btm_sec_free_dev(p_dev_rec);
     /* Tell controller to get rid of the link key, if it has one stored */
-    BTM_DeleteStoredLinkKey(bda, NULL);
+    BTM_DeleteStoredLinkKey(p_dev_rec->bd_addr, NULL);
   }
 
   return true;
index 7f9cb40..687e89d 100644 (file)
@@ -765,8 +765,8 @@ tBTM_STATUS BTM_StartInquiry(tBTM_INQ_PARMS* p_inqparms,
       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;
index 6b1f409..1abb2be 100644 (file)
@@ -105,6 +105,8 @@ extern void btm_process_clk_off_comp_evt(uint16_t hci_handle,
                                          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);
index 5905aeb..b36eaab 100644 (file)
@@ -89,6 +89,9 @@ typedef struct {
 #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 \
index bcefa2a..febb4c5 100644 (file)
@@ -24,7 +24,6 @@
 
 #define LOG_TAG "bt_btm_sec"
 
-#include <log/log.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
@@ -43,8 +42,6 @@
 
 #include "gatt_int.h"
 
-#include "bta/dm/bta_dm_int.h"
-
 #define BTM_SEC_MAX_COLLISION_DELAY (5000)
 
 extern fixed_queue_t* btu_general_alarm_queue;
@@ -3878,6 +3875,50 @@ static void btm_sec_auth_collision(uint16_t handle) {
   }
 }
 
+/******************************************************************************
+ *
+ * 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
@@ -3889,7 +3930,6 @@ static void btm_sec_auth_collision(uint16_t handle) {
  *
  ******************************************************************************/
 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;
@@ -3915,7 +3955,10 @@ void btm_sec_auth_complete(uint16_t handle, uint8_t status) {
       (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();
@@ -3932,10 +3975,6 @@ void btm_sec_auth_complete(uint16_t handle, uint8_t status) {
 
   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))
@@ -4014,37 +4053,6 @@ void btm_sec_auth_complete(uint16_t handle, uint8_t status) {
 
   /* 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) {
@@ -4676,19 +4684,6 @@ void btm_sec_disconnected(uint16_t handle, uint8_t reason) {
           BTM_SEC_ROLE_SWITCHED | BTM_SEC_16_DIGIT_PIN_AUTHED);
   }
 
-  /* Some devices hardcode sample LTK value from spec, instead of generating
-   * one. Treat such devices as insecure, and remove such bonds on
-   * disconnection.
-   */
-  if (is_sample_ltk(p_dev_rec->ble.keys.pltk)) {
-    android_errorWriteLog(0x534e4554, "128437297");
-    LOG(INFO) << __func__ << " removing bond to device that used sample LTK";
-
-    tBTA_DM_MSG p_data;
-    memcpy(p_data.remove_dev.bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN);
-    bta_dm_remove_device(&p_data);
-  }
-
   if (p_dev_rec->sec_state == BTM_SEC_STATE_DISCONNECTING_BOTH) {
     p_dev_rec->sec_state = (transport == BT_TRANSPORT_LE)
                                ? BTM_SEC_STATE_DISCONNECTING
index e511815..1456228 100644 (file)
@@ -31,7 +31,7 @@
 #include <base/callback.h>
 #include <base/location.h>
 #include <base/logging.h>
-#include <log/log.h>
+#include <base/threading/thread.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -51,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);
 
@@ -130,6 +127,18 @@ static void btu_ble_rc_param_req_evt(uint8_t* p);
 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
@@ -405,58 +414,48 @@ void cmd_with_cb_data_cleanup(cmd_with_cb_data* cb_wrapper) {
   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);
 }
 
@@ -468,18 +467,9 @@ static void btu_hcif_command_status_evt_with_cb(uint8_t status, BT_HDR* command,
     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
@@ -716,40 +706,6 @@ static void btu_hcif_rmt_name_request_comp_evt(uint8_t* p, uint16_t evt_len) {
   btm_sec_rmt_name_request_complete(bd_addr, p, status);
 }
 
-constexpr uint8_t MIN_KEY_SIZE = 7;
-
-static void read_encryption_key_size_complete_after_encryption_change(
-    uint8_t status, uint16_t handle, uint8_t key_size) {
-  if (status == HCI_ERR_INSUFFCIENT_SECURITY) {
-    /* If remote device stop the encryption before we call "Read Encryption Key
-     * Size", we might receive Insufficient Security, which means that link is
-     * no longer encrypted. */
-    HCI_TRACE_WARNING("%s encryption stopped on link: 0x%02x", __func__,
-                      handle);
-    return;
-  }
-
-  if (status != HCI_SUCCESS) {
-    HCI_TRACE_WARNING("%s: disconnecting, status: 0x%02x", __func__, status);
-    btsnd_hcic_disconnect(handle, HCI_ERR_PEER_USER);
-    return;
-  }
-
-  if (key_size < MIN_KEY_SIZE) {
-    android_errorWriteLog(0x534e4554, "124301137");
-    HCI_TRACE_ERROR(
-        "%s encryption key too short, disconnecting. handle: 0x%02x, key_size: "
-        "%d",
-        __func__, handle, key_size);
-
-    btsnd_hcic_disconnect(handle, HCI_ERR_HOST_REJECT_SECURITY);
-    return;
-  }
-
-  // good key size - succeed
-  btm_acl_encrypt_change(handle, status, 1 /* enable */);
-  btm_sec_encrypt_change(handle, status, 1 /* enable */);
-}
 /*******************************************************************************
  *
  * Function         btu_hcif_encryption_change_evt
@@ -768,15 +724,8 @@ static void btu_hcif_encryption_change_evt(uint8_t* p) {
   STREAM_TO_UINT16(handle, p);
   STREAM_TO_UINT8(encr_enable, p);
 
-  if (status != HCI_SUCCESS || encr_enable == 0 ||
-      BTM_IsBleConnection(handle)) {
-    btm_acl_encrypt_change(handle, status, encr_enable);
-    btm_sec_encrypt_change(handle, status, encr_enable);
-  } else {
-    btsnd_hcic_read_encryption_key_size(
-        handle,
-        base::Bind(&read_encryption_key_size_complete_after_encryption_change));
-  }
+  btm_acl_encrypt_change(handle, status, encr_enable);
+  btm_sec_encrypt_change(handle, status, encr_enable);
 }
 
 /*******************************************************************************
@@ -1046,37 +995,26 @@ static void btu_hcif_hdl_command_complete(uint16_t opcode, uint8_t* p,
  * 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));
 }
 
 /*******************************************************************************
@@ -1237,33 +1175,20 @@ static void btu_hcif_hdl_command_status(uint16_t opcode, uint8_t status,
  * 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));
 }
 
 /*******************************************************************************
@@ -1314,6 +1239,7 @@ static void btu_hcif_role_change_evt(uint8_t* p) {
   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);
 }
@@ -1688,56 +1614,21 @@ static void btu_hcif_enhanced_flush_complete_evt(void) {
  * End of Simple Pairing Events
  **********************************************/
 
-static void read_encryption_key_size_complete_after_key_refresh(
-    uint8_t status, uint16_t handle, uint8_t key_size) {
-  if (status == HCI_ERR_INSUFFCIENT_SECURITY) {
-    /* If remote device stop the encryption before we call "Read Encryption Key
-     * Size", we might receive Insufficient Security, which means that link is
-     * no longer encrypted. */
-    HCI_TRACE_WARNING("%s encryption stopped on link: 0x%02x", __func__,
-                      handle);
-    return;
-  }
-
-  if (status != HCI_SUCCESS) {
-    HCI_TRACE_WARNING("%s: disconnecting, status: 0x%02x", __func__, status);
-    btsnd_hcic_disconnect(handle, HCI_ERR_PEER_USER);
-    return;
-  }
-
-  if (key_size < MIN_KEY_SIZE) {
-    android_errorWriteLog(0x534e4554, "124301137");
-    HCI_TRACE_ERROR(
-        "%s encryption key too short, disconnecting. handle: 0x%02x, key_size: "
-        "%d",
-        __func__, handle, key_size);
-
-    btsnd_hcic_disconnect(handle, HCI_ERR_HOST_REJECT_SECURITY);
-    return;
-  }
-
-  btm_sec_encrypt_change(handle, status, 1 /* enc_enable */);
-}
-
+/**********************************************
+ * BLE Events
+ **********************************************/
 static void btu_hcif_encryption_key_refresh_cmpl_evt(uint8_t* p) {
   uint8_t status;
+  uint8_t enc_enable = 0;
   uint16_t handle;
 
   STREAM_TO_UINT8(status, p);
   STREAM_TO_UINT16(handle, p);
 
-  if (status != HCI_SUCCESS || BTM_IsBleConnection(handle)) {
-    btm_sec_encrypt_change(handle, status, (status == HCI_SUCCESS) ? 1 : 0);
-  } else {
-    btsnd_hcic_read_encryption_key_size(
-        handle,
-        base::Bind(&read_encryption_key_size_complete_after_key_refresh));
-  }
-}
+  if (status == HCI_SUCCESS) enc_enable = 1;
 
-/**********************************************
- * BLE Events
- **********************************************/
+  btm_sec_encrypt_change(handle, status, enc_enable);
+}
 
 static void btu_ble_ll_conn_complete_evt(uint8_t* p, uint16_t evt_len) {
   btm_ble_conn_complete(p, evt_len, false);
index 8152d3e..103990e 100644 (file)
 #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"
-
-#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
+#include "stack/btm/btm_int.h"
+#include "stack/include/btu.h"
+#include "stack/l2cap/l2c_int.h"
 
-#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);
-
-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);
-}
+static base::MessageLoop* message_loop_ = NULL;
+static base::RunLoop* run_loop_ = NULL;
+static thread_t* message_loop_thread_;
 
-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 @@ static void btu_hci_msg_process(BT_HDR* p_msg) {
   }
 }
 
-void btu_task_start_up(UNUSED_ATTR void* context) {
-  BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_API,
-           "btu_task pending for preload complete event");
+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();
 
-  LOG_INFO(LOG_TAG, "Bluetooth chip preload is complete");
+  delete message_loop_;
+  message_loop_ = NULL;
 
-  BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_API,
-           "btu_task received preload complete event");
+  delete run_loop_;
+  run_loop_ = NULL;
+}
+
+void btu_task_start_up(UNUSED_ATTR void* context) {
+  LOG(INFO) << "Bluetooth chip preload is complete";
 
   /* Initialize the mandatory core stack control blocks
      (BTU, BTM, L2CAP, and SDP)
@@ -170,23 +124,18 @@ void btu_task_start_up(UNUSED_ATTR void* context) {
    */
   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 (file)
index 994ba65..0000000
+++ /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();
-}
index 3c8de00..37c91f5 100644 (file)
@@ -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.
  *  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)
-
-#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
-
-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);
-
-/* 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);
-
-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};
-
-/*******************************************************************************
- *
- * 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;
-
-  for (i_clcb = 0, p_clcb = gap_cb.clcb; i_clcb < GAP_MAX_CL;
-       i_clcb++, p_clcb++) {
-    if (p_clcb->in_use && !memcmp(p_clcb->bda, bda, BD_ADDR_LEN)) {
-      return p_clcb;
-    }
-  }
 
-  return NULL;
+using base::StringPrintf;
+
+namespace {
+
+typedef struct {
+  uint16_t uuid;
+  tGAP_BLE_CMPL_CBACK* p_cback;
+} tGAP_REQUEST;
+
+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;
+
+typedef struct {
+  uint16_t handle;
+  uint16_t uuid;
+  tGAP_BLE_ATTR_VALUE attr_value;
+} tGAP_ATTR;
+
+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*);
+
+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 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;
-    }
-  }
+/** 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 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;
+  return nullptr;
 }
 
-/*******************************************************************************
- *
- * 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);
+/** allocates a GAP connection link control block */
+tGAP_CLCB* clcb_alloc(BD_ADDR bda) {
+  gap_clcbs.emplace_back();
+  tGAP_CLCB& cb = gap_clcbs.back();
 
-    osi_free(p_q);
-  }
-  fixed_queue_free(p_clcb->pending_req_q, NULL);
-
-  memset(p_clcb, 0, sizeof(tGAP_CLCB));
+  memcpy(cb.bda, bda, BD_ADDR_LEN);
+  return &cb;
 }
 
-/*******************************************************************************
- *
- * 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;
+/** 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 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 @@ tGATT_STATUS gap_read_attr_value(uint16_t handle, tGATT_VALUE* p_value,
             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 @@ tGATT_STATUS gap_read_attr_value(uint16_t handle, tGATT_VALUE* p_value,
   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;
-
-  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;
-    }
-  }
+/** 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;
+
   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(&param, 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, &param) == 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 @@ void gap_attr_db_init(void) {
 
   /* 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 @@ void gap_attr_db_init(void) {
   };
 
   /* 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 @@ void gap_attr_db_init(void) {
  *
  * 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 @@ void GAP_BleAttrDBUpdate(uint16_t attr_uuid, tGAP_BLE_ATTR_VALUE* p_value) {
           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 @@ void GAP_BleAttrDBUpdate(uint16_t attr_uuid, tGAP_BLE_ATTR_VALUE* p_value) {
 
 /*******************************************************************************
  *
- * 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(&param, 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, &param) ==
-        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_ble_accept_cl_operation(BD_ADDR peer_bda, uint16_t uuid,
  *
  ******************************************************************************/
 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_BleReadPeerPrefConnParams(BD_ADDR peer_bda) {
  *
  ******************************************************************************/
 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_BleReadPeerDevName(BD_ADDR peer_bda, tGAP_BLE_CMPL_CBACK* p_cback) {
  ******************************************************************************/
 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_BleReadPeerAddressResolutionCap(BD_ADDR peer_bda,
  *
  ******************************************************************************/
 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);
 }
index fcc2161..b05a7b2 100644 (file)
  *
  ******************************************************************************/
 
+#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 @@ static void gap_checks_con_flags(tGAP_CCB* p_ccb);
  *
  ******************************************************************************/
 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 @@ uint16_t GAP_ConnOpen(const char* p_serv_name, uint8_t service_id,
   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 @@ uint16_t GAP_ConnOpen(const char* p_serv_name, uint8_t service_id,
   /* 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 @@ uint16_t GAP_ConnOpen(const char* p_serv_name, uint8_t service_id,
 
   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 @@ uint16_t GAP_ConnOpen(const char* p_serv_name, uint8_t service_id,
   /* 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_ConnOpen(const char* p_serv_name, uint8_t service_id,
 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 @@ uint16_t GAP_ConnReadData(uint16_t gap_handle, uint8_t* p_data,
 
   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 @@ int GAP_GetRxQueueCnt(uint16_t handle, uint32_t* p_rx_queue_count) {
 
   /* 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 @@ int GAP_GetRxQueueCnt(uint16_t handle, uint32_t* p_rx_queue_count) {
   } 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 @@ uint16_t GAP_ConnWriteData(uint16_t gap_handle, uint8_t* p_data,
     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 @@ uint16_t GAP_ConnSetIdleTimeout(uint16_t gap_handle, uint16_t timeout) {
 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 @@ uint8_t* GAP_ConnGetRemoteAddr(uint16_t gap_handle) {
         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 @@ void gap_tx_complete_ind(uint16_t l2cap_cid, uint16_t sdu_sent) {
   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 @@ static void gap_connect_ind(BD_ADDR bd_addr, uint16_t l2cap_cid, uint16_t psm,
   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 @@ static void gap_connect_ind(BD_ADDR bd_addr, uint16_t l2cap_cid, uint16_t psm,
   }
 
   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 @@ static void gap_connect_ind(BD_ADDR bd_addr, uint16_t l2cap_cid, uint16_t psm,
     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_connect_ind(BD_ADDR bd_addr, uint16_t l2cap_cid, uint16_t psm,
  *
  ******************************************************************************/
 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 @@ static void gap_checks_con_flags(tGAP_CCB* p_ccb) {
  * 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_config_cfm(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg) {
 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 @@ static void gap_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg) {
 
     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 @@ static void gap_congestion_ind(uint16_t lcid, bool is_congested) {
   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 @@ static tGAP_CCB* gap_find_ccb_by_cid(uint16_t cid) {
   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 @@ static tGAP_CCB* gap_find_ccb_by_handle(uint16_t handle) {
 
   /* 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 @@ static tGAP_CCB* gap_allocate_ccb(void) {
   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 @@ static void gap_release_ccb(tGAP_CCB* p_ccb) {
   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 @@ static void gap_release_ccb(tGAP_CCB* p_ccb) {
   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 (file)
index 0f27f04..0000000
+++ /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 (file)
index fa8b30e..0000000
+++ /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);
-  }
-}
index b1d1cc6..e215547 100644 (file)
@@ -320,14 +320,14 @@ BT_HDR* attp_build_value_cmd(uint16_t payload_size, uint8_t op_code,
  * 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_TCBtcb, 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 to L2CAP");
@@ -346,7 +346,7 @@ tGATT_STATUS attp_send_msg_to_l2cap(tGATT_TCB* p_tcb, BT_HDR* p_toL2CAP) {
  * 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_TCBtcb, uint8_t op_code,
                           tGATT_SR_MSG* p_msg) {
   BT_HDR* p_cmd = NULL;
   uint16_t offset = 0;
@@ -366,7 +366,7 @@ BT_HDR* attp_build_sr_msg(tGATT_TCB* p_tcb, uint8_t op_code,
     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;
 
@@ -411,16 +411,11 @@ BT_HDR* attp_build_sr_msg(tGATT_TCB* p_tcb, uint8_t op_code,
  *
  *
  ******************************************************************************/
-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_TCBtcb, 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);
 }
 
 /*******************************************************************************
@@ -435,34 +430,31 @@ tGATT_STATUS attp_send_sr_msg(tGATT_TCB* p_tcb, BT_HDR* p_msg) {
  *                  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;
-
-  if (p_tcb != NULL) {
-    cmd_code &= ~GATT_AUTH_SIGN_MASK;
-
-    /* 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;
+  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 */
+  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
@@ -471,7 +463,7 @@ tGATT_STATUS attp_cl_send_cmd(tGATT_TCB* p_tcb, uint16_t clcb_idx,
  *                  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.
  *
@@ -479,91 +471,80 @@ tGATT_STATUS attp_cl_send_cmd(tGATT_TCB* p_tcb, uint16_t clcb_idx,
  *
  *
  ******************************************************************************/
-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;
+
+      tcb.payload_size = p_msg->mtu;
+      p_cmd = attp_build_mtu_cmd(GATT_REQ_MTU, p_msg->mtu);
+      break;
 
-  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;
-
-      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;
-
-      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_HANDLE_VALUE_CONF:
-        p_cmd = attp_build_opcode_cmd(op_code);
-        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_REQ_EXEC_WRITE:
-        p_cmd = attp_build_exec_write_cmd(op_code, p_msg->exec_write);
-        break;
-
-      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;
-
-      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;
-
-      default:
-        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)) return GATT_ILLEGAL_PARAMETER;
 
-    if (p_cmd != NULL)
-      status = attp_cl_send_cmd(p_tcb, clcb_idx, op_code, p_cmd);
+      p_cmd = attp_build_handle_cmd(op_code, handle, offset);
+      break;
+
+    case GATT_HANDLE_VALUE_CONF:
+      p_cmd = attp_build_opcode_cmd(op_code);
+      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;
+
+      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_EXEC_WRITE:
+      p_cmd = attp_build_exec_write_cmd(op_code, p_msg->exec_write);
+      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;
 
-  } else {
-    GATT_TRACE_ERROR("Peer device not connected");
+    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;
+
+    default:
+      break;
   }
 
-  return status;
+  if (p_cmd == NULL) return GATT_NO_RESOURCES;
+
+  return attp_cl_send_cmd(tcb, p_clcb, op_code, p_cmd);
 }
index a91b48e..1c4d2cc 100644 (file)
@@ -522,10 +522,10 @@ tGATT_STATUS GATTS_HandleValueIndication(uint16_t conn_id, uint16_t attr_handle,
       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_HandleValueIndication(uint16_t conn_id, uint16_t attr_handle,
 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 @@ tGATT_STATUS GATTS_HandleValueNotification(uint16_t conn_id,
     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*)&notif);
-    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*)&notif);
+  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 @@ tGATT_STATUS GATTS_SendRsp(uint16_t conn_id, uint32_t trans_id,
     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 @@ tGATT_STATUS GATTC_ConfigureMTU(uint16_t conn_id, uint16_t mtu) {
     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 @@ tGATT_STATUS GATTC_ExecuteWrite(uint16_t conn_id, bool is_execute) {
   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_ExecuteWrite(uint16_t conn_id, bool is_execute) {
  *
  ******************************************************************************/
 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));
+  if (!p_tcb) {
+    GATT_TRACE_ERROR("%s - Unknown conn_id: %u", __func__, conn_id);
+    return GATT_ILLEGAL_PARAMETER;
+  }
 
-  GATT_TRACE_API("GATTC_SendHandleValueConfirm conn_id=%d handle=0x%x", conn_id,
-                 handle);
+  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;
+  }
 
-  if (p_tcb) {
-    if (p_tcb->ind_count > 0) {
-      alarm_cancel(p_tcb->ind_ack_timer);
+  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);
+  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;
+  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);
-  }
   return ret;
 }
 
@@ -1331,59 +1327,49 @@ bool GATT_Connect(tGATT_IF gatt_if, BD_ADDR bd_addr, bool is_direct,
  *
  ******************************************************************************/
 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
 
-  return status;
+  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 true;
 }
 
 /*******************************************************************************
index 82b03a6..ae7cb30 100644 (file)
@@ -91,10 +91,10 @@ static bool gatt_sign_data(tGATT_CLCB* p_clcb) {
  * Returns
  *
  ******************************************************************************/
-void gatt_verify_signature(tGATT_TCB* p_tcb, BT_HDR* p_buf) {
+void gatt_verify_signature(tGATT_TCBtcb, 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 @@ void gatt_verify_signature(tGATT_TCB* p_tcb, BT_HDR* p_buf) {
   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_verify_signature(tGATT_TCB* p_tcb, BT_HDR* p_buf) {
  ******************************************************************************/
 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_sec_check_complete(bool sec_check_ok, tGATT_CLCB* p_clcb,
  ******************************************************************************/
 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;
+  GATT_TRACE_DEBUG("gatt_enc_cmpl_cback");
+  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;
+  }
+
+  if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENC_PENDING) return;
+
+  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);
 
-  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_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 (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 (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_enc_cmpl_cback(BD_ADDR bd_addr, tBT_TRANSPORT transport,
  *
  ******************************************************************************/
 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);
-      }
+  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;
+  }
+
+  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);
-
-      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;
-      }
+  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);
     }
-  } else {
-    GATT_TRACE_DEBUG("notify GATT for encryption completion of unknown device");
   }
-  return;
 }
 /*******************************************************************************
  *
@@ -270,16 +255,10 @@ tGATT_SEC_ACTION gatt_get_sec_act(tGATT_TCB* p_tcb) {
   }
   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 @@ tGATT_SEC_ACTION gatt_determine_sec_act(tGATT_CLCB* p_clcb) {
  * 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_TCBtcb) {
   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 @@ bool gatt_security_check_start(tGATT_CLCB* p_clcb) {
           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:
index d83582a..a3ed6dc 100644 (file)
@@ -46,7 +46,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_TCBtcb, tGATT_CLCB* p_clcb);
 
 uint8_t disc_type_to_att_opcode[GATT_DISC_MAX] = {
     0,
@@ -110,7 +110,7 @@ void gatt_act_discovery(tGATT_CLCB* p_clcb) {
                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);
@@ -129,7 +129,7 @@ void gatt_act_discovery(tGATT_CLCB* p_clcb) {
  *
  ******************************************************************************/
 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;
@@ -192,8 +192,7 @@ void gatt_act_read(tGATT_CLCB* p_clcb, uint16_t offset) {
       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);
@@ -210,7 +209,7 @@ void gatt_act_read(tGATT_CLCB* p_clcb, uint16_t offset) {
  *
  ******************************************************************************/
 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;
 
@@ -220,25 +219,24 @@ void gatt_act_write(tGATT_CLCB* p_clcb, uint8_t sec_act) {
         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:
@@ -267,14 +265,13 @@ void gatt_act_write(tGATT_CLCB* p_clcb, uint8_t sec_act) {
  * Returns          void.
  *
  ******************************************************************************/
-void gatt_send_queue_write_cancel(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
+void gatt_send_queue_write_cancel(tGATT_TCBtcb, 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);
@@ -289,7 +286,7 @@ void gatt_send_queue_write_cancel(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
  * 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_TCBtcb, tGATT_CLCB* p_clcb,
                                      tGATT_VALUE* p_rsp_value) {
   tGATT_VALUE* p_attr = (tGATT_VALUE*)p_clcb->p_attr_buf;
   bool exec = false;
@@ -314,7 +311,7 @@ bool gatt_check_write_long_terminate(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
     }
   }
   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;
@@ -328,7 +325,7 @@ bool gatt_check_write_long_terminate(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
  * Returns          void.
  *
  ******************************************************************************/
-void gatt_send_prepare_write(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb) {
+void gatt_send_prepare_write(tGATT_TCBtcb, 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;
@@ -337,9 +334,9 @@ void gatt_send_prepare_write(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb) {
   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;
 
@@ -350,8 +347,8 @@ void gatt_send_prepare_write(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb) {
 
   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 */
 
@@ -373,7 +370,7 @@ void gatt_send_prepare_write(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb) {
  * 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_TCBtcb,
                                       tGATT_CLCB* p_clcb, uint16_t len,
                                       uint8_t* p_data) {
   tGATT_DISC_RES result;
@@ -421,9 +418,9 @@ void gatt_process_find_type_value_rsp(UNUSED_ATTR tGATT_TCB* p_tcb,
  * 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;
 
@@ -474,7 +471,7 @@ void gatt_process_read_info_rsp(UNUSED_ATTR tGATT_TCB* p_tcb,
  * 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_TCBtcb, tGATT_CLCB* p_clcb,
                               uint8_t opcode, UNUSED_ATTR uint16_t handle,
                               uint8_t reason) {
   tGATT_STATUS status = (tGATT_STATUS)reason;
@@ -510,7 +507,7 @@ void gatt_proc_disc_error_rsp(UNUSED_ATTR tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
  * Returns          void
  *
  ******************************************************************************/
-void gatt_process_error_rsp(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
+void gatt_process_error_rsp(tGATT_TCBtcb, 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;
@@ -538,14 +535,14 @@ void gatt_process_error_rsp(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
   }
 
   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)) &&
@@ -567,7 +564,7 @@ void gatt_process_error_rsp(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
  * Returns          void
  *
  ******************************************************************************/
-void gatt_process_prep_write_rsp(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
+void gatt_process_prep_write_rsp(tGATT_TCBtcb, tGATT_CLCB* p_clcb,
                                  uint8_t op_code, uint16_t len,
                                  uint8_t* p_data) {
   uint8_t* p = p_data;
@@ -599,8 +596,8 @@ void gatt_process_prep_write_rsp(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
 
     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);
   }
 }
 /*******************************************************************************
@@ -612,7 +609,7 @@ void gatt_process_prep_write_rsp(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
  * Returns          void
  *
  ******************************************************************************/
-void gatt_process_notification(tGATT_TCB* p_tcb, uint8_t op_code, uint16_t len,
+void gatt_process_notification(tGATT_TCBtcb, uint8_t op_code, uint16_t len,
                                uint8_t* p_data) {
   tGATT_VALUE value;
   tGATT_REG* p_reg;
@@ -637,12 +634,12 @@ void gatt_process_notification(tGATT_TCB* p_tcb, uint8_t op_code, uint16_t len,
   if (!GATT_HANDLE_IS_VALID(value.handle)) {
     /* illegal handle, send ack now */
     if (op_code == GATT_HANDLE_VALUE_IND)
-      attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL);
+      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.
@@ -651,9 +648,9 @@ void gatt_process_notification(tGATT_TCB* p_tcb, uint8_t op_code, uint16_t len,
       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
@@ -665,21 +662,21 @@ void gatt_process_notification(tGATT_TCB* p_tcb, uint8_t op_code, uint16_t len,
   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);
     }
@@ -697,7 +694,7 @@ void gatt_process_notification(tGATT_TCB* p_tcb, uint8_t op_code, uint16_t len,
  * 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_TCBtcb, tGATT_CLCB* p_clcb,
                                    uint8_t op_code, uint16_t len,
                                    uint8_t* p_data) {
   tGATT_DISC_RES result;
@@ -719,14 +716,14 @@ void gatt_process_read_by_type_rsp(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
 
   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;
   }
@@ -885,7 +882,7 @@ void gatt_process_read_by_type_rsp(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
  * Returns          void
  *
  ******************************************************************************/
-void gatt_process_read_rsp(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
+void gatt_process_read_rsp(tGATT_TCBtcb, tGATT_CLCB* p_clcb,
                            UNUSED_ATTR uint8_t op_code, uint16_t len,
                            uint8_t* p_data) {
   uint16_t offset = p_clcb->counter;
@@ -911,7 +908,7 @@ void gatt_process_read_rsp(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
 
         /* 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(
@@ -978,7 +975,7 @@ void gatt_process_handle_rsp(tGATT_CLCB* p_clcb) {
  * Returns          void
  *
  ******************************************************************************/
-void gatt_process_mtu_rsp(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb, uint16_t len,
+void gatt_process_mtu_rsp(tGATT_TCBtcb, tGATT_CLCB* p_clcb, uint16_t len,
                           uint8_t* p_data) {
   uint16_t mtu;
   tGATT_STATUS status = GATT_SUCCESS;
@@ -989,12 +986,12 @@ void gatt_process_mtu_rsp(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb, uint16_t len,
   } 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);
 }
 /*******************************************************************************
@@ -1015,54 +1012,42 @@ uint8_t gatt_cmd_to_rsp_code(uint8_t cmd_code) {
   }
   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;
+
+    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;
+    }
 
-    if (att_ret == GATT_SUCCESS || att_ret == GATT_CONGESTED) {
-      sent = true;
-      p_cmd->to_send = false;
-      p_cmd->p_cmd = NULL;
+    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 */
-      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);
+      uint8_t rsp_code;
+      tGATT_CLCB* p_clcb = gatt_cmd_dequeue(tcb, &rsp_code);
 
-        /* if no ack needed, keep sending */
-        if (att_ret == GATT_SUCCESS) sent = false;
+      /* send command complete callback here */
+      gatt_end_operation(p_clcb, att_ret, NULL);
 
-        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");
+      /* if no ack needed, keep sending */
+      if (att_ret == GATT_SUCCESS) continue;
 
-      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];
+      return true;
     }
+
+    gatt_start_rsp_timer(cmd.p_clcb);
+    return true;
   }
-  return sent;
+
+  return false;
 }
 
 /*******************************************************************************
@@ -1076,63 +1061,61 @@ bool gatt_cl_send_next_cmd_inq(tGATT_TCB* p_tcb) {
  * Returns          void
  *
  ******************************************************************************/
-void gatt_client_handle_server_rsp(tGATT_TCB* p_tcb, uint8_t op_code,
+void gatt_client_handle_server_rsp(tGATT_TCBtcb, 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:
@@ -1140,7 +1123,7 @@ void gatt_client_handle_server_rsp(tGATT_TCB* p_tcb, uint8_t op_code,
         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:
@@ -1149,7 +1132,7 @@ void gatt_client_handle_server_rsp(tGATT_TCB* p_tcb, uint8_t op_code,
 
       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:
@@ -1159,7 +1142,7 @@ void gatt_client_handle_server_rsp(tGATT_TCB* p_tcb, uint8_t op_code,
   }
 
   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;
index 736958d..2819b0d 100644 (file)
@@ -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_TCBtcb, 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 @@ static tGATT_STATUS read_attr_value(tGATT_ATTR& attr16, uint16_t offset,
  *
  ******************************************************************************/
 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_TCBtcb, 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 @@ tGATT_STATUS gatts_db_read_attr_value_by_type(
                                  &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 @@ tGATT_STATUS gatts_db_read_attr_value_by_type(
 
 #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_ATTR* find_attr_by_handle(tGATT_SVC_DB* p_db, uint16_t handle) {
  *
  ******************************************************************************/
 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_TCBtcb, 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 @@ tGATT_STATUS gatts_read_attr_value_by_handle(
                                         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_ATTR& allocate_attr_in_db(tGATT_SVC_DB& db, const tBT_UUID& uuid,
  *
  ******************************************************************************/
 static tGATT_STATUS gatts_send_app_read_request(
-    tGATT_TCB* p_tcb, uint8_t op_code, uint16_t handle, uint16_t offset,
+    tGATT_TCBtcb, 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) {
index 812d156..bb9186f 100644 (file)
@@ -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 @@ typedef struct {
   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 @@ typedef struct {
 } 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 @@ typedef struct {
   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 @@ typedef struct {
   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 @@ typedef struct {
   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 @@ typedef struct {
   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 @@ typedef struct {
 } 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 @@ typedef struct {
   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 @@ typedef struct {
   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 @@ extern bool gatt_act_connect(tGATT_REG* p_reg, BD_ADDR bd_addr,
                              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 void gatt_add_a_bonded_dev_for_srv_chg(BD_ADDR bda);
 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_TCBtcb, 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_TCBtcb, BT_HDR* p_msg);
+extern tGATT_STATUS attp_send_msg_to_l2cap(tGATT_TCBtcb, BT_HDR* p_toL2CAP);
 
 /* utility functions */
 extern uint8_t* gatt_dbg_op_name(uint8_t op_code);
@@ -455,18 +443,16 @@ extern void gatt_convert_uuid32_to_uuid128(uint8_t uuid_128[LEN_UUID_128],
                                            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_TCBtcb);
+extern tGATT_STATUS gatt_send_error_rsp(tGATT_TCBtcb, 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_set_srv_chg(void);
 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_TCBtcb);
 
 /* reserved handle list */
 extern std::list<tGATT_HDL_LIST_ELEM>::iterator gatt_find_hdl_buffer_by_app_id(
@@ -491,8 +477,7 @@ extern bool gatt_update_auto_connect_dev(tGATT_IF gatt_if, bool add,
                                          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 std::list<tGATT_SRV_LIST_ELEM>::iterator gatt_sr_find_i_rcb_by_handle(
 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_TCBtcb, 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_TCBtcb, 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 bool gatt_is_clcb_allocated(uint16_t conn_id);
 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_TCBtcb);
+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_TCBtcb, 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 tGATT_TCB* gatt_find_tcb_by_addr(BD_ADDR bda, tBT_TRANSPORT transport);
 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_TCBtcb);
+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_end_operation(tGATT_CLCB* p_clcb, tGATT_STATUS status,
 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_TCBtcb, 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_TCBtcb, 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_TCBtcb, 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_TCBtcb);
 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_characteristic(tGATT_SVC_DB& db, tGATT_PERM perm,
 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_TCBtcb, 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_TCBtcb, 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(
index d375b84..3f5e639 100644 (file)
@@ -95,7 +95,7 @@ void gatt_init(void) {
 
   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 @@ void gatt_free(void) {
   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_disconnect(tGATT_TCB* p_tcb) {
  ******************************************************************************/
 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 @@ void gatt_update_app_use_link_flag(tGATT_IF gatt_if, tGATT_TCB* p_tcb,
     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 @@ bool gatt_act_connect(tGATT_REG* p_reg, BD_ADDR bd_addr,
     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 @@ bool gatt_act_connect(tGATT_REG* p_reg, BD_ADDR bd_addr,
     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 @@ static void gatt_channel_congestion(tGATT_TCB* p_tcb, bool congested) {
 
   /* 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 @@ static void gatt_le_data_ind(uint16_t chan, BD_ADDR bd_addr, BT_HDR* p_buf) {
   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 @@ static void gatt_l2cif_data_ind_cback(uint16_t lcid, BT_HDR* p_buf) {
   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_l2cif_congest_cback(uint16_t lcid, bool congested) {
 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 @@ static void gatt_send_conn_cback(tGATT_TCB* p_tcb) {
     }
   }
 
-  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 @@ static void gatt_send_conn_cback(tGATT_TCB* p_tcb) {
  * Returns          void
  *
  ******************************************************************************/
-void gatt_data_process(tGATT_TCB* p_tcb, BT_HDR* p_buf) {
+void gatt_data_process(tGATT_TCBtcb, 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);
+  if (p_buf->len <= 0) {
+    GATT_TRACE_ERROR("invalid data length, ignore");
+    return;
+  }
 
-    /* remove the two MSBs associated with sign write and write cmd */
-    pseudo_op_code = op_code & (~GATT_WRITE_CMD_MASK);
+  uint16_t msg_len = p_buf->len - 1;
+  STREAM_TO_UINT8(op_code, p);
 
-    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 {
-    GATT_TRACE_ERROR("invalid data length, ignore");
+  /* 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;
   }
 
-  osi_free(p_buf);
+  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);
+  }
 }
 
 /*******************************************************************************
index f067a95..2b332d9 100644 (file)
@@ -22,7 +22,6 @@
  *
  ******************************************************************************/
 
-#include <log/log.h>
 #include "bt_target.h"
 #include "bt_utils.h"
 #include "osi/include/osi.h"
@@ -43,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) ||
@@ -53,13 +51,13 @@ uint32_t gatt_sr_enqueue_cmd(tGATT_TCB* p_tcb, uint8_t op_code,
   {
     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;
     }
   }
@@ -76,9 +74,7 @@ uint32_t gatt_sr_enqueue_cmd(tGATT_TCB* p_tcb, uint8_t op_code,
  * 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); }
 
 /*******************************************************************************
  *
@@ -89,18 +85,17 @@ bool gatt_sr_cmd_empty(tGATT_TCB* p_tcb) {
  * Returns          void
  *
  ******************************************************************************/
-void gatt_dequeue_sr_cmd(tGATT_TCB* p_tcb) {
+void gatt_dequeue_sr_cmd(tGATT_TCBtcb) {
   /* 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);
-
-  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));
+  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(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));
 }
 
 /*******************************************************************************
@@ -226,52 +221,51 @@ static bool process_read_multi_rsp(tGATT_SR_CMD* p_cmd, tGATT_STATUS status,
  * 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_TCBtcb, 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;
 }
@@ -286,8 +280,8 @@ tGATT_STATUS gatt_sr_process_app_rsp(tGATT_TCB* p_tcb, tGATT_IF gatt_if,
  * Returns          void
  *
  ******************************************************************************/
-void gatt_process_exec_write_req(tGATT_TCB* p_tcb, uint8_t op_code,
-                                 uint16_t len, uint8_t* p_data) {
+void gatt_process_exec_write_req(tGATT_TCBtcb, 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;
   tGATT_IF gatt_if;
@@ -299,43 +293,36 @@ void gatt_process_exec_write_req(tGATT_TCB* p_tcb, uint8_t op_code,
         "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;
   }
 #endif
 
-  if (len < sizeof(flag)) {
-    android_errorWriteLog(0x534e4554, "73172115");
-    LOG(ERROR) << __func__ << "invalid length";
-    gatt_send_error_rsp(p_tcb, GATT_INVALID_PDU, GATT_REQ_EXEC_WRITE, 0, false);
-    return;
-  }
-
   STREAM_TO_UINT8(flag, p);
 
   /* mask the flag */
   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);
   }
 }
 
@@ -349,8 +336,8 @@ void gatt_process_exec_write_req(tGATT_TCB* p_tcb, uint8_t op_code,
  * 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;
@@ -358,9 +345,9 @@ void gatt_process_read_multi_req(tGATT_TCB* p_tcb, uint8_t op_code,
   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) {
@@ -370,7 +357,7 @@ void gatt_process_read_multi_req(tGATT_TCB* p_tcb, uint8_t op_code,
 
     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;
@@ -378,13 +365,12 @@ void gatt_process_read_multi_req(tGATT_TCB* p_tcb, uint8_t op_code,
 #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,
@@ -405,27 +391,27 @@ void gatt_process_read_multi_req(tGATT_TCB* p_tcb, uint8_t op_code,
     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 */
@@ -438,7 +424,7 @@ void gatt_process_read_multi_req(tGATT_TCB* p_tcb, uint8_t op_code,
   /* 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);
 }
 
 /*******************************************************************************
@@ -452,7 +438,7 @@ void gatt_process_read_multi_req(tGATT_TCB* p_tcb, uint8_t op_code,
  *
  ******************************************************************************/
 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_TCBtcb, 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;
@@ -479,7 +465,7 @@ static tGATT_STATUS gatt_build_primary_service_rsp(
           }
         }
 
-        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)) {
@@ -643,7 +629,7 @@ static tGATT_STATUS gatts_validate_packet_format(
  * Returns          void
  *
  ******************************************************************************/
-void gatts_process_primary_service_req(tGATT_TCB* p_tcb, uint8_t op_code,
+void gatts_process_primary_service_req(tGATT_TCBtcb, 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;
@@ -651,7 +637,7 @@ void gatts_process_primary_service_req(tGATT_TCB* p_tcb, uint8_t op_code,
       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,
@@ -666,7 +652,7 @@ void gatts_process_primary_service_req(tGATT_TCB* p_tcb, uint8_t op_code,
 
       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 {
@@ -686,9 +672,9 @@ void gatts_process_primary_service_req(tGATT_TCB* p_tcb, uint8_t op_code,
 
   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);
 }
 
 /*******************************************************************************
@@ -701,48 +687,48 @@ void gatts_process_primary_service_req(tGATT_TCB* p_tcb, uint8_t op_code,
  * Returns          void
  *
  ******************************************************************************/
-static void gatts_process_find_info(tGATT_TCB* p_tcb, uint8_t op_code,
+static void gatts_process_find_info(tGATT_TCBtcb, 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 = (uint8_t)p_msg->offset;
 
-    p_msg->offset = L2CAP_MIN_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);
 }
 
 /*******************************************************************************
@@ -755,7 +741,7 @@ static void gatts_process_find_info(tGATT_TCB* p_tcb, uint8_t op_code,
  * Returns          void
  *
  ******************************************************************************/
-static void gatts_process_mtu_req(tGATT_TCB* p_tcb, uint16_t len,
+static void gatts_process_mtu_req(tGATT_TCBtcb, uint16_t len,
                                   uint8_t* p_data) {
   uint16_t mtu = 0;
   uint8_t *p = p_data, i;
@@ -763,30 +749,30 @@ static void gatts_process_mtu_req(tGATT_TCB* p_tcb, uint16_t len,
   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 */
@@ -794,10 +780,9 @@ static void gatts_process_mtu_req(tGATT_TCB* p_tcb, uint16_t len,
 
       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);
         }
       }
     }
@@ -819,10 +804,10 @@ static void gatts_process_mtu_req(tGATT_TCB* p_tcb, uint16_t len,
  * 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_TCBtcb, 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;
@@ -838,7 +823,7 @@ void gatts_process_read_by_type_req(tGATT_TCB* p_tcb, uint8_t op_code,
         "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;
@@ -852,16 +837,15 @@ void gatts_process_read_by_type_req(tGATT_TCB* p_tcb, uint8_t op_code,
     *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) {
@@ -884,15 +868,15 @@ void gatts_process_read_by_type_req(tGATT_TCB* p_tcb, uint8_t op_code,
     /* 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_TCBtcb, 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) {
@@ -911,7 +895,7 @@ void gatts_process_write_req(tGATT_TCB* p_tcb, tGATT_SRV_LIST_ELEM& el,
             "%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;
@@ -936,16 +920,16 @@ void gatts_process_write_req(tGATT_TCB* p_tcb, tGATT_SRV_LIST_ELEM& el,
       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) {
@@ -974,7 +958,7 @@ void gatts_process_write_req(tGATT_TCB* p_tcb, tGATT_SRV_LIST_ELEM& el,
    * 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;
 }
@@ -982,23 +966,13 @@ void gatts_process_write_req(tGATT_TCB* p_tcb, tGATT_SRV_LIST_ELEM& el,
 /**
  * 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_TCBtcb, tGATT_SRV_LIST_ELEM& el,
                                    uint8_t op_code, uint16_t handle,
-                                   uint16_t len, uint8_t* p_data) {
-  size_t buf_len = sizeof(BT_HDR) + p_tcb->payload_size + L2CAP_MIN_OFFSET;
+                                   UNUSED_ATTR uint16_t len, uint8_t* p_data) {
+  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;
-
-  if (op_code == GATT_REQ_READ_BLOB && len < sizeof(uint16_t)) {
-    /* Error: packet length is too short */
-    LOG(ERROR) << __func__ << ": packet length=" << len
-               << " too short. min=" << sizeof(uint16_t);
-    android_errorWriteWithInfoLog(0x534e4554, "73172115", -1, NULL, 0);
-    gatt_send_error_rsp(p_tcb, GATT_INVALID_PDU, op_code, 0, false);
-    return;
-  }
-
   BT_HDR* p_msg = (BT_HDR*)osi_calloc(buf_len);
 
   if (op_code == GATT_REQ_READ_BLOB) STREAM_TO_UINT16(offset, p_data);
@@ -1006,12 +980,12 @@ static void gatts_process_read_req(tGATT_TCB* p_tcb, tGATT_SRV_LIST_ELEM& el,
   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;
@@ -1019,12 +993,12 @@ static void gatts_process_read_req(tGATT_TCB* p_tcb, tGATT_SRV_LIST_ELEM& el,
   if (reason != GATT_SUCCESS) {
     osi_free(p_msg);
 
-    /* in theory BUSY is not possible(should already been checked), protected
+    /* 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);
 }
 
 /*******************************************************************************
@@ -1037,8 +1011,8 @@ static void gatts_process_read_req(tGATT_TCB* p_tcb, tGATT_SRV_LIST_ELEM& el,
  * 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;
@@ -1057,7 +1031,7 @@ void gatts_process_attribute_req(tGATT_TCB* p_tcb, uint8_t op_code,
     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;
@@ -1072,14 +1046,14 @@ void gatts_process_attribute_req(tGATT_TCB* p_tcb, uint8_t op_code,
             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:
@@ -1096,7 +1070,7 @@ void gatts_process_attribute_req(tGATT_TCB* p_tcb, uint8_t op_code,
 
   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);
 }
 
 /*******************************************************************************
@@ -1108,13 +1082,13 @@ void gatts_process_attribute_req(tGATT_TCB* p_tcb, uint8_t op_code,
  * 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;
@@ -1135,15 +1109,15 @@ static void gatts_proc_srv_chg_ind_ack(tGATT_TCB* p_tcb) {
  * Returns          void
  *
  ******************************************************************************/
-static void gatts_chk_pending_ind(tGATT_TCB* p_tcb) {
+static void gatts_chk_pending_ind(tGATT_TCBtcb) {
   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));
   }
 }
 
@@ -1157,19 +1131,19 @@ static void gatts_chk_pending_ind(tGATT_TCB* p_tcb) {
  *                  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_TCBtcb, 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;
 }
 
@@ -1183,75 +1157,63 @@ static bool gatts_proc_ind_ack(tGATT_TCB* p_tcb, uint16_t ack_handle) {
  * 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);
-
-    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);
-        }
+  alarm_cancel(tcb.conf_timer);
+  if (!GATT_HANDLE_IS_VALID(handle)) {
+    GATT_TRACE_ERROR("unexpected handle value confirmation");
+    return;
+  }
+
+  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 */
@@ -1260,23 +1222,23 @@ void gatt_server_handle_client_req(tGATT_TCB* p_tcb, uint8_t op_code,
       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:
index 5f1f316..8cb2745 100644 (file)
@@ -102,27 +102,6 @@ void gatt_free_pending_ind(tGATT_TCB* p_tcb) {
 
 /*******************************************************************************
  *
- * Function         gatt_free_pending_enc_queue
- *
- * Description       Free all buffers in pending encyption queue
- *
- * Returns       None
- *
- ******************************************************************************/
-void gatt_free_pending_enc_queue(tGATT_TCB* p_tcb) {
-  GATT_TRACE_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 @@ std::list<tGATT_HDL_LIST_ELEM>::iterator gatt_find_hdl_buffer_by_app_id(
  * 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 @@ tGATT_TCB* gatt_find_tcb_by_addr(BD_ADDR bda, tBT_TRANSPORT transport) {
 
   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 @@ uint8_t gatt_find_i_tcb_free(void) {
  *
  ******************************************************************************/
 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);
+  uint8_t j = gatt_find_i_tcb_by_addr(bda, transport);
+  if (j != GATT_INDEX_INVALID) return &gatt_cb.tcb[j];
+
   /* 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];
-
-    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;
-    }
+  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 @@ bool gatt_parse_uuid_from_cmd(tBT_UUID* p_uuid_rec, uint16_t uuid_size,
  * 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 @@ void gatt_start_conf_timer(tGATT_TCB* p_tcb) {
  * Returns          void
  *
  ******************************************************************************/
-void gatt_start_ind_ack_timer(tGATT_TCB* p_tcb) {
+void gatt_start_ind_ack_timer(tGATT_TCBtcb) {
   /* 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 @@ void gatt_rsp_timeout(void* data) {
       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_indication_confirmation_timeout(void* data) {
  ******************************************************************************/
 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 @@ void gatt_sr_send_req_callback(uint16_t conn_id, uint32_t trans_id,
  * Returns          void
  *
  ******************************************************************************/
-tGATT_STATUS gatt_send_error_rsp(tGATT_TCB* p_tcb, uint8_t err_code,
+tGATT_STATUS gatt_send_error_rsp(tGATT_TCBtcb, uint8_t err_code,
                                  uint8_t op_code, uint16_t handle, bool deq) {
   tGATT_ERROR error;
   tGATT_STATUS status;
@@ -908,13 +864,13 @@ tGATT_STATUS gatt_send_error_rsp(tGATT_TCB* p_tcb, uint8_t err_code,
   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 @@ tGATT_CLCB* gatt_clcb_alloc(uint16_t conn_id) {
 
       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 @@ tGATT_TCB* gatt_find_tcb_by_cid(uint16_t lcid) {
 
 /*******************************************************************************
  *
- * 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 @@ uint8_t gatt_num_clcb_by_bd_addr(BD_ADDR bda) {
   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 @@ void gatt_sr_copy_prep_cnt_to_cback_cnt(tGATT_TCB* p_tcb) {
  * 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 @@ bool gatt_sr_is_cback_cnt_zero(tGATT_TCB* p_tcb) {
  * 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 @@ bool gatt_sr_is_prep_cnt_zero(tGATT_TCB* p_tcb) {
  * 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 @@ void gatt_sr_reset_cback_cnt(tGATT_TCB* p_tcb) {
  * 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 @@ void gatt_sr_reset_prep_cnt(tGATT_TCB* p_tcb) {
  * 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_TCBtcb, 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 @@ void gatt_sr_update_cback_cnt(tGATT_TCB* p_tcb, tGATT_IF gatt_if, bool is_inc,
  * 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_TCBtcb, 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 @@ bool gatt_cancel_open(tGATT_IF gatt_if, BD_ADDR bda) {
       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 @@ bool gatt_cancel_open(tGATT_IF gatt_if, BD_ADDR bda) {
   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;
-
-  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;
+/** 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;
 
-    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 @@ tGATT_CLCB* gatt_cmd_dequeue(tGATT_TCB* p_tcb, uint8_t* p_op_code) {
  * 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 @@ uint8_t gatt_send_write_msg(tGATT_TCB* p_tcb, uint16_t clcb_idx,
   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 @@ void gatt_cleanup_upon_disc(BD_ADDR bda, uint16_t reason,
       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 @@ void gatt_cleanup_upon_disc(BD_ADDR bda, uint16_t reason,
     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 @@ void gatt_cleanup_upon_disc(BD_ADDR bda, uint16_t reason,
                                    transport);
       }
     }
-    memset(p_tcb, 0, sizeof(tGATT_TCB));
+    *p_tcb = tGATT_TCB();
   }
   GATT_TRACE_DEBUG("exit gatt_cleanup_upon_disc ");
 }
@@ -1686,121 +1504,59 @@ void gatt_dbg_display_uuid(tBT_UUID bt_uuid) {
   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
- *
- ******************************************************************************/
-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;
+/** 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) {
+  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 true;
   }
+  // the device is not in the whitelist
 
-  return ret;
+  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 @@ bool gatt_remove_bg_dev_for_app(tGATT_IF gatt_if, BD_ADDR bd_addr) {
   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;
-}
-
-/*******************************************************************************
- *
- * 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;
+  CHECK(BTM_BleUpdateBgConnDev(false, dev_it->remote_bda));
+  gatt_cb.bgconn_dev.erase(dev_it);
+  return true;
 }
 
-/*******************************************************************************
- *
- * 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 @@ void gatt_deregister_bgdev_list(tGATT_IF gatt_if) {
  * 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 @@ bool gatt_update_auto_connect_dev(tGATT_IF gatt_if, bool add, BD_ADDR bd_addr) {
   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 @@ bool gatt_update_auto_connect_dev(tGATT_IF gatt_if, bool add, BD_ADDR bd_addr) {
   }
   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;
-}
index b70cddd..6292baa 100644 (file)
@@ -29,7 +29,6 @@
 #include "hcidefs.h"
 #include "hcimsgs.h"
 
-#include <base/bind.h>
 #include <stddef.h>
 #include <string.h>
 
@@ -1306,32 +1305,6 @@ void btsnd_hcic_read_rssi(uint16_t handle) {
   btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
 }
 
-static void read_encryption_key_size_complete(
-    ReadEncKeySizeCb cb, uint8_t* return_parameters,
-    uint16_t return_parameters_length) {
-  uint8_t status;
-  uint16_t handle;
-  uint8_t key_size;
-  STREAM_TO_UINT8(status, return_parameters);
-  STREAM_TO_UINT16(handle, return_parameters);
-  STREAM_TO_UINT8(key_size, return_parameters);
-
-  std::move(cb).Run(status, handle, key_size);
-}
-
-void btsnd_hcic_read_encryption_key_size(uint16_t handle, ReadEncKeySizeCb cb) {
-  constexpr uint8_t len = 2;
-  uint8_t param[len];
-  memset(param, 0, len);
-
-  uint8_t* p = param;
-  UINT16_TO_STREAM(p, handle);
-
-  btu_hcif_send_cmd_with_cb(
-      FROM_HERE, HCI_READ_ENCR_KEY_SIZE, param, len,
-      base::Bind(&read_encryption_key_size_complete, base::Passed(&cb)));
-}
-
 void btsnd_hcic_enable_test_mode(void) {
   BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
   uint8_t* pp = (uint8_t*)(p + 1);
index 7ee7acf..43f7965 100644 (file)
@@ -122,12 +122,6 @@ bool A2DP_CodecEqualsAac(const uint8_t* p_codec_info_a,
 // 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_GetPacketTimestampAac(const uint8_t* p_codec_info,
 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|.
index c4ab737..15d30d8 100644 (file)
@@ -162,6 +162,17 @@ extern tA2DP_STATUS A2DP_FindService(uint16_t service_uuid, BD_ADDR bd_addr,
 
 /******************************************************************************
  *
+ * 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
index 1c5b261..94871ce 100644 (file)
@@ -579,12 +579,6 @@ bool A2DP_CodecEquals(const uint8_t* p_codec_info_a,
 // 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 @@ const char* A2DP_CodecIndexStr(btav_a2dp_codec_index_t codec_index);
 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)                                 \
index 971523e..a19dd20 100644 (file)
@@ -136,12 +136,6 @@ bool A2DP_CodecEqualsSbc(const uint8_t* p_codec_info_a,
 // 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_GetPacketTimestampSbc(const uint8_t* p_codec_info,
 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|.
index 2a0a6c8..2b90041 100644 (file)
@@ -126,12 +126,6 @@ bool A2DP_VendorCodecEquals(const uint8_t* p_codec_info_a,
 // 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 @@ const char* A2DP_VendorCodecIndexStr(btav_a2dp_codec_index_t codec_index);
 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
index 9fbc5f9..b1bebf0 100644 (file)
@@ -88,12 +88,6 @@ bool A2DP_VendorCodecEqualsAptx(const uint8_t* p_codec_info_a,
 // 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_VendorGetPacketTimestampAptx(const uint8_t* p_codec_info,
 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|.
index 384390c..5a4a748 100644 (file)
@@ -88,12 +88,6 @@ bool A2DP_VendorCodecEqualsAptxHd(const uint8_t* p_codec_info_a,
 // 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 @@ bool A2DP_VendorBuildCodecHeaderAptxHd(const uint8_t* p_codec_info,
                                        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|.
index b3f91f2..5302c07 100644 (file)
@@ -88,12 +88,6 @@ bool A2DP_VendorCodecEqualsLdac(const uint8_t* p_codec_info_a,
 // 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_VendorGetPacketTimestampLdac(const uint8_t* p_codec_info,
 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|.
index 24ee2b3..0efac4f 100644 (file)
 
 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 @@ class AdvertiseDataParser {
       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.
index 24108bc..aaee2da 100644 (file)
@@ -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
index d51161c..b717c5a 100644 (file)
@@ -71,6 +71,7 @@ class BleAdvertisingManager {
 
   static void Initialize(BleAdvertiserHciInterface* interface);
   static void CleanUp();
+  static bool IsInitialized();
   static BleAdvertisingManager* Get();
 
   /* Register an advertising instance, status will be returned in |cb|
index c41fd3d..5540a7e 100644 (file)
@@ -21,7 +21,6 @@
 
 #include <stdbool.h>
 #include <stdint.h>
-#include <string.h>
 
 #ifndef FALSE
 #define FALSE false
 #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*/
@@ -799,7 +795,6 @@ typedef uint8_t tBT_DEVICE_TYPE;
 #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
@@ -1013,13 +1008,4 @@ static inline int bdcmpany(const BD_ADDR a) { return bdcmp(a, bd_addr_any); }
  *
  ******************************************************************************/
 static inline void bdsetany(BD_ADDR a) { bdcpy(a, bd_addr_any); }
-
-static inline bool is_sample_ltk(const BT_OCTET16 ltk) {
-  /* Sample LTK from BT Spec 5.1 | Vol 6, Part C 1
-   * 0x4C68384139F574D836BCF34E9DFB01BF */
-  const uint8_t SAMPLE_LTK[] = {0xbf, 0x01, 0xfb, 0x9d, 0x4e, 0xf3, 0xbc, 0x36,
-                                0xd8, 0x74, 0xf5, 0x39, 0x41, 0x38, 0x68, 0x4c};
-  return memcmp(ltk, SAMPLE_LTK, BT_OCTET16_LEN) == 0;
-}
-
 #endif
index 40f5910..2c0743f 100644 (file)
@@ -1427,16 +1427,15 @@ extern bool BTM_SecAddDevice(BD_ADDR bd_addr, DEV_CLASS dev_class,
                              uint8_t key_type, tBTM_IO_CAP io_cap,
                              uint8_t pin_length);
 
-/** Free resources associated with the device associated with |bd_addr| address.
+/*******************************************************************************
+ *
+ * Function         BTM_SecDeleteDevice
  *
- * *** WARNING ***
- * tBTM_SEC_DEV_REC associated with bd_addr becomes invalid after this function
- * is called, also any of it's fields. i.e. if you use p_dev_rec->bd_addr, it is
- * no longer valid!
- * *** WARNING ***
+ * Description      Free resources associated with the device.
  *
- * Returns true if removed OK, false if not found or ACL link is active.
- */
+ * Returns          true if rmoved OK, false if not found
+ *
+ ******************************************************************************/
 extern bool BTM_SecDeleteDevice(BD_ADDR bd_addr);
 
 /*******************************************************************************
index a4712da..e4a1106 100644 (file)
@@ -49,8 +49,9 @@ enum {
   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;
index ad97239..ee1ede6 100644 (file)
@@ -363,18 +363,6 @@ extern void BTM_ReadConnectionAddr(BD_ADDR remote_bda, BD_ADDR local_conn_addr,
 
 /*******************************************************************************
  *
- * Function         BTM_IsBleConnection
- *
- * Description      This function is called to check if the connection handle
- *                  for an LE link
- *
- * Returns          true if connection is LE link, otherwise false.
- *
- ******************************************************************************/
-extern bool BTM_IsBleConnection(uint16_t conn_handle);
-
-/*******************************************************************************
- *
  * Function         BTM_ReadRemoteConnectionAddr
  *
  * Description      Read the remote device address currently used.
index aef8781..2b6834d 100644 (file)
 
 #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 @@ extern const BD_ADDR BT_BD_ANY;
 /* 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);
index 7954296..024ea54 100644 (file)
@@ -313,18 +313,6 @@ extern uint16_t GAP_ConnGetL2CAPCid(uint16_t gap_handle);
 
 /*******************************************************************************
  *
- * Function         GAP_SetTraceLevel
- *
- * Description      This function sets the trace level for GAP.  If called with
- *                  a value of 0xFF, it simply returns the current trace level.
- *
- * Returns          The new or current trace level
- *
- ******************************************************************************/
-extern uint8_t GAP_SetTraceLevel(uint8_t new_level);
-
-/*******************************************************************************
- *
  * Function         GAP_Init
  *
  * Description      Initializes the control blocks used by GAP.
index 815dce7..18aa91f 100644 (file)
@@ -150,10 +150,6 @@ typedef uint16_t tGATT_DISCONN_REASON;
 #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
index c98e349..0a1984f 100644 (file)
@@ -602,9 +602,6 @@ extern void btsnd_hcic_write_cur_iac_lap(
 
 extern void btsnd_hcic_get_link_quality(uint16_t handle); /* Get Link Quality */
 extern void btsnd_hcic_read_rssi(uint16_t handle);        /* Read RSSI */
-using ReadEncKeySizeCb = base::Callback<void(uint8_t, uint16_t, uint8_t)>;
-extern void btsnd_hcic_read_encryption_key_size(uint16_t handle,
-                                                ReadEncKeySizeCb cb);
 extern void btsnd_hcic_enable_test_mode(
     void); /* Enable Device Under Test Mode */
 extern void btsnd_hcic_write_pagescan_type(
index ecd01d1..dc8cda0 100644 (file)
@@ -293,6 +293,7 @@ void l2cble_scanner_conn_comp(uint16_t handle, BD_ADDR bda, tBLE_ADDR_TYPE type,
     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(
@@ -301,12 +302,14 @@ void l2cble_scanner_conn_comp(uint16_t handle, BD_ADDR bda, tBLE_ADDR_TYPE type,
                    .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);
index 3140265..47714e1 100644 (file)
@@ -24,7 +24,6 @@
  ******************************************************************************/
 
 #include <base/logging.h>
-#include <log/log.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -837,16 +836,7 @@ void l2c_lcc_proc_pdu(tL2C_CCB* p_ccb, BT_HDR* p_buf) {
   }
 
   if (p_ccb->is_first_seg) {
-    if (p_buf->len < sizeof(sdu_length)) {
-      L2CAP_TRACE_ERROR("%s: buffer length=%d too small. Need at least 2.",
-                        __func__, p_buf->len);
-      android_errorWriteWithInfoLog(0x534e4554, "120665616", -1, NULL, 0);
-      /* Discard the buffer */
-      osi_free(p_buf);
-      return;
-    }
     STREAM_TO_UINT16(sdu_length, p);
-
     /* Check the SDU Length with local MTU size */
     if (sdu_length > p_ccb->local_conn_cfg.mtu) {
       /* Discard the buffer */
@@ -854,17 +844,6 @@ void l2c_lcc_proc_pdu(tL2C_CCB* p_ccb, BT_HDR* p_buf) {
       return;
     }
 
-    p_buf->len -= sizeof(sdu_length);
-    p_buf->offset += sizeof(sdu_length);
-
-    if (sdu_length < p_buf->len) {
-      L2CAP_TRACE_ERROR("%s: Invalid sdu_length: %d", __func__, sdu_length);
-      android_errorWriteWithInfoLog(0x534e4554, "112321180", -1, NULL, 0);
-      /* Discard the buffer */
-      osi_free(p_buf);
-      return;
-    }
-
     p_data = (BT_HDR*)osi_malloc(L2CAP_MAX_BUF_SIZE);
     if (p_data == NULL) {
       osi_free(p_buf);
@@ -875,26 +854,12 @@ void l2c_lcc_proc_pdu(tL2C_CCB* p_ccb, BT_HDR* p_buf) {
     p_data->len = 0;
     p_ccb->ble_sdu_length = sdu_length;
     L2CAP_TRACE_DEBUG("%s SDU Length = %d", __func__, sdu_length);
+    p_buf->len -= sizeof(sdu_length);
+    p_buf->offset += sizeof(sdu_length);
     p_data->offset = 0;
 
-  } else {
+  } else
     p_data = p_ccb->ble_sdu;
-    if (p_buf->len > (p_ccb->ble_sdu_length - p_data->len)) {
-      L2CAP_TRACE_ERROR("%s: buffer length=%d too big. max=%d. Dropped",
-                        __func__, p_data->len,
-                        (p_ccb->ble_sdu_length - p_data->len));
-      android_errorWriteWithInfoLog(0x534e4554, "75298652", -1, NULL, 0);
-      osi_free(p_buf);
-
-      /* Throw away all pending fragments and disconnects */
-      p_ccb->is_first_seg = true;
-      osi_free(p_ccb->ble_sdu);
-      p_ccb->ble_sdu = NULL;
-      p_ccb->ble_sdu_length = 0;
-      l2cu_disconnect_chnl(p_ccb);
-      return;
-    }
-  }
 
   memcpy((uint8_t*)(p_data + 1) + p_data->offset + p_data->len,
          (uint8_t*)(p_buf + 1) + p_buf->offset, p_buf->len);
@@ -907,6 +872,9 @@ void l2c_lcc_proc_pdu(tL2C_CCB* p_ccb, BT_HDR* p_buf) {
     p_ccb->ble_sdu_length = 0;
   } else if (p_data->len < p_ccb->ble_sdu_length) {
     p_ccb->is_first_seg = false;
+  } else {
+    L2CAP_TRACE_ERROR("%s Length in the SDU messed up", __func__);
+    // TODO: reset every thing may be???
   }
 
   osi_free(p_buf);
index d6758bb..dde6c8a 100644 (file)
@@ -546,6 +546,14 @@ typedef struct {
 
 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 @@ extern void l2c_process_held_packets(bool timed_out);
 /* 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_set_acl_hci_header(BT_HDR* p_buf, tL2C_CCB* p_ccb);
 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);
 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);
index 7110cff..2730242 100644 (file)
@@ -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 @@ void l2c_link_check_send_pkts(tL2C_LCB* p_lcb, tL2C_CCB* p_ccb, BT_HDR* p_buf) {
 
     /* 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 @@ void l2c_link_check_send_pkts(tL2C_LCB* p_lcb, tL2C_CCB* p_ccb, BT_HDR* p_buf) {
           (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 @@ void l2c_link_check_send_pkts(tL2C_LCB* p_lcb, tL2C_CCB* p_ccb, BT_HDR* p_buf) {
       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 @@ void l2c_link_check_send_pkts(tL2C_LCB* p_lcb, tL2C_CCB* p_ccb, BT_HDR* p_buf) {
 
       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 @@ void l2c_link_check_send_pkts(tL2C_LCB* p_lcb, tL2C_CCB* p_ccb, BT_HDR* p_buf) {
               (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 @@ void l2c_link_check_send_pkts(tL2C_LCB* p_lcb, tL2C_CCB* p_ccb, BT_HDR* p_buf) {
  * 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 @@ static bool l2c_link_send_to_lower(tL2C_LCB* p_lcb, BT_HDR* p_buf) {
   }
 #endif
 
+  if (p_cbi)
+    l2cu_tx_complete(p_cbi);
+
   return true;
 }
 
index 12a4e68..d671110 100644 (file)
@@ -43,6 +43,22 @@ extern fixed_queue_t* btu_general_alarm_queue;
 
 /*******************************************************************************
  *
+ * 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
@@ -2378,14 +2394,14 @@ bool l2cu_set_acl_priority(BD_ADDR bd_addr, uint8_t priority,
       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);
 }
 
@@ -3228,6 +3244,11 @@ static tL2C_CCB* l2cu_get_next_channel(tL2C_LCB* p_lcb) {
 }
 #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
@@ -3238,7 +3259,7 @@ static tL2C_CCB* l2cu_get_next_channel(tL2C_LCB* p_lcb) {
  * 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;
 
@@ -3246,6 +3267,8 @@ BT_HDR* l2cu_get_next_buffer_to_send(tL2C_LCB* p_lcb) {
 #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;
@@ -3274,12 +3297,14 @@ BT_HDR* l2cu_get_next_buffer_to_send(tL2C_LCB* p_lcb) {
       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);
index 8e0ed11..01e1ea4 100644 (file)
@@ -592,11 +592,12 @@ void pan_data_buf_ind_cb(uint16_t handle, uint8_t* src, uint8_t* dst,
       if (pan_cb.pan_data_buf_ind_cb)
         (*pan_cb.pan_data_buf_ind_cb)(pcb->handle, src, dst, protocol, p_buf,
                                       ext, forward);
-      else if (pan_cb.pan_data_ind_cb)
+      else if (pan_cb.pan_data_ind_cb) {
         (*pan_cb.pan_data_ind_cb)(pcb->handle, src, dst, protocol, p_data, len,
                                   ext, forward);
+        osi_free(p_buf);
+      }
 
-      osi_free(p_buf);
       return;
     }
 
@@ -621,10 +622,13 @@ void pan_data_buf_ind_cb(uint16_t handle, uint8_t* src, uint8_t* dst,
   if (pan_cb.pan_data_buf_ind_cb)
     (*pan_cb.pan_data_buf_ind_cb)(pcb->handle, src, dst, protocol, p_buf, ext,
                                   forward);
-  else if (pan_cb.pan_data_ind_cb)
+  else if (pan_cb.pan_data_ind_cb) {
     (*pan_cb.pan_data_ind_cb)(pcb->handle, src, dst, protocol, p_data, len, ext,
                               forward);
-  osi_free(p_buf);
+    osi_free(p_buf);
+  } else
+    osi_free(p_buf);
+
   return;
 }
 
index 20e6a88..32fabec 100644 (file)
@@ -231,10 +231,13 @@ void port_release_port(tPORT* p_port) {
     }
 
     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);
index de80190..d85ef34 100644 (file)
@@ -29,6 +29,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};
@@ -45,37 +46,14 @@ static bool lmp_version_below(BD_ADDR bda, uint8_t version) {
 }
 
 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;
 }
 
 /*******************************************************************************
@@ -1580,12 +1558,21 @@ void smp_process_peer_nonce(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
   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:
@@ -1613,7 +1600,8 @@ void smp_process_peer_nonce(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
       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;
index ebd300b..ae9b8ab 100644 (file)
@@ -212,10 +212,9 @@ bool SMP_PairCancel(BD_ADDR bd_addr) {
   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);
index cb46546..026b98c 100644 (file)
@@ -317,7 +317,8 @@ bool smp_send_msg_to_L2CAP(BD_ADDR rem_bda, BT_HDR* p_toL2CAP) {
   l2cap_ret = L2CA_SendFixedChnlData(fixed_cid, rem_bda, p_toL2CAP);
   if (l2cap_ret == L2CAP_DW_FAILED) {
     smp_cb.total_tx_unacked -= 1;
-    SMP_TRACE_ERROR("SMP failed to pass msg to L2CAP");
+    SMP_TRACE_ERROR("SMP   failed to pass msg:0x%0x to L2CAP",
+                    *((uint8_t*)(p_toL2CAP + 1) + p_toL2CAP->offset));
     return false;
   } else
     return true;
index 46ff3ec..ab6df56 100644 (file)
@@ -23,9 +23,9 @@ TEST(AdvertiseDataParserTest, IsValidEmpty) {
   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 @@ TEST(AdvertiseDataParserTest, IsValidBad) {
   // 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 @@ TEST(AdvertiseDataParserTest, IsValidGood) {
   // 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 @@ TEST(AdvertiseDataParserTest, GetFieldByType) {
   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
index 06808d1..3808df4 100644 (file)
@@ -46,6 +46,26 @@ const uint8_t codec_info_sbc[AVDT_CODEC_SIZE] = {
     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_bits_set) {
 
 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_sbc) {
 
 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_get_codec_type) {
 
 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_sink_codec_supported) {
 
 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 @@ TEST_F(StackA2dpTest, test_a2dp_codec_name) {
 
   // 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_vendor) {
 }
 
 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 @@ TEST_F(StackA2dpTest, test_a2dp_get_track_sample_rate) {
   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_sampling_frequency_code_sbc) {
 
 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_min_bitpool_sbc) {
 
 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 @@ TEST_F(StackA2dpTest, test_a2dp_source_codec_index) {
   // 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 @@ TEST_F(StackA2dpTest, test_a2dp_init_codec_config) {
   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 @@ TEST_F(A2dpCodecConfigTest, setCodecConfig) {
   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 @@ TEST_F(A2dpCodecConfigTest, setCodecConfig) {
   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 (file)
index 0000000..9d72509
--- /dev/null
@@ -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"));
+}
index f8488d7..9df3d47 100755 (executable)
@@ -7,13 +7,16 @@ known_tests=(
   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=(
index a576901..e4d3a2b 100644 (file)
@@ -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 @@ cc_test {
         "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 (file)
index 0000000..eee642a
--- /dev/null
@@ -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 (file)
index 0000000..b3f7461
--- /dev/null
@@ -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 (file)
index 0000000..1357a93
--- /dev/null
@@ -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 (file)
index 0000000..aca07dd
--- /dev/null
@@ -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 (file)
index 0000000..a5fef31
--- /dev/null
@@ -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 (file)
index 0000000..29e50dc
--- /dev/null
@@ -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 (file)
index 0000000..23dfa37
--- /dev/null
@@ -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 (file)
index 0000000..8842c04
--- /dev/null
@@ -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 (file)
index 0000000..2d71ee6
--- /dev/null
@@ -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 (file)
index 0000000..1fb6412
--- /dev/null
@@ -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 (file)
index 0000000..a852d52
--- /dev/null
@@ -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 (file)
index 0000000..e7b8083
--- /dev/null
@@ -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 (file)
index 0000000..7dadc34
--- /dev/null
@@ -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 (file)
index 0000000..c7abd55
--- /dev/null
@@ -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;
+}