Merge "Enable 2-EV3 packets for Wide Band HFP client"
diff --git a/binder/Android.bp b/binder/Android.bp
index 18428c2..faae3a8 100644
--- a/binder/Android.bp
+++ b/binder/Android.bp
@@ -8,7 +8,6 @@
srcs: [
"android/bluetooth/bluetooth_device.cc",
"android/bluetooth/IBluetoothSocketManager.aidl",
- "android/os/parcel_file_descriptor.cc",
"android/os/parcel_uuid.cc",
/* TODO: Uncomment this files as they get converted one-by-one into native implementation
"android/bluetooth/IBluetooth.aidl",
diff --git a/binder/android/os/parcel_file_descriptor.cc b/binder/android/os/parcel_file_descriptor.cc
deleted file mode 100644
index 37bef6d..0000000
--- a/binder/android/os/parcel_file_descriptor.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-//
-// Copyright 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 "android/os/parcel_file_descriptor.h"
-#include <base/logging.h>
-
-using android::OK;
-using android::Parcel;
-using android::status_t;
-
-namespace android {
-namespace os {
-
-status_t ParcelFileDescriptor::writeToParcel(Parcel* parcel) const {
- CHECK(fd_ >= 0);
- return parcel->writeParcelFileDescriptor(fd_, takeOwnership_);
-}
-
-status_t ParcelFileDescriptor::readFromParcel(const Parcel* parcel) {
- LOG(FATAL) << "Don't know how to read ParcelFileDescriptor";
- return OK;
-}
-
-void ParcelFileDescriptor::setFileDescriptor(int fd, bool takeOwnership) {
- fd_ = fd;
- takeOwnership_ = takeOwnership;
-}
-
-} // namespace os
-} // namespace android
diff --git a/binder/android/os/parcel_file_descriptor.h b/binder/android/os/parcel_file_descriptor.h
deleted file mode 100644
index a37b49c..0000000
--- a/binder/android/os/parcel_file_descriptor.h
+++ /dev/null
@@ -1,52 +0,0 @@
-//
-// Copyright 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 <binder/Parcel.h>
-#include <binder/Parcelable.h>
-
-namespace android {
-namespace os {
-
-class ParcelFileDescriptor : public android::Parcelable {
- public:
- ParcelFileDescriptor() : fd_(-1), takeOwnership_(false) {}
- ~ParcelFileDescriptor() = default;
-
- // Write |this| parcelable to the given |parcel|. Keep in mind that
- // implementations of writeToParcel must be manually kept in sync
- // with readFromParcel and the Java equivalent versions of these methods.
- //
- // Returns android::OK on success and an appropriate error otherwise.
- android::status_t writeToParcel(android::Parcel* parcel) const override;
-
- // Read data from the given |parcel| into |this|. After readFromParcel
- // completes, |this| should have equivalent state to the object that
- // wrote itself to the parcel.
- //
- // Returns android::OK on success and an appropriate error otherwise.
- android::status_t readFromParcel(const android::Parcel* parcel) override;
-
- void setFileDescriptor(int fd, bool takeOwnership);
-
- private:
- int fd_;
- bool takeOwnership_;
-};
-
-} // namespace os
-} // namespace android
diff --git a/bta/Android.bp b/bta/Android.bp
index d6919de..57f2b61 100644
--- a/bta/Android.bp
+++ b/bta/Android.bp
@@ -68,6 +68,8 @@
"gatt/bta_gatts_api.cc",
"gatt/bta_gatts_main.cc",
"gatt/bta_gatts_utils.cc",
+ "gatt/database.cc",
+ "gatt/database_builder.cc",
"hearing_aid/hearing_aid.cc",
"hearing_aid/hearing_aid_audio_source.cc",
"hf_client/bta_hf_client_act.cc",
@@ -127,7 +129,9 @@
defaults: ["fluoride_bta_defaults"],
srcs: [
"test/bta_hf_client_test.cc",
- "test/gatt_cache_file_test.cc",
+ "test/gatt/database_builder_test.cc",
+ "test/gatt/database_builder_sample_device_test.cc",
+ "test/gatt/database_test.cc",
],
shared_libs: [
"liblog",
diff --git a/bta/BUILD.gn b/bta/BUILD.gn
index e519b69..648322f 100644
--- a/bta/BUILD.gn
+++ b/bta/BUILD.gn
@@ -49,6 +49,8 @@
"gatt/bta_gatts_api.cc",
"gatt/bta_gatts_main.cc",
"gatt/bta_gatts_utils.cc",
+ "gatt/database.cc",
+ "gatt/database_builder.cc",
"hearing_aid/hearing_aid.cc",
"hearing_aid/hearing_aid_audio_source.cc",
"hf_client/bta_hf_client_act.cc",
@@ -101,6 +103,8 @@
"include",
"sys",
"//",
+ "//linux_include",
+ "//bta",
"//internal_include",
"//btcore/include",
"//hci/include",
@@ -121,5 +125,31 @@
deps = [
"//third_party/libchrome:base"
]
-
}
+
+executable("net_test_bta") {
+ testonly = true
+ sources = [
+ "test/gatt/database_builder_test.cc",
+ "test/gatt/database_builder_sample_device_test.cc",
+ "test/gatt/database_test.cc",
+ "gatt/database.cc",
+ "gatt/database_builder.cc",
+ ]
+
+ include_dirs = [
+ "include",
+ "//",
+ "//bta",
+ "//btcore/include",
+ "//hci/include",
+ "//internal_include",
+ "//stack/btm",
+ ]
+
+ deps = [
+ "//types",
+ "//third_party/googletest:gmock_main",
+ "//third_party/libchrome:base",
+ ]
+}
\ No newline at end of file
diff --git a/bta/ag/bta_ag_sco.cc b/bta/ag/bta_ag_sco.cc
index 0e3f30a..1ff4c7e 100644
--- a/bta/ag/bta_ag_sco.cc
+++ b/bta/ag/bta_ag_sco.cc
@@ -370,6 +370,12 @@
if (!bta_ag_sco_is_active_device(p_scb->peer_addr)) {
LOG(WARNING) << __func__ << ": device " << p_scb->peer_addr
<< " is not active, active_device=" << active_device_addr;
+ if (bta_ag_cb.sco.p_curr_scb != nullptr &&
+ bta_ag_cb.sco.p_curr_scb->in_use && p_scb == bta_ag_cb.sco.p_curr_scb) {
+ do_in_bta_thread(
+ FROM_HERE, base::Bind(&bta_ag_sm_execute, p_scb, BTA_AG_SCO_CLOSE_EVT,
+ tBTA_AG_DATA::kEmpty));
+ }
return;
}
/* Make sure this SCO handle is not already in use */
@@ -555,6 +561,14 @@
APPL_TRACE_DEBUG("%s", __func__);
bta_ag_cb.sco.p_curr_scb = p_scb;
+ // Workaround for misbehaving HFs such as Sony XAV AX100 car kit and Sony
+ // MW600 Headset, which indicate WBS support in SDP, but no codec
+ // negotiation support in BRSF. In this case, using mSBC codec can result
+ // background noise or no audio. Thus, defaulting to CVSD instead.
+ if (!(p_scb->peer_features & BTA_AG_PEER_FEAT_CODEC)) {
+ p_scb->sco_codec = UUID_CODEC_CVSD;
+ }
+
if ((p_scb->codec_updated || p_scb->codec_fallback) &&
(p_scb->peer_features & BTA_AG_PEER_FEAT_CODEC)) {
/* Change the power mode to Active until SCO open is completed. */
diff --git a/bta/av/bta_av_aact.cc b/bta/av/bta_av_aact.cc
index 997f021..297bba4 100644
--- a/bta/av/bta_av_aact.cc
+++ b/bta/av/bta_av_aact.cc
@@ -294,6 +294,9 @@
*
******************************************************************************/
static void notify_start_failed(tBTA_AV_SCB* p_scb) {
+ LOG_ERROR(LOG_TAG, "%s: peer %s role:0x%x channel:%d handle:0x%x", __func__,
+ p_scb->PeerAddress().ToString().c_str(), p_scb->role, p_scb->chnl,
+ p_scb->hndl);
tBTA_AV_START start;
/* if start failed, clear role */
p_scb->role &= ~BTA_AV_ROLE_START_INT;
@@ -675,7 +678,8 @@
void bta_av_role_res(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
bool initiator = false;
- APPL_TRACE_DEBUG("%s: q_tag:%d, wait:0x%x, role:0x%x", __func__, p_scb->q_tag,
+ APPL_TRACE_DEBUG("%s: peer %s q_tag:%d, wait:0x%x, role:0x%x", __func__,
+ p_scb->PeerAddress().ToString().c_str(), p_scb->q_tag,
p_scb->wait, p_scb->role);
if (p_scb->role & BTA_AV_ROLE_START_INT) initiator = true;
@@ -726,12 +730,14 @@
}
} else {
APPL_TRACE_WARNING(
- "%s: unexpected role switch event: q_tag = %d wait = %d", __func__,
- p_scb->q_tag, p_scb->wait);
+ "%s: peer %s unexpected role switch event: q_tag = %d wait = 0x%x",
+ __func__, p_scb->PeerAddress().ToString().c_str(), p_scb->q_tag,
+ p_scb->wait);
}
}
- APPL_TRACE_DEBUG("%s: wait:0x%x, role:0x%x", __func__, p_scb->wait,
+ APPL_TRACE_DEBUG("%s: peer %s wait:0x%x, role:0x%x", __func__,
+ p_scb->PeerAddress().ToString().c_str(), p_scb->wait,
p_scb->role);
}
@@ -886,7 +892,8 @@
tBTA_AV_CONN_CHG msg;
uint8_t role = BTA_AV_ROLE_AD_INT;
- APPL_TRACE_DEBUG("%s", __func__);
+ LOG_INFO(LOG_TAG, "%s peer %s", __func__,
+ p_scb->PeerAddress().ToString().c_str());
/* free any buffers */
p_scb->sdp_discovery_started = false;
@@ -1830,8 +1837,11 @@
uint8_t clear_policy = 0;
uint8_t cur_role;
- APPL_TRACE_DEBUG("%s: sco_occupied:%d, role:0x%x, started:%d", __func__,
- bta_av_cb.sco_occupied, p_scb->role, p_scb->started);
+ LOG_INFO(LOG_TAG,
+ "%s: peer %s sco_occupied:%s role:0x%x started:%s wait:0x%x",
+ __func__, p_scb->PeerAddress().ToString().c_str(),
+ logbool(bta_av_cb.sco_occupied).c_str(), p_scb->role,
+ logbool(p_scb->started).c_str(), p_scb->wait);
if (bta_av_cb.sco_occupied) {
bta_av_start_failed(p_scb, p_data);
return;
@@ -1847,23 +1857,50 @@
bta_sys_clear_policy(BTA_ID_AV, clear_policy, p_scb->PeerAddress());
- if ((!p_scb->started) && ((p_scb->role & BTA_AV_ROLE_START_INT) == 0)) {
+ if (p_scb->started) {
p_scb->role |= BTA_AV_ROLE_START_INT;
- bta_sys_busy(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->PeerAddress());
-
- AVDT_StartReq(&p_scb->avdt_handle, 1);
- } else if (p_scb->started) {
- p_scb->role |= BTA_AV_ROLE_START_INT;
- if (p_scb->wait == 0) {
- if (p_scb->role & BTA_AV_ROLE_SUSPEND) {
- notify_start_failed(p_scb);
- } else {
- bta_av_start_ok(p_scb, NULL);
- }
+ if (p_scb->wait != 0) {
+ LOG_WARN(
+ LOG_TAG,
+ "%s: peer %s start stream request ignored: "
+ "already waiting: sco_occupied:%s role:0x%x started:%s wait:0x%x",
+ __func__, p_scb->PeerAddress().ToString().c_str(),
+ logbool(bta_av_cb.sco_occupied).c_str(), p_scb->role,
+ logbool(p_scb->started).c_str(), p_scb->wait);
+ return;
}
+ if (p_scb->role & BTA_AV_ROLE_SUSPEND) {
+ notify_start_failed(p_scb);
+ } else {
+ bta_av_start_ok(p_scb, NULL);
+ }
+ return;
}
- APPL_TRACE_DEBUG("%s: started %d role:0x%x", __func__, p_scb->started,
- p_scb->role);
+
+ if ((p_scb->role & BTA_AV_ROLE_START_INT) != 0) {
+ LOG_WARN(
+ LOG_TAG,
+ "%s: peer %s start stream request ignored: "
+ "already initiated: sco_occupied:%s role:0x%x started:%s wait:0x%x",
+ __func__, p_scb->PeerAddress().ToString().c_str(),
+ logbool(bta_av_cb.sco_occupied).c_str(), p_scb->role,
+ logbool(p_scb->started).c_str(), p_scb->wait);
+ return;
+ }
+
+ p_scb->role |= BTA_AV_ROLE_START_INT;
+ bta_sys_busy(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->PeerAddress());
+ uint16_t result = AVDT_StartReq(&p_scb->avdt_handle, 1);
+ if (result != AVDT_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: AVDT_StartReq failed for peer %s result:%d",
+ __func__, p_scb->PeerAddress().ToString().c_str(), result);
+ }
+ LOG_INFO(LOG_TAG,
+ "%s: peer %s start requested: sco_occupied:%s role:0x%x "
+ "started:%s wait:0x%x",
+ __func__, p_scb->PeerAddress().ToString().c_str(),
+ logbool(bta_av_cb.sco_occupied).c_str(), p_scb->role,
+ logbool(p_scb->started).c_str(), p_scb->wait);
}
/*******************************************************************************
@@ -1924,7 +1961,8 @@
suspend_rsp.hndl = p_scb->hndl;
if (p_data && p_data->api_stop.suspend) {
- APPL_TRACE_DEBUG("%s: suspending: %d, sup:%d", __func__, start,
+ APPL_TRACE_DEBUG("%s: peer %s suspending: %d, sup:%d", __func__,
+ p_scb->PeerAddress().ToString().c_str(), start,
p_scb->suspend_sup);
if ((start) && (p_scb->suspend_sup)) {
sus_evt = false;
@@ -2190,9 +2228,9 @@
uint8_t cur_role;
uint8_t local_tsep = p_scb->seps[p_scb->sep_idx].tsep;
- APPL_TRACE_DEBUG("%s: peer %s handle:%d wait:0x%x role:0x%x local_tsep:%d",
- __func__, p_scb->PeerAddress().ToString().c_str(),
- p_scb->hndl, p_scb->wait, p_scb->role, local_tsep);
+ LOG_INFO(LOG_TAG, "%s: peer %s handle:%d wait:0x%x role:0x%x local_tsep:%d",
+ __func__, p_scb->PeerAddress().ToString().c_str(), p_scb->hndl,
+ p_scb->wait, p_scb->role, local_tsep);
p_scb->started = true;
@@ -2870,6 +2908,12 @@
******************************************************************************/
void bta_av_chk_2nd_start(tBTA_AV_SCB* p_scb,
UNUSED_ATTR tBTA_AV_DATA* p_data) {
+ LOG_INFO(LOG_TAG,
+ "%s: peer %s channel:%d bta_av_cb.audio_open_cnt:%d role:0x%x "
+ "features:0x%x",
+ __func__, p_scb->PeerAddress().ToString().c_str(), p_scb->chnl,
+ bta_av_cb.audio_open_cnt, p_scb->role, bta_av_cb.features);
+
if ((p_scb->chnl == BTA_AV_CHNL_AUDIO) && (bta_av_cb.audio_open_cnt >= 2) &&
(((p_scb->role & BTA_AV_ROLE_AD_ACP) == 0) || // Outgoing connection or
(bta_av_cb.features & BTA_AV_FEAT_ACP_START))) { // Auto-starting option
@@ -2880,10 +2924,18 @@
bool new_started = false;
for (int i = 0; i < BTA_AV_NUM_STRS; i++) {
tBTA_AV_SCB* p_scbi = bta_av_cb.p_scb[i];
+ if (p_scb == p_scbi) {
+ continue;
+ }
if (p_scbi && p_scbi->chnl == BTA_AV_CHNL_AUDIO && p_scbi->co_started) {
if (!new_started) {
// Start the new stream
new_started = true;
+ LOG_INFO(LOG_TAG,
+ "%s: starting new stream for peer %s because peer %s "
+ "already started",
+ __func__, p_scb->PeerAddress().ToString().c_str(),
+ p_scbi->PeerAddress().ToString().c_str());
bta_av_ssm_execute(p_scb, BTA_AV_AP_START_EVT, NULL);
}
// May need to update the flush timeout of this already started stream
diff --git a/bta/av/bta_av_act.cc b/bta/av/bta_av_act.cc
index bdfbb65..dfa85a2 100644
--- a/bta/av/bta_av_act.cc
+++ b/bta/av/bta_av_act.cc
@@ -1075,8 +1075,9 @@
void bta_av_stream_chg(tBTA_AV_SCB* p_scb, bool started) {
uint8_t started_msk = BTA_AV_HNDL_TO_MSK(p_scb->hdi);
- APPL_TRACE_DEBUG("%s: started:%d started_msk:x%x", __func__, started,
- started_msk);
+ APPL_TRACE_DEBUG("%s: peer %s started:%s started_msk:0x%x", __func__,
+ p_scb->PeerAddress().ToString().c_str(),
+ logbool(started).c_str(), started_msk);
if (started) {
bta_av_cb.audio_streams |= started_msk;
diff --git a/bta/av/bta_av_api.cc b/bta/av/bta_av_api.cc
index 73ffc8d..bb5cca4 100644
--- a/bta/av/bta_av_api.cc
+++ b/bta/av/bta_av_api.cc
@@ -24,6 +24,8 @@
*
******************************************************************************/
+#define LOG_TAG "bt_bta_av"
+
#include <base/logging.h>
#include "bt_target.h"
@@ -36,6 +38,7 @@
#include "bta_sys.h"
#include "osi/include/allocator.h"
+#include "osi/include/log.h"
/*****************************************************************************
* Constants
@@ -153,9 +156,9 @@
******************************************************************************/
void BTA_AvOpen(const RawAddress& bd_addr, tBTA_AV_HNDL handle, bool use_rc,
tBTA_SEC sec_mask, uint16_t uuid) {
- APPL_TRACE_DEBUG("%s: peer %s handle:0x%x use_rc=%s sec_mask=0x%x uuid=0x%x",
- __func__, bd_addr.ToString().c_str(), handle,
- (use_rc) ? "true" : "false", sec_mask, uuid)
+ LOG_INFO(LOG_TAG, "%s: peer %s handle:0x%x use_rc=%s sec_mask=0x%x uuid=0x%x",
+ __func__, bd_addr.ToString().c_str(), handle,
+ (use_rc) ? "true" : "false", sec_mask, uuid);
tBTA_AV_API_OPEN* p_buf =
(tBTA_AV_API_OPEN*)osi_malloc(sizeof(tBTA_AV_API_OPEN));
@@ -181,7 +184,7 @@
*
******************************************************************************/
void BTA_AvClose(tBTA_AV_HNDL handle) {
- APPL_TRACE_DEBUG("%s: handle:0x%x", __func__, handle);
+ LOG_INFO(LOG_TAG, "%s: handle:0x%x", __func__, handle);
BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
@@ -201,6 +204,8 @@
*
******************************************************************************/
void BTA_AvDisconnect(const RawAddress& bd_addr) {
+ LOG_INFO(LOG_TAG, "%s: peer %s", __func__, bd_addr.ToString().c_str());
+
tBTA_AV_API_DISCNT* p_buf =
(tBTA_AV_API_DISCNT*)osi_malloc(sizeof(tBTA_AV_API_DISCNT));
@@ -220,6 +225,8 @@
*
******************************************************************************/
void BTA_AvStart(tBTA_AV_HNDL handle) {
+ LOG_INFO(LOG_TAG, "%s: handle=%d", __func__, handle);
+
BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
p_buf->event = BTA_AV_API_START_EVT;
@@ -238,6 +245,8 @@
*
******************************************************************************/
void BTA_AvOffloadStart(tBTA_AV_HNDL hndl) {
+ LOG_INFO(LOG_TAG, "%s: handle=%d", __func__, hndl);
+
BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
p_buf->event = BTA_AV_API_OFFLOAD_START_EVT;
@@ -278,6 +287,9 @@
*
******************************************************************************/
void BTA_AvStop(tBTA_AV_HNDL handle, bool suspend) {
+ LOG_INFO(LOG_TAG, "%s: handle=%d suspend=%s", __func__, handle,
+ logbool(suspend).c_str());
+
tBTA_AV_API_STOP* p_buf =
(tBTA_AV_API_STOP*)osi_malloc(sizeof(tBTA_AV_API_STOP));
@@ -306,6 +318,9 @@
void BTA_AvReconfig(tBTA_AV_HNDL hndl, bool suspend, uint8_t sep_info_idx,
uint8_t* p_codec_info, uint8_t num_protect,
const uint8_t* p_protect_info) {
+ LOG_INFO(LOG_TAG, "%s: handle=%d suspend=%s sep_info_idx=%d", __func__, hndl,
+ logbool(suspend).c_str(), sep_info_idx);
+
tBTA_AV_API_RCFG* p_buf =
(tBTA_AV_API_RCFG*)osi_malloc(sizeof(tBTA_AV_API_RCFG) + num_protect);
diff --git a/bta/av/bta_av_main.cc b/bta/av/bta_av_main.cc
index e3b74db..6f11dca 100644
--- a/bta/av/bta_av_main.cc
+++ b/bta/av/bta_av_main.cc
@@ -839,6 +839,13 @@
}
}
}
+
+ LOG_INFO(LOG_TAG,
+ "%s: peer %s channel:%d bta_av_cb.audio_open_cnt:%d role:0x%x "
+ "features:0x%x start:%s",
+ __func__, p_scb->PeerAddress().ToString().c_str(), p_scb->chnl,
+ bta_av_cb.audio_open_cnt, p_scb->role, bta_av_cb.features,
+ logbool(start).c_str());
return start;
}
@@ -1078,10 +1085,11 @@
bool is_ok = true;
if (BTM_GetRole(p_scb->PeerAddress(), &role) == BTM_SUCCESS) {
- LOG_INFO(LOG_TAG,
- "%s: hndl:x%x role:%d conn_audio:x%x bits:%d features:x%x",
- __func__, p_scb->hndl, role, bta_av_cb.conn_audio, bits,
- bta_av_cb.features);
+ LOG_INFO(
+ LOG_TAG,
+ "%s: peer %s hndl:0x%x role:%d conn_audio:0x%x bits:%d features:0x%x",
+ __func__, p_scb->PeerAddress().ToString().c_str(), p_scb->hndl, role,
+ bta_av_cb.conn_audio, bits, bta_av_cb.features);
if (BTM_ROLE_MASTER != role &&
(A2DP_BitsSet(bta_av_cb.conn_audio) > bits ||
(bta_av_cb.features & BTA_AV_FEAT_MASTER))) {
@@ -1089,9 +1097,13 @@
bta_sys_clear_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH,
p_scb->PeerAddress());
- if (BTM_CMD_STARTED !=
- BTM_SwitchRole(p_scb->PeerAddress(), BTM_ROLE_MASTER, NULL)) {
+ tBTM_STATUS status =
+ BTM_SwitchRole(p_scb->PeerAddress(), BTM_ROLE_MASTER, NULL);
+ if (status != BTM_CMD_STARTED) {
/* can not switch role on SCB - start the timer on SCB */
+ LOG_ERROR(LOG_TAG,
+ "%s: peer %s BTM_SwitchRole(BTM_ROLE_MASTER) error: %d",
+ __func__, p_scb->PeerAddress().ToString().c_str(), status);
}
is_ok = false;
p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_START;
diff --git a/bta/dm/bta_dm_act.cc b/bta/dm/bta_dm_act.cc
index a78a944..3460ecc 100644
--- a/bta/dm/bta_dm_act.cc
+++ b/bta/dm/bta_dm_act.cc
@@ -72,7 +72,7 @@
BD_NAME bd_name, bool min_16_digit);
static uint8_t bta_dm_new_link_key_cback(const RawAddress& bd_addr,
DEV_CLASS dev_class, BD_NAME bd_name,
- LINK_KEY key, uint8_t key_type);
+ const LinkKey& key, uint8_t key_type);
static uint8_t bta_dm_authentication_complete_cback(const RawAddress& bd_addr,
DEV_CLASS dev_class,
BD_NAME bd_name,
@@ -343,7 +343,6 @@
DEV_CLASS dev_class;
tBTA_DM_SEC_CBACK* temp_cback;
uint8_t key_mask = 0;
- BT_OCTET16 er;
tBTA_BLE_LOCAL_ID_KEYS id_key;
APPL_TRACE_DEBUG("%s with event: %i", __func__, status);
@@ -406,7 +405,8 @@
BTM_SetDeviceClass(dev_class);
/* load BLE local information: ID keys, ER if available */
- bta_dm_co_ble_load_local_keys(&key_mask, er, &id_key);
+ Octet16 er;
+ bta_dm_co_ble_load_local_keys(&key_mask, &er, &id_key);
if (key_mask & BTA_BLE_LOCAL_KEY_TYPE_ER) {
BTM_BleLoadLocalKeys(BTA_BLE_LOCAL_KEY_TYPE_ER,
@@ -705,11 +705,10 @@
* Description This function adds a Link Key to an security database entry.
* It is normally called during host startup to restore all
* required information stored in the NVRAM.
- ***
******************************************************************************/
void bta_dm_add_device(std::unique_ptr<tBTA_DM_API_ADD_DEVICE> msg) {
uint8_t* p_dc = NULL;
- uint8_t* p_lc = NULL;
+ LinkKey* p_lc = NULL;
uint32_t trusted_services_mask[BTM_SEC_SERVICE_ARRAY_SIZE];
uint8_t index = 0;
uint8_t btm_mask_index = 0;
@@ -719,7 +718,7 @@
/* If not all zeros, the device class has been specified */
if (msg->dc_known) p_dc = (uint8_t*)msg->dc;
- if (msg->link_key_known) p_lc = (uint8_t*)msg->link_key;
+ if (msg->link_key_known) p_lc = &msg->link_key;
if (msg->is_trusted) {
/* covert BTA service mask to BTM mask */
@@ -2365,7 +2364,7 @@
******************************************************************************/
static uint8_t bta_dm_new_link_key_cback(const RawAddress& bd_addr,
UNUSED_ATTR DEV_CLASS dev_class,
- BD_NAME bd_name, LINK_KEY key,
+ BD_NAME bd_name, const LinkKey& key,
uint8_t key_type) {
tBTA_DM_SEC sec_event;
tBTA_DM_AUTH_CMPL* p_auth_cmpl;
@@ -2382,12 +2381,10 @@
memcpy(p_auth_cmpl->bd_name, bd_name, (BD_NAME_LEN - 1));
p_auth_cmpl->bd_name[BD_NAME_LEN - 1] = 0;
-
p_auth_cmpl->key_present = true;
p_auth_cmpl->key_type = key_type;
p_auth_cmpl->success = true;
-
- memcpy(p_auth_cmpl->key, key, LINK_KEY_LEN);
+ p_auth_cmpl->key = key;
sec_event.auth_cmpl.fail_reason = HCI_SUCCESS;
// Report the BR link key based on the BR/EDR address and type
@@ -2659,8 +2656,10 @@
tBTA_DM_PEER_DEVICE* p_dev = bta_dm_find_peer_device(bd_addr);
if (!p_dev) return;
- APPL_TRACE_DEBUG("role chg info:x%x new_role:%d dev count:%d", p_dev->info,
- new_role, bta_dm_cb.device_list.count);
+ LOG_INFO(LOG_TAG,
+ "%s: peer %s info:0x%x new_role:0x%x dev count:%d hci_status=%d",
+ __func__, bd_addr.ToString().c_str(), p_dev->info, new_role,
+ bta_dm_cb.device_list.count, hci_status);
if (p_dev->info & BTA_DM_DI_AV_ACTIVE) {
bool need_policy_change = false;
@@ -3850,6 +3849,8 @@
bta_dm_remove_sec_dev_entry(bda);
} else {
sec_event.auth_cmpl.success = true;
+ if (!p_data->complt.smp_over_br)
+ GATT_ConfigServiceChangeCCC(bda, true, BT_TRANSPORT_LE);
}
if (bta_dm_cb.p_sec_cback) {
diff --git a/bta/dm/bta_dm_api.cc b/bta/dm/bta_dm_api.cc
index e968bd1..0740da0 100644
--- a/bta/dm/bta_dm_api.cc
+++ b/bta/dm/bta_dm_api.cc
@@ -296,7 +296,7 @@
*
******************************************************************************/
void BTA_DmAddDevice(const RawAddress& bd_addr, DEV_CLASS dev_class,
- LINK_KEY link_key, tBTA_SERVICE_MASK trusted_mask,
+ const LinkKey& link_key, tBTA_SERVICE_MASK trusted_mask,
bool is_trusted, uint8_t key_type, tBTA_IO_CAP io_cap,
uint8_t pin_length) {
std::unique_ptr<tBTA_DM_API_ADD_DEVICE> msg =
@@ -306,12 +306,9 @@
msg->tm = trusted_mask;
msg->is_trusted = is_trusted;
msg->io_cap = io_cap;
-
- if (link_key) {
- msg->link_key_known = true;
- msg->key_type = key_type;
- memcpy(msg->link_key, link_key, LINK_KEY_LEN);
- }
+ msg->link_key_known = true;
+ msg->key_type = key_type;
+ msg->link_key = link_key;
/* Load device class if specified */
if (dev_class) {
diff --git a/bta/dm/bta_dm_ci.cc b/bta/dm/bta_dm_ci.cc
index 3d40480..16174c0 100644
--- a/bta/dm/bta_dm_ci.cc
+++ b/bta/dm/bta_dm_ci.cc
@@ -60,15 +60,15 @@
* Returns void
*
******************************************************************************/
-void bta_dm_ci_rmt_oob(bool accept, const RawAddress& bd_addr, BT_OCTET16 c,
- BT_OCTET16 r) {
+void bta_dm_ci_rmt_oob(bool accept, const RawAddress& bd_addr, const Octet16& c,
+ const Octet16& r) {
std::unique_ptr<tBTA_DM_CI_RMT_OOB> msg =
std::make_unique<tBTA_DM_CI_RMT_OOB>();
msg->bd_addr = bd_addr;
msg->accept = accept;
- memcpy(msg->c, c, BT_OCTET16_LEN);
- memcpy(msg->r, r, BT_OCTET16_LEN);
+ msg->c = c;
+ msg->r = r;
do_in_bta_thread(FROM_HERE,
base::Bind(bta_dm_ci_rmt_oob_act, base::Passed(&msg)));
diff --git a/bta/dm/bta_dm_int.h b/bta/dm/bta_dm_int.h
index 6aafd7d..0e2e9e3 100644
--- a/bta/dm/bta_dm_int.h
+++ b/bta/dm/bta_dm_int.h
@@ -118,8 +118,8 @@
typedef struct {
RawAddress bd_addr;
- BT_OCTET16 c;
- BT_OCTET16 r;
+ Octet16 c;
+ Octet16 r;
bool accept;
} tBTA_DM_CI_RMT_OOB;
@@ -150,7 +150,7 @@
typedef struct {
RawAddress bd_addr;
DEV_CLASS dc;
- LINK_KEY link_key;
+ LinkKey link_key;
tBTA_SERVICE_MASK tm;
bool is_trusted;
uint8_t key_type;
@@ -250,7 +250,7 @@
} tBTA_DM_SRVCS;
#ifndef BTA_DM_NUM_CONN_SRVS
-#define BTA_DM_NUM_CONN_SRVS 10
+#define BTA_DM_NUM_CONN_SRVS 30
#endif
typedef struct {
diff --git a/bta/gatt/bta_gattc_act.cc b/bta/gatt/bta_gattc_act.cc
index eedd964..cb9d158 100644
--- a/bta/gatt/bta_gattc_act.cc
+++ b/bta/gatt/bta_gattc_act.cc
@@ -473,7 +473,7 @@
if (p_clcb->p_srcb->mtu == 0) p_clcb->p_srcb->mtu = GATT_DEF_BLE_MTU_SIZE;
/* start database cache if needed */
- if (p_clcb->p_srcb->srvc_cache.empty() ||
+ if (p_clcb->p_srcb->gatt_database.IsEmpty() ||
p_clcb->p_srcb->state != BTA_GATTC_SERV_IDLE) {
if (p_clcb->p_srcb->state == BTA_GATTC_SERV_IDLE) {
p_clcb->p_srcb->state = BTA_GATTC_SERV_LOAD;
@@ -654,11 +654,9 @@
/* set all srcb related clcb into discovery ST */
bta_gattc_set_discover_st(p_clcb->p_srcb);
- p_clcb->status = bta_gattc_init_cache(p_clcb->p_srcb);
- if (p_clcb->status == GATT_SUCCESS) {
- p_clcb->status = bta_gattc_discover_pri_service(
- p_clcb->bta_conn_id, p_clcb->p_srcb, GATT_DISC_SRVC_ALL);
- }
+ bta_gattc_init_cache(p_clcb->p_srcb);
+ p_clcb->status = bta_gattc_discover_pri_service(
+ p_clcb->bta_conn_id, p_clcb->p_srcb, GATT_DISC_SRVC_ALL);
if (p_clcb->status != GATT_SUCCESS) {
LOG(ERROR) << "discovery on server failed";
bta_gattc_reset_discover_st(p_clcb->p_srcb, p_clcb->status);
@@ -692,16 +690,15 @@
if (p_clcb->status != GATT_SUCCESS) {
/* clean up cache */
if (p_clcb->p_srcb) {
- // clear reallocating
- std::vector<tBTA_GATTC_SERVICE>().swap(p_clcb->p_srcb->srvc_cache);
+ p_clcb->p_srcb->gatt_database.Clear();
}
/* used to reset cache in application */
bta_gattc_cache_reset(p_clcb->p_srcb->server_bda);
}
+
if (p_clcb->p_srcb) {
- /* release pending attribute list buffer */
- p_clcb->p_srcb->pending_discovery.clear();
+ p_clcb->p_srcb->pending_discovery.Clear();
}
if (p_clcb->auto_update == BTA_GATTC_DISC_WAITING) {
@@ -981,7 +978,7 @@
tGATT_STATUS status = GATT_INTERNAL_ERROR;
tBTA_GATTC cb_data;
VLOG(1) << __func__ << ": conn_id=" << +p_clcb->bta_conn_id;
- if (p_clcb->p_srcb && !p_clcb->p_srcb->srvc_cache.empty()) {
+ if (p_clcb->p_srcb && !p_clcb->p_srcb->gatt_database.IsEmpty()) {
status = GATT_SUCCESS;
/* search the local cache of a server device */
bta_gattc_search_service(p_clcb, p_data->api_search.p_srvc_uuid);
@@ -1105,8 +1102,7 @@
}
/* in all other cases, mark it and delete the cache */
- // clear reallocating
- std::vector<tBTA_GATTC_SERVICE>().swap(p_srvc_cb->srvc_cache);
+ p_srvc_cb->gatt_database.Clear();
}
/* used to reset cache in application */
@@ -1123,10 +1119,10 @@
Uuid gattp_uuid = Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER);
Uuid srvc_chg_uuid = Uuid::From16Bit(GATT_UUID_GATT_SRV_CHGD);
- const tBTA_GATTC_CHARACTERISTIC* p_char =
+ const gatt::Characteristic* p_char =
bta_gattc_get_characteristic_srcb(p_srcb, p_notify->handle);
if (!p_char) return false;
- const tBTA_GATTC_SERVICE* p_svc =
+ const gatt::Service* p_svc =
bta_gattc_get_service_for_handle_srcb(p_srcb, p_char->value_handle);
if (!p_svc || p_svc->uuid != gattp_uuid || p_char->uuid != srvc_chg_uuid) {
return false;
diff --git a/bta/gatt/bta_gattc_api.cc b/bta/gatt/bta_gattc_api.cc
index bec0081..c60d299 100644
--- a/bta/gatt/bta_gattc_api.cc
+++ b/bta/gatt/bta_gattc_api.cc
@@ -246,15 +246,14 @@
bta_sys_sendmsg(p_buf);
}
-void BTA_GATTC_DiscoverServiceByUuid(uint16_t conn_id,
- const Uuid& p_srvc_uuid) {
- tGATT_DISC_PARAM* param = new tGATT_DISC_PARAM;
- param->s_handle = 0x0001;
- param->e_handle = 0xFFFF;
- param->service = p_srvc_uuid;
- do_in_bta_thread(FROM_HERE,
- base::Bind(base::IgnoreResult(&GATTC_Discover), conn_id,
- GATT_DISC_SRVC_BY_UUID, base::Owned(param)));
+void BTA_GATTC_DiscoverServiceByUuid(uint16_t conn_id, const Uuid& srvc_uuid) {
+ do_in_bta_thread(
+ FROM_HERE,
+ base::Bind(
+ base::IgnoreResult<tGATT_STATUS (*)(uint16_t, tGATT_DISC_TYPE,
+ uint16_t, uint16_t, const Uuid&)>(
+ &GATTC_Discover),
+ conn_id, GATT_DISC_SRVC_BY_UUID, 0x0001, 0xFFFF, srvc_uuid));
}
/*******************************************************************************
@@ -266,10 +265,10 @@
*
* Parameters conn_id: connection ID which identify the server.
*
- * Returns returns list of tBTA_GATTC_SERVICE or NULL.
+ * Returns returns list of gatt::Service or NULL.
*
******************************************************************************/
-const std::vector<tBTA_GATTC_SERVICE>* BTA_GATTC_GetServices(uint16_t conn_id) {
+const std::vector<gatt::Service>* BTA_GATTC_GetServices(uint16_t conn_id) {
return bta_gattc_get_services(conn_id);
}
@@ -283,11 +282,11 @@
* Parameters conn_id - connection ID which identify the server.
* handle - characteristic handle
*
- * Returns returns pointer to tBTA_GATTC_CHARACTERISTIC or NULL.
+ * Returns returns pointer to gatt::Characteristic or NULL.
*
******************************************************************************/
-const tBTA_GATTC_CHARACTERISTIC* BTA_GATTC_GetCharacteristic(uint16_t conn_id,
- uint16_t handle) {
+const gatt::Characteristic* BTA_GATTC_GetCharacteristic(uint16_t conn_id,
+ uint16_t handle) {
return bta_gattc_get_characteristic(conn_id, handle);
}
@@ -301,25 +300,25 @@
* Parameters conn_id - connection ID which identify the server.
* handle - descriptor handle
*
- * Returns returns pointer to tBTA_GATTC_DESCRIPTOR or NULL.
+ * Returns returns pointer to gatt::Descriptor or NULL.
*
******************************************************************************/
-const tBTA_GATTC_DESCRIPTOR* BTA_GATTC_GetDescriptor(uint16_t conn_id,
- uint16_t handle) {
+const gatt::Descriptor* BTA_GATTC_GetDescriptor(uint16_t conn_id,
+ uint16_t handle) {
return bta_gattc_get_descriptor(conn_id, handle);
}
/* Return characteristic that owns descriptor with handle equal to |handle|, or
* NULL */
-const tBTA_GATTC_CHARACTERISTIC* BTA_GATTC_GetOwningCharacteristic(
- uint16_t conn_id, uint16_t handle) {
+const gatt::Characteristic* BTA_GATTC_GetOwningCharacteristic(uint16_t conn_id,
+ uint16_t handle) {
return bta_gattc_get_owning_characteristic(conn_id, handle);
}
/* Return service that owns descriptor or characteristic with handle equal to
* |handle|, or NULL */
-const tBTA_GATTC_SERVICE* BTA_GATTC_GetOwningService(uint16_t conn_id,
- uint16_t handle) {
+const gatt::Service* BTA_GATTC_GetOwningService(uint16_t conn_id,
+ uint16_t handle) {
return bta_gattc_get_service_for_handle(conn_id, handle);
}
diff --git a/bta/gatt/bta_gattc_cache.cc b/bta/gatt/bta_gattc_cache.cc
index 9f8c969..6c793f1 100644
--- a/bta/gatt/bta_gattc_cache.cc
+++ b/bta/gatt/bta_gattc_cache.cc
@@ -31,6 +31,7 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
+#include <sstream>
#include "bt_common.h"
#include "bta_gattc_int.h"
@@ -38,25 +39,34 @@
#include "btm_api.h"
#include "btm_ble_api.h"
#include "btm_int.h"
+#include "database.h"
+#include "database_builder.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
#include "sdp_api.h"
#include "sdpdefs.h"
#include "utl.h"
-using bluetooth::Uuid;
using base::StringPrintf;
+using bluetooth::Uuid;
+using gatt::Characteristic;
+using gatt::Database;
+using gatt::DatabaseBuilder;
+using gatt::Descriptor;
+using gatt::IncludedService;
+using gatt::Service;
+using gatt::StoredAttribute;
static void bta_gattc_cache_write(const RawAddress& server_bda,
- uint16_t num_attr, tBTA_GATTC_NV_ATTR* attr);
-static void bta_gattc_char_dscpt_disc_cmpl(uint16_t conn_id,
- tBTA_GATTC_SERV* p_srvc_cb);
+ const std::vector<StoredAttribute>& attr);
static tGATT_STATUS bta_gattc_sdp_service_disc(uint16_t conn_id,
tBTA_GATTC_SERV* p_server_cb);
-const tBTA_GATTC_DESCRIPTOR* bta_gattc_get_descriptor_srcb(
- tBTA_GATTC_SERV* p_srcb, uint16_t handle);
-tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_characteristic_srcb(
- tBTA_GATTC_SERV* p_srcb, uint16_t handle);
+const Descriptor* bta_gattc_get_descriptor_srcb(tBTA_GATTC_SERV* p_srcb,
+ uint16_t handle);
+const Characteristic* bta_gattc_get_characteristic_srcb(tBTA_GATTC_SERV* p_srcb,
+ uint16_t handle);
+static void bta_gattc_explore_srvc_finished(uint16_t conn_id,
+ tBTA_GATTC_SERV* p_srvc_cb);
#define BTA_GATT_SDP_DB_SIZE 4096
@@ -83,195 +93,42 @@
/* utility functions */
/* debug function to display the server cache */
-static void display_db(const std::vector<tBTA_GATTC_SERVICE>& cache) {
- for (const tBTA_GATTC_SERVICE& service : cache) {
- LOG(ERROR) << "Service: s_handle=" << loghex(service.s_handle)
- << ", e_handle=" << loghex(service.e_handle)
- << ", inst=" << loghex(service.handle)
- << ", uuid=" << service.uuid;
-
- if (service.characteristics.empty()) {
- LOG(ERROR) << "\t No characteristics";
- continue;
- }
-
- for (const tBTA_GATTC_CHARACTERISTIC& c : service.characteristics) {
- LOG(ERROR) << "\t Characteristic value_handle=" << loghex(c.value_handle)
- << ", uuid=" << c.uuid << ", prop=" << loghex(c.properties);
-
- if (c.descriptors.empty()) {
- LOG(ERROR) << "\t\t No descriptors";
- continue;
- }
-
- for (const tBTA_GATTC_DESCRIPTOR& d : c.descriptors) {
- LOG(ERROR) << "\t\t Descriptor handle=" << loghex(d.handle)
- << ", uuid=" << d.uuid;
- }
- }
+static void bta_gattc_display_cache_server(const Database& database) {
+ LOG(INFO) << "<================Start Server Cache =============>";
+ std::istringstream iss(database.ToString());
+ for (std::string line; std::getline(iss, line);) {
+ LOG(INFO) << line;
}
-}
-
-/* debug function to display the server cache */
-static void bta_gattc_display_cache_server(
- const std::vector<tBTA_GATTC_SERVICE>& cache) {
- LOG(ERROR) << "<================Start Server Cache =============>";
- display_db(cache);
- LOG(ERROR) << "<================End Server Cache =============>";
- LOG(ERROR) << " ";
+ LOG(INFO) << "<================End Server Cache =============>";
}
/** debug function to display the exploration list */
-static void bta_gattc_display_explore_record(
- const std::vector<tBTA_GATTC_SERVICE>& cache) {
- LOG(ERROR) << "<================Start Explore Queue =============>";
- display_db(cache);
- LOG(ERROR) << "<================ End Explore Queue =============>";
- LOG(ERROR) << " ";
+static void bta_gattc_display_explore_record(const DatabaseBuilder& database) {
+ LOG(INFO) << "<================Start Explore Queue =============>";
+ std::istringstream iss(database.ToString());
+ for (std::string line; std::getline(iss, line);) {
+ LOG(INFO) << line;
+ }
+ LOG(INFO) << "<================ End Explore Queue =============>";
}
#endif /* BTA_GATT_DEBUG == TRUE */
-/*******************************************************************************
- *
- * Function bta_gattc_init_cache
- *
- * Description Initialize the database cache and discovery related
- * resources.
- *
- * Returns status
- *
- ******************************************************************************/
-tGATT_STATUS bta_gattc_init_cache(tBTA_GATTC_SERV* p_srvc_cb) {
- // clear reallocating
- std::vector<tBTA_GATTC_SERVICE>().swap(p_srvc_cb->srvc_cache);
- std::vector<tBTA_GATTC_SERVICE>().swap(p_srvc_cb->pending_discovery);
- return GATT_SUCCESS;
+/** Initialize the database cache and discovery related resources */
+void bta_gattc_init_cache(tBTA_GATTC_SERV* p_srvc_cb) {
+ p_srvc_cb->gatt_database = gatt::Database();
+ p_srvc_cb->pending_discovery.Clear();
}
-tBTA_GATTC_SERVICE* bta_gattc_find_matching_service(
- std::vector<tBTA_GATTC_SERVICE>& services, uint16_t handle) {
- for (tBTA_GATTC_SERVICE& service : services) {
- if (handle >= service.s_handle && handle <= service.e_handle)
+const Service* bta_gattc_find_matching_service(
+ const std::vector<Service>& services, uint16_t handle) {
+ for (const Service& service : services) {
+ if (handle >= service.handle && handle <= service.end_handle)
return &service;
}
return nullptr;
}
-/** Add a service into GATT database */
-static void add_service_to_gatt_db(std::vector<tBTA_GATTC_SERVICE>& gatt_db,
- uint16_t s_handle, uint16_t e_handle,
- const Uuid& uuid, bool is_primary) {
-#if (BTA_GATT_DEBUG == TRUE)
- VLOG(1) << "Add a service into GATT DB";
-#endif
-
- gatt_db.emplace_back(tBTA_GATTC_SERVICE{
- .s_handle = s_handle,
- .e_handle = e_handle,
- .is_primary = is_primary,
- .uuid = uuid,
- .handle = s_handle,
- });
-}
-
-/** Add a characteristic into GATT database */
-static void add_characteristic_to_gatt_db(
- std::vector<tBTA_GATTC_SERVICE>& gatt_db, uint16_t attribute_handle,
- uint16_t value_handle, const Uuid& uuid, uint8_t property) {
-#if (BTA_GATT_DEBUG == TRUE)
- VLOG(1) << __func__
- << ": Add a characteristic into service. handle:" << +value_handle
- << " uuid:" << uuid << " property=0x" << std::hex << +property;
-#endif
-
- tBTA_GATTC_SERVICE* service =
- bta_gattc_find_matching_service(gatt_db, attribute_handle);
- if (!service) {
- LOG(ERROR) << "Illegal action to add char/descr/incl srvc for non-existing "
- "service!";
- return;
- }
-
- /* TODO(jpawlowski): We should use attribute handle, not value handle to refer
- to characteristic.
- This is just a temporary workaround.
- */
- if (service->e_handle < value_handle) service->e_handle = value_handle;
-
- service->characteristics.emplace_back(
- tBTA_GATTC_CHARACTERISTIC{.declaration_handle = attribute_handle,
- .value_handle = value_handle,
- .properties = property,
- .uuid = uuid});
- return;
-}
-
-/* Add an descriptor into database cache buffer */
-static void add_descriptor_to_gatt_db(std::vector<tBTA_GATTC_SERVICE>& gatt_db,
- uint16_t handle, const Uuid& uuid) {
-#if (BTA_GATT_DEBUG == TRUE)
- VLOG(1) << __func__ << ": add descriptor, handle=" << loghex(handle)
- << ", uuid=" << uuid;
-#endif
-
- tBTA_GATTC_SERVICE* service =
- bta_gattc_find_matching_service(gatt_db, handle);
- if (!service) {
- LOG(ERROR) << "Illegal action to add descriptor for non-existing service!";
- return;
- }
-
- if (service->characteristics.empty()) {
- LOG(ERROR) << __func__
- << ": Illegal action to add descriptor before adding a "
- "characteristic!";
- return;
- }
-
- tBTA_GATTC_CHARACTERISTIC* char_node = &service->characteristics.front();
- for (auto it = service->characteristics.begin();
- it != service->characteristics.end(); it++) {
- if (it->value_handle > handle) break;
- char_node = &(*it);
- }
-
- char_node->descriptors.emplace_back(
- tBTA_GATTC_DESCRIPTOR{.handle = handle, .uuid = uuid});
-}
-
-/* Add an attribute into database cache buffer */
-static void add_incl_srvc_to_gatt_db(std::vector<tBTA_GATTC_SERVICE>& gatt_db,
- uint16_t handle, const Uuid& uuid,
- uint16_t incl_srvc_s_handle) {
-#if (BTA_GATT_DEBUG == TRUE)
- VLOG(1) << __func__ << ": add included service, handle=" << loghex(handle)
- << ", uuid=" << uuid;
-#endif
-
- tBTA_GATTC_SERVICE* service =
- bta_gattc_find_matching_service(gatt_db, handle);
- if (!service) {
- LOG(ERROR) << "Illegal action to add incl srvc for non-existing service!";
- return;
- }
-
- tBTA_GATTC_SERVICE* included_service =
- bta_gattc_find_matching_service(gatt_db, incl_srvc_s_handle);
- if (!included_service) {
- LOG(ERROR) << __func__
- << ": Illegal action to add non-existing included service!";
- return;
- }
-
- service->included_svc.emplace_back(tBTA_GATTC_INCLUDED_SVC{
- .handle = handle,
- .uuid = uuid,
- .owning_service = service,
- .included_service = included_service,
- });
-}
-
/** Start primary service discovery */
tGATT_STATUS bta_gattc_discover_pri_service(uint16_t conn_id,
tBTA_GATTC_SERV* p_server_cb,
@@ -280,111 +137,85 @@
if (!p_clcb) return GATT_ERROR;
if (p_clcb->transport == BTA_TRANSPORT_LE) {
- tGATT_DISC_PARAM param{.s_handle = 0x0001, .e_handle = 0xFFFF};
- return GATTC_Discover(conn_id, disc_type, ¶m);
+ return GATTC_Discover(conn_id, disc_type, 0x0001, 0xFFFF);
}
+ // only for Classic transport
return bta_gattc_sdp_service_disc(conn_id, p_server_cb);
}
+/** start exploring next service, or finish discovery if no more services left
+ */
+static void bta_gattc_explore_next_service(uint16_t conn_id,
+ tBTA_GATTC_SERV* p_srvc_cb) {
+ tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+ if (!p_clcb) {
+ LOG(ERROR) << "unknown conn_id=" << loghex(conn_id);
+ return;
+ }
+
+ if (!p_srvc_cb->pending_discovery.StartNextServiceExploration()) {
+ bta_gattc_explore_srvc_finished(conn_id, p_srvc_cb);
+ return;
+ }
+
+ const auto& service = p_srvc_cb->pending_discovery.CurrentlyExploredService();
+ VLOG(1) << "Start service discovery";
+
+ /* start discovering included services */
+ GATTC_Discover(conn_id, GATT_DISC_INC_SRVC, service.first, service.second);
+}
+
+static void bta_gattc_explore_srvc_finished(uint16_t conn_id,
+ tBTA_GATTC_SERV* p_srvc_cb) {
+ tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+ if (!p_clcb) {
+ LOG(ERROR) << "unknown conn_id=" << loghex(conn_id);
+ return;
+ }
+
+ /* no service found at all, the end of server discovery*/
+ LOG(INFO) << __func__ << ": service discovery finished";
+
+ p_srvc_cb->gatt_database = p_srvc_cb->pending_discovery.Build();
+
+#if (BTA_GATT_DEBUG == TRUE)
+ bta_gattc_display_cache_server(p_srvc_cb->gatt_database);
+#endif
+ /* save cache to NV */
+ p_clcb->p_srcb->state = BTA_GATTC_SERV_SAVE;
+
+ if (btm_sec_is_a_bonded_dev(p_srvc_cb->server_bda)) {
+ bta_gattc_cache_write(p_clcb->p_srcb->server_bda,
+ p_clcb->p_srcb->gatt_database.Serialize());
+ }
+
+ bta_gattc_reset_discover_st(p_clcb->p_srcb, GATT_SUCCESS);
+}
+
/** Start discovery for characteristic descriptor */
void bta_gattc_start_disc_char_dscp(uint16_t conn_id,
tBTA_GATTC_SERV* p_srvc_cb) {
VLOG(1) << "starting discover characteristics descriptor";
- auto& characteristic = p_srvc_cb->pending_char;
- uint16_t end_handle = 0xFFFF;
- // if there are more characteristics in the service
- if (std::next(p_srvc_cb->pending_char) !=
- p_srvc_cb->pending_service->characteristics.end()) {
- // end at beginning of next characteristic
- end_handle = std::next(p_srvc_cb->pending_char)->declaration_handle - 1;
- } else {
- // end at the end of current service
- end_handle = p_srvc_cb->pending_service->e_handle;
+ std::pair<uint16_t, uint16_t> range =
+ p_srvc_cb->pending_discovery.NextDescriptorRangeToExplore();
+ if (range == DatabaseBuilder::EXPLORE_END) {
+ goto descriptor_discovery_done;
}
- tGATT_DISC_PARAM param{
- .s_handle = (uint16_t)(characteristic->value_handle + 1),
- .e_handle = end_handle};
- if (GATTC_Discover(conn_id, GATT_DISC_CHAR_DSCPT, ¶m) != 0) {
- bta_gattc_char_dscpt_disc_cmpl(conn_id, p_srvc_cb);
+ if (GATTC_Discover(conn_id, GATT_DISC_CHAR_DSCPT, range.first,
+ range.second) != 0) {
+ goto descriptor_discovery_done;
}
-}
+ return;
-/** process the service discovery complete event */
-static void bta_gattc_explore_srvc(uint16_t conn_id,
- tBTA_GATTC_SERV* p_srvc_cb) {
- tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
- if (!p_clcb) {
- LOG(ERROR) << "unknown conn_id=" << +conn_id;
- return;
- }
-
- /* start expore a service if there is service not been explored */
- if (p_srvc_cb->pending_service != p_srvc_cb->pending_discovery.end()) {
- auto& service = *p_srvc_cb->pending_service;
- VLOG(1) << "Start service discovery";
-
- /* start discovering included services */
- tGATT_DISC_PARAM param = {.s_handle = service.s_handle,
- .e_handle = service.e_handle};
- GATTC_Discover(conn_id, GATT_DISC_INC_SRVC, ¶m);
- return;
- }
-
- /* no service found at all, the end of server discovery*/
- LOG(INFO) << __func__ << ": no more services found";
-
- p_srvc_cb->srvc_cache.swap(p_srvc_cb->pending_discovery);
- std::vector<tBTA_GATTC_SERVICE>().swap(p_srvc_cb->pending_discovery);
-
-#if (BTA_GATT_DEBUG == TRUE)
- bta_gattc_display_cache_server(p_srvc_cb->srvc_cache);
-#endif
- /* save cache to NV */
- p_clcb->p_srcb->state = BTA_GATTC_SERV_SAVE;
-
- if (btm_sec_is_a_bonded_dev(p_srvc_cb->server_bda)) {
- bta_gattc_cache_save(p_clcb->p_srcb, p_clcb->bta_conn_id);
- }
-
- bta_gattc_reset_discover_st(p_clcb->p_srcb, GATT_SUCCESS);
-}
-
-/** process the char descriptor discovery complete event */
-static void bta_gattc_char_dscpt_disc_cmpl(uint16_t conn_id,
- tBTA_GATTC_SERV* p_srvc_cb) {
- ++p_srvc_cb->pending_char;
- if (p_srvc_cb->pending_char !=
- p_srvc_cb->pending_service->characteristics.end()) {
- /* start discoverying next characteristic for char descriptor */
- bta_gattc_start_disc_char_dscp(conn_id, p_srvc_cb);
- return;
- }
-
+descriptor_discovery_done:
/* all characteristic has been explored, start with next service if any */
-#if (BTA_GATT_DEBUG == TRUE)
- LOG(ERROR) << "all char has been explored";
-#endif
- p_srvc_cb->pending_service++;
- bta_gattc_explore_srvc(conn_id, p_srvc_cb);
-}
+ DVLOG(3) << "all characteristics explored";
-static bool bta_gattc_srvc_in_list(std::vector<tBTA_GATTC_SERVICE>& services,
- uint16_t s_handle, uint16_t e_handle, Uuid) {
- if (!GATT_HANDLE_IS_VALID(s_handle) || !GATT_HANDLE_IS_VALID(e_handle)) {
- LOG(ERROR) << "invalid included service s_handle=" << loghex(s_handle)
- << ", e_handle=" << loghex(e_handle);
- return true;
- }
-
- for (tBTA_GATTC_SERVICE& service : services) {
- if (service.s_handle == s_handle || service.e_handle == e_handle)
- return true;
- }
-
- return false;
+ bta_gattc_explore_next_service(conn_id, p_srvc_cb);
+ return;
}
/* Process the discovery result from sdp */
@@ -399,64 +230,61 @@
return;
}
- bool no_pending_disc = p_srvc_cb->pending_discovery.empty();
+ if ((sdp_status != SDP_SUCCESS) && (sdp_status != SDP_DB_FULL)) {
+ bta_gattc_explore_srvc_finished(cb_data->sdp_conn_id, p_srvc_cb);
- if ((sdp_status == SDP_SUCCESS) || (sdp_status == SDP_DB_FULL)) {
- tSDP_DISC_REC* p_sdp_rec =
- SDP_FindServiceInDb(cb_data->p_sdp_db, 0, nullptr);
- while (p_sdp_rec != nullptr) {
- /* find a service record, report it */
- Uuid service_uuid;
- if (!SDP_FindServiceUUIDInRec(p_sdp_rec, &service_uuid)) continue;
+ /* allocated in bta_gattc_sdp_service_disc */
+ osi_free(cb_data);
+ return;
+ }
- tSDP_PROTOCOL_ELEM pe;
- if (!SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_ATT, &pe))
- continue;
+ bool no_pending_disc = !p_srvc_cb->pending_discovery.InProgress();
- uint16_t start_handle = (uint16_t)pe.params[0];
- uint16_t end_handle = (uint16_t)pe.params[1];
+ tSDP_DISC_REC* p_sdp_rec = SDP_FindServiceInDb(cb_data->p_sdp_db, 0, nullptr);
+ while (p_sdp_rec != nullptr) {
+ /* find a service record, report it */
+ Uuid service_uuid;
+ if (!SDP_FindServiceUUIDInRec(p_sdp_rec, &service_uuid)) continue;
+
+ tSDP_PROTOCOL_ELEM pe;
+ if (!SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_ATT, &pe))
+ continue;
+
+ uint16_t start_handle = (uint16_t)pe.params[0];
+ uint16_t end_handle = (uint16_t)pe.params[1];
#if (BTA_GATT_DEBUG == TRUE)
- VLOG(1) << "Found ATT service uuid=" << service_uuid
- << ", s_handle=" << loghex(start_handle)
- << ", e_handle=" << loghex(end_handle);
+ VLOG(1) << "Found ATT service uuid=" << service_uuid
+ << ", s_handle=" << loghex(start_handle)
+ << ", e_handle=" << loghex(end_handle);
#endif
- if (!GATT_HANDLE_IS_VALID(start_handle) ||
- !GATT_HANDLE_IS_VALID(end_handle)) {
- LOG(ERROR) << "invalid start_handle=" << loghex(start_handle)
- << ", end_handle=" << loghex(end_handle);
- continue;
- }
-
- /* discover services result, add services into a service list */
- add_service_to_gatt_db(p_srvc_cb->pending_discovery, start_handle,
- end_handle, service_uuid, true);
-
- p_sdp_rec = SDP_FindServiceInDb(cb_data->p_sdp_db, 0, p_sdp_rec);
+ if (!GATT_HANDLE_IS_VALID(start_handle) ||
+ !GATT_HANDLE_IS_VALID(end_handle)) {
+ LOG(ERROR) << "invalid start_handle=" << loghex(start_handle)
+ << ", end_handle=" << loghex(end_handle);
+ continue;
}
+
+ /* discover services result, add services into a service list */
+ p_srvc_cb->pending_discovery.AddService(start_handle, end_handle,
+ service_uuid, true);
+
+ p_sdp_rec = SDP_FindServiceInDb(cb_data->p_sdp_db, 0, p_sdp_rec);
}
+ // If discovery is already pending, no need to call
+ // bta_gattc_explore_next_service. Next service will be picked up to discovery
+ // once current one is discovered. If discovery is not pending, start one
if (no_pending_disc) {
- p_srvc_cb->pending_service = p_srvc_cb->pending_discovery.begin();
+ bta_gattc_explore_next_service(cb_data->sdp_conn_id, p_srvc_cb);
}
- /* start discover primary service */
- bta_gattc_explore_srvc(cb_data->sdp_conn_id, p_srvc_cb);
-
/* allocated in bta_gattc_sdp_service_disc */
osi_free(cb_data);
}
-/*******************************************************************************
- *
- * Function bta_gattc_sdp_service_disc
- *
- * Description Start DSP Service Discovert
- *
- * Returns void
- *
- ******************************************************************************/
+/* Start DSP Service Discovery */
static tGATT_STATUS bta_gattc_sdp_service_disc(uint16_t conn_id,
tBTA_GATTC_SERV* p_server_cb) {
uint16_t num_attrs = 2;
@@ -499,43 +327,27 @@
switch (disc_type) {
case GATT_DISC_SRVC_ALL:
case GATT_DISC_SRVC_BY_UUID:
- /* discover services result, add services into a service list */
- add_service_to_gatt_db(p_srvc_cb->pending_discovery, p_data->handle,
- p_data->value.group_value.e_handle,
- p_data->value.group_value.service_type, true);
+ p_srvc_cb->pending_discovery.AddService(
+ p_data->handle, p_data->value.group_value.e_handle,
+ p_data->value.group_value.service_type, true);
break;
case GATT_DISC_INC_SRVC:
- /* add included service into service list if it's secondary or it never
- showed up in the primary service search */
- if (!bta_gattc_srvc_in_list(p_srvc_cb->pending_discovery,
- p_data->value.incl_service.s_handle,
- p_data->value.incl_service.e_handle,
- p_data->value.incl_service.service_type)) {
- add_service_to_gatt_db(p_srvc_cb->pending_discovery,
- p_data->value.incl_service.s_handle,
- p_data->value.incl_service.e_handle,
- p_data->value.incl_service.service_type, false);
- }
-
- /* add into database */
- add_incl_srvc_to_gatt_db(p_srvc_cb->pending_discovery, p_data->handle,
- p_data->value.incl_service.service_type,
- p_data->value.incl_service.s_handle);
+ p_srvc_cb->pending_discovery.AddIncludedService(
+ p_data->handle, p_data->value.incl_service.service_type,
+ p_data->value.incl_service.s_handle,
+ p_data->value.incl_service.e_handle);
break;
case GATT_DISC_CHAR:
- /* add char value into database */
- add_characteristic_to_gatt_db(p_srvc_cb->pending_discovery,
- p_data->handle,
- p_data->value.dclr_value.val_handle,
- p_data->value.dclr_value.char_uuid,
- p_data->value.dclr_value.char_prop);
+ p_srvc_cb->pending_discovery.AddCharacteristic(
+ p_data->handle, p_data->value.dclr_value.val_handle,
+ p_data->value.dclr_value.char_uuid,
+ p_data->value.dclr_value.char_prop);
break;
case GATT_DISC_CHAR_DSCPT:
- add_descriptor_to_gatt_db(p_srvc_cb->pending_discovery, p_data->handle,
- p_data->type);
+ p_srvc_cb->pending_discovery.AddDescriptor(p_data->handle, p_data->type);
break;
}
}
@@ -561,18 +373,13 @@
#if (BTA_GATT_DEBUG == TRUE)
bta_gattc_display_explore_record(p_srvc_cb->pending_discovery);
#endif
- p_srvc_cb->pending_service = p_srvc_cb->pending_discovery.begin();
- bta_gattc_explore_srvc(conn_id, p_srvc_cb);
+ bta_gattc_explore_next_service(conn_id, p_srvc_cb);
break;
case GATT_DISC_INC_SRVC: {
- auto& service = *p_srvc_cb->pending_service;
-
- /* start discoverying characteristic */
-
- tGATT_DISC_PARAM param = {.s_handle = service.s_handle,
- .e_handle = service.e_handle};
- GATTC_Discover(conn_id, GATT_DISC_CHAR, ¶m);
+ auto& service = p_srvc_cb->pending_discovery.CurrentlyExploredService();
+ /* start discovering characteristic */
+ GATTC_Discover(conn_id, GATT_DISC_CHAR, service.first, service.second);
break;
}
@@ -580,33 +387,25 @@
#if (BTA_GATT_DEBUG == TRUE)
bta_gattc_display_explore_record(p_srvc_cb->pending_discovery);
#endif
- auto& service = *p_srvc_cb->pending_service;
- if (!service.characteristics.empty()) {
- /* discover descriptors */
- p_srvc_cb->pending_char = service.characteristics.begin();
- bta_gattc_start_disc_char_dscp(conn_id, p_srvc_cb);
- return;
- }
- /* start next service */
- ++p_srvc_cb->pending_service;
- bta_gattc_explore_srvc(conn_id, p_srvc_cb);
+ bta_gattc_start_disc_char_dscp(conn_id, p_srvc_cb);
break;
}
case GATT_DISC_CHAR_DSCPT:
- bta_gattc_char_dscpt_disc_cmpl(conn_id, p_srvc_cb);
+ /* start discovering next characteristic for char descriptor */
+ bta_gattc_start_disc_char_dscp(conn_id, p_srvc_cb);
break;
}
}
/** search local cache for matching service record */
void bta_gattc_search_service(tBTA_GATTC_CLCB* p_clcb, Uuid* p_uuid) {
- for (const tBTA_GATTC_SERVICE& service : p_clcb->p_srcb->srvc_cache) {
+ for (const Service& service : p_clcb->p_srcb->gatt_database.Services()) {
if (p_uuid && *p_uuid != service.uuid) continue;
#if (BTA_GATT_DEBUG == TRUE)
VLOG(1) << __func__ << "found service " << service.uuid
- << ", inst:" << +service.handle << " handle:" << +service.s_handle;
+ << " handle:" << +service.handle;
#endif
if (!p_clcb->p_rcb->p_cback) continue;
@@ -620,14 +419,14 @@
}
}
-std::vector<tBTA_GATTC_SERVICE>* bta_gattc_get_services_srcb(
+const std::vector<Service>* bta_gattc_get_services_srcb(
tBTA_GATTC_SERV* p_srcb) {
- if (!p_srcb || p_srcb->srvc_cache.empty()) return NULL;
+ if (!p_srcb || p_srcb->gatt_database.IsEmpty()) return NULL;
- return &p_srcb->srvc_cache;
+ return &p_srcb->gatt_database.Services();
}
-std::vector<tBTA_GATTC_SERVICE>* bta_gattc_get_services(uint16_t conn_id) {
+const std::vector<Service>* bta_gattc_get_services(uint16_t conn_id) {
tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
if (p_clcb == NULL) return NULL;
@@ -637,38 +436,37 @@
return bta_gattc_get_services_srcb(p_srcb);
}
-tBTA_GATTC_SERVICE* bta_gattc_get_service_for_handle_srcb(
- tBTA_GATTC_SERV* p_srcb, uint16_t handle) {
- std::vector<tBTA_GATTC_SERVICE>* services =
- bta_gattc_get_services_srcb(p_srcb);
+const Service* bta_gattc_get_service_for_handle_srcb(tBTA_GATTC_SERV* p_srcb,
+ uint16_t handle) {
+ const std::vector<Service>* services = bta_gattc_get_services_srcb(p_srcb);
if (services == NULL) return NULL;
return bta_gattc_find_matching_service(*services, handle);
}
-const tBTA_GATTC_SERVICE* bta_gattc_get_service_for_handle(uint16_t conn_id,
- uint16_t handle) {
- std::vector<tBTA_GATTC_SERVICE>* services = bta_gattc_get_services(conn_id);
+const Service* bta_gattc_get_service_for_handle(uint16_t conn_id,
+ uint16_t handle) {
+ const std::vector<Service>* services = bta_gattc_get_services(conn_id);
if (services == NULL) return NULL;
return bta_gattc_find_matching_service(*services, handle);
}
-tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_characteristic_srcb(
- tBTA_GATTC_SERV* p_srcb, uint16_t handle) {
- tBTA_GATTC_SERVICE* service =
+const Characteristic* bta_gattc_get_characteristic_srcb(tBTA_GATTC_SERV* p_srcb,
+ uint16_t handle) {
+ const Service* service =
bta_gattc_get_service_for_handle_srcb(p_srcb, handle);
if (!service) return NULL;
- for (tBTA_GATTC_CHARACTERISTIC& charac : service->characteristics) {
+ for (const Characteristic& charac : service->characteristics) {
if (handle == charac.value_handle) return &charac;
}
return NULL;
}
-tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_characteristic(uint16_t conn_id,
- uint16_t handle) {
+const Characteristic* bta_gattc_get_characteristic(uint16_t conn_id,
+ uint16_t handle) {
tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
if (p_clcb == NULL) return NULL;
@@ -677,17 +475,17 @@
return bta_gattc_get_characteristic_srcb(p_srcb, handle);
}
-const tBTA_GATTC_DESCRIPTOR* bta_gattc_get_descriptor_srcb(
- tBTA_GATTC_SERV* p_srcb, uint16_t handle) {
- const tBTA_GATTC_SERVICE* service =
+const Descriptor* bta_gattc_get_descriptor_srcb(tBTA_GATTC_SERV* p_srcb,
+ uint16_t handle) {
+ const Service* service =
bta_gattc_get_service_for_handle_srcb(p_srcb, handle);
if (!service) {
return NULL;
}
- for (const tBTA_GATTC_CHARACTERISTIC& charac : service->characteristics) {
- for (const tBTA_GATTC_DESCRIPTOR& desc : charac.descriptors) {
+ for (const Characteristic& charac : service->characteristics) {
+ for (const Descriptor& desc : charac.descriptors) {
if (handle == desc.handle) return &desc;
}
}
@@ -695,8 +493,7 @@
return NULL;
}
-const tBTA_GATTC_DESCRIPTOR* bta_gattc_get_descriptor(uint16_t conn_id,
- uint16_t handle) {
+const Descriptor* bta_gattc_get_descriptor(uint16_t conn_id, uint16_t handle) {
tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
if (p_clcb == NULL) return NULL;
@@ -705,15 +502,15 @@
return bta_gattc_get_descriptor_srcb(p_srcb, handle);
}
-tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_owning_characteristic_srcb(
+const Characteristic* bta_gattc_get_owning_characteristic_srcb(
tBTA_GATTC_SERV* p_srcb, uint16_t handle) {
- tBTA_GATTC_SERVICE* service =
+ const Service* service =
bta_gattc_get_service_for_handle_srcb(p_srcb, handle);
if (!service) return NULL;
- for (tBTA_GATTC_CHARACTERISTIC& charac : service->characteristics) {
- for (const tBTA_GATTC_DESCRIPTOR& desc : charac.descriptors) {
+ for (const Characteristic& charac : service->characteristics) {
+ for (const Descriptor& desc : charac.descriptors) {
if (handle == desc.handle) return &charac;
}
}
@@ -721,8 +518,8 @@
return NULL;
}
-const tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_owning_characteristic(
- uint16_t conn_id, uint16_t handle) {
+const Characteristic* bta_gattc_get_owning_characteristic(uint16_t conn_id,
+ uint16_t handle) {
tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
if (!p_clcb) return NULL;
@@ -759,27 +556,27 @@
/*******************************************************************************
* Returns number of elements inside db from start_handle to end_handle
******************************************************************************/
-static size_t bta_gattc_get_db_size(
- const std::vector<tBTA_GATTC_SERVICE>& services, uint16_t start_handle,
- uint16_t end_handle) {
+static size_t bta_gattc_get_db_size(const std::vector<Service>& services,
+ uint16_t start_handle,
+ uint16_t end_handle) {
if (services.empty()) return 0;
size_t db_size = 0;
- for (const tBTA_GATTC_SERVICE& service : services) {
- if (service.s_handle < start_handle) continue;
+ for (const Service& service : services) {
+ if (service.handle < start_handle) continue;
- if (service.e_handle > end_handle) break;
+ if (service.end_handle > end_handle) break;
db_size++;
- for (const tBTA_GATTC_CHARACTERISTIC& charac : service.characteristics) {
+ for (const Characteristic& charac : service.characteristics) {
db_size++;
db_size += charac.descriptors.size();
}
- db_size += service.included_svc.size();
+ db_size += service.included_services.size();
}
return db_size;
@@ -808,39 +605,39 @@
<< StringPrintf(": start_handle 0x%04x, end_handle 0x%04x",
start_handle, end_handle);
- if (p_srvc_cb->srvc_cache.empty()) {
+ if (p_srvc_cb->gatt_database.IsEmpty()) {
*count = 0;
*db = NULL;
return;
}
- size_t db_size =
- bta_gattc_get_db_size(p_srvc_cb->srvc_cache, start_handle, end_handle);
+ size_t db_size = bta_gattc_get_db_size(p_srvc_cb->gatt_database.Services(),
+ start_handle, end_handle);
void* buffer = osi_malloc(db_size * sizeof(btgatt_db_element_t));
btgatt_db_element_t* curr_db_attr = (btgatt_db_element_t*)buffer;
- for (const tBTA_GATTC_SERVICE& service : p_srvc_cb->srvc_cache) {
- if (service.s_handle < start_handle) continue;
+ for (const Service& service : p_srvc_cb->gatt_database.Services()) {
+ if (service.handle < start_handle) continue;
- if (service.e_handle > end_handle) break;
+ if (service.end_handle > end_handle) break;
bta_gattc_fill_gatt_db_el(curr_db_attr,
service.is_primary ? BTGATT_DB_PRIMARY_SERVICE
: BTGATT_DB_SECONDARY_SERVICE,
- 0 /* att_handle */, service.s_handle,
- service.e_handle, service.s_handle, service.uuid,
+ 0 /* att_handle */, service.handle,
+ service.end_handle, service.handle, service.uuid,
0 /* prop */);
curr_db_attr++;
- for (const tBTA_GATTC_CHARACTERISTIC& charac : service.characteristics) {
+ for (const Characteristic& charac : service.characteristics) {
bta_gattc_fill_gatt_db_el(curr_db_attr, BTGATT_DB_CHARACTERISTIC,
charac.value_handle, 0 /* s_handle */,
0 /* e_handle */, charac.value_handle,
charac.uuid, charac.properties);
curr_db_attr++;
- for (const tBTA_GATTC_DESCRIPTOR& desc : charac.descriptors) {
+ for (const Descriptor& desc : charac.descriptors) {
bta_gattc_fill_gatt_db_el(
curr_db_attr, BTGATT_DB_DESCRIPTOR, desc.handle, 0 /* s_handle */,
0 /* e_handle */, desc.handle, desc.uuid, 0 /* property */);
@@ -848,11 +645,11 @@
}
}
- for (const tBTA_GATTC_INCLUDED_SVC& p_isvc : service.included_svc) {
- bta_gattc_fill_gatt_db_el(
- curr_db_attr, BTGATT_DB_INCLUDED_SERVICE, p_isvc.handle,
- p_isvc.included_service ? p_isvc.included_service->s_handle : 0,
- 0 /* e_handle */, p_isvc.handle, p_isvc.uuid, 0 /* property */);
+ for (const IncludedService& p_isvc : service.included_services) {
+ bta_gattc_fill_gatt_db_el(curr_db_attr, BTGATT_DB_INCLUDED_SERVICE,
+ p_isvc.handle, p_isvc.start_handle,
+ 0 /* e_handle */, p_isvc.handle, p_isvc.uuid,
+ 0 /* property */);
curr_db_attr++;
}
}
@@ -891,9 +688,8 @@
return;
}
- if (!p_clcb->p_srcb ||
- !p_clcb->p_srcb->pending_discovery.empty() || /* no active discovery */
- p_clcb->p_srcb->srvc_cache.empty()) {
+ if (!p_clcb->p_srcb || p_clcb->p_srcb->pending_discovery.InProgress() ||
+ p_clcb->p_srcb->gatt_database.IsEmpty()) {
LOG(ERROR) << "No server cache available";
return;
}
@@ -902,89 +698,6 @@
count);
}
-namespace {
-const Uuid PRIMARY_SERVICE = Uuid::From16Bit(GATT_UUID_PRI_SERVICE);
-const Uuid SECONDARY_SERVICE = Uuid::From16Bit(GATT_UUID_SEC_SERVICE);
-const Uuid INCLUDE = Uuid::From16Bit(GATT_UUID_INCLUDE_SERVICE);
-const Uuid CHARACTERISTIC = Uuid::From16Bit(GATT_UUID_CHAR_DECLARE);
-} // namespace
-
-/* rebuild server cache from NV cache */
-void bta_gattc_rebuild_cache(tBTA_GATTC_SERV* p_srvc_cb, uint16_t num_attr,
- tBTA_GATTC_NV_ATTR* p_attr) {
- /* first attribute loading, initialize buffer */
- LOG(INFO) << __func__ << " " << num_attr;
-
- // clear reallocating
- std::vector<tBTA_GATTC_SERVICE>().swap(p_srvc_cb->srvc_cache);
-
- while (num_attr > 0 && p_attr != NULL) {
- if (p_attr->type == PRIMARY_SERVICE || p_attr->type == SECONDARY_SERVICE) {
- add_service_to_gatt_db(
- p_srvc_cb->srvc_cache, p_attr->handle, p_attr->value.service.e_handle,
- p_attr->value.service.uuid, (p_attr->type == PRIMARY_SERVICE));
- } else if (p_attr->type == INCLUDE) {
- add_incl_srvc_to_gatt_db(p_srvc_cb->srvc_cache, p_attr->handle,
- p_attr->value.included_service.uuid,
- p_attr->value.included_service.s_handle);
- } else if (p_attr->type == CHARACTERISTIC) {
- add_characteristic_to_gatt_db(p_srvc_cb->srvc_cache, p_attr->handle,
- p_attr->value.characteristic.value_handle,
- p_attr->value.characteristic.uuid,
- p_attr->value.characteristic.properties);
- } else {
- add_descriptor_to_gatt_db(p_srvc_cb->srvc_cache, p_attr->handle,
- p_attr->type);
- }
-
- p_attr++;
- num_attr--;
- }
-}
-
-/** save the server cache into NV */
-void bta_gattc_cache_save(tBTA_GATTC_SERV* p_srvc_cb, uint16_t conn_id) {
- if (p_srvc_cb->srvc_cache.empty()) return;
-
- int i = 0;
- size_t db_size = bta_gattc_get_db_size(p_srvc_cb->srvc_cache, 0x0000, 0xFFFF);
- tBTA_GATTC_NV_ATTR* nv_attr =
- (tBTA_GATTC_NV_ATTR*)osi_malloc(db_size * sizeof(tBTA_GATTC_NV_ATTR));
-
- for (const tBTA_GATTC_SERVICE& service : p_srvc_cb->srvc_cache) {
- nv_attr[i++] = {
- service.s_handle,
- service.is_primary ? PRIMARY_SERVICE : SECONDARY_SERVICE,
- {.service = {.uuid = service.uuid, .e_handle = service.e_handle}}};
- }
-
- for (const tBTA_GATTC_SERVICE& service : p_srvc_cb->srvc_cache) {
- for (const tBTA_GATTC_INCLUDED_SVC& p_isvc : service.included_svc) {
- nv_attr[i++] = {
- p_isvc.handle,
- INCLUDE,
- {.included_service = {.s_handle = p_isvc.included_service->s_handle,
- .e_handle = p_isvc.included_service->e_handle,
- .uuid = p_isvc.uuid}}};
- }
-
- for (const tBTA_GATTC_CHARACTERISTIC& charac : service.characteristics) {
- nv_attr[i++] = {charac.declaration_handle,
- CHARACTERISTIC,
- {.characteristic = {.properties = charac.properties,
- .value_handle = charac.value_handle,
- .uuid = charac.uuid}}};
-
- for (const tBTA_GATTC_DESCRIPTOR& desc : charac.descriptors) {
- nv_attr[i++] = {desc.handle, desc.uuid, {}};
- }
- }
- }
-
- bta_gattc_cache_write(p_srvc_cb->server_bda, db_size, nv_attr);
- osi_free(nv_attr);
-}
-
/*******************************************************************************
*
* Function bta_gattc_cache_load
@@ -1009,7 +722,6 @@
}
uint16_t cache_ver = 0;
- tBTA_GATTC_NV_ATTR* attr = NULL;
bool success = false;
uint16_t num_attr = 0;
@@ -1029,19 +741,18 @@
goto done;
}
- attr = (tBTA_GATTC_NV_ATTR*)osi_malloc(sizeof(tBTA_GATTC_NV_ATTR) * num_attr);
+ {
+ std::vector<StoredAttribute> attr(num_attr);
- if (fread(attr, sizeof(tBTA_GATTC_NV_ATTR), num_attr, fd) != num_attr) {
- LOG(ERROR) << __func__ << "s: can't read GATT attributes: " << fname;
- goto done;
+ if (fread(attr.data(), sizeof(StoredAttribute), num_attr, fd) != num_attr) {
+ LOG(ERROR) << __func__ << "s: can't read GATT attributes: " << fname;
+ goto done;
+ }
+
+ p_clcb->p_srcb->gatt_database = gatt::Database::Deserialize(attr, &success);
}
- bta_gattc_rebuild_cache(p_clcb->p_srcb, num_attr, attr);
-
- success = true;
-
done:
- osi_free(attr);
fclose(fd);
return success;
}
@@ -1054,13 +765,12 @@
* cache is available to save.
*
* Parameter server_bda: server bd address of this cache belongs to
- * num_attr: number of attribute to be save.
- * attr: pointer to the list of attributes to save.
+ * attr: attributes to save.
* Returns
*
******************************************************************************/
static void bta_gattc_cache_write(const RawAddress& server_bda,
- uint16_t num_attr, tBTA_GATTC_NV_ATTR* attr) {
+ const std::vector<StoredAttribute>& attr) {
char fname[255] = {0};
bta_gattc_generate_cache_file_name(fname, sizeof(fname), server_bda);
@@ -1078,6 +788,7 @@
return;
}
+ uint16_t num_attr = attr.size();
if (fwrite(&num_attr, sizeof(uint16_t), 1, fd) != 1) {
LOG(ERROR) << __func__
<< ": can't write GATT cache attribute count: " << fname;
@@ -1085,7 +796,7 @@
return;
}
- if (fwrite(attr, sizeof(tBTA_GATTC_NV_ATTR), num_attr, fd) != num_attr) {
+ if (fwrite(attr.data(), sizeof(StoredAttribute), num_attr, fd) != num_attr) {
LOG(ERROR) << __func__ << ": can't write GATT cache attributes: " << fname;
fclose(fd);
return;
diff --git a/bta/gatt/bta_gattc_int.h b/bta/gatt/bta_gattc_int.h
index 5b33eae..2b60ac72 100644
--- a/bta/gatt/bta_gattc_int.h
+++ b/bta/gatt/bta_gattc_int.h
@@ -28,6 +28,7 @@
#include "bta_gatt_api.h"
#include "bta_sys.h"
+#include "database_builder.h"
#include "osi/include/fixed_queue.h"
#include "bt_common.h"
@@ -206,13 +207,11 @@
uint8_t state;
- std::vector<tBTA_GATTC_SERVICE> srvc_cache;
+ gatt::Database gatt_database;
uint8_t update_count; /* indication received */
uint8_t num_clcb; /* number of associated CLCB */
- std::vector<tBTA_GATTC_SERVICE> pending_discovery;
- std::vector<tBTA_GATTC_SERVICE>::iterator pending_service;
- std::vector<tBTA_GATTC_CHARACTERISTIC>::iterator pending_char;
+ gatt::DatabaseBuilder pending_discovery;
uint8_t srvc_hdl_chg; /* service handle change indication pending */
uint16_t attr_index; /* cahce NV saving/loading attribute index */
@@ -427,27 +426,24 @@
uint8_t disc_type);
extern void bta_gattc_search_service(tBTA_GATTC_CLCB* p_clcb,
bluetooth::Uuid* p_uuid);
-extern std::vector<tBTA_GATTC_SERVICE>* bta_gattc_get_services(
+extern const std::vector<gatt::Service>* bta_gattc_get_services(
uint16_t conn_id);
-extern const tBTA_GATTC_SERVICE* bta_gattc_get_service_for_handle(
- uint16_t conn_id, uint16_t handle);
-tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_characteristic_srcb(
- tBTA_GATTC_SERV* p_srcb, uint16_t handle);
-extern tBTA_GATTC_SERVICE* bta_gattc_get_service_for_handle_srcb(
- tBTA_GATTC_SERV* p_srcb, uint16_t handle);
-extern tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_characteristic(uint16_t conn_id,
- uint16_t handle);
-extern const tBTA_GATTC_DESCRIPTOR* bta_gattc_get_descriptor(uint16_t conn_id,
+extern const gatt::Service* bta_gattc_get_service_for_handle(uint16_t conn_id,
uint16_t handle);
-extern const tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_owning_characteristic(
+const gatt::Characteristic* bta_gattc_get_characteristic_srcb(
+ tBTA_GATTC_SERV* p_srcb, uint16_t handle);
+extern const gatt::Service* bta_gattc_get_service_for_handle_srcb(
+ tBTA_GATTC_SERV* p_srcb, uint16_t handle);
+extern const gatt::Characteristic* bta_gattc_get_characteristic(
+ uint16_t conn_id, uint16_t handle);
+extern const gatt::Descriptor* bta_gattc_get_descriptor(uint16_t conn_id,
+ uint16_t handle);
+extern const gatt::Characteristic* bta_gattc_get_owning_characteristic(
uint16_t conn_id, uint16_t handle);
extern void bta_gattc_get_gatt_db(uint16_t conn_id, uint16_t start_handle,
uint16_t end_handle, btgatt_db_element_t** db,
int* count);
-extern tGATT_STATUS bta_gattc_init_cache(tBTA_GATTC_SERV* p_srvc_cb);
-extern void bta_gattc_rebuild_cache(tBTA_GATTC_SERV* p_srcv, uint16_t num_attr,
- tBTA_GATTC_NV_ATTR* attr);
-extern void bta_gattc_cache_save(tBTA_GATTC_SERV* p_srvc_cb, uint16_t conn_id);
+extern void bta_gattc_init_cache(tBTA_GATTC_SERV* p_srvc_cb);
extern void bta_gattc_reset_discover_st(tBTA_GATTC_SERV* p_srcb,
tGATT_STATUS status);
diff --git a/bta/gatt/bta_gattc_utils.cc b/bta/gatt/bta_gattc_utils.cc
index 21b63c0..2c8e5fd 100644
--- a/bta/gatt/bta_gattc_utils.cc
+++ b/bta/gatt/bta_gattc_utils.cc
@@ -204,7 +204,7 @@
p_srcb->mtu = 0;
// clear reallocating
- std::vector<tBTA_GATTC_SERVICE>().swap(p_srcb->srvc_cache);
+ p_srcb->gatt_database.Clear();
}
osi_free_and_reset((void**)&p_clcb->p_q_cmd);
@@ -296,8 +296,8 @@
if (p_tcb != NULL) {
// clear reallocating
- std::vector<tBTA_GATTC_SERVICE>().swap(p_tcb->srvc_cache);
- std::vector<tBTA_GATTC_SERVICE>().swap(p_tcb->pending_discovery);
+ p_tcb->gatt_database.Clear();
+ p_tcb->pending_discovery.Clear();
*p_tcb = tBTA_GATTC_SERV();
p_tcb->in_use = true;
diff --git a/bta/gatt/database.cc b/bta/gatt/database.cc
new file mode 100644
index 0000000..5f99d55
--- /dev/null
+++ b/bta/gatt/database.cc
@@ -0,0 +1,185 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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 "database.h"
+#include "bt_trace.h"
+#include "stack/include/gattdefs.h"
+
+#include <base/logging.h>
+#include <memory>
+#include <sstream>
+
+using bluetooth::Uuid;
+
+namespace gatt {
+
+namespace {
+const Uuid PRIMARY_SERVICE = Uuid::From16Bit(GATT_UUID_PRI_SERVICE);
+const Uuid SECONDARY_SERVICE = Uuid::From16Bit(GATT_UUID_SEC_SERVICE);
+const Uuid INCLUDE = Uuid::From16Bit(GATT_UUID_INCLUDE_SERVICE);
+const Uuid CHARACTERISTIC = Uuid::From16Bit(GATT_UUID_CHAR_DECLARE);
+
+bool HandleInRange(const Service& svc, uint16_t handle) {
+ return handle >= svc.handle && handle <= svc.end_handle;
+}
+} // namespace
+
+Service* FindService(std::vector<Service>& services, uint16_t handle) {
+ for (Service& service : services) {
+ if (handle >= service.handle && handle <= service.end_handle)
+ return &service;
+ }
+
+ return nullptr;
+}
+
+std::string Database::ToString() const {
+ std::stringstream tmp;
+
+ for (const Service& service : services) {
+ tmp << "Service: handle=" << loghex(service.handle)
+ << ", end_handle=" << loghex(service.end_handle)
+ << ", uuid=" << service.uuid << "\n";
+
+ for (const auto& is : service.included_services) {
+ tmp << "\t Included service: handle=" << loghex(is.handle)
+ << ", start_handle=" << loghex(is.start_handle)
+ << ", end_handle=" << loghex(is.end_handle) << ", uuid=" << is.uuid
+ << "\n";
+ }
+
+ for (const Characteristic& c : service.characteristics) {
+ tmp << "\t Characteristic: declaration_handle="
+ << loghex(c.declaration_handle)
+ << ", value_handle=" << loghex(c.value_handle) << ", uuid=" << c.uuid
+ << ", prop=" << loghex(c.properties) << "\n";
+
+ for (const Descriptor& d : c.descriptors) {
+ tmp << "\t\t Descriptor: handle=" << loghex(d.handle)
+ << ", uuid=" << d.uuid << "\n";
+ }
+ }
+ }
+ return tmp.str();
+}
+
+std::vector<StoredAttribute> Database::Serialize() const {
+ std::vector<StoredAttribute> nv_attr;
+
+ if (services.empty()) return std::vector<StoredAttribute>();
+
+ for (const Service& service : services) {
+ // TODO: add constructor to NV_ATTR, use emplace_back
+ nv_attr.push_back({service.handle,
+ service.is_primary ? PRIMARY_SERVICE : SECONDARY_SERVICE,
+ {.service = {.uuid = service.uuid,
+ .end_handle = service.end_handle}}});
+ }
+
+ for (const Service& service : services) {
+ for (const IncludedService& p_isvc : service.included_services) {
+ nv_attr.push_back({p_isvc.handle,
+ INCLUDE,
+ {.included_service = {.handle = p_isvc.start_handle,
+ .end_handle = p_isvc.end_handle,
+ .uuid = p_isvc.uuid}}});
+ }
+
+ for (const Characteristic& charac : service.characteristics) {
+ nv_attr.push_back(
+ {charac.declaration_handle,
+ CHARACTERISTIC,
+ {.characteristic = {.properties = charac.properties,
+ .value_handle = charac.value_handle,
+ .uuid = charac.uuid}}});
+
+ for (const Descriptor& desc : charac.descriptors) {
+ nv_attr.push_back({desc.handle, desc.uuid, {}});
+ }
+ }
+ }
+
+ return nv_attr;
+}
+
+Database Database::Deserialize(const std::vector<StoredAttribute>& nv_attr,
+ bool* success) {
+ // clear reallocating
+ Database result;
+ auto it = nv_attr.cbegin();
+
+ for (; it != nv_attr.cend(); ++it) {
+ const auto& attr = *it;
+ if (attr.type != PRIMARY_SERVICE && attr.type != SECONDARY_SERVICE) break;
+ result.services.emplace_back(
+ Service{.handle = attr.handle,
+ .end_handle = attr.value.service.end_handle,
+ .is_primary = (attr.type == PRIMARY_SERVICE),
+ .uuid = attr.value.service.uuid});
+ }
+
+ auto current_service_it = result.services.begin();
+ for (; it != nv_attr.cend(); it++) {
+ const auto& attr = *it;
+
+ // go to the service this attribute belongs to; attributes are stored in
+ // order, so iterating just forward is enough
+ while (current_service_it != result.services.end() &&
+ current_service_it->end_handle < attr.handle) {
+ current_service_it++;
+ }
+
+ if (current_service_it == result.services.end() ||
+ !HandleInRange(*current_service_it, attr.handle)) {
+ LOG(ERROR) << "Can't find service for attribute with handle: "
+ << loghex(attr.handle);
+ *success = false;
+ return result;
+ }
+
+ if (attr.type == INCLUDE) {
+ Service* included_service =
+ FindService(result.services, attr.value.included_service.handle);
+ if (!included_service) {
+ LOG(ERROR) << __func__ << ": Non-existing included service!";
+ *success = false;
+ return result;
+ }
+ current_service_it->included_services.push_back(IncludedService{
+ .handle = attr.handle,
+ .uuid = attr.value.included_service.uuid,
+ .start_handle = attr.value.included_service.handle,
+ .end_handle = attr.value.included_service.end_handle,
+ });
+ } else if (attr.type == CHARACTERISTIC) {
+ current_service_it->characteristics.emplace_back(
+ Characteristic{.declaration_handle = attr.handle,
+ .value_handle = attr.value.characteristic.value_handle,
+ .properties = attr.value.characteristic.properties,
+ .uuid = attr.value.characteristic.uuid});
+
+ } else {
+ current_service_it->characteristics.back().descriptors.emplace_back(
+ Descriptor{.handle = attr.handle, .uuid = attr.type});
+ }
+ }
+ *success = true;
+ return result;
+}
+
+} // namespace gatt
\ No newline at end of file
diff --git a/bta/gatt/database.h b/bta/gatt/database.h
new file mode 100644
index 0000000..1e74809
--- /dev/null
+++ b/bta/gatt/database.h
@@ -0,0 +1,126 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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 <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "types/bluetooth/uuid.h"
+
+namespace gatt {
+constexpr uint16_t HANDLE_MIN = 0x0001;
+constexpr uint16_t HANDLE_MAX = 0xffff;
+
+/* Representation of GATT attribute for storage */
+struct StoredAttribute {
+ uint16_t handle;
+ bluetooth::Uuid type;
+
+ union {
+ /* primary or secondary service definition */
+ struct {
+ bluetooth::Uuid uuid;
+ uint16_t end_handle;
+ } service;
+
+ /* included service definition */
+ struct {
+ uint16_t handle;
+ uint16_t end_handle;
+ bluetooth::Uuid uuid;
+ } included_service;
+
+ /* characteristic deifnition */
+ struct {
+ uint8_t properties;
+ uint16_t value_handle;
+ bluetooth::Uuid uuid;
+ } characteristic;
+
+ /* for descriptor definition we don't store value*/
+ } value;
+};
+
+struct IncludedService;
+struct Characteristic;
+struct Descriptor;
+
+struct Service {
+ uint16_t handle;
+ bluetooth::Uuid uuid;
+ bool is_primary;
+ uint16_t end_handle;
+ std::vector<IncludedService> included_services;
+ std::vector<Characteristic> characteristics;
+};
+
+struct IncludedService {
+ uint16_t handle; /* definition handle */
+ bluetooth::Uuid uuid;
+ uint16_t start_handle; /* start handle of included service */
+ uint16_t end_handle; /* end handle of included service */
+};
+
+struct Characteristic {
+ uint16_t declaration_handle;
+ bluetooth::Uuid uuid;
+ uint16_t value_handle;
+ uint8_t properties;
+ std::vector<Descriptor> descriptors;
+};
+
+struct Descriptor {
+ uint16_t handle;
+ bluetooth::Uuid uuid;
+};
+
+class DatabaseBuilder;
+
+class Database {
+ public:
+ /* Return true if there are no services in this database. */
+ bool IsEmpty() const { return services.empty(); }
+
+ /* Clear the GATT database. This method forces relocation to ensure no extra
+ * space is used unnecesarly */
+ void Clear() { std::vector<Service>().swap(services); }
+
+ /* Return list of services available in this database */
+ const std::vector<Service>& Services() const { return services; }
+
+ std::string ToString() const;
+
+ std::vector<gatt::StoredAttribute> Serialize() const;
+
+ static Database Deserialize(const std::vector<gatt::StoredAttribute>& nv_attr,
+ bool* success);
+
+ friend class DatabaseBuilder;
+
+ private:
+ std::vector<Service> services;
+};
+
+/* Find a service that should contain handle. Helper method for internal use
+ * inside gatt namespace.*/
+Service* FindService(std::vector<Service>& services, uint16_t handle);
+
+} // namespace gatt
diff --git a/bta/gatt/database_builder.cc b/bta/gatt/database_builder.cc
new file mode 100644
index 0000000..ed065ab
--- /dev/null
+++ b/bta/gatt/database_builder.cc
@@ -0,0 +1,190 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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 "database_builder.h"
+
+#include "bt_trace.h"
+
+#include <base/logging.h>
+#include <algorithm>
+
+using bluetooth::Uuid;
+
+namespace gatt {
+
+void DatabaseBuilder::AddService(uint16_t handle, uint16_t end_handle,
+ const Uuid& uuid, bool is_primary) {
+ // general case optimization - we add services in order
+ if (database.services.empty() ||
+ database.services.back().end_handle < handle) {
+ database.services.emplace_back(Service{.handle = handle,
+ .end_handle = end_handle,
+ .is_primary = is_primary,
+ .uuid = uuid});
+ } else {
+ auto& vec = database.services;
+
+ // Find first service whose start handle is bigger than new service handle
+ auto it = std::lower_bound(
+ vec.begin(), vec.end(), handle,
+ [](Service s, uint16_t handle) { return s.end_handle < handle; });
+
+ // Insert new service just before it
+ vec.emplace(it, Service{.handle = handle,
+ .end_handle = end_handle,
+ .is_primary = is_primary,
+ .uuid = uuid});
+ }
+
+ services_to_discover.insert({handle, end_handle});
+}
+
+void DatabaseBuilder::AddIncludedService(uint16_t handle, const Uuid& uuid,
+ uint16_t start_handle,
+ uint16_t end_handle) {
+ Service* service = FindService(database.services, handle);
+ if (!service) {
+ LOG(ERROR) << "Illegal action to add to non-existing service!";
+ return;
+ }
+
+ /* We discover all Primary Services first. If included service was not seen
+ * before, it must be a Secondary Service */
+ if (!FindService(database.services, start_handle)) {
+ AddService(start_handle, end_handle, uuid, false /* not primary */);
+ }
+
+ service->included_services.push_back(IncludedService{
+ .handle = handle,
+ .uuid = uuid,
+ .start_handle = start_handle,
+ .end_handle = end_handle,
+ });
+}
+
+void DatabaseBuilder::AddCharacteristic(uint16_t handle, uint16_t value_handle,
+ const Uuid& uuid, uint8_t properties) {
+ Service* service = FindService(database.services, handle);
+ if (!service) {
+ LOG(ERROR) << "Illegal action to add to non-existing service!";
+ return;
+ }
+
+ if (service->end_handle < value_handle)
+ LOG(WARNING) << "Remote device violates spec: value_handle="
+ << loghex(value_handle) << " is after service end_handle="
+ << loghex(service->end_handle);
+
+ service->characteristics.emplace_back(
+ Characteristic{.declaration_handle = handle,
+ .value_handle = value_handle,
+ .properties = properties,
+ .uuid = uuid});
+ return;
+}
+
+void DatabaseBuilder::AddDescriptor(uint16_t handle, const Uuid& uuid) {
+ Service* service = FindService(database.services, handle);
+ if (!service) {
+ LOG(ERROR) << "Illegal action to add to non-existing service!";
+ return;
+ }
+
+ if (service->characteristics.empty()) {
+ LOG(ERROR) << __func__
+ << ": Illegal action to add to non-existing characteristic!";
+ return;
+ }
+
+ Characteristic* char_node = &service->characteristics.front();
+ for (auto it = service->characteristics.begin();
+ it != service->characteristics.end(); it++) {
+ if (it->declaration_handle > handle) break;
+ char_node = &(*it);
+ }
+
+ char_node->descriptors.emplace_back(
+ gatt::Descriptor{.handle = handle, .uuid = uuid});
+}
+
+bool DatabaseBuilder::StartNextServiceExploration() {
+ while (!services_to_discover.empty()) {
+ auto handle_range = services_to_discover.begin();
+ pending_service = *handle_range;
+ services_to_discover.erase(handle_range);
+
+ // Empty service declaration, nothing to explore, skip to next.
+ if (pending_service.first == pending_service.second) continue;
+
+ pending_characteristic = HANDLE_MIN;
+ return true;
+ }
+ return false;
+}
+
+const std::pair<uint16_t, uint16_t>&
+DatabaseBuilder::CurrentlyExploredService() {
+ return pending_service;
+}
+
+std::pair<uint16_t, uint16_t> DatabaseBuilder::NextDescriptorRangeToExplore() {
+ Service* service = FindService(database.services, pending_service.first);
+ if (!service || service->characteristics.empty()) {
+ return {HANDLE_MAX, HANDLE_MAX};
+ }
+
+ for (auto it = service->characteristics.cbegin();
+ it != service->characteristics.cend(); it++) {
+ if (it->declaration_handle > pending_characteristic) {
+ auto next = std::next(it);
+
+ /* Characteristic Declaration is followed by Characteristic Value
+ * Declaration, first descriptor is after that, see BT Spect 5.0 Vol 3,
+ * Part G 3.3.2 and 3.3.3 */
+ uint16_t start = it->declaration_handle + 2;
+ uint16_t end;
+ if (next != service->characteristics.end())
+ end = next->declaration_handle - 1;
+ else
+ end = service->end_handle;
+
+ // No place for descriptor - skip to next characteristic
+ if (start > end) continue;
+
+ pending_characteristic = start;
+ return {start, end};
+ }
+ }
+
+ pending_characteristic = HANDLE_MAX;
+ return {HANDLE_MAX, HANDLE_MAX};
+}
+
+bool DatabaseBuilder::InProgress() const { return !database.services.empty(); }
+
+Database DatabaseBuilder::Build() {
+ Database tmp = database;
+ database.Clear();
+ return tmp;
+}
+
+void DatabaseBuilder::Clear() { database.Clear(); }
+
+std::string DatabaseBuilder::ToString() const { return database.ToString(); }
+
+} // namespace gatt
diff --git a/bta/gatt/database_builder.h b/bta/gatt/database_builder.h
new file mode 100644
index 0000000..0913100
--- /dev/null
+++ b/bta/gatt/database_builder.h
@@ -0,0 +1,84 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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 "gatt/database.h"
+
+#include <utility>
+#include <vector>
+
+namespace gatt {
+
+class DatabaseBuilder {
+ public:
+ constexpr static std::pair<uint16_t, uint16_t> EXPLORE_END =
+ std::make_pair(0xFFFF, 0xFFFF);
+
+ void AddService(uint16_t handle, uint16_t end_handle,
+ const bluetooth::Uuid& uuid, bool is_primary);
+ void AddIncludedService(uint16_t handle, const bluetooth::Uuid& uuid,
+ uint16_t start_handle, uint16_t end_handle);
+ void AddCharacteristic(uint16_t handle, uint16_t value_handle,
+ const bluetooth::Uuid& uuid, uint8_t properties);
+ void AddDescriptor(uint16_t handle, const bluetooth::Uuid& uuid);
+
+ /* Returns true if next service exploration started, false if there are no
+ * more services to explore. */
+ bool StartNextServiceExploration();
+
+ /* Return pair with start and end handle of the currently explored service.
+ */
+ const std::pair<uint16_t, uint16_t>& CurrentlyExploredService();
+
+ /* Return pair with start and end handle of the descriptor range to discover,
+ * or DatabaseBuilder::EXPLORE_END if no more descriptors left.
+ */
+ std::pair<uint16_t, uint16_t> NextDescriptorRangeToExplore();
+
+ /* Returns true, if GATT discovery is in progress, false if discovery was not
+ * started, or is already finished.
+ */
+ // TODO(jpawlowski): in the future, we might create this object only for the
+ // time of discovery, in such case InProgress won't be needed, because object
+ // existence will mean discovery is pending
+ bool InProgress() const;
+
+ /* Call this method at end of GATT discovery, to obtain object representing
+ * the database of remote device */
+ Database Build();
+
+ void Clear();
+
+ /* Return text representation of internal state for debugging purposes */
+ std::string ToString() const;
+
+ private:
+ Database database;
+ /* Start and end handle of service that is currently being discovered on the
+ * remote device */
+ std::pair<uint16_t, uint16_t> pending_service;
+ /* Characteristic inside pending_service that is currently being explored */
+ uint16_t pending_characteristic;
+
+ /* sorted, unique set of start_handle, end_handle pair of all services that
+ * have not yet been discovered */
+ std::set<std::pair<uint16_t, uint16_t>> services_to_discover;
+};
+
+} // namespace gatt
diff --git a/bta/hearing_aid/hearing_aid.cc b/bta/hearing_aid/hearing_aid.cc
index 8779542..b9156af 100644
--- a/bta/hearing_aid/hearing_aid.cc
+++ b/bta/hearing_aid/hearing_aid.cc
@@ -25,6 +25,7 @@
#include "embdrv/g722/g722_enc_dec.h"
#include "gap_api.h"
#include "gatt_api.h"
+#include "osi/include/properties.h"
#include <base/bind.h>
#include <base/logging.h>
@@ -36,6 +37,13 @@
using bluetooth::Uuid;
using bluetooth::hearing_aid::ConnectionState;
+// The MIN_CE_LEN parameter for Connection Parameters based on the current
+// Connection Interval
+constexpr uint16_t MIN_CE_LEN_10MS_CI = 0x0006;
+constexpr uint16_t MIN_CE_LEN_20MS_CI = 0x000C;
+constexpr uint16_t CONNECTION_INTERVAL_10MS_PARAM = 0x0008;
+constexpr uint16_t CONNECTION_INTERVAL_20MS_PARAM = 0x0010;
+
void btif_storage_add_hearing_aid(const RawAddress& address, uint16_t psm,
uint8_t capabilities, uint16_t codecs,
uint16_t audio_control_point_handle,
@@ -70,8 +78,6 @@
Uuid LE_PSM_UUID = Uuid::FromString("2d410339-82b6-42aa-b34e-e2e01df8cc1a");
// clang-format on
-constexpr uint16_t MIN_CE_LEN_1M = 0x0006;
-
void hearingaid_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data);
void encryption_callback(const RawAddress*, tGATT_TRANSPORT, void*,
tBTM_STATUS);
@@ -252,8 +258,20 @@
: gatt_if(0),
seq_counter(0),
current_volume(VOLUME_UNKNOWN),
- callbacks(callbacks) {
- DVLOG(2) << __func__;
+ callbacks(callbacks),
+ codec_in_use(0) {
+ default_data_interval_ms = (uint16_t)osi_property_get_int32(
+ "persist.bluetooth.hearingaid.interval", (int32_t)HA_INTERVAL_20_MS);
+ if ((default_data_interval_ms != HA_INTERVAL_10_MS) &&
+ (default_data_interval_ms != HA_INTERVAL_20_MS)) {
+ LOG(ERROR) << __func__
+ << ": invalid interval=" << default_data_interval_ms
+ << "ms. Overwriting back to default";
+ default_data_interval_ms = HA_INTERVAL_20_MS;
+ }
+ VLOG(2) << __func__
+ << ", default_data_interval_ms=" << default_data_interval_ms;
+
BTA_GATTC_AppRegister(
hearingaid_gattc_callback,
base::Bind(
@@ -269,6 +287,31 @@
initCb));
}
+ void UpdateBleConnParams(const RawAddress& address) {
+ /* List of parameters that depends on the chosen Connection Interval */
+ uint16_t min_ce_len;
+ uint16_t connection_interval;
+
+ switch (default_data_interval_ms) {
+ case HA_INTERVAL_10_MS:
+ min_ce_len = MIN_CE_LEN_10MS_CI;
+ connection_interval = CONNECTION_INTERVAL_10MS_PARAM;
+ break;
+ case HA_INTERVAL_20_MS:
+ min_ce_len = MIN_CE_LEN_20MS_CI;
+ connection_interval = CONNECTION_INTERVAL_20MS_PARAM;
+ break;
+ default:
+ LOG(ERROR) << __func__ << ":Error: invalid default_data_interval_ms="
+ << default_data_interval_ms;
+ min_ce_len = MIN_CE_LEN_10MS_CI;
+ connection_interval = CONNECTION_INTERVAL_10MS_PARAM;
+ }
+
+ L2CA_UpdateBleConnParams(address, connection_interval, connection_interval,
+ 0x000A, 0x0064 /*1s*/, min_ce_len, min_ce_len);
+ }
+
void Connect(const RawAddress& address) override {
DVLOG(2) << __func__ << " " << address;
hearingDevices.Add(HearingDevice(address, true));
@@ -339,13 +382,12 @@
// update now, it'll be started once current device finishes.
hearingDevice->connection_update_pending = true;
if (!any_update_pending) {
- L2CA_UpdateBleConnParams(address, 0x0008, 0x0008, 0x000A, 0x0064 /*1s*/,
- MIN_CE_LEN_1M, MIN_CE_LEN_1M);
+ UpdateBleConnParams(address);
}
// Set data length
// TODO(jpawlowski: for 16khz only 87 is required, optimize
- BTM_SetBleDataLength(address, 147);
+ BTM_SetBleDataLength(address, 168);
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(address);
if (p_dev_rec) {
@@ -390,8 +432,7 @@
for (auto& device : hearingDevices.devices) {
if (device.conn_id && device.connection_update_pending) {
- L2CA_UpdateBleConnParams(device.address, 0x0008, 0x0008, 0x000A,
- 0x0064 /*1s*/, MIN_CE_LEN_1M, MIN_CE_LEN_1M);
+ UpdateBleConnParams(device.address);
return;
}
}
@@ -444,11 +485,10 @@
return;
}
- const std::vector<tBTA_GATTC_SERVICE>* services =
- BTA_GATTC_GetServices(conn_id);
+ const std::vector<gatt::Service>* services = BTA_GATTC_GetServices(conn_id);
- const tBTA_GATTC_SERVICE* service = nullptr;
- for (const tBTA_GATTC_SERVICE& tmp : *services) {
+ const gatt::Service* service = nullptr;
+ for (const gatt::Service& tmp : *services) {
if (tmp.uuid != HEARING_AID_UUID) continue;
LOG(INFO) << "Found Hearing Aid service, handle=" << loghex(tmp.handle);
service = &tmp;
@@ -463,7 +503,7 @@
}
uint16_t psm_handle = 0x0000;
- for (const tBTA_GATTC_CHARACTERISTIC& charac : service->characteristics) {
+ for (const gatt::Characteristic& charac : service->characteristics) {
if (charac.uuid == READ_ONLY_PROPERTIES_UUID) {
DVLOG(2) << "Reading read only properties "
<< loghex(charac.value_handle);
@@ -557,6 +597,49 @@
}
}
+ uint16_t CalcCompressedAudioPacketSize(uint16_t codec_type,
+ int connection_interval) {
+ int sample_rate;
+
+ const int sample_bit_rate = 16; /* 16 bits per sample */
+ const int compression_ratio = 4; /* G.722 has a 4:1 compression ratio */
+ if (codec_type == CODEC_G722_24KHZ) {
+ sample_rate = 24000;
+ } else {
+ sample_rate = 16000;
+ }
+
+ // compressed_data_packet_size is the size in bytes of the compressed audio
+ // data buffer that is generated for each connection interval.
+ uint32_t compressed_data_packet_size =
+ (sample_rate * connection_interval * (sample_bit_rate / 8) /
+ compression_ratio) /
+ 1000;
+ return ((uint16_t)compressed_data_packet_size);
+ }
+
+ void ChooseCodec(const HearingDevice& hearingDevice) {
+ if (codec_in_use) return;
+
+ // use the best codec available for this pair of devices.
+ uint16_t codecs = hearingDevice.codecs;
+ if (hearingDevice.hi_sync_id != 0) {
+ for (const auto& device : hearingDevices.devices) {
+ if (device.hi_sync_id != hearingDevice.hi_sync_id) continue;
+
+ codecs &= device.codecs;
+ }
+ }
+
+ if ((codecs & (1 << CODEC_G722_24KHZ)) &&
+ controller_get_interface()->supports_ble_2m_phy() &&
+ default_data_interval_ms == HA_INTERVAL_10_MS) {
+ codec_in_use = CODEC_G722_24KHZ;
+ } else if (codecs & (1 << CODEC_G722_16KHZ)) {
+ codec_in_use = CODEC_G722_16KHZ;
+ }
+ }
+
void OnAudioStatus(uint16_t conn_id, tGATT_STATUS status, uint16_t handle,
uint16_t len, uint8_t* value, void* data) {
DVLOG(2) << __func__ << " " << base::HexEncode(value, len);
@@ -648,16 +731,20 @@
hearingDevice->first_connection = false;
}
+ ChooseCodec(*hearingDevice);
+
SendStart(*hearingDevice);
hearingDevice->accepting_audio = true;
LOG(INFO) << __func__ << ": address=" << address
- << ", hi_sync_id=" << loghex(hearingDevice->hi_sync_id);
+ << ", hi_sync_id=" << loghex(hearingDevice->hi_sync_id)
+ << ", codec_in_use=" << loghex(codec_in_use);
+
+ StartSendingAudio(*hearingDevice);
+
callbacks->OnDeviceAvailable(hearingDevice->capabilities,
hearingDevice->hi_sync_id, address);
callbacks->OnConnectionState(ConnectionState::CONNECTED, address);
-
- StartSendingAudio(*hearingDevice);
}
void StartSendingAudio(const HearingDevice& hearingDevice) {
@@ -678,21 +765,15 @@
}
}
- if ((codecs & (1 << CODEC_G722_24KHZ)) &&
- controller_get_interface()->supports_ble_2m_phy()) {
- codec_in_use = CODEC_G722_24KHZ;
+ CodecConfiguration codec;
+ if (codec_in_use == CODEC_G722_24KHZ) {
codec.sample_rate = 24000;
- codec.bit_rate = 16;
- codec.data_interval_ms = 10;
- } else if (codecs & (1 << CODEC_G722_16KHZ)) {
- codec_in_use = CODEC_G722_16KHZ;
+ } else {
codec.sample_rate = 16000;
- codec.bit_rate = 16;
- codec.data_interval_ms = 10;
}
+ codec.bit_rate = 16;
+ codec.data_interval_ms = default_data_interval_ms;
- // TODO: remove once we implement support for other codecs
- codec_in_use = CODEC_G722_16KHZ;
HearingAidAudioSource::Start(codec, audioReceiver);
}
}
@@ -802,7 +883,9 @@
// TODO: this should basically fit the encoded data, tune the size later
std::vector<uint8_t> encoded_data_left;
if (left) {
- encoded_data_left.resize(2000);
+ // TODO: instead of a magic number, we need to figure out the correct
+ // buffer size
+ encoded_data_left.resize(4000);
int encoded_size =
g722_encode(encoder_state_left, encoded_data_left.data(),
(const int16_t*)chan_left.data(), chan_left.size());
@@ -822,7 +905,9 @@
std::vector<uint8_t> encoded_data_right;
if (right) {
- encoded_data_right.resize(2000);
+ // TODO: instead of a magic number, we need to figure out the correct
+ // buffer size
+ encoded_data_right.resize(4000);
int encoded_size =
g722_encode(encoder_state_right, encoded_data_right.data(),
(const int16_t*)chan_right.data(), chan_right.size());
@@ -843,15 +928,8 @@
size_t encoded_data_size =
std::max(encoded_data_left.size(), encoded_data_right.size());
- // TODO: make it also dependent on the interval, when we support intervals
- // different than 10ms
- uint16_t packet_size;
-
- if (codec_in_use == CODEC_G722_24KHZ) {
- packet_size = 120;
- } else /* if (codec_in_use == CODEC_G722_16KHZ) */ {
- packet_size = 80;
- }
+ uint16_t packet_size =
+ CalcCompressedAudioPacketSize(codec_in_use, default_data_interval_ms);
for (size_t i = 0; i < encoded_data_size; i += packet_size) {
if (left) {
@@ -1080,7 +1158,8 @@
/* currently used codec */
uint8_t codec_in_use;
- CodecConfiguration codec;
+
+ uint16_t default_data_interval_ms;
HearingDevices hearingDevices;
};
diff --git a/bta/hearing_aid/hearing_aid_audio_source.cc b/bta/hearing_aid/hearing_aid_audio_source.cc
index 947caaf..e03b040 100644
--- a/bta/hearing_aid/hearing_aid_audio_source.cc
+++ b/bta/hearing_aid/hearing_aid_audio_source.cc
@@ -28,9 +28,9 @@
extern const char* audio_ha_hw_dump_ctrl_event(tHEARING_AID_CTRL_CMD event);
namespace {
-int bit_rate = 16;
-int sample_rate = 16000;
-int data_interval_ms = 10 /* msec */;
+int bit_rate = -1;
+int sample_rate = -1;
+int data_interval_ms = -1;
int num_channels = 2;
alarm_t* audio_timer = nullptr;
@@ -94,6 +94,11 @@
UIPC_Ioctl(*uipc_hearing_aid, UIPC_CH_ID_AV_AUDIO, UIPC_SET_READ_POLL_TMO,
reinterpret_cast<void*>(0));
+ if (data_interval_ms != HA_INTERVAL_10_MS &&
+ data_interval_ms != HA_INTERVAL_20_MS) {
+ LOG(FATAL) << " Unsupported data interval: " << data_interval_ms;
+ }
+
audio_timer = alarm_new_periodic("hearing_aid_data_timer");
alarm_set_on_mloop(audio_timer, data_interval_ms, send_audio_data,
nullptr);
@@ -266,6 +271,11 @@
HearingAidAudioReceiver* audioReceiver) {
localAudioReceiver = audioReceiver;
VLOG(2) << "Hearing Aid UIPC Open";
+
+ bit_rate = codecConfiguration.bit_rate;
+ sample_rate = codecConfiguration.sample_rate;
+ data_interval_ms = codecConfiguration.data_interval_ms;
+
stats.Reset();
}
diff --git a/bta/hf_client/bta_hf_client_main.cc b/bta/hf_client/bta_hf_client_main.cc
index 4f717ae..9bb8ab5 100644
--- a/bta/hf_client/bta_hf_client_main.cc
+++ b/bta/hf_client/bta_hf_client_main.cc
@@ -386,7 +386,7 @@
/* reopen registered server */
/* Collision may be detected before or after we close servers. */
- // bta_hf_client_start_server();
+ bta_hf_client_start_server();
/* Start timer to handle connection opening restart */
alarm_set_on_mloop(client_cb->collision_timer,
diff --git a/bta/hh/bta_hh_le.cc b/bta/hh/bta_hh_le.cc
index adeb957..759d6a1 100644
--- a/bta/hh/bta_hh_le.cc
+++ b/bta/hh/bta_hh_le.cc
@@ -457,9 +457,9 @@
return NULL;
}
-static const tBTA_GATTC_DESCRIPTOR* find_descriptor_by_short_uuid(
+static const gatt::Descriptor* find_descriptor_by_short_uuid(
uint16_t conn_id, uint16_t char_handle, uint16_t short_uuid) {
- const tBTA_GATTC_CHARACTERISTIC* p_char =
+ const gatt::Characteristic* p_char =
BTA_GATTC_GetCharacteristic(conn_id, char_handle);
if (!p_char) {
@@ -467,7 +467,7 @@
return NULL;
}
- for (const tBTA_GATTC_DESCRIPTOR& desc : p_char->descriptors) {
+ for (const gatt::Descriptor& desc : p_char->descriptors) {
if (desc.uuid == Uuid::From16Bit(short_uuid)) return &desc;
}
@@ -486,7 +486,7 @@
uint16_t short_uuid,
GATT_READ_OP_CB cb,
void* cb_data) {
- const tBTA_GATTC_DESCRIPTOR* p_desc =
+ const gatt::Descriptor* p_desc =
find_descriptor_by_short_uuid(p_cb->conn_id, char_handle, short_uuid);
if (!p_desc) return BTA_HH_ERR;
@@ -671,7 +671,7 @@
bool bta_hh_le_write_ccc(tBTA_HH_DEV_CB* p_cb, uint8_t char_handle,
uint16_t clt_cfg_value, GATT_WRITE_OP_CB cb,
void* cb_data) {
- const tBTA_GATTC_DESCRIPTOR* p_desc = find_descriptor_by_short_uuid(
+ const gatt::Descriptor* p_desc = find_descriptor_by_short_uuid(
p_cb->conn_id, char_handle, GATT_UUID_CHAR_CLIENT_CONFIG);
if (!p_desc) return false;
@@ -691,7 +691,7 @@
uint8_t srvc_inst_id, hid_inst_id;
tBTA_HH_DEV_CB* p_dev_cb = (tBTA_HH_DEV_CB*)data;
- const tBTA_GATTC_CHARACTERISTIC* characteristic =
+ const gatt::Characteristic* characteristic =
BTA_GATTC_GetOwningCharacteristic(conn_id, handle);
uint16_t char_uuid = characteristic->uuid.As16Bit();
@@ -1310,17 +1310,16 @@
}
tBTA_HH_DEV_CB* p_dev_cb = (tBTA_HH_DEV_CB*)data;
- const tBTA_GATTC_DESCRIPTOR* p_desc =
- BTA_GATTC_GetDescriptor(conn_id, handle);
+ const gatt::Descriptor* p_desc = BTA_GATTC_GetDescriptor(conn_id, handle);
if (!p_desc) {
APPL_TRACE_ERROR("%s: error: descriptor is null!", __func__);
return;
}
- const tBTA_GATTC_CHARACTERISTIC* characteristic =
+ const gatt::Characteristic* characteristic =
BTA_GATTC_GetOwningCharacteristic(conn_id, handle);
- const tBTA_GATTC_SERVICE* service =
+ const gatt::Service* service =
BTA_GATTC_GetOwningService(conn_id, characteristic->value_handle);
tBTA_HH_LE_RPT* p_rpt;
@@ -1398,10 +1397,10 @@
*
******************************************************************************/
static void bta_hh_le_search_hid_chars(tBTA_HH_DEV_CB* p_dev_cb,
- const tBTA_GATTC_SERVICE* service) {
+ const gatt::Service* service) {
tBTA_HH_LE_RPT* p_rpt;
- for (const tBTA_GATTC_CHARACTERISTIC& charac : service->characteristics) {
+ for (const gatt::Characteristic& charac : service->characteristics) {
if (!charac.uuid.Is16Bit()) continue;
uint16_t uuid16 = charac.uuid.As16Bit();
@@ -1460,7 +1459,7 @@
}
/* Make sure PROTO_MODE is processed as last */
- for (const tBTA_GATTC_CHARACTERISTIC& charac : service->characteristics) {
+ for (const gatt::Characteristic& charac : service->characteristics) {
if (charac.uuid == Uuid::From16Bit(GATT_UUID_HID_PROTO_MODE)) {
p_dev_cb->hid_srvc.proto_mode_handle = charac.value_handle;
bta_hh_le_set_protocol_mode(p_dev_cb, p_dev_cb->mode);
@@ -1491,11 +1490,11 @@
return;
}
- const std::vector<tBTA_GATTC_SERVICE>* services =
+ const std::vector<gatt::Service>* services =
BTA_GATTC_GetServices(p_data->conn_id);
bool have_hid = false;
- for (const tBTA_GATTC_SERVICE& service : *services) {
+ for (const gatt::Service& service : *services) {
if (service.uuid == Uuid::From16Bit(UUID_SERVCLASS_LE_HID) &&
service.is_primary && !have_hid) {
have_hid = true;
@@ -1513,7 +1512,7 @@
} else if (service.uuid == Uuid::From16Bit(UUID_SERVCLASS_SCAN_PARAM)) {
p_dev_cb->scan_refresh_char_handle = 0;
- for (const tBTA_GATTC_CHARACTERISTIC& charac : service.characteristics) {
+ for (const gatt::Characteristic& charac : service.characteristics) {
if (charac.uuid == Uuid::From16Bit(GATT_UUID_SCAN_REFRESH)) {
p_dev_cb->scan_refresh_char_handle = charac.value_handle;
@@ -1528,7 +1527,7 @@
} else if (service.uuid == Uuid::From16Bit(UUID_SERVCLASS_GAP_SERVER)) {
// TODO(jpawlowski): this should be done by GAP profile, remove when GAP
// is fixed.
- for (const tBTA_GATTC_CHARACTERISTIC& charac : service.characteristics) {
+ for (const gatt::Characteristic& charac : service.characteristics) {
if (charac.uuid == Uuid::From16Bit(GATT_UUID_GAP_PREF_CONN_PARAM)) {
/* read the char value */
BtaGattQueue::ReadCharacteristic(p_dev_cb->conn_id,
@@ -1565,7 +1564,7 @@
return;
}
- const tBTA_GATTC_CHARACTERISTIC* p_char =
+ const gatt::Characteristic* p_char =
BTA_GATTC_GetCharacteristic(p_dev_cb->conn_id, p_data->handle);
if (p_char == NULL) {
APPL_TRACE_ERROR(
@@ -1719,7 +1718,7 @@
static void read_report_cb(uint16_t conn_id, tGATT_STATUS status,
uint16_t handle, uint16_t len, uint8_t* value,
void* data) {
- const tBTA_GATTC_CHARACTERISTIC* p_char =
+ const gatt::Characteristic* p_char =
BTA_GATTC_GetCharacteristic(conn_id, handle);
if (p_char == NULL) return;
@@ -1752,7 +1751,7 @@
hs_data.handle = p_dev_cb->hid_handle;
if (status == GATT_SUCCESS) {
- const tBTA_GATTC_SERVICE* p_svc =
+ const gatt::Service* p_svc =
BTA_GATTC_GetOwningService(conn_id, p_char->value_handle);
p_rpt = bta_hh_le_find_report_entry(p_dev_cb, p_svc->handle, char_uuid,
@@ -1818,7 +1817,7 @@
APPL_TRACE_DEBUG("bta_hh_le_write_cmpl w4_evt: %d", p_dev_cb->w4_evt);
#endif
- const tBTA_GATTC_CHARACTERISTIC* p_char =
+ const gatt::Characteristic* p_char =
BTA_GATTC_GetCharacteristic(conn_id, handle);
uint16_t uuid = p_char->uuid.As16Bit();
if (uuid != GATT_UUID_HID_REPORT && uuid != GATT_UUID_HID_BT_KB_INPUT &&
@@ -1867,7 +1866,7 @@
p_cb->w4_evt = w4_evt;
- const tBTA_GATTC_CHARACTERISTIC* p_char =
+ const gatt::Characteristic* p_char =
BTA_GATTC_GetCharacteristic(p_cb->conn_id, p_rpt->char_inst_id);
tGATT_WRITE_TYPE write_type = GATT_WRITE;
diff --git a/bta/include/bta_api.h b/bta/include/bta_api.h
index 9f2ee28..85b50b6 100644
--- a/bta/include/bta_api.h
+++ b/bta/include/bta_api.h
@@ -485,9 +485,9 @@
typedef uint8_t tBTA_DM_BLE_LOCAL_KEY_MASK;
typedef struct {
- BT_OCTET16 ir;
- BT_OCTET16 irk;
- BT_OCTET16 dhk;
+ Octet16 ir;
+ Octet16 irk;
+ Octet16 dhk;
} tBTA_BLE_LOCAL_ID_KEYS;
#define BTA_DM_SEC_GRANTED BTA_SUCCESS
@@ -512,7 +512,7 @@
RawAddress bd_addr; /* BD address peer device. */
BD_NAME bd_name; /* Name of peer device. */
bool key_present; /* Valid link key value in key element */
- LINK_KEY key; /* Link key associated with peer device. */
+ LinkKey key; /* Link key associated with peer device. */
uint8_t key_type; /* The type of Link Key */
bool success; /* true of authentication succeeded, false if failed. */
uint8_t fail_reason; /* The HCI reason/error code for when success=false */
@@ -689,7 +689,7 @@
tBTA_DM_BLE_SEC_REQ ble_req; /* BLE SMP related request */
tBTA_DM_BLE_KEY ble_key; /* BLE SMP keys used when pairing */
tBTA_BLE_LOCAL_ID_KEYS ble_id_keys; /* IR event */
- BT_OCTET16 ble_er; /* ER event data */
+ Octet16 ble_er; /* ER event data */
} tBTA_DM_SEC;
/* Security callback */
@@ -1289,9 +1289,10 @@
*
******************************************************************************/
extern void BTA_DmAddDevice(const RawAddress& bd_addr, DEV_CLASS dev_class,
- LINK_KEY link_key, tBTA_SERVICE_MASK trusted_mask,
- bool is_trusted, uint8_t key_type,
- tBTA_IO_CAP io_cap, uint8_t pin_length);
+ const LinkKey& link_key,
+ tBTA_SERVICE_MASK trusted_mask, bool is_trusted,
+ uint8_t key_type, tBTA_IO_CAP io_cap,
+ uint8_t pin_length);
/*******************************************************************************
*
diff --git a/bta/include/bta_dm_ci.h b/bta/include/bta_dm_ci.h
index dbbace6..a89854a 100644
--- a/bta/include/bta_dm_ci.h
+++ b/bta/include/bta_dm_ci.h
@@ -55,7 +55,7 @@
*
******************************************************************************/
extern void bta_dm_ci_rmt_oob(bool accept, const RawAddress& bd_addr,
- BT_OCTET16 c, BT_OCTET16 r);
+ const Octet16& c, const Octet16& r);
/*******************************************************************************
*
* Function bta_dm_sco_ci_data_ready
diff --git a/bta/include/bta_dm_co.h b/bta/include/bta_dm_co.h
index ddb9d22..4561cbf 100644
--- a/bta/include/bta_dm_co.h
+++ b/bta/include/bta_dm_co.h
@@ -105,7 +105,7 @@
* Returns void.
*
******************************************************************************/
-extern void bta_dm_co_loc_oob(bool valid, BT_OCTET16 c, BT_OCTET16 r);
+extern void bta_dm_co_loc_oob(bool valid, const Octet16& c, const Octet16& r);
/*******************************************************************************
*
@@ -207,7 +207,7 @@
*
******************************************************************************/
extern void bta_dm_co_ble_load_local_keys(
- tBTA_DM_BLE_LOCAL_KEY_MASK* p_key_mask, BT_OCTET16 er,
+ tBTA_DM_BLE_LOCAL_KEY_MASK* p_key_mask, Octet16* p_er,
tBTA_BLE_LOCAL_ID_KEYS* p_id_keys);
#endif /* BTA_DM_CO_H */
diff --git a/bta/include/bta_gatt_api.h b/bta/include/bta_gatt_api.h
index 2dfe26d..618cb04 100644
--- a/bta/include/bta_gatt_api.h
+++ b/bta/include/bta_gatt_api.h
@@ -25,6 +25,7 @@
#ifndef BTA_GATT_API_H
#define BTA_GATT_API_H
+#include "bta/gatt/database.h"
#include "bta_api.h"
#include "gatt_api.h"
@@ -97,34 +98,6 @@
uint16_t handles[BTA_GATTC_MULTI_MAX];
} tBTA_GATTC_MULTI;
-/* Representation of GATT attribute for storage */
-struct tBTA_GATTC_NV_ATTR {
- uint16_t handle;
- bluetooth::Uuid type;
-
- union {
- /* primary or secondary service */
- struct {
- bluetooth::Uuid uuid;
- uint16_t e_handle;
- } service;
-
- struct {
- uint16_t s_handle;
- uint16_t e_handle;
- bluetooth::Uuid uuid;
- } included_service;
-
- struct {
- uint8_t properties;
- uint16_t value_handle;
- bluetooth::Uuid uuid;
- } characteristic;
-
- /* for descriptor we don't store value*/
- } value;
-};
-
/* callback data structure */
typedef struct {
tGATT_STATUS status;
@@ -383,41 +356,6 @@
/* Server callback function */
typedef void(tBTA_GATTS_CBACK)(tBTA_GATTS_EVT event, tBTA_GATTS* p_data);
-struct tBTA_GATTC_CHARACTERISTIC;
-struct tBTA_GATTC_DESCRIPTOR;
-struct tBTA_GATTC_INCLUDED_SVC;
-
-struct tBTA_GATTC_SERVICE {
- bluetooth::Uuid uuid;
- bool is_primary;
- uint16_t handle;
- uint16_t s_handle;
- uint16_t e_handle;
- std::vector<tBTA_GATTC_CHARACTERISTIC> characteristics;
- std::vector<tBTA_GATTC_INCLUDED_SVC> included_svc;
-};
-
-struct tBTA_GATTC_CHARACTERISTIC {
- bluetooth::Uuid uuid;
- // this is used only during discovery, and not persisted in cache
- uint16_t declaration_handle;
- uint16_t value_handle;
- tGATT_CHAR_PROP properties;
- std::vector<tBTA_GATTC_DESCRIPTOR> descriptors;
-};
-
-struct tBTA_GATTC_DESCRIPTOR {
- bluetooth::Uuid uuid;
- uint16_t handle;
-};
-
-struct tBTA_GATTC_INCLUDED_SVC {
- bluetooth::Uuid uuid;
- uint16_t handle;
- tBTA_GATTC_SERVICE* owning_service; /* owning service*/
- tBTA_GATTC_SERVICE* included_service;
-};
-
/*****************************************************************************
* External Function Declarations
****************************************************************************/
@@ -538,7 +476,7 @@
* PTS tests.
*/
extern void BTA_GATTC_DiscoverServiceByUuid(uint16_t conn_id,
- const bluetooth::Uuid& p_srvc_uuid);
+ const bluetooth::Uuid& srvc_uuid);
/*******************************************************************************
*
@@ -549,10 +487,10 @@
*
* Parameters conn_id: connection ID which identify the server.
*
- * Returns returns list of tBTA_GATTC_SERVICE or NULL.
+ * Returns returns list of gatt::Service or NULL.
*
******************************************************************************/
-extern const std::vector<tBTA_GATTC_SERVICE>* BTA_GATTC_GetServices(
+extern const std::vector<gatt::Service>* BTA_GATTC_GetServices(
uint16_t conn_id);
/*******************************************************************************
@@ -565,11 +503,11 @@
* Parameters conn_id: connection ID which identify the server.
* handle: characteristic handle
*
- * Returns returns pointer to tBTA_GATTC_CHARACTERISTIC or NULL.
+ * Returns returns pointer to gatt::Characteristic or NULL.
*
******************************************************************************/
-extern const tBTA_GATTC_CHARACTERISTIC* BTA_GATTC_GetCharacteristic(
- uint16_t conn_id, uint16_t handle);
+extern const gatt::Characteristic* BTA_GATTC_GetCharacteristic(uint16_t conn_id,
+ uint16_t handle);
/*******************************************************************************
*
@@ -581,21 +519,21 @@
* Parameters conn_id: connection ID which identify the server.
* handle: descriptor handle
*
- * Returns returns pointer to tBTA_GATTC_DESCRIPTOR or NULL.
+ * Returns returns pointer to gatt::Descriptor or NULL.
*
******************************************************************************/
-extern const tBTA_GATTC_DESCRIPTOR* BTA_GATTC_GetDescriptor(uint16_t conn_id,
- uint16_t handle);
+extern const gatt::Descriptor* BTA_GATTC_GetDescriptor(uint16_t conn_id,
+ uint16_t handle);
/* Return characteristic that owns descriptor with handle equal to |handle|, or
* NULL */
-extern const tBTA_GATTC_CHARACTERISTIC* BTA_GATTC_GetOwningCharacteristic(
+extern const gatt::Characteristic* BTA_GATTC_GetOwningCharacteristic(
uint16_t conn_id, uint16_t handle);
/* Return service that owns descriptor or characteristic with handle equal to
* |handle|, or NULL */
-extern const tBTA_GATTC_SERVICE* BTA_GATTC_GetOwningService(uint16_t conn_id,
- uint16_t handle);
+extern const gatt::Service* BTA_GATTC_GetOwningService(uint16_t conn_id,
+ uint16_t handle);
/*******************************************************************************
*
diff --git a/bta/include/bta_hearing_aid_api.h b/bta/include/bta_hearing_aid_api.h
index 96ad7e6..e0a3bf5 100644
--- a/bta/include/bta_hearing_aid_api.h
+++ b/bta/include/bta_hearing_aid_api.h
@@ -21,14 +21,16 @@
#include <base/callback_forward.h>
#include <hardware/bt_hearing_aid.h>
+constexpr uint16_t HA_INTERVAL_10_MS = 10;
+constexpr uint16_t HA_INTERVAL_20_MS = 20;
/** Implementations of HearingAid will also implement this interface */
class HearingAidAudioReceiver {
public:
virtual ~HearingAidAudioReceiver() = default;
virtual void OnAudioDataReady(const std::vector<uint8_t>& data) = 0;
- virtual void OnAudioSuspend();
- virtual void OnAudioResume();
+ virtual void OnAudioSuspend() = 0;
+ virtual void OnAudioResume() = 0;
};
class HearingAid {
diff --git a/bta/test/gatt/database_builder_sample_device_test.cc b/bta/test/gatt/database_builder_sample_device_test.cc
new file mode 100644
index 0000000..bd4dabc
--- /dev/null
+++ b/bta/test/gatt/database_builder_sample_device_test.cc
@@ -0,0 +1,286 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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 <gtest/gtest.h>
+
+#include <base/logging.h>
+#include <utility>
+
+#include "gatt/database_builder.h"
+
+using bluetooth::Uuid;
+
+namespace gatt {
+
+namespace {
+/* EXPECT_EQ doesn't work well with static constexpr fields, need a variable
+ * with address */
+constexpr std::pair<uint16_t, uint16_t> EXPLORE_END =
+ DatabaseBuilder::EXPLORE_END;
+
+/* make_pair doesn't work well with EXPECT_EQ, have own helper instead */
+inline std::pair<uint16_t, uint16_t> make_pair_u16(uint16_t first,
+ uint16_t second) {
+ return std::make_pair(first, second);
+}
+
+// clang-format off
+Uuid SERVICE_1_UUID = Uuid::FromString("00001800-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_2_UUID = Uuid::FromString("00001801-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_3_UUID = Uuid::FromString("0000180f-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_4_UUID = Uuid::FromString("0000fef5-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_5_UUID = Uuid::FromString("0000180a-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_6_UUID = Uuid::FromString("0000fe55-0000-1000-8000-00805f9b34fb");
+
+Uuid SERVICE_1_CHAR_1_UUID = Uuid::FromString("00002a00-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_1_CHAR_2_UUID = Uuid::FromString("00002a01-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_1_CHAR_3_UUID = Uuid::FromString("00002a04-0000-1000-8000-00805f9b34fb");
+
+Uuid SERVICE_3_CHAR_1_UUID = Uuid::FromString("00002a19-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_3_CHAR_1_DESC_1_UUID = Uuid::FromString("00002902-0000-1000-8000-00805f9b34fb");
+
+Uuid SERVICE_4_CHAR_1_UUID = Uuid::FromString("8082caa8-41a6-4021-91c6-56f9b954cc34");
+Uuid SERVICE_4_CHAR_2_UUID = Uuid::FromString("724249f0-5ec3-4b5f-8804-42345af08651");
+Uuid SERVICE_4_CHAR_3_UUID = Uuid::FromString("6c53db25-47a1-45fe-a022-7c92fb334fd4");
+Uuid SERVICE_4_CHAR_4_UUID = Uuid::FromString("9d84b9a3-000c-49d8-9183-855b673fda31");
+Uuid SERVICE_4_CHAR_5_UUID = Uuid::FromString("457871e8-d516-4ca1-9116-57d0b17b9cb2");
+Uuid SERVICE_4_CHAR_6_UUID = Uuid::FromString("5f78df94-798c-46f5-990a-b3eb6a065c88");
+Uuid SERVICE_4_CHAR_6_DESC_1_UUID = Uuid::FromString("00002902-0000-1000-8000-00805f9b34fb");
+
+Uuid SERVICE_5_CHAR_1_UUID = Uuid::FromString("00002a29-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_5_CHAR_2_UUID = Uuid::FromString("00002a24-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_5_CHAR_3_UUID = Uuid::FromString("00002a25-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_5_CHAR_4_UUID = Uuid::FromString("00002a27-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_5_CHAR_5_UUID = Uuid::FromString("00002a26-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_5_CHAR_6_UUID = Uuid::FromString("00002a28-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_5_CHAR_7_UUID = Uuid::FromString("00002a50-0000-1000-8000-00805f9b34fb");
+
+Uuid SERVICE_6_CHAR_1_UUID = Uuid::FromString("00000001-1000-1000-8000-00805f9b34fb");
+Uuid SERVICE_6_CHAR_1_DESC_1_UUID = Uuid::FromString("00002902-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_6_CHAR_2_UUID = Uuid::FromString("00000002-1000-1000-8000-00805f9b34fb");
+Uuid SERVICE_6_CHAR_3_UUID = Uuid::FromString("00000003-1000-1000-8000-00805f9b34fb");
+// clang-format on
+
+} // namespace
+
+// clang-format off
+/* Content of sample database, comes from Daydream controller:
+Service: handle=0x0001, end_handle=0x0007, uuid=00001800-0000-1000-8000-00805f9b34fb
+ Characteristic: declaration_handle=0x0002, value_handle=0x0003, uuid=00002a00-0000-1000-8000-00805f9b34fb, prop=0x02
+ Characteristic: declaration_handle=0x0004, value_handle=0x0005, uuid=00002a01-0000-1000-8000-00805f9b34fb, prop=0x02
+ Characteristic: declaration_handle=0x0006, value_handle=0x0007, uuid=00002a04-0000-1000-8000-00805f9b34fb, prop=0x02
+Service: handle=0x0008, end_handle=0x0008, uuid=00001801-0000-1000-8000-00805f9b34fb
+Service: handle=0x0009, end_handle=0x000c, uuid=0000180f-0000-1000-8000-00805f9b34fb
+ Characteristic: declaration_handle=0x000a, value_handle=0x000b, uuid=00002a19-0000-1000-8000-00805f9b34fb, prop=0x12
+ Descriptor: handle=0x000c, uuid=00002902-0000-1000-8000-00805f9b34fb
+Service: handle=0x000d, end_handle=0x001a, uuid=0000fef5-0000-1000-8000-00805f9b34fb
+ Characteristic: declaration_handle=0x000e, value_handle=0x000f, uuid=8082caa8-41a6-4021-91c6-56f9b954cc34, prop=0x0a
+ Characteristic: declaration_handle=0x0010, value_handle=0x0011, uuid=724249f0-5ec3-4b5f-8804-42345af08651, prop=0x0a
+ Characteristic: declaration_handle=0x0012, value_handle=0x0013, uuid=6c53db25-47a1-45fe-a022-7c92fb334fd4, prop=0x02
+ Characteristic: declaration_handle=0x0014, value_handle=0x0015, uuid=9d84b9a3-000c-49d8-9183-855b673fda31, prop=0x0a
+ Characteristic: declaration_handle=0x0016, value_handle=0x0017, uuid=457871e8-d516-4ca1-9116-57d0b17b9cb2, prop=0x0e
+ Characteristic: declaration_handle=0x0018, value_handle=0x0019, uuid=5f78df94-798c-46f5-990a-b3eb6a065c88, prop=0x12
+ Descriptor: handle=0x001a, uuid=00002902-0000-1000-8000-00805f9b34fb
+Service: handle=0x001b, end_handle=0x0029, uuid=0000180a-0000-1000-8000-00805f9b34fb
+ Characteristic: declaration_handle=0x001c, value_handle=0x001d, uuid=00002a29-0000-1000-8000-00805f9b34fb, prop=0x02
+ Characteristic: declaration_handle=0x001e, value_handle=0x001f, uuid=00002a24-0000-1000-8000-00805f9b34fb, prop=0x02
+ Characteristic: declaration_handle=0x0020, value_handle=0x0021, uuid=00002a25-0000-1000-8000-00805f9b34fb, prop=0x02
+ Characteristic: declaration_handle=0x0022, value_handle=0x0023, uuid=00002a27-0000-1000-8000-00805f9b34fb, prop=0x02
+ Characteristic: declaration_handle=0x0024, value_handle=0x0025, uuid=00002a26-0000-1000-8000-00805f9b34fb, prop=0x02
+ Characteristic: declaration_handle=0x0026, value_handle=0x0027, uuid=00002a28-0000-1000-8000-00805f9b34fb, prop=0x02
+ Characteristic: declaration_handle=0x0028, value_handle=0x0029, uuid=00002a50-0000-1000-8000-00805f9b34fb, prop=0x02
+Service: handle=0x002a, end_handle=0x0031, uuid=0000fe55-0000-1000-8000-00805f9b34fb
+ Characteristic: declaration_handle=0x002b, value_handle=0x002c, uuid=00000001-1000-1000-8000-00805f9b34fb, prop=0x10
+ Descriptor: handle=0x002d, uuid=00002902-0000-1000-8000-00805f9b34fb
+ Characteristic: declaration_handle=0x002e, value_handle=0x002f, uuid=00000002-1000-1000-8000-00805f9b34fb, prop=0x08
+ Characteristic: declaration_handle=0x0030, value_handle=0x0031, uuid=00000003-1000-1000-8000-00805f9b34fb, prop=0x02
+*/
+// clang-format on
+
+/* This test verifies that DatabaseBuilder will properly discover database
+ * content from a remote device. It also verify that after the discovery is
+ * done, returned database is equal to the discovered one */
+TEST(DatabaseBuilderSampleDeviceTest, DoDiscovery) {
+ DatabaseBuilder builder;
+
+ EXPECT_FALSE(builder.InProgress());
+
+ // At start of discovery, builder will receive All services in order from
+ // lower layers.
+ builder.AddService(0x0001, 0x0007, SERVICE_1_UUID, true);
+
+ // The moment we receive first service, we are in progress
+ // TODO: we should be able to set InProgress state once we sent GATT request,
+ // not when it's back and parsed
+ EXPECT_TRUE(builder.InProgress());
+
+ builder.AddService(0x0008, 0x0008, SERVICE_2_UUID, true);
+ builder.AddService(0x0009, 0x000c, SERVICE_3_UUID, true);
+ builder.AddService(0x000d, 0x001a, SERVICE_4_UUID, true);
+ builder.AddService(0x001b, 0x0029, SERVICE_5_UUID, true);
+ builder.AddService(0x002a, 0x0031, SERVICE_6_UUID, true);
+
+ // At this moment, all services are received, stack will grab them one and one
+ // to discover their content.
+ EXPECT_TRUE(builder.StartNextServiceExploration());
+
+ // Grabbing first service, to start Included Service and Characteristic
+ // discovery
+ EXPECT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x0001, 0x0007));
+
+ builder.AddCharacteristic(0x0002, 0x0003, SERVICE_1_CHAR_1_UUID, 0x02);
+ builder.AddCharacteristic(0x0004, 0x0005, SERVICE_1_CHAR_2_UUID, 0x02);
+ builder.AddCharacteristic(0x0006, 0x0007, SERVICE_1_CHAR_3_UUID, 0x02);
+
+ // All characteristics were discovered, stack will try to look for
+ // descriptors. Since there is no space for descriptors, builder should return
+ // nothing more to discover
+ EXPECT_EQ(builder.NextDescriptorRangeToExplore(), EXPLORE_END);
+
+ // Service with handles 0x0008, 0x0008 is skipped for exploration - we know
+ // it's empty.
+ EXPECT_TRUE(builder.StartNextServiceExploration());
+ EXPECT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x0009, 0x000c));
+
+ builder.AddCharacteristic(0x000a, 0x000b, SERVICE_3_CHAR_1_UUID, 0x12);
+
+ EXPECT_EQ(builder.NextDescriptorRangeToExplore(),
+ make_pair_u16(0x000c, 0x000c));
+
+ builder.AddDescriptor(0x000c, SERVICE_3_CHAR_1_DESC_1_UUID);
+
+ // All descriptors were explored
+ EXPECT_EQ(builder.NextDescriptorRangeToExplore(), EXPLORE_END);
+
+ EXPECT_TRUE(builder.StartNextServiceExploration());
+ EXPECT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x000d, 0x001a));
+
+ builder.AddCharacteristic(0x000e, 0x000f, SERVICE_4_CHAR_1_UUID, 0x0a);
+ builder.AddCharacteristic(0x0010, 0x0011, SERVICE_4_CHAR_2_UUID, 0x0a);
+ builder.AddCharacteristic(0x0012, 0x0013, SERVICE_4_CHAR_3_UUID, 0x02);
+ builder.AddCharacteristic(0x0014, 0x0015, SERVICE_4_CHAR_4_UUID, 0x0a);
+ builder.AddCharacteristic(0x0016, 0x0017, SERVICE_4_CHAR_5_UUID, 0x0e);
+ builder.AddCharacteristic(0x0018, 0x0019, SERVICE_4_CHAR_6_UUID, 0x12);
+
+ // Just last Characteristic have space for descriptor
+ EXPECT_EQ(builder.NextDescriptorRangeToExplore(),
+ make_pair_u16(0x001a, 0x001a));
+
+ builder.AddDescriptor(0x001a, SERVICE_4_CHAR_6_DESC_1_UUID);
+
+ // All descriptors were explored
+ EXPECT_EQ(builder.NextDescriptorRangeToExplore(), EXPLORE_END);
+
+ EXPECT_TRUE(builder.StartNextServiceExploration());
+ EXPECT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x001b, 0x0029));
+
+ builder.AddCharacteristic(0x001c, 0x001d, SERVICE_5_CHAR_1_UUID, 0x02);
+ builder.AddCharacteristic(0x001e, 0x001f, SERVICE_5_CHAR_2_UUID, 0x02);
+ builder.AddCharacteristic(0x0020, 0x0021, SERVICE_5_CHAR_3_UUID, 0x02);
+ builder.AddCharacteristic(0x0022, 0x0023, SERVICE_5_CHAR_4_UUID, 0x02);
+ builder.AddCharacteristic(0x0024, 0x0025, SERVICE_5_CHAR_5_UUID, 0x02);
+ builder.AddCharacteristic(0x0026, 0x0027, SERVICE_5_CHAR_6_UUID, 0x02);
+ builder.AddCharacteristic(0x0028, 0x0029, SERVICE_5_CHAR_7_UUID, 0x02);
+
+ // No space for descriptors
+ EXPECT_EQ(builder.NextDescriptorRangeToExplore(), EXPLORE_END);
+
+ EXPECT_TRUE(builder.StartNextServiceExploration());
+ EXPECT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x002a, 0x0031));
+
+ builder.AddCharacteristic(0x002b, 0x002c, SERVICE_6_CHAR_1_UUID, 0x10);
+ builder.AddCharacteristic(0x002e, 0x002f, SERVICE_6_CHAR_2_UUID, 0x08);
+ builder.AddCharacteristic(0x0030, 0x0031, SERVICE_6_CHAR_3_UUID, 0x02);
+
+ // Just one Characteristic have space for descriptor
+ EXPECT_EQ(builder.NextDescriptorRangeToExplore(),
+ make_pair_u16(0x002d, 0x002d));
+
+ builder.AddDescriptor(0x002d, SERVICE_6_CHAR_1_DESC_1_UUID);
+
+ // All descriptors were explored
+ EXPECT_EQ(builder.NextDescriptorRangeToExplore(), EXPLORE_END);
+
+ EXPECT_FALSE(builder.StartNextServiceExploration());
+
+ EXPECT_TRUE(builder.InProgress());
+ Database result = builder.Build();
+ EXPECT_FALSE(builder.InProgress());
+
+ // verify that the returned database matches what was discovered
+ EXPECT_EQ(result.Services()[0].handle, 0x0001);
+ EXPECT_EQ(result.Services()[0].uuid, SERVICE_1_UUID);
+ EXPECT_EQ(result.Services()[1].uuid, SERVICE_2_UUID);
+ EXPECT_EQ(result.Services()[2].uuid, SERVICE_3_UUID);
+ EXPECT_EQ(result.Services()[3].uuid, SERVICE_4_UUID);
+ EXPECT_EQ(result.Services()[4].uuid, SERVICE_5_UUID);
+ EXPECT_EQ(result.Services()[5].uuid, SERVICE_6_UUID);
+
+ EXPECT_EQ(result.Services()[0].characteristics[0].uuid,
+ SERVICE_1_CHAR_1_UUID);
+ EXPECT_EQ(result.Services()[0].characteristics[1].uuid,
+ SERVICE_1_CHAR_2_UUID);
+ EXPECT_EQ(result.Services()[0].characteristics[2].uuid,
+ SERVICE_1_CHAR_3_UUID);
+
+ EXPECT_EQ(result.Services()[2].characteristics[0].uuid,
+ SERVICE_3_CHAR_1_UUID);
+ EXPECT_EQ(result.Services()[2].characteristics[0].descriptors[0].uuid,
+ SERVICE_3_CHAR_1_DESC_1_UUID);
+
+ EXPECT_EQ(result.Services()[3].characteristics[0].uuid,
+ SERVICE_4_CHAR_1_UUID);
+ EXPECT_EQ(result.Services()[3].characteristics[1].uuid,
+ SERVICE_4_CHAR_2_UUID);
+ EXPECT_EQ(result.Services()[3].characteristics[2].uuid,
+ SERVICE_4_CHAR_3_UUID);
+ EXPECT_EQ(result.Services()[3].characteristics[3].uuid,
+ SERVICE_4_CHAR_4_UUID);
+ EXPECT_EQ(result.Services()[3].characteristics[4].uuid,
+ SERVICE_4_CHAR_5_UUID);
+ EXPECT_EQ(result.Services()[3].characteristics[5].uuid,
+ SERVICE_4_CHAR_6_UUID);
+ EXPECT_EQ(result.Services()[3].characteristics[5].descriptors[0].uuid,
+ SERVICE_4_CHAR_6_DESC_1_UUID);
+
+ EXPECT_EQ(result.Services()[4].characteristics[0].uuid,
+ SERVICE_5_CHAR_1_UUID);
+ EXPECT_EQ(result.Services()[4].characteristics[1].uuid,
+ SERVICE_5_CHAR_2_UUID);
+ EXPECT_EQ(result.Services()[4].characteristics[2].uuid,
+ SERVICE_5_CHAR_3_UUID);
+ EXPECT_EQ(result.Services()[4].characteristics[3].uuid,
+ SERVICE_5_CHAR_4_UUID);
+ EXPECT_EQ(result.Services()[4].characteristics[4].uuid,
+ SERVICE_5_CHAR_5_UUID);
+ EXPECT_EQ(result.Services()[4].characteristics[5].uuid,
+ SERVICE_5_CHAR_6_UUID);
+ EXPECT_EQ(result.Services()[4].characteristics[6].uuid,
+ SERVICE_5_CHAR_7_UUID);
+
+ EXPECT_EQ(result.Services()[5].characteristics[0].uuid,
+ SERVICE_6_CHAR_1_UUID);
+ EXPECT_EQ(result.Services()[5].characteristics[0].descriptors[0].uuid,
+ SERVICE_6_CHAR_1_DESC_1_UUID);
+ EXPECT_EQ(result.Services()[5].characteristics[1].uuid,
+ SERVICE_6_CHAR_2_UUID);
+ EXPECT_EQ(result.Services()[5].characteristics[2].uuid,
+ SERVICE_6_CHAR_3_UUID);
+}
+
+} // namespace gatt
\ No newline at end of file
diff --git a/bta/test/gatt/database_builder_test.cc b/bta/test/gatt/database_builder_test.cc
new file mode 100644
index 0000000..fcafb49
--- /dev/null
+++ b/bta/test/gatt/database_builder_test.cc
@@ -0,0 +1,165 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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 <gtest/gtest.h>
+
+#include <base/logging.h>
+#include <utility>
+
+#include "gatt/database_builder.h"
+
+using bluetooth::Uuid;
+
+namespace gatt {
+
+namespace {
+/* make_pair doesn't work well with EXPECT_EQ, have own helper instead */
+inline std::pair<uint16_t, uint16_t> make_pair_u16(uint16_t first,
+ uint16_t second) {
+ return std::make_pair(first, second);
+}
+
+Uuid SERVICE_1_UUID = Uuid::FromString("00001800-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_2_UUID = Uuid::FromString("00001801-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_3_UUID = Uuid::FromString("0000180f-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_4_UUID = Uuid::FromString("0000fef5-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_5_UUID = Uuid::FromString("0000180a-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_1_CHAR_1_UUID =
+ Uuid::FromString("00002a00-0000-1000-8000-00805f9b34fb");
+Uuid SERVICE_1_CHAR_1_DESC_1_UUID =
+ Uuid::FromString("00002902-0000-1000-8000-00805f9b34fb");
+
+} // namespace
+
+/* Verify adding empty service works ok */
+TEST(DatabaseBuilderTest, EmptyServiceAddTest) {
+ DatabaseBuilder builder;
+
+ EXPECT_FALSE(builder.InProgress());
+
+ // Simple database, just one empty
+ builder.AddService(0x0001, 0x0001, SERVICE_1_UUID, true);
+ EXPECT_FALSE(builder.StartNextServiceExploration());
+
+ Database result = builder.Build();
+
+ // verify that the returned database matches what was discovered
+ EXPECT_EQ(result.Services()[0].handle, 0x0001);
+ EXPECT_EQ(result.Services()[0].end_handle, 0x0001);
+ EXPECT_EQ(result.Services()[0].is_primary, true);
+ EXPECT_EQ(result.Services()[0].uuid, SERVICE_1_UUID);
+}
+
+/* Verify adding service, characteristic and descriptor work */
+TEST(DatabaseBuilderTest, DescriptorAddTest) {
+ DatabaseBuilder builder;
+
+ EXPECT_FALSE(builder.InProgress());
+
+ // Simple database, just one empty
+ builder.AddService(0x0001, 0x000f, SERVICE_1_UUID, true);
+ builder.AddCharacteristic(0x0002, 0x0003, SERVICE_1_CHAR_1_UUID, 0x02);
+ builder.AddDescriptor(0x0004, SERVICE_1_CHAR_1_DESC_1_UUID);
+
+ Database result = builder.Build();
+
+ // verify that the returned database matches what was discovered
+ EXPECT_EQ(result.Services()[0].handle, 0x0001);
+ EXPECT_EQ(result.Services()[0].end_handle, 0x000f);
+ EXPECT_EQ(result.Services()[0].is_primary, true);
+ EXPECT_EQ(result.Services()[0].uuid, SERVICE_1_UUID);
+
+ EXPECT_EQ(result.Services()[0].characteristics[0].uuid,
+ SERVICE_1_CHAR_1_UUID);
+ EXPECT_EQ(result.Services()[0].characteristics[0].declaration_handle, 0x0002);
+ EXPECT_EQ(result.Services()[0].characteristics[0].value_handle, 0x0003);
+ EXPECT_EQ(result.Services()[0].characteristics[0].properties, 0x02);
+
+ EXPECT_EQ(result.Services()[0].characteristics[0].descriptors[0].uuid,
+ SERVICE_1_CHAR_1_DESC_1_UUID);
+ EXPECT_EQ(result.Services()[0].characteristics[0].descriptors[0].handle,
+ 0x0004);
+}
+
+/* This test verifies that DatabaseBuilder properly handle discovery of
+ * secondary service, that is added to the discovery queue from included service
+ * definition. Such service might come out of order. */
+TEST(DatabaseBuilderTest, SecondaryServiceOutOfOrderTest) {
+ DatabaseBuilder builder;
+
+ EXPECT_FALSE(builder.InProgress());
+
+ // At start of discovery, builder will receive All services in order from
+ // lower layers.
+ builder.AddService(0x0001, 0x000f, SERVICE_1_UUID, true);
+ builder.AddService(0x0030, 0x003f, SERVICE_3_UUID, true);
+ builder.AddService(0x0050, 0x005f, SERVICE_5_UUID, true);
+
+ // First service skipped, no place for handles
+ EXPECT_TRUE(builder.StartNextServiceExploration());
+ EXPECT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x0001, 0x000f));
+
+ // For this test, content of first service is irrevelant
+
+ EXPECT_TRUE(builder.StartNextServiceExploration());
+ // Grabbing first service, to start Included Service and Characteristic
+ // discovery
+ EXPECT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x0030, 0x003f));
+
+ builder.AddIncludedService(0x0031, SERVICE_4_UUID, 0x0040, 0x004f);
+ builder.AddIncludedService(0x0032, SERVICE_2_UUID, 0x0020, 0x002f);
+
+ /* Secondary service exploration */
+ EXPECT_TRUE(builder.StartNextServiceExploration());
+ EXPECT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x0020, 0x002f));
+
+ /* Secondary service exploration */
+ EXPECT_TRUE(builder.StartNextServiceExploration());
+ EXPECT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x0040, 0x004f));
+
+ /* Back to primary service exploration */
+ EXPECT_TRUE(builder.StartNextServiceExploration());
+ EXPECT_EQ(builder.CurrentlyExploredService(), make_pair_u16(0x0050, 0x005f));
+
+ Database result = builder.Build();
+
+ // verify that the returned database matches what was discovered
+ EXPECT_EQ(result.Services()[0].handle, 0x0001);
+ EXPECT_EQ(result.Services()[0].is_primary, true);
+ EXPECT_EQ(result.Services()[0].uuid, SERVICE_1_UUID);
+
+ EXPECT_EQ(result.Services()[1].handle, 0x0020);
+ EXPECT_EQ(result.Services()[1].end_handle, 0x002f);
+ EXPECT_EQ(result.Services()[1].uuid, SERVICE_2_UUID);
+ EXPECT_EQ(result.Services()[1].is_primary, false);
+
+ EXPECT_EQ(result.Services()[2].handle, 0x0030);
+ EXPECT_EQ(result.Services()[2].end_handle, 0x003f);
+ EXPECT_EQ(result.Services()[2].uuid, SERVICE_3_UUID);
+ EXPECT_EQ(result.Services()[2].is_primary, true);
+
+ EXPECT_EQ(result.Services()[3].handle, 0x0040);
+ EXPECT_EQ(result.Services()[3].uuid, SERVICE_4_UUID);
+ EXPECT_EQ(result.Services()[3].is_primary, false);
+
+ EXPECT_EQ(result.Services()[4].handle, 0x0050);
+ EXPECT_EQ(result.Services()[4].uuid, SERVICE_5_UUID);
+ EXPECT_EQ(result.Services()[4].is_primary, true);
+}
+
+} // namespace gatt
\ No newline at end of file
diff --git a/bta/test/gatt/database_test.cc b/bta/test/gatt/database_test.cc
new file mode 100644
index 0000000..78250ec
--- /dev/null
+++ b/bta/test/gatt/database_test.cc
@@ -0,0 +1,207 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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 <gtest/gtest.h>
+
+#include <base/logging.h>
+#include <base/strings/string_number_conversions.h>
+#include "gatt/database.h"
+#include "gatt/database_builder.h"
+#include "stack/include/gattdefs.h"
+
+using bluetooth::Uuid;
+
+namespace gatt {
+
+namespace {
+const Uuid PRIMARY_SERVICE = Uuid::From16Bit(GATT_UUID_PRI_SERVICE);
+const Uuid SECONDARY_SERVICE = Uuid::From16Bit(GATT_UUID_SEC_SERVICE);
+const Uuid INCLUDE = Uuid::From16Bit(GATT_UUID_INCLUDE_SERVICE);
+const Uuid CHARACTERISTIC = Uuid::From16Bit(GATT_UUID_CHAR_DECLARE);
+
+Uuid SERVICE_1_UUID = Uuid::FromString("1800");
+Uuid SERVICE_2_UUID = Uuid::FromString("1801");
+Uuid SERVICE_1_CHAR_1_UUID = Uuid::FromString("2a00");
+Uuid SERVICE_1_CHAR_1_DESC_1_UUID = Uuid::FromString("2902");
+} // namespace
+
+/* This test makes sure that each possible GATT cache element is properly
+ * serialized into StoredAttribute */
+TEST(GattDatabaseTest, serialize_deserialize_binary_test) {
+ DatabaseBuilder builder;
+ builder.AddService(0x0001, 0x000f, SERVICE_1_UUID, true);
+ builder.AddService(0x0010, 0x001f, SERVICE_2_UUID, false);
+ builder.AddIncludedService(0x0002, SERVICE_2_UUID, 0x0010, 0x001f);
+ builder.AddCharacteristic(0x0003, 0x0004, SERVICE_1_CHAR_1_UUID, 0x02);
+ builder.AddDescriptor(0x0005, SERVICE_1_CHAR_1_DESC_1_UUID);
+
+ Database db = builder.Build();
+ std::vector<StoredAttribute> serialized = db.Serialize();
+
+ // Primary Service
+ EXPECT_EQ(serialized[0].handle, 0x0001);
+ EXPECT_EQ(serialized[0].type, PRIMARY_SERVICE);
+ EXPECT_EQ(serialized[0].value.service.uuid, SERVICE_1_UUID);
+ EXPECT_EQ(serialized[0].value.service.end_handle, 0x000f);
+
+ // Secondary Service
+ EXPECT_EQ(serialized[1].handle, 0x0010);
+ EXPECT_EQ(serialized[1].type, SECONDARY_SERVICE);
+ EXPECT_EQ(serialized[1].value.service.uuid, SERVICE_2_UUID);
+ EXPECT_EQ(serialized[1].value.service.end_handle, 0x001f);
+
+ // Included Service
+ EXPECT_EQ(serialized[2].handle, 0x0002);
+ EXPECT_EQ(serialized[2].type, INCLUDE);
+ EXPECT_EQ(serialized[2].value.included_service.handle, 0x0010);
+ EXPECT_EQ(serialized[2].value.included_service.end_handle, 0x001f);
+ EXPECT_EQ(serialized[2].value.included_service.uuid, SERVICE_2_UUID);
+
+ // Characteristic
+ EXPECT_EQ(serialized[3].handle, 0x0003);
+ EXPECT_EQ(serialized[3].type, CHARACTERISTIC);
+ EXPECT_EQ(serialized[3].value.characteristic.properties, 0x02);
+ EXPECT_EQ(serialized[3].value.characteristic.value_handle, 0x0004);
+ EXPECT_EQ(serialized[3].value.characteristic.uuid, SERVICE_1_CHAR_1_UUID);
+
+ // Descriptor
+ EXPECT_EQ(serialized[4].handle, 0x0005);
+ EXPECT_EQ(serialized[4].type, SERVICE_1_CHAR_1_DESC_1_UUID);
+}
+
+/* This test makes sure that Service represented in StoredAttribute have proper
+ * binary format. */
+TEST(GattCacheTest, stored_attribute_to_binary_service_test) {
+ StoredAttribute attr;
+
+ /* make sure padding at end of union is cleared */
+ memset(&attr, 0, sizeof(attr));
+
+ attr = {
+ .handle = 0x0001,
+ .type = PRIMARY_SERVICE,
+ .value = {.service = {.uuid = Uuid::FromString("1800"),
+ .end_handle = 0x001c}},
+ };
+
+ constexpr size_t len = sizeof(StoredAttribute);
+ // clang-format off
+ uint8_t binary_form[len] = {
+ /*handle */ 0x01, 0x00,
+ /* type*/ 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB,
+ /* service uuid */ 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB,
+ /* end handle */ 0x1C, 0x00,
+ /* cleared padding at end of union*/ 0x00, 0x00};
+ // clang-format on
+
+ // useful for debugging:
+ // LOG(ERROR) << " " << base::HexEncode(&attr, len);
+ EXPECT_EQ(memcmp(binary_form, &attr, len), 0);
+}
+
+/* This test makes sure that Service represented in StoredAttribute have proper
+ * binary format. */
+TEST(GattCacheTest, stored_attribute_to_binary_included_service_test) {
+ StoredAttribute attr;
+
+ /* make sure padding at end of union is cleared */
+ memset(&attr, 0, sizeof(attr));
+
+ attr = {
+ .handle = 0x0001,
+ .type = INCLUDE,
+ .value = {.included_service =
+ {
+ .handle = 0x0010,
+ .end_handle = 0x001f,
+ .uuid = Uuid::FromString("1801"),
+ }},
+ };
+
+ constexpr size_t len = sizeof(StoredAttribute);
+ // clang-format off
+ uint8_t binary_form[len] = {
+ /*handle */ 0x01, 0x00,
+ /* type*/ 0x00, 0x00, 0x28, 0x02, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB,
+ /* handle */ 0x10, 0x00,
+ /* end handle */ 0x1f, 0x00,
+ /* service uuid */ 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
+ // clang-format on
+
+ // useful for debugging:
+ // LOG(ERROR) << " " << base::HexEncode(&attr, len);
+ EXPECT_EQ(memcmp(binary_form, &attr, len), 0);
+}
+
+/* This test makes sure that Characteristic represented in StoredAttribute have
+ * proper binary format. */
+TEST(GattCacheTest, stored_attribute_to_binary_characteristic_test) {
+ StoredAttribute attr;
+
+ /* make sure padding at end of union is cleared */
+ memset(&attr, 0, sizeof(attr));
+
+ attr = {
+ .handle = 0x0002,
+ .type = CHARACTERISTIC,
+ .value = {.characteristic = {.properties = 0x02,
+ .value_handle = 0x0003,
+ .uuid = Uuid::FromString("2a00")}},
+ };
+
+ constexpr size_t len = sizeof(StoredAttribute);
+ // clang-format off
+ uint8_t binary_form[len] = {
+ /*handle */ 0x02, 0x00,
+ /* type */ 0x00, 0x00, 0x28, 0x03, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB,
+ /* properties */ 0x02,
+ /* after properties there is one byte padding. This might cause troube
+ on other platforms, investigate if it's ever a problem */ 0x00,
+ /* value handle */ 0x03, 0x00,
+ /* uuid */ 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
+ // clang-format on
+
+ // useful for debugging:
+ // LOG(ERROR) << " " << base::HexEncode(&attr, len);
+ EXPECT_EQ(memcmp(binary_form, &attr, len), 0);
+}
+
+/* This test makes sure that Descriptor represented in StoredAttribute have
+ * proper binary format. */
+TEST(GattCacheTest, stored_attribute_to_binary_descriptor_test) {
+ StoredAttribute attr;
+
+ /* make sure padding at end of union is cleared */
+ memset(&attr, 0, sizeof(attr));
+
+ attr = {.handle = 0x0003, .type = Uuid::FromString("2902"), .value = {}};
+
+ constexpr size_t len = sizeof(StoredAttribute);
+ // clang-format off
+ uint8_t binary_form[len] = {
+ /*handle */ 0x03, 0x00,
+ /* type */ 0x00, 0x00, 0x29, 0x02, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB,
+ /* clear padding */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ // clang-format on
+
+ // useful for debugging:
+ // LOG(ERROR) << " " << base::HexEncode(&attr, len);
+ EXPECT_EQ(memcmp(binary_form, &attr, len), 0);
+}
+} // namespace gatt
\ No newline at end of file
diff --git a/bta/test/gatt_cache_file_test.cc b/bta/test/gatt_cache_file_test.cc
deleted file mode 100644
index 66d1caa..0000000
--- a/bta/test/gatt_cache_file_test.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2018 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 <gtest/gtest.h>
-
-#include <base/logging.h>
-#include <base/strings/string_number_conversions.h>
-#include "bta/include/bta_gatt_api.h"
-
-using bluetooth::Uuid;
-
-/* This test makes sure that cache element is properly encoded into file*/
-TEST(GattCacheTest, nv_attr_service_to_binary_test) {
- tBTA_GATTC_NV_ATTR attr;
-
- /* make sure padding at end of union is cleared */
- memset(&attr, 0, sizeof(attr));
-
- attr = {
- .handle = 0x0001,
- .type = Uuid::FromString("2800"),
- .value = {.service = {.uuid = Uuid::FromString("1800"),
- .e_handle = 0x001c}},
- };
-
- constexpr size_t len = sizeof(tBTA_GATTC_NV_ATTR);
- // clang-format off
- uint8_t binary_form[len] = {
- /*handle */ 0x01, 0x00,
- /* type*/ 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB,
- /* service uuid */ 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB,
- /* end handle */ 0x1C, 0x00,
- /* cleared padding at end of union*/ 0x00, 0x00};
- // clang-format on
-
- // useful for debugging:
- // LOG(ERROR) << " " << base::HexEncode(&attr, len);
- EXPECT_EQ(memcmp(binary_form, &attr, len), 0);
-}
diff --git a/btif/Android.bp b/btif/Android.bp
index f9177a7..4b2dc30 100644
--- a/btif/Android.bp
+++ b/btif/Android.bp
@@ -121,6 +121,7 @@
header_libs: ["libbluetooth_headers"],
shared_libs: [
"libaudioclient",
+ "android.hardware.bluetooth.a2dp@1.0",
"libhidlbase",
"liblog",
"libprotobuf-cpp-lite",
@@ -132,7 +133,9 @@
"libbtcore",
"libbt-stack",
"libbt-sbc-encoder",
+ "libbt-utils",
"libFraunhoferAAC",
+ "libg722codec",
"libbtdevice",
"libbt-hci",
"libudrv-uipc",
diff --git a/btif/BUILD.gn b/btif/BUILD.gn
index c5f820a..56a8d33 100644
--- a/btif/BUILD.gn
+++ b/btif/BUILD.gn
@@ -17,7 +17,9 @@
static_library("btif") {
sources = [
"//audio_a2dp_hw/src/audio_a2dp_hw_utils.cc",
+ "//audio_hearing_aid_hw/src/audio_hearing_aid_hw_utils.cc",
"src/btif_a2dp.cc",
+ "src/btif_a2dp_audio_interface_linux.cc",
"src/btif_a2dp_control.cc",
"src/btif_a2dp_sink.cc",
"src/btif_a2dp_source.cc",
@@ -78,7 +80,9 @@
include_dirs = [
"include",
"//",
+ "//linux_include",
"//audio_a2dp_hw/include",
+ "//audio_hearing_aid_hw/include",
"//bta/include",
"//bta/sys",
"//btcore/include",
diff --git a/btif/avrcp/avrcp_service.cc b/btif/avrcp/avrcp_service.cc
index 16b5fab..186866b 100644
--- a/btif/avrcp/avrcp_service.cc
+++ b/btif/avrcp/avrcp_service.cc
@@ -18,6 +18,9 @@
#include <base/bind.h>
#include <base/logging.h>
+#include <base/task/cancelable_task_tracker.h>
+#include <base/threading/thread.h>
+#include <mutex>
#include <sstream>
#include "bta_closure_api.h"
@@ -31,6 +34,22 @@
AvrcpService* AvrcpService::instance_ = nullptr;
AvrcpService::ServiceInterfaceImpl* AvrcpService::service_interface_ = nullptr;
+std::mutex jni_mutex_;
+base::MessageLoop* jni_message_loop_ = nullptr;
+base::CancelableTaskTracker task_tracker_;
+
+void do_in_avrcp_jni(const base::Closure& task) {
+ std::lock_guard<std::mutex> lock(jni_mutex_);
+
+ if (jni_message_loop_ == nullptr) {
+ LOG(WARNING) << __func__ << ": jni_message_loop_ is null";
+ return;
+ }
+
+ task_tracker_.PostTask(jni_message_loop_->task_runner().get(), FROM_HERE,
+ task);
+}
+
class A2dpInterfaceImpl : public A2dpInterface {
RawAddress active_peer() override { return btif_av_source_active_peer(); }
} a2dp_interface_;
@@ -116,8 +135,8 @@
MediaInterfaceWrapper(MediaInterface* cb) : wrapped_(cb){};
void SendKeyEvent(uint8_t key, KeyState state) override {
- do_in_jni_thread(base::Bind(&MediaInterface::SendKeyEvent,
- base::Unretained(wrapped_), key, state));
+ do_in_avrcp_jni(base::Bind(&MediaInterface::SendKeyEvent,
+ base::Unretained(wrapped_), key, state));
}
void GetSongInfo(SongInfoCallback info_cb) override {
@@ -127,8 +146,8 @@
auto bound_cb = base::Bind(cb_lambda, info_cb);
- do_in_jni_thread(base::Bind(&MediaInterface::GetSongInfo,
- base::Unretained(wrapped_), bound_cb));
+ do_in_avrcp_jni(base::Bind(&MediaInterface::GetSongInfo,
+ base::Unretained(wrapped_), bound_cb));
}
void GetPlayStatus(PlayStatusCallback status_cb) override {
@@ -138,8 +157,8 @@
auto bound_cb = base::Bind(cb_lambda, status_cb);
- do_in_jni_thread(base::Bind(&MediaInterface::GetPlayStatus,
- base::Unretained(wrapped_), bound_cb));
+ do_in_avrcp_jni(base::Bind(&MediaInterface::GetPlayStatus,
+ base::Unretained(wrapped_), bound_cb));
}
void GetNowPlayingList(NowPlayingCallback now_playing_cb) override {
@@ -151,8 +170,8 @@
auto bound_cb = base::Bind(cb_lambda, now_playing_cb);
- do_in_jni_thread(base::Bind(&MediaInterface::GetNowPlayingList,
- base::Unretained(wrapped_), bound_cb));
+ do_in_avrcp_jni(base::Bind(&MediaInterface::GetNowPlayingList,
+ base::Unretained(wrapped_), bound_cb));
}
void GetMediaPlayerList(MediaListCallback list_cb) override {
@@ -164,8 +183,8 @@
auto bound_cb = base::Bind(cb_lambda, list_cb);
- do_in_jni_thread(base::Bind(&MediaInterface::GetMediaPlayerList,
- base::Unretained(wrapped_), bound_cb));
+ do_in_avrcp_jni(base::Bind(&MediaInterface::GetMediaPlayerList,
+ base::Unretained(wrapped_), bound_cb));
}
void GetFolderItems(uint16_t player_id, std::string media_id,
@@ -177,9 +196,9 @@
auto bound_cb = base::Bind(cb_lambda, folder_cb);
- do_in_jni_thread(base::Bind(&MediaInterface::GetFolderItems,
- base::Unretained(wrapped_), player_id, media_id,
- bound_cb));
+ do_in_avrcp_jni(base::Bind(&MediaInterface::GetFolderItems,
+ base::Unretained(wrapped_), player_id, media_id,
+ bound_cb));
}
void SetBrowsedPlayer(uint16_t player_id,
@@ -191,21 +210,21 @@
auto bound_cb = base::Bind(cb_lambda, browse_cb);
- do_in_jni_thread(base::Bind(&MediaInterface::SetBrowsedPlayer,
- base::Unretained(wrapped_), player_id,
- bound_cb));
+ do_in_avrcp_jni(base::Bind(&MediaInterface::SetBrowsedPlayer,
+ base::Unretained(wrapped_), player_id,
+ bound_cb));
}
void PlayItem(uint16_t player_id, bool now_playing,
std::string media_id) override {
- do_in_jni_thread(base::Bind(&MediaInterface::PlayItem,
- base::Unretained(wrapped_), player_id,
- now_playing, media_id));
+ do_in_avrcp_jni(base::Bind(&MediaInterface::PlayItem,
+ base::Unretained(wrapped_), player_id,
+ now_playing, media_id));
}
void SetActiveDevice(const RawAddress& address) override {
- do_in_jni_thread(base::Bind(&MediaInterface::SetActiveDevice,
- base::Unretained(wrapped_), address));
+ do_in_avrcp_jni(base::Bind(&MediaInterface::SetActiveDevice,
+ base::Unretained(wrapped_), address));
}
void RegisterUpdateCallback(MediaCallbacks* callback) override {
@@ -227,7 +246,7 @@
VolumeInterfaceWrapper(VolumeInterface* interface) : wrapped_(interface){};
void DeviceConnected(const RawAddress& bdaddr) override {
- do_in_jni_thread(
+ do_in_avrcp_jni(
base::Bind(static_cast<void (VolumeInterface::*)(const RawAddress&)>(
&VolumeInterface::DeviceConnected),
base::Unretained(wrapped_), bdaddr));
@@ -240,20 +259,20 @@
auto bound_cb = base::Bind(cb_lambda, cb);
- do_in_jni_thread(base::Bind(static_cast<void (VolumeInterface::*)(
- const RawAddress&, VolumeChangedCb)>(
- &VolumeInterface::DeviceConnected),
- base::Unretained(wrapped_), bdaddr, bound_cb));
+ do_in_avrcp_jni(base::Bind(static_cast<void (VolumeInterface::*)(
+ const RawAddress&, VolumeChangedCb)>(
+ &VolumeInterface::DeviceConnected),
+ base::Unretained(wrapped_), bdaddr, bound_cb));
}
void DeviceDisconnected(const RawAddress& bdaddr) override {
- do_in_jni_thread(base::Bind(&VolumeInterface::DeviceDisconnected,
- base::Unretained(wrapped_), bdaddr));
+ do_in_avrcp_jni(base::Bind(&VolumeInterface::DeviceDisconnected,
+ base::Unretained(wrapped_), bdaddr));
}
void SetVolume(int8_t volume) override {
- do_in_jni_thread(base::Bind(&VolumeInterface::SetVolume,
- base::Unretained(wrapped_), volume));
+ do_in_avrcp_jni(base::Bind(&VolumeInterface::SetVolume,
+ base::Unretained(wrapped_), volume));
}
private:
@@ -263,14 +282,11 @@
void AvrcpService::Init(MediaInterface* media_interface,
VolumeInterface* volume_interface) {
LOG(INFO) << "AVRCP Target Service started";
- if (instance_ == nullptr) {
- instance_ = new AvrcpService();
- }
// TODO (apanicke): Add a function that sets up the SDP records once we
// remove the AVRCP SDP setup in AVDTP (bta_av_main.cc)
- instance_->media_interface_ = new MediaInterfaceWrapper(media_interface);
+ media_interface_ = new MediaInterfaceWrapper(media_interface);
media_interface->RegisterUpdateCallback(instance_);
VolumeInterfaceWrapper* wrapped_volume_interface = nullptr;
@@ -278,23 +294,23 @@
wrapped_volume_interface = new VolumeInterfaceWrapper(volume_interface);
}
- instance_->volume_interface_ = wrapped_volume_interface;
+ volume_interface_ = wrapped_volume_interface;
ConnectionHandler::Initialize(
base::Bind(&AvrcpService::DeviceCallback, base::Unretained(instance_)),
&avrcp_interface_, &sdp_interface_, wrapped_volume_interface);
- instance_->connection_handler_ = ConnectionHandler::Get();
+ connection_handler_ = ConnectionHandler::Get();
}
void AvrcpService::Cleanup() {
LOG(INFO) << "AVRCP Target Service stopped";
- instance_->connection_handler_->CleanUp();
- instance_->connection_handler_ = nullptr;
- if (instance_->volume_interface_ != nullptr) {
- delete instance_->volume_interface_;
+ connection_handler_->CleanUp();
+ connection_handler_ = nullptr;
+ if (volume_interface_ != nullptr) {
+ delete volume_interface_;
}
- delete instance_->media_interface_;
+ delete media_interface_;
}
AvrcpService* AvrcpService::Get() {
@@ -310,15 +326,15 @@
return service_interface_;
}
-bool AvrcpService::ConnectDevice(const RawAddress& bdaddr) {
+void AvrcpService::ConnectDevice(const RawAddress& bdaddr) {
LOG(INFO) << __PRETTY_FUNCTION__ << ": address=" << bdaddr.ToString();
- return connection_handler_->ConnectDevice(bdaddr);
+ connection_handler_->ConnectDevice(bdaddr);
}
-bool AvrcpService::DisconnectDevice(const RawAddress& bdaddr) {
+void AvrcpService::DisconnectDevice(const RawAddress& bdaddr) {
LOG(INFO) << __PRETTY_FUNCTION__ << ": address=" << bdaddr.ToString();
- return connection_handler_->DisconnectDevice(bdaddr);
+ connection_handler_->DisconnectDevice(bdaddr);
}
void AvrcpService::SendMediaUpdate(bool track_changed, bool play_state,
@@ -369,37 +385,62 @@
// Service Interface
void AvrcpService::ServiceInterfaceImpl::Init(
- MediaInterface* mediaInterface, VolumeInterface* volume_interface) {
- // TODO (apanicke): Run this in a message loop. This currently works though
- // since the underlying AVRC_API will correctly run this in a message loop so
- // no race conditions can occur, but if that changes it could change the
- // behaviour here.
- CHECK(instance_ == nullptr);
+ MediaInterface* media_interface, VolumeInterface* volume_interface) {
+ std::lock_guard<std::mutex> lock(service_interface_lock_);
- AvrcpService::Init(mediaInterface, volume_interface);
+ // TODO: This function should block until the service is completely up so
+ // that its possible to call Get() on the service immediately after calling
+ // init without issues.
+
+ CHECK(instance_ == nullptr);
+ instance_ = new AvrcpService();
+
+ {
+ std::lock_guard<std::mutex> jni_lock(jni_mutex_);
+ jni_message_loop_ = get_jni_message_loop();
+ }
+
+ do_in_bta_thread(FROM_HERE,
+ base::Bind(&AvrcpService::Init, base::Unretained(instance_),
+ media_interface, volume_interface));
}
bool AvrcpService::ServiceInterfaceImpl::ConnectDevice(
const RawAddress& bdaddr) {
- // TODO (apanicke): Same as above
+ std::lock_guard<std::mutex> lock(service_interface_lock_);
CHECK(instance_ != nullptr);
- return instance_->ConnectDevice(bdaddr);
+ do_in_bta_thread(FROM_HERE, base::Bind(&AvrcpService::ConnectDevice,
+ base::Unretained(instance_), bdaddr));
+ return true;
}
bool AvrcpService::ServiceInterfaceImpl::DisconnectDevice(
const RawAddress& bdaddr) {
- // TODO (apanicke): Same as above
+ std::lock_guard<std::mutex> lock(service_interface_lock_);
CHECK(instance_ != nullptr);
- return instance_->DisconnectDevice(bdaddr);
+ do_in_bta_thread(FROM_HERE, base::Bind(&AvrcpService::DisconnectDevice,
+ base::Unretained(instance_), bdaddr));
+ return true;
}
bool AvrcpService::ServiceInterfaceImpl::Cleanup() {
- // TODO (apanicke): Same as above
+ std::lock_guard<std::mutex> lock(service_interface_lock_);
+
if (instance_ == nullptr) return false;
- instance_->Cleanup();
- delete instance_;
+ {
+ std::lock_guard<std::mutex> jni_lock(jni_mutex_);
+ task_tracker_.TryCancelAll();
+ jni_message_loop_ = nullptr;
+ }
+
+ do_in_bta_thread(FROM_HERE,
+ base::Bind(&AvrcpService::Cleanup, base::Owned(instance_)));
+
+ // Setting instance to nullptr here is fine since it will be deleted on the
+ // other thread.
instance_ = nullptr;
+
return true;
}
diff --git a/btif/avrcp/avrcp_service.h b/btif/avrcp/avrcp_service.h
index 5f8fa2d..e19899d 100644
--- a/btif/avrcp/avrcp_service.h
+++ b/btif/avrcp/avrcp_service.h
@@ -37,9 +37,6 @@
*/
class AvrcpService : public MediaCallbacks {
public:
- static void Init(MediaInterface* media_interface,
- VolumeInterface* volume_interface);
-
/**
* Gets a handle to the AvrcpService
*
@@ -56,10 +53,11 @@
*/
static ServiceInterface* GetServiceInterface();
+ void Init(MediaInterface* media_interface, VolumeInterface* volume_interface);
void Cleanup();
- bool ConnectDevice(const RawAddress& bdaddr);
- bool DisconnectDevice(const RawAddress& bdaddr);
+ void ConnectDevice(const RawAddress& bdaddr);
+ void DisconnectDevice(const RawAddress& bdaddr);
// Functions inherited from MediaCallbacks in order to receive updates
void SendMediaUpdate(bool track_changed, bool play_state,
@@ -75,6 +73,9 @@
bool ConnectDevice(const RawAddress& bdaddr) override;
bool DisconnectDevice(const RawAddress& bdaddr) override;
bool Cleanup() override;
+
+ private:
+ std::mutex service_interface_lock_;
};
static void DebugDump(int fd);
diff --git a/btif/co/bta_dm_co.cc b/btif/co/bta_dm_co.cc
index ab69bfb..200ce55 100644
--- a/btif/co/bta_dm_co.cc
+++ b/btif/co/bta_dm_co.cc
@@ -137,7 +137,7 @@
* Returns void.
*
******************************************************************************/
-void bta_dm_co_loc_oob(bool valid, BT_OCTET16 c, BT_OCTET16 r) {
+void bta_dm_co_loc_oob(bool valid, const Octet16& c, const Octet16& r) {
BTIF_TRACE_DEBUG("bta_dm_co_loc_oob, valid = %d", valid);
#ifdef BTIF_DM_OOB_TEST
btif_dm_proc_loc_oob(valid, c, r);
@@ -158,16 +158,16 @@
*
******************************************************************************/
void bta_dm_co_rmt_oob(const RawAddress& bd_addr) {
- BT_OCTET16 p_c;
- BT_OCTET16 p_r;
+ Octet16 c;
+ Octet16 r;
bool result = false;
#ifdef BTIF_DM_OOB_TEST
- result = btif_dm_proc_rmt_oob(bd_addr, p_c, p_r);
+ result = btif_dm_proc_rmt_oob(bd_addr, &c, &r);
#endif
BTIF_TRACE_DEBUG("bta_dm_co_rmt_oob: result=%d", result);
- bta_dm_ci_rmt_oob(result, bd_addr, p_c, p_r);
+ bta_dm_ci_rmt_oob(result, bd_addr, c, r);
}
/*******************************************************************************
@@ -212,13 +212,13 @@
*
******************************************************************************/
void bta_dm_co_ble_load_local_keys(tBTA_DM_BLE_LOCAL_KEY_MASK* p_key_mask,
- BT_OCTET16 er,
+ Octet16* p_er,
tBTA_BLE_LOCAL_ID_KEYS* p_id_keys) {
BTIF_TRACE_DEBUG("##################################");
BTIF_TRACE_DEBUG(
"bta_dm_co_ble_load_local_keys: Load local keys if any are persisted");
BTIF_TRACE_DEBUG("##################################");
- btif_dm_get_ble_local_keys(p_key_mask, er, p_id_keys);
+ btif_dm_get_ble_local_keys(p_key_mask, p_er, p_id_keys);
}
/*******************************************************************************
diff --git a/btif/include/btif_av.h b/btif/include/btif_av.h
index 53e1ed0..486c2af 100644
--- a/btif/include/btif_av.h
+++ b/btif/include/btif_av.h
@@ -48,8 +48,10 @@
/**
* Stop streaming.
+ *
+ * @param peer_address the peer address or RawAddress::kEmpty to stop all peers
*/
-void btif_av_stream_stop(void);
+void btif_av_stream_stop(const RawAddress& peer_address);
/**
* Suspend streaming.
diff --git a/btif/include/btif_common.h b/btif/include/btif_common.h
index 94fadee..af0beb0 100644
--- a/btif/include/btif_common.h
+++ b/btif/include/btif_common.h
@@ -23,6 +23,7 @@
#include <stdlib.h>
#include <base/bind.h>
+#include <base/message_loop/message_loop.h>
#include <base/tracked_objects.h>
#include <hardware/bluetooth.h>
@@ -177,6 +178,7 @@
extern bt_status_t do_in_jni_thread(const tracked_objects::Location& from_here,
const base::Closure& task);
extern bool is_on_jni_thread();
+extern base::MessageLoop* get_jni_message_loop();
/**
* This template wraps callback into callback that will be executed on jni
* thread
diff --git a/btif/include/btif_dm.h b/btif/include/btif_dm.h
index 6105ab5..a9cb228 100644
--- a/btif/include/btif_dm.h
+++ b/btif/include/btif_dm.h
@@ -61,9 +61,9 @@
tBTA_LE_AUTH_REQ* p_auth_req);
#ifdef BTIF_DM_OOB_TEST
void btif_dm_load_local_oob(void);
-void btif_dm_proc_loc_oob(bool valid, BT_OCTET16 c, BT_OCTET16 r);
-bool btif_dm_proc_rmt_oob(const RawAddress& bd_addr, BT_OCTET16 p_c,
- BT_OCTET16 p_r);
+void btif_dm_proc_loc_oob(bool valid, const Octet16& c, const Octet16& r);
+bool btif_dm_proc_rmt_oob(const RawAddress& bd_addr, Octet16* p_c,
+ Octet16* p_r);
#endif /* BTIF_DM_OOB_TEST */
/*callout for reading SMP properties from Text file*/
@@ -98,7 +98,7 @@
void btif_dm_load_ble_local_keys(void);
void btif_dm_get_ble_local_keys(tBTA_DM_BLE_LOCAL_KEY_MASK* p_key_mask,
- BT_OCTET16 er,
+ Octet16* p_er,
tBTA_BLE_LOCAL_ID_KEYS* p_id_keys);
void btif_dm_save_ble_bonding_keys(void);
void btif_dm_remove_ble_bonding_keys(void);
diff --git a/btif/include/btif_storage.h b/btif/include/btif_storage.h
index 79a94e3..30615ce 100644
--- a/btif/include/btif_storage.h
+++ b/btif/include/btif_storage.h
@@ -151,7 +151,7 @@
*
******************************************************************************/
bt_status_t btif_storage_add_bonded_device(RawAddress* remote_bd_addr,
- LINK_KEY link_key, uint8_t key_type,
+ LinkKey link_key, uint8_t key_type,
uint8_t pin_length);
/*******************************************************************************
@@ -243,6 +243,8 @@
******************************************************************************/
bool btif_storage_is_restricted_device(const RawAddress* remote_bd_addr);
+int btif_storage_get_num_bonded_devices(void);
+
bt_status_t btif_storage_add_ble_bonding_key(RawAddress* remote_bd_addr,
const uint8_t* key,
uint8_t key_type,
@@ -252,13 +254,13 @@
uint8_t* key_value,
int key_length);
-bt_status_t btif_storage_add_ble_local_key(char* key, uint8_t key_type,
- uint8_t key_length);
+bt_status_t btif_storage_add_ble_local_key(const Octet16& key,
+ uint8_t key_type);
bt_status_t btif_storage_remove_ble_bonding_keys(
const RawAddress* remote_bd_addr);
bt_status_t btif_storage_remove_ble_local_keys(void);
-bt_status_t btif_storage_get_ble_local_key(uint8_t key_type, char* key_value,
- int key_len);
+bt_status_t btif_storage_get_ble_local_key(uint8_t key_type,
+ Octet16* key_value);
bt_status_t btif_storage_get_remote_addr_type(const RawAddress* remote_bd_addr,
int* addr_type);
diff --git a/btif/src/bluetooth.cc b/btif/src/bluetooth.cc
index 94dc108..4fb8f64 100644
--- a/btif/src/bluetooth.cc
+++ b/btif/src/bluetooth.cc
@@ -326,8 +326,6 @@
#if (BTSNOOP_MEM == TRUE)
btif_debug_btsnoop_dump(fd);
#endif
-
- close(fd);
}
static void dumpMetrics(std::string* output) {
diff --git a/btif/src/btif_a2dp.cc b/btif/src/btif_a2dp.cc
index d7235eb..86485d4 100644
--- a/btif/src/btif_a2dp.cc
+++ b/btif/src/btif_a2dp.cc
@@ -36,8 +36,8 @@
#include "osi/include/log.h"
void btif_a2dp_on_idle(void) {
- APPL_TRACE_WARNING("## ON A2DP IDLE ## peer_sep = %d",
- btif_av_get_peer_sep());
+ LOG_INFO(LOG_TAG, "%s: ## ON A2DP IDLE ## peer_sep = %d", __func__,
+ btif_av_get_peer_sep());
if (btif_av_get_peer_sep() == AVDT_TSEP_SNK) {
btif_a2dp_source_on_idle();
} else if (btif_av_get_peer_sep() == AVDT_TSEP_SRC) {
@@ -49,7 +49,10 @@
tBTA_AV_START* p_av_start, bool pending_start) {
bool ack = false;
- APPL_TRACE_WARNING("## ON A2DP STARTED ##");
+ LOG_INFO(LOG_TAG,
+ "%s: ## ON A2DP STARTED ## peer %s pending_start:%s p_av_start:%p",
+ __func__, peer_addr.ToString().c_str(),
+ logbool(pending_start).c_str(), p_av_start);
if (p_av_start == NULL) {
/* ack back a local start request */
@@ -60,16 +63,19 @@
} else if (bluetooth::headset::IsCallIdle()) {
btif_av_stream_start_offload();
} else {
- APPL_TRACE_ERROR("%s: call in progress, do not start offload", __func__);
+ LOG_ERROR(LOG_TAG, "%s: peer %s call in progress, do not start offload",
+ __func__, peer_addr.ToString().c_str());
btif_a2dp_audio_on_started(A2DP_CTRL_ACK_INCALL_FAILURE);
}
return true;
}
- APPL_TRACE_WARNING(
- "%s: pending_start = %d status = %d suspending = %d initiator = %d",
- __func__, pending_start, p_av_start->status, p_av_start->suspending,
- p_av_start->initiator);
+ LOG_INFO(LOG_TAG,
+ "%s: peer %s pending_start:%s status:%d suspending:%s initiator:%s",
+ __func__, peer_addr.ToString().c_str(),
+ logbool(pending_start).c_str(), p_av_start->status,
+ logbool(p_av_start->suspending).c_str(),
+ logbool(p_av_start->initiator).c_str());
if (p_av_start->status == BTA_AV_SUCCESS) {
if (!p_av_start->suspending) {
@@ -82,21 +88,31 @@
}
ack = true;
}
+ } else {
+ // We were started remotely
+ if (btif_av_is_a2dp_offload_enabled()) {
+ btif_av_stream_start_offload();
+ }
}
/* media task is autostarted upon a2dp audiopath connection */
}
} else if (pending_start) {
- APPL_TRACE_WARNING("%s: A2DP start request failed: status = %d", __func__,
- p_av_start->status);
- btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
+ LOG_ERROR(LOG_TAG, "%s: peer %s A2DP start request failed: status = %d",
+ __func__, peer_addr.ToString().c_str(), p_av_start->status);
+ if (btif_av_is_a2dp_offload_enabled()) {
+ btif_a2dp_audio_on_started(p_av_start->status);
+ } else {
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
+ }
ack = true;
}
return ack;
}
void btif_a2dp_on_stopped(tBTA_AV_SUSPEND* p_av_suspend) {
- APPL_TRACE_WARNING("## ON A2DP STOPPED ##");
+ LOG_INFO(LOG_TAG, "%s: ## ON A2DP STOPPED ## p_av_suspend=%p", __func__,
+ p_av_suspend);
if (btif_av_get_peer_sep() == AVDT_TSEP_SRC) {
btif_a2dp_sink_on_stopped(p_av_suspend);
@@ -110,7 +126,8 @@
}
void btif_a2dp_on_suspended(tBTA_AV_SUSPEND* p_av_suspend) {
- APPL_TRACE_EVENT("## ON A2DP SUSPENDED ##");
+ LOG_INFO(LOG_TAG, "%s: ## ON A2DP SUSPENDED ## p_av_suspend=%p", __func__,
+ p_av_suspend);
if (!btif_av_is_a2dp_offload_enabled()) {
if (btif_av_get_peer_sep() == AVDT_TSEP_SRC) {
btif_a2dp_sink_on_suspended(p_av_suspend);
@@ -125,18 +142,21 @@
void btif_a2dp_on_offload_started(const RawAddress& peer_addr,
tBTA_AV_STATUS status) {
tA2DP_CTRL_ACK ack;
- APPL_TRACE_EVENT("%s status %d", __func__, status);
+ LOG_INFO(LOG_TAG, "%s: peer %s status %d", __func__,
+ peer_addr.ToString().c_str(), status);
switch (status) {
case BTA_AV_SUCCESS:
ack = A2DP_CTRL_ACK_SUCCESS;
break;
case BTA_AV_FAIL_RESOURCES:
- APPL_TRACE_ERROR("%s FAILED UNSUPPORTED", __func__);
+ LOG_ERROR(LOG_TAG, "%s: peer %s FAILED UNSUPPORTED", __func__,
+ peer_addr.ToString().c_str());
ack = A2DP_CTRL_ACK_UNSUPPORTED;
break;
default:
- APPL_TRACE_ERROR("%s FAILED: status = %d", __func__, status);
+ LOG_ERROR(LOG_TAG, "%s: peer %s FAILED: status = %d", __func__,
+ peer_addr.ToString().c_str(), status);
ack = A2DP_CTRL_ACK_FAILURE;
break;
}
@@ -146,7 +166,8 @@
// Offload request will return with failure from btif_av sm if
// suspend is triggered for remote start. Disconnect only if SoC
// returned failure for offload VSC
- APPL_TRACE_ERROR("%s: offload start failed", __func__);
+ LOG_ERROR(LOG_TAG, "%s: peer %s offload start failed", __func__,
+ peer_addr.ToString().c_str());
btif_av_src_disconnect_sink(peer_addr);
}
} else {
diff --git a/btif/src/btif_a2dp_audio_interface.cc b/btif/src/btif_a2dp_audio_interface.cc
index 3608acd..944318e 100644
--- a/btif/src/btif_a2dp_audio_interface.cc
+++ b/btif/src/btif_a2dp_audio_interface.cc
@@ -19,6 +19,9 @@
#define LOG_TAG "btif_a2dp_audio_interface"
#include "btif_a2dp_audio_interface.h"
+
+#include <mutex>
+
#include <a2dp_vendor.h>
#include <a2dp_vendor_ldac_constants.h>
#include <android/hardware/bluetooth/a2dp/1.0/IBluetoothAudioHost.h>
@@ -37,8 +40,12 @@
#include "btif_av.h"
#include "btif_av_co.h"
#include "btif_hf.h"
+#include "osi/include/metrics.h"
#include "osi/include/osi.h"
+using system_bt_osi::A2dpSessionMetrics;
+using system_bt_osi::BluetoothMetricsLogger;
+
using android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioOffload;
using android::hardware::bluetooth::a2dp::V1_0::IBluetoothAudioHost;
using android::hardware::bluetooth::a2dp::V1_0::Status;
@@ -50,8 +57,10 @@
using android::hardware::ProcessState;
using ::android::hardware::Return;
using ::android::hardware::Void;
+using ::android::hardware::hidl_death_recipient;
using ::android::hardware::hidl_vec;
using ::android::sp;
+using ::android::wp;
android::sp<IBluetoothAudioOffload> btAudio;
#define CASE_RETURN_STR(const) \
@@ -63,11 +72,67 @@
static void btif_a2dp_audio_send_start_req();
static void btif_a2dp_audio_send_suspend_req();
+static void btif_a2dp_audio_send_stop_req();
static void btif_a2dp_audio_interface_init();
static void btif_a2dp_audio_interface_deinit();
+static void btif_a2dp_audio_interface_restart_session();
// Delay reporting
// static void btif_a2dp_audio_send_sink_latency();
+class A2dpOffloadAudioStats {
+ public:
+ A2dpOffloadAudioStats() { Reset(); }
+ void Reset() {
+ std::lock_guard<std::recursive_mutex> lock(lock_);
+ ResetPreserveSession();
+ codec_index_ = -1;
+ }
+ void ResetPreserveSession() {
+ std::lock_guard<std::recursive_mutex> lock(lock_);
+ audio_start_time_ms_ = -1;
+ audio_stop_time_ms_ = -1;
+ }
+ void StoreMetrics() {
+ std::lock_guard<std::recursive_mutex> lock(lock_);
+ if (audio_start_time_ms_ < 0 || audio_stop_time_ms_ < 0) {
+ return;
+ }
+ A2dpSessionMetrics metrics;
+ metrics.codec_index = codec_index_;
+ metrics.is_a2dp_offload = true;
+ if (audio_stop_time_ms_ > audio_start_time_ms_) {
+ metrics.audio_duration_ms = audio_stop_time_ms_ - audio_start_time_ms_;
+ }
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics);
+ }
+ void LogAudioStart() {
+ std::lock_guard<std::recursive_mutex> lock(lock_);
+ audio_start_time_ms_ = time_get_os_boottime_ms();
+ }
+ void LogAudioStop() {
+ std::lock_guard<std::recursive_mutex> lock(lock_);
+ audio_stop_time_ms_ = time_get_os_boottime_ms();
+ }
+ void LogAudioStopMetricsAndReset() {
+ std::lock_guard<std::recursive_mutex> lock(lock_);
+ LogAudioStop();
+ StoreMetrics();
+ ResetPreserveSession();
+ }
+ void SetCodecIndex(int64_t codec_index) {
+ std::lock_guard<std::recursive_mutex> lock(lock_);
+ codec_index_ = codec_index;
+ }
+
+ private:
+ std::recursive_mutex lock_;
+ int64_t audio_start_time_ms_ = -1;
+ int64_t audio_stop_time_ms_ = -1;
+ int64_t codec_index_ = -1;
+};
+
+static A2dpOffloadAudioStats a2dp_offload_audio_stats;
+
class BluetoothAudioHost : public IBluetoothAudioHost {
public:
Return<void> startStream() {
@@ -79,7 +144,7 @@
return Void();
}
Return<void> stopStream() {
- btif_a2dp_audio_process_request(A2DP_CTRL_CMD_STOP);
+ btif_a2dp_audio_send_stop_req();
return Void();
}
@@ -91,6 +156,20 @@
}*/
};
+class BluetoothAudioDeathRecipient : public hidl_death_recipient {
+ public:
+ virtual void serviceDied(
+ uint64_t /*cookie*/,
+ const wp<::android::hidl::base::V1_0::IBase>& /*who*/) {
+ LOG_ERROR(LOG_TAG, "%s", __func__);
+ // Restart the session on the correct thread
+ do_in_bta_thread(FROM_HERE,
+ base::Bind(&btif_a2dp_audio_interface_restart_session));
+ }
+};
+sp<BluetoothAudioDeathRecipient> bluetoothAudioDeathRecipient =
+ new BluetoothAudioDeathRecipient();
+
static Status mapToStatus(uint8_t resp) {
switch (resp) {
case A2DP_CTRL_ACK_SUCCESS:
@@ -118,6 +197,7 @@
a2dpCodecConfig->getCodecSpecificConfig(&a2dp_offload);
btav_a2dp_codec_config_t codec_config;
codec_config = a2dpCodecConfig->getCodecConfig();
+ a2dp_offload_audio_stats.SetCodecIndex(a2dpCodecConfig->codecIndex());
switch (codec_config.codec_type) {
case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
p_codec_info->codecType =
@@ -190,6 +270,12 @@
btAudio = IBluetoothAudioOffload::getService();
CHECK(btAudio != nullptr);
+ auto death_link = btAudio->linkToDeath(bluetoothAudioDeathRecipient, 0);
+ if (!death_link.isOk()) {
+ LOG_ERROR(LOG_TAG, "%s: Cannot observe the Bluetooth Audio HAL's death",
+ __func__);
+ }
+
LOG_DEBUG(
LOG_TAG, "%s: IBluetoothAudioOffload::getService() returned %p (%s)",
__func__, btAudio.get(), (btAudio->isRemote() ? "remote" : "local"));
@@ -199,11 +285,22 @@
static void btif_a2dp_audio_interface_deinit() {
LOG_INFO(LOG_TAG, "%s: start", __func__);
+ if (btAudio != nullptr) {
+ auto death_unlink = btAudio->unlinkToDeath(bluetoothAudioDeathRecipient);
+ if (!death_unlink.isOk()) {
+ LOG_ERROR(LOG_TAG,
+ "%s: Error unlinking death observer from Bluetooth Audio HAL",
+ __func__);
+ }
+ }
btAudio = nullptr;
}
void btif_a2dp_audio_interface_start_session() {
LOG_INFO(LOG_TAG, "%s", __func__);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
+ a2dp_offload_audio_stats.Reset();
btif_a2dp_audio_interface_init();
CHECK(btAudio != nullptr);
CodecConfiguration codec_info;
@@ -214,6 +311,10 @@
void btif_a2dp_audio_interface_end_session() {
LOG_INFO(LOG_TAG, "%s", __func__);
+ a2dp_offload_audio_stats.LogAudioStopMetricsAndReset();
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
+ system_bt_osi::DISCONNECT_REASON_UNKNOWN, 0);
+ a2dp_offload_audio_stats.Reset();
if (btAudio == nullptr) return;
auto ret = btAudio->endSession();
if (!ret.isOk()) {
@@ -222,12 +323,31 @@
btif_a2dp_audio_interface_deinit();
}
+// Conditionally restart the session only if it was started before
+static void btif_a2dp_audio_interface_restart_session() {
+ LOG_INFO(LOG_TAG, "%s", __func__);
+ if (btAudio == nullptr) {
+ LOG_INFO(LOG_TAG, "%s: nothing to restart - session was not started",
+ __func__);
+ return;
+ }
+ btAudio = nullptr;
+ btif_a2dp_audio_interface_start_session();
+}
+
void btif_a2dp_audio_on_started(tBTA_AV_STATUS status) {
LOG_INFO(LOG_TAG, "%s: status = %d", __func__, status);
if (btAudio != nullptr) {
if (a2dp_cmd_pending == A2DP_CTRL_CMD_START) {
+ if (status != A2DP_CTRL_ACK_PENDING) {
+ a2dp_cmd_pending = A2DP_CTRL_CMD_NONE;
+ }
LOG_INFO(LOG_TAG, "%s: calling method onStarted", __func__);
- btAudio->streamStarted(mapToStatus(status));
+ auto hal_status = mapToStatus(status);
+ btAudio->streamStarted(hal_status);
+ if (hal_status == Status::SUCCESS) {
+ a2dp_offload_audio_stats.LogAudioStart();
+ }
}
}
}
@@ -236,8 +356,15 @@
LOG_INFO(LOG_TAG, "%s: status = %d", __func__, status);
if (btAudio != nullptr) {
if (a2dp_cmd_pending == A2DP_CTRL_CMD_SUSPEND) {
+ if (status != A2DP_CTRL_ACK_PENDING) {
+ a2dp_cmd_pending = A2DP_CTRL_CMD_NONE;
+ }
LOG_INFO(LOG_TAG, "calling method onSuspended");
- btAudio->streamSuspended(mapToStatus(status));
+ auto hal_status = mapToStatus(status);
+ btAudio->streamSuspended(hal_status);
+ if (hal_status == Status::SUCCESS) {
+ a2dp_offload_audio_stats.LogAudioStopMetricsAndReset();
+ }
}
}
}
@@ -245,9 +372,11 @@
void btif_a2dp_audio_on_stopped(tBTA_AV_STATUS status) {
LOG_INFO(LOG_TAG, "%s: status = %d", __func__, status);
if (btAudio != nullptr && a2dp_cmd_pending == A2DP_CTRL_CMD_START) {
+ a2dp_cmd_pending = A2DP_CTRL_CMD_NONE;
LOG_INFO(LOG_TAG, "%s: Remote disconnected when start under progress",
__func__);
btAudio->streamStarted(mapToStatus(A2DP_CTRL_ACK_DISCONNECT_IN_PROGRESS));
+ a2dp_offload_audio_stats.LogAudioStopMetricsAndReset();
}
}
void btif_a2dp_audio_send_start_req() {
@@ -255,7 +384,11 @@
uint8_t resp;
resp = btif_a2dp_audio_process_request(A2DP_CTRL_CMD_START);
if (btAudio != nullptr) {
- auto ret = btAudio->streamStarted(mapToStatus(resp));
+ auto status = mapToStatus(resp);
+ auto ret = btAudio->streamStarted(status);
+ if (status == Status::SUCCESS) {
+ a2dp_offload_audio_stats.LogAudioStart();
+ }
if (!ret.isOk()) LOG_ERROR(LOG_TAG, "HAL server died");
}
}
@@ -264,10 +397,21 @@
uint8_t resp;
resp = btif_a2dp_audio_process_request(A2DP_CTRL_CMD_SUSPEND);
if (btAudio != nullptr) {
- auto ret = btAudio->streamSuspended(mapToStatus(resp));
+ auto status = mapToStatus(resp);
+ auto ret = btAudio->streamSuspended(status);
+ if (status == Status::SUCCESS) {
+ a2dp_offload_audio_stats.LogAudioStopMetricsAndReset();
+ }
if (!ret.isOk()) LOG_ERROR(LOG_TAG, "HAL server died");
}
}
+
+void btif_a2dp_audio_send_stop_req() {
+ LOG_INFO(LOG_TAG, "%s", __func__);
+ btif_a2dp_audio_process_request(A2DP_CTRL_CMD_STOP);
+ a2dp_offload_audio_stats.LogAudioStopMetricsAndReset();
+}
+
/*void btif_a2dp_audio_send_sink_latency()
{
LOG_INFO(LOG_TAG, "%s", __func__);
@@ -281,7 +425,6 @@
uint8_t btif_a2dp_audio_process_request(uint8_t cmd) {
LOG_INFO(LOG_TAG, "%s: cmd: %s", __func__,
audio_a2dp_hw_dump_ctrl_event((tA2DP_CTRL_CMD)cmd));
- a2dp_cmd_pending = cmd;
uint8_t status;
switch (cmd) {
case A2DP_CTRL_CMD_START:
@@ -324,7 +467,7 @@
APPL_TRACE_WARNING("%s: A2DP command %s while AV stream is not ready",
__func__,
audio_a2dp_hw_dump_ctrl_event((tA2DP_CTRL_CMD)cmd));
- return A2DP_CTRL_ACK_FAILURE;
+ status = A2DP_CTRL_ACK_FAILURE;
break;
case A2DP_CTRL_CMD_STOP:
@@ -334,8 +477,8 @@
status = A2DP_CTRL_ACK_SUCCESS;
break;
}
- btif_av_stream_stop();
- return A2DP_CTRL_ACK_SUCCESS;
+ btif_av_stream_stop(RawAddress::kEmpty);
+ status = A2DP_CTRL_ACK_SUCCESS;
break;
case A2DP_CTRL_CMD_SUSPEND:
@@ -365,5 +508,10 @@
}
LOG_INFO(LOG_TAG, "a2dp-ctrl-cmd : %s DONE returning status %d",
audio_a2dp_hw_dump_ctrl_event((tA2DP_CTRL_CMD)cmd), status);
+ if (status == A2DP_CTRL_ACK_PENDING) {
+ a2dp_cmd_pending = cmd;
+ } else {
+ a2dp_cmd_pending = A2DP_CTRL_CMD_NONE;
+ }
return status;
}
diff --git a/btif/src/btif_a2dp_audio_interface_linux.cc b/btif/src/btif_a2dp_audio_interface_linux.cc
new file mode 100644
index 0000000..b5a0e19
--- /dev/null
+++ b/btif/src/btif_a2dp_audio_interface_linux.cc
@@ -0,0 +1,37 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2018 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 "btif_a2dp_audio_interface.h"
+
+#include <base/logging.h>
+
+void btif_a2dp_audio_on_started(tBTA_AV_STATUS status) {
+ LOG(FATAL) << "Unimplemented yet";
+}
+void btif_a2dp_audio_on_stopped(tBTA_AV_STATUS status) {
+ LOG(FATAL) << "Unimplemented yet";
+}
+void btif_a2dp_audio_on_suspended(tBTA_AV_STATUS status) {
+ LOG(FATAL) << "Unimplemented yet";
+}
+void btif_a2dp_audio_interface_start_session(void) {
+ LOG(FATAL) << "Unimplemented yet";
+}
+void btif_a2dp_audio_interface_end_session(void) {
+ LOG(FATAL) << "Unimplemented yet";
+}
diff --git a/btif/src/btif_a2dp_control.cc b/btif/src/btif_a2dp_control.cc
index bae6185..fb62480 100644
--- a/btif/src/btif_a2dp_control.cc
+++ b/btif/src/btif_a2dp_control.cc
@@ -163,7 +163,7 @@
btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
break;
}
- btif_av_stream_stop();
+ btif_av_stream_stop(RawAddress::kEmpty);
btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
break;
@@ -385,7 +385,7 @@
*/
if (btif_a2dp_source_is_streaming()) {
/* Post stop event and wait for audio path to stop */
- btif_av_stream_stop();
+ btif_av_stream_stop(RawAddress::kEmpty);
}
break;
diff --git a/btif/src/btif_a2dp_source.cc b/btif/src/btif_a2dp_source.cc
index 9d8fe34..efd842b 100644
--- a/btif/src/btif_a2dp_source.cc
+++ b/btif/src/btif_a2dp_source.cc
@@ -132,6 +132,7 @@
media_read_total_underflow_bytes = 0;
media_read_total_underflow_count = 0;
media_read_last_underflow_us = 0;
+ codec_index = -1;
}
uint64_t session_start_us;
@@ -160,6 +161,8 @@
size_t media_read_total_underflow_bytes;
size_t media_read_total_underflow_count;
uint64_t media_read_last_underflow_us;
+
+ int codec_index = -1;
};
class BtWorkerThread {
@@ -282,6 +285,19 @@
}
BtifA2dpSource::RunState State() const { return state_; }
+ std::string StateStr() const {
+ switch (state_) {
+ case kStateOff:
+ return "STATE_OFF";
+ case kStateStartingUp:
+ return "STATE_STARTING_UP";
+ case kStateRunning:
+ return "STATE_RUNNING";
+ case kStateShuttingDown:
+ return "STATE_SHUTTING_DOWN";
+ }
+ }
+
void SetState(BtifA2dpSource::RunState state) { state_ = state; }
fixed_queue_t* tx_audio_queue;
@@ -380,6 +396,7 @@
dst->media_read_total_underflow_count +=
src->media_read_total_underflow_count;
dst->media_read_last_underflow_us = src->media_read_last_underflow_us;
+ if (dst->codec_index < 0) dst->codec_index = src->codec_index;
btif_a2dp_source_accumulate_scheduling_stats(&src->tx_queue_enqueue_stats,
&dst->tx_queue_enqueue_stats);
btif_a2dp_source_accumulate_scheduling_stats(&src->tx_queue_dequeue_stats,
@@ -403,7 +420,8 @@
}
bool btif_a2dp_source_startup(void) {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+ btif_a2dp_source_cb.StateStr().c_str());
if (btif_a2dp_source_cb.State() != BtifA2dpSource::kStateOff) {
LOG_ERROR(LOG_TAG, "%s: A2DP Source media task already running", __func__);
@@ -422,18 +440,18 @@
}
static void btif_a2dp_source_startup_delayed(void) {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+ btif_a2dp_source_cb.StateStr().c_str());
raise_priority_a2dp(TASK_HIGH_MEDIA);
btif_a2dp_control_init();
btif_a2dp_source_cb.SetState(BtifA2dpSource::kStateRunning);
- BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
- system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
}
bool btif_a2dp_source_start_session(const RawAddress& peer_address) {
- LOG_INFO(LOG_TAG, "%s: peer_address=%s", __func__,
- peer_address.ToString().c_str());
+ LOG_INFO(LOG_TAG, "%s: peer_address=%s state=%s", __func__,
+ peer_address.ToString().c_str(),
+ btif_a2dp_source_cb.StateStr().c_str());
btif_a2dp_source_setup_codec(peer_address);
btif_a2dp_source_thread.DoInThread(
FROM_HERE,
@@ -443,14 +461,18 @@
static void btif_a2dp_source_start_session_delayed(
const RawAddress& peer_address) {
- LOG_INFO(LOG_TAG, "%s: peer_address=%s", __func__,
- peer_address.ToString().c_str());
+ LOG_INFO(LOG_TAG, "%s: peer_address=%s state=%s", __func__,
+ peer_address.ToString().c_str(),
+ btif_a2dp_source_cb.StateStr().c_str());
if (btif_a2dp_source_cb.State() != BtifA2dpSource::kStateRunning) {
LOG_ERROR(LOG_TAG, "%s: A2DP Source media task is not running", __func__);
return;
}
if (btif_av_is_a2dp_offload_enabled()) {
btif_a2dp_audio_interface_start_session();
+ } else {
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
}
}
@@ -458,9 +480,11 @@
const RawAddress& new_peer_address) {
bool is_streaming = alarm_is_scheduled(btif_a2dp_source_cb.media_alarm);
LOG_INFO(LOG_TAG,
- "%s: old_peer_address=%s new_peer_address=%s is_streaming=%s",
+ "%s: old_peer_address=%s new_peer_address=%s is_streaming=%s "
+ "state=%s",
__func__, old_peer_address.ToString().c_str(),
- new_peer_address.ToString().c_str(), logbool(is_streaming).c_str());
+ new_peer_address.ToString().c_str(), logbool(is_streaming).c_str(),
+ btif_a2dp_source_cb.StateStr().c_str());
CHECK(!new_peer_address.IsEmpty());
@@ -487,8 +511,9 @@
}
bool btif_a2dp_source_end_session(const RawAddress& peer_address) {
- LOG_INFO(LOG_TAG, "%s: peer_address=%s", __func__,
- peer_address.ToString().c_str());
+ LOG_INFO(LOG_TAG, "%s: peer_address=%s state=%s", __func__,
+ peer_address.ToString().c_str(),
+ btif_a2dp_source_cb.StateStr().c_str());
btif_a2dp_source_thread.DoInThread(
FROM_HERE,
base::Bind(&btif_a2dp_source_end_session_delayed, peer_address));
@@ -497,20 +522,26 @@
static void btif_a2dp_source_end_session_delayed(
const RawAddress& peer_address) {
- LOG_INFO(LOG_TAG, "%s: peer_address=%s", __func__,
- peer_address.ToString().c_str());
- if (btif_a2dp_source_cb.State() != BtifA2dpSource::kStateRunning) {
+ LOG_INFO(LOG_TAG, "%s: peer_address=%s state=%s", __func__,
+ peer_address.ToString().c_str(),
+ btif_a2dp_source_cb.StateStr().c_str());
+ if (!btif_av_is_a2dp_offload_enabled()) {
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
+ system_bt_osi::DISCONNECT_REASON_UNKNOWN, 0);
+ }
+ if (btif_a2dp_source_cb.State() == BtifA2dpSource::kStateRunning) {
+ btif_av_stream_stop(peer_address);
+ } else {
LOG_ERROR(LOG_TAG, "%s: A2DP Source media task is not running", __func__);
- return;
}
if (btif_av_is_a2dp_offload_enabled()) {
- btif_av_stream_stop();
btif_a2dp_audio_interface_end_session();
}
}
void btif_a2dp_source_shutdown(void) {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+ btif_a2dp_source_cb.StateStr().c_str());
if ((btif_a2dp_source_cb.State() == BtifA2dpSource::kStateOff) ||
(btif_a2dp_source_cb.State() == BtifA2dpSource::kStateShuttingDown)) {
@@ -525,7 +556,8 @@
}
static void btif_a2dp_source_shutdown_delayed(void) {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+ btif_a2dp_source_cb.StateStr().c_str());
// Stop the timer
alarm_free(btif_a2dp_source_cb.media_alarm);
@@ -538,12 +570,11 @@
btif_a2dp_source_cb.tx_audio_queue = nullptr;
btif_a2dp_source_cb.SetState(BtifA2dpSource::kStateOff);
- BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
- system_bt_osi::DISCONNECT_REASON_UNKNOWN, 0);
}
void btif_a2dp_source_cleanup(void) {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+ btif_a2dp_source_cb.StateStr().c_str());
// Make sure the source is shutdown
btif_a2dp_source_shutdown();
@@ -556,7 +587,8 @@
}
static void btif_a2dp_source_cleanup_delayed(void) {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+ btif_a2dp_source_cb.StateStr().c_str());
// Nothing to do
}
@@ -573,8 +605,9 @@
}
static void btif_a2dp_source_setup_codec(const RawAddress& peer_address) {
- LOG_INFO(LOG_TAG, "%s: peer_address=%s", __func__,
- peer_address.ToString().c_str());
+ LOG_INFO(LOG_TAG, "%s: peer_address=%s state=%s", __func__,
+ peer_address.ToString().c_str(),
+ btif_a2dp_source_cb.StateStr().c_str());
// Check to make sure the platform has 8 bits/byte since
// we're using that in frame size calculations now.
@@ -588,8 +621,9 @@
static void btif_a2dp_source_setup_codec_delayed(
const RawAddress& peer_address) {
- LOG_INFO(LOG_TAG, "%s: peer_address=%s", __func__,
- peer_address.ToString().c_str());
+ LOG_INFO(LOG_TAG, "%s: peer_address=%s state=%s", __func__,
+ peer_address.ToString().c_str(),
+ btif_a2dp_source_cb.StateStr().c_str());
tA2DP_ENCODER_INIT_PEER_PARAMS peer_params;
bta_av_co_get_peer_params(peer_address, &peer_params);
@@ -623,37 +657,27 @@
}
void btif_a2dp_source_start_audio_req(void) {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+ btif_a2dp_source_cb.StateStr().c_str());
btif_a2dp_source_thread.DoInThread(
FROM_HERE, base::Bind(&btif_a2dp_source_audio_tx_start_event));
- btif_a2dp_source_cb.stats.Reset();
- // Assign session_start_us to 1 when time_get_os_boottime_us() is 0 to
- // indicate btif_a2dp_source_start_audio_req() has been called
- btif_a2dp_source_cb.stats.session_start_us = time_get_os_boottime_us();
- if (btif_a2dp_source_cb.stats.session_start_us == 0) {
- btif_a2dp_source_cb.stats.session_start_us = 1;
- }
- btif_a2dp_source_cb.stats.session_end_us = 0;
}
void btif_a2dp_source_stop_audio_req(void) {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+ btif_a2dp_source_cb.StateStr().c_str());
btif_a2dp_source_thread.DoInThread(
FROM_HERE, base::Bind(&btif_a2dp_source_audio_tx_stop_event));
-
- btif_a2dp_source_cb.stats.session_end_us = time_get_os_boottime_us();
- btif_a2dp_source_update_metrics();
- btif_a2dp_source_accumulate_stats(&btif_a2dp_source_cb.stats,
- &btif_a2dp_source_cb.accumulated_stats);
}
void btif_a2dp_source_encoder_user_config_update_req(
const RawAddress& peer_address,
const btav_a2dp_codec_config_t& codec_user_config) {
- LOG_INFO(LOG_TAG, "%s: peer_address=%s", __func__,
- peer_address.ToString().c_str());
+ LOG_INFO(LOG_TAG, "%s: peer_address=%s state=%s", __func__,
+ peer_address.ToString().c_str(),
+ btif_a2dp_source_cb.StateStr().c_str());
btif_a2dp_source_thread.DoInThread(
FROM_HERE, base::Bind(&btif_a2dp_source_encoder_user_config_update_event,
peer_address, codec_user_config));
@@ -662,8 +686,9 @@
static void btif_a2dp_source_encoder_user_config_update_event(
const RawAddress& peer_address,
const btav_a2dp_codec_config_t& codec_user_config) {
- LOG_INFO(LOG_TAG, "%s: peer_address=%s", __func__,
- peer_address.ToString().c_str());
+ LOG_INFO(LOG_TAG, "%s: peer_address=%s state=%s", __func__,
+ peer_address.ToString().c_str(),
+ btif_a2dp_source_cb.StateStr().c_str());
if (!bta_av_co_set_codec_user_config(peer_address, codec_user_config)) {
LOG_ERROR(LOG_TAG, "%s: cannot update codec user configuration", __func__);
}
@@ -671,7 +696,8 @@
void btif_a2dp_source_feeding_update_req(
const btav_a2dp_codec_config_t& codec_audio_config) {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+ btif_a2dp_source_cb.StateStr().c_str());
btif_a2dp_source_thread.DoInThread(
FROM_HERE, base::Bind(&btif_a2dp_source_audio_feeding_update_event,
codec_audio_config));
@@ -679,7 +705,8 @@
static void btif_a2dp_source_audio_feeding_update_event(
const btav_a2dp_codec_config_t& codec_audio_config) {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+ btif_a2dp_source_cb.StateStr().c_str());
if (!bta_av_co_set_codec_audio_config(codec_audio_config)) {
LOG_ERROR(LOG_TAG, "%s: cannot update codec audio feeding parameters",
__func__);
@@ -687,7 +714,8 @@
}
void btif_a2dp_source_on_idle(void) {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+ btif_a2dp_source_cb.StateStr().c_str());
if (btif_a2dp_source_cb.State() == BtifA2dpSource::kStateOff) return;
/* Make sure media task is stopped */
@@ -695,7 +723,8 @@
}
void btif_a2dp_source_on_stopped(tBTA_AV_SUSPEND* p_av_suspend) {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+ btif_a2dp_source_cb.StateStr().c_str());
if (btif_a2dp_source_cb.State() == BtifA2dpSource::kStateOff) return;
@@ -724,7 +753,8 @@
}
void btif_a2dp_source_on_suspended(tBTA_AV_SUSPEND* p_av_suspend) {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+ btif_a2dp_source_cb.StateStr().c_str());
if (btif_a2dp_source_cb.State() == BtifA2dpSource::kStateOff) return;
@@ -748,14 +778,17 @@
/* when true media task discards any tx frames */
void btif_a2dp_source_set_tx_flush(bool enable) {
- LOG_INFO(LOG_TAG, "%s: enable=%s", __func__, (enable) ? "true" : "false");
+ LOG_INFO(LOG_TAG, "%s: enable=%s state=%s", __func__,
+ (enable) ? "true" : "false", btif_a2dp_source_cb.StateStr().c_str());
btif_a2dp_source_cb.tx_flush = enable;
}
static void btif_a2dp_source_audio_tx_start_event(void) {
- LOG_INFO(LOG_TAG, "%s: media_alarm is %srunning, streaming %s", __func__,
+ LOG_INFO(LOG_TAG, "%s: media_alarm is %srunning, streaming %s state=%s",
+ __func__,
alarm_is_scheduled(btif_a2dp_source_cb.media_alarm) ? "" : "not ",
- btif_a2dp_source_is_streaming() ? "true" : "false");
+ btif_a2dp_source_is_streaming() ? "true" : "false",
+ btif_a2dp_source_cb.StateStr().c_str());
if (btif_av_is_a2dp_offload_enabled()) return;
@@ -777,16 +810,34 @@
alarm_set(btif_a2dp_source_cb.media_alarm,
btif_a2dp_source_cb.encoder_interface->get_encoder_interval_ms(),
btif_a2dp_source_alarm_cb, nullptr);
+
+ btif_a2dp_source_cb.stats.Reset();
+ // Assign session_start_us to 1 when time_get_os_boottime_us() is 0 to
+ // indicate btif_a2dp_source_start_audio_req() has been called
+ btif_a2dp_source_cb.stats.session_start_us = time_get_os_boottime_us();
+ if (btif_a2dp_source_cb.stats.session_start_us == 0) {
+ btif_a2dp_source_cb.stats.session_start_us = 1;
+ }
+ btif_a2dp_source_cb.stats.session_end_us = 0;
+ A2dpCodecConfig* codec_config = bta_av_get_a2dp_current_codec();
+ if (codec_config != nullptr) {
+ btif_a2dp_source_cb.stats.codec_index = codec_config->codecIndex();
+ }
}
static void btif_a2dp_source_audio_tx_stop_event(void) {
- LOG_INFO(LOG_TAG, "%s: media_alarm is %srunning, streaming %s", __func__,
+ LOG_INFO(LOG_TAG, "%s: media_alarm is %srunning, streaming %s state=%s",
+ __func__,
alarm_is_scheduled(btif_a2dp_source_cb.media_alarm) ? "" : "not ",
- btif_a2dp_source_is_streaming() ? "true" : "false");
+ btif_a2dp_source_is_streaming() ? "true" : "false",
+ btif_a2dp_source_cb.StateStr().c_str());
if (btif_av_is_a2dp_offload_enabled()) return;
- const bool send_ack = btif_a2dp_source_is_streaming();
+ btif_a2dp_source_cb.stats.session_end_us = time_get_os_boottime_us();
+ btif_a2dp_source_update_metrics();
+ btif_a2dp_source_accumulate_stats(&btif_a2dp_source_cb.stats,
+ &btif_a2dp_source_cb.accumulated_stats);
uint8_t p_buf[AUDIO_STREAM_OUTPUT_BUFFER_SZ * 2];
uint16_t event;
@@ -814,7 +865,7 @@
* to get the ACK for any pending command in such cases.
*/
- if (send_ack) btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
/* audio engine stopped, reset tx suspended flag */
btif_a2dp_source_cb.tx_flush = false;
@@ -960,7 +1011,8 @@
static void btif_a2dp_source_audio_tx_flush_event(void) {
/* Flush all enqueued audio buffers (encoded) */
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+ btif_a2dp_source_cb.StateStr().c_str());
if (btif_av_is_a2dp_offload_enabled()) return;
if (btif_a2dp_source_cb.encoder_interface != nullptr)
@@ -976,7 +1028,8 @@
}
static bool btif_a2dp_source_audio_tx_flush_req(void) {
- LOG_INFO(LOG_TAG, "%s", __func__);
+ LOG_INFO(LOG_TAG, "%s: state=%s", __func__,
+ btif_a2dp_source_cb.StateStr().c_str());
btif_a2dp_source_thread.DoInThread(
FROM_HERE, base::Bind(&btif_a2dp_source_audio_tx_flush_event));
@@ -1214,17 +1267,21 @@
}
static void btif_a2dp_source_update_metrics(void) {
- const BtifMediaStats& stats = btif_a2dp_source_cb.stats;
- const SchedulingStats& enqueue_stats = stats.tx_queue_enqueue_stats;
+ BtifMediaStats stats = btif_a2dp_source_cb.stats;
+ SchedulingStats enqueue_stats = stats.tx_queue_enqueue_stats;
A2dpSessionMetrics metrics;
+ metrics.codec_index = stats.codec_index;
+ metrics.is_a2dp_offload = btif_av_is_a2dp_offload_enabled();
// session_start_us is 0 when btif_a2dp_source_start_audio_req() is not called
// mark the metric duration as invalid (-1) in this case
if (stats.session_start_us != 0) {
int64_t session_end_us = stats.session_end_us == 0
? time_get_os_boottime_us()
: stats.session_end_us;
- metrics.audio_duration_ms =
- (session_end_us - stats.session_start_us) / 1000;
+ if (static_cast<uint64_t>(session_end_us) > stats.session_start_us) {
+ metrics.audio_duration_ms =
+ (session_end_us - stats.session_start_us) / 1000;
+ }
}
if (enqueue_stats.total_updates > 1) {
diff --git a/btif/src/btif_av.cc b/btif/src/btif_av.cc
index db9c53a..8d416c1 100644
--- a/btif/src/btif_av.cc
+++ b/btif/src/btif_av.cc
@@ -404,7 +404,6 @@
BTIF_TRACE_WARNING("%s: unable to set active peer to empty in BtaAvCo",
__func__);
}
- btif_av_stream_stop();
btif_a2dp_source_end_session(active_peer_);
btif_a2dp_source_shutdown();
active_peer_ = peer_address;
@@ -1685,7 +1684,8 @@
BTIF_TRACE_DEBUG("%s: Peer %s", __PRETTY_FUNCTION__,
peer_.PeerAddress().ToString().c_str());
- peer_.ClearFlags(BtifAvPeer::kFlagPendingStart |
+ peer_.ClearFlags(BtifAvPeer::kFlagLocalSuspendPending |
+ BtifAvPeer::kFlagPendingStart |
BtifAvPeer::kFlagPendingStop);
// Set the active peer if the first connected device.
@@ -1756,12 +1756,13 @@
// If remote tries to start A2DP when DUT is A2DP Source, then Suspend.
// If A2DP is Sink and call is active, then disconnect the AVDTP channel.
- if (peer_.IsSink() && !peer_.CheckFlags(BtifAvPeer::kFlagPendingStart)) {
+ bool should_suspend = false;
+ if (peer_.IsSink() && !peer_.CheckFlags(BtifAvPeer::kFlagPendingStart |
+ BtifAvPeer::kFlagRemoteSuspend)) {
BTIF_TRACE_WARNING("%s: Peer %s : trigger Suspend as remote initiated",
__PRETTY_FUNCTION__,
peer_.PeerAddress().ToString().c_str());
- btif_av_source_dispatch_sm_event(peer_.PeerAddress(),
- BTIF_AV_SUSPEND_STREAM_REQ_EVT);
+ should_suspend = true;
}
// If peer is A2DP Source, we do not want to ACK commands on UIPC
@@ -1786,6 +1787,11 @@
btif_a2dp_on_started(peer_.PeerAddress(), nullptr, true);
// Pending start flag will be cleared when exit current state
}
+
+ if (should_suspend) {
+ btif_av_source_dispatch_sm_event(peer_.PeerAddress(),
+ BTIF_AV_SUSPEND_STREAM_REQ_EVT);
+ }
peer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateStarted);
} break;
@@ -2018,6 +2024,8 @@
peer_.FlagsToString().c_str());
peer_.SetFlags(BtifAvPeer::kFlagPendingStop);
+ peer_.ClearFlags(BtifAvPeer::kFlagLocalSuspendPending);
+
btif_a2dp_on_stopped(&p_av->suspend);
btif_report_audio_state(peer_.PeerAddress(), BTAV_AUDIO_STATE_STOPPED);
@@ -2729,11 +2737,19 @@
bool btif_av_is_sink_enabled(void) { return btif_av_sink.Enabled(); }
void btif_av_stream_start(void) {
+ LOG_INFO(LOG_TAG, "%s", __func__);
btif_av_source_dispatch_sm_event(btif_av_source_active_peer(),
BTIF_AV_START_STREAM_REQ_EVT);
}
-void btif_av_stream_stop(void) {
+void btif_av_stream_stop(const RawAddress& peer_address) {
+ LOG_INFO(LOG_TAG, "%s peer %s", __func__, peer_address.ToString().c_str());
+
+ if (!peer_address.IsEmpty()) {
+ btif_av_source_dispatch_sm_event(peer_address, BTIF_AV_STOP_STREAM_REQ_EVT);
+ return;
+ }
+
// The active peer might have changed and we might be in the process
// of reconfiguring the stream. We need to stop the appopriate peer(s).
for (auto it : btif_av_source.Peers()) {
@@ -2744,6 +2760,7 @@
}
void btif_av_stream_suspend(void) {
+ LOG_INFO(LOG_TAG, "%s", __func__);
// The active peer might have changed and we might be in the process
// of reconfiguring the stream. We need to suspend the appropriate peer(s).
for (auto it : btif_av_source.Peers()) {
@@ -2754,11 +2771,13 @@
}
void btif_av_stream_start_offload(void) {
+ LOG_INFO(LOG_TAG, "%s", __func__);
btif_av_source_dispatch_sm_event(btif_av_source_active_peer(),
BTIF_AV_OFFLOAD_START_REQ_EVT);
}
void btif_av_src_disconnect_sink(const RawAddress& peer_address) {
+ LOG_INFO(LOG_TAG, "%s: peer %s", __func__, peer_address.ToString().c_str());
src_disconnect_sink(peer_address);
}
diff --git a/btif/src/btif_core.cc b/btif/src/btif_core.cc
index c2b662a..9fa4590 100644
--- a/btif/src/btif_core.cc
+++ b/btif/src/btif_core.cc
@@ -252,6 +252,8 @@
return btif_thread_id_ == PlatformThread::CurrentId();
}
+base::MessageLoop* get_jni_message_loop() { return message_loop_; }
+
/*******************************************************************************
*
* Function btif_is_dut_mode
diff --git a/btif/src/btif_dm.cc b/btif/src/btif_dm.cc
index d8ebbdf..91afabf 100644
--- a/btif/src/btif_dm.cc
+++ b/btif/src/btif_dm.cc
@@ -97,8 +97,9 @@
#define BTIF_DM_MAX_SDP_ATTEMPTS_AFTER_PAIRING 2
#define NUM_TIMEOUT_RETRIES 5
-
+#ifndef PROPERTY_PRODUCT_MODEL
#define PROPERTY_PRODUCT_MODEL "ro.product.model"
+#endif
#define DEFAULT_LOCAL_NAME_MAX 31
#if (DEFAULT_LOCAL_NAME_MAX > BTM_MAX_LOC_BD_NAME_LEN)
#error "default btif local name size exceeds stack supported length"
@@ -125,15 +126,17 @@
btif_dm_ble_cb_t ble;
} btif_dm_pairing_cb_t;
+// TODO(jpawlowski): unify ?
+// btif_dm_local_key_id_t == tBTM_BLE_LOCAL_ID_KEYS == tBTA_BLE_LOCAL_ID_KEYS
typedef struct {
- uint8_t ir[BT_OCTET16_LEN];
- uint8_t irk[BT_OCTET16_LEN];
- uint8_t dhk[BT_OCTET16_LEN];
+ Octet16 ir;
+ Octet16 irk;
+ Octet16 dhk;
} btif_dm_local_key_id_t;
typedef struct {
bool is_er_rcvd;
- uint8_t er[BT_OCTET16_LEN];
+ Octet16 er;
bool is_id_keys_rcvd;
btif_dm_local_key_id_t id_keys; /* ID kyes */
@@ -1395,10 +1398,15 @@
if ((p_data->disc_res.result != BTA_SUCCESS) &&
(pairing_cb.state == BT_BOND_STATE_BONDING) &&
(pairing_cb.sdp_attempts < BTIF_DM_MAX_SDP_ATTEMPTS_AFTER_PAIRING)) {
- BTIF_TRACE_WARNING("%s:SDP failed after bonding re-attempting",
- __func__);
- pairing_cb.sdp_attempts++;
- btif_dm_get_remote_services(bd_addr);
+ if (pairing_cb.sdp_attempts) {
+ BTIF_TRACE_WARNING("%s: SDP failed after bonding re-attempting",
+ __func__);
+ pairing_cb.sdp_attempts++;
+ btif_dm_get_remote_services(bd_addr);
+ } else {
+ BTIF_TRACE_WARNING("%s: SDP triggered by someone failed when bonding",
+ __func__);
+ }
return;
}
prop.type = BT_PROPERTY_UUIDS;
@@ -1791,25 +1799,22 @@
case BTA_DM_BLE_LOCAL_IR_EVT:
BTIF_TRACE_DEBUG("BTA_DM_BLE_LOCAL_IR_EVT. ");
ble_local_key_cb.is_id_keys_rcvd = true;
- memcpy(&ble_local_key_cb.id_keys.irk[0], &p_data->ble_id_keys.irk[0],
- sizeof(BT_OCTET16));
- memcpy(&ble_local_key_cb.id_keys.ir[0], &p_data->ble_id_keys.ir[0],
- sizeof(BT_OCTET16));
- memcpy(&ble_local_key_cb.id_keys.dhk[0], &p_data->ble_id_keys.dhk[0],
- sizeof(BT_OCTET16));
- btif_storage_add_ble_local_key((char*)&ble_local_key_cb.id_keys.irk[0],
- BTIF_DM_LE_LOCAL_KEY_IRK, BT_OCTET16_LEN);
- btif_storage_add_ble_local_key((char*)&ble_local_key_cb.id_keys.ir[0],
- BTIF_DM_LE_LOCAL_KEY_IR, BT_OCTET16_LEN);
- btif_storage_add_ble_local_key((char*)&ble_local_key_cb.id_keys.dhk[0],
- BTIF_DM_LE_LOCAL_KEY_DHK, BT_OCTET16_LEN);
+ ble_local_key_cb.id_keys.irk = p_data->ble_id_keys.irk;
+ ble_local_key_cb.id_keys.ir = p_data->ble_id_keys.ir;
+ ble_local_key_cb.id_keys.dhk = p_data->ble_id_keys.dhk;
+ btif_storage_add_ble_local_key(ble_local_key_cb.id_keys.irk,
+ BTIF_DM_LE_LOCAL_KEY_IRK);
+ btif_storage_add_ble_local_key(ble_local_key_cb.id_keys.ir,
+ BTIF_DM_LE_LOCAL_KEY_IR);
+ btif_storage_add_ble_local_key(ble_local_key_cb.id_keys.dhk,
+ BTIF_DM_LE_LOCAL_KEY_DHK);
break;
case BTA_DM_BLE_LOCAL_ER_EVT:
BTIF_TRACE_DEBUG("BTA_DM_BLE_LOCAL_ER_EVT. ");
ble_local_key_cb.is_er_rcvd = true;
- memcpy(&ble_local_key_cb.er[0], &p_data->ble_er[0], sizeof(BT_OCTET16));
- btif_storage_add_ble_local_key((char*)&ble_local_key_cb.er[0],
- BTIF_DM_LE_LOCAL_KEY_ER, BT_OCTET16_LEN);
+ ble_local_key_cb.er = p_data->ble_er;
+ btif_storage_add_ble_local_key(ble_local_key_cb.er,
+ BTIF_DM_LE_LOCAL_KEY_ER);
break;
case BTA_DM_BLE_AUTH_CMPL_EVT:
@@ -2649,7 +2654,7 @@
}
}
-void btif_dm_proc_loc_oob(bool valid, BT_OCTET16 c, BT_OCTET16 r) {
+void btif_dm_proc_loc_oob(bool valid, const Octet16& c, const Octet16& r) {
FILE* fp;
const char* path_a = "/data/misc/bluedroid/LOCAL/a.key";
const char* path_b = "/data/misc/bluedroid/LOCAL/b.key";
@@ -2658,8 +2663,8 @@
BTIF_TRACE_DEBUG("%s: valid=%d", __func__, valid);
if (is_empty_128bit(oob_cb.oob_data.c192) && valid) {
BTIF_TRACE_DEBUG("save local OOB data in memory");
- memcpy(oob_cb.oob_data.c192, c, BT_OCTET16_LEN);
- memcpy(oob_cb.oob_data.r192, r, BT_OCTET16_LEN);
+ memcpy(oob_cb.oob_data.c192, c.data(), OCTET16_LEN);
+ memcpy(oob_cb.oob_data.r192, r.data(), OCTET16_LEN);
osi_property_get("service.brcm.bt.oob", prop_oob, "3");
BTIF_TRACE_DEBUG("%s: prop_oob = %s", __func__, prop_oob);
if (prop_oob[0] == '1')
@@ -2674,8 +2679,8 @@
} else {
BTIF_TRACE_DEBUG("%s: save local OOB data into file %s", __func__,
path);
- fwrite(c, 1, BT_OCTET16_LEN, fp);
- fwrite(r, 1, BT_OCTET16_LEN, fp);
+ fwrite(c.data(), 1, OCTET16_LEN, fp);
+ fwrite(r.data(), 1, OCTET16_LEN, fp);
fclose(fp);
}
}
@@ -2745,8 +2750,8 @@
return true;
}
-bool btif_dm_proc_rmt_oob(const RawAddress& bd_addr, BT_OCTET16 p_c,
- BT_OCTET16 p_r) {
+bool btif_dm_proc_rmt_oob(const RawAddress& bd_addr, Octet16* p_c,
+ Octet16* p_r) {
const char* path_a = "/data/misc/bluedroid/LOCAL/a.key";
const char* path_b = "/data/misc/bluedroid/LOCAL/b.key";
const char* path = NULL;
@@ -2769,8 +2774,8 @@
}
BTIF_TRACE_DEBUG("%s: read OOB data from %s", __func__, path);
- fread(p_c, 1, BT_OCTET16_LEN, fp);
- fread(p_r, 1, BT_OCTET16_LEN, fp);
+ fread(p_c->data(), 1, OCTET16_LEN, fp);
+ fread(p_r->data(), 1, OCTET16_LEN, fp);
fclose(fp);
RawAddress bt_bd_addr = bd_addr;
@@ -2872,41 +2877,37 @@
void btif_dm_load_ble_local_keys(void) {
memset(&ble_local_key_cb, 0, sizeof(btif_dm_local_key_cb_t));
- if (btif_storage_get_ble_local_key(BTIF_DM_LE_LOCAL_KEY_ER,
- (char*)&ble_local_key_cb.er[0],
- BT_OCTET16_LEN) == BT_STATUS_SUCCESS) {
+ if (btif_storage_get_ble_local_key(
+ BTIF_DM_LE_LOCAL_KEY_ER, &ble_local_key_cb.er) == BT_STATUS_SUCCESS) {
ble_local_key_cb.is_er_rcvd = true;
BTIF_TRACE_DEBUG("%s BLE ER key loaded", __func__);
}
if ((btif_storage_get_ble_local_key(BTIF_DM_LE_LOCAL_KEY_IR,
- (char*)&ble_local_key_cb.id_keys.ir[0],
- BT_OCTET16_LEN) == BT_STATUS_SUCCESS) &&
+ &ble_local_key_cb.id_keys.ir) ==
+ BT_STATUS_SUCCESS) &&
(btif_storage_get_ble_local_key(BTIF_DM_LE_LOCAL_KEY_IRK,
- (char*)&ble_local_key_cb.id_keys.irk[0],
- BT_OCTET16_LEN) == BT_STATUS_SUCCESS) &&
+ &ble_local_key_cb.id_keys.irk) ==
+ BT_STATUS_SUCCESS) &&
(btif_storage_get_ble_local_key(BTIF_DM_LE_LOCAL_KEY_DHK,
- (char*)&ble_local_key_cb.id_keys.dhk[0],
- BT_OCTET16_LEN) == BT_STATUS_SUCCESS)) {
+ &ble_local_key_cb.id_keys.dhk) ==
+ BT_STATUS_SUCCESS)) {
ble_local_key_cb.is_id_keys_rcvd = true;
BTIF_TRACE_DEBUG("%s BLE ID keys loaded", __func__);
}
}
void btif_dm_get_ble_local_keys(tBTA_DM_BLE_LOCAL_KEY_MASK* p_key_mask,
- BT_OCTET16 er,
+ Octet16* p_er,
tBTA_BLE_LOCAL_ID_KEYS* p_id_keys) {
if (ble_local_key_cb.is_er_rcvd) {
- memcpy(&er[0], &ble_local_key_cb.er[0], sizeof(BT_OCTET16));
+ *p_er = ble_local_key_cb.er;
*p_key_mask |= BTA_BLE_LOCAL_KEY_TYPE_ER;
}
if (ble_local_key_cb.is_id_keys_rcvd) {
- memcpy(&p_id_keys->ir[0], &ble_local_key_cb.id_keys.ir[0],
- sizeof(BT_OCTET16));
- memcpy(&p_id_keys->irk[0], &ble_local_key_cb.id_keys.irk[0],
- sizeof(BT_OCTET16));
- memcpy(&p_id_keys->dhk[0], &ble_local_key_cb.id_keys.dhk[0],
- sizeof(BT_OCTET16));
+ p_id_keys->ir = ble_local_key_cb.id_keys.ir;
+ p_id_keys->irk = ble_local_key_cb.id_keys.irk;
+ p_id_keys->dhk = ble_local_key_cb.id_keys.dhk;
*p_key_mask |= BTA_BLE_LOCAL_KEY_TYPE_ID;
}
BTIF_TRACE_DEBUG("%s *p_key_mask=0x%02x", __func__, *p_key_mask);
diff --git a/btif/src/btif_gatt_test.cc b/btif/src/btif_gatt_test.cc
index 1297d50..1c0af35 100644
--- a/btif/src/btif_gatt_test.cc
+++ b/btif/src/btif_gatt_test.cc
@@ -219,24 +219,18 @@
case 0x04: /* Discover */
{
- tGATT_DISC_PARAM param;
- memset(¶m, 0, sizeof(tGATT_DISC_PARAM));
-
if (params->u1 >= GATT_DISC_MAX) {
LOG_ERROR(LOG_TAG, "%s: DISCOVER - Invalid type (%d)!", __func__,
params->u1);
return (bt_status_t)0;
}
- param.s_handle = params->u2;
- param.e_handle = params->u3;
- param.service = *params->uuid1;
-
LOG_DEBUG(LOG_TAG,
"%s: DISCOVER (%s), conn_id=%d, uuid=%s, handles=0x%04x-0x%04x",
__func__, disc_name[params->u1], test_cb.conn_id,
- param.service.ToString().c_str(), params->u2, params->u3);
- GATTC_Discover(test_cb.conn_id, params->u1, ¶m);
+ params->uuid1->ToString().c_str(), params->u2, params->u3);
+ GATTC_Discover(test_cb.conn_id, params->u1, params->u2, params->u3,
+ *params->uuid1);
break;
}
diff --git a/btif/src/btif_hf.cc b/btif/src/btif_hf.cc
index 5388986..038af2e 100644
--- a/btif/src/btif_hf.cc
+++ b/btif/src/btif_hf.cc
@@ -118,16 +118,6 @@
static btif_hf_cb_t btif_hf_cb[BTA_AG_MAX_NUM_CLIENTS];
-/* By default, even though codec negotiation is enabled, we will not use WBS as
- * the default
- * codec unless this variable is set to true.
- */
-#ifndef BTIF_HF_WBS_PREFERRED
-#define BTIF_HF_WBS_PREFERRED false
-#endif
-
-static bool btif_conf_hf_force_wbs = BTIF_HF_WBS_PREFERRED;
-
static const char* dump_hf_call_state(bthf_call_state_t call_state) {
switch (call_state) {
CASE_RETURN_STR(BTHF_CALL_STATE_IDLE)
@@ -511,7 +501,7 @@
we should set the BTA AG Codec to mSBC. This would trigger a +BCS to mSBC
at the time
of SCO connection establishment */
- if ((btif_conf_hf_force_wbs) && (p_data->val.num & BTA_AG_CODEC_MSBC)) {
+ if (p_data->val.num & BTA_AG_CODEC_MSBC) {
BTIF_TRACE_EVENT("%s: btif_hf override-Preferred Codec to MSBC",
__func__);
BTA_AgSetCodec(btif_hf_cb[idx].handle, BTA_AG_CODEC_MSBC);
@@ -783,14 +773,12 @@
LOG(ERROR) << ": SLC not connected for " << *bd_addr;
return BT_STATUS_NOT_READY;
}
- BTA_AgAudioOpen(btif_hf_cb[idx].handle);
- // Inform the application that the audio connection has been initiated
- // successfully
do_in_jni_thread(base::Bind(&Callbacks::AudioStateCallback,
// Manual pointer management for now
base::Unretained(bt_hf_callbacks),
BTHF_AUDIO_STATE_CONNECTING,
&btif_hf_cb[idx].connected_bda));
+ BTA_AgAudioOpen(btif_hf_cb[idx].handle);
return BT_STATUS_SUCCESS;
}
diff --git a/btif/src/btif_rc.cc b/btif/src/btif_rc.cc
index 0113c85..3dafe65 100644
--- a/btif/src/btif_rc.cc
+++ b/btif/src/btif_rc.cc
@@ -3246,8 +3246,9 @@
case AVRC_EVT_ADDR_PLAYER_CHANGE:
do_in_jni_thread(
- FROM_HERE, base::Bind(bt_rc_ctrl_callbacks->set_addressed_player_cb,
- p_dev->rc_addr, BTRC_STS_ADDR_PLAY_CHGD));
+ FROM_HERE,
+ base::Bind(bt_rc_ctrl_callbacks->addressed_player_changed_cb,
+ p_dev->rc_addr, p_rsp->param.addr_player.player_id));
break;
case AVRC_EVT_UIDS_CHANGE:
diff --git a/btif/src/btif_sdp_server.cc b/btif/src/btif_sdp_server.cc
index 4738da4..d3a8808 100644
--- a/btif/src/btif_sdp_server.cc
+++ b/btif/src/btif_sdp_server.cc
@@ -28,6 +28,7 @@
#define LOG_TAG "bt_btif_sdp_server"
+#include <log/log.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
diff --git a/btif/src/btif_storage.cc b/btif/src/btif_storage.cc
index 766dc7f..3b10eee 100644
--- a/btif/src/btif_storage.cc
+++ b/btif/src/btif_storage.cc
@@ -413,9 +413,9 @@
static bt_status_t btif_in_fetch_bonded_device(const std::string& bdstr) {
bool bt_linkkey_file_found = false;
- LINK_KEY link_key;
- size_t size = sizeof(link_key);
- if (btif_config_get_bin(bdstr, "LinkKey", (uint8_t*)link_key, &size)) {
+ LinkKey link_key;
+ size_t size = link_key.size();
+ if (btif_config_get_bin(bdstr, "LinkKey", link_key.data(), &size)) {
int linkkey_type;
if (btif_config_get_int(bdstr, "LinkKeyType", &linkkey_type)) {
bt_linkkey_file_found = true;
@@ -457,9 +457,9 @@
if (!RawAddress::IsValidAddress(name)) continue;
BTIF_TRACE_DEBUG("Remote device:%s", name.c_str());
- LINK_KEY link_key;
+ LinkKey link_key;
size_t size = sizeof(link_key);
- if (btif_config_get_bin(name, "LinkKey", link_key, &size)) {
+ if (btif_config_get_bin(name, "LinkKey", link_key.data(), &size)) {
int linkkey_type;
if (btif_config_get_int(name, "LinkKeyType", &linkkey_type)) {
RawAddress bd_addr;
@@ -815,12 +815,13 @@
******************************************************************************/
bt_status_t btif_storage_add_bonded_device(RawAddress* remote_bd_addr,
- LINK_KEY link_key, uint8_t key_type,
+ LinkKey link_key, uint8_t key_type,
uint8_t pin_length) {
std::string bdstr = remote_bd_addr->ToString();
int ret = btif_config_set_int(bdstr, "LinkKeyType", (int)key_type);
ret &= btif_config_set_int(bdstr, "PinLength", (int)pin_length);
- ret &= btif_config_set_bin(bdstr, "LinkKey", link_key, sizeof(LINK_KEY));
+ ret &=
+ btif_config_set_bin(bdstr, "LinkKey", link_key.data(), link_key.size());
if (is_restricted_mode()) {
BTIF_TRACE_WARNING("%s: '%s' pairing will be removed if unrestricted",
@@ -1125,8 +1126,8 @@
* BT_STATUS_FAIL otherwise
*
******************************************************************************/
-bt_status_t btif_storage_add_ble_local_key(char* key, uint8_t key_type,
- uint8_t key_length) {
+bt_status_t btif_storage_add_ble_local_key(const Octet16& key,
+ uint8_t key_type) {
const char* name;
switch (key_type) {
case BTIF_DM_LE_LOCAL_KEY_IR:
@@ -1144,24 +1145,17 @@
default:
return BT_STATUS_FAIL;
}
- int ret =
- btif_config_set_bin("Adapter", name, (const uint8_t*)key, key_length);
+ int ret = btif_config_set_bin("Adapter", name, key.data(), key.size());
btif_config_save();
return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
}
-/*******************************************************************************
- *
- * Function btif_storage_get_ble_local_key
- *
- * Description
- *
- * Returns BT_STATUS_SUCCESS if the fetch was successful,
- * BT_STATUS_FAIL otherwise
- *
- ******************************************************************************/
-bt_status_t btif_storage_get_ble_local_key(uint8_t key_type, char* key_value,
- int key_length) {
+/** Stores local key of |key_type| into |key_value|
+ * Returns BT_STATUS_SUCCESS if the fetch was successful, BT_STATUS_FAIL
+ * otherwise
+ */
+bt_status_t btif_storage_get_ble_local_key(uint8_t key_type,
+ Octet16* key_value) {
const char* name;
switch (key_type) {
case BTIF_DM_LE_LOCAL_KEY_IR:
@@ -1179,8 +1173,8 @@
default:
return BT_STATUS_FAIL;
}
- size_t length = key_length;
- int ret = btif_config_get_bin("Adapter", name, (uint8_t*)key_value, &length);
+ size_t length = key_value->size();
+ int ret = btif_config_get_bin("Adapter", name, key_value->data(), &length);
return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
}
@@ -1572,6 +1566,12 @@
return btif_config_exist(remote_bd_addr->ToString(), "Restricted");
}
+int btif_storage_get_num_bonded_devices(void) {
+ btif_bonded_devices_t bonded_devices;
+ btif_in_fetch_bonded_devices(&bonded_devices, 0);
+ return bonded_devices.num_devices;
+}
+
/*******************************************************************************
* Function btif_storage_load_hidd
*
diff --git a/build/secondary/third_party/libchrome/BUILD.gn b/build/secondary/third_party/libchrome/BUILD.gn
index 9ffdaa7..df6a886 100644
--- a/build/secondary/third_party/libchrome/BUILD.gn
+++ b/build/secondary/third_party/libchrome/BUILD.gn
@@ -133,6 +133,7 @@
"base/strings/sys_string_conversions_posix.cc",
"base/strings/utf_string_conversions.cc",
"base/strings/utf_string_conversion_utils.cc",
+ "base/synchronization/atomic_flag.cc",
"base/synchronization/condition_variable_posix.cc",
"base/synchronization/lock.cc",
"base/synchronization/lock_impl_posix.cc",
diff --git a/conf/bt_stack.conf b/conf/bt_stack.conf
index f1557b1..d1e7756 100644
--- a/conf/bt_stack.conf
+++ b/conf/bt_stack.conf
@@ -50,6 +50,9 @@
# SMP Pair options (formatted as hex bytes) auth, io, ikey, rkey, ksize
#PTS_SmpOptions=0xD,0x4,0xf,0xf,0x10
+# PTS AVRCP Test mode
+#PTS_AvrcpTest=true
+
# SMP Certification Failure Cases
# Set any of the following SMP error values (from smp_api_types.h)
# to induce pairing failues for various PTS SMP test cases.
diff --git a/doc/pts_guide.md b/doc/pts_guide.md
new file mode 100644
index 0000000..1e13b9d
--- /dev/null
+++ b/doc/pts_guide.md
@@ -0,0 +1,43 @@
+# Fluoride Bluetooth Profile Tuning Suite (PTS) Test Mode
+
+This document provides commands to enable PTS test mode for Fluoride stack. We
+need special handling for some test cases as they are not applicable for the
+Fluoride stack.
+
+## PTS Test Mode system property
+
+Profile services in packages/apps/Bluetooth uses system property
+`persist.bluetooth.pts` to check if the PTS test mode is enabled. To enable it:
+
+```sh
+adb shell setprop persist.bluetooth.pts true
+```
+
+To disable it:
+
+```sh
+adb shell setprop persist.bluetooth.pts false
+```
+
+### Current use case
+
+- In `newavrcp`, we send active player update to remote device only in PTS test
+ mode (AVRCP/TG/MPS/BV-05-C AVRCP/TG/MPS/BV-07-C).
+
+## PTS Helpers in stack config
+
+Native stack also requires some special handling, and the config is stored in
+`conf/bt_stack.conf`. To enable a flag, uncomment the corresponding line and
+push the config file to `/etc/bluetooth/` in IUT.
+
+### Current use case
+
+- `PTS_SecurePairOnly` enables secure connections only mode.
+- `PTS_DisableConnUpdates` disables LE Connection updates.
+- `PTS_DisableSDPOnLEPair` disables BR/EDR discovery after LE pairing to avoid
+ cross key derivation errors.
+- `PTS_SmpOptions` sets SMP Pair options (formatted as hex bytes) `auth, io,
+ ikey, rkey, ksize`.
+- `PTS_AvrcpTest` enables AVRCP test mode. The UID is set to 0xffffffffffffffff
+ in `TrackChangedNotificationResponse` (AVRCP/TG/NFY/BV-04-C).
+- `PTS_SmpFailureCase` enables handling for various SMP failure cases.
diff --git a/hci/src/hci_layer.cc b/hci/src/hci_layer.cc
index 5111fc5..f1e0e7a 100644
--- a/hci/src/hci_layer.cc
+++ b/hci/src/hci_layer.cc
@@ -78,7 +78,9 @@
// Abort if there is no response to an HCI command.
static const uint32_t COMMAND_PENDING_TIMEOUT_MS = 2000;
+static const uint32_t COMMAND_PENDING_MUTEX_ACQUIRE_TIMEOUT_MS = 500;
static const uint32_t COMMAND_TIMEOUT_RESTART_MS = 5000;
+static const int HCI_UNKNOWN_COMMAND_TIMED_OUT = 0x00ffffff;
// Our interface
static bool interface_created;
@@ -105,7 +107,7 @@
// Inbound-related
static alarm_t* command_response_timer;
static list_t* commands_pending_response;
-static std::recursive_mutex commands_pending_response_mutex;
+static std::recursive_timed_mutex commands_pending_response_mutex;
static alarm_t* hci_timeout_abort_timer;
// The hand-off point for data going to a higher layer, set by the higher layer
@@ -255,7 +257,8 @@
// Free the timers
{
- std::lock_guard<std::recursive_mutex> lock(commands_pending_response_mutex);
+ std::lock_guard<std::recursive_timed_mutex> lock(
+ commands_pending_response_mutex);
alarm_free(command_response_timer);
command_response_timer = NULL;
alarm_free(startup_timer);
@@ -277,7 +280,8 @@
hci_close();
{
- std::lock_guard<std::recursive_mutex> lock(commands_pending_response_mutex);
+ std::lock_guard<std::recursive_timed_mutex> lock(
+ commands_pending_response_mutex);
list_free(commands_pending_response);
commands_pending_response = NULL;
}
@@ -371,7 +375,8 @@
static void event_finish_startup(UNUSED_ATTR void* context) {
LOG_INFO(LOG_TAG, "%s", __func__);
- std::lock_guard<std::recursive_mutex> lock(commands_pending_response_mutex);
+ std::lock_guard<std::recursive_timed_mutex> lock(
+ commands_pending_response_mutex);
alarm_cancel(startup_timer);
future_ready(startup_future, FUTURE_SUCCESS);
startup_future = NULL;
@@ -380,9 +385,18 @@
static void startup_timer_expired(UNUSED_ATTR void* context) {
LOG_ERROR(LOG_TAG, "%s", __func__);
- std::lock_guard<std::recursive_mutex> lock(commands_pending_response_mutex);
+ std::unique_lock<std::recursive_timed_mutex> lock(
+ commands_pending_response_mutex, std::defer_lock);
+ if (!lock.try_lock_for(std::chrono::milliseconds(
+ COMMAND_PENDING_MUTEX_ACQUIRE_TIMEOUT_MS))) {
+ LOG_ERROR(LOG_TAG, "%s: Cannot obtain the mutex", __func__);
+ // We cannot recover if the startup timer expired and we are deadlock,
+ // hence abort.
+ abort();
+ }
future_ready(startup_future, FUTURE_FAIL);
startup_future = NULL;
+ lock.unlock();
}
// Command/packet transmitting functions
@@ -408,7 +422,8 @@
static void event_command_ready(waiting_command_t* wait_entry) {
{
/// Move it to the list of commands awaiting response
- std::lock_guard<std::recursive_mutex> lock(commands_pending_response_mutex);
+ std::lock_guard<std::recursive_timed_mutex> lock(
+ commands_pending_response_mutex);
wait_entry->timestamp = std::chrono::steady_clock::now();
list_append(commands_pending_response, wait_entry);
}
@@ -475,10 +490,7 @@
abort();
}
-// Print debugging information and quit. Don't dereference original_wait_entry.
-static void command_timed_out(void* original_wait_entry) {
- std::unique_lock<std::recursive_mutex> lock(commands_pending_response_mutex);
-
+static void command_timed_out_log_info(void* original_wait_entry) {
LOG_ERROR(LOG_TAG, "%s: %d commands pending response", __func__,
get_num_waiting_commands());
@@ -508,7 +520,21 @@
LOG_EVENT_INT(BT_HCI_TIMEOUT_TAG_NUM, wait_entry->opcode);
}
- lock.unlock();
+}
+
+// Print debugging information and quit. Don't dereference original_wait_entry.
+static void command_timed_out(void* original_wait_entry) {
+ LOG_ERROR(LOG_TAG, "%s", __func__);
+ std::unique_lock<std::recursive_timed_mutex> lock(
+ commands_pending_response_mutex, std::defer_lock);
+ if (!lock.try_lock_for(std::chrono::milliseconds(
+ COMMAND_PENDING_MUTEX_ACQUIRE_TIMEOUT_MS))) {
+ LOG_ERROR(LOG_TAG, "%s: Cannot obtain the mutex", __func__);
+ LOG_EVENT_INT(BT_HCI_TIMEOUT_TAG_NUM, HCI_UNKNOWN_COMMAND_TIMED_OUT);
+ } else {
+ command_timed_out_log_info(original_wait_entry);
+ lock.unlock();
+ }
// Don't request a firmware dump for multiple hci timeouts
if (hci_timeout_abort_timer != NULL || hci_firmware_log_fd != INVALID_FD) {
@@ -675,7 +701,8 @@
// Misc internal functions
static waiting_command_t* get_waiting_command(command_opcode_t opcode) {
- std::lock_guard<std::recursive_mutex> lock(commands_pending_response_mutex);
+ std::lock_guard<std::recursive_timed_mutex> lock(
+ commands_pending_response_mutex);
for (const list_node_t* node = list_begin(commands_pending_response);
node != list_end(commands_pending_response); node = list_next(node)) {
@@ -693,12 +720,14 @@
}
static int get_num_waiting_commands() {
- std::lock_guard<std::recursive_mutex> lock(commands_pending_response_mutex);
+ std::lock_guard<std::recursive_timed_mutex> lock(
+ commands_pending_response_mutex);
return list_length(commands_pending_response);
}
static void update_command_response_timer(void) {
- std::lock_guard<std::recursive_mutex> lock(commands_pending_response_mutex);
+ std::lock_guard<std::recursive_timed_mutex> lock(
+ commands_pending_response_mutex);
if (command_response_timer == NULL) return;
if (list_is_empty(commands_pending_response)) {
diff --git a/include/hardware/avrcp/avrcp.h b/include/hardware/avrcp/avrcp.h
index dba43fc..577acb9 100644
--- a/include/hardware/avrcp/avrcp.h
+++ b/include/hardware/avrcp/avrcp.h
@@ -72,10 +72,11 @@
class MediaCallbacks {
public:
- virtual void SendMediaUpdate(bool track_changed, bool play_state, bool queue);
+ virtual void SendMediaUpdate(bool track_changed, bool play_state,
+ bool queue) = 0;
virtual void SendFolderUpdate(bool available_players, bool addressed_players,
- bool uids_changed);
- virtual void SendActiveDeviceChanged(const RawAddress& address);
+ bool uids_changed) = 0;
+ virtual void SendActiveDeviceChanged(const RawAddress& address) = 0;
virtual ~MediaCallbacks() = default;
};
diff --git a/include/hardware/bt_rc.h b/include/hardware/bt_rc.h
index 9349eed..382500d 100644
--- a/include/hardware/bt_rc.h
+++ b/include/hardware/bt_rc.h
@@ -613,6 +613,9 @@
uint8_t depth);
typedef void (*btrc_ctrl_set_addressed_player_callback)(
const RawAddress& bd_addr, uint8_t status);
+typedef void (*btrc_ctrl_addressed_player_changed_callback)(
+ const RawAddress& bd_addr, uint16_t id);
+
/** BT-RC Controller callback structure. */
typedef struct {
/** set to sizeof(BtRcCallbacks) */
@@ -635,6 +638,7 @@
btrc_ctrl_change_path_callback change_folder_path_cb;
btrc_ctrl_set_browsed_player_callback set_browsed_player_cb;
btrc_ctrl_set_addressed_player_callback set_addressed_player_cb;
+ btrc_ctrl_addressed_player_changed_callback addressed_player_changed_cb;
} btrc_ctrl_callbacks_t;
/** Represents the standard BT-RC AVRCP Controller interface. */
diff --git a/internal_include/bt_target.h b/internal_include/bt_target.h
index 10a4b11..e2f5203 100644
--- a/internal_include/bt_target.h
+++ b/internal_include/bt_target.h
@@ -353,7 +353,7 @@
/* The number of SCO links. */
#ifndef BTM_MAX_SCO_LINKS
-#define BTM_MAX_SCO_LINKS 3
+#define BTM_MAX_SCO_LINKS 6
#endif
/* The number of security records for peer devices. */
diff --git a/internal_include/stack_config.h b/internal_include/stack_config.h
index 81396ab..d623fa4 100644
--- a/internal_include/stack_config.h
+++ b/internal_include/stack_config.h
@@ -27,6 +27,7 @@
typedef struct {
bool (*get_trace_config_enabled)(void);
+ bool (*get_pts_avrcp_test)(void);
bool (*get_pts_secure_only_mode)(void);
bool (*get_pts_conn_updates_disabled)(void);
bool (*get_pts_crosskey_sdp_disable)(void);
diff --git a/linux_include/log/log.h b/linux_include/log/log.h
new file mode 100644
index 0000000..7149470
--- /dev/null
+++ b/linux_include/log/log.h
@@ -0,0 +1,26 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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.
+ *
+ ******************************************************************************/
+
+/* This file provides empty implementation of android_errorWriteLog, which is
+ * not required on linux. It should be on include path only for linux build. */
+
+#if defined(OS_GENERIC)
+
+inline int android_errorWriteLog(int, const char*) { return 0; };
+
+#endif
diff --git a/main/BUILD.gn b/main/BUILD.gn
index ccbc49f..8152e3b 100644
--- a/main/BUILD.gn
+++ b/main/BUILD.gn
@@ -70,6 +70,7 @@
"//btcore",
"//btif",
"//device",
+ "//embdrv/g722",
"//embdrv/sbc",
"//hci",
"//osi",
diff --git a/main/stack_config.cc b/main/stack_config.cc
index 6b937aa..0e56250 100644
--- a/main/stack_config.cc
+++ b/main/stack_config.cc
@@ -27,6 +27,7 @@
namespace {
const char* TRACE_CONFIG_ENABLED_KEY = "TraceConf";
+const char* PTS_AVRCP_TEST = "PTS_AvrcpTest";
const char* PTS_SECURE_ONLY_MODE = "PTS_SecurePairOnly";
const char* PTS_LE_CONN_UPDATED_DISABLED = "PTS_DisableConnUpdates";
const char* PTS_DISABLE_SDP_LE_PAIR = "PTS_DisableSDPOnLEPair";
@@ -77,6 +78,11 @@
TRACE_CONFIG_ENABLED_KEY, false);
}
+static bool get_pts_avrcp_test(void) {
+ return config_get_bool(*config, CONFIG_DEFAULT_SECTION, PTS_AVRCP_TEST,
+ false);
+}
+
static bool get_pts_secure_only_mode(void) {
return config_get_bool(*config, CONFIG_DEFAULT_SECTION, PTS_SECURE_ONLY_MODE,
false);
@@ -104,12 +110,10 @@
static config_t* get_all(void) { return config.get(); }
-const stack_config_t interface = {get_trace_config_enabled,
- get_pts_secure_only_mode,
- get_pts_conn_updates_disabled,
- get_pts_crosskey_sdp_disable,
- get_pts_smp_options,
- get_pts_smp_failure_case,
- get_all};
+const stack_config_t interface = {
+ get_trace_config_enabled, get_pts_avrcp_test,
+ get_pts_secure_only_mode, get_pts_conn_updates_disabled,
+ get_pts_crosskey_sdp_disable, get_pts_smp_options,
+ get_pts_smp_failure_case, get_all};
const stack_config_t* stack_config_get_interface(void) { return &interface; }
diff --git a/osi/include/metrics.h b/osi/include/metrics.h
index 4f968d2..504a16a 100644
--- a/osi/include/metrics.h
+++ b/osi/include/metrics.h
@@ -105,6 +105,8 @@
int32_t buffer_overruns_total = -1;
float buffer_underruns_average = -1;
int32_t buffer_underruns_count = -1;
+ int64_t codec_index = -1;
+ bool is_a2dp_offload = false;
};
class BluetoothMetricsLogger {
diff --git a/osi/src/metrics.cc b/osi/src/metrics.cc
index 96907c0..73450b9 100644
--- a/osi/src/metrics.cc
+++ b/osi/src/metrics.cc
@@ -29,6 +29,7 @@
#include <base/base64.h>
#include <base/logging.h>
+#include <include/hardware/bt_av.h>
#include "bluetooth/metrics/bluetooth.pb.h"
#include "osi/include/leaky_bonded_queue.h"
@@ -42,6 +43,7 @@
namespace system_bt_osi {
using bluetooth::metrics::BluetoothMetricsProto::A2DPSession;
+using bluetooth::metrics::BluetoothMetricsProto::A2dpSourceCodec;
using bluetooth::metrics::BluetoothMetricsProto::BluetoothLog;
using bluetooth::metrics::BluetoothMetricsProto::BluetoothSession;
using bluetooth::metrics::BluetoothMetricsProto::
@@ -140,6 +142,12 @@
buffer_underruns_count += metrics.buffer_underruns_count;
}
}
+ if (codec_index < 0) {
+ codec_index = metrics.codec_index;
+ }
+ if (!is_a2dp_offload) {
+ is_a2dp_offload = metrics.is_a2dp_offload;
+ }
}
bool A2dpSessionMetrics::operator==(const A2dpSessionMetrics& rhs) const {
@@ -151,7 +159,9 @@
buffer_overruns_max_count == rhs.buffer_overruns_max_count &&
buffer_overruns_total == rhs.buffer_overruns_total &&
buffer_underruns_average == rhs.buffer_underruns_average &&
- buffer_underruns_count == rhs.buffer_underruns_count;
+ buffer_underruns_count == rhs.buffer_underruns_count &&
+ codec_index == rhs.codec_index &&
+ is_a2dp_offload == rhs.is_a2dp_offload;
}
static DeviceInfo_DeviceType get_device_type(device_type_t type) {
@@ -230,6 +240,23 @@
}
}
+static A2dpSourceCodec get_a2dp_source_codec(int64_t codec_index) {
+ switch (codec_index) {
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
+ return A2dpSourceCodec::A2DP_SOURCE_CODEC_SBC;
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
+ return A2dpSourceCodec::A2DP_SOURCE_CODEC_AAC;
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
+ return A2dpSourceCodec::A2DP_SOURCE_CODEC_APTX;
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD:
+ return A2dpSourceCodec::A2DP_SOURCE_CODEC_APTX_HD;
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC:
+ return A2dpSourceCodec::A2DP_SOURCE_CODEC_LDAC;
+ default:
+ return A2dpSourceCodec::A2DP_SOURCE_CODEC_UNKNOWN;
+ }
+}
+
struct BluetoothMetricsLogger::impl {
impl(size_t max_bluetooth_session, size_t max_pair_event,
size_t max_wake_event, size_t max_scan_event)
@@ -356,6 +383,7 @@
get_disconnect_reason_type(disconnect_reason));
pimpl_->bt_session_queue_->Enqueue(pimpl_->bluetooth_session_);
pimpl_->bluetooth_session_ = nullptr;
+ pimpl_->a2dp_session_metrics_ = A2dpSessionMetrics();
{
std::lock_guard<std::recursive_mutex> log_lock(pimpl_->bluetooth_log_lock_);
pimpl_->bluetooth_log_->set_num_bluetooth_session(
@@ -404,6 +432,10 @@
pimpl_->a2dp_session_metrics_.buffer_underruns_average);
a2dp_session->set_buffer_underruns_count(
pimpl_->a2dp_session_metrics_.buffer_underruns_count);
+ a2dp_session->set_source_codec(
+ get_a2dp_source_codec(pimpl_->a2dp_session_metrics_.codec_index));
+ a2dp_session->set_is_a2dp_offload(
+ pimpl_->a2dp_session_metrics_.is_a2dp_offload);
}
void BluetoothMetricsLogger::LogHeadsetProfileRfcConnection(
diff --git a/osi/src/metrics_linux.cc b/osi/src/metrics_linux.cc
index 76c1fde..5065a67 100644
--- a/osi/src/metrics_linux.cc
+++ b/osi/src/metrics_linux.cc
@@ -176,6 +176,11 @@
// TODO(siyuanh): Implement for linux
}
+void BluetoothMetricsLogger::LogHeadsetProfileRfcConnection(
+ tBTA_SERVICE_ID service_id) {
+ // TODO: Implement for linux
+}
+
void BluetoothMetricsLogger::WriteString(std::string* serialized) {
// TODO(siyuanh): Implement for linux
}
diff --git a/osi/test/metrics_test.cc b/osi/test/metrics_test.cc
index 2c9762f..bfb548f 100644
--- a/osi/test/metrics_test.cc
+++ b/osi/test/metrics_test.cc
@@ -25,6 +25,7 @@
#include <gtest/gtest.h>
#include <base/logging.h>
+#include <include/hardware/bt_av.h>
#include "bluetooth/metrics/bluetooth.pb.h"
#include "osi/include/metrics.h"
@@ -35,6 +36,7 @@
namespace testing {
using bluetooth::metrics::BluetoothMetricsProto::A2DPSession;
+using bluetooth::metrics::BluetoothMetricsProto::A2dpSourceCodec;
using bluetooth::metrics::BluetoothMetricsProto::BluetoothLog;
using bluetooth::metrics::BluetoothMetricsProto::BluetoothSession;
using bluetooth::metrics::BluetoothMetricsProto::
@@ -111,7 +113,8 @@
return event;
}
-A2DPSession* MakeA2DPSession(const A2dpSessionMetrics& metrics) {
+A2DPSession* MakeA2DPSession(const A2dpSessionMetrics& metrics,
+ A2dpSourceCodec source_codec) {
A2DPSession* session = new A2DPSession();
session->set_media_timer_min_millis(metrics.media_timer_min_ms);
session->set_media_timer_max_millis(metrics.media_timer_max_ms);
@@ -121,6 +124,8 @@
session->set_buffer_underruns_average(metrics.buffer_underruns_average);
session->set_buffer_underruns_count(metrics.buffer_underruns_count);
session->set_audio_duration_millis(metrics.audio_duration_ms);
+ session->set_source_codec(source_codec);
+ session->set_is_a2dp_offload(metrics.is_a2dp_offload);
return session;
}
@@ -187,6 +192,8 @@
FloatNear((b).buffer_underruns_average, 0.01)); \
(a).buffer_underruns_average = (b).buffer_underruns_average; \
EXPECT_EQ((a).buffer_underruns_count, (b).buffer_underruns_count); \
+ EXPECT_EQ((a).codec_index, (b).codec_index); \
+ EXPECT_EQ((a).is_a2dp_offload, (b).is_a2dp_offload); \
} while (0)
/*
@@ -220,6 +227,12 @@
metrics2.buffer_underruns_count = 2400;
metrics_sum.buffer_underruns_average = 113.33333333;
metrics_sum.buffer_underruns_count = 3600;
+ metrics1.codec_index = -1;
+ metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
+ metrics_sum.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
+ metrics1.is_a2dp_offload = false;
+ metrics2.is_a2dp_offload = true;
+ metrics_sum.is_a2dp_offload = true;
metrics1.Update(metrics2);
COMPARE_A2DP_METRICS(metrics1, metrics_sum);
EXPECT_TRUE(metrics1 == metrics_sum);
@@ -246,6 +259,10 @@
metrics2.buffer_underruns_count = 2400;
metrics_sum.buffer_underruns_average = 130;
metrics_sum.buffer_underruns_count = 2400;
+ metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_APTX;
+ metrics_sum.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_APTX;
+ metrics2.is_a2dp_offload = true;
+ metrics_sum.is_a2dp_offload = true;
metrics1.Update(metrics2);
COMPARE_A2DP_METRICS(metrics1, metrics_sum);
EXPECT_TRUE(metrics1 == metrics_sum);
@@ -272,6 +289,10 @@
metrics2.buffer_underruns_count = 2400;
metrics_sum.buffer_underruns_average = 130;
metrics_sum.buffer_underruns_count = 2400;
+ metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD;
+ metrics_sum.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD;
+ metrics2.is_a2dp_offload = true;
+ metrics_sum.is_a2dp_offload = true;
metrics2.Update(metrics1);
COMPARE_A2DP_METRICS(metrics2, metrics_sum);
EXPECT_TRUE(metrics2 == metrics_sum);
@@ -560,10 +581,17 @@
metrics2.buffer_underruns_count = 2400;
metrics_sum.buffer_underruns_average = 113.33333333;
metrics_sum.buffer_underruns_count = 3600;
+ metrics1.codec_index = -1;
+ metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
+ metrics_sum.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
+ metrics1.is_a2dp_offload = false;
+ metrics2.is_a2dp_offload = true;
+ metrics_sum.is_a2dp_offload = true;
DeviceInfo* info = MakeDeviceInfo(
BTM_COD_MAJOR_AUDIO_TEST,
DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
- A2DPSession* session = MakeA2DPSession(metrics_sum);
+ A2DPSession* session =
+ MakeA2DPSession(metrics_sum, A2dpSourceCodec::A2DP_SOURCE_CODEC_AAC);
bt_sessions_.push_back(MakeBluetoothSession(
10,
BluetoothSession_ConnectionTechnologyType::
@@ -618,10 +646,13 @@
metrics1.buffer_underruns_count = 1200;
metrics2.buffer_underruns_average = 130;
metrics2.buffer_underruns_count = 2400;
+ metrics1.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_SBC;
+ metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
DeviceInfo* info = MakeDeviceInfo(
BTM_COD_MAJOR_AUDIO_TEST,
DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
- A2DPSession* session = MakeA2DPSession(metrics1);
+ A2DPSession* session =
+ MakeA2DPSession(metrics1, A2dpSourceCodec::A2DP_SOURCE_CODEC_SBC);
bt_sessions_.push_back(MakeBluetoothSession(
1,
BluetoothSession_ConnectionTechnologyType::
@@ -643,7 +674,7 @@
info = MakeDeviceInfo(
BTM_COD_MAJOR_AUDIO_TEST,
DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
- session = MakeA2DPSession(metrics2);
+ session = MakeA2DPSession(metrics2, A2dpSourceCodec::A2DP_SOURCE_CODEC_AAC);
bt_sessions_.push_back(MakeBluetoothSession(
1,
BluetoothSession_ConnectionTechnologyType::
@@ -662,6 +693,86 @@
}
/*
+ * Test Case: A2DPSessionTwoUpdatesSeparatedbyEndTest
+ *
+ * 1. Create Instance
+ * 2. LogBluetoothSessionStart
+ * 3. LogA2dpSession
+ * 4. LogBluetoothSessionEnd
+ * 5. LogBluetoothSessionStart
+ * 6. LogA2dpSession
+ * 7. LogBluetoothSessionEnd
+ * 8. WriteString
+ *
+ */
+TEST_F(BluetoothMetricsLoggerTest, A2DPSessionTwoUpdatesSeparatedbyEndTest) {
+ /* Same metrics from BluetoothA2DPSessionMetricsTest.TestUpdateNormal */
+ A2dpSessionMetrics metrics1;
+ metrics1.audio_duration_ms = 10;
+ metrics1.media_timer_min_ms = 10;
+ metrics1.media_timer_max_ms = 100;
+ metrics1.media_timer_avg_ms = 50;
+ metrics1.total_scheduling_count = 50;
+ metrics1.buffer_overruns_max_count = 70;
+ metrics1.buffer_underruns_average = 80;
+ metrics1.buffer_underruns_count = 1200;
+ metrics1.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_SBC;
+ DeviceInfo* info = MakeDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST,
+ DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
+ A2DPSession* session =
+ MakeA2DPSession(metrics1, A2dpSourceCodec::A2DP_SOURCE_CODEC_SBC);
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 1,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
+ BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_UNKNOWN,
+ info, nullptr, session));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST, system_bt_osi::DEVICE_TYPE_BREDR);
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics1);
+ sleep_ms(1000);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
+ system_bt_osi::DISCONNECT_REASON_UNKNOWN, 0);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+ ClearLog();
+ A2dpSessionMetrics metrics2;
+ metrics2.audio_duration_ms = 25;
+ metrics2.media_timer_min_ms = 25;
+ metrics2.media_timer_max_ms = 200;
+ metrics2.media_timer_avg_ms = 100;
+ metrics2.total_scheduling_count = 50;
+ metrics2.buffer_overruns_max_count = 80;
+ metrics2.buffer_underruns_average = 130;
+ metrics2.buffer_underruns_count = 2400;
+ metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
+ session = MakeA2DPSession(metrics2, A2dpSourceCodec::A2DP_SOURCE_CODEC_AAC);
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 1,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
+ BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_UNKNOWN,
+ nullptr, nullptr, session));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
+ sleep_ms(1000);
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics2);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
+ system_bt_osi::DISCONNECT_REASON_UNKNOWN, 0);
+ msg_str.clear();
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+/*
* Test Case 1: A2DPSessionOnlyTest
*
* 1. Create Instance
@@ -700,10 +811,14 @@
metrics2.buffer_underruns_count = 2400;
metrics_sum.buffer_underruns_average = 113.33333333;
metrics_sum.buffer_underruns_count = 3600;
+ metrics1.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_SBC;
+ metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
+ metrics_sum.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_SBC;
DeviceInfo* info = MakeDeviceInfo(
BTM_COD_MAJOR_AUDIO_TEST,
DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
- A2DPSession* session = MakeA2DPSession(metrics_sum);
+ A2DPSession* session =
+ MakeA2DPSession(metrics_sum, A2dpSourceCodec::A2DP_SOURCE_CODEC_SBC);
bt_sessions_.push_back(MakeBluetoothSession(
1,
BluetoothSession_ConnectionTechnologyType::
@@ -762,6 +877,9 @@
metrics2.buffer_underruns_count = 2400;
metrics_sum.buffer_underruns_average = 113.33333333;
metrics_sum.buffer_underruns_count = 3600;
+ metrics1.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_SBC;
+ metrics2.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
+ metrics_sum.codec_index = BTAV_A2DP_CODEC_INDEX_SOURCE_SBC;
DeviceInfo* info = MakeDeviceInfo(
BTM_COD_MAJOR_AUDIO_TEST,
DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
@@ -785,7 +903,8 @@
info = MakeDeviceInfo(
BTM_COD_MAJOR_AUDIO_TEST,
DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
- A2DPSession* session = MakeA2DPSession(metrics_sum);
+ A2DPSession* session =
+ MakeA2DPSession(metrics_sum, A2dpSourceCodec::A2DP_SOURCE_CODEC_SBC);
bt_sessions_.push_back(MakeBluetoothSession(
1,
BluetoothSession_ConnectionTechnologyType::
diff --git a/packet/tests/avrcp/avrcp_test_packets.h b/packet/tests/avrcp/avrcp_test_packets.h
index e7e820b..13994d0 100644
--- a/packet/tests/avrcp/avrcp_test_packets.h
+++ b/packet/tests/avrcp/avrcp_test_packets.h
@@ -105,6 +105,10 @@
0x03, 0x48, 0x00, 0x00, 0x19, 0x58, 0x31, 0x00,
0x00, 0x05, 0x0d, 0x00, 0x00, 0x00, 0x00};
+// AVRCP Register Notification without any parameter
+std::vector<uint8_t> register_notification_invalid = {
+ 0x03, 0x48, 0x00, 0x00, 0x19, 0x58, 0x31, 0x00, 0x00, 0x05};
+
// AVRCP Interim Playback Status Notification
std::vector<uint8_t> interim_play_status_notification = {
0x0f, 0x48, 0x00, 0x00, 0x19, 0x58, 0x31, 0x00, 0x00, 0x02, 0x01, 0x00};
@@ -297,8 +301,12 @@
0x72, 0x74, 0x69, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x00, 0x6a, 0x00,
0x0a, 0x54, 0x65, 0x73, 0x74, 0x20, 0x41, 0x6c, 0x62, 0x75, 0x6d};
-// AVRCP Set Addressed Player Request with player_id = 1
+// AVRCP Set Addressed Player Request with player_id = 0
std::vector<uint8_t> set_addressed_player_request = {
+ 0x00, 0x48, 0x00, 0x00, 0x19, 0x58, 0x60, 0x00, 0x00, 0x02, 0x00, 0x00};
+
+// AVRCP Set Addressed Player Request with player_id = 1
+std::vector<uint8_t> set_addressed_player_id_1_request = {
0x00, 0x48, 0x00, 0x00, 0x19, 0x58, 0x60, 0x00, 0x00, 0x02, 0x00, 0x01};
// AVRCP Set Addressed Player Response with status success
diff --git a/packet/tests/avrcp/set_addressed_player_packet_test.cc b/packet/tests/avrcp/set_addressed_player_packet_test.cc
index 24d674a..a6ced9e 100644
--- a/packet/tests/avrcp/set_addressed_player_packet_test.cc
+++ b/packet/tests/avrcp/set_addressed_player_packet_test.cc
@@ -39,7 +39,7 @@
auto test_packet =
TestSetAddrPlayerPacket::Make(set_addressed_player_request);
- ASSERT_EQ(test_packet->GetPlayerId(), 0x0001u);
+ ASSERT_EQ(test_packet->GetPlayerId(), 0x0000u);
}
TEST(SetAddressedPlayerRequestTest, validTest) {
@@ -60,4 +60,4 @@
}
} // namespace avrcp
-} // namespace bluetooth
\ No newline at end of file
+} // namespace bluetooth
diff --git a/profile/avrcp/Android.bp b/profile/avrcp/Android.bp
index b10a56d..1e27861 100644
--- a/profile/avrcp/Android.bp
+++ b/profile/avrcp/Android.bp
@@ -4,6 +4,7 @@
host_supported: true,
include_dirs: [
"system/bt",
+ "system/bt/btcore/include",
"system/bt/internal_include",
"system/bt/stack/include",
],
@@ -25,6 +26,7 @@
host_supported: true,
include_dirs: [
"system/bt",
+ "system/bt/btcore/include",
"system/bt/internal_include",
"system/bt/stack/include",
],
diff --git a/profile/avrcp/BUILD.gn b/profile/avrcp/BUILD.gn
index 9144bb8..c37e0a7 100644
--- a/profile/avrcp/BUILD.gn
+++ b/profile/avrcp/BUILD.gn
@@ -22,6 +22,7 @@
include_dirs = [
"//",
+ "//btcore/include",
"//internal_include",
"//stack/include",
"//profile/avrcp",
diff --git a/profile/avrcp/avrcp_message_converter.h b/profile/avrcp/avrcp_message_converter.h
index 495009c..8de704b 100644
--- a/profile/avrcp/avrcp_message_converter.h
+++ b/profile/avrcp/avrcp_message_converter.h
@@ -41,7 +41,7 @@
const std::vector<uint8_t>& GetData() { return *data_; };
- virtual std::string ToString() const {
+ virtual std::string ToString() const override {
std::stringstream ss;
ss << "VectorPacket:" << std::endl;
ss << " â”” Payload =";
diff --git a/profile/avrcp/device.cc b/profile/avrcp/device.cc
index 2b2172d..8efadc8 100644
--- a/profile/avrcp/device.cc
+++ b/profile/avrcp/device.cc
@@ -18,6 +18,7 @@
#include "connection_handler.h"
#include "device.h"
+#include "stack_config.h"
#include "packet/avrcp/avrcp_reject_packet.h"
#include "packet/avrcp/general_reject_packet.h"
@@ -132,9 +133,9 @@
// this currently since the current implementation only has one
// player and the player will never change, but we need it for a
// more complete implementation.
- auto response =
- SetAddressedPlayerResponseBuilder::MakeBuilder(Status::NO_ERROR);
- send_message(label, false, std::move(response));
+ media_interface_->GetMediaPlayerList(base::Bind(
+ &Device::HandleSetAddressedPlayer, weak_ptr_factory_.GetWeakPtr(),
+ label, Packet::Specialize<SetAddressedPlayerRequest>(pkt)));
} break;
default: {
@@ -188,6 +189,14 @@
void Device::HandleNotification(
uint8_t label, const std::shared_ptr<RegisterNotificationRequest>& pkt) {
+ if (!pkt->IsValid()) {
+ DEVICE_LOG(ERROR) << __func__ << ": Request packet is not valid";
+ auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(),
+ Status::INVALID_PARAMETER);
+ send_message(label, false, std::move(response));
+ return;
+ }
+
DEVICE_VLOG(4) << __func__ << ": event=" << pkt->GetEventRegistered();
switch (pkt->GetEventRegistered()) {
@@ -233,7 +242,7 @@
addr_player_changed_ = Notification(true, label);
media_interface_->GetMediaPlayerList(
base::Bind(&Device::AddressedPlayerNotificationResponse,
- weak_ptr_factory_.GetWeakPtr(), label, false));
+ weak_ptr_factory_.GetWeakPtr(), label, true));
} break;
case Event::UIDS_CHANGED: {
@@ -366,6 +375,15 @@
}
}
+ if (curr_song_id == "") {
+ DEVICE_LOG(WARNING) << "Empty media ID";
+ uid = 0;
+ if (stack_config_get_interface()->get_pts_avrcp_test()) {
+ DEVICE_LOG(WARNING) << __func__ << ": pts test mode";
+ uid = 0xffffffffffffffff;
+ }
+ }
+
auto response = RegisterNotificationResponseBuilder::MakeTrackChangedBuilder(
interim, uid);
send_message_cb_.Run(label, false, std::move(response));
@@ -462,12 +480,28 @@
auto response =
RegisterNotificationResponseBuilder::MakeAddressedPlayerBuilder(
- true, curr_player, 0x0000);
+ interim, curr_player, 0x0000);
send_message_cb_.Run(label, false, std::move(response));
if (!interim) {
active_labels_.erase(label);
addr_player_changed_ = Notification(false, 0);
+ RejectNotification();
+ }
+}
+
+void Device::RejectNotification() {
+ DEVICE_VLOG(1) << __func__;
+ Notification* rejectNotification[] = {&play_status_changed_, &track_changed_,
+ &play_pos_changed_,
+ &now_playing_changed_};
+ for (int i = 0; i < 4; i++) {
+ uint8_t label = rejectNotification[i]->second;
+ auto response = RejectBuilder::MakeBuilder(
+ CommandPdu::REGISTER_NOTIFICATION, Status::ADDRESSED_PLAYER_CHANGED);
+ send_message_cb_.Run(label, false, std::move(response));
+ active_labels_.erase(label);
+ rejectNotification[i] = new Notification(false, 0);
}
}
@@ -586,8 +620,8 @@
if (media_id == "") {
DEVICE_VLOG(2) << "Could not find item";
- auto response =
- PlayItemResponseBuilder::MakeBuilder(Status::DOES_NOT_EXIST);
+ auto response = RejectBuilder::MakeBuilder(CommandPdu::PLAY_ITEM,
+ Status::DOES_NOT_EXIST);
send_message(label, false, std::move(response));
return;
}
@@ -599,6 +633,24 @@
send_message(label, false, std::move(response));
}
+void Device::HandleSetAddressedPlayer(
+ uint8_t label, std::shared_ptr<SetAddressedPlayerRequest> pkt,
+ uint16_t curr_player, std::vector<MediaPlayerInfo> players) {
+ DEVICE_VLOG(2) << __func__ << ": PlayerId=" << pkt->GetPlayerId();
+
+ if (curr_player != pkt->GetPlayerId()) {
+ DEVICE_VLOG(2) << "Reject invalid addressed player ID";
+ auto response = RejectBuilder::MakeBuilder(CommandPdu::SET_ADDRESSED_PLAYER,
+ Status::INVALID_PLAYER_ID);
+ send_message(label, false, std::move(response));
+ return;
+ }
+
+ auto response =
+ SetAddressedPlayerResponseBuilder::MakeBuilder(Status::NO_ERROR);
+ send_message(label, false, std::move(response));
+}
+
void Device::BrowseMessageReceived(uint8_t label,
std::shared_ptr<BrowsePacket> pkt) {
DEVICE_VLOG(1) << __func__ << ": pdu=" << pkt->GetPdu();
@@ -1091,16 +1143,12 @@
DEVICE_VLOG(4) << __func__;
if (available_players) {
- // TODO (apanicke): Right now this isn't needed since we only show one
- // player. Implement this in the future for a more complete
- // implementation though.
+ HandleAvailablePlayerUpdate();
}
if (addressed_player) {
- // TODO (apanicke): See above TODO.
+ HandleAddressedPlayerUpdate();
}
-
- CHECK(false) << "NEED TO IMPLEMENT";
}
void Device::HandleTrackUpdate() {
@@ -1175,6 +1223,37 @@
play_pos_changed_.second, false));
}
+void Device::HandleAvailablePlayerUpdate() {
+ DEVICE_VLOG(1) << __func__;
+
+ if (!avail_players_changed_.first) {
+ LOG(WARNING) << "Device is not registered for available player updates";
+ return;
+ }
+
+ auto response =
+ RegisterNotificationResponseBuilder::MakeAvailablePlayersBuilder(false);
+ send_message_cb_.Run(avail_players_changed_.second, false,
+ std::move(response));
+
+ if (!avail_players_changed_.first) {
+ active_labels_.erase(avail_players_changed_.second);
+ avail_players_changed_ = Notification(false, 0);
+ }
+}
+
+void Device::HandleAddressedPlayerUpdate() {
+ DEVICE_VLOG(1) << __func__;
+ if (!addr_player_changed_.first) {
+ DEVICE_LOG(WARNING)
+ << "Device is not registered for addressed player updates";
+ return;
+ }
+ media_interface_->GetMediaPlayerList(base::Bind(
+ &Device::AddressedPlayerNotificationResponse,
+ weak_ptr_factory_.GetWeakPtr(), addr_player_changed_.second, false));
+}
+
void Device::DeviceDisconnected() {
DEVICE_LOG(INFO) << "Device was disconnected";
play_pos_update_cb_.Cancel();
diff --git a/profile/avrcp/device.h b/profile/avrcp/device.h
index 6280905..1be19c0 100644
--- a/profile/avrcp/device.h
+++ b/profile/avrcp/device.h
@@ -35,6 +35,7 @@
#include "packet/avrcp/get_total_number_of_items.h"
#include "packet/avrcp/play_item.h"
#include "packet/avrcp/register_notification_packet.h"
+#include "packet/avrcp/set_addressed_player.h"
#include "packet/avrcp/set_browsed_player.h"
#include "packet/avrcp/vendor_packet.h"
#include "profile/avrcp/media_id_map.h"
@@ -160,7 +161,12 @@
uint8_t label, std::shared_ptr<GetElementAttributesRequest> pkt,
SongInfo info);
+ // AVAILABLE PLAYER CHANGED
+ virtual void HandleAvailablePlayerUpdate();
+
// ADDRESSED PLAYER CHANGED
+ virtual void HandleAddressedPlayerUpdate();
+ virtual void RejectNotification();
virtual void AddressedPlayerNotificationResponse(
uint8_t label, bool interim, uint16_t curr_player,
std::vector<MediaPlayerInfo> /* unused */);
@@ -216,6 +222,11 @@
virtual void HandlePlayItem(uint8_t label,
std::shared_ptr<PlayItemRequest> request);
+ // SET ADDRESSED PLAYER
+ virtual void HandleSetAddressedPlayer(
+ uint8_t label, std::shared_ptr<SetAddressedPlayerRequest> request,
+ uint16_t curr_player, std::vector<MediaPlayerInfo> players);
+
/********************
* MESSAGE REQUESTS
********************/
diff --git a/profile/avrcp/tests/avrcp_device_test.cc b/profile/avrcp/tests/avrcp_device_test.cc
index 63bd208..56f03e4 100644
--- a/profile/avrcp/tests/avrcp_device_test.cc
+++ b/profile/avrcp/tests/avrcp_device_test.cc
@@ -26,6 +26,7 @@
#include "avrcp_packet.h"
#include "avrcp_test_helper.h"
#include "device.h"
+#include "stack_config.h"
#include "tests/avrcp/avrcp_test_packets.h"
#include "tests/packet_test_helper.h"
@@ -45,6 +46,12 @@
using ::testing::NiceMock;
using ::testing::Return;
+bool get_pts_avrcp_test(void) { return false; }
+
+const stack_config_t interface = {
+ nullptr, get_pts_avrcp_test, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr};
+
// TODO (apanicke): All the tests below are just basic positive unit tests.
// Add more tests to increase code coverage.
class AvrcpDeviceTest : public ::testing::Test {
@@ -706,6 +713,23 @@
test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+ MediaPlayerInfo info = {0, "Test Player", true};
+ std::vector<MediaPlayerInfo> list = {info};
+
+ EXPECT_CALL(interface, GetMediaPlayerList(_))
+ .WillRepeatedly(InvokeCb<0>(0, list));
+
+ auto set_addr_player_rej_rsp = RejectBuilder::MakeBuilder(
+ CommandPdu::SET_ADDRESSED_PLAYER, Status::INVALID_PLAYER_ID);
+
+ EXPECT_CALL(response_cb,
+ Call(1, false, matchPacket(std::move(set_addr_player_rej_rsp))))
+ .Times(1);
+
+ auto player_id_1_request =
+ TestAvrcpPacket::Make(set_addressed_player_id_1_request);
+ SendMessage(1, player_id_1_request);
+
auto set_addr_player_rsp =
SetAddressedPlayerResponseBuilder::MakeBuilder(Status::NO_ERROR);
@@ -1024,5 +1048,25 @@
SendBrowseMessage(1, request);
}
+TEST_F(AvrcpDeviceTest, invalidRegisterNotificationTest) {
+ MockMediaInterface interface;
+ NiceMock<MockA2dpInterface> a2dp_interface;
+
+ test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+ auto reg_notif_rej_rsp = RejectBuilder::MakeBuilder(
+ CommandPdu::REGISTER_NOTIFICATION, Status::INVALID_PARAMETER);
+ EXPECT_CALL(response_cb,
+ Call(1, false, matchPacket(std::move(reg_notif_rej_rsp))))
+ .Times(1);
+
+ auto reg_notif_request = TestAvrcpPacket::Make(register_notification_invalid);
+ SendMessage(1, reg_notif_request);
+}
+
} // namespace avrcp
} // namespace bluetooth
+
+const stack_config_t* stack_config_get_interface(void) {
+ return &bluetooth::avrcp::interface;
+}
diff --git a/proto/bluetooth/metrics/bluetooth.proto b/proto/bluetooth/metrics/bluetooth.proto
index 67efac5..b1e28c3 100644
--- a/proto/bluetooth/metrics/bluetooth.proto
+++ b/proto/bluetooth/metrics/bluetooth.proto
@@ -133,6 +133,15 @@
optional int32 tx_bytes = 2;
}
+enum A2dpSourceCodec {
+ A2DP_SOURCE_CODEC_UNKNOWN = 0;
+ A2DP_SOURCE_CODEC_SBC = 1;
+ A2DP_SOURCE_CODEC_AAC = 2;
+ A2DP_SOURCE_CODEC_APTX = 3;
+ A2DP_SOURCE_CODEC_APTX_HD = 4;
+ A2DP_SOURCE_CODEC_LDAC = 5;
+}
+
// Session information that gets logged for A2DP session.
message A2DPSession {
// Media timer in milliseconds.
@@ -158,6 +167,12 @@
// Total audio time in this A2DP session
optional int64 audio_duration_millis = 8;
+
+ // Audio codec used in this A2DP session in A2DP source role
+ optional A2dpSourceCodec source_codec = 9;
+
+ // Whether A2DP offload is enabled in this A2DP session
+ optional bool is_a2dp_offload = 10;
}
message PairEvent {
diff --git a/stack/Android.bp b/stack/Android.bp
index 76cb172..0c7897c 100644
--- a/stack/Android.bp
+++ b/stack/Android.bp
@@ -1,3 +1,9 @@
+crypto_toolbox_srcs = [
+ "crypto_toolbox/aes.cc",
+ "crypto_toolbox/aes_cmac.cc",
+ "crypto_toolbox/crypto_toolbox.cc",
+]
+
// Bluetooth stack static library for target
// ========================================================
cc_library_static {
@@ -40,7 +46,7 @@
"system/bt/bta/sys",
"system/bt/utils/include",
],
- srcs: [
+ srcs: crypto_toolbox_srcs + [
"a2dp/a2dp_aac.cc",
"a2dp/a2dp_aac_decoder.cc",
"a2dp/a2dp_aac_encoder.cc",
@@ -155,14 +161,12 @@
"sdp/sdp_main.cc",
"sdp/sdp_server.cc",
"sdp/sdp_utils.cc",
- "smp/aes.cc",
"smp/p_256_curvepara.cc",
"smp/p_256_ecc_pp.cc",
"smp/p_256_multprecision.cc",
"smp/smp_act.cc",
"smp/smp_api.cc",
"smp/smp_br_main.cc",
- "smp/smp_cmac.cc",
"smp/smp_keys.cc",
"smp/smp_l2c.cc",
"smp/smp_main.cc",
@@ -182,7 +186,7 @@
required: [
"libldacBT_enc",
"libldacBT_abr",
- ]
+ ],
}
// Bluetooth stack unit tests for target
@@ -224,53 +228,53 @@
}
cc_test {
- name: "net_test_stack_rfcomm",
- defaults: ["fluoride_defaults"],
- host_supported: true,
- local_include_dirs: [
- "include",
- "btm",
- "l2cap",
- "smp",
- "rfcomm",
- "test/common",
- ],
- include_dirs: [
- "system/bt",
- "system/bt/internal_include",
- "system/bt/btcore/include",
- "system/bt/hci/include",
- "system/bt/utils/include",
- ],
- srcs: [
- "rfcomm/port_api.cc",
- "rfcomm/port_rfc.cc",
- "rfcomm/port_utils.cc",
- "rfcomm/rfc_l2cap_if.cc",
- "rfcomm/rfc_mx_fsm.cc",
- "rfcomm/rfc_port_fsm.cc",
- "rfcomm/rfc_port_if.cc",
- "rfcomm/rfc_ts_frames.cc",
- "rfcomm/rfc_utils.cc",
- "test/common/mock_btm_layer.cc",
- "test/common/mock_btu_layer.cc",
- "test/common/mock_l2cap_layer.cc",
- "test/common/stack_test_packet_utils.cc",
- "test/rfcomm/stack_rfcomm_test.cc",
- "test/rfcomm/stack_rfcomm_test_main.cc",
- "test/rfcomm/stack_rfcomm_test_utils.cc",
- "test/rfcomm/stack_rfcomm_test_utils_test.cc",
- ],
- shared_libs: [
- "libcutils",
- "libprotobuf-cpp-lite",
- ],
- static_libs: [
- "liblog",
- "libgmock",
- "libosi",
- "libbt-protos-lite",
- ],
+ name: "net_test_stack_rfcomm",
+ defaults: ["fluoride_defaults"],
+ host_supported: true,
+ local_include_dirs: [
+ "include",
+ "btm",
+ "l2cap",
+ "smp",
+ "rfcomm",
+ "test/common",
+ ],
+ include_dirs: [
+ "system/bt",
+ "system/bt/internal_include",
+ "system/bt/btcore/include",
+ "system/bt/hci/include",
+ "system/bt/utils/include",
+ ],
+ srcs: [
+ "rfcomm/port_api.cc",
+ "rfcomm/port_rfc.cc",
+ "rfcomm/port_utils.cc",
+ "rfcomm/rfc_l2cap_if.cc",
+ "rfcomm/rfc_mx_fsm.cc",
+ "rfcomm/rfc_port_fsm.cc",
+ "rfcomm/rfc_port_if.cc",
+ "rfcomm/rfc_ts_frames.cc",
+ "rfcomm/rfc_utils.cc",
+ "test/common/mock_btm_layer.cc",
+ "test/common/mock_btu_layer.cc",
+ "test/common/mock_l2cap_layer.cc",
+ "test/common/stack_test_packet_utils.cc",
+ "test/rfcomm/stack_rfcomm_test.cc",
+ "test/rfcomm/stack_rfcomm_test_main.cc",
+ "test/rfcomm/stack_rfcomm_test_utils.cc",
+ "test/rfcomm/stack_rfcomm_test_utils_test.cc",
+ ],
+ shared_libs: [
+ "libcutils",
+ "libprotobuf-cpp-lite",
+ ],
+ static_libs: [
+ "liblog",
+ "libgmock",
+ "libosi",
+ "libbt-protos-lite",
+ ],
}
// Bluetooth stack smp unit tests for target
@@ -291,12 +295,15 @@
"system/bt/hci/include",
"system/bt/utils/include",
],
- srcs: [
+ srcs: crypto_toolbox_srcs + [
"smp/smp_keys.cc",
- "smp/aes.cc",
+ "smp/p_256_curvepara.cc",
+ "smp/p_256_ecc_pp.cc",
+ "smp/p_256_multprecision.cc",
"smp/smp_api.cc",
"smp/smp_main.cc",
"smp/smp_utils.cc",
+ "test/crypto_toolbox_test.cc",
"test/stack_smp_test.cc",
],
shared_libs: [
@@ -309,7 +316,6 @@
],
}
-
// Bluetooth stack multi-advertising unit tests for target
// ========================================================
cc_test {
diff --git a/stack/BUILD.gn b/stack/BUILD.gn
index 7920f70..a9926e1 100644
--- a/stack/BUILD.gn
+++ b/stack/BUILD.gn
@@ -14,6 +14,22 @@
# limitations under the License.
#
+static_library("crypto_toolbox") {
+ sources = [
+ "crypto_toolbox/crypto_toolbox.cc",
+ "crypto_toolbox/aes.cc",
+ "crypto_toolbox/aes_cmac.cc",
+ ]
+
+ include_dirs = [
+ "//",
+ ]
+
+ deps = [
+ "//third_party/libchrome:base",
+ ]
+}
+
static_library("stack") {
sources = [
"a2dp/a2dp_aac.cc",
@@ -130,14 +146,12 @@
"sdp/sdp_main.cc",
"sdp/sdp_server.cc",
"sdp/sdp_utils.cc",
- "smp/aes.cc",
"smp/p_256_curvepara.cc",
"smp/p_256_ecc_pp.cc",
"smp/p_256_multprecision.cc",
"smp/smp_act.cc",
"smp/smp_api.cc",
"smp/smp_br_main.cc",
- "smp/smp_cmac.cc",
"smp/smp_keys.cc",
"smp/smp_l2c.cc",
"smp/smp_main.cc",
@@ -180,6 +194,7 @@
]
deps = [
+ ":crypto_toolbox",
"//types",
"//third_party/libchrome:base",
"//third_party/libldac:libldacBT_enc",
@@ -236,6 +251,73 @@
]
}
+executable("net_test_stack_crypto_toolbox") {
+ testonly = true
+ sources = [
+ "test/crypto_toolbox_test.cc",
+ ]
+
+ include_dirs = [
+ "//",
+ ]
+
+ deps = [
+ ":crypto_toolbox",
+ "//third_party/googletest:gmock_main",
+ "//third_party/libchrome:base",
+ ]
+}
+
+executable("net_test_stack_smp") {
+ testonly = true
+ sources = [
+ "smp/smp_keys.cc",
+ "smp/smp_api.cc",
+ "smp/smp_main.cc",
+ "smp/smp_utils.cc",
+ "test/stack_smp_test.cc",
+ ]
+
+ include_dirs = [
+ "//",
+ "//internal_include",
+ "//btcore/include",
+ "//hci/include",
+ "//utils/include",
+ "//bta/include",
+ "//bta/sys",
+ "//btcore/include",
+ "//embdrv/sbc/encoder/include",
+ "//hci/include",
+ "//internal_include",
+ "//stack/a2dp",
+ "//stack/l2cap",
+ "//stack/btm",
+ "//stack/include",
+ "//third_party/tinyxml2",
+ "//udrv/include",
+ "//utils/include",
+ "//vnd/include"
+ ]
+
+ libs = [
+ "-ldl",
+ "-lpthread",
+ "-lresolv",
+ "-lrt",
+ "-lz",
+ "-latomic",
+ ]
+
+ deps = [
+ ":crypto_toolbox",
+ "//osi",
+ "//types",
+ "//third_party/googletest:gmock_main",
+ "//third_party/libchrome:base",
+ ]
+}
+
executable("net_test_stack_multi_adv") {
testonly = true
sources = [
diff --git a/stack/a2dp/a2dp_codec_config.cc b/stack/a2dp/a2dp_codec_config.cc
index 196b5f8..47856fe 100644
--- a/stack/a2dp/a2dp_codec_config.cc
+++ b/stack/a2dp/a2dp_codec_config.cc
@@ -596,8 +596,10 @@
}
// In offload mode, disable the codecs based on the property
- if (a2dp_offload_status && (offload_codec_support[i] != true))
+ if ((codec_index < BTAV_A2DP_CODEC_INDEX_SOURCE_MAX) &&
+ a2dp_offload_status && (offload_codec_support[i] != true)) {
codec_priority = BTAV_A2DP_CODEC_PRIORITY_DISABLED;
+ }
A2dpCodecConfig* codec_config =
A2dpCodecConfig::createCodec(codec_index, codec_priority);
diff --git a/stack/a2dp/a2dp_vendor_ldac.cc b/stack/a2dp/a2dp_vendor_ldac.cc
index 266db81..f8238b6 100644
--- a/stack/a2dp/a2dp_vendor_ldac.cc
+++ b/stack/a2dp/a2dp_vendor_ldac.cc
@@ -910,6 +910,7 @@
codec_capability_.sample_rate = codec_user_config_.sample_rate;
codec_config_.sample_rate = codec_user_config_.sample_rate;
}
+ break;
case BTAV_A2DP_CODEC_SAMPLE_RATE_16000:
case BTAV_A2DP_CODEC_SAMPLE_RATE_24000:
case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
diff --git a/stack/avrc/avrc_pars_ct.cc b/stack/avrc/avrc_pars_ct.cc
index d48b721..ce8f1f6 100644
--- a/stack/avrc/avrc_pars_ct.cc
+++ b/stack/avrc/avrc_pars_ct.cc
@@ -132,6 +132,9 @@
break;
case AVRC_EVT_ADDR_PLAYER_CHANGE:
+ BE_STREAM_TO_UINT16(p_rsp->param.addr_player.player_id, p_stream);
+ BE_STREAM_TO_UINT16(p_rsp->param.addr_player.uid_counter, p_stream);
+
break;
case AVRC_EVT_UIDS_CHANGE:
diff --git a/stack/btm/btm_acl.cc b/stack/btm/btm_acl.cc
index 11c5a48..ee2530a 100644
--- a/stack/btm/btm_acl.cc
+++ b/stack/btm/btm_acl.cc
@@ -31,6 +31,8 @@
*
*****************************************************************************/
+#define LOG_TAG "btm_acl"
+
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
@@ -48,6 +50,7 @@
#include "hcidefs.h"
#include "hcimsgs.h"
#include "l2c_int.h"
+#include "osi/include/log.h"
#include "osi/include/osi.h"
static void btm_read_remote_features(uint16_t handle);
@@ -540,7 +543,10 @@
tBTM_STATUS status;
tBTM_PM_MODE pwr_mode;
tBTM_PM_PWR_MD settings;
- VLOG(1) << __func__ << " BDA: " << remote_bd_addr;
+
+ LOG_INFO(LOG_TAG, "%s: peer %s new_role=0x%x p_cb=%p p_switch_role_cb=%p",
+ __func__, remote_bd_addr.ToString().c_str(), new_role, p_cb,
+ btm_cb.devcb.p_switch_role_cb);
/* Make sure the local device supports switching */
if (!controller_get_interface()->supports_master_slave_role_switch())
diff --git a/stack/btm/btm_ble.cc b/stack/btm/btm_ble.cc
index 9edfebb..7a9a1e4 100644
--- a/stack/btm/btm_ble.cc
+++ b/stack/btm/btm_ble.cc
@@ -42,11 +42,8 @@
#include "l2c_int.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
-#include "smp_api.h"
+#include "stack/crypto_toolbox/crypto_toolbox.h"
-extern bool aes_cipher_msg_auth_code(BT_OCTET16 key, uint8_t* input,
- uint16_t length, uint16_t tlen,
- uint8_t* p_signature);
extern void gatt_notify_phy_updated(uint8_t status, uint16_t handle,
uint8_t tx_phy, uint8_t rx_phy);
extern void btm_ble_advertiser_notify_terminated_legacy(
@@ -184,8 +181,7 @@
break;
case BTM_BLE_KEY_TYPE_ER:
- memcpy(p_devcb->ble_encryption_key_value, p_key->er,
- sizeof(BT_OCTET16));
+ p_devcb->ble_encryption_key_value = p_key->er;
break;
default:
@@ -195,54 +191,16 @@
}
}
-/*******************************************************************************
- *
- * Function BTM_GetDeviceEncRoot
- *
- * Description This function is called to read the local device encryption
- * root.
- *
- * Returns void
- * the local device ER is copied into ble_encr_key_value
- *
- ******************************************************************************/
-void BTM_GetDeviceEncRoot(BT_OCTET16 ble_encr_key_value) {
- BTM_TRACE_DEBUG("%s", __func__);
- memcpy(ble_encr_key_value, btm_cb.devcb.ble_encryption_key_value,
- BT_OCTET16_LEN);
+/** Returns local device encryption root (ER) */
+const Octet16& BTM_GetDeviceEncRoot() {
+ return btm_cb.devcb.ble_encryption_key_value;
}
-/*******************************************************************************
- *
- * Function BTM_GetDeviceIDRoot
- *
- * Description This function is called to read the local device identity
- * root.
- *
- * Returns void
- * the local device IR is copied into irk
- *
- ******************************************************************************/
-void BTM_GetDeviceIDRoot(BT_OCTET16 irk) {
- BTM_TRACE_DEBUG("BTM_GetDeviceIDRoot ");
+/** Returns local device identity root (IR). */
+const Octet16& BTM_GetDeviceIDRoot() { return btm_cb.devcb.id_keys.irk; }
- memcpy(irk, btm_cb.devcb.id_keys.irk, BT_OCTET16_LEN);
-}
-
-/*******************************************************************************
- *
- * Function BTM_GetDeviceDHK
- *
- * Description This function is called to read the local device DHK.
- *
- * Returns void
- * the local device DHK is copied into dhk
- *
- ******************************************************************************/
-void BTM_GetDeviceDHK(BT_OCTET16 dhk) {
- BTM_TRACE_DEBUG("BTM_GetDeviceDHK");
- memcpy(dhk, btm_cb.devcb.id_keys.dhk, BT_OCTET16_LEN);
-}
+/** Return local device DHK. */
+const Octet16& BTM_GetDeviceDHK() { return btm_cb.devcb.id_keys.dhk; }
/*******************************************************************************
*
@@ -475,8 +433,8 @@
memset(&oob, 0, sizeof(tSMP_SC_OOB_DATA));
oob.peer_oob_data.present = true;
- memcpy(&oob.peer_oob_data.randomizer, p_r, BT_OCTET16_LEN);
- memcpy(&oob.peer_oob_data.commitment, p_c, BT_OCTET16_LEN);
+ memcpy(&oob.peer_oob_data.randomizer, p_r, OCTET16_LEN);
+ memcpy(&oob.peer_oob_data.commitment, p_c, OCTET16_LEN);
oob.peer_oob_data.addr_rcvd_from.type = p_dev_rec->ble.ble_addr_type;
oob.peer_oob_data.addr_rcvd_from.bda = bd_addr;
@@ -795,6 +753,7 @@
tBTM_STATUS BTM_SetBleDataLength(const RawAddress& bd_addr,
uint16_t tx_pdu_length) {
tACL_CONN* p_acl = btm_bda_to_acl(bd_addr, BT_TRANSPORT_LE);
+ uint16_t tx_time = BTM_BLE_DATA_TX_TIME_MAX_LEGACY;
if (p_acl == NULL) {
BTM_TRACE_ERROR("%s: Wrong mode: no LE link exist or LE not supported",
@@ -819,9 +778,10 @@
else if (tx_pdu_length < BTM_BLE_DATA_SIZE_MIN)
tx_pdu_length = BTM_BLE_DATA_SIZE_MIN;
- /* always set the TxTime to be max, as controller does not care for now */
- btsnd_hcic_ble_set_data_length(p_acl->hci_handle, tx_pdu_length,
- BTM_BLE_DATA_TX_TIME_MAX);
+ if (controller_get_interface()->get_bt_version()->hci_version >= HCI_PROTO_VERSION_5_0)
+ tx_time = BTM_BLE_DATA_TX_TIME_MAX;
+
+ btsnd_hcic_ble_set_data_length(p_acl->hci_handle, tx_pdu_length, tx_time);
return BTM_SUCCESS;
}
@@ -1177,7 +1137,7 @@
if (op_code == HCI_BLE_RAND)
params.param_len = BT_OCTET8_LEN;
else
- params.param_len = BT_OCTET16_LEN;
+ params.param_len = OCTET16_LEN;
/* Fetch return info from HCI event message */
memcpy(p_dest, p, params.param_len);
@@ -1278,7 +1238,6 @@
tBTM_LE_KEY_VALUE* p_keys, bool pass_to_application) {
tBTM_SEC_DEV_REC* p_rec;
tBTM_LE_EVT_DATA cb_data;
- uint8_t i;
BTM_TRACE_DEBUG("btm_sec_save_le_key key_type=0x%x pass_to_application=%d",
key_type, pass_to_application);
@@ -1292,7 +1251,7 @@
switch (key_type) {
case BTM_LE_KEY_PENC:
- memcpy(p_rec->ble.keys.pltk, p_keys->penc_key.ltk, BT_OCTET16_LEN);
+ p_rec->ble.keys.pltk = p_keys->penc_key.ltk;
memcpy(p_rec->ble.keys.rand, p_keys->penc_key.rand, BT_OCTET8_LEN);
p_rec->ble.keys.sec_level = p_keys->penc_key.sec_level;
p_rec->ble.keys.ediv = p_keys->penc_key.ediv;
@@ -1309,12 +1268,7 @@
break;
case BTM_LE_KEY_PID:
- for (i = 0; i < BT_OCTET16_LEN; i++) {
- p_rec->ble.keys.irk[i] = p_keys->pid_key.irk[i];
- }
-
- // memcpy( p_rec->ble.keys.irk, p_keys->pid_key, BT_OCTET16_LEN); todo
- // will crash the system
+ p_rec->ble.keys.irk = p_keys->pid_key.irk;
p_rec->ble.static_addr = p_keys->pid_key.static_addr;
p_rec->ble.static_addr_type = p_keys->pid_key.addr_type;
p_rec->ble.key_type |= BTM_LE_KEY_PID;
@@ -1330,7 +1284,7 @@
break;
case BTM_LE_KEY_PCSRK:
- memcpy(p_rec->ble.keys.pcsrk, p_keys->pcsrk_key.csrk, BT_OCTET16_LEN);
+ p_rec->ble.keys.pcsrk = p_keys->pcsrk_key.csrk;
p_rec->ble.keys.srk_sec_level = p_keys->pcsrk_key.sec_level;
p_rec->ble.keys.counter = p_keys->pcsrk_key.counter;
p_rec->ble.key_type |= BTM_LE_KEY_PCSRK;
@@ -1348,7 +1302,7 @@
break;
case BTM_LE_KEY_LENC:
- memcpy(p_rec->ble.keys.lltk, p_keys->lenc_key.ltk, BT_OCTET16_LEN);
+ p_rec->ble.keys.lltk = p_keys->lenc_key.ltk;
p_rec->ble.keys.div = p_keys->lenc_key.div; /* update DIV */
p_rec->ble.keys.sec_level = p_keys->lenc_key.sec_level;
p_rec->ble.keys.key_size = p_keys->lenc_key.key_size;
@@ -1362,7 +1316,7 @@
break;
case BTM_LE_KEY_LCSRK: /* local CSRK has been delivered */
- memcpy(p_rec->ble.keys.lcsrk, p_keys->lcsrk_key.csrk, BT_OCTET16_LEN);
+ p_rec->ble.keys.lcsrk = p_keys->lcsrk_key.csrk;
p_rec->ble.keys.div = p_keys->lcsrk_key.div; /* update DIV */
p_rec->ble.keys.local_csrk_sec_level = p_keys->lcsrk_key.sec_level;
p_rec->ble.keys.local_counter = p_keys->lcsrk_key.counter;
@@ -1601,7 +1555,6 @@
void btm_ble_ltk_request(uint16_t handle, uint8_t rand[8], uint16_t ediv) {
tBTM_CB* p_cb = &btm_cb;
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(handle);
- BT_OCTET8 dummy_stk = {0};
BTM_TRACE_DEBUG("btm_ble_ltk_request");
@@ -1610,23 +1563,17 @@
memcpy(p_cb->enc_rand, rand, BT_OCTET8_LEN);
if (p_dev_rec != NULL) {
- if (!smp_proc_ltk_request(p_dev_rec->bd_addr))
- btm_ble_ltk_request_reply(p_dev_rec->bd_addr, false, dummy_stk);
+ if (!smp_proc_ltk_request(p_dev_rec->bd_addr)) {
+ btm_ble_ltk_request_reply(p_dev_rec->bd_addr, false, Octet16{0});
+ }
}
}
-/*******************************************************************************
- *
- * Function btm_ble_start_encrypt
- *
- * Description This function is called to start LE encryption.
- *
- *
- * Returns BTM_SUCCESS if encryption was started successfully
- *
- ******************************************************************************/
+/** This function is called to start LE encryption.
+ * Returns BTM_SUCCESS if encryption was started successfully
+ */
tBTM_STATUS btm_ble_start_encrypt(const RawAddress& bda, bool use_stk,
- BT_OCTET16 stk) {
+ Octet16* p_stk) {
tBTM_CB* p_cb = &btm_cb;
tBTM_SEC_DEV_REC* p_rec = btm_find_dev(bda);
BT_OCTET8 dummy_rand = {0};
@@ -1646,7 +1593,7 @@
p_cb->enc_handle = p_rec->ble_hci_handle;
if (use_stk) {
- btsnd_hcic_ble_start_enc(p_rec->ble_hci_handle, dummy_rand, 0, stk);
+ btsnd_hcic_ble_start_enc(p_rec->ble_hci_handle, dummy_rand, 0, *p_stk);
} else if (p_rec->ble.key_type & BTM_LE_KEY_PENC) {
btsnd_hcic_ble_start_enc(p_rec->ble_hci_handle, p_rec->ble.keys.rand,
p_rec->ble.keys.ediv, p_rec->ble.keys.pltk);
@@ -1716,7 +1663,7 @@
*
******************************************************************************/
void btm_ble_ltk_request_reply(const RawAddress& bda, bool use_stk,
- BT_OCTET16 stk) {
+ const Octet16& stk) {
tBTM_SEC_DEV_REC* p_rec = btm_find_dev(bda);
tBTM_CB* p_cb = &btm_cb;
@@ -2016,9 +1963,20 @@
*
*****************************************************************************/
void btm_ble_create_ll_conn_complete(uint8_t status) {
- if (status != HCI_SUCCESS) {
- btm_ble_set_conn_st(BLE_CONN_IDLE);
- btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, NULL, status);
+ if (status == HCI_SUCCESS) return;
+
+ btm_ble_set_conn_st(BLE_CONN_IDLE);
+ btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, NULL, status);
+
+ LOG(WARNING) << "LE Create Connection attempt failed, status="
+ << loghex(status);
+
+ if (status == HCI_ERR_COMMAND_DISALLOWED) {
+ /* There is already either direct connect, or whitelist connection
+ * pending, but we don't know which one, or to which state should we
+ * transition now. This can be triggered only in case of rare race
+ * condition. Crash to recover. */
+ LOG(FATAL) << "LE Create Connection - command disallowed";
}
}
/*****************************************************************************
@@ -2166,45 +2124,42 @@
tBTM_SEC_DEV_REC* p_rec = btm_find_dev(bd_addr);
BTM_TRACE_DEBUG("%s", __func__);
- bool ret = false;
if (p_rec == NULL) {
BTM_TRACE_ERROR("%s-data signing can not be done from unknown device",
__func__);
- } else {
- uint8_t* p_mac = (uint8_t*)signature;
- uint8_t* pp;
- uint8_t* p_buf = (uint8_t*)osi_malloc(len + 4);
-
- BTM_TRACE_DEBUG("%s-Start to generate Local CSRK", __func__);
- pp = p_buf;
- /* prepare plain text */
- if (p_text) {
- memcpy(p_buf, p_text, len);
- pp = (p_buf + len);
- }
-
- UINT32_TO_STREAM(pp, p_rec->ble.keys.local_counter);
- UINT32_TO_STREAM(p_mac, p_rec->ble.keys.local_counter);
-
- ret = aes_cipher_msg_auth_code(p_rec->ble.keys.lcsrk, p_buf,
- (uint16_t)(len + 4), BTM_CMAC_TLEN_SIZE,
- p_mac);
- if (ret) {
- btm_ble_increment_sign_ctr(bd_addr, true);
- }
-
- BTM_TRACE_DEBUG("%s p_mac = %d", __func__, p_mac);
- BTM_TRACE_DEBUG(
- "p_mac[0] = 0x%02x p_mac[1] = 0x%02x p_mac[2] = 0x%02x p_mac[3] = "
- "0x%02x",
- *p_mac, *(p_mac + 1), *(p_mac + 2), *(p_mac + 3));
- BTM_TRACE_DEBUG(
- "p_mac[4] = 0x%02x p_mac[5] = 0x%02x p_mac[6] = 0x%02x p_mac[7] = "
- "0x%02x",
- *(p_mac + 4), *(p_mac + 5), *(p_mac + 6), *(p_mac + 7));
- osi_free(p_buf);
+ return false;
}
- return ret;
+
+ uint8_t* p_mac = (uint8_t*)signature;
+ uint8_t* pp;
+ uint8_t* p_buf = (uint8_t*)osi_malloc(len + 4);
+
+ BTM_TRACE_DEBUG("%s-Start to generate Local CSRK", __func__);
+ pp = p_buf;
+ /* prepare plain text */
+ if (p_text) {
+ memcpy(p_buf, p_text, len);
+ pp = (p_buf + len);
+ }
+
+ UINT32_TO_STREAM(pp, p_rec->ble.keys.local_counter);
+ UINT32_TO_STREAM(p_mac, p_rec->ble.keys.local_counter);
+
+ crypto_toolbox::aes_cmac(p_rec->ble.keys.lcsrk, p_buf, (uint16_t)(len + 4),
+ BTM_CMAC_TLEN_SIZE, p_mac);
+ btm_ble_increment_sign_ctr(bd_addr, true);
+
+ BTM_TRACE_DEBUG("%s p_mac = %d", __func__, p_mac);
+ BTM_TRACE_DEBUG(
+ "p_mac[0] = 0x%02x p_mac[1] = 0x%02x p_mac[2] = 0x%02x p_mac[3] = "
+ "0x%02x",
+ *p_mac, *(p_mac + 1), *(p_mac + 2), *(p_mac + 3));
+ BTM_TRACE_DEBUG(
+ "p_mac[4] = 0x%02x p_mac[5] = 0x%02x p_mac[6] = 0x%02x p_mac[7] = "
+ "0x%02x",
+ *(p_mac + 4), *(p_mac + 5), *(p_mac + 6), *(p_mac + 7));
+ osi_free(p_buf);
+ return true;
}
/*******************************************************************************
@@ -2238,12 +2193,11 @@
BTM_TRACE_DEBUG("%s rcv_cnt=%d >= expected_cnt=%d", __func__, counter,
p_rec->ble.keys.counter);
- if (aes_cipher_msg_auth_code(p_rec->ble.keys.pcsrk, p_orig, len,
- BTM_CMAC_TLEN_SIZE, p_mac)) {
- if (memcmp(p_mac, p_comp, BTM_CMAC_TLEN_SIZE) == 0) {
- btm_ble_increment_sign_ctr(bd_addr, false);
- verified = true;
- }
+ crypto_toolbox::aes_cmac(p_rec->ble.keys.pcsrk, p_orig, len,
+ BTM_CMAC_TLEN_SIZE, p_mac);
+ if (memcmp(p_mac, p_comp, BTM_CMAC_TLEN_SIZE) == 0) {
+ btm_ble_increment_sign_ctr(bd_addr, false);
+ verified = true;
}
}
return verified;
@@ -2377,16 +2331,7 @@
/*******************************************************************************
* Utility functions for LE device IR/ER generation
******************************************************************************/
-/*******************************************************************************
- *
- * Function btm_notify_new_key
- *
- * Description This function is to notify application new keys have been
- * generated.
- *
- * Returns void
- *
- ******************************************************************************/
+/** This function is to notify application new keys have been generated. */
static void btm_notify_new_key(uint8_t key_type) {
tBTM_BLE_LOCAL_KEYS* p_local_keys = NULL;
@@ -2414,112 +2359,67 @@
}
}
-/*******************************************************************************
- *
- * Function btm_ble_process_irk
- *
- * Description This function is called when IRK is generated, store it in
- * local control block.
- *
- * Returns void
- *
- ******************************************************************************/
-static void btm_ble_process_irk(tSMP_ENC* p) {
- BTM_TRACE_DEBUG("btm_ble_process_irk");
- if (p && p->opcode == HCI_BLE_ENCRYPT) {
- memcpy(btm_cb.devcb.id_keys.irk, p->param_buf, BT_OCTET16_LEN);
- btm_notify_new_key(BTM_BLE_KEY_TYPE_ID);
+/** implementation of btm_ble_reset_id */
+static void btm_ble_reset_id_impl(const Octet16& rand1, const Octet16& rand2) {
+ /* Regenerate Identity Root */
+ btm_cb.devcb.id_keys.ir = rand1;
+ uint8_t btm_ble_dhk_pt = 0x03;
+
+ /* generate DHK= Eir({0x03, 0x00, 0x00 ...}) */
+ btm_cb.devcb.id_keys.dhk =
+ crypto_toolbox::aes_128(btm_cb.devcb.id_keys.ir, &btm_ble_dhk_pt, 1);
+
+ uint8_t btm_ble_irk_pt = 0x01;
+ /* IRK = D1(IR, 1) */
+ btm_cb.devcb.id_keys.irk =
+ crypto_toolbox::aes_128(btm_cb.devcb.id_keys.ir, &btm_ble_irk_pt, 1);
+
+ btm_notify_new_key(BTM_BLE_KEY_TYPE_ID);
#if (BLE_PRIVACY_SPT == TRUE)
- /* if privacy is enabled, new RPA should be calculated */
- if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE) {
- btm_gen_resolvable_private_addr(base::Bind(&btm_gen_resolve_paddr_low));
- }
-#endif
- } else {
- BTM_TRACE_ERROR("Generating IRK exception.");
+ /* if privacy is enabled, new RPA should be calculated */
+ if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE) {
+ btm_gen_resolvable_private_addr(base::Bind(&btm_gen_resolve_paddr_low));
}
+#endif
/* proceed generate ER */
- btsnd_hcic_ble_rand(base::Bind([](BT_OCTET8 rand1) {
- memcpy(&btm_cb.devcb.ble_encryption_key_value[0], rand1, BT_OCTET8_LEN);
-
- btsnd_hcic_ble_rand(base::Bind([](BT_OCTET8 rand2) {
- memcpy(&btm_cb.devcb.ble_encryption_key_value[8], rand2, BT_OCTET8_LEN);
- btm_notify_new_key(BTM_BLE_KEY_TYPE_ER);
- }));
-
- }));
+ btm_cb.devcb.ble_encryption_key_value = rand2;
+ btm_notify_new_key(BTM_BLE_KEY_TYPE_ER);
}
-/*******************************************************************************
- *
- * Function btm_ble_process_dhk
- *
- * Description This function is called when DHK is calculated, store it in
- * local control block, and proceed to generate ER, a 128-bits
- * random number.
- *
- * Returns void
- *
- ******************************************************************************/
-static void btm_ble_process_dhk(tSMP_ENC* p) {
- uint8_t btm_ble_irk_pt = 0x01;
- tSMP_ENC output;
+struct reset_id_data {
+ Octet16 rand1;
+ Octet16 rand2;
+};
- BTM_TRACE_DEBUG("btm_ble_process_dhk");
-
- if (p && p->opcode == HCI_BLE_ENCRYPT) {
- memcpy(btm_cb.devcb.id_keys.dhk, p->param_buf, BT_OCTET16_LEN);
- BTM_TRACE_DEBUG("BLE DHK generated.");
-
- /* IRK = D1(IR, 1) */
- if (!SMP_Encrypt(btm_cb.devcb.id_keys.ir, BT_OCTET16_LEN, &btm_ble_irk_pt,
- 1, &output)) {
- /* reset all identity root related key */
- memset(&btm_cb.devcb.id_keys, 0, sizeof(tBTM_BLE_LOCAL_ID_KEYS));
- } else {
- btm_ble_process_irk(&output);
- }
- } else {
- /* reset all identity root related key */
- memset(&btm_cb.devcb.id_keys, 0, sizeof(tBTM_BLE_LOCAL_ID_KEYS));
- }
-}
-
-/*******************************************************************************
- *
- * Function btm_ble_reset_id
- *
- * Description This function is called to reset LE device identity.
- *
- * Returns void
- *
- ******************************************************************************/
+/** This function is called to reset LE device identity. */
void btm_ble_reset_id(void) {
BTM_TRACE_DEBUG("btm_ble_reset_id");
- /* Regenerate Identity Root*/
+ /* In order to reset identity, we need four random numbers. Make four nested
+ * calls to generate them first, then proceed to perform the actual reset in
+ * btm_ble_reset_id_impl. */
btsnd_hcic_ble_rand(base::Bind([](BT_OCTET8 rand) {
- BTM_TRACE_DEBUG("btm_ble_process_ir1");
- memcpy(btm_cb.devcb.id_keys.ir, rand, BT_OCTET8_LEN);
-
- btsnd_hcic_ble_rand(base::Bind([](BT_OCTET8 rand) {
- uint8_t btm_ble_dhk_pt = 0x03;
- tSMP_ENC output;
-
- BTM_TRACE_DEBUG("btm_ble_process_ir2");
-
- /* remembering in control block */
- memcpy(&btm_cb.devcb.id_keys.ir[8], rand, BT_OCTET8_LEN);
- /* generate DHK= Eir({0x03, 0x00, 0x00 ...}) */
-
- SMP_Encrypt(btm_cb.devcb.id_keys.ir, BT_OCTET16_LEN, &btm_ble_dhk_pt, 1,
- &output);
- btm_ble_process_dhk(&output);
-
- BTM_TRACE_DEBUG("BLE IR generated.");
- }));
+ reset_id_data tmp;
+ memcpy(tmp.rand1.data(), rand, BT_OCTET8_LEN);
+ btsnd_hcic_ble_rand(base::Bind(
+ [](reset_id_data tmp, BT_OCTET8 rand) {
+ memcpy(tmp.rand1.data() + 8, rand, BT_OCTET8_LEN);
+ btsnd_hcic_ble_rand(base::Bind(
+ [](reset_id_data tmp, BT_OCTET8 rand) {
+ memcpy(tmp.rand2.data(), rand, BT_OCTET8_LEN);
+ btsnd_hcic_ble_rand(base::Bind(
+ [](reset_id_data tmp, BT_OCTET8 rand) {
+ memcpy(tmp.rand2.data() + 8, rand, BT_OCTET8_LEN);
+ // when all random numbers are ready, do the actual reset.
+ btm_ble_reset_id_impl(tmp.rand1, tmp.rand2);
+ },
+ tmp));
+ },
+ tmp));
+ },
+ tmp));
}));
}
diff --git a/stack/btm/btm_ble_addr.cc b/stack/btm/btm_ble_addr.cc
index 2d0acc6..2528915 100644
--- a/stack/btm/btm_ble_addr.cc
+++ b/stack/btm/btm_ble_addr.cc
@@ -33,88 +33,66 @@
#include "hcimsgs.h"
#include "btm_ble_int.h"
-#include "smp_api.h"
+#include "stack/crypto_toolbox/crypto_toolbox.h"
-/*******************************************************************************
- *
- * Function btm_gen_resolve_paddr_cmpl
- *
- * Description This is callback functioin when resolvable private address
- * generation is complete.
- *
- * Returns void
- *
- ******************************************************************************/
-static void btm_gen_resolve_paddr_cmpl(tSMP_ENC* p) {
- tBTM_LE_RANDOM_CB* p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
- BTM_TRACE_EVENT("btm_gen_resolve_paddr_cmpl");
+/* This function generates Resolvable Private Address (RPA) from Identity
+ * Resolving Key |irk| and |random|*/
+RawAddress generate_rpa_from_irk_and_rand(const Octet16& irk,
+ BT_OCTET8 random) {
+ random[2] &= (~BLE_RESOLVE_ADDR_MASK);
+ random[2] |= BLE_RESOLVE_ADDR_MSB;
- if (p) {
- /* set hash to be LSB of rpAddress */
- p_cb->private_addr.address[5] = p->param_buf[0];
- p_cb->private_addr.address[4] = p->param_buf[1];
- p_cb->private_addr.address[3] = p->param_buf[2];
- /* set it to controller */
- btm_ble_set_random_address(p_cb->private_addr);
+ RawAddress address;
+ address.address[2] = random[0];
+ address.address[1] = random[1];
+ address.address[0] = random[2];
- p_cb->own_addr_type = BLE_ADDR_RANDOM;
+ /* encrypt with IRK */
+ Octet16 p = crypto_toolbox::aes_128(irk, random, 3);
- /* start a periodical timer to refresh random addr */
- period_ms_t interval_ms = BTM_BLE_PRIVATE_ADDR_INT_MS;
-#if (BTM_BLE_CONFORMANCE_TESTING == TRUE)
- interval_ms = btm_cb.ble_ctr_cb.rpa_tout * 1000;
-#endif
- alarm_set_on_mloop(p_cb->refresh_raddr_timer, interval_ms,
- btm_ble_refresh_raddr_timer_timeout, NULL);
- } else {
- /* random address set failure */
- BTM_TRACE_DEBUG("set random address failed");
- }
+ /* set hash to be LSB of rpAddress */
+ address.address[5] = p[0];
+ address.address[4] = p[1];
+ address.address[3] = p[2];
+ return address;
}
-/*******************************************************************************
- *
- * Function btm_gen_resolve_paddr_low
- *
- * Description This function is called when random address has generate the
- * random number base for low 3 byte bd address.
- *
- * Returns void
- *
- ******************************************************************************/
-void btm_gen_resolve_paddr_low(BT_OCTET8 rand) {
+
+/** This function is called when random address for local controller was
+ * generated */
+void btm_gen_resolve_paddr_low(const RawAddress& address) {
tBTM_LE_RANDOM_CB* p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
- tSMP_ENC output;
BTM_TRACE_EVENT("btm_gen_resolve_paddr_low");
- rand[2] &= (~BLE_RESOLVE_ADDR_MASK);
- rand[2] |= BLE_RESOLVE_ADDR_MSB;
- p_cb->private_addr.address[2] = rand[0];
- p_cb->private_addr.address[1] = rand[1];
- p_cb->private_addr.address[0] = rand[2];
+ p_cb->private_addr = address;
- /* encrypt with ur IRK */
- if (!SMP_Encrypt(btm_cb.devcb.id_keys.irk, BT_OCTET16_LEN, rand, 3,
- &output)) {
- btm_gen_resolve_paddr_cmpl(NULL);
- } else {
- btm_gen_resolve_paddr_cmpl(&output);
- }
+ /* set it to controller */
+ btm_ble_set_random_address(p_cb->private_addr);
+
+ p_cb->own_addr_type = BLE_ADDR_RANDOM;
+
+ /* start a periodical timer to refresh random addr */
+ period_ms_t interval_ms = BTM_BLE_PRIVATE_ADDR_INT_MS;
+#if (BTM_BLE_CONFORMANCE_TESTING == TRUE)
+ interval_ms = btm_cb.ble_ctr_cb.rpa_tout * 1000;
+#endif
+ alarm_set_on_mloop(p_cb->refresh_raddr_timer, interval_ms,
+ btm_ble_refresh_raddr_timer_timeout, NULL);
}
-/*******************************************************************************
- *
- * Function btm_gen_resolvable_private_addr
- *
- * Description This function generate a resolvable private address.
- *
- * Returns void
- *
- ******************************************************************************/
-void btm_gen_resolvable_private_addr(base::Callback<void(BT_OCTET8)> cb) {
+
+/** This function generate a resolvable private address using local IRK */
+void btm_gen_resolvable_private_addr(
+ base::Callback<void(const RawAddress&)> cb) {
BTM_TRACE_EVENT("%s", __func__);
/* generate 3B rand as BD LSB, SRK with it, get BD MSB */
- btsnd_hcic_ble_rand(std::move(cb));
+ btsnd_hcic_ble_rand(base::Bind(
+ [](base::Callback<void(const RawAddress&)> cb, BT_OCTET8 random) {
+ const Octet16& irk = BTM_GetDeviceIDRoot();
+ cb.Run(generate_rpa_from_irk_and_rand(irk, random));
+ },
+ std::move(cb)));
}
+
/*******************************************************************************
*
* Function btm_gen_non_resolve_paddr_cmpl
@@ -169,33 +147,6 @@
/*******************************************************************************
* Utility functions for Random address resolving
******************************************************************************/
-/*******************************************************************************
- *
- * Function btm_ble_proc_resolve_x
- *
- * Description This function compares the X with random address 3 MSO bytes
- * to find a match.
- *
- * Returns true on match, false otherwise
- *
- ******************************************************************************/
-static bool btm_ble_proc_resolve_x(const tSMP_ENC& encrypt_output,
- const RawAddress& random_bda) {
- BTM_TRACE_EVENT("btm_ble_proc_resolve_x");
-
- /* compare the hash with 3 LSB of bd address */
- uint8_t comp[3];
- comp[0] = random_bda.address[5];
- comp[1] = random_bda.address[4];
- comp[2] = random_bda.address[3];
-
- if (!memcmp(encrypt_output.param_buf, comp, 3)) {
- BTM_TRACE_EVENT("match is found");
- return true;
- }
-
- return false;
-}
/*******************************************************************************
*
@@ -217,71 +168,56 @@
return false;
}
-/*******************************************************************************
- *
- * Function btm_ble_addr_resolvable
- *
- * Description This function checks if a RPA is resolvable by the device
- * key.
- *
- * Returns true is resolvable; false otherwise.
- *
- ******************************************************************************/
+/* Return true if given Resolvable Privae Address |rpa| matches Identity
+ * Resolving Key |irk| */
+static bool rpa_matches_irk(const RawAddress& rpa, const Octet16& irk) {
+ /* use the 3 MSB of bd address as prand */
+ uint8_t rand[3];
+ rand[0] = rpa.address[2];
+ rand[1] = rpa.address[1];
+ rand[2] = rpa.address[0];
+
+ /* generate X = E irk(R0, R1, R2) and R is random address 3 LSO */
+ Octet16 x = crypto_toolbox::aes_128(irk, &rand[0], 3);
+
+ rand[0] = rpa.address[5];
+ rand[1] = rpa.address[4];
+ rand[2] = rpa.address[3];
+
+ if (memcmp(x.data(), &rand[0], 3) == 0) {
+ // match
+ return true;
+ }
+ // not a match
+ return false;
+}
+
+/** This function checks if a RPA is resolvable by the device key.
+ * Returns true is resolvable; false otherwise.
+ */
bool btm_ble_addr_resolvable(const RawAddress& rpa,
tBTM_SEC_DEV_REC* p_dev_rec) {
- bool rt = false;
+ if (!BTM_BLE_IS_RESOLVE_BDA(rpa)) return false;
- if (!BTM_BLE_IS_RESOLVE_BDA(rpa)) return rt;
-
- uint8_t rand[3];
- tSMP_ENC output;
if ((p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) &&
(p_dev_rec->ble.key_type & BTM_LE_KEY_PID)) {
BTM_TRACE_DEBUG("%s try to resolve", __func__);
- /* use the 3 MSB of bd address as prand */
- rand[0] = rpa.address[2];
- rand[1] = rpa.address[1];
- rand[2] = rpa.address[0];
- /* generate X = E irk(R0, R1, R2) and R is random address 3 LSO */
- SMP_Encrypt(p_dev_rec->ble.keys.irk, BT_OCTET16_LEN, &rand[0], 3, &output);
-
- rand[0] = rpa.address[5];
- rand[1] = rpa.address[4];
- rand[2] = rpa.address[3];
-
- if (!memcmp(output.param_buf, &rand[0], 3)) {
+ if (rpa_matches_irk(rpa, p_dev_rec->ble.keys.irk)) {
btm_ble_init_pseudo_addr(p_dev_rec, rpa);
- rt = true;
+ return true;
}
}
- return rt;
+ return false;
}
-/*******************************************************************************
- *
- * Function btm_ble_match_random_bda
- *
- * Description This function match the random address to the appointed
- * device record, starting from calculating IRK. If the record
- * index exceeds the maximum record number, matching failed and
- * send a callback.
- *
- * Returns None.
- *
- ******************************************************************************/
+/** This function match the random address to the appointed device record,
+ * starting from calculating IRK. If the record index exceeds the maximum record
+ * number, matching failed and send a callback. */
static bool btm_ble_match_random_bda(void* data, void* context) {
- RawAddress* random_bda = (RawAddress*)context;
- /* use the 3 MSB of bd address as prand */
-
- uint8_t rand[3];
- rand[0] = random_bda->address[2];
- rand[1] = random_bda->address[1];
- rand[2] = random_bda->address[0];
-
BTM_TRACE_EVENT("%s next iteration", __func__);
+ RawAddress* random_bda = (RawAddress*)context;
- tSMP_ENC output;
tBTM_SEC_DEV_REC* p_dev_rec = static_cast<tBTM_SEC_DEV_REC*>(data);
BTM_TRACE_DEBUG("sec_flags = %02x device_type = %d", p_dev_rec->sec_flags,
@@ -291,22 +227,20 @@
!(p_dev_rec->ble.key_type & BTM_LE_KEY_PID))
return true;
- /* generate X = E irk(R0, R1, R2) and R is random address 3 LSO */
- SMP_Encrypt(p_dev_rec->ble.keys.irk, BT_OCTET16_LEN, &rand[0], 3, &output);
- // if it was match, finish iteration, otherwise continue
- return !btm_ble_proc_resolve_x(output, *random_bda);
+ if (rpa_matches_irk(*random_bda, p_dev_rec->ble.keys.irk)) {
+ BTM_TRACE_EVENT("match is found");
+ // if it was match, finish iteration, otherwise continue
+ return false;
+ }
+
+ // not a match, continue iteration
+ return true;
}
-/*******************************************************************************
- *
- * Function btm_ble_resolve_random_addr
- *
- * Description This function is called to resolve a random address.
- *
- * Returns pointer to the security record of the device whom a random
- * address is matched to.
- *
- ******************************************************************************/
+/** This function is called to resolve a random address.
+ * Returns pointer to the security record of the device whom a random address is
+ * matched to.
+ */
tBTM_SEC_DEV_REC* btm_ble_resolve_random_addr(const RawAddress& random_bda) {
BTM_TRACE_EVENT("%s", __func__);
diff --git a/stack/btm/btm_ble_bgconn.cc b/stack/btm/btm_ble_bgconn.cc
index cb3e053..4c8dcd8 100644
--- a/stack/btm/btm_ble_bgconn.cc
+++ b/stack/btm/btm_ble_bgconn.cc
@@ -23,50 +23,37 @@
******************************************************************************/
#include <base/logging.h>
-#include <string.h>
#include <unordered_map>
#include "bt_types.h"
-#include "bt_utils.h"
#include "btm_int.h"
#include "btu.h"
#include "device/include/controller.h"
#include "hcimsgs.h"
#include "l2c_int.h"
-#include "osi/include/allocator.h"
-#include "osi/include/osi.h"
-
-#ifndef BTM_BLE_SCAN_PARAM_TOUT
-#define BTM_BLE_SCAN_PARAM_TOUT 50 /* 50 seconds */
-#endif
-
-static void btm_suspend_wl_activity(tBTM_BLE_WL_STATE wl_state);
-static void btm_resume_wl_activity(tBTM_BLE_WL_STATE wl_state);
// Unfortunately (for now?) we have to maintain a copy of the device whitelist
// on the host to determine if a device is pending to be connected or not. This
// controls whether the host should keep trying to scan for whitelisted
// peripherals or not.
// TODO: Move all of this to controller/le/background_list or similar?
-typedef struct background_connection_t {
+struct BackgroundConnection {
RawAddress address;
uint8_t addr_type;
-
bool in_controller_wl;
uint8_t addr_type_in_wl;
-
bool pending_removal;
-} background_connection_t;
+};
struct BgConnHash {
- bool operator()(const RawAddress& x) const {
+ std::size_t operator()(const RawAddress& x) const {
const uint8_t* a = x.address;
return a[0] ^ (a[1] << 8) ^ (a[2] << 16) ^ (a[3] << 24) ^ a[4] ^
(a[5] << 8);
}
};
-static std::unordered_map<RawAddress, background_connection_t, BgConnHash>
+static std::unordered_map<RawAddress, BackgroundConnection, BgConnHash>
background_connections;
static void background_connection_add(uint8_t addr_type,
@@ -74,9 +61,9 @@
auto map_iter = background_connections.find(address);
if (map_iter == background_connections.end()) {
background_connections[address] =
- background_connection_t{address, addr_type, false, 0, false};
+ BackgroundConnection{address, addr_type, false, 0, false};
} else {
- background_connection_t* connection = &map_iter->second;
+ BackgroundConnection* connection = &map_iter->second;
connection->addr_type = addr_type;
connection->pending_removal = false;
}
@@ -97,7 +84,7 @@
static bool background_connections_pending() {
for (auto& map_el : background_connections) {
- background_connection_t* connection = &map_el.second;
+ BackgroundConnection* connection = &map_el.second;
if (connection->pending_removal) continue;
const bool connected =
BTM_IsAclConnectionUp(connection->address, BT_TRANSPORT_LE);
@@ -159,7 +146,7 @@
auto map_it = background_connections.find(bd_addr);
if (map_it != background_connections.end()) {
- background_connection_t* connection = &map_it->second;
+ BackgroundConnection* 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);
@@ -229,7 +216,7 @@
// 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;
+ BackgroundConnection* connection = &map_it->second;
if (connection->pending_removal) {
btsnd_hcic_ble_remove_from_white_list(connection->addr_type_in_wl,
connection->address);
@@ -238,7 +225,7 @@
++map_it;
}
for (auto& map_el : background_connections) {
- background_connection_t* connection = &map_el.second;
+ BackgroundConnection* connection = &map_el.second;
const bool connected =
BTM_IsAclConnectionUp(connection->address, BT_TRANSPORT_LE);
if (!connection->in_controller_wl && !connected) {
@@ -276,9 +263,11 @@
return false;
}
- btm_suspend_wl_activity(p_cb->wl_state);
+ if (p_cb->wl_state & BTM_BLE_WL_INIT) {
+ btm_ble_start_auto_conn(false);
+ }
btm_add_dev_to_controller(to_add, bd_addr);
- btm_resume_wl_activity(p_cb->wl_state);
+ btm_ble_resume_bg_conn();
return true;
}
@@ -289,7 +278,7 @@
* Description This function clears the white list.
*
******************************************************************************/
-void btm_ble_clear_white_list(void) {
+void btm_ble_clear_white_list() {
BTM_TRACE_EVENT("btm_ble_clear_white_list");
btsnd_hcic_ble_clear_white_list();
background_connections_clear();
@@ -352,8 +341,10 @@
/* This is a sign that logic around keeping connection state is broken */
LOG(ERROR)
<< "Attempt to cancel LE connection, when no connection is pending.";
- btm_ble_set_conn_st(BLE_CONN_IDLE);
- btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, nullptr, status);
+ if (btm_ble_get_conn_st() == BLE_CONN_CANCEL) {
+ btm_ble_set_conn_st(BLE_CONN_IDLE);
+ btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, nullptr, status);
+ }
}
}
@@ -409,8 +400,12 @@
bool btm_ble_start_auto_conn(bool start) {
tBTM_BLE_CB* p_cb = &btm_cb.ble_ctr_cb;
bool exec = true;
- uint16_t scan_int;
- uint16_t scan_win;
+ uint16_t scan_int = (p_cb->scan_int == BTM_BLE_SCAN_PARAM_UNDEF)
+ ? BTM_BLE_SCAN_SLOW_INT_1
+ : p_cb->scan_int;
+ uint16_t scan_win = (p_cb->scan_win == BTM_BLE_SCAN_PARAM_UNDEF)
+ ? BTM_BLE_SCAN_SLOW_WIN_1
+ : p_cb->scan_win;
uint8_t own_addr_type = p_cb->addr_mgnt_cb.own_addr_type;
uint8_t peer_addr_type = BLE_ADDR_PUBLIC;
@@ -429,15 +424,6 @@
#if (BLE_PRIVACY_SPT == TRUE)
btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_INIT);
-#endif
- scan_int = (p_cb->scan_int == BTM_BLE_SCAN_PARAM_UNDEF)
- ? BTM_BLE_SCAN_SLOW_INT_1
- : p_cb->scan_int;
- scan_win = (p_cb->scan_win == BTM_BLE_SCAN_PARAM_UNDEF)
- ? BTM_BLE_SCAN_SLOW_WIN_1
- : p_cb->scan_win;
-
-#if (BLE_PRIVACY_SPT == TRUE)
if (btm_cb.ble_ctr_cb.rl_state != BTM_BLE_RL_IDLE &&
controller_get_interface()->supports_ble_privacy()) {
own_addr_type |= BLE_ADDR_TYPE_ID_BIT;
@@ -497,32 +483,7 @@
return false;
}
-/*******************************************************************************
- *
- * Function btm_suspend_wl_activity
- *
- * Description This function is to suspend white list related activity
- *
- * Returns none.
- *
- ******************************************************************************/
-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);
- }
-}
-/*******************************************************************************
- *
- * Function btm_resume_wl_activity
- *
- * Description This function is to resume white list related activity
- *
- * Returns none.
- *
- ******************************************************************************/
-static void btm_resume_wl_activity(tBTM_BLE_WL_STATE wl_state) {
- btm_ble_resume_bg_conn();
-}
+
/*******************************************************************************
*
* Function btm_ble_resume_bg_conn
@@ -620,6 +581,7 @@
}
}
}
+
/*******************************************************************************
*
* Function btm_send_pending_direct_conn
diff --git a/stack/btm/btm_ble_int.h b/stack/btm/btm_ble_int.h
index d4cb411..0544830 100644
--- a/stack/btm/btm_ble_int.h
+++ b/stack/btm/btm_ble_int.h
@@ -80,7 +80,7 @@
tBTM_LE_AUTH_REQ auth_req,
tBTM_BLE_SEC_REQ_ACT* p_sec_req_act);
extern void btm_ble_ltk_request_reply(const RawAddress& bda, bool use_stk,
- BT_OCTET16 stk);
+ const Octet16& stk);
extern uint8_t btm_proc_smp_cback(tSMP_EVT event, const RawAddress& bd_addr,
tSMP_EVT_DATA* p_data);
extern tBTM_STATUS btm_ble_set_encryption(const RawAddress& bd_addr,
@@ -89,7 +89,7 @@
extern void btm_ble_ltk_request(uint16_t handle, uint8_t rand[8],
uint16_t ediv);
extern tBTM_STATUS btm_ble_start_encrypt(const RawAddress& bda, bool use_stk,
- BT_OCTET16 stk);
+ Octet16* p_stk);
extern void btm_ble_link_encrypted(const RawAddress& bd_addr,
uint8_t encr_enable);
@@ -154,12 +154,13 @@
extern void btm_ble_dequeue_direct_conn_req(const RawAddress& rem_bda);
/* BLE address management */
-extern void btm_gen_resolvable_private_addr(base::Callback<void(BT_OCTET8)> cb);
+extern void btm_gen_resolvable_private_addr(
+ base::Callback<void(const RawAddress& rpa)> cb);
extern void btm_gen_non_resolvable_private_addr(tBTM_BLE_ADDR_CBACK* p_cback,
void* p);
extern tBTM_SEC_DEV_REC* btm_ble_resolve_random_addr(
const RawAddress& random_bda);
-extern void btm_gen_resolve_paddr_low(BT_OCTET8 rand);
+extern void btm_gen_resolve_paddr_low(const RawAddress& address);
/* privacy function */
#if (BLE_PRIVACY_SPT == TRUE)
diff --git a/stack/btm/btm_ble_int_types.h b/stack/btm/btm_ble_int_types.h
index 2167f2f..68f46f2 100644
--- a/stack/btm/btm_ble_int_types.h
+++ b/stack/btm/btm_ble_int_types.h
@@ -185,9 +185,8 @@
} tBTM_LE_BG_CONN_DEV;
/* white list using state as a bit mask */
-#define BTM_BLE_WL_IDLE 0
-#define BTM_BLE_WL_INIT 1
-typedef uint8_t tBTM_BLE_WL_STATE;
+constexpr uint8_t BTM_BLE_WL_IDLE = 0;
+constexpr uint8_t BTM_BLE_WL_INIT = 1;
/* resolving list using state as a bit mask */
#define BTM_BLE_RL_IDLE 0
@@ -288,11 +287,11 @@
/* background connection procedure cb value */
tBTM_BLE_CONN_TYPE bg_conn_type;
- uint32_t scan_int;
- uint32_t scan_win;
+ uint16_t scan_int;
+ uint16_t scan_win;
/* white list information */
- tBTM_BLE_WL_STATE wl_state;
+ uint8_t wl_state;
fixed_queue_t* conn_pending_q;
tBTM_BLE_CONN_ST conn_state;
diff --git a/stack/btm/btm_ble_multi_adv.cc b/stack/btm/btm_ble_multi_adv.cc
index f34e9de..a7960cd 100644
--- a/stack/btm/btm_ble_multi_adv.cc
+++ b/stack/btm/btm_ble_multi_adv.cc
@@ -44,7 +44,7 @@
uint8_t /* inst_id */, int8_t /* tx_power */, uint8_t /* status */)>;
using SetEnableData = BleAdvertiserHciInterface::SetEnableData;
extern void btm_gen_resolvable_private_addr(
- base::Callback<void(uint8_t[8])> cb);
+ base::Callback<void(const RawAddress& rpa)> cb);
constexpr int ADV_DATA_LEN_MAX = 251;
@@ -187,38 +187,8 @@
}
}
- void OnRpaGenerationComplete(base::Callback<void(RawAddress)> cb,
- uint8_t rand[8]) {
- VLOG(1) << __func__;
-
- RawAddress bda;
-
- rand[2] &= (~BLE_RESOLVE_ADDR_MASK);
- rand[2] |= BLE_RESOLVE_ADDR_MSB;
-
- bda.address[2] = rand[0];
- bda.address[1] = rand[1];
- bda.address[0] = rand[2];
-
- BT_OCTET16 irk;
- BTM_GetDeviceIDRoot(irk);
- tSMP_ENC output;
-
- if (!SMP_Encrypt(irk, BT_OCTET16_LEN, rand, 3, &output))
- LOG_ASSERT(false) << "SMP_Encrypt failed";
-
- /* set hash to be LSB of rpAddress */
- bda.address[5] = output.param_buf[0];
- bda.address[4] = output.param_buf[1];
- bda.address[3] = output.param_buf[2];
-
- cb.Run(bda);
- }
-
- void GenerateRpa(base::Callback<void(RawAddress)> cb) {
- btm_gen_resolvable_private_addr(
- Bind(&BleAdvertisingManagerImpl::OnRpaGenerationComplete,
- weak_factory_.GetWeakPtr(), std::move(cb)));
+ void GenerateRpa(base::Callback<void(const RawAddress&)> cb) {
+ btm_gen_resolvable_private_addr(std::move(cb));
}
void ConfigureRpa(AdvertisingInstance* p_inst, MultiAdvCb configuredCb) {
@@ -236,7 +206,7 @@
GenerateRpa(Bind(
[](AdvertisingInstance* p_inst, MultiAdvCb configuredCb,
- RawAddress bda) {
+ const RawAddress& bda) {
/* Connectable advertising set must be disabled when updating RPA */
bool restart = p_inst->IsEnabled() && p_inst->IsConnectable();
@@ -285,7 +255,7 @@
[](AdvertisingInstance* p_inst,
base::Callback<void(uint8_t /* inst_id */, uint8_t /* status */)>
cb,
- RawAddress bda) {
+ const RawAddress& bda) {
p_inst->own_address = bda;
alarm_set_on_mloop(p_inst->adv_raddr_timer,
diff --git a/stack/btm/btm_ble_privacy.cc b/stack/btm/btm_ble_privacy.cc
index 3845ba6..6581f25 100644
--- a/stack/btm/btm_ble_privacy.cc
+++ b/stack/btm/btm_ble_privacy.cc
@@ -728,8 +728,8 @@
btm_ble_update_resolving_list(p_dev_rec->bd_addr, true);
if (controller_get_interface()->supports_ble_privacy()) {
- uint8_t* peer_irk = p_dev_rec->ble.keys.irk;
- uint8_t* local_irk = btm_cb.devcb.id_keys.irk;
+ const Octet16& peer_irk = p_dev_rec->ble.keys.irk;
+ const Octet16& local_irk = btm_cb.devcb.id_keys.irk;
if (p_dev_rec->ble.static_addr.IsEmpty()) {
p_dev_rec->ble.static_addr = p_dev_rec->bd_addr;
@@ -754,7 +754,7 @@
uint8_t* p = param;
UINT8_TO_STREAM(p, BTM_BLE_META_ADD_IRK_ENTRY);
- ARRAY_TO_STREAM(p, p_dev_rec->ble.keys.irk, BT_OCTET16_LEN);
+ ARRAY_TO_STREAM(p, p_dev_rec->ble.keys.irk, OCTET16_LEN);
UINT8_TO_STREAM(p, p_dev_rec->ble.static_addr_type);
BDADDR_TO_STREAM(p, p_dev_rec->ble.static_addr);
diff --git a/stack/btm/btm_dev.cc b/stack/btm/btm_dev.cc
index 66382e8..e999fed 100644
--- a/stack/btm/btm_dev.cc
+++ b/stack/btm/btm_dev.cc
@@ -60,7 +60,7 @@
******************************************************************************/
bool BTM_SecAddDevice(const RawAddress& bd_addr, DEV_CLASS dev_class,
BD_NAME bd_name, uint8_t* features,
- uint32_t trusted_mask[], LINK_KEY link_key,
+ uint32_t trusted_mask[], LinkKey* p_link_key,
uint8_t key_type, tBTM_IO_CAP io_cap,
uint8_t pin_length) {
BTM_TRACE_API("%s: link key type:%x", __func__, key_type);
@@ -120,10 +120,10 @@
BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask);
- if (link_key) {
+ if (p_link_key) {
VLOG(2) << __func__ << ": BDA: " << bd_addr;
p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_KNOWN;
- memcpy(p_dev_rec->link_key, link_key, LINK_KEY_LEN);
+ p_dev_rec->link_key = *p_link_key;
p_dev_rec->link_key_type = key_type;
p_dev_rec->pin_code_length = pin_length;
diff --git a/stack/btm/btm_int.h b/stack/btm/btm_int.h
index 21f7ce3..1a696c3 100644
--- a/stack/btm/btm_int.h
+++ b/stack/btm/btm_int.h
@@ -256,7 +256,7 @@
extern void btm_keypress_notif_evt(uint8_t* p);
extern void btm_simple_pair_complete(uint8_t* p);
extern void btm_sec_link_key_notification(const RawAddress& p_bda,
- uint8_t* p_link_key,
+ const Octet16& link_key,
uint8_t key_type);
extern void btm_sec_link_key_request(const RawAddress& p_bda);
extern void btm_sec_pin_code_request(const RawAddress& p_bda);
diff --git a/stack/btm/btm_int_types.h b/stack/btm/btm_int_types.h
index 8f91cef..95acb5d 100644
--- a/stack/btm/btm_int_types.h
+++ b/stack/btm/btm_int_types.h
@@ -170,7 +170,7 @@
uint8_t le_supported_states[BTM_LE_SUPPORT_STATE_SIZE];
tBTM_BLE_LOCAL_ID_KEYS id_keys; /* local BLE ID keys */
- BT_OCTET16 ble_encryption_key_value; /* BLE encryption key */
+ Octet16 ble_encryption_key_value; /* BLE encryption key */
#if (BTM_BLE_CONFORMANCE_TESTING == TRUE)
bool no_disc_if_pair_fail;
@@ -415,12 +415,12 @@
/* LE Security information of device in Slave Role */
typedef struct {
- BT_OCTET16 irk; /* peer diverified identity root */
- BT_OCTET16 pltk; /* peer long term key */
- BT_OCTET16 pcsrk; /* peer SRK peer device used to secured sign local data */
+ Octet16 irk; /* peer diverified identity root */
+ Octet16 pltk; /* peer long term key */
+ Octet16 pcsrk; /* peer SRK peer device used to secured sign local data */
- BT_OCTET16 lltk; /* local long term key */
- BT_OCTET16 lcsrk; /* local SRK peer device used to secured sign local data */
+ Octet16 lltk; /* local long term key */
+ Octet16 lcsrk; /* local SRK peer device used to secured sign local data */
BT_OCTET8 rand; /* random vector for LTK generation */
uint16_t ediv; /* LTK diversifier of this slave device */
@@ -479,7 +479,7 @@
uint16_t clock_offset; /* Latest known clock offset */
RawAddress bd_addr; /* BD_ADDR of the device */
DEV_CLASS dev_class; /* DEV_CLASS of the device */
- LINK_KEY link_key; /* Device link key */
+ LinkKey link_key; /* Device link key */
uint8_t pin_code_length; /* Length of the pin_code used for paring */
#define BTM_SEC_AUTHORIZED BTM_SEC_FLAG_AUTHORIZED /* 0x01 */
diff --git a/stack/btm/btm_sec.cc b/stack/btm/btm_sec.cc
index 442fb77..7ca9976 100644
--- a/stack/btm/btm_sec.cc
+++ b/stack/btm/btm_sec.cc
@@ -224,7 +224,6 @@
*
******************************************************************************/
bool BTM_SecRegister(const tBTM_APPL_INFO* p_cb_info) {
- BT_OCTET16 temp_value = {0};
BTM_TRACE_EVENT("%s application registered", __func__);
@@ -233,8 +232,9 @@
if (p_cb_info->p_le_callback) {
BTM_TRACE_EVENT("%s SMP_Register( btm_proc_smp_cback )", __func__);
SMP_Register(btm_proc_smp_cback);
+ Octet16 zero{0};
/* if no IR is loaded, need to regenerate all the keys */
- if (memcmp(btm_cb.devcb.id_keys.ir, &temp_value, sizeof(BT_OCTET16)) == 0) {
+ if (btm_cb.devcb.id_keys.ir == zero) {
btm_ble_reset_id();
}
} else {
@@ -1169,15 +1169,15 @@
* the device or device record does not contain link key info
*
* Parameters: bd_addr - Address of the device
- * link_key - Link Key is copied into this array
+ * link_key - Link Key is copied into this pointer
*
******************************************************************************/
tBTM_STATUS BTM_SecGetDeviceLinkKey(const RawAddress& bd_addr,
- LINK_KEY link_key) {
+ LinkKey* link_key) {
tBTM_SEC_DEV_REC* p_dev_rec;
p_dev_rec = btm_find_dev(bd_addr);
if ((p_dev_rec != NULL) && (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)) {
- memcpy(link_key, p_dev_rec->link_key, LINK_KEY_LEN);
+ *link_key = p_dev_rec->link_key;
return (BTM_SUCCESS);
}
return (BTM_UNKNOWN_ADDR);
@@ -1558,7 +1558,7 @@
*
******************************************************************************/
void BTM_RemoteOobDataReply(tBTM_STATUS res, const RawAddress& bd_addr,
- BT_OCTET16 c, BT_OCTET16 r) {
+ const Octet16& c, const Octet16& r) {
BTM_TRACE_EVENT("%s() - State: %s res: %d", __func__,
btm_pair_state_descr(btm_cb.pairing_state), res);
@@ -1596,8 +1596,8 @@
* Returns Number of bytes in p_data.
*
******************************************************************************/
-uint16_t BTM_BuildOobData(uint8_t* p_data, uint16_t max_len, BT_OCTET16 c,
- BT_OCTET16 r, uint8_t name_len) {
+uint16_t BTM_BuildOobData(uint8_t* p_data, uint16_t max_len, const Octet16& c,
+ const Octet16& r, uint8_t name_len) {
uint8_t* p = p_data;
uint16_t len = 0;
uint16_t name_size;
@@ -1618,7 +1618,7 @@
if (max_len >= delta) {
*p++ = BTM_OOB_HASH_C_SIZE + 1;
*p++ = BTM_EIR_OOB_SSP_HASH_C_TYPE;
- ARRAY_TO_STREAM(p, c, BTM_OOB_HASH_C_SIZE);
+ ARRAY_TO_STREAM(p, c.data(), BTM_OOB_HASH_C_SIZE);
len += delta;
max_len -= delta;
}
@@ -1628,7 +1628,7 @@
if (max_len >= delta) {
*p++ = BTM_OOB_RAND_R_SIZE + 1;
*p++ = BTM_EIR_OOB_SSP_RAND_R_TYPE;
- ARRAY_TO_STREAM(p, r, BTM_OOB_RAND_R_SIZE);
+ ARRAY_TO_STREAM(p, r.data(), BTM_OOB_RAND_R_SIZE);
len += delta;
max_len -= delta;
}
@@ -3602,8 +3602,8 @@
void btm_rem_oob_req(uint8_t* p) {
tBTM_SP_RMT_OOB evt_data;
tBTM_SEC_DEV_REC* p_dev_rec;
- BT_OCTET16 c;
- BT_OCTET16 r;
+ Octet16 c;
+ Octet16 r;
RawAddress& p_bda = evt_data.bd_addr;
@@ -3648,8 +3648,8 @@
BTM_TRACE_EVENT("btm_read_local_oob_complete:%d", status);
if (status == HCI_SUCCESS) {
evt_data.status = BTM_SUCCESS;
- STREAM_TO_ARRAY16(evt_data.c, p);
- STREAM_TO_ARRAY16(evt_data.r, p);
+ STREAM_TO_ARRAY16(evt_data.c.data(), p);
+ STREAM_TO_ARRAY16(evt_data.r.data(), p);
} else
evt_data.status = BTM_ERR_PROCESSING;
@@ -4039,8 +4039,6 @@
__func__, p_dev_rec, p_dev_rec->p_callback);
p_dev_rec->p_callback = NULL;
l2cu_resubmit_pending_sec_req(&p_dev_rec->bd_addr);
- } else if (p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING) {
- p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
}
return;
}
@@ -4104,6 +4102,7 @@
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bda);
uint8_t res;
bool is_pairing_device = false;
+ bool addr_matched;
tACL_CONN* p_acl_cb;
uint8_t bit_shift = 0;
@@ -4193,8 +4192,9 @@
p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
- if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) &&
- (btm_cb.pairing_bda == bda)) {
+ addr_matched = (btm_cb.pairing_bda == bda);
+
+ if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) && addr_matched) {
/* if we rejected incoming connection from bonding device */
if ((status == HCI_ERR_HOST_REJECT_DEVICE) &&
(btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT)) {
@@ -4290,7 +4290,7 @@
}
}
- if (btm_cb.pairing_bda != bda) {
+ if (!addr_matched) {
/* Don't callback unless this Connection-Complete-failure event has the
* same mac address as the bonding device */
VLOG(1) << __func__
@@ -4551,18 +4551,9 @@
}
}
-/*******************************************************************************
- *
- * Function btm_sec_link_key_notification
- *
- * Description This function is called when a new connection link key is
- * generated
- *
- * Returns Pointer to the record or NULL
- *
- ******************************************************************************/
-void btm_sec_link_key_notification(const RawAddress& p_bda, uint8_t* p_link_key,
- uint8_t key_type) {
+/** This function is called when a new connection link key is generated */
+void btm_sec_link_key_notification(const RawAddress& p_bda,
+ const Octet16& link_key, uint8_t key_type) {
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_or_alloc_dev(p_bda);
bool we_are_bonding = false;
bool ltk_derived_lk = false;
@@ -4595,7 +4586,7 @@
/* BR/EDR connection, update the encryption key size to be 16 as always */
p_dev_rec->enc_key_size = 16;
- memcpy(p_dev_rec->link_key, p_link_key, LINK_KEY_LEN);
+ p_dev_rec->link_key = link_key;
if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) &&
(btm_cb.pairing_bda == p_bda)) {
@@ -4611,7 +4602,7 @@
BTM_TRACE_DEBUG("%s() Save LTK derived LK (key_type = %d)", __func__,
p_dev_rec->link_key_type);
(*btm_cb.api.p_link_key_callback)(p_bda, p_dev_rec->dev_class,
- p_dev_rec->sec_bd_name, p_link_key,
+ p_dev_rec->sec_bd_name, link_key,
p_dev_rec->link_key_type);
}
} else {
@@ -4675,7 +4666,7 @@
p_dev_rec->link_key_type);
} else {
(*btm_cb.api.p_link_key_callback)(p_bda, p_dev_rec->dev_class,
- p_dev_rec->sec_bd_name, p_link_key,
+ p_dev_rec->sec_bd_name, link_key,
p_dev_rec->link_key_type);
}
}
@@ -4695,7 +4686,6 @@
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_or_alloc_dev(bda);
VLOG(2) << __func__ << " bda: " << bda;
- p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
if ((btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_PIN_REQ) &&
(btm_cb.collision_start_time != 0) &&
diff --git a/stack/btu/btu_hcif.cc b/stack/btu/btu_hcif.cc
index eac71a6..0f54a69 100644
--- a/stack/btu/btu_hcif.cc
+++ b/stack/btu/btu_hcif.cc
@@ -1381,11 +1381,11 @@
******************************************************************************/
static void btu_hcif_link_key_notification_evt(uint8_t* p) {
RawAddress bda;
- LINK_KEY key;
+ Octet16 key;
uint8_t key_type;
STREAM_TO_BDADDR(bda, p);
- STREAM_TO_ARRAY16(key, p);
+ STREAM_TO_ARRAY16(key.data(), p);
STREAM_TO_UINT8(key_type, p);
btm_sec_link_key_notification(bda, key, key_type);
diff --git a/stack/smp/aes.cc b/stack/crypto_toolbox/aes.cc
similarity index 99%
rename from stack/smp/aes.cc
rename to stack/crypto_toolbox/aes.cc
index 362a4ee..f53894e 100644
--- a/stack/smp/aes.cc
+++ b/stack/crypto_toolbox/aes.cc
@@ -43,12 +43,9 @@
#endif
#endif
+#include <stdint.h>
#include <stdlib.h>
-/* add the target configuration to allow using internal data types and
- * compilation options */
-#include "bt_target.h"
-
/* define if you have fast 32-bit types on your system */
#if 1
#define HAVE_UINT_32T
diff --git a/stack/smp/aes.h b/stack/crypto_toolbox/aes.h
similarity index 100%
rename from stack/smp/aes.h
rename to stack/crypto_toolbox/aes.h
diff --git a/stack/crypto_toolbox/aes_cmac.cc b/stack/crypto_toolbox/aes_cmac.cc
new file mode 100644
index 0000000..8b8246e
--- /dev/null
+++ b/stack/crypto_toolbox/aes_cmac.cc
@@ -0,0 +1,217 @@
+/******************************************************************************
+ *
+ * Copyright 2008-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the implementation of the AES128 and AES CMAC algorithm.
+ *
+ ******************************************************************************/
+
+#include "stack/crypto_toolbox/aes.h"
+#include "stack/crypto_toolbox/crypto_toolbox.h"
+
+#include <base/logging.h>
+#include <base/strings/string_number_conversions.h>
+
+namespace crypto_toolbox {
+
+namespace {
+
+typedef struct {
+ uint8_t* text;
+ uint16_t len;
+ uint16_t round;
+} tCMAC_CB;
+
+tCMAC_CB cmac_cb;
+
+/* Rb for AES-128 as block cipher, LSB as [0] */
+Octet16 const_Rb{0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+/** utility function to do an biteise exclusive-OR of two bit strings of the
+ * length of OCTET16_LEN. Result is stored in first argument.
+ */
+static void xor_128(Octet16* a, const Octet16& b) {
+ CHECK(a);
+ uint8_t i, *aa = a->data();
+ const uint8_t* bb = b.data();
+
+ for (i = 0; i < OCTET16_LEN; i++) {
+ aa[i] = aa[i] ^ bb[i];
+ }
+}
+} // namespace
+
+/* This function computes AES_128(key, message) */
+Octet16 aes_128(const Octet16& key, const Octet16& message) {
+ Octet16 key_reversed;
+ Octet16 message_reversed;
+ Octet16 output;
+
+ std::reverse_copy(key.begin(), key.end(), key_reversed.begin());
+ std::reverse_copy(message.begin(), message.end(), message_reversed.begin());
+
+ aes_context ctx;
+ aes_set_key(key_reversed.data(), key_reversed.size(), &ctx);
+ aes_encrypt(message_reversed.data(), output.data(), &ctx);
+
+ std::reverse(output.begin(), output.end());
+ return output;
+}
+
+/** utility function to padding the given text to be a 128 bits data. The
+ * parameter dest is input and output parameter, it must point to a
+ * OCTET16_LEN memory space; where include length bytes valid data. */
+static void padding(Octet16* dest, uint8_t length) {
+ uint8_t i, *p = dest->data();
+ /* original last block */
+ for (i = length; i < OCTET16_LEN; i++)
+ p[OCTET16_LEN - i - 1] = (i == length) ? 0x80 : 0;
+}
+
+/** utility function to left shift one bit for a 128 bits value. */
+static void leftshift_onebit(uint8_t* input, uint8_t* output) {
+ uint8_t i, overflow = 0, next_overflow = 0;
+ DVLOG(2) << __func__;
+ /* input[0] is LSB */
+ for (i = 0; i < OCTET16_LEN; i++) {
+ next_overflow = (input[i] & 0x80) ? 1 : 0;
+ output[i] = (input[i] << 1) | overflow;
+ overflow = next_overflow;
+ }
+ return;
+}
+
+/** This function is the calculation of block cipher using AES-128. */
+static Octet16 cmac_aes_k_calculate(const Octet16& key) {
+ Octet16 output;
+ Octet16 x{0}; // zero initialized
+
+ DVLOG(2) << __func__;
+
+ uint8_t i = 1;
+ while (i <= cmac_cb.round) {
+ /* Mi' := Mi (+) X */
+ xor_128((Octet16*)&cmac_cb.text[(cmac_cb.round - i) * OCTET16_LEN], x);
+
+ output = aes_128(key, &cmac_cb.text[(cmac_cb.round - i) * OCTET16_LEN],
+ OCTET16_LEN);
+ x = output;
+ i++;
+ }
+
+ return output;
+}
+
+/** This function proceeed to prepare the last block of message Mn depending on
+ * the size of the message.
+ */
+static void cmac_prepare_last_block(const Octet16& k1, const Octet16& k2) {
+ // uint8_t x[16] = {0};
+ bool flag;
+
+ DVLOG(2) << __func__;
+ /* last block is a complete block set flag to 1 */
+ flag = ((cmac_cb.len % OCTET16_LEN) == 0 && cmac_cb.len != 0) ? true : false;
+
+ DVLOG(2) << "flag=" << flag << " round=" << cmac_cb.round;
+
+ if (flag) { /* last block is complete block */
+ xor_128((Octet16*)&cmac_cb.text[0], k1);
+ } else /* padding then xor with k2 */
+ {
+ padding((Octet16*)&cmac_cb.text[0], (uint8_t)(cmac_cb.len % 16));
+
+ xor_128((Octet16*)&cmac_cb.text[0], k2);
+ }
+}
+
+/** This is the function to generate the two subkeys.
+ * |key| is CMAC key, expect SRK when used by SMP.
+ */
+static void cmac_generate_subkey(const Octet16& key) {
+ DVLOG(2) << __func__;
+
+ Octet16 zero{};
+ Octet16 p = aes_128(key, zero.data(), OCTET16_LEN);
+
+ Octet16 k1, k2;
+ uint8_t* pp = p.data();
+
+ /* If MSB(L) = 0, then K1 = L << 1 */
+ if ((pp[OCTET16_LEN - 1] & 0x80) != 0) {
+ /* Else K1 = ( L << 1 ) (+) Rb */
+ leftshift_onebit(pp, k1.data());
+ xor_128(&k1, const_Rb);
+ } else {
+ leftshift_onebit(pp, k1.data());
+ }
+
+ if ((k1[OCTET16_LEN - 1] & 0x80) != 0) {
+ /* K2 = (K1 << 1) (+) Rb */
+ leftshift_onebit(k1.data(), k2.data());
+ xor_128(&k2, const_Rb);
+ } else {
+ /* If MSB(K1) = 0, then K2 = K1 << 1 */
+ leftshift_onebit(k1.data(), k2.data());
+ }
+
+ cmac_prepare_last_block(k1, k2);
+}
+
+/** key - CMAC key in little endian order
+ * input - text to be signed in little endian byte order.
+ * length - length of the input in byte.
+ */
+Octet16 aes_cmac(const Octet16& key, const uint8_t* input, uint16_t length) {
+ uint16_t len, diff;
+ /* n is number of rounds */
+ uint16_t n = (length + OCTET16_LEN - 1) / OCTET16_LEN;
+
+ DVLOG(2) << __func__;
+
+ if (n == 0) n = 1;
+ len = n * OCTET16_LEN;
+
+ DVLOG(2) << "AES128_CMAC started, allocate buffer size=" << len;
+ /* allocate a memory space of multiple of 16 bytes to hold text */
+ cmac_cb.text = (uint8_t*)alloca(len);
+ cmac_cb.round = n;
+ diff = len - length;
+
+ if (input != NULL && length > 0) {
+ memcpy(&cmac_cb.text[diff], input, (int)length);
+ cmac_cb.len = length;
+ } else {
+ cmac_cb.len = 0;
+ }
+
+ /* prepare calculation for subkey s and last block of data */
+ cmac_generate_subkey(key);
+ /* start calculation */
+ Octet16 signature = cmac_aes_k_calculate(key);
+
+ /* clean up */
+ memset(&cmac_cb, 0, sizeof(tCMAC_CB));
+ // cmac_cb.text is auto-freed by alloca
+
+ return signature;
+}
+
+} // namespace crypto_toolbox
diff --git a/stack/crypto_toolbox/crypto_toolbox.cc b/stack/crypto_toolbox/crypto_toolbox.cc
new file mode 100644
index 0000000..ae33bd9
--- /dev/null
+++ b/stack/crypto_toolbox/crypto_toolbox.cc
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2018 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 "stack/crypto_toolbox/crypto_toolbox.h"
+#include "stack/crypto_toolbox/aes.h"
+
+#include <algorithm>
+
+#include <base/logging.h>
+#include <base/strings/string_number_conversions.h>
+
+using base::HexEncode;
+
+namespace crypto_toolbox {
+
+Octet16 h6(const Octet16& w, std::array<uint8_t, 4> keyid) {
+ return aes_cmac(w, keyid.data(), keyid.size());
+}
+
+Octet16 h7(const Octet16& salt, const Octet16& w) {
+ return aes_cmac(salt, w.data(), w.size());
+}
+
+Octet16 f4(uint8_t* u, uint8_t* v, const Octet16& x, uint8_t z) {
+ constexpr size_t msg_len = BT_OCTET32_LEN /* U size */ +
+ BT_OCTET32_LEN /* V size */ + 1 /* Z size */;
+
+ DVLOG(2) << "U=" << HexEncode(u, BT_OCTET32_LEN)
+ << ", V=" << HexEncode(v, BT_OCTET32_LEN)
+ << ", X=" << HexEncode(x.data(), x.size()) << ", Z=" << std::hex
+ << +z;
+
+ std::array<uint8_t, msg_len> msg;
+ auto it = msg.begin();
+ it = std::copy(&z, &z + 1, it);
+ it = std::copy(v, v + BT_OCTET32_LEN, it);
+ it = std::copy(u, u + BT_OCTET32_LEN, it);
+ return aes_cmac(x, msg.data(), msg.size());
+}
+
+/** helper for f5 */
+static Octet16 calculate_mac_key_or_ltk(const Octet16& t, uint8_t counter,
+ uint8_t* key_id, const Octet16& n1,
+ const Octet16& n2, uint8_t* a1,
+ uint8_t* a2, uint8_t* length) {
+ constexpr size_t msg_len = 1 /* Counter size */ + 4 /* keyID size */ +
+ OCTET16_LEN /* N1 size */ +
+ OCTET16_LEN /* N2 size */ + 7 /* A1 size*/ +
+ 7 /* A2 size*/ + 2 /* Length size */;
+ std::array<uint8_t, msg_len> msg;
+ auto it = msg.begin();
+ it = std::copy(length, length + 2, it);
+ it = std::copy(a2, a2 + 7, it);
+ it = std::copy(a1, a1 + 7, it);
+ it = std::copy(n2.begin(), n2.end(), it);
+ it = std::copy(n1.begin(), n1.end(), it);
+ it = std::copy(key_id, key_id + 4, it);
+ it = std::copy(&counter, &counter + 1, it);
+
+ return aes_cmac(t, msg.data(), msg.size());
+}
+
+void f5(uint8_t* w, const Octet16& n1, const Octet16& n2, uint8_t* a1,
+ uint8_t* a2, Octet16* mac_key, Octet16* ltk) {
+ DVLOG(2) << __func__ << "W=" << HexEncode(w, BT_OCTET32_LEN)
+ << ", N1=" << HexEncode(n1.data(), n1.size())
+ << ", N2=" << HexEncode(n2.data(), n2.size())
+ << ", A1=" << HexEncode(a1, 7) << ", A2=" << HexEncode(a2, 7);
+
+ const Octet16 salt{0xBE, 0x83, 0x60, 0x5A, 0xDB, 0x0B, 0x37, 0x60,
+ 0x38, 0xA5, 0xF5, 0xAA, 0x91, 0x83, 0x88, 0x6C};
+ Octet16 t = aes_cmac(salt, w, BT_OCTET32_LEN);
+
+ DVLOG(2) << "T=" << HexEncode(t.data(), t.size());
+
+ uint8_t key_id[4] = {0x65, 0x6c, 0x74, 0x62}; /* 0x62746c65 */
+ uint8_t length[2] = {0x00, 0x01}; /* 0x0100 */
+
+ *mac_key = calculate_mac_key_or_ltk(t, 0, key_id, n1, n2, a1, a2, length);
+
+ *ltk = calculate_mac_key_or_ltk(t, 1, key_id, n1, n2, a1, a2, length);
+
+ DVLOG(2) << "mac_key=" << HexEncode(mac_key->data(), mac_key->size());
+ DVLOG(2) << "ltk=" << HexEncode(ltk->data(), ltk->size());
+}
+
+Octet16 f6(const Octet16& w, const Octet16& n1, const Octet16& n2,
+ const Octet16& r, uint8_t* iocap, uint8_t* a1, uint8_t* a2) {
+ const uint8_t msg_len = OCTET16_LEN /* N1 size */ +
+ OCTET16_LEN /* N2 size */ + OCTET16_LEN /* R size */ +
+ 3 /* IOcap size */ + 7 /* A1 size*/
+ + 7 /* A2 size*/;
+
+ DVLOG(2) << __func__ << "W=" << HexEncode(w.data(), w.size())
+ << ", N1=" << HexEncode(n1.data(), n1.size())
+ << ", N2=" << HexEncode(n2.data(), n2.size())
+ << ", R=" << HexEncode(r.data(), r.size())
+ << ", IOcap=" << HexEncode(iocap, 3) << ", A1=" << HexEncode(a1, 7)
+ << ", A2=" << HexEncode(a2, 7);
+
+ std::array<uint8_t, msg_len> msg;
+ auto it = msg.begin();
+ it = std::copy(a2, a2 + 7, it);
+ it = std::copy(a1, a1 + 7, it);
+ it = std::copy(iocap, iocap + 3, it);
+ it = std::copy(r.begin(), r.end(), it);
+ it = std::copy(n2.begin(), n2.end(), it);
+ it = std::copy(n1.begin(), n1.end(), it);
+
+ return aes_cmac(w, msg.data(), msg.size());
+}
+
+uint32_t g2(uint8_t* u, uint8_t* v, const Octet16& x, const Octet16& y) {
+ constexpr size_t msg_len = BT_OCTET32_LEN /* U size */ +
+ BT_OCTET32_LEN /* V size */
+ + OCTET16_LEN /* Y size */;
+
+ DVLOG(2) << __func__ << "U=" << HexEncode(u, BT_OCTET32_LEN)
+ << ", V=" << HexEncode(v, BT_OCTET32_LEN)
+ << ", X=" << HexEncode(x.data(), x.size())
+ << ", Y=" << HexEncode(y.data(), y.size());
+
+ std::array<uint8_t, msg_len> msg;
+ auto it = msg.begin();
+ it = std::copy(y.begin(), y.end(), it);
+ it = std::copy(v, v + BT_OCTET32_LEN, it);
+ it = std::copy(u, u + BT_OCTET32_LEN, it);
+
+ Octet16 cmac = aes_cmac(x, msg.data(), msg.size());
+
+ /* vres = cmac mod 2**32 mod 10**6 */
+ uint32_t vres;
+ uint8_t* p = cmac.data();
+ STREAM_TO_UINT32(vres, p);
+
+ vres = vres % 1000000;
+ return vres;
+}
+
+Octet16 ltk_to_link_key(const Octet16& ltk, bool use_h7) {
+ Octet16 ilk; /* intermidiate link key */
+ if (use_h7) {
+ constexpr Octet16 salt{0x31, 0x70, 0x6D, 0x74, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ ilk = h7(salt, ltk);
+ } else {
+ /* "tmp1" mapping to extended ASCII, little endian*/
+ constexpr std::array<uint8_t, 4> keyID_tmp1 = {0x31, 0x70, 0x6D, 0x74};
+ ilk = h6(ltk, keyID_tmp1);
+ }
+
+ /* "lebr" mapping to extended ASCII, little endian */
+ constexpr std::array<uint8_t, 4> keyID_lebr = {0x72, 0x62, 0x65, 0x6c};
+ return h6(ilk, keyID_lebr);
+}
+
+Octet16 link_key_to_ltk(const Octet16& link_key, bool use_h7) {
+ Octet16 iltk; /* intermidiate long term key */
+ if (use_h7) {
+ constexpr Octet16 salt{0x32, 0x70, 0x6D, 0x74, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ iltk = h7(salt, link_key);
+ } else {
+ /* "tmp2" mapping to extended ASCII, little endian */
+ constexpr std::array<uint8_t, 4> keyID_tmp2 = {0x32, 0x70, 0x6D, 0x74};
+ iltk = h6(link_key, keyID_tmp2);
+ }
+
+ /* "brle" mapping to extended ASCII, little endian */
+ constexpr std::array<uint8_t, 4> keyID_brle = {0x65, 0x6c, 0x72, 0x62};
+ return h6(iltk, keyID_brle);
+}
+
+} // namespace crypto_toolbox
diff --git a/stack/crypto_toolbox/crypto_toolbox.h b/stack/crypto_toolbox/crypto_toolbox.h
new file mode 100644
index 0000000..90d7392
--- /dev/null
+++ b/stack/crypto_toolbox/crypto_toolbox.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2018 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 "stack/include/bt_types.h"
+
+namespace crypto_toolbox {
+
+extern Octet16 aes_128(const Octet16& key, const Octet16& message);
+extern Octet16 aes_cmac(const Octet16& key, const uint8_t* message,
+ uint16_t length);
+extern Octet16 f4(uint8_t* u, uint8_t* v, const Octet16& x, uint8_t z);
+extern void f5(uint8_t* w, const Octet16& n1, const Octet16& n2, uint8_t* a1,
+ uint8_t* a2, Octet16* mac_key, Octet16* ltk);
+extern Octet16 f6(const Octet16& w, const Octet16& n1, const Octet16& n2,
+ const Octet16& r, uint8_t* iocap, uint8_t* a1, uint8_t* a2);
+extern Octet16 h6(const Octet16& w, std::array<uint8_t, 4> keyid);
+extern Octet16 h7(const Octet16& salt, const Octet16& w);
+extern uint32_t g2(uint8_t* u, uint8_t* v, const Octet16& x, const Octet16& y);
+extern Octet16 ltk_to_link_key(const Octet16& ltk, bool use_h7);
+extern Octet16 link_key_to_ltk(const Octet16& link_key, bool use_h7);
+
+/* This function computes AES_128(key, message). |key| must be 128bit.
+ * |message| can be at most 16 bytes long, it's length in bytes is given in
+ * |length| */
+inline Octet16 aes_128(const Octet16& key, const uint8_t* message,
+ const uint8_t length) {
+ CHECK(length <= OCTET16_LEN) << "you tried aes_128 more than 16 bytes!";
+ Octet16 msg{0};
+ std::copy(message, message + length, msg.begin());
+ return aes_128(key, msg);
+}
+
+// |tlen| - lenth of mac desired
+// |p_signature| - data pointer to where signed data to be stored, tlen long.
+inline void aes_cmac(const Octet16& key, const uint8_t* message,
+ uint16_t length, uint16_t tlen, uint8_t* p_signature) {
+ Octet16 signature = aes_cmac(key, message, length);
+
+ uint8_t* p_mac = signature.data() + (OCTET16_LEN - tlen);
+ memcpy(p_signature, p_mac, tlen);
+}
+
+inline Octet16 aes_cmac(const Octet16& key, const Octet16& message) {
+ return aes_cmac(key, message.data(), message.size());
+}
+
+} // namespace crypto_toolbox
\ No newline at end of file
diff --git a/stack/gatt/gatt_api.cc b/stack/gatt/gatt_api.cc
index 93a35ca..2d37e9d 100644
--- a/stack/gatt/gatt_api.cc
+++ b/stack/gatt/gatt_api.cc
@@ -613,20 +613,22 @@
*
* Parameters conn_id: connection identifier.
* disc_type:discovery type.
- * p_param: parameters of discovery requirement.
+ * start_handle and end_handle: range of handles for discovery
+ * uuid: uuid to discovery. set to Uuid::kEmpty for requests
+ * that don't need it
*
* Returns GATT_SUCCESS if command received/sent successfully.
*
******************************************************************************/
tGATT_STATUS GATTC_Discover(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
- tGATT_DISC_PARAM* p_param) {
+ uint16_t start_handle, uint16_t end_handle,
+ const Uuid& uuid) {
tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
- if ((p_tcb == NULL) || (p_reg == NULL) || (p_param == NULL) ||
- (disc_type >= GATT_DISC_MAX)) {
+ if ((p_tcb == NULL) || (p_reg == NULL) || (disc_type >= GATT_DISC_MAX)) {
LOG(ERROR) << __func__ << " Illegal param: disc_type=" << +disc_type
<< " conn_id=" << loghex(conn_id);
return GATT_ILLEGAL_PARAMETER;
@@ -634,13 +636,13 @@
LOG(INFO) << __func__ << " conn_id=" << loghex(conn_id)
<< ", disc_type=" << +disc_type
- << ", s_handle=" << loghex(p_param->s_handle)
- << ", e_handle=" << loghex(p_param->e_handle);
+ << ", s_handle=" << loghex(start_handle)
+ << ", e_handle=" << loghex(end_handle);
- if (!GATT_HANDLE_IS_VALID(p_param->s_handle) ||
- !GATT_HANDLE_IS_VALID(p_param->e_handle) ||
+ if (!GATT_HANDLE_IS_VALID(start_handle) ||
+ !GATT_HANDLE_IS_VALID(end_handle) ||
/* search by type does not have a valid UUID param */
- (disc_type == GATT_DISC_SRVC_BY_UUID && p_param->service.IsEmpty())) {
+ (disc_type == GATT_DISC_SRVC_BY_UUID && uuid.IsEmpty())) {
return GATT_ILLEGAL_PARAMETER;
}
@@ -654,14 +656,20 @@
p_clcb->operation = GATTC_OPTYPE_DISCOVERY;
p_clcb->op_subtype = disc_type;
- p_clcb->s_handle = p_param->s_handle;
- p_clcb->e_handle = p_param->e_handle;
- p_clcb->uuid = p_param->service;
+ p_clcb->s_handle = start_handle;
+ p_clcb->e_handle = end_handle;
+ p_clcb->uuid = uuid;
gatt_act_discovery(p_clcb);
return GATT_SUCCESS;
}
+tGATT_STATUS GATTC_Discover(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
+ uint16_t start_handle, uint16_t end_handle) {
+ return GATTC_Discover(conn_id, disc_type, start_handle, end_handle,
+ Uuid::kEmpty);
+}
+
/*******************************************************************************
*
* Function GATTC_Read
diff --git a/stack/gatt/gatt_attr.cc b/stack/gatt/gatt_attr.cc
index 75a8057..8861a7a 100644
--- a/stack/gatt/gatt_attr.cc
+++ b/stack/gatt/gatt_attr.cc
@@ -385,41 +385,35 @@
*
******************************************************************************/
static void gatt_cl_start_config_ccc(tGATT_PROFILE_CLCB* p_clcb) {
- tGATT_DISC_PARAM srvc_disc_param;
- tGATT_VALUE ccc_value;
VLOG(1) << __func__ << ": stage: " << +p_clcb->ccc_stage;
- memset(&srvc_disc_param, 0, sizeof(tGATT_DISC_PARAM));
- memset(&ccc_value, 0, sizeof(tGATT_VALUE));
-
switch (p_clcb->ccc_stage) {
case GATT_SVC_CHANGED_SERVICE: /* discover GATT service */
- srvc_disc_param.s_handle = 1;
- srvc_disc_param.e_handle = 0xffff;
- srvc_disc_param.service = Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER);
- GATTC_Discover(p_clcb->conn_id, GATT_DISC_SRVC_BY_UUID, &srvc_disc_param);
+ GATTC_Discover(p_clcb->conn_id, GATT_DISC_SRVC_BY_UUID, 0x0001, 0xffff,
+ Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER));
break;
case GATT_SVC_CHANGED_CHARACTERISTIC: /* discover service change char */
- srvc_disc_param.s_handle = 1;
- srvc_disc_param.e_handle = p_clcb->e_handle;
- srvc_disc_param.service = Uuid::From16Bit(GATT_UUID_GATT_SRV_CHGD);
- GATTC_Discover(p_clcb->conn_id, GATT_DISC_CHAR, &srvc_disc_param);
+ GATTC_Discover(p_clcb->conn_id, GATT_DISC_CHAR, 0x0001, p_clcb->e_handle,
+ Uuid::From16Bit(GATT_UUID_GATT_SRV_CHGD));
break;
case GATT_SVC_CHANGED_DESCRIPTOR: /* discover service change ccc */
- srvc_disc_param.s_handle = p_clcb->s_handle;
- srvc_disc_param.e_handle = p_clcb->e_handle;
- GATTC_Discover(p_clcb->conn_id, GATT_DISC_CHAR_DSCPT, &srvc_disc_param);
+ GATTC_Discover(p_clcb->conn_id, GATT_DISC_CHAR_DSCPT, p_clcb->s_handle,
+ p_clcb->e_handle);
break;
case GATT_SVC_CHANGED_CONFIGURE_CCCD: /* write ccc */
+ {
+ tGATT_VALUE ccc_value;
+ memset(&ccc_value, 0, sizeof(tGATT_VALUE));
ccc_value.handle = p_clcb->s_handle;
ccc_value.len = 2;
ccc_value.value[0] = GATT_CLT_CONFIG_INDICATION;
GATTC_Write(p_clcb->conn_id, GATT_WRITE, &ccc_value);
break;
+ }
}
}
diff --git a/stack/gatt/gatt_sr.cc b/stack/gatt/gatt_sr.cc
index 35bd993..008702c 100644
--- a/stack/gatt/gatt_sr.cc
+++ b/stack/gatt/gatt_sr.cc
@@ -327,7 +327,7 @@
} else /* nothing needs to be executed , send response now */
{
LOG(ERROR) << "gatt_process_exec_write_req: no prepare write pending";
- gatt_send_error_rsp(tcb, GATT_INVALID_OFFSET, GATT_REQ_EXEC_WRITE, 0, false);
+ gatt_send_error_rsp(tcb, GATT_ERROR, GATT_REQ_EXEC_WRITE, 0, false);
}
}
diff --git a/stack/hcic/hciblecmds.cc b/stack/hcic/hciblecmds.cc
index 30d8d75..40c89e1 100644
--- a/stack/hcic/hciblecmds.cc
+++ b/stack/hcic/hciblecmds.cc
@@ -405,8 +405,7 @@
void btsnd_hcic_ble_start_enc(uint16_t handle,
uint8_t rand[HCIC_BLE_RAND_DI_SIZE],
- uint16_t ediv,
- uint8_t ltk[HCIC_BLE_ENCRYT_KEY_SIZE]) {
+ uint16_t ediv, const Octet16& ltk) {
BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
uint8_t* pp = (uint8_t*)(p + 1);
@@ -419,13 +418,12 @@
UINT16_TO_STREAM(pp, handle);
ARRAY_TO_STREAM(pp, rand, HCIC_BLE_RAND_DI_SIZE);
UINT16_TO_STREAM(pp, ediv);
- ARRAY_TO_STREAM(pp, ltk, HCIC_BLE_ENCRYT_KEY_SIZE);
+ ARRAY_TO_STREAM(pp, ltk.data(), HCIC_BLE_ENCRYT_KEY_SIZE);
btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
}
-void btsnd_hcic_ble_ltk_req_reply(uint16_t handle,
- uint8_t ltk[HCIC_BLE_ENCRYT_KEY_SIZE]) {
+void btsnd_hcic_ble_ltk_req_reply(uint16_t handle, const Octet16& ltk) {
BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
uint8_t* pp = (uint8_t*)(p + 1);
@@ -436,7 +434,7 @@
UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_LTK_REQ_REPLY);
UINT16_TO_STREAM(pp, handle);
- ARRAY_TO_STREAM(pp, ltk, HCIC_BLE_ENCRYT_KEY_SIZE);
+ ARRAY_TO_STREAM(pp, ltk.data(), HCIC_BLE_ENCRYT_KEY_SIZE);
btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
}
@@ -560,9 +558,10 @@
}
#endif
-void btsnd_hcic_ble_add_device_resolving_list(
- uint8_t addr_type_peer, const RawAddress& bda_peer,
- uint8_t irk_peer[HCIC_BLE_IRK_SIZE], uint8_t irk_local[HCIC_BLE_IRK_SIZE]) {
+void btsnd_hcic_ble_add_device_resolving_list(uint8_t addr_type_peer,
+ const RawAddress& bda_peer,
+ const Octet16& irk_peer,
+ const Octet16& irk_local) {
BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
uint8_t* pp = (uint8_t*)(p + 1);
@@ -573,8 +572,8 @@
UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_ADD_DEV_RESOLVING_LIST);
UINT8_TO_STREAM(pp, addr_type_peer);
BDADDR_TO_STREAM(pp, bda_peer);
- ARRAY_TO_STREAM(pp, irk_peer, HCIC_BLE_ENCRYT_KEY_SIZE);
- ARRAY_TO_STREAM(pp, irk_local, HCIC_BLE_ENCRYT_KEY_SIZE);
+ ARRAY_TO_STREAM(pp, irk_peer.data(), HCIC_BLE_ENCRYT_KEY_SIZE);
+ ARRAY_TO_STREAM(pp, irk_local.data(), HCIC_BLE_ENCRYT_KEY_SIZE);
btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
}
diff --git a/stack/hcic/hcicmds.cc b/stack/hcic/hcicmds.cc
index 56ff381..ebed273 100644
--- a/stack/hcic/hcicmds.cc
+++ b/stack/hcic/hcicmds.cc
@@ -207,7 +207,7 @@
}
void btsnd_hcic_link_key_req_reply(const RawAddress& bd_addr,
- LINK_KEY link_key) {
+ const LinkKey& link_key) {
BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
uint8_t* pp = (uint8_t*)(p + 1);
@@ -218,7 +218,7 @@
UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_LINK_KEY_REQ_REPLY);
BDADDR_TO_STREAM(pp, bd_addr);
- ARRAY16_TO_STREAM(pp, link_key);
+ ARRAY16_TO_STREAM(pp, link_key.data());
btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
}
@@ -1196,8 +1196,8 @@
btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
}
-void btsnd_hcic_rem_oob_reply(const RawAddress& bd_addr, uint8_t* p_c,
- uint8_t* p_r) {
+void btsnd_hcic_rem_oob_reply(const RawAddress& bd_addr, const Octet16& c,
+ const Octet16& r) {
BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
uint8_t* pp = (uint8_t*)(p + 1);
@@ -1208,8 +1208,8 @@
UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_REM_OOB_REPLY);
BDADDR_TO_STREAM(pp, bd_addr);
- ARRAY16_TO_STREAM(pp, p_c);
- ARRAY16_TO_STREAM(pp, p_r);
+ ARRAY16_TO_STREAM(pp, c.data());
+ ARRAY16_TO_STREAM(pp, r.data());
btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
}
diff --git a/stack/include/bt_types.h b/stack/include/bt_types.h
index 54a2eb2..6844dad 100644
--- a/stack/include/bt_types.h
+++ b/stack/include/bt_types.h
@@ -561,15 +561,22 @@
#define BT_OCTET8_LEN 8
typedef uint8_t BT_OCTET8[BT_OCTET8_LEN]; /* octet array: size 16 */
-#define LINK_KEY_LEN 16
-typedef uint8_t LINK_KEY[LINK_KEY_LEN]; /* Link Key */
-
#define AMP_LINK_KEY_LEN 32
typedef uint8_t
AMP_LINK_KEY[AMP_LINK_KEY_LEN]; /* Dedicated AMP and GAMP Link Keys */
-#define BT_OCTET16_LEN 16
-typedef uint8_t BT_OCTET16[BT_OCTET16_LEN]; /* octet array: size 16 */
+/* Some C files include this header file */
+#ifdef __cplusplus
+
+#include <array>
+
+constexpr int OCTET16_LEN = 16;
+typedef std::array<uint8_t, OCTET16_LEN> Octet16;
+
+constexpr int LINK_KEY_LEN = OCTET16_LEN;
+typedef Octet16 LinkKey; /* Link Key */
+
+#endif
#define PIN_CODE_LEN 16
typedef uint8_t PIN_CODE[PIN_CODE_LEN]; /* Pin Code (upto 128 bits) MSB is 0 */
diff --git a/stack/include/btm_api.h b/stack/include/btm_api.h
index 146a1b8..457ae3d 100644
--- a/stack/include/btm_api.h
+++ b/stack/include/btm_api.h
@@ -1407,7 +1407,7 @@
******************************************************************************/
extern bool BTM_SecAddDevice(const RawAddress& bd_addr, DEV_CLASS dev_class,
BD_NAME bd_name, uint8_t* features,
- uint32_t trusted_mask[], LINK_KEY link_key,
+ uint32_t trusted_mask[], LinkKey* link_key,
uint8_t key_type, tBTM_IO_CAP io_cap,
uint8_t pin_length);
@@ -1445,7 +1445,7 @@
*
******************************************************************************/
extern tBTM_STATUS BTM_SecGetDeviceLinkKey(const RawAddress& bd_addr,
- LINK_KEY link_key);
+ LinkKey* link_key);
/*******************************************************************************
*
@@ -1661,7 +1661,7 @@
*
******************************************************************************/
extern void BTM_RemoteOobDataReply(tBTM_STATUS res, const RawAddress& bd_addr,
- BT_OCTET16 c, BT_OCTET16 r);
+ const Octet16& c, const Octet16& r);
/*******************************************************************************
*
@@ -1682,7 +1682,8 @@
*
******************************************************************************/
extern uint16_t BTM_BuildOobData(uint8_t* p_data, uint16_t max_len,
- BT_OCTET16 c, BT_OCTET16 r, uint8_t name_len);
+ const Octet16& c, const Octet16& r,
+ uint8_t name_len);
/*******************************************************************************
*
diff --git a/stack/include/btm_api_types.h b/stack/include/btm_api_types.h
index df7b64d..1ae47fe 100644
--- a/stack/include/btm_api_types.h
+++ b/stack/include/btm_api_types.h
@@ -1330,8 +1330,8 @@
*/
typedef uint8_t(tBTM_LINK_KEY_CALLBACK)(const RawAddress& bd_addr,
DEV_CLASS dev_class,
- tBTM_BD_NAME bd_name, uint8_t* key,
- uint8_t key_type);
+ tBTM_BD_NAME bd_name,
+ const LinkKey& key, uint8_t key_type);
/* Remote Name Resolved. Parameters are
* BD Address of remote
@@ -1478,8 +1478,8 @@
/* data type for BTM_SP_LOC_OOB_EVT */
typedef struct {
tBTM_STATUS status; /* */
- BT_OCTET16 c; /* Simple Pairing Hash C */
- BT_OCTET16 r; /* Simple Pairing Randomnizer R */
+ Octet16 c; /* Simple Pairing Hash C */
+ Octet16 r; /* Simple Pairing Randomnizer R */
} tBTM_SP_LOC_OOB;
/* data type for BTM_SP_RMT_OOB_EVT */
@@ -1629,7 +1629,7 @@
/* BLE encryption keys */
typedef struct {
- BT_OCTET16 ltk;
+ Octet16 ltk;
BT_OCTET8 rand;
uint16_t ediv;
uint8_t sec_level;
@@ -1639,13 +1639,13 @@
/* BLE CSRK keys */
typedef struct {
uint32_t counter;
- BT_OCTET16 csrk;
+ Octet16 csrk;
uint8_t sec_level;
} tBTM_LE_PCSRK_KEYS;
/* BLE Encryption reproduction keys */
typedef struct {
- BT_OCTET16 ltk;
+ Octet16 ltk;
uint16_t div;
uint8_t key_size;
uint8_t sec_level;
@@ -1656,11 +1656,11 @@
uint32_t counter;
uint16_t div;
uint8_t sec_level;
- BT_OCTET16 csrk;
+ Octet16 csrk;
} tBTM_LE_LCSRK_KEYS;
typedef struct {
- BT_OCTET16 irk;
+ Octet16 irk;
tBLE_ADDR_TYPE addr_type;
RawAddress static_addr;
} tBTM_LE_PID_KEYS;
@@ -1702,15 +1702,15 @@
#define BTM_BLE_KEY_TYPE_COUNTER 3 // tobe obsolete
typedef struct {
- BT_OCTET16 ir;
- BT_OCTET16 irk;
- BT_OCTET16 dhk;
+ Octet16 ir;
+ Octet16 irk;
+ Octet16 dhk;
} tBTM_BLE_LOCAL_ID_KEYS;
typedef union {
tBTM_BLE_LOCAL_ID_KEYS id_keys;
- BT_OCTET16 er;
+ Octet16 er;
} tBTM_BLE_LOCAL_KEYS;
/* New LE identity key for local device.
@@ -1806,63 +1806,6 @@
} tBTM_DELETE_STORED_LINK_KEY_COMPLETE;
-/* MIP evnets, callbacks */
-enum {
- BTM_MIP_MODE_CHG_EVT,
- BTM_MIP_DISCONNECT_EVT,
- BTM_MIP_PKTS_COMPL_EVT,
- BTM_MIP_RXDATA_EVT
-};
-typedef uint8_t tBTM_MIP_EVT;
-
-typedef struct {
- tBTM_MIP_EVT event;
- RawAddress bd_addr;
- uint16_t mip_id;
-} tBTM_MIP_MODE_CHANGE;
-
-typedef struct {
- tBTM_MIP_EVT event;
- uint16_t mip_id;
- uint8_t disc_reason;
-} tBTM_MIP_CONN_TIMEOUT;
-
-#define BTM_MIP_MAX_RX_LEN 17
-
-typedef struct {
- tBTM_MIP_EVT event;
- uint16_t mip_id;
- uint8_t rx_len;
- uint8_t rx_data[BTM_MIP_MAX_RX_LEN];
-} tBTM_MIP_RXDATA;
-
-typedef struct {
- tBTM_MIP_EVT event;
- RawAddress bd_addr;
- uint8_t data[11]; /* data[0] shows Vender-specific device type */
-} tBTM_MIP_EIR_HANDSHAKE;
-
-typedef struct {
- tBTM_MIP_EVT event;
- uint16_t num_sent; /* Completed packet count at the controller */
-} tBTM_MIP_PKTS_COMPL;
-
-typedef union {
- tBTM_MIP_EVT event;
- tBTM_MIP_MODE_CHANGE mod_chg;
- tBTM_MIP_CONN_TIMEOUT conn_tmo;
- tBTM_MIP_EIR_HANDSHAKE eir;
- tBTM_MIP_PKTS_COMPL completed;
- tBTM_MIP_RXDATA rxdata;
-} tBTM_MIP_EVENT_DATA;
-
-/* MIP event callback function */
-typedef void(tBTM_MIP_EVENTS_CB)(tBTM_MIP_EVT event, tBTM_MIP_EVENT_DATA data);
-
-/* MIP Device query callback function */
-typedef bool(tBTM_MIP_QUERY_CB)(const RawAddress& dev_addr, uint8_t* p_mode,
- LINK_KEY link_key);
-
/* ACL link on, SCO link ongoing, sniff mode */
#define BTM_CONTRL_ACTIVE 1
/* Scan state - paging/inquiry/trying to connect*/
diff --git a/stack/include/btm_ble_api.h b/stack/include/btm_ble_api.h
index f0fb9e6..bd991ef 100644
--- a/stack/include/btm_ble_api.h
+++ b/stack/include/btm_ble_api.h
@@ -196,43 +196,14 @@
tBTM_INQ_RESULTS_CB* p_results_cb,
tBTM_CMPL_CB* p_cmpl_cb);
-/*******************************************************************************
- *
- * Function BTM_GetDeviceIDRoot
- *
- * Description This function is called to read the local device identity
- * root.
- *
- * Returns void
- * the local device ER is copied into er
- *
- ******************************************************************************/
-extern void BTM_GetDeviceIDRoot(BT_OCTET16 ir);
+/** Returns local device encryption root (ER) */
+const Octet16& BTM_GetDeviceEncRoot();
-/*******************************************************************************
- *
- * Function BTM_GetDeviceEncRoot
- *
- * Description This function is called to read the local device encryption
- * root.
- *
- * Returns void
- * the local device ER is copied into er
- *
- ******************************************************************************/
-extern void BTM_GetDeviceEncRoot(BT_OCTET16 er);
+/** Returns local device identity root (IR) */
+extern const Octet16& BTM_GetDeviceIDRoot();
-/*******************************************************************************
- *
- * Function BTM_GetDeviceDHK
- *
- * Description This function is called to read the local device DHK.
- *
- * Returns void
- * the local device DHK is copied into dhk
- *
- ******************************************************************************/
-extern void BTM_GetDeviceDHK(BT_OCTET16 dhk);
+/** Return local device DHK. */
+extern const Octet16& BTM_GetDeviceDHK();
/*******************************************************************************
*
diff --git a/stack/include/btm_ble_api_types.h b/stack/include/btm_ble_api_types.h
index 327a2e6..d7b223f 100644
--- a/stack/include/btm_ble_api_types.h
+++ b/stack/include/btm_ble_api_types.h
@@ -135,7 +135,7 @@
#define BTM_BLE_CONN_SUP_TOUT_MAX 0x0C80
/* use this value when a specific value not to be overwritten */
#define BTM_BLE_CONN_PARAM_UNDEF 0xffff
-#define BTM_BLE_SCAN_PARAM_UNDEF 0xffffffff
+#define BTM_BLE_SCAN_PARAM_UNDEF 0xffff
/* default connection parameters if not configured, use GAP recommended value
* for auto/selective connection */
@@ -279,7 +279,7 @@
uint8_t status;
uint8_t param_len;
uint16_t opcode;
- uint8_t param_buf[BT_OCTET16_LEN];
+ uint8_t param_buf[OCTET16_LEN];
} tBTM_RAND_ENC;
/* General callback function for notifying an application that a synchronous
@@ -335,7 +335,8 @@
/* Preferred maximum number of microseconds that the local Controller
should use to transmit a single Link Layer Data Channel PDU. */
#define BTM_BLE_DATA_TX_TIME_MIN 0x0148
-#define BTM_BLE_DATA_TX_TIME_MAX 0x0848
+#define BTM_BLE_DATA_TX_TIME_MAX_LEGACY 0x0848
+#define BTM_BLE_DATA_TX_TIME_MAX 0x4290
/* adv tx power in dBm */
typedef struct {
diff --git a/stack/include/gatt_api.h b/stack/include/gatt_api.h
index f9c0642..74a9cf0 100644
--- a/stack/include/gatt_api.h
+++ b/stack/include/gatt_api.h
@@ -410,14 +410,6 @@
};
typedef uint8_t tGATT_DISC_TYPE;
-/* Discover parameters of different discovery types
-*/
-typedef struct {
- bluetooth::Uuid service;
- uint16_t s_handle;
- uint16_t e_handle;
-} tGATT_DISC_PARAM;
-
/* GATT read type enumeration
*/
enum {
@@ -825,13 +817,19 @@
*
* Parameters conn_id: connection identifier.
* disc_type:discovery type.
- * p_param: parameters of discovery requirement.
+ * start_handle and end_handle: range of handles for discovery
+ * uuid: uuid to discovery. set to Uuid::kEmpty for requests
+ * that don't need it
*
* Returns GATT_SUCCESS if command received/sent successfully.
*
******************************************************************************/
extern tGATT_STATUS GATTC_Discover(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
- tGATT_DISC_PARAM* p_param);
+ uint16_t start_handle, uint16_t end_handle,
+ const bluetooth::Uuid& uuid);
+extern tGATT_STATUS GATTC_Discover(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
+ uint16_t start_handle, uint16_t end_handle);
+
/*******************************************************************************
*
* Function GATTC_Read
diff --git a/stack/include/hcimsgs.h b/stack/include/hcimsgs.h
index a909751..1d89f31 100644
--- a/stack/include/hcimsgs.h
+++ b/stack/include/hcimsgs.h
@@ -128,7 +128,7 @@
/* Link Key Request Reply */
extern void btsnd_hcic_link_key_req_reply(const RawAddress& bd_addr,
- LINK_KEY link_key);
+ const LinkKey& link_key);
#define HCIC_PARAM_SIZE_LINK_KEY_REQ_REPLY 22
@@ -428,8 +428,8 @@
#define HCI_USER_PASSKEY_NEG_BD_ADDR_OFF 0
/* Remote OOB Data Request Reply */
-extern void btsnd_hcic_rem_oob_reply(const RawAddress& bd_addr, uint8_t* p_c,
- uint8_t* p_r);
+extern void btsnd_hcic_rem_oob_reply(const RawAddress& bd_addr,
+ const Octet16& c, const Octet16& r);
#define HCIC_PARAM_SIZE_REM_OOB_REPLY 38
@@ -667,7 +667,6 @@
* message size
******************************************************************************/
#define HCIC_BLE_RAND_DI_SIZE 8
-#define HCIC_BLE_ENCRYT_KEY_SIZE 16
#define HCIC_BLE_IRK_SIZE 16
#define HCIC_PARAM_SIZE_SET_USED_FEAT_CMD 8
@@ -787,11 +786,9 @@
extern void btsnd_hcic_ble_start_enc(uint16_t handle,
uint8_t rand[HCIC_BLE_RAND_DI_SIZE],
- uint16_t ediv,
- uint8_t ltk[HCIC_BLE_ENCRYT_KEY_SIZE]);
+ uint16_t ediv, const Octet16& ltk);
-extern void btsnd_hcic_ble_ltk_req_reply(uint16_t handle,
- uint8_t ltk[HCIC_BLE_ENCRYT_KEY_SIZE]);
+extern void btsnd_hcic_ble_ltk_req_reply(uint16_t handle, const Octet16& ltk);
extern void btsnd_hcic_ble_ltk_req_neg_reply(uint16_t handle);
@@ -827,9 +824,10 @@
uint16_t tx_octets,
uint16_t tx_time);
-extern void btsnd_hcic_ble_add_device_resolving_list(
- uint8_t addr_type_peer, const RawAddress& bda_peer,
- uint8_t irk_peer[HCIC_BLE_IRK_SIZE], uint8_t irk_local[HCIC_BLE_IRK_SIZE]);
+extern void btsnd_hcic_ble_add_device_resolving_list(uint8_t addr_type_peer,
+ const RawAddress& bda_peer,
+ const Octet16& irk_peer,
+ const Octet16& irk_local);
struct scanning_phy_cfg {
uint8_t scan_type;
@@ -864,10 +862,6 @@
uint8_t initiating_phys,
EXT_CONN_PHY_CFG* phy_cfg);
-extern void btsnd_hcic_ble_add_device_resolving_list(
- uint8_t addr_type_peer, const RawAddress& bda_peer,
- uint8_t irk_peer[HCIC_BLE_IRK_SIZE], uint8_t irk_local[HCIC_BLE_IRK_SIZE]);
-
extern void btsnd_hcic_ble_rm_device_resolving_list(uint8_t addr_type_peer,
const RawAddress& bda_peer);
diff --git a/stack/include/smp_api.h b/stack/include/smp_api.h
index 816407d..8a66aae 100644
--- a/stack/include/smp_api.h
+++ b/stack/include/smp_api.h
@@ -176,24 +176,6 @@
/*******************************************************************************
*
- * Function SMP_Encrypt
- *
- * Description Encrypt the data with the specified key.
- *
- * Parameters: key - Pointer to key key[0] conatins the MSB
- * key_len - key length
- * plain_text - Pointer to data to be encrypted
- * plain_text[0] conatins the MSB
- * pt_len - plain text length
- * p_out - pointer to the encrypted outputs
- *
- * Returns Boolean - true: encryption is successful
- ******************************************************************************/
-extern bool SMP_Encrypt(uint8_t* key, uint8_t key_len, uint8_t* plain_text,
- uint8_t pt_len, tSMP_ENC* p_out);
-
-/*******************************************************************************
- *
* Function SMP_KeypressNotification
*
* Description Notify SM about Keypress Notification.
@@ -227,16 +209,4 @@
// Proceed to send LTK, DIV and ER to master if bonding the devices.
extern void smp_link_encrypted(const RawAddress& bda, uint8_t encr_enable);
-//
-// The AES-CMAC Generation Function with tlen implemented.
-// |key| - CMAC key in little endian order, expect SRK when used by SMP.
-// |input| - text to be signed in little endian byte order.
-// |length| - length of the input in byte.
-// |tlen| - lenth of mac desired
-// |p_signature| - data pointer to where signed data to be stored, tlen long.
-// Returns false if out of resources, true in other cases.
-//
-bool aes_cipher_msg_auth_code(BT_OCTET16 key, uint8_t* input, uint16_t length,
- uint16_t tlen, uint8_t* p_signature);
-
#endif /* SMP_API_H */
diff --git a/stack/include/smp_api_types.h b/stack/include/smp_api_types.h
index f317993..cee1204 100644
--- a/stack/include/smp_api_types.h
+++ b/stack/include/smp_api_types.h
@@ -220,8 +220,8 @@
/* the data associated with the info sent to the peer via OOB interface */
typedef struct {
bool present;
- BT_OCTET16 randomizer;
- BT_OCTET16 commitment;
+ Octet16 randomizer;
+ Octet16 commitment;
tBLE_BD_ADDR addr_sent_to;
BT_OCTET32 private_key_used; /* is used to calculate: */
@@ -234,8 +234,8 @@
/* the data associated with the info received from the peer via OOB interface */
typedef struct {
bool present;
- BT_OCTET16 randomizer;
- BT_OCTET16 commitment;
+ Octet16 randomizer;
+ Octet16 commitment;
tBLE_BD_ADDR addr_rcvd_from;
} tSMP_PEER_OOB_DATA;
@@ -257,7 +257,7 @@
uint8_t status;
uint8_t param_len;
uint16_t opcode;
- uint8_t param_buf[BT_OCTET16_LEN];
+ uint8_t param_buf[OCTET16_LEN];
} tSMP_ENC;
/* Security Manager events - Called by the stack when Security Manager related
diff --git a/stack/l2cap/l2c_ble.cc b/stack/l2cap/l2c_ble.cc
index c82d3cf..528bdee 100644
--- a/stack/l2cap/l2c_ble.cc
+++ b/stack/l2cap/l2c_ble.cc
@@ -853,8 +853,12 @@
bool l2cble_init_direct_conn(tL2C_LCB* p_lcb) {
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_or_alloc_dev(p_lcb->remote_bd_addr);
tBTM_BLE_CB* p_cb = &btm_cb.ble_ctr_cb;
- uint16_t scan_int;
- uint16_t scan_win;
+ uint16_t scan_int = (p_cb->scan_int == BTM_BLE_SCAN_PARAM_UNDEF)
+ ? BTM_BLE_SCAN_FAST_INT
+ : p_cb->scan_int;
+ uint16_t scan_win = (p_cb->scan_win == BTM_BLE_SCAN_PARAM_UNDEF)
+ ? BTM_BLE_SCAN_FAST_WIN
+ : p_cb->scan_win;
RawAddress peer_addr;
uint8_t peer_addr_type = BLE_ADDR_PUBLIC;
uint8_t own_addr_type = BLE_ADDR_PUBLIC;
@@ -865,13 +869,6 @@
return (false);
}
- scan_int = (p_cb->scan_int == BTM_BLE_SCAN_PARAM_UNDEF)
- ? BTM_BLE_SCAN_FAST_INT
- : p_cb->scan_int;
- scan_win = (p_cb->scan_win == BTM_BLE_SCAN_PARAM_UNDEF)
- ? BTM_BLE_SCAN_FAST_WIN
- : p_cb->scan_win;
-
peer_addr_type = p_lcb->ble_addr_type;
peer_addr = p_lcb->remote_bd_addr;
diff --git a/stack/l2cap/l2c_utils.cc b/stack/l2cap/l2c_utils.cc
index cc16090..f43f4b4 100644
--- a/stack/l2cap/l2c_utils.cc
+++ b/stack/l2cap/l2c_utils.cc
@@ -2681,28 +2681,34 @@
/* Tell all registered fixed channels about the connection */
for (int xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++) {
+ uint16_t channel_id = xx + L2CAP_FIRST_FIXED_CHNL;
+
+ /* See BT Spec Ver 5.0 | Vol 3, Part A 2.1 table 2.1 and 2.2 */
+
/* skip sending LE fix channel callbacks on BR/EDR links */
if (p_lcb->transport == BT_TRANSPORT_BR_EDR &&
- xx + L2CAP_FIRST_FIXED_CHNL >= L2CAP_ATT_CID &&
- xx + L2CAP_FIRST_FIXED_CHNL <= L2CAP_SMP_CID)
+ channel_id >= L2CAP_ATT_CID && channel_id <= L2CAP_SMP_CID)
continue;
- if (l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb != NULL) {
- if (p_lcb->peer_chnl_mask[(xx + L2CAP_FIRST_FIXED_CHNL) / 8] &
- (1 << ((xx + L2CAP_FIRST_FIXED_CHNL) % 8))) {
- if (p_lcb->p_fixed_ccbs[xx])
- p_lcb->p_fixed_ccbs[xx]->chnl_state = CST_OPEN;
- (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL,
- p_lcb->remote_bd_addr, true, 0,
- p_lcb->transport);
- } else {
- (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(
- xx + L2CAP_FIRST_FIXED_CHNL, p_lcb->remote_bd_addr, false,
- p_lcb->disc_reason, p_lcb->transport);
- if (p_lcb->p_fixed_ccbs[xx]) {
- l2cu_release_ccb(p_lcb->p_fixed_ccbs[xx]);
- p_lcb->p_fixed_ccbs[xx] = NULL;
- }
+ /* skip sending BR fix channel callbacks on LE links */
+ if (p_lcb->transport == BT_TRANSPORT_LE && channel_id == L2CAP_SMP_BR_CID)
+ continue;
+
+ if (!l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb) continue;
+
+ if (p_lcb->peer_chnl_mask[(channel_id) / 8] & (1 << ((channel_id) % 8))) {
+ if (p_lcb->p_fixed_ccbs[xx])
+ p_lcb->p_fixed_ccbs[xx]->chnl_state = CST_OPEN;
+ (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(
+ channel_id, p_lcb->remote_bd_addr, true, 0, p_lcb->transport);
+ } else {
+ (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(
+ channel_id, p_lcb->remote_bd_addr, false, p_lcb->disc_reason,
+ p_lcb->transport);
+
+ if (p_lcb->p_fixed_ccbs[xx]) {
+ l2cu_release_ccb(p_lcb->p_fixed_ccbs[xx]);
+ p_lcb->p_fixed_ccbs[xx] = NULL;
}
}
}
diff --git a/stack/smp/crypto_toolbox.h b/stack/smp/crypto_toolbox.h
new file mode 100644
index 0000000..d3fceff
--- /dev/null
+++ b/stack/smp/crypto_toolbox.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 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 "stack/include/bt_types.h"
+
+/* Functions below implement cryptographic toolbox, as described in BT Spec
+ * Ver 5.0 | Vol 3, Part H CRYPTOGRAPHIC TOOLBOX. Please see the spec for
+ * description.
+ *
+ * Example of usage is avaliable in cryptographic_toolbox_test.cc */
+
+extern Octet16 smp_calculate_f4(uint8_t* u, uint8_t* v, const Octet16& x,
+ uint8_t z);
+extern uint32_t smp_calculate_g2(uint8_t* u, uint8_t* v, const Octet16& x,
+ const Octet16& y);
+extern void smp_calculate_f5(uint8_t* w, const Octet16& n1, const Octet16& n2,
+ uint8_t* a1, uint8_t* a2, Octet16* mac_key,
+ Octet16* ltk);
+extern Octet16 smp_calculate_f6(const Octet16& w, const Octet16& n1,
+ const Octet16& n2, const Octet16& r,
+ uint8_t* iocap, uint8_t* a1, uint8_t* a2);
+extern Octet16 smp_calculate_h6(const Octet16& w, std::array<uint8_t, 4> keyid);
+extern Octet16 smp_calculate_h7(const Octet16& salt, const Octet16& w);
+extern Octet16 smp_calculate_ltk_to_link_key(const Octet16& ltk, bool use_h7);
+extern Octet16 smp_calculate_link_key_to_ltk(const Octet16& link_key,
+ bool use_h7);
diff --git a/stack/smp/smp_act.cc b/stack/smp/smp_act.cc
index 2c657a5..f7bb30d 100644
--- a/stack/smp/smp_act.cc
+++ b/stack/smp/smp_act.cc
@@ -350,7 +350,7 @@
smp_send_cmd(SMP_OPCODE_MASTER_ID, p_cb);
/* save the DIV and key size information when acting as slave device */
- memcpy(le_key.ltk, p_cb->ltk, BT_OCTET16_LEN);
+ le_key.ltk = p_cb->ltk;
le_key.div = p_cb->div;
le_key.key_size = p_cb->loc_enc_size;
le_key.sec_level = p_cb->sec_level;
@@ -385,10 +385,7 @@
smp_key_distribution_by_transport(p_cb, NULL);
}
-/*******************************************************************************
- * Function smp_send_csrk_info
- * Description send CSRK command.
- ******************************************************************************/
+/** send CSRK command. */
void smp_send_csrk_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
tBTM_LE_LCSRK_KEYS key;
SMP_TRACE_DEBUG("%s", __func__);
@@ -398,7 +395,7 @@
key.div = p_cb->div;
key.sec_level = p_cb->sec_level;
key.counter = 0; /* initialize the local counter */
- memcpy(key.csrk, p_cb->csrk, BT_OCTET16_LEN);
+ key.csrk = p_cb->csrk;
btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LCSRK,
(tBTM_LE_KEY_VALUE*)&key, true);
}
@@ -412,8 +409,11 @@
******************************************************************************/
void smp_send_ltk_reply(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
SMP_TRACE_DEBUG("%s", __func__);
+
+ Octet16 stk;
+ memcpy(stk.data(), p_data->key.p_data, stk.size());
/* send stk as LTK response */
- btm_ble_ltk_request_reply(p_cb->pairing_bda, true, p_data->key.p_data);
+ btm_ble_ltk_request_reply(p_cb->pairing_bda, true, stk);
}
/*******************************************************************************
@@ -585,10 +585,7 @@
}
}
-/*******************************************************************************
- * Function smp_proc_confirm
- * Description process pairing confirm from peer device
- ******************************************************************************/
+/** process pairing confirm from peer device */
void smp_proc_confirm(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
uint8_t* p = p_data->p_data;
@@ -603,16 +600,13 @@
if (p != NULL) {
/* save the SConfirm for comparison later */
- STREAM_TO_ARRAY(p_cb->rconfirm, p, BT_OCTET16_LEN);
+ STREAM_TO_ARRAY(p_cb->rconfirm.data(), p, OCTET16_LEN);
}
p_cb->flags |= SMP_PAIR_FLAGS_CMD_CONFIRM;
}
-/*******************************************************************************
- * Function smp_proc_init
- * Description process pairing initializer from peer device
- ******************************************************************************/
+/** process pairing initializer from peer device */
void smp_proc_init(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
uint8_t* p = p_data->p_data;
@@ -626,7 +620,7 @@
}
/* save the SRand for comparison */
- STREAM_TO_ARRAY(p_cb->rrand, p, BT_OCTET16_LEN);
+ STREAM_TO_ARRAY(p_cb->rrand.data(), p, OCTET16_LEN);
}
/*******************************************************************************
@@ -646,7 +640,7 @@
}
/* save the SRand for comparison */
- STREAM_TO_ARRAY(p_cb->rrand, p, BT_OCTET16_LEN);
+ STREAM_TO_ARRAY(p_cb->rrand.data(), p, OCTET16_LEN);
}
/*******************************************************************************
@@ -695,7 +689,7 @@
p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_COMM;
if (p != NULL) {
- STREAM_TO_ARRAY(p_cb->remote_commitment, p, BT_OCTET16_LEN);
+ STREAM_TO_ARRAY(p_cb->remote_commitment.data(), p, OCTET16_LEN);
}
}
@@ -716,7 +710,7 @@
}
if (p != NULL) {
- STREAM_TO_ARRAY(p_cb->remote_dhkey_check, p, BT_OCTET16_LEN);
+ STREAM_TO_ARRAY(p_cb->remote_dhkey_check.data(), p, OCTET16_LEN);
}
p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_DHK_CHK;
@@ -895,22 +889,17 @@
}
}
-/*******************************************************************************
- * Function smp_proc_enc_info
- * Description process encryption information from peer device
- ******************************************************************************/
+/** process encryption information from peer device */
void smp_proc_enc_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
uint8_t* p = p_data->p_data;
SMP_TRACE_DEBUG("%s", __func__);
- STREAM_TO_ARRAY(p_cb->ltk, p, BT_OCTET16_LEN);
+ STREAM_TO_ARRAY(p_cb->ltk.data(), p, OCTET16_LEN);
smp_key_distribution(p_cb, NULL);
}
-/*******************************************************************************
- * Function smp_proc_master_id
- * Description process master ID from slave device
- ******************************************************************************/
+
+/** process master ID from slave device */
void smp_proc_master_id(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
uint8_t* p = p_data->p_data;
tBTM_LE_PENC_KEYS le_key;
@@ -922,7 +911,7 @@
STREAM_TO_ARRAY(le_key.rand, p, BT_OCTET8_LEN);
/* store the encryption keys from peer device */
- memcpy(le_key.ltk, p_cb->ltk, BT_OCTET16_LEN);
+ le_key.ltk = p_cb->ltk;
le_key.sec_level = p_cb->sec_level;
le_key.key_size = p_cb->loc_enc_size;
@@ -934,22 +923,16 @@
smp_key_distribution(p_cb, NULL);
}
-/*******************************************************************************
- * Function smp_proc_enc_info
- * Description process identity information from peer device
- ******************************************************************************/
+/** process identity information from peer device */
void smp_proc_id_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
uint8_t* p = p_data->p_data;
SMP_TRACE_DEBUG("%s", __func__);
- STREAM_TO_ARRAY(p_cb->tk, p, BT_OCTET16_LEN); /* reuse TK for IRK */
+ STREAM_TO_ARRAY(p_cb->tk.data(), p, OCTET16_LEN); /* reuse TK for IRK */
smp_key_distribution_by_transport(p_cb, NULL);
}
-/*******************************************************************************
- * Function smp_proc_id_addr
- * Description process identity address from peer device
- ******************************************************************************/
+/** process identity address from peer device */
void smp_proc_id_addr(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
uint8_t* p = p_data->p_data;
tBTM_LE_PID_KEYS pid_key;
@@ -959,7 +942,7 @@
STREAM_TO_UINT8(pid_key.addr_type, p);
STREAM_TO_BDADDR(pid_key.static_addr, p);
- memcpy(pid_key.irk, p_cb->tk, BT_OCTET16_LEN);
+ pid_key.irk = p_cb->tk;
/* to use as BD_ADDR for lk derived from ltk */
p_cb->id_addr_rcvd = true;
@@ -974,10 +957,7 @@
smp_key_distribution_by_transport(p_cb, NULL);
}
-/*******************************************************************************
- * Function smp_proc_srk_info
- * Description process security information from peer device
- ******************************************************************************/
+/* process security information from peer device */
void smp_proc_srk_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
tBTM_LE_PCSRK_KEYS le_key;
@@ -988,7 +968,7 @@
le_key.sec_level = p_cb->sec_level;
/* get peer CSRK */
- maybe_non_aligned_memcpy(le_key.csrk, p_data->p_data, BT_OCTET16_LEN);
+ maybe_non_aligned_memcpy(le_key.csrk.data(), p_data->p_data, OCTET16_LEN);
/* initialize the peer counter */
le_key.counter = 0;
@@ -1006,7 +986,7 @@
******************************************************************************/
void smp_proc_compare(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
SMP_TRACE_DEBUG("%s", __func__);
- if (!memcmp(p_cb->rconfirm, p_data->key.p_data, BT_OCTET16_LEN)) {
+ if (!memcmp(p_cb->rconfirm.data(), p_data->key.p_data, OCTET16_LEN)) {
/* compare the max encryption key size, and save the smaller one for the
* link */
if (p_cb->peer_enc_size < p_cb->loc_enc_size)
@@ -1056,10 +1036,12 @@
tBTM_STATUS cmd;
SMP_TRACE_DEBUG("%s", __func__);
- if (p_data != NULL)
- cmd = btm_ble_start_encrypt(p_cb->pairing_bda, true, p_data->key.p_data);
- else
+ if (p_data != NULL) {
+ cmd = btm_ble_start_encrypt(p_cb->pairing_bda, true,
+ (Octet16*)p_data->key.p_data);
+ } else {
cmd = btm_ble_start_encrypt(p_cb->pairing_bda, false, NULL);
+ }
if (cmd != BTM_CMD_STARTED && cmd != BTM_BUSY) {
tSMP_INT_DATA smp_int_data;
@@ -1244,10 +1226,10 @@
tSMP_KEY key;
key.key_type = SMP_KEY_TYPE_TK;
- key.p_data = p_cb->tk;
+ key.p_data = p_cb->tk.data();
smp_int_data.key = key;
- memset(p_cb->tk, 0, BT_OCTET16_LEN);
+ p_cb->tk = {0};
/* TK, ready */
int_evt = SMP_KEY_READY_EVT;
}
@@ -1448,7 +1430,7 @@
switch (p_cb->selected_association_model) {
case SMP_MODEL_SEC_CONN_JUSTWORKS:
case SMP_MODEL_SEC_CONN_NUM_COMP:
- memset(p_cb->local_random, 0, BT_OCTET16_LEN);
+ p_cb->local_random = {0};
smp_start_nonce_generation(p_cb);
break;
case SMP_MODEL_SEC_CONN_PASSKEY_ENT:
@@ -1638,10 +1620,10 @@
* received from the peer DHKey check value.
******************************************************************************/
void smp_match_dhkey_checks(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
-
SMP_TRACE_DEBUG("%s", __func__);
- if (memcmp(p_data->key.p_data, p_cb->remote_dhkey_check, BT_OCTET16_LEN)) {
+ if (memcmp(p_data->key.p_data, p_cb->remote_dhkey_check.data(),
+ OCTET16_LEN)) {
SMP_TRACE_WARNING("dhkey chcks do no match");
tSMP_INT_DATA smp_int_data;
smp_int_data.status = SMP_DHKEY_CHK_FAIL;
@@ -1727,10 +1709,10 @@
uint8_t* p = NULL;
SMP_TRACE_DEBUG("%s", __func__);
- p = p_cb->local_random;
+ p = p_cb->local_random.data();
UINT32_TO_STREAM(p, p_data->passkey);
- p = p_cb->peer_random;
+ p = p_cb->peer_random.data();
UINT32_TO_STREAM(p, p_data->passkey);
p_cb->round = 0;
@@ -1747,21 +1729,18 @@
tSMP_SC_OOB_DATA* p_sc_oob_data = &p_cb->sc_oob_data;
if (p_sc_oob_data->loc_oob_data.present) {
- memcpy(p_cb->local_random, p_sc_oob_data->loc_oob_data.randomizer,
- sizeof(p_cb->local_random));
+ p_cb->local_random = p_sc_oob_data->loc_oob_data.randomizer;
} else {
SMP_TRACE_EVENT("%s: local OOB randomizer is absent", __func__);
- memset(p_cb->local_random, 0, sizeof(p_cb->local_random));
+ p_cb->local_random = {0};
}
if (!p_sc_oob_data->peer_oob_data.present) {
SMP_TRACE_EVENT("%s: peer OOB data is absent", __func__);
- memset(p_cb->peer_random, 0, sizeof(p_cb->peer_random));
+ p_cb->peer_random = {0};
} else {
- memcpy(p_cb->peer_random, p_sc_oob_data->peer_oob_data.randomizer,
- sizeof(p_cb->peer_random));
- memcpy(p_cb->remote_commitment, p_sc_oob_data->peer_oob_data.commitment,
- sizeof(p_cb->remote_commitment));
+ p_cb->peer_random = p_sc_oob_data->peer_oob_data.randomizer;
+ p_cb->remote_commitment = p_sc_oob_data->peer_oob_data.commitment;
/* check commitment */
if (!smp_check_commitment(p_cb)) {
@@ -1777,7 +1756,7 @@
SMP_TRACE_EVENT(
"%s: peer didn't receive local OOB data, set local randomizer to 0",
__func__);
- memset(p_cb->local_random, 0, sizeof(p_cb->local_random));
+ p_cb->local_random = {0};
}
}
@@ -1809,12 +1788,12 @@
******************************************************************************/
void smp_set_local_oob_random_commitment(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
SMP_TRACE_DEBUG("%s", __func__);
- memcpy(p_cb->sc_oob_data.loc_oob_data.randomizer, p_cb->rand, BT_OCTET16_LEN);
+ p_cb->sc_oob_data.loc_oob_data.randomizer = p_cb->rand;
- smp_calculate_f4(p_cb->sc_oob_data.loc_oob_data.publ_key_used.x,
- p_cb->sc_oob_data.loc_oob_data.publ_key_used.x,
- p_cb->sc_oob_data.loc_oob_data.randomizer, 0,
- p_cb->sc_oob_data.loc_oob_data.commitment);
+ p_cb->sc_oob_data.loc_oob_data.commitment =
+ crypto_toolbox::f4(p_cb->sc_oob_data.loc_oob_data.publ_key_used.x,
+ p_cb->sc_oob_data.loc_oob_data.publ_key_used.x,
+ p_cb->sc_oob_data.loc_oob_data.randomizer, 0);
#if (SMP_DEBUG == TRUE)
uint8_t* p_print = NULL;
@@ -1832,9 +1811,9 @@
smp_debug_print_nbyte_little_endian(p_print, "publ_key_used.y",
BT_OCTET32_LEN);
p_print = (uint8_t*)&p_cb->sc_oob_data.loc_oob_data.randomizer;
- smp_debug_print_nbyte_little_endian(p_print, "randomizer", BT_OCTET16_LEN);
+ smp_debug_print_nbyte_little_endian(p_print, "randomizer", OCTET16_LEN);
p_print = (uint8_t*)&p_cb->sc_oob_data.loc_oob_data.commitment;
- smp_debug_print_nbyte_little_endian(p_print, "commitment", BT_OCTET16_LEN);
+ smp_debug_print_nbyte_little_endian(p_print, "commitment", OCTET16_LEN);
SMP_TRACE_DEBUG("");
#endif
diff --git a/stack/smp/smp_api.cc b/stack/smp/smp_api.cc
index d096da5..baa41cf 100644
--- a/stack/smp/smp_api.cc
+++ b/stack/smp/smp_api.cc
@@ -328,7 +328,7 @@
smp_int_data.passkey = passkey;
smp_sm_event(&smp_cb, SMP_SC_KEY_READY_EVT, &smp_int_data);
} else {
- smp_convert_string_to_tk(p_cb->tk, passkey);
+ smp_convert_string_to_tk(&p_cb->tk, passkey);
}
return;
@@ -406,12 +406,12 @@
smp_int_data.status = SMP_OOB_FAIL;
smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
} else {
- if (len > BT_OCTET16_LEN) len = BT_OCTET16_LEN;
+ if (len > OCTET16_LEN) len = OCTET16_LEN;
- memcpy(p_cb->tk, p_data, len);
+ memcpy(p_cb->tk.data(), p_data, len);
key.key_type = SMP_KEY_TYPE_TK;
- key.p_data = p_cb->tk;
+ key.p_data = p_cb->tk.data();
tSMP_INT_DATA smp_int_data;
smp_int_data.key = key;
@@ -484,31 +484,6 @@
/*******************************************************************************
*
- * Function SMP_Encrypt
- *
- * Description This function is called to encrypt the data with the
- * specified key
- *
- * Parameters: key - Pointer to key key[0] conatins the MSB
- * key_len - key length
- * plain_text - Pointer to data to be encrypted
- * plain_text[0] conatins the MSB
- * pt_len - plain text length
- * p_out - output of the encrypted texts
- *
- * Returns Boolean - request is successful
- ******************************************************************************/
-bool SMP_Encrypt(uint8_t* key, uint8_t key_len, uint8_t* plain_text,
- uint8_t pt_len, tSMP_ENC* p_out)
-
-{
- bool status = false;
- status = smp_encrypt_data(key, key_len, plain_text, pt_len, p_out);
- return status;
-}
-
-/*******************************************************************************
- *
* Function SMP_KeypressNotification
*
* Description This function is called to notify Security Manager about
diff --git a/stack/smp/smp_cmac.cc b/stack/smp/smp_cmac.cc
deleted file mode 100644
index 42f91a0..0000000
--- a/stack/smp/smp_cmac.cc
+++ /dev/null
@@ -1,313 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2008-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.
- *
- ******************************************************************************/
-
-/******************************************************************************
- *
- * This file contains the implementation of the AES128 CMAC algorithm.
- *
- ******************************************************************************/
-
-#include "bt_target.h"
-
-#include <stdio.h>
-#include <string.h>
-
-#include "btm_ble_api.h"
-#include "hcimsgs.h"
-#include "smp_int.h"
-
-typedef struct {
- uint8_t* text;
- uint16_t len;
- uint16_t round;
-} tCMAC_CB;
-
-tCMAC_CB cmac_cb;
-
-/* Rb for AES-128 as block cipher, LSB as [0] */
-BT_OCTET16 const_Rb = {0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-
-void print128(BT_OCTET16 x, const uint8_t* key_name) {
-#if (SMP_DEBUG == TRUE && SMP_DEBUG_VERBOSE == TRUE)
- uint8_t* p = (uint8_t*)x;
- uint8_t i;
-
- SMP_TRACE_WARNING("%s(MSB ~ LSB) = ", key_name);
-
- for (i = 0; i < 4; i++) {
- SMP_TRACE_WARNING("%02x %02x %02x %02x", p[BT_OCTET16_LEN - i * 4 - 1],
- p[BT_OCTET16_LEN - i * 4 - 2],
- p[BT_OCTET16_LEN - i * 4 - 3],
- p[BT_OCTET16_LEN - i * 4 - 4]);
- }
-#endif
-}
-
-/*******************************************************************************
- *
- * Function padding
- *
- * Description utility function to padding the given text to be a 128 bits
- * data. The parameter dest is input and output parameter, it
- * must point to a BT_OCTET16_LEN memory space; where include
- * length bytes valid data.
- *
- * Returns void
- *
- ******************************************************************************/
-static void padding(BT_OCTET16 dest, uint8_t length) {
- uint8_t i, *p = dest;
- /* original last block */
- for (i = length; i < BT_OCTET16_LEN; i++)
- p[BT_OCTET16_LEN - i - 1] = (i == length) ? 0x80 : 0;
-}
-/*******************************************************************************
- *
- * Function leftshift_onebit
- *
- * Description utility function to left shift one bit for a 128 bits value.
- *
- * Returns void
- *
- ******************************************************************************/
-static void leftshift_onebit(uint8_t* input, uint8_t* output) {
- uint8_t i, overflow = 0, next_overflow = 0;
- SMP_TRACE_EVENT("leftshift_onebit ");
- /* input[0] is LSB */
- for (i = 0; i < BT_OCTET16_LEN; i++) {
- next_overflow = (input[i] & 0x80) ? 1 : 0;
- output[i] = (input[i] << 1) | overflow;
- overflow = next_overflow;
- }
- return;
-}
-/*******************************************************************************
- *
- * Function cmac_aes_cleanup
- *
- * Description clean up function for AES_CMAC algorithm.
- *
- * Returns void
- *
- ******************************************************************************/
-static void cmac_aes_cleanup(void) {
- osi_free(cmac_cb.text);
- memset(&cmac_cb, 0, sizeof(tCMAC_CB));
-}
-
-/*******************************************************************************
- *
- * Function cmac_aes_k_calculate
- *
- * Description This function is the calculation of block cipher using
- * AES-128.
- *
- * Returns void
- *
- ******************************************************************************/
-static bool cmac_aes_k_calculate(BT_OCTET16 key, uint8_t* p_signature,
- uint16_t tlen) {
- tSMP_ENC output;
- uint8_t i = 1, err = 0;
- uint8_t x[16] = {0};
- uint8_t* p_mac;
-
- SMP_TRACE_EVENT("cmac_aes_k_calculate ");
-
- while (i <= cmac_cb.round) {
- smp_xor_128(&cmac_cb.text[(cmac_cb.round - i) * BT_OCTET16_LEN],
- x); /* Mi' := Mi (+) X */
-
- if (!SMP_Encrypt(key, BT_OCTET16_LEN,
- &cmac_cb.text[(cmac_cb.round - i) * BT_OCTET16_LEN],
- BT_OCTET16_LEN, &output)) {
- err = 1;
- break;
- }
-
- memcpy(x, output.param_buf, BT_OCTET16_LEN);
- i++;
- }
-
- if (!err) {
- p_mac = output.param_buf + (BT_OCTET16_LEN - tlen);
- memcpy(p_signature, p_mac, tlen);
-
- SMP_TRACE_DEBUG("tlen = %d p_mac = %d", tlen, p_mac);
- SMP_TRACE_DEBUG(
- "p_mac[0] = 0x%02x p_mac[1] = 0x%02x p_mac[2] = 0x%02x p_mac[3] = "
- "0x%02x",
- *p_mac, *(p_mac + 1), *(p_mac + 2), *(p_mac + 3));
- SMP_TRACE_DEBUG(
- "p_mac[4] = 0x%02x p_mac[5] = 0x%02x p_mac[6] = 0x%02x p_mac[7] = "
- "0x%02x",
- *(p_mac + 4), *(p_mac + 5), *(p_mac + 6), *(p_mac + 7));
-
- return true;
-
- } else
- return false;
-}
-/*******************************************************************************
- *
- * Function cmac_prepare_last_block
- *
- * Description This function proceeed to prepare the last block of message
- * Mn depending on the size of the message.
- *
- * Returns void
- *
- ******************************************************************************/
-static void cmac_prepare_last_block(BT_OCTET16 k1, BT_OCTET16 k2) {
- // uint8_t x[16] = {0};
- bool flag;
-
- SMP_TRACE_EVENT("cmac_prepare_last_block ");
- /* last block is a complete block set flag to 1 */
- flag =
- ((cmac_cb.len % BT_OCTET16_LEN) == 0 && cmac_cb.len != 0) ? true : false;
-
- SMP_TRACE_WARNING("flag = %d round = %d", flag, cmac_cb.round);
-
- if (flag) { /* last block is complete block */
- smp_xor_128(&cmac_cb.text[0], k1);
- } else /* padding then xor with k2 */
- {
- padding(&cmac_cb.text[0], (uint8_t)(cmac_cb.len % 16));
-
- smp_xor_128(&cmac_cb.text[0], k2);
- }
-}
-/*******************************************************************************
- *
- * Function cmac_subkey_cont
- *
- * Description This is the callback function when CIPHk(0[128]) is
- * completed.
- *
- * Returns void
- *
- ******************************************************************************/
-static void cmac_subkey_cont(tSMP_ENC* p) {
- uint8_t k1[BT_OCTET16_LEN], k2[BT_OCTET16_LEN];
- uint8_t* pp = p->param_buf;
- SMP_TRACE_EVENT("cmac_subkey_cont ");
- print128(pp, (const uint8_t*)"K1 before shift");
-
- /* If MSB(L) = 0, then K1 = L << 1 */
- if ((pp[BT_OCTET16_LEN - 1] & 0x80) != 0) {
- /* Else K1 = ( L << 1 ) (+) Rb */
- leftshift_onebit(pp, k1);
- smp_xor_128(k1, const_Rb);
- } else {
- leftshift_onebit(pp, k1);
- }
-
- if ((k1[BT_OCTET16_LEN - 1] & 0x80) != 0) {
- /* K2 = (K1 << 1) (+) Rb */
- leftshift_onebit(k1, k2);
- smp_xor_128(k2, const_Rb);
- } else {
- /* If MSB(K1) = 0, then K2 = K1 << 1 */
- leftshift_onebit(k1, k2);
- }
-
- print128(k1, (const uint8_t*)"K1");
- print128(k2, (const uint8_t*)"K2");
-
- cmac_prepare_last_block(k1, k2);
-}
-/*******************************************************************************
- *
- * Function cmac_generate_subkey
- *
- * Description This is the function to generate the two subkeys.
- *
- * Parameters key - CMAC key, expect SRK when used by SMP.
- *
- * Returns void
- *
- ******************************************************************************/
-static bool cmac_generate_subkey(BT_OCTET16 key) {
- BT_OCTET16 z = {0};
- bool ret = true;
- tSMP_ENC output;
- SMP_TRACE_EVENT(" cmac_generate_subkey");
-
- if (SMP_Encrypt(key, BT_OCTET16_LEN, z, BT_OCTET16_LEN, &output)) {
- cmac_subkey_cont(&output);
- ;
- } else
- ret = false;
-
- return ret;
-}
-/*******************************************************************************
- *
- * Function aes_cipher_msg_auth_code
- *
- * Description This is the AES-CMAC Generation Function with tlen
- * implemented.
- *
- * Parameters key - CMAC key in little endian order, expect SRK when used
- * by SMP.
- * input - text to be signed in little endian byte order.
- * length - length of the input in byte.
- * tlen - lenth of mac desired
- * p_signature - data pointer to where signed data to be
- * stored, tlen long.
- *
- * Returns false if out of resources, true in other cases.
- *
- ******************************************************************************/
-bool aes_cipher_msg_auth_code(BT_OCTET16 key, uint8_t* input, uint16_t length,
- uint16_t tlen, uint8_t* p_signature) {
- uint16_t len, diff;
- uint16_t n = (length + BT_OCTET16_LEN - 1) /
- BT_OCTET16_LEN; /* n is number of rounds */
- bool ret = false;
-
- SMP_TRACE_EVENT("%s", __func__);
-
- if (n == 0) n = 1;
- len = n * BT_OCTET16_LEN;
-
- SMP_TRACE_WARNING("AES128_CMAC started, allocate buffer size = %d", len);
- /* allocate a memory space of multiple of 16 bytes to hold text */
- cmac_cb.text = (uint8_t*)osi_calloc(len);
- cmac_cb.round = n;
- diff = len - length;
-
- if (input != NULL && length > 0) {
- memcpy(&cmac_cb.text[diff], input, (int)length);
- cmac_cb.len = length;
- } else {
- cmac_cb.len = 0;
- }
-
- /* prepare calculation for subkey s and last block of data */
- if (cmac_generate_subkey(key)) {
- /* start calculation */
- ret = cmac_aes_k_calculate(key, p_signature, tlen);
- }
- /* clean up */
- cmac_aes_cleanup();
-
- return ret;
-}
diff --git a/stack/smp/smp_int.h b/stack/smp/smp_int.h
index c3ad35d..c6fdf71 100644
--- a/stack/smp/smp_int.h
+++ b/stack/smp/smp_int.h
@@ -28,6 +28,7 @@
#include "btm_ble_api.h"
#include "btu.h"
#include "smp_api.h"
+#include "stack/crypto_toolbox/crypto_toolbox.h"
/* Legacy mode */
#define SMP_MODEL_ENCRYPTION_ONLY 0 /* Just Works model */
@@ -244,10 +245,6 @@
/* check if authentication requirement need MITM protection */
#define SMP_NO_MITM_REQUIRED(x) (((x)&SMP_AUTH_YN_BIT) == 0)
-#define SMP_ENCRYT_KEY_SIZE 16
-#define SMP_ENCRYT_DATA_SIZE 16
-#define SMP_ECNCRPYT_STATUS HCI_SUCCESS
-
typedef struct {
RawAddress bd_addr;
BT_HDR* p_copy;
@@ -273,18 +270,18 @@
uint8_t cb_evt;
tSMP_SEC_LEVEL sec_level;
bool connect_initialized;
- BT_OCTET16 confirm;
- BT_OCTET16 rconfirm;
- BT_OCTET16 rrand; /* for SC this is peer nonce */
- BT_OCTET16 rand; /* for SC this is local nonce */
+ Octet16 confirm;
+ Octet16 rconfirm;
+ Octet16 rrand; /* for SC this is peer nonce */
+ Octet16 rand; /* for SC this is local nonce */
BT_OCTET32 private_key;
BT_OCTET32 dhkey;
- BT_OCTET16 commitment;
- BT_OCTET16 remote_commitment;
- BT_OCTET16 local_random; /* local randomizer - passkey or OOB randomizer */
- BT_OCTET16 peer_random; /* peer randomizer - passkey or OOB randomizer */
- BT_OCTET16 dhkey_check;
- BT_OCTET16 remote_dhkey_check;
+ Octet16 commitment;
+ Octet16 remote_commitment;
+ Octet16 local_random; /* local randomizer - passkey or OOB randomizer */
+ Octet16 peer_random; /* peer randomizer - passkey or OOB randomizer */
+ Octet16 dhkey_check;
+ Octet16 remote_dhkey_check;
tSMP_PUBLIC_KEY loc_publ_key;
tSMP_PUBLIC_KEY peer_publ_key;
tSMP_OOB_DATA_TYPE req_oob_type;
@@ -307,7 +304,7 @@
uint8_t
round; /* authentication stage 1 round for passkey association model */
uint32_t number_to_display;
- BT_OCTET16 mac_key;
+ Octet16 mac_key;
uint8_t peer_enc_size;
uint8_t loc_enc_size;
uint8_t peer_i_key;
@@ -315,10 +312,10 @@
uint8_t local_i_key;
uint8_t local_r_key;
- BT_OCTET16 tk;
- BT_OCTET16 ltk;
+ Octet16 tk;
+ Octet16 ltk;
uint16_t div;
- BT_OCTET16 csrk; /* storage for local CSRK */
+ Octet16 csrk; /* storage for local CSRK */
uint16_t ediv;
BT_OCTET8 enc_rand;
uint8_t addr_type;
@@ -345,29 +342,6 @@
extern void smp_sm_event(tSMP_CB* p_cb, tSMP_EVENT event,
tSMP_INT_DATA* p_data);
-extern void smp_proc_sec_request(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
-extern void smp_set_fail_nc(bool enable);
-extern void smp_set_fail_conf(bool enable);
-extern void smp_set_passk_entry_fail(bool enable);
-extern void smp_set_oob_fail(bool enable);
-extern void smp_set_peer_sc_notif(bool enable);
-extern void smp_aes_cmac_rfc4493_chk(uint8_t* key, uint8_t* msg,
- uint8_t msg_len, uint8_t mac_len,
- uint8_t* mac);
-extern void smp_f4_calc_chk(uint8_t* U, uint8_t* V, uint8_t* X, uint8_t* Z,
- uint8_t* mac);
-extern void smp_g2_calc_chk(uint8_t* U, uint8_t* V, uint8_t* X, uint8_t* Y);
-extern void smp_h6_calc_chk(uint8_t* key, uint8_t* key_id, uint8_t* mac);
-extern void smp_f5_key_calc_chk(uint8_t* w, uint8_t* mac);
-extern void smp_f5_mackey_or_ltk_calc_chk(uint8_t* t, uint8_t* counter,
- uint8_t* key_id, uint8_t* n1,
- uint8_t* n2, uint8_t* a1, uint8_t* a2,
- uint8_t* length, uint8_t* mac);
-extern void smp_f5_calc_chk(uint8_t* w, uint8_t* n1, uint8_t* n2, uint8_t* a1,
- uint8_t* a2, uint8_t* mac_key, uint8_t* ltk);
-extern void smp_f6_calc_chk(uint8_t* w, uint8_t* n1, uint8_t* n2, uint8_t* r,
- uint8_t* iocap, uint8_t* a1, uint8_t* a2,
- uint8_t* mac);
extern tSMP_STATE smp_get_state(void);
extern void smp_set_state(tSMP_STATE state);
@@ -470,13 +444,10 @@
extern void smp_cb_cleanup(tSMP_CB* p_cb);
extern void smp_reset_control_value(tSMP_CB* p_cb);
extern void smp_proc_pairing_cmpl(tSMP_CB* p_cb);
-extern void smp_convert_string_to_tk(BT_OCTET16 tk, uint32_t passkey);
-extern void smp_mask_enc_key(uint8_t loc_enc_size, uint8_t* p_data);
+extern void smp_convert_string_to_tk(Octet16* tk, uint32_t passkey);
+extern void smp_mask_enc_key(uint8_t loc_enc_size, Octet16* p_data);
extern void smp_rsp_timeout(void* data);
extern void smp_delayed_auth_complete_timeout(void* data);
-extern void smp_xor_128(BT_OCTET16 a, BT_OCTET16 b);
-extern bool smp_encrypt_data(uint8_t* key, uint8_t key_len, uint8_t* plain_text,
- uint8_t pt_len, tSMP_ENC* p_out);
extern bool smp_command_has_invalid_parameters(tSMP_CB* p_cb);
extern void smp_reject_unexpected_pairing_command(const RawAddress& bd_addr);
extern tSMP_ASSO_MODEL smp_select_association_model(tSMP_CB* p_cb);
@@ -488,7 +459,7 @@
extern void smp_collect_peer_ble_address(uint8_t* le_addr, tSMP_CB* p_cb);
extern bool smp_check_commitment(tSMP_CB* p_cb);
extern void smp_save_secure_connections_long_term_key(tSMP_CB* p_cb);
-extern bool smp_calculate_f5_mackey_and_long_term_key(tSMP_CB* p_cb);
+extern void smp_calculate_f5_mackey_and_long_term_key(tSMP_CB* p_cb);
extern void smp_remove_fixed_channel(tSMP_CB* p_cb);
extern bool smp_request_oob_data(tSMP_CB* p_cb);
@@ -504,7 +475,7 @@
extern void smp_use_oob_private_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
extern void smp_compute_dhkey(tSMP_CB* p_cb);
extern void smp_calculate_local_commitment(tSMP_CB* p_cb);
-extern void smp_calculate_peer_commitment(tSMP_CB* p_cb, BT_OCTET16 output_buf);
+extern Octet16 smp_calculate_peer_commitment(tSMP_CB* p_cb);
extern void smp_calculate_numeric_comparison_display_number(
tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
extern void smp_calculate_local_dhkey_check(tSMP_CB* p_cb,
@@ -514,31 +485,21 @@
extern void smp_start_nonce_generation(tSMP_CB* p_cb);
extern bool smp_calculate_link_key_from_long_term_key(tSMP_CB* p_cb);
extern bool smp_calculate_long_term_key_from_link_key(tSMP_CB* p_cb);
-extern void smp_calculate_f4(uint8_t* u, uint8_t* v, uint8_t* x, uint8_t z,
- uint8_t* c);
-extern uint32_t smp_calculate_g2(uint8_t* u, uint8_t* v, uint8_t* x,
- uint8_t* y);
-extern bool smp_calculate_f5(uint8_t* w, uint8_t* n1, uint8_t* n2, uint8_t* a1,
- uint8_t* a2, uint8_t* mac_key, uint8_t* ltk);
-extern bool smp_calculate_f5_mackey_or_long_term_key(
- uint8_t* t, uint8_t* counter, uint8_t* key_id, uint8_t* n1, uint8_t* n2,
- uint8_t* a1, uint8_t* a2, uint8_t* length, uint8_t* mac);
-extern bool smp_calculate_f5_key(uint8_t* w, uint8_t* t);
-extern bool smp_calculate_f6(uint8_t* w, uint8_t* n1, uint8_t* n2, uint8_t* r,
- uint8_t* iocap, uint8_t* a1, uint8_t* a2,
- uint8_t* f3);
-extern bool smp_calculate_h6(uint8_t* w, uint8_t* keyid, uint8_t* h2);
-extern bool smp_calculate_h7(uint8_t* salt, uint8_t* w, uint8_t* h2);
+
#if (SMP_DEBUG == TRUE)
extern void smp_debug_print_nbyte_little_endian(uint8_t* p,
const char* key_name,
uint8_t len);
+
+inline void smp_debug_print_nbyte_little_endian(const Octet16& p,
+ const char* key_name,
+ uint8_t len) {
+ smp_debug_print_nbyte_little_endian(const_cast<uint8_t*>(p.data()), key_name,
+ len);
+}
#endif
-/* smp_cmac.cc */
-extern bool aes_cipher_msg_auth_code(BT_OCTET16 key, uint8_t* input,
- uint16_t length, uint16_t tlen,
- uint8_t* p_signature);
-extern void print128(BT_OCTET16 x, const uint8_t* key_name);
+extern void print128(const Octet16& x, const uint8_t* key_name);
+extern void smp_xor_128(Octet16* a, const Octet16& b);
#endif /* SMP_INT_H */
diff --git a/stack/smp/smp_keys.cc b/stack/smp/smp_keys.cc
index 6be1da4..da8d0f4 100644
--- a/stack/smp/smp_keys.cc
+++ b/stack/smp/smp_keys.cc
@@ -28,7 +28,6 @@
#endif
#include <base/bind.h>
#include <string.h>
-#include "aes.h"
#include "bt_utils.h"
#include "btm_ble_api.h"
#include "btm_ble_int.h"
@@ -38,16 +37,19 @@
#include "osi/include/osi.h"
#include "p_256_ecc_pp.h"
#include "smp_int.h"
+#include "stack/crypto_toolbox/crypto_toolbox.h"
+
+#include <algorithm>
using base::Bind;
+using crypto_toolbox::aes_128;
#ifndef SMP_MAX_ENC_REPEAT
#define SMP_MAX_ENC_REPEAT 3
#endif
-static void smp_process_stk(tSMP_CB* p_cb, tSMP_ENC* p);
-static bool smp_calculate_legacy_short_term_key(tSMP_CB* p_cb,
- tSMP_ENC* output);
+static void smp_process_stk(tSMP_CB* p_cb, Octet16* p);
+static Octet16 smp_calculate_legacy_short_term_key(tSMP_CB* p_cb);
static void smp_process_private_key(tSMP_CB* p_cb);
#define SMP_PASSKEY_MASK 0xfff00000
@@ -75,6 +77,13 @@
#endif
}
+inline void smp_debug_print_nbyte_little_endian(const Octet16& p,
+ const char* key_name,
+ uint8_t len) {
+ smp_debug_print_nbyte_little_endian(const_cast<uint8_t*>(p.data()), key_name,
+ len);
+}
+
void smp_debug_print_nbyte_big_endian(uint8_t* p, const char* key_name,
uint8_t len) {
#if (SMP_DEBUG == TRUE)
@@ -98,80 +107,9 @@
#endif
}
-/*******************************************************************************
- *
- * Function smp_encrypt_data
- *
- * Description This function is called to encrypt data.
- * It uses AES-128 encryption algorithm.
- * Plain_text is encrypted using key, the result is at p_out.
- *
- * Returns void
- *
- ******************************************************************************/
-bool smp_encrypt_data(uint8_t* key, uint8_t key_len, uint8_t* plain_text,
- uint8_t pt_len, tSMP_ENC* p_out) {
- aes_context ctx;
- uint8_t* p_start = NULL;
- uint8_t* p = NULL;
- uint8_t* p_rev_data = NULL; /* input data in big endilan format */
- uint8_t* p_rev_key = NULL; /* input key in big endilan format */
- uint8_t* p_rev_output = NULL; /* encrypted output in big endilan format */
-
- SMP_TRACE_DEBUG("%s", __func__);
- if ((p_out == NULL) || (key_len != SMP_ENCRYT_KEY_SIZE)) {
- SMP_TRACE_ERROR("%s failed", __func__);
- return false;
- }
-
- p_start = (uint8_t*)osi_calloc(SMP_ENCRYT_DATA_SIZE * 4);
-
- if (pt_len > SMP_ENCRYT_DATA_SIZE) pt_len = SMP_ENCRYT_DATA_SIZE;
-
- p = p_start;
- ARRAY_TO_STREAM(p, plain_text, pt_len); /* byte 0 to byte 15 */
- p_rev_data = p = p_start + SMP_ENCRYT_DATA_SIZE; /* start at byte 16 */
- REVERSE_ARRAY_TO_STREAM(p, p_start,
- SMP_ENCRYT_DATA_SIZE); /* byte 16 to byte 31 */
- p_rev_key = p; /* start at byte 32 */
- REVERSE_ARRAY_TO_STREAM(p, key, SMP_ENCRYT_KEY_SIZE); /* byte 32 to byte 47 */
-
-#if (SMP_DEBUG == TRUE && SMP_DEBUG_VERBOSE == TRUE)
- smp_debug_print_nbyte_little_endian(key, "Key", SMP_ENCRYT_KEY_SIZE);
- smp_debug_print_nbyte_little_endian(p_start, "Plain text",
- SMP_ENCRYT_DATA_SIZE);
-#endif
- p_rev_output = p;
- aes_set_key(p_rev_key, SMP_ENCRYT_KEY_SIZE, &ctx);
- aes_encrypt(p_rev_data, p, &ctx); /* outputs in byte 48 to byte 63 */
-
- p = p_out->param_buf;
- REVERSE_ARRAY_TO_STREAM(p, p_rev_output, SMP_ENCRYT_DATA_SIZE);
-#if (SMP_DEBUG == TRUE && SMP_DEBUG_VERBOSE == TRUE)
- smp_debug_print_nbyte_little_endian(p_out->param_buf, "Encrypted text",
- SMP_ENCRYT_KEY_SIZE);
-#endif
-
- p_out->param_len = SMP_ENCRYT_KEY_SIZE;
- p_out->status = HCI_SUCCESS;
- p_out->opcode = HCI_BLE_ENCRYPT;
-
- osi_free(p_start);
-
- return true;
-}
-
-/*******************************************************************************
- *
- * Function smp_proc_passkey
- *
- * Description This function is called to process a passkey.
- *
- * Returns void
- *
- ******************************************************************************/
+/** This function is called to process a passkey. */
void smp_proc_passkey(tSMP_CB* p_cb, BT_OCTET8 rand) {
- uint8_t* tt = p_cb->tk;
+ uint8_t* tt = p_cb->tk.data();
uint32_t passkey; /* 19655 test number; */
uint8_t* pp = rand;
@@ -183,7 +121,7 @@
while (passkey > BTM_MAX_PASSKEY_VAL) passkey >>= 1;
/* save the TK */
- memset(p_cb->tk, 0, BT_OCTET16_LEN);
+ p_cb->tk = {0};
UINT32_TO_STREAM(tt, passkey);
if (p_cb->p_callback) {
@@ -200,7 +138,7 @@
} else {
tSMP_KEY key;
key.key_type = SMP_KEY_TYPE_TK;
- key.p_data = p_cb->tk;
+ key.p_data = p_cb->tk.data();
tSMP_INT_DATA smp_int_data;
smp_int_data.key = key;
smp_sm_event(p_cb, SMP_KEY_READY_EVT, &smp_int_data);
@@ -234,22 +172,15 @@
*
******************************************************************************/
void smp_generate_stk(tSMP_CB* p_cb, UNUSED_ATTR tSMP_INT_DATA* p_data) {
- tSMP_ENC output;
+ Octet16 output;
SMP_TRACE_DEBUG("%s", __func__);
if (p_cb->le_secure_connections_mode_is_used) {
SMP_TRACE_WARNING("FOR LE SC LTK IS USED INSTEAD OF STK");
- output.param_len = SMP_ENCRYT_KEY_SIZE;
- output.status = HCI_SUCCESS;
- output.opcode = HCI_BLE_ENCRYPT;
- memcpy(output.param_buf, p_cb->ltk, SMP_ENCRYT_DATA_SIZE);
- } else if (!smp_calculate_legacy_short_term_key(p_cb, &output)) {
- SMP_TRACE_ERROR("%s failed", __func__);
- tSMP_INT_DATA smp_int_data;
- smp_int_data.status = SMP_PAIR_FAIL_UNKNOWN;
- smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
- return;
+ output = p_cb->ltk;
+ } else {
+ output = smp_calculate_legacy_short_term_key(p_cb);
}
smp_process_stk(p_cb, &output);
@@ -259,33 +190,20 @@
* This function is called to calculate CSRK
*/
void smp_compute_csrk(uint16_t div, tSMP_CB* p_cb) {
- BT_OCTET16 er;
uint8_t buffer[4]; /* for (r || DIV) r=1*/
uint16_t r = 1;
uint8_t* p = buffer;
- tSMP_ENC output;
p_cb->div = div;
SMP_TRACE_DEBUG("%s: div=%x", __func__, p_cb->div);
- BTM_GetDeviceEncRoot(er);
+ const Octet16& er = BTM_GetDeviceEncRoot();
/* CSRK = d1(ER, DIV, 1) */
UINT16_TO_STREAM(p, p_cb->div);
UINT16_TO_STREAM(p, r);
- if (!SMP_Encrypt(er, BT_OCTET16_LEN, buffer, 4, &output)) {
- SMP_TRACE_ERROR("smp_generate_csrk failed");
- tSMP_INT_DATA smp_int_data;
- smp_int_data.status = SMP_PAIR_FAIL_UNKNOWN;
- if (p_cb->smp_over_br) {
- smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &smp_int_data);
- } else {
- smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
- }
- } else {
- memcpy((void*)p_cb->csrk, output.param_buf, BT_OCTET16_LEN);
- smp_send_csrk_info(p_cb, NULL);
- }
+ p_cb->csrk = aes_128(er, buffer, 4);
+ smp_send_csrk_info(p_cb, NULL);
}
/**
@@ -349,22 +267,16 @@
*p_data = p;
}
-/*******************************************************************************
- *
- * Function smp_gen_p1_4_confirm
- *
- * Description Generate Confirm/Compare Step1:
+/** Generate Confirm/Compare Step1:
* p1 = (MSB) pres || preq || rat' || iat' (LSB)
* Fill in values LSB first thus
* p1 = iat' || rat' || preq || pres
- *
- * Returns void
- *
- ******************************************************************************/
-void smp_gen_p1_4_confirm(tSMP_CB* p_cb, tBLE_ADDR_TYPE remote_bd_addr_type,
- BT_OCTET16 p1) {
+ */
+Octet16 smp_gen_p1_4_confirm(tSMP_CB* p_cb,
+ tBLE_ADDR_TYPE remote_bd_addr_type) {
SMP_TRACE_DEBUG("%s", __func__);
- uint8_t* p = (uint8_t*)p1;
+ Octet16 p1;
+ uint8_t* p = p1.data();
if (p_cb->role == HCI_ROLE_MASTER) {
/* iat': initiator's (local) address type */
UINT8_TO_STREAM(p, p_cb->addr_type);
@@ -384,28 +296,23 @@
/* pres : Pairing Response (local) command */
smp_concatenate_local(p_cb, &p, SMP_OPCODE_PAIRING_RSP);
}
- smp_debug_print_nbyte_little_endian((uint8_t*)p1,
- "p1 = iat' || rat' || preq || pres", 16);
+ smp_debug_print_nbyte_little_endian(p1, "p1 = iat' || rat' || preq || pres",
+ 16);
+
+ return p1;
}
-/*******************************************************************************
- *
- * Function smp_gen_p2_4_confirm
- *
- * Description Generate Confirm/Compare Step2:
+/** Generate Confirm/Compare Step2:
* p2 = (MSB) padding || ia || ra (LSB)
* Fill values LSB first and thus:
* p2 = ra || ia || padding
- *
- * Returns void
- *
- ******************************************************************************/
-void smp_gen_p2_4_confirm(tSMP_CB* p_cb, const RawAddress& remote_bda,
- BT_OCTET16 p2) {
+ */
+Octet16 smp_gen_p2_4_confirm(tSMP_CB* p_cb, const RawAddress& remote_bda) {
SMP_TRACE_DEBUG("%s", __func__);
- uint8_t* p = (uint8_t*)p2;
+ Octet16 p2{0};
+ uint8_t* p = p2.data();
/* 32-bit Padding */
- memset(p, 0, sizeof(BT_OCTET16));
+ memset(p, 0, OCTET16_LEN);
if (p_cb->role == HCI_ROLE_MASTER) {
/* ra : Responder's (remote) address */
BDADDR_TO_STREAM(p, remote_bda);
@@ -418,6 +325,7 @@
BDADDR_TO_STREAM(p, remote_bda);
}
smp_debug_print_nbyte_little_endian(p2, "p2 = ra || ia || padding", 16);
+ return p2;
}
/*******************************************************************************
@@ -429,8 +337,8 @@
* Returns tSMP_STATUS status of confirmation calculation
*
******************************************************************************/
-tSMP_STATUS smp_calculate_comfirm(tSMP_CB* p_cb, BT_OCTET16 rand,
- tSMP_ENC* output) {
+tSMP_STATUS smp_calculate_comfirm(tSMP_CB* p_cb, const Octet16& rand,
+ Octet16* output) {
SMP_TRACE_DEBUG("%s", __func__);
RawAddress remote_bda;
tBLE_ADDR_TYPE remote_bd_addr_type = 0;
@@ -443,31 +351,21 @@
/* get local connection specific bluetooth address */
BTM_ReadConnectionAddr(p_cb->pairing_bda, p_cb->local_bda, &p_cb->addr_type);
/* generate p1 = pres || preq || rat' || iat' */
- BT_OCTET16 p1;
- smp_gen_p1_4_confirm(p_cb, remote_bd_addr_type, p1);
+ Octet16 p1 = smp_gen_p1_4_confirm(p_cb, remote_bd_addr_type);
/* p1' = rand XOR p1 */
- smp_xor_128(p1, rand);
- smp_debug_print_nbyte_little_endian((uint8_t*)p1, "p1' = p1 XOR r", 16);
+ smp_xor_128(&p1, rand);
+ smp_debug_print_nbyte_little_endian(p1, "p1' = p1 XOR r", 16);
/* calculate e1 = e(k, p1'), where k = TK */
- smp_debug_print_nbyte_little_endian(p_cb->tk, "TK", 16);
- memset(output, 0, sizeof(tSMP_ENC));
- if (!SMP_Encrypt(p_cb->tk, BT_OCTET16_LEN, p1, BT_OCTET16_LEN, output)) {
- SMP_TRACE_ERROR("%s: failed encryption at e1 = e(k, p1')");
- return SMP_PAIR_FAIL_UNKNOWN;
- }
- smp_debug_print_nbyte_little_endian(output->param_buf, "e1 = e(k, p1')", 16);
+ smp_debug_print_nbyte_little_endian(p_cb->tk.data(), "TK", 16);
+ Octet16 e1 = aes_128(p_cb->tk, p1);
+ smp_debug_print_nbyte_little_endian(e1.data(), "e1 = e(k, p1')", 16);
/* generate p2 = padding || ia || ra */
- BT_OCTET16 p2;
- smp_gen_p2_4_confirm(p_cb, remote_bda, p2);
+ Octet16 p2 = smp_gen_p2_4_confirm(p_cb, remote_bda);
/* calculate p2' = (p2 XOR e1) */
- smp_xor_128(p2, output->param_buf);
- smp_debug_print_nbyte_little_endian((uint8_t*)p2, "p2' = p2 XOR e1", 16);
+ smp_xor_128(&p2, e1);
+ smp_debug_print_nbyte_little_endian(p2, "p2' = p2 XOR e1", 16);
/* calculate: c1 = e(k, p2') */
- memset(output, 0, sizeof(tSMP_ENC));
- if (!SMP_Encrypt(p_cb->tk, BT_OCTET16_LEN, p2, BT_OCTET16_LEN, output)) {
- SMP_TRACE_ERROR("%s: failed encryption at e1 = e(k, p2')");
- return SMP_PAIR_FAIL_UNKNOWN;
- }
+ *output = aes_128(p_cb->tk, p2);
return SMP_SUCCESS;
}
@@ -484,8 +382,8 @@
******************************************************************************/
static void smp_generate_confirm(tSMP_CB* p_cb) {
SMP_TRACE_DEBUG("%s", __func__);
- smp_debug_print_nbyte_little_endian((uint8_t*)p_cb->rand, "local_rand", 16);
- tSMP_ENC output;
+ smp_debug_print_nbyte_little_endian(p_cb->rand.data(), "local_rand", 16);
+ Octet16 output;
tSMP_STATUS status = smp_calculate_comfirm(p_cb, p_cb->rand, &output);
if (status != SMP_SUCCESS) {
tSMP_INT_DATA smp_int_data;
@@ -494,11 +392,11 @@
return;
}
tSMP_KEY key;
- memcpy(p_cb->confirm, output.param_buf, BT_OCTET16_LEN);
+ p_cb->confirm = output;
smp_debug_print_nbyte_little_endian(p_cb->confirm, "Local Confirm generated",
16);
key.key_type = SMP_KEY_TYPE_CFM;
- key.p_data = output.param_buf;
+ key.p_data = output.data();
tSMP_INT_DATA smp_int_data;
smp_int_data.key = key;
smp_sm_event(p_cb, SMP_KEY_READY_EVT, &smp_int_data);
@@ -521,7 +419,7 @@
/* generate MRand or SRand */
btsnd_hcic_ble_rand(Bind(
[](tSMP_CB* p_cb, BT_OCTET8 rand) {
- memcpy((void*)p_cb->rand, rand, 8);
+ memcpy(p_cb->rand.data(), rand, 8);
/* generate 64 MSB of MRand or SRand */
btsnd_hcic_ble_rand(Bind(
@@ -548,8 +446,8 @@
******************************************************************************/
void smp_generate_compare(tSMP_CB* p_cb, UNUSED_ATTR tSMP_INT_DATA* p_data) {
SMP_TRACE_DEBUG("smp_generate_compare ");
- smp_debug_print_nbyte_little_endian((uint8_t*)p_cb->rrand, "peer rand", 16);
- tSMP_ENC output;
+ smp_debug_print_nbyte_little_endian(p_cb->rrand, "peer rand", 16);
+ Octet16 output;
tSMP_STATUS status = smp_calculate_comfirm(p_cb, p_cb->rrand, &output);
if (status != SMP_SUCCESS) {
tSMP_INT_DATA smp_int_data;
@@ -558,48 +456,38 @@
return;
}
tSMP_KEY key;
- smp_debug_print_nbyte_little_endian(output.param_buf,
- "Remote Confirm generated", 16);
+ smp_debug_print_nbyte_little_endian(output.data(), "Remote Confirm generated",
+ 16);
key.key_type = SMP_KEY_TYPE_CMP;
- key.p_data = output.param_buf;
+ key.p_data = output.data();
tSMP_INT_DATA smp_int_data;
smp_int_data.key = key;
smp_sm_event(p_cb, SMP_KEY_READY_EVT, &smp_int_data);
}
-/*******************************************************************************
- *
- * Function smp_process_stk
- *
- * Description This function is called when STK is generated
- * proceed to send the encrypt the link using STK.
- *
- * Returns void
- *
- ******************************************************************************/
-static void smp_process_stk(tSMP_CB* p_cb, tSMP_ENC* p) {
+/** This function is called when STK is generated proceed to send the encrypt
+ * the link using STK. */
+static void smp_process_stk(tSMP_CB* p_cb, Octet16* p) {
tSMP_KEY key;
SMP_TRACE_DEBUG("smp_process_stk ");
#if (SMP_DEBUG == TRUE)
SMP_TRACE_ERROR("STK Generated");
#endif
- smp_mask_enc_key(p_cb->loc_enc_size, p->param_buf);
+ smp_mask_enc_key(p_cb->loc_enc_size, p);
key.key_type = SMP_KEY_TYPE_STK;
- key.p_data = p->param_buf;
+ key.p_data = p->data();
tSMP_INT_DATA smp_int_data;
smp_int_data.key = key;
smp_sm_event(p_cb, SMP_KEY_READY_EVT, &smp_int_data);
}
-/**
- * This function is to calculate EDIV = Y xor DIV
- */
-static void smp_process_ediv(tSMP_CB* p_cb, tSMP_ENC* p) {
+/** This function calculates EDIV = Y xor DIV */
+static void smp_process_ediv(tSMP_CB* p_cb, Octet16& p) {
tSMP_KEY key;
- uint8_t* pp = p->param_buf;
+ uint8_t* pp = p.data();
uint16_t y;
SMP_TRACE_DEBUG("smp_process_ediv ");
@@ -610,7 +498,7 @@
/* send LTK ready */
SMP_TRACE_ERROR("LTK ready");
key.key_type = SMP_KEY_TYPE_LTK;
- key.p_data = p->param_buf;
+ key.p_data = p.data();
tSMP_INT_DATA smp_int_data;
smp_int_data.key = key;
@@ -623,19 +511,11 @@
static void smp_generate_y(tSMP_CB* p_cb, BT_OCTET8 rand) {
SMP_TRACE_DEBUG("%s ", __func__);
- BT_OCTET16 dhk;
- BTM_GetDeviceDHK(dhk);
+ const Octet16& dhk = BTM_GetDeviceDHK();
memcpy(p_cb->enc_rand, rand, BT_OCTET8_LEN);
- tSMP_ENC output;
- if (!SMP_Encrypt(dhk, BT_OCTET16_LEN, rand, BT_OCTET8_LEN, &output)) {
- SMP_TRACE_ERROR("%s failed", __func__);
- tSMP_INT_DATA smp_int_data;
- smp_int_data.status = SMP_PAIR_FAIL_UNKNOWN;
- smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
- } else {
- smp_process_ediv(p_cb, &output);
- }
+ Octet16 output = aes_128(dhk, rand, BT_OCTET8_LEN);
+ smp_process_ediv(p_cb, output);
}
/**
@@ -645,25 +525,16 @@
p_cb->div = div;
SMP_TRACE_DEBUG("%s", __func__);
- BT_OCTET16 er;
- BTM_GetDeviceEncRoot(er);
+ const Octet16& er = BTM_GetDeviceEncRoot();
- tSMP_ENC output;
/* LTK = d1(ER, DIV, 0)= e(ER, DIV)*/
- if (!SMP_Encrypt(er, BT_OCTET16_LEN, (uint8_t*)&p_cb->div, sizeof(uint16_t),
- &output)) {
- SMP_TRACE_ERROR("%s failed", __func__);
- tSMP_INT_DATA smp_int_data;
- smp_int_data.status = SMP_PAIR_FAIL_UNKNOWN;
- smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
- } else {
- /* mask the LTK */
- smp_mask_enc_key(p_cb->loc_enc_size, output.param_buf);
- memcpy((void*)p_cb->ltk, output.param_buf, BT_OCTET16_LEN);
+ Octet16 ltk = aes_128(er, (uint8_t*)&p_cb->div, sizeof(uint16_t));
+ /* mask the LTK */
+ smp_mask_enc_key(p_cb->loc_enc_size, <k);
+ p_cb->ltk = ltk;
- /* generate EDIV and rand now */
- btsnd_hcic_ble_rand(Bind(&smp_generate_y, p_cb));
- }
+ /* generate EDIV and rand now */
+ btsnd_hcic_ble_rand(Bind(&smp_generate_y, p_cb));
}
/*******************************************************************************
@@ -710,36 +581,21 @@
}
}
-/*******************************************************************************
- *
- * Function smp_calculate_legacy_short_term_key
- *
- * Description The function calculates legacy STK.
- *
- * Returns false if out of resources, true in other cases.
- *
- ******************************************************************************/
-bool smp_calculate_legacy_short_term_key(tSMP_CB* p_cb, tSMP_ENC* output) {
+/* The function calculates legacy STK */
+Octet16 smp_calculate_legacy_short_term_key(tSMP_CB* p_cb) {
SMP_TRACE_DEBUG("%s", __func__);
- BT_OCTET16 ptext;
- uint8_t* p = ptext;
- memset(p, 0, BT_OCTET16_LEN);
+ Octet16 text{0};
if (p_cb->role == HCI_ROLE_MASTER) {
- memcpy(p, p_cb->rand, BT_OCTET8_LEN);
- memcpy(&p[BT_OCTET8_LEN], p_cb->rrand, BT_OCTET8_LEN);
+ memcpy(text.data(), p_cb->rand.data(), BT_OCTET8_LEN);
+ memcpy(text.data() + BT_OCTET8_LEN, p_cb->rrand.data(), BT_OCTET8_LEN);
} else {
- memcpy(p, p_cb->rrand, BT_OCTET8_LEN);
- memcpy(&p[BT_OCTET8_LEN], p_cb->rand, BT_OCTET8_LEN);
+ memcpy(text.data(), p_cb->rrand.data(), BT_OCTET8_LEN);
+ memcpy(text.data() + BT_OCTET8_LEN, p_cb->rand.data(), BT_OCTET8_LEN);
}
/* generate STK = Etk(rand|rrand)*/
- bool encrypted =
- SMP_Encrypt(p_cb->tk, BT_OCTET16_LEN, ptext, BT_OCTET16_LEN, output);
- if (!encrypted) {
- SMP_TRACE_ERROR("%s failed", __func__);
- }
- return encrypted;
+ return aes_128(p_cb->tk, text);
}
/*******************************************************************************
@@ -889,15 +745,7 @@
BT_OCTET32_LEN);
}
-/*******************************************************************************
- *
- * Function smp_calculate_local_commitment
- *
- * Description The function calculates and saves local commmitment in CB.
- *
- * Returns void
- *
- ******************************************************************************/
+/** The function calculates and saves local commmitment in CB. */
void smp_calculate_local_commitment(tSMP_CB* p_cb) {
uint8_t random_input;
@@ -910,21 +758,22 @@
SMP_TRACE_WARNING(
"local commitment calc on master is not expected "
"for Just Works/Numeric Comparison models");
- smp_calculate_f4(p_cb->loc_publ_key.x, p_cb->peer_publ_key.x, p_cb->rand,
- 0, p_cb->commitment);
+ p_cb->commitment = crypto_toolbox::f4(
+ p_cb->loc_publ_key.x, p_cb->peer_publ_key.x, p_cb->rand, 0);
break;
case SMP_MODEL_SEC_CONN_PASSKEY_ENT:
case SMP_MODEL_SEC_CONN_PASSKEY_DISP:
random_input =
- smp_calculate_random_input(p_cb->local_random, p_cb->round);
- smp_calculate_f4(p_cb->loc_publ_key.x, p_cb->peer_publ_key.x, p_cb->rand,
- random_input, p_cb->commitment);
+ smp_calculate_random_input(p_cb->local_random.data(), p_cb->round);
+ p_cb->commitment =
+ crypto_toolbox::f4(p_cb->loc_publ_key.x, p_cb->peer_publ_key.x,
+ p_cb->rand, random_input);
break;
case SMP_MODEL_SEC_CONN_OOB:
SMP_TRACE_WARNING(
"local commitment calc is expected for OOB model BEFORE pairing");
- smp_calculate_f4(p_cb->loc_publ_key.x, p_cb->loc_publ_key.x,
- p_cb->local_random, 0, p_cb->commitment);
+ p_cb->commitment = crypto_toolbox::f4(
+ p_cb->loc_publ_key.x, p_cb->loc_publ_key.x, p_cb->local_random, 0);
break;
default:
SMP_TRACE_ERROR("Association Model = %d is not used in LE SC",
@@ -935,21 +784,12 @@
SMP_TRACE_EVENT("local commitment calculation is completed");
}
-/*******************************************************************************
- *
- * Function smp_calculate_peer_commitment
- *
- * Description The function calculates and saves peer commmitment at the
- * provided output buffer.
- *
- * Returns void
- *
- ******************************************************************************/
-void smp_calculate_peer_commitment(tSMP_CB* p_cb, BT_OCTET16 output_buf) {
+/** The function calculates peer commmitment */
+Octet16 smp_calculate_peer_commitment(tSMP_CB* p_cb) {
uint8_t ri;
SMP_TRACE_DEBUG("%s", __func__);
-
+ Octet16 output;
switch (p_cb->selected_association_model) {
case SMP_MODEL_SEC_CONN_JUSTWORKS:
case SMP_MODEL_SEC_CONN_NUM_COMP:
@@ -957,97 +797,27 @@
SMP_TRACE_WARNING(
"peer commitment calc on slave is not expected "
"for Just Works/Numeric Comparison models");
- smp_calculate_f4(p_cb->peer_publ_key.x, p_cb->loc_publ_key.x, p_cb->rrand,
- 0, output_buf);
+ output = crypto_toolbox::f4(p_cb->peer_publ_key.x, p_cb->loc_publ_key.x,
+ p_cb->rrand, 0);
break;
case SMP_MODEL_SEC_CONN_PASSKEY_ENT:
case SMP_MODEL_SEC_CONN_PASSKEY_DISP:
- ri = smp_calculate_random_input(p_cb->peer_random, p_cb->round);
- smp_calculate_f4(p_cb->peer_publ_key.x, p_cb->loc_publ_key.x, p_cb->rrand,
- ri, output_buf);
+ ri = smp_calculate_random_input(p_cb->peer_random.data(), p_cb->round);
+ output = crypto_toolbox::f4(p_cb->peer_publ_key.x, p_cb->loc_publ_key.x,
+ p_cb->rrand, ri);
break;
case SMP_MODEL_SEC_CONN_OOB:
- smp_calculate_f4(p_cb->peer_publ_key.x, p_cb->peer_publ_key.x,
- p_cb->peer_random, 0, output_buf);
+ output = crypto_toolbox::f4(p_cb->peer_publ_key.x, p_cb->peer_publ_key.x,
+ p_cb->peer_random, 0);
break;
default:
SMP_TRACE_ERROR("Association Model = %d is not used in LE SC",
p_cb->selected_association_model);
- return;
+ return output;
}
SMP_TRACE_EVENT("peer commitment calculation is completed");
-}
-
-/*******************************************************************************
- *
- * Function smp_calculate_f4
- *
- * Description The function calculates
- * C = f4(U, V, X, Z) = AES-CMAC (U||V||Z)
- * X
- * where
- * input: U is 256 bit,
- * V is 256 bit,
- * X is 128 bit,
- * Z is 8 bit,
- * output: C is 128 bit.
- *
- * Returns void
- *
- * Note The LSB is the first octet, the MSB is the last octet of
- * the AES-CMAC input/output stream.
- *
- ******************************************************************************/
-void smp_calculate_f4(uint8_t* u, uint8_t* v, uint8_t* x, uint8_t z,
- uint8_t* c) {
- uint8_t msg_len = BT_OCTET32_LEN /* U size */ + BT_OCTET32_LEN /* V size */ +
- 1 /* Z size */;
- uint8_t msg[BT_OCTET32_LEN + BT_OCTET32_LEN + 1];
- uint8_t key[BT_OCTET16_LEN];
- uint8_t cmac[BT_OCTET16_LEN];
- uint8_t* p = NULL;
-#if (SMP_DEBUG == TRUE)
- uint8_t* p_prnt = NULL;
-#endif
-
- SMP_TRACE_DEBUG("%s", __func__);
-
-#if (SMP_DEBUG == TRUE)
- p_prnt = u;
- smp_debug_print_nbyte_little_endian(p_prnt, "U", BT_OCTET32_LEN);
- p_prnt = v;
- smp_debug_print_nbyte_little_endian(p_prnt, "V", BT_OCTET32_LEN);
- p_prnt = x;
- smp_debug_print_nbyte_little_endian(p_prnt, "X", BT_OCTET16_LEN);
- p_prnt = &z;
- smp_debug_print_nbyte_little_endian(p_prnt, "Z", 1);
-#endif
-
- p = msg;
- UINT8_TO_STREAM(p, z);
- ARRAY_TO_STREAM(p, v, BT_OCTET32_LEN);
- ARRAY_TO_STREAM(p, u, BT_OCTET32_LEN);
-#if (SMP_DEBUG == TRUE)
- p_prnt = msg;
- smp_debug_print_nbyte_little_endian(p_prnt, "M", msg_len);
-#endif
-
- p = key;
- ARRAY_TO_STREAM(p, x, BT_OCTET16_LEN);
-#if (SMP_DEBUG == TRUE)
- p_prnt = key;
- smp_debug_print_nbyte_little_endian(p_prnt, "K", BT_OCTET16_LEN);
-#endif
-
- aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac);
-#if (SMP_DEBUG == TRUE)
- p_prnt = cmac;
- smp_debug_print_nbyte_little_endian(p_prnt, "AES_CMAC", BT_OCTET16_LEN);
-#endif
-
- p = c;
- ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN);
+ return output;
}
/*******************************************************************************
@@ -1065,10 +835,10 @@
SMP_TRACE_DEBUG("%s", __func__);
if (p_cb->role == HCI_ROLE_MASTER) {
- p_cb->number_to_display = smp_calculate_g2(
+ p_cb->number_to_display = crypto_toolbox::g2(
p_cb->loc_publ_key.x, p_cb->peer_publ_key.x, p_cb->rand, p_cb->rrand);
} else {
- p_cb->number_to_display = smp_calculate_g2(
+ p_cb->number_to_display = crypto_toolbox::g2(
p_cb->peer_publ_key.x, p_cb->loc_publ_key.x, p_cb->rrand, p_cb->rand);
}
@@ -1089,398 +859,6 @@
return;
}
-/*******************************************************************************
- *
- * Function smp_calculate_g2
- *
- * Description The function calculates
- * g2(U, V, X, Y) = AES-CMAC (U||V||Y) mod 2**32 mod 10**6
- * X
- * and
- * Vres = g2(U, V, X, Y) mod 10**6
- * where
- * input: U is 256 bit,
- * V is 256 bit,
- * X is 128 bit,
- * Y is 128 bit,
- *
- * Returns Vres.
- * Expected value has to be in the range [0 - 999999] i.e.
- * [0 - 0xF423F].
- * Vres = 1000000 means that the calculation fails.
- *
- * Note The LSB is the first octet, the MSB is the last octet of
- * the AES-CMAC input/output stream.
- *
- ******************************************************************************/
-uint32_t smp_calculate_g2(uint8_t* u, uint8_t* v, uint8_t* x, uint8_t* y) {
- uint8_t msg_len = BT_OCTET32_LEN /* U size */ + BT_OCTET32_LEN /* V size */
- + BT_OCTET16_LEN /* Y size */;
- uint8_t msg[BT_OCTET32_LEN + BT_OCTET32_LEN + BT_OCTET16_LEN];
- uint8_t key[BT_OCTET16_LEN];
- uint8_t cmac[BT_OCTET16_LEN];
- uint8_t* p = NULL;
- uint32_t vres;
-#if (SMP_DEBUG == TRUE)
- uint8_t* p_prnt = NULL;
-#endif
-
- SMP_TRACE_DEBUG("%s", __func__);
-
- p = msg;
- ARRAY_TO_STREAM(p, y, BT_OCTET16_LEN);
- ARRAY_TO_STREAM(p, v, BT_OCTET32_LEN);
- ARRAY_TO_STREAM(p, u, BT_OCTET32_LEN);
-#if (SMP_DEBUG == TRUE)
- p_prnt = u;
- smp_debug_print_nbyte_little_endian(p_prnt, "U", BT_OCTET32_LEN);
- p_prnt = v;
- smp_debug_print_nbyte_little_endian(p_prnt, "V", BT_OCTET32_LEN);
- p_prnt = x;
- smp_debug_print_nbyte_little_endian(p_prnt, "X", BT_OCTET16_LEN);
- p_prnt = y;
- smp_debug_print_nbyte_little_endian(p_prnt, "Y", BT_OCTET16_LEN);
-#endif
-
- p = key;
- ARRAY_TO_STREAM(p, x, BT_OCTET16_LEN);
-#if (SMP_DEBUG == TRUE)
- p_prnt = key;
- smp_debug_print_nbyte_little_endian(p_prnt, "K", BT_OCTET16_LEN);
-#endif
-
- if (!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac)) {
- SMP_TRACE_ERROR("%s failed", __func__);
- return (BTM_MAX_PASSKEY_VAL + 1);
- }
-
-#if (SMP_DEBUG == TRUE)
- p_prnt = cmac;
- smp_debug_print_nbyte_little_endian(p_prnt, "AES-CMAC", BT_OCTET16_LEN);
-#endif
-
- /* vres = cmac mod 2**32 mod 10**6 */
- p = &cmac[0];
- STREAM_TO_UINT32(vres, p);
-#if (SMP_DEBUG == TRUE)
- p_prnt = (uint8_t*)&vres;
- smp_debug_print_nbyte_little_endian(p_prnt, "cmac mod 2**32", 4);
-#endif
-
- while (vres > BTM_MAX_PASSKEY_VAL) vres -= (BTM_MAX_PASSKEY_VAL + 1);
-#if (SMP_DEBUG == TRUE)
- p_prnt = (uint8_t*)&vres;
- smp_debug_print_nbyte_little_endian(p_prnt, "cmac mod 2**32 mod 10**6", 4);
-#endif
-
- SMP_TRACE_ERROR("Value for numeric comparison = %d", vres);
- return vres;
-}
-
-/*******************************************************************************
- *
- * Function smp_calculate_f5
- *
- * Description The function provides two AES-CMAC that are supposed to be
- * used as
- * - MacKey (used in pairing DHKey check calculation);
- * - LTK (used to ecrypt the link after completion of Phase 2
- * and on reconnection, to derive BR/EDR LK).
- * The function inputs are W, N1, N2, A1, A2.
- * F5 rules:
- * - the value used as key in MacKey/LTK (T) is calculated
- * (function smp_calculate_f5_key(...));
- * The formula is:
- * T = AES-CMAC (W)
- * salt
- * where salt is internal parameter of
- * smp_calculate_f5_key(...).
- * - MacKey and LTK are calculated as AES-MAC values received
- * with the key T calculated in the previous step and the
- * plaintext message built from the external parameters N1,
- * N2, A1, A2 and the internal parameters counter, keyID,
- * length.
- * The function smp_calculate_f5_mackey_or_long_term_key(...)
- * is used in the calculations.
- * The same formula is used in calculation of MacKey and LTK
- * and the same parameter values except the value of the
- * internal parameter counter:
- * - in MacKey calculations the value is 0;
- * - in LTK calculations the value is 1.
- * MacKey =
- * AES-CMAC (Counter=0||keyID||N1||N2||A1||A2||Length=256)
- * T
- * LTK =
- * AES-CMAC (Counter=1||keyID||N1||N2||A1||A2||Length=256)
- * T
- * The parameters are
- * input:
- * W is 256 bits,
- * N1 is 128 bits,
- * N2 is 128 bits,
- * A1 is 56 bit,
- * A2 is 56 bit.
- * internal:
- * Counter is 8 bits, its value is 0 for MacKey,
- * 1 for LTK;
- * KeyId is 32 bits, its value is
- * 0x62746c65 (MSB~LSB);
- * Length is 16 bits, its value is 0x0100
- * (MSB~LSB).
- * output:
- * MacKey is 128 bits;
- * LTK is 128 bits
- *
- * Returns false if out of resources, true in other cases.
- *
- * Note The LSB is the first octet, the MSB is the last octet of
- * the AES-CMAC input/output stream.
- *
- ******************************************************************************/
-bool smp_calculate_f5(uint8_t* w, uint8_t* n1, uint8_t* n2, uint8_t* a1,
- uint8_t* a2, uint8_t* mac_key, uint8_t* ltk) {
- BT_OCTET16 t; /* AES-CMAC output in smp_calculate_f5_key(...), key in */
- /* smp_calculate_f5_mackey_or_long_term_key(...) */
-#if (SMP_DEBUG == TRUE)
- uint8_t* p_prnt = NULL;
-#endif
- /* internal parameters: */
-
- /*
- counter is 0 for MacKey,
- is 1 for LTK
- */
- uint8_t counter_mac_key[1] = {0};
- uint8_t counter_ltk[1] = {1};
- /*
- keyID 62746c65
- */
- uint8_t key_id[4] = {0x65, 0x6c, 0x74, 0x62};
- /*
- length 0100
- */
- uint8_t length[2] = {0x00, 0x01};
-
- SMP_TRACE_DEBUG("%s", __func__);
-#if (SMP_DEBUG == TRUE)
- p_prnt = w;
- smp_debug_print_nbyte_little_endian(p_prnt, "W", BT_OCTET32_LEN);
- p_prnt = n1;
- smp_debug_print_nbyte_little_endian(p_prnt, "N1", BT_OCTET16_LEN);
- p_prnt = n2;
- smp_debug_print_nbyte_little_endian(p_prnt, "N2", BT_OCTET16_LEN);
- p_prnt = a1;
- smp_debug_print_nbyte_little_endian(p_prnt, "A1", 7);
- p_prnt = a2;
- smp_debug_print_nbyte_little_endian(p_prnt, "A2", 7);
-#endif
-
- if (!smp_calculate_f5_key(w, t)) {
- SMP_TRACE_ERROR("%s failed to calc T", __func__);
- return false;
- }
-#if (SMP_DEBUG == TRUE)
- p_prnt = t;
- smp_debug_print_nbyte_little_endian(p_prnt, "T", BT_OCTET16_LEN);
-#endif
-
- if (!smp_calculate_f5_mackey_or_long_term_key(t, counter_mac_key, key_id, n1,
- n2, a1, a2, length, mac_key)) {
- SMP_TRACE_ERROR("%s failed to calc MacKey", __func__);
- return false;
- }
-#if (SMP_DEBUG == TRUE)
- p_prnt = mac_key;
- smp_debug_print_nbyte_little_endian(p_prnt, "MacKey", BT_OCTET16_LEN);
-#endif
-
- if (!smp_calculate_f5_mackey_or_long_term_key(t, counter_ltk, key_id, n1, n2,
- a1, a2, length, ltk)) {
- SMP_TRACE_ERROR("%s failed to calc LTK", __func__);
- return false;
- }
-#if (SMP_DEBUG == TRUE)
- p_prnt = ltk;
- smp_debug_print_nbyte_little_endian(p_prnt, "LTK", BT_OCTET16_LEN);
-#endif
-
- return true;
-}
-
-/*******************************************************************************
- *
- * Function smp_calculate_f5_mackey_or_long_term_key
- *
- * Description The function calculates the value of MacKey or LTK by the
- * rules defined for f5 function.
- * At the moment exactly the same formula is used to calculate
- * LTK and MacKey.
- * The difference is the value of input parameter Counter:
- * - in MacKey calculations the value is 0;
- * - in LTK calculations the value is 1.
- * The formula:
- * mac = AES-CMAC (Counter||keyID||N1||N2||A1||A2||Length)
- * T
- * where
- * input: T is 256 bits;
- * Counter is 8 bits, its value is 0 for MacKey,
- * 1 for LTK;
- * keyID is 32 bits, its value is 0x62746c65;
- * N1 is 128 bits;
- * N2 is 128 bits;
- * A1 is 56 bits;
- * A2 is 56 bits;
- * Length is 16 bits, its value is 0x0100
- * output: LTK is 128 bit.
- *
- * Returns false if out of resources, true in other cases.
- *
- * Note The LSB is the first octet, the MSB is the last octet of
- * the AES-CMAC input/output stream.
- *
- ******************************************************************************/
-bool smp_calculate_f5_mackey_or_long_term_key(uint8_t* t, uint8_t* counter,
- uint8_t* key_id, uint8_t* n1,
- uint8_t* n2, uint8_t* a1,
- uint8_t* a2, uint8_t* length,
- uint8_t* mac) {
- uint8_t* p = NULL;
- uint8_t cmac[BT_OCTET16_LEN];
- uint8_t key[BT_OCTET16_LEN];
- uint8_t msg_len = 1 /* Counter size */ + 4 /* keyID size */ +
- BT_OCTET16_LEN /* N1 size */ +
- BT_OCTET16_LEN /* N2 size */ + 7 /* A1 size*/ +
- 7 /* A2 size*/ + 2 /* Length size */;
- uint8_t msg[1 + 4 + BT_OCTET16_LEN + BT_OCTET16_LEN + 7 + 7 + 2];
- bool ret = true;
-#if (SMP_DEBUG == TRUE)
- uint8_t* p_prnt = NULL;
-#endif
-
- SMP_TRACE_DEBUG("%s", __func__);
-#if (SMP_DEBUG == TRUE)
- p_prnt = t;
- smp_debug_print_nbyte_little_endian(p_prnt, "T", BT_OCTET16_LEN);
- p_prnt = counter;
- smp_debug_print_nbyte_little_endian(p_prnt, "Counter", 1);
- p_prnt = key_id;
- smp_debug_print_nbyte_little_endian(p_prnt, "KeyID", 4);
- p_prnt = n1;
- smp_debug_print_nbyte_little_endian(p_prnt, "N1", BT_OCTET16_LEN);
- p_prnt = n2;
- smp_debug_print_nbyte_little_endian(p_prnt, "N2", BT_OCTET16_LEN);
- p_prnt = a1;
- smp_debug_print_nbyte_little_endian(p_prnt, "A1", 7);
- p_prnt = a2;
- smp_debug_print_nbyte_little_endian(p_prnt, "A2", 7);
- p_prnt = length;
- smp_debug_print_nbyte_little_endian(p_prnt, "Length", 2);
-#endif
-
- p = key;
- ARRAY_TO_STREAM(p, t, BT_OCTET16_LEN);
-#if (SMP_DEBUG == TRUE)
- p_prnt = key;
- smp_debug_print_nbyte_little_endian(p_prnt, "K", BT_OCTET16_LEN);
-#endif
- p = msg;
- ARRAY_TO_STREAM(p, length, 2);
- ARRAY_TO_STREAM(p, a2, 7);
- ARRAY_TO_STREAM(p, a1, 7);
- ARRAY_TO_STREAM(p, n2, BT_OCTET16_LEN);
- ARRAY_TO_STREAM(p, n1, BT_OCTET16_LEN);
- ARRAY_TO_STREAM(p, key_id, 4);
- ARRAY_TO_STREAM(p, counter, 1);
-#if (SMP_DEBUG == TRUE)
- p_prnt = msg;
- smp_debug_print_nbyte_little_endian(p_prnt, "M", msg_len);
-#endif
-
- if (!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac)) {
- SMP_TRACE_ERROR("%s failed", __func__);
- ret = false;
- }
-
-#if (SMP_DEBUG == TRUE)
- p_prnt = cmac;
- smp_debug_print_nbyte_little_endian(p_prnt, "AES-CMAC", BT_OCTET16_LEN);
-#endif
-
- p = mac;
- ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN);
- return ret;
-}
-
-/*******************************************************************************
- *
- * Function smp_calculate_f5_key
- *
- * Description The function calculates key T used in calculation of
- * MacKey and LTK (f5 output is defined as MacKey || LTK).
- * T = AES-CMAC (W)
- * salt
- * where
- * Internal: salt is 128 bit.
- * input: W is 256 bit.
- * Output: T is 128 bit.
- *
- * Returns false if out of resources, true in other cases.
- *
- * Note The LSB is the first octet, the MSB is the last octet of
- * the AES-CMAC input/output stream.
- *
- ******************************************************************************/
-bool smp_calculate_f5_key(uint8_t* w, uint8_t* t) {
- uint8_t* p = NULL;
- /* Please see 2.2.7 LE Secure Connections Key Generation Function f5 */
- /*
- salt: 6C88 8391 AAF5 A538 6037 0BDB 5A60 83BE
- */
- BT_OCTET16 salt = {0xBE, 0x83, 0x60, 0x5A, 0xDB, 0x0B, 0x37, 0x60,
- 0x38, 0xA5, 0xF5, 0xAA, 0x91, 0x83, 0x88, 0x6C};
-#if (SMP_DEBUG == TRUE)
- uint8_t* p_prnt = NULL;
-#endif
-
- SMP_TRACE_DEBUG("%s", __func__);
-#if (SMP_DEBUG == TRUE)
- p_prnt = salt;
- smp_debug_print_nbyte_little_endian(p_prnt, "salt", BT_OCTET16_LEN);
- p_prnt = w;
- smp_debug_print_nbyte_little_endian(p_prnt, "W", BT_OCTET32_LEN);
-#endif
-
- BT_OCTET16 key;
- BT_OCTET32 msg;
-
- p = key;
- ARRAY_TO_STREAM(p, salt, BT_OCTET16_LEN);
- p = msg;
- ARRAY_TO_STREAM(p, w, BT_OCTET32_LEN);
-#if (SMP_DEBUG == TRUE)
- p_prnt = key;
- smp_debug_print_nbyte_little_endian(p_prnt, "K", BT_OCTET16_LEN);
- p_prnt = msg;
- smp_debug_print_nbyte_little_endian(p_prnt, "M", BT_OCTET32_LEN);
-#endif
-
- BT_OCTET16 cmac;
- bool ret = true;
- if (!aes_cipher_msg_auth_code(key, msg, BT_OCTET32_LEN, BT_OCTET16_LEN,
- cmac)) {
- SMP_TRACE_ERROR("%s failed", __func__);
- ret = false;
- }
-
-#if (SMP_DEBUG == TRUE)
- p_prnt = cmac;
- smp_debug_print_nbyte_little_endian(p_prnt, "AES-CMAC", BT_OCTET16_LEN);
-#endif
-
- p = t;
- ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN);
- return ret;
-}
/*******************************************************************************
*
@@ -1507,8 +885,8 @@
smp_collect_local_ble_address(a, p_cb);
smp_collect_peer_ble_address(b, p_cb);
- smp_calculate_f6(p_cb->mac_key, p_cb->rand, p_cb->rrand, p_cb->peer_random,
- iocap, a, b, p_cb->dhkey_check);
+ p_cb->dhkey_check = crypto_toolbox::f6(p_cb->mac_key, p_cb->rand, p_cb->rrand,
+ p_cb->peer_random, iocap, a, b);
SMP_TRACE_EVENT("local DHKey check calculation is completed");
}
@@ -1524,8 +902,6 @@
******************************************************************************/
void smp_calculate_peer_dhkey_check(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
uint8_t iocap[3], a[7], b[7];
- BT_OCTET16 param_buf;
- bool ret;
tSMP_KEY key;
SMP_TRACE_DEBUG("%s", __func__);
@@ -1534,119 +910,21 @@
smp_collect_local_ble_address(a, p_cb);
smp_collect_peer_ble_address(b, p_cb);
- ret = smp_calculate_f6(p_cb->mac_key, p_cb->rrand, p_cb->rand,
- p_cb->local_random, iocap, b, a, param_buf);
+ Octet16 param_buf = crypto_toolbox::f6(p_cb->mac_key, p_cb->rrand, p_cb->rand,
+ p_cb->local_random, iocap, b, a);
- if (ret) {
- SMP_TRACE_EVENT("peer DHKey check calculation is completed");
+ SMP_TRACE_EVENT("peer DHKey check calculation is completed");
#if (SMP_DEBUG == TRUE)
- smp_debug_print_nbyte_little_endian(param_buf, "peer DHKey check",
- BT_OCTET16_LEN);
+ smp_debug_print_nbyte_little_endian(param_buf, "peer DHKey check",
+ OCTET16_LEN);
#endif
- key.key_type = SMP_KEY_TYPE_PEER_DHK_CHCK;
- key.p_data = param_buf;
- tSMP_INT_DATA smp_int_data;
- smp_int_data.key = key;
- smp_sm_event(p_cb, SMP_SC_KEY_READY_EVT, &smp_int_data);
- } else {
- SMP_TRACE_EVENT("peer DHKey check calculation failed");
- tSMP_INT_DATA smp_int_data;
- smp_int_data.status = SMP_PAIR_FAIL_UNKNOWN;
- smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
- }
+ key.key_type = SMP_KEY_TYPE_PEER_DHK_CHCK;
+ key.p_data = param_buf.data();
+ tSMP_INT_DATA smp_int_data;
+ smp_int_data.key = key;
+ smp_sm_event(p_cb, SMP_SC_KEY_READY_EVT, &smp_int_data);
}
-/*******************************************************************************
- *
- * Function smp_calculate_f6
- *
- * Description The function calculates
- * C = f6(W, N1, N2, R, IOcap, A1, A2) =
- * AES-CMAC (N1||N2||R||IOcap||A1||A2)
- * W
- * where
- * input: W is 128 bit,
- * N1 is 128 bit,
- * N2 is 128 bit,
- * R is 128 bit,
- * IOcap is 24 bit,
- * A1 is 56 bit,
- * A2 is 56 bit,
- * output: C is 128 bit.
- *
- * Returns false if out of resources, true in other cases.
- *
- * Note The LSB is the first octet, the MSB is the last octet of
- * the AES-CMAC input/output stream.
- *
- ******************************************************************************/
-bool smp_calculate_f6(uint8_t* w, uint8_t* n1, uint8_t* n2, uint8_t* r,
- uint8_t* iocap, uint8_t* a1, uint8_t* a2, uint8_t* c) {
- uint8_t* p = NULL;
- uint8_t msg_len = BT_OCTET16_LEN /* N1 size */ +
- BT_OCTET16_LEN /* N2 size */ + BT_OCTET16_LEN /* R size */ +
- 3 /* IOcap size */ + 7 /* A1 size*/
- + 7 /* A2 size*/;
- uint8_t msg[BT_OCTET16_LEN + BT_OCTET16_LEN + BT_OCTET16_LEN + 3 + 7 + 7];
-#if (SMP_DEBUG == TRUE)
- uint8_t* p_print = NULL;
-#endif
-
- SMP_TRACE_DEBUG("%s", __func__);
-#if (SMP_DEBUG == TRUE)
- p_print = w;
- smp_debug_print_nbyte_little_endian(p_print, "W", BT_OCTET16_LEN);
- p_print = n1;
- smp_debug_print_nbyte_little_endian(p_print, "N1", BT_OCTET16_LEN);
- p_print = n2;
- smp_debug_print_nbyte_little_endian(p_print, "N2", BT_OCTET16_LEN);
- p_print = r;
- smp_debug_print_nbyte_little_endian(p_print, "R", BT_OCTET16_LEN);
- p_print = iocap;
- smp_debug_print_nbyte_little_endian(p_print, "IOcap", 3);
- p_print = a1;
- smp_debug_print_nbyte_little_endian(p_print, "A1", 7);
- p_print = a2;
- smp_debug_print_nbyte_little_endian(p_print, "A2", 7);
-#endif
-
- uint8_t cmac[BT_OCTET16_LEN];
- uint8_t key[BT_OCTET16_LEN];
-
- p = key;
- ARRAY_TO_STREAM(p, w, BT_OCTET16_LEN);
-#if (SMP_DEBUG == TRUE)
- p_print = key;
- smp_debug_print_nbyte_little_endian(p_print, "K", BT_OCTET16_LEN);
-#endif
-
- p = msg;
- ARRAY_TO_STREAM(p, a2, 7);
- ARRAY_TO_STREAM(p, a1, 7);
- ARRAY_TO_STREAM(p, iocap, 3);
- ARRAY_TO_STREAM(p, r, BT_OCTET16_LEN);
- ARRAY_TO_STREAM(p, n2, BT_OCTET16_LEN);
- ARRAY_TO_STREAM(p, n1, BT_OCTET16_LEN);
-#if (SMP_DEBUG == TRUE)
- p_print = msg;
- smp_debug_print_nbyte_little_endian(p_print, "M", msg_len);
-#endif
-
- bool ret = true;
- if (!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac)) {
- SMP_TRACE_ERROR("%s failed", __func__);
- ret = false;
- }
-
-#if (SMP_DEBUG == TRUE)
- p_print = cmac;
- smp_debug_print_nbyte_little_endian(p_print, "AES-CMAC", BT_OCTET16_LEN);
-#endif
-
- p = c;
- ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN);
- return ret;
-}
/*******************************************************************************
*
@@ -1662,8 +940,6 @@
tBTM_SEC_DEV_REC* p_dev_rec;
RawAddress bda_for_lk;
tBLE_ADDR_TYPE conn_addr_type;
- BT_OCTET16 salt = {0x31, 0x70, 0x6D, 0x74, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
SMP_TRACE_DEBUG("%s", __func__);
@@ -1686,79 +962,44 @@
return false;
}
- BT_OCTET16 intermediate_link_key;
- bool ret = true;
+ Octet16 link_key =
+ crypto_toolbox::ltk_to_link_key(p_cb->ltk, p_cb->key_derivation_h7_used);
- if (p_cb->key_derivation_h7_used)
- ret = smp_calculate_h7((uint8_t*)salt, p_cb->ltk, intermediate_link_key);
- else
- ret = smp_calculate_h6(p_cb->ltk, (uint8_t*)"1pmt" /* reversed "tmp1" */,
- intermediate_link_key);
- if (!ret) {
- SMP_TRACE_ERROR("%s failed to derive intermediate_link_key", __func__);
- return ret;
- }
-
- BT_OCTET16 link_key;
- ret = smp_calculate_h6(intermediate_link_key,
- (uint8_t*)"rbel" /* reversed "lebr" */, link_key);
- if (!ret) {
- SMP_TRACE_ERROR("%s failed", __func__);
- } else {
- uint8_t link_key_type;
- if (btm_cb.security_mode == BTM_SEC_MODE_SC) {
- /* Secure Connections Only Mode */
+ uint8_t link_key_type;
+ if (btm_cb.security_mode == BTM_SEC_MODE_SC) {
+ /* Secure Connections Only Mode */
+ link_key_type = BTM_LKEY_TYPE_AUTH_COMB_P_256;
+ } else if (controller_get_interface()->supports_secure_connections()) {
+ /* both transports are SC capable */
+ if (p_cb->sec_level == SMP_SEC_AUTHENTICATED)
link_key_type = BTM_LKEY_TYPE_AUTH_COMB_P_256;
- } else if (controller_get_interface()->supports_secure_connections()) {
- /* both transports are SC capable */
- if (p_cb->sec_level == SMP_SEC_AUTHENTICATED)
- link_key_type = BTM_LKEY_TYPE_AUTH_COMB_P_256;
- else
- link_key_type = BTM_LKEY_TYPE_UNAUTH_COMB_P_256;
- } else if (btm_cb.security_mode == BTM_SEC_MODE_SP) {
- /* BR/EDR transport is SSP capable */
- if (p_cb->sec_level == SMP_SEC_AUTHENTICATED)
- link_key_type = BTM_LKEY_TYPE_AUTH_COMB;
- else
- link_key_type = BTM_LKEY_TYPE_UNAUTH_COMB;
- } else {
- SMP_TRACE_ERROR(
- "%s failed to update link_key. Sec Mode = %d, sm4 = 0x%02x", __func__,
- btm_cb.security_mode, p_dev_rec->sm4);
- return false;
- }
-
- link_key_type += BTM_LTK_DERIVED_LKEY_OFFSET;
-
- uint8_t* p;
- BT_OCTET16 notif_link_key;
- p = notif_link_key;
- ARRAY16_TO_STREAM(p, link_key);
-
- btm_sec_link_key_notification(bda_for_lk, notif_link_key, link_key_type);
-
- SMP_TRACE_EVENT("%s is completed", __func__);
+ else
+ link_key_type = BTM_LKEY_TYPE_UNAUTH_COMB_P_256;
+ } else if (btm_cb.security_mode == BTM_SEC_MODE_SP) {
+ /* BR/EDR transport is SSP capable */
+ if (p_cb->sec_level == SMP_SEC_AUTHENTICATED)
+ link_key_type = BTM_LKEY_TYPE_AUTH_COMB;
+ else
+ link_key_type = BTM_LKEY_TYPE_UNAUTH_COMB;
+ } else {
+ SMP_TRACE_ERROR("%s failed to update link_key. Sec Mode = %d, sm4 = 0x%02x",
+ __func__, btm_cb.security_mode, p_dev_rec->sm4);
+ return false;
}
- return ret;
+ link_key_type += BTM_LTK_DERIVED_LKEY_OFFSET;
+
+ Octet16 notif_link_key = link_key;
+ btm_sec_link_key_notification(bda_for_lk, notif_link_key, link_key_type);
+
+ SMP_TRACE_EVENT("%s is completed", __func__);
+
+ return true;
}
-/*******************************************************************************
- *
- * Function smp_calculate_long_term_key_from_link_key
- *
- * Description The function calculates and saves SC LTK derived from BR/EDR
- * link key.
- *
- * Returns false if out of resources, true in other cases.
- *
- ******************************************************************************/
+/** The function calculates and saves SC LTK derived from BR/EDR link key. */
bool smp_calculate_long_term_key_from_link_key(tSMP_CB* p_cb) {
- bool ret = true;
tBTM_SEC_DEV_REC* p_dev_rec;
- uint8_t rev_link_key[16];
- BT_OCTET16 salt = {0x32, 0x70, 0x6D, 0x74, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
SMP_TRACE_DEBUG("%s", __func__);
@@ -1782,153 +1023,17 @@
return false;
}
- uint8_t* p1;
- uint8_t* p2;
- p1 = rev_link_key;
- p2 = p_dev_rec->link_key;
- REVERSE_ARRAY_TO_STREAM(p1, p2, 16);
+ Octet16 rev_link_key;
+ std::reverse_copy(p_dev_rec->link_key.begin(), p_dev_rec->link_key.end(),
+ rev_link_key.begin());
+ p_cb->ltk = crypto_toolbox::link_key_to_ltk(rev_link_key,
+ p_cb->key_derivation_h7_used);
- BT_OCTET16 intermediate_long_term_key;
- if (p_cb->key_derivation_h7_used) {
- ret = smp_calculate_h7((uint8_t*)salt, rev_link_key,
- intermediate_long_term_key);
- } else {
- /* "tmp2" obtained from the spec */
- ret = smp_calculate_h6(rev_link_key, (uint8_t*)"2pmt" /* reversed "tmp2" */,
- intermediate_long_term_key);
- }
-
- if (!ret) {
- SMP_TRACE_ERROR("%s failed to derive intermediate_long_term_key", __func__);
- return ret;
- }
-
- /* "brle" obtained from the spec */
- ret = smp_calculate_h6(intermediate_long_term_key,
- (uint8_t*)"elrb" /* reversed "brle" */, p_cb->ltk);
-
- if (!ret) {
- SMP_TRACE_ERROR("%s failed", __func__);
- } else {
- p_cb->sec_level = (br_link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256)
- ? SMP_SEC_AUTHENTICATED
- : SMP_SEC_UNAUTHENTICATE;
- SMP_TRACE_EVENT("%s is completed", __func__);
- }
-
- return ret;
-}
-
-/*******************************************************************************
- *
- * Function smp_calculate_h6
- *
- * Description The function calculates
- * C = h6(W, KeyID) = AES-CMAC (KeyID)
- * W
- * where
- * input: W is 128 bit,
- * KeyId is 32 bit,
- * output: C is 128 bit.
- *
- * Returns false if out of resources, true in other cases.
- *
- * Note The LSB is the first octet, the MSB is the last octet of
- * the AES-CMAC input/output stream.
- *
- ******************************************************************************/
-bool smp_calculate_h6(uint8_t* w, uint8_t* keyid, uint8_t* c) {
-#if (SMP_DEBUG == TRUE)
- uint8_t* p_print = NULL;
-#endif
-
- SMP_TRACE_DEBUG("%s", __func__);
-#if (SMP_DEBUG == TRUE)
- p_print = w;
- smp_debug_print_nbyte_little_endian(p_print, "W", BT_OCTET16_LEN);
- p_print = keyid;
- smp_debug_print_nbyte_little_endian(p_print, "keyID", 4);
-#endif
-
- uint8_t* p = NULL;
- uint8_t key[BT_OCTET16_LEN];
-
- p = key;
- ARRAY_TO_STREAM(p, w, BT_OCTET16_LEN);
-
-#if (SMP_DEBUG == TRUE)
- p_print = key;
- smp_debug_print_nbyte_little_endian(p_print, "K", BT_OCTET16_LEN);
-#endif
-
- uint8_t msg_len = 4 /* KeyID size */;
- uint8_t msg[4];
-
- p = msg;
- ARRAY_TO_STREAM(p, keyid, 4);
-
-#if (SMP_DEBUG == TRUE)
- p_print = msg;
- smp_debug_print_nbyte_little_endian(p_print, "M", msg_len);
-#endif
-
- bool ret = true;
- uint8_t cmac[BT_OCTET16_LEN];
- if (!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac)) {
- SMP_TRACE_ERROR("%s failed", __func__);
- ret = false;
- }
-
-#if (SMP_DEBUG == TRUE)
- p_print = cmac;
- smp_debug_print_nbyte_little_endian(p_print, "AES-CMAC", BT_OCTET16_LEN);
-#endif
-
- p = c;
- ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN);
- return ret;
-}
-
-/*******************************************************************************
-**
-** Function smp_calculate_h7
-**
-** Description The function calculates
-** C = h7(SALT, W) = AES-CMAC (W)
-** SALT
-** where
-** input: W is 128 bit,
-** SALT is 128 bit,
-** output: C is 128 bit.
-**
-** Returns FALSE if out of resources, TRUE in other cases.
-**
-** Note The LSB is the first octet, the MSB is the last octet of
-** the AES-CMAC input/output stream.
-**
-*******************************************************************************/
-bool smp_calculate_h7(uint8_t* salt, uint8_t* w, uint8_t* c) {
- SMP_TRACE_DEBUG("%s", __FUNCTION__);
-
- uint8_t key[BT_OCTET16_LEN];
- uint8_t* p = key;
- ARRAY_TO_STREAM(p, salt, BT_OCTET16_LEN);
-
- uint8_t msg_len = BT_OCTET16_LEN /* msg size */;
- uint8_t msg[BT_OCTET16_LEN];
- p = msg;
- ARRAY_TO_STREAM(p, w, BT_OCTET16_LEN);
-
- bool ret = true;
- uint8_t cmac[BT_OCTET16_LEN];
- if (!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac)) {
- SMP_TRACE_ERROR("%s failed", __FUNCTION__);
- ret = false;
- }
-
- p = c;
- ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN);
- return ret;
+ p_cb->sec_level = (br_link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256)
+ ? SMP_SEC_AUTHENTICATED
+ : SMP_SEC_UNAUTHENTICATE;
+ SMP_TRACE_EVENT("%s is completed", __func__);
+ return true;
}
/**
@@ -1938,10 +1043,10 @@
SMP_TRACE_DEBUG("%s", __func__);
btsnd_hcic_ble_rand(Bind(
[](tSMP_CB* p_cb, BT_OCTET8 rand) {
- memcpy((void*)p_cb->rand, rand, BT_OCTET8_LEN);
+ memcpy(p_cb->rand.data(), rand, BT_OCTET8_LEN);
btsnd_hcic_ble_rand(Bind(
[](tSMP_CB* p_cb, BT_OCTET8 rand) {
- memcpy((void*)&p_cb->rand[8], rand, BT_OCTET8_LEN);
+ memcpy(p_cb->rand.data() + 8, rand, BT_OCTET8_LEN);
SMP_TRACE_DEBUG("%s round %d", __func__, p_cb->round);
/* notifies SM that it has new nonce. */
smp_sm_event(p_cb, SMP_HAVE_LOC_NONCE_EVT, NULL);
diff --git a/stack/smp/smp_utils.cc b/stack/smp/smp_utils.cc
index bff5645..be98ed0 100644
--- a/stack/smp/smp_utils.cc
+++ b/stack/smp/smp_utils.cc
@@ -37,20 +37,21 @@
#include "smp_int.h"
#define SMP_PAIRING_REQ_SIZE 7
-#define SMP_CONFIRM_CMD_SIZE (BT_OCTET16_LEN + 1)
-#define SMP_RAND_CMD_SIZE (BT_OCTET16_LEN + 1)
-#define SMP_INIT_CMD_SIZE (BT_OCTET16_LEN + 1)
-#define SMP_ENC_INFO_SIZE (BT_OCTET16_LEN + 1)
+#define SMP_CONFIRM_CMD_SIZE (OCTET16_LEN + 1)
+#define SMP_RAND_CMD_SIZE (OCTET16_LEN + 1)
+#define SMP_INIT_CMD_SIZE (OCTET16_LEN + 1)
+#define SMP_ENC_INFO_SIZE (OCTET16_LEN + 1)
#define SMP_MASTER_ID_SIZE (BT_OCTET8_LEN + 2 + 1)
-#define SMP_ID_INFO_SIZE (BT_OCTET16_LEN + 1)
+#define SMP_ID_INFO_SIZE (OCTET16_LEN + 1)
#define SMP_ID_ADDR_SIZE (BD_ADDR_LEN + 1 + 1)
-#define SMP_SIGN_INFO_SIZE (BT_OCTET16_LEN + 1)
+#define SMP_SIGN_INFO_SIZE (OCTET16_LEN + 1)
#define SMP_PAIR_FAIL_SIZE 2
#define SMP_SECURITY_REQUEST_SIZE 2
#define SMP_PAIR_PUBL_KEY_SIZE (1 /* opcode */ + (2 * BT_OCTET32_LEN))
-#define SMP_PAIR_COMMITM_SIZE (1 /* opcode */ + BT_OCTET16_LEN /*Commitment*/)
+#define SMP_PAIR_COMMITM_SIZE (1 /* opcode */ + OCTET16_LEN /*Commitment*/)
#define SMP_PAIR_DHKEY_CHECK_SIZE \
- (1 /* opcode */ + BT_OCTET16_LEN /*DHKey Check*/)
+ (1 /* opcode */ + OCTET16_LEN /*DHKey \
+ Check*/)
#define SMP_PAIR_KEYPR_NOTIF_SIZE (1 /* opcode */ + 1 /*Notif Type*/)
/* SMP command sizes per spec */
@@ -454,7 +455,7 @@
p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
UINT8_TO_STREAM(p, SMP_OPCODE_CONFIRM);
- ARRAY_TO_STREAM(p, p_cb->confirm, BT_OCTET16_LEN);
+ ARRAY_TO_STREAM(p, p_cb->confirm, OCTET16_LEN);
p_buf->offset = L2CAP_MIN_OFFSET;
p_buf->len = SMP_CONFIRM_CMD_SIZE;
@@ -478,7 +479,7 @@
p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
UINT8_TO_STREAM(p, SMP_OPCODE_RAND);
- ARRAY_TO_STREAM(p, p_cb->rand, BT_OCTET16_LEN);
+ ARRAY_TO_STREAM(p, p_cb->rand, OCTET16_LEN);
p_buf->offset = L2CAP_MIN_OFFSET;
p_buf->len = SMP_RAND_CMD_SIZE;
@@ -503,7 +504,7 @@
p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
UINT8_TO_STREAM(p, SMP_OPCODE_ENCRYPT_INFO);
- ARRAY_TO_STREAM(p, p_cb->ltk, BT_OCTET16_LEN);
+ ARRAY_TO_STREAM(p, p_cb->ltk, OCTET16_LEN);
p_buf->offset = L2CAP_MIN_OFFSET;
p_buf->len = SMP_ENC_INFO_SIZE;
@@ -547,7 +548,6 @@
static BT_HDR* smp_build_identity_info_cmd(UNUSED_ATTR uint8_t cmd_code,
UNUSED_ATTR tSMP_CB* p_cb) {
uint8_t* p;
- BT_OCTET16 irk;
BT_HDR* p_buf =
(BT_HDR*)osi_malloc(sizeof(BT_HDR) + SMP_ID_INFO_SIZE + L2CAP_MIN_OFFSET);
@@ -555,10 +555,10 @@
p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
- BTM_GetDeviceIDRoot(irk);
+ const Octet16& irk = BTM_GetDeviceIDRoot();
UINT8_TO_STREAM(p, SMP_OPCODE_IDENTITY_INFO);
- ARRAY_TO_STREAM(p, irk, BT_OCTET16_LEN);
+ ARRAY_TO_STREAM(p, irk.data(), OCTET16_LEN);
p_buf->offset = L2CAP_MIN_OFFSET;
p_buf->len = SMP_ID_INFO_SIZE;
@@ -609,7 +609,7 @@
p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
UINT8_TO_STREAM(p, SMP_OPCODE_SIGN_INFO);
- ARRAY_TO_STREAM(p, p_cb->csrk, BT_OCTET16_LEN);
+ ARRAY_TO_STREAM(p, p_cb->csrk, OCTET16_LEN);
p_buf->offset = L2CAP_MIN_OFFSET;
p_buf->len = SMP_SIGN_INFO_SIZE;
@@ -716,7 +716,7 @@
p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
UINT8_TO_STREAM(p, SMP_OPCODE_CONFIRM);
- ARRAY_TO_STREAM(p, p_cb->commitment, BT_OCTET16_LEN);
+ ARRAY_TO_STREAM(p, p_cb->commitment, OCTET16_LEN);
p_buf->offset = L2CAP_MIN_OFFSET;
p_buf->len = SMP_PAIR_COMMITM_SIZE;
@@ -741,7 +741,7 @@
p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
UINT8_TO_STREAM(p, SMP_OPCODE_PAIR_DHKEY_CHECK);
- ARRAY_TO_STREAM(p, p_cb->dhkey_check, BT_OCTET16_LEN);
+ ARRAY_TO_STREAM(p, p_cb->dhkey_check, OCTET16_LEN);
p_buf->offset = L2CAP_MIN_OFFSET;
p_buf->len = SMP_PAIR_DHKEY_CHECK_SIZE;
@@ -774,66 +774,42 @@
return p_buf;
}
-/*******************************************************************************
- *
- * Function smp_convert_string_to_tk
- *
- * Description This function is called to convert a 6 to 16 digits numeric
- * character string into SMP TK.
- *
- *
- * Returns void
- *
- ******************************************************************************/
-void smp_convert_string_to_tk(BT_OCTET16 tk, uint32_t passkey) {
- uint8_t* p = tk;
+/** This function is called to convert a 6 to 16 digits numeric character string
+ * into SMP TK. */
+void smp_convert_string_to_tk(Octet16* tk, uint32_t passkey) {
+ uint8_t* p = tk->data();
tSMP_KEY key;
SMP_TRACE_EVENT("smp_convert_string_to_tk");
UINT32_TO_STREAM(p, passkey);
key.key_type = SMP_KEY_TYPE_TK;
- key.p_data = tk;
+ key.p_data = tk->data();
tSMP_INT_DATA smp_int_data;
smp_int_data.key = key;
smp_sm_event(&smp_cb, SMP_KEY_READY_EVT, &smp_int_data);
}
-/*******************************************************************************
- *
- * Function smp_mask_enc_key
- *
- * Description This function is called to mask off the encryption key based
- * on the maximum encryption key size.
- *
- *
- * Returns void
- *
- ******************************************************************************/
-void smp_mask_enc_key(uint8_t loc_enc_size, uint8_t* p_data) {
+/** This function is called to mask off the encryption key based on the maximum
+ * encryption key size. */
+void smp_mask_enc_key(uint8_t loc_enc_size, Octet16* p_data) {
SMP_TRACE_EVENT("smp_mask_enc_key");
- if (loc_enc_size < BT_OCTET16_LEN) {
- for (; loc_enc_size < BT_OCTET16_LEN; loc_enc_size++)
- *(p_data + loc_enc_size) = 0;
+ if (loc_enc_size < OCTET16_LEN) {
+ for (; loc_enc_size < OCTET16_LEN; loc_enc_size++)
+ (*p_data)[loc_enc_size] = 0;
}
return;
}
-/*******************************************************************************
- *
- * Function smp_xor_128
- *
- * Description utility function to do an biteise exclusive-OR of two bit
- * strings of the length of BT_OCTET16_LEN.
- *
- * Returns void
- *
- ******************************************************************************/
-void smp_xor_128(BT_OCTET16 a, BT_OCTET16 b) {
- uint8_t i, *aa = a, *bb = b;
+/** utility function to do an biteise exclusive-OR of two bit strings of the
+ * length of OCTET16_LEN. Result is stored in first argument.
+ */
+void smp_xor_128(Octet16* a, const Octet16& b) {
+ CHECK(a);
+ uint8_t i, *aa = a->data();
+ const uint8_t* bb = b.data();
- SMP_TRACE_EVENT("smp_xor_128");
- for (i = 0; i < BT_OCTET16_LEN; i++) {
+ for (i = 0; i < OCTET16_LEN; i++) {
aa[i] = aa[i] ^ bb[i];
}
}
@@ -1409,15 +1385,14 @@
*
******************************************************************************/
bool smp_check_commitment(tSMP_CB* p_cb) {
- BT_OCTET16 expected;
SMP_TRACE_DEBUG("%s", __func__);
- smp_calculate_peer_commitment(p_cb, expected);
+ Octet16 expected = smp_calculate_peer_commitment(p_cb);
print128(expected, (const uint8_t*)"calculated peer commitment");
print128(p_cb->remote_commitment, (const uint8_t*)"received peer commitment");
- if (memcmp(p_cb->remote_commitment, expected, BT_OCTET16_LEN)) {
+ if (memcmp(p_cb->remote_commitment.data(), expected.data(), OCTET16_LEN)) {
SMP_TRACE_WARNING("%s: Commitment check fails", __func__);
return false;
}
@@ -1441,7 +1416,7 @@
tBTM_LE_PENC_KEYS ple_key;
SMP_TRACE_DEBUG("%s-Save LTK as local LTK key", __func__);
- memcpy(lle_key.ltk, p_cb->ltk, BT_OCTET16_LEN);
+ lle_key.ltk = p_cb->ltk;
lle_key.div = 0;
lle_key.key_size = p_cb->loc_enc_size;
lle_key.sec_level = p_cb->sec_level;
@@ -1451,53 +1426,39 @@
SMP_TRACE_DEBUG("%s-Save LTK as peer LTK key", __func__);
ple_key.ediv = 0;
memset(ple_key.rand, 0, BT_OCTET8_LEN);
- memcpy(ple_key.ltk, p_cb->ltk, BT_OCTET16_LEN);
+ ple_key.ltk = p_cb->ltk;
ple_key.sec_level = p_cb->sec_level;
ple_key.key_size = p_cb->loc_enc_size;
btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PENC,
(tBTM_LE_KEY_VALUE*)&ple_key, true);
}
-/*******************************************************************************
- *
- * Function smp_calculate_f5_mackey_and_long_term_key
- *
- * Description The function calculates MacKey and LTK and saves them in CB.
- * To calculate MacKey and LTK it calls smp_calc_f5(...).
- * MacKey is used in dhkey calculation, LTK is used to encrypt
- * the link.
- *
- * Returns false if out of resources, true otherwise.
- *
- ******************************************************************************/
-bool smp_calculate_f5_mackey_and_long_term_key(tSMP_CB* p_cb) {
+/** The function calculates MacKey and LTK and saves them in CB. To calculate
+ * MacKey and LTK it calls smp_calc_f5(...). MacKey is used in dhkey
+ * calculation, LTK is used to encrypt the link. */
+void smp_calculate_f5_mackey_and_long_term_key(tSMP_CB* p_cb) {
uint8_t a[7];
uint8_t b[7];
- uint8_t* p_na;
- uint8_t* p_nb;
+ Octet16 na;
+ Octet16 nb;
SMP_TRACE_DEBUG("%s", __func__);
if (p_cb->role == HCI_ROLE_MASTER) {
smp_collect_local_ble_address(a, p_cb);
smp_collect_peer_ble_address(b, p_cb);
- p_na = p_cb->rand;
- p_nb = p_cb->rrand;
+ na = p_cb->rand;
+ nb = p_cb->rrand;
} else {
smp_collect_local_ble_address(b, p_cb);
smp_collect_peer_ble_address(a, p_cb);
- p_na = p_cb->rrand;
- p_nb = p_cb->rand;
+ na = p_cb->rrand;
+ nb = p_cb->rand;
}
- if (!smp_calculate_f5(p_cb->dhkey, p_na, p_nb, a, b, p_cb->mac_key,
- p_cb->ltk)) {
- SMP_TRACE_ERROR("%s failed", __func__);
- return false;
- }
+ crypto_toolbox::f5(p_cb->dhkey, na, nb, a, b, &p_cb->mac_key, &p_cb->ltk);
SMP_TRACE_EVENT("%s is completed", __func__);
- return true;
}
/*******************************************************************************
@@ -1538,3 +1499,15 @@
return true;
}
+
+void print128(const Octet16& x, const uint8_t* key_name) {
+ if (VLOG_IS_ON(2) && DLOG_IS_ON(INFO)) {
+ uint8_t* p = (uint8_t*)x.data();
+
+ DVLOG(2) << key_name << " (MSB ~ LSB) = ";
+ for (int i = 0; i < 4; i++) {
+ DVLOG(2) << +p[OCTET16_LEN - i * 4 - 1] << +p[OCTET16_LEN - i * 4 - 2]
+ << +p[OCTET16_LEN - i * 4 - 3] << +p[OCTET16_LEN - i * 4 - 4];
+ }
+ }
+}
diff --git a/stack/test/ble_advertiser_test.cc b/stack/test/ble_advertiser_test.cc
index 65a30d5..6ca0ad4 100644
--- a/stack/test/ble_advertiser_test.cc
+++ b/stack/test/ble_advertiser_test.cc
@@ -47,19 +47,11 @@
uint16_t BTM_ReadDiscoverability(uint16_t* p_window, uint16_t* p_interval) {
return true;
}
-bool SMP_Encrypt(uint8_t* key, uint8_t key_len, uint8_t* plain_text,
- uint8_t pt_len, tSMP_ENC* p_out) {
- return true;
-}
-void BTM_GetDeviceIDRoot(BT_OCTET16 irk) {}
-void btm_ble_update_dmt_flag_bits(uint8_t* flag_value,
- const uint16_t connect_mode,
- const uint16_t disc_mode) {}
void btm_acl_update_conn_addr(uint16_t conn_handle, const RawAddress& address) {
}
-void btm_gen_resolvable_private_addr(base::Callback<void(uint8_t[8])> cb) {
- uint8_t fake_rand[8] = {0, 0, 0, 0, 0, 0, 0, 0};
- cb.Run(fake_rand);
+void btm_gen_resolvable_private_addr(
+ base::Callback<void(const RawAddress& rpa)> cb) {
+ cb.Run(RawAddress::kEmpty);
}
alarm_callback_t last_alarm_cb = nullptr;
diff --git a/stack/test/crypto_toolbox_test.cc b/stack/test/crypto_toolbox_test.cc
new file mode 100644
index 0000000..727668d
--- /dev/null
+++ b/stack/test/crypto_toolbox_test.cc
@@ -0,0 +1,400 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "stack/crypto_toolbox/aes.h"
+#include "stack/crypto_toolbox/crypto_toolbox.h"
+
+#include <base/logging.h>
+#include <base/strings/string_number_conversions.h>
+#include <vector>
+
+using ::testing::ElementsAreArray;
+
+namespace crypto_toolbox {
+
+// BT Spec 5.0 | Vol 3, Part H D.1
+TEST(CryptoToolboxTest, bt_spec_test_d_1_test) {
+ uint8_t k[] = {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
+
+ uint8_t m[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+ uint8_t aes_cmac_k_m[] = {0x7d, 0xf7, 0x6b, 0x0c, 0x1a, 0xb8, 0x99, 0xb3,
+ 0x3e, 0x42, 0xf0, 0x47, 0xb9, 0x1b, 0x54, 0x6f};
+
+ uint8_t output[16];
+ aes_context ctx;
+ aes_set_key(k, sizeof(k), &ctx);
+ aes_encrypt(m, output, &ctx); /* outputs in byte 48 to byte 63 */
+
+ EXPECT_THAT(output, ElementsAreArray(aes_cmac_k_m, OCTET16_LEN));
+
+ // useful for debugging
+ // LOG(INFO) << "k " << base::HexEncode(k, OCTET16_LEN);
+ // LOG(INFO) << "m " << base::HexEncode(m, sizeof(m));
+ // LOG(INFO) << "output " << base::HexEncode(output, OCTET16_LEN);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.1.1
+TEST(CryptoToolboxTest, bt_spec_example_d_1_1_test) {
+ Octet16 k{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
+
+ Octet16 aes_cmac_k_m{0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28,
+ 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(k), std::end(k));
+ std::reverse(std::begin(aes_cmac_k_m), std::end(aes_cmac_k_m));
+
+ Octet16 output = aes_cmac(k, nullptr /* empty message */, 0);
+
+ EXPECT_EQ(output, aes_cmac_k_m);
+
+ // useful for debugging
+ // LOG(INFO) << "k " << base::HexEncode(k.data(), k.size());
+ // LOG(INFO) << "aes_cmac(k,nullptr) "
+ // << base::HexEncode(output.data(), output.size());
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.1.2
+TEST(CryptoToolboxTest, bt_spec_example_d_1_2_test) {
+ Octet16 k{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
+
+ Octet16 m = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a};
+
+ Octet16 aes_cmac_k_m{0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44,
+ 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(k), std::end(k));
+ std::reverse(std::begin(m), std::end(m));
+ std::reverse(std::begin(aes_cmac_k_m), std::end(aes_cmac_k_m));
+
+ Octet16 output = aes_cmac(k, m);
+
+ EXPECT_EQ(output, aes_cmac_k_m);
+
+ // useful for debugging
+ // LOG(INFO) << "k " << base::HexEncode(k.data(), k.size());
+ // LOG(INFO) << "m " << base::HexEncode(m, sizeof(m));
+ // LOG(INFO) << "aes_cmac(k,m) "
+ // << base::HexEncode(output.data(), output.size());
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.1.3
+TEST(CryptoToolboxTest, bt_spec_example_d_1_3_test) {
+ Octet16 k{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
+
+ uint8_t m[] = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d,
+ 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57,
+ 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf,
+ 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11};
+
+ Octet16 aes_cmac_k_m{0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30,
+ 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(k), std::end(k));
+ std::reverse(std::begin(m), std::end(m));
+ std::reverse(std::begin(aes_cmac_k_m), std::end(aes_cmac_k_m));
+
+ Octet16 output = aes_cmac(k, m, sizeof(m));
+ EXPECT_EQ(output, aes_cmac_k_m);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.1.4
+TEST(CryptoToolboxTest, bt_spec_example_d_1_4_test) {
+ Octet16 k{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
+
+ uint8_t m[] = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d,
+ 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57,
+ 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf,
+ 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+ 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, 0xf6, 0x9f,
+ 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b,
+ 0xe6, 0x6c, 0x37, 0x10};
+
+ Octet16 aes_cmac_k_m{0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92,
+ 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(k), std::end(k));
+ std::reverse(std::begin(m), std::end(m));
+ std::reverse(std::begin(aes_cmac_k_m), std::end(aes_cmac_k_m));
+
+ Octet16 output = aes_cmac(k, m, sizeof(m));
+
+ EXPECT_EQ(output, aes_cmac_k_m);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.2
+TEST(CryptoToolboxTest, bt_spec_example_d_2_test) {
+ std::vector<uint8_t> u{0x20, 0xb0, 0x03, 0xd2, 0xf2, 0x97, 0xbe, 0x2c,
+ 0x5e, 0x2c, 0x83, 0xa7, 0xe9, 0xf9, 0xa5, 0xb9,
+ 0xef, 0xf4, 0x91, 0x11, 0xac, 0xf4, 0xfd, 0xdb,
+ 0xcc, 0x03, 0x01, 0x48, 0x0e, 0x35, 0x9d, 0xe6};
+ std::vector<uint8_t> v{0x55, 0x18, 0x8b, 0x3d, 0x32, 0xf6, 0xbb, 0x9a,
+ 0x90, 0x0a, 0xfc, 0xfb, 0xee, 0xd4, 0xe7, 0x2a,
+ 0x59, 0xcb, 0x9a, 0xc2, 0xf1, 0x9d, 0x7c, 0xfb,
+ 0x6b, 0x4f, 0xdd, 0x49, 0xf4, 0x7f, 0xc5, 0xfd};
+ Octet16 x{0xd5, 0xcb, 0x84, 0x54, 0xd1, 0x77, 0x73, 0x3e,
+ 0xff, 0xff, 0xb2, 0xec, 0x71, 0x2b, 0xae, 0xab};
+ uint8_t z = 0x00;
+
+ Octet16 aes_cmac_k_m{0xf2, 0xc9, 0x16, 0xf1, 0x07, 0xa9, 0xbd, 0x1c,
+ 0xf1, 0xed, 0xa1, 0xbe, 0xa9, 0x74, 0x87, 0x2d};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(u), std::end(u));
+ std::reverse(std::begin(v), std::end(v));
+ std::reverse(std::begin(x), std::end(x));
+ std::reverse(std::begin(aes_cmac_k_m), std::end(aes_cmac_k_m));
+
+ Octet16 output = f4(u.data(), v.data(), x, z);
+
+ EXPECT_EQ(output, aes_cmac_k_m);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.3
+TEST(CryptoToolboxTest, bt_spec_example_d_3_test) {
+ std::array<uint8_t, 32> dhkey_w{
+ 0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, 0x34, 0x10, 0x10,
+ 0xa6, 0x0a, 0x39, 0x7d, 0x9b, 0x99, 0x79, 0x6b, 0x13, 0xb4, 0xf8,
+ 0x66, 0xf1, 0x86, 0x8d, 0x34, 0xf3, 0x73, 0xbf, 0xa6, 0x98};
+ Octet16 n1{0xd5, 0xcb, 0x84, 0x54, 0xd1, 0x77, 0x73, 0x3e,
+ 0xff, 0xff, 0xb2, 0xec, 0x71, 0x2b, 0xae, 0xab};
+ Octet16 n2{0xa6, 0xe8, 0xe7, 0xcc, 0x25, 0xa7, 0x5f, 0x6e,
+ 0x21, 0x65, 0x83, 0xf7, 0xff, 0x3d, 0xc4, 0xcf};
+ std::array<uint8_t, 7> a1{0x00, 0x56, 0x12, 0x37, 0x37, 0xbf, 0xce};
+ std::array<uint8_t, 7> a2{0x00, 0xa7, 0x13, 0x70, 0x2d, 0xcf, 0xc1};
+
+ Octet16 expected_ltk{0x69, 0x86, 0x79, 0x11, 0x69, 0xd7, 0xcd, 0x23,
+ 0x98, 0x05, 0x22, 0xb5, 0x94, 0x75, 0x0a, 0x38};
+ Octet16 expected_mac_key{0x29, 0x65, 0xf1, 0x76, 0xa1, 0x08, 0x4a, 0x02,
+ 0xfd, 0x3f, 0x6a, 0x20, 0xce, 0x63, 0x6e, 0x20};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(dhkey_w), std::end(dhkey_w));
+ std::reverse(std::begin(n1), std::end(n1));
+ std::reverse(std::begin(n2), std::end(n2));
+ std::reverse(std::begin(a1), std::end(a1));
+ std::reverse(std::begin(a2), std::end(a2));
+ std::reverse(std::begin(expected_ltk), std::end(expected_ltk));
+ std::reverse(std::begin(expected_mac_key), std::end(expected_mac_key));
+
+ Octet16 mac_key, ltk;
+ f5(dhkey_w.data(), n1, n2, a1.data(), a2.data(), &mac_key, <k);
+
+ EXPECT_EQ(mac_key, expected_mac_key);
+ EXPECT_EQ(ltk, expected_ltk);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.4
+TEST(CryptoToolboxTest, bt_spec_example_d_4_test) {
+ Octet16 n1{0xd5, 0xcb, 0x84, 0x54, 0xd1, 0x77, 0x73, 0x3e,
+ 0xff, 0xff, 0xb2, 0xec, 0x71, 0x2b, 0xae, 0xab};
+ Octet16 n2{0xa6, 0xe8, 0xe7, 0xcc, 0x25, 0xa7, 0x5f, 0x6e,
+ 0x21, 0x65, 0x83, 0xf7, 0xff, 0x3d, 0xc4, 0xcf};
+ Octet16 r{0x12, 0xa3, 0x34, 0x3b, 0xb4, 0x53, 0xbb, 0x54,
+ 0x08, 0xda, 0x42, 0xd2, 0x0c, 0x2d, 0x0f, 0xc8};
+ std::vector<uint8_t> IOcap{0x01, 0x01, 0x02};
+ std::vector<uint8_t> a1{0x00, 0x56, 0x12, 0x37, 0x37, 0xbf, 0xce};
+ std::vector<uint8_t> a2{0x00, 0xa7, 0x13, 0x70, 0x2d, 0xcf, 0xc1};
+
+ Octet16 MacKey{0x29, 0x65, 0xf1, 0x76, 0xa1, 0x08, 0x4a, 0x02,
+ 0xfd, 0x3f, 0x6a, 0x20, 0xce, 0x63, 0x6e, 0x20};
+
+ Octet16 expected_aes_cmac{0xe3, 0xc4, 0x73, 0x98, 0x9c, 0xd0, 0xe8, 0xc5,
+ 0xd2, 0x6c, 0x0b, 0x09, 0xda, 0x95, 0x8f, 0x61};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(n1), std::end(n1));
+ std::reverse(std::begin(n2), std::end(n2));
+ std::reverse(std::begin(r), std::end(r));
+ std::reverse(std::begin(IOcap), std::end(IOcap));
+ std::reverse(std::begin(a1), std::end(a1));
+ std::reverse(std::begin(a2), std::end(a2));
+ std::reverse(std::begin(MacKey), std::end(MacKey));
+ std::reverse(std::begin(expected_aes_cmac), std::end(expected_aes_cmac));
+
+ Octet16 aes_cmac = f6(MacKey, n1, n2, r, IOcap.data(), a1.data(), a2.data());
+
+ EXPECT_EQ(aes_cmac, expected_aes_cmac);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.5
+TEST(CryptoToolboxTest, bt_spec_example_d_5_test) {
+ std::array<uint8_t, 32> u{0x20, 0xb0, 0x03, 0xd2, 0xf2, 0x97, 0xbe, 0x2c,
+ 0x5e, 0x2c, 0x83, 0xa7, 0xe9, 0xf9, 0xa5, 0xb9,
+ 0xef, 0xf4, 0x91, 0x11, 0xac, 0xf4, 0xfd, 0xdb,
+ 0xcc, 0x03, 0x01, 0x48, 0x0e, 0x35, 0x9d, 0xe6};
+ std::array<uint8_t, 32> v{0x55, 0x18, 0x8b, 0x3d, 0x32, 0xf6, 0xbb, 0x9a,
+ 0x90, 0x0a, 0xfc, 0xfb, 0xee, 0xd4, 0xe7, 0x2a,
+ 0x59, 0xcb, 0x9a, 0xc2, 0xf1, 0x9d, 0x7c, 0xfb,
+ 0x6b, 0x4f, 0xdd, 0x49, 0xf4, 0x7f, 0xc5, 0xfd};
+
+ Octet16 x{0xd5, 0xcb, 0x84, 0x54, 0xd1, 0x77, 0x73, 0x3e,
+ 0xff, 0xff, 0xb2, 0xec, 0x71, 0x2b, 0xae, 0xab};
+ Octet16 y{0xa6, 0xe8, 0xe7, 0xcc, 0x25, 0xa7, 0x5f, 0x6e,
+ 0x21, 0x65, 0x83, 0xf7, 0xff, 0x3d, 0xc4, 0xcf};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(u), std::end(u));
+ std::reverse(std::begin(v), std::end(v));
+ std::reverse(std::begin(x), std::end(x));
+ std::reverse(std::begin(y), std::end(y));
+
+ uint32_t val = g2(u.data(), v.data(), x, y);
+
+ /* the returned value is already mod 1000000, so do mod on the test result
+ * value too */
+ EXPECT_EQ(val, 0x2f9ed5baU % 1000000);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.6
+TEST(CryptoToolboxTest, bt_spec_example_d_6_test) {
+ Octet16 key{0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05,
+ 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b};
+ std::array<uint8_t, 4> keyID{0x6c, 0x65, 0x62, 0x72};
+ Octet16 expected_aes_cmac{0x2d, 0x9a, 0xe1, 0x02, 0xe7, 0x6d, 0xc9, 0x1c,
+ 0xe8, 0xd3, 0xa9, 0xe2, 0x80, 0xb1, 0x63, 0x99};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(key), std::end(key));
+ std::reverse(std::begin(keyID), std::end(keyID));
+ std::reverse(std::begin(expected_aes_cmac), std::end(expected_aes_cmac));
+
+ Octet16 aes_cmac = h6(key, keyID);
+ EXPECT_EQ(aes_cmac, expected_aes_cmac);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.7
+TEST(CryptoToolboxTest, bt_spec_example_d_7_test) {
+ Octet16 IRK{0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05,
+ 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b};
+ Octet16 prand{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x81, 0x94};
+ Octet16 expected_aes_128{0x15, 0x9d, 0x5f, 0xb7, 0x2e, 0xbe, 0x23, 0x11,
+ 0xa4, 0x8c, 0x1b, 0xdc, 0xc4, 0x0d, 0xfb, 0xaa};
+ std::array<uint8_t, 3> expected_ah{0x0d, 0xfb, 0xaa};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(IRK), std::end(IRK));
+ std::reverse(std::begin(prand), std::end(prand));
+ std::reverse(std::begin(expected_aes_128), std::end(expected_aes_128));
+ std::reverse(std::begin(expected_ah), std::end(expected_ah));
+
+ Octet16 result = aes_128(IRK, prand.data(), 3);
+ EXPECT_EQ(expected_aes_128, result);
+
+ // little/big endian 24 bits
+ EXPECT_EQ(result[0], expected_ah[0]);
+ EXPECT_EQ(result[1], expected_ah[1]);
+ EXPECT_EQ(result[2], expected_ah[2]);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.8
+TEST(CryptoToolboxTest, bt_spec_example_d_8_test) {
+ Octet16 Key{0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05,
+ 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b};
+ Octet16 SALT{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x74, 0x6D, 0x70, 0x31};
+ Octet16 expected_aes_cmac{0xfb, 0x17, 0x35, 0x97, 0xc6, 0xa3, 0xc0, 0xec,
+ 0xd2, 0x99, 0x8c, 0x2a, 0x75, 0xa5, 0x70, 0x11};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(Key), std::end(Key));
+ std::reverse(std::begin(SALT), std::end(SALT));
+ std::reverse(std::begin(expected_aes_cmac), std::end(expected_aes_cmac));
+
+ Octet16 aes_cmac = h7(SALT, Key);
+ EXPECT_EQ(expected_aes_cmac, aes_cmac);
+}
+
+extern Octet16 smp_calculate_ltk_to_link_key(const Octet16& ltk, bool use_h7);
+
+// BT Spec 5.0 | Vol 3, Part H D.9
+TEST(CryptoToolboxTest, bt_spec_example_d_9_test) {
+ Octet16 LTK{0x36, 0x8d, 0xf9, 0xbc, 0xe3, 0x26, 0x4b, 0x58,
+ 0xbd, 0x06, 0x6c, 0x33, 0x33, 0x4f, 0xbf, 0x64};
+ Octet16 expected_link_key{0x28, 0x7a, 0xd3, 0x79, 0xdc, 0xa4, 0x02, 0x53,
+ 0x0a, 0x39, 0xf1, 0xf4, 0x30, 0x47, 0xb8, 0x35};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(LTK), std::end(LTK));
+ std::reverse(std::begin(expected_link_key), std::end(expected_link_key));
+
+ Octet16 link_key = ltk_to_link_key(LTK, true);
+ EXPECT_EQ(expected_link_key, link_key);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.10
+TEST(CryptoToolboxTest, bt_spec_example_d_10_test) {
+ Octet16 LTK{0x36, 0x8d, 0xf9, 0xbc, 0xe3, 0x26, 0x4b, 0x58,
+ 0xbd, 0x06, 0x6c, 0x33, 0x33, 0x4f, 0xbf, 0x64};
+ Octet16 expected_link_key{0xbc, 0x1c, 0xa4, 0xef, 0x63, 0x3f, 0xc1, 0xbd,
+ 0x0d, 0x82, 0x30, 0xaf, 0xee, 0x38, 0x8f, 0xb0};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(LTK), std::end(LTK));
+ std::reverse(std::begin(expected_link_key), std::end(expected_link_key));
+
+ Octet16 link_key = ltk_to_link_key(LTK, false);
+ EXPECT_EQ(expected_link_key, link_key);
+}
+
+// // BT Spec 5.0 | Vol 3, Part H D.11
+TEST(CryptoToolboxTest, bt_spec_example_d_11_test) {
+ Octet16 link_key{0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00};
+ Octet16 expected_ltk{0xe8, 0x5e, 0x09, 0xeb, 0x5e, 0xcc, 0xb3, 0xe2,
+ 0x69, 0x41, 0x8a, 0x13, 0x32, 0x11, 0xbc, 0x79};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(link_key), std::end(link_key));
+ std::reverse(std::begin(expected_ltk), std::end(expected_ltk));
+
+ Octet16 ltk = link_key_to_ltk(link_key, true);
+ EXPECT_EQ(expected_ltk, ltk);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.12
+TEST(CryptoToolboxTest, bt_spec_example_d_12_test) {
+ Octet16 link_key{0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00};
+ Octet16 expected_ltk{0xa8, 0x13, 0xfb, 0x72, 0xf1, 0xa3, 0xdf, 0xa1,
+ 0x8a, 0x2c, 0x9a, 0x43, 0xf1, 0x0d, 0x0a, 0x30};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(link_key), std::end(link_key));
+ std::reverse(std::begin(expected_ltk), std::end(expected_ltk));
+
+ Octet16 ltk = link_key_to_ltk(link_key, false);
+ EXPECT_EQ(expected_ltk, ltk);
+}
+
+} // namespace crypto_toolbox
diff --git a/stack/test/stack_smp_test.cc b/stack/test/stack_smp_test.cc
index 9070764..2427814 100644
--- a/stack/test/stack_smp_test.cc
+++ b/stack/test/stack_smp_test.cc
@@ -80,70 +80,58 @@
va_end(args);
}
-extern void smp_gen_p1_4_confirm(tSMP_CB* p_cb,
- tBLE_ADDR_TYPE remote_bd_addr_type,
- BT_OCTET16 p1);
+extern Octet16 smp_gen_p1_4_confirm(tSMP_CB* p_cb,
+ tBLE_ADDR_TYPE remote_bd_addr_type);
-extern void smp_gen_p2_4_confirm(tSMP_CB* p_cb, const RawAddress& remote_bda,
- BT_OCTET16 p2);
+extern Octet16 smp_gen_p2_4_confirm(tSMP_CB* p_cb,
+ const RawAddress& remote_bda);
-extern tSMP_STATUS smp_calculate_comfirm(tSMP_CB* p_cb, BT_OCTET16 rand,
- tSMP_ENC* output);
+extern tSMP_STATUS smp_calculate_comfirm(tSMP_CB* p_cb, const Octet16& rand,
+ Octet16* output);
namespace testing {
-void dump_uint128(BT_OCTET16 a, char* buffer) {
- for (unsigned int i = 0; i < sizeof(BT_OCTET16); ++i) {
+void dump_uint128(const Octet16& a, char* buffer) {
+ for (unsigned int i = 0; i < OCTET16_LEN; ++i) {
snprintf(buffer, 3, "%02x", a[i]);
buffer += 2;
}
*buffer = '\0';
}
-void dump_uint128_reverse(BT_OCTET16 a, char* buffer) {
- for (int i = (int)(sizeof(BT_OCTET16) - 1); i >= 0; --i) {
+void dump_uint128_reverse(const Octet16& a, char* buffer) {
+ for (int i = (int)(OCTET16_LEN - 1); i >= 0; --i) {
snprintf(buffer, 3, "%02x", a[i]);
buffer += 2;
}
*buffer = '\0';
}
-void print_uint128(BT_OCTET16 a) {
- for (unsigned int i = 0; i < sizeof(BT_OCTET16); ++i) {
+void print_uint128(const Octet16& a) {
+ for (unsigned int i = 0; i < OCTET16_LEN; ++i) {
printf("%02x", a[i]);
}
printf("\n");
}
-void parse_uint128(const char* input, BT_OCTET16 output) {
- memset(output, 0, sizeof(BT_OCTET16));
- for (unsigned int count = 0; count < sizeof(BT_OCTET16); count++) {
+Octet16 parse_uint128(const char* input) {
+ Octet16 output{0};
+ for (unsigned int count = 0; count < OCTET16_LEN; count++) {
sscanf(input, "%2hhx", &output[count]);
input += 2;
}
-}
-
-void reverse_array_inplace(BT_OCTET16 a) {
- uint8_t tmp;
- uint8_t* a_end = a + sizeof(BT_OCTET16) - 1;
- while (a_end > a) {
- tmp = *a_end;
- *a_end = *a;
- *a = tmp;
- ++a;
- --a_end;
- }
+ return output;
}
class SmpCalculateConfirmTest : public Test {
protected:
tSMP_CB p_cb_;
// Set random to 0x5783D52156AD6F0E6388274EC6702EE0
- BT_OCTET16 rand_ = {0x57, 0x83, 0xD5, 0x21, 0x56, 0xAD, 0x6F, 0x0E,
- 0x63, 0x88, 0x27, 0x4E, 0xC6, 0x70, 0x2E, 0xE0};
+ Octet16 rand_{0x57, 0x83, 0xD5, 0x21, 0x56, 0xAD, 0x6F, 0x0E,
+ 0x63, 0x88, 0x27, 0x4E, 0xC6, 0x70, 0x2E, 0xE0};
void SetUp() {
- memset(p_cb_.tk, 0, sizeof(p_cb_.tk));
+ p_cb_.tk = {0};
// Set pairing request packet to 0x070710000001(01)
p_cb_.local_io_capability = 0x01;
p_cb_.loc_oob_flag = 0x00;
@@ -160,7 +148,7 @@
p_cb_.peer_r_key = 0x05;
// Set role to master
p_cb_.role = HCI_ROLE_MASTER;
- reverse_array_inplace(rand_);
+ std::reverse(rand_.begin(), rand_.end());
}
void TearDown() {}
@@ -169,59 +157,54 @@
// Test smp_gen_p2_4_confirm function implementation
TEST_F(SmpCalculateConfirmTest, test_smp_gen_p2_4_confirm_as_master) {
- BT_OCTET16 p2;
RawAddress remote_bda;
tBLE_ADDR_TYPE remote_bd_addr_type = 0;
BTM_ReadRemoteConnectionAddr(p_cb_.pairing_bda, remote_bda,
&remote_bd_addr_type);
BTM_ReadConnectionAddr(p_cb_.pairing_bda, p_cb_.local_bda, &p_cb_.addr_type);
- smp_gen_p2_4_confirm(&p_cb_, remote_bda, p2);
+ Octet16 p2 = smp_gen_p2_4_confirm(&p_cb_, remote_bda);
// Correct p2 is 0x00000000a1a2a3a4a5a6b1b2b3b4b5b6
const char expected_p2_str[] = "00000000a1a2a3a4a5a6b1b2b3b4b5b6";
- char p2_str[2 * sizeof(BT_OCTET16) + 1];
+ char p2_str[2 * OCTET16_LEN + 1];
dump_uint128_reverse(p2, p2_str);
ASSERT_THAT(p2_str, StrEq(expected_p2_str));
}
-// Test smp_gen_p1_4_confirm and SMP_Encrypt function implementation
-TEST_F(SmpCalculateConfirmTest, test_SMP_Encrypt_as_master) {
- BT_OCTET16 p1;
+// Test smp_gen_p1_4_confirm and aes_128 function implementation
+TEST_F(SmpCalculateConfirmTest, test_aes_128_as_master) {
RawAddress remote_bda;
tBLE_ADDR_TYPE remote_bd_addr_type = 0;
BTM_ReadRemoteConnectionAddr(p_cb_.pairing_bda, remote_bda,
&remote_bd_addr_type);
BTM_ReadConnectionAddr(p_cb_.pairing_bda, p_cb_.local_bda, &p_cb_.addr_type);
- smp_gen_p1_4_confirm(&p_cb_, remote_bd_addr_type, p1);
+ Octet16 p1 = smp_gen_p1_4_confirm(&p_cb_, remote_bd_addr_type);
// Correct p1 is 0x05000800000302070710000001010001
const char expected_p1_str[] = "05000800000302070710000001010001";
- char p1_str[2 * sizeof(BT_OCTET16) + 1];
+ char p1_str[2 * OCTET16_LEN + 1];
dump_uint128_reverse(p1, p1_str);
ASSERT_THAT(p1_str, StrEq(expected_p1_str));
- smp_xor_128(p1, rand_);
+ smp_xor_128(&p1, rand_);
// Correct p1 xor r is 0x5283dd2156ae6d096498274ec7712ee1
const char expected_p1_xor_r_str[] = "5283dd2156ae6d096498274ec7712ee1";
- char p1_xor_r_str[2 * sizeof(BT_OCTET16) + 1];
+ char p1_xor_r_str[2 * OCTET16_LEN + 1];
dump_uint128_reverse(p1, p1_xor_r_str);
ASSERT_THAT(p1_xor_r_str, StrEq(expected_p1_xor_r_str));
- tSMP_ENC output;
- memset(&output, 0, sizeof(tSMP_ENC));
- ASSERT_TRUE(
- SMP_Encrypt(p_cb_.tk, BT_OCTET16_LEN, p1, BT_OCTET16_LEN, &output));
+ Octet16 output = crypto_toolbox::aes_128(p_cb_.tk, p1.data(), OCTET16_LEN);
const char expected_p1_prime_str[] = "02c7aa2a9857ac866ff91232df0e3c95";
- char p1_prime_str[2 * sizeof(BT_OCTET16) + 1];
- dump_uint128_reverse(output.param_buf, p1_prime_str);
+ char p1_prime_str[2 * OCTET16_LEN + 1];
+ dump_uint128_reverse(output, p1_prime_str);
ASSERT_THAT(p1_prime_str, StrEq(expected_p1_prime_str));
}
// Test smp_calculate_comfirm function implementation
TEST_F(SmpCalculateConfirmTest, test_smp_calculate_comfirm_as_master) {
- tSMP_ENC output;
+ Octet16 output;
tSMP_STATUS status = smp_calculate_comfirm(&p_cb_, rand_, &output);
EXPECT_EQ(status, SMP_SUCCESS);
// Correct MConfirm is 0x1e1e3fef878988ead2a74dc5bef13b86
const char expected_confirm_str[] = "1e1e3fef878988ead2a74dc5bef13b86";
- char confirm_str[2 * sizeof(BT_OCTET16) + 1];
- dump_uint128_reverse(output.param_buf, confirm_str);
+ char confirm_str[2 * OCTET16_LEN + 1];
+ dump_uint128_reverse(output, confirm_str);
ASSERT_THAT(confirm_str, StrEq(expected_confirm_str));
}
} // namespace testing
diff --git a/tools/scripts/dump_metrics_ascii.py b/tools/scripts/dump_metrics_ascii.py
new file mode 100755
index 0000000..c24d299
--- /dev/null
+++ b/tools/scripts/dump_metrics_ascii.py
@@ -0,0 +1,140 @@
+#!/usr/bin/env python3
+# Copyright 2018 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.
+
+import base64
+import logging
+import os
+import subprocess
+import sys
+import tempfile
+from distutils.spawn import find_executable
+import google.protobuf.text_format as text_format
+from importlib import import_module
+
+def compile_proto(proto_path, output_dir):
+ """Invoke Protocol Compiler to generate python from given source .proto."""
+ # Find compiler path
+ protoc = None
+ if 'PROTOC' in os.environ and os.path.exists(os.environ['PROTOC']):
+ protoc = os.environ['PROTOC']
+ if not protoc:
+ protoc = find_executable('protoc')
+ if not protoc:
+ logging.error(
+ "Cannot find Protobuf compiler (>=3.0.0), please install"
+ "protobuf-compiler package. Prefer copying from <top>/prebuilts/tools"
+ )
+ logging.error(" prebuilts/tools/linux-x86_64/protoc/bin/protoc")
+ logging.error("If prebuilts are not available, use apt-get:")
+ logging.error(" sudo apt-get install protobuf-compiler")
+ return None
+ # Validate input proto path
+ if not os.path.exists(proto_path):
+ logging.error('Can\'t find required file: %s\n' % proto_path)
+ return None
+ # Validate output py-proto path
+ if not os.path.exists(output_dir):
+ os.mkdirs(output_dir)
+ elif not os.path.isdir(output_dir):
+ logging.error("Output path is not a valid directory: %s" %
+ (output_dir))
+ return None
+ input_dir = os.path.dirname(proto_path)
+ output_filename = os.path.basename(proto_path).replace('.proto', '_pb2.py')
+ output_path = os.path.join(output_dir, output_filename)
+ protoc_command = [
+ protoc, '-I=%s' % (input_dir), '--python_out=%s' % (output_dir),
+ proto_path
+ ]
+ if subprocess.call(protoc_command, stderr=subprocess.STDOUT) != 0:
+ logging.error("Fail to compile proto")
+ return None
+ output_module_name = os.path.splitext(output_filename)[0]
+ return output_module_name
+
+
+def compile_import_proto(output_dir, proto_path):
+ """
+ Compile protobuf from PROTO_PATH and put the result in OUTPUT_DIR.
+ Return the imported module to caller.
+ :param output_dir: To store generated python proto library
+ :param proto_path: Path to the .proto file that needs to be compiled
+ :return: python proto module
+ """
+ output_module_name = compile_proto(proto_path, output_dir)
+ if not output_module_name:
+ return None
+ sys.path.append(output_dir)
+ output_module = None
+ try:
+ output_module = import_module(output_module_name)
+ except ImportError:
+ logging.error("Cannot import generated py-proto %s" %
+ (output_module_name))
+ return output_module
+
+
+def parse_proto_to_ascii(binary_proto_msg):
+ """
+ Parse binary protobuf message to human readable ascii string
+ :param binary_proto_msg:
+ :return: ascii string of the message
+ """
+ return text_format.MessageToString(binary_proto_msg)
+
+def dump_metrics():
+ os.system('adb wait-for-device')
+ p = subprocess.Popen("adb shell dumpsys bluetooth_manager --proto-bin",
+ shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+ stdin=subprocess.PIPE)
+ return p.communicate()
+
+def get_bluetooth_metrics(proto_native_str_64, bluetooth_proto_module):
+ bluetooth_log = bluetooth_proto_module.BluetoothLog()
+ proto_native_str = base64.b64decode(proto_native_str_64)
+ bluetooth_log.MergeFromString(proto_native_str)
+ return bluetooth_log
+
+def main():
+ root = logging.getLogger()
+ root.setLevel(logging.DEBUG)
+ log_handler = logging.StreamHandler(sys.stderr)
+ log_handler.setLevel(logging.DEBUG)
+ formatter = logging.Formatter(
+ "%(asctime)s %(levelname)s %(message)s")
+ log_handler.setFormatter(formatter)
+ root.addHandler(log_handler)
+ if len(sys.argv) < 2:
+ logging.error("Not enough arguments. Need at least 2")
+ logging.error("Usage: " + sys.argv[0] + " <path_to_metric_proto>")
+ sys.exit(1)
+ if sys.argv[1] == "-h":
+ logging.info("Usage: " + sys.argv[0] + " <path_to_metric_proto>")
+ logging.info("Requires Protobuf compiler, protoc, version >=3.0.0")
+ sys.exit(0)
+ bluetooth_proto_module = compile_import_proto(tempfile.gettempdir(),
+ sys.argv[1])
+ if not bluetooth_proto_module:
+ logging.error("Cannot compile " + sys.argv[1])
+ sys.exit(1)
+ stdout, stderr = dump_metrics()
+ stdout = stdout.strip()
+ stderr = stderr.strip()
+ bluetooth_log = get_bluetooth_metrics(stdout, bluetooth_proto_module)
+ bluetooth_log_ascii = parse_proto_to_ascii(bluetooth_log)
+ print(bluetooth_log_ascii)
+
+if __name__ == "__main__":
+ main()
diff --git a/vendor_libs/linux/sepolicy/file_contexts b/vendor_libs/linux/sepolicy/file_contexts
deleted file mode 100644
index 20b69c1..0000000
--- a/vendor_libs/linux/sepolicy/file_contexts
+++ /dev/null
@@ -1,2 +0,0 @@
-/sys/class/rfkill/rfkill[0-9]/state u:object_r:sysfs_bluetooth_writable:s0
-/(vendor|system/vendor)/bin/hw/android\.hardware\.bluetooth@1\.0-service\.btlinux u:object_r:hal_bluetooth_btlinux_exec:s0
diff --git a/vendor_libs/linux/sepolicy/hal_bluetooth_btlinux.te b/vendor_libs/linux/sepolicy/hal_bluetooth_btlinux.te
deleted file mode 100644
index 22d9cf0..0000000
--- a/vendor_libs/linux/sepolicy/hal_bluetooth_btlinux.te
+++ /dev/null
@@ -1,8 +0,0 @@
-type hal_bluetooth_btlinux, domain;
-type hal_bluetooth_btlinux_exec, exec_type, file_type, vendor_file_type;
-
-hal_server_domain(hal_bluetooth_btlinux, hal_bluetooth)
-init_daemon_domain(hal_bluetooth_btlinux)
-
-allow hal_bluetooth_btlinux self:socket { create bind read write };
-allow hal_bluetooth_btlinux self:bluetooth_socket { create bind read write };